diff --git a/tests/api.c b/tests/api.c index d9c75f675..585c18374 100644 --- a/tests/api.c +++ b/tests/api.c @@ -26916,13 +26916,56 @@ static int test_wc_PKCS7_EncodeSignedData(void) } ExpectIntGT(wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz), 0); - wc_PKCS7_Free(pkcs7); pkcs7 = NULL; + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, output, outputSz), 0); +#ifdef ASN_BER_TO_DER + wc_PKCS7_Free(pkcs7); + + /* reinitialize and test setting stream mode */ + { + int signedSz; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0); + + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); + + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->privateKey = key; + pkcs7->privateKeySz = (word32)sizeof(key); + pkcs7->encryptOID = RSAk; + #ifdef NO_SHA + pkcs7->hashOID = SHA256h; + #else + pkcs7->hashOID = SHAh; + #endif + pkcs7->rng = &rng; + } + ExpectIntEQ(wc_PKCS7_GetStreamMode(pkcs7), 0); + ExpectIntEQ(wc_PKCS7_SetStreamMode(pkcs7, 1), 0); + ExpectIntEQ(wc_PKCS7_SetStreamMode(NULL, 1), BAD_FUNC_ARG); + ExpectIntEQ(wc_PKCS7_GetStreamMode(pkcs7), 1); + + ExpectIntGT(signedSz = wc_PKCS7_EncodeSignedData(pkcs7, output, + outputSz), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); + + /* use exact signed buffer size since BER encoded */ + ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, output, signedSz), 0); + } +#endif + /* Pass in bad args. */ ExpectIntEQ(wc_PKCS7_EncodeSignedData(NULL, output, outputSz), BAD_FUNC_ARG); @@ -27953,6 +27996,9 @@ static int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) EXPECT_DECLS; #if defined(HAVE_PKCS7) PKCS7* pkcs7 = NULL; +#ifdef ASN_BER_TO_DER + int encodedSz = 0; +#endif #ifdef ECC_TIMING_RESISTANT WC_RNG rng; #endif @@ -28153,6 +28199,39 @@ static int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) testSz = (int)sizeof(testVectors)/(int)sizeof(pkcs7EnvelopedVector); for (i = 0; i < testSz; i++) { + #ifdef ASN_BER_TO_DER + /* test setting stream mode */ + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (testVectors + i)->cert, + (word32)(testVectors + i)->certSz), 0); + if (pkcs7 != NULL) { + #ifdef ECC_TIMING_RESISTANT + pkcs7->rng = &rng; + #endif + + pkcs7->content = (byte*)(testVectors + i)->content; + pkcs7->contentSz = (testVectors + i)->contentSz; + pkcs7->contentOID = (testVectors + i)->contentOID; + pkcs7->encryptOID = (testVectors + i)->encryptOID; + pkcs7->keyWrapOID = (testVectors + i)->keyWrapOID; + pkcs7->keyAgreeOID = (testVectors + i)->keyAgreeOID; + pkcs7->privateKey = (testVectors + i)->privateKey; + pkcs7->privateKeySz = (testVectors + i)->privateKeySz; + } + ExpectIntEQ(wc_PKCS7_SetStreamMode(pkcs7, 1), 0); + + ExpectIntGE(encodedSz = wc_PKCS7_EncodeEnvelopedData(pkcs7, output, + (word32)sizeof(output)), 0); + + decodedSz = wc_PKCS7_DecodeEnvelopedData(pkcs7, output, + (word32)encodedSz, decoded, (word32)sizeof(decoded)); + ExpectIntGE(decodedSz, 0); + /* Verify the size of each buffer. */ + ExpectIntEQ((word32)sizeof(input)/sizeof(char), decodedSz); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + #endif + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (testVectors + i)->cert, (word32)(testVectors + i)->certSz), 0); if (pkcs7 != NULL) { @@ -28170,6 +28249,11 @@ static int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) pkcs7->privateKeySz = (testVectors + i)->privateKeySz; } + #ifdef ASN_BER_TO_DER + /* test without setting stream mode */ + ExpectIntEQ(wc_PKCS7_GetStreamMode(pkcs7), 0); + #endif + ExpectIntGE(wc_PKCS7_EncodeEnvelopedData(pkcs7, output, (word32)sizeof(output)), 0); @@ -28178,6 +28262,7 @@ static int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) ExpectIntGE(decodedSz, 0); /* Verify the size of each buffer. */ ExpectIntEQ((word32)sizeof(input)/sizeof(char), decodedSz); + /* Don't free the last time through the loop. */ if (i < testSz - 1) { wc_PKCS7_Free(pkcs7); @@ -28871,7 +28956,6 @@ static int test_wc_PKCS7_signed_enveloped(void) #ifdef HAVE_AES_CBC PKCS7* inner = NULL; #endif - void* pt = NULL; WC_RNG rng; unsigned char key[FOURK_BUF/2]; unsigned char cert[FOURK_BUF/2]; @@ -28958,17 +29042,13 @@ static int test_wc_PKCS7_signed_enveloped(void) pkcs7->rng = &rng; } - /* Set no certs in bundle for this test. Hang on to the pointer though to - * free it later. */ + /* Set no certs in bundle for this test. */ if (pkcs7 != NULL) { - pt = (void*)pkcs7->certList; - pkcs7->certList = NULL; /* no certs in bundle */ + ExpectIntEQ(wc_PKCS7_SetNoCerts(pkcs7, 1), 0); + ExpectIntEQ(wc_PKCS7_SetNoCerts(NULL, 1), BAD_FUNC_ARG); + ExpectIntEQ(wc_PKCS7_GetNoCerts(pkcs7), 1); } ExpectIntGT((sigSz = wc_PKCS7_EncodeSignedData(pkcs7, sig, sigSz)), 0); - if (pkcs7 != NULL) { - /* restore pointer for PKCS7 free call */ - pkcs7->certList = (Pkcs7Cert*)pt; - } wc_PKCS7_Free(pkcs7); pkcs7 = NULL; diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 3b61f6fb5..b38ee124d 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -3460,6 +3460,70 @@ word32 SetBitString(word32 len, byte unusedBits, byte* output) #endif /* !NO_RSA || HAVE_ECC || HAVE_ED25519 || HAVE_ED448 */ #ifdef ASN_BER_TO_DER + +#define BER_OCTET_LENGTH 4096 + +/* sets the terminating 0x00 0x00 at the end of an indefinite length + * returns the number of bytes written */ +word32 SetIndefEnd(byte* output) +{ + byte terminate[ASN_INDEF_END_SZ] = { 0x00, 0x00 }; + + if (output != NULL) { + XMEMCPY(output, terminate, ASN_INDEF_END_SZ); + } + + return (word32)ASN_INDEF_END_SZ; +} + + +/* Breaks an octet string up into chunks for use with streaming + * returns 0 on success and updates idx */ +int StreamOctetString(const byte* inBuf, word32 inBufSz, byte* out, word32* outSz, + word32* idx) +{ + word32 i = 0; + word32 outIdx = *idx; + byte* tmp = out; + + if (tmp) tmp += outIdx; + + while (i < inBufSz) { + word32 ret, sz; + + sz = BER_OCTET_LENGTH; + + if ((sz + i) > inBufSz) { + sz = inBufSz - i; + } + + ret = SetOctetString(sz, tmp); + if (ret > 0) { + outIdx += ret; + } + + if (tmp) { + if ((word32)ret + sz + i + outIdx > *outSz) { + return BUFFER_E; + } + XMEMCPY(tmp + ret, inBuf + i, sz); + tmp += sz + ret; + } + outIdx += sz; + i += sz; + } + + if (tmp) { + *idx = outIdx; + return 0; + } + else { + *outSz = outIdx; + return LENGTH_ONLY_E; + } +} + + /* Convert BER to DER */ /* Pull informtation from the ASN.1 BER encoded item header */ @@ -15334,6 +15398,18 @@ word32 SetLength(word32 length, byte* output) return i; } +word32 SetLengthEx(word32 length, byte* output, byte isIndef) +{ + if (isIndef) { + if (output != NULL) { + output[0] = ASN_INDEF_LENGTH; + } + return 1; + } + else { + return SetLength(length, output); + } +} /* Encode a DER header - type/tag and length. * * @param [in] tag DER tag of ASN.1 item. @@ -15341,14 +15417,15 @@ word32 SetLength(word32 length, byte* output) * @param [out] output Buffer to encode into. * @return Number of bytes encoded. */ -static word32 SetHeader(byte tag, word32 len, byte* output) +static word32 SetHeader(byte tag, word32 len, byte* output, byte isIndef) { if (output) { /* Encode tag first. */ output[0] = tag; } /* Encode the length. */ - return SetLength(len, output ? output + ASN_TAG_SZ : NULL) + ASN_TAG_SZ; + return SetLengthEx(len, output ? output + ASN_TAG_SZ : NULL, isIndef) + + ASN_TAG_SZ; } /* Encode a SEQUENCE header in DER. @@ -15359,7 +15436,12 @@ static word32 SetHeader(byte tag, word32 len, byte* output) */ word32 SetSequence(word32 len, byte* output) { - return SetHeader(ASN_SEQUENCE | ASN_CONSTRUCTED, len, output); + return SetHeader(ASN_SEQUENCE | ASN_CONSTRUCTED, len, output, 0); +} + +word32 SetSequenceEx(word32 len, byte* output, byte isIndef) +{ + return SetHeader(ASN_SEQUENCE | ASN_CONSTRUCTED, len, output, isIndef); } /* Encode an OCTET STRING header in DER. @@ -15370,7 +15452,14 @@ word32 SetSequence(word32 len, byte* output) */ word32 SetOctetString(word32 len, byte* output) { - return SetHeader(ASN_OCTET_STRING, len, output); + return SetHeader(ASN_OCTET_STRING, len, output, 0); +} + +word32 SetOctetStringEx(word32 len, byte* output, byte indef) +{ + if (indef) + return SetHeader(ASN_OCTET_STRING | ASN_CONSTRUCTED, len, output, indef); + return SetOctetString(len, output); } /* Encode a SET header in DER. @@ -15381,7 +15470,7 @@ word32 SetOctetString(word32 len, byte* output) */ word32 SetSet(word32 len, byte* output) { - return SetHeader(ASN_SET | ASN_CONSTRUCTED, len, output); + return SetHeader(ASN_SET | ASN_CONSTRUCTED, len, output, 0); } /* Encode an implicit context specific header in DER. @@ -15394,11 +15483,23 @@ word32 SetSet(word32 len, byte* output) * @param [out] output Buffer to encode into. * @return Number of bytes encoded. */ -word32 SetImplicit(byte tag, byte number, word32 len, byte* output) +word32 SetImplicit(byte tag, byte number, word32 len, byte* output, byte isIndef) { - tag = (byte)(((tag == ASN_SEQUENCE || tag == ASN_SET) ? ASN_CONSTRUCTED : 0) - | ASN_CONTEXT_SPECIFIC | number); - return SetHeader(tag, len, output); + byte useIndef = 0; + + if ((tag == ASN_OCTET_STRING) && isIndef) { + tag = ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | number; + } + else { + tag = (byte)(((tag == ASN_SEQUENCE || tag == ASN_SET) ? + ASN_CONSTRUCTED : 0) | ASN_CONTEXT_SPECIFIC | number); + } + + if (isIndef && (tag & ASN_CONSTRUCTED)) { + useIndef = 1; + } + + return SetHeader(tag, len, output, useIndef); } /* Encode an explicit context specific header in DER. @@ -15410,10 +15511,10 @@ word32 SetImplicit(byte tag, byte number, word32 len, byte* output) * @param [out] output Buffer to encode into. * @return Number of bytes encoded. */ -word32 SetExplicit(byte number, word32 len, byte* output) +word32 SetExplicit(byte number, word32 len, byte* output, byte isIndef) { return SetHeader((byte)(ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | number), - len, output); + len, output, isIndef); } #if defined(OPENSSL_EXTRA) @@ -15439,8 +15540,8 @@ word32 SetOthername(void *name, byte *output) nameSz = (word32)nm->value->value.utf8string->length; len = nm->type_id->objSz + - SetHeader(ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC, nameSz + 2, NULL) + - SetHeader(CTC_UTF8, nameSz, NULL) + nameSz; + SetHeader(ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC, nameSz + 2, NULL, 0) + + SetHeader(CTC_UTF8, nameSz, NULL, 0) + nameSz; if (output != NULL) { /* otherName OID */ @@ -15448,9 +15549,9 @@ word32 SetOthername(void *name, byte *output) output += nm->type_id->objSz; output += SetHeader(ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC, nameSz + 2, - output); + output, 0); - output += SetHeader(CTC_UTF8, nameSz, output); + output += SetHeader(CTC_UTF8, nameSz, output, 0); XMEMCPY(output, nameStr, nameSz); } @@ -34454,7 +34555,7 @@ int SetAsymKeyDer(const byte* privKey, word32 privKeyLen, /* pubKey */ if (pubKey) { idx += SetHeader(ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY | - 1, pubKeyLen, output + idx); + 1, pubKeyLen, output + idx, 0); XMEMCPY(output + idx, pubKey, pubKeyLen); idx += pubKeyLen; } @@ -36355,7 +36456,7 @@ int EncodeOcspRequest(OcspRequest* req, byte* output, word32 size) */ extSz = EncodeOcspRequestExtensions(req, extArray + 2, OCSP_NONCE_EXT_SZ); - extSz += SetExplicit(2, extSz, extArray); + extSz += SetExplicit(2, extSz, extArray, 0); } totalSz = algoSz + issuerSz + issuerKeySz + snSz; diff --git a/wolfcrypt/src/pkcs12.c b/wolfcrypt/src/pkcs12.c index 22e641508..123b2e9db 100644 --- a/wolfcrypt/src/pkcs12.c +++ b/wolfcrypt/src/pkcs12.c @@ -1836,7 +1836,7 @@ static int wc_PKCS12_shroud_key(WC_PKCS12* pkcs12, WC_RNG* rng, /* rewind index and set tag and length */ tmpIdx -= MAX_LENGTH_SZ + 1; - sz = (word32)SetExplicit(0, (word32)ret, out + tmpIdx); + sz = (word32)SetExplicit(0, (word32)ret, out + tmpIdx, 0); tmpIdx += sz; totalSz += sz; XMEMMOVE(out + tmpIdx, out + MAX_LENGTH_SZ + 1, (size_t)ret); diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index e312520a1..4f7bbc4b1 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -2462,13 +2462,17 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, esd->innerContSeqSz = 0; esd->contentInfoSeqSz = SetSequence(pkcs7->contentTypeSz, esd->contentInfoSeq); - } else { - esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets); + } + else { + esd->innerOctetsSz = SetOctetStringEx(pkcs7->contentSz, esd->innerOctets, + pkcs7->encodeStream); esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz + - pkcs7->contentSz, esd->innerContSeq); - esd->contentInfoSeqSz = SetSequence(pkcs7->contentSz + + pkcs7->contentSz, esd->innerContSeq, + pkcs7->encodeStream); + esd->contentInfoSeqSz = SetSequenceEx(pkcs7->contentSz + esd->innerOctetsSz + pkcs7->contentTypeSz + - esd->innerContSeqSz, esd->contentInfoSeq); + esd->innerContSeqSz, esd->contentInfoSeq, + pkcs7->encodeStream); } /* SignerIdentifier */ @@ -2495,7 +2499,7 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, /* SubjectKeyIdentifier */ esd->issuerSKIDSz = SetOctetString(keyIdSize, esd->issuerSKID); esd->issuerSKIDSeqSz = SetExplicit(0, esd->issuerSKIDSz + keyIdSize, - esd->issuerSKIDSeq); + esd->issuerSKIDSeq, 0); signerInfoSz += (esd->issuerSKIDSz + esd->issuerSKIDSeqSz + keyIdSize); /* version MUST be 3 */ @@ -2550,7 +2554,7 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, FlattenAttributes(pkcs7, flatSignedAttribs, esd->signedAttribs, esd->signedAttribsCount); esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz, - esd->signedAttribSet); + esd->signedAttribSet, 0); } else { esd->signedAttribSetSz = 0; } @@ -2577,15 +2581,17 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, /* certificates [0] IMPLICIT CertificateSet */ /* get total certificates size */ - certPtr = pkcs7->certList; - while (certPtr != NULL) { - certSetSz += certPtr->derSz; - certPtr = certPtr->next; + if (pkcs7->noCerts != 1) { + certPtr = pkcs7->certList; + while (certPtr != NULL) { + certSetSz += certPtr->derSz; + certPtr = certPtr->next; + } } certPtr = NULL; if (certSetSz > 0) - esd->certsSetSz = SetImplicit(ASN_SET, 0, certSetSz, esd->certsSet); + esd->certsSetSz = SetImplicit(ASN_SET, 0, certSetSz, esd->certsSet, 0); if (pkcs7->sidType != DEGENERATE_SID) { esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId, @@ -2603,19 +2609,47 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz + esd->contentInfoSeqSz + pkcs7->contentTypeSz + - esd->innerContSeqSz + esd->innerOctetsSz + pkcs7->contentSz; + esd->innerContSeqSz + esd->innerOctetsSz; + +#ifdef ASN_BER_TO_DER + if (pkcs7->encodeStream) { + word32 sz = 0, tmpIdx = 0; + totalSz += (3 * ASN_INDEF_END_SZ) ; /* 00's for BER with inner content */ + + StreamOctetString(pkcs7->content, pkcs7->contentSz, NULL, &sz, &tmpIdx); + totalSz += sz + (3 * ASN_INDEF_END_SZ); + } + else +#endif + { + totalSz += pkcs7->contentSz; + } total2Sz = esd->certsSetSz + certSetSz + signerInfoSz; if (pkcs7->detached) { totalSz -= pkcs7->contentSz; } - esd->innerSeqSz = SetSequence(totalSz + total2Sz, esd->innerSeq); + esd->innerSeqSz = SetSequenceEx(totalSz + total2Sz, esd->innerSeq, + pkcs7->encodeStream); totalSz += esd->innerSeqSz; - esd->outerContentSz = SetExplicit(0, totalSz + total2Sz, esd->outerContent); + if (pkcs7->encodeStream) { + totalSz += ASN_INDEF_END_SZ; + } + + esd->outerContentSz = SetExplicit(0, totalSz + total2Sz, + esd->outerContent, pkcs7->encodeStream); totalSz += esd->outerContentSz + signedDataOidSz; - esd->outerSeqSz = SetSequence(totalSz + total2Sz, esd->outerSeq); + if (pkcs7->encodeStream) { + totalSz += ASN_INDEF_END_SZ; + } + + esd->outerSeqSz = SetSequenceEx(totalSz + total2Sz, esd->outerSeq, + pkcs7->encodeStream); totalSz += esd->outerSeqSz; + if (pkcs7->encodeStream) { + totalSz += ASN_INDEF_END_SZ; + } /* if using header/footer, we are not returning the content */ if (output2 && output2Sz) { @@ -2690,8 +2724,26 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, } else { if (!pkcs7->detached && pkcs7->content != NULL && pkcs7->contentSz > 0) { - XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); - idx += pkcs7->contentSz; + #ifdef ASN_BER_TO_DER + if (pkcs7->encodeStream) { + StreamOctetString(pkcs7->content, pkcs7->contentSz, output, + outputSz, (word32*)&idx); + + /* end of content octet string */ + idx += SetIndefEnd(output + idx); + + /* end of inner content seq */ + idx += SetIndefEnd(output + idx); + + /* end of inner content info seq */ + idx += SetIndefEnd(output + idx); + } + else + #endif + { + XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); + idx += pkcs7->contentSz; + } } output2 = output; } @@ -2699,12 +2751,16 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, /* certificates */ XMEMCPY(output2 + idx, esd->certsSet, esd->certsSetSz); idx += esd->certsSetSz; - certPtr = pkcs7->certList; - while (certPtr != NULL) { - XMEMCPY(output2 + idx, certPtr->der, certPtr->derSz); - idx += certPtr->derSz; - certPtr = certPtr->next; + + if (pkcs7->noCerts != 1) { + certPtr = pkcs7->certList; + while (certPtr != NULL) { + XMEMCPY(output2 + idx, certPtr->der, certPtr->derSz); + idx += certPtr->derSz; + certPtr = certPtr->next; + } } + wc_PKCS7_FreeCertSet(pkcs7); XMEMCPY(output2 + idx, esd->signerInfoSet, esd->signerInfoSetSz); @@ -2756,6 +2812,19 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, XMEMCPY(output2 + idx, esd->encContentDigest, esd->encContentDigestSz); idx += esd->encContentDigestSz; +#ifdef ASN_BER_TO_DER + if (pkcs7->encodeStream) { + /* end of signedData seq */ + idx += SetIndefEnd(output2 + idx); + + /* end of outer content set */ + idx += SetIndefEnd(output2 + idx); + + /* end of outer content info seq */ + idx += SetIndefEnd(output2 + idx); + } +#endif + if (output2Sz) { *output2Sz = idx; idx = 0; /* success */ @@ -6009,7 +6078,7 @@ static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID) /* suppPubInfo */ suppPubInfoSeqSz = SetImplicit(ASN_SEQUENCE, 2, kekOctetSz + sizeof(word32), - suppPubInfoSeq); + suppPubInfoSeq, 0); sharedInfoSz += suppPubInfoSeqSz; /* optional ukm/entityInfo */ @@ -6019,7 +6088,7 @@ static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID) entityUInfoExplicitSz = SetExplicit(0, entityUInfoOctetSz + kari->ukmSz, - entityUInfoExplicitSeq); + entityUInfoExplicitSeq, 0); sharedInfoSz += entityUInfoExplicitSz; } @@ -6395,7 +6464,7 @@ int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz, /* RecipientKeyIdentifier IMPLICIT [0] */ recipKeyIdSeqSz = SetImplicit(ASN_SEQUENCE, 0, subjKeyIdOctetSz + - keyIdSize, recipKeyIdSeq); + keyIdSize, recipKeyIdSeq, 0); totalSz += recipKeyIdSeqSz; /* RecipientEncryptedKey */ @@ -6413,7 +6482,7 @@ int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz, totalSz += (ukmOctetSz + kari->ukmSz); ukmExplicitSz = SetExplicit(1, ukmOctetSz + kari->ukmSz, - ukmExplicitSeq); + ukmExplicitSeq, 0); totalSz += ukmExplicitSz; } @@ -6447,14 +6516,14 @@ int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz, /* outer OriginatorPublicKey IMPLICIT [1] */ origPubKeySeqSz = SetImplicit(ASN_SEQUENCE, 1, origAlgIdSz + origPubKeyStrSz + - kari->senderKeyExportSz, origPubKeySeq); + kari->senderKeyExportSz, origPubKeySeq, 0); totalSz += origPubKeySeqSz; /* outer OriginatorIdentifierOrKey IMPLICIT [0] */ origIdOrKeySeqSz = SetImplicit(ASN_SEQUENCE, 0, origPubKeySeqSz + origAlgIdSz + origPubKeyStrSz + kari->senderKeyExportSz, - origIdOrKeySeq); + origIdOrKeySeq, 0); totalSz += origIdOrKeySeqSz; /* version, always 3 */ @@ -6463,7 +6532,7 @@ int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz, recip->recipVersion = 3; /* outer IMPLICIT [1] kari */ - kariSeqSz = SetImplicit(ASN_SEQUENCE, 1, totalSz, kariSeq); + kariSeqSz = SetImplicit(ASN_SEQUENCE, 1, totalSz, kariSeq, 0); totalSz += kariSeqSz; if (totalSz > MAX_RECIP_SZ) { @@ -7578,7 +7647,7 @@ int wc_PKCS7_AddRecipient_ORI(PKCS7* pkcs7, CallbackOriEncrypt oriEncryptCb, oriTypeLenSz = SetLength(oriTypeSz, oriTypeLen); recipSeqSz = SetImplicit(ASN_SEQUENCE, 4, 1 + oriTypeLenSz + oriTypeSz + - oriValueSz, recipSeq); + oriValueSz, recipSeq, 0); idx = 0; XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz); @@ -8028,7 +8097,7 @@ int wc_PKCS7_AddRecipient_PWRI(PKCS7* pkcs7, byte* passwd, word32 pLen, /* set KeyDerivationAlgorithmIdentifier EXPLICIT [0] SEQ */ kdfAlgoIdSeqSz = SetExplicit(0, kdfAlgoIdSz + kdfParamsSeqSz + kdfSaltOctetStrSz + saltSz + kdfIterationsSz, - kdfAlgoIdSeq); + kdfAlgoIdSeq, 0); totalSz += kdfAlgoIdSeqSz; /* set PasswordRecipientInfo CMSVersion, MUST be 0 */ @@ -8037,7 +8106,7 @@ int wc_PKCS7_AddRecipient_PWRI(PKCS7* pkcs7, byte* passwd, word32 pLen, recip->recipVersion = 0; /* set PasswordRecipientInfo SEQ */ - recipSeqSz = SetImplicit(ASN_SEQUENCE, 3, totalSz, recipSeq); + recipSeqSz = SetImplicit(ASN_SEQUENCE, 3, totalSz, recipSeq, 0); totalSz += recipSeqSz; if (totalSz > MAX_RECIP_SZ) { @@ -8280,7 +8349,7 @@ int wc_PKCS7_AddRecipient_KEKRI(PKCS7* pkcs7, int keyWrapOID, byte* kek, recip->recipVersion = 4; /* KEKRecipientInfo SEQ */ - recipSeqSz = SetImplicit(ASN_SEQUENCE, 2, totalSz, recipSeq); + recipSeqSz = SetImplicit(ASN_SEQUENCE, 2, totalSz, recipSeq, 0); totalSz += recipSeqSz; if (totalSz > MAX_RECIP_SZ) { @@ -8585,12 +8654,11 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) } encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz, - encContentOctet); - - encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + - ivOctetStringSz + blockSz + - encContentOctetSz + encryptedOutSz, - encContentSeq); + encContentOctet, pkcs7->encodeStream); + encContentSeqSz = SetSequenceEx(contentTypeSz + contentEncAlgoSz + + ivOctetStringSz + blockSz + + encContentOctetSz + encryptedOutSz, + encContentSeq, pkcs7->encodeStream); /* keep track of sizes for outer wrapper layering */ totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz + @@ -8598,18 +8666,49 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) encContentOctetSz + encryptedOutSz; /* EnvelopedData */ - envDataSeqSz = SetSequence(totalSz, envDataSeq); +#ifdef ASN_BER_TO_DER + if (pkcs7->encodeStream) { + word32 streamSz = 0, tmpIdx = 0; + + /* account for ending of encContentOctet */ + totalSz += ASN_INDEF_END_SZ; + + /* account for ending of encContentSeq */ + totalSz += ASN_INDEF_END_SZ; + + /* account for asn1 syntax around octet strings */ + StreamOctetString(NULL, encryptedOutSz, NULL, &streamSz, &tmpIdx); + totalSz += (streamSz - encryptedOutSz); + } +#endif + envDataSeqSz = SetSequenceEx(totalSz, envDataSeq, pkcs7->encodeStream); totalSz += envDataSeqSz; +#ifdef ASN_BER_TO_DER + if (pkcs7->encodeStream) { + totalSz += ASN_INDEF_END_SZ; + } +#endif /* outer content */ - outerContentSz = SetExplicit(0, totalSz, outerContent); + outerContentSz = SetExplicit(0, totalSz, outerContent, pkcs7->encodeStream); +#ifdef ASN_BER_TO_DER + if (pkcs7->encodeStream) { + totalSz += ASN_INDEF_END_SZ; + } +#endif totalSz += outerContentTypeSz; totalSz += outerContentSz; if (pkcs7->contentOID != FIRMWARE_PKG_DATA) { /* ContentInfo */ - contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); + contentInfoSeqSz = SetSequenceEx(totalSz, contentInfoSeq, + pkcs7->encodeStream); totalSz += contentInfoSeqSz; + #ifdef ASN_BER_TO_DER + if (pkcs7->encodeStream) { + totalSz += ASN_INDEF_END_SZ; + } + #endif } if (totalSz > (int)outputSz) { @@ -8628,6 +8727,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) XMEMCPY(output + idx, outerContent, outerContentSz); idx += outerContentSz; } + XMEMCPY(output + idx, envDataSeq, envDataSeqSz); idx += envDataSeqSz; XMEMCPY(output + idx, ver, verSz); @@ -8642,6 +8742,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) tmpRecip = tmpRecip->next; } wc_PKCS7_FreeEncodedRecipientSet(pkcs7); + XMEMCPY(output + idx, encContentSeq, encContentSeqSz); idx += encContentSeqSz; XMEMCPY(output + idx, contentType, contentTypeSz); @@ -8654,8 +8755,36 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) idx += blockSz; XMEMCPY(output + idx, encContentOctet, encContentOctetSz); idx += encContentOctetSz; - XMEMCPY(output + idx, encryptedContent, encryptedOutSz); - idx += encryptedOutSz; + +#ifdef ASN_BER_TO_DER + /* stream the content (octet string with multiple octet elements) */ + if (pkcs7->encodeStream) { + if (StreamOctetString(encryptedContent, encryptedOutSz, output, + &outputSz, (word32*)&idx) != 0) { + return BUFFER_E; + } + + /* end of encrypted content */ + idx += SetIndefEnd(output + idx); + + /* end of encrypted content info */ + idx += SetIndefEnd(output + idx); + + /* end of Enveloped Data seq */ + idx += SetIndefEnd(output + idx); + + /* end of outer content set */ + idx += SetIndefEnd(output + idx); + + /* end of outer content info seq */ + idx += SetIndefEnd(output + idx); + } + else +#endif + { + XMEMCPY(output + idx, encryptedContent, encryptedOutSz); + idx += encryptedOutSz; + } XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); @@ -11498,7 +11627,7 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, } authAttribsSetSz = SetImplicit(ASN_SET, 1, authAttribsSz, - authAttribSet); + authAttribSet, 0); /* From RFC5083, "For the purpose of constructing the AAD, the * IMPLICIT [1] tag in the authAttrs field is not used for the @@ -11544,7 +11673,7 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, FlattenAttributes(pkcs7, flatUnauthAttribs, unauthAttribs, unauthAttribsCount); unauthAttribsSetSz = SetImplicit(ASN_SET, 2, unauthAttribsSz, - unauthAttribSet); + unauthAttribSet, 0); } /* AES-GCM/CCM does NOT require padding for plaintext content or @@ -11656,8 +11785,7 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, } encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz, - encContentOctet); - + encContentOctet, 0); encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + nonceOctetStringSz + nonceSz + macIntSz + algoParamSeqSz + encContentOctetSz + @@ -11677,7 +11805,7 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, totalSz += envDataSeqSz; /* outer content */ - outerContentSz = SetExplicit(0, totalSz, outerContent); + outerContentSz = SetExplicit(0, totalSz, outerContent, 0); totalSz += outerContentTypeSz; totalSz += outerContentSz; @@ -11730,6 +11858,8 @@ int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, idx += nonceSz; XMEMCPY(output + idx, macInt, macIntSz); idx += macIntSz; + + XMEMCPY(output + idx, encContentOctet, encContentOctetSz); idx += encContentOctetSz; XMEMCPY(output + idx, encryptedContent, encryptedOutSz); @@ -12540,7 +12670,7 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) } encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, - encryptedOutSz, encContentOctet); + encryptedOutSz, encContentOctet, 0); encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + ivOctetStringSz + blockSz + @@ -12586,7 +12716,7 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } - attribsSetSz = SetImplicit(ASN_SET, 1, attribsSz, attribSet); + attribsSetSz = SetImplicit(ASN_SET, 1, attribsSz, attribSet, 0); } else { attribsSz = 0; @@ -12604,7 +12734,7 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (pkcs7->version != 3) { /* outer content */ - outerContentSz = SetExplicit(0, totalSz, outerContent); + outerContentSz = SetExplicit(0, totalSz, outerContent, 0); totalSz += outerContentTypeSz; totalSz += outerContentSz; /* ContentInfo */ @@ -13095,6 +13225,60 @@ int wc_PKCS7_SetDecodeEncryptedCtx(PKCS7* pkcs7, void* ctx) } #endif /* NO_PKCS7_ENCRYPTED_DATA */ + +/* set stream mode for encoding and signing + * returns 0 on success */ +int wc_PKCS7_SetStreamMode(PKCS7* pkcs7, byte flag) +{ + if (pkcs7 == NULL) { + return BAD_FUNC_ARG; + } +#ifdef ASN_BER_TO_DER + pkcs7->encodeStream = flag; + return 0; +#else + (void)flag; + return NOT_COMPILED_IN; +#endif +} + + +/* returns to current stream mode flag on success, negative values on fail */ +int wc_PKCS7_GetStreamMode(PKCS7* pkcs7) +{ + if (pkcs7 == NULL) { + return BAD_FUNC_ARG; + } +#ifdef ASN_BER_TO_DER + return pkcs7->encodeStream; +#else + return 0; +#endif +} + + +/* set option to not include certificates when creating a bundle + * returns 0 on success */ +int wc_PKCS7_SetNoCerts(PKCS7* pkcs7, byte flag) +{ + if (pkcs7 == NULL) { + return BAD_FUNC_ARG; + } + pkcs7->noCerts = flag; + return 0; +} + + +/* returns the current noCerts flag value on success, negative values on fail */ +int wc_PKCS7_GetNoCerts(PKCS7* pkcs7) +{ + if (pkcs7 == NULL) { + return BAD_FUNC_ARG; + } + return pkcs7->noCerts; +} + + #if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA) /* build PKCS#7 compressedData content type, return encrypted size */ @@ -13149,7 +13333,7 @@ int wc_PKCS7_EncodeCompressedData(PKCS7* pkcs7, byte* output, word32 outputSz) totalSz = contentOctetStrSz + compressedSz; /* EXPLICIT [0] eContentType */ - contentSeqSz = SetExplicit(0, totalSz, contentSeq); + contentSeqSz = SetExplicit(0, totalSz, contentSeq, 0); totalSz += contentSeqSz; /* eContentType OBJECT IDENTIFIER */ @@ -13209,7 +13393,7 @@ int wc_PKCS7_EncodeCompressedData(PKCS7* pkcs7, byte* output, word32 outputSz) */ /* ContentInfo content EXPLICIT SEQUENCE */ - contentInfoContentSeqSz = SetExplicit(0, totalSz, contentInfoContentSeq); + contentInfoContentSeqSz = SetExplicit(0, totalSz, contentInfoContentSeq, 0); totalSz += contentInfoContentSeqSz; ret = wc_SetContentType(COMPRESSED_DATA, contentInfoTypeOid, diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index a1a5e0f62..395981407 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1023,6 +1023,7 @@ enum Misc_ASN { #endif TRAILING_ZERO = 1, /* Used for size of zero pad */ ASN_TAG_SZ = 1, /* single byte ASN.1 tag */ + ASN_INDEF_END_SZ = 2, /* 0x00 0x00 at end of indef */ MIN_VERSION_SZ = 3, /* Min bytes needed for GetMyVersion */ MAX_X509_VERSION = 3, /* Max X509 version allowed */ MIN_X509_VERSION = 0, /* Min X509 version allowed */ @@ -2100,6 +2101,8 @@ WOLFSSL_LOCAL int GetName(DecodedCert* cert, int nameType, int maxIdx); WOLFSSL_ASN_API int wc_BerToDer(const byte* ber, word32 berSz, byte* der, word32* derSz); +WOLFSSL_LOCAL int StreamOctetString(const byte* inBuf, word32 inBufSz, + byte* out, word32* outSz, word32* idx); WOLFSSL_ASN_API void FreeAltNames(DNS_entry* altNames, void* heap); WOLFSSL_ASN_API DNS_entry* AltNameNew(void* heap); @@ -2274,12 +2277,18 @@ WOLFSSL_LOCAL word32 SetASNExplicit(byte number, word32 len, byte* output); WOLFSSL_LOCAL word32 SetASNSet(word32 len, byte* output); WOLFSSL_LOCAL word32 SetLength(word32 length, byte* output); +WOLFSSL_LOCAL word32 SetLengthEx(word32 length, byte* output, byte isIndef); WOLFSSL_LOCAL word32 SetSequence(word32 len, byte* output); +WOLFSSL_LOCAL word32 SetSequenceEx(word32 len, byte* output, byte isIndef); +WOLFSSL_LOCAL word32 SetIndefEnd(byte* output); WOLFSSL_LOCAL word32 SetOctetString(word32 len, byte* output); +WOLFSSL_LOCAL word32 SetOctetStringEx(word32 len, byte* output, byte indef); WOLFSSL_LOCAL int SetASNInt(int len, byte firstByte, byte* output); WOLFSSL_LOCAL word32 SetBitString(word32 len, byte unusedBits, byte* output); -WOLFSSL_LOCAL word32 SetImplicit(byte tag,byte number,word32 len,byte* output); -WOLFSSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output); +WOLFSSL_LOCAL word32 SetImplicit(byte tag,byte number,word32 len,byte* output, + byte isIndef); +WOLFSSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output, + byte isIndef); WOLFSSL_LOCAL word32 SetSet(word32 len, byte* output); WOLFSSL_API word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz); WOLFSSL_LOCAL int SetMyVersion(word32 version, byte* output, int header); diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 1e2733c83..f397a8f26 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -248,6 +248,9 @@ struct PKCS7 { byte* der; /* DER encoded version of message */ word32 derSz; #endif + byte encodeStream:1; /* use BER when encoding */ + byte noCerts:1; /* if certificates should be added into bundle + during creation */ byte* cert[MAX_PKCS7_CERTS]; /* array of certs parsed from bundle */ byte* verifyCert; /* cert from array used for verify */ word32 verifyCertSz; @@ -495,6 +498,11 @@ WOLFSSL_API int wc_PKCS7_SetDecodeEncryptedCb(PKCS7* pkcs7, WOLFSSL_API int wc_PKCS7_SetDecodeEncryptedCtx(PKCS7* pkcs7, void* ctx); #endif /* NO_PKCS7_ENCRYPTED_DATA */ +WOLFSSL_API int wc_PKCS7_SetStreamMode(PKCS7* pkcs7, byte flag); +WOLFSSL_API int wc_PKCS7_GetStreamMode(PKCS7* pkcs7); +WOLFSSL_API int wc_PKCS7_SetNoCerts(PKCS7* pkcs7, byte flag); +WOLFSSL_API int wc_PKCS7_GetNoCerts(PKCS7* pkcs7); + /* CMS/PKCS#7 CompressedData */ #if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA) WOLFSSL_API int wc_PKCS7_EncodeCompressedData(PKCS7* pkcs7, byte* output,