diff options
author | tb <> | 2024-06-17 05:31:26 +0000 |
---|---|---|
committer | tb <> | 2024-06-17 05:31:26 +0000 |
commit | 1cce7a8778d5b86a020d7d0546bc2401506d5117 (patch) | |
tree | 528a222420b347d3261eacb9ebc8744a2aea9e43 /src | |
parent | 8d9a11036e953db2041151dae4ab5fd4c82a8608 (diff) | |
download | openbsd-1cce7a8778d5b86a020d7d0546bc2401506d5117.tar.gz openbsd-1cce7a8778d5b86a020d7d0546bc2401506d5117.tar.bz2 openbsd-1cce7a8778d5b86a020d7d0546bc2401506d5117.zip |
Rewrite X509V3_get_d2i()
This API is wrapped by nine *_get{,1}_ext_d2i() functions and they all
have the same defect: if an idx variable is passed in, multiple extensions
are handled incorrectly.
Clean up the mess that was the current implementation by replacing the
reimplementation of X509v3_get_ext_by_NID() with extra twists by actual
calls to the real thing. This way the madness is implemented explicitly
and can be explained in comments. The code still gets shorter.
In brief: always call this API with a known nid, pass crit, and a NULL idx.
If NULL is returned, crit != -1 is an error (malformed cert or allocation
failure).
ok jsing
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libcrypto/x509/x509_lib.c | 103 |
1 files changed, 47 insertions, 56 deletions
diff --git a/src/lib/libcrypto/x509/x509_lib.c b/src/lib/libcrypto/x509/x509_lib.c index 4347875885..161e638427 100644 --- a/src/lib/libcrypto/x509/x509_lib.c +++ b/src/lib/libcrypto/x509/x509_lib.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_lib.c,v 1.21 2024/05/28 15:40:38 tb Exp $ */ | 1 | /* $OpenBSD: x509_lib.c,v 1.22 2024/06/17 05:31:26 tb Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 1999. | 3 | * project 1999. |
4 | */ | 4 | */ |
@@ -178,69 +178,60 @@ X509V3_EXT_d2i(X509_EXTENSION *ext) | |||
178 | } | 178 | } |
179 | LCRYPTO_ALIAS(X509V3_EXT_d2i); | 179 | LCRYPTO_ALIAS(X509V3_EXT_d2i); |
180 | 180 | ||
181 | /* Get critical flag and decoded version of extension from a NID. | 181 | /* |
182 | * The "idx" variable returns the last found extension and can | 182 | * This API is only safe to call with known nid, crit != NULL and idx == NULL. |
183 | * be used to retrieve multiple extensions of the same NID. | 183 | * On NULL return, crit acts as a failure indicator: crit == -1 means an |
184 | * However multiple extensions with the same NID is usually | 184 | * extension of type nid was not present, crit != -1 is fatal: crit == -2 |
185 | * due to a badly encoded certificate so if idx is NULL we | 185 | * means multiple extensions of type nid are present; if crit is 0 or 1, this |
186 | * choke if multiple extensions exist. | 186 | * implies the extension was found but could not be decoded. |
187 | * The "crit" variable is set to the critical value. | ||
188 | * The return value is the decoded extension or NULL on | ||
189 | * error. The actual error can have several different causes, | ||
190 | * the value of *crit reflects the cause: | ||
191 | * >= 0, extension found but not decoded (reflects critical value). | ||
192 | * -1 extension not found. | ||
193 | * -2 extension occurs more than once. | ||
194 | */ | 187 | */ |
195 | 188 | ||
196 | void * | 189 | void * |
197 | X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx) | 190 | X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx) |
198 | { | 191 | { |
199 | int lastpos, i; | 192 | X509_EXTENSION *ext; |
200 | X509_EXTENSION *ex, *found_ex = NULL; | 193 | int lastpos = idx == NULL ? -1 : *idx; |
201 | 194 | ||
202 | if (!x) { | 195 | if (crit != NULL) |
203 | if (idx) | 196 | *crit = -1; |
204 | *idx = -1; | 197 | if (idx != NULL) |
205 | if (crit) | 198 | *idx = -1; |
206 | *crit = -1; | 199 | |
200 | /* | ||
201 | * Nothing to do if no extensions, unknown nid, or missing extension. | ||
202 | */ | ||
203 | |||
204 | if (x == NULL) | ||
205 | return NULL; | ||
206 | if ((lastpos = X509v3_get_ext_by_NID(x, nid, lastpos)) < 0) | ||
207 | return NULL; | ||
208 | if ((ext = X509v3_get_ext(x, lastpos)) == NULL) | ||
209 | return NULL; | ||
210 | |||
211 | /* | ||
212 | * API madness. Only check for a second extension of type nid if | ||
213 | * idx == NULL. Indicate this by setting *crit to -2. If idx != NULL, | ||
214 | * don't care and set *idx to the index of the first extension found. | ||
215 | */ | ||
216 | |||
217 | if (idx == NULL && X509v3_get_ext_by_NID(x, nid, lastpos) > 0) { | ||
218 | if (crit != NULL) | ||
219 | *crit = -2; | ||
207 | return NULL; | 220 | return NULL; |
208 | } | ||
209 | if (idx) | ||
210 | lastpos = *idx + 1; | ||
211 | else | ||
212 | lastpos = 0; | ||
213 | if (lastpos < 0) | ||
214 | lastpos = 0; | ||
215 | for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) { | ||
216 | ex = sk_X509_EXTENSION_value(x, i); | ||
217 | if (OBJ_obj2nid(ex->object) == nid) { | ||
218 | if (idx) { | ||
219 | *idx = i; | ||
220 | found_ex = ex; | ||
221 | break; | ||
222 | } else if (found_ex) { | ||
223 | /* Found more than one */ | ||
224 | if (crit) | ||
225 | *crit = -2; | ||
226 | return NULL; | ||
227 | } | ||
228 | found_ex = ex; | ||
229 | } | ||
230 | } | ||
231 | if (found_ex) { | ||
232 | /* Found it */ | ||
233 | if (crit) | ||
234 | *crit = X509_EXTENSION_get_critical(found_ex); | ||
235 | return X509V3_EXT_d2i(found_ex); | ||
236 | } | 221 | } |
237 | 222 | ||
238 | /* Extension not found */ | 223 | /* |
239 | if (idx) | 224 | * Another beautiful API detail: *crit will be set to 0 or 1, so if the |
240 | *idx = -1; | 225 | * extension fails to decode, we can deduce this from return value NULL |
241 | if (crit) | 226 | * and crit != -1. |
242 | *crit = -1; | 227 | */ |
243 | return NULL; | 228 | |
229 | if (crit != NULL) | ||
230 | *crit = X509_EXTENSION_get_critical(ext); | ||
231 | if (idx != NULL) | ||
232 | *idx = lastpos; | ||
233 | |||
234 | return X509V3_EXT_d2i(ext); | ||
244 | } | 235 | } |
245 | LCRYPTO_ALIAS(X509V3_get_d2i); | 236 | LCRYPTO_ALIAS(X509V3_get_d2i); |
246 | 237 | ||