2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 #define DIRNAME "test/x509"
33 #define CONFFILE (DIRNAME "/alltests.txt")
34 #define DEFAULT_TIME "2016-08-30T18:00:00Z"
46 fprintf(stderr
, "error: cannot allocate %lu byte(s)\n",
62 xstrdup(const char *name
)
81 static string_builder
*
86 sb
= xmalloc(sizeof *sb
);
88 sb
->buf
= xmalloc(sb
->len
);
94 SB_expand(string_builder
*sb
, size_t extra_len
)
99 if (extra_len
< (sb
->len
- sb
->ptr
)) {
103 if (extra_len
> (nlen
- sb
->ptr
)) {
104 nlen
= sb
->ptr
+ extra_len
;
106 nbuf
= xmalloc(nlen
);
107 memcpy(nbuf
, sb
->buf
, sb
->ptr
);
114 SB_append_char(string_builder
*sb
, int c
)
117 sb
->buf
[sb
->ptr
++] = c
;
122 SB_append_string(string_builder *sb, const char *s)
128 memcpy(sb->buf + sb->ptr, s, n);
135 SB_to_string(string_builder *sb)
139 s = xmalloc(sb->ptr + 1);
140 memcpy(s, sb->buf, sb->ptr);
147 SB_contents(string_builder
*sb
)
153 SB_length(string_builder
*sb
)
159 SB_set_length(string_builder
*sb
, size_t len
)
162 SB_expand(sb
, len
- sb
->ptr
);
163 memset(sb
->buf
+ sb
->ptr
, ' ', len
- sb
->ptr
);
169 SB_reset(string_builder
*sb
)
171 SB_set_length(sb
, 0);
175 SB_free(string_builder
*sb
)
181 typedef struct ht_elt_
{
184 struct ht_elt_
*next
;
199 ht
= xmalloc(sizeof *ht
);
202 ht
->buckets
= xmalloc(ht
->num_buckets
* sizeof(ht_elt
*));
203 for (u
= 0; u
< ht
->num_buckets
; u
++) {
204 ht
->buckets
[u
] = NULL
;
210 hash_string(const char *name
)
219 x
= *(const unsigned char *)name
;
220 if (x
>= 'A' && x
<= 'Z') {
230 eqstring(const char *s1
, const char *s2
)
235 x1
= *(const unsigned char *)s1
;
236 x2
= *(const unsigned char *)s2
;
237 if (x1
>= 'A' && x1
<= 'Z') {
240 if (x2
>= 'A' && x2
<= 'Z') {
249 return !(*s1
|| *s2
);
256 ht_elt
**new_buckets
;
260 new_buckets
= xmalloc(n2
* sizeof *new_buckets
);
261 for (u
= 0; u
< n
; u
++) {
265 for (e
= ht
->buckets
[u
]; e
!= NULL
; e
= f
) {
269 hc
= hash_string(e
->name
);
270 v
= (size_t)(hc
& ((uint32_t)n2
- 1));
272 e
->next
= new_buckets
[v
];
277 ht
->buckets
= new_buckets
;
278 ht
->num_buckets
= n2
;
282 HT_put(HT
*ht
, const char *name
, void *value
)
288 hc
= hash_string(name
);
289 k
= (size_t)(hc
& ((uint32_t)ht
->num_buckets
- 1));
290 prev
= &ht
->buckets
[k
];
293 if (eqstring(name
, e
->name
)) {
296 old_value
= e
->value
;
311 e
= xmalloc(sizeof *e
);
312 e
->name
= xstrdup(name
);
314 e
->next
= ht
->buckets
[k
];
317 if (ht
->size
> ht
->num_buckets
) {
326 HT_remove(HT *ht, const char *name)
328 return HT_put(ht, name, NULL);
333 HT_get(const HT
*ht
, const char *name
)
339 hc
= hash_string(name
);
340 k
= (size_t)(hc
& ((uint32_t)ht
->num_buckets
- 1));
341 for (e
= ht
->buckets
[k
]; e
!= NULL
; e
= e
->next
) {
342 if (eqstring(name
, e
->name
)) {
350 HT_clear(HT
*ht
, void (*free_value
)(void *value
))
354 for (u
= 0; u
< ht
->num_buckets
; u
++) {
358 for (e
= ht
->buckets
[u
]; e
!= NULL
; e
= f
) {
361 if (free_value
!= 0) {
362 free_value(e
->value
);
366 ht
->buckets
[u
] = NULL
;
372 HT_free(HT
*ht
, void (*free_value
)(void *value
))
374 HT_clear(ht
, free_value
);
387 static unsigned char *
388 read_all(FILE *f
, size_t *len
)
403 buf2
= xmalloc(blen
);
404 memcpy(buf2
, buf
, ptr
);
408 rlen
= fread(buf
+ ptr
, 1, blen
- ptr
, f
);
413 memcpy(buf3
, buf
, ptr
);
422 static unsigned char *
423 read_file(const char *name
, size_t *len
)
431 dname
= xmalloc(strlen(DIRNAME
) + strlen(name
) + 2);
432 sprintf(dname
, "%s/%s", DIRNAME
, name
);
435 f
= fopen(name
, "rb");
437 fprintf(stderr
, "could not open file '%s'\n", name
);
440 buf
= read_all(f
, len
);
442 fprintf(stderr
, "read error on file '%s'\n", name
);
453 parse_dec(const char *s
, unsigned len
, int *val
)
462 if (c
>= '0' && c
<= '9') {
463 acc
= (acc
* 10) + (c
- '0');
473 parse_choice(const char *s
, const char *acceptable
)
478 while (*acceptable
) {
479 if (c
== *acceptable
++) {
487 month_length(int year
, int month
)
489 static const int base_month_length
[] = {
490 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
495 x
= base_month_length
[month
- 1];
496 if (month
== 2 && year
% 4 == 0
497 && (year
% 100 != 0 || year
% 400 == 0))
505 * Convert a time string to a days+seconds count. Returned value is 0
506 * on success, -1 on error.
509 string_to_time(const char *s
, uint32_t *days
, uint32_t *seconds
)
511 int year
, month
, day
, hour
, minute
, second
;
512 int day_of_year
, leaps
;
514 if (parse_dec(s
, 4, &year
) < 0) {
518 if (parse_choice(s
++, "-:/ ") < 0) {
521 if (parse_dec(s
, 2, &month
) < 0) {
525 if (parse_choice(s
++, "-:/ ") < 0) {
528 if (parse_dec(s
, 2, &day
) < 0) {
532 if (parse_choice(s
++, " T") < 0) {
535 if (parse_dec(s
, 2, &hour
) < 0) {
539 if (parse_choice(s
++, "-:/ ") < 0) {
542 if (parse_dec(s
, 2, &minute
) < 0) {
546 if (parse_choice(s
++, "-:/ ") < 0) {
549 if (parse_dec(s
, 2, &second
) < 0) {
554 while (*s
&& *s
>= '0' && *s
<= '9') {
567 if (month
< 1 || month
> 12) {
571 for (int i
= 1; i
< month
; i
++) {
572 day_of_year
+= month_length(year
, i
);
574 if (day
< 1 || day
> month_length(year
, month
)) {
577 day_of_year
+= (day
- 1);
578 leaps
= (year
+ 3) / 4 - (year
+ 99) / 100 + (year
+ 399) / 400;
580 if (hour
> 23 || minute
> 59 || second
> 60) {
583 *days
= (uint32_t)year
* 365 + (uint32_t)leaps
+ day_of_year
;
584 *seconds
= (uint32_t)hour
* 3600 + minute
* 60 + second
;
589 static int conf_delayed_char
;
590 static long conf_linenum
;
591 static string_builder
*line_builder
;
592 static long current_linenum
;
595 conf_init(const char *fname
)
597 conf
= fopen(fname
, "r");
599 fprintf(stderr
, "could not open file '%s'\n", fname
);
602 conf_delayed_char
= -1;
604 line_builder
= SB_new();
612 fprintf(stderr
, "read error on configuration file\n");
618 if (line_builder
!= NULL
) {
619 SB_free(line_builder
);
625 * Get next character from the config file.
632 x
= conf_delayed_char
;
634 conf_delayed_char
= -1;
647 conf_delayed_char
= x
;
666 return (c
>= 'A' && c
<= 'Z')
667 || (c
>= 'a' && c
<= 'z')
668 || (c
>= '0' && c
<= '9')
669 || (c
== '_' || c
== '-' || c
== '.');
673 * Read a complete line. This handles line continuation; empty lines and
674 * comment lines are skipped; leading and trailing whitespace is removed.
675 * Returned value is 0 (line read) or -1 (no line, EOF reached). The line
676 * contents are accumulated in the line_builder.
685 SB_reset(line_builder
);
688 * Get first non-whitespace character. This skips empty
689 * lines. Comment lines (first non-whitespace character
690 * is a semicolon) are also skipped.
716 * Read up the remaining of the line. The line continuation
717 * sequence (final backslash) is detected and processed.
719 current_linenum
= conf_linenum
;
721 SB_append_char(line_builder
, c
);
729 SB_set_length(line_builder
,
730 SB_length(line_builder
) - 1);
737 } else if (c
== '\\') {
740 SB_append_char(line_builder
, c
);
744 * Remove trailing whitespace (if any).
749 u
= SB_length(line_builder
);
750 if (u
== 0 || !is_ws(
751 SB_contents(line_builder
)[u
- 1]))
755 SB_set_length(line_builder
, u
- 1);
759 * We might end up with a totally empty line (in case there
760 * was a line continuation but nothing else), in which case
763 if (SB_length(line_builder
) > 0) {
770 * Test whether the current line is a section header. If yes, then the
771 * header name is extracted, and returned as a newly allocated string.
772 * Otherwise, NULL is returned.
775 parse_header_name(void)
780 buf
= SB_contents(line_builder
);
781 len
= SB_length(line_builder
);
782 if (len
< 2 || buf
[0] != '[' || buf
[len
- 1] != ']') {
787 while (u
< v
&& is_ws(buf
[u
])) {
790 while (u
< v
&& is_ws(buf
[v
- 1])) {
796 for (w
= u
; w
< v
; w
++) {
797 if (!is_name_char(buf
[w
])) {
802 name
= xmalloc(len
+ 1);
803 memcpy(name
, buf
+ u
, len
);
809 * Parse the current line as a 'name = value' pair. The pair is pushed into
810 * the provided hash table. On error (including a duplicate key name),
811 * this function returns -1; otherwise, it returns 0.
814 parse_keyvalue(HT
*d
)
816 char *buf
, *name
, *value
;
819 buf
= SB_contents(line_builder
);
820 len
= SB_length(line_builder
);
821 for (u
= 0; u
< len
; u
++) {
822 if (!is_name_char(buf
[u
])) {
829 name
= xmalloc(u
+ 1);
830 memcpy(name
, buf
, u
);
832 if (HT_get(d
, name
) != NULL
) {
836 while (u
< len
&& is_ws(buf
[u
])) {
839 if (u
>= len
|| buf
[u
] != '=') {
844 while (u
< len
&& is_ws(buf
[u
])) {
847 value
= xmalloc(len
- u
+ 1);
848 memcpy(value
, buf
+ u
, len
- u
);
850 HT_put(d
, name
, value
);
856 * Public keys, indexed by name. Elements are pointers to br_x509_pkey
862 * Trust anchors, indexed by name. Elements are pointers to
863 * test_trust_anchor structures.
865 static HT
*trust_anchors
;
875 * Test case: trust anchors, certificates (file names), key type and
876 * usage, expected status and EE public key.
883 unsigned key_type_usage
;
887 uint32_t days
, seconds
;
890 static test_case
*all_chains
;
891 static size_t all_chains_ptr
, all_chains_len
;
894 free_key(void *value
)
899 switch (pk
->key_type
) {
901 xfree((void *)pk
->key
.rsa
.n
);
902 xfree((void *)pk
->key
.rsa
.e
);
905 xfree((void *)pk
->key
.ec
.q
);
908 fprintf(stderr
, "unknown key type: %d\n", pk
->key_type
);
916 free_trust_anchor(void *value
)
918 test_trust_anchor
*ttc
;
922 xfree(ttc
->key_name
);
927 free_test_case_contents(test_case
*tc
)
932 for (u
= 0; tc
->ta_names
[u
]; u
++) {
933 xfree(tc
->ta_names
[u
]);
936 for (u
= 0; tc
->cert_names
[u
]; u
++) {
937 xfree(tc
->cert_names
[u
]);
939 xfree(tc
->cert_names
);
940 xfree(tc
->servername
);
941 xfree(tc
->ee_key_name
);
945 get_value(char *objtype
, HT
*objdata
, long linenum
, char *name
)
949 value
= HT_get(objdata
, name
);
952 "missing property '%s' in section '%s' (line %ld)\n",
953 name
, objtype
, linenum
);
959 static unsigned char *
960 parse_hex(const char *name
, long linenum
, const char *value
, size_t *len
)
972 for (u
= 0; value
[u
]; u
++) {
976 if (c
>= '0' && c
<= '9') {
978 } else if (c
>= 'A' && c
<= 'F') {
980 } else if (c
>= 'a' && c
<= 'f') {
982 } else if (c
== ' ' || c
== ':') {
985 fprintf(stderr
, "invalid hexadecimal character"
986 " in '%s' (line %ld)\n",
992 buf
[ptr
] = (acc
<< 4) + c
;
1001 fprintf(stderr
, "invalid hexadecimal value (partial"
1002 " byte) in '%s' (line %ld)\n",
1016 split_names(const char *value
)
1022 len
= strlen(value
);
1031 while (u
< len
&& is_ws(value
[u
])) {
1035 while (v
< len
&& !is_ws(value
[v
])) {
1039 if (names
!= NULL
) {
1042 name
= xmalloc(v
- u
+ 1);
1043 memcpy(name
, value
+ u
, v
- u
);
1051 if (names
== NULL
) {
1052 names
= xmalloc((ptr
+ 1) * sizeof *names
);
1061 string_to_hash(const char *name
)
1066 for (u
= 0, v
= 0; name
[u
]; u
++) {
1070 if ((c
>= '0' && c
<= '9')
1071 || (c
>= 'A' && c
<= 'Z')
1072 || (c
>= 'a' && c
<= 'z'))
1075 if (v
== sizeof tmp
) {
1081 if (eqstring(tmp
, "md5")) {
1083 } else if (eqstring(tmp
, "sha1")) {
1085 } else if (eqstring(tmp
, "sha224")) {
1086 return br_sha224_ID
;
1087 } else if (eqstring(tmp
, "sha256")) {
1088 return br_sha256_ID
;
1089 } else if (eqstring(tmp
, "sha384")) {
1090 return br_sha384_ID
;
1091 } else if (eqstring(tmp
, "sha512")) {
1092 return br_sha512_ID
;
1099 string_to_curve(const char *name
)
1104 for (u
= 0, v
= 0; name
[u
]; u
++) {
1108 if ((c
>= '0' && c
<= '9')
1109 || (c
>= 'A' && c
<= 'Z')
1110 || (c
>= 'a' && c
<= 'z'))
1113 if (v
== sizeof tmp
) {
1119 if (eqstring(tmp
, "p256") || eqstring(tmp
, "secp256r1")) {
1120 return BR_EC_secp256r1
;
1121 } else if (eqstring(tmp
, "p384") || eqstring(tmp
, "secp384r1")) {
1122 return BR_EC_secp384r1
;
1123 } else if (eqstring(tmp
, "p521") || eqstring(tmp
, "secp521r1")) {
1124 return BR_EC_secp521r1
;
1131 parse_object(char *objtype
, HT
*objdata
, long linenum
)
1135 name
= get_value(objtype
, objdata
, linenum
, "name");
1136 if (eqstring(objtype
, "key")) {
1140 stype
= get_value(objtype
, objdata
, linenum
, "type");
1141 pk
= xmalloc(sizeof *pk
);
1142 if (eqstring(stype
, "RSA")) {
1145 sn
= get_value(objtype
, objdata
, linenum
, "n");
1146 se
= get_value(objtype
, objdata
, linenum
, "e");
1147 pk
->key_type
= BR_KEYTYPE_RSA
;
1148 pk
->key
.rsa
.n
= parse_hex("modulus", linenum
,
1149 sn
, &pk
->key
.rsa
.nlen
);
1150 pk
->key
.rsa
.e
= parse_hex("exponent", linenum
,
1151 se
, &pk
->key
.rsa
.elen
);
1152 } else if (eqstring(stype
, "EC")) {
1156 sc
= get_value(objtype
, objdata
, linenum
, "curve");
1157 sq
= get_value(objtype
, objdata
, linenum
, "q");
1158 curve
= string_to_curve(sc
);
1160 fprintf(stderr
, "unknown curve name: '%s'"
1161 " (line %ld)\n", sc
, linenum
);
1164 pk
->key_type
= BR_KEYTYPE_EC
;
1165 pk
->key
.ec
.curve
= curve
;
1166 pk
->key
.ec
.q
= parse_hex("public point", linenum
,
1167 sq
, &pk
->key
.ec
.qlen
);
1169 fprintf(stderr
, "unknown key type '%s' (line %ld)\n",
1173 if (HT_put(keys
, name
, pk
) != NULL
) {
1174 fprintf(stderr
, "duplicate key: '%s' (line %ld)\n",
1178 } else if (eqstring(objtype
, "anchor")) {
1179 char *dnfile
, *kname
, *tatype
;
1180 test_trust_anchor
*tta
;
1182 dnfile
= get_value(objtype
, objdata
, linenum
, "DN_file");
1183 kname
= get_value(objtype
, objdata
, linenum
, "key");
1184 tatype
= get_value(objtype
, objdata
, linenum
, "type");
1185 tta
= xmalloc(sizeof *tta
);
1186 tta
->dn
= read_file(dnfile
, &tta
->dn_len
);
1187 tta
->key_name
= xstrdup(kname
);
1188 if (eqstring(tatype
, "CA")) {
1189 tta
->flags
= BR_X509_TA_CA
;
1190 } else if (eqstring(tatype
, "EE")) {
1194 "unknown trust anchor type: '%s' (line %ld)\n",
1197 if (HT_put(trust_anchors
, name
, tta
) != NULL
) {
1199 "duplicate trust anchor: '%s' (line %ld)\n",
1203 } else if (eqstring(objtype
, "chain")) {
1205 char *ktype
, *kusage
, *sstatus
, *shashes
, *stime
;
1207 ktype
= get_value(objtype
, objdata
, linenum
, "keytype");
1208 kusage
= get_value(objtype
, objdata
, linenum
, "keyusage");
1209 sstatus
= get_value(objtype
, objdata
, linenum
, "status");
1210 tc
.name
= xstrdup(name
);
1211 tc
.ta_names
= split_names(
1212 get_value(objtype
, objdata
, linenum
, "anchors"));
1213 tc
.cert_names
= split_names(
1214 get_value(objtype
, objdata
, linenum
, "chain"));
1215 tc
.servername
= xstrdup(HT_get(objdata
, "servername"));
1216 if (eqstring(ktype
, "RSA")) {
1217 tc
.key_type_usage
= BR_KEYTYPE_RSA
;
1218 } else if (eqstring(ktype
, "EC")) {
1219 tc
.key_type_usage
= BR_KEYTYPE_EC
;
1222 "unknown key type: '%s' (line %ld)\n",
1226 if (eqstring(kusage
, "KEYX")) {
1227 tc
.key_type_usage
|= BR_KEYTYPE_KEYX
;
1228 } else if (eqstring(kusage
, "SIGN")) {
1229 tc
.key_type_usage
|= BR_KEYTYPE_SIGN
;
1232 "unknown key usage: '%s' (line %ld)\n",
1236 tc
.status
= (unsigned)atoi(sstatus
);
1237 if (tc
.status
== 0) {
1238 tc
.ee_key_name
= xstrdup(
1239 get_value(objtype
, objdata
, linenum
, "eekey"));
1241 tc
.ee_key_name
= NULL
;
1243 shashes
= HT_get(objdata
, "hashes");
1244 if (shashes
== NULL
) {
1245 tc
.hashes
= (unsigned)-1;
1251 hns
= split_names(shashes
);
1252 for (u
= 0;; u
++) {
1260 id
= string_to_hash(hn
);
1263 "unknown hash function '%s'"
1264 " (line %ld)\n", hn
, linenum
);
1267 tc
.hashes
|= (unsigned)1 << id
;
1272 stime
= HT_get(objdata
, "time");
1273 if (stime
== NULL
) {
1274 stime
= DEFAULT_TIME
;
1276 if (string_to_time(stime
, &tc
.days
, &tc
.seconds
) < 0) {
1277 fprintf(stderr
, "invalid time string '%s' (line %ld)\n",
1281 if (all_chains_ptr
== all_chains_len
) {
1282 if (all_chains_len
== 0) {
1284 all_chains
= xmalloc(
1285 all_chains_len
* sizeof *all_chains
);
1290 nlen
= all_chains_len
<< 1;
1291 ntc
= xmalloc(nlen
* sizeof *ntc
);
1292 memcpy(ntc
, all_chains
,
1293 all_chains_len
* sizeof *all_chains
);
1296 all_chains_len
= nlen
;
1299 all_chains
[all_chains_ptr
++] = tc
;
1301 fprintf(stderr
, "unknown section type '%s' (line %ld)\n",
1308 process_conf_file(const char *fname
)
1315 trust_anchors
= HT_new();
1326 if (conf_next_line() < 0) {
1329 hname
= parse_header_name();
1330 if (hname
!= NULL
) {
1331 if (objtype
!= NULL
) {
1332 parse_object(objtype
, objdata
, objlinenum
);
1333 HT_clear(objdata
, xfree
);
1337 objlinenum
= current_linenum
;
1340 if (objtype
== NULL
) {
1341 fprintf(stderr
, "no current section (line %ld)\n",
1345 if (parse_keyvalue(objdata
) < 0) {
1346 fprintf(stderr
, "wrong configuration, line %ld\n",
1351 if (objtype
!= NULL
) {
1352 parse_object(objtype
, objdata
, objlinenum
);
1355 HT_free(objdata
, xfree
);
1359 static const struct {
1361 const br_hash_class
*impl
;
1363 { br_md5_ID
, &br_md5_vtable
},
1364 { br_sha1_ID
, &br_sha1_vtable
},
1365 { br_sha224_ID
, &br_sha224_vtable
},
1366 { br_sha256_ID
, &br_sha256_vtable
},
1367 { br_sha384_ID
, &br_sha384_vtable
},
1368 { br_sha512_ID
, &br_sha512_vtable
},
1373 unsigned char *data
;
1378 eqbigint(const unsigned char *b1
, size_t b1_len
,
1379 const unsigned char *b2
, size_t b2_len
)
1381 while (b1_len
> 0 && *b1
== 0) {
1385 while (b2_len
> 0 && *b2
== 0) {
1389 return b1_len
== b2_len
&& memcmp(b1
, b2
, b1_len
) == 0;
1393 eqpkey(const br_x509_pkey
*pk1
, const br_x509_pkey
*pk2
)
1398 if (pk1
== NULL
|| pk2
== NULL
) {
1401 if (pk1
->key_type
!= pk2
->key_type
) {
1404 switch (pk1
->key_type
) {
1405 case BR_KEYTYPE_RSA
:
1406 return eqbigint(pk1
->key
.rsa
.n
, pk1
->key
.rsa
.nlen
,
1407 pk2
->key
.rsa
.n
, pk2
->key
.rsa
.nlen
)
1408 && eqbigint(pk1
->key
.rsa
.e
, pk1
->key
.rsa
.elen
,
1409 pk2
->key
.rsa
.e
, pk2
->key
.rsa
.elen
);
1411 return pk1
->key
.ec
.curve
== pk2
->key
.ec
.curve
1412 && pk1
->key
.ec
.qlen
== pk2
->key
.ec
.qlen
1413 && memcmp(pk1
->key
.ec
.q
,
1414 pk2
->key
.ec
.q
, pk1
->key
.ec
.qlen
) == 0;
1416 fprintf(stderr
, "unknown key type: %d\n", pk1
->key_type
);
1423 static size_t max_dp_usage
;
1424 static size_t max_rp_usage
;
1427 run_test_case(test_case
*tc
)
1429 br_x509_minimal_context ctx
;
1430 br_x509_trust_anchor
*anchors
;
1433 const br_hash_class
*dnhash
;
1436 br_x509_pkey
*ee_pkey_ref
;
1437 const br_x509_pkey
*ee_pkey
;
1440 printf("%s: ", tc
->name
);
1444 * Get the hash function to use for hashing DN. We can use just
1445 * any supported hash function, but for the elegance of things,
1446 * we will use one of the hash function implementations
1447 * supported for this test case (with SHA-1 as fallback).
1449 dnhash
= &br_sha1_vtable
;
1450 for (u
= 0; hash_impls
[u
].id
; u
++) {
1451 if ((tc
->hashes
& ((unsigned)1 << (hash_impls
[u
].id
))) != 0) {
1452 dnhash
= hash_impls
[u
].impl
;
1457 * Get trust anchors.
1459 for (num_anchors
= 0; tc
->ta_names
[num_anchors
]; num_anchors
++);
1460 anchors
= xmalloc(num_anchors
* sizeof *anchors
);
1461 for (u
= 0; tc
->ta_names
[u
]; u
++) {
1462 test_trust_anchor
*tta
;
1465 tta
= HT_get(trust_anchors
, tc
->ta_names
[u
]);
1467 fprintf(stderr
, "no such trust anchor: '%s'\n",
1471 tak
= HT_get(keys
, tta
->key_name
);
1473 fprintf(stderr
, "no such public key: '%s'\n",
1477 anchors
[u
].dn
= tta
->dn
;
1478 anchors
[u
].dn_len
= tta
->dn_len
;
1479 anchors
[u
].flags
= tta
->flags
;
1480 anchors
[u
].pkey
= *tak
;
1484 * Read all relevant certificates.
1486 for (num_certs
= 0; tc
->cert_names
[num_certs
]; num_certs
++);
1487 certs
= xmalloc(num_certs
* sizeof *certs
);
1488 for (u
= 0; u
< num_certs
; u
++) {
1489 certs
[u
].data
= read_file(tc
->cert_names
[u
], &certs
[u
].len
);
1493 * Get expected EE public key (if any).
1495 if (tc
->ee_key_name
== NULL
) {
1498 ee_pkey_ref
= HT_get(keys
, tc
->ee_key_name
);
1499 if (ee_pkey_ref
== NULL
) {
1500 fprintf(stderr
, "no such public key: '%s'\n",
1507 * Initialise the engine.
1509 br_x509_minimal_init(&ctx
, dnhash
, anchors
, num_anchors
);
1510 for (u
= 0; hash_impls
[u
].id
; u
++) {
1513 id
= hash_impls
[u
].id
;
1514 if ((tc
->hashes
& ((unsigned)1 << id
)) != 0) {
1515 br_x509_minimal_set_hash(&ctx
, id
, hash_impls
[u
].impl
);
1518 br_x509_minimal_set_rsa(&ctx
, br_rsa_i32_pkcs1_vrfy
);
1519 br_x509_minimal_set_ecdsa(&ctx
,
1520 &br_ec_prime_i31
, br_ecdsa_i31_vrfy_asn1
);
1523 * Set the validation date.
1525 br_x509_minimal_set_time(&ctx
, tc
->days
, tc
->seconds
);
1528 * Put "canaries" to detect actual stack usage.
1530 for (u
= 0; u
< (sizeof ctx
.dp_stack
) / sizeof(uint32_t); u
++) {
1531 ctx
.dp_stack
[u
] = 0xA7C083FE;
1533 for (u
= 0; u
< (sizeof ctx
.rp_stack
) / sizeof(uint32_t); u
++) {
1534 ctx
.rp_stack
[u
] = 0xA7C083FE;
1538 * Run the engine. We inject certificates by chunks of 100 bytes
1539 * in order to exercise the coroutine API.
1541 ctx
.vtable
->start_chain(&ctx
.vtable
,
1542 tc
->key_type_usage
, tc
->servername
);
1543 for (u
= 0; u
< num_certs
; u
++) {
1546 ctx
.vtable
->start_cert(&ctx
.vtable
, certs
[u
].len
);
1548 while (v
< certs
[u
].len
) {
1551 w
= certs
[u
].len
- v
;
1555 ctx
.vtable
->append(&ctx
.vtable
, certs
[u
].data
+ v
, w
);
1558 ctx
.vtable
->end_cert(&ctx
.vtable
);
1560 status
= ctx
.vtable
->end_chain(&ctx
.vtable
);
1561 ee_pkey
= ctx
.vtable
->get_pkey(&ctx
.vtable
);
1564 * Check results. Note that we may still get a public key if
1565 * the path is "not trusted" (but otherwise fine).
1567 if (status
!= tc
->status
) {
1568 fprintf(stderr
, "wrong status (got %d, expected %d)\n",
1569 status
, tc
->status
);
1572 if (status
== BR_ERR_X509_NOT_TRUSTED
) {
1575 if (!eqpkey(ee_pkey
, ee_pkey_ref
)) {
1576 fprintf(stderr
, "wrong EE public key\n");
1581 * Check stack usage.
1583 for (u
= (sizeof ctx
.dp_stack
) / sizeof(uint32_t); u
> 0; u
--) {
1584 if (ctx
.dp_stack
[u
- 1] != 0xA7C083FE) {
1585 if (max_dp_usage
< u
) {
1591 for (u
= (sizeof ctx
.rp_stack
) / sizeof(uint32_t); u
> 0; u
--) {
1592 if (ctx
.rp_stack
[u
- 1] != 0xA7C083FE) {
1593 if (max_rp_usage
< u
) {
1601 * Release everything.
1603 for (u
= 0; u
< num_certs
; u
++) {
1604 xfree(certs
[u
].data
);
1616 process_conf_file(CONFFILE
);
1620 for (u
= 0; u
< all_chains_ptr
; u
++) {
1621 run_test_case(&all_chains
[u
]);
1624 printf("Maximum data stack usage: %u\n", (unsigned)max_dp_usage
);
1625 printf("Maximum return stack usage: %u\n", (unsigned)max_rp_usage
);
1627 HT_free(keys
, free_key
);
1628 HT_free(trust_anchors
, free_trust_anchor
);
1629 for (u
= 0; u
< all_chains_ptr
; u
++) {
1630 free_test_case_contents(&all_chains
[u
]);