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 *
create_basic_constraints(int ca)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 *
ext_create_basic_constraints(int ca,int critical)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
test_x509v3_add1_i2d_empty_stack(STACK_OF (X509_EXTENSION)** extensions)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
test_x509v3_add1_i2d_single_nid(STACK_OF (X509_EXTENSION)** extensions)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
test_x509v3_add1_i2d_add_append(STACK_OF (X509_EXTENSION)** extensions)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
test_x509v3_add1_i2d_invalid_operations(STACK_OF (X509_EXTENSION)** extensions)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
test_x509v3_add1_i2d(void)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
test_x509v3_get_d2i_null(void)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
test_x509v3_get_d2i_multiple_basic_constraints(void)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
test_x509v3_get_d2i(void)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
main(void)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