summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authortb <>2024-05-28 15:40:38 +0000
committertb <>2024-05-28 15:40:38 +0000
commitce5b4803a36a06007a2dbe499a78a74f7e4ffd2d (patch)
tree58662c1e8cc9049aa5b0bb12bf13fe1494a5c9e5 /src/lib
parent3736b64da9b4f391ef4ec6e13fb42575c1766d50 (diff)
downloadopenbsd-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.c146
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}
245LCRYPTO_ALIAS(X509V3_get_d2i); 245LCRYPTO_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
252int 247int
253X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, 248X509V3_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
322err: 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}
327LCRYPTO_ALIAS(X509V3_add1_i2d); 359LCRYPTO_ALIAS(X509V3_add1_i2d);
328 360