Skip to content

Commit fb691fa

Browse files
authored
Merge pull request #8947 from SparkiDev/mldsa_openssl_der
ML-DSA/Dilithium: support OpenSSL format
2 parents d8caa84 + 519d143 commit fb691fa

File tree

2 files changed

+74
-4
lines changed

2 files changed

+74
-4
lines changed

wolfcrypt/src/asn.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36869,7 +36869,8 @@ static const ASNItem edKeyASN[] = {
3686936869
/* privateKey */
3687036870
/* PKEY */ { 1, ASN_OCTET_STRING, 0, 1, 0 },
3687136871
/* CurvePrivateKey */
36872-
/* PKEY_CURVEPKEY */ { 2, ASN_OCTET_STRING, 0, 0, 0 },
36872+
/* PKEY_CURVEPKEY */ { 2, ASN_OCTET_STRING, 0, 0, 2 },
36873+
/* PKEY_MLDSASEQ */ { 2, ASN_SEQUENCE, 1, 0, 2 },
3687336874
/* attributes */
3687436875
/* ATTRS */ { 1, ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_ATTRS, 1, 1, 1 },
3687536876
/* publicKey */
@@ -36882,6 +36883,7 @@ enum {
3688236883
EDKEYASN_IDX_PKEYALGO_OID,
3688336884
EDKEYASN_IDX_PKEY,
3688436885
EDKEYASN_IDX_PKEY_CURVEPKEY,
36886+
EDKEYASN_IDX_PKEY_MLDSASEQ,
3688536887
EDKEYASN_IDX_ATTRS,
3688636888
EDKEYASN_IDX_PUBKEY
3688736889
};
@@ -36947,8 +36949,15 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
3694736949
if (GetOctetString(input, inOutIdx, &length, inSz) < 0)
3694836950
return ASN_PARSE_E;
3694936951

36950-
if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0)
36951-
return ASN_PARSE_E;
36952+
if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) {
36953+
if (oid != ML_DSA_LEVEL2k && oid != ML_DSA_LEVEL3k &&
36954+
oid != ML_DSA_LEVEL5k) {
36955+
return ASN_PARSE_E;
36956+
}
36957+
if (GetSequence(input, inOutIdx, &privSz, inSz) < 0) {
36958+
return ASN_PARSE_E;
36959+
}
36960+
}
3695236961

3695336962
priv = input + *inOutIdx;
3695436963
*inOutIdx += (word32)privSz;
@@ -37026,11 +37035,24 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
3702637035
(int)dataASN[EDKEYASN_IDX_PKEYALGO_OID].data.oid.sum;
3702737036
}
3702837037
}
37029-
if (ret == 0) {
37038+
if (ret == 0 && dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length != 0) {
3703037039
/* Import private value. */
3703137040
*privKeyLen = dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length;
3703237041
*privKey = dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY].data.ref.data;
3703337042
}
37043+
else if (ret == 0 &&
37044+
dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].data.ref.length != 0) {
37045+
if (*inOutKeyType != ML_DSA_LEVEL2k &&
37046+
*inOutKeyType != ML_DSA_LEVEL3k &&
37047+
*inOutKeyType != ML_DSA_LEVEL5k) {
37048+
ret = ASN_PARSE_E;
37049+
}
37050+
else {
37051+
/* Import private value. */
37052+
*privKeyLen = dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].data.ref.length;
37053+
*privKey = dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].data.ref.data;
37054+
}
37055+
}
3703437056
if ((ret == 0) && dataASN[EDKEYASN_IDX_PUBKEY].tag == 0) {
3703537057
/* Set public length to 0 as not seen. */
3703637058
if (pubKeyLen != NULL)
@@ -37454,6 +37476,8 @@ int SetAsymKeyDer(const byte* privKey, word32 privKeyLen,
3745437476
SetASN_Buffer(&dataASN[EDKEYASN_IDX_PKEY_CURVEPKEY], NULL, privKeyLen);
3745537477
/* Don't write out attributes. */
3745637478
dataASN[EDKEYASN_IDX_ATTRS].noOut = 1;
37479+
/* Don't write sequence. */
37480+
dataASN[EDKEYASN_IDX_PKEY_MLDSASEQ].noOut = 1;
3745737481
if (pubKey) {
3745837482
/* Leave space for public key. */
3745937483
SetASN_Buffer(&dataASN[EDKEYASN_IDX_PUBKEY], NULL, pubKeyLen);

wolfcrypt/src/dilithium.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9660,6 +9660,31 @@ int dilithium_get_oid_sum(dilithium_key* key, int* keyFormat) {
96609660

96619661
#if defined(WOLFSSL_DILITHIUM_PRIVATE_KEY)
96629662

9663+
/* OCT <seed of 32 bytes> OCT <private key data of more than 256 bytes> */
9664+
#define ALT_PRIV_DER_PREFIX (2 + 32 + 4)
9665+
/* SEQ [ OCT <seed of 32 bytes> OCT <private key data> ] */
9666+
#define ALT_PRIV_DER_PREFIX_SEQ (4 + 2 + 32 + 4)
9667+
9668+
/* Get the private only key size for the ML-DSA level/parameter id.
9669+
*
9670+
* @param [in] level Level of the ML-DSA key.
9671+
* @return Private key only encoding size for key level on success.
9672+
* @return 0 on failure.
9673+
*/
9674+
static word32 dilithium_get_priv_size(int level)
9675+
{
9676+
switch (level) {
9677+
case WC_ML_DSA_44:
9678+
return ML_DSA_LEVEL2_KEY_SIZE;
9679+
case WC_ML_DSA_65:
9680+
return ML_DSA_LEVEL3_KEY_SIZE;
9681+
case WC_ML_DSA_87:
9682+
return ML_DSA_LEVEL5_KEY_SIZE;
9683+
default:
9684+
return 0;
9685+
}
9686+
}
9687+
96639688
/* Decode the DER encoded Dilithium key.
96649689
*
96659690
* @param [in] input Array holding DER encoded data.
@@ -9746,6 +9771,19 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
97469771
ret = wc_dilithium_set_level(key, (byte)ret);
97479772
}
97489773
}
9774+
/* If it failed to decode try alternative DER encoding. */
9775+
else if (ret != 0) {
9776+
word32 levelSize = dilithium_get_priv_size(key->level);
9777+
privKey = input + *inOutIdx;
9778+
privKeyLen = inSz - *inOutIdx;
9779+
9780+
/* Check for an alternative DER encoding. */
9781+
if (privKeyLen == ALT_PRIV_DER_PREFIX_SEQ + levelSize) {
9782+
privKey += ALT_PRIV_DER_PREFIX_SEQ;
9783+
privKeyLen -= ALT_PRIV_DER_PREFIX_SEQ;
9784+
ret = 0;
9785+
}
9786+
}
97499787
}
97509788
if ((ret == 0) && (pubKey == NULL) && (pubKeyLen == 0)) {
97519789
/* Check if the public key is included in the private key. */
@@ -9791,6 +9829,14 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
97919829
pubKeyLen = ML_DSA_LEVEL5_PUB_KEY_SIZE;
97929830
privKeyLen -= ML_DSA_LEVEL5_PUB_KEY_SIZE;
97939831
}
9832+
else {
9833+
word32 levelSize = dilithium_get_priv_size(key->level);
9834+
9835+
if (privKeyLen == ALT_PRIV_DER_PREFIX + levelSize) {
9836+
privKey += ALT_PRIV_DER_PREFIX;
9837+
privKeyLen -= ALT_PRIV_DER_PREFIX;
9838+
}
9839+
}
97949840
}
97959841

97969842
if (ret == 0) {

0 commit comments

Comments
 (0)