gpt4 book ai didi

c - 如何使用 openssl 在 C 代码中进行相互 tls 身份验证?

转载 作者:太空宇宙 更新时间:2023-11-03 23:38:02 26 4
gpt4 key购买 nike

我将尝试使用 openssl 进行双向身份验证的 TLS。

但是如下图输出结果,客户端可以收到服务器证书并输出,但是服务器没有收到客户端证书。

我的工作详情如下。

  1. 服务器和客户端证书生成(无需通过 CA 进行证书签名,只需自签名)

(1) 生成服务器 key 和证书。

$ openssl genrsa -des3 -out server.key 2048

$ openssl req -new -key server.key -out server.csr

$ cp server.key server.key.origin

$ openssl rsa -in server.key.origin -out server.key

$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

(2) 生成客户端 key 和证书。$ openssl genrsa -des3 -out client.key 2048

$ openssl req -new -key client.key -out client.csr

$ cp client.key client.key.origin

$ openssl rsa -in client.key.origin -out client.key

$ openssl x509 -req -days 365 -in client.csr -signkey client.key -out client.crt

//服务器.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/rsa.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define HOME "./"
#define CERTF HOME "server.crt"
#define KEYF HOME "server.key"

#define CHK_NULL(x) if((x) == NULL) exit(1);
#define CHK_ERR(err, s) if((err) == -1) { perror(s); exit(1); }
#define CHK_SSL(err) if((err) == -1) { ERR_print_errors_fp(stderr); exit(2); }

int main(void) {
int err;
int listen_sd;
int sd;
struct sockaddr_in sa_serv;
struct sockaddr_in sa_cli;
size_t client_len;

SSL_CTX *ctx;
SSL *ssl;
X509 *client_cert;
char *str;
char buf[4096];
SSL_METHOD *meth;

SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
meth = TLSv1_2_server_method();
ctx = SSL_CTX_new(meth);

if(!ctx) {
ERR_print_errors_fp(stderr);
exit(2);
}

if(SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(3);
}

if(SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(4);
}

if(!SSL_CTX_check_private_key(ctx)) {
fprintf(stderr, "Private key does not match the certificate public keyn");
exit(5);
}

listen_sd = socket(AF_INET, SOCK_STREAM, 0);
CHK_ERR(listen_sd, "socket");

memset(&sa_serv, 0x00, sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons(1111);

err = bind(listen_sd, (struct sockaddr*)&sa_serv, sizeof(sa_serv));
CHK_ERR(err, "bind");

err = listen(listen_sd, 5);
CHK_ERR(err, "listen");

client_len = sizeof(sa_cli);
sd = accept(listen_sd, (struct sockaddr*)&sa_cli, &client_len);
CHK_ERR(sd, "accept");
close(listen_sd);

ssl = SSL_new(ctx);
CHK_NULL(ssl);
SSL_set_fd(ssl, sd);

// to request client's certificate
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

err = SSL_accept(ssl);
CHK_SSL(err);

printf("SSL connection using %s \n", SSL_get_cipher(ssl));

client_cert = SSL_get_peer_certificate(ssl);

if(client_cert != NULL) {
printf("Client certificate: \n");

str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
CHK_NULL(str);
printf("\t subject: %s\n", str);
OPENSSL_free(str);

str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
CHK_NULL(str);
printf("\t issuer: %s\n", str);
OPENSSL_free(str);

X509_free(client_cert);
} else {
printf("Client does not have certificate. \n");
}

err = SSL_read(ssl, buf, sizeof(buf)-1);
CHK_SSL(err);
buf[err] = 0x00;
printf("Got %d chars: %s \n", err, buf);

err = SSL_write(ssl, "I hear you/", strlen("I hear you."));
CHK_SSL(err);

close(sd);
SSL_free(ssl);
SSL_CTX_free(ctx);

return(0);
}

//客户端.c

#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define CHK_NULL(x) if((x) == NULL) exit(1);
#define CHK_ERR(err, s) if((err) == -1) { perror(s); exit(1); }
#define CHK_SSL(err) if((err) == -1) { ERR_print_errors_fp(stderr); exit(2); }

int main(void) {
int err;
int sd;
struct sockaddr_in sa;

SSL_CTX *ctx;
SSL *ssl;
X509 *server_cert;
char *str;
char buf[4096];
SSL_METHOD *meth;

SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
meth = TLSv1_2_client_method();
ctx = SSL_CTX_new(meth);
CHK_NULL(ctx);

if(SSL_CTX_use_certificate_file(ctx, "./client.crt", SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(3);
}

if(SSL_CTX_use_PrivateKey_file(ctx, "./client.key", SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(4);
}

if(!SSL_CTX_check_private_key(ctx)) {
fprintf(stderr, "Private key does not match the certificate public keyn");
exit(5);
}

CHK_SSL(err);

sd = socket(AF_INET, SOCK_STREAM, 0);
CHK_ERR(sd, "socket");

memset(&sa, 0x00, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
sa.sin_port = htons(1111);

err = connect(sd, (struct sockaddr*)&sa, sizeof(sa));
CHK_ERR(err, "connect");

ssl = SSL_new(ctx);
CHK_NULL(ssl);

SSL_set_fd(ssl, sd);
err = SSL_connect(ssl);
CHK_NULL(err);

printf("SSL connection using %s \n", SSL_get_cipher(ssl));

server_cert = SSL_get_peer_certificate(ssl);
CHK_NULL(server_cert);
printf("Server certificate: \n");

str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
CHK_NULL(str);
printf("\t subject: %s \n", str);
OPENSSL_free(str);

str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
CHK_NULL(str);
printf("\t issuer: %s \n", str);
OPENSSL_free(str);

X509_free(server_cert);

err = SSL_write(ssl, "Hello World!", strlen("Hello World!"));
CHK_SSL(err);

err = SSL_read(ssl, buf, sizeof(buf)-1);
CHK_SSL(err);
buf[err] = 0x0;
printf("Got %d chars: %s \n", err, buf);
SSL_shutdown(ssl);

close(sd);
SSL_free(ssl);
SSL_CTX_free(ctx);

return 0;
}

下面是输出结果。

(1) 服务器

$./服务器

使用 ECDHE-RSA-AES256-GCM-SHA384 的 SSL 连接

客户端没有证书。

得到 12 个字符:Hello World!

(2) 客户端

$./客户

使用 ECDHE-RSA-AES256-GCM-SHA384 的 SSL 连接

服务器证书:

主题:/C=IN/ST=WB/L=Kolkata/O=TEST-INFO-CLIENTA/OU=IT/CN=clienta.com/emailAddress=aaa@aaa.com

发行人:/C=IN/ST=WB/L=Kolkata/O=TEST-INFO-CLIENTA/OU=IT/CN=clienta.com/emailAddress=aaa@aaa.com

得到 11 个字符:我听到你了/

============================================= ========

我不知道为什么服务器的输出说“客户端没有证书”。

虽然我在server.c中添加了“SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL)”,但是服务器没有收到客户端的证书。

如果有人知道这件事,请回复。

最佳答案

如何避免证书验证失败错误?

If you are creating a 'rootCA' and then issuing the Server Certificate and Client Certificate using the same 'rootCA', you need to ensure that the 'rootCA' certificate file is added as CA to OpenSSL through the API SSL_CTX_load_verify_locations. Even if only self signed certificates are used, then we need to still add them using the API SSL_CTX_load_verify_locations. This operation must be done before SSL_new.

有没有办法将证书的验证与客户端分开?现在代码是 SSL_accept (ssl);似乎证书验证是在函数中完成的。也就是说,我要的是服务端收到客户端证书后,先打印出证书信息,然后进行验证。

To have some control over the validation of the certificate received from client, you can set the certificate verification callback. You will get the certificate received from client in this callback, which you print for debugging purposes and then continue with the validation. Please refer to the API SSL_CTX_set_verify. Though you seem to be setting it, you are passing for NULL for callback. If you pass a valid callback function as argument, you will receive the certificate in your callback.

关于c - 如何使用 openssl 在 C 代码中进行相互 tls 身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53952695/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com