Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
x509.c
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
Generated on Tue Jul 12 2022 18:48:01 by
1.7.2