diff --git a/cyassl/ssl.h b/cyassl/ssl.h index c25f580ac..0ba47f481 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -337,6 +337,9 @@ * needs investigation in regards to macros in fips */ #define WOLFSSL_MAX_16BIT CYASSL_MAX_16BIT #define WOLFSSL_MSG(x) CYASSL_MSG(x) +#define NO_WOLFSSL_ALLOC_ALIGN NO_CYASSL_ALLOC_ALIGN /* @TODO*/ + + /* for arc4 reverse compatibility */ #ifndef NO_RC4 @@ -376,14 +379,13 @@ /* for hc128 reverse compatibility */ #ifdef HAVE_HC128 - #define NO_WOLFSSL_ALLOC_ALIGN NO_CYASSL_ALLOC_ALIGN /* @TODO*/ #define Hc128_Process wc_Hc128_Process #define Hc128_SetKey wc_Hc128_SetKey #endif /* for md2 reverse compatibility */ -#define CYASSL_MD2 WOLFSSL_MD@ /* @TODO */ +#define CYASSL_MD2 WOLFSSL_MD2 /* @TODO */ #ifdef WOLFSSL_MD2 #define InitMd2 wc_InitMd2 #define Md2Update wc_Md2Update @@ -409,6 +411,49 @@ #endif +/* for poly1305 reverse compatibility */ +#ifdef HAVE_POLY1305 + #define Poly1305SetKey wc_Poly1305SetKey + #define Poly1305Update wc_Poly1305Update + #define Poly1305Final wc_Poly1305Final +#endif + + +/* for rabbit reverse compatibility */ +#ifndef NO_RABBIT + #define RabbitProcess wc_RabbitProcess + #define RabbitSetKey wc_RabbitSetKey +#endif + + +/* for ripemd reverse compatibility */ +#define CYASSL_RIPEMD WOLFSSL_RIPEMD /* @TODO */ +#ifdef WOLFSSL_RIPEMD + #define InitRipeMd wc_InitRipeMd + #define RipeMdUpdate wc_RipeMdUpdate + #define RipeMdFinal wc_RipeMdFinal +#endif + + +/* for pkcs7 reverse compatibility */ +#ifdef HAVE_PKCS7 + #define SetContentType wc_SetContentType + #define GetContentType wc_GetContentType + #define CreateRecipientInfo wc_CreateRecipientInfo + #define PKCS7_InitWithCert wc_PKCS7_InitWithCert + #define PKCS7_Free wc_PKCS7_Free + #define PKCS7_EncodeData wc_PKCS7_EncodeData + #define PKCS7_EncodeSignedData wc_PKCS7_EncodeSignedData + #define PKCS7_VerifySignedData wc_PKCS7_VerifySignedData + #define PKCS7_EncodeEnvelopedData wc_PKCS7_EncodeEnvelopedData + #define PKCS7_DecodeEnvelopedData wc_PKCS7_DecodeEnvelopedData +#endif + + +/* for pwdbased reverse compatibility */ + + + #ifdef __cplusplus } /* extern "C" */ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c new file mode 100644 index 000000000..b80c36aff --- /dev/null +++ b/wolfcrypt/src/pkcs7.c @@ -0,0 +1,1849 @@ +/* pkcs7.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef HAVE_PKCS7 + +#include +#include +#include + +#ifndef min + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } +#endif + + +/* 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_PKS7_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, SHA_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 = InitSha(&esd->sha); + if (ret != 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + if (pkcs7->contentSz != 0) + { + ShaUpdate(&esd->sha, pkcs7->content, pkcs7->contentSz); + esd->contentDigest[0] = ASN_OCTET_STRING; + esd->contentDigest[1] = SHA_DIGEST_SIZE; + 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 = InitSha(&esd->sha); + if (ret < 0) { + XFREE(flatSignedAttribs, 0, NULL); +#ifdef WOLFSSL_SMALL_STACK + XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + ShaUpdate(&esd->sha, attribSet, attribSetSz); + ShaUpdate(&esd->sha, flatSignedAttribs, flatSignedAttribsSz); + } + 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 = InitRsaKey(privKey, NULL); + if (result == 0) + result = 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 = RsaSSL_Sign(digestInfo, digIdx, + esd->encContentDigest, + sizeof(esd->encContentDigest), + privKey, pkcs7->rng); + + 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_PKS7_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 = 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 (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 = RsaSSL_Verify(sig, sigSz, digest, digestSz, key); + 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->serial == NULL || 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 = 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 (RsaPublicKeyDecode(decoded->publicKey, &idx, pubKey, + decoded->pubKeySize) < 0) { + WOLFSSL_MSG("ASN RSA key decode error"); + 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 = RsaPublicEncrypt(contentKeyPlain, blockKeySz, contentKeyEnc, + MAX_ENCRYPTED_KEY_SZ, pubKey, rng); + 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 = InitRng(&rng); + if (ret != 0) + return ret; + + ret = RNG_GenerateBlock(&rng, contentKeyPlain, blockKeySz); + if (ret != 0) + 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); + 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); + + XMEMSET(contentKeyEnc, 0, 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"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); +#endif + return recipSz; + } + recipSetSz = SetSet(recipSz, recipSet); + + /* generate IV for block cipher */ + ret = RNG_GenerateBlock(&rng, tmpIv, DES_BLOCK_SIZE); + 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 = Des_SetKey(&des, contentKeyPlain, tmpIv, DES_ENCRYPTION); + + if (ret == 0) + 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 = Des3_SetKey(&des3, contentKeyPlain, tmpIv, DES_ENCRYPTION); + + if (ret == 0) + ret = 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; + +#if defined(HAVE_HASHDRBG) || defined(NO_RC4) + FreeRng(&rng); +#endif + + XMEMSET(contentKeyPlain, 0, 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 = 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 = 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 = RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, + &decryptedKey, privKey); + 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 = Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); + + if (ret == 0) + 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 = Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); + if (ret == 0) + ret = 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 */ + XMEMSET(encryptedKey, 0, MAX_ENCRYPTED_KEY_SZ); + XMEMSET(encryptedContent, 0, 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 */ + diff --git a/wolfcrypt/src/poly1305.c b/wolfcrypt/src/poly1305.c new file mode 100644 index 000000000..56441b9ab --- /dev/null +++ b/wolfcrypt/src/poly1305.c @@ -0,0 +1,554 @@ +/* poly1305.c + * + * Copyright (C) 2006-2014 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 + * + * Based off the public domain implementations by Andrew Moon + * and Daniel J. Bernstein + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef HAVE_POLY1305 +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #include +#endif +#ifdef CHACHA_AEAD_TEST + #include +#endif + +#ifdef _MSC_VER + /* 4127 warning constant while(1) */ + #pragma warning(disable: 4127) +#endif + +#if defined(POLY130564) + + #if defined(_MSC_VER) + #define POLY1305_NOINLINE __declspec(noinline) + #elif defined(__GNUC__) + #define POLY1305_NOINLINE __attribute__((noinline)) + #else + #define POLY1305_NOINLINE + #endif + + #if defined(_MSC_VER) + #include + + typedef struct word128 { + word64 lo; + word64 hi; + } word128; + + #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi) + #define ADD(out, in) { word64 t = out.lo; out.lo += in.lo; + out.hi += (out.lo < t) + in.hi; } + #define ADDLO(out, in) { word64 t = out.lo; out.lo += in; + out.hi += (out.lo < t); } + #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift))) + #define LO(in) (in.lo) + + #elif defined(__GNUC__) + #if defined(__SIZEOF_INT128__) + typedef unsigned __int128 word128; + #else + typedef unsigned word128 __attribute__((mode(TI))); + #endif + + #define MUL(out, x, y) out = ((word128)x * y) + #define ADD(out, in) out += in + #define ADDLO(out, in) out += in + #define SHR(in, shift) (word64)(in >> (shift)) + #define LO(in) (word64)(in) + #endif + + static word64 U8TO64(const byte* p) { + return + (((word64)(p[0] & 0xff) ) | + ((word64)(p[1] & 0xff) << 8) | + ((word64)(p[2] & 0xff) << 16) | + ((word64)(p[3] & 0xff) << 24) | + ((word64)(p[4] & 0xff) << 32) | + ((word64)(p[5] & 0xff) << 40) | + ((word64)(p[6] & 0xff) << 48) | + ((word64)(p[7] & 0xff) << 56)); + } + + static void U64TO8(byte* p, word64 v) { + p[0] = (v ) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + p[4] = (v >> 32) & 0xff; + p[5] = (v >> 40) & 0xff; + p[6] = (v >> 48) & 0xff; + p[7] = (v >> 56) & 0xff; + } + +#else /* if not 64 bit then use 32 bit */ + + static word32 U8TO32(const byte *p) { + return + (((word32)(p[0] & 0xff) ) | + ((word32)(p[1] & 0xff) << 8) | + ((word32)(p[2] & 0xff) << 16) | + ((word32)(p[3] & 0xff) << 24)); + } + + static void U32TO8(byte *p, word32 v) { + p[0] = (v ) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + } +#endif + +static void poly1305_blocks(Poly1305* ctx, const unsigned char *m, + size_t bytes) { + +#ifdef POLY130564 + + const word64 hibit = (ctx->final) ? 0 : ((word64)1 << 40); /* 1 << 128 */ + word64 r0,r1,r2; + word64 s1,s2; + word64 h0,h1,h2; + word64 c; + word128 d0,d1,d2,d; + +#else + + const word32 hibit = (ctx->final) ? 0 : (1 << 24); /* 1 << 128 */ + word32 r0,r1,r2,r3,r4; + word32 s1,s2,s3,s4; + word32 h0,h1,h2,h3,h4; + word64 d0,d1,d2,d3,d4; + word32 c; + +#endif + +#ifdef POLY130564 + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); + + while (bytes >= POLY1305_BLOCK_SIZE) { + word64 t0,t1; + + /* h += m[i] */ + t0 = U8TO64(&m[0]); + t1 = U8TO64(&m[8]); + + h0 += (( t0 ) & 0xfffffffffff); + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); + h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; + + /* h *= r */ + MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); + MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); + MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); + + /* (partial) h %= p */ + c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; + ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; + ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; + h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; + h1 += c; + + m += POLY1305_BLOCK_SIZE; + bytes -= POLY1305_BLOCK_SIZE; + } + + ctx->h[0] = h0; + ctx->h[1] = h1; + ctx->h[2] = h2; + +#else /* if not 64 bit then use 32 bit */ + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + r3 = ctx->r[3]; + r4 = ctx->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + h3 = ctx->h[3]; + h4 = ctx->h[4]; + + while (bytes >= POLY1305_BLOCK_SIZE) { + /* h += m[i] */ + h0 += (U8TO32(m+ 0) ) & 0x3ffffff; + h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; + h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; + h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; + h4 += (U8TO32(m+12) >> 8) | hibit; + + /* h *= r */ + d0 = ((word64)h0 * r0) + ((word64)h1 * s4) + ((word64)h2 * s3) + + ((word64)h3 * s2) + ((word64)h4 * s1); + d1 = ((word64)h0 * r1) + ((word64)h1 * r0) + ((word64)h2 * s4) + + ((word64)h3 * s3) + ((word64)h4 * s2); + d2 = ((word64)h0 * r2) + ((word64)h1 * r1) + ((word64)h2 * r0) + + ((word64)h3 * s4) + ((word64)h4 * s3); + d3 = ((word64)h0 * r3) + ((word64)h1 * r2) + ((word64)h2 * r1) + + ((word64)h3 * r0) + ((word64)h4 * s4); + d4 = ((word64)h0 * r4) + ((word64)h1 * r3) + ((word64)h2 * r2) + + ((word64)h3 * r1) + ((word64)h4 * r0); + + /* (partial) h %= p */ + c = (word32)(d0 >> 26); h0 = (word32)d0 & 0x3ffffff; + d1 += c; c = (word32)(d1 >> 26); h1 = (word32)d1 & 0x3ffffff; + d2 += c; c = (word32)(d2 >> 26); h2 = (word32)d2 & 0x3ffffff; + d3 += c; c = (word32)(d3 >> 26); h3 = (word32)d3 & 0x3ffffff; + d4 += c; c = (word32)(d4 >> 26); h4 = (word32)d4 & 0x3ffffff; + h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; + h1 += c; + + m += POLY1305_BLOCK_SIZE; + bytes -= POLY1305_BLOCK_SIZE; + } + + ctx->h[0] = h0; + ctx->h[1] = h1; + ctx->h[2] = h2; + ctx->h[3] = h3; + ctx->h[4] = h4; + +#endif /* end of 64 bit cpu blocks or 32 bit cpu */ +} + + +int wc_Poly1305SetKey(Poly1305* ctx, const byte* key, word32 keySz) { + +#if defined(POLY130564) + word64 t0,t1; +#endif + +#ifdef CHACHA_AEAD_TEST + word32 k; + printf("Poly key used:\n"); + for (k = 0; k < keySz; k++) { + printf("%02x", key[k]); + if ((k+1) % 8 == 0) + printf("\n"); + } + printf("\n"); +#endif + + if (keySz != 32 || ctx == NULL) + return BAD_FUNC_ARG; + +#if defined(POLY130564) + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + t0 = U8TO64(key + 0); + t1 = U8TO64(key + 8); + + ctx->r[0] = ( t0 ) & 0xffc0fffffff; + ctx->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + ctx->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; + + /* h (accumulator) = 0 */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + + /* save pad for later */ + ctx->pad[0] = U8TO64(key + 16); + ctx->pad[1] = U8TO64(key + 24); + +#else /* if not 64 bit then use 32 bit */ + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + ctx->r[0] = (U8TO32(key + 0) ) & 0x3ffffff; + ctx->r[1] = (U8TO32(key + 3) >> 2) & 0x3ffff03; + ctx->r[2] = (U8TO32(key + 6) >> 4) & 0x3ffc0ff; + ctx->r[3] = (U8TO32(key + 9) >> 6) & 0x3f03fff; + ctx->r[4] = (U8TO32(key + 12) >> 8) & 0x00fffff; + + /* h = 0 */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + ctx->h[3] = 0; + ctx->h[4] = 0; + + /* save pad for later */ + ctx->pad[0] = U8TO32(key + 16); + ctx->pad[1] = U8TO32(key + 20); + ctx->pad[2] = U8TO32(key + 24); + ctx->pad[3] = U8TO32(key + 28); + +#endif + + ctx->leftover = 0; + ctx->final = 0; + + return 0; +} + + +int wc_Poly1305Final(Poly1305* ctx, byte* mac) { + +#if defined(POLY130564) + + word64 h0,h1,h2,c; + word64 g0,g1,g2; + word64 t0,t1; + +#else + + word32 h0,h1,h2,h3,h4,c; + word32 g0,g1,g2,g3,g4; + word64 f; + word32 mask; + +#endif + + if (ctx == NULL) + return BAD_FUNC_ARG; + +#if defined(POLY130564) + + /* process the remaining block */ + if (ctx->leftover) { + size_t i = ctx->leftover; + ctx->buffer[i] = 1; + for (i = i + 1; i < POLY1305_BLOCK_SIZE; i++) + ctx->buffer[i] = 0; + ctx->final = 1; + poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE); + } + + /* fully carry h */ + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + + c = (h1 >> 44); h1 &= 0xfffffffffff; + h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; + h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; + h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; + h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; + h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; + g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; + g2 = h2 + c - ((word64)1 << 42); + + /* select h if h < p, or h + -p if h >= p */ + c = (g2 >> ((sizeof(word64) * 8) - 1)) - 1; + g0 &= c; + g1 &= c; + g2 &= c; + c = ~c; + h0 = (h0 & c) | g0; + h1 = (h1 & c) | g1; + h2 = (h2 & c) | g2; + + /* h = (h + pad) */ + t0 = ctx->pad[0]; + t1 = ctx->pad[1]; + + h0 += (( t0 ) & 0xfffffffffff) ; + c = (h0 >> 44); h0 &= 0xfffffffffff; + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; + c = (h1 >> 44); h1 &= 0xfffffffffff; + h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; + h2 &= 0x3ffffffffff; + + /* mac = h % (2^128) */ + h0 = ((h0 ) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); + + U64TO8(mac + 0, h0); + U64TO8(mac + 8, h1); + + /* zero out the state */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + ctx->r[0] = 0; + ctx->r[1] = 0; + ctx->r[2] = 0; + ctx->pad[0] = 0; + ctx->pad[1] = 0; + +#else /* if not 64 bit then use 32 bit */ + + /* process the remaining block */ + if (ctx->leftover) { + size_t i = ctx->leftover; + ctx->buffer[i++] = 1; + for (; i < POLY1305_BLOCK_SIZE; i++) + ctx->buffer[i] = 0; + ctx->final = 1; + poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE); + } + + /* fully carry h */ + h0 = ctx->h[0]; + h1 = ctx->h[1]; + h2 = ctx->h[2]; + h3 = ctx->h[3]; + h4 = ctx->h[4]; + + c = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + c - (1 << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(word32) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (word64)h0 + ctx->pad[0] ; h0 = (word32)f; + f = (word64)h1 + ctx->pad[1] + (f >> 32); h1 = (word32)f; + f = (word64)h2 + ctx->pad[2] + (f >> 32); h2 = (word32)f; + f = (word64)h3 + ctx->pad[3] + (f >> 32); h3 = (word32)f; + + U32TO8(mac + 0, h0); + U32TO8(mac + 4, h1); + U32TO8(mac + 8, h2); + U32TO8(mac + 12, h3); + + /* zero out the state */ + ctx->h[0] = 0; + ctx->h[1] = 0; + ctx->h[2] = 0; + ctx->h[3] = 0; + ctx->h[4] = 0; + ctx->r[0] = 0; + ctx->r[1] = 0; + ctx->r[2] = 0; + ctx->r[3] = 0; + ctx->r[4] = 0; + ctx->pad[0] = 0; + ctx->pad[1] = 0; + ctx->pad[2] = 0; + ctx->pad[3] = 0; + +#endif + + return 0; +} + + +int wc_Poly1305Update(Poly1305* ctx, const byte* m, word32 bytes) { + + size_t i; + +#ifdef CHACHA_AEAD_TEST + word32 k; + printf("Raw input to poly:\n"); + for (k = 0; k < bytes; k++) { + printf("%02x", m[k]); + if ((k+1) % 16 == 0) + printf("\n"); + } + printf("\n"); +#endif + + if (ctx == NULL) + return BAD_FUNC_ARG; + + /* handle leftover */ + if (ctx->leftover) { + size_t want = (POLY1305_BLOCK_SIZE - ctx->leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + ctx->buffer[ctx->leftover + i] = m[i]; + bytes -= want; + m += want; + ctx->leftover += want; + if (ctx->leftover < POLY1305_BLOCK_SIZE) + return 0; + poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE); + ctx->leftover = 0; + } + + /* process full blocks */ + if (bytes >= POLY1305_BLOCK_SIZE) { + size_t want = (bytes & ~(POLY1305_BLOCK_SIZE - 1)); + poly1305_blocks(ctx, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) + ctx->buffer[ctx->leftover + i] = m[i]; + ctx->leftover += bytes; + } + return 0; +} +#endif /* HAVE_POLY1305 */ + diff --git a/wolfcrypt/src/pwdbased.c b/wolfcrypt/src/pwdbased.c new file mode 100644 index 000000000..582c80fb9 --- /dev/null +++ b/wolfcrypt/src/pwdbased.c @@ -0,0 +1,474 @@ +/* pwdbased.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of CyaSSL. + * + * CyaSSL 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. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef NO_PWDBASED + +#ifdef CYASSL_PIC32MZ_HASH + +#define InitMd5 InitMd5_sw +#define Md5Update Md5Update_sw +#define Md5Final Md5Final_sw + +#define InitSha InitSha_sw +#define ShaUpdate ShaUpdate_sw +#define ShaFinal ShaFinal_sw + +#define InitSha256 InitSha256_sw +#define Sha256Update Sha256Update_sw +#define Sha256Final Sha256Final_sw + +#endif + +#include +#include +#include +#include +#if defined(CYASSL_SHA512) || defined(CYASSL_SHA384) + #include +#endif + +#ifdef NO_INLINE + #include +#else + #include +#endif + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +int PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt, + int sLen, int iterations, int kLen, int hashType) +{ + Md5 md5; + Sha sha; + int hLen = (hashType == MD5) ? (int)MD5_DIGEST_SIZE : (int)SHA_DIGEST_SIZE; + int i, ret = 0; + byte buffer[SHA_DIGEST_SIZE]; /* max size */ + + if (hashType != MD5 && hashType != SHA) + return BAD_FUNC_ARG; + + if (kLen > hLen) + return BAD_FUNC_ARG; + + if (iterations < 1) + return BAD_FUNC_ARG; + + if (hashType == MD5) { + InitMd5(&md5); + Md5Update(&md5, passwd, pLen); + Md5Update(&md5, salt, sLen); + Md5Final(&md5, buffer); + } + else { + ret = InitSha(&sha); + if (ret != 0) + return ret; + ShaUpdate(&sha, passwd, pLen); + ShaUpdate(&sha, salt, sLen); + ShaFinal(&sha, buffer); + } + + for (i = 1; i < iterations; i++) { + if (hashType == MD5) { + Md5Update(&md5, buffer, hLen); + Md5Final(&md5, buffer); + } + else { + ShaUpdate(&sha, buffer, hLen); + ShaFinal(&sha, buffer); + } + } + XMEMCPY(output, buffer, kLen); + + return 0; +} + + +int PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, + int sLen, int iterations, int kLen, int hashType) +{ + word32 i = 1; + int hLen; + int j, ret; + Hmac hmac; +#ifdef CYASSL_SMALL_STACK + byte* buffer; +#else + byte buffer[MAX_DIGEST_SIZE]; +#endif + + if (hashType == MD5) { + hLen = MD5_DIGEST_SIZE; + } + else if (hashType == SHA) { + hLen = SHA_DIGEST_SIZE; + } +#ifndef NO_SHA256 + else if (hashType == SHA256) { + hLen = SHA256_DIGEST_SIZE; + } +#endif +#ifdef CYASSL_SHA512 + else if (hashType == SHA512) { + hLen = SHA512_DIGEST_SIZE; + } +#endif + else + return BAD_FUNC_ARG; + +#ifdef CYASSL_SMALL_STACK + buffer = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buffer == NULL) + return MEMORY_E; +#endif + + ret = HmacSetKey(&hmac, hashType, passwd, pLen); + + if (ret == 0) { + while (kLen) { + int currentLen; + + ret = HmacUpdate(&hmac, salt, sLen); + if (ret != 0) + break; + + /* encode i */ + for (j = 0; j < 4; j++) { + byte b = (byte)(i >> ((3-j) * 8)); + + ret = HmacUpdate(&hmac, &b, 1); + if (ret != 0) + break; + } + + /* check ret from inside for loop */ + if (ret != 0) + break; + + ret = HmacFinal(&hmac, buffer); + if (ret != 0) + break; + + currentLen = min(kLen, hLen); + XMEMCPY(output, buffer, currentLen); + + for (j = 1; j < iterations; j++) { + ret = HmacUpdate(&hmac, buffer, hLen); + if (ret != 0) + break; + ret = HmacFinal(&hmac, buffer); + if (ret != 0) + break; + xorbuf(output, buffer, currentLen); + } + + /* check ret from inside for loop */ + if (ret != 0) + break; + + output += currentLen; + kLen -= currentLen; + i++; + } + } + +#ifdef CYASSL_SMALL_STACK + XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#ifdef CYASSL_SHA512 +#define PBKDF_DIGEST_SIZE SHA512_BLOCK_SIZE +#elif !defined(NO_SHA256) +#define PBKDF_DIGEST_SIZE SHA256_BLOCK_SIZE +#else +#define PBKDF_DIGEST_SIZE SHA_DIGEST_SIZE +#endif + +int PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* salt, + int saltLen, int iterations, int kLen, int hashType, int id) +{ + /* all in bytes instead of bits */ + word32 u, v, dLen, pLen, iLen, sLen, totalLen; + int dynamic = 0; + int ret = 0; + int i; + byte *D, *S, *P, *I; +#ifdef CYASSL_SMALL_STACK + byte staticBuffer[1]; /* force dynamic usage */ +#else + byte staticBuffer[1024]; +#endif + byte* buffer = staticBuffer; + +#ifdef CYASSL_SMALL_STACK + byte* Ai; + byte* B; +#else + byte Ai[PBKDF_DIGEST_SIZE]; + byte B[PBKDF_DIGEST_SIZE]; +#endif + + if (!iterations) + iterations = 1; + + if (hashType == MD5) { + v = MD5_BLOCK_SIZE; + u = MD5_DIGEST_SIZE; + } + else if (hashType == SHA) { + v = SHA_BLOCK_SIZE; + u = SHA_DIGEST_SIZE; + } +#ifndef NO_SHA256 + else if (hashType == SHA256) { + v = SHA256_BLOCK_SIZE; + u = SHA256_DIGEST_SIZE; + } +#endif +#ifdef CYASSL_SHA512 + else if (hashType == SHA512) { + v = SHA512_BLOCK_SIZE; + u = SHA512_DIGEST_SIZE; + } +#endif + else + return BAD_FUNC_ARG; + +#ifdef CYASSL_SMALL_STACK + Ai = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (Ai == NULL) + return MEMORY_E; + + B = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (B == NULL) { + XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + dLen = v; + sLen = v * ((saltLen + v - 1) / v); + if (passLen) + pLen = v * ((passLen + v - 1) / v); + else + pLen = 0; + iLen = sLen + pLen; + + totalLen = dLen + sLen + pLen; + + if (totalLen > sizeof(staticBuffer)) { + buffer = (byte*)XMALLOC(totalLen, 0, DYNAMIC_TYPE_KEY); + if (buffer == NULL) { +#ifdef CYASSL_SMALL_STACK + XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(B, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return MEMORY_E; + } + dynamic = 1; + } + + D = buffer; + S = D + dLen; + P = S + sLen; + I = S; + + XMEMSET(D, id, dLen); + + for (i = 0; i < (int)sLen; i++) + S[i] = salt[i % saltLen]; + for (i = 0; i < (int)pLen; i++) + P[i] = passwd[i % passLen]; + + while (kLen > 0) { + word32 currentLen; + mp_int B1; + + if (hashType == MD5) { + Md5 md5; + + InitMd5(&md5); + Md5Update(&md5, buffer, totalLen); + Md5Final(&md5, Ai); + + for (i = 1; i < iterations; i++) { + Md5Update(&md5, Ai, u); + Md5Final(&md5, Ai); + } + } + else if (hashType == SHA) { + Sha sha; + + ret = InitSha(&sha); + if (ret != 0) + break; + ShaUpdate(&sha, buffer, totalLen); + ShaFinal(&sha, Ai); + + for (i = 1; i < iterations; i++) { + ShaUpdate(&sha, Ai, u); + ShaFinal(&sha, Ai); + } + } +#ifndef NO_SHA256 + else if (hashType == SHA256) { + Sha256 sha256; + + ret = InitSha256(&sha256); + if (ret != 0) + break; + + ret = Sha256Update(&sha256, buffer, totalLen); + if (ret != 0) + break; + + ret = Sha256Final(&sha256, Ai); + if (ret != 0) + break; + + for (i = 1; i < iterations; i++) { + ret = Sha256Update(&sha256, Ai, u); + if (ret != 0) + break; + + ret = Sha256Final(&sha256, Ai); + if (ret != 0) + break; + } + } +#endif +#ifdef CYASSL_SHA512 + else if (hashType == SHA512) { + Sha512 sha512; + + ret = InitSha512(&sha512); + if (ret != 0) + break; + + ret = Sha512Update(&sha512, buffer, totalLen); + if (ret != 0) + break; + + ret = Sha512Final(&sha512, Ai); + if (ret != 0) + break; + + for (i = 1; i < iterations; i++) { + ret = Sha512Update(&sha512, Ai, u); + if (ret != 0) + break; + + ret = Sha512Final(&sha512, Ai); + if (ret != 0) + break; + } + } +#endif + + for (i = 0; i < (int)v; i++) + B[i] = Ai[i % u]; + + if (mp_init(&B1) != MP_OKAY) + ret = MP_INIT_E; + else if (mp_read_unsigned_bin(&B1, B, v) != MP_OKAY) + ret = MP_READ_E; + else if (mp_add_d(&B1, (mp_digit)1, &B1) != MP_OKAY) + ret = MP_ADD_E; + + if (ret != 0) { + mp_clear(&B1); + break; + } + + for (i = 0; i < (int)iLen; i += v) { + int outSz; + mp_int i1; + mp_int res; + + if (mp_init_multi(&i1, &res, NULL, NULL, NULL, NULL) != MP_OKAY) { + ret = MP_INIT_E; + break; + } + if (mp_read_unsigned_bin(&i1, I + i, v) != MP_OKAY) + ret = MP_READ_E; + else if (mp_add(&i1, &B1, &res) != MP_OKAY) + ret = MP_ADD_E; + else if ( (outSz = mp_unsigned_bin_size(&res)) < 0) + ret = MP_TO_E; + else { + if (outSz > (int)v) { + /* take off MSB */ + byte tmp[129]; + ret = mp_to_unsigned_bin(&res, tmp); + XMEMCPY(I + i, tmp + 1, v); + } + else if (outSz < (int)v) { + XMEMSET(I + i, 0, v - outSz); + ret = mp_to_unsigned_bin(&res, I + i + v - outSz); + } + else + ret = mp_to_unsigned_bin(&res, I + i); + } + + mp_clear(&i1); + mp_clear(&res); + if (ret < 0) break; + } + + currentLen = min(kLen, (int)u); + XMEMCPY(output, Ai, currentLen); + output += currentLen; + kLen -= currentLen; + mp_clear(&B1); + } + + if (dynamic) XFREE(buffer, 0, DYNAMIC_TYPE_KEY); + +#ifdef CYASSL_SMALL_STACK + XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(B, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#undef PBKDF_DIGEST_SIZE + +#endif /* NO_PWDBASED */ + diff --git a/wolfcrypt/src/rabbit.c b/wolfcrypt/src/rabbit.c new file mode 100644 index 000000000..414c8b1f7 --- /dev/null +++ b/wolfcrypt/src/rabbit.c @@ -0,0 +1,310 @@ +/* rabbit.c + * + * Copyright (C) 2006-2014 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef NO_RABBIT + +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #include +#endif + + +#ifdef BIG_ENDIAN_ORDER + #define LITTLE32(x) ByteReverseWord32(x) +#else + #define LITTLE32(x) (x) +#endif + +#define U32V(x) ((word32)(x) & 0xFFFFFFFFU) + + +/* Square a 32-bit unsigned integer to obtain the 64-bit result and return */ +/* the upper 32 bits XOR the lower 32 bits */ +static word32 RABBIT_g_func(word32 x) +{ + /* Temporary variables */ + word32 a, b, h, l; + + /* Construct high and low argument for squaring */ + a = x&0xFFFF; + b = x>>16; + + /* Calculate high and low result of squaring */ + h = (((U32V(a*a)>>17) + U32V(a*b))>>15) + b*b; + l = x*x; + + /* Return high XOR low */ + return U32V(h^l); +} + + +/* Calculate the next internal state */ +static void RABBIT_next_state(RabbitCtx* ctx) +{ + /* Temporary variables */ + word32 g[8], c_old[8], i; + + /* Save old counter values */ + for (i=0; i<8; i++) + c_old[i] = ctx->c[i]; + + /* Calculate new counter values */ + ctx->c[0] = U32V(ctx->c[0] + 0x4D34D34D + ctx->carry); + ctx->c[1] = U32V(ctx->c[1] + 0xD34D34D3 + (ctx->c[0] < c_old[0])); + ctx->c[2] = U32V(ctx->c[2] + 0x34D34D34 + (ctx->c[1] < c_old[1])); + ctx->c[3] = U32V(ctx->c[3] + 0x4D34D34D + (ctx->c[2] < c_old[2])); + ctx->c[4] = U32V(ctx->c[4] + 0xD34D34D3 + (ctx->c[3] < c_old[3])); + ctx->c[5] = U32V(ctx->c[5] + 0x34D34D34 + (ctx->c[4] < c_old[4])); + ctx->c[6] = U32V(ctx->c[6] + 0x4D34D34D + (ctx->c[5] < c_old[5])); + ctx->c[7] = U32V(ctx->c[7] + 0xD34D34D3 + (ctx->c[6] < c_old[6])); + ctx->carry = (ctx->c[7] < c_old[7]); + + /* Calculate the g-values */ + for (i=0;i<8;i++) + g[i] = RABBIT_g_func(U32V(ctx->x[i] + ctx->c[i])); + + /* Calculate new state values */ + ctx->x[0] = U32V(g[0] + rotlFixed(g[7],16) + rotlFixed(g[6], 16)); + ctx->x[1] = U32V(g[1] + rotlFixed(g[0], 8) + g[7]); + ctx->x[2] = U32V(g[2] + rotlFixed(g[1],16) + rotlFixed(g[0], 16)); + ctx->x[3] = U32V(g[3] + rotlFixed(g[2], 8) + g[1]); + ctx->x[4] = U32V(g[4] + rotlFixed(g[3],16) + rotlFixed(g[2], 16)); + ctx->x[5] = U32V(g[5] + rotlFixed(g[4], 8) + g[3]); + ctx->x[6] = U32V(g[6] + rotlFixed(g[5],16) + rotlFixed(g[4], 16)); + ctx->x[7] = U32V(g[7] + rotlFixed(g[6], 8) + g[5]); +} + + +/* IV setup */ +static void RabbitSetIV(Rabbit* ctx, const byte* inIv) +{ + /* Temporary variables */ + word32 i0, i1, i2, i3, i; + word32 iv[2]; + + if (inIv) + XMEMCPY(iv, inIv, sizeof(iv)); + else + XMEMSET(iv, 0, sizeof(iv)); + + /* Generate four subvectors */ + i0 = LITTLE32(iv[0]); + i2 = LITTLE32(iv[1]); + i1 = (i0>>16) | (i2&0xFFFF0000); + i3 = (i2<<16) | (i0&0x0000FFFF); + + /* Modify counter values */ + ctx->workCtx.c[0] = ctx->masterCtx.c[0] ^ i0; + ctx->workCtx.c[1] = ctx->masterCtx.c[1] ^ i1; + ctx->workCtx.c[2] = ctx->masterCtx.c[2] ^ i2; + ctx->workCtx.c[3] = ctx->masterCtx.c[3] ^ i3; + ctx->workCtx.c[4] = ctx->masterCtx.c[4] ^ i0; + ctx->workCtx.c[5] = ctx->masterCtx.c[5] ^ i1; + ctx->workCtx.c[6] = ctx->masterCtx.c[6] ^ i2; + ctx->workCtx.c[7] = ctx->masterCtx.c[7] ^ i3; + + /* Copy state variables */ + for (i=0; i<8; i++) + ctx->workCtx.x[i] = ctx->masterCtx.x[i]; + ctx->workCtx.carry = ctx->masterCtx.carry; + + /* Iterate the system four times */ + for (i=0; i<4; i++) + RABBIT_next_state(&(ctx->workCtx)); +} + + +/* Key setup */ +static INLINE int DoKey(Rabbit* ctx, const byte* key, const byte* iv) +{ + /* Temporary variables */ + word32 k0, k1, k2, k3, i; + + /* Generate four subkeys */ + k0 = LITTLE32(*(word32*)(key+ 0)); + k1 = LITTLE32(*(word32*)(key+ 4)); + k2 = LITTLE32(*(word32*)(key+ 8)); + k3 = LITTLE32(*(word32*)(key+12)); + + /* Generate initial state variables */ + ctx->masterCtx.x[0] = k0; + ctx->masterCtx.x[2] = k1; + ctx->masterCtx.x[4] = k2; + ctx->masterCtx.x[6] = k3; + ctx->masterCtx.x[1] = U32V(k3<<16) | (k2>>16); + ctx->masterCtx.x[3] = U32V(k0<<16) | (k3>>16); + ctx->masterCtx.x[5] = U32V(k1<<16) | (k0>>16); + ctx->masterCtx.x[7] = U32V(k2<<16) | (k1>>16); + + /* Generate initial counter values */ + ctx->masterCtx.c[0] = rotlFixed(k2, 16); + ctx->masterCtx.c[2] = rotlFixed(k3, 16); + ctx->masterCtx.c[4] = rotlFixed(k0, 16); + ctx->masterCtx.c[6] = rotlFixed(k1, 16); + ctx->masterCtx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF); + ctx->masterCtx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF); + ctx->masterCtx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF); + ctx->masterCtx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF); + + /* Clear carry bit */ + ctx->masterCtx.carry = 0; + + /* Iterate the system four times */ + for (i=0; i<4; i++) + RABBIT_next_state(&(ctx->masterCtx)); + + /* Modify the counters */ + for (i=0; i<8; i++) + ctx->masterCtx.c[i] ^= ctx->masterCtx.x[(i+4)&0x7]; + + /* Copy master instance to work instance */ + for (i=0; i<8; i++) { + ctx->workCtx.x[i] = ctx->masterCtx.x[i]; + ctx->workCtx.c[i] = ctx->masterCtx.c[i]; + } + ctx->workCtx.carry = ctx->masterCtx.carry; + + RabbitSetIV(ctx, iv); + + return 0; +} + + +/* Key setup */ +int wc_RabbitSetKey(Rabbit* ctx, const byte* key, const byte* iv) +{ +#ifdef XSTREAM_ALIGN + if ((cyassl_word)key % 4) { + int alignKey[4]; + + /* iv aligned in SetIV */ + WOLFSSL_MSG("wc_RabbitSetKey unaligned key"); + + XMEMCPY(alignKey, key, sizeof(alignKey)); + + return DoKey(ctx, (const byte*)alignKey, iv); + } +#endif /* XSTREAM_ALIGN */ + + return DoKey(ctx, key, iv); +} + + +/* Encrypt/decrypt a message of any size */ +static INLINE int DoProcess(Rabbit* ctx, byte* output, const byte* input, + word32 msglen) +{ + /* Encrypt/decrypt all full blocks */ + while (msglen >= 16) { + /* Iterate the system */ + RABBIT_next_state(&(ctx->workCtx)); + + /* Encrypt/decrypt 16 bytes of data */ + *(word32*)(output+ 0) = *(word32*)(input+ 0) ^ + LITTLE32(ctx->workCtx.x[0] ^ (ctx->workCtx.x[5]>>16) ^ + U32V(ctx->workCtx.x[3]<<16)); + *(word32*)(output+ 4) = *(word32*)(input+ 4) ^ + LITTLE32(ctx->workCtx.x[2] ^ (ctx->workCtx.x[7]>>16) ^ + U32V(ctx->workCtx.x[5]<<16)); + *(word32*)(output+ 8) = *(word32*)(input+ 8) ^ + LITTLE32(ctx->workCtx.x[4] ^ (ctx->workCtx.x[1]>>16) ^ + U32V(ctx->workCtx.x[7]<<16)); + *(word32*)(output+12) = *(word32*)(input+12) ^ + LITTLE32(ctx->workCtx.x[6] ^ (ctx->workCtx.x[3]>>16) ^ + U32V(ctx->workCtx.x[1]<<16)); + + /* Increment pointers and decrement length */ + input += 16; + output += 16; + msglen -= 16; + } + + /* Encrypt/decrypt remaining data */ + if (msglen) { + + word32 i; + word32 tmp[4]; + byte* buffer = (byte*)tmp; + + XMEMSET(tmp, 0, sizeof(tmp)); /* help static analysis */ + + /* Iterate the system */ + RABBIT_next_state(&(ctx->workCtx)); + + /* Generate 16 bytes of pseudo-random data */ + tmp[0] = LITTLE32(ctx->workCtx.x[0] ^ + (ctx->workCtx.x[5]>>16) ^ U32V(ctx->workCtx.x[3]<<16)); + tmp[1] = LITTLE32(ctx->workCtx.x[2] ^ + (ctx->workCtx.x[7]>>16) ^ U32V(ctx->workCtx.x[5]<<16)); + tmp[2] = LITTLE32(ctx->workCtx.x[4] ^ + (ctx->workCtx.x[1]>>16) ^ U32V(ctx->workCtx.x[7]<<16)); + tmp[3] = LITTLE32(ctx->workCtx.x[6] ^ + (ctx->workCtx.x[3]>>16) ^ U32V(ctx->workCtx.x[1]<<16)); + + /* Encrypt/decrypt the data */ + for (i=0; i +#endif + +#include + +#ifdef WOLFSSL_RIPEMD + +#include +#ifdef NO_INLINE + #include +#else + #include +#endif + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void wc_InitRipeMd(RipeMd* ripemd) +{ + ripemd->digest[0] = 0x67452301L; + ripemd->digest[1] = 0xEFCDAB89L; + ripemd->digest[2] = 0x98BADCFEL; + ripemd->digest[3] = 0x10325476L; + ripemd->digest[4] = 0xC3D2E1F0L; + + ripemd->buffLen = 0; + ripemd->loLen = 0; + ripemd->hiLen = 0; +} + + +/* for all */ +#define F(x, y, z) (x ^ y ^ z) +#define G(x, y, z) (z ^ (x & (y^z))) +#define H(x, y, z) (z ^ (x | ~y)) +#define I(x, y, z) (y ^ (z & (x^y))) +#define J(x, y, z) (x ^ (y | ~z)) + +#define k0 0 +#define k1 0x5a827999 +#define k2 0x6ed9eba1 +#define k3 0x8f1bbcdc +#define k4 0xa953fd4e +#define k5 0x50a28be6 +#define k6 0x5c4dd124 +#define k7 0x6d703ef3 +#define k8 0x7a6d76e9 +#define k9 0 + +/* for 160 and 320 */ +#define Subround(f, a, b, c, d, e, x, s, k) \ + a += f(b, c, d) + x + k;\ + a = rotlFixed((word32)a, s) + e;\ + c = rotlFixed((word32)c, 10U) + +static void Transform(RipeMd* ripemd) +{ + word32 a1, b1, c1, d1, e1, a2, b2, c2, d2, e2; + a1 = a2 = ripemd->digest[0]; + b1 = b2 = ripemd->digest[1]; + c1 = c2 = ripemd->digest[2]; + d1 = d2 = ripemd->digest[3]; + e1 = e2 = ripemd->digest[4]; + + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 11, k0); + Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 1], 14, k0); + Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 2], 15, k0); + Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 12, k0); + Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 4], 5, k0); + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 5], 8, k0); + Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 6], 7, k0); + Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 7], 9, k0); + Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 11, k0); + Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 13, k0); + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[10], 14, k0); + Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[11], 15, k0); + Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[12], 6, k0); + Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[13], 7, k0); + Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[14], 9, k0); + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[15], 8, k0); + + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 7], 7, k1); + Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 4], 6, k1); + Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[13], 8, k1); + Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 13, k1); + Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[10], 11, k1); + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 6], 9, k1); + Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[15], 7, k1); + Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 15, k1); + Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[12], 7, k1); + Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 12, k1); + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 15, k1); + Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 5], 9, k1); + Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 11, k1); + Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[14], 7, k1); + Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[11], 13, k1); + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 8], 12, k1); + + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 11, k2); + Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[10], 13, k2); + Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[14], 6, k2); + Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 4], 7, k2); + Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 14, k2); + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[15], 9, k2); + Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 13, k2); + Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 15, k2); + Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 14, k2); + Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 7], 8, k2); + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 13, k2); + Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 6], 6, k2); + Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[13], 5, k2); + Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[11], 12, k2); + Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 7, k2); + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[12], 5, k2); + + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 11, k3); + Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 12, k3); + Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[11], 14, k3); + Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[10], 15, k3); + Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 14, k3); + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 15, k3); + Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[12], 9, k3); + Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[ 4], 8, k3); + Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[13], 9, k3); + Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 14, k3); + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 7], 5, k3); + Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[15], 6, k3); + Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[14], 8, k3); + Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 6, k3); + Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 6], 5, k3); + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 12, k3); + + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 4], 9, k4); + Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 15, k4); + Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 5, k4); + Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 9], 11, k4); + Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 7], 6, k4); + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[12], 8, k4); + Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 13, k4); + Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[10], 12, k4); + Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[14], 5, k4); + Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 12, k4); + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 3], 13, k4); + Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 8], 14, k4); + Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[11], 11, k4); + Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 6], 8, k4); + Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[15], 5, k4); + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[13], 6, k4); + + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 5], 8, k5); + Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[14], 9, k5); + Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 7], 9, k5); + Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[ 0], 11, k5); + Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 13, k5); + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 2], 15, k5); + Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[11], 15, k5); + Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 4], 5, k5); + Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[13], 7, k5); + Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 6], 7, k5); + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[15], 8, k5); + Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 11, k5); + Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 1], 14, k5); + Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[10], 14, k5); + Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 3], 12, k5); + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[12], 6, k5); + + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 6], 9, k6); + Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[11], 13, k6); + Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 3], 15, k6); + Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 7], 7, k6); + Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 12, k6); + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[13], 8, k6); + Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[ 5], 9, k6); + Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[10], 11, k6); + Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[14], 7, k6); + Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[15], 7, k6); + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 12, k6); + Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[12], 7, k6); + Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 4], 6, k6); + Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 15, k6); + Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 1], 13, k6); + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 2], 11, k6); + + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[15], 9, k7); + Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 5], 7, k7); + Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 1], 15, k7); + Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 3], 11, k7); + Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 8, k7); + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[14], 6, k7); + Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 6], 6, k7); + Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 14, k7); + Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[11], 12, k7); + Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 13, k7); + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[12], 5, k7); + Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 14, k7); + Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[10], 13, k7); + Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 13, k7); + Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 4], 7, k7); + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[13], 5, k7); + + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 8], 15, k8); + Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[ 6], 5, k8); + Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 4], 8, k8); + Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 1], 11, k8); + Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 14, k8); + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[11], 14, k8); + Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[15], 6, k8); + Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 14, k8); + Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 5], 6, k8); + Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[12], 9, k8); + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 12, k8); + Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[13], 9, k8); + Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 9], 12, k8); + Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 5, k8); + Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[10], 15, k8); + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[14], 8, k8); + + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[12], 8, k9); + Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[15], 5, k9); + Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[10], 12, k9); + Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 4], 9, k9); + Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 1], 12, k9); + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[ 5], 5, k9); + Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[ 8], 14, k9); + Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 6, k9); + Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 6], 8, k9); + Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 13, k9); + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[13], 6, k9); + Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[14], 5, k9); + Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 0], 15, k9); + Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 13, k9); + Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 9], 11, k9); + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[11], 11, k9); + + c1 = ripemd->digest[1] + c1 + d2; + ripemd->digest[1] = ripemd->digest[2] + d1 + e2; + ripemd->digest[2] = ripemd->digest[3] + e1 + a2; + ripemd->digest[3] = ripemd->digest[4] + a1 + b2; + ripemd->digest[4] = ripemd->digest[0] + b1 + c2; + ripemd->digest[0] = c1; +} + + +static INLINE void AddLength(RipeMd* ripemd, word32 len) +{ + word32 tmp = ripemd->loLen; + if ( (ripemd->loLen += len) < tmp) + ripemd->hiLen++; /* carry low to high */ +} + + +void wc_RipeMdUpdate(RipeMd* ripemd, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)ripemd->buffer; + + while (len) { + word32 add = min(len, RIPEMD_BLOCK_SIZE - ripemd->buffLen); + XMEMCPY(&local[ripemd->buffLen], data, add); + + ripemd->buffLen += add; + data += add; + len -= add; + + if (ripemd->buffLen == RIPEMD_BLOCK_SIZE) { + #ifdef BIG_ENDIAN_ORDER + ByteReverseWords(ripemd->buffer, ripemd->buffer, + RIPEMD_BLOCK_SIZE); + #endif + Transform(ripemd); + AddLength(ripemd, RIPEMD_BLOCK_SIZE); + ripemd->buffLen = 0; + } + } +} + + +void wc_RipeMdFinal(RipeMd* ripemd, byte* hash) +{ + byte* local = (byte*)ripemd->buffer; + + AddLength(ripemd, ripemd->buffLen); /* before adding pads */ + + local[ripemd->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (ripemd->buffLen > RIPEMD_PAD_SIZE) { + XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_BLOCK_SIZE - ripemd->buffLen); + ripemd->buffLen += RIPEMD_BLOCK_SIZE - ripemd->buffLen; + + #ifdef BIG_ENDIAN_ORDER + ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE); + #endif + Transform(ripemd); + ripemd->buffLen = 0; + } + XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_PAD_SIZE - ripemd->buffLen); + + /* put lengths in bits */ + ripemd->loLen = ripemd->loLen << 3; + ripemd->hiLen = (ripemd->loLen >> (8*sizeof(ripemd->loLen) - 3)) + + (ripemd->hiLen << 3); + + /* store lengths */ + #ifdef BIG_ENDIAN_ORDER + ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[RIPEMD_PAD_SIZE], &ripemd->loLen, sizeof(word32)); + XMEMCPY(&local[RIPEMD_PAD_SIZE + sizeof(word32)], &ripemd->hiLen, + sizeof(word32)); + + Transform(ripemd); + #ifdef BIG_ENDIAN_ORDER + ByteReverseWords(ripemd->digest, ripemd->digest, RIPEMD_DIGEST_SIZE); + #endif + XMEMCPY(hash, ripemd->digest, RIPEMD_DIGEST_SIZE); + + wc_InitRipeMd(ripemd); /* reset state */ +} + + +#endif /* WOLFSSL_RIPEMD */