forked from wolfSSL/wolfssl
- Add ability to obtain Dilithium security level (parameters) from a DER
encoded key based on the algorithm type OID - Add test coverage for decoding DER keys without level specified
This commit is contained in:
@ -9501,6 +9501,82 @@ int wc_dilithium_export_key(dilithium_key* key, byte* priv, word32 *privSz,
|
|||||||
|
|
||||||
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
|
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
|
||||||
|
|
||||||
|
/* Maps ASN.1 OID to wolfCrypt security level macros */
|
||||||
|
static int mapOidToSecLevel(word32 oid)
|
||||||
|
{
|
||||||
|
switch (oid) {
|
||||||
|
case ML_DSA_LEVEL2k:
|
||||||
|
return WC_ML_DSA_44;
|
||||||
|
case ML_DSA_LEVEL3k:
|
||||||
|
return WC_ML_DSA_65;
|
||||||
|
case ML_DSA_LEVEL5k:
|
||||||
|
return WC_ML_DSA_87;
|
||||||
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
||||||
|
case DILITHIUM_LEVEL2k:
|
||||||
|
return WC_ML_DSA_44_DRAFT;
|
||||||
|
case DILITHIUM_LEVEL3k:
|
||||||
|
return WC_ML_DSA_65_DRAFT;
|
||||||
|
case DILITHIUM_LEVEL5k:
|
||||||
|
return WC_ML_DSA_87_DRAFT;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return ASN_UNKNOWN_OID_E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get security level from DER encoded key. Returns a positive security level
|
||||||
|
* (e.g. WC_ML_DSA_44, etc.) on success, or a negative value on error.
|
||||||
|
*
|
||||||
|
* Expected ASN.1 Structure:
|
||||||
|
*
|
||||||
|
* SEQUENCE { -- Outer wrapper
|
||||||
|
* version INTEGER, -- Version number (usually 0)
|
||||||
|
* algorithm SEQUENCE { -- AlgorithmIdentifier
|
||||||
|
* algorithm OBJECT IDENTIFIER -- OID identifying Dilithium variant
|
||||||
|
* }
|
||||||
|
* -- Note: Remaining key data after algorithm is ignored for this function
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static int getSecLevelFromDer(const byte* der, word32 derSz)
|
||||||
|
{
|
||||||
|
word32 idx = 0;
|
||||||
|
int seqSz, algSeqSz;
|
||||||
|
int ret;
|
||||||
|
word32 oid = 0;
|
||||||
|
int version;
|
||||||
|
|
||||||
|
if (der == NULL || derSz == 0) {
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse outer SEQUENCE wrapper and get its size
|
||||||
|
* Advances idx past the SEQUENCE header */
|
||||||
|
if ((ret = GetSequence(der, &idx, &seqSz, derSz)) < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse and skip over version INTEGER
|
||||||
|
* Advances idx past the version field */
|
||||||
|
if ((ret = GetMyVersion(der, &idx, &version, derSz)) < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse AlgorithmIdentifier SEQUENCE and get its size
|
||||||
|
* Advances idx past the SEQUENCE header */
|
||||||
|
if ((ret = GetSequence(der, &idx, &algSeqSz, derSz)) < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse OID value from AlgorithmIdentifier
|
||||||
|
* Advances idx past the OID, stores numeric OID value
|
||||||
|
* oidSigType indicates this is a signature algorithm OID */
|
||||||
|
if ((ret = GetObjectId(der, &idx, &oid, oidSigType, derSz - idx)) < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapOidToSecLevel(oid);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(WOLFSSL_DILITHIUM_PRIVATE_KEY)
|
#if defined(WOLFSSL_DILITHIUM_PRIVATE_KEY)
|
||||||
|
|
||||||
/* Decode the DER encoded Dilithium key.
|
/* Decode the DER encoded Dilithium key.
|
||||||
@ -9508,11 +9584,18 @@ int wc_dilithium_export_key(dilithium_key* key, byte* priv, word32 *privSz,
|
|||||||
* @param [in] input Array holding DER encoded data.
|
* @param [in] input Array holding DER encoded data.
|
||||||
* @param [in, out] inOutIdx On in, index into array of start of DER encoding.
|
* @param [in, out] inOutIdx On in, index into array of start of DER encoding.
|
||||||
* On out, index into array after DER encoding.
|
* On out, index into array after DER encoding.
|
||||||
* @param [in, out] key Dilithium key to store key.
|
* @param [in, out] key Dilithium key structure to hold the decoded key.
|
||||||
* @param [in] inSz Total size of data in array.
|
* If the security level is set in the key structure on
|
||||||
|
* input, the DER key will be decoded as such and will
|
||||||
|
* fail if there is a mismatch. If the level and
|
||||||
|
* parameters are not set in the key structure on
|
||||||
|
* input, the level will be detected from the DER
|
||||||
|
* file based on the algorithm OID, appropriately
|
||||||
|
* decoded, then updated in the key structure on
|
||||||
|
* output.
|
||||||
|
* @param [in] inSz Total size of the input DER buffer array.
|
||||||
* @return 0 on success.
|
* @return 0 on success.
|
||||||
* @return BAD_FUNC_ARG when input, inOutIdx or key is NULL or inSz is 0.
|
* @return BAD_FUNC_ARG when input, inOutIdx or key is NULL or inSz is 0.
|
||||||
* @return BAD_FUNC_ARG when level not set.
|
|
||||||
* @return Other negative on parse error.
|
* @return Other negative on parse error.
|
||||||
*/
|
*/
|
||||||
int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
|
int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
|
||||||
@ -9530,6 +9613,23 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
|
|||||||
ret = BAD_FUNC_ARG;
|
ret = BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If expected security level not set in key, detect it from DER */
|
||||||
|
if (key->level == 0 || key->params == NULL
|
||||||
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
||||||
|
|| key->params->level == 0)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
int level;
|
||||||
|
level = getSecLevelFromDer(input + *inOutIdx, inSz - *inOutIdx);
|
||||||
|
if (level < 0) {
|
||||||
|
ret = level;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Set params based on level parsed from DER*/
|
||||||
|
ret = wc_dilithium_set_level(key, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
/* Get OID sum for level. */
|
/* Get OID sum for level. */
|
||||||
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
||||||
@ -9756,7 +9856,15 @@ static int dilithium_check_type(const byte* input, word32* inOutIdx, byte type,
|
|||||||
* @param [in] input Array holding DER encoded data.
|
* @param [in] input Array holding DER encoded data.
|
||||||
* @param [in, out] inOutIdx On in, index into array of start of DER encoding.
|
* @param [in, out] inOutIdx On in, index into array of start of DER encoding.
|
||||||
* On out, index into array after DER encoding.
|
* On out, index into array after DER encoding.
|
||||||
* @param [in, out] key Dilithium key to store key.
|
* @param [in, out] key Dilithium key structure to hold the decoded key.
|
||||||
|
* If the security level is set in the key structure
|
||||||
|
* on input, the DER key will be decoded as such
|
||||||
|
* and will fail if there is a mismatch. If the level
|
||||||
|
* and parameters are not set in the key structure on
|
||||||
|
* input, the level will be detected from the DER file
|
||||||
|
* based on the algorithm OID, appropriately decoded,
|
||||||
|
* then updated in the key structure on output.
|
||||||
|
* updated in the key structure on output.
|
||||||
* @param [in] inSz Total size of data in array.
|
* @param [in] inSz Total size of data in array.
|
||||||
* @return 0 on success.
|
* @return 0 on success.
|
||||||
* @return BAD_FUNC_ARG when input, inOutIdx or key is NULL or inSz is 0.
|
* @return BAD_FUNC_ARG when input, inOutIdx or key is NULL or inSz is 0.
|
||||||
@ -9775,6 +9883,25 @@ int wc_Dilithium_PublicKeyDecode(const byte* input, word32* inOutIdx,
|
|||||||
ret = BAD_FUNC_ARG;
|
ret = BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(WOLFSSL_DILITHIUM_NO_ASN1)
|
||||||
|
/* If expected security level not set in key, detect it from DER */
|
||||||
|
if (key->level == 0 || key->params == NULL
|
||||||
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
||||||
|
|| key->params->level == 0)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
int level;
|
||||||
|
level = getSecLevelFromDer(input + *inOutIdx, inSz - *inOutIdx);
|
||||||
|
if (level < 0) {
|
||||||
|
ret = level;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Set params based on level parsed from DER*/
|
||||||
|
ret = wc_dilithium_set_level(key, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !WOLFSSL_DILITHIUM_NO_ASN1 */
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
/* Try to import the key directly. */
|
/* Try to import the key directly. */
|
||||||
ret = wc_dilithium_import_public(input, inSz, key);
|
ret = wc_dilithium_import_public(input, inSz, key);
|
||||||
|
@ -45669,6 +45669,112 @@ out:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Tests decoding a key from DER without the security level specified */
|
||||||
|
static wc_test_ret_t test_dilithium_decode_level(const byte* rawKey,
|
||||||
|
word32 rawKeySz,
|
||||||
|
int expectedLevel)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
dilithium_key key;
|
||||||
|
word32 idx;
|
||||||
|
byte* der;
|
||||||
|
word32 derSz;
|
||||||
|
|
||||||
|
/* DER encoding adds ~256 bytes of overhead to raw key */
|
||||||
|
const word32 estimatedDerSz = rawKeySz + 256;
|
||||||
|
|
||||||
|
/* Allocate DER buffer */
|
||||||
|
der = (byte*)XMALLOC(estimatedDerSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
if (der == NULL) {
|
||||||
|
return MEMORY_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize key */
|
||||||
|
ret = wc_dilithium_init(&key);
|
||||||
|
|
||||||
|
/* Import raw key, setting the security level */
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = wc_dilithium_set_level(&key, expectedLevel);
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = wc_dilithium_import_private(rawKey, rawKeySz, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Export raw key as DER */
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = wc_Dilithium_PrivateKeyToDer(&key, der, estimatedDerSz);
|
||||||
|
if (ret >= 0) {
|
||||||
|
derSz = ret;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free and reinit key to test fresh decode */
|
||||||
|
if (ret == 0) {
|
||||||
|
wc_dilithium_free(&key);
|
||||||
|
ret = wc_dilithium_init(&key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test decoding without setting security level - should auto-detect */
|
||||||
|
if (ret == 0) {
|
||||||
|
idx = 0;
|
||||||
|
ret = wc_Dilithium_PrivateKeyDecode(der, &idx, &key, derSz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify detected security level */
|
||||||
|
if (ret == 0 && key.level != expectedLevel) {
|
||||||
|
printf("Dilithium key decode failed to detect level.\n"
|
||||||
|
"\tExpected level=%d\n\tGot level=%d\n",
|
||||||
|
expectedLevel, key.level);
|
||||||
|
ret = WC_TEST_RET_ENC_NC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
wc_dilithium_free(&key);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test Dilithium private key decoding and security level detection */
|
||||||
|
static wc_test_ret_t dilithium_decode_test(void)
|
||||||
|
{
|
||||||
|
wc_test_ret_t ret;
|
||||||
|
const byte* privKey;
|
||||||
|
word32 privKeySz;
|
||||||
|
|
||||||
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
||||||
|
/* Test ML-DSA-44 */
|
||||||
|
privKey = bench_dilithium_level2_key;
|
||||||
|
privKeySz = sizeof_bench_dilithium_level2_key;
|
||||||
|
ret = test_dilithium_decode_level(privKey, privKeySz, WC_ML_DSA_44);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_NO_ML_DSA_44 */
|
||||||
|
|
||||||
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
||||||
|
/* Test ML-DSA-65 */
|
||||||
|
privKey = bench_dilithium_level3_key;
|
||||||
|
privKeySz = sizeof_bench_dilithium_level3_key;
|
||||||
|
ret = test_dilithium_decode_level(privKey, privKeySz, WC_ML_DSA_65);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_NO_ML_DSA_65 */
|
||||||
|
|
||||||
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
||||||
|
/* Test ML-DSA-87 */
|
||||||
|
privKey = bench_dilithium_level5_key;
|
||||||
|
privKeySz = sizeof_bench_dilithium_level5_key;
|
||||||
|
ret = test_dilithium_decode_level(privKey, privKeySz, WC_ML_DSA_87);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_NO_ML_DSA_87 */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dilithium_test(void)
|
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dilithium_test(void)
|
||||||
{
|
{
|
||||||
wc_test_ret_t ret;
|
wc_test_ret_t ret;
|
||||||
@ -45727,6 +45833,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dilithium_test(void)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ret = dilithium_decode_test();
|
||||||
|
if (ret != 0) {
|
||||||
|
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
|
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
|
||||||
!defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
!defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
||||||
out:
|
out:
|
||||||
|
Reference in New Issue
Block a user