diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index b186f3c0b..bf4ae6c13 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -36869,7 +36869,8 @@ static const ASNItem edKeyASN[] = { /* privateKey */ /* PKEY */ { 1, ASN_OCTET_STRING, 0, 1, 0 }, /* CurvePrivateKey */ -/* PKEY_CURVEPKEY */ { 2, ASN_OCTET_STRING, 0, 0, 0 }, +/* PKEY_CURVEPKEY */ { 2, ASN_OCTET_STRING, 0, 0, 2 }, +/* PKEY_MLDSASEQ */ { 2, ASN_SEQUENCE, 1, 0, 2 }, /* attributes */ /* ATTRS */ { 1, ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_ATTRS, 1, 1, 1 }, /* publicKey */ @@ -36882,6 +36883,7 @@ enum { EDKEYASN_IDX_PKEYALGO_OID, EDKEYASN_IDX_PKEY, EDKEYASN_IDX_PKEY_CURVEPKEY, + EDKEYASN_IDX_PKEY_MLDSASEQ, EDKEYASN_IDX_ATTRS, EDKEYASN_IDX_PUBKEY }; @@ -36947,8 +36949,15 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz, if (GetOctetString(input, inOutIdx, &length, inSz) < 0) return ASN_PARSE_E; - if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) - return ASN_PARSE_E; + if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) { + if (oid != ML_DSA_LEVEL2k && oid != ML_DSA_LEVEL3k && + oid != ML_DSA_LEVEL5k) { + return ASN_PARSE_E; + } + if (GetSequence(input, inOutIdx, &privSz, inSz) < 0) { + return ASN_PARSE_E; + } + } priv = input + *inOutIdx; *inOutIdx += (word32)privSz; @@ -37026,11 +37035,24 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz, (int)dataASN[EDKEYASN_IDX_PKEYALGO_OID].data.oid.sum; } } - if (ret == 0) { + if (ret == 0 && dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length != 0) { /* Import private value. */ *privKeyLen = dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length; *privKey = dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY].data.ref.data; } + else if (ret == 0 && + dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].data.ref.length != 0) { + if (*inOutKeyType != ML_DSA_LEVEL2k && + *inOutKeyType != ML_DSA_LEVEL3k && + *inOutKeyType != ML_DSA_LEVEL5k) { + ret = ASN_PARSE_E; + } + else { + /* Import private value. */ + *privKeyLen = dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].data.ref.length; + *privKey = dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].data.ref.data; + } + } if ((ret == 0) && dataASN[EDKEYASN_IDX_PUBKEY].tag == 0) { /* Set public length to 0 as not seen. */ if (pubKeyLen != NULL) @@ -37454,6 +37476,8 @@ int SetAsymKeyDer(const byte* privKey, word32 privKeyLen, SetASN_Buffer(&dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY], NULL, privKeyLen); /* Don't write out attributes. */ dataASN[EDKEYASN_IDX_ATTRS].noOut = 1; + /* Don't write sequence. */ + dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].noOut = 1; if (pubKey) { /* Leave space for public key. */ SetASN_Buffer(&dataASN[EDKEYASN_IDX_PUBKEY], NULL, pubKeyLen); diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index 6e3266412..65e301473 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -9660,6 +9660,31 @@ int dilithium_get_oid_sum(dilithium_key* key, int* keyFormat) { #if defined(WOLFSSL_DILITHIUM_PRIVATE_KEY) +/* OCT OCT */ +#define ALT_PRIV_DER_PREFIX (2 + 32 + 4) +/* SEQ [ OCT OCT ] */ +#define ALT_PRIV_DER_PREFIX_SEQ (4 + 2 + 32 + 4) + +/* Get the private only key size for the ML-DSA level/parameter id. + * + * @param [in] level Level of the ML-DSA key. + * @return Private key only encoding size for key level on success. + * @return 0 on failure. + */ +static word32 dilithium_get_priv_size(int level) +{ + switch (level) { + case WC_ML_DSA_44: + return ML_DSA_LEVEL2_KEY_SIZE; + case WC_ML_DSA_65: + return ML_DSA_LEVEL3_KEY_SIZE; + case WC_ML_DSA_87: + return ML_DSA_LEVEL5_KEY_SIZE; + default: + return 0; + } +} + /* Decode the DER encoded Dilithium key. * * @param [in] input Array holding DER encoded data. @@ -9746,6 +9771,19 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx, ret = wc_dilithium_set_level(key, (byte)ret); } } + /* If it failed to decode try alternative DER encoding. */ + else if (ret != 0) { + word32 levelSize = dilithium_get_priv_size(key->level); + privKey = input + *inOutIdx; + privKeyLen = inSz - *inOutIdx; + + /* Check for an alternative DER encoding. */ + if (privKeyLen == ALT_PRIV_DER_PREFIX_SEQ + levelSize) { + privKey += ALT_PRIV_DER_PREFIX_SEQ; + privKeyLen -= ALT_PRIV_DER_PREFIX_SEQ; + ret = 0; + } + } } if ((ret == 0) && (pubKey == NULL) && (pubKeyLen == 0)) { /* Check if the public key is included in the private key. */ @@ -9791,6 +9829,14 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx, pubKeyLen = ML_DSA_LEVEL5_PUB_KEY_SIZE; privKeyLen -= ML_DSA_LEVEL5_PUB_KEY_SIZE; } + else { + word32 levelSize = dilithium_get_priv_size(key->level); + + if (privKeyLen == ALT_PRIV_DER_PREFIX + levelSize) { + privKey += ALT_PRIV_DER_PREFIX; + privKeyLen -= ALT_PRIV_DER_PREFIX; + } + } } if (ret == 0) {