一、OpenSSL简介
OpenSSL是一个强大的加密库,广泛应用于互联网的各个角落,用于保护数据传输的安全。它实现了SSL和TLS协议,这些协议是现代网络安全的基石。
二、OpenSSL概述
OpenSSL是一个强大的开源工具,用于实现SSL和TLS协议,保障网络通信的安全。它不仅提供了加密库,还包括了命令行工具,可以用于创建证书、生成密钥、测试SSL/TLS连接等。
OpenSSL 库主要包含三大部分:
openssl: 多用途的命令行工具,可以执行交互或批量命令。
libcrypto: 加解密算法库。
libssl:加密模块应用库,实现了ssl及tls。
2.1 主要功能
-
**加密算法支持 **: 支持多种加密算法,如RSA、AES等。
-
SSL/TLS协议实现: 提供SSL v2/v3和TLS协议的实现。
-
**证书处理 **: 生成和管理SSL证书。
2.2 安装配置
2.3 基本概念
2.3.1 SSL/TLS
-
SSL (Secure Sockets Layer): 安全套接层,用于在互联网上提供加密通信。
-
TLS (Transport Layer Security):传输层安全, SSL的后续版本,提供更强的安全性。
2.3.2 加密密钥
-
公钥 (Public Key): 用于加密数据,可以公开。
-
私钥 (Private Key): 用于解密数据,必须保密。
2.3.3 证书
数字证书 (Digital Certificate): 用于验证实体身份的电子文件。
2.3.4 证书、私钥和证书签署请求(CSR)获取
OpenSSL 精粹:SSL 证书、私钥和 CSR | Linux 中国 - 知乎 (zhihu.com)
自签名证书
适合测试和开发环境。可以使用 OpenSSL 工具来生成
#生成私钥
openssl genrsa -des3 -out privkey.pem 2048 #这个命令会生成一个2048位的密钥,同时有一个des3方法加密的密码
#如果不想要每次都输入密码,可以改成:
openssl genrsa -out privkey.pem 2048
#生成证书文件
#用上面生成的密钥privkey.pem生成一个数字证书cacert.pem,有效期为3650天
#在这一步,会提示输入信息,Common Name (eg, your name or your server's hostname) []:是必填,其他的可以选择回车使用默认值,输入点"."将信息项留空
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 3650
#生成公钥文件
openssl rsa -in privkey.pem -inform pem -pubout -out pubkey.pem
#查看密钥信息
openssl rsa -noout -text -in privkey.pem
三、SSL/TLS协议
SSL协议在互联网中应用特别广泛,成为事实上的互联网标准。在1999年IETF组织将SSL3.0协议规范进行了标准化,就是TLS协议。不过由于SSL3.0和TLS之间存在加密算法上的差异,因此不能互相操作。他们是两个不同的协议。这两个协议统称为SSL/TLS协议。
3.1 SSL和TLS的应用
SSL/TLS是一个安全通信框架,上面可以承载HTTP协议或者SMTP/POP3协议等。
3.2 SSL/TLS原理简介
SSL/TLS协议严格的说位于OSI-7层模型的会话层,在传输层(TCP, UDP)协议之上。
SSL/TLS协议是一个分层协议,本身可以分为上下两层:
下层为记录协议(record layer protocal)
上层为握手协议(handshake layer protocal)
Record层是SSL/TLS的基础封装协议,所有的交互报文都需要通过Record 层进行封装。
3.3 SSL 安全套接字层
3.3.1 SSL协议架构
- SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。
- SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
3.3.2 SSL协议的工作流程
服务器认证阶段:
1)客户端向服务器发送一个开始信息“Hello”开始一个新的会话连接;
2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;
3)客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;
4)服务器恢复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。
用户认证阶段:
在此之前,服务器已经通过了客户认证,这一阶段主要完成对客户的认证。经认证的服务器发送一个提问给客户,客户则返回数字签名后的提问和其公开密钥,从而向服务器提供认证。
3.4 TLS安全传输层协议
3.4.1 TLS协议架构
- TLS记录协议(TLS Record):建立在可靠的传输协议(如TCP)之上,用于封装高层协议,使用对称密码对消息进行加密。
- TLS握手协议(TLS Handshake):它建立在TLS记录协议之上。主要分为握手协议,密码规格变更协议和应用数据协议4个部分。
- 握手协议负责在客户端和服务器端商定密码算法和共享密钥,包括证书认证。
- 密码规格变更协议负责向通信对象传达变更密码方式的信号
- 警告协议负责在发生错误的时候将错误传达给对方
- 应用数据协议负责将TLS承载的应用数据传达给通信对象的协议。
3.4.2 握手协议
握手协议是TLS协议中非常重要的协议,通过客户端和服务器端的交互,和共享一些必要信息,从而生成共享密钥和交互证书。
主密码和预备主密码
步骤8生成了预备主密码,主密码是根据密码套件中定义的单向散列函数实现的伪随机数生成器+预备主密码+客户端随机数+服务器端随机数生成的。
主密码主要用来生成称密码的密钥,消息认证码的密钥和对称密码的CBC模式所使用的初始化向量。
3.4.3 记录协议
消息首先将会被分段,然后压缩,再计算其消息验证码,然后使用对称密码进行加密。得到密文之后会附加类型,版本和长度等其他信息,最终组成最后的报文数据。
四、ssl bufferevent
常用函数
初始化
int SSL_library_init(void);
功能:
初始化整个 OpenSSL 库
void SSL_load_error_strings(void);
功能:
加载错误字符串,可以将错误代码转换为可读的错误消息。
void OpenSSL_add_all_algorithms(void);
功能:
注册所有可用的加密算法、摘要算法和哈希算法。
void ERR_load_crypto_strings(void);
功能:
加载 OpenSSL 加密库(Crypto)的错误消息字符串。
释放
SSL_CTX_free(ssl_ctx);
功能:
释放 SSL_CTX 对象,与SSL_library_init()对应
EVP_cleanup();
功能:
清理所有的加密算法。与 OpenSSL_add_all_algorithms() 对应。
ERR_free_strings();
功能:
释放所有加载的错误消息字符串。与SSL_load_error_strings() 对应。
创建并初始化对象
SSL_CTX *SSL_CTX_new(const SSL_METHOD *method);
功能:
创建并初始化一个新的SSL 对象,用于保存 SSL/TLS 配置和状态信息,并在多个 SSL 连接中共享这些信息。
参数:
const SSL_METHOD *method:指向一个 SSL_METHOD 结构的指针,定义了 SSL/TLS 的协议版本和选项。
常用的 SSL_METHOD 包括:
TLS_method():支持客户端和服务器端的通用 TLS 方法(包括 TLS 1.0 到 TLS 1.3)。
TLS_server_method():服务器端的通用 TLS 方法。
TLS_client_method():客户端的通用 TLS 方法。
返回值:
成功:指向新创建的 SSL_CTX 结构的指针。
失败:NULL,并设置相应的错误信息,可以通过 ERR_get_error 函数获取详细错误代码。
SSL *SSL_new(SSL_CTX *ssl_ctx);
功能:
创建一个新的 SSL 连接对象。这个新创建的对象可以用于发起或接受 SSL/TLS 连接。
参数:
SSL_CTX *ssl_ctx:通过 SSL_CTX_new() 函数创建的指向 SSL_CTX 结构的指针
返回值:
成功:指向新创建的 SSL 结构的指针
失败:NULL
SSL_CTX和SSL的区别
SSL_CTX
(SSL Context)是一个上下文对象,它包含了多个 SSL 连接共享的配置信息和状态。它的主要作用是存储 SSL/TLS 连接的全局设置,包括证书、私钥、会话参数、信任链等。
SSL
(SSL Connection)是一个连接对象,它包含了特定 SSL/TLS 连接的状态和数据。每个 SSL
对象对应一个单独的 SSL/TLS 会话,包含特定连接的详细信息。它的主要作用是是管理单个链接的状态,进行握手操作和读写数据。
步骤:
-
创建
SSL_CTX
对象。 -
配置
SSL_CTX
对象(加载证书、设置选项等)。 -
基于
SSL_CTX
创建SSL
对象。 -
关联
SSL
对象与一个网络连接,SSL_set_fd(ssl, sockfd)
-
进行 SSL/TLS 握手,
SSL_connect(ssl)
注:第四步和第五步可以使用
bufferevent_openssl_socket_new()
来代替,它提供了一种更高层次的抽象,简化了 OpenSSL 和 libevent 的集成 -
使用
SSL
对象进行数据传输。 -
关闭连接,释放
SSL
对象。
设置服务器证书链和私钥
int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file);
功能:
设置服务器的证书链,从文件中加载包含证书链的证书文件。
参数:
SSL_CTX *ssl_ctx:SSL_CTX 对象
const char *file:包含证书链的文件名
返回值:
成功:1
失败:0
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type);
功能:
设置服务器的私钥。它从文件中加载服务器的私钥。
参数:
SSL_CTX *ssl_ctx:SSL_CTX 对象
const char *file:包含私钥的文件名
int type:指定私钥文件的格式,通常为 SSL_FILETYPE_PEM(PEM 格式)或 SSL_FILETYPE_ASN1(DER 格式)
返回值:
成功:1
失败:0
创建SSL加密的缓存事件
struct bufferevent *bufferevent_openssl_socket_new(struct event_base *base, evutil_socket_t fd,SSL *ssl, enum bufferevent_ssl_state state, int options);
功能:
创建一个新的 SSL 缓冲事件(bufferevent),用于加密的数据传输。
使用场景(区别于bufferevent_openssl_filter_new函数):
直接处理一个套接字上的加密通信,适合于需要从头开始创建并管理套接字通信
参数:
struct event_base *base: 事件对象
evutil_socket_t fd: 套接字,如果为-1,会自动调用socket(),再异步调用connect(),如果指定了,那么bev只去做connect()操作
SSL *ssl: 已初始化的 SSL 对象
enum bufferevent_ssl_state state: SSL的初始状态,通常为 BUFFEREVENT_SSL_CONNECTING(客户端) 或 BUFFEREVENT_SSL_ACCEPTING(服务器端)
int options: 选项标志,如 BEV_OPT_CLOSE_ON_FREE
返回值:
成功:bufferevent 对象指针
失败:NULL
struct bufferevent *bufferevent_openssl_filter_new(struct event_base *base, struct bufferevent *underlying, SSL *ssl, enum bufferevent_ssl_state state, int options);
功能:
创建一个新的 SSL 过滤缓冲事件,使现有的 bufferevent 支持 SSL/TLS 加密。
使用场景(区别于bufferevent_openssl_socket_new函数):
已经有一个缓冲事件并希望在其上添加SSL/TLS层,适合于已有非加密通信需要升级为加密通信的情况
参数:
struct event_base *base:事件对象
struct bufferevent *underlying:底层的bufferevent对象,bufferevent_socket_new()的返回值
SSL *ssl: SSL 对象
enum bufferevent_ssl_state state: SSL 的初始状态
int options:选项标志
返回值:
成功:新的 bufferevent 对象指针
失败:NULL
获取SSL对象
SSL *bufferevent_get_ssl(struct bufferevent *bev);
功能:
获取与 bufferevent 关联的 SSL 对象。
参数:
struct bufferevent *bev:需要获取 SSL 对象的 bufferevent 对象
返回值:
与 bufferevent 关联的 SSL 对象指针
关闭SSL连接
int bufferevent_openssl_shutdown(struct bufferevent *bev, int how);
功能:
关闭 SSL bufferevent,包括关闭 SSL 连接
参数:
struct bufferevent *bev: SSL bufferevent 对象
int how: 关闭方式的标志,通常为 BEV_SSL_CLOSE_FREE
返回值:
成功:0
失败:-1
TLS和SSL加密的区别
在 bufferevent 中使用 TLS 和 SSL 加密的区别主要在于 SSL/TLS 上下文对象的初始化和配置上,以及选择特定的加密协议版本。(通常使用TLS)
创建并初始化对象:
TLS:SSL_CTX_new(TLS_method())
TLS_method()
:
SSL_CTX_new(TLS_client_method())
SSL_CTX_new(TLS_server_method())`
SSL:SSL_CTX_new(SSL_method())
SSL_method()
:
SSL_CTX_new(SSLv23_client_method())
SSL_CTX_new(SSLv23_server_method())