]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
5c19dc3a | 2 | * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5c19dc3a | 5 | * |
b1ab9ed8 A |
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. | |
5c19dc3a | 12 | * |
b1ab9ed8 A |
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. | |
5c19dc3a | 20 | * |
b1ab9ed8 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
24 | #include "SecKey.h" | |
25 | #include "SecKeyPriv.h" | |
26 | #include "SecItem.h" | |
27 | #include "SecItemPriv.h" | |
28 | #include <libDER/asn1Types.h> | |
29 | #include <libDER/DER_Encode.h> | |
30 | #include <libDER/DER_Decode.h> | |
31 | #include <libDER/DER_Keys.h> | |
32 | #include <Security/SecAsn1Types.h> | |
33 | #include <Security/SecAsn1Coder.h> | |
34 | #include <security_keychain/KeyItem.h> | |
6b200bc3 | 35 | #include <security_utilities/casts.h> |
b1ab9ed8 A |
36 | #include <CommonCrypto/CommonKeyDerivation.h> |
37 | ||
38 | #include "SecBridge.h" | |
39 | ||
40 | #include <security_keychain/Access.h> | |
41 | #include <security_keychain/Keychains.h> | |
42 | #include <security_keychain/KeyItem.h> | |
43 | #include <string.h> | |
44 | #include <syslog.h> | |
45 | ||
46 | #include <security_cdsa_utils/cuCdsaUtils.h> | |
47 | #include <security_cdsa_client/wrapkey.h> | |
fa7225c8 A |
48 | #include <security_cdsa_client/genkey.h> |
49 | #include <security_cdsa_client/signclient.h> | |
50 | #include <security_cdsa_client/cryptoclient.h> | |
b1ab9ed8 A |
51 | |
52 | #include "SecImportExportCrypto.h" | |
53 | ||
fa7225c8 A |
54 | static OSStatus |
55 | SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { | |
56 | key->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData)); | |
57 | key->key->initializeWithSecKeyRef(key); | |
b04fe171 | 58 | key->credentialType = kSecCredentialTypeDefault; |
fa7225c8 A |
59 | return errSecSuccess; |
60 | } | |
61 | ||
62 | static void | |
63 | SecCDSAKeyDestroy(SecKeyRef keyRef) { | |
64 | // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation. | |
65 | // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset. | |
66 | // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex. | |
67 | ||
68 | KeyItem *keyItem = keyRef->key; | |
69 | if (keyItem == NULL) { | |
70 | // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us. | |
71 | return; | |
72 | } | |
73 | ||
74 | Keychain kc = keyItem->keychain(); | |
75 | ||
76 | { | |
77 | StMaybeLock<Mutex> _(keyItem->getMutexForObject()); | |
78 | keyItem = keyRef->key; | |
79 | if (keyItem == NULL) { | |
80 | // Second version of the check above, the definitive one because this one is performed with locked object's mutex, therefore we can be sure that KeyImpl is still connected to this keyRef instance. | |
81 | return; | |
82 | } | |
83 | ||
84 | keyItem->aboutToDestruct(); | |
85 | delete keyItem; | |
86 | } | |
87 | ||
88 | (void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain. | |
89 | } | |
90 | ||
91 | static size_t | |
92 | SecCDSAKeyGetBlockSize(SecKeyRef key) { | |
93 | ||
94 | CFErrorRef *error = NULL; | |
95 | BEGIN_SECKEYAPI(size_t,0) | |
96 | ||
97 | const CssmKey::Header keyHeader = key->key->unverifiedKeyHeader(); | |
98 | switch(keyHeader.algorithm()) | |
99 | { | |
100 | case CSSM_ALGID_RSA: | |
101 | case CSSM_ALGID_DSA: | |
102 | result = keyHeader.LogicalKeySizeInBits / 8; | |
103 | break; | |
104 | case CSSM_ALGID_ECDSA: | |
105 | { | |
106 | /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers, | |
107 | * plus both coordinates for the point used */ | |
108 | #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8) | |
109 | #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1) | |
110 | size_t coordSize = ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader.LogicalKeySizeInBits); | |
111 | assert(coordSize < 256); /* size must fit in a byte for DER */ | |
112 | size_t coordDERLen = (coordSize > 127) ? 2 : 1; | |
113 | size_t coordLen = 1 + coordDERLen + coordSize; | |
114 | ||
115 | size_t pointSize = 2 * coordLen; | |
116 | assert(pointSize < 256); /* size must fit in a byte for DER */ | |
117 | size_t pointDERLen = (pointSize > 127) ? 2 : 1; | |
118 | size_t pointLen = 1 + pointDERLen + pointSize; | |
119 | ||
120 | result = pointLen; | |
121 | } | |
122 | break; | |
123 | case CSSM_ALGID_AES: | |
124 | result = 16; /* all AES keys use 128-bit blocks */ | |
125 | break; | |
126 | case CSSM_ALGID_DES: | |
127 | case CSSM_ALGID_3DES_3KEY: | |
128 | result = 8; /* all DES keys use 64-bit blocks */ | |
129 | break; | |
130 | default: | |
131 | assert(0); /* some other key algorithm */ | |
132 | result = 16; /* FIXME: revisit this */ | |
133 | break; | |
134 | } | |
135 | ||
136 | END_SECKEYAPI | |
137 | } | |
b1ab9ed8 | 138 | |
fa7225c8 A |
139 | static CFIndex |
140 | SecCDSAKeyGetAlgorithmId(SecKeyRef key) { | |
141 | ||
142 | CFErrorRef *error = NULL; | |
143 | BEGIN_SECKEYAPI(CFIndex, 0) | |
144 | ||
145 | result = kSecNullAlgorithmID; | |
146 | switch (key->key->unverifiedKeyHeader().AlgorithmId) { | |
147 | case CSSM_ALGID_RSA: | |
148 | result = kSecRSAAlgorithmID; | |
149 | break; | |
150 | case CSSM_ALGID_DSA: | |
151 | result = kSecDSAAlgorithmID; | |
152 | break; | |
153 | case CSSM_ALGID_ECDSA: | |
154 | result = kSecECDSAAlgorithmID; | |
155 | break; | |
156 | default: | |
157 | assert(0); /* other algorithms TBA */ | |
158 | } | |
159 | ||
160 | END_SECKEYAPI | |
161 | } | |
162 | ||
163 | static CFDataRef SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo) { | |
164 | // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic | |
165 | // and export data as is. | |
6b200bc3 | 166 | DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }, pubKeyItem; |
fa7225c8 A |
167 | DERByte numUnused; |
168 | DERSubjPubKeyInfo subjPubKey; | |
169 | if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs, | |
170 | DERSubjPubKeyInfoItemSpecs, | |
171 | &subjPubKey, sizeof(subjPubKey)) == DR_Success && | |
172 | DERParseBitString(&subjPubKey.pubKey, &pubKeyItem, &numUnused) == DR_Success) { | |
173 | return CFDataCreate(kCFAllocatorDefault, pubKeyItem.data, pubKeyItem.length); | |
174 | } | |
175 | ||
176 | return CFDataRef(CFRetain(pubKeyInfo)); | |
177 | } | |
178 | ||
179 | static CFDataRef SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CFDataRef pubKeyInfo) { | |
180 | // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type. | |
6b200bc3 | 181 | DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }; |
fa7225c8 A |
182 | DERSubjPubKeyInfo subjPubKey; |
183 | if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs, | |
184 | DERSubjPubKeyInfoItemSpecs, | |
185 | &subjPubKey, sizeof(subjPubKey)) == DR_Success) { | |
186 | return CFDataRef(CFRetain(pubKeyInfo)); | |
187 | } | |
188 | ||
189 | // We have always size rounded to full bytes so bitstring encodes leading 00. | |
190 | CFRef<CFMutableDataRef> bitStringPubKey = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
191 | CFDataSetLength(bitStringPubKey, 1); | |
192 | CFDataAppendBytes(bitStringPubKey, CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo)); | |
193 | subjPubKey.pubKey.data = static_cast<DERByte *>(const_cast<UInt8 *>(CFDataGetBytePtr(bitStringPubKey))); | |
194 | subjPubKey.pubKey.length = CFDataGetLength(bitStringPubKey); | |
195 | ||
196 | // Encode algId according to algorithm used. | |
197 | static const DERByte oidRSA[] = { | |
198 | 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, | |
199 | }; | |
200 | static const DERByte oidECsecp256[] = { | |
201 | 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, | |
202 | }; | |
203 | static const DERByte oidECsecp384[] = { | |
204 | 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, | |
205 | }; | |
206 | static const DERByte oidECsecp521[] = { | |
207 | 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, | |
208 | }; | |
209 | subjPubKey.algId.length = 0; | |
210 | if (algorithm == CSSM_ALGID_RSA) { | |
211 | subjPubKey.algId.data = const_cast<DERByte *>(oidRSA); | |
212 | subjPubKey.algId.length = sizeof(oidRSA); | |
213 | } else if (algorithm == CSSM_ALGID_ECDSA) { | |
214 | if (keySizeInBits == 256) { | |
215 | subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp256); | |
216 | subjPubKey.algId.length = sizeof(oidECsecp256); | |
217 | } else if (keySizeInBits == 384) { | |
218 | subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp384); | |
6b200bc3 | 219 | subjPubKey.algId.length = sizeof(oidECsecp384); |
fa7225c8 A |
220 | } if (keySizeInBits == 521) { |
221 | subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp521); | |
6b200bc3 | 222 | subjPubKey.algId.length = sizeof(oidECsecp521); |
fa7225c8 A |
223 | } |
224 | } | |
225 | DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey, | |
226 | DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs); | |
227 | CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size); | |
228 | CFDataSetLength(keyData, size); | |
229 | if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey, | |
230 | DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs, | |
231 | static_cast<DERByte *>(CFDataGetMutableBytePtr(keyData)), &size) == DR_Success) { | |
232 | CFDataSetLength(keyData, size); | |
233 | } else { | |
234 | keyData.release(); | |
235 | } | |
236 | ||
237 | return keyData.yield(); | |
238 | } | |
239 | ||
240 | static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serialization) { | |
241 | ||
242 | CFErrorRef *error = NULL; | |
243 | BEGIN_SECKEYAPI(OSStatus, errSecSuccess) | |
244 | ||
245 | const CssmKey::Header &header = key->key->key().header(); | |
246 | switch (header.algorithm()) { | |
247 | case CSSM_ALGID_RSA: { | |
248 | switch (header.keyClass()) { | |
249 | case CSSM_KEYCLASS_PRIVATE_KEY: { | |
250 | CFRef<CFDataRef> privKeyData; | |
251 | result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, privKeyData.take()); | |
252 | if (result == errSecSuccess) { | |
6b200bc3 | 253 | DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), int_cast<CFIndex, DERSize>(CFDataGetLength(privKeyData)) }; |
fa7225c8 A |
254 | DERRSAKeyPair keyPair; |
255 | if (DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs, | |
256 | &keyPair, sizeof(keyPair)) == DR_Success) { | |
257 | DERRSAPubKeyPKCS1 pubKey = { keyPair.n, keyPair.e }; | |
258 | DERSize size = DERLengthOfEncodedSequence(ASN1_SEQUENCE, &pubKey, | |
259 | DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs); | |
260 | CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size); | |
261 | CFDataSetLength(keyData, size); | |
262 | UInt8 *data = CFDataGetMutableBytePtr(keyData); | |
263 | if (DEREncodeSequence(ASN1_SEQUENCE, &pubKey, | |
264 | DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs, | |
265 | data, &size) == DR_Success) { | |
266 | CFDataSetLength(keyData, size); | |
267 | *data = ONE_BYTE_ASN1_CONSTR_SEQUENCE; | |
268 | *serialization = keyData.yield(); | |
269 | } else { | |
270 | *serialization = NULL; | |
271 | result = errSecParam; | |
272 | } | |
273 | } | |
274 | } | |
275 | break; | |
276 | } | |
277 | case CSSM_KEYCLASS_PUBLIC_KEY: | |
278 | result = SecItemExport(key, kSecFormatBSAFE, 0, NULL, serialization); | |
279 | break; | |
280 | } | |
281 | break; | |
282 | } | |
283 | case CSSM_ALGID_ECDSA: { | |
284 | *serialization = NULL; | |
285 | CFRef<CFDataRef> tempPublicData; | |
286 | result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, tempPublicData.take()); | |
287 | if (result == errSecSuccess) { | |
288 | *serialization = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData); | |
289 | } | |
290 | break; | |
291 | } | |
292 | default: | |
293 | result = errSecUnimplemented; | |
294 | } | |
b1ab9ed8 | 295 | |
fa7225c8 | 296 | END_SECKEYAPI |
b1ab9ed8 A |
297 | } |
298 | ||
fa7225c8 A |
299 | typedef struct { |
300 | DERItem privateKey; | |
301 | DERItem publicKey; | |
302 | } DERECPrivateKey; | |
303 | ||
304 | static const DERItemSpec DERECPrivateKeyItemSpecs[] = | |
305 | { | |
306 | { 0, | |
307 | ASN1_INTEGER, | |
308 | DER_DEC_SKIP }, | |
309 | { DER_OFFSET(DERECPrivateKey, privateKey), | |
310 | ASN1_OCTET_STRING, | |
311 | DER_DEC_NO_OPTS | DER_ENC_NO_OPTS }, | |
312 | { 0, | |
313 | ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0, | |
314 | DER_DEC_SKIP | DER_ENC_NO_OPTS }, | |
315 | { DER_OFFSET(DERECPrivateKey, publicKey), | |
316 | ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1, | |
317 | DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT }, | |
318 | }; | |
319 | static const DERSize DERNumECPrivateKeyItemSpecs = | |
320 | sizeof(DERECPrivateKeyItemSpecs) / sizeof(DERItemSpec); | |
321 | ||
322 | typedef struct { | |
323 | DERItem bitString; | |
324 | } DERECPrivateKeyPublicKey; | |
325 | ||
326 | static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs[] = | |
5c19dc3a | 327 | { |
fa7225c8 A |
328 | { DER_OFFSET(DERECPrivateKeyPublicKey, bitString), |
329 | ASN1_BIT_STRING, | |
330 | DER_DEC_NO_OPTS | DER_ENC_NO_OPTS }, | |
331 | }; | |
332 | static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs = | |
333 | sizeof(DERECPrivateKeyPublicKeyItemSpecs) / sizeof(DERItemSpec); | |
334 | ||
335 | static CFDataRef | |
336 | SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { | |
337 | ||
338 | BEGIN_SECKEYAPI(CFDataRef, NULL) | |
339 | ||
340 | result = NULL; | |
341 | const CssmKey::Header header = key->key->unverifiedKeyHeader(); | |
342 | CFRef<CFDataRef> keyData; | |
343 | switch (header.algorithm()) { | |
344 | case CSSM_ALGID_RSA: | |
345 | MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take())); | |
346 | break; | |
347 | case CSSM_ALGID_ECDSA: { | |
348 | MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take())); | |
349 | if (header.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY) { | |
350 | // Convert DER format into x9.63 format, which is expected for exported key. | |
6b200bc3 | 351 | DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), int_cast<CFIndex, DERSize>(CFDataGetLength(keyData)) }; |
fa7225c8 A |
352 | DERECPrivateKey privateKey; |
353 | DERECPrivateKeyPublicKey privateKeyPublicKey; | |
354 | DERByte numUnused; | |
355 | DERItem pubKeyItem; | |
356 | if (DERParseSequence(&keyItem, DERNumECPrivateKeyItemSpecs, DERECPrivateKeyItemSpecs, | |
357 | &privateKey, sizeof(privateKey)) == DR_Success && | |
358 | DERParseSequenceContent(&privateKey.publicKey, DERNumECPrivateKeyPublicKeyItemSpecs, | |
359 | DERECPrivateKeyPublicKeyItemSpecs, | |
360 | &privateKeyPublicKey, sizeof(privateKeyPublicKey)) == DR_Success && | |
361 | DERParseBitString(&privateKeyPublicKey.bitString, &pubKeyItem, &numUnused) == DR_Success) { | |
362 | CFRef<CFMutableDataRef> key = CFDataCreateMutable(kCFAllocatorDefault, | |
363 | pubKeyItem.length + privateKey.privateKey.length); | |
364 | CFDataSetLength(key, pubKeyItem.length + privateKey.privateKey.length); | |
365 | CFDataReplaceBytes(key, CFRangeMake(0, pubKeyItem.length), pubKeyItem.data, pubKeyItem.length); | |
366 | CFDataReplaceBytes(key, CFRangeMake(pubKeyItem.length, privateKey.privateKey.length), | |
367 | privateKey.privateKey.data, privateKey.privateKey.length); | |
368 | keyData = key.as<CFDataRef>(); | |
369 | } | |
370 | } | |
371 | break; | |
372 | } | |
373 | default: | |
374 | MacOSError::throwMe(errSecUnimplemented); | |
375 | } | |
376 | ||
377 | if (header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) { | |
378 | result = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData); | |
379 | } else { | |
380 | result = keyData.yield(); | |
381 | } | |
382 | ||
383 | END_SECKEYAPI | |
384 | } | |
385 | ||
386 | static CFDataRef SecCDSAKeyCopyLabel(SecKeyRef key) { | |
387 | CFDataRef label = NULL; | |
388 | if (key->key->isPersistent()) { | |
389 | UInt32 tags[] = { kSecKeyLabel }, formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB }; | |
390 | SecKeychainAttributeInfo info = { 1, tags, formats }; | |
391 | SecKeychainAttributeList *list = NULL; | |
392 | key->key->getAttributesAndData(&info, NULL, &list, NULL, NULL); | |
393 | if (list->count == 1) { | |
394 | SecKeychainAttribute *attr = list->attr; | |
395 | label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attr->data, (CFIndex)attr->length); | |
396 | } | |
397 | key->key->freeAttributesAndData(list, NULL); | |
398 | } | |
399 | return label; | |
400 | } | |
401 | ||
402 | static CFDictionaryRef | |
403 | SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) { | |
404 | ||
405 | CFErrorRef *error = NULL; | |
406 | BEGIN_SECKEYAPI(CFDictionaryRef, NULL) | |
407 | ||
408 | CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, | |
409 | &kCFTypeDictionaryValueCallBacks); | |
410 | ||
411 | CFDictionarySetValue(dict, kSecClass, kSecClassKey); | |
412 | ||
413 | const CssmKey::Header header = key->key->unverifiedKeyHeader(); | |
414 | CFIndex sizeValue = header.LogicalKeySizeInBits; | |
415 | CFRef<CFNumberRef> sizeInBits = CFNumberCreate(NULL, kCFNumberCFIndexType, &sizeValue); | |
416 | CFDictionarySetValue(dict, kSecAttrKeySizeInBits, sizeInBits); | |
417 | CFDictionarySetValue(dict, kSecAttrEffectiveKeySize, sizeInBits); | |
418 | ||
419 | CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(key); | |
420 | if (!label) { | |
421 | // For floating keys, calculate label as SHA1 of pubkey bytes. | |
422 | CFRef<CFDataRef> pubKeyBlob; | |
423 | if (SecCDSAKeyCopyPublicBytes(key, pubKeyBlob.take()) == errSecSuccess) { | |
424 | uint8_t pubKeyHash[CC_SHA1_DIGEST_LENGTH]; | |
425 | CC_SHA1(CFDataGetBytePtr(pubKeyBlob), CC_LONG(CFDataGetLength(pubKeyBlob)), pubKeyHash); | |
426 | label.take(CFDataCreate(kCFAllocatorDefault, pubKeyHash, sizeof(pubKeyHash))); | |
427 | } | |
428 | } | |
429 | ||
430 | if (label) { | |
431 | CFDictionarySetValue(dict, kSecAttrApplicationLabel, label); | |
432 | } | |
433 | ||
434 | CSSM_KEYATTR_FLAGS attrs = header.attributes(); | |
435 | CFDictionarySetValue(dict, kSecAttrIsPermanent, (attrs & CSSM_KEYATTR_PERMANENT) ? kCFBooleanTrue : kCFBooleanFalse); | |
436 | CFDictionarySetValue(dict, kSecAttrIsPrivate, (attrs & CSSM_KEYATTR_PRIVATE) ? kCFBooleanTrue : kCFBooleanFalse); | |
437 | CFDictionarySetValue(dict, kSecAttrIsModifiable, (attrs & CSSM_KEYATTR_MODIFIABLE) ? kCFBooleanTrue : kCFBooleanFalse); | |
438 | CFDictionarySetValue(dict, kSecAttrIsSensitive, (attrs & CSSM_KEYATTR_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse); | |
439 | CFDictionarySetValue(dict, kSecAttrIsExtractable, (attrs & CSSM_KEYATTR_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse); | |
440 | CFDictionarySetValue(dict, kSecAttrWasAlwaysSensitive, (attrs & CSSM_KEYATTR_ALWAYS_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse); | |
441 | CFDictionarySetValue(dict, kSecAttrWasNeverExtractable, (attrs & CSSM_KEYATTR_NEVER_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse); | |
442 | ||
443 | CFDictionarySetValue(dict, kSecAttrCanEncrypt, (header.useFor(CSSM_KEYUSE_ENCRYPT)) ? kCFBooleanTrue : kCFBooleanFalse); | |
444 | CFDictionarySetValue(dict, kSecAttrCanDecrypt, (header.useFor(CSSM_KEYUSE_DECRYPT)) ? kCFBooleanTrue : kCFBooleanFalse); | |
445 | CFDictionarySetValue(dict, kSecAttrCanSign, (header.useFor(CSSM_KEYUSE_SIGN)) ? kCFBooleanTrue : kCFBooleanFalse); | |
446 | CFDictionarySetValue(dict, kSecAttrCanVerify, (header.useFor(CSSM_KEYUSE_VERIFY)) ? kCFBooleanTrue : kCFBooleanFalse); | |
447 | CFDictionarySetValue(dict, kSecAttrCanSignRecover, (header.useFor(CSSM_KEYUSE_SIGN_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse); | |
448 | CFDictionarySetValue(dict, kSecAttrCanVerifyRecover, (header.useFor(CSSM_KEYUSE_VERIFY_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse); | |
449 | CFDictionarySetValue(dict, kSecAttrCanWrap, (header.useFor(CSSM_KEYUSE_WRAP)) ? kCFBooleanTrue : kCFBooleanFalse); | |
450 | CFDictionarySetValue(dict, kSecAttrCanUnwrap, (header.useFor(CSSM_KEYUSE_UNWRAP)) ? kCFBooleanTrue : kCFBooleanFalse); | |
451 | CFDictionarySetValue(dict, kSecAttrCanDerive, (header.useFor(CSSM_KEYUSE_DERIVE)) ? kCFBooleanTrue : kCFBooleanFalse); | |
452 | ||
453 | switch (header.keyClass()) { | |
454 | case CSSM_KEYCLASS_PUBLIC_KEY: | |
455 | CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic); | |
456 | break; | |
457 | case CSSM_KEYCLASS_PRIVATE_KEY: | |
458 | CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPrivate); | |
459 | break; | |
460 | } | |
461 | ||
462 | switch (header.algorithm()) { | |
463 | case CSSM_ALGID_RSA: | |
464 | CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeRSA); | |
465 | break; | |
466 | case CSSM_ALGID_ECDSA: | |
467 | CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECDSA); | |
468 | break; | |
469 | } | |
470 | ||
471 | CFRef<CFDataRef> keyData; | |
472 | if (SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()) == errSecSuccess) { | |
473 | CFDictionarySetValue(dict, kSecValueData, keyData); | |
474 | } | |
475 | ||
476 | if (header.algorithm() == CSSM_ALGID_RSA && header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY && | |
477 | header.blobType() == CSSM_KEYBLOB_RAW) { | |
478 | const CssmData &keyData = key->key->key()->keyData(); | |
479 | DERItem keyItem = { static_cast<DERByte *>(keyData.data()), keyData.length() }; | |
480 | DERRSAPubKeyPKCS1 decodedKey; | |
481 | if (DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs, | |
482 | DERRSAPubKeyPKCS1ItemSpecs, | |
483 | &decodedKey, sizeof(decodedKey)) == DR_Success) { | |
484 | CFRef<CFDataRef> modulus = CFDataCreate(kCFAllocatorDefault, decodedKey.modulus.data, | |
485 | decodedKey.modulus.length); | |
486 | CFDictionarySetValue(dict, CFSTR("_rsam"), modulus); | |
487 | CFRef<CFDataRef> exponent = CFDataCreate(kCFAllocatorDefault, decodedKey.pubExponent.data, | |
488 | decodedKey.pubExponent.length); | |
489 | CFDictionarySetValue(dict, CFSTR("_rsae"), exponent); | |
490 | } | |
491 | } | |
492 | ||
493 | result = dict; | |
494 | ||
495 | END_SECKEYAPI | |
496 | } | |
497 | ||
498 | #pragma clang diagnostic push | |
499 | #pragma clang diagnostic ignored "-Wunused-const-variable" | |
500 | static CSSM_DB_NAME_ATTR(kInfoKeyLabel, kSecKeyLabel, (char*) "Label", 0, NULL, BLOB); | |
501 | #pragma clang diagnostic pop | |
502 | ||
503 | static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) { | |
504 | CFErrorRef *error; | |
505 | BEGIN_SECKEYAPI(SecKeyRef, NULL) | |
506 | ||
507 | result = NULL; | |
508 | KeyItem *key = privateKey->key; | |
509 | CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(privateKey); | |
510 | if (label) { | |
511 | // Lookup public key in the database. | |
512 | DbUniqueRecord uniqueId; | |
513 | SSDb ssDb(dynamic_cast<SSDbImpl *>(&(*key->keychain()->database()))); | |
514 | SSDbCursor dbCursor(ssDb, 1); | |
515 | dbCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY); | |
516 | dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, CssmData(CFDataRef(label))); | |
517 | if (dbCursor->next(NULL, NULL, uniqueId)) { | |
518 | Item publicKey = key->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, uniqueId); | |
519 | result = reinterpret_cast<SecKeyRef>(publicKey->handle()); | |
520 | } | |
6b200bc3 A |
521 | } |
522 | ||
523 | if (result == NULL && key->publicKey()) { | |
866f8763 | 524 | SecPointer<KeyItem> publicKey(new KeyItem(key->publicKey())); |
fa7225c8 A |
525 | result = reinterpret_cast<SecKeyRef>(publicKey->handle()); |
526 | } | |
527 | ||
528 | END_SECKEYAPI | |
529 | } | |
530 | ||
866f8763 | 531 | static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType &operation, SecKeyAlgorithm algorithm, |
fa7225c8 | 532 | CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm, |
b04fe171 | 533 | CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) { |
fa7225c8 A |
534 | KeyItem *keyItem = key->key; |
535 | CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass(); | |
536 | baseAlgorithm = keyItem->key()->header().algorithm(); | |
537 | switch (baseAlgorithm) { | |
538 | case CSSM_ALGID_RSA: | |
539 | if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) || | |
540 | (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) { | |
541 | if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) { | |
542 | secondaryAlgorithm = CSSM_ALGID_NONE; | |
543 | paddingAlgorithm = CSSM_PADDING_NONE; | |
b04fe171 | 544 | inputSizeLimit = 0; |
fa7225c8 A |
545 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)) { |
546 | secondaryAlgorithm = CSSM_ALGID_NONE; | |
547 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 548 | inputSizeLimit = -11; |
fa7225c8 A |
549 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) { |
550 | secondaryAlgorithm = CSSM_ALGID_SHA1; | |
551 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 552 | inputSizeLimit = 20; |
fa7225c8 A |
553 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) { |
554 | secondaryAlgorithm = CSSM_ALGID_SHA224; | |
555 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 556 | inputSizeLimit = 224 / 8; |
fa7225c8 A |
557 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) { |
558 | secondaryAlgorithm = CSSM_ALGID_SHA256; | |
559 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 560 | inputSizeLimit = 256 / 8; |
fa7225c8 A |
561 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) { |
562 | secondaryAlgorithm = CSSM_ALGID_SHA384; | |
563 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 564 | inputSizeLimit = 384 / 8; |
fa7225c8 A |
565 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) { |
566 | secondaryAlgorithm = CSSM_ALGID_SHA512; | |
567 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 568 | inputSizeLimit = 512 / 8; |
fa7225c8 A |
569 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5)) { |
570 | secondaryAlgorithm = CSSM_ALGID_MD5; | |
571 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 572 | inputSizeLimit = 16; |
fa7225c8 A |
573 | } else { |
574 | return NULL; | |
575 | } | |
576 | } else if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeDecrypt) || | |
577 | (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeEncrypt)) { | |
578 | if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { | |
579 | secondaryAlgorithm = CSSM_ALGID_NONE; | |
580 | paddingAlgorithm = CSSM_PADDING_NONE; | |
b04fe171 | 581 | inputSizeLimit = 0; |
fa7225c8 A |
582 | } else if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionPKCS1)) { |
583 | secondaryAlgorithm = CSSM_ALGID_NONE; | |
584 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
b04fe171 | 585 | inputSizeLimit = operation == kSecKeyOperationTypeEncrypt ? -11 : 0; |
fa7225c8 A |
586 | } else { |
587 | return NULL; | |
588 | } | |
866f8763 A |
589 | } else if (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeDecrypt && |
590 | CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { | |
591 | // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption, | |
592 | // because CDSA keys refuses to perform decrypt using public key. | |
593 | operation = kSecKeyOperationTypeEncrypt; | |
594 | secondaryAlgorithm = CSSM_ALGID_NONE; | |
595 | paddingAlgorithm = CSSM_PADDING_NONE; | |
596 | inputSizeLimit = 0; | |
fa7225c8 A |
597 | } else { |
598 | return NULL; | |
599 | } | |
600 | break; | |
601 | case CSSM_ALGID_ECDSA: | |
602 | if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) || | |
603 | (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) { | |
604 | if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureRFC4754)) { | |
605 | secondaryAlgorithm = CSSM_ALGID_NONE; | |
606 | paddingAlgorithm = CSSM_PADDING_SIGRAW; | |
607 | } else if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) { | |
608 | secondaryAlgorithm = CSSM_ALGID_NONE; | |
609 | paddingAlgorithm = CSSM_PADDING_PKCS1; | |
610 | } else { | |
611 | return NULL; | |
612 | } | |
613 | } else if (keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeKeyExchange) { | |
614 | if (CFEqual(algorithm,kSecKeyAlgorithmECDHKeyExchangeStandard) || | |
615 | CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) { | |
616 | baseAlgorithm = CSSM_ALGID_ECDH; | |
617 | } else if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1) || | |
618 | CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1)) { | |
619 | baseAlgorithm = CSSM_ALGID_ECDH_X963_KDF; | |
620 | } else { | |
621 | return NULL; | |
622 | } | |
623 | } else { | |
624 | return NULL; | |
625 | } | |
626 | break; | |
627 | default: | |
628 | MacOSError::throwMe(errSecParam); | |
629 | } | |
630 | return keyItem; | |
631 | } | |
632 | ||
633 | static CFDataRef | |
634 | SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key, CFDataRef plaintext, SecKeyAlgorithm algorithm) { | |
635 | CFIndex blockSize = key->key->key().header().LogicalKeySizeInBits / 8; | |
636 | CFIndex plaintextLength = CFDataGetLength(plaintext); | |
637 | if ((algorithm == kSecKeyAlgorithmRSAEncryptionRaw || algorithm == kSecKeyAlgorithmRSASignatureRaw) | |
638 | && plaintextLength < blockSize) { | |
639 | // Pre-pad with zeroes. | |
640 | CFMutableDataRef result(CFDataCreateMutable(kCFAllocatorDefault, blockSize)); | |
641 | CFDataSetLength(result, blockSize); | |
642 | CFDataReplaceBytes(result, CFRangeMake(blockSize - plaintextLength, plaintextLength), | |
643 | CFDataGetBytePtr(plaintext), plaintextLength); | |
644 | return result; | |
645 | } else { | |
646 | return CFDataRef(CFRetain(plaintext)); | |
647 | } | |
5c19dc3a A |
648 | } |
649 | ||
fa7225c8 A |
650 | static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, |
651 | CFArrayRef allAlgorithms, SecKeyOperationMode mode, | |
652 | CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
653 | BEGIN_SECKEYAPI(CFTypeRef, kCFNull) | |
b04fe171 | 654 | CFIndex inputSizeLimit = 0; |
fa7225c8 | 655 | CSSM_ALGORITHMS baseAlgorithm, secondaryAlgorithm, paddingAlgorithm; |
b04fe171 | 656 | KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm, inputSizeLimit); |
fa7225c8 A |
657 | if (keyItem == NULL) { |
658 | // Operation/algorithm/key combination is not supported. | |
659 | return kCFNull; | |
660 | } else if (mode == kSecKeyOperationModeCheckIfSupported) { | |
661 | // Operation is supported and caller wants to just know that. | |
662 | return kCFBooleanTrue; | |
b04fe171 A |
663 | } else if (baseAlgorithm == CSSM_ALGID_RSA) { |
664 | if (inputSizeLimit <= 0) { | |
665 | inputSizeLimit += SecCDSAKeyGetBlockSize(key); | |
666 | } | |
667 | if (CFDataGetLength((CFDataRef)in1) > inputSizeLimit) { | |
668 | MacOSError::throwMe(errSecParam); | |
669 | } | |
fa7225c8 A |
670 | } |
671 | ||
672 | switch (operation) { | |
673 | case kSecKeyOperationTypeSign: { | |
674 | CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm); | |
675 | signContext.key(keyItem->key()); | |
b04fe171 | 676 | signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, key->credentialType)); |
fa7225c8 A |
677 | signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm); |
678 | CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm); | |
679 | CssmAutoData signature(signContext.allocator()); | |
680 | signContext.sign(CssmData(CFDataRef(input)), signature.get()); | |
681 | result = CFDataCreate(NULL, static_cast<const UInt8 *>(signature.data()), CFIndex(signature.length())); | |
682 | break; | |
683 | } | |
684 | case kSecKeyOperationTypeVerify: { | |
685 | CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm); | |
686 | verifyContext.key(keyItem->key()); | |
b04fe171 | 687 | verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, key->credentialType)); |
fa7225c8 A |
688 | verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm); |
689 | CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm); | |
690 | verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef<CFDataRef>::check(in2, errSecParam))); | |
691 | result = kCFBooleanTrue; | |
692 | break; | |
693 | } | |
694 | case kSecKeyOperationTypeEncrypt: { | |
695 | CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm); | |
696 | encryptContext.key(keyItem->key()); | |
697 | encryptContext.padding(paddingAlgorithm); | |
b04fe171 | 698 | encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, key->credentialType)); |
fa7225c8 A |
699 | CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm); |
700 | CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator()); | |
701 | size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get()); | |
702 | result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length()); | |
703 | CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length()); | |
704 | CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length()); | |
705 | CFDataSetLength(CFMutableDataRef(result), length); | |
706 | break; | |
707 | } | |
708 | case kSecKeyOperationTypeDecrypt: { | |
709 | CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm); | |
710 | decryptContext.key(keyItem->key()); | |
711 | decryptContext.padding(paddingAlgorithm); | |
b04fe171 | 712 | decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, key->credentialType)); |
fa7225c8 A |
713 | CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator()); |
714 | size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)), | |
715 | output.get(), remainingData.get()); | |
716 | result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length()); | |
717 | CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length()); | |
718 | CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length()); | |
719 | CFDataSetLength(CFMutableDataRef(result), length); | |
720 | break; | |
721 | } | |
722 | case kSecKeyOperationTypeKeyExchange: { | |
723 | CFIndex requestedLength = 0; | |
724 | CssmData sharedInfo; | |
725 | switch (baseAlgorithm) { | |
726 | case CSSM_ALGID_ECDH: | |
727 | requestedLength = (keyItem->key().header().LogicalKeySizeInBits + 7) / 8; | |
728 | break; | |
729 | case CSSM_ALGID_ECDH_X963_KDF: | |
730 | CFDictionaryRef params = CFRef<CFDictionaryRef>::check(in2, errSecParam); | |
731 | CFTypeRef value = params ? CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterRequestedSize) : NULL; | |
732 | if (value == NULL || CFGetTypeID(value) != CFNumberGetTypeID() || | |
733 | !CFNumberGetValue(CFNumberRef(value), kCFNumberCFIndexType, &requestedLength)) { | |
734 | MacOSError::throwMe(errSecParam); | |
735 | } | |
736 | value = CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterSharedInfo); | |
737 | if (value != NULL && CFGetTypeID(value) == CFDataGetTypeID()) { | |
738 | sharedInfo = CssmData(CFDataRef(value)); | |
739 | } | |
740 | break; | |
741 | } | |
742 | ||
743 | CssmClient::DeriveKey derive(keyItem->csp(), baseAlgorithm, CSSM_ALGID_AES, uint32(requestedLength * 8)); | |
744 | derive.key(keyItem->key()); | |
745 | derive.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE, kSecCredentialTypeDefault)); | |
746 | derive.salt(sharedInfo); | |
747 | CssmData param(CFRef<CFDataRef>::check(in1, errSecParam)); | |
748 | Key derivedKey = derive(¶m, KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE)); | |
749 | ||
750 | // Export raw data of newly derived key (by wrapping with an empty key). | |
751 | CssmClient::WrapKey wrapper(keyItem->csp(), CSSM_ALGID_NONE); | |
752 | Key wrappedKey = wrapper(derivedKey); | |
753 | result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)wrappedKey->data(), CFIndex(wrappedKey->length())); | |
754 | break; | |
755 | } | |
756 | default: | |
757 | break; | |
758 | } | |
759 | ||
760 | END_SECKEYAPI | |
761 | } | |
762 | ||
b04fe171 | 763 | static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) { |
fa7225c8 A |
764 | CFErrorRef *error; |
765 | BEGIN_SECKEYAPI(Boolean, false) | |
766 | ||
767 | result = key1->key->equal(*key2->key); | |
768 | ||
769 | END_SECKEYAPI | |
770 | } | |
771 | ||
b04fe171 A |
772 | static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) { |
773 | BEGIN_SECKEYAPI(Boolean, false) | |
774 | ||
775 | if (CFEqual(name, kSecUseAuthenticationUI)) { | |
776 | key->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI; | |
777 | result = true; | |
778 | } else { | |
779 | result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name); | |
780 | } | |
781 | ||
782 | END_SECKEYAPI | |
783 | } | |
784 | ||
fa7225c8 A |
785 | const SecKeyDescriptor kSecCDSAKeyDescriptor = { |
786 | .version = kSecKeyDescriptorVersion, | |
787 | .name = "CDSAKey", | |
788 | ||
789 | .init = SecCDSAKeyInit, | |
790 | .destroy = SecCDSAKeyDestroy, | |
791 | .blockSize = SecCDSAKeyGetBlockSize, | |
792 | .getAlgorithmID = SecCDSAKeyGetAlgorithmId, | |
793 | .copyDictionary = SecCDSAKeyCopyAttributeDictionary, | |
794 | .copyPublic = SecCDSAKeyCopyPublicBytes, | |
795 | .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation, | |
796 | .copyPublicKey = SecCDSAKeyCopyPublicKey, | |
797 | .copyOperationResult = SecCDSAKeyCopyOperationResult, | |
b04fe171 A |
798 | .isEqual = SecCDSAKeyIsEqual, |
799 | .setParameter = SecCDSAKeySetParameter, | |
fa7225c8 A |
800 | }; |
801 | ||
802 | namespace Security { | |
803 | namespace KeychainCore { | |
804 | SecCFObject *KeyItem::fromSecKeyRef(CFTypeRef ptr) { | |
805 | if (ptr == NULL || CFGetTypeID(ptr) != SecKeyGetTypeID()) { | |
806 | return NULL; | |
807 | } | |
808 | ||
809 | SecKeyRef key = static_cast<SecKeyRef>(const_cast<void *>(ptr)); | |
810 | if (key->key_class == &kSecCDSAKeyDescriptor) { | |
811 | return static_cast<SecCFObject *>(key->key); | |
812 | } | |
813 | ||
814 | if (key->cdsaKey == NULL) { | |
815 | // Create CDSA key from exported data of existing key. | |
816 | CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL); | |
817 | CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key); | |
818 | if (keyData && keyAttributes) { | |
819 | key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL); | |
820 | } | |
821 | } | |
822 | ||
823 | return (key->cdsaKey != NULL) ? key->cdsaKey->key : NULL; | |
824 | } | |
825 | ||
826 | // You need to hold this key's MutexForObject when you run this | |
827 | void KeyItem::attachSecKeyRef() const { | |
828 | SecKeyRef key = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, reinterpret_cast<const uint8_t *>(this), 0, 0); | |
829 | key->key->mWeakSecKeyRef = key; | |
830 | } | |
831 | ||
832 | } | |
833 | } | |
834 | ||
835 | extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref); | |
836 | Boolean SecKeyIsCDSAKey(SecKeyRef ref) { | |
837 | return ref->key_class == &kSecCDSAKeyDescriptor; | |
838 | } | |
839 | ||
840 | ||
427c49bc | 841 | static OSStatus SecKeyCreatePairInternal( |
b1ab9ed8 A |
842 | SecKeychainRef keychainRef, |
843 | CSSM_ALGORITHMS algorithm, | |
844 | uint32 keySizeInBits, | |
845 | CSSM_CC_HANDLE contextHandle, | |
846 | CSSM_KEYUSE publicKeyUsage, | |
847 | uint32 publicKeyAttr, | |
848 | CSSM_KEYUSE privateKeyUsage, | |
849 | uint32 privateKeyAttr, | |
850 | SecAccessRef initialAccess, | |
851 | SecKeyRef* publicKeyRef, | |
852 | SecKeyRef* privateKeyRef) | |
853 | { | |
854 | BEGIN_SECAPI | |
855 | ||
fa7225c8 A |
856 | Keychain keychain; |
857 | SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>")); | |
858 | SecPointer<KeyItem> pubItem, privItem; | |
859 | if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) { | |
860 | keychain = Keychain::optional(keychainRef); | |
fa7225c8 | 861 | } |
866f8763 A |
862 | StMaybeLock<Mutex> _(keychain ? keychain->getKeychainMutex() : NULL); |
863 | KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, | |
864 | privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); | |
b1ab9ed8 A |
865 | |
866 | // Return the generated keys. | |
867 | if (publicKeyRef) | |
868 | *publicKeyRef = pubItem->handle(); | |
869 | if (privateKeyRef) | |
870 | *privateKeyRef = privItem->handle(); | |
871 | ||
872 | END_SECAPI | |
873 | } | |
874 | ||
427c49bc A |
875 | OSStatus |
876 | SecKeyCreatePair( | |
877 | SecKeychainRef keychainRef, | |
878 | CSSM_ALGORITHMS algorithm, | |
879 | uint32 keySizeInBits, | |
880 | CSSM_CC_HANDLE contextHandle, | |
881 | CSSM_KEYUSE publicKeyUsage, | |
882 | uint32 publicKeyAttr, | |
883 | CSSM_KEYUSE privateKeyUsage, | |
884 | uint32 privateKeyAttr, | |
885 | SecAccessRef initialAccess, | |
886 | SecKeyRef* publicKeyRef, | |
887 | SecKeyRef* privateKeyRef) | |
888 | { | |
889 | OSStatus result = SecKeyCreatePairInternal(keychainRef, algorithm, keySizeInBits, contextHandle, publicKeyUsage, | |
890 | publicKeyAttr, privateKeyUsage, privateKeyAttr, initialAccess, publicKeyRef, privateKeyRef); | |
5c19dc3a | 891 | |
427c49bc A |
892 | return result; |
893 | } | |
894 | ||
895 | ||
896 | ||
b1ab9ed8 A |
897 | OSStatus |
898 | SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey) | |
899 | { | |
900 | BEGIN_SECAPI | |
901 | ||
902 | Required(cssmKey) = KeyItem::required(key)->key(); | |
903 | ||
904 | END_SECAPI | |
905 | } | |
906 | ||
907 | ||
908 | // | |
909 | // Private APIs | |
910 | // | |
911 | ||
866f8763 A |
912 | static ModuleNexus<Mutex> gSecReturnedKeyCSPsMutex; |
913 | static std::set<CssmClient::CSP> gSecReturnedKeyCSPs; | |
914 | ||
b1ab9ed8 A |
915 | OSStatus |
916 | SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) | |
917 | { | |
918 | BEGIN_SECAPI | |
919 | ||
920 | SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); | |
866f8763 A |
921 | |
922 | // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). | |
923 | // Keep a global pointer to it to force the CSP to stay live forever. | |
924 | CssmClient::CSP returnedKeyCSP = keyItem->csp(); | |
925 | { | |
926 | StLock<Mutex> _(gSecReturnedKeyCSPsMutex()); | |
927 | gSecReturnedKeyCSPs.insert(returnedKeyCSP); | |
928 | } | |
929 | Required(cspHandle) = returnedKeyCSP->handle(); | |
b1ab9ed8 A |
930 | |
931 | END_SECAPI | |
932 | } | |
933 | ||
934 | /* deprecated as of 10.8 */ | |
935 | OSStatus | |
936 | SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) | |
937 | { | |
5c19dc3a | 938 | BEGIN_SECAPI |
b1ab9ed8 A |
939 | |
940 | SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); | |
941 | Required(algid) = &keyItem->algorithmIdentifier(); | |
942 | ||
943 | END_SECAPI | |
944 | } | |
945 | ||
b1ab9ed8 A |
946 | OSStatus |
947 | SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength) | |
948 | { | |
949 | BEGIN_SECAPI | |
950 | ||
951 | SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); | |
952 | Required(strength) = keyItem->strengthInBits(algid); | |
953 | ||
954 | END_SECAPI | |
955 | } | |
956 | ||
957 | OSStatus | |
958 | SecKeyGetCredentials( | |
959 | SecKeyRef keyRef, | |
960 | CSSM_ACL_AUTHORIZATION_TAG operation, | |
961 | SecCredentialType credentialType, | |
962 | const CSSM_ACCESS_CREDENTIALS **outCredentials) | |
963 | { | |
964 | BEGIN_SECAPI | |
965 | ||
966 | SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); | |
967 | Required(outCredentials) = keyItem->getCredentials(operation, credentialType); | |
968 | ||
969 | END_SECAPI | |
970 | } | |
971 | ||
972 | OSStatus | |
973 | SecKeyImportPair( | |
974 | SecKeychainRef keychainRef, | |
975 | const CSSM_KEY *publicCssmKey, | |
976 | const CSSM_KEY *privateCssmKey, | |
977 | SecAccessRef initialAccess, | |
978 | SecKeyRef* publicKey, | |
979 | SecKeyRef* privateKey) | |
980 | { | |
981 | BEGIN_SECAPI | |
982 | ||
983 | Keychain keychain = Keychain::optional(keychainRef); | |
984 | SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>")); | |
985 | SecPointer<KeyItem> pubItem, privItem; | |
986 | ||
987 | KeyItem::importPair(keychain, | |
988 | Required(publicCssmKey), | |
989 | Required(privateCssmKey), | |
990 | theAccess, | |
991 | pubItem, | |
992 | privItem); | |
993 | ||
994 | // Return the generated keys. | |
995 | if (publicKey) | |
996 | *publicKey = pubItem->handle(); | |
997 | if (privateKey) | |
998 | *privateKey = privItem->handle(); | |
999 | ||
1000 | END_SECAPI | |
1001 | } | |
1002 | ||
427c49bc | 1003 | static OSStatus |
b1ab9ed8 A |
1004 | SecKeyGenerateWithAttributes( |
1005 | SecKeychainAttributeList* attrList, | |
1006 | SecKeychainRef keychainRef, | |
1007 | CSSM_ALGORITHMS algorithm, | |
1008 | uint32 keySizeInBits, | |
1009 | CSSM_CC_HANDLE contextHandle, | |
1010 | CSSM_KEYUSE keyUsage, | |
1011 | uint32 keyAttr, | |
1012 | SecAccessRef initialAccess, | |
1013 | SecKeyRef* keyRef) | |
1014 | { | |
1015 | BEGIN_SECAPI | |
1016 | ||
1017 | Keychain keychain; | |
1018 | SecPointer<Access> theAccess; | |
1019 | ||
1020 | if (keychainRef) | |
1021 | keychain = KeychainImpl::required(keychainRef); | |
1022 | if (initialAccess) | |
1023 | theAccess = Access::required(initialAccess); | |
1024 | ||
1025 | SecPointer<KeyItem> item = KeyItem::generateWithAttributes(attrList, | |
1026 | keychain, | |
1027 | algorithm, | |
1028 | keySizeInBits, | |
1029 | contextHandle, | |
1030 | keyUsage, | |
1031 | keyAttr, | |
1032 | theAccess); | |
1033 | ||
1034 | // Return the generated key. | |
1035 | if (keyRef) | |
1036 | *keyRef = item->handle(); | |
1037 | ||
1038 | END_SECAPI | |
1039 | } | |
1040 | ||
1041 | OSStatus | |
1042 | SecKeyGenerate( | |
1043 | SecKeychainRef keychainRef, | |
1044 | CSSM_ALGORITHMS algorithm, | |
1045 | uint32 keySizeInBits, | |
1046 | CSSM_CC_HANDLE contextHandle, | |
1047 | CSSM_KEYUSE keyUsage, | |
1048 | uint32 keyAttr, | |
1049 | SecAccessRef initialAccess, | |
1050 | SecKeyRef* keyRef) | |
1051 | { | |
1052 | return SecKeyGenerateWithAttributes(NULL, | |
1053 | keychainRef, algorithm, keySizeInBits, | |
1054 | contextHandle, keyUsage, keyAttr, | |
1055 | initialAccess, keyRef); | |
1056 | } | |
1057 | ||
b1ab9ed8 A |
1058 | /* new in 10.6 */ |
1059 | /* Generate a floating key reference from a CSSM_KEY */ | |
1060 | OSStatus | |
1061 | SecKeyCreateWithCSSMKey(const CSSM_KEY *cssmKey, | |
1062 | SecKeyRef *keyRef) | |
1063 | { | |
1064 | BEGIN_SECAPI | |
1065 | ||
1066 | Required(cssmKey); | |
d8f41ccd A |
1067 | if(cssmKey->KeyData.Length == 0){ |
1068 | MacOSError::throwMe(errSecInvalidAttributeKeyLength); | |
1069 | } | |
1070 | if(cssmKey->KeyData.Data == NULL){ | |
1071 | MacOSError::throwMe(errSecInvalidPointer); | |
1072 | } | |
b1ab9ed8 A |
1073 | CssmClient::CSP csp(cssmKey->KeyHeader.CspId); |
1074 | CssmClient::Key key(csp, *cssmKey); | |
1075 | KeyItem *item = new KeyItem(key); | |
1076 | ||
1077 | // Return the generated key. | |
1078 | if (keyRef) | |
fa7225c8 | 1079 | *keyRef = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, (const uint8_t *)item, 0, 0); |
b1ab9ed8 A |
1080 | |
1081 | END_SECAPI | |
1082 | } | |
1083 | ||
1084 | ||
1085 | ||
1086 | static u_int32_t ConvertCFStringToInteger(CFStringRef ref) | |
1087 | { | |
1088 | if (ref == NULL) | |
1089 | { | |
1090 | return 0; | |
1091 | } | |
1092 | ||
1093 | // figure out the size of the string | |
427c49bc | 1094 | CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8); |
866f8763 A |
1095 | char *buffer = (char *)malloc(numChars); |
1096 | if (NULL == buffer) { | |
1097 | UnixError::throwMe(ENOMEM); | |
1098 | } | |
b1ab9ed8 A |
1099 | if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8)) |
1100 | { | |
866f8763 | 1101 | free(buffer); |
427c49bc | 1102 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
1103 | } |
1104 | ||
866f8763 A |
1105 | u_int32_t result = atoi(buffer); |
1106 | free(buffer); | |
1107 | return result; | |
b1ab9ed8 A |
1108 | } |
1109 | ||
1110 | ||
1111 | ||
1112 | static OSStatus CheckAlgorithmType(CFDictionaryRef parameters, CSSM_ALGORITHMS &algorithms) | |
1113 | { | |
1114 | // figure out the algorithm to use | |
1115 | CFStringRef ktype = (CFStringRef) CFDictionaryGetValue(parameters, kSecAttrKeyType); | |
1116 | if (ktype == NULL) | |
1117 | { | |
1118 | return errSecParam; | |
1119 | } | |
1120 | ||
1121 | if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { | |
1122 | algorithms = CSSM_ALGID_RSA; | |
427c49bc A |
1123 | return errSecSuccess; |
1124 | } else if(CFEqual(ktype, kSecAttrKeyTypeECDSA) || | |
1125 | CFEqual(ktype, kSecAttrKeyTypeEC)) { | |
b1ab9ed8 | 1126 | algorithms = CSSM_ALGID_ECDSA; |
427c49bc | 1127 | return errSecSuccess; |
b1ab9ed8 A |
1128 | } else if(CFEqual(ktype, kSecAttrKeyTypeAES)) { |
1129 | algorithms = CSSM_ALGID_AES; | |
427c49bc | 1130 | return errSecSuccess; |
b1ab9ed8 A |
1131 | } else if(CFEqual(ktype, kSecAttrKeyType3DES)) { |
1132 | algorithms = CSSM_ALGID_3DES; | |
427c49bc | 1133 | return errSecSuccess; |
b1ab9ed8 A |
1134 | } else { |
1135 | return errSecUnsupportedAlgorithm; | |
1136 | } | |
1137 | } | |
1138 | ||
1139 | ||
1140 | ||
1141 | static OSStatus GetKeySize(CFDictionaryRef parameters, CSSM_ALGORITHMS algorithms, uint32 &keySizeInBits) | |
1142 | { | |
1143 | ||
1144 | // get the key size and check it for validity | |
1145 | CFTypeRef ref = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); | |
1146 | ||
1147 | keySizeInBits = kSecDefaultKeySize; | |
1148 | ||
1149 | CFTypeID bitSizeType = CFGetTypeID(ref); | |
1150 | if (bitSizeType == CFStringGetTypeID()) | |
1151 | keySizeInBits = ConvertCFStringToInteger((CFStringRef) ref); | |
1152 | else if (bitSizeType == CFNumberGetTypeID()) | |
1153 | CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &keySizeInBits); | |
1154 | else return errSecParam; | |
1155 | ||
1156 | ||
1157 | switch (algorithms) { | |
1158 | case CSSM_ALGID_ECDSA: | |
1159 | if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecp256r1; | |
427c49bc | 1160 | if(keySizeInBits == kSecp192r1 || keySizeInBits == kSecp256r1 || keySizeInBits == kSecp384r1 || keySizeInBits == kSecp521r1 ) return errSecSuccess; |
b1ab9ed8 A |
1161 | break; |
1162 | case CSSM_ALGID_RSA: | |
1163 | if(keySizeInBits % 8) return errSecParam; | |
1164 | if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = 2048; | |
427c49bc | 1165 | if(keySizeInBits >= kSecRSAMin && keySizeInBits <= kSecRSAMax) return errSecSuccess; |
b1ab9ed8 A |
1166 | break; |
1167 | case CSSM_ALGID_AES: | |
1168 | if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecAES128; | |
427c49bc | 1169 | if(keySizeInBits == kSecAES128 || keySizeInBits == kSecAES192 || keySizeInBits == kSecAES256) return errSecSuccess; |
b1ab9ed8 A |
1170 | break; |
1171 | case CSSM_ALGID_3DES: | |
1172 | if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSec3DES192; | |
427c49bc | 1173 | if(keySizeInBits == kSec3DES192) return errSecSuccess; |
b1ab9ed8 A |
1174 | break; |
1175 | default: | |
1176 | break; | |
1177 | } | |
1178 | return errSecParam; | |
1179 | } | |
1180 | ||
1181 | ||
1182 | ||
1183 | enum AttributeType | |
1184 | { | |
1185 | kStringType, | |
1186 | kBooleanType, | |
1187 | kIntegerType | |
1188 | }; | |
1189 | ||
1190 | ||
1191 | ||
1192 | struct ParameterAttribute | |
1193 | { | |
5c19dc3a | 1194 | const CFStringRef *name; |
b1ab9ed8 A |
1195 | AttributeType type; |
1196 | }; | |
1197 | ||
1198 | ||
1199 | ||
1200 | static ParameterAttribute gAttributes[] = | |
1201 | { | |
1202 | { | |
1203 | &kSecAttrLabel, | |
1204 | kStringType | |
1205 | }, | |
1206 | { | |
1207 | &kSecAttrIsPermanent, | |
1208 | kBooleanType | |
1209 | }, | |
1210 | { | |
1211 | &kSecAttrApplicationTag, | |
1212 | kStringType | |
1213 | }, | |
1214 | { | |
1215 | &kSecAttrEffectiveKeySize, | |
1216 | kBooleanType | |
1217 | }, | |
1218 | { | |
1219 | &kSecAttrCanEncrypt, | |
1220 | kBooleanType | |
1221 | }, | |
1222 | { | |
1223 | &kSecAttrCanDecrypt, | |
1224 | kBooleanType | |
1225 | }, | |
1226 | { | |
1227 | &kSecAttrCanDerive, | |
1228 | kBooleanType | |
1229 | }, | |
1230 | { | |
1231 | &kSecAttrCanSign, | |
1232 | kBooleanType | |
1233 | }, | |
1234 | { | |
1235 | &kSecAttrCanVerify, | |
1236 | kBooleanType | |
1237 | }, | |
1238 | { | |
1239 | &kSecAttrCanUnwrap, | |
1240 | kBooleanType | |
1241 | } | |
1242 | }; | |
1243 | ||
1244 | const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute); | |
1245 | ||
1246 | static OSStatus ScanDictionaryForParameters(CFDictionaryRef parameters, void* attributePointers[]) | |
1247 | { | |
1248 | int i; | |
1249 | for (i = 0; i < kNumberOfAttributes; ++i) | |
1250 | { | |
1251 | // see if the corresponding tag exists in the dictionary | |
1252 | CFTypeRef value = CFDictionaryGetValue(parameters, *(gAttributes[i].name)); | |
1253 | if (value != NULL) | |
1254 | { | |
1255 | switch (gAttributes[i].type) | |
1256 | { | |
1257 | case kStringType: | |
1258 | // just return the value | |
1259 | *(CFTypeRef*) attributePointers[i] = value; | |
1260 | break; | |
1261 | ||
1262 | case kBooleanType: | |
1263 | { | |
1264 | CFBooleanRef bRef = (CFBooleanRef) value; | |
1265 | *(bool*) attributePointers[i] = CFBooleanGetValue(bRef); | |
1266 | } | |
1267 | break; | |
1268 | ||
1269 | case kIntegerType: | |
1270 | { | |
1271 | CFNumberRef nRef = (CFNumberRef) value; | |
1272 | CFNumberGetValue(nRef, kCFNumberSInt32Type, attributePointers[i]); | |
1273 | } | |
1274 | break; | |
1275 | } | |
1276 | } | |
1277 | } | |
1278 | ||
427c49bc | 1279 | return errSecSuccess; |
b1ab9ed8 A |
1280 | } |
1281 | ||
1282 | ||
1283 | ||
1284 | static OSStatus GetKeyParameters(CFDictionaryRef parameters, int keySize, bool isPublic, CSSM_KEYUSE &keyUse, uint32 &attrs, CFTypeRef &labelRef, CFDataRef &applicationTagRef) | |
1285 | { | |
1286 | // establish default values | |
1287 | labelRef = NULL; | |
1288 | bool isPermanent = false; | |
1289 | applicationTagRef = NULL; | |
1290 | CFTypeRef effectiveKeySize = NULL; | |
1291 | bool canDecrypt = isPublic ? false : true; | |
1292 | bool canEncrypt = !canDecrypt; | |
1293 | bool canDerive = true; | |
1294 | bool canSign = isPublic ? false : true; | |
1295 | bool canVerify = !canSign; | |
1296 | bool canUnwrap = isPublic ? false : true; | |
1297 | attrs = CSSM_KEYATTR_EXTRACTABLE; | |
1298 | keyUse = 0; | |
1299 | ||
1300 | void* attributePointers[] = {&labelRef, &isPermanent, &applicationTagRef, &effectiveKeySize, &canEncrypt, &canDecrypt, | |
1301 | &canDerive, &canSign, &canVerify, &canUnwrap}; | |
1302 | ||
1303 | // look for modifiers in the general dictionary | |
1304 | OSStatus result = ScanDictionaryForParameters(parameters, attributePointers); | |
427c49bc | 1305 | if (result != errSecSuccess) |
b1ab9ed8 A |
1306 | { |
1307 | return result; | |
1308 | } | |
1309 | ||
1310 | // see if we have anything which modifies the defaults | |
1311 | CFTypeRef key; | |
1312 | if (isPublic) | |
1313 | { | |
1314 | key = kSecPublicKeyAttrs; | |
1315 | } | |
1316 | else | |
1317 | { | |
1318 | key = kSecPrivateKeyAttrs; | |
1319 | } | |
1320 | ||
1321 | CFTypeRef dType = CFDictionaryGetValue(parameters, key); | |
1322 | if (dType != NULL) | |
1323 | { | |
1324 | // this had better be a dictionary | |
1325 | if (CFGetTypeID(dType) != CFDictionaryGetTypeID()) | |
1326 | { | |
1327 | return errSecParam; | |
1328 | } | |
1329 | ||
1330 | // pull any additional parameters out of this dictionary | |
427c49bc A |
1331 | result = ScanDictionaryForParameters((CFDictionaryRef)dType, attributePointers); |
1332 | if (result != errSecSuccess) | |
b1ab9ed8 A |
1333 | { |
1334 | return result; | |
1335 | } | |
1336 | } | |
1337 | ||
1338 | // figure out the key usage | |
1339 | keyUse = 0; | |
1340 | if (canDecrypt) | |
1341 | { | |
1342 | keyUse |= CSSM_KEYUSE_DECRYPT; | |
1343 | } | |
1344 | ||
1345 | if (canEncrypt) | |
1346 | { | |
1347 | keyUse |= CSSM_KEYUSE_ENCRYPT; | |
1348 | } | |
1349 | ||
1350 | if (canDerive) | |
1351 | { | |
1352 | keyUse |= CSSM_KEYUSE_DERIVE; | |
1353 | } | |
1354 | ||
1355 | if (canSign) | |
1356 | { | |
1357 | keyUse |= CSSM_KEYUSE_SIGN; | |
1358 | } | |
1359 | ||
1360 | if (canVerify) | |
1361 | { | |
1362 | keyUse |= CSSM_KEYUSE_VERIFY; | |
1363 | } | |
1364 | ||
1365 | if (canUnwrap) | |
1366 | { | |
1367 | keyUse |= CSSM_KEYUSE_UNWRAP; | |
1368 | } | |
1369 | ||
1370 | // public key is always extractable; | |
1371 | // private key is extractable by default unless explicitly set to false | |
1372 | CFTypeRef value = NULL; | |
1373 | if (!isPublic && CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value) && value) | |
1374 | { | |
1375 | Boolean keyIsExtractable = CFEqual(kCFBooleanTrue, value); | |
1376 | if (!keyIsExtractable) | |
1377 | attrs = 0; | |
1378 | } | |
1379 | ||
fa7225c8 A |
1380 | if (isPermanent) { |
1381 | attrs |= CSSM_KEYATTR_PERMANENT; | |
1382 | } | |
b1ab9ed8 | 1383 | |
427c49bc | 1384 | return errSecSuccess; |
b1ab9ed8 A |
1385 | } |
1386 | ||
1387 | ||
1388 | ||
1389 | static OSStatus MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters, | |
1390 | CSSM_ALGORITHMS &algorithms, | |
1391 | uint32 &keySizeInBits, | |
1392 | CSSM_KEYUSE &publicKeyUse, | |
1393 | uint32 &publicKeyAttr, | |
1394 | CFTypeRef &publicKeyLabelRef, | |
1395 | CFDataRef &publicKeyAttributeTagRef, | |
1396 | CSSM_KEYUSE &privateKeyUse, | |
1397 | uint32 &privateKeyAttr, | |
1398 | CFTypeRef &privateKeyLabelRef, | |
1399 | CFDataRef &privateKeyAttributeTagRef, | |
1400 | SecAccessRef &initialAccess) | |
1401 | { | |
1402 | OSStatus result; | |
1403 | ||
1404 | result = CheckAlgorithmType(parameters, algorithms); | |
427c49bc | 1405 | if (result != errSecSuccess) |
b1ab9ed8 A |
1406 | { |
1407 | return result; | |
1408 | } | |
1409 | ||
1410 | result = GetKeySize(parameters, algorithms, keySizeInBits); | |
427c49bc | 1411 | if (result != errSecSuccess) |
b1ab9ed8 A |
1412 | { |
1413 | return result; | |
1414 | } | |
1415 | ||
427c49bc A |
1416 | result = GetKeyParameters(parameters, keySizeInBits, false, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef); |
1417 | if (result != errSecSuccess) | |
b1ab9ed8 A |
1418 | { |
1419 | return result; | |
1420 | } | |
1421 | ||
427c49bc A |
1422 | result = GetKeyParameters(parameters, keySizeInBits, true, publicKeyUse, publicKeyAttr, publicKeyLabelRef, publicKeyAttributeTagRef); |
1423 | if (result != errSecSuccess) | |
b1ab9ed8 A |
1424 | { |
1425 | return result; | |
1426 | } | |
1427 | ||
1428 | if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&initialAccess)) | |
1429 | { | |
1430 | initialAccess = NULL; | |
1431 | } | |
1432 | else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess)) | |
1433 | { | |
427c49bc | 1434 | return errSecParam; |
b1ab9ed8 A |
1435 | } |
1436 | ||
427c49bc | 1437 | return errSecSuccess; |
b1ab9ed8 A |
1438 | } |
1439 | ||
1440 | ||
1441 | ||
1442 | static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef tag) | |
1443 | { | |
1444 | int numToModify = 0; | |
1445 | if (label != NULL) | |
1446 | { | |
1447 | numToModify += 1; | |
1448 | } | |
1449 | ||
1450 | if (tag != NULL) | |
1451 | { | |
1452 | numToModify += 1; | |
1453 | } | |
1454 | ||
1455 | if (numToModify == 0) | |
1456 | { | |
427c49bc | 1457 | return errSecSuccess; |
b1ab9ed8 A |
1458 | } |
1459 | ||
1460 | SecKeychainAttributeList attrList; | |
1461 | SecKeychainAttribute attributes[numToModify]; | |
1462 | ||
1463 | int i = 0; | |
866f8763 | 1464 | void *data = NULL; |
b1ab9ed8 A |
1465 | |
1466 | if (label != NULL) | |
1467 | { | |
1468 | if (CFStringGetTypeID() == CFGetTypeID(label)) { | |
1469 | CFStringRef label_string = static_cast<CFStringRef>(label); | |
1470 | attributes[i].tag = kSecKeyPrintName; | |
1471 | attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8); | |
1472 | if (NULL == attributes[i].data) { | |
1473 | CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8); | |
866f8763 | 1474 | data = attributes[i].data = malloc((size_t)buffer_length); |
b1ab9ed8 A |
1475 | if (NULL == attributes[i].data) { |
1476 | UnixError::throwMe(ENOMEM); | |
1477 | } | |
1478 | if (!CFStringGetCString(label_string, static_cast<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) { | |
866f8763 | 1479 | free(data); |
427c49bc | 1480 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
1481 | } |
1482 | } | |
427c49bc | 1483 | attributes[i].length = (UInt32)strlen(static_cast<char *>(attributes[i].data)); |
b1ab9ed8 A |
1484 | } else if (CFDataGetTypeID() == CFGetTypeID(label)) { |
1485 | // 10.6 bug compatibility | |
1486 | CFDataRef label_data = static_cast<CFDataRef>(label); | |
1487 | attributes[i].tag = kSecKeyLabel; | |
1488 | attributes[i].data = (void*) CFDataGetBytePtr(label_data); | |
427c49bc | 1489 | attributes[i].length = (UInt32)CFDataGetLength(label_data); |
b1ab9ed8 | 1490 | } else { |
427c49bc | 1491 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
1492 | } |
1493 | i++; | |
1494 | } | |
1495 | ||
1496 | if (tag != NULL) | |
1497 | { | |
1498 | attributes[i].tag = kSecKeyApplicationTag; | |
1499 | attributes[i].data = (void*) CFDataGetBytePtr(tag); | |
427c49bc | 1500 | attributes[i].length = (UInt32)CFDataGetLength(tag); |
b1ab9ed8 A |
1501 | i++; |
1502 | } | |
1503 | ||
1504 | attrList.count = numToModify; | |
1505 | attrList.attr = attributes; | |
866f8763 A |
1506 | |
1507 | OSStatus result = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL); | |
1508 | if (data) | |
1509 | { | |
1510 | free(data); | |
1511 | } | |
1512 | ||
1513 | return result; | |
b1ab9ed8 A |
1514 | } |
1515 | ||
1516 | ||
fa7225c8 A |
1517 | static CFTypeRef GetAttributeFromParams(CFDictionaryRef parameters, CFTypeRef attr, CFTypeRef subParams) { |
1518 | if (subParams != NULL) { | |
1519 | CFDictionaryRef subParamsDict = (CFDictionaryRef)CFDictionaryGetValue(parameters, subParams); | |
1520 | if (subParamsDict != NULL) { | |
1521 | CFTypeRef value = CFDictionaryGetValue(subParamsDict, attr); | |
1522 | if (value != NULL) { | |
1523 | return value; | |
1524 | } | |
1525 | } | |
1526 | } | |
1527 | return CFDictionaryGetValue(parameters, attr); | |
1528 | } | |
1529 | ||
1530 | extern "C" OSStatus SecKeyGeneratePair_ios(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey); | |
b1ab9ed8 A |
1531 | |
1532 | /* new in 10.6 */ | |
1533 | /* Generate a private/public keypair. */ | |
fa7225c8 A |
1534 | static OSStatus |
1535 | SecKeyGeneratePairInternal( | |
1536 | bool alwaysPermanent, | |
b1ab9ed8 A |
1537 | CFDictionaryRef parameters, |
1538 | SecKeyRef *publicKey, | |
1539 | SecKeyRef *privateKey) | |
1540 | { | |
1541 | BEGIN_SECAPI | |
1542 | ||
1543 | Required(parameters); | |
fa7225c8 A |
1544 | Required(publicKey); |
1545 | Required(privateKey); | |
1546 | ||
1547 | CFTypeRef tokenID = GetAttributeFromParams(parameters, kSecAttrTokenID, NULL); | |
1548 | CFTypeRef noLegacy = GetAttributeFromParams(parameters, kSecAttrNoLegacy, NULL); | |
1549 | CFTypeRef sync = GetAttributeFromParams(parameters, kSecAttrSynchronizable, kSecPrivateKeyAttrs); | |
1550 | CFTypeRef accessControl = GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPrivateKeyAttrs) ?: | |
1551 | GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPublicKeyAttrs); | |
1552 | CFTypeRef accessGroup = GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPrivateKeyAttrs) ?: | |
1553 | GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPublicKeyAttrs); | |
1554 | ||
1555 | // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain). | |
1556 | if (tokenID != NULL || | |
1557 | (noLegacy != NULL && CFBooleanGetValue((CFBooleanRef)noLegacy)) || | |
1558 | (sync != NULL && CFBooleanGetValue((CFBooleanRef)sync)) || | |
1559 | accessControl != NULL || (accessGroup != NULL && CFEqual(accessGroup, kSecAttrAccessGroupToken))) { | |
1560 | // Generate keys in iOS keychain. | |
1561 | return SecKeyGeneratePair_ios(parameters, publicKey, privateKey); | |
1562 | } | |
b1ab9ed8 A |
1563 | |
1564 | CSSM_ALGORITHMS algorithms; | |
1565 | uint32 keySizeInBits; | |
1566 | CSSM_KEYUSE publicKeyUse; | |
1567 | uint32 publicKeyAttr; | |
1568 | CFTypeRef publicKeyLabelRef; | |
1569 | CFDataRef publicKeyAttributeTagRef; | |
1570 | CSSM_KEYUSE privateKeyUse; | |
1571 | uint32 privateKeyAttr; | |
1572 | CFTypeRef privateKeyLabelRef; | |
1573 | CFDataRef privateKeyAttributeTagRef; | |
1574 | SecAccessRef initialAccess; | |
1575 | SecKeychainRef keychain; | |
1576 | ||
1577 | OSStatus result = MakeKeyGenParametersFromDictionary(parameters, algorithms, keySizeInBits, publicKeyUse, publicKeyAttr, publicKeyLabelRef, | |
1578 | publicKeyAttributeTagRef, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef, | |
1579 | initialAccess); | |
1580 | ||
fa7225c8 | 1581 | if (result != errSecSuccess) { |
b1ab9ed8 A |
1582 | return result; |
1583 | } | |
1584 | ||
1585 | // verify keychain parameter | |
fa7225c8 A |
1586 | keychain = (SecKeychainRef)CFDictionaryGetValue(parameters, kSecUseKeychain); |
1587 | if (keychain != NULL && SecKeychainGetTypeID() != CFGetTypeID(keychain)) { | |
b1ab9ed8 | 1588 | keychain = NULL; |
fa7225c8 A |
1589 | } |
1590 | ||
1591 | if (alwaysPermanent) { | |
1592 | publicKeyAttr |= CSSM_KEYATTR_PERMANENT; | |
1593 | privateKeyAttr |= CSSM_KEYATTR_PERMANENT; | |
1594 | } | |
b1ab9ed8 A |
1595 | |
1596 | // do the key generation | |
1597 | result = SecKeyCreatePair(keychain, algorithms, keySizeInBits, 0, publicKeyUse, publicKeyAttr, privateKeyUse, privateKeyAttr, initialAccess, publicKey, privateKey); | |
fa7225c8 | 1598 | if (result != errSecSuccess) { |
b1ab9ed8 A |
1599 | return result; |
1600 | } | |
1601 | ||
1602 | // set the label and print attributes on the keys | |
fa7225c8 A |
1603 | SetKeyLabelAndTag(*publicKey, publicKeyLabelRef, publicKeyAttributeTagRef); |
1604 | SetKeyLabelAndTag(*privateKey, privateKeyLabelRef, privateKeyAttributeTagRef); | |
b1ab9ed8 A |
1605 | return result; |
1606 | ||
1607 | END_SECAPI | |
1608 | } | |
1609 | ||
b1ab9ed8 | 1610 | OSStatus |
fa7225c8 A |
1611 | SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) { |
1612 | return SecKeyGeneratePairInternal(true, parameters, publicKey, privateKey); | |
1613 | } | |
b1ab9ed8 | 1614 | |
fa7225c8 A |
1615 | SecKeyRef |
1616 | SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) { | |
1617 | SecKeyRef privateKey = NULL, publicKey = NULL; | |
1618 | OSStatus status = SecKeyGeneratePairInternal(false, parameters, &publicKey, &privateKey); | |
1619 | SecError(status, error, CFSTR("failed to generate asymmetric keypair")); | |
1620 | if (publicKey != NULL) { | |
1621 | CFRelease(publicKey); | |
1622 | } | |
1623 | return privateKey; | |
b1ab9ed8 A |
1624 | } |
1625 | ||
427c49bc A |
1626 | OSStatus SecKeyRawVerifyOSX( |
1627 | SecKeyRef key, /* Public key */ | |
1628 | SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ | |
1629 | const uint8_t *signedData, /* signature over this data */ | |
1630 | size_t signedDataLen, /* length of dataToSign */ | |
1631 | const uint8_t *sig, /* signature */ | |
1632 | size_t sigLen) | |
1633 | { | |
1634 | return SecKeyRawVerify(key,padding,signedData,signedDataLen,sig,sigLen); | |
1635 | } | |
1636 | ||
b1ab9ed8 A |
1637 | /* |
1638 | M4 Additions | |
1639 | */ | |
1640 | ||
1641 | static CFTypeRef | |
1642 | utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue) | |
1643 | { | |
1644 | CFTypeRef value = CFDictionaryGetValue(parameters, key); | |
1645 | if (value != NULL) return value; | |
1646 | return defaultValue; | |
1647 | } | |
1648 | ||
1649 | static uint32_t | |
1650 | utilGetNumberFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t defaultValue) | |
1651 | { | |
1652 | uint32_t integerValue; | |
1653 | CFTypeRef value = CFDictionaryGetValue(parameters, key); | |
1654 | if (value != NULL) { | |
1655 | CFNumberRef nRef = (CFNumberRef) value; | |
1656 | CFNumberGetValue(nRef, kCFNumberSInt32Type, &integerValue); | |
1657 | return integerValue; | |
1658 | } | |
1659 | return defaultValue; | |
1660 | } | |
1661 | ||
1662 | static uint32_t | |
1663 | utilGetMaskValFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t maskValue) | |
1664 | { | |
1665 | CFTypeRef value = CFDictionaryGetValue(parameters, key); | |
1666 | if (value != NULL) { | |
1667 | CFBooleanRef bRef = (CFBooleanRef) value; | |
1668 | if(CFBooleanGetValue(bRef)) return maskValue; | |
1669 | } | |
1670 | return 0; | |
1671 | } | |
1672 | ||
1673 | static void | |
1674 | utilGetKeyParametersFromCFDict(CFDictionaryRef parameters, CSSM_ALGORITHMS *algorithm, uint32 *keySizeInBits, CSSM_KEYUSE *keyUsage, CSSM_KEYCLASS *keyClass) | |
1675 | { | |
1676 | CFTypeRef algorithmDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES); | |
1677 | CFTypeRef keyClassDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyClass, kSecAttrKeyClassSymmetric); | |
1678 | ||
1679 | if(CFEqual(algorithmDictValue, kSecAttrKeyTypeAES)) { | |
1680 | *algorithm = CSSM_ALGID_AES; | |
1681 | *keySizeInBits = 128; | |
1682 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1683 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDES)) { | |
1684 | *algorithm = CSSM_ALGID_DES; | |
1685 | *keySizeInBits = 128; | |
1686 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1687 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyType3DES)) { | |
1688 | *algorithm = CSSM_ALGID_3DES_3KEY_EDE; | |
1689 | *keySizeInBits = 128; | |
1690 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1691 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC4)) { | |
1692 | *algorithm = CSSM_ALGID_RC4; | |
1693 | *keySizeInBits = 128; | |
1694 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1695 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC2)) { | |
1696 | *algorithm = CSSM_ALGID_RC2; | |
1697 | *keySizeInBits = 128; | |
1698 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1699 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeCAST)) { | |
1700 | *algorithm = CSSM_ALGID_CAST; | |
1701 | *keySizeInBits = 128; | |
1702 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1703 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRSA)) { | |
1704 | *algorithm = CSSM_ALGID_RSA; | |
1705 | *keySizeInBits = 128; | |
1706 | *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; | |
1707 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDSA)) { | |
1708 | *algorithm = CSSM_ALGID_DSA; | |
1709 | *keySizeInBits = 128; | |
1710 | *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; | |
427c49bc A |
1711 | } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeECDSA) || |
1712 | CFEqual(algorithmDictValue, kSecAttrKeyTypeEC)) { | |
b1ab9ed8 A |
1713 | *algorithm = CSSM_ALGID_ECDSA; |
1714 | *keySizeInBits = 128; | |
1715 | *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; | |
1716 | } else { | |
1717 | *algorithm = CSSM_ALGID_AES; | |
1718 | *keySizeInBits = 128; | |
1719 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1720 | } | |
1721 | ||
1722 | if(CFEqual(keyClassDictValue, kSecAttrKeyClassPublic)) { | |
1723 | *keyClass = CSSM_KEYCLASS_PUBLIC_KEY; | |
1724 | } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassPrivate)) { | |
1725 | *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; | |
1726 | } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassSymmetric)) { | |
1727 | *keyClass = CSSM_KEYCLASS_SESSION_KEY; | |
1728 | } | |
1729 | ||
1730 | *keySizeInBits = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, *keySizeInBits); | |
1731 | *keyUsage = utilGetMaskValFromCFDict(parameters, kSecAttrCanEncrypt, CSSM_KEYUSE_ENCRYPT) | | |
1732 | utilGetMaskValFromCFDict(parameters, kSecAttrCanDecrypt, CSSM_KEYUSE_DECRYPT) | | |
1733 | utilGetMaskValFromCFDict(parameters, kSecAttrCanWrap, CSSM_KEYUSE_WRAP) | | |
1734 | utilGetMaskValFromCFDict(parameters, kSecAttrCanUnwrap, CSSM_KEYUSE_UNWRAP); | |
1735 | ||
1736 | ||
1737 | if(*keyClass == CSSM_KEYCLASS_PRIVATE_KEY || *keyClass == CSSM_KEYCLASS_PUBLIC_KEY) { | |
1738 | *keyUsage |= utilGetMaskValFromCFDict(parameters, kSecAttrCanSign, CSSM_KEYUSE_SIGN) | | |
1739 | utilGetMaskValFromCFDict(parameters, kSecAttrCanVerify, CSSM_KEYUSE_VERIFY); | |
1740 | } | |
1741 | ||
1742 | if(*keyUsage == 0) { | |
1743 | switch (*keyClass) { | |
1744 | case CSSM_KEYCLASS_PRIVATE_KEY: | |
1745 | *keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN; | |
1746 | break; | |
1747 | case CSSM_KEYCLASS_PUBLIC_KEY: | |
1748 | *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP; | |
1749 | break; | |
1750 | default: | |
1751 | *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY; | |
1752 | break; | |
1753 | } | |
1754 | } | |
1755 | } | |
1756 | ||
1757 | static CFStringRef | |
1758 | utilCopyDefaultKeyLabel(void) | |
1759 | { | |
1760 | // generate a default label from the current date | |
1761 | CFDateRef dateNow = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); | |
1762 | CFStringRef defaultLabel = CFCopyDescription(dateNow); | |
1763 | CFRelease(dateNow); | |
1764 | ||
1765 | return defaultLabel; | |
1766 | } | |
1767 | ||
1768 | SecKeyRef | |
1769 | SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error) | |
1770 | { | |
427c49bc | 1771 | OSStatus result = errSecParam; // default result for an early exit |
b1ab9ed8 A |
1772 | SecKeyRef key = NULL; |
1773 | SecKeychainRef keychain = NULL; | |
1774 | SecAccessRef access; | |
1775 | CFStringRef label; | |
1776 | CFStringRef appLabel; | |
1777 | CFStringRef appTag; | |
1778 | CFStringRef dateLabel = NULL; | |
1779 | ||
1780 | CSSM_ALGORITHMS algorithm; | |
1781 | uint32 keySizeInBits; | |
1782 | CSSM_KEYUSE keyUsage; | |
1783 | uint32 keyAttr = CSSM_KEYATTR_RETURN_DEFAULT; | |
1784 | CSSM_KEYCLASS keyClass; | |
1785 | CFTypeRef value; | |
1786 | Boolean isPermanent; | |
1787 | Boolean isExtractable; | |
1788 | ||
1789 | // verify keychain parameter | |
1790 | if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain)) | |
1791 | keychain = NULL; | |
1792 | else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) { | |
1793 | keychain = NULL; | |
1794 | goto errorExit; | |
1795 | } | |
1796 | else | |
1797 | CFRetain(keychain); | |
1798 | ||
1799 | // verify permanent parameter | |
1800 | if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsPermanent, (const void **)&value)) | |
1801 | isPermanent = false; | |
1802 | else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value))) | |
1803 | goto errorExit; | |
1804 | else | |
1805 | isPermanent = CFEqual(kCFBooleanTrue, value); | |
1806 | if (isPermanent) { | |
1807 | if (keychain == NULL) { | |
1808 | // no keychain was specified, so use the default keychain | |
1809 | result = SecKeychainCopyDefault(&keychain); | |
1810 | } | |
1811 | keyAttr |= CSSM_KEYATTR_PERMANENT; | |
1812 | } | |
1813 | ||
1814 | // verify extractable parameter | |
1815 | if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value)) | |
1816 | isExtractable = true; // default to extractable if value not specified | |
1817 | else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value))) | |
1818 | goto errorExit; | |
1819 | else | |
1820 | isExtractable = CFEqual(kCFBooleanTrue, value); | |
1821 | if (isExtractable) | |
1822 | keyAttr |= CSSM_KEYATTR_EXTRACTABLE; | |
1823 | ||
1824 | // verify access parameter | |
1825 | if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&access)) | |
1826 | access = NULL; | |
1827 | else if (SecAccessGetTypeID() != CFGetTypeID(access)) | |
1828 | goto errorExit; | |
1829 | ||
1830 | // verify label parameter | |
1831 | if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrLabel, (const void **)&label)) | |
1832 | label = (dateLabel = utilCopyDefaultKeyLabel()); // no label provided, so use default | |
1833 | else if (CFStringGetTypeID() != CFGetTypeID(label)) | |
1834 | goto errorExit; | |
1835 | ||
1836 | // verify application label parameter | |
1837 | if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationLabel, (const void **)&appLabel)) | |
1838 | appLabel = (dateLabel) ? dateLabel : (dateLabel = utilCopyDefaultKeyLabel()); | |
1839 | else if (CFStringGetTypeID() != CFGetTypeID(appLabel)) | |
1840 | goto errorExit; | |
1841 | ||
1842 | // verify application tag parameter | |
1843 | if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationTag, (const void **)&appTag)) | |
1844 | appTag = NULL; | |
1845 | else if (CFStringGetTypeID() != CFGetTypeID(appTag)) | |
1846 | goto errorExit; | |
1847 | ||
1848 | utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass); | |
1849 | ||
1850 | if (!keychain) { | |
1851 | // the generated key will not be stored in any keychain | |
1852 | result = SecKeyGenerate(keychain, algorithm, keySizeInBits, 0, keyUsage, keyAttr, access, &key); | |
1853 | } | |
1854 | else { | |
1855 | // we can set the label attributes on the generated key if it's a keychain item | |
866f8763 | 1856 | size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 1; |
b1ab9ed8 | 1857 | char *labelBuf = (char *)malloc(labelBufLen); |
866f8763 | 1858 | size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 1; |
b1ab9ed8 | 1859 | char *appLabelBuf = (char *)malloc(appLabelBufLen); |
866f8763 | 1860 | size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 1; |
b1ab9ed8 A |
1861 | char *appTagBuf = (char *)malloc(appTagBufLen); |
1862 | ||
866f8763 | 1863 | if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8)) |
b1ab9ed8 | 1864 | labelBuf[0]=0; |
866f8763 | 1865 | if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8)) |
b1ab9ed8 | 1866 | appLabelBuf[0]=0; |
866f8763 | 1867 | if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8)) |
b1ab9ed8 A |
1868 | appTagBuf[0]=0; |
1869 | ||
1870 | SecKeychainAttribute attrs[] = { | |
427c49bc A |
1871 | { kSecKeyPrintName, (UInt32)strlen(labelBuf), (char *)labelBuf }, |
1872 | { kSecKeyLabel, (UInt32)strlen(appLabelBuf), (char *)appLabelBuf }, | |
1873 | { kSecKeyApplicationTag, (UInt32)strlen(appTagBuf), (char *)appTagBuf } }; | |
b1ab9ed8 A |
1874 | SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; |
1875 | if (!appTag) --attributes.count; | |
1876 | ||
1877 | result = SecKeyGenerateWithAttributes(&attributes, | |
1878 | keychain, algorithm, keySizeInBits, 0, | |
1879 | keyUsage, keyAttr, access, &key); | |
1880 | ||
1881 | free(labelBuf); | |
1882 | free(appLabelBuf); | |
1883 | free(appTagBuf); | |
1884 | } | |
1885 | ||
1886 | errorExit: | |
1887 | if (result && error) { | |
1888 | *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, result, NULL); | |
1889 | } | |
1890 | if (dateLabel) | |
1891 | CFRelease(dateLabel); | |
1892 | if (keychain) | |
1893 | CFRelease(keychain); | |
1894 | ||
1895 | return key; | |
1896 | } | |
1897 | ||
1898 | ||
1899 | ||
1900 | SecKeyRef | |
1901 | SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *error) | |
1902 | { | |
1903 | CSSM_ALGORITHMS algorithm; | |
1904 | uint32 keySizeInBits; | |
1905 | CSSM_KEYUSE keyUsage; | |
1906 | CSSM_KEYCLASS keyClass; | |
1907 | CSSM_RETURN crtn; | |
5c19dc3a | 1908 | |
d8f41ccd A |
1909 | if(keyData == NULL || CFDataGetLength(keyData) == 0){ |
1910 | MacOSError::throwMe(errSecUnsupportedKeySize); | |
1911 | } | |
5c19dc3a | 1912 | |
b1ab9ed8 A |
1913 | utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass); |
1914 | ||
1915 | CSSM_CSP_HANDLE cspHandle = cuCspStartup(CSSM_FALSE); // TRUE => CSP, FALSE => CSPDL | |
1916 | ||
1917 | SecKeyImportExportParameters iparam; | |
1918 | memset(&iparam, 0, sizeof(iparam)); | |
1919 | iparam.keyUsage = keyUsage; | |
1920 | ||
fa7225c8 | 1921 | CFRef<CFDataRef> data; |
b1ab9ed8 A |
1922 | SecExternalItemType itype; |
1923 | switch (keyClass) { | |
1924 | case CSSM_KEYCLASS_PRIVATE_KEY: | |
1925 | itype = kSecItemTypePrivateKey; | |
1926 | break; | |
fa7225c8 | 1927 | case CSSM_KEYCLASS_PUBLIC_KEY: { |
b1ab9ed8 | 1928 | itype = kSecItemTypePublicKey; |
fa7225c8 A |
1929 | // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format, |
1930 | // so we have to detect bare format here and extend to full X509 if detected. | |
1931 | data.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm, keySizeInBits, keyData)); | |
1932 | break; | |
1933 | } | |
b1ab9ed8 A |
1934 | case CSSM_KEYCLASS_SESSION_KEY: |
1935 | itype = kSecItemTypeSessionKey; | |
1936 | break; | |
1937 | default: | |
1938 | itype = kSecItemTypeUnknown; | |
1939 | break; | |
1940 | } | |
1941 | ||
1942 | CFMutableArrayRef ka = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
1943 | // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful. | |
fa7225c8 | 1944 | crtn = impExpImportRawKey(data ? CFDataRef(data) : keyData, kSecFormatUnknown, itype, algorithm, NULL, cspHandle, 0, NULL, NULL, ka); |
b1ab9ed8 A |
1945 | if (crtn == CSSM_OK && CFArrayGetCount((CFArrayRef)ka)) { |
1946 | SecKeyRef sk = (SecKeyRef)CFArrayGetValueAtIndex((CFArrayRef)ka, 0); | |
1947 | CFRetain(sk); | |
1948 | CFRelease(ka); | |
1949 | return sk; | |
1950 | } else { | |
866f8763 | 1951 | CFRelease(ka); |
b1ab9ed8 A |
1952 | if (error) { |
1953 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL); | |
1954 | } | |
1955 | return NULL; | |
1956 | } | |
1957 | } | |
1958 | ||
1959 | ||
1960 | void | |
1961 | SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable, dispatch_queue_t deliveryQueue, | |
1962 | SecKeyGeneratePairBlock result) | |
1963 | { | |
1964 | CFDictionaryRef parameters = CFDictionaryCreateCopy(NULL, parametersWhichMightBeMutiable); | |
1965 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
1966 | SecKeyRef publicKey = NULL; | |
1967 | SecKeyRef privateKey = NULL; | |
1968 | OSStatus status = SecKeyGeneratePair(parameters, &publicKey, &privateKey); | |
1969 | dispatch_async(deliveryQueue, ^{ | |
1970 | CFErrorRef error = NULL; | |
427c49bc | 1971 | if (errSecSuccess != status) { |
b1ab9ed8 A |
1972 | error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL); |
1973 | } | |
1974 | result(publicKey, privateKey, error); | |
1975 | if (error) { | |
1976 | CFRelease(error); | |
1977 | } | |
1978 | if (publicKey) { | |
1979 | CFRelease(publicKey); | |
1980 | } | |
1981 | if (privateKey) { | |
1982 | CFRelease(privateKey); | |
1983 | } | |
1984 | CFRelease(parameters); | |
1985 | }); | |
1986 | }); | |
1987 | } | |
1988 | ||
d8f41ccd A |
1989 | static inline void utilClearAndFree(void *p, size_t len) { |
1990 | if(p) { | |
1991 | if(len) bzero(p, len); | |
1992 | free(p); | |
1993 | } | |
1994 | } | |
1995 | ||
b1ab9ed8 A |
1996 | SecKeyRef |
1997 | SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErrorRef *error) | |
1998 | { | |
d8f41ccd A |
1999 | CCPBKDFAlgorithm algorithm; |
2000 | CFIndex passwordLen = 0; | |
2001 | CFDataRef keyData = NULL; | |
b1ab9ed8 | 2002 | char *thePassword = NULL; |
b1ab9ed8 | 2003 | uint8_t *salt = NULL; |
b1ab9ed8 | 2004 | uint8_t *derivedKey = NULL; |
d8f41ccd A |
2005 | size_t saltLen = 0, derivedKeyLen = 0; |
2006 | uint rounds; | |
b1ab9ed8 | 2007 | CFDataRef saltDictValue, algorithmDictValue; |
d8f41ccd | 2008 | SecKeyRef retval = NULL; |
5c19dc3a | 2009 | |
b1ab9ed8 A |
2010 | /* Pick Values from parameters */ |
2011 | ||
2012 | if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) { | |
866f8763 A |
2013 | if(error) { |
2014 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL); | |
2015 | } | |
d8f41ccd | 2016 | goto errOut; |
b1ab9ed8 A |
2017 | } |
2018 | ||
2019 | derivedKeyLen = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, 128); | |
2020 | // This value come in bits but the rest of the code treats it as bytes | |
2021 | derivedKeyLen /= 8; | |
2022 | ||
2023 | algorithmDictValue = (CFDataRef) utilGetStringFromCFDict(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256); | |
2024 | ||
2025 | rounds = utilGetNumberFromCFDict(parameters, kSecAttrRounds, 0); | |
2026 | ||
2027 | /* Convert any remaining parameters and get the password bytes */ | |
2028 | ||
2029 | saltLen = CFDataGetLength(saltDictValue); | |
2030 | if((salt = (uint8_t *) malloc(saltLen)) == NULL) { | |
866f8763 A |
2031 | if(error) { |
2032 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); | |
2033 | } | |
d8f41ccd | 2034 | goto errOut; |
b1ab9ed8 A |
2035 | } |
2036 | ||
2037 | CFDataGetBytes(saltDictValue, CFRangeMake(0, saltLen), (UInt8 *) salt); | |
2038 | ||
2039 | passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1; | |
2040 | if((thePassword = (char *) malloc(passwordLen)) == NULL) { | |
866f8763 A |
2041 | if(error) { |
2042 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); | |
2043 | } | |
d8f41ccd | 2044 | goto errOut; |
b1ab9ed8 A |
2045 | } |
2046 | CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen); | |
2047 | ||
2048 | if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) { | |
866f8763 A |
2049 | if(error) { |
2050 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); | |
2051 | } | |
d8f41ccd | 2052 | goto errOut; |
b1ab9ed8 A |
2053 | } |
2054 | ||
b1ab9ed8 A |
2055 | if(algorithmDictValue == NULL) { |
2056 | algorithm = kCCPRFHmacAlgSHA1; /* default */ | |
2057 | } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA1)) { | |
2058 | algorithm = kCCPRFHmacAlgSHA1; | |
2059 | } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA224)) { | |
2060 | algorithm = kCCPRFHmacAlgSHA224; | |
2061 | } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA256)) { | |
2062 | algorithm = kCCPRFHmacAlgSHA256; | |
2063 | } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA384)) { | |
2064 | algorithm = kCCPRFHmacAlgSHA384; | |
2065 | } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) { | |
2066 | algorithm = kCCPRFHmacAlgSHA512; | |
427c49bc | 2067 | } else { |
6b200bc3 A |
2068 | if(error) { |
2069 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL); | |
2070 | } | |
d8f41ccd | 2071 | goto errOut; |
b1ab9ed8 A |
2072 | } |
2073 | ||
2074 | if(rounds == 0) { | |
2075 | rounds = 33333; // we need to pass back a consistent value since there's no way to record the round count. | |
2076 | } | |
2077 | ||
b1ab9ed8 | 2078 | if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) { |
866f8763 A |
2079 | if(error) { |
2080 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); | |
2081 | } | |
d8f41ccd | 2082 | goto errOut; |
b1ab9ed8 | 2083 | } |
5c19dc3a | 2084 | |
d8f41ccd A |
2085 | if((keyData = CFDataCreate(NULL, derivedKey, derivedKeyLen)) != NULL) { |
2086 | retval = SecKeyCreateFromData(parameters, keyData, error); | |
2087 | CFRelease(keyData); | |
2088 | } else { | |
6b200bc3 A |
2089 | if(error) { |
2090 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); | |
2091 | } | |
d8f41ccd | 2092 | } |
5c19dc3a | 2093 | |
d8f41ccd A |
2094 | errOut: |
2095 | utilClearAndFree(salt, saltLen); | |
2096 | utilClearAndFree(thePassword, passwordLen); | |
2097 | utilClearAndFree(derivedKey, derivedKeyLen); | |
b1ab9ed8 | 2098 | return retval; |
b1ab9ed8 A |
2099 | } |
2100 | ||
2101 | CFDataRef | |
2102 | SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error) | |
2103 | { | |
6b200bc3 A |
2104 | if(error) { |
2105 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL); | |
2106 | } | |
b1ab9ed8 A |
2107 | return NULL; |
2108 | } | |
2109 | ||
2110 | SecKeyRef | |
2111 | SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error) | |
2112 | { | |
6b200bc3 A |
2113 | if(error) { |
2114 | *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL); | |
2115 | } | |
b1ab9ed8 A |
2116 | return NULL; |
2117 | } |