Annotation of embedaddon/axTLS/ssl/x509.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2007, Cameron Rich
! 3: *
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions are met:
! 8: *
! 9: * * Redistributions of source code must retain the above copyright notice,
! 10: * this list of conditions and the following disclaimer.
! 11: * * Redistributions in binary form must reproduce the above copyright notice,
! 12: * this list of conditions and the following disclaimer in the documentation
! 13: * and/or other materials provided with the distribution.
! 14: * * Neither the name of the axTLS project nor the names of its contributors
! 15: * may be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
! 19: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
! 20: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
! 21: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
! 22: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 23: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 24: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
! 25: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
! 26: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
! 27: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! 28: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 29: */
! 30:
! 31: /**
! 32: * @file x509.c
! 33: *
! 34: * Certificate processing.
! 35: */
! 36:
! 37: #include <stdio.h>
! 38: #include <stdlib.h>
! 39: #include <string.h>
! 40: #include <time.h>
! 41: #include "os_port.h"
! 42: #include "crypto_misc.h"
! 43:
! 44: #ifdef CONFIG_SSL_CERT_VERIFICATION
! 45: /**
! 46: * Retrieve the signature from a certificate.
! 47: */
! 48: static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
! 49: {
! 50: int offset = 0;
! 51: const uint8_t *ptr = NULL;
! 52:
! 53: if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
! 54: asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
! 55: goto end_get_sig;
! 56:
! 57: if (asn1_sig[offset++] != ASN1_OCTET_STRING)
! 58: goto end_get_sig;
! 59: *len = get_asn1_length(asn1_sig, &offset);
! 60: ptr = &asn1_sig[offset]; /* all ok */
! 61:
! 62: end_get_sig:
! 63: return ptr;
! 64: }
! 65:
! 66: #endif
! 67:
! 68: /**
! 69: * Construct a new x509 object.
! 70: * @return 0 if ok. < 0 if there was a problem.
! 71: */
! 72: int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
! 73: {
! 74: int begin_tbs, end_tbs;
! 75: int ret = X509_NOT_OK, offset = 0, cert_size = 0;
! 76: X509_CTX *x509_ctx;
! 77: BI_CTX *bi_ctx;
! 78:
! 79: *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
! 80: x509_ctx = *ctx;
! 81:
! 82: /* get the certificate size */
! 83: asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
! 84:
! 85: if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
! 86: goto end_cert;
! 87:
! 88: begin_tbs = offset; /* start of the tbs */
! 89: end_tbs = begin_tbs; /* work out the end of the tbs */
! 90: asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
! 91:
! 92: if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
! 93: goto end_cert;
! 94:
! 95: if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
! 96: {
! 97: if (asn1_version(cert, &offset, x509_ctx))
! 98: goto end_cert;
! 99: }
! 100:
! 101: if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
! 102: asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
! 103: goto end_cert;
! 104:
! 105: /* make sure the signature is ok */
! 106: if (asn1_signature_type(cert, &offset, x509_ctx))
! 107: {
! 108: ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
! 109: goto end_cert;
! 110: }
! 111:
! 112: if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
! 113: asn1_validity(cert, &offset, x509_ctx) ||
! 114: asn1_name(cert, &offset, x509_ctx->cert_dn) ||
! 115: asn1_public_key(cert, &offset, x509_ctx))
! 116: {
! 117: goto end_cert;
! 118: }
! 119:
! 120: bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
! 121:
! 122: #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
! 123: /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
! 124: if (x509_ctx->sig_type == SIG_TYPE_MD5)
! 125: {
! 126: MD5_CTX md5_ctx;
! 127: uint8_t md5_dgst[MD5_SIZE];
! 128: MD5_Init(&md5_ctx);
! 129: MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
! 130: MD5_Final(md5_dgst, &md5_ctx);
! 131: x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
! 132: }
! 133: else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
! 134: {
! 135: SHA1_CTX sha_ctx;
! 136: uint8_t sha_dgst[SHA1_SIZE];
! 137: SHA1_Init(&sha_ctx);
! 138: SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
! 139: SHA1_Final(sha_dgst, &sha_ctx);
! 140: x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
! 141: }
! 142: else if (x509_ctx->sig_type == SIG_TYPE_MD2)
! 143: {
! 144: MD2_CTX md2_ctx;
! 145: uint8_t md2_dgst[MD2_SIZE];
! 146: MD2_Init(&md2_ctx);
! 147: MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
! 148: MD2_Final(md2_dgst, &md2_ctx);
! 149: x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
! 150: }
! 151:
! 152: if (cert[offset] == ASN1_V3_DATA)
! 153: {
! 154: int suboffset;
! 155:
! 156: ++offset;
! 157: get_asn1_length(cert, &offset);
! 158:
! 159: if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
! 160: {
! 161: if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
! 162: {
! 163: int altlen;
! 164:
! 165: if ((altlen = asn1_next_obj(cert,
! 166: &suboffset, ASN1_SEQUENCE)) > 0)
! 167: {
! 168: int endalt = suboffset + altlen;
! 169: int totalnames = 0;
! 170:
! 171: while (suboffset < endalt)
! 172: {
! 173: int type = cert[suboffset++];
! 174: int dnslen = get_asn1_length(cert, &suboffset);
! 175:
! 176: if (type == ASN1_CONTEXT_DNSNAME)
! 177: {
! 178: x509_ctx->subject_alt_dnsnames = (char**)
! 179: realloc(x509_ctx->subject_alt_dnsnames,
! 180: (totalnames + 2) * sizeof(char*));
! 181: x509_ctx->subject_alt_dnsnames[totalnames] =
! 182: (char*)malloc(dnslen + 1);
! 183: x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
! 184: memcpy(x509_ctx->subject_alt_dnsnames[totalnames],
! 185: cert + suboffset, dnslen);
! 186: x509_ctx->subject_alt_dnsnames[
! 187: totalnames][dnslen] = 0;
! 188: ++totalnames;
! 189: }
! 190:
! 191: suboffset += dnslen;
! 192: }
! 193: }
! 194: }
! 195: }
! 196: }
! 197:
! 198: offset = end_tbs; /* skip the rest of v3 data */
! 199: if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
! 200: asn1_signature(cert, &offset, x509_ctx))
! 201: goto end_cert;
! 202: #endif
! 203: ret = X509_OK;
! 204: end_cert:
! 205: if (len)
! 206: {
! 207: *len = cert_size;
! 208: }
! 209:
! 210: if (ret)
! 211: {
! 212: #ifdef CONFIG_SSL_FULL_MODE
! 213: printf("Error: Invalid X509 ASN.1 file (%s)\n",
! 214: x509_display_error(ret));
! 215: #endif
! 216: x509_free(x509_ctx);
! 217: *ctx = NULL;
! 218: }
! 219:
! 220: return ret;
! 221: }
! 222:
! 223: /**
! 224: * Free an X.509 object's resources.
! 225: */
! 226: void x509_free(X509_CTX *x509_ctx)
! 227: {
! 228: X509_CTX *next;
! 229: int i;
! 230:
! 231: if (x509_ctx == NULL) /* if already null, then don't bother */
! 232: return;
! 233:
! 234: for (i = 0; i < X509_NUM_DN_TYPES; i++)
! 235: {
! 236: free(x509_ctx->ca_cert_dn[i]);
! 237: free(x509_ctx->cert_dn[i]);
! 238: }
! 239:
! 240: free(x509_ctx->signature);
! 241:
! 242: #ifdef CONFIG_SSL_CERT_VERIFICATION
! 243: if (x509_ctx->digest)
! 244: {
! 245: bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
! 246: }
! 247:
! 248: if (x509_ctx->subject_alt_dnsnames)
! 249: {
! 250: for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
! 251: free(x509_ctx->subject_alt_dnsnames[i]);
! 252:
! 253: free(x509_ctx->subject_alt_dnsnames);
! 254: }
! 255: #endif
! 256:
! 257: RSA_free(x509_ctx->rsa_ctx);
! 258: next = x509_ctx->next;
! 259: free(x509_ctx);
! 260: x509_free(next); /* clear the chain */
! 261: }
! 262:
! 263: #ifdef CONFIG_SSL_CERT_VERIFICATION
! 264: /**
! 265: * Take a signature and decrypt it.
! 266: */
! 267: static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
! 268: bigint *modulus, bigint *pub_exp)
! 269: {
! 270: int i, size;
! 271: bigint *decrypted_bi, *dat_bi;
! 272: bigint *bir = NULL;
! 273: uint8_t *block = (uint8_t *)alloca(sig_len);
! 274:
! 275: /* decrypt */
! 276: dat_bi = bi_import(ctx, sig, sig_len);
! 277: ctx->mod_offset = BIGINT_M_OFFSET;
! 278:
! 279: /* convert to a normal block */
! 280: decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
! 281:
! 282: bi_export(ctx, decrypted_bi, block, sig_len);
! 283: ctx->mod_offset = BIGINT_M_OFFSET;
! 284:
! 285: i = 10; /* start at the first possible non-padded byte */
! 286: while (block[i++] && i < sig_len);
! 287: size = sig_len - i;
! 288:
! 289: /* get only the bit we want */
! 290: if (size > 0)
! 291: {
! 292: int len;
! 293: const uint8_t *sig_ptr = get_signature(&block[i], &len);
! 294:
! 295: if (sig_ptr)
! 296: {
! 297: bir = bi_import(ctx, sig_ptr, len);
! 298: }
! 299: }
! 300:
! 301: /* save a few bytes of memory */
! 302: bi_clear_cache(ctx);
! 303: return bir;
! 304: }
! 305:
! 306: /**
! 307: * Do some basic checks on the certificate chain.
! 308: *
! 309: * Certificate verification consists of a number of checks:
! 310: * - The date of the certificate is after the start date.
! 311: * - The date of the certificate is before the finish date.
! 312: * - A root certificate exists in the certificate store.
! 313: * - That the certificate(s) are not self-signed.
! 314: * - The certificate chain is valid.
! 315: * - The signature of the certificate is valid.
! 316: */
! 317: int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
! 318: {
! 319: int ret = X509_OK, i = 0;
! 320: bigint *cert_sig;
! 321: X509_CTX *next_cert = NULL;
! 322: BI_CTX *ctx = NULL;
! 323: bigint *mod = NULL, *expn = NULL;
! 324: int match_ca_cert = 0;
! 325: struct timeval tv;
! 326: uint8_t is_self_signed = 0;
! 327:
! 328: if (cert == NULL)
! 329: {
! 330: ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
! 331: goto end_verify;
! 332: }
! 333:
! 334: /* a self-signed certificate that is not in the CA store - use this
! 335: to check the signature */
! 336: if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
! 337: {
! 338: is_self_signed = 1;
! 339: ctx = cert->rsa_ctx->bi_ctx;
! 340: mod = cert->rsa_ctx->m;
! 341: expn = cert->rsa_ctx->e;
! 342: }
! 343:
! 344: gettimeofday(&tv, NULL);
! 345:
! 346: /* check the not before date */
! 347: if (tv.tv_sec < cert->not_before)
! 348: {
! 349: ret = X509_VFY_ERROR_NOT_YET_VALID;
! 350: goto end_verify;
! 351: }
! 352:
! 353: /* check the not after date */
! 354: if (tv.tv_sec > cert->not_after)
! 355: {
! 356: ret = X509_VFY_ERROR_EXPIRED;
! 357: goto end_verify;
! 358: }
! 359:
! 360: next_cert = cert->next;
! 361:
! 362: /* last cert in the chain - look for a trusted cert */
! 363: if (next_cert == NULL)
! 364: {
! 365: if (ca_cert_ctx != NULL)
! 366: {
! 367: /* go thu the CA store */
! 368: while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
! 369: {
! 370: if (asn1_compare_dn(cert->ca_cert_dn,
! 371: ca_cert_ctx->cert[i]->cert_dn) == 0)
! 372: {
! 373: /* use this CA certificate for signature verification */
! 374: match_ca_cert = 1;
! 375: ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
! 376: mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
! 377: expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
! 378: break;
! 379: }
! 380:
! 381: i++;
! 382: }
! 383: }
! 384:
! 385: /* couldn't find a trusted cert (& let self-signed errors
! 386: be returned) */
! 387: if (!match_ca_cert && !is_self_signed)
! 388: {
! 389: ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
! 390: goto end_verify;
! 391: }
! 392: }
! 393: else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
! 394: {
! 395: /* check the chain */
! 396: ret = X509_VFY_ERROR_INVALID_CHAIN;
! 397: goto end_verify;
! 398: }
! 399: else /* use the next certificate in the chain for signature verify */
! 400: {
! 401: ctx = next_cert->rsa_ctx->bi_ctx;
! 402: mod = next_cert->rsa_ctx->m;
! 403: expn = next_cert->rsa_ctx->e;
! 404: }
! 405:
! 406: /* cert is self signed */
! 407: if (!match_ca_cert && is_self_signed)
! 408: {
! 409: ret = X509_VFY_ERROR_SELF_SIGNED;
! 410: goto end_verify;
! 411: }
! 412:
! 413: /* check the signature */
! 414: cert_sig = sig_verify(ctx, cert->signature, cert->sig_len,
! 415: bi_clone(ctx, mod), bi_clone(ctx, expn));
! 416:
! 417: if (cert_sig && cert->digest)
! 418: {
! 419: if (bi_compare(cert_sig, cert->digest) != 0)
! 420: ret = X509_VFY_ERROR_BAD_SIGNATURE;
! 421:
! 422:
! 423: bi_free(ctx, cert_sig);
! 424: }
! 425: else
! 426: {
! 427: ret = X509_VFY_ERROR_BAD_SIGNATURE;
! 428: }
! 429:
! 430: if (ret)
! 431: goto end_verify;
! 432:
! 433: /* go down the certificate chain using recursion. */
! 434: if (next_cert != NULL)
! 435: {
! 436: ret = x509_verify(ca_cert_ctx, next_cert);
! 437: }
! 438:
! 439: end_verify:
! 440: return ret;
! 441: }
! 442: #endif
! 443:
! 444: #if defined (CONFIG_SSL_FULL_MODE)
! 445: /**
! 446: * Used for diagnostics.
! 447: */
! 448: static const char *not_part_of_cert = "<Not Part Of Certificate>";
! 449: void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx)
! 450: {
! 451: if (cert == NULL)
! 452: return;
! 453:
! 454: printf("=== CERTIFICATE ISSUED TO ===\n");
! 455: printf("Common Name (CN):\t\t");
! 456: printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ?
! 457: cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
! 458:
! 459: printf("Organization (O):\t\t");
! 460: printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ?
! 461: cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
! 462:
! 463: printf("Organizational Unit (OU):\t");
! 464: printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
! 465: cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
! 466:
! 467: printf("=== CERTIFICATE ISSUED BY ===\n");
! 468: printf("Common Name (CN):\t\t");
! 469: printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
! 470: cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
! 471:
! 472: printf("Organization (O):\t\t");
! 473: printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
! 474: cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
! 475:
! 476: printf("Organizational Unit (OU):\t");
! 477: printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
! 478: cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
! 479:
! 480: printf("Not Before:\t\t\t%s", ctime(&cert->not_before));
! 481: printf("Not After:\t\t\t%s", ctime(&cert->not_after));
! 482: printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8);
! 483: printf("Sig Type:\t\t\t");
! 484: switch (cert->sig_type)
! 485: {
! 486: case SIG_TYPE_MD5:
! 487: printf("MD5\n");
! 488: break;
! 489: case SIG_TYPE_SHA1:
! 490: printf("SHA1\n");
! 491: break;
! 492: case SIG_TYPE_MD2:
! 493: printf("MD2\n");
! 494: break;
! 495: default:
! 496: printf("Unrecognized: %d\n", cert->sig_type);
! 497: break;
! 498: }
! 499:
! 500: if (ca_cert_ctx)
! 501: {
! 502: printf("Verify:\t\t\t\t%s\n",
! 503: x509_display_error(x509_verify(ca_cert_ctx, cert)));
! 504: }
! 505:
! 506: #if 0
! 507: print_blob("Signature", cert->signature, cert->sig_len);
! 508: bi_print("Modulus", cert->rsa_ctx->m);
! 509: bi_print("Pub Exp", cert->rsa_ctx->e);
! 510: #endif
! 511:
! 512: if (ca_cert_ctx)
! 513: {
! 514: x509_print(cert->next, ca_cert_ctx);
! 515: }
! 516:
! 517: TTY_FLUSH();
! 518: }
! 519:
! 520: const char * x509_display_error(int error)
! 521: {
! 522: switch (error)
! 523: {
! 524: case X509_OK:
! 525: return "Certificate verify successful";
! 526:
! 527: case X509_NOT_OK:
! 528: return "X509 not ok";
! 529:
! 530: case X509_VFY_ERROR_NO_TRUSTED_CERT:
! 531: return "No trusted cert is available";
! 532:
! 533: case X509_VFY_ERROR_BAD_SIGNATURE:
! 534: return "Bad signature";
! 535:
! 536: case X509_VFY_ERROR_NOT_YET_VALID:
! 537: return "Cert is not yet valid";
! 538:
! 539: case X509_VFY_ERROR_EXPIRED:
! 540: return "Cert has expired";
! 541:
! 542: case X509_VFY_ERROR_SELF_SIGNED:
! 543: return "Cert is self-signed";
! 544:
! 545: case X509_VFY_ERROR_INVALID_CHAIN:
! 546: return "Chain is invalid (check order of certs)";
! 547:
! 548: case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
! 549: return "Unsupported digest";
! 550:
! 551: case X509_INVALID_PRIV_KEY:
! 552: return "Invalid private key";
! 553:
! 554: default:
! 555: return "Unknown";
! 556: }
! 557: }
! 558: #endif /* CONFIG_SSL_FULL_MODE */
! 559:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>