diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
commit | 4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch) | |
tree | 65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/lib/axtls/ssl/x509.c | |
parent | 0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff) |
add circuitpython code
Diffstat (limited to 'circuitpython/lib/axtls/ssl/x509.c')
-rw-r--r-- | circuitpython/lib/axtls/ssl/x509.c | 921 |
1 files changed, 921 insertions, 0 deletions
diff --git a/circuitpython/lib/axtls/ssl/x509.c b/circuitpython/lib/axtls/ssl/x509.c new file mode 100644 index 0000000..b36f205 --- /dev/null +++ b/circuitpython/lib/axtls/ssl/x509.c @@ -0,0 +1,921 @@ +/* + * Copyright (c) 2007-2017, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + */ + +/** + * @file x509.c + * + * Certificate processing. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "os_port.h" +#include "crypto_misc.h" + +#ifdef CONFIG_SSL_CERT_VERIFICATION +static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, + X509_CTX *x509_ctx); +static int x509_v3_basic_constraints(const uint8_t *cert, int offset, + X509_CTX *x509_ctx); +static int x509_v3_key_usage(const uint8_t *cert, int offset, + X509_CTX *x509_ctx); +#endif + +/** + * Construct a new x509 object. + * @return 0 if ok. < 0 if there was a problem. + */ +int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) +{ + int begin_tbs, end_tbs; + int ret = X509_NOT_OK, offset = 0, cert_size = 0; + int version = 0; + X509_CTX *x509_ctx; +#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ + BI_CTX *bi_ctx; +#endif + + *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); + x509_ctx = *ctx; + + /* get the certificate size */ + asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); + + if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + begin_tbs = offset; /* start of the tbs */ + end_tbs = begin_tbs; /* work out the end of the tbs */ + asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); + + if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + /* optional version */ + if (cert[offset] == ASN1_EXPLICIT_TAG && + asn1_version(cert, &offset, &version) == X509_NOT_OK) + goto end_cert; + + if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ + asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) + goto end_cert; + + /* make sure the signature is ok */ + if (asn1_signature_type(cert, &offset, x509_ctx)) + { + ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; + goto end_cert; + } + + if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || + asn1_validity(cert, &offset, x509_ctx) || + asn1_name(cert, &offset, x509_ctx->cert_dn) || + asn1_public_key(cert, &offset, x509_ctx)) + { + goto end_cert; + } + +#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ + bi_ctx = x509_ctx->rsa_ctx->bi_ctx; + + /* use the appropriate signature algorithm */ + switch (x509_ctx->sig_type) + { + case SIG_TYPE_MD5: + { + MD5_CTX md5_ctx; + uint8_t md5_dgst[MD5_SIZE]; + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + MD5_Final(md5_dgst, &md5_ctx); + x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); + } + break; + + case SIG_TYPE_SHA1: + { + SHA1_CTX sha_ctx; + uint8_t sha_dgst[SHA1_SIZE]; + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA1_Final(sha_dgst, &sha_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); + } + break; + + case SIG_TYPE_SHA256: + { + SHA256_CTX sha256_ctx; + uint8_t sha256_dgst[SHA256_SIZE]; + SHA256_Init(&sha256_ctx); + SHA256_Update(&sha256_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA256_Final(sha256_dgst, &sha256_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha256_dgst, SHA256_SIZE); + } + break; + + case SIG_TYPE_SHA384: + { + SHA384_CTX sha384_ctx; + uint8_t sha384_dgst[SHA384_SIZE]; + SHA384_Init(&sha384_ctx); + SHA384_Update(&sha384_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA384_Final(sha384_dgst, &sha384_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha384_dgst, SHA384_SIZE); + } + break; + + case SIG_TYPE_SHA512: + { + SHA512_CTX sha512_ctx; + uint8_t sha512_dgst[SHA512_SIZE]; + SHA512_Init(&sha512_ctx); + SHA512_Update(&sha512_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA512_Final(sha512_dgst, &sha512_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha512_dgst, SHA512_SIZE); + } + break; + } + + if (version == 2 && asn1_next_obj(cert, &offset, ASN1_V3_DATA) > 0) + { + x509_v3_subject_alt_name(cert, offset, x509_ctx); + x509_v3_basic_constraints(cert, offset, x509_ctx); + x509_v3_key_usage(cert, offset, x509_ctx); + } + + offset = end_tbs; /* skip the rest of v3 data */ + if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || + asn1_signature(cert, &offset, x509_ctx)) + goto end_cert; +#endif + ret = X509_OK; +end_cert: + if (len) + { + *len = cert_size; + } + + if (ret) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: Invalid X509 ASN.1 file (%s)\n", + x509_display_error(ret)); +#endif + x509_free(x509_ctx); + *ctx = NULL; + } + + return ret; +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ +static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, + X509_CTX *x509_ctx) +{ + if ((offset = asn1_is_subject_alt_name(cert, offset)) > 0) + { + x509_ctx->subject_alt_name_present = true; + x509_ctx->subject_alt_name_is_critical = + asn1_is_critical_ext(cert, &offset); + + if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) > 0) + { + int altlen; + + if ((altlen = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) > 0) + { + int endalt = offset + altlen; + int totalnames = 0; + + while (offset < endalt) + { + int type = cert[offset++]; + int dnslen = get_asn1_length(cert, &offset); + + if (type == ASN1_CONTEXT_DNSNAME) + { + /* sanity check the hostname due to +https://tools.cisco.com/security/center/viewAlert.x?alertId=18852 + */ + if (strnlen((const char *)&cert[offset], dnslen) != + dnslen) + { + return X509_VFY_ERROR_NO_TRUSTED_CERT; + } + + x509_ctx->subject_alt_dnsnames = (char**) + realloc(x509_ctx->subject_alt_dnsnames, + (totalnames + 2) * sizeof(char*)); + x509_ctx->subject_alt_dnsnames[totalnames] = + (char*)malloc(dnslen + 1); + x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; + memcpy(x509_ctx->subject_alt_dnsnames[totalnames], + cert + offset, dnslen); + x509_ctx->subject_alt_dnsnames[totalnames][dnslen] = 0; + totalnames++; + } + + offset += dnslen; + } + } + } + } + + return X509_OK; +} + +/** + * Basic constraints - see https://tools.ietf.org/html/rfc5280#page-39 + */ +static int x509_v3_basic_constraints(const uint8_t *cert, int offset, + X509_CTX *x509_ctx) +{ + int ret = X509_OK; + int lenSeq = 0; + + if ((offset = asn1_is_basic_constraints(cert, offset)) == 0) + goto end_contraints; + + x509_ctx->basic_constraint_present = true; + x509_ctx->basic_constraint_is_critical = + asn1_is_critical_ext(cert, &offset); + + /* Assign Defaults in case not specified + basic_constraint_cA will already by zero by virtue of the calloc */ + x509_ctx->basic_constraint_cA = 0; + /* basic_constraint_pathLenConstraint is unlimited by default. + 10000 is just a large number (limits.h is not already included) */ + x509_ctx->basic_constraint_pathLenConstraint = 10000; + + if ((asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0) || + ((lenSeq = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) < 0)) + { + ret = X509_NOT_OK; + } + + /* If the Sequence Length is greater than zero, + continue with the basic_constraint_cA */ + if ((lenSeq>0)&&(asn1_get_bool(cert, &offset, + &x509_ctx->basic_constraint_cA) < 0)) + { + ret = X509_NOT_OK; + } + + /* If the Sequence Length is greater than 3, it has more content than + the basic_constraint_cA bool, so grab the pathLenConstraint */ + if ((lenSeq>3) && (asn1_get_int(cert, &offset, + &x509_ctx->basic_constraint_pathLenConstraint) < 0)) + { + ret = X509_NOT_OK; + } + +end_contraints: + return ret; +} + +/* + * Key usage - see https://tools.ietf.org/html/rfc5280#section-4.2.1.3 + */ +static int x509_v3_key_usage(const uint8_t *cert, int offset, + X509_CTX *x509_ctx) +{ + int ret = X509_OK; + + if ((offset = asn1_is_key_usage(cert, offset)) == 0) + goto end_key_usage; + + x509_ctx->key_usage_present = true; + x509_ctx->key_usage_is_critical = asn1_is_critical_ext(cert, &offset); + + if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || + asn1_get_bit_string_as_int(cert, &offset, &x509_ctx->key_usage)) + { + ret = X509_NOT_OK; + } + +end_key_usage: + return ret; +} +#endif + +/** + * Free an X.509 object's resources. + */ +void x509_free(X509_CTX *x509_ctx) +{ + X509_CTX *next; + int i; + + if (x509_ctx == NULL) /* if already null, then don't bother */ + return; + + for (i = 0; i < X509_NUM_DN_TYPES; i++) + { + free(x509_ctx->ca_cert_dn[i]); + free(x509_ctx->cert_dn[i]); + } + + free(x509_ctx->signature); + +#ifdef CONFIG_SSL_CERT_VERIFICATION + if (x509_ctx->digest) + { + bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); + } + + if (x509_ctx->subject_alt_dnsnames) + { + for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) + free(x509_ctx->subject_alt_dnsnames[i]); + + free(x509_ctx->subject_alt_dnsnames); + } +#endif + + RSA_free(x509_ctx->rsa_ctx); + next = x509_ctx->next; + free(x509_ctx); + x509_free(next); /* clear the chain */ +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION + +static const uint8_t sig_prefix_md5[] = {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; +static const uint8_t sig_prefix_sha1[] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14}; +static const uint8_t sig_prefix_sha256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; +static const uint8_t sig_prefix_sha384[] = {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}; +static const uint8_t sig_prefix_sha512[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; + +/** + * Take a signature and decrypt it. + */ +static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + uint8_t sig_type, bigint *modulus, bigint *pub_exp) +{ + int i; + bigint *decrypted_bi, *dat_bi; + bigint *bir = NULL; + uint8_t *block = (uint8_t *)alloca(sig_len); + + const uint8_t *sig_prefix = NULL; + uint8_t sig_prefix_size = 0, hash_len = 0; + /* adjust our expections */ + switch (sig_type) + { + case SIG_TYPE_MD5: + sig_prefix = sig_prefix_md5; + sig_prefix_size = sizeof(sig_prefix_md5); + break; + case SIG_TYPE_SHA1: + sig_prefix = sig_prefix_sha1; + sig_prefix_size = sizeof(sig_prefix_sha1); + break; + case SIG_TYPE_SHA256: + sig_prefix = sig_prefix_sha256; + sig_prefix_size = sizeof(sig_prefix_sha256); + break; + case SIG_TYPE_SHA384: + sig_prefix = sig_prefix_sha384; + sig_prefix_size = sizeof(sig_prefix_sha384); + break; + case SIG_TYPE_SHA512: + sig_prefix = sig_prefix_sha512; + sig_prefix_size = sizeof(sig_prefix_sha512); + break; + } + + if (sig_prefix) + hash_len = sig_prefix[sig_prefix_size - 1]; + + /* check length (#A) */ + if (sig_len < 2 + 8 + 1 + sig_prefix_size + hash_len) + goto err; + + /* decrypt */ + dat_bi = bi_import(ctx, sig, sig_len); + ctx->mod_offset = BIGINT_M_OFFSET; + + /* convert to a normal block */ + decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); + + bi_export(ctx, decrypted_bi, block, sig_len); + ctx->mod_offset = BIGINT_M_OFFSET; + + /* check the first 2 bytes */ + if (block[0] != 0 || block[1] != 1) + goto err; + + /* check the padding */ + i = 2; /* start at the first padding byte */ + while (i < sig_len - 1 - sig_prefix_size - hash_len) + { /* together with (#A), we require at least 8 bytes of padding */ + if (block[i++] != 0xFF) + goto err; + } + + /* check end of padding */ + if (block[i++] != 0) + goto err; + + /* check the ASN.1 metadata */ + if (memcmp(block+i, sig_prefix, sig_prefix_size)) + goto err; + + /* now we can get the hash we need */ + bir = bi_import(ctx, block + i + sig_prefix_size, hash_len); + +err: + /* save a few bytes of memory */ + bi_clear_cache(ctx); + return bir; +} + +/** + * Do some basic checks on the certificate chain. + * + * Certificate verification consists of a number of checks: + * - The date of the certificate is after the start date. + * - The date of the certificate is before the finish date. + * - A root certificate exists in the certificate store. + * - That the certificate(s) are not self-signed. + * - The certificate chain is valid. + * - The signature of the certificate is valid. + * - Basic constraints + */ +int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert, + int *pathLenConstraint) +{ + int ret = X509_OK, i = 0; + bigint *cert_sig; + X509_CTX *next_cert = NULL; + BI_CTX *ctx = NULL; + bigint *mod = NULL, *expn = NULL; + int match_ca_cert = 0; + struct timeval tv; + uint8_t is_self_signed = 0; + + if (cert == NULL) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + + /* a self-signed certificate that is not in the CA store - use this + to check the signature */ + if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) + { + is_self_signed = 1; + ctx = cert->rsa_ctx->bi_ctx; + mod = cert->rsa_ctx->m; + expn = cert->rsa_ctx->e; + } + + gettimeofday(&tv, NULL); + + /* check the not before date */ + if (tv.tv_sec < cert->not_before) + { + ret = X509_VFY_ERROR_NOT_YET_VALID; + goto end_verify; + } + + /* check the not after date */ + if (tv.tv_sec > cert->not_after) + { + ret = X509_VFY_ERROR_EXPIRED; + goto end_verify; + } + + if (cert->basic_constraint_present) + { + /* If the cA boolean is not asserted, + then the keyCertSign bit in the key usage extension MUST NOT be + asserted. */ + if (!cert->basic_constraint_cA && + IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) + { + ret = X509_VFY_ERROR_BASIC_CONSTRAINT; + goto end_verify; + } + + /* The pathLenConstraint field is meaningful only if the cA boolean is + asserted and the key usage extension, if present, asserts the + keyCertSign bit. In this case, it gives the maximum number of + non-self-issued intermediate certificates that may follow this + certificate in a valid certification path. */ + if (cert->basic_constraint_cA && + (!cert->key_usage_present || + IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) && + (cert->basic_constraint_pathLenConstraint+1) < *pathLenConstraint) + { + ret = X509_VFY_ERROR_BASIC_CONSTRAINT; + goto end_verify; + } + } + + next_cert = cert->next; + + /* last cert in the chain - look for a trusted cert */ + if (next_cert == NULL) + { + if (ca_cert_ctx != NULL) + { + /* go thru the CA store */ + while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + { + /* the extension is present but the cA boolean is not + asserted, then the certified public key MUST NOT be used + to verify certificate signatures. */ + if (cert->basic_constraint_present && + !ca_cert_ctx->cert[i]->basic_constraint_cA) + { + i++; + continue; + } + + if (asn1_compare_dn(cert->ca_cert_dn, + ca_cert_ctx->cert[i]->cert_dn) == 0) + { + /* use this CA certificate for signature verification */ + match_ca_cert = true; + ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx; + mod = ca_cert_ctx->cert[i]->rsa_ctx->m; + expn = ca_cert_ctx->cert[i]->rsa_ctx->e; + + + break; + } + + i++; + } + } + + /* couldn't find a trusted cert (& let self-signed errors + be returned) */ + if (!match_ca_cert && !is_self_signed) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + } + else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) + { + /* check the chain */ + ret = X509_VFY_ERROR_INVALID_CHAIN; + goto end_verify; + } + else /* use the next certificate in the chain for signature verify */ + { + ctx = next_cert->rsa_ctx->bi_ctx; + mod = next_cert->rsa_ctx->m; + expn = next_cert->rsa_ctx->e; + } + + /* cert is self signed */ + if (!match_ca_cert && is_self_signed) + { + ret = X509_VFY_ERROR_SELF_SIGNED; + goto end_verify; + } + + /* check the signature */ + cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, cert->sig_type, + bi_clone(ctx, mod), bi_clone(ctx, expn)); + + if (cert_sig && cert->digest) + { + if (bi_compare(cert_sig, cert->digest) != 0) + ret = X509_VFY_ERROR_BAD_SIGNATURE; + + + bi_free(ctx, cert_sig); + } + else + { + ret = X509_VFY_ERROR_BAD_SIGNATURE; + } + + if (ret) + goto end_verify; + + /* go down the certificate chain using recursion. */ + if (next_cert != NULL) + { + (*pathLenConstraint)++; /* don't include last certificate */ + ret = x509_verify(ca_cert_ctx, next_cert, pathLenConstraint); + } + +end_verify: + return ret; +} +#endif + +#if defined (CONFIG_SSL_FULL_MODE) +/** + * Used for diagnostics. + */ +static const char *not_part_of_cert = "<Not Part Of Certificate>"; +void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) +{ + if (cert == NULL) + return; + + printf("=== CERTIFICATE ISSUED TO ===\n"); + printf("Common Name (CN):\t\t"); + printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ? + cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); + + printf("Organization (O):\t\t"); + printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ? + cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + if (cert->cert_dn[X509_ORGANIZATIONAL_UNIT]) + { + printf("Organizational Unit (OU):\t"); + printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT]); + } + + if (cert->cert_dn[X509_LOCATION]) + { + printf("Location (L):\t\t\t"); + printf("%s\n", cert->cert_dn[X509_LOCATION]); + } + + if (cert->cert_dn[X509_COUNTRY]) + { + printf("Country (C):\t\t\t"); + printf("%s\n", cert->cert_dn[X509_COUNTRY]); + } + + if (cert->cert_dn[X509_STATE]) + { + printf("State (ST):\t\t\t"); + printf("%s\n", cert->cert_dn[X509_STATE]); + } + + if (cert->basic_constraint_present) + { + printf("Basic Constraints:\t\t%sCA:%s, pathlen:%d\n", + cert->basic_constraint_is_critical ? + "critical, " : "", + cert->basic_constraint_cA? "TRUE" : "FALSE", + cert->basic_constraint_pathLenConstraint); + } + + if (cert->key_usage_present) + { + printf("Key Usage:\t\t\t%s", cert->key_usage_is_critical ? + "critical, " : ""); + bool has_started = false; + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DIGITAL_SIGNATURE)) + { + printf("Digital Signature"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_NON_REPUDIATION)) + { + if (has_started) + printf(", "); + + printf("Non Repudiation"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_ENCIPHERMENT)) + { + if (has_started) + printf(", "); + + printf("Key Encipherment"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DATA_ENCIPHERMENT)) + { + if (has_started) + printf(", "); + + printf("Data Encipherment"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_AGREEMENT)) + { + if (has_started) + printf(", "); + + printf("Key Agreement"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) + { + if (has_started) + printf(", "); + + printf("Key Cert Sign"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_CRL_SIGN)) + { + if (has_started) + printf(", "); + + printf("CRL Sign"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_ENCIPHER_ONLY)) + { + if (has_started) + printf(", "); + + printf("Encipher Only"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DECIPHER_ONLY)) + { + if (has_started) + printf(", "); + + printf("Decipher Only"); + has_started = true; + } + + printf("\n"); + } + + if (cert->subject_alt_name_present) + { + printf("Subject Alt Name:\t\t%s", cert->subject_alt_name_is_critical + ? "critical, " : ""); + if (cert->subject_alt_dnsnames) + { + int i = 0; + + while (cert->subject_alt_dnsnames[i]) + printf("%s ", cert->subject_alt_dnsnames[i++]); + } + printf("\n"); + + } + + printf("=== CERTIFICATE ISSUED BY ===\n"); + printf("Common Name (CN):\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ? + cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert); + + printf("Organization (O):\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ? + cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + if (cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]) + { + printf("Organizational Unit (OU):\t"); + printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]); + } + + if (cert->ca_cert_dn[X509_LOCATION]) + { + printf("Location (L):\t\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_LOCATION]); + } + + if (cert->ca_cert_dn[X509_COUNTRY]) + { + printf("Country (C):\t\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_COUNTRY]); + } + + if (cert->ca_cert_dn[X509_STATE]) + { + printf("State (ST):\t\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_STATE]); + } + + printf("Not Before:\t\t\t%s", ctime(&cert->not_before)); + printf("Not After:\t\t\t%s", ctime(&cert->not_after)); + printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8); + printf("Sig Type:\t\t\t"); + switch (cert->sig_type) + { + case SIG_TYPE_MD5: + printf("MD5\n"); + break; + case SIG_TYPE_SHA1: + printf("SHA1\n"); + break; + case SIG_TYPE_SHA256: + printf("SHA256\n"); + break; + case SIG_TYPE_SHA384: + printf("SHA384\n"); + break; + case SIG_TYPE_SHA512: + printf("SHA512\n"); + break; + default: + printf("Unrecognized: %d\n", cert->sig_type); + break; + } + + if (ca_cert_ctx) + { + int pathLenConstraint = 0; + printf("Verify:\t\t\t\t%s\n", + x509_display_error(x509_verify(ca_cert_ctx, cert, + &pathLenConstraint))); + } + +#if 0 + print_blob("Signature", cert->signature, cert->sig_len); + bi_print("Modulus", cert->rsa_ctx->m); + bi_print("Pub Exp", cert->rsa_ctx->e); +#endif + + if (ca_cert_ctx) + { + x509_print(cert->next, ca_cert_ctx); + } + + TTY_FLUSH(); +} +#endif + +const char * x509_display_error(int error) +{ + switch (error) + { + case X509_OK: + return "Certificate verify successful"; + + case X509_NOT_OK: + return "X509 not ok"; + + case X509_VFY_ERROR_NO_TRUSTED_CERT: + return "No trusted cert is available"; + + case X509_VFY_ERROR_BAD_SIGNATURE: + return "Bad signature"; + + case X509_VFY_ERROR_NOT_YET_VALID: + return "Cert is not yet valid"; + + case X509_VFY_ERROR_EXPIRED: + return "Cert has expired"; + + case X509_VFY_ERROR_SELF_SIGNED: + return "Cert is self-signed"; + + case X509_VFY_ERROR_INVALID_CHAIN: + return "Chain is invalid (check order of certs)"; + + case X509_VFY_ERROR_UNSUPPORTED_DIGEST: + return "Unsupported digest"; + + case X509_INVALID_PRIV_KEY: + return "Invalid private key"; + + case X509_VFY_ERROR_BASIC_CONSTRAINT: + return "Basic constraint invalid"; + + default: + return "Unknown"; + } +} +//#endif /* CONFIG_SSL_FULL_MODE */ + |