diff --git a/crypto/x509/pkcs7.c b/crypto/x509/pkcs7.c index 9a4e490c..bb860776 100644 --- a/crypto/x509/pkcs7.c +++ b/crypto/x509/pkcs7.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "../bytestring/internal.h" @@ -213,6 +214,50 @@ err: return ret; } +int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, BIO *pem_bio) { + uint8_t *data; + long len; + int ret; + + /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM + * internally will actually allow several other values too, including + * "CERTIFICATE". */ + if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */, + PEM_STRING_PKCS7, pem_bio, + NULL /* password callback */, + NULL /* password callback argument */)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, data, len); + ret = PKCS7_get_certificates(out_certs, &cbs); + OPENSSL_free(data); + return ret; +} + +int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, BIO *pem_bio) { + uint8_t *data; + long len; + int ret; + + /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM + * internally will actually allow several other values too, including + * "CERTIFICATE". */ + if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */, + PEM_STRING_PKCS7, pem_bio, + NULL /* password callback */, + NULL /* password callback argument */)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, data, len); + ret = PKCS7_get_CRLs(out_crls, &cbs); + OPENSSL_free(data); + return ret; +} + /* pkcs7_bundle writes a PKCS#7, SignedData structure to |out| and then calls * |cb| with a CBB to which certificate or CRL data can be written, and the * opaque context pointer, |arg|. The callback can return zero to indicate an diff --git a/crypto/x509/pkcs7_test.c b/crypto/x509/pkcs7_test.c index ff61a2ba..bac9fb28 100644 --- a/crypto/x509/pkcs7_test.c +++ b/crypto/x509/pkcs7_test.c @@ -412,6 +412,60 @@ static const uint8_t kOpenSSLCRL[] = { 0xf0, 0x00, 0x54, 0x31, 0x00, }; +/* kPEMCert is the result of exporting the mail.google.com certificate from + * Chrome and then running it through: + * openssl pkcs7 -inform DER -in mail.google.com -outform PEM */ +static const char kPEMCert[] = + "-----BEGIN PKCS7-----\n" + "MIID+wYJKoZIhvcNAQcCoIID7DCCA+gCAQExADALBgkqhkiG9w0BBwGgggPQMIID\n" + "zDCCArSgAwIBAgIIWesoywKxoNQwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMC\n" + "VVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5l\n" + "dCBBdXRob3JpdHkgRzIwHhcNMTUwMjExMTQxNTA2WhcNMTUwNTEyMDAwMDAwWjBp\n" + "MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91\n" + "bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFpbC5n\n" + "b29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7MdALmCkcRRf/tzQ\n" + "a8eu3J7S5CTQa5ns0ReF9ktlbB1RL56BVGAu4p7BrT32D6gDpiggXq3gxN81A0TG\n" + "C2yICKOCAWEwggFdMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAsBgNV\n" + "HREEJTAjgg9tYWlsLmdvb2dsZS5jb22CEGluYm94Lmdvb2dsZS5jb20wCwYDVR0P\n" + "BAQDAgeAMGgGCCsGAQUFBwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5n\n" + "b29nbGUuY29tL0dJQUcyLmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMx\n" + "Lmdvb2dsZS5jb20vb2NzcDAdBgNVHQ4EFgQUQqsYsRoWLiG6qmV2N1mpYaHawxAw\n" + "DAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAX\n" + "BgNVHSAEEDAOMAwGCisGAQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDov\n" + "L3BraS5nb29nbGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAKNh3\n" + "isNuGBisPKVlekOsZR6S8oP/fS/xt6Hqvg0EwFXvhxoJ40rxAB2LMykY17e+ln3P\n" + "MwBBlRkwY1btcDT15JwzgaZb38rq/r+Pkb5Qgmx/InA/pw0QHDtwHQp5uXZuvu6p\n" + "J/SlCwyq7EOvByWdVQcMU/dhGa3idXEkn/zwfqcG6YjdWKoDmXWZYv3RiP3wJcRB\n" + "9+3U1wOe3uebnZLRWO6/w0to1XY8TFHklyw5rwIE5sbxOx5N3Ne8+GgPrUDvGAz0\n" + "rAUKnh3b7GNXL1qlZh2qkhB6rUzvtPpg397Asg3xVtExCHOk4zPqzzicttoEbVVy\n" + "0T8rIMUNwC4Beh4JVjEA\n" + "-----END PKCS7-----\n"; + +/* kPEMCRL is the result of downloading the Equifax CRL and running: + openssl crl2pkcs7 -inform DER -in secureca.crl */ +static const char kPEMCRL[] = + "-----BEGIN PKCS7-----\n" + "MIIDhQYJKoZIhvcNAQcCoIIDdjCCA3ICAQExADALBgkqhkiG9w0BBwGgAKGCA1gw\n" + "ggNUMIICvTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UEChMH\n" + "RXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0\n" + "aG9yaXR5Fw0xNTAyMjcwMTIzMDBaFw0xNTAzMDkwMTIzMDBaMIICPDAUAgMPWOQX\n" + "DTE0MDQyNzA4MTkyMlowFAIDFHYZFw0xNDA2MTgxNTAwMDNaMBQCAw+a+xcNMTQw\n" + "NDI5MTgwOTE3WjAUAgMUi8AXDTE0MDcwOTE5NDYzM1owFAIDFOScFw0xNDA0MTYy\n" + "MzM5MzVaMBQCAw+GBxcNMTQwNTIxMTU1MDUzWjAUAgMS4ikXDTE0MDYxNzE4NTUx\n" + "NVowFAIDDUJmFw0xMjA2MjcxNzEwNTNaMBQCAwMeMxcNMDIwNTE1MTMwNjExWjAU\n" + "AgMS4iMXDTE0MDYwNjIwNDAyMVowFAIDE5yrFw0xMDA3MjkxNjQ0MzlaMBQCAxLG\n" + "ChcNMTQwNjA2MjIyMTM5WjAUAgMDJYUXDTAyMDUxNDE4MTE1N1owFAIDFIbmFw0x\n" + "NDA3MjUwMjAwMzhaMBQCAxOcoRcNMTAwNzI5MTY0NzMyWjAUAgMVTVwXDTE0MDQz\n" + "MDAwMDQ0MlowFAIDD/otFw0xNDA2MTcxODUwMTFaMBQCAxN1VRcNMTUwMTE4MDIy\n" + "MTMzWjAUAgMPVpYXDTE0MDYyNDEyMzEwMlowFAIDC4CKFw0xMjA2MjcxNzEwMjVa\n" + "MBQCAw+UFhcNMTAwMzAxMTM0NTMxWjAUAgMUFrMXDTE0MDYxODE0MzI1NlowFAID\n" + "CuGFFw0xMjA2MjcxNzEwMTdaMBQCAxTMPhcNMTQwNzExMTI1NTMxWjAUAgMQW8sX\n" + "DTEwMDczMDIxMzEyMFowFAIDFWofFw0xNDAyMjYxMjM1MTlaMA0GCSqGSIb3DQEB\n" + "BQUAA4GBAB1cJwcRA/IAvfRGPnH9EISD2dLSGaAg9xpDPazaM/y3QmAapKiyB1xR\n" + "FsBCgAoP8EdbS3iQr8esSPjKPBNe9tGIrlWjDIpiRyn4crgkF6+yBh6ncnarlh3g\n" + "fNQMQoI9So4Vdy88Kow6BBBV3Lu6sZHue+cjxXETrmshNdNk8ABUMQA=\n" + "-----END PKCS7-----\n"; + static int test_cert_reparse(const uint8_t *der_bytes, size_t der_len) { CBS pkcs7; CBB cbb; @@ -540,12 +594,58 @@ static int test_crl_reparse(const uint8_t *der_bytes, size_t der_len) { return 1; } +static int test_pem_certs(const char *pem) { + BIO *bio = BIO_new_mem_buf((char *) pem, strlen(pem)); + STACK_OF(X509) *certs = sk_X509_new_null(); + + if (!PKCS7_get_PEM_certificates(certs, bio)) { + fprintf(stderr, "PKCS7_get_PEM_certificates failed.\n"); + return 0; + } + + if (sk_X509_num(certs) != 1) { + fprintf(stderr, + "Bad number of certificates from PKCS7_get_PEM_certificates: %u\n", + (unsigned)sk_X509_num(certs)); + return 0; + } + + BIO_free(bio); + sk_X509_pop_free(certs, X509_free); + + return 1; +} + +static int test_pem_crls(const char *pem) { + BIO *bio = BIO_new_mem_buf((char *) pem, strlen(pem)); + STACK_OF(X509_CRL) *crls = sk_X509_CRL_new_null(); + + if (!PKCS7_get_PEM_CRLs(crls, bio)) { + fprintf(stderr, "PKCS7_get_PEM_CRLs failed.\n"); + return 0; + } + + if (sk_X509_CRL_num(crls) != 1) { + fprintf(stderr, + "Bad number of CRLs from PKCS7_get_PEM_CRLs: %u\n", + (unsigned)sk_X509_CRL_num(crls)); + return 0; + } + + BIO_free(bio); + sk_X509_CRL_pop_free(crls, X509_CRL_free); + + return 1; +} + int main(void) { CRYPTO_library_init(); if (!test_cert_reparse(kPKCS7NSS, sizeof(kPKCS7NSS)) || !test_cert_reparse(kPKCS7Windows, sizeof(kPKCS7Windows)) || - !test_crl_reparse(kOpenSSLCRL, sizeof(kOpenSSLCRL))) { + !test_crl_reparse(kOpenSSLCRL, sizeof(kOpenSSLCRL)) || + !test_pem_certs(kPEMCert) || + !test_pem_crls(kPEMCRL)) { return 1; } diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 4025cf9b..ef1d7fb6 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1176,6 +1176,17 @@ OPENSSL_EXPORT int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs); * |crls| to |out|. It returns one on success and zero on error. */ OPENSSL_EXPORT int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls); +/* PKCS7_get_PEM_certificates reads a PEM-encoded, PKCS#7, SignedData structure + * from |pem_bio| and appends the included certificates to |out_certs|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, + BIO *pem_bio); + +/* PKCS7_get_PEM_CRLs reads a PEM-encoded, PKCS#7, SignedData structure from + * |pem_bio| and appends the included CRLs to |out_crls|. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, + BIO *pem_bio); /* EVP_PK values indicate the algorithm of the public key in a certificate. */