gpt4 book ai didi

c++ - 用于验证 SSL_get_peer_certificate 返回的服务器证书的客户端程序?

转载 作者:行者123 更新时间:2023-11-30 01:42:09 24 4
gpt4 key购买 nike

我有一个使用 C++ 编程语言的 OpenSSL 的 SSL/TLS 客户端程序。我正在寻找方法来验证 SSL_get_peer_certificate 函数调用返回的服务器证书 (X509)。此外,我使用 SSL_CTX_load_verify_locations 函数加载了自己的 CA 证书。 CA认证了服务器证书。

我能够与我的服务器建立 SSL session 。现在,我想使用我自己的 CA 验证在 SSL 握手期间收到的服务器证书。我找不到用 C 或 C++ 执行此操作的方法。

#include <iostream>
#include <string.h>

#include <unistd.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

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


#define DEFAULT_PORT_NUMBER 443

int create_socket(char *, uint16_t port_num);

int openSSL_client_init()
{
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();

if (SSL_library_init() < 0)
return -1;
return 0;
}

int openSSL_create_client_ctx(SSL_CTX **ctx)
{
const SSL_METHOD *method = SSLv23_client_method();

if ((*ctx = SSL_CTX_new(method)) == NULL)
return -1;


//SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2);

return 0;
}

int main(int argc, char *argv[])
{
BIO *outbio = NULL;

X509 *cert;
X509_NAME *certname = NULL;

SSL_CTX *ctx;
SSL *ssl;
int server = 0;
int ret, i;

if (openSSL_client_init()) {
std :: cerr << "Could not initialize the OpenSSL library !" << std :: endl;
return -1;
}

outbio = BIO_new_fp(stdout, BIO_NOCLOSE);

if (openSSL_create_client_ctx(&ctx)) {
std :: cerr << "Unable to create a new SSL context structure." << std :: endl;
return -1;
}


std :: cout << "Adding Certifcate" << std :: endl;
if (SSL_CTX_load_verify_locations(ctx, "ca-cert.pem", NULL) <= 0) {
std :: cerr << "Unable to Load certificate" << std :: endl;
return -1;
}


ssl = SSL_new(ctx);
server = create_socket(argv[1], atoi(argv[2]));

if (server < 0) {
std :: cerr << "Error: Can't create TCP session" << std :: endl;
return -1;
}
std :: cout << "Successfully made the TCP connection to: " << argv[1] << " port: " << atoi(argv[2]) << std :: endl;

SSL_set_fd(ssl, server);

if (SSL_connect(ssl) != 1) {
std :: cerr << "Error: Could not build a SSL session to: " << argv[1] << std :: endl;
return -1;
}

std :: cout << "Successfully enabled SSL/TLS session to: " << argv[1] << std :: endl;
//SSL_SESSION *ss = SSL_get_session(ssl);

cert = SSL_get_peer_certificate(ssl);
if (cert == NULL) {
std :: cerr << "Error: Could not get a certificate from: " << argv[1] << std :: endl;
return -1;
}

certname = X509_NAME_new();
certname = X509_get_subject_name(cert);

std :: cout << "Displaying the certificate subject data:" << std :: endl;
X509_NAME_print_ex(outbio, certname, 0, 0);
std :: cout << std :: endl;


char msg[100000] = "GET / HTTP/1.1\r\nHOST: www.siliconbolt.com\r\n\r\n";
SSL_write(ssl, msg, strlen(msg));
SSL_read(ssl, msg, 100000);
std :: cout << "Message is " << msg << std :: endl;


SSL_free(ssl);
close(server);
X509_free(cert);
SSL_CTX_free(ctx);
std :: cout << "Finished SSL/TLS connection with server" << std :: endl;
return 0;
}


int create_socket(char *ip_cstr, uint16_t port_num)
{
int fd;
struct sockaddr_in dest_addr;

fd = socket(AF_INET, SOCK_STREAM, 0);

dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port_num);
dest_addr.sin_addr.s_addr = inet_addr(ip_cstr);

memset(&(dest_addr.sin_zero), '\0', 8);

if (connect(fd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) == -1)
return -1;

return fd;
}

最佳答案

正确的证书验证是一件复杂的事情,而 OpenSSL 在这方面的帮助很小。如果您希望每个步骤都有完整的代码,我会认为这个问题太宽泛了。因此,我将专注于验证所需的基本部分,并主要指出其他资源以获取特定部分的实现细节。


验证服务器证书的第一步是建立到受信任的根 CA 证书的信任链。如果您设置了受信任的根(即在代码中调用 SSL_CTX_load_verify_locations)并且还使用 SSL_CTX_set_verify 设置了验证模式,这将由 TLS 握手中的 openssl 隐式完成。到 SSL_VERIFY_PEER。此内置验证还包括检查叶证书和链证书是否已经有效且尚未过期。

下一步是验证证书的主题是否与预期的匹配。对于服务器证书,这通常意味着目标主机名以某种方式包含在证书的通用名称或主题备用名称中。实际要求取决于应用层协议(protocol),即 HTTP、SMTP、LDAP ... 都有略微不同的规则,尤其是在涉及通配符的情况下。由于 OpenSSL 1.0.2 a a X509_check_host功能可用,在大多数情况下可用于检查规则。使用早期版本的 OpenSSL,您可以自己实现这样的功能。请注意,您明确需要验证主机名,即 OpenSSL 不会为您执行此操作,省略此步骤将使中间人攻击您的应用程序变得容易。

此时您知道证书是由受信任的根 CA 直接或间接颁发的,并且证书与预期的主机名匹配。您现在需要检查证书是否被吊销。一种方法是使用您在某处获得的证书撤销列表 (CRL),另一种方法是使用在线证书状态协议(protocol) (OCSP)。

对于 CRL,请参阅 Does OpenSSL automatically handle CRLs (Certificate Revocation Lists) now?如何使用您已经下载的 CRL。但是 OpenSSL 首先不会帮助您下载 CRL。相反,您需要从叶证书中提取 CRL 分发点,自行下载 CRL,然后才能使用。

至于 OCSP,OpenSSL 提供必要的 API 来构建 OCSP 请求和验证 OCSP 响应。您仍然需要自行确定将此 OCSP 请求发送到何处。这需要通过解析叶证书并从授权信息访问字段中提取 OCSP URL 来再次完成。虽然其余部分有 API,但它不容易使用,并且至少在 OpenSSL 1.1.0 版之前大部分或完全没有记录。我不知道使用此 API 实现 OCSP 验证的好且易于理解的示例,但您可以查看 openssl ocsp 命令和 its implementation .


如果您编写了一个客户端应用程序并且只想接受一个证书,您可以省略所有针对 PKI 进行验证的复杂步骤。但只检查证书是否完全符合预期,即证书固定。参见 OWASP: Certificate and Public Key Pinning有关这方面的更多信息和示例代码。

关于c++ - 用于验证 SSL_get_peer_certificate 返回的服务器证书的客户端程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40063533/

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