Merge pull request #8129 from bigbrett/curve25519-generic-keyparsing

Curve25519 generic keyparsing
pull/8138/head
Sean Parkinson 2024-11-01 09:04:50 +10:00 committed by GitHub
commit 24003b265a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 479 additions and 0 deletions

View File

@ -1557,6 +1557,219 @@ int wc_EccPublicKeyToDer(ecc_key* key, byte* output,
int wc_EccPublicKeyToDer_ex(ecc_key* key, byte* output, int wc_EccPublicKeyToDer_ex(ecc_key* key, byte* output,
word32 inLen, int with_AlgCurve, int comp); word32 inLen, int with_AlgCurve, int comp);
/*!
\ingroup ASN
\brief This function decodes a Curve25519 private key (only) from a DER
encoded buffer
\return 0 Success
\return BAD_FUNC_ARG Returns if input, inOutIdx or key is null
\return ASN_PARSE_E Returns if there is an error parsing the DER encoded
data
\return ECC_BAD_ARG_E Returns if the key length is not CURVE25519_KEYSIZE or
the DER key contains other issues despite being properly formatted.
\return BUFFER_E Returns if the input buffer is too small to contain a
valid DER encoded key.
\param input Pointer to buffer containing DER encoded private key
\param inOutIdx Index to start reading input buffer from. On output,
index is set to last position parsed of input buffer.
\param key Pointer to curve25519_key structure to store decoded key
\param inSz Size of input DER buffer
\sa wc_Curve25519KeyDecode
\sa wc_Curve25519PublicKeyDecode
_Example_
\code
byte der[] = { // DER encoded key };
word32 idx = 0;
curve25519_key key;
wc_curve25519_init(&key);
if (wc_Curve25519PrivateKeyDecode(der, &idx, &key, sizeof(der)) != 0) {
// Error decoding private key
}
\endcode
*/
int wc_Curve25519PrivateKeyDecode(const byte* input, word32* inOutIdx,
curve25519_key* key, word32 inSz);
/*!
\ingroup ASN
\brief This function decodes a Curve25519 public key (only) from a DER
encoded buffer.
\return 0 Success
\return BAD_FUNC_ARG Returns if input, inOutIdx or key is null
\return ASN_PARSE_E Returns if there is an error parsing the DER encoded
data
\return ECC_BAD_ARG_E Returns if the key length is not CURVE25519_KEYSIZE or
the DER key contains other issues despite being properly formatted.
\return BUFFER_E Returns if the input buffer is too small to contain a
valid DER encoded key.
\param input Pointer to buffer containing DER encoded public key
\param inOutIdx Index to start reading input buffer from. On output,
index is set to last position parsed of input buffer.
\param key Pointer to curve25519_key structure to store decoded key
\param inSz Size of input DER buffer
\sa wc_Curve25519KeyDecode
\sa wc_Curve25519PrivateKeyDecode
_Example_
\code
byte der[] = { // DER encoded key };
word32 idx = 0;
curve25519_key key;
wc_curve25519_init(&key);
if (wc_Curve25519PublicKeyDecode(der, &idx, &key, sizeof(der)) != 0) {
// Error decoding public key
}
\endcode
*/
int wc_Curve25519PublicKeyDecode(const byte* input, word32* inOutIdx,
curve25519_key* key, word32 inSz);
/*!
\ingroup ASN
\brief This function decodes a Curve25519 key from a DER encoded buffer. It
can decode either a private key, a public key, or both.
\return 0 Success
\return BAD_FUNC_ARG Returns if input, inOutIdx or key is null
\return ASN_PARSE_E Returns if there is an error parsing the DER encoded
data
\return ECC_BAD_ARG_E Returns if the key length is not CURVE25519_KEYSIZE or
the DER key contains other issues despite being properly formatted.
\return BUFFER_E Returns if the input buffer is too small to contain a
valid DER encoded key.
\param input Pointer to buffer containing DER encoded key
\param inOutIdx Index to start reading input buffer from. On output,
index is set to last position parsed of input buffer.
\param key Pointer to curve25519_key structure to store decoded key
\param inSz Size of input DER buffer
\sa wc_Curve25519PrivateKeyDecode
\sa wc_Curve25519PublicKeyDecode
_Example_
\code
byte der[] = { // DER encoded key };
word32 idx = 0;
curve25519_key key;
wc_curve25519_init(&key);
if (wc_Curve25519KeyDecode(der, &idx, &key, sizeof(der)) != 0) {
// Error decoding key
}
\endcode
*/
int wc_Curve25519KeyDecode(const byte* input, word32* inOutIdx,
curve25519_key* key, word32 inSz);
/*!
\ingroup ASN
\brief This function encodes a Curve25519 private key to DER format. If the
input key structure contains a public key, it will be ignored.
\return >0 Success, length of DER encoding
\return BAD_FUNC_ARG Returns if key or output is null
\return MEMORY_E Returns if there is an allocation failure
\return BUFFER_E Returns if output buffer is too small
\param key Pointer to curve25519_key structure containing private key to
encode
\param output Buffer to hold DER encoding
\param inLen Size of output buffer
\sa wc_Curve25519KeyToDer
\sa wc_Curve25519PublicKeyToDer
_Example_
\code
curve25519_key key;
wc_curve25519_init(&key);
...
int derSz = 128; // Some appropriate size for output DER
byte der[derSz];
wc_Curve25519PrivateKeyToDer(&key, der, derSz);
\endcode
*/
int wc_Curve25519PrivateKeyToDer(curve25519_key* key, byte* output,
word32 inLen);
/*!
\ingroup ASN
\brief This function encodes a Curve25519 public key to DER format. If the
input key structure contains a private key, it will be ignored.
\return >0 Success, length of DER encoding
\return BAD_FUNC_ARG Returns if key or output is null
\return MEMORY_E Returns if there is an allocation failure
\return BUFFER_E Returns if output buffer is too small
\param key Pointer to curve25519_key structure containing public key to
encode
\param output Buffer to hold DER encoding
\param inLen Size of output buffer
\param withAlg Whether to include algorithm identifier in the DER encoding
\sa wc_Curve25519KeyToDer
\sa wc_Curve25519PrivateKeyToDer
_Example_
\code
curve25519_key key;
wc_curve25519_init(&key);
...
int derSz = 128; // Some appropriate size for output DER
byte der[derSz];
wc_Curve25519PublicKeyToDer(&key, der, derSz, 1);
\endcode
*/
int wc_Curve25519PublicKeyToDer(curve25519_key* key, byte* output, word32 inLen,
int withAlg);
/*!
\ingroup ASN
\brief This function encodes a Curve25519 key to DER format. It can encode
either a private key, a public key, or both.
\return >0 Success, length of DER encoding
\return BAD_FUNC_ARG Returns if key or output is null
\return MEMORY_E Returns if there is an allocation failure
\return BUFFER_E Returns if output buffer is too small
\param key Pointer to curve25519_key structure containing key to encode
\param output Buffer to hold DER encoding
\param inLen Size of output buffer
\param withAlg Whether to include algorithm identifier in the DER encoding
\sa wc_Curve25519PrivateKeyToDer
\sa wc_Curve25519PublicKeyToDer
_Example_
\code
curve25519_key key;
wc_curve25519_init(&key);
...
int derSz = 128; // Some appropriate size for output DER
byte der[derSz];
wc_Curve25519KeyToDer(&key, der, derSz, 1);
\endcode
*/
int wc_Curve25519KeyToDer(curve25519_key* key, byte* output, word32 inLen,
int withAlg);
/*! /*!
\ingroup ASN \ingroup ASN

View File

@ -35661,6 +35661,55 @@ int wc_Curve25519PublicKeyDecode(const byte* input, word32* inOutIdx,
} }
return ret; return ret;
} }
/* Decode Curve25519 key from DER format - can handle private only,
* public only, or private+public key pairs.
* return 0 on success, negative on error */
int wc_Curve25519KeyDecode(const byte* input, word32* inOutIdx,
curve25519_key* key, word32 inSz)
{
int ret;
byte privKey[CURVE25519_KEYSIZE];
byte pubKey[CURVE25519_PUB_KEY_SIZE];
word32 privKeyLen = CURVE25519_KEYSIZE;
word32 pubKeyLen = CURVE25519_PUB_KEY_SIZE;
/* sanity check */
if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) {
return BAD_FUNC_ARG;
}
/* Try to decode as private key first (may include public) */
ret = DecodeAsymKey(input, inOutIdx, inSz, privKey, &privKeyLen,
pubKey, &pubKeyLen, X25519k);
if (ret == 0) {
/* Successfully decoded private key */
if (pubKeyLen > 0) {
/* Have both private and public */
ret = wc_curve25519_import_private_raw(privKey, privKeyLen,
pubKey, pubKeyLen, key);
}
else {
/* Private only */
ret = wc_curve25519_import_private(privKey, privKeyLen, key);
}
}
else {
/* Try decoding as public key */
*inOutIdx = 0; /* Reset index */
pubKeyLen = CURVE25519_KEYSIZE;
ret = DecodeAsymKeyPublic(input, inOutIdx, inSz,
pubKey, &pubKeyLen, X25519k);
if (ret == 0) {
/* Successfully decoded public key */
ret = wc_curve25519_import_public(pubKey, pubKeyLen, key);
}
}
return ret;
}
#endif /* HAVE_CURVE25519 && HAVE_ED25519_KEY_IMPORT */ #endif /* HAVE_CURVE25519 && HAVE_ED25519_KEY_IMPORT */
@ -35868,6 +35917,63 @@ int wc_Curve25519PublicKeyToDer(curve25519_key* key, byte* output, word32 inLen,
} }
return ret; return ret;
} }
/* Export Curve25519 key to DER format - handles private only, public only,
* or private+public key pairs based on what's set in the key structure.
* Returns length written on success, negative on error */
int wc_Curve25519KeyToDer(curve25519_key* key, byte* output, word32 inLen, int withAlg)
{
int ret;
byte privKey[CURVE25519_KEYSIZE];
byte pubKey[CURVE25519_PUB_KEY_SIZE];
word32 privKeyLen = CURVE25519_KEYSIZE;
word32 pubKeyLen = CURVE25519_PUB_KEY_SIZE;
if (key == NULL) {
return BAD_FUNC_ARG;
}
/* Check what we have in the key structure */
if (key->privSet) {
/* Export private key to buffer */
ret = wc_curve25519_export_private_raw(key, privKey, &privKeyLen);
if (ret != 0) {
return ret;
}
if (key->pubSet) {
/* Export public key if available */
ret = wc_curve25519_export_public(key, pubKey, &pubKeyLen);
if (ret != 0) {
return ret;
}
/* Export both private and public */
ret = SetAsymKeyDer(privKey, privKeyLen,
pubKey, pubKeyLen,
output, inLen, X25519k);
}
else {
/* Export private only */
ret = SetAsymKeyDer(privKey, privKeyLen,
NULL, 0,
output, inLen, X25519k);
}
}
else if (key->pubSet) {
/* Export public key only */
ret = wc_curve25519_export_public(key, pubKey, &pubKeyLen);
if (ret == 0) {
ret = SetAsymKeyDerPublic(pubKey, pubKeyLen,
output, inLen, X25519k, withAlg);
}
}
else {
/* Neither public nor private key is set */
ret = BAD_FUNC_ARG;
}
return ret;
}
#endif /* HAVE_CURVE25519 && HAVE_CURVE25519_KEY_EXPORT */ #endif /* HAVE_CURVE25519 && HAVE_CURVE25519_KEY_EXPORT */
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) #if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)

View File

@ -35043,6 +35043,162 @@ static wc_test_ret_t curve255519_der_test(void)
ret = WC_TEST_RET_ENC_NC; ret = WC_TEST_RET_ENC_NC;
} }
/* Test decode/encode of Curve25519 private key (only) using generic API */
if (ret == 0) {
/* clear key, since generic API will try to decode all fields */
XMEMSET(&key, 0, sizeof(key));
idx = 0;
ret = wc_Curve25519KeyDecode(kCurve25519PrivDer, &idx, &key,
(word32)sizeof(kCurve25519PrivDer));
if (ret < 0) {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
if (ret == 0) {
outputSz = (word32)sizeof(output);
ret = wc_Curve25519KeyToDer(&key, output, outputSz, 1);
if (ret >= 0) {
outputSz = (word32)ret;
ret = 0;
}
else {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
if (ret == 0 && (outputSz != (word32)sizeof(kCurve25519PrivDer) ||
XMEMCMP(output, kCurve25519PrivDer, outputSz) != 0)) {
ret = WC_TEST_RET_ENC_NC;
}
/* Test decode/encode of Curve25519 public key (only) using generic API */
if (ret == 0) {
/* clear key, since generic API will try to decode all fields */
XMEMSET(&key, 0, sizeof(key));
idx = 0;
ret = wc_Curve25519KeyDecode(kCurve25519PubDer, &idx, &key,
(word32)sizeof(kCurve25519PubDer));
if (ret < 0) {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
if (ret == 0) {
outputSz = (word32)sizeof(output);
ret = wc_Curve25519KeyToDer(&key, output, outputSz, 1);
if (ret >= 0) {
outputSz = (word32)ret;
ret = 0;
}
else {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
if (ret == 0 && (outputSz != (word32)sizeof(kCurve25519PubDer) ||
XMEMCMP(output, kCurve25519PubDer, outputSz) != 0)) {
ret = WC_TEST_RET_ENC_NC;
}
/* Test decode/encode key data containing both public and private fields */
if (ret == 0) {
XMEMSET(&key, 0 , sizeof(key));
/* Decode public key */
idx = 0;
ret = wc_Curve25519KeyDecode(kCurve25519PubDer, &idx, &key,
(word32)sizeof(kCurve25519PubDer));
if (ret < 0) {
ret = WC_TEST_RET_ENC_EC(ret);
}
if (ret == 0) {
/* Decode private key */
idx = 0;
ret = wc_Curve25519KeyDecode(kCurve25519PrivDer, &idx, &key,
(word32)sizeof(kCurve25519PrivDer));
if (ret < 0) {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
/* Both public and private flags should be set */
if ((ret == 0) && (!key.pubSet && !key.privSet)) {
ret = WC_TEST_RET_ENC_NC;
}
if (ret == 0) {
/* Export key to temporary DER */
outputSz = (word32)sizeof(output);
ret = wc_Curve25519KeyToDer(&key, output, outputSz, 1);
if (ret >= 0) {
outputSz = (word32)ret;
ret = 0;
}
else {
ret = WC_TEST_RET_ENC_EC(ret);
}
/* Re-import temporary DER */
if (ret == 0) {
idx = 0;
ret = wc_Curve25519KeyDecode(output, &idx, &key, sizeof(output));
if (ret < 0) {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
/* Ensure public and private keys survived combined keypair
* export/import by re-exporting DER for private and public keys,
* individually, and re-checking output against known good vectors.
* This is slightly circuitous but does test the functionality
* without requiring the addition of new test keys */
if (ret == 0) {
idx = 0;
ret = wc_Curve25519PrivateKeyDecode(kCurve25519PrivDer, &idx,
&key, (word32)sizeof(kCurve25519PrivDer));
if (ret < 0)
ret = WC_TEST_RET_ENC_EC(ret);
}
if (ret == 0) {
outputSz = (word32)sizeof(output);
ret = wc_Curve25519PrivateKeyToDer(&key, output, outputSz);
if (ret >= 0) {
outputSz = (word32)ret;
ret = 0;
}
else {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
if ((ret == 0) &&
(outputSz != (word32)sizeof(kCurve25519PrivDer) ||
XMEMCMP(output, kCurve25519PrivDer, outputSz) != 0)) {
ret = WC_TEST_RET_ENC_NC;
}
if (ret == 0) {
idx = 0;
ret = wc_Curve25519PublicKeyDecode(kCurve25519PubDer, &idx,
&key, (word32)sizeof(kCurve25519PubDer));
if (ret < 0)
ret = WC_TEST_RET_ENC_EC(ret);
}
if (ret == 0) {
outputSz = (word32)sizeof(output);
ret = wc_Curve25519PublicKeyToDer(&key, output, outputSz, 1);
if (ret >= 0) {
outputSz = (word32)ret;
ret = 0;
}
else {
ret = WC_TEST_RET_ENC_EC(ret);
}
}
if ((ret == 0) &&
(outputSz != (word32)sizeof(kCurve25519PubDer) ||
XMEMCMP(output, kCurve25519PubDer, outputSz) != 0)) {
ret = WC_TEST_RET_ENC_NC;
}
}
}
wc_curve25519_free(&key); wc_curve25519_free(&key);
return ret; return ret;

View File

@ -841,12 +841,16 @@ WOLFSSL_API int wc_Curve25519PrivateKeyDecode(
const byte* input, word32* inOutIdx, curve25519_key* key, word32 inSz); const byte* input, word32* inOutIdx, curve25519_key* key, word32 inSz);
WOLFSSL_API int wc_Curve25519PublicKeyDecode( WOLFSSL_API int wc_Curve25519PublicKeyDecode(
const byte* input, word32* inOutIdx, curve25519_key* key, word32 inSz); const byte* input, word32* inOutIdx, curve25519_key* key, word32 inSz);
WOLFSSL_API int wc_Curve25519KeyDecode(const byte *input, word32 *inOutIdx,
curve25519_key *key, word32 inSz);
#endif #endif
#ifdef HAVE_CURVE25519_KEY_EXPORT #ifdef HAVE_CURVE25519_KEY_EXPORT
WOLFSSL_API int wc_Curve25519PrivateKeyToDer( WOLFSSL_API int wc_Curve25519PrivateKeyToDer(
curve25519_key* key, byte* output, word32 inLen); curve25519_key* key, byte* output, word32 inLen);
WOLFSSL_API int wc_Curve25519PublicKeyToDer( WOLFSSL_API int wc_Curve25519PublicKeyToDer(
curve25519_key* key, byte* output, word32 inLen, int withAlg); curve25519_key* key, byte* output, word32 inLen, int withAlg);
WOLFSSL_API int wc_Curve25519KeyToDer(curve25519_key* key, byte* output,
word32 inLen, int withAlg);
#endif #endif
#endif /* HAVE_CURVE25519 */ #endif /* HAVE_CURVE25519 */