Changeset View
Standalone View
lib/libve/vets.c
- This file was added.
Property | Old Value | New Value |
---|---|---|
svn:eol-style | null | native \ No newline at end of property |
svn:keywords | null | FreeBSD=%H \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
/*- | |||||
* Copyright (c) 2017, Juniper Networks, Inc. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
#include <sys/cdefs.h> | |||||
__FBSDID("$FreeBSD$"); | |||||
/** | |||||
* @file vets.c - trust store | |||||
* @brief verify signatures | |||||
* | |||||
* We leverage code from BearSSL www.bearssl.org | |||||
*/ | |||||
#include <sys/time.h> | |||||
#include <stdarg.h> | |||||
#define NEED_BRSSL_H | |||||
#include "libve-priv.h" | |||||
#include <brssl.h> | |||||
#include "ta.h" | |||||
#ifndef TRUST_ANCHOR_STR | |||||
# define TRUST_ANCHOR_STR ta_PEM | |||||
#endif | |||||
int DebugVe = 0; | |||||
typedef VECTOR(br_x509_certificate) cert_list; | |||||
static anchor_list trust_anchors = VEC_INIT; | |||||
void | |||||
ve_debug_set(int n) | |||||
{ | |||||
DebugVe = n; | |||||
} | |||||
static char ebuf[512]; | |||||
char * | |||||
ve_error_get(void) | |||||
{ | |||||
return (ebuf); | |||||
} | |||||
int | |||||
ve_error_set(const char *fmt, ...) | |||||
{ | |||||
int rc; | |||||
va_list ap; | |||||
va_start(ap, fmt); | |||||
ebuf[0] = '\0'; | |||||
rc = 0; | |||||
if (fmt) { | |||||
#ifdef STAND_H | |||||
vsprintf(ebuf, fmt, ap); /* no vsnprintf in libstand */ | |||||
ebuf[sizeof(ebuf) - 1] = '\0'; | |||||
rc = strlen(ebuf); | |||||
#else | |||||
rc = vsnprintf(ebuf, sizeof(ebuf), fmt, ap); | |||||
#endif | |||||
} | |||||
va_end(ap); | |||||
return (rc); | |||||
} | |||||
/* this is the time we use for verifying certs */ | |||||
static time_t ve_utc = 0; | |||||
/** | |||||
* @brief | |||||
* set ve_utc used for certificate verification | |||||
* | |||||
* @param[in] utc | |||||
* time - ignored unless greater than current value. | |||||
*/ | |||||
void | |||||
ve_utc_set(time_t utc) | |||||
{ | |||||
if (utc > ve_utc) { | |||||
DEBUG_PRINTF(2, ("Set ve_utc=%jd\n", (intmax_t)utc)); | |||||
ve_utc = utc; | |||||
} | |||||
} | |||||
static void | |||||
free_cert_contents(br_x509_certificate *xc) | |||||
{ | |||||
xfree(xc->data); | |||||
} | |||||
/** | |||||
* @brief | |||||
* add certs to our trust store | |||||
*/ | |||||
size_t | |||||
ve_trust_anchors_add(br_x509_certificate *xcs, size_t num) | |||||
{ | |||||
br_x509_trust_anchor ta; | |||||
size_t u; | |||||
for (u = 0; u < num; u++) { | |||||
if (certificate_to_trust_anchor_inner(&ta, &xcs[u]) < 0) { | |||||
break; | |||||
} | |||||
cem: this indentation appears to be inconsistent | |||||
VEC_ADD(trust_anchors, ta); | |||||
} | |||||
return (u); | |||||
} | |||||
/** | |||||
* @brief | |||||
* initialize our trust_anchors from ta_PEM | |||||
*/ | |||||
int | |||||
ve_trust_init(void) | |||||
{ | |||||
br_x509_certificate *xcs; | |||||
static int once = -1; | |||||
size_t num; | |||||
if (once >= 0) | |||||
return (once); | |||||
once = 0; | |||||
ve_utc_set(time(NULL)); | |||||
#ifdef BUILD_UTC | |||||
ve_utc_set(BUILD_UTC); /* just in case */ | |||||
#endif | |||||
ve_error_set(NULL); /* make sure it is empty */ | |||||
ve_pcr_init(0); /* default pcr size */ | |||||
#ifdef TRUST_ANCHOR_STR | |||||
xcs = parse_certificates((unsigned char *)TRUST_ANCHOR_STR, | |||||
sizeof(TRUST_ANCHOR_STR), &num); | |||||
if (xcs == NULL) | |||||
return (0); | |||||
num = ve_trust_anchors_add(xcs, num); | |||||
once = (int) num; | |||||
#else | |||||
num = 0; | |||||
#endif | |||||
return (num); | |||||
} | |||||
/** | |||||
* if we can verify the certificate chain in "certs", | |||||
* return the public key and if "xcp" is !NULL the associated | |||||
* certificate | |||||
*/ | |||||
static br_x509_pkey * | |||||
verify_signer_xcs(br_x509_certificate *xcs, | |||||
size_t num, | |||||
br_name_element *elts, size_t num_elts) | |||||
{ | |||||
br_x509_minimal_context mc; | |||||
br_x509_certificate *xc; | |||||
size_t u; | |||||
cert_list chain = VEC_INIT; | |||||
const br_x509_pkey *tpk; | |||||
br_x509_pkey *pk; | |||||
unsigned int usages; | |||||
int err; | |||||
DEBUG_PRINTF(5, ("verify_signer: %zu certs in chain\n", num)); | |||||
VEC_ADDMANY(chain, xcs, num); | |||||
if (VEC_LEN(chain) == 0) { | |||||
ve_error_set("ERROR: no/invalid certificate chain\n"); | |||||
return (NULL); | |||||
} | |||||
DEBUG_PRINTF(5, ("verify_signer: %zu trust anchors\n", | |||||
VEC_LEN(trust_anchors))); | |||||
br_x509_minimal_init(&mc, &br_sha256_vtable, | |||||
&VEC_ELT(trust_anchors, 0), | |||||
VEC_LEN(trust_anchors)); | |||||
#ifdef VE_ECDSA_SUPPORT | |||||
br_x509_minimal_set_ecdsa(&mc, | |||||
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); | |||||
#endif | |||||
#ifdef VE_RSA_SUPPORT | |||||
br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy); | |||||
#endif | |||||
#if defined(UNIT_TEST) && defined(VE_DEPRECATED_RSA_SHA1_SUPPORT) | |||||
/* This is deprecated! do not enable unless you absoultely have to */ | |||||
br_x509_minimal_set_hash(&mc, br_sha1_ID, &br_sha1_vtable); | |||||
#endif | |||||
Not Done Inline ActionsJust remove it. There's no reason to be using SHA1 in novel cryptographic designs in 2018. If you use it in JunOS, keep the SHA1 stuff in JunOS, but I'd suggest moving away from SHA1 there, too. cem: Just remove it. There's no reason to be using SHA1 in novel cryptographic designs in 2018. If… | |||||
br_x509_minimal_set_hash(&mc, br_sha256_ID, &br_sha256_vtable); | |||||
#ifdef VE_SHA384_SUPPORT | |||||
br_x509_minimal_set_hash(&mc, br_sha384_ID, &br_sha384_vtable); | |||||
#endif | |||||
#ifdef VE_SHA512_SUPPORT | |||||
br_x509_minimal_set_hash(&mc, br_sha512_ID, &br_sha512_vtable); | |||||
#endif | |||||
br_x509_minimal_set_name_elements(&mc, elts, num_elts); | |||||
#ifdef LOADER_VERIEXEC | |||||
/* | |||||
* Clock is probably bogus so we use ve_utc. | |||||
* The conversion is lifted from BearSSL x509_minimal. | |||||
*/ | |||||
Not Done Inline Actionsmagic numbers cem: magic numbers | |||||
Not Done Inline ActionsYes, I added the comment to indicate that this conversion is from BearSSL. sjg: Yes, I added the comment to indicate that this conversion is from BearSSL.
This btw is only… | |||||
Not Done Inline Actions86400 is 60*60*24 and defining it as such would make the derivation clear. Or #define SECONDS_PER_DAY 86400. Either way. 719528 looks to about 1970 years, so br_x509_minimal_context starts at year zero, I guess. Again, #define X509_DAYS_TO_UTC0 719528 would make that clear. cem: 86400 is 60*60*24 and defining it as such would make the derivation clear. Or `#define… | |||||
Not Done Inline ActionsSure. sjg: Sure. | |||||
mc.days = (ve_utc / 86400) + 719528; | |||||
mc.seconds = (ve_utc % 86400); | |||||
#endif | |||||
mc.vtable->start_chain(&mc.vtable, NULL); | |||||
for (u = 0; u < VEC_LEN(chain); u ++) { | |||||
xc = &VEC_ELT(chain, u); | |||||
mc.vtable->start_cert(&mc.vtable, xc->data_len); | |||||
mc.vtable->append(&mc.vtable, xc->data, xc->data_len); | |||||
mc.vtable->end_cert(&mc.vtable); | |||||
switch (mc.err) { | |||||
case 0: | |||||
case BR_ERR_X509_OK: | |||||
case BR_ERR_X509_EXPIRED: | |||||
break; | |||||
default: | |||||
printf("u=%zu mc.err=%d\n", u, mc.err); | |||||
break; | |||||
} | |||||
} | |||||
err = mc.vtable->end_chain(&mc.vtable); | |||||
pk = NULL; | |||||
if (err) { | |||||
ve_error_set("Validation failed, err = %d", err); | |||||
} else { | |||||
tpk = mc.vtable->get_pkey(&mc.vtable, &usages); | |||||
if (tpk != NULL) { | |||||
pk = xpkeydup(tpk); | |||||
} | |||||
} | |||||
VEC_CLEAREXT(chain, &free_cert_contents); | |||||
return (pk); | |||||
} | |||||
static br_x509_pkey * | |||||
verify_signer(const char *certs, | |||||
br_name_element *elts, size_t num_elts) | |||||
{ | |||||
br_x509_certificate *xcs; | |||||
br_x509_pkey *pk; | |||||
size_t num; | |||||
ve_trust_init(); | |||||
ve_self_tests(); | |||||
xcs = read_certificates(certs, &num); | |||||
if (xcs == NULL) { | |||||
ve_error_set("cannot read certificates\n"); | |||||
return (NULL); | |||||
} | |||||
pk = verify_signer_xcs(xcs, num, elts, num_elts); | |||||
xfree(xcs); | |||||
return (pk); | |||||
} | |||||
/** | |||||
* we need a hex digest including trailing newline below | |||||
*/ | |||||
char * | |||||
hexdigest(unsigned char *foo, size_t foo_len) | |||||
{ | |||||
/* every binary byte is 2 chars in hex + newline + null */ | |||||
static char hex[br_sha512_SIZE * 2 + 2]; | |||||
char const hex2ascii[] = "0123456789abcdef"; | |||||
size_t i; | |||||
for (i = 0; i < foo_len; i++) { | |||||
hex[i * 2] = hex2ascii[foo[i] >> 4]; | |||||
hex[i * 2 + 1] = hex2ascii[foo[i] & 0x0f]; | |||||
} | |||||
hex[i * 2] = 0x0A; /* we also want a newline */ | |||||
hex[i * 2 + 1] = '\0'; | |||||
Not Done Inline ActionsEw. Is this loader-only code? cem: Ew. Is this loader-only code? | |||||
Not Done Inline ActionsNo. sjg: No. | |||||
Done Inline ActionsThen please move the storage to callers instead of returning a reference to function-local static storage. cem: Then please move the storage to callers instead of returning a reference to function-local… | |||||
return (hex); | |||||
} | |||||
/** | |||||
* @brief | |||||
* verify file against sigfile using pk | |||||
* | |||||
* When we generated the signature in sigfile, | |||||
* we hashed (sha256) file, and sent that to signing server | |||||
* which hashed (sha256) that hash. | |||||
* | |||||
* To verify we need to replicate that result. | |||||
* | |||||
* @param[in] pk | |||||
* br_x509_pkey | |||||
* | |||||
* @paramp[in] file | |||||
* file to be verified | |||||
* | |||||
* @param[in] sigfile | |||||
* signature (PEM encoded) | |||||
* | |||||
* @return NULL on error, otherwise content of file. | |||||
*/ | |||||
#ifdef VE_ECDSA_SUPPORT | |||||
static unsigned char * | |||||
verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile) | |||||
{ | |||||
unsigned char rhbuf[br_sha512_SIZE]; | |||||
char *hex; | |||||
br_sha256_context ctx; | |||||
unsigned char *fcp, *scp; | |||||
size_t flen, slen, plen; | |||||
pem_object *po; | |||||
const br_ec_impl *ec; | |||||
br_ecdsa_vrfy vrfy; | |||||
if ((fcp = read_file(file, &flen)) == NULL) | |||||
return (NULL); | |||||
if ((scp = read_file(sigfile, &slen)) == NULL) { | |||||
free(fcp); | |||||
return (NULL); | |||||
} | |||||
if ((po = decode_pem(scp, slen, &plen)) == NULL) { | |||||
free(fcp); | |||||
free(scp); | |||||
return (NULL); | |||||
} | |||||
br_sha256_init(&ctx); | |||||
br_sha256_update(&ctx, fcp, flen); | |||||
br_sha256_out(&ctx, rhbuf); | |||||
hex = hexdigest(rhbuf, br_sha256_SIZE); | |||||
/* now hash that */ | |||||
br_sha256_init(&ctx); | |||||
br_sha256_update(&ctx, hex, strlen(hex)); | |||||
br_sha256_out(&ctx, rhbuf); | |||||
ec = br_ec_get_default(); | |||||
vrfy = br_ecdsa_vrfy_asn1_get_default(); | |||||
if (!vrfy(ec, rhbuf, br_sha256_SIZE, &pk->key.ec, po->data, | |||||
po->data_len)) { | |||||
free(fcp); | |||||
fcp = NULL; | |||||
} | |||||
free(scp); | |||||
return (fcp); | |||||
} | |||||
#endif | |||||
#if defined(VE_RSA_SUPPORT) || defined(VE_OPENPGP_SUPPORT) | |||||
/** | |||||
* @brief verify an rsa digest | |||||
* | |||||
* @return 0 on failure | |||||
*/ | |||||
int | |||||
verify_rsa_digest (br_rsa_public_key *pkey, | |||||
const unsigned char *hash_oid, | |||||
unsigned char *mdata, size_t mlen, | |||||
unsigned char *sdata, size_t slen) | |||||
{ | |||||
br_rsa_pkcs1_vrfy vrfy; | |||||
unsigned char vhbuf[br_sha512_SIZE]; | |||||
vrfy = br_rsa_pkcs1_vrfy_get_default(); | |||||
Not Done Inline Actionsshould this be timingsafe_memcmp? cem: should this be timingsafe_memcmp? | |||||
Not Done Inline ActionsI don't see that anything would be gained. sjg: I don't see that anything would be gained.
There's no secret info to be guessed at. | |||||
Not Done Inline ActionsOk cem: Ok | |||||
if (!vrfy(sdata, slen, hash_oid, mlen, pkey, vhbuf) || | |||||
memcmp(vhbuf, mdata, mlen) != 0) { | |||||
return (0); /* fail */ | |||||
} | |||||
return (1); /* ok */ | |||||
} | |||||
#endif | |||||
/** | |||||
* @brief | |||||
* verify file against sigfile using pk | |||||
* | |||||
* When we generated the signature in sigfile, | |||||
* we hashed (sha256) file, and sent that to signing server | |||||
* which hashed (sha256) that hash. | |||||
* | |||||
* Or (deprecated) we simply used sha1 hash directly. | |||||
* | |||||
* To verify we need to replicate that result. | |||||
* | |||||
* @param[in] pk | |||||
* br_x509_pkey | |||||
* | |||||
* @paramp[in] file | |||||
* file to be verified | |||||
* | |||||
* @param[in] sigfile | |||||
* signature (PEM encoded) | |||||
* | |||||
* @return NULL on error, otherwise content of file. | |||||
*/ | |||||
#ifdef VE_RSA_SUPPORT | |||||
static unsigned char * | |||||
verify_rsa(br_x509_pkey *pk, const char *file, const char *sigfile) | |||||
{ | |||||
unsigned char rhbuf[br_sha512_SIZE]; | |||||
unsigned char vhbuf[br_sha512_SIZE]; | |||||
const unsigned char *hash_oid; | |||||
const br_hash_class *md; | |||||
br_hash_compat_context mctx; | |||||
unsigned char *fcp, *scp; | |||||
size_t flen, slen, plen, hlen; | |||||
pem_object *po; | |||||
if ((fcp = read_file(file, &flen)) == NULL) | |||||
return (NULL); | |||||
if ((scp = read_file(sigfile, &slen)) == NULL) { | |||||
free(fcp); | |||||
return (NULL); | |||||
} | |||||
if ((po = decode_pem(scp, slen, &plen)) == NULL) { | |||||
free(fcp); | |||||
free(scp); | |||||
return (NULL); | |||||
} | |||||
switch (po->data_len) { | |||||
Not Done Inline Actionsthen don't commit it cem: then don't commit it | |||||
#if defined(UNIT_TEST) && defined(VE_DEPRECATED_RSA_SHA1_SUPPORT) | |||||
case 256: | |||||
// this is our old deprecated sig method | |||||
md = &br_sha1_vtable; | |||||
hlen = br_sha1_SIZE; | |||||
hash_oid = BR_HASH_OID_SHA1; | |||||
break; | |||||
#endif | |||||
default: | |||||
md = &br_sha256_vtable; | |||||
hlen = br_sha256_SIZE; | |||||
hash_oid = BR_HASH_OID_SHA256; | |||||
break; | |||||
} | |||||
md->init(&mctx.vtable); | |||||
md->update(&mctx.vtable, fcp, flen); | |||||
md->out(&mctx.vtable, rhbuf); | |||||
if (!verify_rsa_digest(&pk->key.rsa, hash_oid, | |||||
rhbuf, hlen, po->data, po->data_len)) { | |||||
free(fcp); | |||||
fcp = NULL; | |||||
} | |||||
free(scp); | |||||
return (fcp); | |||||
} | |||||
#endif | |||||
/** | |||||
* @brief | |||||
* verify a signature and return content of signed file | |||||
* | |||||
* @param[in] sigfile | |||||
* file containing signature | |||||
* we derrive path of signed file and certificate change from | |||||
* this. | |||||
* | |||||
* @param[in] flags | |||||
* only bit 1 significant so far | |||||
* | |||||
* @return NULL on error otherwise content of signed file | |||||
*/ | |||||
unsigned char * | |||||
verify_sig(const char *sigfile, int flags) | |||||
{ | |||||
br_x509_pkey *pk; | |||||
Not Done Inline Actionslarge stack buffer cem: large stack buffer | |||||
br_name_element cn; | |||||
char cn_buf[80]; | |||||
unsigned char cn_oid[4]; | |||||
char pbuf[MAXPATHLEN]; | |||||
char *cp; | |||||
unsigned char *ucp; | |||||
size_t n; | |||||
DEBUG_PRINTF(5, ("verify_sig: %s\n", sigfile)); | |||||
n = strlcpy(pbuf, sigfile, sizeof(pbuf)); | |||||
if (n > (sizeof(pbuf) - 5) || strcmp(&sigfile[n - 3], "sig") != 0) | |||||
return (NULL); | |||||
cp = strcpy(&pbuf[n - 3], "certs"); | |||||
/* | |||||
* We want the commonName field | |||||
* the OID we want is 2,5,4,3 - but DER encoded | |||||
*/ | |||||
Not Done Inline ActionsThis is pretty magical cem: This is pretty magical | |||||
Not Done Inline ActionsYes, as the comment says this is the DER encoded OID for commonName field sjg: Yes, as the comment says this is the DER encoded OID for commonName field
which we want so we… | |||||
Not Done Inline ActionsSurely these could be named constants? cem: Surely these could be named constants? | |||||
cn_oid[0] = 3; | |||||
cn_oid[1] = 0x55; | |||||
cn_oid[2] = 4; | |||||
cn_oid[3] = 3; | |||||
cn.oid = cn_oid; | |||||
cn.buf = cn_buf; | |||||
cn.len = sizeof(cn_buf); | |||||
pk = verify_signer(pbuf, &cn, 1); | |||||
if (!pk) { | |||||
printf("cannot verify: %s: %s\n", pbuf, ve_error_get()); | |||||
return (NULL); | |||||
} | |||||
for (; cp > pbuf; cp--) { | |||||
if (*cp == '.') { | |||||
*cp = '\0'; | |||||
break; | |||||
} | |||||
} | |||||
switch (pk->key_type) { | |||||
#ifdef VE_ECDSA_SUPPORT | |||||
case BR_KEYTYPE_EC: | |||||
ucp = verify_ec(pk, pbuf, sigfile); | |||||
break; | |||||
#endif | |||||
#ifdef VE_RSA_SUPPORT | |||||
case BR_KEYTYPE_RSA: | |||||
ucp = verify_rsa(pk, pbuf, sigfile); | |||||
break; | |||||
#endif | |||||
default: | |||||
ucp = NULL; /* not supported */ | |||||
} | |||||
xfreepkey(pk); | |||||
if (!ucp) { | |||||
printf("Unverified %s (%s)\n", pbuf, | |||||
cn.status ? cn_buf : "unknown"); | |||||
} else if ((flags & 1) != 0) { | |||||
printf("Verified %s signed by %s\n", pbuf, | |||||
cn.status ? cn_buf : "someone we trust"); | |||||
} | |||||
return (ucp); | |||||
} | |||||
#ifdef VERIFY_CERTS_STR | |||||
static int | |||||
test_hash(const br_hash_class *md, size_t hlen, | |||||
const char *hname, | |||||
const char *s, const char *want) | |||||
{ | |||||
br_hash_compat_context mctx; | |||||
md->init(&mctx.vtable); | |||||
md->update(&mctx.vtable, s, strlen(s)); | |||||
return (ve_check_hash(&mctx, md, hname, want, hlen) != VE_FINGERPRINT_OK); | |||||
} | |||||
#endif | |||||
#define ve_test_hash(n, N) \ | |||||
printf("Testing hash: " #n "\t\t\t\t%s\n", \ | |||||
test_hash(&br_ ## n ## _vtable, br_ ## n ## _SIZE, #n, \ | |||||
VERIFY_CERTS_STR, vc_ ## N) ? "Failed" : "Passed") | |||||
/** | |||||
* @brief | |||||
* run self tests on hash and signature verification | |||||
* | |||||
* Test that the hash methods (SHA1 and SHA256) work. | |||||
* Test that we can verify a certificate for each supported | |||||
* Root CA. | |||||
* | |||||
* @return cached result. | |||||
*/ | |||||
int | |||||
ve_self_tests(void) | |||||
{ | |||||
static int once = -1; | |||||
#ifdef VERIFY_CERTS_STR | |||||
br_x509_certificate *xcs; | |||||
br_x509_pkey *pk; | |||||
br_name_element cn; | |||||
char cn_buf[80]; | |||||
unsigned char cn_oid[4]; | |||||
size_t num; | |||||
size_t u; | |||||
#endif | |||||
if (once >= 0) | |||||
return (once); | |||||
once = 0; | |||||
DEBUG_PRINTF(5, ("Self tests...\n")); | |||||
#ifdef VERIFY_CERTS_STR | |||||
xcs = parse_certificates((unsigned char *)VERIFY_CERTS_STR, | |||||
sizeof(VERIFY_CERTS_STR), &num); | |||||
if (xcs == NULL) | |||||
return (0); | |||||
#ifdef VE_SHA1_SUPPORT | |||||
ve_test_hash(sha1, SHA1); | |||||
#endif | |||||
#ifdef VE_SHA256_SUPPORT | |||||
ve_test_hash(sha256, SHA256); | |||||
#endif | |||||
#ifdef VE_SHA384_SUPPORT | |||||
ve_test_hash(sha384, SHA384); | |||||
#endif | |||||
#ifdef VE_SHA512_SUPPORT | |||||
ve_test_hash(sha512, SHA512); | |||||
#endif | |||||
/* | |||||
* We want the commonName field | |||||
* the OID we want is 2,5,4,3 - but DER encoded | |||||
*/ | |||||
cn_oid[0] = 3; | |||||
cn_oid[1] = 0x55; | |||||
cn_oid[2] = 4; | |||||
cn_oid[3] = 3; | |||||
cn.oid = cn_oid; | |||||
cn.buf = cn_buf; | |||||
for (u = 0; u < num; u ++) { | |||||
cn.len = sizeof(cn_buf); | |||||
if ((pk = verify_signer_xcs(&xcs[u], 1, &cn, 1)) != NULL) { | |||||
once++; | |||||
printf("Testing verify certificate: %s\tPassed\n", | |||||
cn.status ? cn_buf : ""); | |||||
xfreepkey(pk); | |||||
} | |||||
} | |||||
if (!once) | |||||
printf("Testing verify certificate:\t\t\tFailed\n"); | |||||
xfree(xcs); | |||||
#else | |||||
printf("No X.509 self tests\n"); | |||||
#endif /* VERIFY_CERTS_STR */ | |||||
#ifdef VE_OPENPGP_SUPPORT | |||||
if (!openpgp_self_tests()) | |||||
once++; | |||||
#endif | |||||
return (once); | |||||
} |
this indentation appears to be inconsistent