TLS协议格式

 

 握手协议:双方拿到对方的证书,取出公钥,最终协商出一个共享密钥;整个握手协议是建立在TCP三次握手基础之上。

以下是客户端和服务器的握手过程和密钥导出过程。

 

   这里有两个问题,为什么后面还要发送消息认证码?

    在握手协议的前两步,是明文通信,如果有人将客户端所支持的密钥算法套件中的安全级别较高的算法改为低强度算法,从而减小入侵者的破解难度。所有为了防止这种篡改,在后面向对方发送MAC.

  不重数有什么用?

    每次的SSL连接使用不同的不重数,而通信主密钥是由不重数和前主密钥PMS产生,即使两次通信的PMS相同,而不重数不同产生的子密钥也不同。如果服务器接收到来自客户端SSL连接记录的重放,该记录无法通过完整性校验。总之不重数用来防御连接重放攻击。

TLS记录协议规定了数据包如何发送,数据完整性校验。发送方将消息分块,压缩后添加上一个MAC,再进行加密发送。接受发收到后,用相应的对称密钥EB解密后,再用MB进行数据的完整性校验。

OpenSSL中用于TLS通信的接口有两类,一是SSL_CTX上下文接口,通信协商出的协议,后面就按照这种协议,包括密钥、证书、是否验证证书。二是SSL接口,负责具体的通信,包括建立连接,接受连接,用协商好的密钥来发送数据和接受数据。

1、SSL_CTX接口介绍

  创建ssl_ctx上下文对象,记得之后用SSL_CTX_free(SSL_CTX*ctx)释放对象。客户端和服务器都需要初始化这个对象,区别在于参数不同。客户端参数填TLS_client_method(),服务端填TLS_server_method()

SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);

  客户端验证服务端的证书,如果需要,服务端也可以验证客户端的证书;

//@param mode SSL_VERIFY_PEER
//@param callback回调函数
void CTX_set_verify(SSL_CTX *ctx, int mode, SSL_verify_cb callback);

  服务端加载自己的证书、私钥

//@file证书所在的文件位置
//@type 证书的类型:PEM和DER
//成功返回1
int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file,
                                        int type);
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file,
                                       int type);

  服务端验证证书和私钥是否一致

int SSL_CTX_check_private_key(const SSL_CTX *ctx);

2、以上SSL_CTX完成后可以通过SSL_new(SSL_CTX*ctx)创建SSL安全通信的对象,SSL接口如下

  将ssl对象和文件描述符关联起来

int SSL_set_fd(SSL *s, int fd);

  握手协议,交换各自的版本和算法,还有证书。以下调用完成后双方协商好一个共享密钥,用于之后的加密通信。

int SSL_connect(SSL *ssl);
int SSL_accept(SSL *ssl);

   发送数据和接收数据

int SSL_write(SSL *ssl, const void *buf, int num);
int SSL_read(SSL *ssl, void *buf, int num);

  当双方通信完成之后,需要释放资源

void SSL_shutdown(SSL*ssl);
void SSL_CTX_free(SSL_CTX *);
void SSL_free(SSL *ssl);

使用OpenSSL进行安全通信的流程图

源码

https://gitee.com/tangxiao1/openssl.git