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
);