diff options
author | tb <> | 2024-05-28 15:40:38 +0000 |
---|---|---|
committer | tb <> | 2024-05-28 15:40:38 +0000 |
commit | ce5b4803a36a06007a2dbe499a78a74f7e4ffd2d (patch) | |
tree | 58662c1e8cc9049aa5b0bb12bf13fe1494a5c9e5 /src/lib | |
parent | 3736b64da9b4f391ef4ec6e13fb42575c1766d50 (diff) | |
download | openbsd-ce5b4803a36a06007a2dbe499a78a74f7e4ffd2d.tar.gz openbsd-ce5b4803a36a06007a2dbe499a78a74f7e4ffd2d.tar.bz2 openbsd-ce5b4803a36a06007a2dbe499a78a74f7e4ffd2d.zip |
Clean up and fix X509V3_EXT_add1_i2d()
When looking at this code I noticed a few leaks. Fixing those leaks
was straightforward, but following the code was really hard.
This attempts to make the logic a bit clearer. In short, there are
6 mutually exclusive modes for this function (passed in the variable
aptly called flags). The default mode is to append the extension of
type nid and to error if such an extension already exists. Then there
are other modes with varying degree of madness.
The existing code didn't make X509V3_ADD_REPLACE explicit, which is
confusing. Operations 6-15 would all be treated like X509V3_ADD_REPLACE
due to the way the function was written. Handle the supported operations
via a switch and error for operations 6-15. This and the elimination
of leaks are the only changes of behavior, as validated by relatively
extensive test coverage.
ok jsing
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/x509/x509_lib.c | 146 |
1 files changed, 89 insertions, 57 deletions
diff --git a/src/lib/libcrypto/x509/x509_lib.c b/src/lib/libcrypto/x509/x509_lib.c index 578f55ec55..4347875885 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.20 2024/05/11 18:59:39 tb Exp $ */ | 1 | /* $OpenBSD: x509_lib.c,v 1.21 2024/05/28 15:40:38 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 | */ |
@@ -244,85 +244,117 @@ X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx) | |||
244 | } | 244 | } |
245 | LCRYPTO_ALIAS(X509V3_get_d2i); | 245 | LCRYPTO_ALIAS(X509V3_get_d2i); |
246 | 246 | ||
247 | /* This function is a general extension append, replace and delete utility. | ||
248 | * The precise operation is governed by the 'flags' value. The 'crit' and | ||
249 | * 'value' arguments (if relevant) are the extensions internal structure. | ||
250 | */ | ||
251 | |||
252 | int | 247 | int |
253 | X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, | 248 | X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, |
254 | int crit, unsigned long flags) | 249 | int crit, unsigned long flags) |
255 | { | 250 | { |
256 | int extidx = -1; | 251 | STACK_OF(X509_EXTENSION) *exts = *x; |
257 | int errcode; | 252 | X509_EXTENSION *ext = NULL; |
258 | X509_EXTENSION *ext, *extmp; | 253 | X509_EXTENSION *existing; |
259 | unsigned long ext_op = flags & X509V3_ADD_OP_MASK; | 254 | int extidx; |
260 | 255 | int errcode = 0; | |
261 | /* If appending we don't care if it exists, otherwise | 256 | int ret = 0; |
262 | * look for existing extension. | 257 | |
263 | */ | 258 | /* See if the extension already exists. */ |
264 | if (ext_op != X509V3_ADD_APPEND) | 259 | extidx = X509v3_get_ext_by_NID(*x, nid, -1); |
265 | extidx = X509v3_get_ext_by_NID(*x, nid, -1); | 260 | |
266 | 261 | switch (flags & X509V3_ADD_OP_MASK) { | |
267 | /* See if extension exists */ | 262 | case X509V3_ADD_DEFAULT: |
268 | if (extidx >= 0) { | 263 | /* If the extension exists, adding another one is an error. */ |
269 | /* If keep existing, nothing to do */ | 264 | if (extidx >= 0) { |
270 | if (ext_op == X509V3_ADD_KEEP_EXISTING) | ||
271 | return 1; | ||
272 | /* If default then its an error */ | ||
273 | if (ext_op == X509V3_ADD_DEFAULT) { | ||
274 | errcode = X509V3_R_EXTENSION_EXISTS; | 265 | errcode = X509V3_R_EXTENSION_EXISTS; |
275 | goto err; | 266 | goto err; |
276 | } | 267 | } |
277 | /* If delete, just delete it */ | 268 | break; |
278 | if (ext_op == X509V3_ADD_DELETE) { | 269 | case X509V3_ADD_APPEND: |
279 | if ((extmp = sk_X509_EXTENSION_delete(*x, extidx)) == NULL) | 270 | /* |
280 | return -1; | 271 | * XXX - Total misfeature. If the extension exists, appending |
281 | X509_EXTENSION_free(extmp); | 272 | * another one will invalidate the certificate. Unfortunately |
282 | return 1; | 273 | * things use this, in particular Viktor's DANE code. |
283 | } | ||
284 | } else { | ||
285 | /* If replace existing or delete, error since | ||
286 | * extension must exist | ||
287 | */ | 274 | */ |
288 | if ((ext_op == X509V3_ADD_REPLACE_EXISTING) || | 275 | /* Pretend the extension didn't exist and append the new one. */ |
289 | (ext_op == X509V3_ADD_DELETE)) { | 276 | extidx = -1; |
277 | break; | ||
278 | case X509V3_ADD_REPLACE: | ||
279 | /* Replace existing extension, otherwise append the new one. */ | ||
280 | break; | ||
281 | case X509V3_ADD_REPLACE_EXISTING: | ||
282 | /* Can't replace a non-existent extension. */ | ||
283 | if (extidx < 0) { | ||
290 | errcode = X509V3_R_EXTENSION_NOT_FOUND; | 284 | errcode = X509V3_R_EXTENSION_NOT_FOUND; |
291 | goto err; | 285 | goto err; |
292 | } | 286 | } |
287 | break; | ||
288 | case X509V3_ADD_KEEP_EXISTING: | ||
289 | /* If the extension exists, there's nothing to do. */ | ||
290 | if (extidx >= 0) | ||
291 | goto done; | ||
292 | break; | ||
293 | case X509V3_ADD_DELETE: | ||
294 | /* Can't delete a non-existent extension. */ | ||
295 | if (extidx < 0) { | ||
296 | errcode = X509V3_R_EXTENSION_NOT_FOUND; | ||
297 | goto err; | ||
298 | } | ||
299 | if ((existing = sk_X509_EXTENSION_delete(*x, extidx)) == NULL) { | ||
300 | ret = -1; | ||
301 | goto err; | ||
302 | } | ||
303 | X509_EXTENSION_free(existing); | ||
304 | existing = NULL; | ||
305 | goto done; | ||
306 | default: | ||
307 | errcode = X509V3_R_UNSUPPORTED_OPTION; /* XXX */ | ||
308 | ret = -1; | ||
309 | goto err; | ||
293 | } | 310 | } |
294 | 311 | ||
295 | /* If we get this far then we have to create an extension: | 312 | if ((ext = X509V3_EXT_i2d(nid, crit, value)) == NULL) { |
296 | * could have some flags for alternative encoding schemes... | ||
297 | */ | ||
298 | |||
299 | ext = X509V3_EXT_i2d(nid, crit, value); | ||
300 | |||
301 | if (!ext) { | ||
302 | X509V3error(X509V3_R_ERROR_CREATING_EXTENSION); | 313 | X509V3error(X509V3_R_ERROR_CREATING_EXTENSION); |
303 | return 0; | 314 | goto err; |
304 | } | 315 | } |
305 | 316 | ||
306 | /* If extension exists replace it.. */ | 317 | /* From here, errors are fatal. */ |
318 | ret = -1; | ||
319 | |||
320 | /* If extension exists, replace it. */ | ||
307 | if (extidx >= 0) { | 321 | if (extidx >= 0) { |
308 | extmp = sk_X509_EXTENSION_value(*x, extidx); | 322 | existing = sk_X509_EXTENSION_value(*x, extidx); |
309 | X509_EXTENSION_free(extmp); | 323 | X509_EXTENSION_free(existing); |
310 | if (!sk_X509_EXTENSION_set(*x, extidx, ext)) | 324 | existing = NULL; |
311 | return -1; | 325 | if (sk_X509_EXTENSION_set(*x, extidx, ext) == NULL) { |
312 | return 1; | 326 | /* |
327 | * XXX - Can't happen. If it did happen, |existing| is | ||
328 | * now a freed pointer. Nothing we can do here. | ||
329 | */ | ||
330 | goto err; | ||
331 | } | ||
332 | goto done; | ||
313 | } | 333 | } |
314 | 334 | ||
315 | if (!*x && !(*x = sk_X509_EXTENSION_new_null())) | 335 | if (exts == NULL) |
316 | return -1; | 336 | exts = sk_X509_EXTENSION_new_null(); |
317 | if (!sk_X509_EXTENSION_push(*x, ext)) | 337 | if (exts == NULL) |
318 | return -1; | 338 | goto err; |
339 | |||
340 | if (!sk_X509_EXTENSION_push(exts, ext)) | ||
341 | goto err; | ||
342 | ext = NULL; | ||
343 | |||
344 | *x = exts; | ||
319 | 345 | ||
346 | done: | ||
320 | return 1; | 347 | return 1; |
321 | 348 | ||
322 | err: | 349 | err: |
323 | if (!(flags & X509V3_ADD_SILENT)) | 350 | if ((flags & X509V3_ADD_SILENT) == 0 && errcode != 0) |
324 | X509V3error(errcode); | 351 | X509V3error(errcode); |
325 | return 0; | 352 | |
353 | if (exts != *x) | ||
354 | sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); | ||
355 | X509_EXTENSION_free(ext); | ||
356 | |||
357 | return ret; | ||
326 | } | 358 | } |
327 | LCRYPTO_ALIAS(X509V3_add1_i2d); | 359 | LCRYPTO_ALIAS(X509V3_add1_i2d); |
328 | 360 | ||