SSL握手通信详解及linux下c/c++ SSL Socket代码举例

摘自:http://www.169it.com/article/3215130236.html

 
分享到:8
    发布时间:2013-8-13  
    本文导语:  SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。 安全证书既包含了用于加密数据的密钥,...

SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer SecurityTLS)是为网络通信提供安全及数据完整性的一种安全协议。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)如果服务器要求验证客户身份,则检查签署客户证书的CACertificate Authority,证书机构)是否可信。如果不在信任列表中,结束本次会话。如果检查通过,服务器用自己的私钥解密收到的预备主密码(pre-master secret),并用它通过某些算法生成本次会话的主密码(master secret)。

(7)客户端与服务器端均使用此主密码(master secret)生成此次会话的会话密钥(对称密钥)。在双方SSL握手结束后传递任何消息均使用此会话密钥。这样做的主要原因是对称加密比非对称加密的运算量要低一个数量级以上,能够显著提高双方会话时的运算速度

(8)客户端通知服务器此后发送的消息都使用这个会话密钥进行加密,并通知服务器客户端已经完成本次SSL握手。

(9)服务器通知客户端此后发送的消息都使用这个会话密钥进行加密,并通知客户端服务器已经完成本次SSL握手。

(10)本次握手过程结束,SSL会话已经建立。在接下来的会话过程中,双方使用同一个会话密钥分别对发送和接收的信息进行加密和解密。

以下为 linux c/c++ ssl socket clientserver的代码参考。

客户端代码如下:

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代码举例的更多相关文章

  1. SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码)

    SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码) 摘自: https://blog.csdn.net/sjin_1314/article/det ...

  2. 转:SSL 握手协议详解

    SSL 握手协议详解 RSA作为身份认证,ECDHE来交换加密密钥,AES/DES等作为加密. 如果RSA来加解密,那么身份认证后,直接用认证后的RSA公钥解密.不需要再额外交换加密密钥了. 相关报文 ...

  3. SSL 握手协议详解

    这里重点介绍一下服务端的验证和密钥交换.这个阶段的前面的(a)证书 和(b)服务器密钥交换是基于密钥交换方法的.而在SSL中密钥交换算法有6种:无效(没有密钥交换).RSA.匿名Diffie-Hell ...

  4. 【图文详解】linux下配置远程免密登录

    linux下各种集群搭建往往需要配置远程免密登录,本文主要描述了CentOs6.3系统下配置免密登录的详细过程. ssh远程登录,两种身份验证: 用户名+密码 密钥验证 机器1生成密钥对并将公钥发给机 ...

  5. 详解在Linux下实现(彩色)进度条程序,并通过makefile进行编译.

    彩色进度条的实现与makefile编译: 创建一个process文件,在里面编写实现进度条的代码    1.在编写代码的时候我们首先要区分两个转义字符:\n \r \n:表示换行,换到下一行,并位于起 ...

  6. 详解hdparm: linux下的硬盘测速工具

    hdparm的功能:显示与设定硬盘的参数.hdparm可检测,显示与设定IDE或SCSI硬盘的参数. 语法: hdparm [-CfghiIqtTvyYZ][-a <快取分区>][-A & ...

  7. SSL/TLS协议详解(下)——TLS握手协议

    本文转载自SSL/TLS协议详解(下)--TLS握手协议 导语 在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容 ...

  8. 开源项目SMSS发开指南(五)——SSL/TLS加密通信详解(下)

    继上一篇介绍如何在多种语言之间使用SSL加密通信,今天我们关注Java端的证书创建以及支持SSL的NioSocket服务端开发.完整源码 一.创建keystore文件 网上大多数是通过jdk命令创建秘 ...

  9. SSL/TLS 握手过程详解

    在现代社会,互联网已经渗透到人们日常生活的方方面面,娱乐.经济.社会关系等都离不开互联网的帮助.在这个背景下,互联网安全就显得十分重要,没有提供足够的安全保障,人们是不会如此依赖它的.幸运的是,在大牛 ...

随机推荐

  1. MySQL 练习题4

    1.表结构如下: #课程表 CREATE TABLE `course` ( `c_id` ) NOT NULL, `c_name` ) DEFAULT NULL, `t_id` ) DEFAULT N ...

  2. LeetCode OJ - Best Time to Buy and Sell Stock

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/xiezhihua120/article/details/32939749 Say you have ...

  3. N​Unit的Attribute​使​用​详​解

    NUNIT使用详解(一) 2008/08/26 11:40 NUnit是一个单元测试框架,专门针对于.NET来写的,它是是xUnit的一员.NUnit完全由C#语言来编写,并且编写时充分利用了许多.N ...

  4. SIM800/SIM900/SIM7000/SIM7600底层操作接口_句柄方式完全分离通信底层

    使用SIMCOM公司通信模块将底层的通信与应用完全进行了分离,便于移植. SIMCOM.h //定义了相关的结构体与类型. SIMCOM_AT.c//定义了底层的AT接口 SIMCOM_GSM.c// ...

  5. 远程连接Linux虚拟机上的mysql失败的解决方法

    今天在虚拟机Ubuntu上折腾了一晚上mysql,然后试着用java连接,搞了很久都没成功,但是同学配好的Debian上却连接成功了,也就是说我的配置有问题. 折腾了很久,最后还是通过理解异常信息来大 ...

  6. WindowsServer2012显示计算机的方法

    WindowsServer2012显示计算机的方法 (转) 消失的"计算机"?[这周九叔工作比较忙,还有其他琐事缠身,因此SystemCenter2012SP1系列的发布稍慢,抱歉 ...

  7. linux上安装Qt4.8.6+QtCreator4.0.3

    一.Qt简介 Qt是1991年奇趣科技开发的一个跨平台的C++图形用户界面应用程序框架.它提供给应用程序开发者建立艺术级的图形用户界面所需的所有功能.Qt很容易扩展,并且允许真正地组件编程. 准备工作 ...

  8. bzoj1811 mea

    Description 考虑一个非递减的整数序列 S1,....Sn+1(Si<=Si+1  1<=i<=n). 序列M1...Mn是定义在序列S的基础上,关系式为 Mi=( Si ...

  9. 关系型数据库与Key-value型数据库Mongodb模式设计对比

    MongoDb 相比于传统的 SQL 关系型数据库,最大的不同在于它们的模式设计( Schema Design )上的差别,正是由于这一层次的差别衍生出其它各方面的不同. 我们可以简单的认为关系型数据 ...

  10. Mongodb第一步资料

    学习的时候收集了部分好文章,这个文章主要收集的是下载,安装的基本资料 官方http://docs.mongodb.org/manual/tutorial/install-mongodb-on-wind ...