/** * Read the modulus and public exponent of a certificate. */ int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) { int ret = X509_NOT_OK, mod_len, pub_len; uint8_t *modulus = NULL, *pub_exp = NULL; if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(cert, offset, ASN1_SEQUENCE) || asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0) goto end_pub_key; (*offset)++; /* ignore the padding bit field */ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) goto end_pub_key; mod_len = asn1_get_int(cert, offset, &modulus); pub_len = asn1_get_int(cert, offset, &pub_exp); RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len); free(modulus); free(pub_exp); ret = X509_OK; end_pub_key: return ret; }
/* * Retrieve the salt/iteration details from a PBE block. */ static int get_pbe_params(uint8_t *buf, int *offset, const uint8_t **salt, int *iterations) { static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 }; int i, len; uint8_t *iter = NULL; int error_code = SSL_ERROR_NOT_SUPPORTED; /* Get the PBE type */ if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) goto error; /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1) which is the only algorithm we support */ if (len != sizeof(pbeSH1RC4) || memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4))) { #ifdef CONFIG_SSL_FULL_MODE printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n"); #endif goto error; } *offset += len; if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 || len != 8) goto error; *salt = &buf[*offset]; *offset += len; if ((len = asn1_get_big_int(buf, offset, &iter)) < 0) goto error; *iterations = 0; for (i = 0; i < len; i++) { (*iterations) <<= 8; (*iterations) += iter[i]; } free(iter); error_code = SSL_OK; /* got here - we are ok */ error: return error_code; }
/** * Get the subject name (or the issuer) of a certificate. */ int asn1_name(const uint8_t *cert, int *offset, char *dn[]) { int ret = X509_NOT_OK; int dn_type; char *tmp; if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) goto end_name; while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) { int i, found = 0; if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || (dn_type = asn1_get_oid_x520(cert, offset)) < 0) goto end_name; tmp = NULL; if (asn1_get_printable_str(cert, offset, &tmp) < 0) { free(tmp); goto end_name; } /* find the distinguished named type */ for (i = 0; i < X509_NUM_DN_TYPES; i++) { if (dn_type == g_dn_types[i]) { if (dn[i] == NULL) { dn[i] = tmp; found = 1; break; } } } if (found == 0) /* not found so get rid of it */ { free(tmp); } } ret = X509_OK; end_name: return ret; }
static int asn1_find_oid(const uint8_t* cert, int* offset, const uint8_t* oid, int oid_length) { int seqlen; if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0) { int end = *offset + seqlen; while (*offset < end) { int type = cert[(*offset)++]; int length = get_asn1_length(cert, offset); int noffset = *offset + length; if (type == ASN1_SEQUENCE) { type = cert[(*offset)++]; length = get_asn1_length(cert, offset); if (type == ASN1_OID && length == oid_length && memcmp(cert + *offset, oid, oid_length) == 0) { *offset += oid_length; return 1; } } *offset = noffset; } } return 0; }
/* Saves a few bytes of memory */ bi_clear_cache(bi_ctx); #endif ret = X509_OK; end_cert: if (len) { *len = cert_size; } if (ret) { #ifdef CONFIG_SSL_FULL_MODE char buff[64]; printf("Error: Invalid X509 ASN.1 file (%s)\n", x509_display_error(ret, buff)); #endif x509_free(x509_ctx); *ctx = NULL; } return ret; } #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, X509_CTX *x509_ctx) { if ((offset = asn1_is_subject_alt_name(cert, offset)) > 0) { x509_ctx->subject_alt_name_present = true; x509_ctx->subject_alt_name_is_critical = asn1_is_critical_ext(cert, &offset); if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) > 0) { int altlen; if ((altlen = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) > 0) { int endalt = offset + altlen; int totalnames = 0; while (offset < endalt) { int type = cert[offset++]; int dnslen = get_asn1_length(cert, &offset); if (type == ASN1_CONTEXT_DNSNAME) { x509_ctx->subject_alt_dnsnames = (char**) realloc(x509_ctx->subject_alt_dnsnames, (totalnames + 2) * sizeof(char*)); x509_ctx->subject_alt_dnsnames[totalnames] = (char*)malloc(dnslen + 1); x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; memcpy(x509_ctx->subject_alt_dnsnames[totalnames], cert + offset, dnslen); x509_ctx->subject_alt_dnsnames[totalnames][dnslen] = 0; totalnames++; } offset += dnslen; } } } } return X509_OK; }
/** * Basic constraints - see https://tools.ietf.org/html/rfc5280#page-39 */ static int x509_v3_basic_constraints(const uint8_t *cert, int offset, X509_CTX *x509_ctx) { int ret = X509_OK; int lenSeq = 0; if ((offset = asn1_is_basic_constraints(cert, offset)) == 0) goto end_contraints; x509_ctx->basic_constraint_present = true; x509_ctx->basic_constraint_is_critical = asn1_is_critical_ext(cert, &offset); /* Assign Defaults in case not specified basic_constraint_cA will already by zero by virtue of the calloc */ x509_ctx->basic_constraint_cA = 0; /* basic_constraint_pathLenConstraint is unlimited by default. 10000 is just a large number (limits.h is not already included) */ x509_ctx->basic_constraint_pathLenConstraint = 10000; if ((asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0) || ((lenSeq = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) < 0)) { ret = X509_NOT_OK; } /* If the Sequence Length is greater than zero, continue with the basic_constraint_cA */ if ((lenSeq>0)&&(asn1_get_bool(cert, &offset, &x509_ctx->basic_constraint_cA) < 0)) { ret = X509_NOT_OK; } /* If the Sequence Length is greater than 3, it has more content than the basic_constraint_cA bool, so grab the pathLenConstraint */ if ((lenSeq>3) && (asn1_get_int(cert, &offset, &x509_ctx->basic_constraint_pathLenConstraint) < 0)) { ret = X509_NOT_OK; } end_contraints: return ret; }
/* * Take a raw pkcs8 block and then decrypt it and turn it into a normal key. */ int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) { uint8_t *buf = ssl_obj->buf; int len, offset = 0; int iterations; int ret = SSL_NOT_OK; uint8_t *version = NULL; const uint8_t *salt; uint8_t *priv_key; int uni_pass_len; char *uni_pass = make_uni_pass(password, &uni_pass_len); if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) { #ifdef CONFIG_SSL_FULL_MODE printf("Error: Invalid p8 ASN.1 file\n"); #endif goto error; } /* unencrypted key? */ if (asn1_get_big_int(buf, &offset, &version) > 0 && *version == 0) { ret = p8_add_key(ssl_ctx, buf); goto error; } if (get_pbe_params(buf, &offset, &salt, &iterations) < 0) goto error; if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) goto error; priv_key = &buf[offset]; p8_decrypt(uni_pass, uni_pass_len, salt, iterations, priv_key, len, PKCS12_KEY_ID); ret = p8_add_key(ssl_ctx, priv_key); error: free(version); free(uni_pass); return ret; }
/* * Take the unencrypted pkcs8 and turn it into a private key */ static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key) { uint8_t *buf = priv_key; int len, offset = 0; int ret = SSL_NOT_OK; /* Skip the preamble and go straight to the private key. We only support rsaEncryption (1.2.840.113549.1.1.1) */ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) goto error; ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx); error: return ret; }
/** * Retrieve the signature from a certificate. */ static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len) { int offset = 0; const uint8_t *ptr = NULL; if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) goto end_get_sig; if (asn1_sig[offset++] != ASN1_OCTET_STRING) goto end_get_sig; *len = get_asn1_length(asn1_sig, &offset); ptr = &asn1_sig[offset]; /* all ok */ end_get_sig: return ptr; }
/** * Get the components of a distinguished name */ static int asn1_get_oid_x520(const uint8_t *buf, int *offset) { int dn_type = 0; int len; if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) goto end_oid; /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name components we are interested in. */ if (len == 3 && buf[*offset] == 0x55 && buf[*offset+1] == 0x04) { /* GBG */ dn_type = buf[*offset+2]; } *offset += len; /* skip over it */ end_oid: return dn_type; }
/* * Key usage - see https://tools.ietf.org/html/rfc5280#section-4.2.1.3 */ static int x509_v3_key_usage(const uint8_t *cert, int offset, X509_CTX *x509_ctx) { int ret = X509_OK; if ((offset = asn1_is_key_usage(cert, offset)) == 0) goto end_key_usage; x509_ctx->key_usage_present = true; x509_ctx->key_usage_is_critical = asn1_is_critical_ext(cert, &offset); if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || asn1_get_bit_string_as_int(cert, &offset, &x509_ctx->key_usage)) { ret = X509_NOT_OK; } end_key_usage: return ret; }
/** * Read an integer value for ASN.1 data * Note: This function allocates memory which must be freed by the user. */ int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object) { int len; if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0) goto end_int_array; if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */ { len--; (*offset)++; } *object = (uint8_t *)malloc(len); memcpy(*object, &buf[*offset], len); *offset += len; end_int_array: return len; }
/** * Get the components of a distinguished name */ static int ICACHE_FLASH_ATTR asn1_get_oid_x520(const uint8_t *buf, int *offset) { int dn_type = 0; int len; if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) goto end_oid; /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name components we are interested in. */ if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04) dn_type = buf[(*offset)++]; else { *offset += len; /* skip over it */ } end_oid: return dn_type; }
/** * Get the subject name (or the issuer) of a certificate. */ int asn1_name(const uint8_t *cert, int *offset, char *dn[]) { int ret = X509_NOT_OK; int dn_type = 0; char *name = NULL; char* name_prefix = NULL; /* GBG */ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) goto end_name; while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) { int i, found = 0; if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) { /* GBG */ goto end_name; } /* get the oid */ { int len = asn1_next_obj(cert, offset, ASN1_OID); int oid_offset = *offset; if (len < 0) goto end_name; if (len == 3 && cert[oid_offset] == 0x55 && cert[oid_offset+1] == 0x04) { dn_type = cert[oid_offset+2]; } else { /* convert the OID to a string */ name_prefix = asn1_oid_to_string(cert+oid_offset, len); if (name_prefix == NULL) goto end_name; } *offset += len; } if (asn1_get_printable_str(cert, offset, &name) < 0) { free(name); if (name_prefix) free(name_prefix); goto end_name; } /* add the prefix if there is one */ if (name_prefix) { int name_prefix_len = (int)strlen(name_prefix); int name_len = (int)strlen(name); char* compound = malloc(name_prefix_len+name_len+2); memcpy(compound, name_prefix, name_prefix_len); compound[name_prefix_len] = '='; memcpy(compound+name_prefix_len+1, name, name_len+1); free(name); free(name_prefix); name = compound; name_prefix = NULL; } /* find the distinguished named type */ for (i = 0; i < X509_NUM_DN_TYPES; i++) { if (dn_type == g_dn_types[i]) { if (dn[i] == NULL) { dn[i] = name; found = 1; break; } } } if (found == 0) /* not found so get rid of it */ { free(name); } } ret = X509_OK; end_name: return ret; }
/** * Retrieve the notbefore and notafter certificate times. */ int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) { return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || asn1_get_utc_time(cert, offset, &x509_ctx->not_before) || asn1_get_utc_time(cert, offset, &x509_ctx->not_after)); }
/** * Construct a new x509 object. * @return 0 if ok. < 0 if there was a problem. */ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) { int begin_tbs, end_tbs, begin_spki, end_spki; int ret = X509_NOT_OK, offset = 0, cert_size = 0; int version = 0; X509_CTX *x509_ctx; #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ BI_CTX *bi_ctx; #endif *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); x509_ctx = *ctx; /* get the certificate size */ asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) goto end_cert; begin_tbs = offset; /* start of the tbs */ end_tbs = begin_tbs; /* work out the end of the tbs */ asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) goto end_cert; /* optional version */ if (cert[offset] == ASN1_EXPLICIT_TAG && asn1_version(cert, &offset, &version) == X509_NOT_OK) goto end_cert; if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) goto end_cert; /* make sure the signature is ok */ if (asn1_signature_type(cert, &offset, x509_ctx)) { ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; goto end_cert; } if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || asn1_validity(cert, &offset, x509_ctx) || asn1_name(cert, &offset, x509_ctx->cert_dn)) { goto end_cert; } begin_spki = offset; if (asn1_public_key(cert, &offset, x509_ctx)) goto end_cert; end_spki = offset; x509_ctx->fingerprint = malloc(SHA1_SIZE); SHA1_CTX sha_fp_ctx; SHA1_Init(&sha_fp_ctx); SHA1_Update(&sha_fp_ctx, &cert[0], cert_size); SHA1_Final(x509_ctx->fingerprint, &sha_fp_ctx); x509_ctx->spki_sha256 = malloc(SHA256_SIZE); SHA256_CTX spki_hash_ctx; SHA256_Init(&spki_hash_ctx); SHA256_Update(&spki_hash_ctx, &cert[begin_spki], end_spki-begin_spki); SHA256_Final(x509_ctx->spki_sha256, &spki_hash_ctx); #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ bi_ctx = x509_ctx->rsa_ctx->bi_ctx; /* use the appropriate signature algorithm */ switch (x509_ctx->sig_type) { case SIG_TYPE_MD5: { MD5_CTX md5_ctx; uint8_t md5_dgst[MD5_SIZE]; MD5_Init(&md5_ctx); MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); MD5_Final(md5_dgst, &md5_ctx); x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); } break; case SIG_TYPE_SHA1: { SHA1_CTX sha_ctx; uint8_t sha_dgst[SHA1_SIZE]; SHA1_Init(&sha_ctx); SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); SHA1_Final(sha_dgst, &sha_ctx); x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); } break; case SIG_TYPE_SHA256: { SHA256_CTX sha256_ctx; uint8_t sha256_dgst[SHA256_SIZE]; SHA256_Init(&sha256_ctx); SHA256_Update(&sha256_ctx, &cert[begin_tbs], end_tbs-begin_tbs); SHA256_Final(sha256_dgst, &sha256_ctx); x509_ctx->digest = bi_import(bi_ctx, sha256_dgst, SHA256_SIZE); } break; case SIG_TYPE_SHA384: { SHA384_CTX sha384_ctx; uint8_t sha384_dgst[SHA384_SIZE]; SHA384_Init(&sha384_ctx); SHA384_Update(&sha384_ctx, &cert[begin_tbs], end_tbs-begin_tbs); SHA384_Final(sha384_dgst, &sha384_ctx); x509_ctx->digest = bi_import(bi_ctx, sha384_dgst, SHA384_SIZE); } break; case SIG_TYPE_SHA512: { SHA512_CTX sha512_ctx; uint8_t sha512_dgst[SHA512_SIZE]; SHA512_Init(&sha512_ctx); SHA512_Update(&sha512_ctx, &cert[begin_tbs], end_tbs-begin_tbs); SHA512_Final(sha512_dgst, &sha512_ctx); x509_ctx->digest = bi_import(bi_ctx, sha512_dgst, SHA512_SIZE); } break; } if (version == 2 && asn1_next_obj(cert, &offset, ASN1_V3_DATA) > 0) { x509_v3_subject_alt_name(cert, offset, x509_ctx); x509_v3_basic_constraints(cert, offset, x509_ctx); x509_v3_key_usage(cert, offset, x509_ctx); } offset = end_tbs; /* skip the rest of v3 data */ if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || asn1_signature(cert, &offset, x509_ctx)) goto end_cert; /* Saves a few bytes of memory */ bi_clear_cache(bi_ctx); #endif ret = X509_OK; end_cert: if (len) { *len = cert_size; } if (ret) { #ifdef CONFIG_SSL_FULL_MODE char buff[64]; printf("Error: Invalid X509 ASN.1 file (%s)\n", x509_display_error(ret, buff)); #endif x509_free(x509_ctx); *ctx = NULL; } return ret; }
/** * Construct a new x509 object. * @return 0 if ok. < 0 if there was a problem. */ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) { int begin_tbs, end_tbs; int ret = X509_NOT_OK, offset = 0, cert_size = 0; X509_CTX *x509_ctx; BI_CTX *bi_ctx; *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); x509_ctx = *ctx; /* get the certificate size */ asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) goto end_cert; begin_tbs = offset; /* start of the tbs */ end_tbs = begin_tbs; /* work out the end of the tbs */ asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) goto end_cert; if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */ { if (asn1_version(cert, &offset, x509_ctx)) goto end_cert; } if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) goto end_cert; /* make sure the signature is ok */ if (asn1_signature_type(cert, &offset, x509_ctx)) { ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; goto end_cert; } if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || asn1_validity(cert, &offset, x509_ctx) || asn1_name(cert, &offset, x509_ctx->cert_dn) || asn1_public_key(cert, &offset, x509_ctx)) { goto end_cert; } bi_ctx = x509_ctx->rsa_ctx->bi_ctx; x509_ctx->fingerprint = malloc(SHA1_SIZE); SHA1_CTX sha_fp_ctx; SHA1_Init(&sha_fp_ctx); SHA1_Update(&sha_fp_ctx, &cert[0], cert_size); SHA1_Final(x509_ctx->fingerprint, &sha_fp_ctx); #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ /* use the appropriate signature algorithm (SHA1/MD5/MD2) */ if (x509_ctx->sig_type == SIG_TYPE_MD5) { MD5_CTX md5_ctx; uint8_t md5_dgst[MD5_SIZE]; MD5_Init(&md5_ctx); MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); MD5_Final(md5_dgst, &md5_ctx); x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); } else if (x509_ctx->sig_type == SIG_TYPE_SHA1) { SHA1_CTX sha_ctx; uint8_t sha_dgst[SHA1_SIZE]; SHA1_Init(&sha_ctx); SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); SHA1_Final(sha_dgst, &sha_ctx); x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); } else if (x509_ctx->sig_type == SIG_TYPE_MD2) { MD2_CTX md2_ctx; uint8_t md2_dgst[MD2_SIZE]; MD2_Init(&md2_ctx); MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs); MD2_Final(md2_dgst, &md2_ctx); x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE); } if (cert[offset] == ASN1_V3_DATA) { int suboffset; ++offset; get_asn1_length(cert, &offset); if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0) { if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0) { int altlen; if ((altlen = asn1_next_obj(cert, &suboffset, ASN1_SEQUENCE)) > 0) { int endalt = suboffset + altlen; int totalnames = 0; while (suboffset < endalt) { int type = cert[suboffset++]; int dnslen = get_asn1_length(cert, &suboffset); if (type == ASN1_CONTEXT_DNSNAME) { x509_ctx->subject_alt_dnsnames = (char**) realloc(x509_ctx->subject_alt_dnsnames, (totalnames + 2) * sizeof(char*)); x509_ctx->subject_alt_dnsnames[totalnames] = (char*)malloc(dnslen + 1); x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; memcpy(x509_ctx->subject_alt_dnsnames[totalnames], cert + suboffset, dnslen); x509_ctx->subject_alt_dnsnames[ totalnames][dnslen] = 0; ++totalnames; } suboffset += dnslen; } } } } } offset = end_tbs; /* skip the rest of v3 data */ if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || asn1_signature(cert, &offset, x509_ctx)) goto end_cert; #endif ret = X509_OK; end_cert: if (len) { *len = cert_size; } if (ret) { #ifdef CONFIG_SSL_FULL_MODE printf("Error: Invalid X509 ASN.1 file (%s)\n", x509_display_error(ret)); #endif x509_free(x509_ctx); *ctx = NULL; } return ret; }
/* * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s) * and keys. */ int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) { uint8_t *buf = ssl_obj->buf; int len, iterations, auth_safes_start, auth_safes_end, auth_safes_len, key_offset, offset = 0; int all_certs = 0; uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac; uint8_t key[SHA1_SIZE]; uint8_t mac[SHA1_SIZE]; const uint8_t *salt; int uni_pass_len, ret = SSL_OK; char *uni_pass = make_uni_pass(password, &uni_pass_len); static const uint8_t pkcs_data[] = /* pkc7 data */ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 }; static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 }; static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 }; if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) { #ifdef CONFIG_SSL_FULL_MODE printf("Error: Invalid p12 ASN.1 file\n"); #endif goto error; } if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3) { ret = SSL_ERROR_INVALID_VERSION; goto error; } /* remove all the boring pcks7 bits */ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || len != sizeof(pkcs_data) || memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) goto error; offset += len; if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0) goto error; /* work out the MAC start/end points (done on AuthSafes) */ auth_safes_start = offset; auth_safes_end = offset; if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0) goto error; auth_safes_len = auth_safes_end - auth_safes_start; auth_safes = malloc(auth_safes_len); memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len); if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || (len != sizeof(pkcs_encrypted) || memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted)))) goto error; offset += len; if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || len != sizeof(pkcs_data) || memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) goto error; offset += len; /* work out the salt for the certificate */ if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0) goto error; /* decrypt the certificate */ cert = &buf[offset]; if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, len, PKCS12_KEY_ID)) < 0) goto error; offset += len; /* load the certificate */ key_offset = 0; all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE); /* keep going until all certs are loaded */ while (key_offset < all_certs) { int cert_offset = key_offset; if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 || asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0) goto error; if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0) goto error; key_offset = cert_offset; } if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || len != sizeof(pkcs_data) || memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) goto error; offset += len; if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 || asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || (len != sizeof(pkcs8_key_bag)) || memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag))) goto error; offset += len; /* work out the salt for the private key */ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || get_pbe_params(buf, &offset, &salt, &iterations) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) goto error; /* decrypt the private key */ cert = &buf[offset]; if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, len, PKCS12_KEY_ID)) < 0) goto error; offset += len; /* load the private key */ if ((ret = p8_add_key(ssl_ctx, cert)) < 0) goto error; /* miss out on friendly name, local key id etc */ if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0) goto error; /* work out the MAC */ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != SHA1_SIZE) goto error; orig_mac = &buf[offset]; offset += len; /* get the salt */ if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8) goto error; salt = &buf[offset]; /* work out what the mac should be */ if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, key, SHA1_SIZE, PKCS12_MAC_ID)) < 0) goto error; hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); if (memcmp(mac, orig_mac, SHA1_SIZE)) { ret = SSL_ERROR_INVALID_HMAC; goto error; } error: free(version); free(uni_pass); free(auth_safes); return ret; }