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 握手过程详解
在现代社会,互联网已经渗透到人们日常生活的方方面面,娱乐.经济.社会关系等都离不开互联网的帮助.在这个背景下,互联网安全就显得十分重要,没有提供足够的安全保障,人们是不会如此依赖它的.幸运的是,在大牛 ...
随机推荐
- org.springframework.orm.hibernate3.HibernateTemplate
当session中出现两个相同标示的(相同主键)的对象,一个是持久态,一个是瞬时态,想更新瞬时态对象到数据库,如果不做处理,则报出异常,session中出现两个相同标示的不同对象异常.处理方法.(业务 ...
- centos 7 安装rabbitmq 3.6.12
0 安装 epel yum -y install http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-7-11. ...
- 使用纯生js实现图片轮换
效果图预览. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...
- Python VIL Service Bin
#!/usr/bin/python #coding:UTF-8 import sys import re import getopt import md5 import os import subpr ...
- vim之vundle
git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle,下载到本地 gvim ~/.vimrc set nocompat ...
- java 面向对象 — 继承
继承中的构造方法,先执行父类中的构造方法,然后执行子类中的构造方法 继承中的属性,最后执行的属性 覆盖前面的属性 因为是开辟了 两个内存空间,所以相比较是不同的. 如果想比较两个对象的值是否相同的话, ...
- JAVA面向对象编程课程设计——web版斗地主
一.团队课程设计博客链接 JAVA面向对象编程课程设计--网络版单机斗地主 二.个人负责模块或任务说明 实体类的设计 斗地主规则的实现 人机自动出牌的算法 实现数据库的DAO模式 三.自己的代码提交记 ...
- bzoj4466 超立方体
Description 超立方体是立方体在高维空间内的拓展(其在 2 维情况下退化为正方形,1维情况下退化成线段).在理论计算机科学领域里,超立方体往往可以和 2 进制编码联系到一起.对理论计算机科学 ...
- 解决phpexcel保存时文件命中文出现 乱码 (这个真的有用)
Phpexcel导出Excel文件时有两个主要的过程: 1.定义文件名 2.填充Excel数据 这两个过程中可能会出现一些乱码问题,下面我来说一下解决办法: 解决文件名的乱码: 乱码原因:客户使用的中 ...
- babun编译安装git(2.12.0)遇到的问题及解决办法
1. 下载git wget https://www.kernel.org/pub/software/scm/git/git-2.12.0.tar.xz 你或许需要加上选项: --no-check-ce ...