xref: /openbsd-src/regress/lib/libcrypto/x509/x509_extensions_test.c (revision f475ad27b09c6d0a71ec6c04c2d3bf6f36e667ce)
1 /*	$OpenBSD: x509_extensions_test.c,v 1.2 2024/05/28 15:42:09 tb Exp $ */
2 
3 /*
4  * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <err.h>
20 #include <stdio.h>
21 
22 #include <openssl/asn1.h>
23 #include <openssl/err.h>
24 #include <openssl/x509.h>
25 #include <openssl/x509v3.h>
26 
27 #define ASN1_BOOLEAN_TRUE	0xff
28 #define ASN1_BOOLEAN_FALSE	0x00
29 
30 static BASIC_CONSTRAINTS *
31 create_basic_constraints(int ca)
32 {
33 	BASIC_CONSTRAINTS *bc;
34 
35 	if ((bc = BASIC_CONSTRAINTS_new()) == NULL)
36 		errx(1, "BASIC_CONSTRAINTS_new");
37 
38 	bc->ca = ca ? ASN1_BOOLEAN_TRUE : ASN1_BOOLEAN_FALSE;
39 
40 	return bc;
41 }
42 
43 static int
44 test_x509v3_add1_i2d_empty_stack(STACK_OF(X509_EXTENSION) **extensions)
45 {
46 	unsigned long error;
47 	int op, got;
48 	int nid = NID_basic_constraints;
49 	int failed = 1;
50 
51 	if (X509v3_get_ext_count(*extensions) != 0) {
52 		fprintf(stderr, "%s: FAIL: need empty stack\n", __func__);
53 		goto err;
54 	}
55 
56 	ERR_clear_error();
57 
58 	op = X509V3_ADD_REPLACE_EXISTING;
59 
60 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
61 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
62 		    "want %d, got %d.\n", __func__, 0, got);
63 		goto err;
64 	}
65 
66 	error = ERR_get_error();
67 	if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_NOT_FOUND) {
68 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
69 		    "pushed %d for empty stack, want %d.\n", __func__,
70 		    ERR_GET_REASON(error), X509V3_R_EXTENSION_NOT_FOUND);
71 		goto err;
72 	}
73 	if ((error = ERR_get_error()) != 0) {
74 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
75 		    "expected exactly one error.\n", __func__);
76 		goto err;
77 	}
78 
79 	op = X509V3_ADD_REPLACE_EXISTING | X509V3_ADD_SILENT;
80 
81 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
82 		fprintf(stderr, "%s: FAIL: silent X509V3_ADD_REPLACE_EXISTING "
83 		    "want %d, got %d.\n", __func__, 0, got);
84 		goto err;
85 	}
86 	if ((error = ERR_get_error()) != 0) {
87 		fprintf(stderr, "%s: FAIL: silent X509V3_ADD_REPLACE_EXISTING "
88 		    "added error %d, want %d.\n", __func__,
89 		    ERR_GET_REASON(error), 0);
90 		goto err;
91 	}
92 
93 	op = X509V3_ADD_DELETE;
94 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
95 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
96 		    "want %d, got %d.\n", __func__, 0, got);
97 		goto err;
98 	}
99 
100 	error = ERR_get_error();
101 	if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_NOT_FOUND) {
102 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
103 		    "pushed %d for empty stack, want %d.\n", __func__,
104 		    ERR_GET_REASON(error), X509V3_R_EXTENSION_NOT_FOUND);
105 		goto err;
106 	}
107 
108 	if ((error = ERR_get_error()) != 0) {
109 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
110 		    "expected exactly one error.\n", __func__);
111 		goto err;
112 	}
113 
114 	failed = 0;
115 
116  err:
117 
118 	return failed;
119 }
120 
121 static int
122 test_x509v3_add1_i2d_single_nid(STACK_OF(X509_EXTENSION) **extensions)
123 {
124 	BASIC_CONSTRAINTS *bc = NULL;
125 	unsigned long error;
126 	int crit, got, nid, op;
127 	int failed = 1;
128 
129 	if (X509v3_get_ext_count(*extensions) != 0) {
130 		fprintf(stderr, "%s: FAIL: need an empty stack.\n", __func__);
131 		goto err;
132 	}
133 
134 	/*
135 	 * Add basic ca constraints.
136 	 */
137 
138 	nid = NID_basic_constraints;
139 	bc = create_basic_constraints(1);
140 	op = X509V3_ADD_DEFAULT;
141 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
142 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT failed to add "
143 		    "basic constraints to empty stack: want %d, got %d.\n",
144 		    __func__, 1, got);
145 		goto err;
146 	}
147 	BASIC_CONSTRAINTS_free(bc);
148 	bc = NULL;
149 
150 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
151 		fprintf(stderr, "%s: FAIL: expected 1 extension, have %d.\n",
152 		    __func__, got);
153 		goto err;
154 	}
155 
156 	/*
157 	 * Can't delete or replace non-existent extension.
158 	 */
159 
160 	nid = NID_policy_constraints;
161 	op = X509V3_ADD_DELETE;
162 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
163 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE non-existent "
164 		    "want %d, got %d,\n", __func__, 0, got);
165 		goto err;
166 	}
167 	nid = NID_policy_constraints;
168 	op = X509V3_ADD_REPLACE_EXISTING;
169 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
170 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING non-existent "
171 		    "want %d, got %d.\n", __func__, 0, got);
172 		goto err;
173 	}
174 
175 	/*
176 	 * X509V3_ADD_DEFAULT refuses to add second basic constraints extension.
177 	 */
178 
179 	ERR_clear_error();
180 
181 	nid = NID_basic_constraints;
182 	bc = create_basic_constraints(0);
183 	op = X509V3_ADD_DEFAULT;
184 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 0) {
185 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second constraints "
186 		    "want %d, got %d.\n", __func__, 0, got);
187 		goto err;
188 	}
189 	BASIC_CONSTRAINTS_free(bc);
190 	bc = NULL;
191 
192 	error = ERR_get_error();
193 	if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_EXISTS) {
194 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second constraints "
195 		    " pushed %d, want %d.\n", __func__,
196 		    ERR_GET_REASON(error), X509V3_R_EXTENSION_EXISTS);
197 		goto err;
198 	}
199 
200 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
201 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second contraints "
202 		    "expected 1 extension, have %d.\n", __func__, got);
203 		goto err;
204 	}
205 
206 	/*
207 	 * We can replace existing basic constraints using X509V3_ADD_REPLACE.
208 	 */
209 
210 	nid = NID_basic_constraints;
211 	bc = create_basic_constraints(0);
212 	op = X509V3_ADD_REPLACE;
213 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
214 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
215 		    "want %d, got %d.\n", __func__, 1, got);
216 		goto err;
217 	}
218 	BASIC_CONSTRAINTS_free(bc);
219 	bc = NULL;
220 
221 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
222 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
223 		    "expected 1 extension, have %d.\n", __func__, got);
224 		goto err;
225 	}
226 
227 	/* Check that the extension was actually replaced. */
228 	nid = NID_basic_constraints;
229 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) {
230 		if (crit != -1)
231 			errx(1, "X509V3_get_d2i");
232 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
233 		    "expected basic constraints\n", __func__);
234 		goto err;
235 	}
236 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
237 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
238 		    "expected cA = false in basic constraints\n", __func__);
239 		goto err;
240 	}
241 	BASIC_CONSTRAINTS_free(bc);
242 	bc = NULL;
243 
244 	/*
245 	 * X509V3_ADD_KEEP_EXISTING existing does what it is supposed to do
246 	 * if basic constraints are already present.
247 	 */
248 
249 	nid = NID_basic_constraints;
250 	bc = create_basic_constraints(1);
251 	op = X509V3_ADD_KEEP_EXISTING;
252 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
253 		fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING "
254 		    "want %d, got %d.\n", __func__, 1, got);
255 		goto err;
256 	}
257 	BASIC_CONSTRAINTS_free(bc);
258 	bc = NULL;
259 
260 	/*
261 	 * Check we still have non-ca basic constraints.
262 	 */
263 
264 	nid = NID_basic_constraints;
265 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) {
266 		if (crit != -1)
267 			errx(1, "X509V3_get_d2i");
268 		fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING "
269 		   "expected basic constraints\n", __func__);
270 		goto err;
271 	}
272 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
273 		fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING "
274 		   "expected non-ca basic constraints\n", __func__);
275 		goto err;
276 	}
277 	BASIC_CONSTRAINTS_free(bc);
278 	bc = NULL;
279 
280 	/*
281 	 * X509V3_ADD_REPLACE_EXISTING also works.
282 	 */
283 
284 	nid = NID_basic_constraints;
285 	bc = create_basic_constraints(1);
286 	op = X509V3_ADD_REPLACE_EXISTING;
287 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
288 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
289 		    "want %d, got %d.\n", __func__, 1, got);
290 		goto err;
291 	}
292 	BASIC_CONSTRAINTS_free(bc);
293 	bc = NULL;
294 
295 	/*
296 	 * Check we again have ca basic constraints.
297 	 */
298 
299 	nid = NID_basic_constraints;
300 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) {
301 		if (crit != -1)
302 			errx(1, "X509V3_get_d2i");
303 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
304 		   "expected basic constraints\n", __func__);
305 		goto err;
306 	}
307 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
308 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
309 		   "expected ca basic constraints\n", __func__);
310 		goto err;
311 	}
312 	BASIC_CONSTRAINTS_free(bc);
313 	bc = NULL;
314 
315 	/*
316 	 * And X509V3_ADD_DELETE now works.
317 	 */
318 
319 	nid = NID_basic_constraints;
320 	op = X509V3_ADD_DELETE;
321 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
322 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
323 		    "want %d, got %d.\n", __func__, 0, got);
324 		goto err;
325 	}
326 
327 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
328 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
329 		    "expected 0 extensions, have %d.\n", __func__, got);
330 		goto err;
331 	}
332 
333 	/*
334 	 * X509V3_ADD_REPLACE adds the extension to empty stack as it should.
335 	 */
336 
337 	nid = NID_basic_constraints;
338 	bc = create_basic_constraints(0);
339 	op = X509V3_ADD_REPLACE;
340 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
341 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE on empty stack "
342 		    "want %d, got %d.\n", __func__, 1, got);
343 		goto err;
344 	}
345 	BASIC_CONSTRAINTS_free(bc);
346 	bc = NULL;
347 
348 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
349 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
350 		    "expected 1 extension, have %d.\n", __func__, got);
351 		goto err;
352 	}
353 
354 	/*
355 	 * And X509V3_ADD_DELETE works again.
356 	 */
357 
358 	nid = NID_basic_constraints;
359 	op = X509V3_ADD_DELETE;
360 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
361 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE after add replace "
362 		    "want %d, got %d.\n", __func__, 0, got);
363 		goto err;
364 	}
365 
366 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
367 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
368 		    "expected 0 extensions, have %d.\n", __func__, got);
369 		goto err;
370 	}
371 
372 	failed = 0;
373 
374  err:
375 	BASIC_CONSTRAINTS_free(bc);
376 
377 	return failed;
378 }
379 
380 static int
381 test_x509v3_add1_i2d_add_append(STACK_OF(X509_EXTENSION) **extensions)
382 {
383 	BASIC_CONSTRAINTS *bc = NULL;
384 	int crit, got, idx, nid, op;
385 	int failed = 1;
386 
387 	if (X509v3_get_ext_count(*extensions) != 0) {
388 		fprintf(stderr, "%s: FAIL: need empty stack.\n", __func__);
389 		goto err;
390 	}
391 
392 	/*
393 	 * Let the toolkit add two basic constraints extensions.
394 	 */
395 
396 	nid = NID_basic_constraints;
397 	bc = create_basic_constraints(1);
398 	crit = 1;
399 	op = X509V3_ADD_APPEND;
400 	if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) {
401 		fprintf(stderr, "%s: FAIL: first X509V3_ADD_APPEND "
402 		    "want %d, got %d.\n", __func__, 0, got);
403 		goto err;
404 	}
405 	BASIC_CONSTRAINTS_free(bc);
406 	bc = NULL;
407 
408 	nid = NID_basic_constraints;
409 	bc = create_basic_constraints(0);
410 	crit = 1;
411 	op = X509V3_ADD_APPEND;
412 	if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) {
413 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
414 		    "want %d, got %d.\n", __func__, 0, got);
415 		goto err;
416 	}
417 	BASIC_CONSTRAINTS_free(bc);
418 	bc = NULL;
419 
420 	if ((got = X509v3_get_ext_count(*extensions)) != 2) {
421 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
422 		    "expected 2 extensions, have %d.\n", __func__, got);
423 		goto err;
424 	}
425 
426 	/*
427 	 * Inspect the extensions on the stack. First we should get the one
428 	 * with the ca bit set and it should be critical.
429 	 */
430 
431 	nid = NID_basic_constraints;
432 	idx = -1;
433 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
434 		fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND "
435 		    "expected basic constraints.\n", __func__);
436 		goto err;
437 	}
438 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
439 		fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND "
440 		    "expected ca basic constraints.\n", __func__);
441 		goto err;
442 	}
443 	if (crit != 1) {
444 		fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND "
445 		    "expected critical basic constraints.\n", __func__);
446 		goto err;
447 	}
448 	BASIC_CONSTRAINTS_free(bc);
449 	bc = NULL;
450 
451 	/* Redo the exercise and get the basic constraints with ca bit unset. */
452 	nid = NID_basic_constraints;
453 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
454 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
455 		    "expected basic constraints.\n", __func__);
456 		goto err;
457 	}
458 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
459 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
460 		    "expected basic constraints to be non-ca.\n", __func__);
461 		goto err;
462 	}
463 	if (crit != 1) {
464 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
465 		    "expected critical basic constraints.\n", __func__);
466 		goto err;
467 	}
468 	BASIC_CONSTRAINTS_free(bc);
469 	bc = NULL;
470 
471 	/*
472 	 * Now X509V3_ADD_REPLACE non-critical ca constraints. They should
473 	 * replace the critical ca constraints we added before.
474 	 */
475 
476 	nid = NID_basic_constraints;
477 	bc = create_basic_constraints(1);
478 	crit = 0;
479 	op = X509V3_ADD_REPLACE;
480 	if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) {
481 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
482 		    "want %d, got %d\n", __func__, 1, got);
483 		goto err;
484 	}
485 	BASIC_CONSTRAINTS_free(bc);
486 	bc = NULL;
487 
488 	/*
489 	 * If we get basic constraints now, we get the non-critical one with the
490 	 * ca bit set.
491 	 */
492 
493 	nid = NID_basic_constraints;
494 	idx = -1;
495 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
496 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
497 		    "expected basic constraints.\n", __func__);
498 		goto err;
499 	}
500 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
501 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
502 		    "expected ca basic constraints.\n", __func__);
503 		goto err;
504 	}
505 	if (crit != 0) {
506 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
507 		    "expected non-critical basic constraints.\n", __func__);
508 		goto err;
509 	}
510 	BASIC_CONSTRAINTS_free(bc);
511 	bc = NULL;
512 
513 	if ((got = X509v3_get_ext_count(*extensions)) != 2) {
514 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
515 		    "expected 2 extensions, got %d.\n", __func__, got);
516 		goto err;
517 	}
518 
519 	nid = NID_basic_constraints;
520 	op = X509V3_ADD_DELETE;
521 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
522 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
523 		    "want %d, got %d\n", __func__, 1, got);
524 		goto err;
525 	}
526 
527 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
528 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
529 		    "expected 1 extension, got %d.\n", __func__, got);
530 		goto err;
531 	}
532 
533 	/* The last deletion will have left the critical non-ca constraints. */
534 	nid = NID_basic_constraints;
535 	idx = -1;
536 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
537 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
538 		    "expected basic constraints.\n", __func__);
539 		goto err;
540 	}
541 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
542 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
543 		    "expected ca basic constraints.\n", __func__);
544 		goto err;
545 	}
546 	if (crit != 1) {
547 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
548 		    "expected critical basic constraints.\n", __func__);
549 		goto err;
550 	}
551 	BASIC_CONSTRAINTS_free(bc);
552 	bc = NULL;
553 
554 	/* Now delete the last extension. */
555 	nid = NID_basic_constraints;
556 	op = X509V3_ADD_DELETE;
557 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
558 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_DELETE "
559 		    "want %d, got %d\n", __func__, 1, got);
560 		goto err;
561 	}
562 
563 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
564 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_DELETE "
565 		    "expected 0 extensions, got %d.\n", __func__, got);
566 		goto err;
567 	}
568 
569 	failed = 0;
570 
571  err:
572 	BASIC_CONSTRAINTS_free(bc);
573 
574 	return failed;
575 }
576 
577 static int
578 test_x509v3_add1_i2d_invalid_operations(STACK_OF(X509_EXTENSION) **extensions)
579 {
580 	BASIC_CONSTRAINTS *bc = NULL;
581 	long error;
582 	int crit, got, nid, op;
583 	int failed = 1;
584 
585 	if (X509v3_get_ext_count(*extensions) != 0) {
586 		fprintf(stderr, "%s: FAIL: need empty stack.\n", __func__);
587 		goto err;
588 	}
589 
590 	/*
591 	 * Attempt to add a basic constraint extension with invalid operations
592 	 */
593 
594 	nid = NID_basic_constraints;
595 	bc = create_basic_constraints(1);
596 	crit = 1;
597 	for (op = X509V3_ADD_DELETE + 1; op <= X509V3_ADD_OP_MASK; op++) {
598 		if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != -1) {
599 			fprintf(stderr, "%s: FAIL: operation %d "
600 			    "want %d, got %d.\n", __func__, op, -1, got);
601 			goto err;
602 		}
603 		error = ERR_get_error();
604 		if (ERR_GET_REASON(error) != X509V3_R_UNSUPPORTED_OPTION) {
605 			fprintf(stderr, "%s: FAIL: invalid operation %d "
606 			    " pushed %d, want %d.\n", __func__, op,
607 			    ERR_GET_REASON(error), X509V3_R_EXTENSION_EXISTS);
608 			goto err;
609 		}
610 	}
611 	BASIC_CONSTRAINTS_free(bc);
612 	bc = NULL;
613 
614 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
615 		fprintf(stderr, "%s: FAIL: expected 0 extensions, have %d.\n",
616 		    __func__, got);
617 		goto err;
618 	}
619 
620 	failed = 0;
621 
622  err:
623 	BASIC_CONSTRAINTS_free(bc);
624 
625 	return failed;
626 }
627 
628 static int
629 test_x509v3_add1_i2d(void)
630 {
631 	STACK_OF(X509_EXTENSION) *extensions;
632 	int failed = 0;
633 
634 	if ((extensions = sk_X509_EXTENSION_new_null()) == NULL)
635 		errx(1, "sk_X509_EXTENSION_new_null");
636 
637 	failed |= test_x509v3_add1_i2d_empty_stack(&extensions);
638 	failed |= test_x509v3_add1_i2d_single_nid(&extensions);
639 	failed |= test_x509v3_add1_i2d_add_append(&extensions);
640 	failed |= test_x509v3_add1_i2d_invalid_operations(&extensions);
641 
642 	sk_X509_EXTENSION_pop_free(extensions, X509_EXTENSION_free);
643 
644 	return failed;
645 }
646 
647 int
648 main(void)
649 {
650 	int failed = 0;
651 
652 	failed |= test_x509v3_add1_i2d();
653 
654 	return failed;
655 }
656