Ashley Mills / axTLS
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers x509.c Source File

x509.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007, Cameron Rich
00003  * 
00004  * All rights reserved.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without 
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  * * Redistributions of source code must retain the above copyright notice, 
00010  *   this list of conditions and the following disclaimer.
00011  * * Redistributions in binary form must reproduce the above copyright notice, 
00012  *   this list of conditions and the following disclaimer in the documentation 
00013  *   and/or other materials provided with the distribution.
00014  * * Neither the name of the axTLS project nor the names of its contributors 
00015  *   may be used to endorse or promote products derived from this software 
00016  *   without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00021  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00022  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00025  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00027  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 /**
00032  * @file x509.c
00033  * 
00034  * Certificate processing.
00035  */
00036 
00037 #include <time.h>
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include "os_port.h"
00042 #include "crypto_misc.h "
00043 #include "sockets.h"
00044 #include "config.h"
00045 #ifdef CONFIG_SSL_CERT_VERIFICATION
00046 /**
00047  * Retrieve the signature from a certificate.
00048  */
00049 static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
00050 {
00051     int offset = 0;
00052     const uint8_t *ptr = NULL;
00053 
00054     if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || 
00055             asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
00056         goto end_get_sig;
00057 
00058     if (asn1_sig[offset++] != ASN1_OCTET_STRING)
00059         goto end_get_sig;
00060     *len = get_asn1_length(asn1_sig, &offset);
00061     ptr = &asn1_sig[offset];          /* all ok */
00062 
00063 end_get_sig:
00064     return ptr;
00065 }
00066 
00067 #endif
00068 
00069 /**
00070  * Construct a new x509 object.
00071  * @return 0 if ok. < 0 if there was a problem.
00072  */
00073 int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
00074 {
00075     int begin_tbs, end_tbs;
00076     int ret = X509_NOT_OK, offset = 0, cert_size = 0;
00077     X509_CTX *x509_ctx;
00078     BI_CTX *bi_ctx;
00079 
00080     *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
00081     x509_ctx = *ctx;
00082 
00083     /* get the certificate size */
00084     asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); 
00085 
00086     if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
00087         goto end_cert;
00088 
00089     begin_tbs = offset;         /* start of the tbs */
00090     end_tbs = begin_tbs;        /* work out the end of the tbs */
00091     asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
00092 
00093     if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
00094         goto end_cert;
00095 
00096     if (cert[offset] == ASN1_EXPLICIT_TAG)   /* optional version */
00097     {
00098         if (asn1_version(cert, &offset, x509_ctx))
00099             goto end_cert;
00100     }
00101 
00102     if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ 
00103             asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
00104         goto end_cert;
00105 
00106     /* make sure the signature is ok */
00107     if (asn1_signature_type(cert, &offset, x509_ctx))
00108     {
00109         ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
00110         goto end_cert;
00111     }
00112 
00113     if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || 
00114             asn1_validity(cert, &offset, x509_ctx) ||
00115             asn1_name(cert, &offset, x509_ctx->cert_dn) ||
00116             asn1_public_key(cert, &offset, x509_ctx))
00117     {
00118         goto end_cert;
00119     }
00120 
00121     bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
00122 
00123 #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
00124     /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
00125     if (x509_ctx->sig_type == SIG_TYPE_MD5)
00126     {
00127         MD5_CTX md5_ctx;
00128         uint8_t md5_dgst[MD5_SIZE];
00129         MD5_Init(&md5_ctx);
00130         MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
00131         MD5_Final(md5_dgst, &md5_ctx);
00132         x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
00133     }
00134     else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
00135     {
00136         SHA1_CTX sha_ctx;
00137         uint8_t sha_dgst[SHA1_SIZE];
00138         SHA1_Init(&sha_ctx);
00139         SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
00140         SHA1_Final(sha_dgst, &sha_ctx);
00141         x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
00142     }
00143     else if (x509_ctx->sig_type == SIG_TYPE_MD2)
00144     {
00145         MD2_CTX md2_ctx;
00146         uint8_t md2_dgst[MD2_SIZE];
00147         MD2_Init(&md2_ctx);
00148         MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
00149         MD2_Final(md2_dgst, &md2_ctx);
00150         x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
00151     }
00152 
00153     if (cert[offset] == ASN1_V3_DATA)
00154     {
00155         int suboffset;
00156 
00157         ++offset;
00158         get_asn1_length(cert, &offset);
00159 
00160         if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
00161         {
00162             if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
00163             {
00164                 int altlen;
00165 
00166                 if ((altlen = asn1_next_obj(cert, 
00167                                             &suboffset, ASN1_SEQUENCE)) > 0)
00168                 {
00169                     int endalt = suboffset + altlen;
00170                     int totalnames = 0;
00171 
00172                     while (suboffset < endalt)
00173                     {
00174                         int type = cert[suboffset++];
00175                         int dnslen = get_asn1_length(cert, &suboffset);
00176 
00177                         if (type == ASN1_CONTEXT_DNSNAME)
00178                         {
00179                             x509_ctx->subject_alt_dnsnames = (char**)
00180                                     realloc(x509_ctx->subject_alt_dnsnames, 
00181                                        (totalnames + 2) * sizeof(char*));
00182                             x509_ctx->subject_alt_dnsnames[totalnames] = 
00183                                     (char*)malloc(dnslen + 1);
00184                             x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
00185                             memcpy(x509_ctx->subject_alt_dnsnames[totalnames], 
00186                                     cert + suboffset, dnslen);
00187                             x509_ctx->subject_alt_dnsnames[
00188                                     totalnames][dnslen] = 0;
00189                             ++totalnames;
00190                         }
00191 
00192                         suboffset += dnslen;
00193                     }
00194                 }
00195             }
00196         }
00197     }
00198 
00199     offset = end_tbs;   /* skip the rest of v3 data */
00200     if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || 
00201             asn1_signature(cert, &offset, x509_ctx))
00202         goto end_cert;
00203 #endif
00204     ret = X509_OK;
00205 end_cert:
00206     if (len)
00207     {
00208         *len = cert_size;
00209     }
00210 
00211     if (ret)
00212     {
00213 #ifdef CONFIG_SSL_FULL_MODE
00214         printf("Error: Invalid X509 ASN.1 file (%s)\n",
00215                         x509_display_error(ret));
00216 #endif
00217         x509_free(x509_ctx);
00218         *ctx = NULL;
00219     }
00220 
00221     return ret;
00222 }
00223 
00224 /**
00225  * Free an X.509 object's resources.
00226  */
00227 void x509_free(X509_CTX *x509_ctx)
00228 {
00229     X509_CTX *next;
00230     int i;
00231 
00232     if (x509_ctx == NULL)       /* if already null, then don't bother */
00233         return;
00234 
00235     for (i = 0; i < X509_NUM_DN_TYPES; i++)
00236     {
00237         free(x509_ctx->ca_cert_dn[i]);
00238         free(x509_ctx->cert_dn[i]);
00239     }
00240 
00241     free(x509_ctx->signature);
00242 
00243 #ifdef CONFIG_SSL_CERT_VERIFICATION 
00244     if (x509_ctx->digest)
00245     {
00246         bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
00247     }
00248 
00249     if (x509_ctx->subject_alt_dnsnames)
00250     {
00251         for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
00252             free(x509_ctx->subject_alt_dnsnames[i]);
00253 
00254         free(x509_ctx->subject_alt_dnsnames);
00255     }
00256 #endif
00257 
00258     RSA_free(x509_ctx->rsa_ctx);
00259     next = x509_ctx->next;
00260     free(x509_ctx);
00261     x509_free(next);        /* clear the chain */
00262 }
00263 
00264 #ifdef CONFIG_SSL_CERT_VERIFICATION
00265 /**
00266  * Take a signature and decrypt it.
00267  */
00268 static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
00269         bigint *modulus, bigint *pub_exp)
00270 {
00271     int i, size;
00272     bigint *decrypted_bi, *dat_bi;
00273     bigint *bir = NULL;
00274     uint8_t *block = (uint8_t *)alloca(sig_len);
00275 
00276     /* decrypt */
00277     dat_bi = bi_import(ctx, sig, sig_len);
00278     ctx->mod_offset = BIGINT_M_OFFSET;
00279 
00280     /* convert to a normal block */
00281     decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
00282 
00283     bi_export(ctx, decrypted_bi, block, sig_len);
00284     ctx->mod_offset = BIGINT_M_OFFSET;
00285 
00286     i = 10; /* start at the first possible non-padded byte */
00287     while (block[i++] && i < sig_len);
00288     size = sig_len - i;
00289 
00290     /* get only the bit we want */
00291     if (size > 0)
00292     {
00293         int len;
00294         const uint8_t *sig_ptr = get_signature(&block[i], &len);
00295 
00296         if (sig_ptr)
00297         {
00298             bir = bi_import(ctx, sig_ptr, len);
00299         }
00300     }
00301 
00302     /* save a few bytes of memory */
00303     bi_clear_cache(ctx);
00304     return bir;
00305 }
00306 
00307 /**
00308  * Do some basic checks on the certificate chain.
00309  *
00310  * Certificate verification consists of a number of checks:
00311  * - The date of the certificate is after the start date.
00312  * - The date of the certificate is before the finish date.
00313  * - A root certificate exists in the certificate store.
00314  * - That the certificate(s) are not self-signed.
00315  * - The certificate chain is valid.
00316  * - The signature of the certificate is valid.
00317  */
00318 int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) 
00319 {
00320     int ret = X509_OK, i = 0;
00321     bigint *cert_sig;
00322     X509_CTX *next_cert = NULL;
00323     BI_CTX *ctx = NULL;
00324     bigint *mod = NULL, *expn = NULL;
00325     int match_ca_cert = 0;
00326     struct timeval tv;
00327     uint8_t is_self_signed = 0;
00328 
00329     if (cert == NULL)
00330     {
00331         ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
00332         goto end_verify;
00333     }
00334 
00335     /* a self-signed certificate that is not in the CA store - use this 
00336        to check the signature */
00337     if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
00338     {
00339         printf("self signed cert\r\n");
00340         is_self_signed = 1;
00341         ctx = cert->rsa_ctx->bi_ctx;
00342         mod = cert->rsa_ctx->m;
00343         expn = cert->rsa_ctx->e;
00344     }
00345 
00346     gettimeofday(&tv, NULL);
00347     
00348     /* check the not before date */
00349     if (tv.tv_sec < cert->not_before)
00350     {
00351         ret = X509_VFY_ERROR_NOT_YET_VALID;
00352         goto end_verify;
00353     }
00354 
00355     /* check the not after date */
00356     if (tv.tv_sec > cert->not_after)
00357     {
00358         ret = X509_VFY_ERROR_EXPIRED;
00359         goto end_verify;
00360     }
00361 
00362     next_cert = cert->next;
00363 
00364     /* last cert in the chain - look for a trusted cert */
00365     if (next_cert == NULL)
00366     {
00367        if (ca_cert_ctx != NULL) 
00368        {
00369             /* go thu the CA store */
00370             while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
00371             {
00372                 if (asn1_compare_dn(cert->ca_cert_dn,
00373                                             ca_cert_ctx->cert[i]->cert_dn) == 0)
00374                 {
00375                     /* use this CA certificate for signature verification */
00376                     match_ca_cert = 1;
00377                     ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
00378                     mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
00379                     expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
00380                     break;
00381                 }
00382 
00383                 i++;
00384             }
00385         }
00386 
00387         /* couldn't find a trusted cert (& let self-signed errors 
00388            be returned) */
00389         if (!match_ca_cert && !is_self_signed)
00390         {
00391             ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
00392             goto end_verify;
00393         }
00394     }
00395     else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
00396     {
00397         /* check the chain */
00398         ret = X509_VFY_ERROR_INVALID_CHAIN;
00399         goto end_verify;
00400     }
00401     else /* use the next certificate in the chain for signature verify */
00402     {
00403         ctx = next_cert->rsa_ctx->bi_ctx;
00404         mod = next_cert->rsa_ctx->m;
00405         expn = next_cert->rsa_ctx->e;
00406     }
00407 
00408     /* cert is self signed */
00409     if (!match_ca_cert && is_self_signed)
00410     {
00411         ret = X509_VFY_ERROR_SELF_SIGNED;
00412         goto end_verify;
00413     }
00414 
00415     /* check the signature */
00416     cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, 
00417                         bi_clone(ctx, mod), bi_clone(ctx, expn));
00418 
00419     if (cert_sig && cert->digest)
00420     {
00421         if (bi_compare(cert_sig, cert->digest) != 0)
00422             ret = X509_VFY_ERROR_BAD_SIGNATURE;
00423 
00424 
00425         bi_free(ctx, cert_sig);
00426     }
00427     else
00428     {
00429         ret = X509_VFY_ERROR_BAD_SIGNATURE;
00430     }
00431 
00432     if (ret)
00433         goto end_verify;
00434 
00435     /* go down the certificate chain using recursion. */
00436     if (next_cert != NULL)
00437     {
00438         ret = x509_verify(ca_cert_ctx, next_cert);
00439     }
00440 
00441 end_verify:
00442     return ret;
00443 }
00444 #endif
00445 
00446 #if defined (CONFIG_SSL_FULL_MODE)
00447 /**
00448  * Used for diagnostics.
00449  */
00450 static const char *not_part_of_cert = "<Not Part Of Certificate>";
00451 void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) 
00452 {
00453     if (cert == NULL)
00454         return;
00455 
00456     printf("=== CERTIFICATE ISSUED TO ===\n");
00457     printf("Common Name (CN):\t\t");
00458     printf("%s\r\n", cert->cert_dn[X509_COMMON_NAME] ?
00459                     cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
00460 
00461     printf("Organization (O):\t\t");
00462     printf("%s\r\n", cert->cert_dn[X509_ORGANIZATION] ?
00463         cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
00464 
00465     printf("Organizational Unit (OU):\t");
00466     printf("%s\r\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
00467         cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
00468 
00469     printf("=== CERTIFICATE ISSUED BY ===\r\n");
00470     printf("Common Name (CN):\t\t");
00471     printf("%s\r\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
00472                     cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
00473 
00474     printf("Organization (O):\t\t");
00475     printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
00476         cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
00477 
00478     printf("Organizational Unit (OU):\t");
00479     printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
00480         cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
00481 
00482     printf("Not Before:\t\t\t%s\r\n", ctime(&cert->not_before));
00483     printf("Not After:\t\t\t%s\r\n", ctime(&cert->not_after));
00484     printf("RSA bitsize:\t\t\t%d\r\n", cert->rsa_ctx->num_octets*8);
00485     printf("Sig Type:\t\t\t");
00486     switch (cert->sig_type)
00487     {
00488         case SIG_TYPE_MD5:
00489             printf("MD5\r\n");
00490             break;
00491         case SIG_TYPE_SHA1:
00492             printf("SHA1\r\n");
00493             break;
00494         case SIG_TYPE_MD2:
00495             printf("MD2\r\n");
00496             break;
00497         default:
00498             printf("Unrecognized: %d\r\n", cert->sig_type);
00499             break;
00500     }
00501 
00502     if (ca_cert_ctx)
00503     {
00504         printf("Verify:\t\t\t\t%s\r\n",
00505                 x509_display_error(x509_verify(ca_cert_ctx, cert)));
00506     }
00507 
00508 #if 0
00509     print_blob("Signature", cert->signature, cert->sig_len);
00510     bi_print("Modulus", cert->rsa_ctx->m);
00511     bi_print("Pub Exp", cert->rsa_ctx->e);
00512 #endif
00513 
00514     if (ca_cert_ctx)
00515     {
00516         x509_print(cert->next, ca_cert_ctx);
00517     }
00518 
00519     TTY_FLUSH();
00520 }
00521 
00522 const char * x509_display_error(int error)
00523 {
00524     switch (error)
00525     {
00526         case X509_OK:
00527             return "Certificate verify successful";
00528 
00529         case X509_NOT_OK:
00530             return "X509 not ok";
00531 
00532         case X509_VFY_ERROR_NO_TRUSTED_CERT:
00533             return "No trusted cert is available";
00534 
00535         case X509_VFY_ERROR_BAD_SIGNATURE:
00536             return "Bad signature";
00537 
00538         case X509_VFY_ERROR_NOT_YET_VALID:
00539             return "Cert is not yet valid";
00540 
00541         case X509_VFY_ERROR_EXPIRED:
00542             return "Cert has expired";
00543 
00544         case X509_VFY_ERROR_SELF_SIGNED:
00545             return "Cert is self-signed";
00546 
00547         case X509_VFY_ERROR_INVALID_CHAIN:
00548             return "Chain is invalid (check order of certs)";
00549 
00550         case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
00551             return "Unsupported digest";
00552 
00553         case X509_INVALID_PRIV_KEY:
00554             return "Invalid private key";
00555 
00556         default:
00557             return "Unknown";
00558     }
00559 }
00560 #endif      /* CONFIG_SSL_FULL_MODE */
00561