xref: /freebsd/lib/libsecureboot/vets.c (revision 3ae2a848aeea53aedf625bdb540ad9a5a4a42551)
15fff9558SSimon J. Gerraty /*-
25fff9558SSimon J. Gerraty  * Copyright (c) 2017-2018, Juniper Networks, Inc.
35fff9558SSimon J. Gerraty  *
45fff9558SSimon J. Gerraty  * Redistribution and use in source and binary forms, with or without
55fff9558SSimon J. Gerraty  * modification, are permitted provided that the following conditions
65fff9558SSimon J. Gerraty  * are met:
75fff9558SSimon J. Gerraty  * 1. Redistributions of source code must retain the above copyright
85fff9558SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer.
95fff9558SSimon J. Gerraty  * 2. Redistributions in binary form must reproduce the above copyright
105fff9558SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer in the
115fff9558SSimon J. Gerraty  *    documentation and/or other materials provided with the distribution.
125fff9558SSimon J. Gerraty  *
135fff9558SSimon J. Gerraty  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
145fff9558SSimon J. Gerraty  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
155fff9558SSimon J. Gerraty  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
165fff9558SSimon J. Gerraty  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
175fff9558SSimon J. Gerraty  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
185fff9558SSimon J. Gerraty  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
195fff9558SSimon J. Gerraty  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
205fff9558SSimon J. Gerraty  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
215fff9558SSimon J. Gerraty  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
225fff9558SSimon J. Gerraty  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
235fff9558SSimon J. Gerraty  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
245fff9558SSimon J. Gerraty  */
255fff9558SSimon J. Gerraty #include <sys/cdefs.h>
265fff9558SSimon J. Gerraty __FBSDID("$FreeBSD$");
275fff9558SSimon J. Gerraty 
285fff9558SSimon J. Gerraty /**
295fff9558SSimon J. Gerraty  * @file vets.c - trust store
305fff9558SSimon J. Gerraty  * @brief verify signatures
315fff9558SSimon J. Gerraty  *
325fff9558SSimon J. Gerraty  * We leverage code from BearSSL www.bearssl.org
335fff9558SSimon J. Gerraty  */
345fff9558SSimon J. Gerraty 
355fff9558SSimon J. Gerraty #include <sys/time.h>
365fff9558SSimon J. Gerraty #include <stdarg.h>
375fff9558SSimon J. Gerraty #define NEED_BRSSL_H
385fff9558SSimon J. Gerraty #include "libsecureboot-priv.h"
395fff9558SSimon J. Gerraty #include <brssl.h>
405fff9558SSimon J. Gerraty #include <ta.h>
415fff9558SSimon J. Gerraty 
425fff9558SSimon J. Gerraty #ifndef TRUST_ANCHOR_STR
435fff9558SSimon J. Gerraty # define TRUST_ANCHOR_STR ta_PEM
445fff9558SSimon J. Gerraty #endif
455fff9558SSimon J. Gerraty 
465fff9558SSimon J. Gerraty #define SECONDS_PER_DAY		86400
475fff9558SSimon J. Gerraty #define X509_DAYS_TO_UTC0	719528
485fff9558SSimon J. Gerraty 
495fff9558SSimon J. Gerraty int DebugVe = 0;
505fff9558SSimon J. Gerraty 
515fff9558SSimon J. Gerraty typedef VECTOR(br_x509_certificate) cert_list;
5213ea0450SMarcin Wojtas typedef VECTOR(hash_data) digest_list;
535fff9558SSimon J. Gerraty 
545fff9558SSimon J. Gerraty static anchor_list trust_anchors = VEC_INIT;
5513ea0450SMarcin Wojtas static anchor_list forbidden_anchors = VEC_INIT;
5613ea0450SMarcin Wojtas static digest_list forbidden_digests = VEC_INIT;
575fff9558SSimon J. Gerraty 
58f9510887SSimon J. Gerraty static int anchor_verbose = 0;
59f9510887SSimon J. Gerraty 
60f9510887SSimon J. Gerraty void
61f9510887SSimon J. Gerraty ve_anchor_verbose_set(int n)
62f9510887SSimon J. Gerraty {
63f9510887SSimon J. Gerraty 	anchor_verbose = n;
64f9510887SSimon J. Gerraty }
65f9510887SSimon J. Gerraty 
66f9510887SSimon J. Gerraty int
67f9510887SSimon J. Gerraty ve_anchor_verbose_get(void)
68f9510887SSimon J. Gerraty {
69f9510887SSimon J. Gerraty 	return (anchor_verbose);
70f9510887SSimon J. Gerraty }
71f9510887SSimon J. Gerraty 
725fff9558SSimon J. Gerraty void
735fff9558SSimon J. Gerraty ve_debug_set(int n)
745fff9558SSimon J. Gerraty {
755fff9558SSimon J. Gerraty 	DebugVe = n;
765fff9558SSimon J. Gerraty }
775fff9558SSimon J. Gerraty 
785fff9558SSimon J. Gerraty static char ebuf[512];
795fff9558SSimon J. Gerraty 
805fff9558SSimon J. Gerraty char *
815fff9558SSimon J. Gerraty ve_error_get(void)
825fff9558SSimon J. Gerraty {
835fff9558SSimon J. Gerraty 	return (ebuf);
845fff9558SSimon J. Gerraty }
855fff9558SSimon J. Gerraty 
865fff9558SSimon J. Gerraty int
875fff9558SSimon J. Gerraty ve_error_set(const char *fmt, ...)
885fff9558SSimon J. Gerraty {
895fff9558SSimon J. Gerraty 	int rc;
905fff9558SSimon J. Gerraty 	va_list ap;
915fff9558SSimon J. Gerraty 
925fff9558SSimon J. Gerraty 	va_start(ap, fmt);
935fff9558SSimon J. Gerraty 	ebuf[0] = '\0';
945fff9558SSimon J. Gerraty 	rc = 0;
955fff9558SSimon J. Gerraty 	if (fmt) {
965fff9558SSimon J. Gerraty #ifdef STAND_H
975fff9558SSimon J. Gerraty 		vsprintf(ebuf, fmt, ap); /* no vsnprintf in libstand */
985fff9558SSimon J. Gerraty 		ebuf[sizeof(ebuf) - 1] = '\0';
995fff9558SSimon J. Gerraty 		rc = strlen(ebuf);
1005fff9558SSimon J. Gerraty #else
1015fff9558SSimon J. Gerraty 		rc = vsnprintf(ebuf, sizeof(ebuf), fmt, ap);
1025fff9558SSimon J. Gerraty #endif
1035fff9558SSimon J. Gerraty 	}
1045fff9558SSimon J. Gerraty 	va_end(ap);
1055fff9558SSimon J. Gerraty 	return (rc);
1065fff9558SSimon J. Gerraty }
1075fff9558SSimon J. Gerraty 
1085fff9558SSimon J. Gerraty /* this is the time we use for verifying certs */
1095fff9558SSimon J. Gerraty static time_t ve_utc = 0;
1105fff9558SSimon J. Gerraty 
1115fff9558SSimon J. Gerraty /**
1125fff9558SSimon J. Gerraty  * @brief
1135fff9558SSimon J. Gerraty  * set ve_utc used for certificate verification
1145fff9558SSimon J. Gerraty  *
1155fff9558SSimon J. Gerraty  * @param[in] utc
1165fff9558SSimon J. Gerraty  *	time - ignored unless greater than current value.
1175fff9558SSimon J. Gerraty  */
1185fff9558SSimon J. Gerraty void
1195fff9558SSimon J. Gerraty ve_utc_set(time_t utc)
1205fff9558SSimon J. Gerraty {
1215fff9558SSimon J. Gerraty 	if (utc > ve_utc) {
1225fff9558SSimon J. Gerraty 		DEBUG_PRINTF(2, ("Set ve_utc=%jd\n", (intmax_t)utc));
1235fff9558SSimon J. Gerraty 		ve_utc = utc;
1245fff9558SSimon J. Gerraty 	}
1255fff9558SSimon J. Gerraty }
1265fff9558SSimon J. Gerraty 
1275fff9558SSimon J. Gerraty static void
1285fff9558SSimon J. Gerraty free_cert_contents(br_x509_certificate *xc)
1295fff9558SSimon J. Gerraty {
1305fff9558SSimon J. Gerraty 	xfree(xc->data);
1315fff9558SSimon J. Gerraty }
1325fff9558SSimon J. Gerraty 
133f9510887SSimon J. Gerraty /*
134f9510887SSimon J. Gerraty  * a bit of a dance to get commonName from a certificate
135f9510887SSimon J. Gerraty  */
136f9510887SSimon J. Gerraty static char *
137f9510887SSimon J. Gerraty x509_cn_get(br_x509_certificate *xc, char *buf, size_t len)
138f9510887SSimon J. Gerraty {
139f9510887SSimon J. Gerraty 	br_x509_minimal_context mc;
140f9510887SSimon J. Gerraty 	br_name_element cn;
141f9510887SSimon J. Gerraty 	unsigned char cn_oid[4];
142f9510887SSimon J. Gerraty 	int err;
143f9510887SSimon J. Gerraty 
144f9510887SSimon J. Gerraty 	if (buf == NULL)
145f9510887SSimon J. Gerraty 		return (buf);
146f9510887SSimon J. Gerraty 	/*
147f9510887SSimon J. Gerraty 	 * We want the commonName field
148f9510887SSimon J. Gerraty 	 * the OID we want is 2,5,4,3 - but DER encoded
149f9510887SSimon J. Gerraty 	 */
150f9510887SSimon J. Gerraty 	cn_oid[0] = 3;
151f9510887SSimon J. Gerraty 	cn_oid[1] = 0x55;
152f9510887SSimon J. Gerraty 	cn_oid[2] = 4;
153f9510887SSimon J. Gerraty 	cn_oid[3] = 3;
154f9510887SSimon J. Gerraty 	cn.oid = cn_oid;
155f9510887SSimon J. Gerraty 	cn.buf = buf;
156f9510887SSimon J. Gerraty 	cn.len = len;
157f9510887SSimon J. Gerraty 	cn.buf[0] = '\0';
158f9510887SSimon J. Gerraty 
159f9510887SSimon J. Gerraty 	br_x509_minimal_init(&mc, &br_sha256_vtable, NULL, 0);
160f9510887SSimon J. Gerraty 	br_x509_minimal_set_name_elements(&mc, &cn, 1);
161f9510887SSimon J. Gerraty 	/* the below actually does the work - updates cn.status */
162f9510887SSimon J. Gerraty 	mc.vtable->start_chain(&mc.vtable, NULL);
163f9510887SSimon J. Gerraty 	mc.vtable->start_cert(&mc.vtable, xc->data_len);
164f9510887SSimon J. Gerraty 	mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
165f9510887SSimon J. Gerraty 	mc.vtable->end_cert(&mc.vtable);
166f9510887SSimon J. Gerraty 	/* we don' actually care about cert status - just its name */
167f9510887SSimon J. Gerraty 	err = mc.vtable->end_chain(&mc.vtable);
168f9510887SSimon J. Gerraty 
169f9510887SSimon J. Gerraty 	if (!cn.status)
170f9510887SSimon J. Gerraty 		buf = NULL;
171f9510887SSimon J. Gerraty 	return (buf);
172f9510887SSimon J. Gerraty }
173f9510887SSimon J. Gerraty 
17413ea0450SMarcin Wojtas /* ASN parsing related defines */
17513ea0450SMarcin Wojtas #define ASN1_PRIMITIVE_TAG 0x1F
17613ea0450SMarcin Wojtas #define ASN1_INF_LENGTH    0x80
17713ea0450SMarcin Wojtas #define ASN1_LENGTH_MASK   0x7F
17813ea0450SMarcin Wojtas 
17913ea0450SMarcin Wojtas /*
18013ea0450SMarcin Wojtas  * Get TBS part of certificate.
18113ea0450SMarcin Wojtas  * Since BearSSL doesn't provide any API to do this,
18213ea0450SMarcin Wojtas  * it has to be implemented here.
1835fff9558SSimon J. Gerraty  */
18413ea0450SMarcin Wojtas static void*
18513ea0450SMarcin Wojtas X509_to_tbs(unsigned char* cert, size_t* output_size)
18613ea0450SMarcin Wojtas {
18713ea0450SMarcin Wojtas 	unsigned char *result;
18813ea0450SMarcin Wojtas 	size_t tbs_size;
18913ea0450SMarcin Wojtas 	int size, i;
19013ea0450SMarcin Wojtas 
19113ea0450SMarcin Wojtas 	if (cert == NULL)
19213ea0450SMarcin Wojtas 		return (NULL);
19313ea0450SMarcin Wojtas 
19413ea0450SMarcin Wojtas 	/* Strip two sequences to get to the TBS section */
19513ea0450SMarcin Wojtas 	for (i = 0; i < 2; i++) {
19613ea0450SMarcin Wojtas 		/*
19713ea0450SMarcin Wojtas 		 * XXX: We don't need to support extended tags since
19813ea0450SMarcin Wojtas 		 * they should not be present in certificates.
19913ea0450SMarcin Wojtas 		 */
20013ea0450SMarcin Wojtas 		if ((*cert & ASN1_PRIMITIVE_TAG) == ASN1_PRIMITIVE_TAG)
20113ea0450SMarcin Wojtas 			return (NULL);
20213ea0450SMarcin Wojtas 
20313ea0450SMarcin Wojtas 		cert++;
20413ea0450SMarcin Wojtas 
20513ea0450SMarcin Wojtas 		if (*cert == ASN1_INF_LENGTH)
20613ea0450SMarcin Wojtas 			return (NULL);
20713ea0450SMarcin Wojtas 
20813ea0450SMarcin Wojtas 		size = *cert & ASN1_LENGTH_MASK;
20913ea0450SMarcin Wojtas 		tbs_size = 0;
21013ea0450SMarcin Wojtas 
21113ea0450SMarcin Wojtas 		/* Size can either be stored on a single or multiple bytes */
21213ea0450SMarcin Wojtas 		if (*cert & (ASN1_LENGTH_MASK + 1)) {
21313ea0450SMarcin Wojtas 			cert++;
21413ea0450SMarcin Wojtas 			while (*cert == 0 && size > 0) {
21513ea0450SMarcin Wojtas 				cert++;
21613ea0450SMarcin Wojtas 				size--;
21713ea0450SMarcin Wojtas 			}
21813ea0450SMarcin Wojtas 			while (size-- > 0) {
21913ea0450SMarcin Wojtas 				tbs_size <<= 8;
22013ea0450SMarcin Wojtas 				tbs_size |= *(cert++);
22113ea0450SMarcin Wojtas 			}
22213ea0450SMarcin Wojtas 		}
22313ea0450SMarcin Wojtas 		if (i == 0)
22413ea0450SMarcin Wojtas 			result = cert;
22513ea0450SMarcin Wojtas 	}
22613ea0450SMarcin Wojtas 	tbs_size += (cert - result);
22713ea0450SMarcin Wojtas 
22813ea0450SMarcin Wojtas 	if (output_size != NULL)
22913ea0450SMarcin Wojtas 		*output_size = tbs_size;
23013ea0450SMarcin Wojtas 
23113ea0450SMarcin Wojtas 	return (result);
23213ea0450SMarcin Wojtas }
23313ea0450SMarcin Wojtas 
23413ea0450SMarcin Wojtas void
23513ea0450SMarcin Wojtas ve_forbidden_digest_add(hash_data *digest, size_t num)
23613ea0450SMarcin Wojtas {
23713ea0450SMarcin Wojtas 	while (num--)
23813ea0450SMarcin Wojtas 		VEC_ADD(forbidden_digests, digest[num]);
23913ea0450SMarcin Wojtas }
24013ea0450SMarcin Wojtas 
24113ea0450SMarcin Wojtas static size_t
242f9510887SSimon J. Gerraty ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors,
243f9510887SSimon J. Gerraty     char *anchors_name)
2445fff9558SSimon J. Gerraty {
2455fff9558SSimon J. Gerraty 	br_x509_trust_anchor ta;
2465fff9558SSimon J. Gerraty 	size_t u;
2475fff9558SSimon J. Gerraty 
2485fff9558SSimon J. Gerraty 	for (u = 0; u < num; u++) {
2495fff9558SSimon J. Gerraty 		if (certificate_to_trust_anchor_inner(&ta, &xcs[u]) < 0) {
2505fff9558SSimon J. Gerraty 			break;
2515fff9558SSimon J. Gerraty 		}
25213ea0450SMarcin Wojtas 		VEC_ADD(*anchors, ta);
253f9510887SSimon J. Gerraty 		if (anchor_verbose && anchors_name) {
254f9510887SSimon J. Gerraty 			char buf[64];
255f9510887SSimon J. Gerraty 			char *cp;
256f9510887SSimon J. Gerraty 
257f9510887SSimon J. Gerraty 			cp = x509_cn_get(&xcs[u], buf, sizeof(buf));
258f9510887SSimon J. Gerraty 			if (cp) {
259f9510887SSimon J. Gerraty 				printf("x509_anchor(%s) %s\n", cp, anchors_name);
260f9510887SSimon J. Gerraty 			}
261f9510887SSimon J. Gerraty 		}
2625fff9558SSimon J. Gerraty 	}
2635fff9558SSimon J. Gerraty 	return (u);
2645fff9558SSimon J. Gerraty }
2655fff9558SSimon J. Gerraty 
2665fff9558SSimon J. Gerraty /**
2675fff9558SSimon J. Gerraty  * @brief
26813ea0450SMarcin Wojtas  * add certs to our trust store
26913ea0450SMarcin Wojtas  */
27013ea0450SMarcin Wojtas size_t
27113ea0450SMarcin Wojtas ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
27213ea0450SMarcin Wojtas {
273f9510887SSimon J. Gerraty 	return (ve_anchors_add(xcs, num, &trust_anchors, "trusted"));
27413ea0450SMarcin Wojtas }
27513ea0450SMarcin Wojtas 
27613ea0450SMarcin Wojtas size_t
27713ea0450SMarcin Wojtas ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num)
27813ea0450SMarcin Wojtas {
279f9510887SSimon J. Gerraty 	return (ve_anchors_add(xcs, num, &forbidden_anchors, "forbidden"));
280f9510887SSimon J. Gerraty }
281f9510887SSimon J. Gerraty 
282f9510887SSimon J. Gerraty 
283f9510887SSimon J. Gerraty /**
284f9510887SSimon J. Gerraty  * @brief add trust anchors in buf
285f9510887SSimon J. Gerraty  *
286f9510887SSimon J. Gerraty  * Assume buf contains x509 certificates, but if not and
287f9510887SSimon J. Gerraty  * we support OpenPGP try adding as that.
288f9510887SSimon J. Gerraty  *
289f9510887SSimon J. Gerraty  * @return number of anchors added
290f9510887SSimon J. Gerraty  */
291f9510887SSimon J. Gerraty size_t
292f9510887SSimon J. Gerraty ve_trust_anchors_add_buf(unsigned char *buf, size_t len)
293f9510887SSimon J. Gerraty {
294f9510887SSimon J. Gerraty 	br_x509_certificate *xcs;
295f9510887SSimon J. Gerraty 	size_t num;
296f9510887SSimon J. Gerraty 
297f9510887SSimon J. Gerraty 	num = 0;
298f9510887SSimon J. Gerraty 	xcs = parse_certificates(buf, len, &num);
299f9510887SSimon J. Gerraty 	if (xcs != NULL) {
300f9510887SSimon J. Gerraty 		num = ve_trust_anchors_add(xcs, num);
301f9510887SSimon J. Gerraty #ifdef VE_OPENPGP_SUPPORT
302f9510887SSimon J. Gerraty 	} else {
303f9510887SSimon J. Gerraty 		num = openpgp_trust_add_buf(buf, len);
304f9510887SSimon J. Gerraty #endif
305f9510887SSimon J. Gerraty 	}
306f9510887SSimon J. Gerraty 	return (num);
307f9510887SSimon J. Gerraty }
308f9510887SSimon J. Gerraty 
309f9510887SSimon J. Gerraty /**
310f9510887SSimon J. Gerraty  * @brief revoke trust anchors in buf
311f9510887SSimon J. Gerraty  *
312f9510887SSimon J. Gerraty  * Assume buf contains x509 certificates, but if not and
313f9510887SSimon J. Gerraty  * we support OpenPGP try revoking keyId
314f9510887SSimon J. Gerraty  *
315f9510887SSimon J. Gerraty  * @return number of anchors revoked
316f9510887SSimon J. Gerraty  */
317f9510887SSimon J. Gerraty size_t
318f9510887SSimon J. Gerraty ve_trust_anchors_revoke(unsigned char *buf, size_t len)
319f9510887SSimon J. Gerraty {
320f9510887SSimon J. Gerraty 	br_x509_certificate *xcs;
321f9510887SSimon J. Gerraty 	size_t num;
322f9510887SSimon J. Gerraty 
323f9510887SSimon J. Gerraty 	num = 0;
324f9510887SSimon J. Gerraty 	xcs = parse_certificates(buf, len, &num);
325f9510887SSimon J. Gerraty 	if (xcs != NULL) {
326f9510887SSimon J. Gerraty 		num = ve_forbidden_anchors_add(xcs, num);
327f9510887SSimon J. Gerraty #ifdef VE_OPENPGP_SUPPORT
328f9510887SSimon J. Gerraty 	} else {
329f9510887SSimon J. Gerraty 		if (buf[len - 1] == '\n')
330f9510887SSimon J. Gerraty 			buf[len - 1] = '\0';
331f9510887SSimon J. Gerraty 		num = openpgp_trust_revoke((char *)buf);
332f9510887SSimon J. Gerraty #endif
333f9510887SSimon J. Gerraty 	}
334f9510887SSimon J. Gerraty 	return (num);
33513ea0450SMarcin Wojtas }
33613ea0450SMarcin Wojtas 
33713ea0450SMarcin Wojtas /**
33813ea0450SMarcin Wojtas  * @brief
3395fff9558SSimon J. Gerraty  * initialize our trust_anchors from ta_PEM
3405fff9558SSimon J. Gerraty  */
3415fff9558SSimon J. Gerraty int
3425fff9558SSimon J. Gerraty ve_trust_init(void)
3435fff9558SSimon J. Gerraty {
3445fff9558SSimon J. Gerraty 	static int once = -1;
3455fff9558SSimon J. Gerraty 
3465fff9558SSimon J. Gerraty 	if (once >= 0)
3475fff9558SSimon J. Gerraty 		return (once);
348*3ae2a848SSimon J. Gerraty 	once = 0;			/* to be sure */
3495fff9558SSimon J. Gerraty 	ve_utc_set(time(NULL));
3505fff9558SSimon J. Gerraty #ifdef BUILD_UTC
3515fff9558SSimon J. Gerraty 	ve_utc_set(BUILD_UTC);		/* just in case */
3525fff9558SSimon J. Gerraty #endif
3535fff9558SSimon J. Gerraty 	ve_error_set(NULL);		/* make sure it is empty */
3545fff9558SSimon J. Gerraty #ifdef VE_PCR_SUPPORT
3555fff9558SSimon J. Gerraty 	ve_pcr_init();
3565fff9558SSimon J. Gerraty #endif
3575fff9558SSimon J. Gerraty 
3585fff9558SSimon J. Gerraty #ifdef TRUST_ANCHOR_STR
359f9510887SSimon J. Gerraty 	ve_trust_anchors_add_buf(__DECONST(unsigned char *, TRUST_ANCHOR_STR),
360f9510887SSimon J. Gerraty 	    sizeof(TRUST_ANCHOR_STR));
3615fff9558SSimon J. Gerraty #endif
36213ea0450SMarcin Wojtas 	once = (int) VEC_LEN(trust_anchors);
3639bee6a60SSimon J. Gerraty #ifdef VE_OPENPGP_SUPPORT
3649bee6a60SSimon J. Gerraty 	once += openpgp_trust_init();
3659bee6a60SSimon J. Gerraty #endif
36613ea0450SMarcin Wojtas 	return (once);
3675fff9558SSimon J. Gerraty }
3685fff9558SSimon J. Gerraty 
3695fff9558SSimon J. Gerraty /**
3705fff9558SSimon J. Gerraty  * if we can verify the certificate chain in "certs",
3715fff9558SSimon J. Gerraty  * return the public key and if "xcp" is !NULL the associated
3725fff9558SSimon J. Gerraty  * certificate
3735fff9558SSimon J. Gerraty  */
3745fff9558SSimon J. Gerraty static br_x509_pkey *
3755fff9558SSimon J. Gerraty verify_signer_xcs(br_x509_certificate *xcs,
3765fff9558SSimon J. Gerraty     size_t num,
37713ea0450SMarcin Wojtas     br_name_element *elts, size_t num_elts,
37813ea0450SMarcin Wojtas     anchor_list *anchors)
3795fff9558SSimon J. Gerraty {
3805fff9558SSimon J. Gerraty 	br_x509_minimal_context mc;
3815fff9558SSimon J. Gerraty 	br_x509_certificate *xc;
3825fff9558SSimon J. Gerraty 	size_t u;
3835fff9558SSimon J. Gerraty 	cert_list chain = VEC_INIT;
3845fff9558SSimon J. Gerraty 	const br_x509_pkey *tpk;
3855fff9558SSimon J. Gerraty 	br_x509_pkey *pk;
3865fff9558SSimon J. Gerraty 	unsigned int usages;
3875fff9558SSimon J. Gerraty 	int err;
3885fff9558SSimon J. Gerraty 
3895fff9558SSimon J. Gerraty 	DEBUG_PRINTF(5, ("verify_signer: %zu certs in chain\n", num));
3905fff9558SSimon J. Gerraty 	VEC_ADDMANY(chain, xcs, num);
3915fff9558SSimon J. Gerraty 	if (VEC_LEN(chain) == 0) {
3925fff9558SSimon J. Gerraty 		ve_error_set("ERROR: no/invalid certificate chain\n");
3935fff9558SSimon J. Gerraty 		return (NULL);
3945fff9558SSimon J. Gerraty 	}
3955fff9558SSimon J. Gerraty 
3965fff9558SSimon J. Gerraty 	DEBUG_PRINTF(5, ("verify_signer: %zu trust anchors\n",
39713ea0450SMarcin Wojtas 		VEC_LEN(*anchors)));
3985fff9558SSimon J. Gerraty 
3995fff9558SSimon J. Gerraty 	br_x509_minimal_init(&mc, &br_sha256_vtable,
40013ea0450SMarcin Wojtas 	    &VEC_ELT(*anchors, 0),
40113ea0450SMarcin Wojtas 	    VEC_LEN(*anchors));
4025fff9558SSimon J. Gerraty #ifdef VE_ECDSA_SUPPORT
4035fff9558SSimon J. Gerraty 	br_x509_minimal_set_ecdsa(&mc,
4045fff9558SSimon J. Gerraty 	    &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
4055fff9558SSimon J. Gerraty #endif
4065fff9558SSimon J. Gerraty #ifdef VE_RSA_SUPPORT
4075fff9558SSimon J. Gerraty 	br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
4085fff9558SSimon J. Gerraty #endif
4095fff9558SSimon J. Gerraty #if defined(UNIT_TEST) && defined(VE_DEPRECATED_RSA_SHA1_SUPPORT)
4105fff9558SSimon J. Gerraty 	/* This is deprecated! do not enable unless you absoultely have to */
4115fff9558SSimon J. Gerraty 	br_x509_minimal_set_hash(&mc, br_sha1_ID, &br_sha1_vtable);
4125fff9558SSimon J. Gerraty #endif
4135fff9558SSimon J. Gerraty 	br_x509_minimal_set_hash(&mc, br_sha256_ID, &br_sha256_vtable);
4145fff9558SSimon J. Gerraty #ifdef VE_SHA384_SUPPORT
4155fff9558SSimon J. Gerraty 	br_x509_minimal_set_hash(&mc, br_sha384_ID, &br_sha384_vtable);
4165fff9558SSimon J. Gerraty #endif
4175fff9558SSimon J. Gerraty #ifdef VE_SHA512_SUPPORT
4185fff9558SSimon J. Gerraty 	br_x509_minimal_set_hash(&mc, br_sha512_ID, &br_sha512_vtable);
4195fff9558SSimon J. Gerraty #endif
4205fff9558SSimon J. Gerraty 	br_x509_minimal_set_name_elements(&mc, elts, num_elts);
4215fff9558SSimon J. Gerraty 
4225fff9558SSimon J. Gerraty #ifdef _STANDALONE
4235fff9558SSimon J. Gerraty 	/*
4245fff9558SSimon J. Gerraty 	 * Clock is probably bogus so we use ve_utc.
4255fff9558SSimon J. Gerraty 	 */
4265fff9558SSimon J. Gerraty 	mc.days = (ve_utc / SECONDS_PER_DAY) + X509_DAYS_TO_UTC0;
4275fff9558SSimon J. Gerraty 	mc.seconds = (ve_utc % SECONDS_PER_DAY);
4285fff9558SSimon J. Gerraty #endif
4295fff9558SSimon J. Gerraty 
4305fff9558SSimon J. Gerraty 	mc.vtable->start_chain(&mc.vtable, NULL);
4315fff9558SSimon J. Gerraty 	for (u = 0; u < VEC_LEN(chain); u ++) {
4325fff9558SSimon J. Gerraty 		xc = &VEC_ELT(chain, u);
4335fff9558SSimon J. Gerraty 		mc.vtable->start_cert(&mc.vtable, xc->data_len);
4345fff9558SSimon J. Gerraty 		mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
4355fff9558SSimon J. Gerraty 		mc.vtable->end_cert(&mc.vtable);
4365fff9558SSimon J. Gerraty 		switch (mc.err) {
4375fff9558SSimon J. Gerraty 		case 0:
4385fff9558SSimon J. Gerraty 		case BR_ERR_X509_OK:
4395fff9558SSimon J. Gerraty 		case BR_ERR_X509_EXPIRED:
4405fff9558SSimon J. Gerraty 			break;
4415fff9558SSimon J. Gerraty 		default:
4425fff9558SSimon J. Gerraty 			printf("u=%zu mc.err=%d\n", u, mc.err);
4435fff9558SSimon J. Gerraty 			break;
4445fff9558SSimon J. Gerraty 		}
4455fff9558SSimon J. Gerraty 	}
4465fff9558SSimon J. Gerraty 	err = mc.vtable->end_chain(&mc.vtable);
4475fff9558SSimon J. Gerraty 	pk = NULL;
4485fff9558SSimon J. Gerraty 	if (err) {
4495fff9558SSimon J. Gerraty 		ve_error_set("Validation failed, err = %d", err);
4505fff9558SSimon J. Gerraty 	} else {
4515fff9558SSimon J. Gerraty 		tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
4525fff9558SSimon J. Gerraty 		if (tpk != NULL) {
4535fff9558SSimon J. Gerraty 			pk = xpkeydup(tpk);
4545fff9558SSimon J. Gerraty 		}
4555fff9558SSimon J. Gerraty 	}
45613ea0450SMarcin Wojtas 	VEC_CLEAR(chain);
4575fff9558SSimon J. Gerraty 	return (pk);
4585fff9558SSimon J. Gerraty }
4595fff9558SSimon J. Gerraty 
46013ea0450SMarcin Wojtas /*
46113ea0450SMarcin Wojtas  * Check if digest of one of the certificates from verified chain
46213ea0450SMarcin Wojtas  * is present in the forbidden database.
46313ea0450SMarcin Wojtas  * Since UEFI allows to store three types of digests
46413ea0450SMarcin Wojtas  * all of them have to be checked separately.
46513ea0450SMarcin Wojtas  */
46613ea0450SMarcin Wojtas static int
46713ea0450SMarcin Wojtas check_forbidden_digests(br_x509_certificate *xcs, size_t num)
46813ea0450SMarcin Wojtas {
46913ea0450SMarcin Wojtas 	unsigned char sha256_digest[br_sha256_SIZE];
47013ea0450SMarcin Wojtas 	unsigned char sha384_digest[br_sha384_SIZE];
47113ea0450SMarcin Wojtas 	unsigned char sha512_digest[br_sha512_SIZE];
47213ea0450SMarcin Wojtas 	void *tbs;
47313ea0450SMarcin Wojtas 	hash_data *digest;
47413ea0450SMarcin Wojtas 	br_hash_compat_context ctx;
47513ea0450SMarcin Wojtas 	const br_hash_class *md;
47613ea0450SMarcin Wojtas 	size_t tbs_len, i;
47713ea0450SMarcin Wojtas 	int have_sha256, have_sha384, have_sha512;
47813ea0450SMarcin Wojtas 
47913ea0450SMarcin Wojtas 	if (VEC_LEN(forbidden_digests) == 0)
48013ea0450SMarcin Wojtas 		return (0);
48113ea0450SMarcin Wojtas 
48213ea0450SMarcin Wojtas 	/*
48313ea0450SMarcin Wojtas 	 * Iterate through certificates, extract their To-Be-Signed section,
48413ea0450SMarcin Wojtas 	 * and compare its digest against the ones in the forbidden database.
48513ea0450SMarcin Wojtas 	 */
48613ea0450SMarcin Wojtas 	while (num--) {
48713ea0450SMarcin Wojtas 		tbs = X509_to_tbs(xcs[num].data, &tbs_len);
48813ea0450SMarcin Wojtas 		if (tbs == NULL) {
48913ea0450SMarcin Wojtas 			printf("Failed to obtain TBS part of certificate\n");
49013ea0450SMarcin Wojtas 			return (1);
49113ea0450SMarcin Wojtas 		}
49213ea0450SMarcin Wojtas 		have_sha256 = have_sha384 = have_sha512 = 0;
49313ea0450SMarcin Wojtas 
49413ea0450SMarcin Wojtas 		for (i = 0; i < VEC_LEN(forbidden_digests); i++) {
49513ea0450SMarcin Wojtas 			digest = &VEC_ELT(forbidden_digests, i);
49613ea0450SMarcin Wojtas 			switch (digest->hash_size) {
49713ea0450SMarcin Wojtas 			case br_sha256_SIZE:
49813ea0450SMarcin Wojtas 				if (!have_sha256) {
49913ea0450SMarcin Wojtas 					have_sha256 = 1;
50013ea0450SMarcin Wojtas 					md = &br_sha256_vtable;
50113ea0450SMarcin Wojtas 					md->init(&ctx.vtable);
50213ea0450SMarcin Wojtas 					md->update(&ctx.vtable, tbs, tbs_len);
50313ea0450SMarcin Wojtas 					md->out(&ctx.vtable, sha256_digest);
50413ea0450SMarcin Wojtas 				}
50513ea0450SMarcin Wojtas 				if (!memcmp(sha256_digest,
50613ea0450SMarcin Wojtas 					digest->data,
50713ea0450SMarcin Wojtas 					br_sha256_SIZE))
50813ea0450SMarcin Wojtas 					return (1);
50913ea0450SMarcin Wojtas 
51013ea0450SMarcin Wojtas 				break;
51113ea0450SMarcin Wojtas 			case br_sha384_SIZE:
51213ea0450SMarcin Wojtas 				if (!have_sha384) {
51313ea0450SMarcin Wojtas 					have_sha384 = 1;
51413ea0450SMarcin Wojtas 					md = &br_sha384_vtable;
51513ea0450SMarcin Wojtas 					md->init(&ctx.vtable);
51613ea0450SMarcin Wojtas 					md->update(&ctx.vtable, tbs, tbs_len);
51713ea0450SMarcin Wojtas 					md->out(&ctx.vtable, sha384_digest);
51813ea0450SMarcin Wojtas 				}
51913ea0450SMarcin Wojtas 				if (!memcmp(sha384_digest,
52013ea0450SMarcin Wojtas 					digest->data,
52113ea0450SMarcin Wojtas 					br_sha384_SIZE))
52213ea0450SMarcin Wojtas 					return (1);
52313ea0450SMarcin Wojtas 
52413ea0450SMarcin Wojtas 				break;
52513ea0450SMarcin Wojtas 			case br_sha512_SIZE:
52613ea0450SMarcin Wojtas 				if (!have_sha512) {
52713ea0450SMarcin Wojtas 					have_sha512 = 1;
52813ea0450SMarcin Wojtas 					md = &br_sha512_vtable;
52913ea0450SMarcin Wojtas 					md->init(&ctx.vtable);
53013ea0450SMarcin Wojtas 					md->update(&ctx.vtable, tbs, tbs_len);
53113ea0450SMarcin Wojtas 					md->out(&ctx.vtable, sha512_digest);
53213ea0450SMarcin Wojtas 				}
53313ea0450SMarcin Wojtas 				if (!memcmp(sha512_digest,
53413ea0450SMarcin Wojtas 					digest->data,
53513ea0450SMarcin Wojtas 					br_sha512_SIZE))
53613ea0450SMarcin Wojtas 					return (1);
53713ea0450SMarcin Wojtas 
53813ea0450SMarcin Wojtas 				break;
53913ea0450SMarcin Wojtas 			}
54013ea0450SMarcin Wojtas 		}
54113ea0450SMarcin Wojtas 	}
54213ea0450SMarcin Wojtas 
54313ea0450SMarcin Wojtas 	return (0);
54413ea0450SMarcin Wojtas }
54513ea0450SMarcin Wojtas 
5465fff9558SSimon J. Gerraty static br_x509_pkey *
5475fff9558SSimon J. Gerraty verify_signer(const char *certs,
5485fff9558SSimon J. Gerraty     br_name_element *elts, size_t num_elts)
5495fff9558SSimon J. Gerraty {
5505fff9558SSimon J. Gerraty 	br_x509_certificate *xcs;
5515fff9558SSimon J. Gerraty 	br_x509_pkey *pk;
5525fff9558SSimon J. Gerraty 	size_t num;
5535fff9558SSimon J. Gerraty 
55413ea0450SMarcin Wojtas 	pk = NULL;
55513ea0450SMarcin Wojtas 
5565fff9558SSimon J. Gerraty 	ve_trust_init();
5575fff9558SSimon J. Gerraty 	xcs = read_certificates(certs, &num);
5585fff9558SSimon J. Gerraty 	if (xcs == NULL) {
5595fff9558SSimon J. Gerraty 		ve_error_set("cannot read certificates\n");
5605fff9558SSimon J. Gerraty 		return (NULL);
5615fff9558SSimon J. Gerraty 	}
56213ea0450SMarcin Wojtas 
56313ea0450SMarcin Wojtas 	/*
56413ea0450SMarcin Wojtas 	 * Check if either
56513ea0450SMarcin Wojtas 	 * 1. There is a direct match between cert from forbidden_anchors
56613ea0450SMarcin Wojtas 	 * and a cert from chain.
56713ea0450SMarcin Wojtas 	 * 2. CA that signed the chain is found in forbidden_anchors.
56813ea0450SMarcin Wojtas 	 */
56913ea0450SMarcin Wojtas 	if (VEC_LEN(forbidden_anchors) > 0)
57013ea0450SMarcin Wojtas 		pk = verify_signer_xcs(xcs, num, elts, num_elts, &forbidden_anchors);
57113ea0450SMarcin Wojtas 	if (pk != NULL) {
57213ea0450SMarcin Wojtas 		ve_error_set("Certificate is on forbidden list\n");
57313ea0450SMarcin Wojtas 		xfreepkey(pk);
57413ea0450SMarcin Wojtas 		pk = NULL;
57513ea0450SMarcin Wojtas 		goto out;
57613ea0450SMarcin Wojtas 	}
57713ea0450SMarcin Wojtas 
57813ea0450SMarcin Wojtas 	pk = verify_signer_xcs(xcs, num, elts, num_elts, &trust_anchors);
57913ea0450SMarcin Wojtas 	if (pk == NULL)
58013ea0450SMarcin Wojtas 		goto out;
58113ea0450SMarcin Wojtas 
58213ea0450SMarcin Wojtas 	/*
58313ea0450SMarcin Wojtas 	 * Check if hash of tbs part of any certificate in chain
58413ea0450SMarcin Wojtas 	 * is on the forbidden list.
58513ea0450SMarcin Wojtas 	 */
58613ea0450SMarcin Wojtas 	if (check_forbidden_digests(xcs, num)) {
58713ea0450SMarcin Wojtas 		ve_error_set("Certificate hash is on forbidden list\n");
58813ea0450SMarcin Wojtas 		xfreepkey(pk);
58913ea0450SMarcin Wojtas 		pk = NULL;
59013ea0450SMarcin Wojtas 	}
59113ea0450SMarcin Wojtas out:
59213ea0450SMarcin Wojtas 	free_certificates(xcs, num);
5935fff9558SSimon J. Gerraty 	return (pk);
5945fff9558SSimon J. Gerraty }
5955fff9558SSimon J. Gerraty 
5965fff9558SSimon J. Gerraty /**
5975fff9558SSimon J. Gerraty  * we need a hex digest including trailing newline below
5985fff9558SSimon J. Gerraty  */
5995fff9558SSimon J. Gerraty char *
6005fff9558SSimon J. Gerraty hexdigest(char *buf, size_t bufsz, unsigned char *foo, size_t foo_len)
6015fff9558SSimon J. Gerraty {
6025fff9558SSimon J. Gerraty 	char const hex2ascii[] = "0123456789abcdef";
6035fff9558SSimon J. Gerraty 	size_t i;
6045fff9558SSimon J. Gerraty 
6055fff9558SSimon J. Gerraty 	/* every binary byte is 2 chars in hex + newline + null  */
6065fff9558SSimon J. Gerraty 	if (bufsz < (2 * foo_len) + 2)
6075fff9558SSimon J. Gerraty 		return (NULL);
6085fff9558SSimon J. Gerraty 
6095fff9558SSimon J. Gerraty 	for (i = 0; i < foo_len; i++) {
6105fff9558SSimon J. Gerraty 		buf[i * 2] = hex2ascii[foo[i] >> 4];
6115fff9558SSimon J. Gerraty 		buf[i * 2 + 1] = hex2ascii[foo[i] & 0x0f];
6125fff9558SSimon J. Gerraty 	}
6135fff9558SSimon J. Gerraty 
6145fff9558SSimon J. Gerraty 	buf[i * 2] = 0x0A; /* we also want a newline */
6155fff9558SSimon J. Gerraty 	buf[i * 2 + 1] = '\0';
6165fff9558SSimon J. Gerraty 
6175fff9558SSimon J. Gerraty 	return (buf);
6185fff9558SSimon J. Gerraty }
6195fff9558SSimon J. Gerraty 
6205fff9558SSimon J. Gerraty /**
6215fff9558SSimon J. Gerraty  * @brief
6225fff9558SSimon J. Gerraty  * verify file against sigfile using pk
6235fff9558SSimon J. Gerraty  *
6245fff9558SSimon J. Gerraty  * When we generated the signature in sigfile,
6255fff9558SSimon J. Gerraty  * we hashed (sha256) file, and sent that to signing server
6265fff9558SSimon J. Gerraty  * which hashed (sha256) that hash.
6275fff9558SSimon J. Gerraty  *
6285fff9558SSimon J. Gerraty  * To verify we need to replicate that result.
6295fff9558SSimon J. Gerraty  *
6305fff9558SSimon J. Gerraty  * @param[in] pk
6315fff9558SSimon J. Gerraty  *	br_x509_pkey
6325fff9558SSimon J. Gerraty  *
6335fff9558SSimon J. Gerraty  * @paramp[in] file
6345fff9558SSimon J. Gerraty  *	file to be verified
6355fff9558SSimon J. Gerraty  *
6365fff9558SSimon J. Gerraty  * @param[in] sigfile
6375fff9558SSimon J. Gerraty  * 	signature (PEM encoded)
6385fff9558SSimon J. Gerraty  *
6395fff9558SSimon J. Gerraty  * @return NULL on error, otherwise content of file.
6405fff9558SSimon J. Gerraty  */
6415fff9558SSimon J. Gerraty #ifdef VE_ECDSA_SUPPORT
6425fff9558SSimon J. Gerraty static unsigned char *
6435fff9558SSimon J. Gerraty verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile)
6445fff9558SSimon J. Gerraty {
6455fff9558SSimon J. Gerraty 	char hexbuf[br_sha512_SIZE * 2 + 2];
6465fff9558SSimon J. Gerraty 	unsigned char rhbuf[br_sha512_SIZE];
6475fff9558SSimon J. Gerraty 	char *hex;
6485fff9558SSimon J. Gerraty 	br_sha256_context ctx;
6495fff9558SSimon J. Gerraty 	unsigned char *fcp, *scp;
6505fff9558SSimon J. Gerraty 	size_t flen, slen, plen;
6515fff9558SSimon J. Gerraty 	pem_object *po;
6525fff9558SSimon J. Gerraty 	const br_ec_impl *ec;
6535fff9558SSimon J. Gerraty 	br_ecdsa_vrfy vrfy;
6545fff9558SSimon J. Gerraty 
6555fff9558SSimon J. Gerraty 	if ((fcp = read_file(file, &flen)) == NULL)
6565fff9558SSimon J. Gerraty 		return (NULL);
6575fff9558SSimon J. Gerraty 	if ((scp = read_file(sigfile, &slen)) == NULL) {
6585fff9558SSimon J. Gerraty 		free(fcp);
6595fff9558SSimon J. Gerraty 		return (NULL);
6605fff9558SSimon J. Gerraty 	}
6615fff9558SSimon J. Gerraty 	if ((po = decode_pem(scp, slen, &plen)) == NULL) {
6625fff9558SSimon J. Gerraty 		free(fcp);
6635fff9558SSimon J. Gerraty 		free(scp);
6645fff9558SSimon J. Gerraty 		return (NULL);
6655fff9558SSimon J. Gerraty 	}
6665fff9558SSimon J. Gerraty 	br_sha256_init(&ctx);
6675fff9558SSimon J. Gerraty 	br_sha256_update(&ctx, fcp, flen);
6685fff9558SSimon J. Gerraty 	br_sha256_out(&ctx, rhbuf);
669f9510887SSimon J. Gerraty #ifdef VE_ECDSA_HASH_AGAIN
6705fff9558SSimon J. Gerraty 	hex = hexdigest(hexbuf, sizeof(hexbuf), rhbuf, br_sha256_SIZE);
6715fff9558SSimon J. Gerraty 	/* now hash that */
6725fff9558SSimon J. Gerraty 	if (hex) {
6735fff9558SSimon J. Gerraty 		br_sha256_init(&ctx);
6745fff9558SSimon J. Gerraty 		br_sha256_update(&ctx, hex, strlen(hex));
6755fff9558SSimon J. Gerraty 		br_sha256_out(&ctx, rhbuf);
6765fff9558SSimon J. Gerraty 	}
677f9510887SSimon J. Gerraty #endif
6785fff9558SSimon J. Gerraty 	ec = br_ec_get_default();
6795fff9558SSimon J. Gerraty 	vrfy = br_ecdsa_vrfy_asn1_get_default();
6805fff9558SSimon J. Gerraty 	if (!vrfy(ec, rhbuf, br_sha256_SIZE, &pk->key.ec, po->data,
6815fff9558SSimon J. Gerraty 		po->data_len)) {
6825fff9558SSimon J. Gerraty 		free(fcp);
6835fff9558SSimon J. Gerraty 		fcp = NULL;
6845fff9558SSimon J. Gerraty 	}
6855fff9558SSimon J. Gerraty 	free(scp);
6865fff9558SSimon J. Gerraty 	return (fcp);
6875fff9558SSimon J. Gerraty }
6885fff9558SSimon J. Gerraty #endif
6895fff9558SSimon J. Gerraty 
6905fff9558SSimon J. Gerraty #if defined(VE_RSA_SUPPORT) || defined(VE_OPENPGP_SUPPORT)
6915fff9558SSimon J. Gerraty /**
6925fff9558SSimon J. Gerraty  * @brief verify an rsa digest
6935fff9558SSimon J. Gerraty  *
6945fff9558SSimon J. Gerraty  * @return 0 on failure
6955fff9558SSimon J. Gerraty  */
6965fff9558SSimon J. Gerraty int
6975fff9558SSimon J. Gerraty verify_rsa_digest (br_rsa_public_key *pkey,
6985fff9558SSimon J. Gerraty     const unsigned char *hash_oid,
6995fff9558SSimon J. Gerraty     unsigned char *mdata, size_t mlen,
7005fff9558SSimon J. Gerraty     unsigned char *sdata, size_t slen)
7015fff9558SSimon J. Gerraty {
7025fff9558SSimon J. Gerraty 	br_rsa_pkcs1_vrfy vrfy;
7035fff9558SSimon J. Gerraty 	unsigned char vhbuf[br_sha512_SIZE];
7045fff9558SSimon J. Gerraty 
7055fff9558SSimon J. Gerraty 	vrfy = br_rsa_pkcs1_vrfy_get_default();
7065fff9558SSimon J. Gerraty 
7075fff9558SSimon J. Gerraty 	if (!vrfy(sdata, slen, hash_oid, mlen, pkey, vhbuf) ||
7085fff9558SSimon J. Gerraty 	    memcmp(vhbuf, mdata, mlen) != 0) {
7095fff9558SSimon J. Gerraty 		return (0);		/* fail */
7105fff9558SSimon J. Gerraty 	}
7115fff9558SSimon J. Gerraty 	return (1);			/* ok */
7125fff9558SSimon J. Gerraty }
7135fff9558SSimon J. Gerraty #endif
7145fff9558SSimon J. Gerraty 
7155fff9558SSimon J. Gerraty /**
7165fff9558SSimon J. Gerraty  * @brief
7175fff9558SSimon J. Gerraty  * verify file against sigfile using pk
7185fff9558SSimon J. Gerraty  *
7195fff9558SSimon J. Gerraty  * When we generated the signature in sigfile,
7205fff9558SSimon J. Gerraty  * we hashed (sha256) file, and sent that to signing server
7215fff9558SSimon J. Gerraty  * which hashed (sha256) that hash.
7225fff9558SSimon J. Gerraty  *
7235fff9558SSimon J. Gerraty  * Or (deprecated) we simply used sha1 hash directly.
7245fff9558SSimon J. Gerraty  *
7255fff9558SSimon J. Gerraty  * To verify we need to replicate that result.
7265fff9558SSimon J. Gerraty  *
7275fff9558SSimon J. Gerraty  * @param[in] pk
7285fff9558SSimon J. Gerraty  *	br_x509_pkey
7295fff9558SSimon J. Gerraty  *
7305fff9558SSimon J. Gerraty  * @paramp[in] file
7315fff9558SSimon J. Gerraty  *	file to be verified
7325fff9558SSimon J. Gerraty  *
7335fff9558SSimon J. Gerraty  * @param[in] sigfile
7345fff9558SSimon J. Gerraty  * 	signature (PEM encoded)
7355fff9558SSimon J. Gerraty  *
7365fff9558SSimon J. Gerraty  * @return NULL on error, otherwise content of file.
7375fff9558SSimon J. Gerraty  */
7385fff9558SSimon J. Gerraty #ifdef VE_RSA_SUPPORT
7395fff9558SSimon J. Gerraty static unsigned char *
7405fff9558SSimon J. Gerraty verify_rsa(br_x509_pkey *pk,  const char *file, const char *sigfile)
7415fff9558SSimon J. Gerraty {
7425fff9558SSimon J. Gerraty 	unsigned char rhbuf[br_sha512_SIZE];
7435fff9558SSimon J. Gerraty 	const unsigned char *hash_oid;
7445fff9558SSimon J. Gerraty 	const br_hash_class *md;
7455fff9558SSimon J. Gerraty 	br_hash_compat_context mctx;
7465fff9558SSimon J. Gerraty 	unsigned char *fcp, *scp;
7475fff9558SSimon J. Gerraty 	size_t flen, slen, plen, hlen;
7485fff9558SSimon J. Gerraty 	pem_object *po;
7495fff9558SSimon J. Gerraty 
7505fff9558SSimon J. Gerraty 	if ((fcp = read_file(file, &flen)) == NULL)
7515fff9558SSimon J. Gerraty 		return (NULL);
7525fff9558SSimon J. Gerraty 	if ((scp = read_file(sigfile, &slen)) == NULL) {
7535fff9558SSimon J. Gerraty 		free(fcp);
7545fff9558SSimon J. Gerraty 		return (NULL);
7555fff9558SSimon J. Gerraty 	}
7565fff9558SSimon J. Gerraty 	if ((po = decode_pem(scp, slen, &plen)) == NULL) {
7575fff9558SSimon J. Gerraty 		free(fcp);
7585fff9558SSimon J. Gerraty 		free(scp);
7595fff9558SSimon J. Gerraty 		return (NULL);
7605fff9558SSimon J. Gerraty 	}
7615fff9558SSimon J. Gerraty 
7625fff9558SSimon J. Gerraty 	switch (po->data_len) {
7635fff9558SSimon J. Gerraty #if defined(UNIT_TEST) && defined(VE_DEPRECATED_RSA_SHA1_SUPPORT)
7645fff9558SSimon J. Gerraty 	case 256:
7655fff9558SSimon J. Gerraty 		// this is our old deprecated sig method
7665fff9558SSimon J. Gerraty 		md = &br_sha1_vtable;
7675fff9558SSimon J. Gerraty 		hlen = br_sha1_SIZE;
7685fff9558SSimon J. Gerraty 		hash_oid = BR_HASH_OID_SHA1;
7695fff9558SSimon J. Gerraty 		break;
7705fff9558SSimon J. Gerraty #endif
7715fff9558SSimon J. Gerraty 	default:
7725fff9558SSimon J. Gerraty 		md = &br_sha256_vtable;
7735fff9558SSimon J. Gerraty 		hlen = br_sha256_SIZE;
7745fff9558SSimon J. Gerraty 		hash_oid = BR_HASH_OID_SHA256;
7755fff9558SSimon J. Gerraty 		break;
7765fff9558SSimon J. Gerraty 	}
7775fff9558SSimon J. Gerraty 	md->init(&mctx.vtable);
7785fff9558SSimon J. Gerraty 	md->update(&mctx.vtable, fcp, flen);
7795fff9558SSimon J. Gerraty 	md->out(&mctx.vtable, rhbuf);
7805fff9558SSimon J. Gerraty 	if (!verify_rsa_digest(&pk->key.rsa, hash_oid,
7815fff9558SSimon J. Gerraty 		rhbuf, hlen, po->data, po->data_len)) {
7825fff9558SSimon J. Gerraty 		free(fcp);
7835fff9558SSimon J. Gerraty 		fcp = NULL;
7845fff9558SSimon J. Gerraty 	}
7855fff9558SSimon J. Gerraty 	free(scp);
7865fff9558SSimon J. Gerraty 	return (fcp);
7875fff9558SSimon J. Gerraty }
7885fff9558SSimon J. Gerraty #endif
7895fff9558SSimon J. Gerraty 
7905fff9558SSimon J. Gerraty /**
7915fff9558SSimon J. Gerraty  * @brief
7925fff9558SSimon J. Gerraty  * verify a signature and return content of signed file
7935fff9558SSimon J. Gerraty  *
7945fff9558SSimon J. Gerraty  * @param[in] sigfile
7955fff9558SSimon J. Gerraty  * 	file containing signature
7965fff9558SSimon J. Gerraty  * 	we derrive path of signed file and certificate change from
7975fff9558SSimon J. Gerraty  * 	this.
7985fff9558SSimon J. Gerraty  *
7995fff9558SSimon J. Gerraty  * @param[in] flags
8005fff9558SSimon J. Gerraty  * 	only bit 1 significant so far
8015fff9558SSimon J. Gerraty  *
8025fff9558SSimon J. Gerraty  * @return NULL on error otherwise content of signed file
8035fff9558SSimon J. Gerraty  */
8045fff9558SSimon J. Gerraty unsigned char *
8055fff9558SSimon J. Gerraty verify_sig(const char *sigfile, int flags)
8065fff9558SSimon J. Gerraty {
8075fff9558SSimon J. Gerraty 	br_x509_pkey *pk;
8085fff9558SSimon J. Gerraty 	br_name_element cn;
8095fff9558SSimon J. Gerraty 	char cn_buf[80];
8105fff9558SSimon J. Gerraty 	unsigned char cn_oid[4];
8115fff9558SSimon J. Gerraty 	char pbuf[MAXPATHLEN];
8125fff9558SSimon J. Gerraty 	char *cp;
8135fff9558SSimon J. Gerraty 	unsigned char *ucp;
8145fff9558SSimon J. Gerraty 	size_t n;
8155fff9558SSimon J. Gerraty 
8165fff9558SSimon J. Gerraty 	DEBUG_PRINTF(5, ("verify_sig: %s\n", sigfile));
8175fff9558SSimon J. Gerraty 	n = strlcpy(pbuf, sigfile, sizeof(pbuf));
8185fff9558SSimon J. Gerraty 	if (n > (sizeof(pbuf) - 5) || strcmp(&sigfile[n - 3], "sig") != 0)
8195fff9558SSimon J. Gerraty 		return (NULL);
8205fff9558SSimon J. Gerraty 	cp = strcpy(&pbuf[n - 3], "certs");
8215fff9558SSimon J. Gerraty 	/*
8225fff9558SSimon J. Gerraty 	 * We want the commonName field
8235fff9558SSimon J. Gerraty 	 * the OID we want is 2,5,4,3 - but DER encoded
8245fff9558SSimon J. Gerraty 	 */
8255fff9558SSimon J. Gerraty 	cn_oid[0] = 3;
8265fff9558SSimon J. Gerraty 	cn_oid[1] = 0x55;
8275fff9558SSimon J. Gerraty 	cn_oid[2] = 4;
8285fff9558SSimon J. Gerraty 	cn_oid[3] = 3;
8295fff9558SSimon J. Gerraty 	cn.oid = cn_oid;
8305fff9558SSimon J. Gerraty 	cn.buf = cn_buf;
8315fff9558SSimon J. Gerraty 	cn.len = sizeof(cn_buf);
8325fff9558SSimon J. Gerraty 
8335fff9558SSimon J. Gerraty 	pk = verify_signer(pbuf, &cn, 1);
8345fff9558SSimon J. Gerraty 	if (!pk) {
8355fff9558SSimon J. Gerraty 		printf("cannot verify: %s: %s\n", pbuf, ve_error_get());
8365fff9558SSimon J. Gerraty 		return (NULL);
8375fff9558SSimon J. Gerraty 	}
8385fff9558SSimon J. Gerraty 	for (; cp > pbuf; cp--) {
8395fff9558SSimon J. Gerraty 		if (*cp == '.') {
8405fff9558SSimon J. Gerraty 			*cp = '\0';
8415fff9558SSimon J. Gerraty 			break;
8425fff9558SSimon J. Gerraty 		}
8435fff9558SSimon J. Gerraty 	}
8445fff9558SSimon J. Gerraty 	switch (pk->key_type) {
8455fff9558SSimon J. Gerraty #ifdef VE_ECDSA_SUPPORT
8465fff9558SSimon J. Gerraty 	case BR_KEYTYPE_EC:
8475fff9558SSimon J. Gerraty 		ucp = verify_ec(pk, pbuf, sigfile);
8485fff9558SSimon J. Gerraty 		break;
8495fff9558SSimon J. Gerraty #endif
8505fff9558SSimon J. Gerraty #ifdef VE_RSA_SUPPORT
8515fff9558SSimon J. Gerraty 	case BR_KEYTYPE_RSA:
8525fff9558SSimon J. Gerraty 		ucp = verify_rsa(pk, pbuf, sigfile);
8535fff9558SSimon J. Gerraty 		break;
8545fff9558SSimon J. Gerraty #endif
8555fff9558SSimon J. Gerraty 	default:
8565fff9558SSimon J. Gerraty 		ucp = NULL;		/* not supported */
8575fff9558SSimon J. Gerraty 	}
8585fff9558SSimon J. Gerraty 	xfreepkey(pk);
8595fff9558SSimon J. Gerraty 	if (!ucp) {
8605fff9558SSimon J. Gerraty 		printf("Unverified %s (%s)\n", pbuf,
8615fff9558SSimon J. Gerraty 		    cn.status ? cn_buf : "unknown");
8625fff9558SSimon J. Gerraty 	} else if ((flags & 1) != 0) {
8635fff9558SSimon J. Gerraty 		printf("Verified %s signed by %s\n", pbuf,
8645fff9558SSimon J. Gerraty 		    cn.status ? cn_buf : "someone we trust");
8655fff9558SSimon J. Gerraty 	}
8665fff9558SSimon J. Gerraty 	return (ucp);
8675fff9558SSimon J. Gerraty }
8685fff9558SSimon J. Gerraty 
8695fff9558SSimon J. Gerraty 
8705fff9558SSimon J. Gerraty /**
8715fff9558SSimon J. Gerraty  * @brief verify hash matches
8725fff9558SSimon J. Gerraty  *
8735fff9558SSimon J. Gerraty  * We have finished hashing a file,
8745fff9558SSimon J. Gerraty  * see if we got the desired result.
8755fff9558SSimon J. Gerraty  *
8765fff9558SSimon J. Gerraty  * @param[in] ctx
8775fff9558SSimon J. Gerraty  *	pointer to hash context
8785fff9558SSimon J. Gerraty  *
8795fff9558SSimon J. Gerraty  * @param[in] md
8805fff9558SSimon J. Gerraty  *	pointer to hash class
8815fff9558SSimon J. Gerraty  *
8825fff9558SSimon J. Gerraty  * @param[in] path
8835fff9558SSimon J. Gerraty  *	name of the file we are checking
8845fff9558SSimon J. Gerraty  *
8855fff9558SSimon J. Gerraty  * @param[in] want
8865fff9558SSimon J. Gerraty  *	the expected result
8875fff9558SSimon J. Gerraty  *
8885fff9558SSimon J. Gerraty  * @param[in] hlen
8895fff9558SSimon J. Gerraty  *	size of hash output
8905fff9558SSimon J. Gerraty  *
8915fff9558SSimon J. Gerraty  * @return 0 on success
8925fff9558SSimon J. Gerraty  */
8935fff9558SSimon J. Gerraty int
8945fff9558SSimon J. Gerraty ve_check_hash(br_hash_compat_context *ctx, const br_hash_class *md,
8955fff9558SSimon J. Gerraty     const char *path, const char *want, size_t hlen)
8965fff9558SSimon J. Gerraty {
8975fff9558SSimon J. Gerraty 	char hexbuf[br_sha512_SIZE * 2 + 2];
8985fff9558SSimon J. Gerraty 	unsigned char hbuf[br_sha512_SIZE];
8995fff9558SSimon J. Gerraty 	char *hex;
9005fff9558SSimon J. Gerraty 	int rc;
9015fff9558SSimon J. Gerraty 	int n;
9025fff9558SSimon J. Gerraty 
9035fff9558SSimon J. Gerraty 	md->out(&ctx->vtable, hbuf);
9045fff9558SSimon J. Gerraty #ifdef VE_PCR_SUPPORT
9055fff9558SSimon J. Gerraty 	ve_pcr_update(hbuf, hlen);
9065fff9558SSimon J. Gerraty #endif
9075fff9558SSimon J. Gerraty 	hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
9085fff9558SSimon J. Gerraty 	if (!hex)
9095fff9558SSimon J. Gerraty 		return (VE_FINGERPRINT_WRONG);
9105fff9558SSimon J. Gerraty 	n = 2*hlen;
9115fff9558SSimon J. Gerraty 	if ((rc = strncmp(hex, want, n))) {
9125fff9558SSimon J. Gerraty 		ve_error_set("%s: %.*s != %.*s", path, n, hex, n, want);
9135fff9558SSimon J. Gerraty 		rc = VE_FINGERPRINT_WRONG;
9145fff9558SSimon J. Gerraty 	}
9155fff9558SSimon J. Gerraty 	return (rc ? rc : VE_FINGERPRINT_OK);
9165fff9558SSimon J. Gerraty }
9175fff9558SSimon J. Gerraty 
9185fff9558SSimon J. Gerraty #ifdef VE_HASH_KAT_STR
9195fff9558SSimon J. Gerraty static int
9205fff9558SSimon J. Gerraty test_hash(const br_hash_class *md, size_t hlen,
9215fff9558SSimon J. Gerraty     const char *hname, const char *s, size_t slen, const char *want)
9225fff9558SSimon J. Gerraty {
9235fff9558SSimon J. Gerraty 	br_hash_compat_context mctx;
9245fff9558SSimon J. Gerraty 
9255fff9558SSimon J. Gerraty 	md->init(&mctx.vtable);
9265fff9558SSimon J. Gerraty 	md->update(&mctx.vtable, s, slen);
9275fff9558SSimon J. Gerraty 	return (ve_check_hash(&mctx, md, hname, want, hlen) != VE_FINGERPRINT_OK);
9285fff9558SSimon J. Gerraty }
9295fff9558SSimon J. Gerraty 
9305fff9558SSimon J. Gerraty #endif
9315fff9558SSimon J. Gerraty 
9325fff9558SSimon J. Gerraty #define ve_test_hash(n, N) \
9335fff9558SSimon J. Gerraty 	printf("Testing hash: " #n "\t\t\t\t%s\n", \
9345fff9558SSimon J. Gerraty 	    test_hash(&br_ ## n ## _vtable, br_ ## n ## _SIZE, #n, \
9359bee6a60SSimon J. Gerraty 	    VE_HASH_KAT_STR, VE_HASH_KAT_STRLEN(VE_HASH_KAT_STR), \
9365fff9558SSimon J. Gerraty 	    vh_ ## N) ? "Failed" : "Passed")
9375fff9558SSimon J. Gerraty 
9385fff9558SSimon J. Gerraty /**
9395fff9558SSimon J. Gerraty  * @brief
9405fff9558SSimon J. Gerraty  * run self tests on hash and signature verification
9415fff9558SSimon J. Gerraty  *
9425fff9558SSimon J. Gerraty  * Test that the hash methods (SHA1 and SHA256) work.
9435fff9558SSimon J. Gerraty  * Test that we can verify a certificate for each supported
9445fff9558SSimon J. Gerraty  * Root CA.
9455fff9558SSimon J. Gerraty  *
9465fff9558SSimon J. Gerraty  * @return cached result.
9475fff9558SSimon J. Gerraty  */
9485fff9558SSimon J. Gerraty int
9495fff9558SSimon J. Gerraty ve_self_tests(void)
9505fff9558SSimon J. Gerraty {
9515fff9558SSimon J. Gerraty 	static int once = -1;
9525fff9558SSimon J. Gerraty #ifdef VERIFY_CERTS_STR
9535fff9558SSimon J. Gerraty 	br_x509_certificate *xcs;
9545fff9558SSimon J. Gerraty 	br_x509_pkey *pk;
9555fff9558SSimon J. Gerraty 	br_name_element cn;
9565fff9558SSimon J. Gerraty 	char cn_buf[80];
9575fff9558SSimon J. Gerraty 	unsigned char cn_oid[4];
9585fff9558SSimon J. Gerraty 	size_t num;
9595fff9558SSimon J. Gerraty 	size_t u;
9605fff9558SSimon J. Gerraty #endif
9615fff9558SSimon J. Gerraty 
9625fff9558SSimon J. Gerraty 	if (once >= 0)
9635fff9558SSimon J. Gerraty 		return (once);
9645fff9558SSimon J. Gerraty 	once = 0;
9655fff9558SSimon J. Gerraty 
9665fff9558SSimon J. Gerraty 	DEBUG_PRINTF(5, ("Self tests...\n"));
9675fff9558SSimon J. Gerraty #ifdef VE_HASH_KAT_STR
9685fff9558SSimon J. Gerraty #ifdef VE_SHA1_SUPPORT
9695fff9558SSimon J. Gerraty 	ve_test_hash(sha1, SHA1);
9705fff9558SSimon J. Gerraty #endif
9715fff9558SSimon J. Gerraty #ifdef VE_SHA256_SUPPORT
9725fff9558SSimon J. Gerraty 	ve_test_hash(sha256, SHA256);
9735fff9558SSimon J. Gerraty #endif
9745fff9558SSimon J. Gerraty #ifdef VE_SHA384_SUPPORT
9755fff9558SSimon J. Gerraty 	ve_test_hash(sha384, SHA384);
9765fff9558SSimon J. Gerraty #endif
9775fff9558SSimon J. Gerraty #ifdef VE_SHA512_SUPPORT
9785fff9558SSimon J. Gerraty 	ve_test_hash(sha512, SHA512);
9795fff9558SSimon J. Gerraty #endif
9805fff9558SSimon J. Gerraty #endif
9815fff9558SSimon J. Gerraty #ifdef VERIFY_CERTS_STR
9825fff9558SSimon J. Gerraty 	xcs = parse_certificates(__DECONST(unsigned char *, VERIFY_CERTS_STR),
9835fff9558SSimon J. Gerraty 	    sizeof(VERIFY_CERTS_STR), &num);
9849bee6a60SSimon J. Gerraty 	if (xcs != NULL) {
9855fff9558SSimon J. Gerraty 		/*
9865fff9558SSimon J. Gerraty 		 * We want the commonName field
9875fff9558SSimon J. Gerraty 		 * the OID we want is 2,5,4,3 - but DER encoded
9885fff9558SSimon J. Gerraty 		 */
9895fff9558SSimon J. Gerraty 		cn_oid[0] = 3;
9905fff9558SSimon J. Gerraty 		cn_oid[1] = 0x55;
9915fff9558SSimon J. Gerraty 		cn_oid[2] = 4;
9925fff9558SSimon J. Gerraty 		cn_oid[3] = 3;
9935fff9558SSimon J. Gerraty 		cn.oid = cn_oid;
9945fff9558SSimon J. Gerraty 		cn.buf = cn_buf;
9955fff9558SSimon J. Gerraty 
9965fff9558SSimon J. Gerraty 		for (u = 0; u < num; u ++) {
9975fff9558SSimon J. Gerraty 			cn.len = sizeof(cn_buf);
99813ea0450SMarcin Wojtas 			if ((pk = verify_signer_xcs(&xcs[u], 1, &cn, 1, &trust_anchors)) != NULL) {
99913ea0450SMarcin Wojtas 				free_cert_contents(&xcs[u]);
10005fff9558SSimon J. Gerraty 				once++;
10015fff9558SSimon J. Gerraty 				printf("Testing verify certificate: %s\tPassed\n",
10025fff9558SSimon J. Gerraty 				    cn.status ? cn_buf : "");
10035fff9558SSimon J. Gerraty 				xfreepkey(pk);
10045fff9558SSimon J. Gerraty 			}
10055fff9558SSimon J. Gerraty 		}
10065fff9558SSimon J. Gerraty 		if (!once)
10075fff9558SSimon J. Gerraty 			printf("Testing verify certificate:\t\t\tFailed\n");
10085fff9558SSimon J. Gerraty 		xfree(xcs);
10099bee6a60SSimon J. Gerraty 	}
10105fff9558SSimon J. Gerraty #endif	/* VERIFY_CERTS_STR */
10115fff9558SSimon J. Gerraty #ifdef VE_OPENPGP_SUPPORT
10125fff9558SSimon J. Gerraty 	if (!openpgp_self_tests())
10135fff9558SSimon J. Gerraty 		once++;
10145fff9558SSimon J. Gerraty #endif
10155fff9558SSimon J. Gerraty 	return (once);
10165fff9558SSimon J. Gerraty }
1017