From 2874696a5a8d46639d261571f915c493cd875897 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 13 Aug 2013 22:20:33 -0700 Subject: [PATCH] Fix CVE-2013-4073 - handling of certs with null bytes --- NEWS | 4 ++ ext/openssl/openssl.c | 86 ++++++++++++++++++++++++++++++++++++- ext/openssl/tests/cve2013_4073.pem | 28 ++++++++++++ ext/openssl/tests/cve2013_4073.phpt | 19 ++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 ext/openssl/tests/cve2013_4073.pem create mode 100644 ext/openssl/tests/cve2013_4073.phpt diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index d7ac117..c32748c 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1398,6 +1398,74 @@ PHP_FUNCTION(openssl_x509_check_private_key) } /* }}} */ +/* Special handling of subjectAltName, see CVE-2013-4073 + * Christian Heimes + */ + +static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) +{ + GENERAL_NAMES *names; + const X509V3_EXT_METHOD *method = NULL; + long i, length, num; + const unsigned char *p; + + method = X509V3_EXT_get(extension); + if (method == NULL) { + return -1; + } + + p = extension->value->data; + length = extension->value->length; + if (method->it) { + names = (GENERAL_NAMES*)(ASN1_item_d2i(NULL, &p, length, + ASN1_ITEM_ptr(method->it))); + } else { + names = (GENERAL_NAMES*)(method->d2i(NULL, &p, length)); + } + if (names == NULL) { + return -1; + } + + num = sk_GENERAL_NAME_num(names); + for (i = 0; i < num; i++) { + GENERAL_NAME *name; + ASN1_STRING *as; + name = sk_GENERAL_NAME_value(names, i); + switch (name->type) { + case GEN_EMAIL: + BIO_puts(bio, "email:"); + as = name->d.rfc822Name; + BIO_write(bio, ASN1_STRING_data(as), + ASN1_STRING_length(as)); + break; + case GEN_DNS: + BIO_puts(bio, "DNS:"); + as = name->d.dNSName; + BIO_write(bio, ASN1_STRING_data(as), + ASN1_STRING_length(as)); + break; + case GEN_URI: + BIO_puts(bio, "URI:"); + as = name->d.uniformResourceIdentifier; + BIO_write(bio, ASN1_STRING_data(as), + ASN1_STRING_length(as)); + break; + default: + /* use builtin print for GEN_OTHERNAME, GEN_X400, + * GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID + */ + GENERAL_NAME_print(bio, name); + } + /* trailing ', ' except for last element */ + if (i < (num - 1)) { + BIO_puts(bio, ", "); + } + } + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); + + return 0; +} + /* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true]) Returns an array of the fields/values of the CERT */ PHP_FUNCTION(openssl_x509_parse) @@ -1494,15 +1562,29 @@ PHP_FUNCTION(openssl_x509_parse) for (i = 0; i < X509_get_ext_count(cert); i++) { + int nid; extension = X509_get_ext(cert, i); - if (OBJ_obj2nid(X509_EXTENSION_get_object(extension)) != NID_undef) { + nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension)); + if (nid != NID_undef) { extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension))); } else { OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1); extname = buf; } bio_out = BIO_new(BIO_s_mem()); - if (X509V3_EXT_print(bio_out, extension, 0, 0)) { + if (nid == NID_subject_alt_name) { + if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) { + add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1); + } else { + zval_dtor(return_value); + if (certresource == -1 && cert) { + X509_free(cert); + } + BIO_free(bio_out); + RETURN_FALSE; + } + } + else if (X509V3_EXT_print(bio_out, extension, 0, 0)) { BIO_get_mem_ptr(bio_out, &bio_buf); add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1); } else { diff --git a/ext/openssl/tests/cve2013_4073.pem b/ext/openssl/tests/cve2013_4073.pem new file mode 100644 index 0000000..7ebb994 --- /dev/null +++ b/ext/openssl/tests/cve2013_4073.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE2DCCA8CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBxTELMAkGA1UEBhMCVVMx +DzANBgNVBAgMBk9yZWdvbjESMBAGA1UEBwwJQmVhdmVydG9uMSMwIQYDVQQKDBpQ +eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEgMB4GA1UECwwXUHl0aG9uIENvcmUg +RGV2ZWxvcG1lbnQxJDAiBgNVBAMMG251bGwucHl0aG9uLm9yZwBleGFtcGxlLm9y +ZzEkMCIGCSqGSIb3DQEJARYVcHl0aG9uLWRldkBweXRob24ub3JnMB4XDTEzMDgw +NzEzMTE1MloXDTEzMDgwNzEzMTI1MlowgcUxCzAJBgNVBAYTAlVTMQ8wDQYDVQQI +DAZPcmVnb24xEjAQBgNVBAcMCUJlYXZlcnRvbjEjMCEGA1UECgwaUHl0aG9uIFNv +ZnR3YXJlIEZvdW5kYXRpb24xIDAeBgNVBAsMF1B5dGhvbiBDb3JlIERldmVsb3Bt +ZW50MSQwIgYDVQQDDBtudWxsLnB5dGhvbi5vcmcAZXhhbXBsZS5vcmcxJDAiBgkq +hkiG9w0BCQEWFXB5dGhvbi1kZXZAcHl0aG9uLm9yZzCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALXq7cn7Rn1vO3aA3TrzA5QLp6bb7B3f/yN0CJ2XFj+j +pHs+Gw6WWSUDpybiiKnPec33BFawq3kyblnBMjBU61ioy5HwQqVkJ8vUVjGIUq3P +vX/wBmQfzCe4o4uM89gpHyUL9UYGG8oCRa17dgqcv7u5rg0Wq2B1rgY+nHwx3JIv +KRrgSwyRkGzpN8WQ1yrXlxWjgI9de0mPVDDUlywcWze1q2kwaEPTM3hLAmD1PESA +oY/n8A/RXoeeRs9i/Pm/DGUS8ZPINXk/yOzsR/XvvkTVroIeLZqfmFpnZeF0cHzL +08LODkVJJ9zjLdT7SA4vnne4FEbAxDbKAq5qkYzaL4UCAwEAAaOB0DCBzTAMBgNV +HRMBAf8EAjAAMB0GA1UdDgQWBBSIWlXAUv9hzVKjNQ/qWpwkOCL3XDALBgNVHQ8E +BAMCBeAwgZAGA1UdEQSBiDCBhYIeYWx0bnVsbC5weXRob24ub3JnAGV4YW1wbGUu +Y29tgSBudWxsQHB5dGhvbi5vcmcAdXNlckBleGFtcGxlLm9yZ4YpaHR0cDovL251 +bGwucHl0aG9uLm9yZwBodHRwOi8vZXhhbXBsZS5vcmeHBMAAAgGHECABDbgAAAAA +AAAAAAAAAAEwDQYJKoZIhvcNAQEFBQADggEBAKxPRe99SaghcI6IWT7UNkJw9aO9 +i9eo0Fj2MUqxpKbdb9noRDy2CnHWf7EIYZ1gznXPdwzSN4YCjV5d+Q9xtBaowT0j +HPERs1ZuytCNNJTmhyqZ8q6uzMLoht4IqH/FBfpvgaeC5tBTnTT0rD5A/olXeimk +kX4LxlEx5RAvpGB2zZVRGr6LobD9rVK91xuHYNIxxxfEGE8tCCWjp0+3ksri9SXx +VHWBnbM9YaL32u3hxm8sYB/Yb8WSBavJCWJJqRStVRHM1koZlJmXNx2BX4vPo6iW +RFEIPQsFZRLrtnCAiEhyT8bC2s/Njlu6ly9gtJZWSV46Q3ZjBL4q9sHKqZQ= +-----END CERTIFICATE----- diff --git a/ext/openssl/tests/cve2013_4073.phpt b/ext/openssl/tests/cve2013_4073.phpt new file mode 100644 index 0000000..e676ddf --- /dev/null +++ b/ext/openssl/tests/cve2013_4073.phpt @@ -0,0 +1,19 @@ +--TEST-- +CVE 2013-4073: Null-byte certificate handling +--SKIPIF-- + 'CA:FALSE', + 'subjectKeyIdentifier' => '88:5A:55:C0:52:FF:61:CD:52:A3:35:0F:EA:5A:9C:24:38:22:F7:5C', + 'keyUsage' => 'Digital Signature, Non Repudiation, Key Encipherment', + 'subjectAltName' => 'DNS:altnull.python.org' . "\0" . 'example.com, email:null@python.org' . "\0" . 'user@example.org, URI:http://null.python.org' . "\0" . 'http://example.org, IP Address:192.0.2.1, IP Address:2001:DB8:0:0:0:0:0:1 +', +) -- 1.7.11.5 From c1c49d6e3983c9ce0b43ffe7bf6e03b809ed048b Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 19 Aug 2013 01:02:12 -0700 Subject: [PATCH] fix using wrong buffer pointer --- ext/openssl/openssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index c7a9f5c..e7672e4 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1502,6 +1502,7 @@ PHP_FUNCTION(openssl_x509_parse) bio_out = BIO_new(BIO_s_mem()); if (nid == NID_subject_alt_name) { if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) { + BIO_get_mem_ptr(bio_out, &bio_buf); add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1); } else { zval_dtor(return_value); -- 1.7.11.5