Rough and ready port of axTLS

Committer:
ashleymills
Date:
Mon May 13 18:15:18 2013 +0000
Revision:
0:5a29fd060ac8
initial commit

Who changed what in which revision?

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