Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
430 changes: 380 additions & 50 deletions src/wh_client_crypto.c

Large diffs are not rendered by default.

148 changes: 129 additions & 19 deletions src/wh_server_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,19 @@ static int _HandleRsaKeyGen(whServerContext* ctx, uint16_t magic, int devId,
label_size, label);
}
WH_DEBUG_SERVER_VERBOSE("RsaKeyGen CacheKeyRsa: keyId:%u, ret:%d\n", key_id, ret);
if (ret == 0) {
/* Best-effort: also export the public key into the response
* body so the client avoids a separate ExportPublicKey
* call. On failure leave the body empty and still return the
* cached keyId rather than orphaning the committed key. */
int pub_ret = wc_RsaKeyToPublicDer(rsa, out, max_size);
if (pub_ret > 0) {
der_size = (uint16_t)pub_ret;
}
}
if (ret == 0) {
res.keyId = wh_KeyId_TranslateToClient(key_id);
res.len = 0;
res.len = der_size;
}
}
}
Expand Down Expand Up @@ -1201,13 +1211,6 @@ static int _HandleEccKeyGen(whServerContext* ctx, uint16_t magic, int devId,
key_id = WH_KEYID_ERASED;
ret = wh_Crypto_EccSerializeKeyDer(key, max_size, res_out,
&res_size);
/* TODO: RSA has the following, should we do the same? */
/*
if (ret == 0) {
res.keyId = 0;
res.len = res_size;
}
*/
}
else {
/* Must import the key into the cache and return keyid
Expand All @@ -1228,11 +1231,17 @@ static int _HandleEccKeyGen(whServerContext* ctx, uint16_t magic, int devId,
label_size, label);
}
WH_DEBUG_SERVER("CacheImport: keyId:%u, ret:%d\n", key_id, ret);
/* TODO: RSA has the following, should we do the same? */
/*
res.keyId = WH_KEYID_ID(key_id);
res.len = 0;
*/
if (ret == 0) {
/* Best-effort: also export the public key into the response
* body so the client avoids a separate ExportPublicKey
* call. On failure leave the body empty and still return the
* cached keyId rather than orphaning the committed key. */
int pub_ret =
wc_EccPublicKeyToDer(key, res_out, max_size, 1);
if (pub_ret > 0) {
res_size = (uint16_t)pub_ret;
}
}
}
}
wc_ecc_free(key);
Expand Down Expand Up @@ -2061,6 +2070,9 @@ static int _HandleCurve25519KeyGen(whServerContext* ctx, uint16_t magic,
ret = wh_Crypto_Curve25519SerializeKey(key, out, &ser_size);
}
else {
uint16_t max_size =
(uint16_t)(WOLFHSM_CFG_COMM_DATA_LEN -
(out - (uint8_t*)cryptoDataOut));
ser_size = 0;
/* Must import the key into the cache and return keyid */
if (WH_KEYID_ISERASED(key_id)) {
Expand All @@ -2081,6 +2093,17 @@ static int _HandleCurve25519KeyGen(whServerContext* ctx, uint16_t magic,
}
WH_DEBUG_SERVER_VERBOSE("CacheImport: keyId:%u, ret:%d\n",
key_id, ret);
if (ret == 0) {
/* Best-effort: also export the public key into the response
* body so the client avoids a separate ExportPublicKey
* call. On failure leave the body empty and still return the
* cached keyId rather than orphaning the committed key. */
int pub_ret =
wc_Curve25519PublicKeyToDer(key, out, max_size, 1);
if (pub_ret > 0) {
ser_size = (uint16_t)pub_ret;
}
}
}
}
wc_curve25519_free(key);
Expand Down Expand Up @@ -2297,6 +2320,17 @@ static int _HandleEd25519KeyGen(whServerContext* ctx, uint16_t magic, int devId,
ret = wh_Server_CacheImportEd25519Key(
ctx, key, key_id, flags, label_size, label);
}
if (ret == 0) {
/* Best-effort: also export the public key into the response
* body so the client avoids a separate ExportPublicKey
* call. On failure leave the body empty and still return the
* cached keyId rather than orphaning the committed key. */
int pub_ret =
wc_Ed25519PublicKeyToDer(key, res_out, max_size, 1);
if (pub_ret > 0) {
ser_size = (uint16_t)pub_ret;
}
}
}
}
wc_ed25519_free(key);
Expand Down Expand Up @@ -4801,6 +4835,20 @@ static int _HandleMlDsaKeyGen(whServerContext* ctx, uint16_t magic, int devId,
}
WH_DEBUG_SERVER("CacheImport: keyId:%u, ret:%d\n",
key_id, ret);
#ifdef WOLFSSL_MLDSA_PUBLIC_KEY
if (ret == 0) {
/* Best-effort: also export the public key into the
* response body so the client avoids a separate
* ExportPublicKey call. On failure leave the body
* empty and still return the cached keyId rather
* than orphaning the committed key. */
int pub_ret = wc_MlDsaKey_PublicKeyToDer(
key, res_out, max_size, 1);
if (pub_ret > 0) {
res_size = (uint16_t)pub_ret;
}
}
#endif /* WOLFSSL_MLDSA_PUBLIC_KEY */
}
}
}
Expand Down Expand Up @@ -5140,6 +5188,19 @@ static int _HandleMlKemKeyGen(whServerContext* ctx, uint16_t magic, int devId,
req.flags, label_size,
req.label);
}
if (ret == WH_ERROR_OK) {
/* Best-effort: also export the public key into the response
* body so the client avoids a separate ExportPublicKey
* call. On failure leave the body empty and still return the
* cached keyId rather than orphaning the committed key. */
word32 pubSize = 0;
if ((wc_MlKemKey_PublicKeySize(key, &pubSize) == 0) &&
((uint32_t)pubSize <= (uint32_t)max_size) &&
(wc_MlKemKey_EncodePublicKey(key, res_out, pubSize) ==
0)) {
res_size = (uint16_t)pubSize;
}
}
}
}
wc_MlKemKey_Free(key);
Expand Down Expand Up @@ -6458,11 +6519,36 @@ static int _HandleMlDsaKeyGenDma(whServerContext* ctx, uint16_t magic,
req.label);
WH_DEBUG_SERVER("CacheImport: keyId:%u, ret:%d\n",
keyId, ret);
if (ret == 0) {
res.keyId = wh_KeyId_TranslateToClient(keyId);
res.keySize = keySize;
}
#ifdef WOLFSSL_MLDSA_PUBLIC_KEY
/* Best-effort: stream the public key back through the
* client's DMA buffer so it gets the pubkey without a
* separate ExportPublicKey call. On failure leave
* keySize 0 and still return the cached keyId rather
* than orphaning the committed key. */
if (ret == 0) {
int rc = wh_Server_DmaProcessClientAddress(
ctx, req.key.addr, &clientOutAddr, req.key.sz,
WH_DMA_OPER_CLIENT_WRITE_PRE,
(whServerDmaFlags){0});
if (rc == 0) {
int pub_ret = wc_MlDsaKey_PublicKeyToDer(
key, (byte*)clientOutAddr,
(word32)req.key.sz, 1);
if (pub_ret > 0) {
keySize = (uint16_t)pub_ret;
}
(void)wh_Server_DmaProcessClientAddress(
ctx, req.key.addr, &clientOutAddr, keySize,
WH_DMA_OPER_CLIENT_WRITE_POST,
(whServerDmaFlags){0});
}
}
#endif /* WOLFSSL_MLDSA_PUBLIC_KEY */
if (ret == 0) {
res.keyId = wh_KeyId_TranslateToClient(keyId);
res.keySize = keySize;
}
}
}
}
Expand Down Expand Up @@ -6888,11 +6974,35 @@ static int _HandleMlKemKeyGenDma(whServerContext* ctx, uint16_t magic,
ret = wh_Server_MlKemKeyCacheImport(
ctx, key, keyId, req.flags, req.labelSize,
req.label);
if (ret == WH_ERROR_OK) {
res.keyId = wh_KeyId_TranslateToClient(keyId);
res.keySize = keySize;
}
/* Best-effort: stream the public key back through the
* client's DMA buffer so it gets the pubkey without a
* separate ExportPublicKey call. On failure leave keySize 0
* and still return the cached keyId rather than orphaning
* the committed key. */
if (ret == WH_ERROR_OK) {
word32 pubSize = 0;
if ((wc_MlKemKey_PublicKeySize(key, &pubSize) == 0) &&
((uint64_t)pubSize <= req.key.sz) &&
(wh_Server_DmaProcessClientAddress(
ctx, req.key.addr, &clientOutAddr, pubSize,
WH_DMA_OPER_CLIENT_WRITE_PRE,
(whServerDmaFlags){0}) == 0)) {
if (wc_MlKemKey_EncodePublicKey(
key, (uint8_t*)clientOutAddr, pubSize) ==
0) {
keySize = (uint16_t)pubSize;
}
(void)wh_Server_DmaProcessClientAddress(
ctx, req.key.addr, &clientOutAddr, keySize,
WH_DMA_OPER_CLIENT_WRITE_POST,
(whServerDmaFlags){0});
}
}
if (ret == WH_ERROR_OK) {
res.keyId = wh_KeyId_TranslateToClient(keyId);
res.keySize = keySize;
}
}
}
wc_MlKemKey_Free(key);
Expand Down
120 changes: 120 additions & 0 deletions test-refactor/client-server/wh_test_crypto_curve25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,130 @@ static int _whTest_CryptoCurve25519ExportPublicKey(whClientContext* ctx)
return ret;
}

/* One keygen call caches the private key and returns the public key. Verify
* the returned public key byte-matches wh_Client_Curve25519ExportPublicKey and
* that an X25519 shared secret round-trips against the cached private key. */
static int _whTest_CryptoCurve25519CacheKeyAndExportPublic(whClientContext* ctx)
{
int devId = WH_CLIENT_DEVID(ctx);
int ret = 0;
WC_RNG rng[1];
curve25519_key genPub[1] = {0};
curve25519_key refPub[1] = {0};
curve25519_key hsmPriv[1] = {0};
curve25519_key localKey[1] = {0};
uint8_t genRaw[CURVE25519_KEYSIZE] = {0};
uint8_t refRaw[CURVE25519_KEYSIZE] = {0};
word32 genRawLen = sizeof(genRaw);
word32 refRawLen = sizeof(refRaw);
uint8_t sharedHsm[CURVE25519_KEYSIZE] = {0};
uint8_t sharedLocal[CURVE25519_KEYSIZE] = {0};
word32 secLen = 0;
whKeyId keyId = WH_KEYID_ERASED;

ret = wc_InitRng_ex(rng, NULL, devId);
if (ret != 0) {
WH_ERROR_PRINT("Failed to wc_InitRng_ex %d\n", ret);
return ret;
}

ret = wc_curve25519_init_ex(genPub, NULL, INVALID_DEVID);
if (ret != 0) {
WH_ERROR_PRINT("Failed to wc_curve25519_init_ex %d\n", ret);
(void)wc_FreeRng(rng);
return ret;
}

ret = wh_Client_Curve25519MakeCacheKeyAndExportPublic(
ctx, (uint16_t)CURVE25519_KEYSIZE, &keyId, WH_NVM_FLAGS_USAGE_DERIVE,
NULL, 0, genPub);
if (ret != 0) {
WH_ERROR_PRINT("Curve25519MakeCacheKeyAndExportPublic failed %d\n", ret);
}

/* Cross-check against a separate public export of the same keyId. */
if (ret == 0) {
ret = wc_curve25519_init_ex(refPub, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wh_Client_Curve25519ExportPublicKey(ctx, keyId, refPub, 0,
NULL);
if (ret != 0) {
WH_ERROR_PRINT(
"wh_Client_Curve25519ExportPublicKey failed %d\n", ret);
}
}
}
if (ret == 0) {
ret = wc_curve25519_export_public(genPub, genRaw, &genRawLen);
if (ret == 0) {
ret = wc_curve25519_export_public(refPub, refRaw, &refRawLen);
}
if (ret != 0) {
WH_ERROR_PRINT("Curve25519 export_public failed %d\n", ret);
}
else if ((genRawLen != refRawLen) ||
(memcmp(genRaw, refRaw, genRawLen) != 0)) {
WH_ERROR_PRINT("keygen pubkey mismatch vs export\n");
ret = -1;
}
}

/* Shared-secret round-trip: local priv * keygen pub vs HSM priv * local
* pub. Both must agree. */
if (ret == 0) {
ret = wc_curve25519_init_ex(localKey, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_curve25519_make_key(rng, CURVE25519_KEYSIZE, localKey);
}
}
if (ret == 0) {
secLen = sizeof(sharedLocal);
ret = wc_curve25519_shared_secret(localKey, genPub, sharedLocal,
&secLen);
if (ret != 0) {
WH_ERROR_PRINT("Local Curve25519 shared secret failed %d\n", ret);
}
}
if (ret == 0) {
ret = wc_curve25519_init_ex(hsmPriv, NULL, devId);
if (ret == 0) {
ret = wh_Client_Curve25519SetKeyId(hsmPriv, keyId);
}
if (ret == 0) {
secLen = sizeof(sharedHsm);
ret = wc_curve25519_shared_secret(hsmPriv, localKey, sharedHsm,
&secLen);
if (ret != 0) {
WH_ERROR_PRINT("HSM Curve25519 shared secret failed %d\n", ret);
}
}
wc_curve25519_free(hsmPriv);
}
if (ret == 0 && memcmp(sharedHsm, sharedLocal, secLen) != 0) {
WH_ERROR_PRINT("Curve25519 keygen-pub shared secret mismatch\n");
ret = -1;
}

wc_curve25519_free(localKey);
wc_curve25519_free(refPub);
wc_curve25519_free(genPub);
if (!WH_KEYID_ISERASED(keyId)) {
(void)wh_Client_KeyEvict(ctx, keyId);
}
(void)wc_FreeRng(rng);

if (ret == 0) {
WH_TEST_PRINT("CURVE25519 CACHE-AND-EXPORT-PUBLIC DEVID=0x%X SUCCESS\n",
devId);
}
return ret;
}

int whTest_Crypto_Curve25519(whClientContext* ctx)
{
WH_TEST_RETURN_ON_FAIL(_whTest_CryptoCurve25519(ctx));
WH_TEST_RETURN_ON_FAIL(_whTest_CryptoCurve25519ExportPublicKey(ctx));
WH_TEST_RETURN_ON_FAIL(_whTest_CryptoCurve25519CacheKeyAndExportPublic(ctx));
return 0;
}
#endif /* HAVE_CURVE25519 */
Expand Down
Loading
Loading