1 # |
|
2 # This patch contains the fixes for CVE-2013-4073 (NULL bytes in subjectAltName |
|
3 # not correctly interpreted). |
|
4 # The patch was taken from: |
|
5 # https://code.launchpad.net/~heimes/pyopenssl/pyopenssl/+merge/179673 |
|
6 # and modified to fit the the 0.13 release code (original fix was based off tip |
|
7 # code in pyopenssl repo). |
|
8 # |
|
9 --- pyOpenSSL-0.13/ChangeLog 2011-09-02 08:46:13.000000000 -0700 |
|
10 +++ pyOpenSSL-0.13/ChangeLog 2013-08-26 14:40:43.941191227 -0700 |
|
11 @@ -1,3 +1,9 @@ |
|
12 +2013-08-11 Christian Heimes <[email protected]> |
|
13 + |
|
14 + * OpenSSL/crypto/x509ext.c: Fix handling of NULL bytes inside |
|
15 + subjectAltName general names, CVE-2013-4073. |
|
16 + * OpenSSL/crypto/x509.c: Fix memory leak in get_extension(). |
|
17 + |
|
18 2011-09-02 Jean-Paul Calderone <[email protected]> |
|
19 |
|
20 * Release 0.13 |
|
21 --- pyOpenSSL-0.13/OpenSSL/crypto/x509.c 2011-09-02 08:46:13.000000000 -0700 |
|
22 +++ pyOpenSSL-0.13/OpenSSL/crypto/x509.c 2013-08-26 14:41:34.379545946 -0700 |
|
23 @@ -756,6 +756,7 @@ |
|
24 |
|
25 extobj = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type); |
|
26 extobj->x509_extension = X509_EXTENSION_dup(ext); |
|
27 + extobj->dealloc = 1; |
|
28 |
|
29 return (PyObject*)extobj; |
|
30 } |
|
31 --- pyOpenSSL-0.13/OpenSSL/crypto/x509ext.c 2011-09-02 08:46:13.000000000 -0700 |
|
32 +++ pyOpenSSL-0.13/OpenSSL/crypto/x509ext.c 2013-08-26 14:53:08.501972021 -0700 |
|
33 @@ -236,6 +236,75 @@ |
|
34 PyObject_Del(self); |
|
35 } |
|
36 |
|
37 + |
|
38 +/* Special handling of subjectAltName, see CVE-2013-4073 */ |
|
39 + |
|
40 +int |
|
41 +crypto_X509Extension_str_san(crypto_X509ExtensionObj *self, BIO *bio) |
|
42 +{ |
|
43 + GENERAL_NAMES *names; |
|
44 + const X509V3_EXT_METHOD *method = NULL; |
|
45 + long i, length, num; |
|
46 + const unsigned char *p; |
|
47 + |
|
48 + method = X509V3_EXT_get(self->x509_extension); |
|
49 + if (method == NULL) { |
|
50 + return -1; |
|
51 + } |
|
52 + |
|
53 + p = self->x509_extension->value->data; |
|
54 + length = self->x509_extension->value->length; |
|
55 + if (method->it) { |
|
56 + names = (GENERAL_NAMES*)(ASN1_item_d2i(NULL, &p, length, |
|
57 + ASN1_ITEM_ptr(method->it))); |
|
58 + } |
|
59 + else { |
|
60 + names = (GENERAL_NAMES*)(method->d2i(NULL, &p, length)); |
|
61 + } |
|
62 + if (names == NULL) { |
|
63 + return -1; |
|
64 + } |
|
65 + |
|
66 + num = sk_GENERAL_NAME_num(names); |
|
67 + for (i = 0; i < num; i++) { |
|
68 + GENERAL_NAME *name; |
|
69 + ASN1_STRING *as; |
|
70 + name = sk_GENERAL_NAME_value(names, i); |
|
71 + switch (name->type) { |
|
72 + case GEN_EMAIL: |
|
73 + BIO_puts(bio, "email:"); |
|
74 + as = name->d.rfc822Name; |
|
75 + BIO_write(bio, ASN1_STRING_data(as), |
|
76 + ASN1_STRING_length(as)); |
|
77 + break; |
|
78 + case GEN_DNS: |
|
79 + BIO_puts(bio, "DNS:"); |
|
80 + as = name->d.dNSName; |
|
81 + BIO_write(bio, ASN1_STRING_data(as), |
|
82 + ASN1_STRING_length(as)); |
|
83 + break; |
|
84 + case GEN_URI: |
|
85 + BIO_puts(bio, "URI:"); |
|
86 + as = name->d.uniformResourceIdentifier; |
|
87 + BIO_write(bio, ASN1_STRING_data(as), |
|
88 + ASN1_STRING_length(as)); |
|
89 + break; |
|
90 + default: |
|
91 + /* use builtin print for GEN_OTHERNAME, GEN_X400, |
|
92 + * GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID |
|
93 + */ |
|
94 + GENERAL_NAME_print(bio, name); |
|
95 + } |
|
96 + /* trailing ', ' except for last element */ |
|
97 + if (i < (num - 1)) { |
|
98 + BIO_puts(bio, ", "); |
|
99 + } |
|
100 + } |
|
101 + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); |
|
102 + |
|
103 + return 0; |
|
104 +} |
|
105 + |
|
106 /* |
|
107 * Print a nice text representation of the certificate request. |
|
108 */ |
|
109 @@ -247,7 +316,14 @@ |
|
110 PyObject *str; |
|
111 BIO *bio = BIO_new(BIO_s_mem()); |
|
112 |
|
113 - if (!X509V3_EXT_print(bio, self->x509_extension, 0, 0)) |
|
114 + if (OBJ_obj2nid(self->x509_extension->object) == NID_subject_alt_name) { |
|
115 + if (crypto_X509Extension_str_san(self, bio) == -1) { |
|
116 + BIO_free(bio); |
|
117 + exception_from_error_queue(crypto_Error); |
|
118 + return NULL; |
|
119 + } |
|
120 + } |
|
121 + else if (!X509V3_EXT_print(bio, self->x509_extension, 0, 0)) |
|
122 { |
|
123 BIO_free(bio); |
|
124 exception_from_error_queue(crypto_Error); |
|
125 --- pyOpenSSL-0.13/OpenSSL/test/test_crypto.py 2011-09-02 08:46:13.000000000 -0700 |
|
126 +++ pyOpenSSL-0.13/OpenSSL/test/test_crypto.py 2013-08-26 14:57:06.933614387 -0700 |
|
127 @@ -265,6 +265,37 @@ |
|
128 -----END RSA PRIVATE KEY----- |
|
129 """) |
|
130 |
|
131 +# certificate with NULL bytes in subjectAltName and common name |
|
132 + |
|
133 +nullbyte_san_PEM = b("""-----BEGIN CERTIFICATE----- |
|
134 +MIIE2DCCA8CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBxTELMAkGA1UEBhMCVVMx |
|
135 +DzANBgNVBAgMBk9yZWdvbjESMBAGA1UEBwwJQmVhdmVydG9uMSMwIQYDVQQKDBpQ |
|
136 +eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEgMB4GA1UECwwXUHl0aG9uIENvcmUg |
|
137 +RGV2ZWxvcG1lbnQxJDAiBgNVBAMMG251bGwucHl0aG9uLm9yZwBleGFtcGxlLm9y |
|
138 +ZzEkMCIGCSqGSIb3DQEJARYVcHl0aG9uLWRldkBweXRob24ub3JnMB4XDTEzMDgw |
|
139 +NzEzMTE1MloXDTEzMDgwNzEzMTI1MlowgcUxCzAJBgNVBAYTAlVTMQ8wDQYDVQQI |
|
140 +DAZPcmVnb24xEjAQBgNVBAcMCUJlYXZlcnRvbjEjMCEGA1UECgwaUHl0aG9uIFNv |
|
141 +ZnR3YXJlIEZvdW5kYXRpb24xIDAeBgNVBAsMF1B5dGhvbiBDb3JlIERldmVsb3Bt |
|
142 +ZW50MSQwIgYDVQQDDBtudWxsLnB5dGhvbi5vcmcAZXhhbXBsZS5vcmcxJDAiBgkq |
|
143 +hkiG9w0BCQEWFXB5dGhvbi1kZXZAcHl0aG9uLm9yZzCCASIwDQYJKoZIhvcNAQEB |
|
144 +BQADggEPADCCAQoCggEBALXq7cn7Rn1vO3aA3TrzA5QLp6bb7B3f/yN0CJ2XFj+j |
|
145 +pHs+Gw6WWSUDpybiiKnPec33BFawq3kyblnBMjBU61ioy5HwQqVkJ8vUVjGIUq3P |
|
146 +vX/wBmQfzCe4o4uM89gpHyUL9UYGG8oCRa17dgqcv7u5rg0Wq2B1rgY+nHwx3JIv |
|
147 +KRrgSwyRkGzpN8WQ1yrXlxWjgI9de0mPVDDUlywcWze1q2kwaEPTM3hLAmD1PESA |
|
148 +oY/n8A/RXoeeRs9i/Pm/DGUS8ZPINXk/yOzsR/XvvkTVroIeLZqfmFpnZeF0cHzL |
|
149 +08LODkVJJ9zjLdT7SA4vnne4FEbAxDbKAq5qkYzaL4UCAwEAAaOB0DCBzTAMBgNV |
|
150 +HRMBAf8EAjAAMB0GA1UdDgQWBBSIWlXAUv9hzVKjNQ/qWpwkOCL3XDALBgNVHQ8E |
|
151 +BAMCBeAwgZAGA1UdEQSBiDCBhYIeYWx0bnVsbC5weXRob24ub3JnAGV4YW1wbGUu |
|
152 +Y29tgSBudWxsQHB5dGhvbi5vcmcAdXNlckBleGFtcGxlLm9yZ4YpaHR0cDovL251 |
|
153 +bGwucHl0aG9uLm9yZwBodHRwOi8vZXhhbXBsZS5vcmeHBMAAAgGHECABDbgAAAAA |
|
154 +AAAAAAAAAAEwDQYJKoZIhvcNAQEFBQADggEBAKxPRe99SaghcI6IWT7UNkJw9aO9 |
|
155 +i9eo0Fj2MUqxpKbdb9noRDy2CnHWf7EIYZ1gznXPdwzSN4YCjV5d+Q9xtBaowT0j |
|
156 +HPERs1ZuytCNNJTmhyqZ8q6uzMLoht4IqH/FBfpvgaeC5tBTnTT0rD5A/olXeimk |
|
157 +kX4LxlEx5RAvpGB2zZVRGr6LobD9rVK91xuHYNIxxxfEGE8tCCWjp0+3ksri9SXx |
|
158 +VHWBnbM9YaL32u3hxm8sYB/Yb8WSBavJCWJJqRStVRHM1koZlJmXNx2BX4vPo6iW |
|
159 +RFEIPQsFZRLrtnCAiEhyT8bC2s/Njlu6ly9gtJZWSV46Q3ZjBL4q9sHKqZQ= |
|
160 +-----END CERTIFICATE-----""") |
|
161 + |
|
162 |
|
163 class X509ExtTests(TestCase): |
|
164 """ |
|
165 @@ -1382,6 +1413,36 @@ |
|
166 self.assertRaises(TypeError, cert.get_extension, "hello") |
|
167 |
|
168 |
|
169 + def test_nullbyte_san(self): |
|
170 + """ |
|
171 + Test correct handling of CN and SAN with NULL bytes |
|
172 + |
|
173 + see CVE-2013-4073 |
|
174 + """ |
|
175 + cert = load_certificate(FILETYPE_PEM, nullbyte_san_PEM) |
|
176 + subject = cert.get_subject() |
|
177 + self.assertEqual(subject.CN, 'null.python.org\x00example.org') |
|
178 + issuer = cert.get_issuer() |
|
179 + self.assertEqual(issuer.CN, 'null.python.org\x00example.org') |
|
180 + |
|
181 + ext = cert.get_extension(0) |
|
182 + self.assertEqual(ext.get_short_name(), b('basicConstraints')) |
|
183 + |
|
184 + ext = cert.get_extension(1) |
|
185 + self.assertEqual(ext.get_short_name(), b('subjectKeyIdentifier')) |
|
186 + |
|
187 + ext = cert.get_extension(2) |
|
188 + self.assertEqual(ext.get_short_name(), b('keyUsage')) |
|
189 + |
|
190 + ext = cert.get_extension(3) |
|
191 + self.assertEqual(ext.get_short_name(), b('subjectAltName')) |
|
192 + self.assertEqual(str(ext), |
|
193 + 'DNS:altnull.python.org\x00example.com, ' |
|
194 + 'email:[email protected]\[email protected], ' |
|
195 + 'URI:http://null.python.org\x00http://example.org, ' |
|
196 + 'IP Address:192.0.2.1, IP Address:2001:DB8:0:0:0:0:0:1\n') |
|
197 + |
|
198 + |
|
199 def test_invalid_digest_algorithm(self): |
|
200 """ |
|
201 L{X509.digest} raises L{ValueError} if called with an unrecognized hash |
|