基于openssl建立tls双向验证连接方法

1. 概述

本文介绍了如何基于openssl库建立tls加密通道连接。

2. 步骤
X509        *cert   = NULL;  // 客户端公钥证书指针
EVP_PKEY    *key    = NULL;  // 客户端私钥证书指针
const SSL_METHOD *meth = NULL;
g_bio_err = dup_bio_err(FORMAT_TEXT);
SSL *con = NULL;
struct sockaddr_in serv_addr;
int sockfd  = 0;
// 准备数据
// 选择客户端方法
meth = TLS_client_method();
// 初始化tls上下文
ssl_ctx = SSL_CTX_new(meth);
if (ssl_ctx == NULL) {
    LOG(ERROR,"ca_client_connect -->> create ssl_ctx failed");
    ERR_print_errors(g_bio_err);
    SSL_CTX_free(ssl_ctx);
    return -1;
}

//  加载公钥证书(用以服务端校验)
cert = load_cert("certfile.pem");
if (cert == NULL) {
    LOG(ERROR, "load_cert() failed");
    return -1;
}

// 加载私钥证书
key = load_key("keyfile.pem");
if (key == NULL) {
    LOG(ERROR, "load_key() failed");
    return -1;
}

// 将公钥证书应用到上下文
if (SSL_CTX_use_certificate(ssl_ctx, cert) <= 0) {
    LOG(ERROR, "ca_client_connect -->>SSL_CTX_use_certificate() failed");
    SSL_CTX_free(ssl_ctx);
    return -1;
}

// 将私钥应用到上下文
if (SSL_CTX_use_PrivateKey(ssl_ctx, key) <= 0) {
    LOG(ERROR, "ca_client_connect -->>SSL_CTX_use_PrivateKey() failed");
    SSL_CTX_free(ssl_ctx);
    return -1;
}

// 检验公私钥是否匹配
if (!SSL_CTX_check_private_key(ssl_ctx)) {
    LOG(ERROR, "ca_client_connect -->>SSL_CTX_use_PrivateKey() failed");
    SSL_CTX_free(ssl_ctx);
    return -1;
}

// 加载客户端ca证书 (用以校验服务端)
if (!SSL_CTX_load_verify_locations(ssl_ctx, "cafile.pem", 0))
{
    LOG(ERROR, "ca_client_connect -->>SSL_CTX_load_verify_locations() failed || ctx->cafile: %s",ctx->cafile);
    SSL_CTX_free(ssl_ctx);
    return -1;
}
// 建立连接
//建立socket连接
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
    SSL_CTX_free(ssl_ctx);
    return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(ctx->host);
serv_addr.sin_port = htons(atoi(ctx->port));
ret = connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (ret < 0) {
    LOG(ERROR,  "connect() failed\n");
    ERR_print_errors(g_bio_err);
    SSL_CTX_free(ssl_ctx);
    return -1;
}
// 建立tls连接
sslConn = SSL_new(ssl_ctx);
if(sslConn == NULL)
{
    SSL_CTX_free(ssl_ctx);
    return -1;
}
sbio = BIO_new_socket(sockfd, BIO_NOCLOSE);
// 设置读写io都为sslConn
SSL_set_bio(sslConn, sbio, sbio);
// 设置连接状态
SSL_set_connect_state(sslConn);
//握手
ret = SSL_do_handshake(sslConn);
if (ret != 1) {
    LOG(ERROR,  "SSL_do_handshake failed");
    ERR_print_errors(g_bio_err);
    SSL_free(sslConn);
    SSL_CTX_free(ssl_ctx);
    return -1;
}   

上述tls加密通道连接建立后得到sslConn句柄以进行读写通信。发送消息时用

// conn = sslConn, data为发送消息指针,inl为发送消息的长度
ret = SSL_write(conn, data, inl);

进行发送消息。接收消息时用SSL_read进行读取消息,如下:

// data为输出数据的指针,outl为输出数据的长度
for (;;) {
         // len = BIO_read(conn, (char *)data + offset, maxlen);
          len = SSL_read(conn, (char *)data + offset, maxlen);
         if (len <= 0) {
             // read complete
             break;
         }
         else if (len == maxlen) {
             // buffer is not enough
             return 0;
         }
         else {
            *outl += len;
            offset += len;
            maxlen -= len;
         }
    }

小结

以上即为作为客户端如何基于tls建立加密通道。

展开阅读全文

没有更多推荐了,返回首页