From 0f6c6efd814a46a51981a29a5cb64c7a0858d5eb Mon Sep 17 00:00:00 2001 From: DaVieS Date: Mon, 31 Dec 2018 01:36:05 +0100 Subject: cacertinmem.c: use multiple certificates for loading CA-chain Closes #3421 --- docs/examples/cacertinmem.c | 148 ++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 75 deletions(-) diff --git a/docs/examples/cacertinmem.c b/docs/examples/cacertinmem.c index 6f4c61cbf..9e15eb79d 100644 --- a/docs/examples/cacertinmem.c +++ b/docs/examples/cacertinmem.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,7 +29,7 @@ #include #include -size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) +static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) { fwrite(ptr, size, nmemb, (FILE *)stream); return (nmemb*size); @@ -38,88 +38,86 @@ size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) { CURLcode rv = CURLE_ABORTED_BY_CALLBACK; - X509_STORE *store = NULL; - X509 *cert = NULL; - BIO *bio = NULL; - char *mypem = - /* CA for example.com. CN = DigiCert High Assurance EV Root CA */ + + /** This example uses two (fake) certificates **/ + static const char mypem[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE\n" + "AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw\n" + "CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ\n" + "BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND\n" + "VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb\n" + "qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY\n" + "HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo\n" + "G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA\n" + "0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH\n" + "k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47\n" + "JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m\n" + "AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD\n" + "vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms\n" + "tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH\n" + "7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h\n" + "I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA\n" + "h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF\n" + "d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H\n" + "pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7\n" + "-----END CERTIFICATE-----\n" "-----BEGIN CERTIFICATE-----\n" - "MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" - "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" - "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" - "ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" - "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" - "LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" - "RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" - "+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" - "PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" - "xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" - "Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" - "hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" - "EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" - "MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" - "FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" - "nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" - "eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" - "hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" - "Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" - "vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" - "+OkuE6N36B9K\n" + "MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE\n" + "AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x\n" + "CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW\n" + "MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF\n" + "RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC\n" + "AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7\n" + "09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7\n" + "XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P\n" + "gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe\n" + "I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i\n" + "5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi\n" + "ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn\n" + "MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ\n" + "o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6\n" + "zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN\n" + "GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt\n" + "r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK\n" + "Z05phkOTOPu220+DkdRgfks+KzgHVZhepA==\n" "-----END CERTIFICATE-----\n"; - /* clear the current thread's OpenSSL error queue */ - ERR_clear_error(); + BIO *cbio = BIO_new_mem_buf(mypem, sizeof(mypem)); + X509_STORE *cts = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); + X509_INFO *itmp; + int i, count = 0; + STACK_OF(X509_INFO) *inf; + (void)curl; + (void)parm; - /* get a BIO */ - bio = BIO_new_mem_buf(mypem, -1); - if(!bio) - goto err; - - /* use it to read the PEM formatted certificate from memory into an X509 - * structure that SSL can use - */ - if(!PEM_read_bio_X509(bio, &cert, 0, NULL)) - goto err; - - /* get a pointer to the X509 certificate store (which may be empty!) */ - store = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); - if(!store) - goto err; - - /* add our certificate to this store */ - if(!X509_STORE_add_cert(store, cert)) { - unsigned long error = ERR_peek_last_error(); - - /* Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the - * certificate is already in the store. That could happen if - * libcurl already loaded the certificate from a ca cert bundle - * set at libcurl build-time or runtime. - */ - if(ERR_GET_LIB(error) != ERR_LIB_X509 || - ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) - goto err; - - ERR_clear_error(); + if(!cts || !cbio) { + return rv; } - rv = CURLE_OK; + inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL); -err: - if(rv != CURLE_OK) { - char errbuf[256]; - unsigned long error = ERR_peek_last_error(); + if(!inf) { + BIO_free(cbio); + return rv; + } - fprintf(stderr, "error adding certificate\n"); - if(error) { - ERR_error_string_n(error, errbuf, sizeof(errbuf)); - fprintf(stderr, "%s\n", errbuf); + for(i = 0; i < sk_X509_INFO_num(inf); i++) { + itmp = sk_X509_INFO_value(inf, i); + if(itmp->x509) { + X509_STORE_add_cert(cts, itmp->x509); + count++; + } + if(itmp->crl) { + X509_STORE_add_crl(cts, itmp->crl); + count++; } } - X509_free(cert); - BIO_free(bio); - ERR_clear_error(); + sk_X509_INFO_pop_free(inf, X509_INFO_free); + BIO_free(cbio); + rv = CURLE_OK; return rv; } @@ -142,9 +140,9 @@ int main(void) rv = curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); rv = curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); - /* turn off the default CA locations (optional) - * otherwise libcurl will load CA certificates from the locations that - * were detected/specified at build-time + /* Turn off the default CA locations, otherwise libcurl will load CA + * certificates from the locations that were detected/specified at + * build-time */ rv = curl_easy_setopt(ch, CURLOPT_CAINFO, NULL); rv = curl_easy_setopt(ch, CURLOPT_CAPATH, NULL); -- cgit v1.2.1