]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/Security/SecImportExportPkcs8.cpp
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / Security / SecImportExportPkcs8.cpp
diff --git a/OSX/libsecurity_keychain/Security/SecImportExportPkcs8.cpp b/OSX/libsecurity_keychain/Security/SecImportExportPkcs8.cpp
deleted file mode 100644 (file)
index 1354795..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- * Copyright (c) 2000-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@
- */
-/*
- * SecImportExportPkcs8.cpp - support for generating and parsing/decoding 
- * private keys in PKCS8 format.  
- *
- * The current version (as of March 12 2004) can parse and decode every 
- * PKCS8 blob generated by openssl with the exception of those using 
- * double DES encryption. This has been verified by actually generating 
- * those blobs with openssl and decoding them here. 
- *
- * PLEASE: don't even *think* about changing a single line of code here 
- * without verifying the results against the full import/export regression
- * test in SecurityTests/clxutils/importExport. 
- * 
- */
-
-#include <Security/SecImportExport.h>
-#include "SecImportExportPkcs8.h"
-#include "SecPkcs8Templates.h"
-#include "SecImportExportUtils.h"
-#include "SecImportExportCrypto.h"
-#include <security_pkcs12/pkcs12Utils.h>
-#include <security_pkcs12/pkcs12Crypto.h>
-#include <security_asn1/SecNssCoder.h>
-#include <Security/keyTemplates.h>     
-#include <Security/SecAsn1Templates.h> 
-#include <Security/secasn1t.h>
-#include <security_asn1/nssUtils.h>
-#include <security_utilities/debugging.h>
-#include <security_utilities/devrandom.h>
-#include <Security/oidsalg.h>
-#include <Security/SecKeyPriv.h>
-#include <security_cdsa_utils/cuCdsaUtils.h>
-#include <openssl/pem.h>
-#include <assert.h>
-#include <Security/SecBase.h>
-
-#define SecPkcs8Dbg(args...)   secdebug("SecPkcs8", ## args)
-
-#pragma mark --- PKCS5 v1.5 Key Derivation ---
-
-/*
- * PKCS5 v1.5. Caller has gleaned everything except salt, 
- * iterationCount, and IV from the AlgId.algorithm OID.
- *
- * We get salt and iteration count from the incoming alg params.
- * IV is derived along with the unwrapping key from the passphrase. 
- */
-static CSSM_RETURN pkcs5_v15_genKey(
-       CSSM_CSP_HANDLE                 cspHand,
-       SecNssCoder                             &coder,
-       const SecKeyImportExportParameters *keyParams,  
-       const CSSM_DATA                 &paramData,
-       CSSM_ALGORITHMS                 keyAlg, 
-       CSSM_ALGORITHMS                 pbeHashAlg, 
-       uint32                                  keySizeInBits,
-       uint32                                  blockSizeInBytes,
-       impExpKeyUnwrapParams   *unwrapParams)
-{
-       CSSM_KEY                                *passKey = NULL;
-       CFDataRef                               cfPhrase = NULL;
-       CSSM_RETURN                             crtn;
-       OSStatus                                ortn;
-       CSSM_CRYPTO_DATA                seed;
-       CSSM_CC_HANDLE                  ccHand = 0;
-       CSSM_ACCESS_CREDENTIALS creds;
-       
-       
-       /* passphrase or passkey? */
-       ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, VP_Import,
-               (CFTypeRef *)&cfPhrase, &passKey);
-       if(ortn) {
-               return ortn;
-       }
-       /* subsequent errors to errOut: */
-       
-       memset(&seed, 0, sizeof(seed));
-       if(cfPhrase != NULL) {
-               size_t len = CFDataGetLength(cfPhrase);
-               coder.allocItem(seed.Param, len);
-               memmove(seed.Param.Data, CFDataGetBytePtr(cfPhrase), len);
-               CFRelease(cfPhrase);
-       }
-
-       /* hash algorithm --> PBE alg for CSP */
-       CSSM_ALGORITHMS         pbeAlg;
-       switch(pbeHashAlg) {
-               case CSSM_ALGID_MD2:
-                       pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_MD2;
-                       break;
-               case CSSM_ALGID_MD5:
-                       pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_MD5;
-                       break;
-               case CSSM_ALGID_SHA1:
-                       pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_SHA1;
-                       break;
-               default:
-                       /* really shouldn't happen - pbeHashAlg was inferred by 
-                        * pkcsOidToParams() */
-                       SecPkcs8Dbg("PKCS8: PKCS5 v1/5 bogus hash alg");
-                       crtn = CSSMERR_CSP_INTERNAL_ERROR;
-                       goto errOut;
-       }
-       
-       /* Salt and iteration count from alg parameters */
-       impExpPKCS5_PBE_Parameters pbeParams;
-       memset(&pbeParams, 0, sizeof(pbeParams));
-       if(coder.decodeItem(paramData, impExpPKCS5_PBE_ParametersTemplate, &pbeParams)) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v1.5 pbeParams decode error");
-               crtn = errSecUnknownFormat;
-               goto errOut;
-       }
-       uint32 iterCount;
-       if(!p12DataToInt(pbeParams.iterations, iterCount)) {
-               SecPkcs8Dbg("PKCS8: bad PKCS5 v1.5 iteration count");
-               crtn = errSecUnknownFormat;
-               goto errOut;
-       }
-
-       /* ask for hard coded 8 bytes of IV */
-       coder.allocItem(unwrapParams->iv, 8);
-       
-       memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
-       crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
-               pbeAlg,
-               keyAlg,
-               keySizeInBits,
-               &creds,
-               passKey,                // BaseKey
-               iterCount,
-               &pbeParams.salt,
-               &seed,  
-               &ccHand);
-       if(crtn) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_CSP_CreateDeriveKeyContext failure");
-               goto errOut;
-       }
-       
-       memset(unwrapParams->unwrappingKey, 0, sizeof(CSSM_KEY));
-
-       CSSM_DATA               dummyLabel;
-       dummyLabel.Data = (uint8 *)"temp unwrap key";
-       dummyLabel.Length = strlen((char *)dummyLabel.Data);
-       
-       crtn = CSSM_DeriveKey(ccHand,
-               &unwrapParams->iv,              // IV returned in in/out Param
-               CSSM_KEYUSE_ANY,
-               /* not extractable even for the short time this key lives */
-               CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
-               &dummyLabel,
-               NULL,                   // cred and acl
-               unwrapParams->unwrappingKey);
-       if(crtn) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v1.5 CSSM_DeriveKey failure");
-       }
-errOut:
-       if(ccHand != 0) {
-               CSSM_DeleteContext(ccHand);
-       }
-       if(passKey != NULL) {
-               CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
-               free(passKey);
-       }
-       return crtn;
-}
-
-#pragma mark --- PKCS5 v2.0 Key Derivation ---
-
-/*
- * PKCS5 v2.0 has different means of encoding algorithm parameters, 
- * depending on the encryption algorithm.
- */
-/*
- * Obtain encryption parameters for PKCS5 v2.0, DES and DES3 variants.
- */
-static OSStatus pkcs5_DES_params(
-       const CSSM_DATA                 &paramData,             // encryptionScheme.parameters
-       CSSM_OID                                *encrOid,
-       impExpKeyUnwrapParams   *unwrapParams,  
-       CSSM_ALGORITHMS                 *keyAlg,                // RETURNED
-       uint32                                  *keySizeInBits, // IN/OUT (returned if 0 on entry)
-       SecNssCoder                             &coder)
-{
-       /* Params is iv as OCTET STRING */
-       if(coder.decodeItem(paramData, kSecAsn1OctetStringTemplate, &unwrapParams->iv)) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 DES init vector decode error");
-               return errSecUnknownFormat;
-       }
-       if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_DES_EDE3_CBC)) {
-               *keyAlg = CSSM_ALGID_3DES_3KEY;
-               unwrapParams->encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
-               if(*keySizeInBits == 0) {
-                       *keySizeInBits = 3 * 64;
-               }
-       }
-       else {
-               *keyAlg = CSSM_ALGID_DES;
-               unwrapParams->encrAlg = CSSM_ALGID_DES;
-               if(*keySizeInBits == 0) {
-                       *keySizeInBits = 64;
-               }
-       }
-       unwrapParams->encrPad  = CSSM_PADDING_PKCS7;
-       unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
-       return errSecSuccess;
-}
-
-/*
- * Obtain encryption parameters for PKCS5 v2.0, RC2 variant. 
- */
-static OSStatus pkcs5_RC2_params(
-       const CSSM_DATA                 &paramData,             // encryptionScheme.parameters
-       impExpKeyUnwrapParams   *unwrapParams,  
-       CSSM_ALGORITHMS                 *keyAlg,                // RETURNED
-       uint32                                  *keySizeInBits, // IN/OUT (returned if 0 on entry)
-       SecNssCoder                             &coder)
-{
-       /* Params is impExpPKCS5_RC2Params */
-       impExpPKCS5_RC2Params rc2Params;
-       memset(&rc2Params, 0, sizeof(rc2Params));
-       if(coder.decodeItem(paramData, impExpPKCS5_RC2ParamsTemplate, &rc2Params)) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 RC2 params decode error");
-               return errSecUnknownFormat;
-       }
-
-       *keyAlg = CSSM_ALGID_RC2;
-       unwrapParams->encrAlg  = CSSM_ALGID_RC2;
-       unwrapParams->encrPad  = CSSM_PADDING_PKCS7;
-       unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
-
-       /* the version actually maps to effective key size like this */
-       /* I swear all of this is in the PKCS5 v2.0 spec */
-       unwrapParams->effectiveKeySizeInBits = 32;              // default
-       if(rc2Params.version.Data) {
-               uint32 v;
-               if(!p12DataToInt(rc2Params.version, v)) {
-                       SecPkcs8Dbg("PKCS8: bad PKCS5 rc2Params.version");
-                       return errSecUnknownFormat;
-               }
-               switch(v) {
-                       case 160:
-                               unwrapParams->effectiveKeySizeInBits = 40; 
-                               break;
-                       case 120: 
-                               unwrapParams->effectiveKeySizeInBits = 64; 
-                               break;
-                       case 58:  
-                               unwrapParams->effectiveKeySizeInBits = 128; 
-                               break;
-                       default:
-                               if(v >= 256) {
-                                       unwrapParams->effectiveKeySizeInBits = v;
-                               }
-                               else {
-                                       /* not in the spec, use as zero */
-                               }
-                               break;
-               }
-       }
-       unwrapParams->iv = rc2Params.iv;
-       
-       /* the PKCS5 spec does not give a default for the RC2 key size */
-       if(*keySizeInBits == 0) {
-               SecPkcs8Dbg("PKCS8: NO RC2 DEFAULT KEYSIZE!");
-               return errSecUnknownFormat;
-       }
-       return errSecSuccess;
-}
-
-/*
- * Infer encryption parameters for PKCS5 v2.0, RC5 variant. 
- * All info contained in encryptionScheme.parameters. 
- */
-static OSStatus pkcs5_RC5_params(
-       const CSSM_DATA                 &paramData,             // encryptionScheme.parameters
-       impExpKeyUnwrapParams   *unwrapParams,  
-       CSSM_ALGORITHMS                 *keyAlg,                // RETURNED
-       uint32                                  *keySizeInBits, // IN/OUT (returned if 0 on entry)
-       SecNssCoder                             &coder)
-{
-       /* Params is a impExpPKCS5_RC5Params */
-       impExpPKCS5_RC5Params rc5Params;
-       memset(&rc5Params, 0, sizeof(rc5Params));
-       if(coder.decodeItem(paramData, impExpPKCS5_RC5ParamsTemplate, &rc5Params)) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 RC5 params decode error");
-               return errSecUnknownFormat;
-       }
-
-       *keyAlg = CSSM_ALGID_RC5;
-       unwrapParams->encrAlg  = CSSM_ALGID_RC5;
-       unwrapParams->encrPad  = CSSM_PADDING_PKCS7;
-       unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
-
-       if(rc5Params.rounds.Data) {
-               if(!p12DataToInt(rc5Params.rounds, unwrapParams->rounds)) {
-                       SecPkcs8Dbg("PKCS8: bad PKCS5 rc5Params.rounds");
-                       return errSecUnknownFormat;
-               }
-       }
-       if(rc5Params.blockSizeInBits.Data) {
-               if(!p12DataToInt(rc5Params.blockSizeInBits, unwrapParams->blockSizeInBits)) {
-                       SecPkcs8Dbg("PKCS8: bad PKCS5 rc5Params.blockSizeInBits");
-                       return errSecUnknownFormat;
-               }
-       }
-       
-       /* Spec says default iv is zeroes */
-       unwrapParams->iv = rc5Params.iv;
-       if(unwrapParams->iv.Length == 0) {
-               uint32 len = unwrapParams->blockSizeInBits / 8;
-               coder.allocItem(unwrapParams->iv, len);
-               memset(unwrapParams->iv.Data, 0, len);
-       }
-       
-       /*
-        * Spec does not give a default for key RC5 size, and openssl doesn't 
-        * support RC5 for PKCS8.
-        */
-       if(*keySizeInBits == 0) {
-               SecPkcs8Dbg("PKCS8: NO RC5 DEFAULT KEYSIZE!");
-               return errSecUnknownFormat;
-       }
-       return errSecSuccess;
-}
-
-/* 
- * Common code to derive a wrap/unwrap key using PBKDF2 (i.e., using PKCS5 v2.0
- * key derivation). Caller must CSSM_FreeKey when done. 
- */
-static CSSM_RETURN pbkdf2DeriveKey(
-       CSSM_CSP_HANDLE         cspHand,
-       SecNssCoder                     &coder,
-       CSSM_ALGORITHMS         keyAlg,
-       uint32                          keySizeInBits,
-       uint32                          iterationCount,
-       const CSSM_DATA         &salt,
-       const SecKeyImportExportParameters      *keyParams,             // required 
-       impExpVerifyPhrase  verifyPhrase,   // for secure passphrase
-       CSSM_KEY_PTR            symKey)                                                 // RETURNED
-{
-       CSSM_KEY                                        *passKey = NULL;
-       CFDataRef                                       cfPhrase = NULL;
-       CSSM_PKCS5_PBKDF2_PARAMS        pbeParams;
-       CSSM_RETURN                                     crtn;
-       OSStatus                                        ortn;
-       CSSM_DATA                                       dummyLabel;
-       CSSM_DATA                                       pbeData;
-       uint32                                          keyAttr;
-       CSSM_CC_HANDLE                          ccHand = 0;
-       CSSM_ACCESS_CREDENTIALS         creds;
-       
-       memset(&pbeParams, 0, sizeof(pbeParams));
-
-       /* passphrase or passkey? */
-       ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, verifyPhrase,
-               (CFTypeRef *)&cfPhrase, &passKey);
-       if(ortn) {
-               return ortn;
-       }
-       /* subsequent errors to errOut: */
-
-       if(cfPhrase != NULL) {
-               size_t len = CFDataGetLength(cfPhrase);
-               coder.allocItem(pbeParams.Passphrase, len);
-               memmove(pbeParams.Passphrase.Data, 
-                       CFDataGetBytePtr(cfPhrase), len);
-               CFRelease(cfPhrase);
-       }
-
-       memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
-       crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
-               CSSM_ALGID_PKCS5_PBKDF2,
-               keyAlg,
-               keySizeInBits,
-               &creds,
-               passKey,                // BaseKey
-               iterationCount,
-               &salt,
-               NULL,                   // seed
-               &ccHand);
-       if(crtn) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_CSP_CreateDeriveKeyContext failure");
-               goto errOut;
-       }
-       
-       memset(symKey, 0, sizeof(CSSM_KEY));
-
-       /* not extractable even for the short time this key lives */
-       keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE;
-       dummyLabel.Data = (uint8 *)"temp unwrap key";
-       dummyLabel.Length = strlen((char *)dummyLabel.Data);
-       
-       pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
-       pbeData.Data = (uint8 *)&pbeParams;
-       pbeData.Length = sizeof(pbeParams);
-       crtn = CSSM_DeriveKey(ccHand,
-               &pbeData,
-               CSSM_KEYUSE_ANY,
-               keyAttr,
-               &dummyLabel,
-               NULL,                   // cred and acl
-               symKey);
-       if(crtn) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_DeriveKey failure");
-       }
-errOut:
-       if(ccHand != 0) {
-               CSSM_DeleteContext(ccHand);
-       }
-       if(passKey != NULL) {
-               CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
-               free(passKey);
-       }
-       return crtn;
-}
-
-/* 
- * Obtain PKCS5, v.2.0 key derivation and encryption parameters and 
- * derive the key. This one obtains all of the crypt parameters 
- * from the top-level AlgId.Params. What a mess. 
- */
-static CSSM_RETURN pkcs5_v2_genKey(
-       CSSM_CSP_HANDLE                 cspHand,
-       SecNssCoder                             &coder,
-       const CSSM_DATA                 &paramData,
-       const SecKeyImportExportParameters *keyParams,
-       impExpKeyUnwrapParams   *unwrapParams)
-{
-       SecPkcs8Dbg("PKCS8: generating PKCS5 v2.0 key");
-
-       CSSM_ALGORITHMS         keyAlg = CSSM_ALGID_NONE;
-       uint32                          prf = 0;                // CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1...
-       
-       /* caller should check */
-       assert(keyParams != NULL);
-
-       /* AlgId.Params --> impExpPKCS5_PBES2_Params */
-       if(paramData.Length == 0) {
-               SecPkcs8Dbg("PKCS8: empty PKCS5 v2 pbes2Params");
-               return errSecUnknownFormat;
-       }
-       impExpPKCS5_PBES2_Params pbes2Params;
-       memset(&pbes2Params, 0, sizeof(pbes2Params));
-       if(coder.decodeItem(paramData, impExpPKCS5_PBES2_ParamsTemplate, &pbes2Params)) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 pbes2Params decode error");
-               return errSecUnknownFormat;
-       }
-       
-       /*
-        * As far as I know the keyDerivationFunc OID must be id-PBKDF2 
-        */
-       if(!nssCompareCssmData(&pbes2Params.keyDerivationFunc.algorithm, 
-                       &CSSMOID_PKCS5_PBKDF2)) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 unexpected keyDerivationFunc alg");
-               return errSecUnknownFormat;
-       }
-       
-       /*
-        * The params of the keyDerivationFunc algId are an encoded 
-        * impExpPKCS5_PBKDF2_Params.
-        */
-       impExpPKCS5_PBKDF2_Params pbkdf2Params;
-       memset(&pbkdf2Params, 0, sizeof(pbkdf2Params));
-       if(coder.decodeItem(pbes2Params.keyDerivationFunc.parameters,
-                       impExpPKCS5_PBKDF2_ParamsTemplate, &pbkdf2Params)) {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 pbkdf2Params decode error");
-               return errSecUnknownFormat;
-       }
-       
-       /*
-        * Salt and iteration count from the impExpPKCS5_PBKDF2_Params (ignoring the 
-        * possible CHOICE for salt source).
-        */
-       CSSM_DATA salt = pbkdf2Params.salt;
-       uint32 iterCount;
-       if(!p12DataToInt(pbkdf2Params.iterationCount, iterCount)) {
-               SecPkcs8Dbg("PKCS8: bad PKCS5 v2 iteration count");
-               return errSecUnknownFormat;
-       }
-       
-       /*
-        * Key size optional, use defaults per alg (later) if it's not there
-        */
-       uint32 keySizeInBits = 0;
-       if(pbkdf2Params.keyLengthInBytes.Data) {
-               uint32 keyLengthInBytes;
-               if(!p12DataToInt(pbkdf2Params.keyLengthInBytes, keyLengthInBytes)) {
-                       SecPkcs8Dbg("PKCS8: bad PKCS5 v2 key size");
-                       return errSecUnknownFormat;
-               }
-               keySizeInBits = keyLengthInBytes * 8;
-       }
-       /* else we'll infer key size from the encryption algorithm */
-       
-       /* prf optional, but if it's there it better be CSSMOID_PKCS5_HMAC_SHA1 */
-       if(pbkdf2Params.prf.Data) {
-               if(!nssCompareCssmData(&pbkdf2Params.prf, &CSSMOID_PKCS5_HMAC_SHA1)) {
-                       SecPkcs8Dbg("PKCS8: PKCS5 v2 unexpected prf OID");
-                       return errSecUnknownFormat;
-               }
-       }
-       prf = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
-
-       /*
-        * Now process the encryptionScheme, which is even messier - the algParams
-        * varies per encryption algorithm.
-        */
-       CSSM_X509_ALGORITHM_IDENTIFIER &encrScheme = pbes2Params.encryptionScheme;
-       CSSM_OID *encrOid = &encrScheme.algorithm;
-       OSStatus ortn;
-       CSSM_DATA &encrParam = encrScheme.parameters;
-       
-       if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_DES_EDE3_CBC) ||
-          nssCompareCssmData(encrOid, &CSSMOID_DES_CBC)) {
-               ortn = pkcs5_DES_params(encrParam, encrOid, unwrapParams, &keyAlg, 
-                       &keySizeInBits, coder);
-               if(ortn) {
-                       return ortn;
-               }
-       }
-       else if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_RC2_CBC)) {
-               ortn = pkcs5_RC2_params(encrParam, unwrapParams, &keyAlg, 
-                       &keySizeInBits, coder);
-               if(ortn) {
-                       return ortn;
-               }
-       }
-       else if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_RC5_CBC)) {
-               ortn = pkcs5_RC5_params(encrParam, unwrapParams, &keyAlg, 
-                       &keySizeInBits, coder);
-               if(ortn) {
-                       return ortn;
-               }
-       }
-       else {
-               SecPkcs8Dbg("PKCS8: PKCS5 v2 unknown encrScheme.algorithm");
-               return errSecUnknownFormat;
-       }
-       
-       /* We should be ready to go */
-       assert(keyAlg != CSSM_ALGID_NONE);
-       assert(unwrapParams->encrAlg != CSSM_ALGID_NONE);
-       
-       /* use all the stuff we just figured out to derive a symmetric decryption key */
-       return pbkdf2DeriveKey(cspHand, coder,
-               keyAlg, keySizeInBits, 
-               iterCount, salt,
-               keyParams, 
-               VP_Import,
-               unwrapParams->unwrappingKey);
-}
-
-#pragma mark --- PKCS12 Key Derivation ---
-
-/*
- * PKCS12 style key derivation. Caller has gleaned everything except 
- * salt, iterationCount, and IV from the AlgId.algorithm OID.
- *
- * We get salt and iteration count from the incoming alg params.
- * IV is derived along with the unwrapping key from the passphrase. 
- */
-static CSSM_RETURN pkcs12_genKey(
-       CSSM_CSP_HANDLE         cspHand,
-       SecNssCoder                     &coder,
-       const SecKeyImportExportParameters *keyParams,
-       const CSSM_DATA         &paramData,                     // from algID
-       CSSM_ALGORITHMS         keyAlg,                         // valid on entry 
-       CSSM_ALGORITHMS         pbeHashAlg,                     // valid on entry 
-       uint32                          keySizeInBits,          // valid on entry
-       uint32                          blockSizeInBytes,   // for IV
-       impExpKeyUnwrapParams  *unwrapParams)
-{
-       SecPkcs8Dbg("PKCS8: generating PKCS12 key");
-       
-       assert(keyAlg != CSSM_ALGID_NONE);
-       assert(pbeHashAlg != CSSM_ALGID_NONE);
-       assert(keySizeInBits != 0);
-       
-       /* get iteration count, salt from alg params */
-       NSS_P12_PBE_Params pbeParams;
-       
-       if(paramData.Length == 0) {
-               SecPkcs8Dbg("PKCS8: empty P12 pbeParams");
-               return errSecUnknownFormat;
-       }
-       memset(&pbeParams, 0, sizeof(pbeParams));
-       if(coder.decodeItem(paramData, NSS_P12_PBE_ParamsTemplate, &pbeParams)) {
-               SecPkcs8Dbg("PKCS8: P12 pbeParams decode error");
-               return errSecUnknownFormat;
-       }
-
-       uint32 iterCount = 0;
-       if(!p12DataToInt(pbeParams.iterations, iterCount)) {
-               SecPkcs8Dbg("PKCS8: bad P12 iteration count");
-               return errSecUnknownFormat;
-       }
-       
-       /* passphrase or passkey? */
-       CSSM_KEY *passKey = NULL;
-       CFStringRef phraseStr = NULL;
-       CSSM_DATA phraseData = {0, NULL};
-       CSSM_DATA *phraseDataP = NULL;
-       OSStatus ortn;
-       CSSM_RETURN crtn;
-       
-       assert(keyParams != NULL);
-       
-       ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_String, VP_Import,
-               (CFTypeRef *)&phraseStr, &passKey);
-       if(ortn) {
-               return ortn;
-       }
-       /* subsequent errors to errOut: */
-       
-       if(phraseStr != NULL) {
-               /* convert to CSSM_DATA for use with p12KeyGen() */
-               try {
-                       p12ImportPassPhrase(phraseStr, coder, phraseData);              
-               } 
-               catch(...) {
-                       SecPkcs8Dbg("PKCS8: p12ImportPassPhrase threw");
-                       crtn = errSecAllocate;
-                       goto errOut;
-               }
-               CFRelease(phraseStr);
-               phraseDataP = &phraseData;
-       }   
-       
-       /* use p12 module to cook up the key and IV */
-       if(blockSizeInBytes) {
-               coder.allocItem(unwrapParams->iv, blockSizeInBytes);
-       }
-       crtn = p12KeyGen(cspHand, 
-               *unwrapParams->unwrappingKey,
-               true,           // isForEncr
-               keyAlg,
-               pbeHashAlg,
-               keySizeInBits,
-               iterCount,
-               pbeParams.salt,
-               phraseDataP,
-               passKey,
-               unwrapParams->iv);
-       if(crtn) {
-               SecPkcs8Dbg("PKCS8: p12KeyGen failed");
-       }
-errOut:
-       if(passKey != NULL) {
-               CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
-               free(passKey);
-       }
-       return crtn;
-}
-
-#pragma mark --- Public PKCS8 import function ---
-
-/* 
- * Called out from SecImportRep::importWrappedKey().
- * If cspHand is provided instead of importKeychain, the CSP 
- * handle MUST be for the CSPDL, not for the raw CSP.
- */
-OSStatus impExpPkcs8Import(
-       CFDataRef                                                       inData,
-       SecKeychainRef                                          importKeychain, // optional
-       CSSM_CSP_HANDLE                                         cspHand,                // required
-       SecItemImportExportFlags                        flags,
-       const SecKeyImportExportParameters      *keyParams,             // REQUIRED for unwrap 
-       CFMutableArrayRef                                       outArray)               // optional, append here 
-{
-       CSSM_KEY                        wrappedKey;
-       CSSM_KEYHEADER          &hdr = wrappedKey.KeyHeader;
-       CSSM_RETURN                     crtn = CSSM_OK;
-       
-       /* key derivation and encryption parameters gleaned from alg ID */
-       impExpKeyUnwrapParams unwrapParams;
-       memset(&unwrapParams, 0, sizeof(unwrapParams));
-       CSSM_ALGORITHMS         keyAlg = CSSM_ALGID_NONE;
-       CSSM_ALGORITHMS         pbeHashAlg = CSSM_ALGID_NONE;   // SHA1 or MD5
-       uint32                          keySizeInBits;
-       uint32                          blockSizeInBytes;
-       PKCS_Which                      pkcs = PW_None;                 
-       
-       if( (keyParams == NULL) ||
-           ( (keyParams->passphrase == NULL) && 
-                 !(keyParams->flags & kSecKeySecurePassphrase) ) ) {
-               /* passphrase mandatory */
-               return errSecPassphraseRequired;
-       }
-       assert(cspHand != 0);
-       
-       /*
-        * Top-level decode 
-        */
-       SecNssCoder                                     coder;
-       NSS_EncryptedPrivateKeyInfo encrPrivKeyInfo;
-       
-       memset(&encrPrivKeyInfo, 0, sizeof(encrPrivKeyInfo));
-       if(coder.decode(CFDataGetBytePtr(inData),
-                       CFDataGetLength(inData),
-                       kSecAsn1EncryptedPrivateKeyInfoTemplate, &encrPrivKeyInfo)) {
-               SecImpExpDbg("impExpPkcs8Import: error decoding top-level encrPrivKeyInfo");
-               return errSecUnknownFormat;
-       }
-       
-       /*
-        * The algorithm OID of that top-level struct is the key piece of info 
-        * for now...
-        */
-       bool found = false;
-       found = pkcsOidToParams(&encrPrivKeyInfo.algorithm.algorithm,
-               keyAlg, unwrapParams.encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
-               unwrapParams.encrPad, unwrapParams.encrMode, pkcs);
-       if(!found) {
-               SecImpExpDbg("impExpPkcs8Import: unknown OID in top-level encrPrivKeyInfo");
-               return errSecUnknownFormat;
-       }
-       
-       /* 
-        * Each PBE method has its own way of filling in the remaining gaps
-        * in impExpKeyUnwrapParams and generating a key.
-        */
-       CSSM_KEY unwrappingKey;
-       memset(&unwrappingKey, 0, sizeof(unwrappingKey));
-       unwrapParams.unwrappingKey = &unwrappingKey;
-       CSSM_DATA &paramData = encrPrivKeyInfo.algorithm.parameters;
-
-       switch(pkcs) {
-               case PW_PKCS5_v1_5:
-                       /* we have everything except iv, iterations, salt */
-                       crtn = pkcs5_v15_genKey(cspHand, coder, keyParams, paramData,
-                               keyAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
-                               &unwrapParams);
-                       break;
-                       
-               case PW_PKCS5_v2:
-                       /* obtain everything, including iv, from alg params */
-                       crtn = pkcs5_v2_genKey(cspHand, coder, paramData, keyParams, &unwrapParams);
-                       break;
-               case PW_PKCS12:
-                       /* we have everything except iv, iterations, salt */
-                       crtn = pkcs12_genKey(cspHand, coder, keyParams, paramData,
-                               keyAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
-                               &unwrapParams);
-                       break;
-               case PW_None:
-                       /* satisfy compiler */
-                       assert(0);
-                       return errSecUnknownFormat; 
-       }
-       if(crtn) {
-               SecPkcs8Dbg("PKCS8: key derivation failed");
-               return crtn;
-       }
-       
-       /* we should be ready to rock'n'roll no matter how we got here */
-       assert(unwrapParams.encrAlg != CSSM_ALGID_NONE);
-       assert(unwrappingKey.KeyData.Data != NULL);
-       assert(unwrappingKey.KeyHeader.AlgorithmId != CSSM_ALGID_NONE);
-       
-       /* set up key to unwrap */
-       memset(&wrappedKey, 0, sizeof(CSSM_KEY));
-       hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
-       /* CspId : don't care */
-       hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
-       hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
-       /* AlgorithmId : inferred by CSP */
-       hdr.AlgorithmId = CSSM_ALGID_NONE;
-       hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
-       /* LogicalKeySizeInBits : calculated by CSP during unwrap */
-       hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
-       hdr.KeyUsage = CSSM_KEYUSE_ANY;
-
-       wrappedKey.KeyData = encrPrivKeyInfo.encryptedData;
-
-       crtn = impExpImportKeyCommon(
-               &wrappedKey,
-               importKeychain,
-               cspHand,
-               flags,
-               keyParams,
-               &unwrapParams,
-               NULL,                   // default label 
-               outArray);
-       CSSM_FreeKey(cspHand, NULL, &unwrappingKey, CSSM_FALSE);
-       return crtn;
-}
-
-#pragma mark --- Public PKCS8 export function ---
-
-#define PKCS5_V2_SALT_LEN              8
-#define PKCS5_V2_ITERATIONS            2048
-#define PKCS5_V2_DES_IV_SIZE   8
-
-/*
- * Unlike impExpPkcs8Import(), which can handle every PBE algorithm in the spec
- * and implemented by openssl, this one has a fixed PBE and encryption scheme. 
- * We do not provide a means at the API for the client to specify these. 
- *
- * We generate blobs with triple DES encryption, with PKCS5 v2.0 key 
- * derivation.
- */
-OSStatus impExpPkcs8Export(
-       SecKeyRef                                                       secKey,
-       SecItemImportExportFlags                        flags,          
-       const SecKeyImportExportParameters      *keyParams,             // optional 
-       CFMutableDataRef                                        outData,                // output appended here
-       const char                                                      **pemHeader)    
-{
-       DevRandomGenerator                              rng;
-       SecNssCoder                                             coder;
-       impExpPKCS5_PBES2_Params                pbes2Params;
-       CSSM_X509_ALGORITHM_IDENTIFIER  &keyDeriveAlgId = pbes2Params.keyDerivationFunc;
-       CSSM_ATTRIBUTE_TYPE                             formatAttrType = CSSM_ATTRIBUTE_NONE;
-       CSSM_KEYBLOB_FORMAT                             blobForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
-       const CSSM_KEY                                  *cssmKey;
-       
-       if(keyParams == NULL) {
-               return errSecParam;
-       }
-       assert(secKey != NULL);
-       assert(outData != NULL);
-       
-       memset(&pbes2Params, 0, sizeof(pbes2Params));
-       
-       /* 
-        * keyDeriveAlgId
-        * parameters is an encoded impExpPKCS5_PBKDF2_Params 
-        * We generate random salt
-        */
-       keyDeriveAlgId.algorithm = CSSMOID_PKCS5_PBKDF2;
-       impExpPKCS5_PBKDF2_Params pbkdf2Params;
-       memset(&pbkdf2Params, 0, sizeof(pbkdf2Params));
-       coder.allocItem(pbkdf2Params.salt, PKCS5_V2_SALT_LEN);
-       rng.random(pbkdf2Params.salt.Data, PKCS5_V2_SALT_LEN);
-       p12IntToData(PKCS5_V2_ITERATIONS, pbkdf2Params.iterationCount, coder);
-       /* leave pbkdf2Params.keyLengthInBytes NULL for default */
-       /* openssl can't handle this, which is the default value:
-          pbkdf2Params.prf = CSSMOID_PKCS5_HMAC_SHA1;
-        */
-       
-       coder.encodeItem(&pbkdf2Params, impExpPKCS5_PBKDF2_ParamsTemplate,
-                       keyDeriveAlgId.parameters);
-
-       /*
-        * encryptionScheme
-        * parameters is an encoded OCTET STRING containing the (random) IV
-        */
-       CSSM_X509_ALGORITHM_IDENTIFIER &encrScheme = pbes2Params.encryptionScheme;
-       encrScheme.algorithm = CSSMOID_PKCS5_DES_EDE3_CBC;
-       CSSM_DATA rawIv = {0, NULL};
-       coder.allocItem(rawIv, PKCS5_V2_DES_IV_SIZE);
-       rng.random(rawIv.Data, PKCS5_V2_DES_IV_SIZE);
-
-       coder.encodeItem(&rawIv, kSecAsn1OctetStringTemplate,
-                       encrScheme.parameters);
-       
-       /*
-        * Top level NSS_EncryptedPrivateKeyInfo, whose parameters is the encoded 
-        * impExpPKCS5_PBES2_Params. 
-        */
-       NSS_EncryptedPrivateKeyInfo encrPrivKeyInfo;
-       memset(&encrPrivKeyInfo, 0, sizeof(encrPrivKeyInfo));
-       CSSM_X509_ALGORITHM_IDENTIFIER &topAlgId = encrPrivKeyInfo.algorithm;
-       topAlgId.algorithm = CSSMOID_PKCS5_PBES2;
-       coder.encodeItem(&pbes2Params, impExpPKCS5_PBES2_ParamsTemplate,
-                       topAlgId.parameters);
-                       
-       /*
-        * Now all we have to do is generate the encrypted key data itself. 
-        * When doing a WrapKey op in PKCS8 form, the CSP gives us the 
-        * NSS_EncryptedPrivateKeyInfo.encryptedData values. 
-        */
-       
-       /* we need a CSPDL handle - try to get it from the key */
-       CSSM_CSP_HANDLE cspdlHand = 0;
-       OSStatus ortn;
-       bool releaseCspHand = false;
-       CSSM_DATA encodedKeyInfo = {0, NULL};
-       
-       ortn = SecKeyGetCSPHandle(secKey, &cspdlHand);
-       if(ortn) {
-               cspdlHand = cuCspStartup(CSSM_FALSE);
-               if(cspdlHand == 0) {
-                       return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
-               }
-               releaseCspHand = true;
-       }
-       /* subsequent errors to errOut: */
-       
-       /* get wrapping key from parameters we just set up */
-       CSSM_KEY wrappingKey;
-       memset(&wrappingKey, 0, sizeof(CSSM_KEY));
-       CSSM_RETURN crtn = pbkdf2DeriveKey(cspdlHand, coder,
-               CSSM_ALGID_3DES_3KEY, 3 * 64, 
-               PKCS5_V2_ITERATIONS, pbkdf2Params.salt,
-               keyParams,
-               VP_Export,
-               &wrappingKey);
-       if(crtn) {
-               goto errOut;
-       }
-
-       /*
-        * Special case for DSA, ECDSA: specify that the raw blob, pre-encrypt, is in 
-        * the PKCS8 PrivateKeyInfo format that openssl understands. The
-        * default is BSAFE.
-        */
-       crtn = SecKeyGetCSSMKey(secKey, &cssmKey);
-       if(crtn) {
-               SecImpExpDbg("impExpPkcs8Export SecKeyGetCSSMKey error");
-               goto errOut;
-       }
-       switch(cssmKey->KeyHeader.AlgorithmId) {
-               case CSSM_ALGID_DSA:
-               case CSSM_ALGID_ECDSA:
-                       formatAttrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
-                       blobForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
-                       break;
-               default:
-                       break;
-       }
-       
-       /* GO */
-       CSSM_KEY wrappedKey;
-       memset(&wrappedKey, 0, sizeof(CSSM_KEY));
-       
-       crtn = impExpExportKeyCommon(cspdlHand, secKey, &wrappingKey, &wrappedKey,
-               CSSM_ALGID_3DES_3KEY_EDE, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS7,
-               CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8, formatAttrType, blobForm, NULL, &rawIv);
-       if(crtn) {
-               goto errOut;
-       }
-       
-       /*
-        * OK... *that* wrapped key's data goes into the top-level 
-        * NSS_EncryptedPrivateKeyInfo, which we then encode; the caller
-        * gets the result of that encoding. 
-        */
-       encrPrivKeyInfo.encryptedData = wrappedKey.KeyData;
-       coder.encodeItem(&encrPrivKeyInfo, kSecAsn1EncryptedPrivateKeyInfoTemplate,
-                       encodedKeyInfo);
-       
-       CFDataAppendBytes(outData, encodedKeyInfo.Data, encodedKeyInfo.Length);
-       CSSM_FreeKey(cspdlHand, NULL, &wrappedKey, CSSM_FALSE);
-       
-       *pemHeader = PEM_STRING_PKCS8;
-       
-errOut:
-       if(wrappingKey.KeyData.Data) {
-               CSSM_FreeKey(cspdlHand, NULL, &wrappingKey, CSSM_FALSE);
-       }
-       if(releaseCspHand) {
-               cuCspDetachUnload(cspdlHand, CSSM_FALSE);
-       }
-       return crtn;
-}