基于openssl建立tls双向验证连接方法
程序员文章站
2022-07-12 21:54:42
...
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建立加密通道。
下一篇: 使用Openssl验证证书链(转)