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
520 changes: 335 additions & 185 deletions src/wh_client_crypto.c

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/wh_message_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,11 @@ int wh_MessageCrypto_TranslateEcdhRequest(
WH_T32(magic, dest, src, options);
WH_T32(magic, dest, src, privateKeyId);
WH_T32(magic, dest, src, publicKeyId);
WH_T32(magic, dest, src, flags);
WH_T32(magic, dest, src, keyId);
if (src != dest) {
memcpy(dest->label, src->label, sizeof(src->label));
}
return 0;
}

Expand All @@ -400,6 +405,7 @@ int wh_MessageCrypto_TranslateEcdhResponse(
return WH_ERROR_BADARGS;
}
WH_T32(magic, dest, src, sz);
WH_T32(magic, dest, src, keyId);
return 0;
}

Expand Down Expand Up @@ -525,6 +531,11 @@ int wh_MessageCrypto_TranslateCurve25519Request(
WH_T32(magic, dest, src, privateKeyId);
WH_T32(magic, dest, src, publicKeyId);
WH_T32(magic, dest, src, endian);
WH_T32(magic, dest, src, flags);
WH_T32(magic, dest, src, keyId);
if (src != dest) {
memcpy(dest->label, src->label, sizeof(src->label));
}
return 0;
}

Expand All @@ -537,6 +548,7 @@ int wh_MessageCrypto_TranslateCurve25519Response(
return WH_ERROR_BADARGS;
}
WH_T32(magic, dest, src, sz);
WH_T32(magic, dest, src, keyId);
return 0;
}

Expand Down
139 changes: 122 additions & 17 deletions src/wh_server_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -984,12 +984,15 @@ static int _HandleEccSharedSecret(whServerContext* ctx, uint16_t magic,
uint16_t inSize, void* cryptoDataOut,
uint16_t* outSize)
{
(void)inSize;

int ret = WH_ERROR_OK;
ecc_key pub_key[1];
ecc_key prv_key[1];
whMessageCrypto_EcdhRequest req;
whKeyId out_key_id = WH_KEYID_ERASED;

if (inSize < sizeof(whMessageCrypto_EcdhRequest)) {
return WH_ERROR_BADARGS;
}

/* Translate request */
ret = wh_MessageCrypto_TranslateEcdhRequest(
Expand All @@ -1006,6 +1009,8 @@ static int _HandleEccSharedSecret(whServerContext* ctx, uint16_t magic,
WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.publicKeyId);
whKeyId prv_key_id = wh_KeyId_TranslateFromClient(
WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.privateKeyId);
whNvmFlags flags = (whNvmFlags)req.flags;
int cache = !(flags & WH_NVM_FLAGS_EPHEMERAL);

/* Validate key usage policy for key derivation (private key) */
if (!WH_KEYID_ISERASED(prv_key_id)) {
Expand Down Expand Up @@ -1047,6 +1052,41 @@ static int _HandleEccSharedSecret(whServerContext* ctx, uint16_t magic,
}
wc_ecc_free(pub_key);
}

/* If caching, move the secret out of the response buffer into a cache
* slot and return only its keyId. */
if ((ret == WH_ERROR_OK) && cache) {
out_key_id = wh_KeyId_TranslateFromClient(
WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId);
/* Hold the NVM lock so id allocation and cache import are atomic
* with respect to other server contexts under THREADSAFE. */
ret = WH_SERVER_NVM_LOCK(ctx);
if (ret == WH_ERROR_OK) {
if (WH_KEYID_ISERASED(out_key_id)) {
ret = wh_Server_KeystoreGetUniqueId(ctx, &out_key_id);
}
if (ret == WH_ERROR_OK) {
ret = wh_Server_KeyCacheImportRaw(ctx, res_out, res_len,
out_key_id, flags,
WH_NVM_LABEL_LEN, req.label);
}
(void)WH_SERVER_NVM_UNLOCK(ctx);
} /* WH_SERVER_NVM_LOCK() */
/* Scrub the secret from the response buffer regardless of import
* success/failure. */
memset(res_out, 0, res_len);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would you consider getting a cache slot with wh_Server_KeystoreGetCacheSlotChecked before the wc_ecc_shared_secret operation to avoid a copy and a memset?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I thought about this but it means that the crypto would have to occur inside the critical section, otherwise there could be a race on getting a cache slot for global keys. For now I think its best to follow the pattern of the other handlers that work similarly. Would rather pay for a small copy inside the critical section than pay for a public key crypto operation

/* If the cached output id collides with an auto-imported input id,
* suppress the matching eviction so cleanup does not delete the
* just-cached secret. */
if (ret == WH_ERROR_OK) {
if (evict_pub && (out_key_id == pub_key_id)) {
evict_pub = 0;
}
if (evict_prv && (out_key_id == prv_key_id)) {
evict_prv = 0;
}
}
}
cleanup:
if (evict_pub) {
/* User requested to evict from cache, even if the call failed */
Expand All @@ -1058,12 +1098,22 @@ static int _HandleEccSharedSecret(whServerContext* ctx, uint16_t magic,
}
if (ret == 0) {
whMessageCrypto_EcdhResponse res;
res.sz = res_len;
uint16_t payload_len;
if (cache) {
res.sz = 0;
res.keyId = wh_KeyId_TranslateToClient(out_key_id);
payload_len = 0;
}
else {
res.sz = res_len;
res.keyId = 0;
payload_len = (uint16_t)res_len;
}

wh_MessageCrypto_TranslateEcdhResponse(
magic, &res, (whMessageCrypto_EcdhResponse*)cryptoDataOut);

*outSize = sizeof(whMessageCrypto_EcdhResponse) + res_len;
*outSize = sizeof(whMessageCrypto_EcdhResponse) + payload_len;
}
return ret;
}
Expand Down Expand Up @@ -1321,11 +1371,10 @@ static int _HandleRng(whServerContext* ctx, uint16_t magic, int devId,
}
#endif /* WC_NO_RNG */

#ifdef HAVE_HKDF
int wh_Server_HkdfKeyCacheImport(whServerContext* ctx, const uint8_t* keyData,
uint32_t keySize, whKeyId keyId,
whNvmFlags flags, uint16_t label_len,
uint8_t* label)
int wh_Server_KeyCacheImportRaw(whServerContext* ctx, const uint8_t* keyData,
uint32_t keySize, whKeyId keyId,
whNvmFlags flags, uint16_t label_len,
uint8_t* label)
{
int ret = WH_ERROR_OK;
uint8_t* cacheBuf;
Expand All @@ -1340,12 +1389,8 @@ int wh_Server_HkdfKeyCacheImport(whServerContext* ctx, const uint8_t* keyData,
ret = wh_Server_KeystoreGetCacheSlotChecked(ctx, keyId, keySize, &cacheBuf,
&cacheMeta);
if (ret == WH_ERROR_OK) {
/* Copy the key data to cache buffer */
memcpy(cacheBuf, keyData, keySize);
}

if (ret == WH_ERROR_OK) {
/* Set metadata */
cacheMeta->id = keyId;
cacheMeta->len = keySize;
cacheMeta->flags = flags;
Expand All @@ -1359,6 +1404,16 @@ int wh_Server_HkdfKeyCacheImport(whServerContext* ctx, const uint8_t* keyData,
return ret;
}

#ifdef HAVE_HKDF
int wh_Server_HkdfKeyCacheImport(whServerContext* ctx, const uint8_t* keyData,
uint32_t keySize, whKeyId keyId,
whNvmFlags flags, uint16_t label_len,
uint8_t* label)
{
return wh_Server_KeyCacheImportRaw(ctx, keyData, keySize, keyId, flags,
label_len, label);
}

#endif /* HAVE_HKDF */

#ifdef HAVE_CMAC_KDF
Expand Down Expand Up @@ -1778,14 +1833,17 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic,
uint16_t inSize, void* cryptoDataOut,
uint16_t* outSize)
{
(void)inSize;

int ret;
curve25519_key priv[1] = {0};
curve25519_key pub[1] = {0};

whMessageCrypto_Curve25519Request req;
whMessageCrypto_Curve25519Response res;
whKeyId out_key_id = WH_KEYID_ERASED;

if (inSize < sizeof(whMessageCrypto_Curve25519Request)) {
return WH_ERROR_BADARGS;
}

/* Translate request */
ret = wh_MessageCrypto_TranslateCurve25519Request(
Expand All @@ -1803,6 +1861,8 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic,
whKeyId prv_key_id = wh_KeyId_TranslateFromClient(
WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.privateKeyId);
int endian = req.endian;
whNvmFlags flags = (whNvmFlags)req.flags;
int cache = !(flags & WH_NVM_FLAGS_EPHEMERAL);

/* Validate key usage policy for key derivation (private key) */
if (!WH_KEYID_ISERASED(prv_key_id)) {
Expand Down Expand Up @@ -1846,6 +1906,41 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic,
}
wc_curve25519_free(priv);
}

/* If caching, move the secret out of the response buffer into a cache
* slot and return only its keyId. */
if ((ret == WH_ERROR_OK) && cache) {
out_key_id = wh_KeyId_TranslateFromClient(
WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId);
/* Hold the NVM lock so id allocation and cache import are atomic
* with respect to other server contexts under THREADSAFE. */
ret = WH_SERVER_NVM_LOCK(ctx);
if (ret == WH_ERROR_OK) {
if (WH_KEYID_ISERASED(out_key_id)) {
ret = wh_Server_KeystoreGetUniqueId(ctx, &out_key_id);
}
if (ret == WH_ERROR_OK) {
ret = wh_Server_KeyCacheImportRaw(ctx, res_out, res_len,
out_key_id, flags,
WH_NVM_LABEL_LEN, req.label);
}
(void)WH_SERVER_NVM_UNLOCK(ctx);
} /* WH_SERVER_NVM_LOCK() */
/* Scrub the secret from the response buffer regardless of import
* success/failure. */
memset(res_out, 0, res_len);
/* If the cached output id collides with an auto-imported input id,
* suppress the matching eviction so cleanup does not delete the
* just-cached secret. */
if (ret == WH_ERROR_OK) {
if (evict_pub && (out_key_id == pub_key_id)) {
evict_pub = 0;
}
if (evict_prv && (out_key_id == prv_key_id)) {
evict_prv = 0;
}
}
}
cleanup:
if (evict_pub) {
/* User requested to evict from cache, even if the call failed */
Expand All @@ -1856,13 +1951,23 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic,
(void)wh_Server_KeystoreEvictKey(ctx, prv_key_id);
}
if (ret == 0) {
res.sz = res_len;
uint16_t payload_len;
if (cache) {
res.sz = 0;
res.keyId = wh_KeyId_TranslateToClient(out_key_id);
payload_len = 0;
}
else {
res.sz = res_len;
res.keyId = 0;
payload_len = (uint16_t)res_len;
}

wh_MessageCrypto_TranslateCurve25519Response(
magic, &res,
(whMessageCrypto_Curve25519Response*)cryptoDataOut);

*outSize = sizeof(whMessageCrypto_Curve25519Response) + res_len;
*outSize = sizeof(whMessageCrypto_Curve25519Response) + payload_len;
}
return ret;
}
Expand Down
2 changes: 2 additions & 0 deletions test/wh_test_check_struct_padding.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ whMessageCrypto_RsaRequest pkRsaReq;
whMessageCrypto_RsaGetSizeRequest pkRsaGetSizeReq;
whMessageCrypto_EccKeyGenRequest pkEckgReq;
whMessageCrypto_EcdhRequest pkEcdhReq;
whMessageCrypto_Curve25519Request pkCurve25519Req;
whMessageCrypto_EccSignRequest pkEccSignReq;
whMessageCrypto_EccVerifyRequest pkEccVerifyReq;
whMessageCrypto_EccCheckRequest pkEccCheckReq;
Expand All @@ -114,6 +115,7 @@ whMessageCrypto_RsaResponse pkRsaRes;
whMessageCrypto_RsaGetSizeResponse pkRsaGetSizeRes;
whMessageCrypto_EccKeyGenResponse pkEckgRes;
whMessageCrypto_EcdhResponse pkEcdhRes;
whMessageCrypto_Curve25519Response pkCurve25519Res;
whMessageCrypto_EccSignResponse pkEccSignRes;
whMessageCrypto_EccVerifyResponse pkEccVerifyRes;
whMessageCrypto_EccCheckResponse pkEccCheckRes;
Expand Down
Loading
Loading