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