Skip to content

Commit e0914ea

Browse files
committed
Add support for HKDF offload
1 parent 8d579d6 commit e0914ea

File tree

8 files changed

+648
-0
lines changed

8 files changed

+648
-0
lines changed

src/wh_client_crypto.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ static int _RsaMakeKey(whClientContext* ctx, uint32_t size, uint32_t e,
8989
whKeyId* inout_key_id, RsaKey* rsa);
9090
#endif
9191

92+
#ifdef HAVE_HKDF
93+
/* Generate HKDF output on the server based on the flags */
94+
static int _HkdfMakeKey(whClientContext* ctx, int hashType,
95+
const uint8_t* inKey, uint32_t inKeySz,
96+
const uint8_t* salt, uint32_t saltSz,
97+
const uint8_t* info, uint32_t infoSz, whNvmFlags flags,
98+
uint32_t label_len, const uint8_t* label,
99+
whKeyId* inout_key_id, uint8_t* out, uint32_t outSz);
100+
#endif
101+
92102
#ifdef HAVE_DILITHIUM
93103
/* Make a ML-DSA key on the server based on the flags */
94104
static int _MlDsaMakeKey(whClientContext* ctx, int size, int level,
@@ -2282,6 +2292,180 @@ int wh_Client_RsaGetSize(whClientContext* ctx, const RsaKey* key, int* out_size)
22822292

22832293
#endif /* !NO_RSA */
22842294

2295+
#ifdef HAVE_HKDF
2296+
/* Internal helper function to generate HKDF output on the server */
2297+
static int _HkdfMakeKey(whClientContext* ctx, int hashType,
2298+
const uint8_t* inKey, uint32_t inKeySz,
2299+
const uint8_t* salt, uint32_t saltSz,
2300+
const uint8_t* info, uint32_t infoSz, whNvmFlags flags,
2301+
uint32_t label_len, const uint8_t* label,
2302+
whKeyId* inout_key_id, uint8_t* out, uint32_t outSz)
2303+
{
2304+
int ret = WH_ERROR_OK;
2305+
uint8_t* dataPtr = NULL;
2306+
whMessageCrypto_HkdfRequest* req = NULL;
2307+
whMessageCrypto_HkdfResponse* res = NULL;
2308+
uint16_t group = WH_MESSAGE_GROUP_CRYPTO;
2309+
uint16_t action = WC_ALGO_TYPE_KDF;
2310+
whKeyId key_id = WH_KEYID_ERASED;
2311+
2312+
if ((ctx == NULL) || (inKey == NULL)) {
2313+
return WH_ERROR_BADARGS;
2314+
}
2315+
2316+
/* Get data pointer from the context to use as request/response storage */
2317+
dataPtr = wh_CommClient_GetDataPtr(ctx->comm);
2318+
if (dataPtr == NULL) {
2319+
return WH_ERROR_BADARGS;
2320+
}
2321+
2322+
/* Setup generic header and get pointer to request data */
2323+
req = (whMessageCrypto_HkdfRequest*)_createCryptoRequest(dataPtr,
2324+
WC_ALGO_TYPE_KDF);
2325+
2326+
/* Calculate request length including variable-length data */
2327+
uint16_t req_len = sizeof(whMessageCrypto_GenericRequestHeader) +
2328+
sizeof(*req) + inKeySz + saltSz + infoSz;
2329+
2330+
/* Use the supplied key id if provided */
2331+
if (inout_key_id != NULL) {
2332+
key_id = *inout_key_id;
2333+
}
2334+
2335+
/* Populate request body */
2336+
req->flags = flags;
2337+
req->keyId = key_id;
2338+
req->hashType = hashType;
2339+
req->inKeySz = inKeySz;
2340+
req->saltSz = saltSz;
2341+
req->infoSz = infoSz;
2342+
req->outSz = outSz;
2343+
2344+
/* Copy label if provided */
2345+
if ((label != NULL) && (label_len > 0)) {
2346+
if (label_len > WH_NVM_LABEL_LEN) {
2347+
label_len = WH_NVM_LABEL_LEN;
2348+
}
2349+
memcpy(req->label, label, label_len);
2350+
if (label_len < WH_NVM_LABEL_LEN) {
2351+
req->label[label_len] = '\0';
2352+
}
2353+
}
2354+
else {
2355+
memset(req->label, 0, WH_NVM_LABEL_LEN);
2356+
}
2357+
2358+
/* Copy variable-length data after the request structure */
2359+
uint8_t* data_ptr = (uint8_t*)(req + 1);
2360+
2361+
/* Copy input key material */
2362+
memcpy(data_ptr, inKey, inKeySz);
2363+
data_ptr += inKeySz;
2364+
2365+
/* Copy salt if provided */
2366+
if (salt != NULL && saltSz > 0) {
2367+
memcpy(data_ptr, salt, saltSz);
2368+
data_ptr += saltSz;
2369+
}
2370+
2371+
/* Copy info if provided */
2372+
if (info != NULL && infoSz > 0) {
2373+
memcpy(data_ptr, info, infoSz);
2374+
}
2375+
2376+
/* Send Request */
2377+
ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr);
2378+
2379+
#ifdef DEBUG_CRYPTOCB_VERBOSE
2380+
printf("HKDF Req sent: hashType:%d inKeySz:%u saltSz:%u infoSz:%u outSz:%u "
2381+
"ret:%d\n",
2382+
req->hashType, req->inKeySz, req->saltSz, req->infoSz, req->outSz,
2383+
ret);
2384+
#endif
2385+
2386+
if (ret == 0) {
2387+
uint16_t res_len = 0;
2388+
do {
2389+
ret =
2390+
wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr);
2391+
} while (ret == WH_ERROR_NOTREADY);
2392+
2393+
#ifdef DEBUG_CRYPTOCB_VERBOSE
2394+
printf("HKDF Res recv: ret:%d, res_len: %u\n", ret, res_len);
2395+
#endif
2396+
2397+
if (ret == WH_ERROR_OK) {
2398+
/* Get response structure pointer, validates generic header rc */
2399+
ret =
2400+
_getCryptoResponse(dataPtr, WC_ALGO_TYPE_KDF, (uint8_t**)&res);
2401+
}
2402+
2403+
if (ret == WH_ERROR_OK) {
2404+
/* Key is cached on server or is ephemeral */
2405+
key_id = (whKeyId)(res->keyId);
2406+
2407+
/* Update output variable if requested */
2408+
if (inout_key_id != NULL) {
2409+
*inout_key_id = key_id;
2410+
}
2411+
2412+
/* Copy output key material if output buffer provided */
2413+
if (out != NULL) {
2414+
if (res->outSz <= outSz) {
2415+
uint8_t* hkdf_out = (uint8_t*)(res + 1);
2416+
memcpy(out, hkdf_out, res->outSz);
2417+
2418+
#ifdef DEBUG_CRYPTOCB_VERBOSE
2419+
printf("[client] %s Set key_id:%x with flags:%x outSz:%u\n",
2420+
__func__, key_id, flags, res->outSz);
2421+
#endif
2422+
}
2423+
else {
2424+
/* Server returned more than we can handle - error */
2425+
ret = WH_ERROR_ABORTED;
2426+
}
2427+
}
2428+
}
2429+
}
2430+
return ret;
2431+
}
2432+
2433+
int wh_Client_HkdfMakeCacheKey(whClientContext* ctx, int hashType,
2434+
const uint8_t* inKey, uint32_t inKeySz,
2435+
const uint8_t* salt, uint32_t saltSz,
2436+
const uint8_t* info, uint32_t infoSz,
2437+
whKeyId* inout_key_id, whNvmFlags flags,
2438+
const uint8_t* label, uint32_t label_len,
2439+
uint32_t outSz)
2440+
{
2441+
/* Valid ctx and keyid ptr are required in this form */
2442+
if ((ctx == NULL) || (inout_key_id == NULL)) {
2443+
return WH_ERROR_BADARGS;
2444+
}
2445+
2446+
return _HkdfMakeKey(ctx, hashType, inKey, inKeySz, salt, saltSz, info,
2447+
infoSz, flags, label_len, label, inout_key_id, NULL,
2448+
outSz);
2449+
}
2450+
2451+
int wh_Client_HkdfMakeExportKey(whClientContext* ctx, int hashType,
2452+
const uint8_t* inKey, uint32_t inKeySz,
2453+
const uint8_t* salt, uint32_t saltSz,
2454+
const uint8_t* info, uint32_t infoSz,
2455+
uint8_t* out, uint32_t outSz)
2456+
{
2457+
/* Valid ctx and out are required for this form */
2458+
if ((ctx == NULL) || (out == NULL)) {
2459+
return WH_ERROR_BADARGS;
2460+
}
2461+
2462+
return _HkdfMakeKey(ctx, hashType, inKey, inKeySz, salt, saltSz, info,
2463+
infoSz, WH_NVM_FLAGS_EPHEMERAL, 0, NULL, NULL, out,
2464+
outSz);
2465+
}
2466+
2467+
#endif /* HAVE_HKDF */
2468+
22852469
#ifndef NO_AES
22862470
int wh_Client_AesSetKeyId(Aes* key, whNvmId keyId)
22872471
{

src/wh_client_cryptocb.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,33 @@ int wh_Client_CryptoCb(int devId, wc_CryptoInfo* info, void* inCtx)
464464
}
465465
} break; /* case WC_ALGO_TYPE_HASH */
466466

467+
#ifdef HAVE_HKDF
468+
case WC_ALGO_TYPE_KDF: {
469+
/* Handle different KDF types */
470+
switch (info->kdf.type) {
471+
case WC_KDF_TYPE_HKDF: {
472+
/* Extract HKDF-specific parameters */
473+
int hashType = info->kdf.hkdf.hashType;
474+
const byte* inKey = info->kdf.hkdf.inKey;
475+
word32 inKeySz = info->kdf.hkdf.inKeySz;
476+
const byte* salt = info->kdf.hkdf.salt;
477+
word32 saltSz = info->kdf.hkdf.saltSz;
478+
const byte* kdf_info = info->kdf.hkdf.info;
479+
word32 infoSz = info->kdf.hkdf.infoSz;
480+
byte* out = info->kdf.hkdf.out;
481+
word32 outSz = info->kdf.hkdf.outSz;
482+
483+
ret = wh_Client_HkdfMakeExportKey(ctx, hashType, inKey, inKeySz,
484+
salt, saltSz, kdf_info,
485+
infoSz, out, outSz);
486+
} break;
487+
default:
488+
ret = CRYPTOCB_UNAVAILABLE;
489+
break;
490+
}
491+
} break; /* case WC_ALGO_TYPE_KDF */
492+
#endif /* HAVE_HKDF */
493+
467494
case WC_ALGO_TYPE_NONE:
468495
default:
469496
ret = CRYPTOCB_UNAVAILABLE;

src/wh_message_crypto.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,41 @@ int wh_MessageCrypto_TranslateRsaGetSizeResponse(
273273
return 0;
274274
}
275275

276+
/* HKDF Request translation */
277+
int wh_MessageCrypto_TranslateHkdfRequest(
278+
uint16_t magic, const whMessageCrypto_HkdfRequest* src,
279+
whMessageCrypto_HkdfRequest* dest)
280+
{
281+
if ((src == NULL) || (dest == NULL)) {
282+
return WH_ERROR_BADARGS;
283+
}
284+
WH_T32(magic, dest, src, flags);
285+
WH_T32(magic, dest, src, keyId);
286+
WH_T32(magic, dest, src, hashType);
287+
WH_T32(magic, dest, src, inKeySz);
288+
WH_T32(magic, dest, src, saltSz);
289+
WH_T32(magic, dest, src, infoSz);
290+
WH_T32(magic, dest, src, outSz);
291+
/* Label is just a byte array, no translation needed */
292+
if (src != dest) {
293+
memcpy(dest->label, src->label, WH_NVM_LABEL_LEN);
294+
}
295+
return 0;
296+
}
297+
298+
/* HKDF Response translation */
299+
int wh_MessageCrypto_TranslateHkdfResponse(
300+
uint16_t magic, const whMessageCrypto_HkdfResponse* src,
301+
whMessageCrypto_HkdfResponse* dest)
302+
{
303+
if ((src == NULL) || (dest == NULL)) {
304+
return WH_ERROR_BADARGS;
305+
}
306+
WH_T32(magic, dest, src, keyId);
307+
WH_T32(magic, dest, src, outSz);
308+
return 0;
309+
}
310+
276311
/* ECC Key Generation Request translation */
277312
int wh_MessageCrypto_TranslateEccKeyGenRequest(
278313
uint16_t magic, const whMessageCrypto_EccKeyGenRequest* src,

0 commit comments

Comments
 (0)