]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2010 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 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; | |
427c49bc | 58 | OSStatus __secapiresult = 0; |
b1ab9ed8 A |
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()); } | |
427c49bc A |
66 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
67 | catch (...) { __secapiresult=errSecInternalComponent; } | |
68 | secdebug("FDERecovery", "SecFDERecoveryUnwrapCRSKWithPrivKey: %d", (int)__secapiresult); | |
b1ab9ed8 A |
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 | assert(cssmData->Length <= sizeof(outHeader.publicKeyHash)); | |
427c49bc | 104 | outHeader.publicKeyHashSize = (uint32_t)cssmData->Length; |
b1ab9ed8 A |
105 | memcpy(outHeader.publicKeyHash, cssmData->Data, cssmData->Length); |
106 | fCSP.allocator().free(cssmData->Data); | |
107 | fCSP.allocator().free(cssmData); | |
108 | ||
109 | /* Now encrypt the blob with the public key. */ | |
110 | CssmClient::Encrypt encrypt(fCSP, key->KeyHeader.AlgorithmId); | |
111 | encrypt.key(cKey); | |
112 | CssmData clearBuf(outHeader.encryptedBlob, sizeof(outHeader.encryptedBlob)); | |
113 | CssmAutoData remData(fCSP.allocator()); | |
114 | encrypt.padding(CSSM_PADDING_PKCS1); | |
115 | ||
427c49bc | 116 | outHeader.encryptedBlobSize = (uint32_t)encrypt.encrypt(inBlob, clearBuf, remData.get()); |
b1ab9ed8 A |
117 | if (outHeader.encryptedBlobSize > sizeof(outHeader.encryptedBlob)) |
118 | secdebug("FDERecovery", "encodePrivateKeyHeader: encrypted blob too big: %d", outHeader.encryptedBlobSize); | |
119 | } | |
120 | ||
121 | CFDataRef decodePrivateKeyHeader(SecKeychainRef keychain, const FVPrivateKeyHeader &inHeader) | |
122 | { | |
123 | // kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h | |
124 | SecKeychainAttribute attrs[] = | |
125 | { | |
126 | { 6 /* kSecKeyLabel */, inHeader.publicKeyHashSize, const_cast<uint8 *>(inHeader.publicKeyHash) } | |
127 | }; | |
128 | SecKeychainAttributeList attrList = | |
129 | { | |
130 | sizeof(attrs) / sizeof(SecKeychainAttribute), | |
131 | attrs | |
132 | }; | |
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; | |
137 | ||
138 | SecKeychainSearchRef _searchRef; | |
139 | throwIfError(SecKeychainSearchCreateFromAttributes(keychain, CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &_searchRef)); | |
140 | CFRef<SecKeychainSearchRef> searchRef(_searchRef); | |
141 | ||
142 | SecKeychainItemRef _item; | |
143 | if (SecKeychainSearchCopyNext(searchRef, &_item)) | |
144 | return false; | |
145 | ||
146 | CFRef<SecKeyRef> keyItem(reinterpret_cast<SecKeyRef>(_item)); | |
147 | throwIfError(SecKeyGetCSPHandle(keyItem, &cspHandle)); | |
148 | throwIfError(SecKeyGetCSSMKey(keyItem, &cssmKey)); | |
149 | throwIfError(SecKeyGetCredentials(keyItem, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault, &accessCred)); | |
150 | throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle, cssmKey->KeyHeader.AlgorithmId, accessCred, cssmKey, CSSM_PADDING_PKCS1, &cc)); | |
151 | CFDataRef result; | |
152 | ||
153 | try | |
154 | { | |
155 | CssmMemoryFunctions memFuncs; | |
156 | throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle, &memFuncs)); | |
157 | CssmMemoryFunctionsAllocator allocator(memFuncs); | |
158 | ||
159 | const CssmData cipherBuf(const_cast<uint8 *>(inHeader.encryptedBlob), inHeader.encryptedBlobSize); | |
160 | CssmAutoData clearBuf(allocator); | |
161 | CssmAutoData remData(allocator); | |
162 | size_t bytesDecrypted; | |
163 | CSSM_RETURN crx = CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get()); | |
164 | secdebug("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx); | |
165 | throwIfError(crx); | |
166 | // throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get())); | |
167 | clearBuf.length(bytesDecrypted); | |
168 | // rawKey.copy(clearBuf.get()); | |
169 | result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)clearBuf.get().data(), clearBuf.get().length()); | |
170 | // result = parseKeyBlob(clearBuf.get()); | |
171 | } | |
172 | catch(...) | |
173 | { | |
174 | CSSM_DeleteContext(cc); | |
175 | throw; | |
176 | } | |
177 | ||
178 | throwIfError(CSSM_DeleteContext(cc)); | |
179 | ||
180 | return result; | |
181 | } | |
182 | ||
183 | static void throwIfError(CSSM_RETURN rv) | |
184 | { | |
185 | if (rv) | |
186 | CssmError::throwMe(rv); | |
187 | } | |
188 |