This is a fork of the mbed port of axTLS

Dependents:   TLS_axTLS-Example HTTPSClientExample

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 #include "../../cert_manager.h"
00047 
00048 /**
00049  * Retrieve the signature from a certificate.
00050  */
00051 static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
00052 {
00053     int offset = 0;
00054     const uint8_t *ptr = NULL;
00055 
00056     if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || 
00057             asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
00058         goto end_get_sig;
00059 
00060     if (asn1_sig[offset++] != ASN1_OCTET_STRING)
00061         goto end_get_sig;
00062     *len = get_asn1_length(asn1_sig, &offset);
00063     ptr = &asn1_sig[offset];          /* all ok */
00064 
00065 end_get_sig:
00066     return ptr;
00067 }
00068 
00069 #endif
00070 
00071 /**
00072  * Construct a new x509 object.
00073  * @return 0 if ok. < 0 if there was a problem.
00074  */
00075 int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
00076 {
00077 
00078     int begin_tbs, end_tbs;
00079     int ret = X509_NOT_OK, offset = 0, cert_size = 0;
00080     X509_CTX *x509_ctx;
00081     BI_CTX *bi_ctx;
00082     *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
00083     x509_ctx = *ctx;
00084     /* get the certificate size */
00085     asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); 
00086 
00087     if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
00088         goto end_cert;
00089 
00090     begin_tbs = offset;         /* start of the tbs */
00091     end_tbs = begin_tbs;        /* work out the end of the tbs */
00092     asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
00093     if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
00094         goto end_cert;
00095     if (cert[offset] == ASN1_EXPLICIT_TAG)   /* optional version */
00096     {
00097         if (asn1_version(cert, &offset, x509_ctx))
00098             goto end_cert;
00099     }
00100     if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ 
00101             asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
00102     {
00103         goto end_cert;
00104     }
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     if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || 
00113             asn1_validity(cert, &offset, x509_ctx) ||
00114             asn1_name(cert, &offset, x509_ctx->cert_dn) ||
00115             asn1_public_key(cert, &offset, x509_ctx))
00116     {
00117         goto end_cert;
00118     }
00119     bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
00120 
00121 
00122 #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
00123     
00124     /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
00125     
00126     if (x509_ctx->sig_type == SIG_TYPE_MD5)
00127     {
00128         MD5_CTX md5_ctx;
00129         uint8_t md5_dgst[MD5_SIZE];
00130         MD5_Init(&md5_ctx);
00131         MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
00132         MD5_Final(md5_dgst, &md5_ctx);
00133         x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
00134     }
00135     else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
00136     {
00137         SHA1_CTX sha_ctx;
00138         uint8_t sha_dgst[SHA1_SIZE];
00139         SHA1_Init(&sha_ctx);
00140         SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
00141         SHA1_Final(sha_dgst, &sha_ctx);
00142         x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
00143     }
00144     else if (x509_ctx->sig_type == SIG_TYPE_MD2)
00145     {
00146         MD2_CTX md2_ctx;
00147         uint8_t md2_dgst[MD2_SIZE];
00148         MD2_Init(&md2_ctx);
00149         MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
00150         MD2_Final(md2_dgst, &md2_ctx);
00151         x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
00152     }
00153     
00154     if (cert[offset] == ASN1_V3_DATA)
00155     {
00156         int suboffset;
00157 
00158         ++offset;
00159         get_asn1_length(cert, &offset);
00160 
00161         if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
00162         {
00163             if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
00164             {
00165                 int altlen;
00166 
00167                 if ((altlen = asn1_next_obj(cert, 
00168                                             &suboffset, ASN1_SEQUENCE)) > 0)
00169                 {
00170                     int endalt = suboffset + altlen;
00171                     int totalnames = 0;
00172 
00173                     while (suboffset < endalt)
00174                     {
00175                         int type = cert[suboffset++];
00176                         int dnslen = get_asn1_length(cert, &suboffset);
00177 
00178                         if (type == ASN1_CONTEXT_DNSNAME)
00179                         {
00180                             x509_ctx->subject_alt_dnsnames = (char**)
00181                                     realloc(x509_ctx->subject_alt_dnsnames, 
00182                                        (totalnames + 2) * sizeof(char*));
00183                             x509_ctx->subject_alt_dnsnames[totalnames] = 
00184                                     (char*)malloc(dnslen + 1);
00185                             x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
00186                             memcpy(x509_ctx->subject_alt_dnsnames[totalnames], 
00187                                     cert + suboffset, dnslen);
00188                             x509_ctx->subject_alt_dnsnames[
00189                                     totalnames][dnslen] = 0;
00190                             ++totalnames;
00191                         }
00192 
00193                         suboffset += dnslen;
00194                     }
00195                 }
00196             }
00197         }
00198     }
00199     
00200     offset = end_tbs;   /* skip the rest of v3 data */
00201     if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || 
00202             asn1_signature(cert, &offset, x509_ctx))
00203         goto end_cert;
00204         
00205 #endif
00206     ret = X509_OK;
00207 end_cert:
00208     if (len)
00209     {
00210         *len = cert_size;
00211     }
00212 
00213     if (ret)
00214     {
00215 #ifdef CONFIG_SSL_FULL_MODE
00216         printf("Error: Invalid X509 ASN.1 file (%s)\n",
00217                         x509_display_error(ret));
00218 #endif
00219         x509_free(x509_ctx);
00220         *ctx = NULL;
00221     }
00222     return ret;
00223 }
00224 
00225 /**
00226  * Free an X.509 object's resources.
00227  */
00228 void x509_free(X509_CTX *x509_ctx)
00229 {
00230     X509_CTX *next;
00231     int i;
00232 
00233     if (x509_ctx == NULL)       /* if already null, then don't bother */
00234         return;
00235 
00236     for (i = 0; i < X509_NUM_DN_TYPES; i++)
00237     {
00238         free(x509_ctx->ca_cert_dn[i]);
00239         free(x509_ctx->cert_dn[i]);
00240     }
00241 
00242     free(x509_ctx->signature);
00243 
00244 #ifdef CONFIG_SSL_CERT_VERIFICATION 
00245     if (x509_ctx->digest)
00246     {
00247         bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
00248     }
00249 
00250     if (x509_ctx->subject_alt_dnsnames)
00251     {
00252         for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
00253             free(x509_ctx->subject_alt_dnsnames[i]);
00254 
00255         free(x509_ctx->subject_alt_dnsnames);
00256     }
00257 #endif
00258 
00259     RSA_free(x509_ctx->rsa_ctx);
00260     next = x509_ctx->next;
00261     free(x509_ctx);
00262     x509_free(next);        /* clear the chain */
00263 }
00264 
00265 #ifdef CONFIG_SSL_CERT_VERIFICATION
00266 /**
00267  * Take a signature and decrypt it.
00268  */
00269 bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
00270         bigint *modulus, bigint *pub_exp)
00271 {
00272     int i, size;
00273     bigint *decrypted_bi, *dat_bi;
00274     bigint *bir = NULL;
00275     uint8_t *block = (uint8_t *)alloca(sig_len);
00276 
00277     /* decrypt */
00278     dat_bi = bi_import(ctx, sig, sig_len);
00279     ctx->mod_offset = BIGINT_M_OFFSET;
00280 
00281     /* convert to a normal block */
00282     decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
00283 
00284     bi_export(ctx, decrypted_bi, block, sig_len);
00285     ctx->mod_offset = BIGINT_M_OFFSET;
00286 
00287     i = 10; /* start at the first possible non-padded byte */
00288     while (block[i++] && i < sig_len);
00289     size = sig_len - i;
00290 
00291     /* get only the bit we want */
00292     if (size > 0)
00293     {
00294         int len = 0;
00295         const uint8_t *sig_ptr = get_signature(&block[i], &len);
00296 
00297         if (sig_ptr)
00298         {
00299             bir = bi_import(ctx, sig_ptr, len);
00300         }
00301     }
00302 
00303     /* save a few bytes of memory */
00304     bi_clear_cache(ctx);
00305     return bir;
00306 }
00307 
00308 
00309 /**
00310  * Do some basic checks on the certificate chain.
00311  *
00312  * Certificate verification consists of a number of checks:
00313  * - The date of the certificate is after the start date.
00314  * - The date of the certificate is before the finish date.
00315  * - A root certificate exists in the certificate store.
00316  * - That the certificate(s) are not self-signed.
00317  * - The certificate chain is valid.
00318  * - The signature of the certificate is valid.
00319  */
00320 int x509_verify(PrecomputedCertificate *cert) 
00321 {
00322 
00323     int ret = X509_OK;
00324     PrecomputedCertificate *next_cert = NULL;
00325     int match_ca_cert = 0;
00326     uint8_t is_self_signed = 0;
00327     uint8_t *mod = NULL, *expn = NULL;
00328     bigint *bi_mod = NULL, *bi_expn = NULL;
00329     BI_CTX *bi_ctx = NULL;
00330     char precomputed = is_precomputed();
00331 
00332     if (cert == NULL)
00333     {
00334         ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
00335         goto end_verify;
00336     }
00337     /* a self-signed certificate that is not in the CA store - use this 
00338        to check the signature */
00339     if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
00340     {
00341         is_self_signed = 1;
00342         if(precomputed)
00343         {
00344             mod = cert->mod;
00345             expn = cert->expn;
00346         }
00347         else
00348         {
00349             bi_ctx = bi_initialize();
00350             bi_mod = bi_import(bi_ctx, cert->mod, cert->mod_len);
00351             bi_expn = bi_import(bi_ctx, cert->expn, cert->expn_len);
00352         }
00353     }    
00354 
00355     next_cert = cert->next;
00356 
00357     /* last cert in the chain - look for a trusted cert */
00358     if (next_cert == NULL)
00359     {
00360         if(precomputed)
00361         {
00362             PrecomputedCertificate tmp = get_precomputed_cert(cert->cert_dn, cert->ca_cert_dn);
00363             mod = tmp.mod;
00364             expn = tmp.expn;
00365         }
00366         else
00367         {
00368             X509_CTX *root = get_cert(cert->ca_cert_dn);
00369             bi_ctx = root->rsa_ctx->bi_ctx;
00370             bi_mod = bi_clone(bi_ctx,root->rsa_ctx->m);
00371             bi_expn = bi_clone(bi_ctx, root->rsa_ctx->e);
00372         }
00373     }
00374     else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
00375     {
00376         /* check the chain */
00377         ret = X509_VFY_ERROR_INVALID_CHAIN;
00378         goto end_verify;
00379     }
00380     else /* use the next certificate in the chain for signature verify */
00381     {
00382         if(precomputed)
00383         {
00384             mod = next_cert->mod;
00385             expn = next_cert->expn;
00386         }
00387         else
00388         {
00389             bi_ctx = bi_initialize();
00390             bi_mod = bi_import(bi_ctx, next_cert->mod, next_cert->mod_len);
00391             bi_expn = bi_import(bi_ctx, next_cert->expn, next_cert->expn_len);
00392         }
00393     }
00394 
00395     /* cert is self signed */
00396     if (!match_ca_cert && is_self_signed)
00397     {
00398         ret = X509_VFY_ERROR_SELF_SIGNED;
00399         goto end_verify;
00400     }
00401 
00402     /* check the signature */
00403     if(precomputed)
00404     {
00405         PrecomputedCertificate pc = get_precomputed_cert(cert->cert_dn, cert->ca_cert_dn);
00406         
00407         if(memcmp(cert->sig, pc.sig, pc.sig_len)
00408         || memcmp(cert->digest, pc.digest, pc.digest_len)
00409         || memcmp(mod, pc.mod, pc.mod_len)
00410         || memcmp(expn, pc.expn, pc.expn_len))
00411             ret = X509_VFY_ERROR_BAD_SIGNATURE;
00412     }
00413     else
00414     {
00415         bigint* cert_sig = sig_verify(bi_ctx, cert->sig, cert->sig_len, 
00416                            bi_mod, bi_expn);        
00417         
00418         if (cert_sig && cert->digest)
00419         {
00420             uint8_t paddingLength = 0;
00421             uint8_t digest[64];
00422             bi_export(bi_ctx, cert_sig, digest, sizeof(digest));
00423             while(digest[paddingLength] == 0) paddingLength++;
00424             uint8_t digest_len = 64 - paddingLength;
00425             if (memcmp(digest, cert->digest, digest_len) != 0)
00426                 ret = X509_VFY_ERROR_BAD_SIGNATURE;
00427         }
00428         else
00429         {
00430             ret = X509_VFY_ERROR_BAD_SIGNATURE;
00431         }
00432         if(is_self_signed || next_cert != NULL)
00433             bi_terminate(bi_ctx);
00434     }
00435     
00436 
00437     if (ret)
00438         goto end_verify;
00439 
00440     /* go down the certificate chain using recursion. */
00441     if (next_cert != NULL)
00442     {
00443         ret = x509_verify(next_cert);
00444     }
00445 
00446 end_verify:
00447     return ret;
00448 }
00449 #endif
00450 
00451 #if defined (CONFIG_SSL_FULL_MODE)
00452 /**
00453  * Used for diagnostics.
00454  */
00455 static const char *not_part_of_cert = "<Not Part Of Certificate>";
00456 void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) 
00457 {
00458     if (cert == NULL)
00459         return;
00460 
00461     printf("=== CERTIFICATE ISSUED TO ===\n");
00462     printf("Common Name (CN):\t\t");
00463     printf("%s\r\n", cert->cert_dn[X509_COMMON_NAME] ?
00464                     cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
00465 
00466     printf("Organization (O):\t\t");
00467     printf("%s\r\n", cert->cert_dn[X509_ORGANIZATION] ?
00468         cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
00469 
00470     printf("Organizational Unit (OU):\t");
00471     printf("%s\r\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
00472         cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
00473 
00474     printf("=== CERTIFICATE ISSUED BY ===\r\n");
00475     printf("Common Name (CN):\t\t");
00476     printf("%s\r\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
00477                     cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
00478 
00479     printf("Organization (O):\t\t");
00480     printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
00481         cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
00482 
00483     printf("Organizational Unit (OU):\t");
00484     printf("%s\r\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
00485         cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
00486 
00487     printf("Not Before:\t\t\t%s\r\n", ctime(&cert->not_before));
00488     printf("Not After:\t\t\t%s\r\n", ctime(&cert->not_after));
00489     printf("RSA bitsize:\t\t\t%d\r\n", cert->rsa_ctx->num_octets*8);
00490     printf("Sig Type:\t\t\t");
00491     switch (cert->sig_type)
00492     {
00493         case SIG_TYPE_MD5:
00494             printf("MD5\r\n");
00495             break;
00496         case SIG_TYPE_SHA1:
00497             printf("SHA1\r\n");
00498             break;
00499         case SIG_TYPE_MD2:
00500             printf("MD2\r\n");
00501             break;
00502         default:
00503             printf("Unrecognized: %d\r\n", cert->sig_type);
00504             break;
00505     }
00506 
00507     if (ca_cert_ctx)
00508     {
00509        // printf("Verify:\t\t\t\t%s\r\n",
00510         //        x509_display_error(x509_verify(cert)));
00511     }
00512 
00513 #if 0
00514     print_blob("Signature", cert->signature, cert->sig_len);
00515     bi_print("Modulus", cert->rsa_ctx->m);
00516     bi_print("Pub Exp", cert->rsa_ctx->e);
00517 #endif
00518 
00519     if (ca_cert_ctx)
00520     {
00521         x509_print(cert->next, ca_cert_ctx);
00522     }
00523 
00524     TTY_FLUSH();
00525 }
00526 
00527 const char * x509_display_error(int error)
00528 {
00529     switch (error)
00530     {
00531         case X509_OK:
00532             return "Certificate verify successful";
00533 
00534         case X509_NOT_OK:
00535             return "X509 not ok";
00536 
00537         case X509_VFY_ERROR_NO_TRUSTED_CERT:
00538             return "No trusted cert is available";
00539 
00540         case X509_VFY_ERROR_BAD_SIGNATURE:
00541             return "Bad signature";
00542 
00543         case X509_VFY_ERROR_NOT_YET_VALID:
00544             return "Cert is not yet valid";
00545 
00546         case X509_VFY_ERROR_EXPIRED:
00547             return "Cert has expired";
00548 
00549         case X509_VFY_ERROR_SELF_SIGNED:
00550             return "Cert is self-signed";
00551 
00552         case X509_VFY_ERROR_INVALID_CHAIN:
00553             return "Chain is invalid (check order of certs)";
00554 
00555         case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
00556             return "Unsupported digest";
00557 
00558         case X509_INVALID_PRIV_KEY:
00559             return "Invalid private key";
00560             
00561         case X509_KEY_SIZE_TOO_BIG:
00562             return "Only keys less or equal to 1024 bits are supported";
00563             
00564         default:
00565             return "Unknown";
00566     }
00567 }
00568 #endif      /* CONFIG_SSL_FULL_MODE */
00569 
00570 
00571