| /* 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 <config.h> |
| #endif |
| |
| #include <wolfssl/wolfcrypt/settings.h> |
| |
| #ifdef HAVE_PKCS7 |
| |
| #include <wolfssl/wolfcrypt/pkcs7.h> |
| #include <wolfssl/wolfcrypt/error-crypt.h> |
| #include <wolfssl/wolfcrypt/logging.h> |
| #ifdef NO_INLINE |
| #include <wolfssl/wolfcrypt/misc.h> |
| #else |
| #include <wolfcrypt/src/misc.c> |
| #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 */ |
| |