基于openssl实现tls+socket的安全通信-2

接基于openssl实现tls+socket的安全通信-1,这篇主要是讲解生成秘钥、证书,并且是使用socket apiopenssl api来实现基于tls的安全通信。由于证书链并没有新东西,该篇主要还是以单证书为例,后续可以再整一个基于证书链的通信。

时隔一年,来补第二篇了。

一、SSL/TLS建立连接的过程

上一篇文章简单的说明下tls的过程,接下来分别从理论上、秘钥证书生成以及代码的角度分析建立连接的过程。下图既是单边TLS校验的全过程(server校验client)。

 

在建立好tcp连接之后,client首先会发送client hello,如下图所示,client hello主要包括随机字字符串;session id用于识别对话(有局限性,所以后面又有session ticket);Extension里面也是包含很多东西的,比如有支持的版本有哪些,椭圆曲线参数,session ticket等,针对不同的场景包含的内容也不同,大多时候我们是不怎么关心,需要的时候可以具体再查看一下;一些密码信息,比如支持哪些加密算法(cipher suites);还有就是client端的公钥,在key_share字段里面。这篇文章,对tls握手阶段的字段解释蛮清楚的:tls hello解析。不过这篇文章对ack的解释是错误的,跟加密无关,对端回ack既是证明对端收到这个报文,这是tcp的特性。

client hello之后,sever也会发server hello,server hello总结下来既是对client发过的一些信息进行确认(协商)。如下图,上个过程中,client把自己的公钥给了server,接下来server也会把自己的公钥给到client,同样是在key_share上面,并且选择跟client一样的椭圆曲线算法参数;server 也会从client cipher suite中选择一个client支持的加密算法,比如下面server选择的事TLS_AES_256_GCM_SHA384.

在client端收到server hello后,会根据两个公钥计算出用于对称加密的秘钥,并通过change cipher spec的报文通知到server,如下图所示,至此后续通信即可使用对称秘钥进行加密通信了。

所以总结下来,tls 握手过程是协商一些关键信息,比如版本、加密算法、椭圆算法的参数等,同时利用非对称加密使双方拿到对称加密的秘钥。这就避免了其前面文章,基于openssl实现tls+socket的安全通信-1,对称秘钥被其他窃取的可能,而不使用非对称的秘钥原因是因为对称秘钥加解密的效率更加高效,因为对称秘钥本身是加密传输的,所以也基本不可能被窃取。非对称加密和对称加密组合使用,既保证了安全性也保证了效率。

1. 证书和秘钥生成

证书是由秘钥生成的。openssl的介绍和使用通过这篇文章的介绍,我们可以生成最简单的秘钥和证书。如果想要使用更多参数,一定要多使用--help。格式如:openssl req --help, openssl genrsa --help,而不是openssl --help

秘钥生成:openssl genrsa -out test.key 2048

证书生成:openssl req -new -x509 -key test.key -out test.dvc -days 1095

可以生成一个秘钥test.key和证书test.dvc

2. tls socket编程

代码在:我的git仓库--tls_test

TLS server代码本身没有什么很大难度,但是我们可以借助代码进一步的理解握手和整个通信本身。

//tls_server.c

#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define MAXBUF 1024

int main(int argc, char **argv) {
    int sockfd, new_fd;
    socklen_t len;
    struct sockaddr_in server_addr, client_addr;
    char buf[MAXBUF + 1];
    SSL_CTX *ctx = NULL;

    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    ctx = SSL_CTX_new(SSLv23_server_method());
    if (ctx == NULL) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    printf("certificate file: '%s'.\n", argv[1]);
    if (SSL_CTX_use_certificate_file(ctx, argv[1], SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    printf("privatekey file: '%s'.\n", argv[1]);
    if (SSL_CTX_use_PrivateKey_file(ctx, argv[2], SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    if (!SSL_CTX_check_private_key(ctx)) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    } else
        printf("socket created\n");

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = PF_INET;
    server_addr.sin_port = htons(7838);
    if (argv[3])
        server_addr.sin_addr.s_addr = inet_addr(argv[3]);
    else
        server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        exit(1);
    } else
        printf("binded\n");

    if (listen(sockfd, 3) == -1) {
        perror("listen");
        exit(1);
    } else
        printf("begin listen\n");

    while (1) {
        SSL *ssl;
        len = sizeof(struct sockaddr);

        if ((new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &len)) == -1) {
            perror("accept");
            exit(errno);
        } else
            printf("server: got connection from '%s', port %d, socket %d\n", inet_ntoa(client_addr.sin_addr),
                   ntohs(client_addr.sin_port), new_fd);

        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, new_fd);
        if (SSL_accept(ssl) == -1) {
            perror("accept");
            close(new_fd);
            break;
        }

        bzero(buf, MAXBUF + 1);
        strcpy(buf, "server->client");
        len = SSL_write(ssl, buf, strlen(buf));

        if (len <= 0) {
            printf("send '%s' failed, errno: %d, error infomation: '%s' \n", buf, errno, strerror(errno));
            goto finish;
        } else{
            printf("send %d bytes '%s' successfuly.\n", len, buf);
        }

        bzero(buf, MAXBUF + 1);
        len = SSL_read(ssl, buf, MAXBUF);
        if (len > 0)
            printf("recv %d bytes with '%s'.", len, buf);
        else
            printf("recvive error. errno: %d, error infomation:'%s'.\n", errno, strerror(errno));

    finish:
        SSL_shutdown(ssl);
        SSL_free(ssl);
        close(new_fd);
    }
    close(sockfd);
    SSL_CTX_free(ctx);
    return 0;
}

TLS client

// tls_client.c
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define MAXBUF 1024

void ShowCerts(SSL *ssl) {
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    if (cert != NULL) {
        printf("certificate info:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("subject: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("issuer: %s\n", line);
        free(line);
        X509_free(cert);
    } else{
        printf("no certificate infomation.\n");
    }
}

int main(int argc, char **argv) {
    int sockfd, len;
    struct sockaddr_in dest;
    char buffer[MAXBUF + 1];
    SSL_CTX *ctx;
    SSL *ssl;

    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    ctx = SSL_CTX_new(SSLv23_client_method());
    if (ctx == NULL) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket");
        exit(errno);
    }
    printf("socket created\n");

    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(atoi(argv[2]));
    if (inet_aton(argv[1], (struct in_addr *)&dest.sin_addr.s_addr) == 0) {
        perror(argv[1]);
        exit(errno);
    }
    printf("address created\n");
    if (connect(sockfd, (struct sockaddr *)&dest, sizeof(dest)) != 0) {
        perror("Connect ");
        exit(errno);
    }
    printf("server connected\n");

    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);
    //implement handshake
    if (SSL_connect(ssl) == -1)
        ERR_print_errors_fp(stderr);
    else {
        printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
        ShowCerts(ssl);
    }

    bzero(buffer, MAXBUF + 1);
    len = SSL_read(ssl, buffer, MAXBUF);
    if (len > 0){
        printf("recv %d bytes with '%s'.\n", len, buffer);
    } else{
        printf("recvive error. errno: %d, error infomation:%s.\n", errno, strerror(errno));
        goto finish;
    }

    bzero(buffer, MAXBUF + 1);
    strcpy(buffer, "from client->server");

    len = SSL_write(ssl, buffer, strlen(buffer));
    if (len <= 0) {
        printf("send '%s' failed, errno: %d, error infomation: '%s'.\n", buffer, errno, strerror(errno));
        goto finish;
    } else{
        printf("send %d bytes '%s' successfuly.\n", len, buffer);
    }

finish:
    SSL_shutdown(ssl);
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
    return 0;
}

 

to write again!!!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇