Skip to content

Commit 308dca9

Browse files
fix X509V3_EXT_METHODs for ocsp nonce extension (aws#1603)
This backports more of the changes done in 736a283 to reintroduce the "old-style" `X509V3_EXT_METHOD`s. Although we're reintroducing the methods we discourage using, I've added checks to ensure that these are only used with `NID_id_pkix_OCSP_Nonce`. The assertion in `X509V3_EXT_add` is kept so that we continue to only allow |ASN1_ITEM|-based extensions for consumers that add their own. I've abstracted out the freeing logic to `x509v3_ext_free_with_method`. This used to be all over the place. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.
1 parent 6ced83c commit 308dca9

File tree

7 files changed

+116
-26
lines changed

7 files changed

+116
-26
lines changed

crypto/asn1/tasn_dec.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
170170
ASN1_VALUE **pchptr;
171171
int combine = aclass & ASN1_TFLG_COMBINE;
172172
aclass &= ~ASN1_TFLG_COMBINE;
173-
if (!pval) {
173+
if (pval == NULL || it == NULL) {
174174
return 0;
175175
}
176176

crypto/asn1/tasn_fre.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
7878
const ASN1_TEMPLATE *tt = NULL, *seqtt;
7979
const ASN1_EXTERN_FUNCS *ef;
8080
int i;
81-
if (!pval) {
81+
if (pval == NULL || it == NULL) {
8282
return;
8383
}
8484
if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) {

crypto/x509/internal.h

+4
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,10 @@ typedef struct {
480480
int x509V3_add_value_asn1_string(const char *name, const ASN1_STRING *value,
481481
STACK_OF(CONF_VALUE) **extlist);
482482

483+
// x509v3_ext_free_with_method frees |ext_data| with |ext_method|.
484+
int x509v3_ext_free_with_method(const X509V3_EXT_METHOD *ext_method,
485+
void *ext_data);
486+
483487
// X509V3_NAME_from_section adds attributes to |nm| by interpreting the
484488
// key/value pairs in |dn_sk|. It returns one on success and zero on error.
485489
// |chtype|, which should be one of |MBSTRING_*| constants, determines the

crypto/x509/v3_conf.c

+7-8
Original file line numberDiff line numberDiff line change
@@ -205,20 +205,19 @@ static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid,
205205
if (ext_len < 0) {
206206
return NULL;
207207
}
208-
} else {
209-
// This is using the "old-style" ASN.1 callbacks. The only X509v3 extension
210-
// that's still dependent on this code internally are OCSP nonce extensions.
211-
// We can't easily migrate OCSP nonce extensions to use the "new" callbacks
212-
// either, since OCSP nonces are handled differently in the code (according
213-
// to OpenSSL and us having to maintain backwards compatibility with them).
214-
// Every other |X509V3_EXT_METHOD|, both inside and outside the library, has
215-
// and should have an |ASN1_ITEM|.
208+
} else if (method->ext_nid == NID_id_pkix_OCSP_Nonce && method->i2d != NULL) {
209+
// |NID_id_pkix_OCSP_Nonce| is the only extension using the "old-style"
210+
// ASN.1 callbacks for backwards compatibility reasons.
211+
// Note: See |v3_ext_method| under "include/openssl/x509.h".
216212
ext_len = method->i2d(ext_struc, NULL);
217213
if (!(ext_der = OPENSSL_malloc(ext_len))) {
218214
return NULL;
219215
}
220216
unsigned char *p = ext_der;
221217
method->i2d(ext_struc, &p);
218+
} else {
219+
OPENSSL_PUT_ERROR(X509, X509V3_R_OPERATION_NOT_DEFINED);
220+
return NULL;
222221
}
223222

224223
ASN1_OCTET_STRING *ext_oct = ASN1_OCTET_STRING_new();

crypto/x509/v3_lib.c

+62-10
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,27 @@ static int ext_cmp(const void *void_a, const void *void_b) {
9898
return ext_stack_cmp(a, b);
9999
}
100100

101+
static int x509v3_ext_method_validate(const X509V3_EXT_METHOD *ext_method) {
102+
if (ext_method == NULL) {
103+
return 0;
104+
}
105+
106+
if (ext_method->ext_nid == NID_id_pkix_OCSP_Nonce &&
107+
ext_method->d2i != NULL && ext_method->i2d != NULL &&
108+
ext_method->ext_new != NULL && ext_method->ext_free != NULL) {
109+
// |NID_id_pkix_OCSP_Nonce| is the only extension using the "old-style"
110+
// ASN.1 callbacks for backwards compatibility reasons.
111+
// Note: See |v3_ext_method| under "include/openssl/x509.h".
112+
return 1;
113+
}
114+
115+
if (ext_method->it == NULL) {
116+
OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED);
117+
return 0;
118+
}
119+
return 1;
120+
}
121+
101122
const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) {
102123
X509V3_EXT_METHOD tmp;
103124
const X509V3_EXT_METHOD *t = &tmp, *const * ret;
@@ -109,7 +130,7 @@ const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) {
109130
tmp.ext_nid = nid;
110131
ret = bsearch(&t, standard_exts, STANDARD_EXTENSION_COUNT,
111132
sizeof(X509V3_EXT_METHOD *), ext_cmp);
112-
if (ret) {
133+
if (ret != NULL && x509v3_ext_method_validate(*ret)) {
113134
return *ret;
114135
}
115136
if (!ext_list) {
@@ -119,7 +140,12 @@ const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) {
119140
if (!sk_X509V3_EXT_METHOD_find_awslc(ext_list, &idx, &tmp)) {
120141
return NULL;
121142
}
122-
return sk_X509V3_EXT_METHOD_value(ext_list, idx);
143+
144+
const X509V3_EXT_METHOD *method = sk_X509V3_EXT_METHOD_value(ext_list, idx);
145+
if (method != NULL && x509v3_ext_method_validate(method)) {
146+
return method;
147+
}
148+
return NULL;
123149
}
124150

125151
const X509V3_EXT_METHOD *X509V3_EXT_get(const X509_EXTENSION *ext) {
@@ -130,19 +156,34 @@ const X509V3_EXT_METHOD *X509V3_EXT_get(const X509_EXTENSION *ext) {
130156
return X509V3_EXT_get_nid(nid);
131157
}
132158

133-
int X509V3_EXT_free(int nid, void *ext_data) {
134-
const X509V3_EXT_METHOD *ext_method = X509V3_EXT_get_nid(nid);
159+
int x509v3_ext_free_with_method(const X509V3_EXT_METHOD *ext_method,
160+
void *ext_data) {
135161
if (ext_method == NULL) {
136162
OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
137163
return 0;
138164
}
139165

140-
ASN1_item_free(ext_data, ASN1_ITEM_ptr(ext_method->it));
166+
if (ext_method->it != NULL) {
167+
ASN1_item_free(ext_data, ASN1_ITEM_ptr(ext_method->it));
168+
} else if (ext_method->ext_nid == NID_id_pkix_OCSP_Nonce &&
169+
ext_method->ext_free != NULL) {
170+
// |NID_id_pkix_OCSP_Nonce| is the only extension using the "old-style"
171+
// ASN.1 callbacks for backwards compatibility reasons.
172+
// Note: See |v3_ext_method| under "include/openssl/x509.h".
173+
ext_method->ext_free(ext_data);
174+
} else {
175+
OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
176+
return 0;
177+
}
141178
return 1;
142179
}
143180

181+
int X509V3_EXT_free(int nid, void *ext_data) {
182+
return x509v3_ext_free_with_method(X509V3_EXT_get_nid(nid), ext_data);
183+
}
184+
144185
int X509V3_EXT_add_alias(int nid_to, int nid_from) {
145-
OPENSSL_BEGIN_ALLOW_DEPRECATED
186+
OPENSSL_BEGIN_ALLOW_DEPRECATED
146187
const X509V3_EXT_METHOD *ext;
147188
X509V3_EXT_METHOD *tmpext;
148189

@@ -161,7 +202,7 @@ OPENSSL_BEGIN_ALLOW_DEPRECATED
161202
return 0;
162203
}
163204
return 1;
164-
OPENSSL_END_ALLOW_DEPRECATED
205+
OPENSSL_END_ALLOW_DEPRECATED
165206
}
166207

167208
// Legacy function: we don't need to add standard extensions any more because
@@ -179,14 +220,25 @@ void *X509V3_EXT_d2i(const X509_EXTENSION *ext) {
179220
return NULL;
180221
}
181222
p = ext->value->data;
182-
void *ret =
183-
ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it));
223+
void *ret = NULL;
224+
if (method->it) {
225+
ret =
226+
ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it));
227+
} else if (method->ext_nid == NID_id_pkix_OCSP_Nonce && method->d2i != NULL) {
228+
// |NID_id_pkix_OCSP_Nonce| is the only extension using the "old-style"
229+
// ASN.1 callbacks for backwards compatibility reasons.
230+
// Note: See |v3_ext_method| under "include/openssl/x509.h".
231+
ret = method->d2i(NULL, &p, ext->value->length);
232+
} else {
233+
assert(0);
234+
}
235+
184236
if (ret == NULL) {
185237
return NULL;
186238
}
187239
// Check for trailing data.
188240
if (p != ext->value->data + ext->value->length) {
189-
ASN1_item_free(ret, ASN1_ITEM_ptr(method->it));
241+
x509v3_ext_free_with_method(method, ret);
190242
OPENSSL_PUT_ERROR(X509V3, X509V3_R_TRAILING_DATA_IN_EXTENSION);
191243
return NULL;
192244
}

crypto/x509/v3_prn.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
#include <openssl/mem.h>
6464
#include <openssl/x509.h>
6565

66+
#include "internal.h"
67+
6668
// Extension printing routines
6769

6870
static int unknown_ext_print(BIO *out, const X509_EXTENSION *ext,
@@ -114,8 +116,14 @@ int X509V3_EXT_print(BIO *out, const X509_EXTENSION *ext, unsigned long flag,
114116
if (method->it) {
115117
ext_str = ASN1_item_d2i(NULL, &p, ASN1_STRING_length(ext_data),
116118
ASN1_ITEM_ptr(method->it));
117-
} else {
119+
} else if (method->ext_nid == NID_id_pkix_OCSP_Nonce && method->d2i != NULL) {
120+
// |NID_id_pkix_OCSP_Nonce| is the only extension using the "old-style"
121+
// ASN.1 callbacks for backwards compatibility reasons.
122+
// Note: See |v3_ext_method| under "include/openssl/x509.h".
118123
ext_str = method->d2i(NULL, &p, ASN1_STRING_length(ext_data));
124+
} else {
125+
OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED);
126+
return 0;
119127
}
120128

121129
if (!ext_str) {
@@ -150,11 +158,7 @@ int X509V3_EXT_print(BIO *out, const X509_EXTENSION *ext, unsigned long flag,
150158
err:
151159
sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
152160
OPENSSL_free(value);
153-
if (method->it) {
154-
ASN1_item_free(ext_str, ASN1_ITEM_ptr(method->it));
155-
} else {
156-
method->ext_free(ext_str);
157-
}
161+
x509v3_ext_free_with_method(method, ext_str);
158162
return ok;
159163
}
160164

crypto/x509/x509_test.cc

+31
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,23 @@
4242
#include <thread>
4343
#endif
4444

45+
static const char kX509ExtensionsCert[] = R"(
46+
-----BEGIN CERTIFICATE-----
47+
MIICwDCCAimgAwIBAgIEAJNOazANBgkqhkiG9w0BAQEFADAQMQ4wDAYDVQQKEwVjYXNzYTAeFw0xMTAz
48+
MzAxMTEwMzZaFw0xNDAzMzAxNTQwMzZaMC0xDjAMBgNVBAoMBWNhc9ijMRswGQYDVQQDExJlbXMuZ3J1
49+
cG9jYXNzYdeckJIwgZ8wDQYJKoZIhvcNAQEJBQADgY0AMIGJAoGBAFUEB/i0583rnah0hLRk1hleI5T0
50+
xw+naVIxs/h4ZHu19xva671kvXfN97PZBmzAwFAWXmfs5MUrviy6RjZjhc0Ad2510cmqWy9FUx4D7kjy
51+
iuZZIaA0xL0AAfvJbDkXrGpHZWz8BkANFZ/RHl961BRB3fTGvPWiZK6C4mCwPgIDaQABjwGjggEIMIIB
52+
BDALBgNVHRAEBAMCBaAwKwYDVR0VBCQKCf8O1s/Ozk3MzM8xNTo7MzZaMIIBBDALBgNVHRAEBAMCBaAw
53+
KwYDVR0VBCQKCf8O1s/OKoUDBwExNTo7MzZagQ8BBDALBgNVHRAEBAMCBaAwKwYDVR0VBCQKAYPxKTDO
54+
zs3MzM8xNTo7MzZagQ8yMDEzMDAxMzAxKjUwNlowEQYJKwYBBQUHMAECBAQDAgEHMBEGCWCGSAGG+EJZ
55+
AQQEAwIGQDAbBgNVHQ0EFDASMBAGCSqGSIb2fQcQBAQDAgWgMCsGA1UdFQQkCiFD8Skwzs7NzMzPMTU6
56+
OzM2WoEPAQQwCwYDVR0QBAQDAgWgMA0GCSsGAQUFBzABBQUAA4GBAKTNw5fTOnPCcOFMARmAD1RtaAN8
57+
0TBKIy2A0hG/2dlNeI6s0dqZe6juverYmC5sOResakdlbPwGQA0Vn9EeX8Yr67/d9Ma89aJkroLiXbA+
58+
j2kCAwG+LLpGNmNwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBw5lmgITTEvXIj+8ls
59+
-----END CERTIFICATE-----
60+
)";
61+
4562

4663
std::string GetTestData(const char *path);
4764

@@ -1550,6 +1567,20 @@ static int Verify(
15501567
return X509_V_OK;
15511568
}
15521569

1570+
TEST(X509Test, X509Extensions) {
1571+
bssl::UniquePtr<X509> cert(CertFromPEM(kX509ExtensionsCert));
1572+
ASSERT_TRUE(cert);
1573+
1574+
for (int i = 0; i < X509_get_ext_count(cert.get()); i++) {
1575+
const X509_EXTENSION *ext = X509_get_ext(cert.get(), i);
1576+
void *parsed = X509V3_EXT_d2i(ext);
1577+
if (parsed != nullptr) {
1578+
int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
1579+
ASSERT_TRUE(X509V3_EXT_free(nid, parsed));
1580+
}
1581+
}
1582+
}
1583+
15531584
TEST(X509Test, TestVerify) {
15541585
// cross_signing_root
15551586
// |

0 commit comments

Comments
 (0)