我在C中创建了一个TLS客户端。我的目标是与pop3服务器建立TLS连接。我在Windows上使用OpenSSL API。 为了验证服务器证书。我加载" ROOT"带有Wincrypt API的Windows证书存储中的CA证书。 我使用以下函数加载证书:
wincrypt: CertOpenSystemStore(), CertEnumCertificatesInStore()
Openssl: d2i_X509(), X509_STORE_add_cert()
调用SSL_get_verify_result()时,我的验证回调出现了证书验证错误,请参阅以下输出。
[-] verify error:num=20:unable to get local issuer certificate:depth=1:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign Organization Validation CA - G2
[-] verify error:num=27:certificate not trusted:depth=1:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign Organization Validation CA - G2
[+] depth=0:/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=*.hotmail.com
...
[-] Server certificates X509 is not trust...
我不理解错误输出。
你能帮助我吗?
我可能做错了什么但我不知道是什么!!!
提前感谢您的帮助!!!!! ;)
我发布了客户端HERE的所有代码(它尝试与Microsoft pop3服务器建立TLS连接)。
使用CL.exe编译得很好:
//////////////////////////////////////////////////////////////////////////////////////////////////
// author: rasta
// programme: client TLS with certificate verification
// stack owerflow: API: Openssl / Wincrypt : unable to get local issuer certificate / certificate not trusted
//
//Compilation of the client:
//
//Ajust your own environnement variable:
// set LIB_PATH=C:\your\library\path\to\openssl
// set INCLUDE_PATH=C:\your\include\path\to\openssl
//
//command line compilaton:
// cl.exe /MD sample_ssl.c /I"%INCLUDE_PATH%" /Dinline= /link /libpath:"%LIB_PATH%" libeay32.lib ssleay32.lib Crypt32.lib Ws2_32.lib
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <wincrypt.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>
typedef struct
{
int verbose_mode;
int verify_depth;
int always_continue;
} mydata_t;
int mydata_index;
int openssl_init(void)
{
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;
}
//
// This function load the certificate from the windows certicate store
// modification of a part of the original source from:
// http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/external/bsd/wpa/dist/src/crypto/tls_openssl.c
//
int cryptoapi_ca_cert(SSL_CTX *ssl_ctx, const char *store_name)
{
HCERTSTORE cs;
PCCERT_CONTEXT ctx = NULL;
X509 *cert;
char buf[128];
ssl_ctx->cert_store = X509_STORE_new();
cs = CertOpenSystemStore(0, store_name);
if (cs == NULL)
{
printf("[-] CryptoAPI: failed to open system cert store '%s': error=%d\n", store_name,(int) GetLastError());
return -1;
}
while((ctx = CertEnumCertificatesInStore(cs, ctx)))
{
cert = d2i_X509(NULL, &ctx->pbCertEncoded,ctx->cbCertEncoded);
if (cert == NULL)
{
printf("[-] CryptoAPI: Could not process X509 DER encoding for CA cert\n");
continue;
}
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
printf("[+] OpenSSL: Loaded CA certificate for system certificate store:\n subject='%s'\n\n", buf);
if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert))
printf("[-] Failed to add ca_cert to OpenSSL certificate store");
X509_free(cert);
}
if (!CertCloseStore(cs, 0))
printf("[-] failed to close system cert store '%s': error=%d", store_name,(int) GetLastError());
return 0;
}
//
// The certificate verification callback
// example from openssl documentation:
// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
//
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
char buf[256];
X509 *err_cert;
int err, depth;
SSL *ssl;
mydata_t *mydata;
err_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
/*
* Retrieve the pointer to the SSL of the connection currently treated
* and the application specific data stored into the SSL object.
*/
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
mydata = SSL_get_ex_data(ssl, mydata_index);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
/*
* Catch a too long certificate chain. The depth limit set using
* SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
* that whenever the "depth>verify_depth" condition is met, we
* have violated the limit and want to log this error condition.
* We must do it here, because the CHAIN_TOO_LONG error would not
* be found explicitly; only errors introduced by cutting off the
* additional certificates would be logged.
*/
if(depth > mydata->verify_depth)
{
preverify_ok = 0;
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
X509_STORE_CTX_set_error(ctx, err);
}
if(!preverify_ok)
{
printf("[-] verify error:num=%d:%s:depth=%d:%s\n", err,
X509_verify_cert_error_string(err), depth, buf);
}
else if (mydata->verbose_mode)
{
printf("[+] depth=%d:%s\n", depth, buf);
}
/*
* At this point, err contains the last verification error. We can use
* it for something special
*/
if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
{
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
printf("[-] issuer= %s\n", buf);
}
if (mydata->always_continue)
{
return 1;
}
else
{
return preverify_ok;
}
}
int connect_socket(const char url[], const short port)
{
WSADATA wsa;
char hostname[256]={0};
struct hostent *host;
struct sockaddr_in dest_addr;
int sockfd;
if(WSAStartup(MAKEWORD(2,2), &wsa))
return -1;
strncpy(hostname, strstr(url, "://")+3, sizeof(hostname));
if((host = gethostbyname(hostname)) == NULL)
return -1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons(port);
dest_addr.sin_addr.s_addr = *(long*)(host->h_addr);
memset(&(dest_addr.sin_zero), '\0', 8);
if(connect(sockfd, (struct sockaddr *) &dest_addr, sizeof(struct sockaddr)) != 0)
return -1;
return sockfd;
}
int main(void)
{
BIO *outbio = NULL;
BIO *certbio = NULL;
const SSL_METHOD *method;
SSL_CTX *ctx;
X509_STORE *root_certs= NULL;
SSL *ssl=NULL;
int sockfd;
char url[] = "pop3s://pop3.live.com\0";
short port = 995;
X509 *server_cert = NULL;
X509_NAME *server_certname = NULL;
mydata_t mydata;
certbio = BIO_new(BIO_s_file());
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
// OpenSSL initialisation
if(openssl_init() != 0)
exit(0);
// TLS context initialisation
method = TLSv1_client_method();
if((ctx = SSL_CTX_new(method)) == NULL)
exit(0);
// load the Windows CA certificates
if(cryptoapi_ca_cert(ctx, "ROOT") == 0)
printf("\n[+] CA certificates loaded\n");
else
printf("\n[-] CA certificates not loaded\n");
// create a new SSL structure
// and set the certificat verification callback
mydata_index = SSL_get_ex_new_index(0, "mydata index", NULL, NULL, NULL);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback);
ssl = SSL_new(ctx);
SSL_set_ex_data(ssl, mydata_index, &mydata);
// Connection to the server
if((sockfd = connect_socket(url, port)) == -1)
{
printf("[-] Failed to connecte at %s\n", url);
exit(0);
}
else
printf("[+] Connected at %s\n", url);
// attach the socket at lib openSSL
SSL_set_fd(ssl, sockfd);
// establish the SSL layer
if( SSL_connect(ssl) != 1)
{
printf("[-] Failed to establish ssl layer\n");
exit(0);
}
else
printf("[+] ssl layer established\n");
// get the server certificate
if((server_cert = SSL_get_peer_certificate(ssl)) == NULL)
printf("[-] Error: Could not get a certificate from: %s.\n", url);
else
printf("[+] Retrieved the server's certificate from: %s.\n", url);
// verify the validity of the SSL server certificate
if(SSL_get_verify_result(ssl) == X509_V_OK)
printf("[+] Server certificates X509 is trust!\n\n");
else
printf("[-] Server certificates X509 is not trust...\n\n");
// print server certificate informations
server_certname = X509_NAME_new();
server_certname = X509_get_subject_name(server_cert);
printf("the certificate subject data:\n\n");
X509_NAME_print_ex(outbio, server_certname, 0, 0);
printf("\n");
// close the connexion
SSL_free(ssl);
closesocket(sockfd);
X509_free(server_cert);
SSL_CTX_free(ctx);
return 0;
}
客户的输出:
C:\Users\bts\Desktop\home\projet_test_openssl>sample_ssl.exe
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/DC=com/DC=microsoft/CN=Microsoft Root Certificate Authority'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=ZA/ST=Western Cape/L=Durbanville/O=Thawte/OU=Thawte Certification/CN=Thawte Timestamping CA'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/OU=Copyright (c) 1997 Microsoft Corp./OU=Microsoft Corporation/CN=Microsoft Root Authority'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=MSFT/CN=Microsoft Authenticode(tm) Root Authority'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/O=Microsoft Trust Network/OU=Microsoft Corporation/OU=Microsoft Time Stamping Service Root'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/O=VeriSign Trust Network/OU=VeriSign, Inc./OU=VeriSign Time Stamping Service Root'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Object'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=Equifax/OU=Equifax Secure Certificate Authority'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Root Certificate Authority 2011'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/L=Internet/O=VeriSign, Inc./OU=VeriSign Commercial Software Publishers CA'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA'
[+] OpenSSL: Loaded CA certificate for system certificate store:
subject='/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root'
[+] CA certificates loaded
[+] Connected at pop3s://pop3.live.com
[-] verify error:num=20:unable to get local issuer certificate:depth=1:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign Organization Validation CA - G2
[-] verify error:num=27:certificate not trusted:depth=1:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign Organization Validation CA - G2
[+] depth=0:/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=*.hotmail.com
[+] ssl layer established
[+] Retrieved the server's certificate from: pop3s://pop3.live.com.
[-] Server certificates X509 is not trust...
the certificate subject data:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=*.hotmail.com
答案 0 :(得分:0)
这段代码工作得非常好,它只是我的Windows,两年后没有更新。我在Windows中的CA证书太旧了。
通过
)