SSL握手通信详解及linux下c/c++ SSL Socket代码举例
SSL握手通信详解及linux下c/c++ SSL Socket代码举例
摘自:http://www.169it.com/article/3215130236.html
SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
安全证书既包含了用于加密数据的密钥,又包含了用于证实身份的数字签名。安全证书采用公钥加密技术。公钥加密是指使用一对非对称的密钥进行加密或解密。每一对密钥由公钥和私钥组成。公钥被广泛发布。私钥是隐秘的,不公开。用公钥加密的数据只能够被私钥解密。反过来,使用私钥加密的数据只能被公钥解密。这个非对称的特性使得公钥加密很有用。在安全证书中包含着一对非对称的密钥。只有安全证书的所有者才知道私钥。当通信方A将自己的安全证书发送给通信方B时,实际上发给通信方B的是公开密钥,接着通信方B可以向通信方A发送用公钥加密的数据,只有通信方A才能使用私钥对数据进行解密,从而获得通信方B发送的原始数据。安全证书中的数字签名部分是通信方A的电子身份证。数字签名告诉通信方B该信息确实由通信方A发出,不是伪造的,也没有被篡改。
客户与服务器通信时,首先要进行SSL握手,SSL握手主要完成以下任务:
1)协商使用的加密套件。加密套件中包括一组加密参数,这些参数指定了加密算法和密钥的长度等信息。
2)验证对方的身份,此操作是可选的。
3)确定使用的加密算法。
4)SSL握手过程采用非对称加密方法传递数据,由此来建立一个安全的SSL会话。SSL握手完成后,通信双方将采用对称加密方法传递实际的应用数据。
以下是SSL握手的具体流程:
(1)客户将自己的SSL版本号、加密参数、与SSL会话有关的数据及其他一些必要信息发送到服务器。
(2)服务器将自己的SSL版本号、加密参数、与SSL会话有关的数据及其他一些必要信息发送给客户,同时发给客户的还有服务器的证书。如果服务器需要验证客户身份,服务器还会发出要求客户提供安全证书的请求。
(3)客户端验证服务器证书,如果验证失败,就提示不能建立SSL连接。如果成功,那么继续下一步骤。
(4)客户端为本次SSL会话生成预备主密码(pre-master secret),并将其用服务器公钥加密后发送给服务器。
(5)如果服务器要求验证客户身份,客户端还要对另外一些数据签名后,将其与客户端证书一起发送给服务器。
(6)如果服务器要求验证客户身份,则检查签署客户证书的CA(Certificate Authority,证书机构)是否可信。如果不在信任列表中,结束本次会话。如果检查通过,服务器用自己的私钥解密收到的预备主密码(pre-master secret),并用它通过某些算法生成本次会话的主密码(master secret)。
(7)客户端与服务器端均使用此主密码(master secret)生成此次会话的会话密钥(对称密钥)。在双方SSL握手结束后传递任何消息均使用此会话密钥。这样做的主要原因是对称加密比非对称加密的运算量要低一个数量级以上,能够显著提高双方会话时的运算速度。
(8)客户端通知服务器此后发送的消息都使用这个会话密钥进行加密,并通知服务器客户端已经完成本次SSL握手。
(9)服务器通知客户端此后发送的消息都使用这个会话密钥进行加密,并通知客户端服务器已经完成本次SSL握手。
(10)本次握手过程结束,SSL会话已经建立。在接下来的会话过程中,双方使用同一个会话密钥分别对发送和接收的信息进行加密和解密。
以下为 linux c/c++ ssl socket client和server的代码参考。
客户端代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#include <stdio.h> #include <errno.h> #include <unistd.h> #include <malloc.h> #include <string.h> #include <sys/socket.h> #include <resolv.h> #include <netdb.h> #include <openssl/ssl.h> #include <openssl/err.h> #define FAIL -1 int OpenConnection( const char *hostname, int port) { int sd; struct hostent *host; struct sockaddr_in addr; if ( (host = gethostbyname(hostname)) == NULL ) { printf ( 'Eroor: %sn' ,hostname); perror (hostname); abort (); } sd = socket(PF_INET, SOCK_STREAM, 0); bzero(&addr, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = *( long *)(host->h_addr); if ( connect(sd, ( struct sockaddr*)&addr, sizeof (addr)) != 0 ) { close(sd); perror (hostname); abort (); } return sd; } SSL_CTX* InitCTX( void ) { SSL_METHOD *method; SSL_CTX *ctx; OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */ SSL_load_error_strings(); /* Bring in and register error messages */ method = SSLv2_client_method(); /* Create new client-method instance */ ctx = SSL_CTX_new(method); /* Create new context */ if ( ctx == NULL ) { ERR_print_errors_fp(stderr); printf ( 'Eroor: %sn' ,stderr); abort (); } return ctx; } void ShowCerts(SSL* ssl) { X509 *cert; char *line; cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */ if ( cert != NULL ) { printf ( "Server certificates:n" ); line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); printf ( "Subject: %sn" , line); free (line); /* free the malloc'ed string */ line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf ( "Issuer: %sn" , line); free (line); /* free the malloc'ed string */ X509_free(cert); /* free the malloc'ed certificate copy */ } else printf ( "No certificates.n" ); } int main( int count, char *strings[]) { SSL_CTX *ctx; int server; SSL *ssl; char buf[1024]; int bytes; char *hostname, *portnum; if ( count != 3 ) { printf ( "usage: %s <hostname> <portnum>n" , strings[0]); exit (0); } SSL_library_init(); hostname=strings[1]; portnum=strings[2]; ctx = InitCTX(); server = OpenConnection(hostname, atoi (portnum)); ssl = SSL_new(ctx); /* create new SSL connection state */ SSL_set_fd(ssl, server); /* attach the socket descriptor */ if ( SSL_connect(ssl) == FAIL ) /* perform the connection */ { printf ( 'Eroor: %sn' ,stderr); ERR_print_errors_fp(stderr); } else { char *msg = "HelloWorld" ; printf ( "Connected with %s encryptionn" , SSL_get_cipher(ssl)); ShowCerts(ssl); /* get any certs */ SSL_write(ssl, msg, strlen (msg)); /* encrypt & send message */ bytes = SSL_read(ssl, buf, sizeof (buf)); /* get reply & decrypt */ buf[bytes] = 0; printf ( "Received: " %s "n" , buf); SSL_free(ssl); /* release connection state */ } close(server); /* close socket */ SSL_CTX_free(ctx); /* release context */ return 0; } |
服务端代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#include <errno.h> #include <unistd.h> #include <malloc.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <resolv.h> #include "openssl/ssl.h" #include "openssl/err.h" #define FAIL -1 using namespace std; int OpenListener( int port) { int sd; struct sockaddr_in addr; sd = socket(PF_INET, SOCK_STREAM, 0); bzero(&addr, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if ( bind(sd, ( struct sockaddr*)&addr, sizeof (addr)) != 0 ) { perror ( "can't bind port" ); abort (); } if ( listen(sd, 10) != 0 ) { perror ( "Can't configure listening port" ); abort (); } return sd; } SSL_CTX* InitServerCTX( void ) { SSL_CTX *ctx = NULL; #if OPENSSL_VERSION_NUMBER >= 0x10000000L const SSL_METHOD *method; #else SSL_METHOD *method; #endif SSL_library_init(); OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ SSL_load_error_strings(); /* load all error messages */ method = SSLv23_client_method(); /* create new server-method instance */ ctx = SSL_CTX_new(method); /* create new context from method */ if ( ctx == NULL ) { ERR_print_errors_fp(stderr); abort (); } return ctx; } void LoadCertificates(SSL_CTX* ctx, char * CertFile, char * KeyFile) { //New lines if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1) ERR_print_errors_fp(stderr); if (SSL_CTX_set_default_verify_paths(ctx) != 1) ERR_print_errors_fp(stderr); //End new lines /* set the local certificate from CertFile */ if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 ) { ERR_print_errors_fp(stderr); abort (); } /* set the private key from KeyFile (may be the same as CertFile) */ if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 ) { ERR_print_errors_fp(stderr); abort (); } /* verify private key */ if ( !SSL_CTX_check_private_key(ctx) ) { fprintf (stderr, "Private key does not match the public certificaten" ); abort (); } printf ( "LoadCertificates Compleate Successfully.....n" ); } void ShowCerts(SSL* ssl) { X509 *cert; char *line; cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */ if ( cert != NULL ) { printf ( "Server certificates:n" ); line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); printf ( "Subject: %sn" , line); free (line); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf ( "Issuer: %sn" , line); free (line); X509_free(cert); } else printf ( "No certificates.n" ); } void Servlet(SSL* ssl) /* Serve the connection -- threadable */ { char buf[1024]; char reply[1024]; int sd, bytes; const char * HTMLecho= "<html><body><pre>%s</pre></body></html>nn" ; if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */ ERR_print_errors_fp(stderr); else { ShowCerts(ssl); /* get any certificates */ bytes = SSL_read(ssl, buf, sizeof (buf)); /* get request */ if ( bytes > 0 ) { buf[bytes] = 0; printf ( "Client msg: " %s "n" , buf); sprintf (reply, HTMLecho, buf); /* construct reply */ SSL_write(ssl, reply, strlen (reply)); /* send reply */ } else ERR_print_errors_fp(stderr); } sd = SSL_get_fd(ssl); /* get socket connection */ SSL_free(ssl); /* release SSL state */ close(sd); /* close connection */ } int main( int count, char *strings[]) { SSL_CTX *ctx; int server; char *portnum; if ( count != 2 ) { printf ( "Usage: %s <portnum>n" , strings[0]); exit (0); } else { printf ( "Usage: %s <portnum>n" , strings[1]); } SSL_library_init(); portnum = strings[1]; ctx = InitServerCTX(); /* initialize SSL */ LoadCertificates(ctx, "/home/stud/kawsar/mycert.pem" , "/home/stud/kawsar/mycert.pem" ); /* load certs */ server = OpenListener( atoi (portnum)); /* create server socket */ while (1) { struct sockaddr_in addr; socklen_t len = sizeof (addr); SSL *ssl; int client = accept(server, ( struct sockaddr*)&addr, &len); /* accept connection as usual */ printf ( "Connection: %s:%dn" ,inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); ssl = SSL_new(ctx); /* get new SSL state with context */ SSL_set_fd(ssl, client); /* set connection socket to SSL state */ Servlet(ssl); /* service connection */ } close(server); /* close server socket */ SSL_CTX_free(ctx); /* release context */ }
|
SSL握手通信详解及linux下c/c++ SSL Socket代码举例的更多相关文章
- SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码)
SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码) 摘自: https://blog.csdn.net/sjin_1314/article/det ...
- 转:SSL 握手协议详解
SSL 握手协议详解 RSA作为身份认证,ECDHE来交换加密密钥,AES/DES等作为加密. 如果RSA来加解密,那么身份认证后,直接用认证后的RSA公钥解密.不需要再额外交换加密密钥了. 相关报文 ...
- SSL 握手协议详解
这里重点介绍一下服务端的验证和密钥交换.这个阶段的前面的(a)证书 和(b)服务器密钥交换是基于密钥交换方法的.而在SSL中密钥交换算法有6种:无效(没有密钥交换).RSA.匿名Diffie-Hell ...
- 【图文详解】linux下配置远程免密登录
linux下各种集群搭建往往需要配置远程免密登录,本文主要描述了CentOs6.3系统下配置免密登录的详细过程. ssh远程登录,两种身份验证: 用户名+密码 密钥验证 机器1生成密钥对并将公钥发给机 ...
- 详解在Linux下实现(彩色)进度条程序,并通过makefile进行编译.
彩色进度条的实现与makefile编译: 创建一个process文件,在里面编写实现进度条的代码 1.在编写代码的时候我们首先要区分两个转义字符:\n \r \n:表示换行,换到下一行,并位于起 ...
- 详解hdparm: linux下的硬盘测速工具
hdparm的功能:显示与设定硬盘的参数.hdparm可检测,显示与设定IDE或SCSI硬盘的参数. 语法: hdparm [-CfghiIqtTvyYZ][-a <快取分区>][-A & ...
- SSL/TLS协议详解(下)——TLS握手协议
本文转载自SSL/TLS协议详解(下)--TLS握手协议 导语 在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容 ...
- 开源项目SMSS发开指南(五)——SSL/TLS加密通信详解(下)
继上一篇介绍如何在多种语言之间使用SSL加密通信,今天我们关注Java端的证书创建以及支持SSL的NioSocket服务端开发.完整源码 一.创建keystore文件 网上大多数是通过jdk命令创建秘 ...
- SSL/TLS 握手过程详解
在现代社会,互联网已经渗透到人们日常生活的方方面面,娱乐.经济.社会关系等都离不开互联网的帮助.在这个背景下,互联网安全就显得十分重要,没有提供足够的安全保障,人们是不会如此依赖它的.幸运的是,在大牛 ...
随机推荐
- 6-18 Two Stacks In One Array(20 分)
Write routines to implement two stacks using only one array. Your stack routines should not declare ...
- soql取第一件数据
User u = [select ID,Name from User Limit 1];
- Phonegap 开发环境搭建
以Android为例介绍Phonegap开发环境搭建 一. 软件下载 1. JDK 8 下载 http://www.oracle.com/technetwork/java/javase/downloa ...
- CentOS7 防火墙配置-详解
CentOS 7 防火墙配置 1.防火墙的简述 防火墙对服务器起到一定的保护作用,所以了解一些相关的操作是很有必要的. 在CentOS 7.x中,有了一种新的防火墙策略叫FireWall , 在6.x ...
- MariaDB Galera Cluster的配置测试
参考的https://fykuan.hsnuer.net/blog/2015/01/23/debian-%E4%B8%8A%E5%AE%89%E8%A3%9D-mariadb-galera-clust ...
- 蓝桥杯 生命之树【树状dp】
生命之树 在X森林里,上帝创建了生命之树. 他给每棵树的每个节点(叶子也称为一个节点)上, 都标了一个整数,代表这个点的和谐值. 上帝要在这棵树内选出一个非空节点集S, 使得对于S中的任意两个点a,b ...
- configure: error: Please reinstall the libcurl distribution - easy.h should be in <curl-dir>/include/curl/
编译php出现错误: configure: error: Please reinstall the libcurl distribution - easy.h should be in <cur ...
- 源文件封装为IP的步骤
因为模块的交接,最好将写好的源文件和生成的IP封装一个IP,然后再转交给其他的同事使用,这是一种好的习惯.但是对于,封装的过程还是需要注意一下.实际的看看步骤吧.1)将源文件和使用到的IP生成工程. ...
- MySql 日期函数比较
查询当天数据 select * from tab where FROM_UNIXTIME(fabutime, '%Y%m%d') = 20121217; mysql TO_DAYS(date) 函 ...
- tesseract-ocr训练方法
tesseract-ocr有2和3两个版本,不同版本训练方法稍有不同. 第3版本的训练方法官版教程在这里:TrainingTesseract3 第2版的训练方法官版教程在这里:TrainingTess ...