SM2算法第八篇:SSL Socket通信详解

转载 2016年05月16日 13:31:09


原文地址:http://blog.csdn.net/pony_maggie/article/details/51315824

作者:小马

一、SSL原理:

比如 A要和B互相通讯,为了安全他们希望双方发送的数据都是经过加密的。这就要求双方有一个共同的加解密密钥(一般加密都是基于对称加密算法)。如何才能让双方都拥有同一个密钥呢?有人说由一方生成发给另一方不就行了。这样就带来另一个问题,如何保证这个传送的密钥是安全的呢?

SSL实现了通过非对称的RSA加解密原理实现密钥的交换。(这里就不细讲RSA的原理了,不明白的可以先补充一下这部分知识)。我们假设A是服务器端,B是客户端。然后还有一个角色,是一个可信任的第三方CA( Certificate Authority)。A首先生成一个RSA公私钥对,然后再由这个可信的第三方用自己的私钥(为了便于描述, 后面叫CA_PRIVATE_KEY)把这个DES密钥连同RSA公钥一起签发一个客户端证书(后面叫CLIENT_CERT),这个证书中同时也包含一段签名。

A会把CA证书(证书中包含CA_PRIVATE_KEY 对应的公钥, 后面叫CA_CERT)连同CLIENT_CERT一起发给客户端,当然客户端也可以由其它途径获取这两个证书(比如由专门的安全设备中导入到本地)。同时RSA私钥(后面叫CLIENT_PRIVATE_KEY)也会一起下发到客户端。

客户端首先用CA_CERT对CLIENT_CERT做验签,以确保数据确实是由A发出来的。如果验签能过,其实就已经说明B已经认证了A的身份。前面说到CLIENT_CERT包含服务器的公钥,B用这个公钥对一个对称的DES密钥加密,然后可以公开发出去,他不用担心这个密钥会被截取,因为只有A才有CLIENT_PRIVATE_KEY,也只有A才能解密出来这个DES密钥。这样就完成了对称密钥的交换。

下图表示了以上的通信流程——对称秘钥的交换




服务器(A)下发给客户端(B)的资料数据包含以下部分:

(1)客户端证书(CLIENT_CERT)——第三方私钥(CA_PRIVATE_KEY)、服务器公钥(RS公钥)和DES密钥(需要交换的对称密钥)、一段签名

(2)可信任的第三方证书(CA_CERT)——包含第三方的私钥(CA_PRIVATE_KEY) 对应的公钥

(3)服务器私钥(RSA私钥)——CLIENT_PRIVATE_KEY

大部分时候到这里,SSL通讯前的握手已经完成了,可以进行安全的数据通讯了。不过有时候会有双向认证的需求,也就是A也想认证B。这个时候CLIENT_PRIVATE_KEY就发生作用了,B会用这个私钥自己生成签名,然后发给A来认证。

这些基本就是SSL的原理了。

上面讲到的这些流程,如果用程序实现还是有点复杂的。幸运的是,开源库openssl已经帮我们做了大部分的事情(openssl的实现机制更复杂也更灵活,但基本原理跟上面是一致的)。我们只需要调用一些基本的接口就可以完成SSL socket通讯。

二、OpenSSL与Socket

基于ssl的socket通讯一般分为几个步骤。

第一步:初始化


这一步主要是初始化openssl库,创建会话上下文等,

SSL_METHOD *method = NULL;

SSL_library_init ();

SSL_load_error_strings();

OpenSSL_add_ssl_algorithms();

method = SSLv3_client_method();

g_ctx = SSL_CTX_new(method); /* Create new context */

SSLv3_client_method 是指定ssl要使用的协议。SSL协议由美国 NetScape公司开发的,V1.0版本从没有公开发表过;V2.0版本于1995年2月发布。但是,由于V2.0版本有许多安全漏洞,所以,1996年紧接着就发布了V3.0版本。微软从IE 7开始就已经把浏览器的缺省设置不支持SSL 2.0,但可能是考虑到有些网站还只支持SSL 2.0,所以IE浏览器留了一个可以由用户设置支持SSL 2.0的选项,以便能正常访问只支持SSL 2.0的网站。IE7/IE8支持SSL 3.0和TLS1.0,而IE9还支持TLS1.1和1.2。

在openssl里指定协议很简单,每个协议都有对应的函数,一行代码就可以搞定。

SSL_METHOD* TLSv1_client_method(void); TLSv1.0 协议

SSL_METHOD* SSLv2_client_method(void); SSLv2 协议

SSL_METHOD* SSLv3_client_method(void); SSLv3 协议

SSL_METHOD* SSLv23_client_method(void); SSLv2/v3 协议

SSL_CTX_new创建ssl上下文,这里面很多全局变量要被各个阶段共享。

SSL_load_error_strings(void );

如果想打印出一些方便阅读的调试信息的话,便要在一开始调用此函数.

第二步:加载证书和私钥


前面提到过,证书有CA_CERT,还有CLIENT_CERT,私钥是CLIENT_PRIVATE_KEY。也是几个接口就搞定的事情,

int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,const char *CApath);

此函数用来便是加载CA_CERT文件的.

int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);

加载客户端自己CLIENT_CERT文件.

int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);

加载自己的私钥,以用于签名.

void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);

加载私钥时一般要一个验证密码,这个密码是由生成私钥的一方来设定的,客户端得到这个密码后要通过一个接口传入验证:

void SSL_CTX_set_verify(SSL_CTX ctx,int mode,int (*callback)(int, X509_STORE_CTX ));

缺省mode是SSL_VERIFY_NONE,如果想要验证对方的话,便要将此项变成SSL_VERIFY_PEER.SSL/TLS中缺省只验证server,如果没有设置 SSL_VERIFY_PEER的话,客户端连证书都不会发过来.

第三步:建立ssl socket连接


首先要建立普通的socket连接,这个就不多说了,连接成功后返回一个socket描述符,假设名称为socket_fd。然后与ssl进行关联,三个接口就可以完成:

g_ssl = SSL_new(g_ctx);

SSL_set_fd(g_ssl, socket_fd);

SSL_connect(g_ssl);

这样后面所以的发送,接收过程都是基于g_ssl这个ssl的全局字段了。

第四步:发送和接收


收发数据就更简单了,

发送,

SSL_write(g_ssl, pData, bytes_left);

接收,

SSL_read(g_ssl, pData, bytes_left);

当然,一般我们在普通的socket收发都会加一些超时处理机制,对于ssl的收发也是一样的,后面我的示例中会给出来一个较完善的处理过程。

第五步:释放资源


如果不使用了,就要把所有占用的资源都释放掉。

当然首先要把socket关闭,

close(socket_fd);

然后是和ssl相关的资源释放

SSL_CTX_free(g_ctx);

SSL_shutdown(g_ssl);

SSL_free(g_ssl);

ERR_free_strings();

三、示例


初始化,连接等操作都很简单,这里只给出一个ssl发送函数的实现方法,带超时处理的,供大家参考。

int socket_send_ssl(const char *data,

    unsigned int data_len,int time_out)
{
    int iRet = -1;
    struct timeval tm;
    tm.tv_sec = time_out;
    tm.tv_usec = 0;

    char *pData = data;

    int bytes_left = data_len;
    int written_bytes = 0;
    if((data == NULL) || (data_len <= 0))
    {
        return -2;
    }

    iRet = setsockopt(socket_fd,SOL_SOCKET,SO_SNDTIMEO,&tm,sizeof(tm));//设置发送超时

    while(bytes_left > 0)
    {
        written_bytes = SSL_write(g_ssl, pData, bytes_left);
        if(written_bytes <= 0)
        {
            if(errno == EINTR)
            {
                written_bytes = 0;   
            }
            else
            {
                return -1;

            }

        }
        bytes_left -= written_bytes;
        pData += written_bytes;

    }
    return 0;
}












相关文章推荐

SM2算法第九篇:SSL协议详解

SSL协议详解

SSL通信中DH算法key长度问题

先做下名词解释和说明 客户端 B 服务端 S DH算法  迪菲赫尔曼算法 TLS   SSL协议的升级(建议将SSL协议升级到TLS1.0或者更高版本) 继续之前,建议一定先仔细看下SSL通信过程...

SSL原理分析

关键词:SSL,PKI,MAC 摘    要:SSL利用数据加密、身份验证和消息完整性验证机制,为基于TCP等可靠连接的应用层协议提供安全性保证。本文介绍了SSL的产生背景、安全机制、工作过程及典型...

SM2算法第二篇:“七问”SM2椭圆曲线公钥密码算法

“七问”SM2椭圆曲线公钥密码算法

SM2算法第十八篇:SM2毕设论文

咋写论文

C语言创建一个n个结点的单链表

#include #include //类型定义typedef在使用的时候如果直接按下面的方式定义,是错误的: /*typedef struct Node { int data; N...
  • Zevin
  • Zevin
  • 2011-08-02 18:49
  • 3184

SM2算法第零篇:《SM2椭圆曲线公钥密码算法》概略

毕业设计,《SM2椭圆曲线公钥密码算法》概略

FPGA第二篇:查找表结构(LUT)

这篇博客为了阐明以下原理: (1)任何组合逻辑电路均可化为”与或“表达式,用”与门-或门“二级电路实现,而任何时序电路又都是组合电路加上存储单元(触发器)构成。因此,从原理上说,与或阵列加上触发器的结...

“登陆网站”还是“登录网站”

解 青  近来,笔者经常在一些报刊、杂志或互联网上看到“登lu网站”一词使用不规范、不统一,甚至错误使用的现象。有的使用“登陆”,有的使用“登录”,为了避免以讹传讹,纠正错误用法,规范正确用法,笔者认...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)