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 -1int 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 -1using 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 握手过程详解
在现代社会,互联网已经渗透到人们日常生活的方方面面,娱乐.经济.社会关系等都离不开互联网的帮助.在这个背景下,互联网安全就显得十分重要,没有提供足够的安全保障,人们是不会如此依赖它的.幸运的是,在大牛 ...
随机推荐
- iOS NSLog去掉时间戳及其他输出样式
1.一般项目中我的NSLog会在Prefix.pch文件添加如下代码,已保证在非调试状态下NSLog不工作 1 2 3 4 5 #ifdef DEBUG #define NSLog(...) NS ...
- .NET4.0中使用4.5中的 async/await 功能实现异步
在.NET Framework 4.5中添加了新的异步操作库,但是在.NET Framework 4.0中却无法使用.这时不免面临着抉择,到底是升级整个解决方案还是不使用呢? 如果你的软件还没发布出去 ...
- 零基础学Cocos2d-X 3.0 - 04
忙完两个项目后.最终有时间继续学习Cocos2d-X 了. 常听人说.Cocos2d-X 有四个类是最经常使用的,包含: Director 类----> 导演 Scene 类 -----> ...
- VsCode中运行nodeJs代码的简单方法
VsCode安装包默认内置的node debug插件需要配置工程调试运行文件才能正常运行,对于想要运行一个简单的js文件或者就是一段js代码时比较麻烦,为此可以安装Code Runner插件 安装完后 ...
- emacs之配置4,颜色插件
来自https://github.com/oneKelvinSmith/monokai-emacs/blob/master/monokai-theme.el monokai-theme.el ;;; ...
- 马士兵Spring-hibernate整合
spring整合hibernate: 1.sessionFactory只需要一个就可以了,单例,适合spring管理: 2.HIbernate中的SessionFactory是接口:spring中实现 ...
- C++ 函数特性_函数重载
函数重载 在相同作用域内 用同一函数名定义的多个函数: 参数个数和参数类型不同 int getMax(int x,int y,int z) // 函数名相同都是 getMax() { // to do ...
- E: Invalid operation build-depgcc(给字符界面的ubuntu安装gcc 报错
sudo apt-get build-depgccE: Invalid operation build-depgcc 原因是中间少了个空格, 使用如下命令即可. sudo apt-get buil ...
- 十一、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)远程的监控工具连接到本地的JVM执行命令
目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...
- Bootstrap-Other:UI 编辑器
ylbtech-Bootstrap-Other:UI 编辑器 1.返回顶部 1. Bootstrap UI 编辑器 以下是 15 款最好的 Bootstrap 编辑器或者是在线编辑工具. 1. Boo ...