123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- /*
- * Copyright (c) 2007, 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
- /**
- * Retrieve the signature from a certificate.
- */
- static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
- {
- int offset = 0;
- const uint8_t *ptr = NULL;
- if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
- asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
- goto end_get_sig;
- if (asn1_sig[offset++] != ASN1_OCTET_STRING)
- goto end_get_sig;
- *len = get_asn1_length(asn1_sig, &offset);
- ptr = &asn1_sig[offset]; /* all ok */
- end_get_sig:
- return ptr;
- }
- #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;
- X509_CTX *x509_ctx;
- BI_CTX *bi_ctx;
- *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;
- if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
- {
- if (asn1_version(cert, &offset, x509_ctx))
- 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;
- bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
- #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
- /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
- if (x509_ctx->sig_type == 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);
- }
- else if (x509_ctx->sig_type == 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);
- }
- else if (x509_ctx->sig_type == SIG_TYPE_MD2)
- {
- MD2_CTX md2_ctx;
- uint8_t md2_dgst[MD2_SIZE];
- MD2_Init(&md2_ctx);
- MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
- MD2_Final(md2_dgst, &md2_ctx);
- x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
- }
- offset = end_tbs; /* skip the v3 data */
- if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
- asn1_signature(cert, &offset, x509_ctx))
- goto end_cert;
- #endif
- if (len)
- {
- *len = cert_size;
- }
- ret = X509_OK;
- end_cert:
- #ifdef CONFIG_SSL_FULL_MODE
- if (ret)
- {
- printf("Error: Invalid X509 ASN.1 file\n");
- }
- #endif
- return ret;
- }
- /**
- * 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);
- }
- #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
- /**
- * Take a signature and decrypt it.
- */
- static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
- bigint *modulus, bigint *pub_exp)
- {
- int i, size;
- bigint *decrypted_bi, *dat_bi;
- bigint *bir = NULL;
- uint8_t *block = (uint8_t *)alloca(sig_len);
- /* 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;
- i = 10; /* start at the first possible non-padded byte */
- while (block[i++] && i < sig_len);
- size = sig_len - i;
- /* get only the bit we want */
- if (size > 0)
- {
- int len;
- const uint8_t *sig_ptr = get_signature(&block[i], &len);
- if (sig_ptr)
- {
- bir = bi_import(ctx, sig_ptr, len);
- }
- }
- /* 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.
- */
- int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
- {
- 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;
- }
- next_cert = cert->next;
- /* last cert in the chain - look for a trusted cert */
- if (next_cert == NULL)
- {
- if (ca_cert_ctx != NULL)
- {
- /* go thu the CA store */
- while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
- {
- 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 = 1;
- 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,
- 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)
- {
- ret = x509_verify(ca_cert_ctx, next_cert);
- }
- 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);
- printf("Organizational Unit (OU):\t");
- printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
- cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
- 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);
- printf("Organizational Unit (OU):\t");
- printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
- cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
- 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_MD2:
- printf("MD2\n");
- break;
- default:
- printf("Unrecognized: %d\n", cert->sig_type);
- break;
- }
- if (ca_cert_ctx)
- {
- printf("Verify:\t\t\t\t%s\n",
- x509_display_error(x509_verify(ca_cert_ctx, cert)));
- }
- #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();
- }
- 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";
- default:
- return "Unknown";
- }
- }
- #endif /* CONFIG_SSL_FULL_MODE */
|