THierarchicalStorage::THierarchicalStorage(const UnicodeString & AStorage) : FStorage(AStorage), FKeyHistory(new TStringList()) { SetAccessMode(smRead); SetExplicit(false); // While this was implemented in 5.0 already, for some reason // it was disabled (by mistake?). So although enabled for 5.6.1 only, // data written in Unicode/UTF8 can be read by all versions back to 5.0. SetForceAnsi(false); SetMungeStringValues(true); }
/* build PKCS#7 envelopedData content type, return enveloped size */ int 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]; byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ]; byte* plain; byte* encryptedContent; int recipSz, recipSetSz; byte recip[MAX_RECIP_SZ]; 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: CYASSL_MSG("Unsupported content cipher type"); return ALGO_ID_E; }; /* outer content type */ outerContentTypeSz = 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; /* build RecipientInfo, only handle 1 for now */ recipSz = CreateRecipientInfo(pkcs7->singleCert, pkcs7->singleCertSz, RSAk, blockKeySz, &rng, contentKeyPlain, contentKeyEnc, &contentKeyEncSz, recip, MAX_RECIP_SZ); if (recipSz < 0) { CYASSL_MSG("Failed to create RecipientInfo"); return recipSz; } recipSetSz = SetSet(recipSz, recipSet); /* generate IV for block cipher */ ret = RNG_GenerateBlock(&rng, tmpIv, DES_BLOCK_SIZE); if (ret != 0) return ret; /* EncryptedContentInfo */ contentTypeSz = SetContentType(pkcs7->contentOID, contentType); if (contentTypeSz == 0) 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 = XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (plain == NULL) { 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 = XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (encryptedContent == NULL) { if (dynamicFlag) XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); 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) 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); 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); 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) { CYASSL_MSG("Pkcs7_encrypt output buffer too small"); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (dynamicFlag) XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER); 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; #ifdef NO_RC4 FreeRng(&rng); #endif XMEMSET(contentKeyPlain, 0, MAX_CONTENT_KEY_LEN); XMEMSET(contentKeyEnc, 0, MAX_ENCRYPTED_KEY_SZ); if (dynamicFlag) XFREE(plain, NULL, DYNAMMIC_TYPE_TMP_BUFFER); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); return idx; }
/* build PKCS#7 signedData content type */ int 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 }; ESD esd; 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; XMEMSET(&esd, 0, sizeof(esd)); ret = InitSha(&esd.sha); if (ret != 0) 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) 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. */ { RsaKey privKey; int result; word32 scratch = 0; byte digestInfo[MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE]; 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); 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); 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; result = InitRsaKey(&privKey, NULL); if (result == 0) result = RsaPrivateKeyDecode(pkcs7->privateKey, &scratch, &privKey, pkcs7->privateKeySz); if (result < 0) { XFREE(flatSignedAttribs, 0, NULL); return PUBLIC_KEY_E; } result = RsaSSL_Sign(digestInfo, digIdx, esd.encContentDigest, sizeof(esd.encContentDigest), &privKey, pkcs7->rng); FreeRsaKey(&privKey); if (result < 0) { XFREE(flatSignedAttribs, 0, NULL); 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) 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; return idx; }