/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This 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. */ // // pkcs8.cpp - PKCS8 key wrap/unwrap support. // #include "pkcs8.h" #include "AppleCSPUtils.h" #include "AppleCSPKeys.h" #include #include #include #include "AppleCSPSession.h" #include /* * Given a key in PKCS8 format, fill in the following * header fields: * * CSSM_KEYBLOB_FORMAT Format * CSSM_ALGORITHMS AlgorithmId * uint32 LogicalKeySizeInBits */ void AppleCSPSession::pkcs8InferKeyHeader( CssmKey &key) { /* * Incoming key blob is a PrivateKeyInfo. Take it apart * to get its algorithm info, from which we infer other * fields. */ NSS_PrivateKeyInfo privKeyInfo; SecNssCoder coder; CSSM_DATA &keyData = key.KeyData; memset(&privKeyInfo, 0, sizeof(privKeyInfo)); if(coder.decodeItem(keyData, kSecAsn1PrivateKeyInfoTemplate, &privKeyInfo)) { errorLog0("pkcs8InferKeyHeader decode error\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } CSSM_KEYHEADER &hdr = key.KeyHeader; if(!cssmOidToAlg(&privKeyInfo.algorithm.algorithm, &hdr.AlgorithmId)) { errorLog0("pkcs8InferKeyHeader unknown algorithm\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } switch(hdr.AlgorithmId) { case CSSM_ALGID_RSA: hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; break; case CSSM_ALGID_DSA: /* * Try openssl style first, though our default when * wrapping is FIPS186 */ hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; break; default: /* punt */ hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE; break; } /* * Find someone who knows about this key and ask them the * key size. infoProvider() throws if no provider found. */ CSSM_KEY_SIZE keySize; try { auto_ptr provider(infoProvider(key)); provider->QueryKeySizeInBits(keySize); } catch(const CssmError &cerror) { /* * Special case: DSA private keys keys can be in two forms - FIPS186 * (for legacy implementations) and PKCS8 (for openssl). We're wired to * *generate* FIPS186 blobs by default in pkcs8RawKeyFormat(), but to * decode openssl-generated DSA private keys in wrapped FIPS186 format * we have to try both. */ if((cerror.error == CSSMERR_CSP_INVALID_KEY) && (hdr.AlgorithmId == CSSM_ALGID_DSA)) { hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186; try { auto_ptr provider(infoProvider(key)); provider->QueryKeySizeInBits(keySize); } catch(...) { /* out of luck */ throw; } } else { /* other error, give up */ throw; } } catch(...) { /* other (non-CSSM) error, give up */ throw; } hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits; } /* * When doing a PKCS8 wrap operation on a reference key, this * is used to infer the blob type to obtain before the encryption. * App can override this with a * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT * context attribute. */ CSSM_KEYBLOB_FORMAT pkcs8RawKeyFormat( CSSM_ALGORITHMS keyAlg) { switch(keyAlg) { case CSSM_ALGID_RSA: return CSSM_KEYBLOB_RAW_FORMAT_PKCS8; case CSSM_ALGID_DSA: return CSSM_KEYBLOB_RAW_FORMAT_FIPS186; default: /* punt */ return CSSM_KEYBLOB_RAW_FORMAT_NONE; } } /* * When doing a OPENSSL style wrap operation on a reference key, this * is used to infer the blob type to obtain before the encryption. * App can override this with a * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT * context attribute. */ CSSM_KEYBLOB_FORMAT opensslRawKeyFormat( CSSM_ALGORITHMS keyAlg) { switch(keyAlg) { case CSSM_ALGID_RSA: return CSSM_KEYBLOB_RAW_FORMAT_PKCS1; case CSSM_ALGID_DSA: return CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; default: /* punt */ return CSSM_KEYBLOB_RAW_FORMAT_NONE; } } /* * Given a key in some kind of openssl format (just subsequent to decryption * during an unwrap), fill in the following header fields: * * CSSM_KEYBLOB_FORMAT Format * uint32 LogicalKeySizeInBits */ void AppleCSPSession::opensslInferKeyHeader( CssmKey &key) { CSSM_KEYHEADER &hdr = key.KeyHeader; switch(hdr.AlgorithmId) { case CSSM_ALGID_RSA: hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; break; case CSSM_ALGID_DSA: hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; break; default: /* punt */ hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE; return; } /* now figure out the key size by finding a provider for this key */ CSSM_KEY_SIZE keySize; try { auto_ptr provider(infoProvider(key)); provider->QueryKeySizeInBits(keySize); } catch(...) { /* no recovery possible */ throw; } hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits; return; }