2  * Copyright (c) 2010-2013 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24 #include "SecFDERecoveryAsymmetricCrypto.h" 
  25 #include "SecBridge.h" 
  27 #include <security_cdsa_client/clclient.h> 
  28 #include <security_cdsa_client/wrapkey.h> 
  29 #include <security_utilities/cfutilities.h> 
  31 #include <Security/SecCertificate.h> 
  32 #include <Security/SecKeychain.h> 
  33 #include <Security/SecKeychainSearch.h> 
  34 #include <Security/SecKey.h> 
  36 static void encodePrivateKeyHeader(const CssmData 
&inBlob
, CFDataRef certificate
, FVPrivateKeyHeader 
&outHeader
); 
  37 static CFDataRef 
decodePrivateKeyHeader(SecKeychainRef keychainName
, const FVPrivateKeyHeader 
&inHeader
); 
  38 static void throwIfError(CSSM_RETURN rv
); 
  40 #pragma mark ----- Public SPI ----- 
  42 int SecFDERecoveryWrapCRSKWithPubKey(const uint8_t *crsk
, size_t crskLen
,  
  43         SecCertificateRef certificateRef
, FVPrivateKeyHeader 
*outHeader
) 
  47         CssmData 
inBlob((unsigned char *)crsk
, (size_t)crskLen
); 
  48         Required(certificateRef
); 
  49         CFRef
<CFDataRef
> certificateData(SecCertificateCopyData(certificateRef
)); 
  50         encodePrivateKeyHeader(inBlob
, certificateData
, Required(outHeader
)); 
  55 CFDataRef 
SecFDERecoveryUnwrapCRSKWithPrivKey(SecKeychainRef keychain
, const FVPrivateKeyHeader 
*inHeader
) 
  57         CFDataRef result 
= NULL
; 
  58         OSStatus __secapiresult 
= 0; 
  62                 result 
= decodePrivateKeyHeader(keychain
, Required(inHeader
)); 
  64         catch (const MacOSError 
&err
) { __secapiresult
=err
.osStatus(); } 
  65         catch (const CommonError 
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); } 
  66         catch (const std::bad_alloc 
&) { __secapiresult
=errSecAllocate
; } 
  67         catch (...) { __secapiresult
=errSecInternalComponent
; } 
  68         secinfo("FDERecovery", "SecFDERecoveryUnwrapCRSKWithPrivKey: %d", (int)__secapiresult
); 
  73 #pragma mark ----- Asymmetric Crypto ----- 
  75 static void encodePrivateKeyHeader(const CssmData 
&inBlob
, CFDataRef certificate
, FVPrivateKeyHeader 
&outHeader
) 
  77         CssmClient::CL 
cl(gGuidAppleX509CL
); 
  78         const CssmData 
cert(const_cast<UInt8 
*>(CFDataGetBytePtr(certificate
)), CFDataGetLength(certificate
)); 
  80         if (CSSM_RETURN rv 
= CSSM_CL_CertGetKeyInfo(cl
->handle(), &cert
, &key
)) 
  81                 CssmError::throwMe(rv
); 
  83         Security::CssmClient::CSP 
fCSP(gGuidAppleCSP
); 
  85         // Set it up so the cl is used to free key and key->KeyData 
  86         // CssmAutoData _keyData(cl.allocator()); 
  87         // _keyData.set(CssmData::overlay(key->KeyData)); 
  88         CssmAutoData 
_key(cl
.allocator()); 
  89         _key
.set(reinterpret_cast<uint8 
*>(key
), sizeof(*key
)); 
  90         CssmClient::Key 
cKey(fCSP
, *key
); 
  92         /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the  
  93                 * associated key blob.  
  94                 * Key is specified in CSSM_CSP_CreatePassThroughContext. 
  95                 * Hash is allocated by the CSP, in the App's memory, and returned 
  97         CssmClient::PassThrough 
passThrough(fCSP
); 
 100         passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
); 
 101         CssmData 
*cssmData 
= reinterpret_cast<CssmData 
*>(outData
); 
 103         assert(cssmData
->Length 
<= sizeof(outHeader
.publicKeyHash
)); 
 104         outHeader
.publicKeyHashSize 
= (uint32_t)cssmData
->Length
; 
 105         memcpy(outHeader
.publicKeyHash
, cssmData
->Data
, cssmData
->Length
); 
 106         fCSP
.allocator().free(cssmData
->Data
); 
 107         fCSP
.allocator().free(cssmData
); 
 109         /* Now encrypt the blob with the public key. */ 
 110     CssmClient::Encrypt 
encrypt(fCSP
, key
->KeyHeader
.AlgorithmId
); 
 112         CssmData 
clearBuf(outHeader
.encryptedBlob
, sizeof(outHeader
.encryptedBlob
)); 
 113         CssmAutoData 
remData(fCSP
.allocator()); 
 114         encrypt
.padding(CSSM_PADDING_PKCS1
); 
 116         outHeader
.encryptedBlobSize 
= (uint32_t)encrypt
.encrypt(inBlob
, clearBuf
, remData
.get()); 
 117         if (outHeader
.encryptedBlobSize 
> sizeof(outHeader
.encryptedBlob
)) 
 118                 secinfo("FDERecovery", "encodePrivateKeyHeader: encrypted blob too big: %d", outHeader
.encryptedBlobSize
); 
 121 CFDataRef 
decodePrivateKeyHeader(SecKeychainRef keychain
, const FVPrivateKeyHeader 
&inHeader
) 
 123         // kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h 
 124         SecKeychainAttribute attrs
[] = 
 126                 { 6 /* kSecKeyLabel */, inHeader
.publicKeyHashSize
, const_cast<uint8 
*>(inHeader
.publicKeyHash
) } 
 128         SecKeychainAttributeList attrList 
= 
 130                 sizeof(attrs
) / sizeof(SecKeychainAttribute
), 
 133         CSSM_CSP_HANDLE cspHandle 
= 0; 
 134         const CSSM_KEY 
*cssmKey 
= NULL
; 
 135     const CSSM_ACCESS_CREDENTIALS 
*accessCred 
= NULL
; 
 136     CSSM_CC_HANDLE cc 
= 0; 
 138         SecKeychainSearchRef _searchRef
; 
 139         throwIfError(SecKeychainSearchCreateFromAttributes(keychain
, (SecItemClass
) CSSM_DL_DB_RECORD_PRIVATE_KEY
, &attrList
, &_searchRef
)); 
 140         CFRef
<SecKeychainSearchRef
> searchRef(_searchRef
); 
 142         SecKeychainItemRef _item
; 
 143     if (SecKeychainSearchCopyNext(searchRef
, &_item
) != 0) { 
 144                 return NULL
;  // XXX possibly should throw here? 
 147         CFRef
<SecKeyRef
> keyItem(reinterpret_cast<SecKeyRef
>(_item
)); 
 148         throwIfError(SecKeyGetCSPHandle(keyItem
, &cspHandle
)); 
 149         throwIfError(SecKeyGetCSSMKey(keyItem
, &cssmKey
)); 
 150     throwIfError(SecKeyGetCredentials(keyItem
, CSSM_ACL_AUTHORIZATION_DECRYPT
, kSecCredentialTypeDefault
, &accessCred
)); 
 151     throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle
, cssmKey
->KeyHeader
.AlgorithmId
, accessCred
, cssmKey
, CSSM_PADDING_PKCS1
, &cc
)); 
 156                 CssmMemoryFunctions memFuncs
; 
 157                 throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle
, &memFuncs
)); 
 158                 CssmMemoryFunctionsAllocator 
allocator(memFuncs
); 
 160                 const CssmData 
cipherBuf(const_cast<uint8 
*>(inHeader
.encryptedBlob
), inHeader
.encryptedBlobSize
); 
 161                 CssmAutoData 
clearBuf(allocator
); 
 162                 CssmAutoData 
remData(allocator
); 
 163                 size_t bytesDecrypted
; 
 164                 CSSM_RETURN crx 
= CSSM_DecryptData(cc
, &cipherBuf
, 1, &clearBuf
.get(), 1, &bytesDecrypted
, &remData
.get()); 
 165                 secinfo("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx
); 
 167 //              throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get())); 
 168                 clearBuf
.length(bytesDecrypted
); 
 169 //              rawKey.copy(clearBuf.get()); 
 170                 result 
= CFDataCreate(kCFAllocatorDefault
, (const UInt8 
*)clearBuf
.get().data(), clearBuf
.get().length()); 
 171 //              result = parseKeyBlob(clearBuf.get()); 
 175                 CSSM_DeleteContext(cc
); 
 179         throwIfError(CSSM_DeleteContext(cc
)); 
 184 static void throwIfError(CSSM_RETURN rv
) 
 187                 CssmError::throwMe(rv
);