+++ /dev/null
-/*
- * Copyright (c) 2003-2004,2011,2014 Apple 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@
- */
-
-/*
- * pkc12Crypto.cpp - PKCS12-specific cyptrographic routines
- */
-
-#include "pkcs12Crypto.h"
-#include "pkcs12Utils.h"
-#include "pkcs12Debug.h"
-#include <security_cdsa_utils/cuCdsaUtils.h>
-#include <security_cdsa_utilities/cssmacl.h>
-#include <security_keychain/Access.h>
-
-/*
- * Given appropriate P12-style parameters, cook up a CSSM_KEY.
- * Caller MUST CSSM_FreeKey() when it's done with the key.
- */
-#define KEY_LABEL "p12 key"
-
-CSSM_RETURN p12KeyGen(
- CSSM_CSP_HANDLE cspHand,
- CSSM_KEY &key,
- bool isForEncr, // true: en/decrypt false: MAC
- CSSM_ALGORITHMS keyAlg,
- CSSM_ALGORITHMS pbeHashAlg, // actually must be SHA1 for now
- uint32 keySizeInBits,
- uint32 iterCount,
- const CSSM_DATA &salt,
- /* exactly one of the following two must be valid */
- const CSSM_DATA *pwd, // unicode external representation
- const CSSM_KEY *passKey,
- CSSM_DATA &iv) // referent is optional
-{
- CSSM_RETURN crtn;
- CSSM_CC_HANDLE ccHand;
- CSSM_DATA dummyLabel;
- CSSM_ACCESS_CREDENTIALS creds;
-
- memset(&key, 0, sizeof(CSSM_KEY));
- memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
-
- /* infer key derivation algorithm */
- CSSM_ALGORITHMS deriveAlg = CSSM_ALGID_NONE;
- if(pbeHashAlg != CSSM_ALGID_SHA1) {
- return CSSMERR_CSP_INVALID_ALGORITHM;
- }
- if(isForEncr) {
- /*
- * FIXME - if this key is going to be used to wrap/unwrap a
- * shrouded key bag, its usage will change accordingly...
- */
- deriveAlg = CSSM_ALGID_PKCS12_PBE_ENCR;
- }
- else {
- deriveAlg = CSSM_ALGID_PKCS12_PBE_MAC;
- }
- CSSM_CRYPTO_DATA seed;
- if(pwd) {
- seed.Param = *pwd;
- }
- else {
- seed.Param.Data = NULL;
- seed.Param.Length = 0;
- }
- seed.Callback = NULL;
- seed.CallerCtx = NULL;
-
- crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
- deriveAlg,
- keyAlg,
- keySizeInBits,
- &creds,
- passKey, // BaseKey
- iterCount,
- &salt,
- &seed, // seed
- &ccHand);
- if(crtn) {
- p12LogCssmError("CSSM_CSP_CreateDeriveKeyContext", crtn);
- return crtn;
- }
-
- dummyLabel.Length = strlen(KEY_LABEL);
- dummyLabel.Data = (uint8 *)KEY_LABEL;
-
- /* KEYUSE_ANY - this is just an ephemeral session key */
- crtn = CSSM_DeriveKey(ccHand,
- &iv,
- CSSM_KEYUSE_ANY,
- CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
- &dummyLabel,
- NULL, // cred and acl
- &key);
- CSSM_DeleteContext(ccHand);
- if(crtn) {
- p12LogCssmError("CSSM_DeriveKey", crtn);
- }
- return crtn;
-}
-
-/*
- * Decrypt (typically, an encrypted P7 ContentInfo contents)
- */
-CSSM_RETURN p12Decrypt(
- CSSM_CSP_HANDLE cspHand,
- const CSSM_DATA &cipherText,
- CSSM_ALGORITHMS keyAlg,
- CSSM_ALGORITHMS encrAlg,
- CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only
- uint32 keySizeInBits,
- uint32 blockSizeInBytes, // for IV
- CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc.
- CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc.
- uint32 iterCount,
- const CSSM_DATA &salt,
- /* exactly one of the following two must be valid */
- const CSSM_DATA *pwd, // unicode external representation
- const CSSM_KEY *passKey,
- SecNssCoder &coder, // for mallocing plainText
- CSSM_DATA &plainText)
-{
- CSSM_RETURN crtn;
- CSSM_KEY ckey;
- CSSM_CC_HANDLE ccHand = 0;
- CSSM_DATA ourPtext = {0, NULL};
- CSSM_DATA remData = {0, NULL};
-
- /* P12 style IV derivation, optional */
- CSSM_DATA iv = {0, NULL};
- CSSM_DATA_PTR ivPtr = NULL;
- if(blockSizeInBytes) {
- coder.allocItem(iv, blockSizeInBytes);
- ivPtr = &iv;
- }
-
- /* P12 style key derivation */
- crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
- keySizeInBits, iterCount, salt, pwd, passKey, iv);
- if(crtn) {
- return crtn;
- }
- /* subsequent errors to errOut: */
-
- /* CSSM context */
- crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
- encrAlg,
- mode,
- NULL, // access cred
- &ckey,
- ivPtr, // InitVector, optional
- padding,
- NULL, // Params
- &ccHand);
- if(crtn) {
- cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
- goto errOut;
- }
-
- /* go - CSP mallocs ptext and rem data */
- CSSM_SIZE bytesDecrypted;
- crtn = CSSM_DecryptData(ccHand,
- &cipherText,
- 1,
- &ourPtext,
- 1,
- &bytesDecrypted,
- &remData);
- if(crtn) {
- cuPrintError("CSSM_DecryptData", crtn);
- }
- else {
- coder.allocCopyItem(ourPtext, plainText);
- plainText.Length = bytesDecrypted;
-
- /* plaintext copied into coder space; free the memory allocated
- * by the CSP */
- freeCssmMemory(cspHand, ourPtext.Data);
- }
- /* an artifact of CSPFullPLuginSession - this never contains
- * valid data but sometimes gets mallocds */
- if(remData.Data) {
- freeCssmMemory(cspHand, remData.Data);
- }
-errOut:
- if(ccHand) {
- CSSM_DeleteContext(ccHand);
- }
- CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
- return crtn;
-}
-
-/*
- * Decrypt (typically, an encrypted P7 ContentInfo contents)
- */
-CSSM_RETURN p12Encrypt(
- CSSM_CSP_HANDLE cspHand,
- const CSSM_DATA &plainText,
- CSSM_ALGORITHMS keyAlg,
- CSSM_ALGORITHMS encrAlg,
- CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only
- uint32 keySizeInBits,
- uint32 blockSizeInBytes, // for IV
- CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc.
- CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc.
- uint32 iterCount,
- const CSSM_DATA &salt,
- /* exactly one of the following two must be valid */
- const CSSM_DATA *pwd, // unicode external representation
- const CSSM_KEY *passKey,
- SecNssCoder &coder, // for mallocing cipherText
- CSSM_DATA &cipherText)
-{
- CSSM_RETURN crtn;
- CSSM_KEY ckey;
- CSSM_CC_HANDLE ccHand = 0;
- CSSM_DATA ourCtext = {0, NULL};
- CSSM_DATA remData = {0, NULL};
-
- /* P12 style IV derivation, optional */
- CSSM_DATA iv = {0, NULL};
- CSSM_DATA_PTR ivPtr = NULL;
- if(blockSizeInBytes) {
- coder.allocItem(iv, blockSizeInBytes);
- ivPtr = &iv;
- }
-
- /* P12 style key derivation */
- crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
- keySizeInBits, iterCount, salt, pwd, passKey, iv);
- if(crtn) {
- return crtn;
- }
- /* subsequent errors to errOut: */
-
- /* CSSM context */
- crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
- encrAlg,
- mode,
- NULL, // access cred
- &ckey,
- ivPtr, // InitVector, optional
- padding,
- NULL, // Params
- &ccHand);
- if(crtn) {
- cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
- goto errOut;
- }
-
- /* go - CSP mallocs ctext and rem data */
- CSSM_SIZE bytesEncrypted;
- crtn = CSSM_EncryptData(ccHand,
- &plainText,
- 1,
- &ourCtext,
- 1,
- &bytesEncrypted,
- &remData);
- if(crtn) {
- cuPrintError("CSSM_DecryptData", crtn);
- }
- else {
- coder.allocCopyItem(ourCtext, cipherText);
- cipherText.Length = bytesEncrypted;
-
- /* plaintext copied into coder space; free the memory allocated
- * by the CSP */
- freeCssmMemory(cspHand, ourCtext.Data);
- }
- /* an artifact of CSPFUllPLuginSession - this never contains
- * valid data but sometimes gets mallocds */
- if(remData.Data) {
- freeCssmMemory(cspHand, remData.Data);
- }
-errOut:
- if(ccHand) {
- CSSM_DeleteContext(ccHand);
- }
- CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
- return crtn;
-}
-
-/*
- * Calculate the MAC for a PFX. Caller is either going compare
- * the result against an existing PFX's MAC or drop the result into
- * a newly created PFX.
- */
-CSSM_RETURN p12GenMac(
- CSSM_CSP_HANDLE cspHand,
- const CSSM_DATA &ptext, // e.g., NSS_P12_DecodedPFX.derAuthSaafe
- CSSM_ALGORITHMS alg, // better be SHA1!
- unsigned iterCount,
- const CSSM_DATA &salt,
- /* exactly one of the following two must be valid */
- const CSSM_DATA *pwd, // unicode external representation
- const CSSM_KEY *passKey,
- SecNssCoder &coder, // for mallocing macData
- CSSM_DATA &macData) // RETURNED
-{
- CSSM_RETURN crtn;
- CSSM_CC_HANDLE ccHand = 0;
-
- /* P12 style key derivation */
- unsigned keySizeInBits;
- CSSM_ALGORITHMS hmacAlg;
- switch(alg) {
- case CSSM_ALGID_SHA1:
- keySizeInBits = 160;
- hmacAlg = CSSM_ALGID_SHA1HMAC;
- break;
- case CSSM_ALGID_MD5:
- /* not even sure if this is legal in p12 world... */
- keySizeInBits = 128;
- hmacAlg = CSSM_ALGID_MD5HMAC;
- break;
- default:
- return CSSMERR_CSP_INVALID_ALGORITHM;
- }
- CSSM_KEY macKey;
- CSSM_DATA iv = {0, NULL};
- crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg,
- keySizeInBits, iterCount, salt, pwd, passKey, iv);
- if(crtn) {
- return crtn;
- }
- /* subsequent errors to errOut: */
-
- /* prealloc the mac data */
- coder.allocItem(macData, keySizeInBits / 8);
- crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand);
- if(crtn) {
- cuPrintError("CSSM_CSP_CreateMacContext", crtn);
- goto errOut;
- }
-
- crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData);
- if(crtn) {
- cuPrintError("CSSM_GenerateMac", crtn);
- }
-errOut:
- if(ccHand) {
- CSSM_DeleteContext(ccHand);
- }
- CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE);
- return crtn;
-}
-
-/*
- * Unwrap a shrouded key.
- */
-CSSM_RETURN p12UnwrapKey(
- CSSM_CSP_HANDLE cspHand,
- CSSM_DL_DB_HANDLE_PTR dlDbHand, // optional
- int keyIsPermanent, // nonzero - store in DB
- const CSSM_DATA &shroudedKeyBits,
- CSSM_ALGORITHMS keyAlg, // of the unwrapping key
- CSSM_ALGORITHMS encrAlg,
- CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only
- uint32 keySizeInBits,
- uint32 blockSizeInBytes, // for IV
- CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc.
- CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc.
- uint32 iterCount,
- const CSSM_DATA &salt,
- const CSSM_DATA *pwd, // unicode external representation
- const CSSM_KEY *passKey,
- SecNssCoder &coder, // for mallocing privKey
- const CSSM_DATA &labelData,
- SecAccessRef access, // optional
- bool noAcl,
- CSSM_KEYUSE keyUsage,
- CSSM_KEYATTR_FLAGS keyAttrs,
-
- /*
- * Result: a private key, reference format, optionaly stored
- * in dlDbHand
- */
- CSSM_KEY_PTR &privKey)
-{
- CSSM_RETURN crtn;
- CSSM_KEY ckey;
- CSSM_CC_HANDLE ccHand = 0;
- CSSM_KEY wrappedKey;
- CSSM_KEY unwrappedKey;
- CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader;
- CSSM_DATA descrData = {0, NULL}; // not used for PKCS8 wrap
- CSSM_KEYATTR_FLAGS reqAttr = keyAttrs;
-
- ResourceControlContext rcc;
- ResourceControlContext *rccPtr = NULL;
- Security::KeychainCore::Access::Maker maker;
-
- /* P12 style IV derivation, optional */
- CSSM_DATA iv = {0, NULL};
- CSSM_DATA_PTR ivPtr = NULL;
- if(blockSizeInBytes) {
- coder.allocItem(iv, blockSizeInBytes);
- ivPtr = &iv;
- }
-
- /* P12 style key derivation */
- crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
- keySizeInBits, iterCount, salt, pwd, passKey, iv);
- if(crtn) {
- return crtn;
- }
- /* subsequent errors to errOut: */
-
- /* CSSM context */
- crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
- encrAlg,
- mode,
- NULL, // access cred
- &ckey,
- ivPtr, // InitVector, optional
- padding,
- NULL, // Params
- &ccHand);
- if(crtn) {
- p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn);
- goto errOut;
- }
- if(dlDbHand) {
- crtn = p12AddContextAttribute(ccHand,
- CSSM_ATTRIBUTE_DL_DB_HANDLE,
- sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
- dlDbHand);
- if(crtn) {
- p12LogCssmError("AddContextAttribute", crtn);
- goto errOut;
- }
- }
-
- /*
- * Cook up minimal WrappedKey header fields
- */
- memset(&wrappedKey, 0, sizeof(CSSM_KEY));
- memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
-
- hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
- hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
- hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
-
- /*
- * This one we do not know. The CSP will figure out the format
- * of the unwrapped key after it decrypts the raw key material.
- */
- hdr.AlgorithmId = CSSM_ALGID_NONE;
- hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
-
- /* also inferred by CSP */
- hdr.LogicalKeySizeInBits = 0;
- hdr.KeyAttr = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
- hdr.KeyUsage = CSSM_KEYUSE_ANY;
- hdr.WrapAlgorithmId = encrAlg;
- hdr.WrapMode = mode;
-
- if(dlDbHand && keyIsPermanent) {
- reqAttr |= CSSM_KEYATTR_PERMANENT;
- }
-
- wrappedKey.KeyData = shroudedKeyBits;
-
- if(!noAcl) {
- // Create a Access::Maker for the initial owner of the private key.
- memset(&rcc, 0, sizeof(rcc));
- maker.initialOwner(rcc);
- rccPtr = &rcc;
- }
-
- crtn = CSSM_UnwrapKey(ccHand,
- NULL, // PublicKey
- &wrappedKey,
- keyUsage,
- reqAttr,
- &labelData,
- rccPtr, // CredAndAclEntry
- privKey,
- &descrData); // required
- if(crtn) {
- p12LogCssmError("CSSM_UnwrapKey", crtn);
- if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) {
- /* report in a keychain-friendly way */
- crtn = errSecDuplicateItem;
- }
- }
-
- // Finally fix the acl and owner of the private key to the
- // specified access control settings.
- if((crtn == CSSM_OK) && !noAcl) {
- try {
- CssmClient::KeyAclBearer bearer(
- cspHand, *privKey, Allocator::standard());
- SecPointer<KeychainCore::Access> initialAccess(access ?
- KeychainCore::Access::required(access) : /* caller-supplied */
- new KeychainCore::Access("privateKey")); /* default */
- initialAccess->setAccess(bearer, maker);
- }
- catch (const CssmError &e) {
- /* not implemented means we're talking to the CSP which does
- * not implement ACLs */
- if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) {
- crtn = e.error;
- }
- }
- catch(...) {
- p12ErrorLog("p12 exception on setAccess\n");
- crtn = errSecAuthFailed; /* ??? */
- }
- }
-
-errOut:
- if(ccHand) {
- CSSM_DeleteContext(ccHand);
- }
- CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
- return crtn;
-}
-
-/*
- * Wrap a private key, yielding shrouded key bits.
- */
-CSSM_RETURN p12WrapKey(
- CSSM_CSP_HANDLE cspHand,
- CSSM_KEY_PTR privKey,
- const CSSM_ACCESS_CREDENTIALS *privKeyCreds,
- CSSM_ALGORITHMS keyAlg, // of the unwrapping key
- CSSM_ALGORITHMS encrAlg,
- CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only
- uint32 keySizeInBits,
- uint32 blockSizeInBytes, // for IV
- CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc.
- CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc.
- uint32 iterCount,
- const CSSM_DATA &salt,
- const CSSM_DATA *pwd, // unicode external representation
- const CSSM_KEY *passKey,
- SecNssCoder &coder, // for mallocing keyBits
- CSSM_DATA &shroudedKeyBits) // RETURNED
-{
- CSSM_RETURN crtn;
- CSSM_KEY ckey;
- CSSM_CC_HANDLE ccHand = 0;
- CSSM_KEY wrappedKey;
- CSSM_CONTEXT_ATTRIBUTE attr;
- CSSM_DATA descrData = {0, NULL};
- CSSM_ACCESS_CREDENTIALS creds;
-
- /* key must be extractable */
- if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
- return errSecDataNotAvailable;
- }
-
- if(privKeyCreds == NULL) {
- /* i.e., key is from the bare CSP with no ACL support */
- memset(&creds, 0, sizeof(creds));
- privKeyCreds = &creds;
- }
-
- /* P12 style IV derivation, optional */
- CSSM_DATA iv = {0, NULL};
- CSSM_DATA_PTR ivPtr = NULL;
- if(blockSizeInBytes) {
- coder.allocItem(iv, blockSizeInBytes);
- ivPtr = &iv;
- }
-
- /* P12 style key derivation */
- crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
- keySizeInBits, iterCount, salt, pwd, passKey, iv);
- if(crtn) {
- return crtn;
- }
- /* subsequent errors to errOut: */
-
- /* CSSM context */
- crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
- encrAlg,
- mode,
- NULL, // access cred
- &ckey,
- ivPtr, // InitVector, optional
- padding,
- NULL, // Params
- &ccHand);
- if(crtn) {
- p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn);
- goto errOut;
- }
-
- memset(&wrappedKey, 0, sizeof(CSSM_KEY));
-
- /* specify PKCS8 wrap format */
- attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT;
- attr.AttributeLength = sizeof(uint32);
- attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
- crtn = CSSM_UpdateContextAttributes(
- ccHand,
- 1,
- &attr);
- if(crtn) {
- p12LogCssmError("CSSM_UpdateContextAttributes", crtn);
- goto errOut;
- }
-
- crtn = CSSM_WrapKey(ccHand,
- privKeyCreds,
- privKey,
- &descrData, // DescriptiveData
- &wrappedKey);
- if(crtn) {
- p12LogCssmError("CSSM_WrapKey", crtn);
- }
- else {
- coder.allocCopyItem(wrappedKey.KeyData, shroudedKeyBits);
-
- /* this was mallocd by CSP */
- freeCssmMemory(cspHand, wrappedKey.KeyData.Data);
- }
-errOut:
- if(ccHand) {
- CSSM_DeleteContext(ccHand);
- }
- CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
- return crtn;
-}