/* pkcs7.c * * Copyright (C) 2006-2015 wolfSSL Inc. * * This file is part of wolfSSL. (formerly known as CyaSSL) * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifdef HAVE_CONFIG_H #include #endif #include #ifdef HAVE_PKCS7 #include #include #include #ifdef NO_INLINE #include #else #include #endif #ifndef WOLFSSL_HAVE_MIN #define WOLFSSL_HAVE_MIN static INLINE word32 min(word32 a, word32 b) { return a > b ? b : a; } #endif /* WOLFSSL_HAVE_MIN */ /* placed ASN.1 contentType OID into *output, return idx on success, * 0 upon failure */ WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output) { /* PKCS#7 content types, RFC 2315, section 14 */ static const byte pkcs7[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07 }; static const byte data[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; static const byte signedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02}; static const byte envelopedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03 }; static const byte signedAndEnveloped[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04 }; static const byte digestedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05 }; static const byte encryptedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 }; int idSz; int typeSz = 0, idx = 0; const byte* typeName = 0; byte ID_Length[MAX_LENGTH_SZ]; switch (pkcs7TypeOID) { case PKCS7_MSG: typeSz = sizeof(pkcs7); typeName = pkcs7; break; case DATA: typeSz = sizeof(data); typeName = data; break; case SIGNED_DATA: typeSz = sizeof(signedData); typeName = signedData; break; case ENVELOPED_DATA: typeSz = sizeof(envelopedData); typeName = envelopedData; break; case SIGNED_AND_ENVELOPED_DATA: typeSz = sizeof(signedAndEnveloped); typeName = signedAndEnveloped; break; case DIGESTED_DATA: typeSz = sizeof(digestedData); typeName = digestedData; break; case ENCRYPTED_DATA: typeSz = sizeof(encryptedData); typeName = encryptedData; break; default: WOLFSSL_MSG("Unknown PKCS#7 Type"); return 0; }; idSz = SetLength(typeSz, ID_Length); output[idx++] = ASN_OBJECT_ID; XMEMCPY(output + idx, ID_Length, idSz); idx += idSz; XMEMCPY(output + idx, typeName, typeSz); idx += typeSz; return idx; } /* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */ int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, word32 maxIdx) { int length; word32 i = *inOutIdx; byte b; *oid = 0; WOLFSSL_ENTER("wc_GetContentType"); b = input[i++]; if (b != ASN_OBJECT_ID) return ASN_OBJECT_ID_E; if (GetLength(input, &i, &length, maxIdx) < 0) return ASN_PARSE_E; while(length--) { *oid += input[i]; i++; } *inOutIdx = i; return 0; } /* init PKCS7 struct with recipient cert, decode into DecodedCert */ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) { int ret = 0; XMEMSET(pkcs7, 0, sizeof(PKCS7)); if (cert != NULL && certSz > 0) { #ifdef WOLFSSL_SMALL_STACK DecodedCert* dCert; dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dCert == NULL) return MEMORY_E; #else DecodedCert stack_dCert; DecodedCert* dCert = &stack_dCert; #endif pkcs7->singleCert = cert; pkcs7->singleCertSz = certSz; InitDecodedCert(dCert, cert, certSz, 0); ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0); if (ret < 0) { FreeDecodedCert(dCert); #ifdef WOLFSSL_SMALL_STACK XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } XMEMCPY(pkcs7->publicKey, dCert->publicKey, dCert->pubKeySize); pkcs7->publicKeySz = dCert->pubKeySize; XMEMCPY(pkcs7->issuerHash, dCert->issuerHash, KEYID_SIZE); pkcs7->issuer = dCert->issuerRaw; pkcs7->issuerSz = dCert->issuerRawLen; XMEMCPY(pkcs7->issuerSn, dCert->serial, dCert->serialSz); pkcs7->issuerSnSz = dCert->serialSz; FreeDecodedCert(dCert); #ifdef WOLFSSL_SMALL_STACK XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif } return ret; } /* releases any memory allocated by a PKCS7 initializer */ void wc_PKCS7_Free(PKCS7* pkcs7) { (void)pkcs7; } /* build PKCS#7 data content type */ int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz) { static const byte oid[] = { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; byte seq[MAX_SEQ_SZ]; byte octetStr[MAX_OCTET_STR_SZ]; word32 seqSz; word32 octetStrSz; word32 oidSz = (word32)sizeof(oid); int idx = 0; octetStrSz = SetOctetString(pkcs7->contentSz, octetStr); seqSz = SetSequence(pkcs7->contentSz + octetStrSz + oidSz, seq); if (outputSz < pkcs7->contentSz + octetStrSz + oidSz + seqSz) return BUFFER_E; XMEMCPY(output, seq, seqSz); idx += seqSz; XMEMCPY(output + idx, oid, oidSz); idx += oidSz; XMEMCPY(output + idx, octetStr, octetStrSz); idx += octetStrSz; XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); idx += pkcs7->contentSz; return idx; } typedef struct EncodedAttrib { byte valueSeq[MAX_SEQ_SZ]; const byte* oid; byte valueSet[MAX_SET_SZ]; const byte* value; word32 valueSeqSz, oidSz, idSz, valueSetSz, valueSz, totalSz; } EncodedAttrib; typedef struct ESD { Sha sha; byte contentDigest[SHA_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */ byte contentAttribsDigest[SHA_DIGEST_SIZE]; byte encContentDigest[512]; byte outerSeq[MAX_SEQ_SZ]; byte outerContent[MAX_EXP_SZ]; byte innerSeq[MAX_SEQ_SZ]; byte version[MAX_VERSION_SZ]; byte digAlgoIdSet[MAX_SET_SZ]; byte singleDigAlgoId[MAX_ALGO_SZ]; byte contentInfoSeq[MAX_SEQ_SZ]; byte innerContSeq[MAX_EXP_SZ]; byte innerOctets[MAX_OCTET_STR_SZ]; byte certsSet[MAX_SET_SZ]; byte signerInfoSet[MAX_SET_SZ]; byte signerInfoSeq[MAX_SEQ_SZ]; byte signerVersion[MAX_VERSION_SZ]; byte issuerSnSeq[MAX_SEQ_SZ]; byte issuerName[MAX_SEQ_SZ]; byte issuerSn[MAX_SN_SZ]; byte signerDigAlgoId[MAX_ALGO_SZ]; byte digEncAlgoId[MAX_ALGO_SZ]; byte signedAttribSet[MAX_SET_SZ]; EncodedAttrib signedAttribs[6]; byte signerDigest[MAX_OCTET_STR_SZ]; word32 innerOctetsSz, innerContSeqSz, contentInfoSeqSz; word32 outerSeqSz, outerContentSz, innerSeqSz, versionSz, digAlgoIdSetSz, singleDigAlgoIdSz, certsSetSz; word32 signerInfoSetSz, signerInfoSeqSz, signerVersionSz, issuerSnSeqSz, issuerNameSz, issuerSnSz, signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz; word32 encContentDigestSz, signedAttribsSz, signedAttribsCount, signedAttribSetSz; } ESD; static int EncodeAttributes(EncodedAttrib* ea, int eaSz, PKCS7Attrib* attribs, int attribsSz) { int i; int maxSz = min(eaSz, attribsSz); int allAttribsSz = 0; for (i = 0; i < maxSz; i++) { int attribSz = 0; ea[i].value = attribs[i].value; ea[i].valueSz = attribs[i].valueSz; attribSz += ea[i].valueSz; ea[i].valueSetSz = SetSet(attribSz, ea[i].valueSet); attribSz += ea[i].valueSetSz; ea[i].oid = attribs[i].oid; ea[i].oidSz = attribs[i].oidSz; attribSz += ea[i].oidSz; ea[i].valueSeqSz = SetSequence(attribSz, ea[i].valueSeq); attribSz += ea[i].valueSeqSz; ea[i].totalSz = attribSz; allAttribsSz += attribSz; } return allAttribsSz; } static int FlattenAttributes(byte* output, EncodedAttrib* ea, int eaSz) { int i, idx; idx = 0; for (i = 0; i < eaSz; i++) { XMEMCPY(output + idx, ea[i].valueSeq, ea[i].valueSeqSz); idx += ea[i].valueSeqSz; XMEMCPY(output + idx, ea[i].oid, ea[i].oidSz); idx += ea[i].oidSz; XMEMCPY(output + idx, ea[i].valueSet, ea[i].valueSetSz); idx += ea[i].valueSetSz; XMEMCPY(output + idx, ea[i].value, ea[i].valueSz); idx += ea[i].valueSz; } return 0; } /* build PKCS#7 signedData content type */ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) { static const byte outerOid[] = { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 }; static const byte innerOid[] = { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; #ifdef WOLFSSL_SMALL_STACK ESD* esd = NULL; #else ESD stack_esd; ESD* esd = &stack_esd; #endif word32 signerInfoSz = 0; word32 totalSz = 0; int idx = 0, ret = 0; byte* flatSignedAttribs = NULL; word32 flatSignedAttribsSz = 0; word32 innerOidSz = sizeof(innerOid); word32 outerOidSz = sizeof(outerOid); if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0 || output == NULL || outputSz == 0) return BAD_FUNC_ARG; #ifdef WOLFSSL_SMALL_STACK esd = (ESD*)XMALLOC(sizeof(ESD), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (esd == NULL) return MEMORY_E; #endif XMEMSET(esd, 0, sizeof(ESD)); ret = wc_InitSha(&esd->sha); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } if (pkcs7->contentSz != 0) { wc_ShaUpdate(&esd->sha, pkcs7->content, pkcs7->contentSz); esd->contentDigest[0] = ASN_OCTET_STRING; esd->contentDigest[1] = SHA_DIGEST_SIZE; wc_ShaFinal(&esd->sha, &esd->contentDigest[2]); } esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets); esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz + pkcs7->contentSz, esd->innerContSeq); esd->contentInfoSeqSz = SetSequence(pkcs7->contentSz + esd->innerOctetsSz + innerOidSz + esd->innerContSeqSz, esd->contentInfoSeq); esd->issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz, esd->issuerSn); signerInfoSz += esd->issuerSnSz; esd->issuerNameSz = SetSequence(pkcs7->issuerSz, esd->issuerName); signerInfoSz += esd->issuerNameSz + pkcs7->issuerSz; esd->issuerSnSeqSz = SetSequence(signerInfoSz, esd->issuerSnSeq); signerInfoSz += esd->issuerSnSeqSz; esd->signerVersionSz = SetMyVersion(1, esd->signerVersion, 0); signerInfoSz += esd->signerVersionSz; esd->signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->signerDigAlgoId, hashType, 0); signerInfoSz += esd->signerDigAlgoIdSz; esd->digEncAlgoIdSz = SetAlgoID(pkcs7->encryptOID, esd->digEncAlgoId, keyType, 0); signerInfoSz += esd->digEncAlgoIdSz; if (pkcs7->signedAttribsSz != 0) { byte contentTypeOid[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, 0x09, 0x03 }; byte contentType[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 }; byte messageDigestOid[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04 }; PKCS7Attrib cannedAttribs[2] = { { contentTypeOid, sizeof(contentTypeOid), contentType, sizeof(contentType) }, { messageDigestOid, sizeof(messageDigestOid), esd->contentDigest, sizeof(esd->contentDigest) } }; word32 cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib); esd->signedAttribsCount += cannedAttribsCount; esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[0], 2, cannedAttribs, cannedAttribsCount); esd->signedAttribsCount += pkcs7->signedAttribsSz; esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[2], 4, pkcs7->signedAttribs, pkcs7->signedAttribsSz); flatSignedAttribs = (byte*)XMALLOC(esd->signedAttribsSz, 0, NULL); flatSignedAttribsSz = esd->signedAttribsSz; if (flatSignedAttribs == NULL) { #ifdef WOLFSSL_SMALL_STACK XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } FlattenAttributes(flatSignedAttribs, esd->signedAttribs, esd->signedAttribsCount); esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz, esd->signedAttribSet); } /* Calculate the final hash and encrypt it. */ { int result; word32 scratch = 0; #ifdef WOLFSSL_SMALL_STACK byte* digestInfo; RsaKey* privKey; #else RsaKey stack_privKey; RsaKey* privKey = &stack_privKey; byte digestInfo[MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE]; #endif byte digestInfoSeq[MAX_SEQ_SZ]; byte digestStr[MAX_OCTET_STR_SZ]; word32 digestInfoSeqSz, digestStrSz; int digIdx = 0; if (pkcs7->signedAttribsSz != 0) { byte attribSet[MAX_SET_SZ]; word32 attribSetSz; attribSetSz = SetSet(flatSignedAttribsSz, attribSet); ret = wc_InitSha(&esd->sha); if (ret < 0) { XFREE(flatSignedAttribs, 0, NULL); #ifdef WOLFSSL_SMALL_STACK XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } wc_ShaUpdate(&esd->sha, attribSet, attribSetSz); wc_ShaUpdate(&esd->sha, flatSignedAttribs, flatSignedAttribsSz); } wc_ShaFinal(&esd->sha, esd->contentAttribsDigest); digestStrSz = SetOctetString(SHA_DIGEST_SIZE, digestStr); digestInfoSeqSz = SetSequence(esd->signerDigAlgoIdSz + digestStrSz + SHA_DIGEST_SIZE, digestInfoSeq); #ifdef WOLFSSL_SMALL_STACK digestInfo = (byte*)XMALLOC(MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (digestInfo == NULL) { if (pkcs7->signedAttribsSz != 0) XFREE(flatSignedAttribs, 0, NULL); XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #endif XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz); digIdx += digestInfoSeqSz; XMEMCPY(digestInfo + digIdx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz); digIdx += esd->signerDigAlgoIdSz; XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz); digIdx += digestStrSz; XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest, SHA_DIGEST_SIZE); digIdx += SHA_DIGEST_SIZE; #ifdef WOLFSSL_SMALL_STACK privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (privKey == NULL) { if (pkcs7->signedAttribsSz != 0) XFREE(flatSignedAttribs, 0, NULL); XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #endif result = wc_InitRsaKey(privKey, NULL); if (result == 0) result = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &scratch, privKey, pkcs7->privateKeySz); if (result < 0) { if (pkcs7->signedAttribsSz != 0) XFREE(flatSignedAttribs, 0, NULL); #ifdef WOLFSSL_SMALL_STACK XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return PUBLIC_KEY_E; } result = wc_RsaSSL_Sign(digestInfo, digIdx, esd->encContentDigest, sizeof(esd->encContentDigest), privKey, pkcs7->rng); wc_FreeRsaKey(privKey); #ifdef WOLFSSL_SMALL_STACK XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif if (result < 0) { if (pkcs7->signedAttribsSz != 0) XFREE(flatSignedAttribs, 0, NULL); #ifdef WOLFSSL_SMALL_STACK XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return result; } esd->encContentDigestSz = (word32)result; } signerInfoSz += flatSignedAttribsSz + esd->signedAttribSetSz; esd->signerDigestSz = SetOctetString(esd->encContentDigestSz, esd->signerDigest); signerInfoSz += esd->signerDigestSz + esd->encContentDigestSz; esd->signerInfoSeqSz = SetSequence(signerInfoSz, esd->signerInfoSeq); signerInfoSz += esd->signerInfoSeqSz; esd->signerInfoSetSz = SetSet(signerInfoSz, esd->signerInfoSet); signerInfoSz += esd->signerInfoSetSz; esd->certsSetSz = SetImplicit(ASN_SET, 0, pkcs7->singleCertSz, esd->certsSet); esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId, hashType, 0); esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet); esd->versionSz = SetMyVersion(1, esd->version, 0); totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz + esd->contentInfoSeqSz + esd->certsSetSz + pkcs7->singleCertSz + esd->innerOctetsSz + esd->innerContSeqSz + innerOidSz + pkcs7->contentSz + signerInfoSz; esd->innerSeqSz = SetSequence(totalSz, esd->innerSeq); totalSz += esd->innerSeqSz; esd->outerContentSz = SetExplicit(0, totalSz, esd->outerContent); totalSz += esd->outerContentSz + outerOidSz; esd->outerSeqSz = SetSequence(totalSz, esd->outerSeq); totalSz += esd->outerSeqSz; if (outputSz < totalSz) { if (pkcs7->signedAttribsSz != 0) XFREE(flatSignedAttribs, 0, NULL); #ifdef WOLFSSL_SMALL_STACK XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return BUFFER_E; } idx = 0; XMEMCPY(output + idx, esd->outerSeq, esd->outerSeqSz); idx += esd->outerSeqSz; XMEMCPY(output + idx, outerOid, outerOidSz); idx += outerOidSz; XMEMCPY(output + idx, esd->outerContent, esd->outerContentSz); idx += esd->outerContentSz; XMEMCPY(output + idx, esd->innerSeq, esd->innerSeqSz); idx += esd->innerSeqSz; XMEMCPY(output + idx, esd->version, esd->versionSz); idx += esd->versionSz; XMEMCPY(output + idx, esd->digAlgoIdSet, esd->digAlgoIdSetSz); idx += esd->digAlgoIdSetSz; XMEMCPY(output + idx, esd->singleDigAlgoId, esd->singleDigAlgoIdSz); idx += esd->singleDigAlgoIdSz; XMEMCPY(output + idx, esd->contentInfoSeq, esd->contentInfoSeqSz); idx += esd->contentInfoSeqSz; XMEMCPY(output + idx, innerOid, innerOidSz); idx += innerOidSz; XMEMCPY(output + idx, esd->innerContSeq, esd->innerContSeqSz); idx += esd->innerContSeqSz; XMEMCPY(output + idx, esd->innerOctets, esd->innerOctetsSz); idx += esd->innerOctetsSz; XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); idx += pkcs7->contentSz; XMEMCPY(output + idx, esd->certsSet, esd->certsSetSz); idx += esd->certsSetSz; XMEMCPY(output + idx, pkcs7->singleCert, pkcs7->singleCertSz); idx += pkcs7->singleCertSz; XMEMCPY(output + idx, esd->signerInfoSet, esd->signerInfoSetSz); idx += esd->signerInfoSetSz; XMEMCPY(output + idx, esd->signerInfoSeq, esd->signerInfoSeqSz); idx += esd->signerInfoSeqSz; XMEMCPY(output + idx, esd->signerVersion, esd->signerVersionSz); idx += esd->signerVersionSz; XMEMCPY(output + idx, esd->issuerSnSeq, esd->issuerSnSeqSz); idx += esd->issuerSnSeqSz; XMEMCPY(output + idx, esd->issuerName, esd->issuerNameSz); idx += esd->issuerNameSz; XMEMCPY(output + idx, pkcs7->issuer, pkcs7->issuerSz); idx += pkcs7->issuerSz; XMEMCPY(output + idx, esd->issuerSn, esd->issuerSnSz); idx += esd->issuerSnSz; XMEMCPY(output + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz); idx += esd->signerDigAlgoIdSz; /* SignerInfo:Attributes */ if (pkcs7->signedAttribsSz != 0) { XMEMCPY(output + idx, esd->signedAttribSet, esd->signedAttribSetSz); idx += esd->signedAttribSetSz; XMEMCPY(output + idx, flatSignedAttribs, flatSignedAttribsSz); idx += flatSignedAttribsSz; XFREE(flatSignedAttribs, 0, NULL); } XMEMCPY(output + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz); idx += esd->digEncAlgoIdSz; XMEMCPY(output + idx, esd->signerDigest, esd->signerDigestSz); idx += esd->signerDigestSz; XMEMCPY(output + idx, esd->encContentDigest, esd->encContentDigestSz); idx += esd->encContentDigestSz; #ifdef WOLFSSL_SMALL_STACK XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return idx; } /* Finds the certificates in the message and saves it. */ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) { word32 idx, contentType; int length, version, ret; byte* content = NULL; byte* sig = NULL; byte* cert = NULL; int contentSz = 0, sigSz = 0, certSz = 0; if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0) return BAD_FUNC_ARG; idx = 0; /* Get the contentInfo sequence */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the contentInfo contentType */ if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (contentType != SIGNED_DATA) { WOLFSSL_MSG("PKCS#7 input not of type SignedData"); return PKCS7_OID_E; } /* get the ContentInfo content */ if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the signedData sequence */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the version */ if (GetMyVersion(pkiMsg, &idx, &version) < 0) return ASN_PARSE_E; if (version != 1) { WOLFSSL_MSG("PKCS#7 signedData needs to be of version 1"); return ASN_VERSION_E; } /* Get the set of DigestAlgorithmIdentifiers */ if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip the set. */ idx += length; /* Get the inner ContentInfo sequence */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the inner ContentInfo contentType */ if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (contentType != DATA) { WOLFSSL_MSG("PKCS#7 inner input not of type Data"); return PKCS7_OID_E; } if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (pkiMsg[idx++] != ASN_OCTET_STRING) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Save the inner data as the content. */ if (length > 0) { /* Local pointer for calculating hashes later */ pkcs7->content = content = &pkiMsg[idx]; pkcs7->contentSz = contentSz = length; idx += length; } /* Get the implicit[0] set of certificates */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (length > 0) { /* At this point, idx is at the first certificate in * a set of certificates. There may be more than one, * or none, or they may be a PKCS 6 extended * certificate. We want to save the first cert if it * is X.509. */ word32 certIdx = idx; if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { if (GetLength(pkiMsg, &certIdx, &certSz, pkiMsgSz) < 0) return ASN_PARSE_E; cert = &pkiMsg[idx]; certSz += (certIdx - idx); } wc_PKCS7_InitWithCert(pkcs7, cert, certSz); } idx += length; } /* Get the implicit[1] set of crls */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip the set */ idx += length; } /* Get the set of signerInfos */ if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (length > 0) { /* Get the sequence of the first signerInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the version */ if (GetMyVersion(pkiMsg, &idx, &version) < 0) return ASN_PARSE_E; if (version != 1) { WOLFSSL_MSG("PKCS#7 signerInfo needs to be of version 1"); return ASN_VERSION_E; } /* Get the sequence of IssuerAndSerialNumber */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip it */ idx += length; /* Get the sequence of digestAlgorithm */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip it */ idx += length; /* Get the IMPLICIT[0] SET OF signedAttributes */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; idx += length; } /* Get the sequence of digestEncryptionAlgorithm */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip it */ idx += length; /* Get the signature */ if (pkiMsg[idx] == ASN_OCTET_STRING) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* save pointer and length */ sig = &pkiMsg[idx]; sigSz = length; idx += length; } pkcs7->content = content; pkcs7->contentSz = contentSz; { word32 scratch = 0; int plainSz = 0; int digestSz = MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE; #ifdef WOLFSSL_SMALL_STACK byte* digest; RsaKey* key; digest = (byte*)XMALLOC(digestSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (digest == NULL) return MEMORY_E; key = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (key == NULL) { XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #else byte digest[digestSz]; RsaKey stack_key; RsaKey* key = &stack_key; #endif XMEMSET(digest, 0, digestSz); ret = wc_InitRsaKey(key, NULL); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } if (wc_RsaPublicKeyDecode(pkcs7->publicKey, &scratch, key, pkcs7->publicKeySz) < 0) { WOLFSSL_MSG("ASN RSA key decode error"); #ifdef WOLFSSL_SMALL_STACK XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return PUBLIC_KEY_E; } plainSz = wc_RsaSSL_Verify(sig, sigSz, digest, digestSz, key); wc_FreeRsaKey(key); #ifdef WOLFSSL_SMALL_STACK XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif if (plainSz < 0) return plainSz; } } return 0; } /* create ASN.1 fomatted RecipientInfo structure, returns sequence size */ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, int keyEncAlgo, int blockKeySz, RNG* rng, byte* contentKeyPlain, byte* contentKeyEnc, int* keyEncSz, byte* out, word32 outSz) { word32 idx = 0; int ret = 0, totalSz = 0; int verSz, issuerSz, snSz, keyEncAlgSz; int issuerSeqSz, recipSeqSz, issuerSerialSeqSz; int encKeyOctetStrSz; byte ver[MAX_VERSION_SZ]; byte issuerSerialSeq[MAX_SEQ_SZ]; byte recipSeq[MAX_SEQ_SZ]; byte issuerSeq[MAX_SEQ_SZ]; byte encKeyOctetStr[MAX_OCTET_STR_SZ]; #ifdef WOLFSSL_SMALL_STACK byte *serial; byte *keyAlgArray; RsaKey* pubKey; DecodedCert* decoded; serial = (byte*)XMALLOC(MAX_SN_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); keyAlgArray = (byte*)XMALLOC(MAX_SN_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (decoded == NULL || serial == NULL || keyAlgArray == NULL) { if (serial) XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (keyAlgArray) XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (decoded) XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #else byte serial[MAX_SN_SZ]; byte keyAlgArray[MAX_ALGO_SZ]; RsaKey stack_pubKey; RsaKey* pubKey = &stack_pubKey; DecodedCert stack_decoded; DecodedCert* decoded = &stack_decoded; #endif InitDecodedCert(decoded, (byte*)cert, certSz, 0); ret = ParseCert(decoded, CA_TYPE, NO_VERIFY, 0); if (ret < 0) { FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } /* version */ verSz = SetMyVersion(0, ver, 0); /* IssuerAndSerialNumber */ if (decoded->issuerRaw == NULL || decoded->issuerRawLen == 0) { WOLFSSL_MSG("DecodedCert lacks raw issuer pointer and length"); FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return -1; } issuerSz = decoded->issuerRawLen; issuerSeqSz = SetSequence(issuerSz, issuerSeq); if (decoded->serialSz == 0) { WOLFSSL_MSG("DecodedCert missing serial number"); FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return -1; } snSz = SetSerialNumber(decoded->serial, decoded->serialSz, serial); issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz, issuerSerialSeq); /* KeyEncryptionAlgorithmIdentifier, only support RSA now */ if (keyEncAlgo != RSAk) { FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ALGO_ID_E; } keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, keyType, 0); if (keyEncAlgSz == 0) { FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return BAD_FUNC_ARG; } #ifdef WOLFSSL_SMALL_STACK pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (pubKey == NULL) { FreeDecodedCert(decoded); XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #endif /* EncryptedKey */ ret = wc_InitRsaKey(pubKey, 0); if (ret != 0) { FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } if (wc_RsaPublicKeyDecode(decoded->publicKey, &idx, pubKey, decoded->pubKeySize) < 0) { WOLFSSL_MSG("ASN RSA key decode error"); wc_FreeRsaKey(pubKey); FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return PUBLIC_KEY_E; } *keyEncSz = wc_RsaPublicEncrypt(contentKeyPlain, blockKeySz, contentKeyEnc, MAX_ENCRYPTED_KEY_SZ, pubKey, rng); wc_FreeRsaKey(pubKey); #ifdef WOLFSSL_SMALL_STACK XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif if (*keyEncSz < 0) { WOLFSSL_MSG("RSA Public Encrypt failed"); FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return *keyEncSz; } encKeyOctetStrSz = SetOctetString(*keyEncSz, encKeyOctetStr); /* RecipientInfo */ recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz + issuerSz + snSz + keyEncAlgSz + encKeyOctetStrSz + *keyEncSz, recipSeq); if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz + keyEncAlgSz + encKeyOctetStrSz + *keyEncSz > (int)outSz) { WOLFSSL_MSG("RecipientInfo output buffer too small"); FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return BUFFER_E; } XMEMCPY(out + totalSz, recipSeq, recipSeqSz); totalSz += recipSeqSz; XMEMCPY(out + totalSz, ver, verSz); totalSz += verSz; XMEMCPY(out + totalSz, issuerSerialSeq, issuerSerialSeqSz); totalSz += issuerSerialSeqSz; XMEMCPY(out + totalSz, issuerSeq, issuerSeqSz); totalSz += issuerSeqSz; XMEMCPY(out + totalSz, decoded->issuerRaw, issuerSz); totalSz += issuerSz; XMEMCPY(out + totalSz, serial, snSz); totalSz += snSz; XMEMCPY(out + totalSz, keyAlgArray, keyEncAlgSz); totalSz += keyEncAlgSz; XMEMCPY(out + totalSz, encKeyOctetStr, encKeyOctetStrSz); totalSz += encKeyOctetStrSz; XMEMCPY(out + totalSz, contentKeyEnc, *keyEncSz); totalSz += *keyEncSz; FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return totalSz; } /* build PKCS#7 envelopedData content type, return enveloped size */ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) { int i, ret = 0, idx = 0; int totalSz = 0, padSz = 0, desOutSz = 0; int contentInfoSeqSz, outerContentTypeSz, outerContentSz; byte contentInfoSeq[MAX_SEQ_SZ]; byte outerContentType[MAX_ALGO_SZ]; byte outerContent[MAX_SEQ_SZ]; int envDataSeqSz, verSz; byte envDataSeq[MAX_SEQ_SZ]; byte ver[MAX_VERSION_SZ]; RNG rng; int contentKeyEncSz, blockKeySz; int dynamicFlag = 0; byte contentKeyPlain[MAX_CONTENT_KEY_LEN]; #ifdef WOLFSSL_SMALL_STACK byte* contentKeyEnc; #else byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ]; #endif byte* plain; byte* encryptedContent; int recipSz, recipSetSz; #ifdef WOLFSSL_SMALL_STACK byte* recip; #else byte recip[MAX_RECIP_SZ]; #endif byte recipSet[MAX_SET_SZ]; int encContentOctetSz, encContentSeqSz, contentTypeSz; int contentEncAlgoSz, ivOctetStringSz; byte encContentSeq[MAX_SEQ_SZ]; byte contentType[MAX_ALGO_SZ]; byte contentEncAlgo[MAX_ALGO_SZ]; byte tmpIv[DES_BLOCK_SIZE]; byte ivOctetString[MAX_OCTET_STR_SZ]; byte encContentOctet[MAX_OCTET_STR_SZ]; if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL) return BAD_FUNC_ARG; if (output == NULL || outputSz == 0) return BAD_FUNC_ARG; /* PKCS#7 only supports DES, 3DES for now */ switch (pkcs7->encryptOID) { case DESb: blockKeySz = DES_KEYLEN; break; case DES3b: blockKeySz = DES3_KEYLEN; break; default: WOLFSSL_MSG("Unsupported content cipher type"); return ALGO_ID_E; }; /* outer content type */ outerContentTypeSz = wc_SetContentType(ENVELOPED_DATA, outerContentType); /* version, defined as 0 in RFC 2315 */ verSz = SetMyVersion(0, ver, 0); /* generate random content encryption key */ ret = wc_InitRng(&rng); if (ret != 0) return ret; ret = wc_RNG_GenerateBlock(&rng, contentKeyPlain, blockKeySz); if (ret != 0) { wc_FreeRng(&rng); return ret; } #ifdef WOLFSSL_SMALL_STACK recip = (byte*)XMALLOC(MAX_RECIP_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (contentKeyEnc == NULL || recip == NULL) { if (recip) XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (contentKeyEnc) XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER); wc_FreeRng(&rng); return MEMORY_E; } #endif /* build RecipientInfo, only handle 1 for now */ recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, pkcs7->singleCertSz, RSAk, blockKeySz, &rng, contentKeyPlain, contentKeyEnc, &contentKeyEncSz, recip, MAX_RECIP_SZ); ForceZero(contentKeyEnc, MAX_ENCRYPTED_KEY_SZ); #ifdef WOLFSSL_SMALL_STACK XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif if (recipSz < 0) { WOLFSSL_MSG("Failed to create RecipientInfo"); wc_FreeRng(&rng); #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return recipSz; } recipSetSz = SetSet(recipSz, recipSet); /* generate IV for block cipher */ ret = wc_RNG_GenerateBlock(&rng, tmpIv, DES_BLOCK_SIZE); wc_FreeRng(&rng); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return ret; } /* EncryptedContentInfo */ contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); if (contentTypeSz == 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return BAD_FUNC_ARG; } /* allocate encrypted content buffer, pad if necessary, PKCS#7 padding */ padSz = DES_BLOCK_SIZE - (pkcs7->contentSz % DES_BLOCK_SIZE); desOutSz = pkcs7->contentSz + padSz; if (padSz != 0) { plain = (byte*)XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (plain == NULL) { #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } XMEMCPY(plain, pkcs7->content, pkcs7->contentSz); dynamicFlag = 1; for (i = 0; i < padSz; i++) { plain[pkcs7->contentSz + i] = padSz; } } else { plain = pkcs7->content; desOutSz = pkcs7->contentSz; } encryptedContent = (byte*)XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (encryptedContent == NULL) { if (dynamicFlag) XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } /* put together IV OCTET STRING */ ivOctetStringSz = SetOctetString(DES_BLOCK_SIZE, ivOctetString); /* build up our ContentEncryptionAlgorithmIdentifier sequence, * adding (ivOctetStringSz + DES_BLOCK_SIZE) for IV OCTET STRING */ contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, blkType, ivOctetStringSz + DES_BLOCK_SIZE); if (contentEncAlgoSz == 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dynamicFlag) XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return BAD_FUNC_ARG; } /* encrypt content */ if (pkcs7->encryptOID == DESb) { Des des; ret = wc_Des_SetKey(&des, contentKeyPlain, tmpIv, DES_ENCRYPTION); if (ret == 0) wc_Des_CbcEncrypt(&des, encryptedContent, plain, desOutSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dynamicFlag) XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return ret; } } else if (pkcs7->encryptOID == DES3b) { Des3 des3; ret = wc_Des3_SetKey(&des3, contentKeyPlain, tmpIv, DES_ENCRYPTION); if (ret == 0) ret = wc_Des3_CbcEncrypt(&des3, encryptedContent, plain, desOutSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dynamicFlag) XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return ret; } } encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, desOutSz, encContentOctet); encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + ivOctetStringSz + DES_BLOCK_SIZE + encContentOctetSz + desOutSz, encContentSeq); /* keep track of sizes for outer wrapper layering */ totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + ivOctetStringSz + DES_BLOCK_SIZE + encContentOctetSz + desOutSz; /* EnvelopedData */ envDataSeqSz = SetSequence(totalSz, envDataSeq); totalSz += envDataSeqSz; /* outer content */ outerContentSz = SetExplicit(0, totalSz, outerContent); totalSz += outerContentTypeSz; totalSz += outerContentSz; /* ContentInfo */ contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); totalSz += contentInfoSeqSz; if (totalSz > (int)outputSz) { WOLFSSL_MSG("Pkcs7_encrypt output buffer too small"); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dynamicFlag) XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return BUFFER_E; } XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz); idx += contentInfoSeqSz; XMEMCPY(output + idx, outerContentType, outerContentTypeSz); idx += outerContentTypeSz; XMEMCPY(output + idx, outerContent, outerContentSz); idx += outerContentSz; XMEMCPY(output + idx, envDataSeq, envDataSeqSz); idx += envDataSeqSz; XMEMCPY(output + idx, ver, verSz); idx += verSz; XMEMCPY(output + idx, recipSet, recipSetSz); idx += recipSetSz; XMEMCPY(output + idx, recip, recipSz); idx += recipSz; XMEMCPY(output + idx, encContentSeq, encContentSeqSz); idx += encContentSeqSz; XMEMCPY(output + idx, contentType, contentTypeSz); idx += contentTypeSz; XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz); idx += contentEncAlgoSz; XMEMCPY(output + idx, ivOctetString, ivOctetStringSz); idx += ivOctetStringSz; XMEMCPY(output + idx, tmpIv, DES_BLOCK_SIZE); idx += DES_BLOCK_SIZE; XMEMCPY(output + idx, encContentOctet, encContentOctetSz); idx += encContentOctetSz; XMEMCPY(output + idx, encryptedContent, desOutSz); idx += desOutSz; ForceZero(contentKeyPlain, MAX_CONTENT_KEY_LEN); if (dynamicFlag) XFREE(plain, NULL, DYNAMMIC_TYPE_TMP_BUFFER); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return idx; } /* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, byte* output, word32 outputSz) { int recipFound = 0; int ret, version, length; word32 savedIdx = 0, idx = 0; word32 contentType, encOID; byte issuerHash[SHA_DIGEST_SIZE]; int encryptedKeySz, keySz; byte tmpIv[DES_BLOCK_SIZE]; byte* decryptedKey = NULL; #ifdef WOLFSSL_SMALL_STACK mp_int* serialNum; byte* encryptedKey; RsaKey* privKey; #else mp_int stack_serialNum; mp_int* serialNum = &stack_serialNum; byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; RsaKey stack_privKey; RsaKey* privKey = &stack_privKey; #endif int encryptedContentSz; byte padLen; byte* encryptedContent = NULL; if (pkcs7 == NULL || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0) return BAD_FUNC_ARG; if (pkiMsg == NULL || pkiMsgSz == 0 || output == NULL || outputSz == 0) return BAD_FUNC_ARG; /* read past ContentInfo, verify type is envelopedData */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (contentType != ENVELOPED_DATA) { WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData"); return PKCS7_OID_E; } if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* remove EnvelopedData and version */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetMyVersion(pkiMsg, &idx, &version) < 0) return ASN_PARSE_E; if (version != 0) { WOLFSSL_MSG("PKCS#7 envelopedData needs to be of version 0"); return ASN_VERSION_E; } /* walk through RecipientInfo set, find correct recipient */ if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; #ifdef WOLFSSL_SMALL_STACK encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (encryptedKey == NULL) return MEMORY_E; #endif savedIdx = idx; recipFound = 0; /* when looking for next recipient, use first sequence and version to * indicate there is another, if not, move on */ while(recipFound == 0) { /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to * last good saved one */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { idx = savedIdx; break; } if (GetMyVersion(pkiMsg, &idx, &version) < 0) { idx = savedIdx; break; } if (version != 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_VERSION_E; } /* remove IssuerAndSerialNumber */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } /* if we found correct recipient, issuer hashes will match */ if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) { recipFound = 1; } #ifdef WOLFSSL_SMALL_STACK serialNum = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (serialNum == NULL) { XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #endif if (GetInt(serialNum, pkiMsg, &idx, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } mp_clear(serialNum); #ifdef WOLFSSL_SMALL_STACK XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } /* key encryption algorithm must be RSA for now */ if (encOID != RSAk) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ALGO_ID_E; } /* read encryptedKey */ if (pkiMsg[idx++] != ASN_OCTET_STRING) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (recipFound == 1) XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz); idx += encryptedKeySz; /* update good idx */ savedIdx = idx; } if (recipFound == 0) { WOLFSSL_MSG("No recipient found in envelopedData that matches input"); #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return PKCS7_RECIP_E; } /* remove EncryptedContentInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ if (pkiMsg[idx++] != ASN_OCTET_STRING) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (length != DES_BLOCK_SIZE) { WOLFSSL_MSG("Incorrect IV length, must be of DES_BLOCK_SIZE"); #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } XMEMCPY(tmpIv, &pkiMsg[idx], length); idx += length; /* read encryptedContent, cont[0] */ if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ASN_PARSE_E; } encryptedContent = (byte*)XMALLOC(encryptedContentSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (encryptedContent == NULL) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); /* load private key */ #ifdef WOLFSSL_SMALL_STACK privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (privKey == NULL) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #endif ret = wc_InitRsaKey(privKey, 0); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } idx = 0; ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey, pkcs7->privateKeySz); if (ret != 0) { WOLFSSL_MSG("Failed to decode RSA private key"); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } /* decrypt encryptedKey */ keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, &decryptedKey, privKey); wc_FreeRsaKey(privKey); #ifdef WOLFSSL_SMALL_STACK XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif if (keySz <= 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return keySz; } /* decrypt encryptedContent */ if (encOID == DESb) { Des des; ret = wc_Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); if (ret == 0) wc_Des_CbcDecrypt(&des, encryptedContent, encryptedContent, encryptedContentSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } } else if (encOID == DES3b) { Des3 des; ret = wc_Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); if (ret == 0) ret = wc_Des3_CbcDecrypt(&des, encryptedContent, encryptedContent, encryptedContentSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } } else { WOLFSSL_MSG("Unsupported content encryption OID type"); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return ALGO_ID_E; } padLen = encryptedContent[encryptedContentSz-1]; /* copy plaintext to output */ XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); /* free memory, zero out keys */ ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); ForceZero(encryptedContent, encryptedContentSz); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return encryptedContentSz - padLen; } #else /* HAVE_PKCS7 */ #ifdef _MSC_VER /* 4206 warning for blank file */ #pragma warning(disable: 4206) #endif #endif /* HAVE_PKCS7 */