Skip to content

Commit

Permalink
- Move automatic OID detection from Dilithium code into ASN code
Browse files Browse the repository at this point in the history
  • Loading branch information
bigbrett committed Nov 13, 2024
1 parent 6b1b6ec commit f672105
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 134 deletions.
108 changes: 89 additions & 19 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -35307,9 +35307,10 @@ enum {
|| (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) \
|| defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS))

int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,

int DecodeAsymKey_Assign_ex(const byte* input, word32* inOutIdx, word32 inSz,
const byte** privKey, word32* privKeyLen,
const byte** pubKey, word32* pubKeyLen, int keyType)
const byte** pubKey, word32* pubKeyLen, int* inOutKeyType)
{
#ifndef WOLFSSL_ASN_TEMPLATE
word32 oid;
Expand Down Expand Up @@ -35337,14 +35338,24 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
return ASN_PARSE_E;
if (version != 0) {
WOLFSSL_MSG("Unrecognized version of ED25519 private key");
WOLFSSL_MSG("Unrecognized version of private key");
return ASN_PARSE_E;
}

if (GetAlgoId(input, inOutIdx, &oid, oidKeyType, inSz) < 0)
return ASN_PARSE_E;
if (oid != (word32)keyType)
return ASN_PARSE_E;

if (inOutKeyType != NULL) {
/* If user supplies ANONk (0) key type, we want to auto-detect from
* DER and copy it back to user */
if (*inOutKeyType == ANONk) {
*inOutKeyType = oid;
}
/* Otherwise strictly validate against the expected type */
else if (oid != (word32)*inOutKeyType) {
return ASN_PARSE_E;
}
}

if (GetOctetString(input, inOutIdx, &length, inSz) < 0)
return ASN_PARSE_E;
Expand Down Expand Up @@ -35394,10 +35405,21 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
return 0;
#else
if (ret == 0) {
/* Require OID. */
word32 oidSz;
const byte* oid = OidFromId((word32)keyType, oidKeyType, &oidSz);
GetASN_ExpBuffer(&dataASN[EDKEYASN_IDX_PKEYALGO_OID], oid, oidSz);
/* If user supplies an expected keyType (algorithm OID sum), attempt to
* process DER accordingly */
if (inOutKeyType != NULL && *inOutKeyType != 0) {
word32 oidSz;
/* Explicit OID check - use expected type */
const byte* oidDerBytes = OidFromId((word32)*inOutKeyType,
oidKeyType, &oidSz);
GetASN_ExpBuffer(&dataASN[EDKEYASN_IDX_PKEYALGO_OID], oidDerBytes,
oidSz);
}
else {
/* Auto-detect OID using template */
GetASN_OID(&dataASN[EDKEYASN_IDX_PKEYALGO_OID], oidKeyType);
}

/* Parse full private key. */
ret = GetASN_Items(edKeyASN, dataASN, edKeyASN_Length, 1, input,
inOutIdx, inSz);
Expand All @@ -35410,6 +35432,12 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
ret = ASN_PARSE_E;
}
}

/* Store detected OID if requested */
if (ret == 0 && inOutKeyType != NULL && *inOutKeyType == ANONk) {
*inOutKeyType =
(int)dataASN[EDKEYASN_IDX_PKEYALGO_OID].data.oid.sum;
}
}
if (ret == 0) {
/* Import private value. */
Expand All @@ -35434,6 +35462,15 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
#endif /* WOLFSSL_ASN_TEMPLATE */
}


int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
const byte** privKey, word32* privKeyLen,
const byte** pubKey, word32* pubKeyLen, int keyType)
{
return DecodeAsymKey_Assign_ex(input, inOutIdx, inSz, privKey, privKeyLen,
pubKey, pubKeyLen, &keyType);
}

int DecodeAsymKey(const byte* input, word32* inOutIdx, word32 inSz,
byte* privKey, word32* privKeyLen,
byte* pubKey, word32* pubKeyLen, int keyType)
Expand Down Expand Up @@ -35472,8 +35509,8 @@ int DecodeAsymKey(const byte* input, word32* inOutIdx, word32 inSz,
return ret;
}

int DecodeAsymKeyPublic_Assign(const byte* input, word32* inOutIdx, word32 inSz,
const byte** pubKey, word32* pubKeyLen, int keyType)
int DecodeAsymKeyPublic_Assign_ex(const byte* input, word32* inOutIdx, word32 inSz,
const byte** pubKey, word32* pubKeyLen, int *inOutKeyType)
{
int ret = 0;
#ifndef WOLFSSL_ASN_TEMPLATE
Expand All @@ -35498,8 +35535,18 @@ int DecodeAsymKeyPublic_Assign(const byte* input, word32* inOutIdx, word32 inSz,

if (GetObjectId(input, inOutIdx, &oid, oidKeyType, inSz) < 0)
return ASN_PARSE_E;
if (oid != (word32)keyType)
return ASN_PARSE_E;

if (inOutKeyType != NULL) {
/* If user supplies ANONk (0) key type, we want to auto-detect from
* DER and copy it back to user */
if (*inOutKeyType == ANONk) {
*inOutKeyType = oid;
}
/* Otherwise strictly validate against the expected type */
else if (oid != (word32)*inOutKeyType) {
return ASN_PARSE_E;
}
}

/* key header */
ret = CheckBitString(input, inOutIdx, &length, inSz, 1, NULL);
Expand All @@ -35519,19 +35566,34 @@ int DecodeAsymKeyPublic_Assign(const byte* input, word32* inOutIdx, word32 inSz,
CALLOC_ASNGETDATA(dataASN, publicKeyASN_Length, ret, NULL);

if (ret == 0) {
/* Require OID. */
word32 oidSz;
const byte* oid = OidFromId((word32)keyType, oidKeyType, &oidSz);

GetASN_ExpBuffer(&dataASN[PUBKEYASN_IDX_ALGOID_OID], oid, oidSz);
/* Decode Ed25519 private key. */
/* If user supplies an expected keyType (algorithm OID sum), attempt to
* process DER accordingly */
if (inOutKeyType != NULL && *inOutKeyType != ANONk) {
word32 oidSz;
/* Explicit OID check - use expected type */
const byte* oidDerBytes = OidFromId((word32)*inOutKeyType,
oidKeyType, &oidSz);
GetASN_ExpBuffer(&dataASN[PUBKEYASN_IDX_ALGOID_OID], oidDerBytes,
oidSz);
}
else {
/* Auto-detect OID using template */
GetASN_OID(&dataASN[PUBKEYASN_IDX_ALGOID_OID], oidKeyType);
}
/* Decode public key. */
ret = GetASN_Items(publicKeyASN, dataASN, publicKeyASN_Length, 1,
input, inOutIdx, inSz);
if (ret != 0)
ret = ASN_PARSE_E;
/* check that input buffer is exhausted */
if (*inOutIdx != inSz)
ret = ASN_PARSE_E;

/* Store detected OID if requested */
if (ret == 0 && inOutKeyType != NULL && *inOutKeyType == ANONk) {
*inOutKeyType =
(int)dataASN[PUBKEYASN_IDX_ALGOID_OID].data.oid.sum;
}
}
/* Check that the all the buffer was used. */
if ((ret == 0) &&
Expand All @@ -35546,6 +35608,14 @@ int DecodeAsymKeyPublic_Assign(const byte* input, word32* inOutIdx, word32 inSz,
FREE_ASNGETDATA(dataASN, NULL);
#endif /* WOLFSSL_ASN_TEMPLATE */
return ret;

}

int DecodeAsymKeyPublic_Assign(const byte* input, word32* inOutIdx, word32 inSz,
const byte** pubKey, word32* pubKeyLen, int keyType)
{
return DecodeAsymKeyPublic_Assign_ex(input, inOutIdx, inSz, pubKey,
pubKeyLen, &keyType);
}

int DecodeAsymKeyPublic(const byte* input, word32* inOutIdx, word32 inSz,
Expand Down
129 changes: 32 additions & 97 deletions wolfcrypt/src/dilithium.c
Original file line number Diff line number Diff line change
Expand Up @@ -9524,59 +9524,6 @@ static int mapOidToSecLevel(word32 oid)
}
}

/* 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)

/* Decode the DER encoded Dilithium key.
Expand Down Expand Up @@ -9613,23 +9560,6 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
ret = BAD_FUNC_ARG;
}

/* If expected security level not set in key, detect it from DER */
if (key->level == 0
#ifdef WOLFSSL_WC_DILITHIUM
|| key->params == NULL
#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) {
/* Get OID sum for level. */
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
Expand Down Expand Up @@ -9657,15 +9587,27 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
keytype = ML_DSA_LEVEL5k;
}
else {
/* Level not set. */
ret = BAD_FUNC_ARG;
/* Level not set by caller, decode from DER */
keytype = ANONk; /* 0, not a valid key type in this situation*/
}
}

if (ret == 0) {
/* Decode the asymmetric key and get out private and public key data. */
ret = DecodeAsymKey_Assign(input, inOutIdx, inSz, &privKey, &privKeyLen,
&pubKey, &pubKeyLen, keytype);
ret = DecodeAsymKey_Assign_ex(input, inOutIdx, inSz,
&privKey, &privKeyLen,
&pubKey, &pubKeyLen, &keytype);
if (ret == 0
#ifdef WOLFSSL_WC_DILITHIUM
&& key->params == NULL
#endif
) {
/* Set the security level based on the decoded key. */
ret = mapOidToSecLevel(keytype);
if (ret > 0) {
ret = wc_dilithium_set_level(key, ret);
}
}
}
if ((ret == 0) && (pubKey == NULL) && (pubKeyLen == 0)) {
/* Check if the public key is included in the private key. */
Expand Down Expand Up @@ -9883,25 +9825,6 @@ int wc_Dilithium_PublicKeyDecode(const byte* input, word32* inOutIdx,
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
#ifdef WOLFSSL_WC_DILITHIUM
|| key->params == NULL
#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) {
/* Try to import the key directly. */
ret = wc_dilithium_import_public(input, inSz, key);
Expand Down Expand Up @@ -9945,13 +9868,25 @@ int wc_Dilithium_PublicKeyDecode(const byte* input, word32* inOutIdx,
keytype = ML_DSA_LEVEL5k;
}
else {
/* Level not set. */
ret = BAD_FUNC_ARG;
/* Level not set by caller, decode from DER */
keytype = ANONk; /* 0, not a valid key type in this situation*/
}
if (ret == 0) {
/* Decode the asymmetric key and get out public key data. */
ret = DecodeAsymKeyPublic_Assign(input, inOutIdx, inSz, &pubKey,
&pubKeyLen, keytype);
ret = DecodeAsymKeyPublic_Assign_ex(input, inOutIdx, inSz,
&pubKey, &pubKeyLen,
&keytype);
if (ret == 0
#ifdef WOLFSSL_WC_DILITHIUM
&& key->params == NULL
#endif
) {
/* Set the security level based on the decoded key. */
ret = mapOidToSecLevel(keytype);
if (ret > 0) {
ret = wc_dilithium_set_level(key, ret);
}
}
}
#else
/* Get OID sum for level. */
Expand Down
Loading

0 comments on commit f672105

Please sign in to comment.