Two more private key checks.
- When a PKCS#8 has both seed and key cross check the implicit rejection value |z| - When an import (EVP_PKEY_fromdata call) provides both a private and public key, fail if the redundant public key does not match the copy in the private key. Reviewed-by: Shane Lontis <shane.lontis@oracle.com> Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26656)
This commit is contained in:
parent
2ea9903c16
commit
b3dd681f07
4 changed files with 43 additions and 14 deletions
|
@ -146,11 +146,12 @@ This format represents B<PKCS#8> objects in which both the FIPS 203 64-byte
|
|||
B<(d, z)> seed and the decapsulation key B<dk> are present in the private key
|
||||
as part of the DER encoding of the ASN.1 sequence:
|
||||
|
||||
PrivateKey ::= SEQUENCE {
|
||||
seed OCTET STRING OPTIONAL,
|
||||
expandedKey [1] IMPLICIT OCTET STRING OPTIONAL }
|
||||
(WITH COMPONENTS {..., seed PRESENT } |
|
||||
WITH COMPONENTS {..., expandedKey PRESENT })
|
||||
ML-KEM-PrivateKey ::= CHOICE {
|
||||
seed [0] IMPLICIT OCTET STRING (SIZE (64)),
|
||||
expandedKey OCTET STRING (SIZE (1632 | 2400 | 3168)),
|
||||
both SEQUENCE {
|
||||
seed OCTET STRING (SIZE (64)),
|
||||
expandedKey OCTET STRING (SIZE (1632 | 2400 | 3168)) } }
|
||||
|
||||
If the C<seed-priv> format is not included in the list, this format will not be
|
||||
recognised on input.
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
* corresponding to the "either or both" variants of:
|
||||
*
|
||||
* ML-KEM-PrivateKey ::= CHOICE {
|
||||
* seed [0] IMPLICIT OCTET STRING SIZE (64),
|
||||
* expandedKey OCTET STRING SIZE (1632 | 2400 | 3168)
|
||||
* seed [0] IMPLICIT OCTET STRING (SIZE (64)),
|
||||
* expandedKey OCTET STRING (SIZE (1632 | 2400 | 3168)),
|
||||
* both SEQUENCE {
|
||||
* seed OCTET STRING SIZE (64),
|
||||
* expandedKey OCTET STRING SIZE (1632 | 2400 | 3168) } }
|
||||
* seed OCTET STRING (SIZE (64)),
|
||||
* expandedKey OCTET STRING (SIZE (1632 | 2400 | 3168)) } }
|
||||
*
|
||||
* one more for a historical OQS encoding:
|
||||
*
|
||||
|
|
|
@ -36,11 +36,11 @@ typedef struct {
|
|||
* corresponding to the "either or both" variants of:
|
||||
*
|
||||
* ML-KEM-PrivateKey ::= CHOICE {
|
||||
* seed [0] IMPLICIT OCTET STRING SIZE (64),
|
||||
* expandedKey OCTET STRING SIZE (1632 | 2400 | 3168)
|
||||
* seed [0] IMPLICIT OCTET STRING (SIZE (64)),
|
||||
* expandedKey OCTET STRING (SIZE (1632 | 2400 | 3168)),
|
||||
* both SEQUENCE {
|
||||
* seed OCTET STRING SIZE (64),
|
||||
* expandedKey OCTET STRING SIZE (1632 | 2400 | 3168) } }
|
||||
* seed OCTET STRING (SIZE (64)),
|
||||
* expandedKey OCTET STRING SIZE ((1632 | 2400 | 3168)) } }
|
||||
*
|
||||
* one more for a historical OQS encoding:
|
||||
*
|
||||
|
|
|
@ -318,7 +318,7 @@ static int ml_kem_key_fromdata(ML_KEM_KEY *key,
|
|||
{
|
||||
const OSSL_PARAM *p = NULL;
|
||||
const void *pubenc = NULL, *prvenc = NULL, *seedenc = NULL;
|
||||
size_t publen = 0, prvlen = 0, seedlen = 0;
|
||||
size_t publen = 0, prvlen = 0, seedlen = 0, puboff;
|
||||
const ML_KEM_VINFO *v;
|
||||
|
||||
/* Invalid attempt to mutate a key, what is the right error to report? */
|
||||
|
@ -370,6 +370,18 @@ static int ml_kem_key_fromdata(ML_KEM_KEY *key,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Check any explicit public key against embedded value in private key */
|
||||
if (publen > 0 && prvlen > 0) {
|
||||
/* point to the ek offset in the DKpke||ek||H(ek)||z */
|
||||
puboff = prvlen - ML_KEM_RANDOM_BYTES - ML_KEM_PKHASH_BYTES - publen;
|
||||
if (memcmp(pubenc, (unsigned char *)prvenc + puboff, publen) != 0) {
|
||||
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
|
||||
"explicit %s public key does not match private",
|
||||
v->algorithm_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (seedlen != 0 && (prvlen == 0 || key->prefer_seed))
|
||||
return ossl_ml_kem_set_seed(seedenc, seedlen, key)
|
||||
&& ossl_ml_kem_genkey(NULL, 0, key);
|
||||
|
@ -427,6 +439,8 @@ void *ml_kem_load(const void *reference, size_t reference_sz)
|
|||
{
|
||||
ML_KEM_KEY *key = NULL;
|
||||
uint8_t *encoded_dk;
|
||||
uint8_t seed[ML_KEM_SEED_BYTES];
|
||||
size_t zlen = ML_KEM_RANDOM_BYTES;
|
||||
|
||||
if (ossl_prov_is_running() && reference_sz == sizeof(key)) {
|
||||
/* The contents of the reference is the address to our object */
|
||||
|
@ -435,6 +449,20 @@ void *ml_kem_load(const void *reference, size_t reference_sz)
|
|||
key->encoded_dk = NULL;
|
||||
/* We grabbed, so we detach it */
|
||||
*(ML_KEM_KEY **)reference = NULL;
|
||||
/*
|
||||
* Reject |z| mismatch between seed and key, the seed buffer holds |z|
|
||||
* followed by |d|.
|
||||
*/
|
||||
if (encoded_dk != NULL
|
||||
&& ossl_ml_kem_encode_seed(seed, sizeof(seed), key)
|
||||
&& memcmp(seed + sizeof(seed) - zlen,
|
||||
encoded_dk + key->vinfo->prvkey_bytes - zlen,
|
||||
zlen) != 0) {
|
||||
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
|
||||
"private %s key implicit rejection secret does"
|
||||
" not match seed", key->vinfo->algorithm_name);
|
||||
goto err;
|
||||
}
|
||||
/* Generate the key now, if it holds only a stashed seed. */
|
||||
if (ossl_ml_kem_have_seed(key) &&
|
||||
(encoded_dk == NULL || key->prefer_seed)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue