@@ -1300,6 +1300,40 @@ static int wolfCose_EncodeKeyOptionalFields(WOLFCOSE_CBOR_CTX* ctx,
13001300 return ret ;
13011301}
13021302
1303+ #ifdef WOLFCOSE_HAVE_RSA_PRIVATE_KEY
1304+ /* RFC 8230: write one RSA component (label + bstr) from its mp_int. */
1305+ static int wolfCose_EncodeRsaMp (WOLFCOSE_CBOR_CTX * ctx , int64_t label ,
1306+ mp_int * a , word32 keySz )
1307+ {
1308+ int ret = WOLFCOSE_SUCCESS ;
1309+ word32 len = keySz ;
1310+
1311+ if (keySz == 0u ) {
1312+ ret = WOLFCOSE_E_INVALID_ARG ;
1313+ }
1314+ if (ret == WOLFCOSE_SUCCESS ) {
1315+ ret = wc_CBOR_EncodeInt (ctx , label );
1316+ }
1317+ if (ret == WOLFCOSE_SUCCESS ) {
1318+ ret = wolfCose_CBOR_EncodeHead (ctx , WOLFCOSE_CBOR_BSTR ,
1319+ (uint64_t )keySz );
1320+ }
1321+ if (ret == WOLFCOSE_SUCCESS ) {
1322+ if ((ctx -> idx + (size_t )keySz ) > ctx -> bufSz ) {
1323+ ret = WOLFCOSE_E_BUFFER_TOO_SMALL ;
1324+ }
1325+ else if (wc_export_int (a , & ctx -> buf [ctx -> idx ], & len , keySz ,
1326+ WC_TYPE_UNSIGNED_BIN ) != 0 ) {
1327+ ret = WOLFCOSE_E_CRYPTO ;
1328+ }
1329+ else {
1330+ ctx -> idx += (size_t )len ;
1331+ }
1332+ }
1333+ return ret ;
1334+ }
1335+ #endif /* WOLFCOSE_HAVE_RSA_PRIVATE_KEY */
1336+
13031337int wc_CoseKey_Encode (WOLFCOSE_KEY * key , uint8_t * out , size_t outSz ,
13041338 size_t * outLen )
13051339{
@@ -1412,19 +1446,40 @@ int wc_CoseKey_Encode(WOLFCOSE_KEY* key, uint8_t* out, size_t outSz,
14121446#endif /* HAVE_ECC */
14131447#ifdef WOLFCOSE_HAVE_RSAPSS
14141448 if (key -> kty == WOLFCOSE_KTY_RSA ) {
1415- /* RFC 8230: {1:3, -1:n_bstr , -2:e_bstr [, -3:d_bstr]}
1416- * Export n and d directly into output buffer to avoid
1417- * large stack allocations (RSA-4096 modulus = 512 bytes). */
1449+ /* RFC 8230: {1:3, -1:n , -2:e [, -3:d, -4:p, -5:q, -8:qInv]}.
1450+ * Export large components straight into the output buffer to
1451+ * avoid stack copies (RSA-4096 modulus = 512 bytes). */
14181452 uint8_t eBuf [8 ]; /* exponent, typically 3 bytes */
14191453 word32 eLen = (word32 )sizeof (eBuf );
14201454 word32 nLen ;
14211455 size_t hdrPos ;
14221456 size_t mapEntries ;
1457+ int rsaPriv = 0 ;
1458+ #ifdef WOLFCOSE_HAVE_RSA_PRIVATE_KEY
1459+ word32 halfSz = 0 ;
1460+ #endif
14231461
1462+ if (key -> key .rsa == NULL ) {
1463+ ret = WOLFCOSE_E_INVALID_ARG ;
1464+ }
1465+ /* Private round-trip needs the CRT export; else public-only. */
1466+ #ifdef WOLFCOSE_HAVE_RSA_PRIVATE_KEY
1467+ if ((ret == WOLFCOSE_SUCCESS ) && (key -> hasPrivate != 0u )) {
1468+ rsaPriv = 1 ;
1469+ #ifdef WOLF_CRYPTO_CB
1470+ /* Device-backed keys have no local CRT to export. */
1471+ if (key -> key .rsa -> devId != INVALID_DEVID ) {
1472+ rsaPriv = 0 ;
1473+ }
1474+ #endif
1475+ }
1476+ #endif
14241477 /* Get n directly into output buffer, e into small stack buf */
1425- mapEntries = (key -> hasPrivate != 0u ) ? (size_t )4 : (size_t )3 ;
1478+ mapEntries = (rsaPriv != 0 ) ? (size_t )7 : (size_t )3 ;
14261479 mapEntries += wolfCose_KeyOptionalEntries (key );
1427- ret = wc_CBOR_EncodeMapStart (& ctx , mapEntries );
1480+ if (ret == WOLFCOSE_SUCCESS ) {
1481+ ret = wc_CBOR_EncodeMapStart (& ctx , mapEntries );
1482+ }
14281483
14291484 /* 1: kty */
14301485 if (ret == WOLFCOSE_SUCCESS ) {
@@ -1477,7 +1532,7 @@ int wc_CoseKey_Encode(WOLFCOSE_KEY* key, uint8_t* out, size_t outSz,
14771532 ret = wc_CBOR_EncodeBstr (& ctx , eBuf , (size_t )eLen );
14781533 }
14791534 /* -3: d (private exponent, optional) — direct export */
1480- if ((ret == WOLFCOSE_SUCCESS ) && (key -> hasPrivate != 0u )) {
1535+ if ((ret == WOLFCOSE_SUCCESS ) && (rsaPriv != 0 )) {
14811536 ret = wc_CBOR_EncodeInt (& ctx ,
14821537 (int64_t )WOLFCOSE_KEY_LABEL_Y );
14831538 if (ret == WOLFCOSE_SUCCESS ) {
@@ -1555,6 +1610,30 @@ int wc_CoseKey_Encode(WOLFCOSE_KEY* key, uint8_t* out, size_t outSz,
15551610 }
15561611 }
15571612 }
1613+ #ifdef WOLFCOSE_HAVE_RSA_PRIVATE_KEY
1614+ /* -4 p, -5 q, -8 qInv: CRT factors so a decoded key can sign. */
1615+ if ((ret == WOLFCOSE_SUCCESS ) && (rsaPriv != 0 )) {
1616+ int modSz = wc_RsaEncryptSize (key -> key .rsa );
1617+ if (modSz <= 0 ) {
1618+ ret = WOLFCOSE_E_CRYPTO ;
1619+ }
1620+ else {
1621+ halfSz = ((word32 )modSz + 1u ) / 2u ;
1622+ }
1623+ }
1624+ if ((ret == WOLFCOSE_SUCCESS ) && (rsaPriv != 0 )) {
1625+ ret = wolfCose_EncodeRsaMp (& ctx , WOLFCOSE_KEY_LABEL_RSA_P ,
1626+ & key -> key .rsa -> p , halfSz );
1627+ }
1628+ if ((ret == WOLFCOSE_SUCCESS ) && (rsaPriv != 0 )) {
1629+ ret = wolfCose_EncodeRsaMp (& ctx , WOLFCOSE_KEY_LABEL_RSA_Q ,
1630+ & key -> key .rsa -> q , halfSz );
1631+ }
1632+ if ((ret == WOLFCOSE_SUCCESS ) && (rsaPriv != 0 )) {
1633+ ret = wolfCose_EncodeRsaMp (& ctx , WOLFCOSE_KEY_LABEL_RSA_QINV ,
1634+ & key -> key .rsa -> u , halfSz );
1635+ }
1636+ #endif /* WOLFCOSE_HAVE_RSA_PRIVATE_KEY */
15581637
15591638 if (ret == WOLFCOSE_SUCCESS ) {
15601639 * outLen = ctx .idx ;
@@ -1851,10 +1930,16 @@ int wc_CoseKey_Decode(WOLFCOSE_KEY* key, const uint8_t* in, size_t inSz)
18511930 size_t xLen = 0 ;
18521931 const uint8_t * yData = NULL ; /* EC2: y coord, RSA: d (private exp) */
18531932 size_t yLen = 0 ;
1854- const uint8_t * dData = NULL ; /* EC2/OKP: private key */
1933+ const uint8_t * dData = NULL ; /* EC2/OKP: private key, RSA: p */
18551934 size_t dLen = 0 ;
18561935 const uint8_t * nData = NULL ; /* RSA: n (modulus) */
18571936 size_t nLen = 0 ;
1937+ #ifdef WOLFCOSE_HAVE_RSA_PRIVATE_KEY
1938+ const uint8_t * qData = NULL ; /* RSA: q (second prime) */
1939+ size_t qLen = 0 ;
1940+ const uint8_t * qiData = NULL ; /* RSA: qInv (CRT coefficient) */
1941+ size_t qiLen = 0 ;
1942+ #endif
18581943 WOLFCOSE_HDR_STATE keyLabelState ;
18591944
18601945 if ((key == NULL ) || (in == NULL ) || (inSz == 0u )) {
@@ -1975,6 +2060,16 @@ int wc_CoseKey_Decode(WOLFCOSE_KEY* key, const uint8_t* in, size_t inSz)
19752060 (label == WOLFCOSE_KEY_LABEL_D )) {
19762061 ret = wc_CBOR_DecodeBstr (& ctx , & dData , & dLen );
19772062 }
2063+ #ifdef WOLFCOSE_HAVE_RSA_PRIVATE_KEY
2064+ else if ((ret == WOLFCOSE_SUCCESS ) &&
2065+ (label == WOLFCOSE_KEY_LABEL_RSA_Q )) {
2066+ ret = wc_CBOR_DecodeBstr (& ctx , & qData , & qLen );
2067+ }
2068+ else if ((ret == WOLFCOSE_SUCCESS ) &&
2069+ (label == WOLFCOSE_KEY_LABEL_RSA_QINV )) {
2070+ ret = wc_CBOR_DecodeBstr (& ctx , & qiData , & qiLen );
2071+ }
2072+ #endif
19782073 else {
19792074 if (ret == WOLFCOSE_SUCCESS ) {
19802075 ret = wc_CBOR_Skip (& ctx );
@@ -2072,10 +2167,27 @@ int wc_CoseKey_Decode(WOLFCOSE_KEY* key, const uint8_t* in, size_t inSz)
20722167#endif
20732168#ifdef WOLFCOSE_HAVE_RSAPSS
20742169 if ((key -> kty == WOLFCOSE_KTY_RSA ) && (key -> key .rsa != NULL )) {
2075- /* RFC 8230: -1=n(bstr) , -2=e(bstr) , -3=d(bstr) */
2170+ /* RFC 8230: -1 n , -2 e , -3 d, -4 p, -5 q, -8 qInv. */
20762171 if ((nData == NULL ) || (xData == NULL )) {
20772172 ret = WOLFCOSE_E_COSE_BAD_HDR ;
20782173 }
2174+ #ifdef WOLFCOSE_HAVE_RSA_PRIVATE_KEY
2175+ else if ((yData != NULL) && (dData != NULL) &&
2176+ (qData != NULL) && (qiData != NULL)) {
2177+ INJECT_FAILURE (WOLF_FAIL_RSA_PUBLIC_DECODE , -1 )
2178+ ret = wc_RsaPrivateKeyDecodeRaw (nData , (word32 )nLen ,
2179+ xData , (word32 )xLen , yData , (word32 )yLen ,
2180+ qiData , (word32 )qiLen , dData , (word32 )dLen ,
2181+ qData , (word32 )qLen , NULL , 0 , NULL , 0 ,
2182+ key -> key .rsa );
2183+ if (ret != 0 ) {
2184+ ret = WOLFCOSE_E_CRYPTO ;
2185+ }
2186+ else {
2187+ key -> hasPrivate = 1u ;
2188+ }
2189+ }
2190+ #endif /* WOLFCOSE_HAVE_RSA_PRIVATE_KEY */
20792191 else {
20802192 INJECT_FAILURE (WOLF_FAIL_RSA_PUBLIC_DECODE , -1 )
20812193 {
@@ -2086,9 +2198,6 @@ int wc_CoseKey_Decode(WOLFCOSE_KEY* key, const uint8_t* in, size_t inSz)
20862198 ret = WOLFCOSE_E_CRYPTO ;
20872199 }
20882200 else {
2089- /* TODO(#34): public key only. RSA private round-trip
2090- * needs n,e,d,p,q,qInv via wc_RsaPrivateKeyDecodeRaw;
2091- * the COSE_Key format must also carry p,q,qInv. */
20922201 key -> hasPrivate = 0u ;
20932202 }
20942203 }
0 commit comments