API:Openssl / Wincrypt:无法获得本地颁发者证书/证书不受信任

时间:2014-11-19 20:41:26

标签: windows ssl openssl x509

我在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

1 个答案:

答案 0 :(得分:0)

这段代码工作得非常好,它只是我的Windows,两年后没有更新。我在Windows中的CA证书太旧了。

通过