Nginx+openssl的web https访问:
1证书的生成:
openssl genrsa -des3 -out host.key 2048
生成签发机构密钥
openssl req -new -x509 -days 7305 -key host.key -out host.crt
生成签发用证书
openssl genrsa -des3 -out applier.pem 1024
请求认证的公司生成私钥
openssl rsa -in applier.pem -out applier.key
生成applier.pem对应的解密密钥applier.key
openssl req -new -key applier.pem -out applier.csr
请求认证的证书申请
openssl ca -policy policy_anything -days 1460 -cert host.crt -keyfile host.key -in applier.csr -out applier.crt
Ca对applier.csr签名并发布证书applier.crt
//认证环境
mkdir -p CA/newcerts
touch CA/index.txt
touch CA/serial
echo "01" > CA/serial
2 Nginx的配置
Server{
Listen 443 ssl default_server;
Index index.html index.htm;
Location / {
Root /rootdir
}
Ssl on
Ssl_certificate /path/applier.crt #提供证书
Ssl_certificate_key /path/applier.key #提供解密私钥
}
访问时通过https协议直接访问localhost,此时浏览器会与服务器握手并收到证书消息,由于试验中使用的自签名证书,因此浏览器会提示证书不可信,将此证书添加到exception中即可访问。在服务器发给客户机的证书报文段中,包含有服务器证书的公钥;客户机接收到该报文段后,按照协议规定,从报文段的对应位置中读取出服务器证书的公钥存入相关变量中。
与网站建立SSL安全连接时使用https协议,即采用https://ip:port/的方式来访问。浏览器与Web Server之间要经过一个握手的过程来完成身份鉴定与密钥交换,从而建立安全连接。具体过程如下:
1用户浏览器将其SSL版本号、加密设置参数、与session有关的数据以及其它一些必要信息发送到服务器。
服务器将其SSL版本号、加密设置参数、与session有关的数据以及其它一些必要信息发送给浏览器,同时发给浏览器的还有服务器的证书。如果配置服务器的SSL需要验证用户身份,还要发出请求要求浏览器提供用户证书。
2客户端检查服务器证书,如果检查失败,提示不能建立SSL连接。如果成功,那么继续。客户端浏览器为本次会话生成pre-master secret,并将其用服务器公钥加密后发送给服务器。如果服务器要求鉴别客户身份,客户端还要再对另外一些数据签名后并将其与客户端证书一起发送给服务器。
如果服务器要求鉴别客户身份,则检查签署客户证书的CA是否可信。如果不在信任列表中,结束本次会话。如果检查通过,服务器用自己的私钥解密收到的pre-master secret,并用它通过某些算法生成本次会话的master secret。
3客户端与服务器均使用此master secret生成本次会话的会话密钥(对称密钥)。在双方SSL握手结束后传递任何消息均使用此会话密钥。这样做的主要原因是对称加密比非对称加密的运算量低一个数量级以上,能够显著提高双方会话时的运算速度。 客户端通知服务器此后发送的消息都使用这个会话密钥进行加密。并通知服务器客户端已经完成本次SSL握手。 服务器通知客户端此后发送的消息都使用这个会话密钥进行加密。并通知客户端服务器已经完成本次SSL握手。
x509协议api
证书的初始化函数:
void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ){
memset( crt, 0, sizeof(mbedtls_x509_crt) );}
证书的空间释放函数
void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
证书结构:
typedef struct mbedtls_x509_crt
{
mbedtls_x509_buf raw;随机数据
mbedtls_x509_buf tbs;签名
int version;版本
mbedtls_x509_buf serial; CA颁发的唯一序列号
mbedtls_x509_buf sig_oid;签名算法,比如. sha1RSA *
mbedtls_x509_time valid_from;证书有效起始时间
mbedtls_x509_time valid_to;证书失效时间
mbedtls_pk_context pk;公钥容器
int ext_types; /**< Bit string containing detected and parsed extensions */
int max_pathlen;最大路径长度
mbedtls_x509_buf sig;用私钥加密后的签名
mbedtls_md_type_t sig_md;信息摘要生成算法名称. MBEDTLS_MD_SHA256mbedtls_pk_type_t sig_pk;签名加密算法集的名称MBEDTLS_PK_RSA */
struct mbedtls_x509_crt *next;指向下一个证书的指针
}
Mbedtls中的握手:
客户端函数
int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl )
输入参数为ssl_context为安全连接的配置参数,包含了握手状态、握手参数、会话数据、客户端ID以及相关回调入口等参数。
以下程序摘自ssl_tls.c文件,可以看出mbed根据宏定义分别实现了server端和client端
#if defined(MBEDTLS_SSL_CLI_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
ret = mbedtls_ssl_handshake_client_step( ssl );
#endif
#if defined(MBEDTLS_SSL_SRV_C)
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
ret = mbedtls_ssl_handshake_server_step( ssl );
#endif
Client端的逻辑:
Client发起clienthello请求后,server回serverhello包以及certificate(如果对客户端有认证需求则会跟随发送一个certificate request包来请求客户端的证书),之后client开始分析传来的server证书是否有效合法:
首先确认是否需要证书验证,通过判断ssl->transform_negotiate->ciphersuite_info字段
MBEDTLS_KEY_EXCHANGE_ECJPAKE,
MBEDTLS_KEY_EXCHANGE_PSK,
MBEDTLS_KEY_EXCHANGE_DHE_PSK,
MBEDTLS_KEY_EXCHANGE_ECDHE_PSK
以上四种psk加密套件不需要证书交互,需要证书的加密套件如下:
MBEDTLS_KEY_EXCHANGE_ECDHE_RSA,
MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
MBEDTLS_KEY_EXCHANGE_ECDH_RSA,
MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA,
其次验证证书的有效性:mbedtls_x509_crt_verify_with_profile是x509_crt.c中的验证函数,其输入参数是会话的peer证书、证书链、可信ca列表、认证配置文件、以及认证参数等。
1、对比CN字段是否匹配,若不匹配返回CN_MISMATCH错误---x509_memcasecmp函数
2、根据配置文件检查密钥大小和类型是否正确,不正确返回BAD_KEY错误----x509_profile_check_key函数
3、判断CA的签发方以及父签发方(签发链)是否可信-----x509_crt_check_parent函数
验证完毕后,会判断证书使用的是否是EC密钥,如果是的话会使用函数mbedtls_ssl_check_curve来验证椭圆曲线是否正确。