This isn't strictly necessary for Chromium yet, but we already have a decoupled version of hash algorithm parsing available. For now, don't export it but eventually we may wish to use it for OCSP. BUG=54 Change-Id: If460d38d48bd47a2b4a853779f210c0cf7ee236b Reviewed-on: https://boringssl-review.googlesource.com/14211 Reviewed-by: Steven Valdez <svaldez@chromium.org> Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: Steven Valdez <svaldez@chromium.org> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>kris/onging/CECPQ3_patch15
@@ -60,6 +60,7 @@ | |||||
#include <string.h> | #include <string.h> | ||||
#include <openssl/asn1.h> | #include <openssl/asn1.h> | ||||
#include <openssl/bytestring.h> | |||||
#include <openssl/md4.h> | #include <openssl/md4.h> | ||||
#include <openssl/md5.h> | #include <openssl/md5.h> | ||||
#include <openssl/nid.h> | #include <openssl/nid.h> | ||||
@@ -328,20 +329,58 @@ static const struct { | |||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, EVP_sha224 }, | { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, EVP_sha224 }, | ||||
}; | }; | ||||
static const EVP_MD *cbs_to_md(const CBS *cbs) { | |||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) { | |||||
if (CBS_len(cbs) == kMDOIDs[i].oid_len && | |||||
OPENSSL_memcmp(CBS_data(cbs), kMDOIDs[i].oid, kMDOIDs[i].oid_len) == | |||||
0) { | |||||
return kMDOIDs[i].md_func(); | |||||
} | |||||
} | |||||
return NULL; | |||||
} | |||||
const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj) { | const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj) { | ||||
/* Handle objects with no corresponding OID. */ | /* Handle objects with no corresponding OID. */ | ||||
if (obj->nid != NID_undef) { | if (obj->nid != NID_undef) { | ||||
return EVP_get_digestbynid(obj->nid); | return EVP_get_digestbynid(obj->nid); | ||||
} | } | ||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) { | |||||
if (obj->length == kMDOIDs[i].oid_len && | |||||
memcmp(obj->data, kMDOIDs[i].oid, obj->length) == 0) { | |||||
return kMDOIDs[i].md_func(); | |||||
CBS cbs; | |||||
CBS_init(&cbs, obj->data, obj->length); | |||||
return cbs_to_md(&cbs); | |||||
} | |||||
const EVP_MD *EVP_parse_digest_algorithm(CBS *cbs) { | |||||
CBS algorithm, oid; | |||||
if (!CBS_get_asn1(cbs, &algorithm, CBS_ASN1_SEQUENCE) || | |||||
!CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT)) { | |||||
OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_DECODE_ERROR); | |||||
return NULL; | |||||
} | |||||
const EVP_MD *ret = cbs_to_md(&oid); | |||||
if (ret == NULL) { | |||||
OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_UNKNOWN_HASH); | |||||
return NULL; | |||||
} | |||||
/* The parameters, if present, must be NULL. Historically, whether the NULL | |||||
* was included or omitted was not well-specified. When parsing an | |||||
* AlgorithmIdentifier, we allow both. (Note this code is not used when | |||||
* verifying RSASSA-PKCS1-v1_5 signatures.) */ | |||||
if (CBS_len(&algorithm) > 0) { | |||||
CBS param; | |||||
if (!CBS_get_asn1(&algorithm, ¶m, CBS_ASN1_NULL) || | |||||
CBS_len(¶m) != 0 || | |||||
CBS_len(&algorithm) != 0) { | |||||
OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_DECODE_ERROR); | |||||
return NULL; | |||||
} | } | ||||
} | } | ||||
return NULL; | |||||
return ret; | |||||
} | } | ||||
const EVP_MD *EVP_get_digestbyname(const char *name) { | const EVP_MD *EVP_get_digestbyname(const char *name) { | ||||
@@ -104,6 +104,8 @@ struct evp_md_pctx_ops { | |||||
EVP_PKEY_CTX* (*dup) (EVP_PKEY_CTX *pctx); | EVP_PKEY_CTX* (*dup) (EVP_PKEY_CTX *pctx); | ||||
}; | }; | ||||
const EVP_MD *EVP_parse_digest_algorithm(CBS *cbs); | |||||
#if defined(__cplusplus) | #if defined(__cplusplus) | ||||
} /* extern C */ | } /* extern C */ | ||||
@@ -1 +1,3 @@ | |||||
DIGEST,101,DECODE_ERROR | |||||
DIGEST,100,INPUT_NOT_INITIALIZED | DIGEST,100,INPUT_NOT_INITIALIZED | ||||
DIGEST,102,UNKNOWN_HASH |
@@ -74,6 +74,7 @@ | |||||
#include "internal.h" | #include "internal.h" | ||||
#include "../internal.h" | #include "../internal.h" | ||||
#include "../bytestring/internal.h" | #include "../bytestring/internal.h" | ||||
#include "../digest/internal.h" | |||||
#define PKCS12_KEY_ID 1 | #define PKCS12_KEY_ID 1 | ||||
@@ -1032,25 +1033,25 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, | |||||
/* Verify the MAC. */ | /* Verify the MAC. */ | ||||
{ | { | ||||
CBS mac, hash_type_seq, hash_oid, salt, expected_mac; | |||||
uint64_t iterations; | |||||
int hash_nid; | |||||
const EVP_MD *md; | |||||
uint8_t hmac_key[EVP_MAX_MD_SIZE]; | |||||
uint8_t hmac[EVP_MAX_MD_SIZE]; | |||||
unsigned hmac_len; | |||||
CBS mac, salt, expected_mac; | |||||
if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE)) { | |||||
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); | |||||
goto err; | |||||
} | |||||
if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE) || | |||||
!CBS_get_asn1(&mac, &hash_type_seq, CBS_ASN1_SEQUENCE) || | |||||
!CBS_get_asn1(&hash_type_seq, &hash_oid, CBS_ASN1_OBJECT) || | |||||
!CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) || | |||||
const EVP_MD *md = EVP_parse_digest_algorithm(&mac); | |||||
if (md == NULL) { | |||||
goto err; | |||||
} | |||||
if (!CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) || | |||||
!CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) { | !CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) { | ||||
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); | OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); | ||||
goto err; | goto err; | ||||
} | } | ||||
/* The iteration count is optional and the default is one. */ | /* The iteration count is optional and the default is one. */ | ||||
iterations = 1; | |||||
uint64_t iterations = 1; | |||||
if (CBS_len(&mac_data) > 0) { | if (CBS_len(&mac_data) > 0) { | ||||
if (!CBS_get_asn1_uint64(&mac_data, &iterations) || | if (!CBS_get_asn1_uint64(&mac_data, &iterations) || | ||||
iterations > UINT_MAX) { | iterations > UINT_MAX) { | ||||
@@ -1059,19 +1060,15 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, | |||||
} | } | ||||
} | } | ||||
hash_nid = OBJ_cbs2nid(&hash_oid); | |||||
if (hash_nid == NID_undef || | |||||
(md = EVP_get_digestbynid(hash_nid)) == NULL) { | |||||
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_HASH); | |||||
goto err; | |||||
} | |||||
uint8_t hmac_key[EVP_MAX_MD_SIZE]; | |||||
if (!pkcs12_key_gen_raw(ctx.password, ctx.password_len, CBS_data(&salt), | if (!pkcs12_key_gen_raw(ctx.password, ctx.password_len, CBS_data(&salt), | ||||
CBS_len(&salt), PKCS12_MAC_ID, iterations, | CBS_len(&salt), PKCS12_MAC_ID, iterations, | ||||
EVP_MD_size(md), hmac_key, md)) { | EVP_MD_size(md), hmac_key, md)) { | ||||
goto err; | goto err; | ||||
} | } | ||||
uint8_t hmac[EVP_MAX_MD_SIZE]; | |||||
unsigned hmac_len; | |||||
if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes), | if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes), | ||||
CBS_len(&authsafes), hmac, &hmac_len)) { | CBS_len(&authsafes), hmac, &hmac_len)) { | ||||
goto err; | goto err; | ||||
@@ -283,5 +283,7 @@ using ScopedEVP_MD_CTX = | |||||
#endif | #endif | ||||
#define DIGEST_R_INPUT_NOT_INITIALIZED 100 | #define DIGEST_R_INPUT_NOT_INITIALIZED 100 | ||||
#define DIGEST_R_DECODE_ERROR 101 | |||||
#define DIGEST_R_UNKNOWN_HASH 102 | |||||
#endif /* OPENSSL_HEADER_DIGEST_H */ | #endif /* OPENSSL_HEADER_DIGEST_H */ |