diff --git a/.gitignore b/.gitignore index 58f4aa6ff..538acaa5b 100644 --- a/.gitignore +++ b/.gitignore @@ -111,6 +111,7 @@ pkcs7authEnvelopedDataAES256GCM.der pkcs7authEnvelopedDataAES256GCM_ECDH_SHA256KDF.der pkcs7authEnvelopedDataAES256GCM_ECDH_SHA512KDF.der pkcs7authEnvelopedDataAES256GCM_ECDH_SHA512KDF_ukm.der +pkcs7authEnvelopedDataAES256GCM_firmwarePkgData.der pkcs7authEnvelopedDataAES256GCM_IANDS.der pkcs7authEnvelopedDataAES256GCM_SKID.der pkcs7compressedData_data_zlib.der diff --git a/Makefile.am b/Makefile.am index 85d8f76e0..6213db8f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,6 +49,7 @@ CLEANFILES+= cert.der \ pkcs7authEnvelopedDataAES256GCM_ECDH_SHA256KDF.der \ pkcs7authEnvelopedDataAES256GCM_ECDH_SHA512KDF.der \ pkcs7authEnvelopedDataAES256GCM_ECDH_SHA512KDF_ukm.der \ + pkcs7authEnvelopedDataAES256GCM_firmwarePkgData.der \ pkcs7authEnvelopedDataAES256GCM_IANDS.der \ pkcs7authEnvelopedDataAES256GCM_SKID.der \ pkcs7compressedData_data_zlib.der \ diff --git a/tests/api.c b/tests/api.c index d3f0ad366..e87552e66 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14854,18 +14854,21 @@ static void test_wc_PKCS7_New (void) static void test_wc_PKCS7_Init (void) { #if defined(HAVE_PKCS7) - PKCS7 pkcs7; + PKCS7* pkcs7; void* heap = NULL; printf(testingFmt, "wc_PKCS7_Init()"); - AssertIntEQ(wc_PKCS7_Init(&pkcs7, heap, devId), 0); + pkcs7 = wc_PKCS7_New(heap, devId); + AssertNotNull(pkcs7); + + AssertIntEQ(wc_PKCS7_Init(pkcs7, heap, devId), 0); /* Pass in bad args. */ AssertIntEQ(wc_PKCS7_Init(NULL, heap, devId), BAD_FUNC_ARG); printf(resultFmt, passed); - wc_PKCS7_Free(&pkcs7); + wc_PKCS7_Free(pkcs7); #endif } /* END test-wc_PKCS7_Init */ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 6c39920df..5148e81b1 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -176,8 +176,10 @@ static int wc_SetContentType(int pkcs7TypeOID, byte* output, word32 outputSz) return 0; }; - if (outputSz < (MAX_LENGTH_SZ + 1 + typeSz)) + if (outputSz < (MAX_LENGTH_SZ + 1 + typeSz)) { + WOLFSSL_MSG("CMS content type buffer too small"); return BAD_FUNC_ARG; + } idSz = SetLength(typeSz, ID_Length); output[idx++] = ASN_OBJECT_ID; @@ -7117,6 +7119,23 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, byte macInt[MAX_VERSION_SZ]; word32 nonceSz, macIntSz; + byte* flatAuthAttribs = NULL; + word32 flatAuthAttribsSz = 0; + byte* aadBuffer = NULL; + word32 aadBufferSz = 0; + byte authAttribSet[MAX_SET_SZ]; + byte authAttribAadSet[MAX_SET_SZ]; + EncodedAttrib authAttribs[MAX_SIGNED_ATTRIBS_SZ]; + word32 authAttribsSz = 0, authAttribsCount = 0; + word32 authAttribsSetSz = 0, authAttribsAadSetSz = 0; + + PKCS7Attrib contentTypeAttrib; + byte contentTypeValue[MAX_OID_SZ]; + /* contentType OID (1.2.840.113549.1.9.3) */ + const byte contentTypeOid[] = + { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, + 0x09, 0x03 }; + if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0) return BAD_FUNC_ARG; @@ -7219,20 +7238,99 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, return ret; } + /* build up authenticated attributes (authAttrs) */ + if (pkcs7->contentOID != DATA) { + + /* if type is not id-data, contentType attribute MUST be added */ + contentTypeAttrib.oid = contentTypeOid; + contentTypeAttrib.oidSz = sizeof(contentTypeOid); + + /* try to set from contentOID first, known types */ + ret = wc_SetContentType(pkcs7->contentOID, contentTypeValue, + sizeof(contentTypeValue)); + if (ret > 0) { + contentTypeAttrib.value = contentTypeValue; + contentTypeAttrib.valueSz = ret; + + } else if (ret <= 0) { + /* try to set from custom content type */ + if (pkcs7->contentType == NULL || pkcs7->contentTypeSz == 0) { + WOLFSSL_MSG("CMS pkcs7->contentType must be set if " + "contentOID is not"); + return BAD_FUNC_ARG; + } + contentTypeAttrib.value = pkcs7->contentType; + contentTypeAttrib.valueSz = pkcs7->contentTypeSz; + } + + authAttribsCount += 1; + authAttribsSz += EncodeAttributes(authAttribs, 1, + &contentTypeAttrib, 1); + + /* add in user's signed attributes */ + if (pkcs7->authAttribsSz > 0) { + authAttribsCount += pkcs7->authAttribsSz; + authAttribsSz += EncodeAttributes(authAttribs + + authAttribsCount * sizeof(PKCS7Attrib), + MAX_SIGNED_ATTRIBS_SZ - authAttribsCount, + pkcs7->authAttribs, + pkcs7->authAttribsSz); + + } + + flatAuthAttribs = (byte*)XMALLOC(authAttribsSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + flatAuthAttribsSz = authAttribsSz; + if (flatAuthAttribs == NULL) { + return MEMORY_E; + } + + FlattenAttributes(flatAuthAttribs, authAttribs, authAttribsCount); + authAttribsSetSz = SetImplicit(ASN_SET, 1, authAttribsSz, + authAttribSet); + + /* From RFC5083, "For the purpose of constructing the AAD, the + * IMPLICIT [1] tag in the authAttrs field is not used for the + * DER encoding: rather a universal SET OF tag is used. */ + authAttribsAadSetSz = SetSet(authAttribsSz, authAttribAadSet); + + /* allocate temp buffer to hold alternate attrib encoding for aad */ + aadBuffer = (byte*)XMALLOC(flatAuthAttribsSz + authAttribsAadSetSz, + pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (aadBuffer == NULL) { + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return MEMORY_E; + } + + /* build up alternate attrib encoding for aad */ + aadBufferSz = 0; + XMEMCPY(aadBuffer + aadBufferSz, authAttribAadSet, authAttribsAadSetSz); + aadBufferSz += authAttribsAadSetSz; + XMEMCPY(aadBuffer + aadBufferSz, flatAuthAttribs, flatAuthAttribsSz); + aadBufferSz += flatAuthAttribsSz; + } + /* allocate encrypted content buffer */ encryptedOutSz = pkcs7->contentSz; - encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (encryptedContent == NULL) + if (encryptedContent == NULL) { + if (flatAuthAttribs) + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return MEMORY_E; + } /* encrypt content */ ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->cek, - pkcs7->cekSz, nonce, nonceSz, NULL, 0, authTag, sizeof(authTag), - pkcs7->content, encryptedOutSz, encryptedContent); + pkcs7->cekSz, nonce, nonceSz, aadBuffer, aadBufferSz, authTag, + sizeof(authTag), pkcs7->content, encryptedOutSz, encryptedContent); + + if (aadBuffer) + XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); if (ret != 0) { + if (flatAuthAttribs) + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } @@ -7240,8 +7338,12 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, /* EncryptedContentInfo */ ret = wc_SetContentType(pkcs7->contentOID, contentType, sizeof(contentType)); - if (ret < 0) + if (ret < 0) { + if (flatAuthAttribs) + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; + } contentTypeSz = ret; @@ -7259,6 +7361,8 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, macIntSz); if (contentEncAlgoSz == 0) { + if (flatAuthAttribs) + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return BAD_FUNC_ARG; } @@ -7276,8 +7380,8 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, /* keep track of sizes for outer wrapper layering */ totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + nonceOctetStringSz + nonceSz + macIntSz + - encContentOctetSz + encryptedOutSz + macOctetStringSz + - sizeof(authTag); + encContentOctetSz + encryptedOutSz + flatAuthAttribsSz + + authAttribsSetSz + macOctetStringSz + sizeof(authTag); /* EnvelopedData */ envDataSeqSz = SetSequence(totalSz, envDataSeq); @@ -7294,6 +7398,8 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, if (totalSz > (int)outputSz) { WOLFSSL_MSG("Pkcs7_encrypt output buffer too small"); + if (flatAuthAttribs) + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return BUFFER_E; } @@ -7334,6 +7440,16 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, idx += encContentOctetSz; XMEMCPY(output + idx, encryptedContent, encryptedOutSz); idx += encryptedOutSz; + + /* authenticated attributes */ + if (flatAuthAttribsSz > 0) { + XMEMCPY(output + idx, authAttribSet, authAttribsSetSz); + idx += authAttribsSetSz; + XMEMCPY(output + idx, flatAuthAttribs, flatAuthAttribsSz); + idx += flatAuthAttribsSz; + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + } + XMEMCPY(output + idx, macOctetString, macOctetStringSz); idx += macOctetStringSz; XMEMCPY(output + idx, authTag, sizeof(authTag)); @@ -7370,6 +7486,12 @@ WOLFSSL_API int wc_PKCS7_DecodeAuthEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, byte* encryptedContent = NULL; int explicitOctet; + byte authAttribSetByte = 0; + byte* encodedAttribs = NULL; + word32 encodedAttribIdx = 0, encodedAttribSz = 0; + byte* authAttrib = NULL; + int authAttribSz = 0; + if (pkcs7 == NULL) return BAD_FUNC_ARG; @@ -7527,6 +7649,28 @@ WOLFSSL_API int wc_PKCS7_DecodeAuthEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); idx += encryptedContentSz; + /* may have IMPLICIT [1] authenticatedAttributes */ + if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + encodedAttribIdx = idx; + encodedAttribs = pkiMsg + idx; + idx++; + + if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* save pointer and length */ + authAttrib = &pkiMsg[idx]; + authAttribSz = length; + encodedAttribSz = length + (idx - encodedAttribIdx); + + if (wc_PKCS7_ParseAttribs(pkcs7, authAttrib, authAttribSz) < 0) { + WOLFSSL_MSG("Error parsing authenticated attributes"); + return ASN_PARSE_E; + } + + idx += length; + } + /* get authTag OCTET STRING */ if (pkiMsg[idx++] != ASN_OCTET_STRING) { #ifdef WOLFSSL_SMALL_STACK @@ -7553,11 +7697,20 @@ WOLFSSL_API int wc_PKCS7_DecodeAuthEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, XMEMCPY(authTag, &pkiMsg[idx], authTagSz); idx += authTagSz; + if (authAttrib != NULL) { + /* temporarily swap authAttribs byte[0] to SET OF instead of + * IMPLICIT [1], for aad calculation */ + authAttribSetByte = encodedAttribs[0]; + + encodedAttribs[0] = ASN_SET | ASN_CONSTRUCTED; + } + /* decrypt encryptedContent */ ret = wc_PKCS7_DecryptContent(encOID, decryptedKey, blockKeySz, - nonce, nonceSz, NULL, 0, authTag, - authTagSz, encryptedContent, - encryptedContentSz, encryptedContent); + nonce, nonceSz, encodedAttribs, + encodedAttribSz, authTag, authTagSz, + encryptedContent, encryptedContentSz, + encryptedContent); if (ret != 0) { XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK @@ -7566,6 +7719,11 @@ WOLFSSL_API int wc_PKCS7_DecodeAuthEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, return ret; } + if (authAttrib != NULL) { + /* restore authAttrib IMPLICIT [1] */ + encodedAttribs[0] = authAttribSetByte; + } + /* copy plaintext to output */ XMEMCPY(output, encryptedContent, encryptedContentSz); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index d7f19cb4d..2c007286a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -19640,6 +19640,12 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, NULL, NULL, 0, NULL, 0, 0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, "pkcs7authEnvelopedDataAES256GCM.der"}, + /* test with contentType set to FirmwarePkgData */ + {data, (word32)sizeof(data), FIRMWARE_PKG_DATA, AES256GCMb, 0, 0, + rsaCert, rsaCertSz, rsaPrivKey, rsaPrivKeySz, NULL, 0, NULL, 0, 0, 0, + NULL, 0, NULL, 0, NULL, NULL, 0, NULL, 0, 0, NULL, 0, NULL, 0, 0, 0, + 0, 0, 0, 0, 0, "pkcs7authEnvelopedDataAES256GCM_firmwarePkgData.der"}, + /* explicitly using SKID for SubjectKeyIdentifier */ {data, (word32)sizeof(data), DATA, AES256GCMb, 0, 0, rsaCert, rsaCertSz, rsaPrivKey, rsaPrivKeySz, NULL, 0, NULL, 0, CMS_SKID, 0, NULL, 0, @@ -19797,7 +19803,6 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, testVectors[i].kekEncryptOID, testVectors[i].pwriOptions); if (ret < 0) { - printf("CHRIS: ret = %d\n", ret); wc_PKCS7_Free(pkcs7); return -9219; } diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 49a413d7b..9f2d19fff 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -58,6 +58,10 @@ #define MAX_ORI_VALUE_SZ 512 #endif +#ifndef MAX_SIGNED_ATTRIBS_SZ + #define MAX_SIGNED_ATTRIBS_SZ 7 +#endif + /* PKCS#7 content types, ref RFC 2315 (Section 14) */ enum PKCS7_TYPES { PKCS7_MSG = 650, /* 1.2.840.113549.1.7 */ @@ -205,6 +209,9 @@ typedef struct PKCS7 { void* oriEncryptCtx; /* ORI encrypt user context ptr */ void* oriDecryptCtx; /* ORI decrypt user context ptr */ + PKCS7Attrib* authAttribs; /* authenticated attribs */ + word32 authAttribsSz; + /* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */ } PKCS7;