之前在微博上看到一个分享,关于HTTPS的,原文链接The First Few Milliseconds of an HTTPS Connection,加上最近也在学习openssl 的相关知识。所以也进行简单的实验,并整理一些资料,以加深对SSL、TLS的了解。
一,基本概念
SSL 是安全套接层(Secure Socket Layer)的缩写,而TLS表示传输层安全(Transport Layer Security)的缩写。SSl最初由网景公司提出,最初目的是为了保护web安全,然而现在用来提高传输层的安全。TLS是IETF基于SSLv3制 定的标准,两者基本一致,只有少许的差别。首先我们来看一下SSLv3 /TLS协议在TCP/IP协议栈中的位置,通常我们认为SSLv3 /TLS处于传输层和应用层之间。而将SSLv3/TLS通常又分为握手层和记录层,如下图所示:
图片1
1,Handshake 握手协议的基本功能
(1)服务器认证
(2)客户端认证(可选)
(3)算法协商
(4)密钥生成
2,Change Cipher Spec 更改密码规范协议
在安全协商后,服务器和客户端会交互这条消息,来提示使用协商好的安全参数
3,Alert 警告协议
(1)提供报错机制
(2)安全断连机制
二,WireShark 实验
首先来了解一下SSLv3/TLS协议流程,如下图所示,而4,6这两个过程通常不会出现在我们的浏览器访问过程中。下面我们以WireShark来分析浏览器访问https://github.com 来了解一下TLS建链路的过程。
图片1
1 Client Hello
从下图中,可以看出,采用的TLS协议版本为1.1,握手协议为Client hello,主要包含以下信息:32字节的随机数random;Session ID;客户端支持的密码套件Cipher Suites 以及压缩算法Compression Methods。
-
- struct
- {
- uint32gmt_unix_time;
- opaquerandom_bytes[28];
- }Random;
-
- struct{
- ProtocolVersionclient_version;
- Randomrandom;
- SessionIDsession_id;
- CipherSuitecipher_suites<2..2^16-1>;
- CompressionMethodcompression_methods<1..2^8-1>;
- }ClientHello;
图片1
2 Server Hello
服务器端消息定义如下同clientHello的区别是,服务器端选择双方支持的密码套件及压缩算法,在下图中可以看到选择的密码套件为:TLS_RSA_WITH_RC4_128_SHA,而压缩算法为NULL即不支持压缩。
- struct {
- ProtocolVersion server_version;
- Random random;
- SessionID session_id;
- CipherSuite cipher_suite;
- CompressionMethod compression_method;
- } ServerHello;
图片1
3~6 Send certificate and Server Hello Done
服务气短讲证书链发送给客户端。证书链中证书的顺序是每个证书的签名都由随后证书的公 钥进行验证。紧接着是一个Sever Hello Done的消息,因为这边包含可选的认证,发送Server Hello Done表明服务器端hello 信息结束。因为服务器没有要求验证客户端身份故4和6步骤没有。
图片1
7~13 key exchange and change cipher spec
至此链路建立
图片1
三,Openssl 中相关函数
SSL协议源码位于ssl目录下。它实现了sslv2、sslv3、TLS以及DTLS(Datagram TLS,基于UDP的TLS实现)。ssl实现中,对于每个协议,都有客户端实现(XXX_clnt.c)、服务端实现(XXX_srvr.c)、加密实现(XXX_enc.c)、记录协议实现(XXX_pkt.c)、METHOD方法(XXX_meth.c)、客户端服务端都用到的握手方法实现(XXX_both.c),以及对外提供的函数实现(XXX_lib.c)。
四,Polarssl 中的SSL实例
Polarssl 是一个轻量级的ssl 适合用于嵌入式平台中,我简单看了一下其中的代码结构,感觉非常清晰。看其中的代码也便于理解SSL。具体代码可以查看 polarssl/programs/ssl 下的几个文件。下面列出一些客户端关键的代码,服务器端可以自己查看代码,理解如何自己建立SSL链路。
-
-
-
-
- #if defined(POLARSSL_CERTS_C)
- ret = x509parse_crt( &cacert
- , (const unsigned char *) test_ca_crt,strlen( test_ca_crt ) );
- #endif
-
-
-
-
-
-
- printf( " . Loading the client cert. and key..." );
- #if defined(POLARSSL_CERTS_C)
- ret = x509parse_crt( &clicert
- , (const unsigned char *) test_cli_crt,strlen( test_cli_crt ) );
- #endif
-
- #if defined(POLARSSL_CERTS_C)
- ret = x509parse_key( &rsa
- , (const unsigned char *) test_cli_key,strlen( test_cli_key ), NULL, 0 );
- #endif
-
-
-
-
- printf( " . Connecting to tcp/%s/%-4d...", opt.server_name, opt.server_port );
- if( ( ret = net_connect( &server_fd, opt.server_name,opt.server_port ) ) != 0 )
- {
- ....
- }
-
-
-
- printf( " . Setting up the SSL/TLS structure..." );
- if( ( ret = ssl_init( &ssl ) ) != 0 )
- {
- ....
- }
- ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
- ssl_set_authmode( &ssl, opt.auth_mode );
- ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
- ssl_set_dbg( &ssl, my_debug, stdout );
- ssl_set_bio( &ssl, net_recv, &server_fd,
- net_send, &server_fd );
- if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
- ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
- ssl_set_renegotiation( &ssl, opt.renegotiation );
- ssl_legacy_renegotiation( &ssl, opt.allow_legacy );
- ssl_set_ca_chain( &ssl, &cacert, NULL, opt.server_name );
- ssl_set_own_cert( &ssl, &clicert, &rsa );
- ssl_set_hostname( &ssl, opt.server_name );
-
- if( opt.min_version != -1 )
- ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
- if( opt.max_version != -1 )
- ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
-
-
-
- printf( " . Performing the SSL/TLS handshake..." );
- fflush( stdout );
-
- while( ( ret = ssl_handshake( &ssl ) ) != 0 )
- {
- if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
- {
- ....
- }
- }
-
-
-
- printf( " . Verifying peer X.509 certificate..." );
-
- if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
- {
- printf( " failed\n" );
- ...
- printf( "\n" );
- }
-
- printf( " . Peer certificate information ...\n" );
- x509parse_cert_info( (char *) buf, sizeof( buf ) - 1
- , " ",ssl_get_peer_cert( &ssl ) );
-
-
-
- len = sprintf( (char *) buf, GET_REQUEST, opt.request_page );
- while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 )
- {
- ...
- }
-
-
-
- printf( " < Read from server:" );
- fflush( stdout );
-
- do
- {
- ret = ssl_read( &ssl, buf, len );
- ....
- }while(1);
- ssl_close_notify( &ssl );
- }
关键握手协议在ssl_handshake函数中,循环调用ssl_handshake_step,直至握手过程完成。
- int ssl_handshake( ssl_context *ssl )
- {
- int ret = 0;
-
- SSL_DEBUG_MSG( 2, ( "=> handshake" ) );
-
- while( ssl->state != SSL_HANDSHAKE_OVER )
- {
- ret = ssl_handshake_step( ssl );
-
- if( ret != 0 )
- break;
- }
-
- SSL_DEBUG_MSG( 2, ( "<= handshake" ) );
-
- return( ret );
- }
client端最后调用的是ssl_handshake_client_step函数,在library/ssl_cli.c中,代码注释非常清晰,不再复述。
- int ssl_handshake_client_step( ssl_context *ssl )
- {
- int ret = 0;
-
- if( ssl->state == SSL_HANDSHAKE_OVER )
- return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
-
- SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );
-
- if( ( ret = ssl_flush_output( ssl ) ) != 0 )
- return( ret );
-
- switch( ssl->state )
- {
- case SSL_HELLO_REQUEST:
- ssl->state = SSL_CLIENT_HELLO;
- break;
-
-
-
-
- case SSL_CLIENT_HELLO:
- ret = ssl_write_client_hello( ssl );
- break;
-
-
-
-
-
-
-
-
- case SSL_SERVER_HELLO:
- ret = ssl_parse_server_hello( ssl );
- break;
-
- case SSL_SERVER_CERTIFICATE:
- ret = ssl_parse_certificate( ssl );
- break;
-
- case SSL_SERVER_KEY_EXCHANGE:
- ret = ssl_parse_server_key_exchange( ssl );
- break;
-
- case SSL_CERTIFICATE_REQUEST:
- ret = ssl_parse_certificate_request( ssl );
- break;
-
- case SSL_SERVER_HELLO_DONE:
- ret = ssl_parse_server_hello_done( ssl );
- break;
-
-
-
-
-
-
-
-
- case SSL_CLIENT_CERTIFICATE:
- ret = ssl_write_certificate( ssl );
- break;
-
- case SSL_CLIENT_KEY_EXCHANGE:
- ret = ssl_write_client_key_exchange( ssl );
- break;
-
- case SSL_CERTIFICATE_VERIFY:
- ret = ssl_write_certificate_verify( ssl );
- break;
-
- case SSL_CLIENT_CHANGE_CIPHER_SPEC:
- ret = ssl_write_change_cipher_spec( ssl );
- break;
-
- case SSL_CLIENT_FINISHED:
- ret = ssl_write_finished( ssl );
- break;
-
-
-
-
-
- case SSL_SERVER_CHANGE_CIPHER_SPEC:
- ret = ssl_parse_change_cipher_spec( ssl );
- break;
-
- case SSL_SERVER_FINISHED:
- ret = ssl_parse_finished( ssl );
- break;
-
- case SSL_FLUSH_BUFFERS:
- SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
- ssl->state = SSL_HANDSHAKE_WRAPUP;
- break;
-
- case SSL_HANDSHAKE_WRAPUP:
- ssl_handshake_wrapup( ssl );
- break;
-
- default:
- SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
- return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
- }
-
- return( ret );
- }
(kkxgx) |