/* * 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 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; }