]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecFDERecoveryAsymmetricCrypto.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecFDERecoveryAsymmetricCrypto.cpp
1 /*
2 * Copyright (c) 2010-2013 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "SecFDERecoveryAsymmetricCrypto.h"
25 #include "SecBridge.h"
26
27 #include <security_cdsa_client/clclient.h>
28 #include <security_cdsa_client/wrapkey.h>
29 #include <security_utilities/cfutilities.h>
30
31 #include <Security/SecCertificate.h>
32 #include <Security/SecKeychain.h>
33 #include <Security/SecKeychainSearch.h>
34 #include <Security/SecKey.h>
35
36 static void encodePrivateKeyHeader(const CssmData &inBlob, CFDataRef certificate, FVPrivateKeyHeader &outHeader);
37 static CFDataRef CF_RETURNS_RETAINED decodePrivateKeyHeader(SecKeychainRef keychainName, const FVPrivateKeyHeader &inHeader);
38 static void throwIfError(CSSM_RETURN rv);
39
40 #pragma mark ----- Public SPI -----
41
42 int SecFDERecoveryWrapCRSKWithPubKey(const uint8_t *crsk, size_t crskLen,
43 SecCertificateRef certificateRef, FVPrivateKeyHeader *outHeader)
44 {
45 BEGIN_SECAPI
46
47 CssmData inBlob((unsigned char *)crsk, (size_t)crskLen);
48 Required(certificateRef);
49 CFRef<CFDataRef> certificateData(SecCertificateCopyData(certificateRef));
50 encodePrivateKeyHeader(inBlob, certificateData, Required(outHeader));
51
52 END_SECAPI
53 }
54
55 CFDataRef SecFDERecoveryUnwrapCRSKWithPrivKey(SecKeychainRef keychain, const FVPrivateKeyHeader *inHeader)
56 {
57 CFDataRef result = NULL;
58 OSStatus __secapiresult = 0;
59
60 try
61 {
62 result = decodePrivateKeyHeader(keychain, Required(inHeader));
63 }
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);
69 return result;
70 }
71
72
73 #pragma mark ----- Asymmetric Crypto -----
74
75 static void encodePrivateKeyHeader(const CssmData &inBlob, CFDataRef certificate, FVPrivateKeyHeader &outHeader)
76 {
77 CssmClient::CL cl(gGuidAppleX509CL);
78 const CssmData cert(const_cast<UInt8 *>(CFDataGetBytePtr(certificate)), CFDataGetLength(certificate));
79 CSSM_KEY_PTR key;
80 if (CSSM_RETURN rv = CSSM_CL_CertGetKeyInfo(cl->handle(), &cert, &key))
81 CssmError::throwMe(rv);
82
83 Security::CssmClient::CSP fCSP(gGuidAppleCSP);
84
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);
91
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
96 * in *outData. */
97 CssmClient::PassThrough passThrough(fCSP);
98 passThrough.key(key);
99 void *outData;
100 passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData);
101 CssmData *cssmData = reinterpret_cast<CssmData *>(outData);
102
103 outHeader.publicKeyHashSize = (uint32_t)cssmData->Length;
104 if (outHeader.publicKeyHashSize > sizeof(outHeader.publicKeyHash)) {
105 secinfo("FDERecovery", "encodePrivateKeyHeader: publicKeyHash too big: %d", outHeader.publicKeyHashSize);
106 outHeader.publicKeyHashSize = 0; /* failed to copy hash value */
107 } else {
108 memcpy(outHeader.publicKeyHash, cssmData->Data, outHeader.publicKeyHashSize);
109 }
110 fCSP.allocator().free(cssmData->Data);
111 fCSP.allocator().free(cssmData);
112
113 /* Now encrypt the blob with the public key. */
114 CssmClient::Encrypt encrypt(fCSP, key->KeyHeader.AlgorithmId);
115 encrypt.key(cKey);
116 CssmData clearBuf(outHeader.encryptedBlob, sizeof(outHeader.encryptedBlob));
117 CssmAutoData remData(fCSP.allocator());
118 encrypt.padding(CSSM_PADDING_PKCS1);
119
120 outHeader.encryptedBlobSize = (uint32_t)encrypt.encrypt(inBlob, clearBuf, remData.get());
121 if (outHeader.encryptedBlobSize > sizeof(outHeader.encryptedBlob))
122 secinfo("FDERecovery", "encodePrivateKeyHeader: encrypted blob too big: %d", outHeader.encryptedBlobSize);
123 }
124
125 CFDataRef decodePrivateKeyHeader(SecKeychainRef keychain, const FVPrivateKeyHeader &inHeader)
126 {
127 // kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h
128 SecKeychainAttribute attrs[] =
129 {
130 { 6 /* kSecKeyLabel */, inHeader.publicKeyHashSize, const_cast<uint8 *>(inHeader.publicKeyHash) }
131 };
132 SecKeychainAttributeList attrList =
133 {
134 sizeof(attrs) / sizeof(SecKeychainAttribute),
135 attrs
136 };
137 CSSM_CSP_HANDLE cspHandle = 0;
138 const CSSM_KEY *cssmKey = NULL;
139 const CSSM_ACCESS_CREDENTIALS *accessCred = NULL;
140 CSSM_CC_HANDLE cc = 0;
141
142 SecKeychainSearchRef _searchRef;
143 throwIfError(SecKeychainSearchCreateFromAttributes(keychain, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &_searchRef));
144 CFRef<SecKeychainSearchRef> searchRef(_searchRef);
145
146 SecKeychainItemRef _item;
147 if (SecKeychainSearchCopyNext(searchRef, &_item) != 0) {
148 return NULL; // XXX possibly should throw here?
149 }
150
151 CFRef<SecKeyRef> keyItem(reinterpret_cast<SecKeyRef>(_item));
152 throwIfError(SecKeyGetCSPHandle(keyItem, &cspHandle));
153 throwIfError(SecKeyGetCSSMKey(keyItem, &cssmKey));
154 throwIfError(SecKeyGetCredentials(keyItem, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault, &accessCred));
155 throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle, cssmKey->KeyHeader.AlgorithmId, accessCred, cssmKey, CSSM_PADDING_PKCS1, &cc));
156 CFDataRef result;
157
158 try
159 {
160 CssmMemoryFunctions memFuncs;
161 throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle, &memFuncs));
162 CssmMemoryFunctionsAllocator allocator(memFuncs);
163
164 const CssmData cipherBuf(const_cast<uint8 *>(inHeader.encryptedBlob), inHeader.encryptedBlobSize);
165 CssmAutoData clearBuf(allocator);
166 CssmAutoData remData(allocator);
167 size_t bytesDecrypted;
168 CSSM_RETURN crx = CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get());
169 secinfo("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx);
170 throwIfError(crx);
171 // throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get()));
172 clearBuf.length(bytesDecrypted);
173 // rawKey.copy(clearBuf.get());
174 result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)clearBuf.get().data(), clearBuf.get().length());
175 // result = parseKeyBlob(clearBuf.get());
176 }
177 catch(...)
178 {
179 CSSM_DeleteContext(cc);
180 throw;
181 }
182
183 throwIfError(CSSM_DeleteContext(cc));
184
185 return result;
186 }
187
188 static void throwIfError(CSSM_RETURN rv)
189 {
190 if (rv)
191 CssmError::throwMe(rv);
192 }
193