mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-24 15:31:56 -04:00
1859 lines
59 KiB
C
1859 lines
59 KiB
C
/* 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 */
|
|
|