xref: /freebsd/contrib/bearssl/test/test_x509.c (revision cc9e6590773dba57440750c124173ed531349a06)
10957b409SSimon J. Gerraty /*
20957b409SSimon J. Gerraty  * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
30957b409SSimon J. Gerraty  *
40957b409SSimon J. Gerraty  * Permission is hereby granted, free of charge, to any person obtaining
50957b409SSimon J. Gerraty  * a copy of this software and associated documentation files (the
60957b409SSimon J. Gerraty  * "Software"), to deal in the Software without restriction, including
70957b409SSimon J. Gerraty  * without limitation the rights to use, copy, modify, merge, publish,
80957b409SSimon J. Gerraty  * distribute, sublicense, and/or sell copies of the Software, and to
90957b409SSimon J. Gerraty  * permit persons to whom the Software is furnished to do so, subject to
100957b409SSimon J. Gerraty  * the following conditions:
110957b409SSimon J. Gerraty  *
120957b409SSimon J. Gerraty  * The above copyright notice and this permission notice shall be
130957b409SSimon J. Gerraty  * included in all copies or substantial portions of the Software.
140957b409SSimon J. Gerraty  *
150957b409SSimon J. Gerraty  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
160957b409SSimon J. Gerraty  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
170957b409SSimon J. Gerraty  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
180957b409SSimon J. Gerraty  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
190957b409SSimon J. Gerraty  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
200957b409SSimon J. Gerraty  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
210957b409SSimon J. Gerraty  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
220957b409SSimon J. Gerraty  * SOFTWARE.
230957b409SSimon J. Gerraty  */
240957b409SSimon J. Gerraty 
250957b409SSimon J. Gerraty #include <stdio.h>
260957b409SSimon J. Gerraty #include <stdlib.h>
270957b409SSimon J. Gerraty #include <string.h>
280957b409SSimon J. Gerraty #include <stdint.h>
290957b409SSimon J. Gerraty 
300957b409SSimon J. Gerraty #ifdef _WIN32
310957b409SSimon J. Gerraty #include <windows.h>
320957b409SSimon J. Gerraty #else
330957b409SSimon J. Gerraty #include <unistd.h>
340957b409SSimon J. Gerraty #endif
350957b409SSimon J. Gerraty 
360957b409SSimon J. Gerraty #include "bearssl.h"
370957b409SSimon J. Gerraty 
380957b409SSimon J. Gerraty #define STR(x)    STR_(x)
390957b409SSimon J. Gerraty #define STR_(x)   #x
400957b409SSimon J. Gerraty #ifdef SRCDIRNAME
410957b409SSimon J. Gerraty #define DIRNAME        STR(SRCDIRNAME) "/test/x509"
420957b409SSimon J. Gerraty #else
430957b409SSimon J. Gerraty #define DIRNAME        "test/x509"
440957b409SSimon J. Gerraty #endif
450957b409SSimon J. Gerraty #define CONFFILE       DIRNAME "/alltests.txt"
460957b409SSimon J. Gerraty #define DEFAULT_TIME   "2016-08-30T18:00:00Z"
470957b409SSimon J. Gerraty 
480957b409SSimon J. Gerraty static void *
xmalloc(size_t len)490957b409SSimon J. Gerraty xmalloc(size_t len)
500957b409SSimon J. Gerraty {
510957b409SSimon J. Gerraty 	void *buf;
520957b409SSimon J. Gerraty 
530957b409SSimon J. Gerraty 	if (len == 0) {
540957b409SSimon J. Gerraty 		return NULL;
550957b409SSimon J. Gerraty 	}
560957b409SSimon J. Gerraty 	buf = malloc(len);
570957b409SSimon J. Gerraty 	if (buf == NULL) {
580957b409SSimon J. Gerraty 		fprintf(stderr, "error: cannot allocate %lu byte(s)\n",
590957b409SSimon J. Gerraty 			(unsigned long)len);
600957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
610957b409SSimon J. Gerraty 	}
620957b409SSimon J. Gerraty 	return buf;
630957b409SSimon J. Gerraty }
640957b409SSimon J. Gerraty 
650957b409SSimon J. Gerraty static void
xfree(void * buf)660957b409SSimon J. Gerraty xfree(void *buf)
670957b409SSimon J. Gerraty {
680957b409SSimon J. Gerraty 	if (buf != NULL) {
690957b409SSimon J. Gerraty 		free(buf);
700957b409SSimon J. Gerraty 	}
710957b409SSimon J. Gerraty }
720957b409SSimon J. Gerraty 
730957b409SSimon J. Gerraty static char *
xstrdup(const char * name)740957b409SSimon J. Gerraty xstrdup(const char *name)
750957b409SSimon J. Gerraty {
760957b409SSimon J. Gerraty 	size_t n;
770957b409SSimon J. Gerraty 	char *s;
780957b409SSimon J. Gerraty 
790957b409SSimon J. Gerraty 	if (name == NULL) {
800957b409SSimon J. Gerraty 		return NULL;
810957b409SSimon J. Gerraty 	}
820957b409SSimon J. Gerraty 	n = strlen(name) + 1;
830957b409SSimon J. Gerraty 	s = xmalloc(n);
840957b409SSimon J. Gerraty 	memcpy(s, name, n);
850957b409SSimon J. Gerraty 	return s;
860957b409SSimon J. Gerraty }
870957b409SSimon J. Gerraty 
880957b409SSimon J. Gerraty typedef struct {
890957b409SSimon J. Gerraty 	char *buf;
900957b409SSimon J. Gerraty 	size_t ptr, len;
910957b409SSimon J. Gerraty } string_builder;
920957b409SSimon J. Gerraty 
930957b409SSimon J. Gerraty static string_builder *
SB_new(void)940957b409SSimon J. Gerraty SB_new(void)
950957b409SSimon J. Gerraty {
960957b409SSimon J. Gerraty 	string_builder *sb;
970957b409SSimon J. Gerraty 
980957b409SSimon J. Gerraty 	sb = xmalloc(sizeof *sb);
990957b409SSimon J. Gerraty 	sb->len = 8;
1000957b409SSimon J. Gerraty 	sb->buf = xmalloc(sb->len);
1010957b409SSimon J. Gerraty 	sb->ptr = 0;
1020957b409SSimon J. Gerraty 	return sb;
1030957b409SSimon J. Gerraty }
1040957b409SSimon J. Gerraty 
1050957b409SSimon J. Gerraty static void
SB_expand(string_builder * sb,size_t extra_len)1060957b409SSimon J. Gerraty SB_expand(string_builder *sb, size_t extra_len)
1070957b409SSimon J. Gerraty {
1080957b409SSimon J. Gerraty 	size_t nlen;
1090957b409SSimon J. Gerraty 	char *nbuf;
1100957b409SSimon J. Gerraty 
1110957b409SSimon J. Gerraty 	if (extra_len < (sb->len - sb->ptr)) {
1120957b409SSimon J. Gerraty 		return;
1130957b409SSimon J. Gerraty 	}
1140957b409SSimon J. Gerraty 	nlen = sb->len << 1;
1150957b409SSimon J. Gerraty 	if (extra_len > (nlen - sb->ptr)) {
1160957b409SSimon J. Gerraty 		nlen = sb->ptr + extra_len;
1170957b409SSimon J. Gerraty 	}
1180957b409SSimon J. Gerraty 	nbuf = xmalloc(nlen);
1190957b409SSimon J. Gerraty 	memcpy(nbuf, sb->buf, sb->ptr);
1200957b409SSimon J. Gerraty 	xfree(sb->buf);
1210957b409SSimon J. Gerraty 	sb->buf = nbuf;
1220957b409SSimon J. Gerraty 	sb->len = nlen;
1230957b409SSimon J. Gerraty }
1240957b409SSimon J. Gerraty 
1250957b409SSimon J. Gerraty static void
SB_append_char(string_builder * sb,int c)1260957b409SSimon J. Gerraty SB_append_char(string_builder *sb, int c)
1270957b409SSimon J. Gerraty {
1280957b409SSimon J. Gerraty 	SB_expand(sb, 1);
1290957b409SSimon J. Gerraty 	sb->buf[sb->ptr ++] = c;
1300957b409SSimon J. Gerraty }
1310957b409SSimon J. Gerraty 
1320957b409SSimon J. Gerraty /* unused
1330957b409SSimon J. Gerraty static void
1340957b409SSimon J. Gerraty SB_append_string(string_builder *sb, const char *s)
1350957b409SSimon J. Gerraty {
1360957b409SSimon J. Gerraty 	size_t n;
1370957b409SSimon J. Gerraty 
1380957b409SSimon J. Gerraty 	n = strlen(s);
1390957b409SSimon J. Gerraty 	SB_expand(sb, n);
1400957b409SSimon J. Gerraty 	memcpy(sb->buf + sb->ptr, s, n);
1410957b409SSimon J. Gerraty 	sb->ptr += n;
1420957b409SSimon J. Gerraty }
1430957b409SSimon J. Gerraty */
1440957b409SSimon J. Gerraty 
1450957b409SSimon J. Gerraty /* unused
1460957b409SSimon J. Gerraty static char *
1470957b409SSimon J. Gerraty SB_to_string(string_builder *sb)
1480957b409SSimon J. Gerraty {
1490957b409SSimon J. Gerraty 	char *s;
1500957b409SSimon J. Gerraty 
1510957b409SSimon J. Gerraty 	s = xmalloc(sb->ptr + 1);
1520957b409SSimon J. Gerraty 	memcpy(s, sb->buf, sb->ptr);
1530957b409SSimon J. Gerraty 	s[sb->ptr] = 0;
1540957b409SSimon J. Gerraty 	return s;
1550957b409SSimon J. Gerraty }
1560957b409SSimon J. Gerraty */
1570957b409SSimon J. Gerraty 
1580957b409SSimon J. Gerraty static char *
SB_contents(string_builder * sb)1590957b409SSimon J. Gerraty SB_contents(string_builder *sb)
1600957b409SSimon J. Gerraty {
1610957b409SSimon J. Gerraty 	return sb->buf;
1620957b409SSimon J. Gerraty }
1630957b409SSimon J. Gerraty 
1640957b409SSimon J. Gerraty static size_t
SB_length(string_builder * sb)1650957b409SSimon J. Gerraty SB_length(string_builder *sb)
1660957b409SSimon J. Gerraty {
1670957b409SSimon J. Gerraty 	return sb->ptr;
1680957b409SSimon J. Gerraty }
1690957b409SSimon J. Gerraty 
1700957b409SSimon J. Gerraty static void
SB_set_length(string_builder * sb,size_t len)1710957b409SSimon J. Gerraty SB_set_length(string_builder *sb, size_t len)
1720957b409SSimon J. Gerraty {
1730957b409SSimon J. Gerraty 	if (sb->ptr < len) {
1740957b409SSimon J. Gerraty 		SB_expand(sb, len - sb->ptr);
1750957b409SSimon J. Gerraty 		memset(sb->buf + sb->ptr, ' ', len - sb->ptr);
1760957b409SSimon J. Gerraty 	}
1770957b409SSimon J. Gerraty 	sb->ptr = len;
1780957b409SSimon J. Gerraty }
1790957b409SSimon J. Gerraty 
1800957b409SSimon J. Gerraty static void
SB_reset(string_builder * sb)1810957b409SSimon J. Gerraty SB_reset(string_builder *sb)
1820957b409SSimon J. Gerraty {
1830957b409SSimon J. Gerraty 	SB_set_length(sb, 0);
1840957b409SSimon J. Gerraty }
1850957b409SSimon J. Gerraty 
1860957b409SSimon J. Gerraty static void
SB_free(string_builder * sb)1870957b409SSimon J. Gerraty SB_free(string_builder *sb)
1880957b409SSimon J. Gerraty {
1890957b409SSimon J. Gerraty 	xfree(sb->buf);
1900957b409SSimon J. Gerraty 	xfree(sb);
1910957b409SSimon J. Gerraty }
1920957b409SSimon J. Gerraty 
1930957b409SSimon J. Gerraty typedef struct ht_elt_ {
1940957b409SSimon J. Gerraty 	char *name;
1950957b409SSimon J. Gerraty 	void *value;
1960957b409SSimon J. Gerraty 	struct ht_elt_ *next;
1970957b409SSimon J. Gerraty } ht_elt;
1980957b409SSimon J. Gerraty 
1990957b409SSimon J. Gerraty typedef struct {
2000957b409SSimon J. Gerraty 	size_t size;
2010957b409SSimon J. Gerraty 	ht_elt **buckets;
2020957b409SSimon J. Gerraty 	size_t num_buckets;
2030957b409SSimon J. Gerraty } HT;
2040957b409SSimon J. Gerraty 
2050957b409SSimon J. Gerraty static HT *
HT_new(void)2060957b409SSimon J. Gerraty HT_new(void)
2070957b409SSimon J. Gerraty {
2080957b409SSimon J. Gerraty 	HT *ht;
2090957b409SSimon J. Gerraty 	size_t u;
2100957b409SSimon J. Gerraty 
2110957b409SSimon J. Gerraty 	ht = xmalloc(sizeof *ht);
2120957b409SSimon J. Gerraty 	ht->size = 0;
2130957b409SSimon J. Gerraty 	ht->num_buckets = 8;
2140957b409SSimon J. Gerraty 	ht->buckets = xmalloc(ht->num_buckets * sizeof(ht_elt *));
2150957b409SSimon J. Gerraty 	for (u = 0; u < ht->num_buckets; u ++) {
2160957b409SSimon J. Gerraty 		ht->buckets[u] = NULL;
2170957b409SSimon J. Gerraty 	}
2180957b409SSimon J. Gerraty 	return ht;
2190957b409SSimon J. Gerraty }
2200957b409SSimon J. Gerraty 
2210957b409SSimon J. Gerraty static uint32_t
hash_string(const char * name)2220957b409SSimon J. Gerraty hash_string(const char *name)
2230957b409SSimon J. Gerraty {
2240957b409SSimon J. Gerraty 	uint32_t hc;
2250957b409SSimon J. Gerraty 
2260957b409SSimon J. Gerraty 	hc = 0;
2270957b409SSimon J. Gerraty 	while (*name) {
2280957b409SSimon J. Gerraty 		int x;
2290957b409SSimon J. Gerraty 
2300957b409SSimon J. Gerraty 		hc = (hc << 5) - hc;
2310957b409SSimon J. Gerraty 		x = *(const unsigned char *)name;
2320957b409SSimon J. Gerraty 		if (x >= 'A' && x <= 'Z') {
2330957b409SSimon J. Gerraty 			x += 'a' - 'A';
2340957b409SSimon J. Gerraty 		}
2350957b409SSimon J. Gerraty 		hc += (uint32_t)x;
2360957b409SSimon J. Gerraty 		name ++;
2370957b409SSimon J. Gerraty 	}
2380957b409SSimon J. Gerraty 	return hc;
2390957b409SSimon J. Gerraty }
2400957b409SSimon J. Gerraty 
2410957b409SSimon J. Gerraty static int
eqstring(const char * s1,const char * s2)2420957b409SSimon J. Gerraty eqstring(const char *s1, const char *s2)
2430957b409SSimon J. Gerraty {
2440957b409SSimon J. Gerraty 	while (*s1 && *s2) {
2450957b409SSimon J. Gerraty 		int x1, x2;
2460957b409SSimon J. Gerraty 
2470957b409SSimon J. Gerraty 		x1 = *(const unsigned char *)s1;
2480957b409SSimon J. Gerraty 		x2 = *(const unsigned char *)s2;
2490957b409SSimon J. Gerraty 		if (x1 >= 'A' && x1 <= 'Z') {
2500957b409SSimon J. Gerraty 			x1 += 'a' - 'A';
2510957b409SSimon J. Gerraty 		}
2520957b409SSimon J. Gerraty 		if (x2 >= 'A' && x2 <= 'Z') {
2530957b409SSimon J. Gerraty 			x2 += 'a' - 'A';
2540957b409SSimon J. Gerraty 		}
2550957b409SSimon J. Gerraty 		if (x1 != x2) {
2560957b409SSimon J. Gerraty 			return 0;
2570957b409SSimon J. Gerraty 		}
2580957b409SSimon J. Gerraty 		s1 ++;
2590957b409SSimon J. Gerraty 		s2 ++;
2600957b409SSimon J. Gerraty 	}
2610957b409SSimon J. Gerraty 	return !(*s1 || *s2);
2620957b409SSimon J. Gerraty }
2630957b409SSimon J. Gerraty 
2640957b409SSimon J. Gerraty static void
HT_expand(HT * ht)2650957b409SSimon J. Gerraty HT_expand(HT *ht)
2660957b409SSimon J. Gerraty {
2670957b409SSimon J. Gerraty 	size_t n, n2, u;
2680957b409SSimon J. Gerraty 	ht_elt **new_buckets;
2690957b409SSimon J. Gerraty 
2700957b409SSimon J. Gerraty 	n = ht->num_buckets;
2710957b409SSimon J. Gerraty 	n2 = n << 1;
2720957b409SSimon J. Gerraty 	new_buckets = xmalloc(n2 * sizeof *new_buckets);
2730957b409SSimon J. Gerraty 	for (u = 0; u < n2; u ++) {
2740957b409SSimon J. Gerraty 		new_buckets[u] = NULL;
2750957b409SSimon J. Gerraty 	}
2760957b409SSimon J. Gerraty 	for (u = 0; u < n; u ++) {
2770957b409SSimon J. Gerraty 		ht_elt *e, *f;
2780957b409SSimon J. Gerraty 
2790957b409SSimon J. Gerraty 		f = NULL;
2800957b409SSimon J. Gerraty 		for (e = ht->buckets[u]; e != NULL; e = f) {
2810957b409SSimon J. Gerraty 			uint32_t hc;
2820957b409SSimon J. Gerraty 			size_t v;
2830957b409SSimon J. Gerraty 
2840957b409SSimon J. Gerraty 			hc = hash_string(e->name);
2850957b409SSimon J. Gerraty 			v = (size_t)(hc & ((uint32_t)n2 - 1));
2860957b409SSimon J. Gerraty 			f = e->next;
2870957b409SSimon J. Gerraty 			e->next = new_buckets[v];
2880957b409SSimon J. Gerraty 			new_buckets[v] = e;
2890957b409SSimon J. Gerraty 		}
2900957b409SSimon J. Gerraty 	}
2910957b409SSimon J. Gerraty 	xfree(ht->buckets);
2920957b409SSimon J. Gerraty 	ht->buckets = new_buckets;
2930957b409SSimon J. Gerraty 	ht->num_buckets = n2;
2940957b409SSimon J. Gerraty }
2950957b409SSimon J. Gerraty 
2960957b409SSimon J. Gerraty static void *
HT_put(HT * ht,const char * name,void * value)2970957b409SSimon J. Gerraty HT_put(HT *ht, const char *name, void *value)
2980957b409SSimon J. Gerraty {
2990957b409SSimon J. Gerraty 	uint32_t hc;
3000957b409SSimon J. Gerraty 	size_t k;
3010957b409SSimon J. Gerraty 	ht_elt *e, **prev;
3020957b409SSimon J. Gerraty 
3030957b409SSimon J. Gerraty 	hc = hash_string(name);
3040957b409SSimon J. Gerraty 	k = (size_t)(hc & ((uint32_t)ht->num_buckets - 1));
3050957b409SSimon J. Gerraty 	prev = &ht->buckets[k];
3060957b409SSimon J. Gerraty 	e = *prev;
3070957b409SSimon J. Gerraty 	while (e != NULL) {
3080957b409SSimon J. Gerraty 		if (eqstring(name, e->name)) {
3090957b409SSimon J. Gerraty 			void *old_value;
3100957b409SSimon J. Gerraty 
3110957b409SSimon J. Gerraty 			old_value = e->value;
3120957b409SSimon J. Gerraty 			if (value == NULL) {
3130957b409SSimon J. Gerraty 				*prev = e->next;
3140957b409SSimon J. Gerraty 				xfree(e->name);
3150957b409SSimon J. Gerraty 				xfree(e);
3160957b409SSimon J. Gerraty 				ht->size --;
3170957b409SSimon J. Gerraty 			} else {
3180957b409SSimon J. Gerraty 				e->value = value;
3190957b409SSimon J. Gerraty 			}
3200957b409SSimon J. Gerraty 			return old_value;
3210957b409SSimon J. Gerraty 		}
3220957b409SSimon J. Gerraty 		prev = &e->next;
3230957b409SSimon J. Gerraty 		e = *prev;
3240957b409SSimon J. Gerraty 	}
3250957b409SSimon J. Gerraty 	if (value != NULL) {
3260957b409SSimon J. Gerraty 		e = xmalloc(sizeof *e);
3270957b409SSimon J. Gerraty 		e->name = xstrdup(name);
3280957b409SSimon J. Gerraty 		e->value = value;
3290957b409SSimon J. Gerraty 		e->next = ht->buckets[k];
3300957b409SSimon J. Gerraty 		ht->buckets[k] = e;
3310957b409SSimon J. Gerraty 		ht->size ++;
3320957b409SSimon J. Gerraty 		if (ht->size > ht->num_buckets) {
3330957b409SSimon J. Gerraty 			HT_expand(ht);
3340957b409SSimon J. Gerraty 		}
3350957b409SSimon J. Gerraty 	}
3360957b409SSimon J. Gerraty 	return NULL;
3370957b409SSimon J. Gerraty }
3380957b409SSimon J. Gerraty 
3390957b409SSimon J. Gerraty /* unused
3400957b409SSimon J. Gerraty static void *
3410957b409SSimon J. Gerraty HT_remove(HT *ht, const char *name)
3420957b409SSimon J. Gerraty {
3430957b409SSimon J. Gerraty 	return HT_put(ht, name, NULL);
3440957b409SSimon J. Gerraty }
3450957b409SSimon J. Gerraty */
3460957b409SSimon J. Gerraty 
3470957b409SSimon J. Gerraty static void *
HT_get(const HT * ht,const char * name)3480957b409SSimon J. Gerraty HT_get(const HT *ht, const char *name)
3490957b409SSimon J. Gerraty {
3500957b409SSimon J. Gerraty 	uint32_t hc;
3510957b409SSimon J. Gerraty 	size_t k;
3520957b409SSimon J. Gerraty 	ht_elt *e;
3530957b409SSimon J. Gerraty 
3540957b409SSimon J. Gerraty 	hc = hash_string(name);
3550957b409SSimon J. Gerraty 	k = (size_t)(hc & ((uint32_t)ht->num_buckets - 1));
3560957b409SSimon J. Gerraty 	for (e = ht->buckets[k]; e != NULL; e = e->next) {
3570957b409SSimon J. Gerraty 		if (eqstring(name, e->name)) {
3580957b409SSimon J. Gerraty 			return e->value;
3590957b409SSimon J. Gerraty 		}
3600957b409SSimon J. Gerraty 	}
3610957b409SSimon J. Gerraty 	return NULL;
3620957b409SSimon J. Gerraty }
3630957b409SSimon J. Gerraty 
3640957b409SSimon J. Gerraty static void
HT_clear(HT * ht,void (* free_value)(void * value))3650957b409SSimon J. Gerraty HT_clear(HT *ht, void (*free_value)(void *value))
3660957b409SSimon J. Gerraty {
3670957b409SSimon J. Gerraty 	size_t u;
3680957b409SSimon J. Gerraty 
3690957b409SSimon J. Gerraty 	for (u = 0; u < ht->num_buckets; u ++) {
3700957b409SSimon J. Gerraty 		ht_elt *e, *f;
3710957b409SSimon J. Gerraty 
3720957b409SSimon J. Gerraty 		f = NULL;
3730957b409SSimon J. Gerraty 		for (e = ht->buckets[u]; e != NULL; e = f) {
3740957b409SSimon J. Gerraty 			f = e->next;
3750957b409SSimon J. Gerraty 			xfree(e->name);
3760957b409SSimon J. Gerraty 			if (free_value != 0) {
3770957b409SSimon J. Gerraty 				free_value(e->value);
3780957b409SSimon J. Gerraty 			}
3790957b409SSimon J. Gerraty 			xfree(e);
3800957b409SSimon J. Gerraty 		}
3810957b409SSimon J. Gerraty 		ht->buckets[u] = NULL;
3820957b409SSimon J. Gerraty 	}
3830957b409SSimon J. Gerraty 	ht->size = 0;
3840957b409SSimon J. Gerraty }
3850957b409SSimon J. Gerraty 
3860957b409SSimon J. Gerraty static void
HT_free(HT * ht,void (* free_value)(void * value))3870957b409SSimon J. Gerraty HT_free(HT *ht, void (*free_value)(void *value))
3880957b409SSimon J. Gerraty {
3890957b409SSimon J. Gerraty 	HT_clear(ht, free_value);
3900957b409SSimon J. Gerraty 	xfree(ht->buckets);
3910957b409SSimon J. Gerraty 	xfree(ht);
3920957b409SSimon J. Gerraty }
3930957b409SSimon J. Gerraty 
3940957b409SSimon J. Gerraty /* unused
3950957b409SSimon J. Gerraty static size_t
3960957b409SSimon J. Gerraty HT_size(HT *ht)
3970957b409SSimon J. Gerraty {
3980957b409SSimon J. Gerraty 	return ht->size;
3990957b409SSimon J. Gerraty }
4000957b409SSimon J. Gerraty */
4010957b409SSimon J. Gerraty 
4020957b409SSimon J. Gerraty static unsigned char *
read_all(FILE * f,size_t * len)4030957b409SSimon J. Gerraty read_all(FILE *f, size_t *len)
4040957b409SSimon J. Gerraty {
4050957b409SSimon J. Gerraty 	unsigned char *buf;
4060957b409SSimon J. Gerraty 	size_t ptr, blen;
4070957b409SSimon J. Gerraty 
4080957b409SSimon J. Gerraty 	blen = 1024;
4090957b409SSimon J. Gerraty 	buf = xmalloc(blen);
4100957b409SSimon J. Gerraty 	ptr = 0;
4110957b409SSimon J. Gerraty 	for (;;) {
4120957b409SSimon J. Gerraty 		size_t rlen;
4130957b409SSimon J. Gerraty 
4140957b409SSimon J. Gerraty 		if (ptr == blen) {
4150957b409SSimon J. Gerraty 			unsigned char *buf2;
4160957b409SSimon J. Gerraty 
4170957b409SSimon J. Gerraty 			blen <<= 1;
4180957b409SSimon J. Gerraty 			buf2 = xmalloc(blen);
4190957b409SSimon J. Gerraty 			memcpy(buf2, buf, ptr);
4200957b409SSimon J. Gerraty 			xfree(buf);
4210957b409SSimon J. Gerraty 			buf = buf2;
4220957b409SSimon J. Gerraty 		}
4230957b409SSimon J. Gerraty 		rlen = fread(buf + ptr, 1, blen - ptr, f);
4240957b409SSimon J. Gerraty 		if (rlen == 0) {
4250957b409SSimon J. Gerraty 			unsigned char *buf3;
4260957b409SSimon J. Gerraty 
4270957b409SSimon J. Gerraty 			buf3 = xmalloc(ptr);
4280957b409SSimon J. Gerraty 			memcpy(buf3, buf, ptr);
4290957b409SSimon J. Gerraty 			xfree(buf);
4300957b409SSimon J. Gerraty 			*len = ptr;
4310957b409SSimon J. Gerraty 			return buf3;
4320957b409SSimon J. Gerraty 		}
4330957b409SSimon J. Gerraty 		ptr += rlen;
4340957b409SSimon J. Gerraty 	}
4350957b409SSimon J. Gerraty }
4360957b409SSimon J. Gerraty 
4370957b409SSimon J. Gerraty static unsigned char *
read_file(const char * name,size_t * len)4380957b409SSimon J. Gerraty read_file(const char *name, size_t *len)
4390957b409SSimon J. Gerraty {
4400957b409SSimon J. Gerraty 	FILE *f;
4410957b409SSimon J. Gerraty 	unsigned char *buf;
4420957b409SSimon J. Gerraty 
4430957b409SSimon J. Gerraty #ifdef DIRNAME
4440957b409SSimon J. Gerraty 	char *dname;
4450957b409SSimon J. Gerraty 
4460957b409SSimon J. Gerraty 	dname = xmalloc(strlen(DIRNAME) + strlen(name) + 2);
4470957b409SSimon J. Gerraty 	sprintf(dname, "%s/%s", DIRNAME, name);
4480957b409SSimon J. Gerraty 	name = dname;
4490957b409SSimon J. Gerraty #endif
4500957b409SSimon J. Gerraty 	f = fopen(name, "rb");
4510957b409SSimon J. Gerraty 	if (f == NULL) {
4520957b409SSimon J. Gerraty 		fprintf(stderr, "could not open file '%s'\n", name);
4530957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
4540957b409SSimon J. Gerraty 	}
4550957b409SSimon J. Gerraty 	buf = read_all(f, len);
4560957b409SSimon J. Gerraty 	if (ferror(f)) {
4570957b409SSimon J. Gerraty 		fprintf(stderr, "read error on file '%s'\n", name);
4580957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
4590957b409SSimon J. Gerraty 	}
4600957b409SSimon J. Gerraty 	fclose(f);
4610957b409SSimon J. Gerraty #ifdef DIRNAME
4620957b409SSimon J. Gerraty 	xfree(dname);
4630957b409SSimon J. Gerraty #endif
4640957b409SSimon J. Gerraty 	return buf;
4650957b409SSimon J. Gerraty }
4660957b409SSimon J. Gerraty 
4670957b409SSimon J. Gerraty static int
parse_dec(const char * s,unsigned len,int * val)4680957b409SSimon J. Gerraty parse_dec(const char *s, unsigned len, int *val)
4690957b409SSimon J. Gerraty {
4700957b409SSimon J. Gerraty 	int acc;
4710957b409SSimon J. Gerraty 
4720957b409SSimon J. Gerraty 	acc = 0;
4730957b409SSimon J. Gerraty 	while (len -- > 0) {
4740957b409SSimon J. Gerraty 		int c;
4750957b409SSimon J. Gerraty 
4760957b409SSimon J. Gerraty 		c = *s ++;
4770957b409SSimon J. Gerraty 		if (c >= '0' && c <= '9') {
4780957b409SSimon J. Gerraty 			acc = (acc * 10) + (c - '0');
4790957b409SSimon J. Gerraty 		} else {
4800957b409SSimon J. Gerraty 			return -1;
4810957b409SSimon J. Gerraty 		}
4820957b409SSimon J. Gerraty 	}
4830957b409SSimon J. Gerraty 	*val = acc;
4840957b409SSimon J. Gerraty 	return 0;
4850957b409SSimon J. Gerraty }
4860957b409SSimon J. Gerraty 
4870957b409SSimon J. Gerraty static int
parse_choice(const char * s,const char * acceptable)4880957b409SSimon J. Gerraty parse_choice(const char *s, const char *acceptable)
4890957b409SSimon J. Gerraty {
4900957b409SSimon J. Gerraty 	int c;
4910957b409SSimon J. Gerraty 
4920957b409SSimon J. Gerraty 	c = *s;
4930957b409SSimon J. Gerraty 	while (*acceptable) {
4940957b409SSimon J. Gerraty 		if (c == *acceptable ++) {
4950957b409SSimon J. Gerraty 			return 0;
4960957b409SSimon J. Gerraty 		}
4970957b409SSimon J. Gerraty 	}
4980957b409SSimon J. Gerraty 	return -1;
4990957b409SSimon J. Gerraty }
5000957b409SSimon J. Gerraty 
5010957b409SSimon J. Gerraty static int
month_length(int year,int month)5020957b409SSimon J. Gerraty month_length(int year, int month)
5030957b409SSimon J. Gerraty {
5040957b409SSimon J. Gerraty 	static const int base_month_length[] = {
5050957b409SSimon J. Gerraty 		31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
5060957b409SSimon J. Gerraty 	};
5070957b409SSimon J. Gerraty 
5080957b409SSimon J. Gerraty 	int x;
5090957b409SSimon J. Gerraty 
5100957b409SSimon J. Gerraty 	x = base_month_length[month - 1];
5110957b409SSimon J. Gerraty 	if (month == 2 && year % 4 == 0
5120957b409SSimon J. Gerraty 		&& (year % 100 != 0 || year % 400 == 0))
5130957b409SSimon J. Gerraty 	{
5140957b409SSimon J. Gerraty 		x ++;
5150957b409SSimon J. Gerraty 	}
5160957b409SSimon J. Gerraty 	return x;
5170957b409SSimon J. Gerraty }
5180957b409SSimon J. Gerraty 
5190957b409SSimon J. Gerraty /*
5200957b409SSimon J. Gerraty  * Convert a time string to a days+seconds count. Returned value is 0
5210957b409SSimon J. Gerraty  * on success, -1 on error.
5220957b409SSimon J. Gerraty  */
5230957b409SSimon J. Gerraty static int
string_to_time(const char * s,uint32_t * days,uint32_t * seconds)5240957b409SSimon J. Gerraty string_to_time(const char *s, uint32_t *days, uint32_t *seconds)
5250957b409SSimon J. Gerraty {
5260957b409SSimon J. Gerraty 	int year, month, day, hour, minute, second;
5270957b409SSimon J. Gerraty 	int day_of_year, leaps, i;
5280957b409SSimon J. Gerraty 
5290957b409SSimon J. Gerraty 	if (parse_dec(s, 4, &year) < 0) {
5300957b409SSimon J. Gerraty 		return -1;
5310957b409SSimon J. Gerraty 	}
5320957b409SSimon J. Gerraty 	s += 4;
5330957b409SSimon J. Gerraty 	if (parse_choice(s ++, "-:/ ") < 0) {
5340957b409SSimon J. Gerraty 		return -1;
5350957b409SSimon J. Gerraty 	}
5360957b409SSimon J. Gerraty 	if (parse_dec(s, 2, &month) < 0) {
5370957b409SSimon J. Gerraty 		return -1;
5380957b409SSimon J. Gerraty 	}
5390957b409SSimon J. Gerraty 	s += 2;
5400957b409SSimon J. Gerraty 	if (parse_choice(s ++, "-:/ ") < 0) {
5410957b409SSimon J. Gerraty 		return -1;
5420957b409SSimon J. Gerraty 	}
5430957b409SSimon J. Gerraty 	if (parse_dec(s, 2, &day) < 0) {
5440957b409SSimon J. Gerraty 		return -1;
5450957b409SSimon J. Gerraty 	}
5460957b409SSimon J. Gerraty 	s += 2;
5470957b409SSimon J. Gerraty 	if (parse_choice(s ++, " T") < 0) {
5480957b409SSimon J. Gerraty 		return -1;
5490957b409SSimon J. Gerraty 	}
5500957b409SSimon J. Gerraty 	if (parse_dec(s, 2, &hour) < 0) {
5510957b409SSimon J. Gerraty 		return -1;
5520957b409SSimon J. Gerraty 	}
5530957b409SSimon J. Gerraty 	s += 2;
5540957b409SSimon J. Gerraty 	if (parse_choice(s ++, "-:/ ") < 0) {
5550957b409SSimon J. Gerraty 		return -1;
5560957b409SSimon J. Gerraty 	}
5570957b409SSimon J. Gerraty 	if (parse_dec(s, 2, &minute) < 0) {
5580957b409SSimon J. Gerraty 		return -1;
5590957b409SSimon J. Gerraty 	}
5600957b409SSimon J. Gerraty 	s += 2;
5610957b409SSimon J. Gerraty 	if (parse_choice(s ++, "-:/ ") < 0) {
5620957b409SSimon J. Gerraty 		return -1;
5630957b409SSimon J. Gerraty 	}
5640957b409SSimon J. Gerraty 	if (parse_dec(s, 2, &second) < 0) {
5650957b409SSimon J. Gerraty 		return -1;
5660957b409SSimon J. Gerraty 	}
5670957b409SSimon J. Gerraty 	s += 2;
5680957b409SSimon J. Gerraty 	if (*s == '.') {
5690957b409SSimon J. Gerraty 		while (*s && *s >= '0' && *s <= '9') {
5700957b409SSimon J. Gerraty 			s ++;
5710957b409SSimon J. Gerraty 		}
5720957b409SSimon J. Gerraty 	}
5730957b409SSimon J. Gerraty 	if (*s) {
5740957b409SSimon J. Gerraty 		if (*s ++ != 'Z') {
5750957b409SSimon J. Gerraty 			return -1;
5760957b409SSimon J. Gerraty 		}
5770957b409SSimon J. Gerraty 		if (*s) {
5780957b409SSimon J. Gerraty 			return -1;
5790957b409SSimon J. Gerraty 		}
5800957b409SSimon J. Gerraty 	}
5810957b409SSimon J. Gerraty 
5820957b409SSimon J. Gerraty 	if (month < 1 || month > 12) {
5830957b409SSimon J. Gerraty 		return -1;
5840957b409SSimon J. Gerraty 	}
5850957b409SSimon J. Gerraty 	day_of_year = 0;
5860957b409SSimon J. Gerraty 	for (i = 1; i < month; i ++) {
5870957b409SSimon J. Gerraty 		day_of_year += month_length(year, i);
5880957b409SSimon J. Gerraty 	}
5890957b409SSimon J. Gerraty 	if (day < 1 || day > month_length(year, month)) {
5900957b409SSimon J. Gerraty 		return -1;
5910957b409SSimon J. Gerraty 	}
5920957b409SSimon J. Gerraty 	day_of_year += (day - 1);
5930957b409SSimon J. Gerraty 	leaps = (year + 3) / 4 - (year + 99) / 100 + (year + 399) / 400;
5940957b409SSimon J. Gerraty 
5950957b409SSimon J. Gerraty 	if (hour > 23 || minute > 59 || second > 60) {
5960957b409SSimon J. Gerraty 		return -1;
5970957b409SSimon J. Gerraty 	}
5980957b409SSimon J. Gerraty 	*days = (uint32_t)year * 365 + (uint32_t)leaps + day_of_year;
5990957b409SSimon J. Gerraty 	*seconds = (uint32_t)hour * 3600 + minute * 60 + second;
6000957b409SSimon J. Gerraty 	return 0;
6010957b409SSimon J. Gerraty }
6020957b409SSimon J. Gerraty 
6030957b409SSimon J. Gerraty static FILE *conf;
6040957b409SSimon J. Gerraty static int conf_delayed_char;
6050957b409SSimon J. Gerraty static long conf_linenum;
6060957b409SSimon J. Gerraty static string_builder *line_builder;
6070957b409SSimon J. Gerraty static long current_linenum;
6080957b409SSimon J. Gerraty 
6090957b409SSimon J. Gerraty static void
conf_init(const char * fname)6100957b409SSimon J. Gerraty conf_init(const char *fname)
6110957b409SSimon J. Gerraty {
6120957b409SSimon J. Gerraty 	conf = fopen(fname, "r");
6130957b409SSimon J. Gerraty 	if (conf == NULL) {
6140957b409SSimon J. Gerraty 		fprintf(stderr, "could not open file '%s'\n", fname);
6150957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
6160957b409SSimon J. Gerraty 	}
6170957b409SSimon J. Gerraty 	conf_delayed_char = -1;
6180957b409SSimon J. Gerraty 	conf_linenum = 1;
6190957b409SSimon J. Gerraty 	line_builder = SB_new();
6200957b409SSimon J. Gerraty }
6210957b409SSimon J. Gerraty 
6220957b409SSimon J. Gerraty static void
conf_close(void)6230957b409SSimon J. Gerraty conf_close(void)
6240957b409SSimon J. Gerraty {
6250957b409SSimon J. Gerraty 	if (conf != NULL) {
6260957b409SSimon J. Gerraty 		if (ferror(conf)) {
6270957b409SSimon J. Gerraty 			fprintf(stderr, "read error on configuration file\n");
6280957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
6290957b409SSimon J. Gerraty 		}
6300957b409SSimon J. Gerraty 		fclose(conf);
6310957b409SSimon J. Gerraty 		conf = NULL;
6320957b409SSimon J. Gerraty 	}
6330957b409SSimon J. Gerraty 	if (line_builder != NULL) {
6340957b409SSimon J. Gerraty 		SB_free(line_builder);
6350957b409SSimon J. Gerraty 		line_builder = NULL;
6360957b409SSimon J. Gerraty 	}
6370957b409SSimon J. Gerraty }
6380957b409SSimon J. Gerraty 
6390957b409SSimon J. Gerraty /*
6400957b409SSimon J. Gerraty  * Get next character from the config file.
6410957b409SSimon J. Gerraty  */
6420957b409SSimon J. Gerraty static int
conf_next_low(void)6430957b409SSimon J. Gerraty conf_next_low(void)
6440957b409SSimon J. Gerraty {
6450957b409SSimon J. Gerraty 	int x;
6460957b409SSimon J. Gerraty 
6470957b409SSimon J. Gerraty 	x = conf_delayed_char;
6480957b409SSimon J. Gerraty 	if (x >= 0) {
6490957b409SSimon J. Gerraty 		conf_delayed_char = -1;
6500957b409SSimon J. Gerraty 	} else {
6510957b409SSimon J. Gerraty 		x = fgetc(conf);
6520957b409SSimon J. Gerraty 		if (x == EOF) {
6530957b409SSimon J. Gerraty 			x = -1;
6540957b409SSimon J. Gerraty 		}
6550957b409SSimon J. Gerraty 	}
6560957b409SSimon J. Gerraty 	if (x == '\r') {
6570957b409SSimon J. Gerraty 		x = fgetc(conf);
6580957b409SSimon J. Gerraty 		if (x == EOF) {
6590957b409SSimon J. Gerraty 			x = -1;
6600957b409SSimon J. Gerraty 		}
6610957b409SSimon J. Gerraty 		if (x != '\n') {
6620957b409SSimon J. Gerraty 			conf_delayed_char = x;
6630957b409SSimon J. Gerraty 			x = '\n';
6640957b409SSimon J. Gerraty 		}
6650957b409SSimon J. Gerraty 	}
6660957b409SSimon J. Gerraty 	if (x == '\n') {
6670957b409SSimon J. Gerraty 		conf_linenum ++;
6680957b409SSimon J. Gerraty 	}
6690957b409SSimon J. Gerraty 	return x;
6700957b409SSimon J. Gerraty }
6710957b409SSimon J. Gerraty 
6720957b409SSimon J. Gerraty static int
is_ws(int x)6730957b409SSimon J. Gerraty is_ws(int x)
6740957b409SSimon J. Gerraty {
6750957b409SSimon J. Gerraty 	return x <= 32;
6760957b409SSimon J. Gerraty }
6770957b409SSimon J. Gerraty 
6780957b409SSimon J. Gerraty static int
is_name_char(int c)6790957b409SSimon J. Gerraty is_name_char(int c)
6800957b409SSimon J. Gerraty {
6810957b409SSimon J. Gerraty 	return (c >= 'A' && c <= 'Z')
6820957b409SSimon J. Gerraty 		|| (c >= 'a' && c <= 'z')
6830957b409SSimon J. Gerraty 		|| (c >= '0' && c <= '9')
6840957b409SSimon J. Gerraty 		|| (c == '_' || c == '-' || c == '.');
6850957b409SSimon J. Gerraty }
6860957b409SSimon J. Gerraty 
6870957b409SSimon J. Gerraty /*
6880957b409SSimon J. Gerraty  * Read a complete line. This handles line continuation; empty lines and
6890957b409SSimon J. Gerraty  * comment lines are skipped; leading and trailing whitespace is removed.
6900957b409SSimon J. Gerraty  * Returned value is 0 (line read) or -1 (no line, EOF reached). The line
6910957b409SSimon J. Gerraty  * contents are accumulated in the line_builder.
6920957b409SSimon J. Gerraty  */
6930957b409SSimon J. Gerraty static int
conf_next_line(void)6940957b409SSimon J. Gerraty conf_next_line(void)
6950957b409SSimon J. Gerraty {
6960957b409SSimon J. Gerraty 	for (;;) {
6970957b409SSimon J. Gerraty 		int c;
6980957b409SSimon J. Gerraty 		int lcwb;
6990957b409SSimon J. Gerraty 
7000957b409SSimon J. Gerraty 		SB_reset(line_builder);
7010957b409SSimon J. Gerraty 
7020957b409SSimon J. Gerraty 		/*
7030957b409SSimon J. Gerraty 		 * Get first non-whitespace character. This skips empty
7040957b409SSimon J. Gerraty 		 * lines. Comment lines (first non-whitespace character
7050957b409SSimon J. Gerraty 		 * is a semicolon) are also skipped.
7060957b409SSimon J. Gerraty 		 */
7070957b409SSimon J. Gerraty 		for (;;) {
7080957b409SSimon J. Gerraty 			c = conf_next_low();
7090957b409SSimon J. Gerraty 			if (c < 0) {
7100957b409SSimon J. Gerraty 				return -1;
7110957b409SSimon J. Gerraty 			}
7120957b409SSimon J. Gerraty 			if (is_ws(c)) {
7130957b409SSimon J. Gerraty 				continue;
7140957b409SSimon J. Gerraty 			}
7150957b409SSimon J. Gerraty 			if (c == ';') {
7160957b409SSimon J. Gerraty 				for (;;) {
7170957b409SSimon J. Gerraty 					c = conf_next_low();
7180957b409SSimon J. Gerraty 					if (c < 0) {
7190957b409SSimon J. Gerraty 						return -1;
7200957b409SSimon J. Gerraty 					}
7210957b409SSimon J. Gerraty 					if (c == '\n') {
7220957b409SSimon J. Gerraty 						break;
7230957b409SSimon J. Gerraty 					}
7240957b409SSimon J. Gerraty 				}
7250957b409SSimon J. Gerraty 				continue;
7260957b409SSimon J. Gerraty 			}
7270957b409SSimon J. Gerraty 			break;
7280957b409SSimon J. Gerraty 		}
7290957b409SSimon J. Gerraty 
7300957b409SSimon J. Gerraty 		/*
7310957b409SSimon J. Gerraty 		 * Read up the remaining of the line. The line continuation
7320957b409SSimon J. Gerraty 		 * sequence (final backslash) is detected and processed.
7330957b409SSimon J. Gerraty 		 */
7340957b409SSimon J. Gerraty 		current_linenum = conf_linenum;
7350957b409SSimon J. Gerraty 		lcwb = (c == '\\');
7360957b409SSimon J. Gerraty 		SB_append_char(line_builder, c);
7370957b409SSimon J. Gerraty 		for (;;) {
7380957b409SSimon J. Gerraty 			c = conf_next_low();
7390957b409SSimon J. Gerraty 			if (c < 0) {
7400957b409SSimon J. Gerraty 				break;
7410957b409SSimon J. Gerraty 			}
7420957b409SSimon J. Gerraty 			if (lcwb) {
7430957b409SSimon J. Gerraty 				if (c == '\n') {
7440957b409SSimon J. Gerraty 					SB_set_length(line_builder,
7450957b409SSimon J. Gerraty 						SB_length(line_builder) - 1);
7460957b409SSimon J. Gerraty 				}
7470957b409SSimon J. Gerraty 				lcwb = 0;
7480957b409SSimon J. Gerraty 				continue;
7490957b409SSimon J. Gerraty 			}
7500957b409SSimon J. Gerraty 			if (c == '\n') {
7510957b409SSimon J. Gerraty 				break;
7520957b409SSimon J. Gerraty 			} else if (c == '\\') {
7530957b409SSimon J. Gerraty 				lcwb = 1;
7540957b409SSimon J. Gerraty 			}
7550957b409SSimon J. Gerraty 			SB_append_char(line_builder, c);
7560957b409SSimon J. Gerraty 		}
7570957b409SSimon J. Gerraty 
7580957b409SSimon J. Gerraty 		/*
7590957b409SSimon J. Gerraty 		 * Remove trailing whitespace (if any).
7600957b409SSimon J. Gerraty 		 */
7610957b409SSimon J. Gerraty 		for (;;) {
7620957b409SSimon J. Gerraty 			size_t u;
7630957b409SSimon J. Gerraty 
7640957b409SSimon J. Gerraty 			u = SB_length(line_builder);
7650957b409SSimon J. Gerraty 			if (u == 0 || !is_ws(
7660957b409SSimon J. Gerraty 				SB_contents(line_builder)[u - 1]))
7670957b409SSimon J. Gerraty 			{
7680957b409SSimon J. Gerraty 				break;
7690957b409SSimon J. Gerraty 			}
7700957b409SSimon J. Gerraty 			SB_set_length(line_builder, u - 1);
7710957b409SSimon J. Gerraty 		}
7720957b409SSimon J. Gerraty 
7730957b409SSimon J. Gerraty 		/*
7740957b409SSimon J. Gerraty 		 * We might end up with a totally empty line (in case there
7750957b409SSimon J. Gerraty 		 * was a line continuation but nothing else), in which case
7760957b409SSimon J. Gerraty 		 * we must loop.
7770957b409SSimon J. Gerraty 		 */
7780957b409SSimon J. Gerraty 		if (SB_length(line_builder) > 0) {
7790957b409SSimon J. Gerraty 			return 0;
7800957b409SSimon J. Gerraty 		}
7810957b409SSimon J. Gerraty 	}
7820957b409SSimon J. Gerraty }
7830957b409SSimon J. Gerraty 
7840957b409SSimon J. Gerraty /*
7850957b409SSimon J. Gerraty  * Test whether the current line is a section header. If yes, then the
7860957b409SSimon J. Gerraty  * header name is extracted, and returned as a newly allocated string.
7870957b409SSimon J. Gerraty  * Otherwise, NULL is returned.
7880957b409SSimon J. Gerraty  */
7890957b409SSimon J. Gerraty static char *
parse_header_name(void)7900957b409SSimon J. Gerraty parse_header_name(void)
7910957b409SSimon J. Gerraty {
7920957b409SSimon J. Gerraty 	char *buf, *name;
7930957b409SSimon J. Gerraty 	size_t u, v, w, len;
7940957b409SSimon J. Gerraty 
7950957b409SSimon J. Gerraty 	buf = SB_contents(line_builder);
7960957b409SSimon J. Gerraty 	len = SB_length(line_builder);
7970957b409SSimon J. Gerraty 	if (len < 2 || buf[0] != '[' || buf[len - 1] != ']') {
7980957b409SSimon J. Gerraty 		return NULL;
7990957b409SSimon J. Gerraty 	}
8000957b409SSimon J. Gerraty 	u = 1;
8010957b409SSimon J. Gerraty 	v = len - 1;
8020957b409SSimon J. Gerraty 	while (u < v && is_ws(buf[u])) {
8030957b409SSimon J. Gerraty 		u ++;
8040957b409SSimon J. Gerraty 	}
8050957b409SSimon J. Gerraty 	while (u < v && is_ws(buf[v - 1])) {
8060957b409SSimon J. Gerraty 		v --;
8070957b409SSimon J. Gerraty 	}
8080957b409SSimon J. Gerraty 	if (u == v) {
8090957b409SSimon J. Gerraty 		return NULL;
8100957b409SSimon J. Gerraty 	}
8110957b409SSimon J. Gerraty 	for (w = u; w < v; w ++) {
8120957b409SSimon J. Gerraty 		if (!is_name_char(buf[w])) {
8130957b409SSimon J. Gerraty 			return NULL;
8140957b409SSimon J. Gerraty 		}
8150957b409SSimon J. Gerraty 	}
8160957b409SSimon J. Gerraty 	len = v - u;
8170957b409SSimon J. Gerraty 	name = xmalloc(len + 1);
8180957b409SSimon J. Gerraty 	memcpy(name, buf + u, len);
8190957b409SSimon J. Gerraty 	name[len] = 0;
8200957b409SSimon J. Gerraty 	return name;
8210957b409SSimon J. Gerraty }
8220957b409SSimon J. Gerraty 
8230957b409SSimon J. Gerraty /*
8240957b409SSimon J. Gerraty  * Parse the current line as a 'name = value' pair. The pair is pushed into
8250957b409SSimon J. Gerraty  * the provided hash table. On error (including a duplicate key name),
8260957b409SSimon J. Gerraty  * this function returns -1; otherwise, it returns 0.
8270957b409SSimon J. Gerraty  */
8280957b409SSimon J. Gerraty static int
parse_keyvalue(HT * d)8290957b409SSimon J. Gerraty parse_keyvalue(HT *d)
8300957b409SSimon J. Gerraty {
8310957b409SSimon J. Gerraty 	char *buf, *name, *value;
8320957b409SSimon J. Gerraty 	size_t u, len;
8330957b409SSimon J. Gerraty 
8340957b409SSimon J. Gerraty 	buf = SB_contents(line_builder);
8350957b409SSimon J. Gerraty 	len = SB_length(line_builder);
8360957b409SSimon J. Gerraty 	for (u = 0; u < len; u ++) {
8370957b409SSimon J. Gerraty 		if (!is_name_char(buf[u])) {
8380957b409SSimon J. Gerraty 			break;
8390957b409SSimon J. Gerraty 		}
8400957b409SSimon J. Gerraty 	}
8410957b409SSimon J. Gerraty 	if (u == 0) {
8420957b409SSimon J. Gerraty 		return -1;
8430957b409SSimon J. Gerraty 	}
8440957b409SSimon J. Gerraty 	name = xmalloc(u + 1);
8450957b409SSimon J. Gerraty 	memcpy(name, buf, u);
8460957b409SSimon J. Gerraty 	name[u] = 0;
8470957b409SSimon J. Gerraty 	if (HT_get(d, name) != NULL) {
8480957b409SSimon J. Gerraty 		xfree(name);
8490957b409SSimon J. Gerraty 		return -1;
8500957b409SSimon J. Gerraty 	}
8510957b409SSimon J. Gerraty 	while (u < len && is_ws(buf[u])) {
8520957b409SSimon J. Gerraty 		u ++;
8530957b409SSimon J. Gerraty 	}
8540957b409SSimon J. Gerraty 	if (u >= len || buf[u] != '=') {
8550957b409SSimon J. Gerraty 		xfree(name);
8560957b409SSimon J. Gerraty 		return -1;
8570957b409SSimon J. Gerraty 	}
8580957b409SSimon J. Gerraty 	u ++;
8590957b409SSimon J. Gerraty 	while (u < len && is_ws(buf[u])) {
8600957b409SSimon J. Gerraty 		u ++;
8610957b409SSimon J. Gerraty 	}
8620957b409SSimon J. Gerraty 	value = xmalloc(len - u + 1);
8630957b409SSimon J. Gerraty 	memcpy(value, buf + u, len - u);
8640957b409SSimon J. Gerraty 	value[len - u] = 0;
8650957b409SSimon J. Gerraty 	HT_put(d, name, value);
8660957b409SSimon J. Gerraty 	xfree(name);
8670957b409SSimon J. Gerraty 	return 0;
8680957b409SSimon J. Gerraty }
8690957b409SSimon J. Gerraty 
8700957b409SSimon J. Gerraty /*
8710957b409SSimon J. Gerraty  * Public keys, indexed by name. Elements are pointers to br_x509_pkey
8720957b409SSimon J. Gerraty  * structures.
8730957b409SSimon J. Gerraty  */
8740957b409SSimon J. Gerraty static HT *keys;
8750957b409SSimon J. Gerraty 
8760957b409SSimon J. Gerraty /*
8770957b409SSimon J. Gerraty  * Trust anchors, indexed by name. Elements are pointers to
8780957b409SSimon J. Gerraty  * test_trust_anchor structures.
8790957b409SSimon J. Gerraty  */
8800957b409SSimon J. Gerraty static HT *trust_anchors;
8810957b409SSimon J. Gerraty 
8820957b409SSimon J. Gerraty typedef struct {
8830957b409SSimon J. Gerraty 	unsigned char *dn;
8840957b409SSimon J. Gerraty 	size_t dn_len;
8850957b409SSimon J. Gerraty 	unsigned flags;
8860957b409SSimon J. Gerraty 	char *key_name;
8870957b409SSimon J. Gerraty } test_trust_anchor;
8880957b409SSimon J. Gerraty 
8890957b409SSimon J. Gerraty /*
8900957b409SSimon J. Gerraty  * Test case: trust anchors, certificates (file names), key type and
8910957b409SSimon J. Gerraty  * usage, expected status and EE public key.
8920957b409SSimon J. Gerraty  */
8930957b409SSimon J. Gerraty typedef struct {
8940957b409SSimon J. Gerraty 	char *name;
8950957b409SSimon J. Gerraty 	char **ta_names;
8960957b409SSimon J. Gerraty 	char **cert_names;
8970957b409SSimon J. Gerraty 	char *servername;
8980957b409SSimon J. Gerraty 	unsigned key_type_usage;
8990957b409SSimon J. Gerraty 	unsigned status;
9000957b409SSimon J. Gerraty 	char *ee_key_name;
9010957b409SSimon J. Gerraty 	unsigned hashes;
9020957b409SSimon J. Gerraty 	uint32_t days, seconds;
9030957b409SSimon J. Gerraty } test_case;
9040957b409SSimon J. Gerraty 
9050957b409SSimon J. Gerraty static test_case *all_chains;
9060957b409SSimon J. Gerraty static size_t all_chains_ptr, all_chains_len;
9070957b409SSimon J. Gerraty 
9080957b409SSimon J. Gerraty static void
free_key(void * value)9090957b409SSimon J. Gerraty free_key(void *value)
9100957b409SSimon J. Gerraty {
9110957b409SSimon J. Gerraty 	br_x509_pkey *pk;
9120957b409SSimon J. Gerraty 
9130957b409SSimon J. Gerraty 	pk = value;
9140957b409SSimon J. Gerraty 	switch (pk->key_type) {
9150957b409SSimon J. Gerraty 	case BR_KEYTYPE_RSA:
9160957b409SSimon J. Gerraty 		xfree((void *)pk->key.rsa.n);
9170957b409SSimon J. Gerraty 		xfree((void *)pk->key.rsa.e);
9180957b409SSimon J. Gerraty 		break;
9190957b409SSimon J. Gerraty 	case BR_KEYTYPE_EC:
9200957b409SSimon J. Gerraty 		xfree((void *)pk->key.ec.q);
9210957b409SSimon J. Gerraty 		break;
9220957b409SSimon J. Gerraty 	default:
9230957b409SSimon J. Gerraty 		fprintf(stderr, "unknown key type: %d\n", pk->key_type);
9240957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
9250957b409SSimon J. Gerraty 		break;
9260957b409SSimon J. Gerraty 	}
9270957b409SSimon J. Gerraty 	xfree(pk);
9280957b409SSimon J. Gerraty }
9290957b409SSimon J. Gerraty 
9300957b409SSimon J. Gerraty static void
free_trust_anchor(void * value)9310957b409SSimon J. Gerraty free_trust_anchor(void *value)
9320957b409SSimon J. Gerraty {
9330957b409SSimon J. Gerraty 	test_trust_anchor *ttc;
9340957b409SSimon J. Gerraty 
9350957b409SSimon J. Gerraty 	ttc = value;
9360957b409SSimon J. Gerraty 	xfree(ttc->dn);
9370957b409SSimon J. Gerraty 	xfree(ttc->key_name);
9380957b409SSimon J. Gerraty 	xfree(ttc);
9390957b409SSimon J. Gerraty }
9400957b409SSimon J. Gerraty 
9410957b409SSimon J. Gerraty static void
free_test_case_contents(test_case * tc)9420957b409SSimon J. Gerraty free_test_case_contents(test_case *tc)
9430957b409SSimon J. Gerraty {
9440957b409SSimon J. Gerraty 	size_t u;
9450957b409SSimon J. Gerraty 
9460957b409SSimon J. Gerraty 	xfree(tc->name);
9470957b409SSimon J. Gerraty 	for (u = 0; tc->ta_names[u]; u ++) {
9480957b409SSimon J. Gerraty 		xfree(tc->ta_names[u]);
9490957b409SSimon J. Gerraty 	}
9500957b409SSimon J. Gerraty 	xfree(tc->ta_names);
9510957b409SSimon J. Gerraty 	for (u = 0; tc->cert_names[u]; u ++) {
9520957b409SSimon J. Gerraty 		xfree(tc->cert_names[u]);
9530957b409SSimon J. Gerraty 	}
9540957b409SSimon J. Gerraty 	xfree(tc->cert_names);
9550957b409SSimon J. Gerraty 	xfree(tc->servername);
9560957b409SSimon J. Gerraty 	xfree(tc->ee_key_name);
9570957b409SSimon J. Gerraty }
9580957b409SSimon J. Gerraty 
9590957b409SSimon J. Gerraty static char *
get_value(char * objtype,HT * objdata,long linenum,char * name)9600957b409SSimon J. Gerraty get_value(char *objtype, HT *objdata, long linenum, char *name)
9610957b409SSimon J. Gerraty {
9620957b409SSimon J. Gerraty 	char *value;
9630957b409SSimon J. Gerraty 
9640957b409SSimon J. Gerraty 	value = HT_get(objdata, name);
9650957b409SSimon J. Gerraty 	if (value == NULL) {
9660957b409SSimon J. Gerraty 		fprintf(stderr,
9670957b409SSimon J. Gerraty 			"missing property '%s' in section '%s' (line %ld)\n",
9680957b409SSimon J. Gerraty 			name, objtype, linenum);
9690957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
9700957b409SSimon J. Gerraty 	}
9710957b409SSimon J. Gerraty 	return value;
9720957b409SSimon J. Gerraty }
9730957b409SSimon J. Gerraty 
9740957b409SSimon J. Gerraty static unsigned char *
parse_hex(const char * name,long linenum,const char * value,size_t * len)9750957b409SSimon J. Gerraty parse_hex(const char *name, long linenum, const char *value, size_t *len)
9760957b409SSimon J. Gerraty {
9770957b409SSimon J. Gerraty 	unsigned char *buf;
9780957b409SSimon J. Gerraty 
9790957b409SSimon J. Gerraty 	buf = NULL;
9800957b409SSimon J. Gerraty 	for (;;) {
9810957b409SSimon J. Gerraty 		size_t u, ptr;
9820957b409SSimon J. Gerraty 		int acc, z;
9830957b409SSimon J. Gerraty 
9840957b409SSimon J. Gerraty 		ptr = 0;
9850957b409SSimon J. Gerraty 		acc = 0;
9860957b409SSimon J. Gerraty 		z = 0;
9870957b409SSimon J. Gerraty 		for (u = 0; value[u]; u ++) {
9880957b409SSimon J. Gerraty 			int c;
9890957b409SSimon J. Gerraty 
9900957b409SSimon J. Gerraty 			c = value[u];
9910957b409SSimon J. Gerraty 			if (c >= '0' && c <= '9') {
9920957b409SSimon J. Gerraty 				c -= '0';
9930957b409SSimon J. Gerraty 			} else if (c >= 'A' && c <= 'F') {
9940957b409SSimon J. Gerraty 				c -= 'A' - 10;
9950957b409SSimon J. Gerraty 			} else if (c >= 'a' && c <= 'f') {
9960957b409SSimon J. Gerraty 				c -= 'a' - 10;
9970957b409SSimon J. Gerraty 			} else if (c == ' ' || c == ':') {
9980957b409SSimon J. Gerraty 				continue;
9990957b409SSimon J. Gerraty 			} else {
10000957b409SSimon J. Gerraty 				fprintf(stderr, "invalid hexadecimal character"
10010957b409SSimon J. Gerraty 					" in '%s' (line %ld)\n",
10020957b409SSimon J. Gerraty 					name, linenum);
10030957b409SSimon J. Gerraty 				exit(EXIT_FAILURE);
10040957b409SSimon J. Gerraty 			}
10050957b409SSimon J. Gerraty 			if (z) {
10060957b409SSimon J. Gerraty 				if (buf != NULL) {
10070957b409SSimon J. Gerraty 					buf[ptr] = (acc << 4) + c;
10080957b409SSimon J. Gerraty 				}
10090957b409SSimon J. Gerraty 				ptr ++;
10100957b409SSimon J. Gerraty 			} else {
10110957b409SSimon J. Gerraty 				acc = c;
10120957b409SSimon J. Gerraty 			}
10130957b409SSimon J. Gerraty 			z = !z;
10140957b409SSimon J. Gerraty 		}
10150957b409SSimon J. Gerraty 		if (z) {
10160957b409SSimon J. Gerraty 			fprintf(stderr, "invalid hexadecimal value (partial"
10170957b409SSimon J. Gerraty 				" byte) in '%s' (line %ld)\n",
10180957b409SSimon J. Gerraty 				name, linenum);
10190957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
10200957b409SSimon J. Gerraty 		}
10210957b409SSimon J. Gerraty 		if (buf == NULL) {
10220957b409SSimon J. Gerraty 			buf = xmalloc(ptr);
10230957b409SSimon J. Gerraty 		} else {
10240957b409SSimon J. Gerraty 			*len = ptr;
10250957b409SSimon J. Gerraty 			return buf;
10260957b409SSimon J. Gerraty 		}
10270957b409SSimon J. Gerraty 	}
10280957b409SSimon J. Gerraty }
10290957b409SSimon J. Gerraty 
10300957b409SSimon J. Gerraty static char **
split_names(const char * value)10310957b409SSimon J. Gerraty split_names(const char *value)
10320957b409SSimon J. Gerraty {
10330957b409SSimon J. Gerraty 	char **names;
10340957b409SSimon J. Gerraty 	size_t len;
10350957b409SSimon J. Gerraty 
10360957b409SSimon J. Gerraty 	names = NULL;
10370957b409SSimon J. Gerraty 	len = strlen(value);
10380957b409SSimon J. Gerraty 	for (;;) {
10390957b409SSimon J. Gerraty 		size_t u, ptr;
10400957b409SSimon J. Gerraty 
10410957b409SSimon J. Gerraty 		ptr = 0;
10420957b409SSimon J. Gerraty 		u = 0;
10430957b409SSimon J. Gerraty 		while (u < len) {
10440957b409SSimon J. Gerraty 			size_t v;
10450957b409SSimon J. Gerraty 
10460957b409SSimon J. Gerraty 			while (u < len && is_ws(value[u])) {
10470957b409SSimon J. Gerraty 				u ++;
10480957b409SSimon J. Gerraty 			}
10490957b409SSimon J. Gerraty 			v = u;
10500957b409SSimon J. Gerraty 			while (v < len && !is_ws(value[v])) {
10510957b409SSimon J. Gerraty 				v ++;
10520957b409SSimon J. Gerraty 			}
10530957b409SSimon J. Gerraty 			if (v > u) {
10540957b409SSimon J. Gerraty 				if (names != NULL) {
10550957b409SSimon J. Gerraty 					char *name;
10560957b409SSimon J. Gerraty 
10570957b409SSimon J. Gerraty 					name = xmalloc(v - u + 1);
10580957b409SSimon J. Gerraty 					memcpy(name, value + u, v - u);
10590957b409SSimon J. Gerraty 					name[v - u] = 0;
10600957b409SSimon J. Gerraty 					names[ptr] = name;
10610957b409SSimon J. Gerraty 				}
10620957b409SSimon J. Gerraty 				ptr ++;
10630957b409SSimon J. Gerraty 			}
10640957b409SSimon J. Gerraty 			u = v;
10650957b409SSimon J. Gerraty 		}
10660957b409SSimon J. Gerraty 		if (names == NULL) {
10670957b409SSimon J. Gerraty 			names = xmalloc((ptr + 1) * sizeof *names);
10680957b409SSimon J. Gerraty 		} else {
10690957b409SSimon J. Gerraty 			names[ptr] = NULL;
10700957b409SSimon J. Gerraty 			return names;
10710957b409SSimon J. Gerraty 		}
10720957b409SSimon J. Gerraty 	}
10730957b409SSimon J. Gerraty }
10740957b409SSimon J. Gerraty 
10750957b409SSimon J. Gerraty static int
string_to_hash(const char * name)10760957b409SSimon J. Gerraty string_to_hash(const char *name)
10770957b409SSimon J. Gerraty {
10780957b409SSimon J. Gerraty 	char tmp[20];
10790957b409SSimon J. Gerraty 	size_t u, v;
10800957b409SSimon J. Gerraty 
10810957b409SSimon J. Gerraty 	for (u = 0, v = 0; name[u]; u ++) {
10820957b409SSimon J. Gerraty 		int c;
10830957b409SSimon J. Gerraty 
10840957b409SSimon J. Gerraty 		c = name[u];
10850957b409SSimon J. Gerraty 		if ((c >= '0' && c <= '9')
10860957b409SSimon J. Gerraty 			|| (c >= 'A' && c <= 'Z')
10870957b409SSimon J. Gerraty 			|| (c >= 'a' && c <= 'z'))
10880957b409SSimon J. Gerraty 		{
10890957b409SSimon J. Gerraty 			tmp[v ++] = c;
10900957b409SSimon J. Gerraty 			if (v == sizeof tmp) {
10910957b409SSimon J. Gerraty 				return -1;
10920957b409SSimon J. Gerraty 			}
10930957b409SSimon J. Gerraty 		}
10940957b409SSimon J. Gerraty 	}
10950957b409SSimon J. Gerraty 	tmp[v] = 0;
10960957b409SSimon J. Gerraty 	if (eqstring(tmp, "md5")) {
10970957b409SSimon J. Gerraty 		return br_md5_ID;
10980957b409SSimon J. Gerraty 	} else if (eqstring(tmp, "sha1")) {
10990957b409SSimon J. Gerraty 		return br_sha1_ID;
11000957b409SSimon J. Gerraty 	} else if (eqstring(tmp, "sha224")) {
11010957b409SSimon J. Gerraty 		return br_sha224_ID;
11020957b409SSimon J. Gerraty 	} else if (eqstring(tmp, "sha256")) {
11030957b409SSimon J. Gerraty 		return br_sha256_ID;
11040957b409SSimon J. Gerraty 	} else if (eqstring(tmp, "sha384")) {
11050957b409SSimon J. Gerraty 		return br_sha384_ID;
11060957b409SSimon J. Gerraty 	} else if (eqstring(tmp, "sha512")) {
11070957b409SSimon J. Gerraty 		return br_sha512_ID;
11080957b409SSimon J. Gerraty 	} else {
11090957b409SSimon J. Gerraty 		return -1;
11100957b409SSimon J. Gerraty 	}
11110957b409SSimon J. Gerraty }
11120957b409SSimon J. Gerraty 
11130957b409SSimon J. Gerraty static int
string_to_curve(const char * name)11140957b409SSimon J. Gerraty string_to_curve(const char *name)
11150957b409SSimon J. Gerraty {
11160957b409SSimon J. Gerraty 	char tmp[20];
11170957b409SSimon J. Gerraty 	size_t u, v;
11180957b409SSimon J. Gerraty 
11190957b409SSimon J. Gerraty 	for (u = 0, v = 0; name[u]; u ++) {
11200957b409SSimon J. Gerraty 		int c;
11210957b409SSimon J. Gerraty 
11220957b409SSimon J. Gerraty 		c = name[u];
11230957b409SSimon J. Gerraty 		if ((c >= '0' && c <= '9')
11240957b409SSimon J. Gerraty 			|| (c >= 'A' && c <= 'Z')
11250957b409SSimon J. Gerraty 			|| (c >= 'a' && c <= 'z'))
11260957b409SSimon J. Gerraty 		{
11270957b409SSimon J. Gerraty 			tmp[v ++] = c;
11280957b409SSimon J. Gerraty 			if (v == sizeof tmp) {
11290957b409SSimon J. Gerraty 				return -1;
11300957b409SSimon J. Gerraty 			}
11310957b409SSimon J. Gerraty 		}
11320957b409SSimon J. Gerraty 	}
11330957b409SSimon J. Gerraty 	tmp[v] = 0;
11340957b409SSimon J. Gerraty 	if (eqstring(tmp, "p256") || eqstring(tmp, "secp256r1")) {
11350957b409SSimon J. Gerraty 		return BR_EC_secp256r1;
11360957b409SSimon J. Gerraty 	} else if (eqstring(tmp, "p384") || eqstring(tmp, "secp384r1")) {
11370957b409SSimon J. Gerraty 		return BR_EC_secp384r1;
11380957b409SSimon J. Gerraty 	} else if (eqstring(tmp, "p521") || eqstring(tmp, "secp521r1")) {
11390957b409SSimon J. Gerraty 		return BR_EC_secp521r1;
11400957b409SSimon J. Gerraty 	} else {
11410957b409SSimon J. Gerraty 		return -1;
11420957b409SSimon J. Gerraty 	}
11430957b409SSimon J. Gerraty }
11440957b409SSimon J. Gerraty 
11450957b409SSimon J. Gerraty static void
parse_object(char * objtype,HT * objdata,long linenum)11460957b409SSimon J. Gerraty parse_object(char *objtype, HT *objdata, long linenum)
11470957b409SSimon J. Gerraty {
11480957b409SSimon J. Gerraty 	char *name;
11490957b409SSimon J. Gerraty 
11500957b409SSimon J. Gerraty 	name = get_value(objtype, objdata, linenum, "name");
11510957b409SSimon J. Gerraty 	if (eqstring(objtype, "key")) {
11520957b409SSimon J. Gerraty 		char *stype;
11530957b409SSimon J. Gerraty 		br_x509_pkey *pk;
11540957b409SSimon J. Gerraty 
11550957b409SSimon J. Gerraty 		stype = get_value(objtype, objdata, linenum, "type");
11560957b409SSimon J. Gerraty 		pk = xmalloc(sizeof *pk);
11570957b409SSimon J. Gerraty 		if (eqstring(stype, "RSA")) {
11580957b409SSimon J. Gerraty 			char *sn, *se;
11590957b409SSimon J. Gerraty 
11600957b409SSimon J. Gerraty 			sn = get_value(objtype, objdata, linenum, "n");
11610957b409SSimon J. Gerraty 			se = get_value(objtype, objdata, linenum, "e");
11620957b409SSimon J. Gerraty 			pk->key_type = BR_KEYTYPE_RSA;
11630957b409SSimon J. Gerraty 			pk->key.rsa.n = parse_hex("modulus", linenum,
11640957b409SSimon J. Gerraty 				sn, &pk->key.rsa.nlen);
11650957b409SSimon J. Gerraty 			pk->key.rsa.e = parse_hex("exponent", linenum,
11660957b409SSimon J. Gerraty 				se, &pk->key.rsa.elen);
11670957b409SSimon J. Gerraty 		} else if (eqstring(stype, "EC")) {
11680957b409SSimon J. Gerraty 			char *sc, *sq;
11690957b409SSimon J. Gerraty 			int curve;
11700957b409SSimon J. Gerraty 
11710957b409SSimon J. Gerraty 			sc = get_value(objtype, objdata, linenum, "curve");
11720957b409SSimon J. Gerraty 			sq = get_value(objtype, objdata, linenum, "q");
11730957b409SSimon J. Gerraty 			curve = string_to_curve(sc);
11740957b409SSimon J. Gerraty 			if (curve < 0) {
11750957b409SSimon J. Gerraty 				fprintf(stderr, "unknown curve name: '%s'"
11760957b409SSimon J. Gerraty 					" (line %ld)\n", sc, linenum);
11770957b409SSimon J. Gerraty 				exit(EXIT_FAILURE);
11780957b409SSimon J. Gerraty 			}
11790957b409SSimon J. Gerraty 			pk->key_type = BR_KEYTYPE_EC;
11800957b409SSimon J. Gerraty 			pk->key.ec.curve = curve;
11810957b409SSimon J. Gerraty 			pk->key.ec.q = parse_hex("public point", linenum,
11820957b409SSimon J. Gerraty 				sq, &pk->key.ec.qlen);
11830957b409SSimon J. Gerraty 		} else {
11840957b409SSimon J. Gerraty 			fprintf(stderr, "unknown key type '%s' (line %ld)\n",
11850957b409SSimon J. Gerraty 				stype, linenum);
11860957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
11870957b409SSimon J. Gerraty 		}
11880957b409SSimon J. Gerraty 		if (HT_put(keys, name, pk) != NULL) {
11890957b409SSimon J. Gerraty 			fprintf(stderr, "duplicate key: '%s' (line %ld)\n",
11900957b409SSimon J. Gerraty 				name, linenum);
11910957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
11920957b409SSimon J. Gerraty 		}
11930957b409SSimon J. Gerraty 	} else if (eqstring(objtype, "anchor")) {
11940957b409SSimon J. Gerraty 		char *dnfile, *kname, *tatype;
11950957b409SSimon J. Gerraty 		test_trust_anchor *tta;
11960957b409SSimon J. Gerraty 
11970957b409SSimon J. Gerraty 		dnfile = get_value(objtype, objdata, linenum, "DN_file");
11980957b409SSimon J. Gerraty 		kname = get_value(objtype, objdata, linenum, "key");
11990957b409SSimon J. Gerraty 		tatype = get_value(objtype, objdata, linenum, "type");
12000957b409SSimon J. Gerraty 		tta = xmalloc(sizeof *tta);
12010957b409SSimon J. Gerraty 		tta->dn = read_file(dnfile, &tta->dn_len);
12020957b409SSimon J. Gerraty 		tta->key_name = xstrdup(kname);
12030957b409SSimon J. Gerraty 		if (eqstring(tatype, "CA")) {
12040957b409SSimon J. Gerraty 			tta->flags = BR_X509_TA_CA;
12050957b409SSimon J. Gerraty 		} else if (eqstring(tatype, "EE")) {
12060957b409SSimon J. Gerraty 			tta->flags = 0;
12070957b409SSimon J. Gerraty 		} else {
12080957b409SSimon J. Gerraty 			fprintf(stderr,
12090957b409SSimon J. Gerraty 				"unknown trust anchor type: '%s' (line %ld)\n",
12100957b409SSimon J. Gerraty 				tatype, linenum);
12110957b409SSimon J. Gerraty 		}
12120957b409SSimon J. Gerraty 		if (HT_put(trust_anchors, name, tta) != NULL) {
12130957b409SSimon J. Gerraty 			fprintf(stderr,
12140957b409SSimon J. Gerraty 				"duplicate trust anchor: '%s' (line %ld)\n",
12150957b409SSimon J. Gerraty 				name, linenum);
12160957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
12170957b409SSimon J. Gerraty 		}
12180957b409SSimon J. Gerraty 	} else if (eqstring(objtype, "chain")) {
12190957b409SSimon J. Gerraty 		test_case tc;
12200957b409SSimon J. Gerraty 		char *ktype, *kusage, *sstatus, *shashes, *stime;
12210957b409SSimon J. Gerraty 
12220957b409SSimon J. Gerraty 		ktype = get_value(objtype, objdata, linenum, "keytype");
12230957b409SSimon J. Gerraty 		kusage = get_value(objtype, objdata, linenum, "keyusage");
12240957b409SSimon J. Gerraty 		sstatus = get_value(objtype, objdata, linenum, "status");
12250957b409SSimon J. Gerraty 		tc.name = xstrdup(name);
12260957b409SSimon J. Gerraty 		tc.ta_names = split_names(
12270957b409SSimon J. Gerraty 			get_value(objtype, objdata, linenum, "anchors"));
12280957b409SSimon J. Gerraty 		tc.cert_names = split_names(
12290957b409SSimon J. Gerraty 			get_value(objtype, objdata, linenum, "chain"));
12300957b409SSimon J. Gerraty 		tc.servername = xstrdup(HT_get(objdata, "servername"));
12310957b409SSimon J. Gerraty 		if (eqstring(ktype, "RSA")) {
12320957b409SSimon J. Gerraty 			tc.key_type_usage = BR_KEYTYPE_RSA;
12330957b409SSimon J. Gerraty 		} else if (eqstring(ktype, "EC")) {
12340957b409SSimon J. Gerraty 			tc.key_type_usage = BR_KEYTYPE_EC;
12350957b409SSimon J. Gerraty 		} else {
12360957b409SSimon J. Gerraty 			fprintf(stderr,
12370957b409SSimon J. Gerraty 				"unknown key type: '%s' (line %ld)\n",
12380957b409SSimon J. Gerraty 				ktype, linenum);
12390957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
12400957b409SSimon J. Gerraty 		}
12410957b409SSimon J. Gerraty 		if (eqstring(kusage, "KEYX")) {
12420957b409SSimon J. Gerraty 			tc.key_type_usage |= BR_KEYTYPE_KEYX;
12430957b409SSimon J. Gerraty 		} else if (eqstring(kusage, "SIGN")) {
12440957b409SSimon J. Gerraty 			tc.key_type_usage |= BR_KEYTYPE_SIGN;
12450957b409SSimon J. Gerraty 		} else {
12460957b409SSimon J. Gerraty 			fprintf(stderr,
12470957b409SSimon J. Gerraty 				"unknown key usage: '%s' (line %ld)\n",
12480957b409SSimon J. Gerraty 				kusage, linenum);
12490957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
12500957b409SSimon J. Gerraty 		}
12510957b409SSimon J. Gerraty 		tc.status = (unsigned)atoi(sstatus);
12520957b409SSimon J. Gerraty 		if (tc.status == 0) {
12530957b409SSimon J. Gerraty 			tc.ee_key_name = xstrdup(
12540957b409SSimon J. Gerraty 				get_value(objtype, objdata, linenum, "eekey"));
12550957b409SSimon J. Gerraty 		} else {
12560957b409SSimon J. Gerraty 			tc.ee_key_name = NULL;
12570957b409SSimon J. Gerraty 		}
12580957b409SSimon J. Gerraty 		shashes = HT_get(objdata, "hashes");
12590957b409SSimon J. Gerraty 		if (shashes == NULL) {
12600957b409SSimon J. Gerraty 			tc.hashes = (unsigned)-1;
12610957b409SSimon J. Gerraty 		} else {
12620957b409SSimon J. Gerraty 			char **hns;
12630957b409SSimon J. Gerraty 			size_t u;
12640957b409SSimon J. Gerraty 
12650957b409SSimon J. Gerraty 			tc.hashes = 0;
12660957b409SSimon J. Gerraty 			hns = split_names(shashes);
12670957b409SSimon J. Gerraty 			for (u = 0;; u ++) {
12680957b409SSimon J. Gerraty 				char *hn;
12690957b409SSimon J. Gerraty 				int id;
12700957b409SSimon J. Gerraty 
12710957b409SSimon J. Gerraty 				hn = hns[u];
12720957b409SSimon J. Gerraty 				if (hn == NULL) {
12730957b409SSimon J. Gerraty 					break;
12740957b409SSimon J. Gerraty 				}
12750957b409SSimon J. Gerraty 				id = string_to_hash(hn);
12760957b409SSimon J. Gerraty 				if (id < 0) {
12770957b409SSimon J. Gerraty 					fprintf(stderr,
12780957b409SSimon J. Gerraty 						"unknown hash function '%s'"
12790957b409SSimon J. Gerraty 						" (line %ld)\n", hn, linenum);
12800957b409SSimon J. Gerraty 					exit(EXIT_FAILURE);
12810957b409SSimon J. Gerraty 				}
12820957b409SSimon J. Gerraty 				tc.hashes |= (unsigned)1 << id;
12830957b409SSimon J. Gerraty 				xfree(hn);
12840957b409SSimon J. Gerraty 			}
12850957b409SSimon J. Gerraty 			xfree(hns);
12860957b409SSimon J. Gerraty 		}
12870957b409SSimon J. Gerraty 		stime = HT_get(objdata, "time");
12880957b409SSimon J. Gerraty 		if (stime == NULL) {
12890957b409SSimon J. Gerraty 			stime = DEFAULT_TIME;
12900957b409SSimon J. Gerraty 		}
12910957b409SSimon J. Gerraty 		if (string_to_time(stime, &tc.days, &tc.seconds) < 0) {
12920957b409SSimon J. Gerraty 			fprintf(stderr, "invalid time string '%s' (line %ld)\n",
12930957b409SSimon J. Gerraty 				stime, linenum);
12940957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
12950957b409SSimon J. Gerraty 		}
12960957b409SSimon J. Gerraty 		if (all_chains_ptr == all_chains_len) {
12970957b409SSimon J. Gerraty 			if (all_chains_len == 0) {
12980957b409SSimon J. Gerraty 				all_chains_len = 8;
12990957b409SSimon J. Gerraty 				all_chains = xmalloc(
13000957b409SSimon J. Gerraty 					all_chains_len * sizeof *all_chains);
13010957b409SSimon J. Gerraty 			} else {
13020957b409SSimon J. Gerraty 				test_case *ntc;
13030957b409SSimon J. Gerraty 				size_t nlen;
13040957b409SSimon J. Gerraty 
13050957b409SSimon J. Gerraty 				nlen = all_chains_len << 1;
13060957b409SSimon J. Gerraty 				ntc = xmalloc(nlen * sizeof *ntc);
13070957b409SSimon J. Gerraty 				memcpy(ntc, all_chains,
13080957b409SSimon J. Gerraty 					all_chains_len * sizeof *all_chains);
13090957b409SSimon J. Gerraty 				xfree(all_chains);
13100957b409SSimon J. Gerraty 				all_chains = ntc;
13110957b409SSimon J. Gerraty 				all_chains_len = nlen;
13120957b409SSimon J. Gerraty 			}
13130957b409SSimon J. Gerraty 		}
13140957b409SSimon J. Gerraty 		all_chains[all_chains_ptr ++] = tc;
13150957b409SSimon J. Gerraty 	} else {
13160957b409SSimon J. Gerraty 		fprintf(stderr, "unknown section type '%s' (line %ld)\n",
13170957b409SSimon J. Gerraty 			objtype, linenum);
13180957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
13190957b409SSimon J. Gerraty 	}
13200957b409SSimon J. Gerraty }
13210957b409SSimon J. Gerraty 
13220957b409SSimon J. Gerraty static void
process_conf_file(const char * fname)13230957b409SSimon J. Gerraty process_conf_file(const char *fname)
13240957b409SSimon J. Gerraty {
13250957b409SSimon J. Gerraty 	char *objtype;
13260957b409SSimon J. Gerraty 	HT *objdata;
13270957b409SSimon J. Gerraty 	long objlinenum;
13280957b409SSimon J. Gerraty 
13290957b409SSimon J. Gerraty 	keys = HT_new();
13300957b409SSimon J. Gerraty 	trust_anchors = HT_new();
13310957b409SSimon J. Gerraty 	all_chains = NULL;
13320957b409SSimon J. Gerraty 	all_chains_ptr = 0;
13330957b409SSimon J. Gerraty 	all_chains_len = 0;
13340957b409SSimon J. Gerraty 	conf_init(fname);
13350957b409SSimon J. Gerraty 	objtype = NULL;
13360957b409SSimon J. Gerraty 	objdata = HT_new();
13370957b409SSimon J. Gerraty 	objlinenum = 0;
13380957b409SSimon J. Gerraty 	for (;;) {
13390957b409SSimon J. Gerraty 		char *hname;
13400957b409SSimon J. Gerraty 
13410957b409SSimon J. Gerraty 		if (conf_next_line() < 0) {
13420957b409SSimon J. Gerraty 			break;
13430957b409SSimon J. Gerraty 		}
13440957b409SSimon J. Gerraty 		hname = parse_header_name();
13450957b409SSimon J. Gerraty 		if (hname != NULL) {
13460957b409SSimon J. Gerraty 			if (objtype != NULL) {
13470957b409SSimon J. Gerraty 				parse_object(objtype, objdata, objlinenum);
13480957b409SSimon J. Gerraty 				HT_clear(objdata, xfree);
13490957b409SSimon J. Gerraty 				xfree(objtype);
13500957b409SSimon J. Gerraty 			}
13510957b409SSimon J. Gerraty 			objtype = hname;
13520957b409SSimon J. Gerraty 			objlinenum = current_linenum;
13530957b409SSimon J. Gerraty 			continue;
13540957b409SSimon J. Gerraty 		}
13550957b409SSimon J. Gerraty 		if (objtype == NULL) {
13560957b409SSimon J. Gerraty 			fprintf(stderr, "no current section (line %ld)\n",
13570957b409SSimon J. Gerraty 				current_linenum);
13580957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
13590957b409SSimon J. Gerraty 		}
13600957b409SSimon J. Gerraty 		if (parse_keyvalue(objdata) < 0) {
13610957b409SSimon J. Gerraty 			fprintf(stderr, "wrong configuration, line %ld\n",
13620957b409SSimon J. Gerraty 				current_linenum);
13630957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
13640957b409SSimon J. Gerraty 		}
13650957b409SSimon J. Gerraty 	}
13660957b409SSimon J. Gerraty 	if (objtype != NULL) {
13670957b409SSimon J. Gerraty 		parse_object(objtype, objdata, objlinenum);
13680957b409SSimon J. Gerraty 		xfree(objtype);
13690957b409SSimon J. Gerraty 	}
13700957b409SSimon J. Gerraty 	HT_free(objdata, xfree);
13710957b409SSimon J. Gerraty 	conf_close();
13720957b409SSimon J. Gerraty }
13730957b409SSimon J. Gerraty 
13740957b409SSimon J. Gerraty static const struct {
13750957b409SSimon J. Gerraty 	int id;
13760957b409SSimon J. Gerraty 	const br_hash_class *impl;
13770957b409SSimon J. Gerraty } hash_impls[] = {
13780957b409SSimon J. Gerraty 	{ br_md5_ID, &br_md5_vtable },
13790957b409SSimon J. Gerraty 	{ br_sha1_ID, &br_sha1_vtable },
13800957b409SSimon J. Gerraty 	{ br_sha224_ID, &br_sha224_vtable },
13810957b409SSimon J. Gerraty 	{ br_sha256_ID, &br_sha256_vtable },
13820957b409SSimon J. Gerraty 	{ br_sha384_ID, &br_sha384_vtable },
13830957b409SSimon J. Gerraty 	{ br_sha512_ID, &br_sha512_vtable },
13840957b409SSimon J. Gerraty 	{ 0, NULL }
13850957b409SSimon J. Gerraty };
13860957b409SSimon J. Gerraty 
13870957b409SSimon J. Gerraty typedef struct {
13880957b409SSimon J. Gerraty 	unsigned char *data;
13890957b409SSimon J. Gerraty 	size_t len;
13900957b409SSimon J. Gerraty } blob;
13910957b409SSimon J. Gerraty 
13920957b409SSimon J. Gerraty static int
eqbigint(const unsigned char * b1,size_t b1_len,const unsigned char * b2,size_t b2_len)13930957b409SSimon J. Gerraty eqbigint(const unsigned char *b1, size_t b1_len,
13940957b409SSimon J. Gerraty 	const unsigned char *b2, size_t b2_len)
13950957b409SSimon J. Gerraty {
13960957b409SSimon J. Gerraty 	while (b1_len > 0 && *b1 == 0) {
13970957b409SSimon J. Gerraty 		b1 ++;
13980957b409SSimon J. Gerraty 		b1_len --;
13990957b409SSimon J. Gerraty 	}
14000957b409SSimon J. Gerraty 	while (b2_len > 0 && *b2 == 0) {
14010957b409SSimon J. Gerraty 		b2 ++;
14020957b409SSimon J. Gerraty 		b2_len --;
14030957b409SSimon J. Gerraty 	}
14040957b409SSimon J. Gerraty 	return b1_len == b2_len && memcmp(b1, b2, b1_len) == 0;
14050957b409SSimon J. Gerraty }
14060957b409SSimon J. Gerraty 
14070957b409SSimon J. Gerraty static int
eqpkey(const br_x509_pkey * pk1,const br_x509_pkey * pk2)14080957b409SSimon J. Gerraty eqpkey(const br_x509_pkey *pk1, const br_x509_pkey *pk2)
14090957b409SSimon J. Gerraty {
14100957b409SSimon J. Gerraty 	if (pk1 == pk2) {
14110957b409SSimon J. Gerraty 		return 1;
14120957b409SSimon J. Gerraty 	}
14130957b409SSimon J. Gerraty 	if (pk1 == NULL || pk2 == NULL) {
14140957b409SSimon J. Gerraty 		return 0;
14150957b409SSimon J. Gerraty 	}
14160957b409SSimon J. Gerraty 	if (pk1->key_type != pk2->key_type) {
14170957b409SSimon J. Gerraty 		return 0;
14180957b409SSimon J. Gerraty 	}
14190957b409SSimon J. Gerraty 	switch (pk1->key_type) {
14200957b409SSimon J. Gerraty 	case BR_KEYTYPE_RSA:
14210957b409SSimon J. Gerraty 		return eqbigint(pk1->key.rsa.n, pk1->key.rsa.nlen,
14220957b409SSimon J. Gerraty 			pk2->key.rsa.n, pk2->key.rsa.nlen)
14230957b409SSimon J. Gerraty 			&& eqbigint(pk1->key.rsa.e, pk1->key.rsa.elen,
14240957b409SSimon J. Gerraty 			pk2->key.rsa.e, pk2->key.rsa.elen);
14250957b409SSimon J. Gerraty 	case BR_KEYTYPE_EC:
14260957b409SSimon J. Gerraty 		return pk1->key.ec.curve == pk2->key.ec.curve
14270957b409SSimon J. Gerraty 			&& pk1->key.ec.qlen == pk2->key.ec.qlen
14280957b409SSimon J. Gerraty 			&& memcmp(pk1->key.ec.q,
14290957b409SSimon J. Gerraty 				pk2->key.ec.q, pk1->key.ec.qlen) == 0;
14300957b409SSimon J. Gerraty 	default:
14310957b409SSimon J. Gerraty 		fprintf(stderr, "unknown key type: %d\n", pk1->key_type);
14320957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
14330957b409SSimon J. Gerraty 		break;
14340957b409SSimon J. Gerraty 	}
14350957b409SSimon J. Gerraty 	return 0;
14360957b409SSimon J. Gerraty }
14370957b409SSimon J. Gerraty 
14380957b409SSimon J. Gerraty static size_t max_dp_usage;
14390957b409SSimon J. Gerraty static size_t max_rp_usage;
14400957b409SSimon J. Gerraty 
1441*cc9e6590SSimon J. Gerraty static int
check_time(void * ctx,uint32_t nbd,uint32_t nbs,uint32_t nad,uint32_t nas)1442*cc9e6590SSimon J. Gerraty check_time(void *ctx, uint32_t nbd, uint32_t nbs, uint32_t nad, uint32_t nas)
1443*cc9e6590SSimon J. Gerraty {
1444*cc9e6590SSimon J. Gerraty 	test_case *tc;
1445*cc9e6590SSimon J. Gerraty 
1446*cc9e6590SSimon J. Gerraty 	tc = ctx;
1447*cc9e6590SSimon J. Gerraty 	if (tc->days < nbd || (tc->days == nbd && tc->seconds < nbs)) {
1448*cc9e6590SSimon J. Gerraty 		return -1;
1449*cc9e6590SSimon J. Gerraty 	}
1450*cc9e6590SSimon J. Gerraty 	if (tc->days > nad || (tc->days == nad && tc->seconds > nas)) {
1451*cc9e6590SSimon J. Gerraty 		return 1;
1452*cc9e6590SSimon J. Gerraty 	}
1453*cc9e6590SSimon J. Gerraty 	return 0;
1454*cc9e6590SSimon J. Gerraty }
1455*cc9e6590SSimon J. Gerraty 
14560957b409SSimon J. Gerraty static void
run_test_case(test_case * tc)14570957b409SSimon J. Gerraty run_test_case(test_case *tc)
14580957b409SSimon J. Gerraty {
14590957b409SSimon J. Gerraty 	br_x509_minimal_context ctx;
14600957b409SSimon J. Gerraty 	br_x509_trust_anchor *anchors;
14610957b409SSimon J. Gerraty 	size_t num_anchors;
14620957b409SSimon J. Gerraty 	size_t u;
14630957b409SSimon J. Gerraty 	const br_hash_class *dnhash;
14640957b409SSimon J. Gerraty 	size_t num_certs;
14650957b409SSimon J. Gerraty 	blob *certs;
14660957b409SSimon J. Gerraty 	br_x509_pkey *ee_pkey_ref;
14670957b409SSimon J. Gerraty 	const br_x509_pkey *ee_pkey;
14680957b409SSimon J. Gerraty 	unsigned usages;
14690957b409SSimon J. Gerraty 	unsigned status;
1470*cc9e6590SSimon J. Gerraty 	int j;
14710957b409SSimon J. Gerraty 
14720957b409SSimon J. Gerraty 	printf("%s: ", tc->name);
14730957b409SSimon J. Gerraty 	fflush(stdout);
14740957b409SSimon J. Gerraty 
14750957b409SSimon J. Gerraty 	/*
14760957b409SSimon J. Gerraty 	 * Get the hash function to use for hashing DN. We can use just
14770957b409SSimon J. Gerraty 	 * any supported hash function, but for the elegance of things,
14780957b409SSimon J. Gerraty 	 * we will use one of the hash function implementations
14790957b409SSimon J. Gerraty 	 * supported for this test case (with SHA-1 as fallback).
14800957b409SSimon J. Gerraty 	 */
14810957b409SSimon J. Gerraty 	dnhash = &br_sha1_vtable;
14820957b409SSimon J. Gerraty 	for (u = 0; hash_impls[u].id; u ++) {
14830957b409SSimon J. Gerraty 		if ((tc->hashes & ((unsigned)1 << (hash_impls[u].id))) != 0) {
14840957b409SSimon J. Gerraty 			dnhash = hash_impls[u].impl;
14850957b409SSimon J. Gerraty 		}
14860957b409SSimon J. Gerraty 	}
14870957b409SSimon J. Gerraty 
14880957b409SSimon J. Gerraty 	/*
14890957b409SSimon J. Gerraty 	 * Get trust anchors.
14900957b409SSimon J. Gerraty 	 */
14910957b409SSimon J. Gerraty 	for (num_anchors = 0; tc->ta_names[num_anchors]; num_anchors ++);
14920957b409SSimon J. Gerraty 	anchors = xmalloc(num_anchors * sizeof *anchors);
14930957b409SSimon J. Gerraty 	for (u = 0; tc->ta_names[u]; u ++) {
14940957b409SSimon J. Gerraty 		test_trust_anchor *tta;
14950957b409SSimon J. Gerraty 		br_x509_pkey *tak;
14960957b409SSimon J. Gerraty 
14970957b409SSimon J. Gerraty 		tta = HT_get(trust_anchors, tc->ta_names[u]);
14980957b409SSimon J. Gerraty 		if (tta == NULL) {
14990957b409SSimon J. Gerraty 			fprintf(stderr, "no such trust anchor: '%s'\n",
15000957b409SSimon J. Gerraty 				tc->ta_names[u]);
15010957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
15020957b409SSimon J. Gerraty 		}
15030957b409SSimon J. Gerraty 		tak = HT_get(keys, tta->key_name);
15040957b409SSimon J. Gerraty 		if (tak == NULL) {
15050957b409SSimon J. Gerraty 			fprintf(stderr, "no such public key: '%s'\n",
15060957b409SSimon J. Gerraty 				tta->key_name);
15070957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
15080957b409SSimon J. Gerraty 		}
15090957b409SSimon J. Gerraty 		anchors[u].dn.data = tta->dn;
15100957b409SSimon J. Gerraty 		anchors[u].dn.len = tta->dn_len;
15110957b409SSimon J. Gerraty 		anchors[u].flags = tta->flags;
15120957b409SSimon J. Gerraty 		anchors[u].pkey = *tak;
15130957b409SSimon J. Gerraty 	}
15140957b409SSimon J. Gerraty 
15150957b409SSimon J. Gerraty 	/*
15160957b409SSimon J. Gerraty 	 * Read all relevant certificates.
15170957b409SSimon J. Gerraty 	 */
15180957b409SSimon J. Gerraty 	for (num_certs = 0; tc->cert_names[num_certs]; num_certs ++);
15190957b409SSimon J. Gerraty 	certs = xmalloc(num_certs * sizeof *certs);
15200957b409SSimon J. Gerraty 	for (u = 0; u < num_certs; u ++) {
15210957b409SSimon J. Gerraty 		certs[u].data = read_file(tc->cert_names[u], &certs[u].len);
15220957b409SSimon J. Gerraty 	}
15230957b409SSimon J. Gerraty 
15240957b409SSimon J. Gerraty 	/*
15250957b409SSimon J. Gerraty 	 * Get expected EE public key (if any).
15260957b409SSimon J. Gerraty 	 */
15270957b409SSimon J. Gerraty 	if (tc->ee_key_name == NULL) {
15280957b409SSimon J. Gerraty 		ee_pkey_ref = NULL;
15290957b409SSimon J. Gerraty 	} else {
15300957b409SSimon J. Gerraty 		ee_pkey_ref = HT_get(keys, tc->ee_key_name);
15310957b409SSimon J. Gerraty 		if (ee_pkey_ref == NULL) {
15320957b409SSimon J. Gerraty 			fprintf(stderr, "no such public key: '%s'\n",
15330957b409SSimon J. Gerraty 				tc->ee_key_name);
15340957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
15350957b409SSimon J. Gerraty 		}
15360957b409SSimon J. Gerraty 	}
15370957b409SSimon J. Gerraty 
15380957b409SSimon J. Gerraty 	/*
1539*cc9e6590SSimon J. Gerraty 	 * We do the test twice, to exercise distinct API functions.
1540*cc9e6590SSimon J. Gerraty 	 */
1541*cc9e6590SSimon J. Gerraty 	for (j = 0; j < 2; j ++) {
1542*cc9e6590SSimon J. Gerraty 		/*
15430957b409SSimon J. Gerraty 		 * Initialise the engine.
15440957b409SSimon J. Gerraty 		 */
15450957b409SSimon J. Gerraty 		br_x509_minimal_init(&ctx, dnhash, anchors, num_anchors);
15460957b409SSimon J. Gerraty 		for (u = 0; hash_impls[u].id; u ++) {
15470957b409SSimon J. Gerraty 			int id;
15480957b409SSimon J. Gerraty 
15490957b409SSimon J. Gerraty 			id = hash_impls[u].id;
15500957b409SSimon J. Gerraty 			if ((tc->hashes & ((unsigned)1 << id)) != 0) {
1551*cc9e6590SSimon J. Gerraty 				br_x509_minimal_set_hash(&ctx,
1552*cc9e6590SSimon J. Gerraty 					id, hash_impls[u].impl);
15530957b409SSimon J. Gerraty 			}
15540957b409SSimon J. Gerraty 		}
15550957b409SSimon J. Gerraty 		br_x509_minimal_set_rsa(&ctx, br_rsa_pkcs1_vrfy_get_default());
15560957b409SSimon J. Gerraty 		br_x509_minimal_set_ecdsa(&ctx,
15570957b409SSimon J. Gerraty 			br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
15580957b409SSimon J. Gerraty 
15590957b409SSimon J. Gerraty 		/*
15600957b409SSimon J. Gerraty 		 * Set the validation date.
15610957b409SSimon J. Gerraty 		 */
1562*cc9e6590SSimon J. Gerraty 		if (j == 0) {
15630957b409SSimon J. Gerraty 			br_x509_minimal_set_time(&ctx, tc->days, tc->seconds);
1564*cc9e6590SSimon J. Gerraty 		} else {
1565*cc9e6590SSimon J. Gerraty 			br_x509_minimal_set_time_callback(&ctx,
1566*cc9e6590SSimon J. Gerraty 				tc, &check_time);
1567*cc9e6590SSimon J. Gerraty 		}
15680957b409SSimon J. Gerraty 
15690957b409SSimon J. Gerraty 		/*
15700957b409SSimon J. Gerraty 		 * Put "canaries" to detect actual stack usage.
15710957b409SSimon J. Gerraty 		 */
1572*cc9e6590SSimon J. Gerraty 		for (u = 0; u < (sizeof ctx.dp_stack) / sizeof(uint32_t);
1573*cc9e6590SSimon J. Gerraty 			u ++)
1574*cc9e6590SSimon J. Gerraty 		{
15750957b409SSimon J. Gerraty 			ctx.dp_stack[u] = 0xA7C083FE;
15760957b409SSimon J. Gerraty 		}
1577*cc9e6590SSimon J. Gerraty 		for (u = 0; u < (sizeof ctx.rp_stack) / sizeof(uint32_t);
1578*cc9e6590SSimon J. Gerraty 			u ++)
1579*cc9e6590SSimon J. Gerraty 		{
15800957b409SSimon J. Gerraty 			ctx.rp_stack[u] = 0xA7C083FE;
15810957b409SSimon J. Gerraty 		}
15820957b409SSimon J. Gerraty 
15830957b409SSimon J. Gerraty 		/*
1584*cc9e6590SSimon J. Gerraty 		 * Run the engine. We inject certificates by chunks of 100
1585*cc9e6590SSimon J. Gerraty 		 * bytes in order to exercise the coroutine API.
15860957b409SSimon J. Gerraty 		 */
15870957b409SSimon J. Gerraty 		ctx.vtable->start_chain(&ctx.vtable, tc->servername);
15880957b409SSimon J. Gerraty 		for (u = 0; u < num_certs; u ++) {
15890957b409SSimon J. Gerraty 			size_t v;
15900957b409SSimon J. Gerraty 
15910957b409SSimon J. Gerraty 			ctx.vtable->start_cert(&ctx.vtable, certs[u].len);
15920957b409SSimon J. Gerraty 			v = 0;
15930957b409SSimon J. Gerraty 			while (v < certs[u].len) {
15940957b409SSimon J. Gerraty 				size_t w;
15950957b409SSimon J. Gerraty 
15960957b409SSimon J. Gerraty 				w = certs[u].len - v;
15970957b409SSimon J. Gerraty 				if (w > 100) {
15980957b409SSimon J. Gerraty 					w = 100;
15990957b409SSimon J. Gerraty 				}
1600*cc9e6590SSimon J. Gerraty 				ctx.vtable->append(&ctx.vtable,
1601*cc9e6590SSimon J. Gerraty 					certs[u].data + v, w);
16020957b409SSimon J. Gerraty 				v += w;
16030957b409SSimon J. Gerraty 			}
16040957b409SSimon J. Gerraty 			ctx.vtable->end_cert(&ctx.vtable);
16050957b409SSimon J. Gerraty 		}
16060957b409SSimon J. Gerraty 		status = ctx.vtable->end_chain(&ctx.vtable);
16070957b409SSimon J. Gerraty 		ee_pkey = ctx.vtable->get_pkey(&ctx.vtable, &usages);
16080957b409SSimon J. Gerraty 
16090957b409SSimon J. Gerraty 		/*
16100957b409SSimon J. Gerraty 		 * Check key type and usage.
16110957b409SSimon J. Gerraty 		 */
16120957b409SSimon J. Gerraty 		if (ee_pkey != NULL) {
16130957b409SSimon J. Gerraty 			unsigned ktu;
16140957b409SSimon J. Gerraty 
16150957b409SSimon J. Gerraty 			ktu = ee_pkey->key_type | usages;
16160957b409SSimon J. Gerraty 			if (tc->key_type_usage != (ktu & tc->key_type_usage)) {
16170957b409SSimon J. Gerraty 				fprintf(stderr, "wrong key type + usage"
16180957b409SSimon J. Gerraty 					" (expected 0x%02X, got 0x%02X)\n",
16190957b409SSimon J. Gerraty 					tc->key_type_usage, ktu);
16200957b409SSimon J. Gerraty 				exit(EXIT_FAILURE);
16210957b409SSimon J. Gerraty 			}
16220957b409SSimon J. Gerraty 		}
16230957b409SSimon J. Gerraty 
16240957b409SSimon J. Gerraty 		/*
16250957b409SSimon J. Gerraty 		 * Check results. Note that we may still get a public key if
16260957b409SSimon J. Gerraty 		 * the path is "not trusted" (but otherwise fine).
16270957b409SSimon J. Gerraty 		 */
16280957b409SSimon J. Gerraty 		if (status != tc->status) {
16290957b409SSimon J. Gerraty 			fprintf(stderr, "wrong status (got %d, expected %d)\n",
16300957b409SSimon J. Gerraty 				status, tc->status);
16310957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
16320957b409SSimon J. Gerraty 		}
16330957b409SSimon J. Gerraty 		if (status == BR_ERR_X509_NOT_TRUSTED) {
16340957b409SSimon J. Gerraty 			ee_pkey = NULL;
16350957b409SSimon J. Gerraty 		}
16360957b409SSimon J. Gerraty 		if (!eqpkey(ee_pkey, ee_pkey_ref)) {
16370957b409SSimon J. Gerraty 			fprintf(stderr, "wrong EE public key\n");
16380957b409SSimon J. Gerraty 			exit(EXIT_FAILURE);
16390957b409SSimon J. Gerraty 		}
16400957b409SSimon J. Gerraty 
16410957b409SSimon J. Gerraty 		/*
16420957b409SSimon J. Gerraty 		 * Check stack usage.
16430957b409SSimon J. Gerraty 		 */
1644*cc9e6590SSimon J. Gerraty 		for (u = (sizeof ctx.dp_stack) / sizeof(uint32_t);
1645*cc9e6590SSimon J. Gerraty 			u > 0; u --)
1646*cc9e6590SSimon J. Gerraty 		{
16470957b409SSimon J. Gerraty 			if (ctx.dp_stack[u - 1] != 0xA7C083FE) {
16480957b409SSimon J. Gerraty 				if (max_dp_usage < u) {
16490957b409SSimon J. Gerraty 					max_dp_usage = u;
16500957b409SSimon J. Gerraty 				}
16510957b409SSimon J. Gerraty 				break;
16520957b409SSimon J. Gerraty 			}
16530957b409SSimon J. Gerraty 		}
1654*cc9e6590SSimon J. Gerraty 		for (u = (sizeof ctx.rp_stack) / sizeof(uint32_t);
1655*cc9e6590SSimon J. Gerraty 			u > 0; u --)
1656*cc9e6590SSimon J. Gerraty 		{
16570957b409SSimon J. Gerraty 			if (ctx.rp_stack[u - 1] != 0xA7C083FE) {
16580957b409SSimon J. Gerraty 				if (max_rp_usage < u) {
16590957b409SSimon J. Gerraty 					max_rp_usage = u;
16600957b409SSimon J. Gerraty 				}
16610957b409SSimon J. Gerraty 				break;
16620957b409SSimon J. Gerraty 			}
16630957b409SSimon J. Gerraty 		}
1664*cc9e6590SSimon J. Gerraty 	}
16650957b409SSimon J. Gerraty 
16660957b409SSimon J. Gerraty 	/*
16670957b409SSimon J. Gerraty 	 * Release everything.
16680957b409SSimon J. Gerraty 	 */
16690957b409SSimon J. Gerraty 	for (u = 0; u < num_certs; u ++) {
16700957b409SSimon J. Gerraty 		xfree(certs[u].data);
16710957b409SSimon J. Gerraty 	}
16720957b409SSimon J. Gerraty 	xfree(certs);
16730957b409SSimon J. Gerraty 	xfree(anchors);
16740957b409SSimon J. Gerraty 	printf("OK\n");
16750957b409SSimon J. Gerraty }
16760957b409SSimon J. Gerraty 
16770957b409SSimon J. Gerraty /*
16780957b409SSimon J. Gerraty  * A custom structure for tests, synchronised with the test certificate
16790957b409SSimon J. Gerraty  * names.crt.
16800957b409SSimon J. Gerraty  *
16810957b409SSimon J. Gerraty  * If num is 1 or more, then this is a DN element with OID '1.1.1.1.num'.
16820957b409SSimon J. Gerraty  * If num is -1 or less, then this is a SAN element of type -num.
16830957b409SSimon J. Gerraty  * If num is 0, then this is a SAN element of type OtherName with
16840957b409SSimon J. Gerraty  * OID 1.3.6.1.4.1.311.20.2.3 (Microsoft UPN).
16850957b409SSimon J. Gerraty  */
16860957b409SSimon J. Gerraty typedef struct {
16870957b409SSimon J. Gerraty 	int num;
16880957b409SSimon J. Gerraty 	int status;
16890957b409SSimon J. Gerraty 	const char *expected;
16900957b409SSimon J. Gerraty } name_element_test;
16910957b409SSimon J. Gerraty 
16920957b409SSimon J. Gerraty static name_element_test names_ref[] = {
16930957b409SSimon J. Gerraty 	/* === DN tests === */
16940957b409SSimon J. Gerraty 	{
16950957b409SSimon J. Gerraty 		/* [12] 66:6f:6f */
16960957b409SSimon J. Gerraty 		1, 1, "foo"
16970957b409SSimon J. Gerraty 	},
16980957b409SSimon J. Gerraty 	{
16990957b409SSimon J. Gerraty 		/* [12] 62:61:72 */
17000957b409SSimon J. Gerraty 		1, 1, "bar"
17010957b409SSimon J. Gerraty 	},
17020957b409SSimon J. Gerraty 	{
17030957b409SSimon J. Gerraty 		/* [18] 31:32:33:34 */
17040957b409SSimon J. Gerraty 		2, 1, "1234"
17050957b409SSimon J. Gerraty 	},
17060957b409SSimon J. Gerraty 	{
17070957b409SSimon J. Gerraty 		/* [19] 66:6f:6f */
17080957b409SSimon J. Gerraty 		3, 1, "foo"
17090957b409SSimon J. Gerraty 	},
17100957b409SSimon J. Gerraty 	{
17110957b409SSimon J. Gerraty 		/* [20] 66:6f:6f */
17120957b409SSimon J. Gerraty 		4, 1, "foo"
17130957b409SSimon J. Gerraty 	},
17140957b409SSimon J. Gerraty 	{
17150957b409SSimon J. Gerraty 		/* [22] 66:6f:6f */
17160957b409SSimon J. Gerraty 		5, 1, "foo"
17170957b409SSimon J. Gerraty 	},
17180957b409SSimon J. Gerraty 	{
17190957b409SSimon J. Gerraty 		/* [30] 00:66:00:6f:00:6f */
17200957b409SSimon J. Gerraty 		6, 1, "foo"
17210957b409SSimon J. Gerraty 	},
17220957b409SSimon J. Gerraty 	{
17230957b409SSimon J. Gerraty 		/* [30] fe:ff:00:66:00:6f:00:6f */
17240957b409SSimon J. Gerraty 		7, 1, "foo"
17250957b409SSimon J. Gerraty 	},
17260957b409SSimon J. Gerraty 	{
17270957b409SSimon J. Gerraty 		/* [30] ff:fe:66:00:6f:00:6f:00 */
17280957b409SSimon J. Gerraty 		8, 1, "foo"
17290957b409SSimon J. Gerraty 	},
17300957b409SSimon J. Gerraty 	{
17310957b409SSimon J. Gerraty 		/* [20] 63:61:66:e9 */
17320957b409SSimon J. Gerraty 		9, 1, "caf\xC3\xA9"
17330957b409SSimon J. Gerraty 	},
17340957b409SSimon J. Gerraty 	{
17350957b409SSimon J. Gerraty 		/* [12] 63:61:66:c3:a9 */
17360957b409SSimon J. Gerraty 		10, 1, "caf\xC3\xA9"
17370957b409SSimon J. Gerraty 	},
17380957b409SSimon J. Gerraty 	{
17390957b409SSimon J. Gerraty 		/* [12] 63:61:66:e0:83:a9 */
17400957b409SSimon J. Gerraty 		11, -1, NULL
17410957b409SSimon J. Gerraty 	},
17420957b409SSimon J. Gerraty 	{
17430957b409SSimon J. Gerraty 		/* [12] 63:61:66:e3:90:8c */
17440957b409SSimon J. Gerraty 		12, 1, "caf\xE3\x90\x8C"
17450957b409SSimon J. Gerraty 	},
17460957b409SSimon J. Gerraty 	{
17470957b409SSimon J. Gerraty 		/* [30] 00:63:00:61:00:66:34:0c */
17480957b409SSimon J. Gerraty 		13, 1, "caf\xE3\x90\x8C"
17490957b409SSimon J. Gerraty 	},
17500957b409SSimon J. Gerraty 	{
17510957b409SSimon J. Gerraty 		/* [12] 63:61:66:c3 */
17520957b409SSimon J. Gerraty 		14, -1, NULL
17530957b409SSimon J. Gerraty 	},
17540957b409SSimon J. Gerraty 	{
17550957b409SSimon J. Gerraty 		/* [30] d8:42:df:f4:00:67:00:6f */
17560957b409SSimon J. Gerraty 		15, 1, "\xF0\xA0\xAF\xB4go"
17570957b409SSimon J. Gerraty 	},
17580957b409SSimon J. Gerraty 	{
17590957b409SSimon J. Gerraty 		/* [30] 00:66:d8:42 */
17600957b409SSimon J. Gerraty 		16, -1, NULL
17610957b409SSimon J. Gerraty 	},
17620957b409SSimon J. Gerraty 	{
17630957b409SSimon J. Gerraty 		/* [30] d8:42:00:66 */
17640957b409SSimon J. Gerraty 		17, -1, NULL
17650957b409SSimon J. Gerraty 	},
17660957b409SSimon J. Gerraty 	{
17670957b409SSimon J. Gerraty 		/* [30] df:f4:00:66 */
17680957b409SSimon J. Gerraty 		18, -1, NULL
17690957b409SSimon J. Gerraty 	},
17700957b409SSimon J. Gerraty 	{
17710957b409SSimon J. Gerraty 		/* [12] 66:00:6f */
17720957b409SSimon J. Gerraty 		19, -1, NULL
17730957b409SSimon J. Gerraty 	},
17740957b409SSimon J. Gerraty 	{
17750957b409SSimon J. Gerraty 		/* [30] 00:00:34:0c */
17760957b409SSimon J. Gerraty 		20, -1, NULL
17770957b409SSimon J. Gerraty 	},
17780957b409SSimon J. Gerraty 	{
17790957b409SSimon J. Gerraty 		/* [30] 34:0c:00:00:00:66 */
17800957b409SSimon J. Gerraty 		21, -1, NULL
17810957b409SSimon J. Gerraty 	},
17820957b409SSimon J. Gerraty 	{
17830957b409SSimon J. Gerraty 		/* [12] ef:bb:bf:66:6f:6f */
17840957b409SSimon J. Gerraty 		22, 1, "foo"
17850957b409SSimon J. Gerraty 	},
17860957b409SSimon J. Gerraty 	{
17870957b409SSimon J. Gerraty 		/* [30] 00:66:ff:fe:00:6f */
17880957b409SSimon J. Gerraty 		23, -1, NULL
17890957b409SSimon J. Gerraty 	},
17900957b409SSimon J. Gerraty 	{
17910957b409SSimon J. Gerraty 		/* [30] 00:66:ff:fd:00:6f */
17920957b409SSimon J. Gerraty 		24, 1, "f\xEF\xBF\xBDo"
17930957b409SSimon J. Gerraty 	},
17940957b409SSimon J. Gerraty 
17950957b409SSimon J. Gerraty 	/* === Value not found in the DN === */
17960957b409SSimon J. Gerraty 	{
17970957b409SSimon J. Gerraty 		127, 0, NULL
17980957b409SSimon J. Gerraty 	},
17990957b409SSimon J. Gerraty 
18000957b409SSimon J. Gerraty 	/* === SAN tests === */
18010957b409SSimon J. Gerraty 	{
18020957b409SSimon J. Gerraty 		/* SAN OtherName (Microsoft UPN) */
18030957b409SSimon J. Gerraty 		0, 1, "foo@bar.com"
18040957b409SSimon J. Gerraty 	},
18050957b409SSimon J. Gerraty 	{
18060957b409SSimon J. Gerraty 		/* SAN rfc822Name */
18070957b409SSimon J. Gerraty 		-1, 1, "bar@foo.com"
18080957b409SSimon J. Gerraty 	},
18090957b409SSimon J. Gerraty 	{
18100957b409SSimon J. Gerraty 		/* SAN dNSName */
18110957b409SSimon J. Gerraty 		-2, 1, "example.com"
18120957b409SSimon J. Gerraty 	},
18130957b409SSimon J. Gerraty 	{
18140957b409SSimon J. Gerraty 		/* SAN dNSName */
18150957b409SSimon J. Gerraty 		-2, 1, "www.example.com"
18160957b409SSimon J. Gerraty 	},
18170957b409SSimon J. Gerraty 	{
18180957b409SSimon J. Gerraty 		/* uniformResourceIdentifier */
18190957b409SSimon J. Gerraty 		-6, 1, "http://www.example.com/"
18200957b409SSimon J. Gerraty 	}
18210957b409SSimon J. Gerraty };
18220957b409SSimon J. Gerraty 
18230957b409SSimon J. Gerraty static void
free_name_elements(br_name_element * elts,size_t num)18240957b409SSimon J. Gerraty free_name_elements(br_name_element *elts, size_t num)
18250957b409SSimon J. Gerraty {
18260957b409SSimon J. Gerraty 	size_t u;
18270957b409SSimon J. Gerraty 
18280957b409SSimon J. Gerraty 	for (u = 0; u < num; u ++) {
18290957b409SSimon J. Gerraty 		xfree((void *)elts[u].oid);
18300957b409SSimon J. Gerraty 		xfree(elts[u].buf);
18310957b409SSimon J. Gerraty 	}
18320957b409SSimon J. Gerraty 	xfree(elts);
18330957b409SSimon J. Gerraty }
18340957b409SSimon J. Gerraty 
18350957b409SSimon J. Gerraty static void
test_name_extraction(void)18360957b409SSimon J. Gerraty test_name_extraction(void)
18370957b409SSimon J. Gerraty {
18380957b409SSimon J. Gerraty 	unsigned char *data;
18390957b409SSimon J. Gerraty 	size_t len;
18400957b409SSimon J. Gerraty 	br_x509_minimal_context ctx;
18410957b409SSimon J. Gerraty 	uint32_t days, seconds;
18420957b409SSimon J. Gerraty 	size_t u;
18430957b409SSimon J. Gerraty 	unsigned status;
18440957b409SSimon J. Gerraty 	br_name_element *names;
18450957b409SSimon J. Gerraty 	size_t num_names;
18460957b409SSimon J. Gerraty 	int good;
18470957b409SSimon J. Gerraty 
18480957b409SSimon J. Gerraty 	printf("Name extraction: ");
18490957b409SSimon J. Gerraty 	fflush(stdout);
18500957b409SSimon J. Gerraty 	data = read_file("names.crt", &len);
18510957b409SSimon J. Gerraty 	br_x509_minimal_init(&ctx, &br_sha256_vtable, NULL, 0);
18520957b409SSimon J. Gerraty 	for (u = 0; hash_impls[u].id; u ++) {
18530957b409SSimon J. Gerraty 		int id;
18540957b409SSimon J. Gerraty 
18550957b409SSimon J. Gerraty 		id = hash_impls[u].id;
18560957b409SSimon J. Gerraty 		br_x509_minimal_set_hash(&ctx, id, hash_impls[u].impl);
18570957b409SSimon J. Gerraty 	}
18580957b409SSimon J. Gerraty 	br_x509_minimal_set_rsa(&ctx, br_rsa_pkcs1_vrfy_get_default());
18590957b409SSimon J. Gerraty 	br_x509_minimal_set_ecdsa(&ctx,
18600957b409SSimon J. Gerraty 		br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
18610957b409SSimon J. Gerraty 	string_to_time(DEFAULT_TIME, &days, &seconds);
18620957b409SSimon J. Gerraty 	br_x509_minimal_set_time(&ctx, days, seconds);
18630957b409SSimon J. Gerraty 
18640957b409SSimon J. Gerraty 	num_names = (sizeof names_ref) / (sizeof names_ref[0]);
18650957b409SSimon J. Gerraty 	names = xmalloc(num_names * sizeof *names);
18660957b409SSimon J. Gerraty 	for (u = 0; u < num_names; u ++) {
18670957b409SSimon J. Gerraty 		int num;
18680957b409SSimon J. Gerraty 		unsigned char *oid;
18690957b409SSimon J. Gerraty 
18700957b409SSimon J. Gerraty 		num = names_ref[u].num;
18710957b409SSimon J. Gerraty 		if (num > 0) {
18720957b409SSimon J. Gerraty 			oid = xmalloc(5);
18730957b409SSimon J. Gerraty 			oid[0] = 4;
18740957b409SSimon J. Gerraty 			oid[1] = 0x29;
18750957b409SSimon J. Gerraty 			oid[2] = 0x01;
18760957b409SSimon J. Gerraty 			oid[3] = 0x01;
18770957b409SSimon J. Gerraty 			oid[4] = num;
18780957b409SSimon J. Gerraty 		} else if (num == 0) {
18790957b409SSimon J. Gerraty 			oid = xmalloc(13);
18800957b409SSimon J. Gerraty 			oid[0] = 0x00;
18810957b409SSimon J. Gerraty 			oid[1] = 0x00;
18820957b409SSimon J. Gerraty 			oid[2] = 0x0A;
18830957b409SSimon J. Gerraty 			oid[3] = 0x2B;
18840957b409SSimon J. Gerraty 			oid[4] = 0x06;
18850957b409SSimon J. Gerraty 			oid[5] = 0x01;
18860957b409SSimon J. Gerraty 			oid[6] = 0x04;
18870957b409SSimon J. Gerraty 			oid[7] = 0x01;
18880957b409SSimon J. Gerraty 			oid[8] = 0x82;
18890957b409SSimon J. Gerraty 			oid[9] = 0x37;
18900957b409SSimon J. Gerraty 			oid[10] = 0x14;
18910957b409SSimon J. Gerraty 			oid[11] = 0x02;
18920957b409SSimon J. Gerraty 			oid[12] = 0x03;
18930957b409SSimon J. Gerraty 		} else {
18940957b409SSimon J. Gerraty 			oid = xmalloc(2);
18950957b409SSimon J. Gerraty 			oid[0] = 0x00;
18960957b409SSimon J. Gerraty 			oid[1] = -num;
18970957b409SSimon J. Gerraty 		}
18980957b409SSimon J. Gerraty 		names[u].oid = oid;
18990957b409SSimon J. Gerraty 		names[u].buf = xmalloc(256);
19000957b409SSimon J. Gerraty 		names[u].len = 256;
19010957b409SSimon J. Gerraty 	}
19020957b409SSimon J. Gerraty 	br_x509_minimal_set_name_elements(&ctx, names, num_names);
19030957b409SSimon J. Gerraty 
19040957b409SSimon J. Gerraty 	/*
19050957b409SSimon J. Gerraty 	 * Put "canaries" to detect actual stack usage.
19060957b409SSimon J. Gerraty 	 */
19070957b409SSimon J. Gerraty 	for (u = 0; u < (sizeof ctx.dp_stack) / sizeof(uint32_t); u ++) {
19080957b409SSimon J. Gerraty 		ctx.dp_stack[u] = 0xA7C083FE;
19090957b409SSimon J. Gerraty 	}
19100957b409SSimon J. Gerraty 	for (u = 0; u < (sizeof ctx.rp_stack) / sizeof(uint32_t); u ++) {
19110957b409SSimon J. Gerraty 		ctx.rp_stack[u] = 0xA7C083FE;
19120957b409SSimon J. Gerraty 	}
19130957b409SSimon J. Gerraty 
19140957b409SSimon J. Gerraty 	/*
19150957b409SSimon J. Gerraty 	 * Run the engine. Since we set no trust anchor, we expect a status
19160957b409SSimon J. Gerraty 	 * of "not trusted".
19170957b409SSimon J. Gerraty 	 */
19180957b409SSimon J. Gerraty 	ctx.vtable->start_chain(&ctx.vtable, NULL);
19190957b409SSimon J. Gerraty 	ctx.vtable->start_cert(&ctx.vtable, len);
19200957b409SSimon J. Gerraty 	ctx.vtable->append(&ctx.vtable, data, len);
19210957b409SSimon J. Gerraty 	ctx.vtable->end_cert(&ctx.vtable);
19220957b409SSimon J. Gerraty 	status = ctx.vtable->end_chain(&ctx.vtable);
19230957b409SSimon J. Gerraty 	if (status != BR_ERR_X509_NOT_TRUSTED) {
19240957b409SSimon J. Gerraty 		fprintf(stderr, "wrong status: %u\n", status);
19250957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
19260957b409SSimon J. Gerraty 	}
19270957b409SSimon J. Gerraty 
19280957b409SSimon J. Gerraty 	/*
19290957b409SSimon J. Gerraty 	 * Check stack usage.
19300957b409SSimon J. Gerraty 	 */
19310957b409SSimon J. Gerraty 	for (u = (sizeof ctx.dp_stack) / sizeof(uint32_t); u > 0; u --) {
19320957b409SSimon J. Gerraty 		if (ctx.dp_stack[u - 1] != 0xA7C083FE) {
19330957b409SSimon J. Gerraty 			if (max_dp_usage < u) {
19340957b409SSimon J. Gerraty 				max_dp_usage = u;
19350957b409SSimon J. Gerraty 			}
19360957b409SSimon J. Gerraty 			break;
19370957b409SSimon J. Gerraty 		}
19380957b409SSimon J. Gerraty 	}
19390957b409SSimon J. Gerraty 	for (u = (sizeof ctx.rp_stack) / sizeof(uint32_t); u > 0; u --) {
19400957b409SSimon J. Gerraty 		if (ctx.rp_stack[u - 1] != 0xA7C083FE) {
19410957b409SSimon J. Gerraty 			if (max_rp_usage < u) {
19420957b409SSimon J. Gerraty 				max_rp_usage = u;
19430957b409SSimon J. Gerraty 			}
19440957b409SSimon J. Gerraty 			break;
19450957b409SSimon J. Gerraty 		}
19460957b409SSimon J. Gerraty 	}
19470957b409SSimon J. Gerraty 
19480957b409SSimon J. Gerraty 	good = 1;
19490957b409SSimon J. Gerraty 	for (u = 0; u < num_names; u ++) {
19500957b409SSimon J. Gerraty 		if (names[u].status != names_ref[u].status) {
19510957b409SSimon J. Gerraty 			printf("ERR: name %u (id=%d): status=%d, expected=%d\n",
19520957b409SSimon J. Gerraty 				(unsigned)u, names_ref[u].num,
19530957b409SSimon J. Gerraty 				names[u].status, names_ref[u].status);
19540957b409SSimon J. Gerraty 			if (names[u].status > 0) {
19550957b409SSimon J. Gerraty 				unsigned char *p;
19560957b409SSimon J. Gerraty 
19570957b409SSimon J. Gerraty 				printf("  obtained:");
19580957b409SSimon J. Gerraty 				p = (unsigned char *)names[u].buf;
19590957b409SSimon J. Gerraty 				while (*p) {
19600957b409SSimon J. Gerraty 					printf(" %02X", *p ++);
19610957b409SSimon J. Gerraty 				}
19620957b409SSimon J. Gerraty 				printf("\n");
19630957b409SSimon J. Gerraty 			}
19640957b409SSimon J. Gerraty 			good = 0;
19650957b409SSimon J. Gerraty 			continue;
19660957b409SSimon J. Gerraty 		}
19670957b409SSimon J. Gerraty 		if (names_ref[u].expected == NULL) {
19680957b409SSimon J. Gerraty 			if (names[u].buf[0] != 0) {
19690957b409SSimon J. Gerraty 				printf("ERR: name %u not zero-terminated\n",
19700957b409SSimon J. Gerraty 					(unsigned)u);
19710957b409SSimon J. Gerraty 				good = 0;
19720957b409SSimon J. Gerraty 				continue;
19730957b409SSimon J. Gerraty 			}
19740957b409SSimon J. Gerraty 		} else {
19750957b409SSimon J. Gerraty 			if (strcmp(names[u].buf, names_ref[u].expected) != 0) {
19760957b409SSimon J. Gerraty 				unsigned char *p;
19770957b409SSimon J. Gerraty 
19780957b409SSimon J. Gerraty 				printf("ERR: name %u (id=%d): wrong value\n",
19790957b409SSimon J. Gerraty 					(unsigned)u, names_ref[u].num);
19800957b409SSimon J. Gerraty 				printf("  expected:");
19810957b409SSimon J. Gerraty 				p = (unsigned char *)names_ref[u].expected;
19820957b409SSimon J. Gerraty 				while (*p) {
19830957b409SSimon J. Gerraty 					printf(" %02X", *p ++);
19840957b409SSimon J. Gerraty 				}
19850957b409SSimon J. Gerraty 				printf("\n");
19860957b409SSimon J. Gerraty 				printf("  obtained:");
19870957b409SSimon J. Gerraty 				p = (unsigned char *)names[u].buf;
19880957b409SSimon J. Gerraty 				while (*p) {
19890957b409SSimon J. Gerraty 					printf(" %02X", *p ++);
19900957b409SSimon J. Gerraty 				}
19910957b409SSimon J. Gerraty 				printf("\n");
19920957b409SSimon J. Gerraty 				good = 0;
19930957b409SSimon J. Gerraty 				continue;
19940957b409SSimon J. Gerraty 			}
19950957b409SSimon J. Gerraty 		}
19960957b409SSimon J. Gerraty 	}
19970957b409SSimon J. Gerraty 	if (!good) {
19980957b409SSimon J. Gerraty 		exit(EXIT_FAILURE);
19990957b409SSimon J. Gerraty 	}
20000957b409SSimon J. Gerraty 
20010957b409SSimon J. Gerraty 	/*
20020957b409SSimon J. Gerraty 	for (u = 0; u < num_names; u ++) {
20030957b409SSimon J. Gerraty 		printf("%u: (%d)", (unsigned)u, names[u].status);
20040957b409SSimon J. Gerraty 		if (names[u].status > 0) {
20050957b409SSimon J. Gerraty 			size_t v;
20060957b409SSimon J. Gerraty 
20070957b409SSimon J. Gerraty 			for (v = 0; names[u].buf[v]; v ++) {
20080957b409SSimon J. Gerraty 				printf(" %02x", names[u].buf[v]);
20090957b409SSimon J. Gerraty 			}
20100957b409SSimon J. Gerraty 		}
20110957b409SSimon J. Gerraty 		printf("\n");
20120957b409SSimon J. Gerraty 	}
20130957b409SSimon J. Gerraty 	*/
20140957b409SSimon J. Gerraty 
20150957b409SSimon J. Gerraty 	xfree(data);
20160957b409SSimon J. Gerraty 	free_name_elements(names, num_names);
20170957b409SSimon J. Gerraty 	printf("OK\n");
20180957b409SSimon J. Gerraty }
20190957b409SSimon J. Gerraty 
20200957b409SSimon J. Gerraty int
main(int argc,const char * argv[])20210957b409SSimon J. Gerraty main(int argc, const char *argv[])
20220957b409SSimon J. Gerraty {
20230957b409SSimon J. Gerraty 	size_t u;
20240957b409SSimon J. Gerraty 
20250957b409SSimon J. Gerraty #ifdef SRCDIRNAME
20260957b409SSimon J. Gerraty 	/*
20270957b409SSimon J. Gerraty 	 * We want to change the current directory to that of the
20280957b409SSimon J. Gerraty 	 * executable, so that test files are reliably located. We
20290957b409SSimon J. Gerraty 	 * do that only if SRCDIRNAME is defined (old Makefile would
20300957b409SSimon J. Gerraty 	 * not do that).
20310957b409SSimon J. Gerraty 	 */
20320957b409SSimon J. Gerraty 	if (argc >= 1) {
20330957b409SSimon J. Gerraty 		const char *arg, *c;
20340957b409SSimon J. Gerraty 
20350957b409SSimon J. Gerraty 		arg = argv[0];
20360957b409SSimon J. Gerraty 		for (c = arg + strlen(arg);; c --) {
20370957b409SSimon J. Gerraty 			int sep, r;
20380957b409SSimon J. Gerraty 
20390957b409SSimon J. Gerraty #ifdef _WIN32
20400957b409SSimon J. Gerraty 			sep = (*c == '/') || (*c == '\\');
20410957b409SSimon J. Gerraty #else
20420957b409SSimon J. Gerraty 			sep = (*c == '/');
20430957b409SSimon J. Gerraty #endif
20440957b409SSimon J. Gerraty 			if (sep) {
20450957b409SSimon J. Gerraty 				size_t len;
20460957b409SSimon J. Gerraty 				char *dn;
20470957b409SSimon J. Gerraty 
20480957b409SSimon J. Gerraty 				len = 1 + (c - arg);
20490957b409SSimon J. Gerraty 				dn = xmalloc(len + 1);
20500957b409SSimon J. Gerraty 				memcpy(dn, arg, len);
20510957b409SSimon J. Gerraty 				dn[len] = 0;
20520957b409SSimon J. Gerraty #ifdef _WIN32
20530957b409SSimon J. Gerraty 				r = _chdir(dn);
20540957b409SSimon J. Gerraty #else
20550957b409SSimon J. Gerraty 				r = chdir(dn);
20560957b409SSimon J. Gerraty #endif
20570957b409SSimon J. Gerraty 				if (r != 0) {
20580957b409SSimon J. Gerraty 					fprintf(stderr, "warning: could not"
20590957b409SSimon J. Gerraty 						" set directory to '%s'\n", dn);
20600957b409SSimon J. Gerraty 				}
20610957b409SSimon J. Gerraty 				xfree(dn);
20620957b409SSimon J. Gerraty 				break;
20630957b409SSimon J. Gerraty 			}
20640957b409SSimon J. Gerraty 			if (c == arg) {
20650957b409SSimon J. Gerraty 				break;
20660957b409SSimon J. Gerraty 			}
20670957b409SSimon J. Gerraty 		}
20680957b409SSimon J. Gerraty 	}
20690957b409SSimon J. Gerraty #else
20700957b409SSimon J. Gerraty 	(void)argc;
20710957b409SSimon J. Gerraty 	(void)argv;
20720957b409SSimon J. Gerraty #endif
20730957b409SSimon J. Gerraty 
20740957b409SSimon J. Gerraty 	process_conf_file(CONFFILE);
20750957b409SSimon J. Gerraty 
20760957b409SSimon J. Gerraty 	max_dp_usage = 0;
20770957b409SSimon J. Gerraty 	max_rp_usage = 0;
20780957b409SSimon J. Gerraty 	for (u = 0; u < all_chains_ptr; u ++) {
20790957b409SSimon J. Gerraty 		run_test_case(&all_chains[u]);
20800957b409SSimon J. Gerraty 	}
20810957b409SSimon J. Gerraty 	test_name_extraction();
20820957b409SSimon J. Gerraty 
20830957b409SSimon J. Gerraty 	printf("Maximum data stack usage:    %u\n", (unsigned)max_dp_usage);
20840957b409SSimon J. Gerraty 	printf("Maximum return stack usage:  %u\n", (unsigned)max_rp_usage);
20850957b409SSimon J. Gerraty 
20860957b409SSimon J. Gerraty 	HT_free(keys, free_key);
20870957b409SSimon J. Gerraty 	HT_free(trust_anchors, free_trust_anchor);
20880957b409SSimon J. Gerraty 	for (u = 0; u < all_chains_ptr; u ++) {
20890957b409SSimon J. Gerraty 		free_test_case_contents(&all_chains[u]);
20900957b409SSimon J. Gerraty 	}
20910957b409SSimon J. Gerraty 	xfree(all_chains);
20920957b409SSimon J. Gerraty 
20930957b409SSimon J. Gerraty 	return 0;
20940957b409SSimon J. Gerraty }
2095