X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_pkcs12/lib/pkcs12Encode.cpp diff --git a/libsecurity_pkcs12/lib/pkcs12Encode.cpp b/libsecurity_pkcs12/lib/pkcs12Encode.cpp deleted file mode 100644 index d99c3998..00000000 --- a/libsecurity_pkcs12/lib/pkcs12Encode.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * pkcs12Encode.h - P12Coder encoding engine. - * - * Unlike the decoding side of P12Coder, which can parse PFXs with - * more or less arbitrary structures, this encoding engine has - * a specific layout for what bags go where in the jungle of - * SafeContents and ContentInfos. It would be impractical to allow - * (or to expect) the app to specify this structure. - * - * The knowledge of how a PFX is built out of various components - * is encapsulated in the authSafeBuild() member function. The rest - * of the functions in this file are pretty much "PFX-structure- - * agnostic", so if one wanted to change the overall PFX structure, - * one would only have to focus on the authSafeBuild() function. - */ - -#include "pkcs12Coder.h" -#include "pkcs12Debug.h" -#include "pkcs12Crypto.h" -#include "pkcs12Templates.h" -#include "pkcs12Utils.h" -#include -#include -#include - -void P12Coder::encode( - CFDataRef *cpfx) // RETURNED -{ - p12EncodeLog("encode top"); - SecNssCoder localCdr; - NSS_P12_DecodedPFX pfx; - - memset(&pfx, 0, sizeof(pfx)); - p12IntToData(3, pfx.version, localCdr); - authSafeBuild(pfx.authSafe, localCdr); - macSignPfx(pfx, localCdr); - CSSM_DATA derPfx = {0, NULL}; - if(localCdr.encodeItem(&pfx, NSS_P12_DecodedPFXTemplate, derPfx)) { - p12ErrorLog("Error encoding top-level pfx\n"); - P12_THROW_ENCODE; - } - CFDataRef cp = CFDataCreate(NULL, derPfx.Data, derPfx.Length); - *cpfx = cp; -} - -void P12Coder::macSignPfx( - NSS_P12_DecodedPFX &pfx, - SecNssCoder &localCdr) -{ - p12EncodeLog("macSignPfx"); - NSS_P12_MacData *macData = localCdr.mallocn(); - pfx.macData = macData; - p12GenSalt(macData->macSalt, localCdr); - p12IntToData(mMacIterCount, macData->iterations, localCdr); - NSS_P7_DigestInfo &digInfo = macData->mac; - - /* this is not negotiable; it's the only one P12 allows */ - localCdr.allocCopyItem(CSSMOID_SHA1, digInfo.digestAlgorithm.algorithm); - /* null algorithm parameters */ - p12NullAlgParams(digInfo.digestAlgorithm); - - const CSSM_DATA *macPhrase = getMacPassPhrase(); - const CSSM_KEY *macPassKey = getMacPassKey(); - if((macPhrase == NULL) && (macPassKey == NULL)) { - p12ErrorLog("no passphrase set\n"); - CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE); - } - - CSSM_RETURN crtn = p12GenMac(mCspHand, - *pfx.authSafe.content.data, - CSSM_ALGID_SHA1, mMacIterCount, macData->macSalt, - macPhrase, macPassKey, localCdr, digInfo.digest); - if(crtn) { - p12ErrorLog("Error generating PFX MAC\n"); - CssmError::throwMe(crtn); - } -} - -/* - * This is the heart of the encoding engine. All knowledge of - * "what bags go where" is here. The PFX structure implemented here - * is derived from empirical observation of PFXs obtained from - * Mozilla 1.2b and from the DoD test vectors for "Conformance - * Testing of Relying Party Client Certificate Path Processing - * Logic", written by Cygnacom, Septemtber 28, 2001. - * - * The PFX structure is as follows: - * - * -- One AuthenticatedSafe element (a PKCS7 ContentInfo) containing - * all certificates and CRLs. - * - * ContentInfo.type = CT_EncryptedData - * Encryption algorithm is our "weak" encryption Alg, default - * of CSSMOID_PKCS12_pbeWithSHAAnd40BitRC4. - * - * -- One AuthenticatedSafe element containing all private keys in - * the form of ShroudedKeyBags. - * - * ContentInfo.type = CT_Data - * Encryption algorithm for shrouded key bags is our "strong" - * encryption, default CSSMOID_PKCS12_pbeWithSHAAnd3Key3DESCBC - * - * -- Everything else goes in another AuthenticatedSafe element. - * - * ContentInfo.type = CT_EncryptedData - * Encryption algorithm is our "strong" encryption Alg - */ -void P12Coder::authSafeBuild( - NSS_P7_DecodedContentInfo &authSafe, - SecNssCoder &localCdr) -{ - p12EncodeLog("authSafeBuild top"); - - /* how many contentInfos are we going to build? */ - unsigned numContents = 0; - if(mCerts.size() || mCrls.size()) { - numContents++; - } - if(mKeys.size()) { - numContents++; - } - if(mOpaques.size()) { - numContents++; - } - - if(numContents == 0) { - p12ErrorLog("authSafeBuild: no contents\n"); - MacOSError::throwMe(errSecParam); - } - - NSS_P7_DecodedContentInfo **contents = - (NSS_P7_DecodedContentInfo **)p12NssNullArray(numContents, - localCdr); - unsigned contentDex = 0; - - NSS_P12_SafeBag **safeBags; - - /* certs & crls */ - unsigned numBags = (unsigned)(mCerts.size() + mCrls.size()); - p12EncodeLog("authSafeBuild : %u certs + CRLS", numBags); - if(numBags) { - safeBags = (NSS_P12_SafeBag **)p12NssNullArray(numBags, localCdr); - unsigned bagDex = 0; - for(unsigned dex=0; dex(); - authSafe.content.data = adata; - adata->Data = NULL; - adata->Length = 0; - if(localCdr.encodeItem(&safe, NSS_P12_AuthenticatedSafeTemplate, - *adata)) { - p12ErrorLog("authSafeBuild: error encoding auth safe\n"); - P12_THROW_ENCODE; - } - authSafe.type = CT_Data; - authSafe.contentType = CSSMOID_PKCS7_Data; -} - -/* - * Build a AuthSafe element of specified type out of the - * specified array of bags. - */ -NSS_P7_DecodedContentInfo *P12Coder::safeContentsBuild( - NSS_P12_SafeBag **bags, - NSS_P7_CI_Type type, // CT_Data, CT_EncryptedData - CSSM_OID *encrOid, // only for CT_EncryptedData - unsigned iterCount, // ditto - SecNssCoder &localCdr) -{ - p12EncodeLog("safeContentsBuild type %u", (unsigned)type); - - /* - * First, encode the bag array as a SafeContents - */ - CSSM_DATA encSafeContents = {0, NULL}; - NSS_P12_SafeContents safeContents = {bags}; - if(localCdr.encodeItem(&safeContents, - NSS_P12_SafeContentsTemplate, encSafeContents)) { - p12ErrorLog("error encoding SafeContents\n"); - P12_THROW_ENCODE; - } - - NSS_P7_DecodedContentInfo *dci = - localCdr.mallocn(); - dci->type = type; - if(type == CT_Data) { - /* plaintext gets encoded as an octet string */ - localCdr.allocCopyItem(CSSMOID_PKCS7_Data, dci->contentType); - dci->content.data = localCdr.mallocn(); - localCdr.allocCopyItem(encSafeContents, *dci->content.data); - } - else if(type == CT_EncryptedData) { - /* encrypt the encoded SafeContents */ - localCdr.allocCopyItem(CSSMOID_PKCS7_EncryptedData, - dci->contentType); - dci->content.encryptData = localCdr.mallocn(); - NSS_P7_EncryptedData *ed = dci->content.encryptData; - assert(encrOid != NULL); - encryptData(encSafeContents, *encrOid, iterCount, *ed, localCdr); - } - else { - p12ErrorLog("bad type in safeContentsBuild\n"); - CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); - } - return dci; -} - -/* - * Encrypt the specified plaintext with specified algorithm. - * Drop result and other interesting info into an NSS_P7_EncryptedData. - */ -void P12Coder::encryptData( - const CSSM_DATA &ptext, - CSSM_OID &encrOid, - unsigned iterCount, - NSS_P7_EncryptedData &ed, - SecNssCoder &localCdr) -{ - p12EncodeLog("encryptData"); - - /* do the raw encrypt first to make sure we can do it... */ - CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES - CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE - CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5 - uint32 keySizeInBits; - uint32 blockSizeInBytes; // for IV, optional - CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc. - CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc. - PKCS_Which pkcs; - - bool found = pkcsOidToParams(&encrOid, - keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, - padding, mode, pkcs); - if(!found || (pkcs != PW_PKCS12)) { - p12ErrorLog("encryptData encrAlg not understood\n"); - CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); - } - - /* Salt: we generate random bytes */ - CSSM_DATA salt; - p12GenSalt(salt, localCdr); - - const CSSM_DATA *pwd = getEncrPassPhrase(); - const CSSM_KEY *passKey = getEncrPassKey(); - if((pwd == NULL) && (passKey == NULL)) { - p12ErrorLog("no passphrase set\n"); - CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE); - } - CSSM_DATA ctext = {0, NULL}; - - CSSM_RETURN crtn = p12Encrypt(mCspHand, ptext, - keyAlg, encrAlg, pbeHashAlg, - keySizeInBits, blockSizeInBytes, - padding, mode, - iterCount, salt, - pwd, passKey, localCdr, - ctext); - if(crtn) { - CssmError::throwMe(crtn); - } - - /* Now fill in the NSS_P7_EncryptedData */ - p12IntToData(0, ed.version, localCdr); - NSS_P7_EncrContentInfo &eci = ed.contentInfo; - localCdr.allocCopyItem(CSSMOID_PKCS7_Data, eci.contentType); - algIdBuild(eci.encrAlg, encrOid, salt, iterCount, localCdr); - eci.encrContent = ctext; -} - -/* - * Fill in an CSSM_X509_ALGORITHM_IDENTIFIER with parameters in - * the form of an encoded NSS_P12_PBE_Params - */ -void P12Coder::algIdBuild( - CSSM_X509_ALGORITHM_IDENTIFIER &algId, - const CSSM_OID &algOid, - const CSSM_DATA &salt, - unsigned iterCount, - SecNssCoder &localCdr) -{ - p12EncodeLog("algIdBuild"); - localCdr.allocCopyItem(algOid, algId.algorithm); - NSS_P12_PBE_Params pbeParams; - pbeParams.salt = salt; - p12IntToData(iterCount, pbeParams.iterations, localCdr); - if(localCdr.encodeItem(&pbeParams, NSS_P12_PBE_ParamsTemplate, - algId.parameters)) { - p12ErrorLog("error encoding NSS_P12_PBE_Params\n"); - P12_THROW_ENCODE; - } -} - -#pragma mark --- Individual Bag Builders --- - -NSS_P12_SafeBag *P12Coder::certBagBuild( - P12CertBag *cert, - SecNssCoder &localCdr) -{ - p12EncodeLog("certBagBuild"); - - NSS_P12_SafeBag *safeBag = localCdr.mallocn(); - safeBag->bagId = CSSMOID_PKCS12_certBag; - safeBag->type = BT_CertBag; - - NSS_P12_CertBag *certBag = localCdr.mallocn(); - safeBag->bagValue.certBag = certBag; - const CSSM_OID *certTypeOid = NULL; - switch(cert->certType()) { - case CT_X509: - certTypeOid = &CSSMOID_PKCS9_X509Certificate; - break; - case CT_SDSI: - certTypeOid = &CSSMOID_PKCS9_SdsiCertificate; - break; - default: - p12ErrorLog("unknown certType on encode\n"); - CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); - - } - - /* copies not needed, same scope as P12CertBag */ - certBag->bagType = *certTypeOid; - certBag->type = cert->certType(); - certBag->certValue = cert->certData(); - safeBag->bagAttrs = cert->getAllAttrs(); - return safeBag; -} - -NSS_P12_SafeBag *P12Coder::crlBagBuild( - P12CrlBag *crl, - SecNssCoder &localCdr) -{ - p12EncodeLog("crlBagBuild"); - - NSS_P12_SafeBag *safeBag = localCdr.mallocn(); - safeBag->bagId = CSSMOID_PKCS12_crlBag; - safeBag->type = BT_CrlBag; - - NSS_P12_CrlBag *crlBag = localCdr.mallocn(); - safeBag->bagValue.crlBag = crlBag; - const CSSM_OID *crlTypeOid = NULL; - switch(crl->crlType()) { - case CRT_X509: - crlTypeOid = &CSSMOID_PKCS9_X509Crl; - break; - default: - p12ErrorLog("unknown crlType on encode\n"); - CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); - - } - - /* copies not needed, same scope as P12CrlBag */ - crlBag->bagType = *crlTypeOid; - crlBag->type = crl->crlType(); - crlBag->crlValue = crl->crlData(); - safeBag->bagAttrs = crl->getAllAttrs(); - return safeBag; -} - -NSS_P12_SafeBag *P12Coder::keyBagBuild( - P12KeyBag *key, - SecNssCoder &localCdr) -{ - p12EncodeLog("keyBagBuild"); - - NSS_P12_SafeBag *safeBag = localCdr.mallocn(); - safeBag->bagId = CSSMOID_PKCS12_shroudedKeyBag; - safeBag->type = BT_ShroudedKeyBag; - - NSS_EncryptedPrivateKeyInfo *keyInfo = localCdr. - mallocn(); - safeBag->bagValue.shroudedKeyBag = keyInfo; - safeBag->bagAttrs = key->getAllAttrs(); - - /* Prepare for key wrap */ - CSSM_DATA salt; - p12GenSalt(salt, localCdr); - algIdBuild(keyInfo->algorithm, mStrongEncrAlg, salt, - mStrongEncrIterCount, localCdr); - - CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES - CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE - CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5 - uint32 keySizeInBits; - uint32 blockSizeInBytes; // for IV, optional - CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc. - CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc. - PKCS_Which pkcs; - - bool found = pkcsOidToParams(&mStrongEncrAlg, - keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, - padding, mode, pkcs); - if(!found || (pkcs != PW_PKCS12)) { - /* app config error - they gave us bogus algorithm */ - p12ErrorLog("keyBagBuild encrAlg not understood\n"); - CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); - } - const CSSM_DATA *encrPhrase = getEncrPassPhrase(); - const CSSM_KEY *passKey = getEncrPassKey(); - if((encrPhrase == NULL) && (passKey == NULL)) { - p12ErrorLog("no passphrase set\n"); - CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE); - } - CSSM_DATA shroudedBits = {0, NULL}; - - CSSM_RETURN crtn = p12WrapKey(mCspHand, - key->key(), key->privKeyCreds(), - keyAlg, encrAlg, pbeHashAlg, - keySizeInBits, blockSizeInBytes, - padding, mode, - mStrongEncrIterCount, salt, - encrPhrase, - passKey, - localCdr, - shroudedBits); - if(crtn) { - p12ErrorLog("Error wrapping private key\n"); - CssmError::throwMe(crtn); - } - - keyInfo->encryptedData = shroudedBits; - return safeBag; -} - -NSS_P12_SafeBag *P12Coder::opaqueBagBuild( - P12OpaqueBag *opaque, - SecNssCoder &localCdr) -{ - p12EncodeLog("opaqueBagBuild"); - NSS_P12_SafeBag *safeBag = localCdr.mallocn(); - safeBag->bagId = opaque->oid(); - safeBag->bagValue.secretBag = &opaque->blob(); - safeBag->bagAttrs = opaque->getAllAttrs(); - return safeBag; -}