/* pkcs7_parse_header reads the non-certificate/non-CRL prefix of a PKCS#7 * SignedData blob from |cbs| and sets |*out| to point to the rest of the * input. If the input is in BER format, then |*der_bytes| will be set to a * pointer that needs to be freed by the caller once they have finished * processing |*out| (which will be pointing into |*der_bytes|). * * It returns one on success or zero on error. On error, |*der_bytes| is * NULL. */ static int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) { size_t der_len; CBS in, content_info, content_type, wrapped_signed_data, signed_data; uint64_t version; /* The input may be in BER format. */ *der_bytes = NULL; if (!CBS_asn1_ber_to_der(cbs, der_bytes, &der_len)) { return 0; } if (*der_bytes != NULL) { CBS_init(&in, *der_bytes, der_len); } else { CBS_init(&in, CBS_data(cbs), CBS_len(cbs)); } /* See https://tools.ietf.org/html/rfc2315#section-7 */ if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) { goto err; } if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) { OPENSSL_PUT_ERROR(X509, pkcs7_parse_header, X509_R_NOT_PKCS7_SIGNED_DATA); goto err; } /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ if (!CBS_get_asn1(&content_info, &wrapped_signed_data, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || !CBS_get_asn1(&wrapped_signed_data, &signed_data, CBS_ASN1_SEQUENCE) || !CBS_get_asn1_uint64(&signed_data, &version) || !CBS_get_asn1(&signed_data, NULL /* digests */, CBS_ASN1_SET) || !CBS_get_asn1(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) { goto err; } if (version < 1) { OPENSSL_PUT_ERROR(X509, pkcs7_parse_header, X509_R_BAD_PKCS7_VERSION); goto err; } CBS_init(out, CBS_data(&signed_data), CBS_len(&signed_data)); return 1; err: if (*der_bytes) { OPENSSL_free(*der_bytes); *der_bytes = NULL; } return 0; }
EVP_PKEY *EVP_parse_public_key(CBS *cbs) { /* Parse the SubjectPublicKeyInfo. */ CBS spki, algorithm, oid, key; uint8_t padding; if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || !CBS_get_asn1(&spki, &key, CBS_ASN1_BITSTRING) || CBS_len(&spki) != 0 || /* Every key type defined encodes the key as a byte string with the same * conversion to BIT STRING. */ !CBS_get_u8(&key, &padding) || padding != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return NULL; } /* Set up an |EVP_PKEY| of the appropriate type. */ EVP_PKEY *ret = EVP_PKEY_new(); if (ret == NULL || !EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) { goto err; } /* Call into the type-specific SPKI decoding function. */ if (ret->ameth->pub_decode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); goto err; } if (!ret->ameth->pub_decode(ret, &algorithm, &key)) { goto err; } return ret; err: EVP_PKEY_free(ret); return NULL; }
EVP_PKEY *EVP_parse_private_key(CBS *cbs) { /* Parse the PrivateKeyInfo. */ CBS pkcs8, algorithm, oid, key; uint64_t version; if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) || !CBS_get_asn1_uint64(&pkcs8, &version) || version != 0 || !CBS_get_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || !CBS_get_asn1(&pkcs8, &key, CBS_ASN1_OCTETSTRING)) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); return NULL; } /* A PrivateKeyInfo ends with a SET of Attributes which we ignore. */ /* Set up an |EVP_PKEY| of the appropriate type. */ EVP_PKEY *ret = EVP_PKEY_new(); if (ret == NULL || !EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) { goto err; } /* Call into the type-specific PrivateKeyInfo decoding function. */ if (ret->ameth->priv_decode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); goto err; } if (!ret->ameth->priv_decode(ret, &algorithm, &key)) { goto err; } return ret; err: EVP_PKEY_free(ret); return NULL; }
/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a * PKCS#12 structure. */ static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, struct pkcs12_context *ctx) { CBS content_type, wrapped_contents, contents, content_infos; int nid, ret = 0; if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) || !CBS_get_asn1(content_info, &wrapped_contents, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA); goto err; } nid = OBJ_cbs2nid(&content_type); if (nid == NID_pkcs7_encrypted) { /* See https://tools.ietf.org/html/rfc2315#section-13. * * PKCS#7 encrypted data inside a PKCS#12 structure is generally an * encrypted certificate bag and it's generally encrypted with 40-bit * RC2-CBC. */ CBS version_bytes, eci, contents_type, ai, encrypted_contents; X509_ALGOR *algor = NULL; const uint8_t *inp; uint8_t *out; size_t out_len; if (!CBS_get_asn1(&wrapped_contents, &contents, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&contents, &version_bytes, CBS_ASN1_INTEGER) || /* EncryptedContentInfo, see * https://tools.ietf.org/html/rfc2315#section-10.1 */ !CBS_get_asn1(&contents, &eci, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) || /* AlgorithmIdentifier, see * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */ !CBS_get_asn1_element(&eci, &ai, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&eci, &encrypted_contents, CBS_ASN1_CONTEXT_SPECIFIC | 0)) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); goto err; } if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); goto err; } inp = CBS_data(&ai); algor = d2i_X509_ALGOR(NULL, &inp, CBS_len(&ai)); if (algor == NULL) { goto err; } if (inp != CBS_data(&ai) + CBS_len(&ai)) { X509_ALGOR_free(algor); OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); goto err; } if (!pbe_crypt(algor, ctx->password, ctx->password_len, CBS_data(&encrypted_contents), CBS_len(&encrypted_contents), &out, &out_len, 0 /* decrypt */)) { X509_ALGOR_free(algor); goto err; } X509_ALGOR_free(algor); CBS_init(&content_infos, out, out_len); ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx); OPENSSL_free(out); } else if (nid == NID_pkcs7_data) { CBS octet_string_contents; if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents, CBS_ASN1_OCTETSTRING)) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); goto err; } ret = PKCS12_handle_content_infos(&octet_string_contents, depth + 1, ctx); } else if (nid == NID_pkcs8ShroudedKeyBag) { /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section * 4.2.2. */ const uint8_t *inp = CBS_data(&wrapped_contents); PKCS8_PRIV_KEY_INFO *pki = NULL; X509_SIG *encrypted = NULL; if (*ctx->out_key) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12); goto err; } /* encrypted isn't actually an X.509 signature, but it has the same * structure as one and so |X509_SIG| is reused to store it. */ encrypted = d2i_X509_SIG(NULL, &inp, CBS_len(&wrapped_contents)); if (encrypted == NULL) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); goto err; } if (inp != CBS_data(&wrapped_contents) + CBS_len(&wrapped_contents)) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); X509_SIG_free(encrypted); goto err; } pki = PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len); X509_SIG_free(encrypted); if (pki == NULL) { goto err; } *ctx->out_key = EVP_PKCS82PKEY(pki); PKCS8_PRIV_KEY_INFO_free(pki); if (ctx->out_key == NULL) { goto err; } ret = 1; } else if (nid == NID_certBag) { CBS cert_bag, cert_type, wrapped_cert, cert; if (!CBS_get_asn1(&wrapped_contents, &cert_bag, CBS_ASN1_SEQUENCE) || !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) || !CBS_get_asn1(&cert_bag, &wrapped_cert, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); goto err; } if (OBJ_cbs2nid(&cert_type) == NID_x509Certificate) { const uint8_t *inp = CBS_data(&cert); X509 *x509 = d2i_X509(NULL, &inp, CBS_len(&cert)); if (!x509) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); goto err; } if (inp != CBS_data(&cert) + CBS_len(&cert)) { OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info, PKCS8_R_BAD_PKCS12_DATA); X509_free(x509); goto err; } if (0 == sk_X509_push(ctx->out_certs, x509)) { X509_free(x509); goto err; } } ret = 1; } else { /* Unknown element type - ignore it. */ ret = 1; } err: return ret; }