1 /*	$OpenBSD: x509_extensions_test.c,v 1.3 2024/06/17 05:04:54 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 #define X509V3_EXT_CRITICAL	1
31 #define X509V3_EXT_NONCRITICAL	0
32 
33 static BASIC_CONSTRAINTS *
34 create_basic_constraints(int ca)
35 {
36 	BASIC_CONSTRAINTS *bc;
37 
38 	if ((bc = BASIC_CONSTRAINTS_new()) == NULL)
39 		errx(1, "BASIC_CONSTRAINTS_new");
40 
41 	bc->ca = ca ? ASN1_BOOLEAN_TRUE : ASN1_BOOLEAN_FALSE;
42 
43 	return bc;
44 }
45 
46 static X509_EXTENSION *
47 ext_create_basic_constraints(int ca, int critical)
48 {
49 	X509_EXTENSION *ext;
50 	BASIC_CONSTRAINTS *bc;
51 
52 	bc = create_basic_constraints(ca);
53 	if ((ext = X509V3_EXT_i2d(NID_basic_constraints, critical, bc)) == NULL)
54 		errx(1, "X509V3_EXT_i2d");
55 	BASIC_CONSTRAINTS_free(bc);
56 
57 	return ext;
58 }
59 
60 static int
61 test_x509v3_add1_i2d_empty_stack(STACK_OF(X509_EXTENSION) **extensions)
62 {
63 	unsigned long error;
64 	int op, got;
65 	int nid = NID_basic_constraints;
66 	int failed = 1;
67 
68 	if (X509v3_get_ext_count(*extensions) != 0) {
69 		fprintf(stderr, "%s: FAIL: need empty stack\n", __func__);
70 		goto err;
71 	}
72 
73 	ERR_clear_error();
74 
75 	op = X509V3_ADD_REPLACE_EXISTING;
76 
77 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
78 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
79 		    "want %d, got %d.\n", __func__, 0, got);
80 		goto err;
81 	}
82 
83 	error = ERR_get_error();
84 	if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_NOT_FOUND) {
85 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
86 		    "pushed %d for empty stack, want %d.\n", __func__,
87 		    ERR_GET_REASON(error), X509V3_R_EXTENSION_NOT_FOUND);
88 		goto err;
89 	}
90 	if ((error = ERR_get_error()) != 0) {
91 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
92 		    "expected exactly one error.\n", __func__);
93 		goto err;
94 	}
95 
96 	op = X509V3_ADD_REPLACE_EXISTING | X509V3_ADD_SILENT;
97 
98 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
99 		fprintf(stderr, "%s: FAIL: silent X509V3_ADD_REPLACE_EXISTING "
100 		    "want %d, got %d.\n", __func__, 0, got);
101 		goto err;
102 	}
103 	if ((error = ERR_get_error()) != 0) {
104 		fprintf(stderr, "%s: FAIL: silent X509V3_ADD_REPLACE_EXISTING "
105 		    "added error %d, want %d.\n", __func__,
106 		    ERR_GET_REASON(error), 0);
107 		goto err;
108 	}
109 
110 	op = X509V3_ADD_DELETE;
111 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
112 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
113 		    "want %d, got %d.\n", __func__, 0, got);
114 		goto err;
115 	}
116 
117 	error = ERR_get_error();
118 	if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_NOT_FOUND) {
119 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
120 		    "pushed %d for empty stack, want %d.\n", __func__,
121 		    ERR_GET_REASON(error), X509V3_R_EXTENSION_NOT_FOUND);
122 		goto err;
123 	}
124 
125 	if ((error = ERR_get_error()) != 0) {
126 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
127 		    "expected exactly one error.\n", __func__);
128 		goto err;
129 	}
130 
131 	failed = 0;
132 
133  err:
134 
135 	return failed;
136 }
137 
138 static int
139 test_x509v3_add1_i2d_single_nid(STACK_OF(X509_EXTENSION) **extensions)
140 {
141 	BASIC_CONSTRAINTS *bc = NULL;
142 	unsigned long error;
143 	int crit, got, nid, op;
144 	int failed = 1;
145 
146 	if (X509v3_get_ext_count(*extensions) != 0) {
147 		fprintf(stderr, "%s: FAIL: need an empty stack.\n", __func__);
148 		goto err;
149 	}
150 
151 	/*
152 	 * Add basic ca constraints.
153 	 */
154 
155 	nid = NID_basic_constraints;
156 	bc = create_basic_constraints(1);
157 	op = X509V3_ADD_DEFAULT;
158 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
159 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT failed to add "
160 		    "basic constraints to empty stack: want %d, got %d.\n",
161 		    __func__, 1, got);
162 		goto err;
163 	}
164 	BASIC_CONSTRAINTS_free(bc);
165 	bc = NULL;
166 
167 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
168 		fprintf(stderr, "%s: FAIL: expected 1 extension, have %d.\n",
169 		    __func__, got);
170 		goto err;
171 	}
172 
173 	/*
174 	 * Can't delete or replace non-existent extension.
175 	 */
176 
177 	nid = NID_policy_constraints;
178 	op = X509V3_ADD_DELETE;
179 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
180 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE non-existent "
181 		    "want %d, got %d,\n", __func__, 0, got);
182 		goto err;
183 	}
184 	nid = NID_policy_constraints;
185 	op = X509V3_ADD_REPLACE_EXISTING;
186 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) {
187 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING non-existent "
188 		    "want %d, got %d.\n", __func__, 0, got);
189 		goto err;
190 	}
191 
192 	/*
193 	 * X509V3_ADD_DEFAULT refuses to add second basic constraints extension.
194 	 */
195 
196 	ERR_clear_error();
197 
198 	nid = NID_basic_constraints;
199 	bc = create_basic_constraints(0);
200 	op = X509V3_ADD_DEFAULT;
201 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 0) {
202 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second constraints "
203 		    "want %d, got %d.\n", __func__, 0, got);
204 		goto err;
205 	}
206 	BASIC_CONSTRAINTS_free(bc);
207 	bc = NULL;
208 
209 	error = ERR_get_error();
210 	if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_EXISTS) {
211 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second constraints "
212 		    " pushed %d, want %d.\n", __func__,
213 		    ERR_GET_REASON(error), X509V3_R_EXTENSION_EXISTS);
214 		goto err;
215 	}
216 
217 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
218 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second contraints "
219 		    "expected 1 extension, have %d.\n", __func__, got);
220 		goto err;
221 	}
222 
223 	/*
224 	 * We can replace existing basic constraints using X509V3_ADD_REPLACE.
225 	 */
226 
227 	nid = NID_basic_constraints;
228 	bc = create_basic_constraints(0);
229 	op = X509V3_ADD_REPLACE;
230 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
231 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
232 		    "want %d, got %d.\n", __func__, 1, got);
233 		goto err;
234 	}
235 	BASIC_CONSTRAINTS_free(bc);
236 	bc = NULL;
237 
238 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
239 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
240 		    "expected 1 extension, have %d.\n", __func__, got);
241 		goto err;
242 	}
243 
244 	/* Check that the extension was actually replaced. */
245 	nid = NID_basic_constraints;
246 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) {
247 		if (crit != -1)
248 			errx(1, "X509V3_get_d2i");
249 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
250 		    "expected basic constraints\n", __func__);
251 		goto err;
252 	}
253 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
254 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
255 		    "expected cA = false in basic constraints\n", __func__);
256 		goto err;
257 	}
258 	BASIC_CONSTRAINTS_free(bc);
259 	bc = NULL;
260 
261 	/*
262 	 * X509V3_ADD_KEEP_EXISTING existing does what it is supposed to do
263 	 * if basic constraints are already present.
264 	 */
265 
266 	nid = NID_basic_constraints;
267 	bc = create_basic_constraints(1);
268 	op = X509V3_ADD_KEEP_EXISTING;
269 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
270 		fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING "
271 		    "want %d, got %d.\n", __func__, 1, got);
272 		goto err;
273 	}
274 	BASIC_CONSTRAINTS_free(bc);
275 	bc = NULL;
276 
277 	/*
278 	 * Check we still have non-ca basic constraints.
279 	 */
280 
281 	nid = NID_basic_constraints;
282 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) {
283 		if (crit != -1)
284 			errx(1, "X509V3_get_d2i");
285 		fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING "
286 		   "expected basic constraints\n", __func__);
287 		goto err;
288 	}
289 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
290 		fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING "
291 		   "expected non-ca basic constraints\n", __func__);
292 		goto err;
293 	}
294 	BASIC_CONSTRAINTS_free(bc);
295 	bc = NULL;
296 
297 	/*
298 	 * X509V3_ADD_REPLACE_EXISTING also works.
299 	 */
300 
301 	nid = NID_basic_constraints;
302 	bc = create_basic_constraints(1);
303 	op = X509V3_ADD_REPLACE_EXISTING;
304 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
305 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
306 		    "want %d, got %d.\n", __func__, 1, got);
307 		goto err;
308 	}
309 	BASIC_CONSTRAINTS_free(bc);
310 	bc = NULL;
311 
312 	/*
313 	 * Check we again have ca basic constraints.
314 	 */
315 
316 	nid = NID_basic_constraints;
317 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) {
318 		if (crit != -1)
319 			errx(1, "X509V3_get_d2i");
320 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
321 		   "expected basic constraints\n", __func__);
322 		goto err;
323 	}
324 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
325 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING "
326 		   "expected ca basic constraints\n", __func__);
327 		goto err;
328 	}
329 	BASIC_CONSTRAINTS_free(bc);
330 	bc = NULL;
331 
332 	/*
333 	 * And X509V3_ADD_DELETE now works.
334 	 */
335 
336 	nid = NID_basic_constraints;
337 	op = X509V3_ADD_DELETE;
338 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
339 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
340 		    "want %d, got %d.\n", __func__, 0, got);
341 		goto err;
342 	}
343 
344 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
345 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
346 		    "expected 0 extensions, have %d.\n", __func__, got);
347 		goto err;
348 	}
349 
350 	/*
351 	 * X509V3_ADD_REPLACE adds the extension to empty stack as it should.
352 	 */
353 
354 	nid = NID_basic_constraints;
355 	bc = create_basic_constraints(0);
356 	op = X509V3_ADD_REPLACE;
357 	if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) {
358 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE on empty stack "
359 		    "want %d, got %d.\n", __func__, 1, got);
360 		goto err;
361 	}
362 	BASIC_CONSTRAINTS_free(bc);
363 	bc = NULL;
364 
365 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
366 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
367 		    "expected 1 extension, have %d.\n", __func__, got);
368 		goto err;
369 	}
370 
371 	/*
372 	 * And X509V3_ADD_DELETE works again.
373 	 */
374 
375 	nid = NID_basic_constraints;
376 	op = X509V3_ADD_DELETE;
377 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
378 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE after add replace "
379 		    "want %d, got %d.\n", __func__, 0, got);
380 		goto err;
381 	}
382 
383 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
384 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
385 		    "expected 0 extensions, have %d.\n", __func__, got);
386 		goto err;
387 	}
388 
389 	failed = 0;
390 
391  err:
392 	BASIC_CONSTRAINTS_free(bc);
393 
394 	return failed;
395 }
396 
397 static int
398 test_x509v3_add1_i2d_add_append(STACK_OF(X509_EXTENSION) **extensions)
399 {
400 	BASIC_CONSTRAINTS *bc = NULL;
401 	int crit, got, idx, nid, op;
402 	int failed = 1;
403 
404 	if (X509v3_get_ext_count(*extensions) != 0) {
405 		fprintf(stderr, "%s: FAIL: need empty stack.\n", __func__);
406 		goto err;
407 	}
408 
409 	/*
410 	 * Let the toolkit add two basic constraints extensions.
411 	 */
412 
413 	nid = NID_basic_constraints;
414 	bc = create_basic_constraints(1);
415 	crit = 1;
416 	op = X509V3_ADD_APPEND;
417 	if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) {
418 		fprintf(stderr, "%s: FAIL: first X509V3_ADD_APPEND "
419 		    "want %d, got %d.\n", __func__, 0, got);
420 		goto err;
421 	}
422 	BASIC_CONSTRAINTS_free(bc);
423 	bc = NULL;
424 
425 	nid = NID_basic_constraints;
426 	bc = create_basic_constraints(0);
427 	crit = 1;
428 	op = X509V3_ADD_APPEND;
429 	if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) {
430 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
431 		    "want %d, got %d.\n", __func__, 0, got);
432 		goto err;
433 	}
434 	BASIC_CONSTRAINTS_free(bc);
435 	bc = NULL;
436 
437 	if ((got = X509v3_get_ext_count(*extensions)) != 2) {
438 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
439 		    "expected 2 extensions, have %d.\n", __func__, got);
440 		goto err;
441 	}
442 
443 	/*
444 	 * Inspect the extensions on the stack. First we should get the one
445 	 * with the ca bit set and it should be critical.
446 	 */
447 
448 	nid = NID_basic_constraints;
449 	idx = -1;
450 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
451 		fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND "
452 		    "expected basic constraints.\n", __func__);
453 		goto err;
454 	}
455 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
456 		fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND "
457 		    "expected ca basic constraints.\n", __func__);
458 		goto err;
459 	}
460 	if (crit != 1) {
461 		fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND "
462 		    "expected critical basic constraints.\n", __func__);
463 		goto err;
464 	}
465 	BASIC_CONSTRAINTS_free(bc);
466 	bc = NULL;
467 
468 	/* Redo the exercise and get the basic constraints with ca bit unset. */
469 	nid = NID_basic_constraints;
470 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
471 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
472 		    "expected basic constraints.\n", __func__);
473 		goto err;
474 	}
475 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
476 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
477 		    "expected basic constraints to be non-ca.\n", __func__);
478 		goto err;
479 	}
480 	if (crit != 1) {
481 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND "
482 		    "expected critical basic constraints.\n", __func__);
483 		goto err;
484 	}
485 	BASIC_CONSTRAINTS_free(bc);
486 	bc = NULL;
487 
488 	/*
489 	 * Now X509V3_ADD_REPLACE non-critical ca constraints. They should
490 	 * replace the critical ca constraints we added before.
491 	 */
492 
493 	nid = NID_basic_constraints;
494 	bc = create_basic_constraints(1);
495 	crit = 0;
496 	op = X509V3_ADD_REPLACE;
497 	if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) {
498 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
499 		    "want %d, got %d\n", __func__, 1, got);
500 		goto err;
501 	}
502 	BASIC_CONSTRAINTS_free(bc);
503 	bc = NULL;
504 
505 	/*
506 	 * If we get basic constraints now, we get the non-critical one with the
507 	 * ca bit set.
508 	 */
509 
510 	nid = NID_basic_constraints;
511 	idx = -1;
512 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
513 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
514 		    "expected basic constraints.\n", __func__);
515 		goto err;
516 	}
517 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
518 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
519 		    "expected ca basic constraints.\n", __func__);
520 		goto err;
521 	}
522 	if (crit != 0) {
523 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
524 		    "expected non-critical basic constraints.\n", __func__);
525 		goto err;
526 	}
527 	BASIC_CONSTRAINTS_free(bc);
528 	bc = NULL;
529 
530 	if ((got = X509v3_get_ext_count(*extensions)) != 2) {
531 		fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE "
532 		    "expected 2 extensions, got %d.\n", __func__, got);
533 		goto err;
534 	}
535 
536 	nid = NID_basic_constraints;
537 	op = X509V3_ADD_DELETE;
538 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
539 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
540 		    "want %d, got %d\n", __func__, 1, got);
541 		goto err;
542 	}
543 
544 	if ((got = X509v3_get_ext_count(*extensions)) != 1) {
545 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
546 		    "expected 1 extension, got %d.\n", __func__, got);
547 		goto err;
548 	}
549 
550 	/* The last deletion will have left the critical non-ca constraints. */
551 	nid = NID_basic_constraints;
552 	idx = -1;
553 	if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) {
554 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
555 		    "expected basic constraints.\n", __func__);
556 		goto err;
557 	}
558 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
559 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
560 		    "expected ca basic constraints.\n", __func__);
561 		goto err;
562 	}
563 	if (crit != 1) {
564 		fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE "
565 		    "expected critical basic constraints.\n", __func__);
566 		goto err;
567 	}
568 	BASIC_CONSTRAINTS_free(bc);
569 	bc = NULL;
570 
571 	/* Now delete the last extension. */
572 	nid = NID_basic_constraints;
573 	op = X509V3_ADD_DELETE;
574 	if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) {
575 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_DELETE "
576 		    "want %d, got %d\n", __func__, 1, got);
577 		goto err;
578 	}
579 
580 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
581 		fprintf(stderr, "%s: FAIL: second X509V3_ADD_DELETE "
582 		    "expected 0 extensions, got %d.\n", __func__, got);
583 		goto err;
584 	}
585 
586 	failed = 0;
587 
588  err:
589 	BASIC_CONSTRAINTS_free(bc);
590 
591 	return failed;
592 }
593 
594 static int
595 test_x509v3_add1_i2d_invalid_operations(STACK_OF(X509_EXTENSION) **extensions)
596 {
597 	BASIC_CONSTRAINTS *bc = NULL;
598 	long error;
599 	int crit, got, nid, op;
600 	int failed = 1;
601 
602 	if (X509v3_get_ext_count(*extensions) != 0) {
603 		fprintf(stderr, "%s: FAIL: need empty stack.\n", __func__);
604 		goto err;
605 	}
606 
607 	/*
608 	 * Attempt to add a basic constraint extension with invalid operations
609 	 */
610 
611 	nid = NID_basic_constraints;
612 	bc = create_basic_constraints(1);
613 	crit = 1;
614 	for (op = X509V3_ADD_DELETE + 1; op <= X509V3_ADD_OP_MASK; op++) {
615 		if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != -1) {
616 			fprintf(stderr, "%s: FAIL: operation %d "
617 			    "want %d, got %d.\n", __func__, op, -1, got);
618 			goto err;
619 		}
620 		error = ERR_get_error();
621 		if (ERR_GET_REASON(error) != X509V3_R_UNSUPPORTED_OPTION) {
622 			fprintf(stderr, "%s: FAIL: invalid operation %d "
623 			    " pushed %d, want %d.\n", __func__, op,
624 			    ERR_GET_REASON(error), X509V3_R_EXTENSION_EXISTS);
625 			goto err;
626 		}
627 	}
628 	BASIC_CONSTRAINTS_free(bc);
629 	bc = NULL;
630 
631 	if ((got = X509v3_get_ext_count(*extensions)) != 0) {
632 		fprintf(stderr, "%s: FAIL: expected 0 extensions, have %d.\n",
633 		    __func__, got);
634 		goto err;
635 	}
636 
637 	failed = 0;
638 
639  err:
640 	BASIC_CONSTRAINTS_free(bc);
641 
642 	return failed;
643 }
644 
645 static int
646 test_x509v3_add1_i2d(void)
647 {
648 	STACK_OF(X509_EXTENSION) *extensions;
649 	int failed = 0;
650 
651 	if ((extensions = sk_X509_EXTENSION_new_null()) == NULL)
652 		errx(1, "sk_X509_EXTENSION_new_null");
653 
654 	failed |= test_x509v3_add1_i2d_empty_stack(&extensions);
655 	failed |= test_x509v3_add1_i2d_single_nid(&extensions);
656 	failed |= test_x509v3_add1_i2d_add_append(&extensions);
657 	failed |= test_x509v3_add1_i2d_invalid_operations(&extensions);
658 
659 	sk_X509_EXTENSION_pop_free(extensions, X509_EXTENSION_free);
660 
661 	return failed;
662 }
663 
664 static int
665 test_x509v3_get_d2i_null(void)
666 {
667 	X509_EXTENSION *ext;
668 	int crit, idx;
669 	int failed = 1;
670 
671 	if ((ext = X509V3_get_d2i(NULL, NID_undef, NULL, NULL)) != NULL) {
672 		fprintf(stderr, "FAIL: %s: expected X509V3_get_d2i with three "
673 		    "NULL arguments to return NULL\n", __func__);
674 		goto err;
675 	}
676 
677 	idx = -5;
678 	if (X509V3_get_d2i(NULL, NID_undef, &crit, &idx) != NULL) {
679 		/* Leaks whatever garbage libcrypto decoded. What to do... */
680 		fprintf(stderr, "FAIL: %s: expected X509V3_get_d2i NULL stack"
681 		    "to return NULL\n", __func__);
682 		goto err;
683 	}
684 
685 	if (crit != -1 || idx != -1) {
686 		fprintf(stderr, "FAIL: %s: crit: want: %d, got: %d; "
687 		    "idx: want: %d, got: %d\n", __func__, -1, crit, -1, idx);
688 		goto err;
689 	}
690 
691 	failed = 0;
692 
693  err:
694 	X509_EXTENSION_free(ext);
695 
696 	return failed;
697 }
698 
699 static int
700 test_x509v3_get_d2i_multiple_basic_constraints(void)
701 {
702 	STACK_OF(X509_EXTENSION) *exts = NULL;
703 	ASN1_BIT_STRING *abs = NULL;
704 	BASIC_CONSTRAINTS *bc = NULL;
705 	X509_EXTENSION *ext;
706 	int crit, idx;
707 	int ca, nid;
708 	int failed = 1;
709 
710 	/*
711 	 * Create extension stack containing three basic constraints extensions:
712 	 * 1. critical CA basic constraints,
713 	 * 2. non-critical CA basic constraints,
714 	 * 3. critical non-CA basic constraints.
715 	 */
716 
717 	if ((exts = sk_X509_EXTENSION_new_null()) == NULL)
718 		errx(1, "sk_X509_EXTENSION_new_null");
719 
720 	ca = 1;
721 	ext = ext_create_basic_constraints(ca, X509V3_EXT_CRITICAL);
722 
723 	if (sk_X509_EXTENSION_push(exts, ext) <= 0)
724 		errx(1, "sk_X509_EXTENSION_push");
725 	ext = NULL;
726 
727 	ca = 1;
728 	ext = ext_create_basic_constraints(ca, X509V3_EXT_NONCRITICAL);
729 
730 	if (sk_X509_EXTENSION_push(exts, ext) <= 0)
731 		errx(1, "sk_X509_EXTENSION_push");
732 	ext = NULL;
733 
734 	ca = 0;
735 	ext = ext_create_basic_constraints(ca, X509V3_EXT_CRITICAL);
736 
737 	if (sk_X509_EXTENSION_push(exts, ext) <= 0)
738 		errx(1, "sk_X509_EXTENSION_push");
739 	ext = NULL;
740 
741 	/*
742 	 * There is no key usage in this stack, so we shouldn't find any.
743 	 */
744 
745 	nid = NID_key_usage;
746 	if ((abs = X509V3_get_d2i(exts, nid, &crit, NULL)) != NULL) {
747 		fprintf(stderr, "FAIL: %s: found key usage extension\n",
748 		    __func__);
749 		goto err;
750 	}
751 	if (crit != -1) {
752 		fprintf(stderr, "FAIL: %s: key usage: crit: want %d, got %d\n",
753 		    __func__, -1, crit);
754 		goto err;
755 	}
756 
757 	/*
758 	 * If we pass no idx and look for basic constraints,
759 	 * we should fail with crit == -2.
760 	 */
761 
762 	nid = NID_basic_constraints;
763 	if ((bc = X509V3_get_d2i(exts, nid, &crit, NULL)) != NULL) {
764 		fprintf(stderr, "FAIL: %s (NULL idx): did not expect to find "
765 		    "basic constraints\n", __func__);
766 		goto err;
767 	}
768 	if (crit != -2) {
769 		fprintf(stderr, "FAIL: %s: basic constraints, no idx: \n"
770 		    "crit: want %d, got %d\n", __func__, -2, crit);
771 		goto err;
772 	}
773 
774 	/*
775 	 * If we pass idx = -1 and look for basic constraints, we should find
776 	 * the first one: it is critical at idx = 0, with ca bit set to true.
777 	 */
778 
779 	nid = NID_basic_constraints;
780 	idx = -1;
781 	if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) == NULL) {
782 		fprintf(stderr, "FAIL: %s (idx %d): expected to find"
783 		    "basic constraints\n", __func__, -1);
784 		goto err;
785 	}
786 	if (crit != 1) {
787 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
788 		    "crit: want %d, got %d\n", __func__, -1, 1, crit);
789 		goto err;
790 	}
791 	if (idx != 0) {
792 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
793 		    "idx: want %d, got %d\n", __func__, -1, 0, idx);
794 		goto err;
795 	}
796 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
797 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
798 		    "cA bit: want %x, got %x\n", __func__, -1,
799 		    ASN1_BOOLEAN_TRUE, bc->ca);
800 		goto err;
801 	}
802 	BASIC_CONSTRAINTS_free(bc);
803 	bc = NULL;
804 
805 	/*
806 	 * Now pass idx = 0 and look for basic constraints, we should find
807 	 * the second one: non-critical at idx = 1, with ca bit set to true.
808 	 */
809 
810 	nid = NID_basic_constraints;
811 	idx = 0;
812 	if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) == NULL) {
813 		fprintf(stderr, "FAIL: %s (idx %d): expected to find"
814 		    "basic constraints\n", __func__, 0);
815 		goto err;
816 	}
817 	if (crit != 0) {
818 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
819 		    "crit: want %d, got %d\n", __func__, 0, 0, crit);
820 		goto err;
821 	}
822 	if (idx != 1) {
823 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
824 		    "idx: want %d, got %d\n", __func__, 0, 1, idx);
825 		goto err;
826 	}
827 	if (bc->ca != ASN1_BOOLEAN_TRUE) {
828 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
829 		    "cA bit: want %x, got %x\n", __func__, 0,
830 		    ASN1_BOOLEAN_TRUE, bc->ca);
831 		goto err;
832 	}
833 	BASIC_CONSTRAINTS_free(bc);
834 	bc = NULL;
835 
836 	/*
837 	 * Now pass idx = 1 and look for basic constraints, we should find the
838 	 * third one: critical at idx = 2, with ca bit set to false.
839 	 */
840 
841 	nid = NID_basic_constraints;
842 	idx = 1;
843 	if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) == NULL) {
844 		fprintf(stderr, "FAIL: %s (idx %d): expected to find"
845 		    "basic constraints\n", __func__, 1);
846 		goto err;
847 	}
848 	if (crit != 1) {
849 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
850 		    "crit: want %d, got %d\n", __func__, 1, 0, crit);
851 		goto err;
852 	}
853 	if (idx != 2) {
854 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
855 		    "idx: want %d, got %d\n", __func__, 1, 2, idx);
856 		goto err;
857 	}
858 	if (bc->ca != ASN1_BOOLEAN_FALSE) {
859 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
860 		    "cA bit: want %x, got %x\n", __func__, 1,
861 		    ASN1_BOOLEAN_FALSE, bc->ca);
862 		goto err;
863 	}
864 	BASIC_CONSTRAINTS_free(bc);
865 	bc = NULL;
866 
867 	/*
868 	 * Finally, pass idx = 2 and we should find no basic constraints.
869 	 */
870 
871 	nid = NID_basic_constraints;
872 	idx = 2;
873 	if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) != NULL) {
874 		fprintf(stderr, "FAIL: %s (idx %d): expected to find"
875 		    "no basic constraints\n", __func__, 2);
876 		goto err;
877 	}
878 	if (crit != -1) {
879 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
880 		    "crit: want %d, got %d\n", __func__, 2, -1, crit);
881 		goto err;
882 	}
883 	if (idx != -1) {
884 		fprintf(stderr, "FAIL: %s: basic constraints (idx %d): "
885 		    "idx: want %d, got %d\n", __func__, 2, -1, idx);
886 		goto err;
887 	}
888 
889 	failed = 0;
890 
891  err:
892 	sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
893 	ASN1_BIT_STRING_free(abs);
894 	BASIC_CONSTRAINTS_free(bc);
895 
896 	return failed;
897 }
898 
899 static int
900 test_x509v3_get_d2i(void)
901 {
902 	int failed = 0;
903 
904 	failed |= test_x509v3_get_d2i_null();
905 	failed |= test_x509v3_get_d2i_multiple_basic_constraints();
906 
907 	return failed;
908 }
909 
910 int
911 main(void)
912 {
913 	int failed = 0;
914 
915 	failed |= test_x509v3_add1_i2d();
916 	failed |= test_x509v3_get_d2i();
917 
918 	return failed;
919 }
920