OpenSSLは、tls双方向検証接続方法を確立します

著作権表示:この記事は、CSDNブロガー「liyakai_cn」の元の記事です。CC4.0BY-SAの著作権表示に従います。転載するには、元のソースリンクとこの文を添付してください。
元のリンク:https://blog.csdn.net/weixin_41564401/article/details/80232783

 

クライアントを再印刷して、TLSに基づいて暗号化されたチャネルを確立する方法

/*客户端代码*/

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;
}

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;
}  

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

// 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;
         }
    }

 

おすすめ

転載: blog.csdn.net/woailp___2005/article/details/107517317