Skip to content

Commit 6d6d0ab

Browse files
committed
Add PKCS7 ECC raw sign callback support
1 parent 7e0a855 commit 6d6d0ab

File tree

4 files changed

+225
-5
lines changed

4 files changed

+225
-5
lines changed

.wolfssl_known_macro_extras

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ HAVE_INTEL_QAT_SYNC
280280
HAVE_INTEL_SPEEDUP
281281
HAVE_MDK_RTX
282282
HAVE_NETX_BSD
283+
HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK
283284
HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK
284285
HAVE_POCO_LIB
285286
HAVE_RTP_SYS

tests/api/test_pkcs7.c

Lines changed: 149 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,15 @@ int test_wc_PKCS7_EncodeData(void)
388388

389389
#if defined(HAVE_PKCS7) && defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && \
390390
!defined(NO_RSA) && !defined(NO_SHA256)
391-
/* RSA sign raw digest callback */
391+
/* RSA sign raw digest callback
392+
* This callback demonstrates HSM/secure element use case where the private
393+
* key is not passed through PKCS7 structure but obtained independently.
394+
*/
392395
static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz,
393396
byte* out, word32 outSz, byte* privateKey,
394397
word32 privateKeySz, int devid, int hashOID)
395398
{
396-
/* specific DigestInfo ASN.1 encoding prefix for a SHA2565 digest */
399+
/* specific DigestInfo ASN.1 encoding prefix for a SHA256 digest */
397400
byte digInfoEncoding[] = {
398401
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
399402
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
@@ -407,6 +410,11 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz,
407410
word32 idx = 0;
408411
RsaKey rsa;
409412

413+
/* privateKey may be NULL in HSM/secure element use case - we load it
414+
* independently in this callback to simulate that scenario */
415+
(void)privateKey;
416+
(void)privateKeySz;
417+
410418
/* SHA-256 required only for this example callback due to above
411419
* digInfoEncoding[] */
412420
if (pkcs7 == NULL || digest == NULL || out == NULL ||
@@ -427,7 +435,33 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz,
427435
return ret;
428436
}
429437

430-
ret = wc_RsaPrivateKeyDecode(privateKey, &idx, &rsa, privateKeySz);
438+
/* Load key from test buffer - simulates HSM/secure element access */
439+
#if defined(USE_CERT_BUFFERS_2048)
440+
ret = wc_RsaPrivateKeyDecode(client_key_der_2048, &idx, &rsa,
441+
sizeof_client_key_der_2048);
442+
#elif defined(USE_CERT_BUFFERS_1024)
443+
ret = wc_RsaPrivateKeyDecode(client_key_der_1024, &idx, &rsa,
444+
sizeof_client_key_der_1024);
445+
#else
446+
{
447+
XFILE fp;
448+
byte keyBuf[ONEK_BUF];
449+
int keySz;
450+
451+
fp = XFOPEN("./certs/client-key.der", "rb");
452+
if (fp == XBADFILE) {
453+
wc_FreeRsaKey(&rsa);
454+
return -1;
455+
}
456+
keySz = (int)XFREAD(keyBuf, 1, sizeof(keyBuf), fp);
457+
XFCLOSE(fp);
458+
if (keySz <= 0) {
459+
wc_FreeRsaKey(&rsa);
460+
return -1;
461+
}
462+
ret = wc_RsaPrivateKeyDecode(keyBuf, &idx, &rsa, (word32)keySz);
463+
}
464+
#endif
431465

432466
/* sign DigestInfo */
433467
if (ret == 0) {
@@ -451,6 +485,76 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz,
451485
}
452486
#endif
453487

488+
#if defined(HAVE_PKCS7) && defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && \
489+
defined(HAVE_ECC) && !defined(NO_SHA256)
490+
/* ECC sign raw digest callback
491+
* This callback demonstrates HSM/secure element use case where the private
492+
* key is not passed through PKCS7 structure but obtained independently.
493+
*/
494+
static int eccSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz,
495+
byte* out, word32 outSz, byte* privateKey,
496+
word32 privateKeySz, int devid, int hashOID)
497+
{
498+
int ret;
499+
word32 idx = 0;
500+
word32 sigSz = outSz;
501+
ecc_key ecc;
502+
503+
/* privateKey may be NULL in HSM/secure element use case - we load it
504+
* independently in this callback to simulate that scenario */
505+
(void)privateKey;
506+
(void)privateKeySz;
507+
(void)hashOID;
508+
509+
if (pkcs7 == NULL || digest == NULL || out == NULL) {
510+
return -1;
511+
}
512+
513+
/* set up ECC key */
514+
ret = wc_ecc_init_ex(&ecc, pkcs7->heap, devid);
515+
if (ret != 0) {
516+
return ret;
517+
}
518+
519+
/* Load key from test buffer - simulates HSM/secure element access */
520+
#if defined(USE_CERT_BUFFERS_256)
521+
ret = wc_EccPrivateKeyDecode(ecc_clikey_der_256, &idx, &ecc,
522+
sizeof_ecc_clikey_der_256);
523+
#else
524+
{
525+
XFILE fp;
526+
byte keyBuf[ONEK_BUF];
527+
int keySz;
528+
529+
fp = XFOPEN("./certs/client-ecc-key.der", "rb");
530+
if (fp == XBADFILE) {
531+
wc_ecc_free(&ecc);
532+
return -1;
533+
}
534+
keySz = (int)XFREAD(keyBuf, 1, sizeof(keyBuf), fp);
535+
XFCLOSE(fp);
536+
if (keySz <= 0) {
537+
wc_ecc_free(&ecc);
538+
return -1;
539+
}
540+
ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &ecc, (word32)keySz);
541+
}
542+
#endif
543+
544+
/* sign digest */
545+
if (ret == 0) {
546+
ret = wc_ecc_sign_hash(digest, digestSz, out, &sigSz, pkcs7->rng, &ecc);
547+
if (ret == 0) {
548+
ret = (int)sigSz;
549+
}
550+
}
551+
552+
wc_ecc_free(&ecc);
553+
554+
return ret;
555+
}
556+
#endif
557+
454558
#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER)
455559
typedef struct encodeSignedDataStream {
456560
byte out[FOURK_BUF*3];
@@ -757,8 +861,7 @@ int test_wc_PKCS7_EncodeSignedData(void)
757861
if (pkcs7 != NULL) {
758862
pkcs7->content = data;
759863
pkcs7->contentSz = (word32)sizeof(data);
760-
pkcs7->privateKey = key;
761-
pkcs7->privateKeySz = (word32)sizeof(key);
864+
/* privateKey not set - callback simulates HSM/secure element access */
762865
pkcs7->encryptOID = RSAk;
763866
pkcs7->hashOID = SHA256h;
764867
pkcs7->rng = &rng;
@@ -769,6 +872,47 @@ int test_wc_PKCS7_EncodeSignedData(void)
769872
ExpectIntGT(wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz), 0);
770873
#endif
771874

875+
#if defined(HAVE_PKCS7) && defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && \
876+
defined(HAVE_ECC) && !defined(NO_SHA256)
877+
/* test ECC sign raw digest callback, if using ECC and compiled in.
878+
* Example callback assumes SHA-256, so only run test if compiled in. */
879+
{
880+
#if defined(USE_CERT_BUFFERS_256)
881+
byte eccCert[sizeof(cliecc_cert_der_256)];
882+
word32 eccCertSz = (word32)sizeof(eccCert);
883+
XMEMCPY(eccCert, cliecc_cert_der_256, eccCertSz);
884+
#else
885+
byte eccCert[ONEK_BUF];
886+
int eccCertSz;
887+
XFILE eccFp = XBADFILE;
888+
889+
ExpectTrue((eccFp = XFOPEN("./certs/client-ecc-cert.der", "rb")) !=
890+
XBADFILE);
891+
ExpectIntGT(eccCertSz = (int)XFREAD(eccCert, 1, ONEK_BUF, eccFp), 0);
892+
if (eccFp != XBADFILE)
893+
XFCLOSE(eccFp);
894+
#endif
895+
896+
wc_PKCS7_Free(pkcs7);
897+
pkcs7 = NULL;
898+
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
899+
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, eccCert, (word32)eccCertSz), 0);
900+
901+
if (pkcs7 != NULL) {
902+
pkcs7->content = data;
903+
pkcs7->contentSz = (word32)sizeof(data);
904+
/* privateKey not set - callback simulates HSM/secure element access */
905+
pkcs7->encryptOID = ECDSAk;
906+
pkcs7->hashOID = SHA256h;
907+
pkcs7->rng = &rng;
908+
}
909+
910+
ExpectIntEQ(wc_PKCS7_SetEccSignRawDigestCb(pkcs7, eccSignRawDigestCb), 0);
911+
912+
ExpectIntGT(wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz), 0);
913+
}
914+
#endif
915+
772916
wc_PKCS7_Free(pkcs7);
773917
DoExpectIntEQ(wc_FreeRng(&rng), 0);
774918

wolfcrypt/src/pkcs7.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,16 @@ static int wc_PKCS7_ImportRSA(wc_PKCS7* pkcs7, RsaKey* privKey)
17941794
}
17951795
#endif
17961796
}
1797+
#ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK
1798+
else if (pkcs7->rsaSignRawDigestCb != NULL && pkcs7->publicKeySz > 0) {
1799+
/* When using raw sign callback (e.g., HSM/secure element), private
1800+
* key may not be available. Use public key from signer certificate
1801+
* for signature size calculation. */
1802+
idx = 0;
1803+
ret = wc_RsaPublicKeyDecode(pkcs7->publicKey, &idx, privKey,
1804+
pkcs7->publicKeySz);
1805+
}
1806+
#endif
17971807
else if (pkcs7->devId == INVALID_DEVID) {
17981808
ret = BAD_FUNC_ARG;
17991809
}
@@ -1874,6 +1884,16 @@ static int wc_PKCS7_ImportECC(wc_PKCS7* pkcs7, ecc_key* privKey)
18741884
}
18751885
#endif
18761886
}
1887+
#ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK
1888+
else if (pkcs7->eccSignRawDigestCb != NULL && pkcs7->publicKeySz > 0) {
1889+
/* When using raw sign callback (e.g., HSM/secure element), private
1890+
* key may not be available. Use public key from signer certificate
1891+
* for signature size calculation. */
1892+
idx = 0;
1893+
ret = wc_EccPublicKeyDecode(pkcs7->publicKey, &idx, privKey,
1894+
pkcs7->publicKeySz);
1895+
}
1896+
#endif
18771897
else if (pkcs7->devId == INVALID_DEVID) {
18781898
ret = BAD_FUNC_ARG;
18791899
}
@@ -2398,6 +2418,20 @@ static int wc_PKCS7_SignedDataBuildSignature(wc_PKCS7* pkcs7,
23982418

23992419
#ifdef HAVE_ECC
24002420
case ECDSAk:
2421+
#ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK
2422+
if (pkcs7->eccSignRawDigestCb != NULL) {
2423+
/* get hash OID */
2424+
int eccHashOID = wc_HashGetOID(esd->hashType);
2425+
2426+
/* user signing plain digest */
2427+
ret = pkcs7->eccSignRawDigestCb(pkcs7,
2428+
esd->contentAttribsDigest, hashSz,
2429+
esd->encContentDigest, sizeof(esd->encContentDigest),
2430+
pkcs7->privateKey, pkcs7->privateKeySz, pkcs7->devId,
2431+
eccHashOID);
2432+
break;
2433+
}
2434+
#endif
24012435
/* CMS with ECDSA does not sign DigestInfo structure
24022436
* like PKCS#7 with RSA does */
24032437
ret = wc_PKCS7_EcdsaSign(pkcs7, esd->contentAttribsDigest,
@@ -3986,6 +4020,30 @@ int wc_PKCS7_SetRsaSignRawDigestCb(wc_PKCS7* pkcs7, CallbackRsaSignRawDigest cb)
39864020
}
39874021
#endif
39884022

4023+
#endif /* NO_RSA */
4024+
4025+
4026+
#ifdef HAVE_ECC
4027+
4028+
#ifdef HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK
4029+
/* register raw ECC sign digest callback */
4030+
int wc_PKCS7_SetEccSignRawDigestCb(wc_PKCS7* pkcs7, CallbackEccSignRawDigest cb)
4031+
{
4032+
if (pkcs7 == NULL || cb == NULL) {
4033+
return BAD_FUNC_ARG;
4034+
}
4035+
4036+
pkcs7->eccSignRawDigestCb = cb;
4037+
4038+
return 0;
4039+
}
4040+
#endif
4041+
4042+
#endif /* HAVE_ECC */
4043+
4044+
4045+
#ifndef NO_RSA
4046+
39894047
/* returns size of signature put into out, negative on error */
39904048
static int wc_PKCS7_RsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz,
39914049
byte* hash, word32 hashSz)

wolfssl/wolfcrypt/pkcs7.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ typedef int (*CallbackRsaSignRawDigest)(wc_PKCS7* pkcs7, byte* digest,
229229
int devId, int hashOID);
230230
#endif
231231

232+
#if defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && defined(HAVE_ECC)
233+
/* ECC sign raw digest callback, user signs hash directly */
234+
typedef int (*CallbackEccSignRawDigest)(wc_PKCS7* pkcs7, byte* digest,
235+
word32 digestSz, byte* out, word32 outSz,
236+
byte* privateKey, word32 privateKeySz,
237+
int devId, int hashOID);
238+
#endif
239+
232240

233241
/* Public Structure Warning:
234242
* Existing members must not be changed to maintain backwards compatibility!
@@ -376,6 +384,10 @@ struct wc_PKCS7 {
376384

377385
CallbackAESKeyWrapUnwrap aesKeyWrapUnwrapCb;
378386

387+
#if defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && defined(HAVE_ECC)
388+
CallbackEccSignRawDigest eccSignRawDigestCb;
389+
#endif
390+
379391
/* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */
380392
};
381393

@@ -511,6 +523,11 @@ WOLFSSL_API int wc_PKCS7_SetRsaSignRawDigestCb(wc_PKCS7* pkcs7,
511523
CallbackRsaSignRawDigest cb);
512524
#endif
513525

526+
#if defined(HAVE_PKCS7_ECC_RAW_SIGN_CALLBACK) && defined(HAVE_ECC)
527+
WOLFSSL_API int wc_PKCS7_SetEccSignRawDigestCb(wc_PKCS7* pkcs7,
528+
CallbackEccSignRawDigest cb);
529+
#endif
530+
514531
/* CMS/PKCS#7 EnvelopedData */
515532
WOLFSSL_API int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7,
516533
byte* output, word32 outputSz);

0 commit comments

Comments
 (0)