]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
5c19dc3a | 2 | * Copyright (c) 2006-2015 Apple Inc. All Rights Reserved. |
427c49bc | 3 | * |
b1ab9ed8 | 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 | ||
427c49bc | 24 | /* |
b54c578e | 25 | * SecKey.m - CoreFoundation based key object |
b1ab9ed8 | 26 | */ |
b54c578e | 27 | #include <AssertMacros.h> |
6b200bc3 | 28 | #include <Security/SecBase.h> |
b1ab9ed8 A |
29 | |
30 | #include <Security/SecKeyInternal.h> | |
31 | #include <Security/SecItem.h> | |
32 | #include <Security/SecItemPriv.h> | |
fa7225c8 | 33 | #include <Security/SecItemShim.h> |
b1ab9ed8 | 34 | #include <Security/SecFramework.h> |
dbe77505 | 35 | #include <Security/SecCertificate.h> |
b1ab9ed8 | 36 | |
427c49bc A |
37 | #include <utilities/SecIOFormat.h> |
38 | ||
39 | #include <utilities/SecCFWrappers.h> | |
fa7225c8 | 40 | #include <utilities/array_size.h> |
427c49bc | 41 | |
b54c578e | 42 | #include <Security/SecKeyPriv.h> |
b1ab9ed8 | 43 | #include "SecRSAKeyPriv.h" |
d8f41ccd | 44 | #include "SecECKeyPriv.h" |
5c19dc3a | 45 | #include "SecCTKKeyPriv.h" |
b54c578e | 46 | #include <Security/SecBasePriv.h> |
b1ab9ed8 A |
47 | |
48 | #include <CoreFoundation/CFNumber.h> | |
49 | #include <CoreFoundation/CFString.h> | |
79b9da22 | 50 | #include <CoreFoundation/CFPriv.h> |
b1ab9ed8 A |
51 | #include <pthread.h> |
52 | #include <string.h> | |
427c49bc A |
53 | #include <utilities/debugging.h> |
54 | #include <utilities/SecCFError.h> | |
b1ab9ed8 A |
55 | #include <CommonCrypto/CommonDigest.h> |
56 | #include <Security/SecAsn1Coder.h> | |
57 | #include <Security/oidsalg.h> | |
58 | #include <Security/SecInternal.h> | |
59 | #include <Security/SecRandom.h> | |
fa7225c8 A |
60 | #include <Security/SecureTransport.h> /* For error codes. */ |
61 | ||
b1ab9ed8 | 62 | #include <corecrypto/ccrng_system.h> |
fa7225c8 | 63 | |
b1ab9ed8 | 64 | #include <asl.h> |
427c49bc | 65 | #include <stdlib.h> |
b54c578e | 66 | #include <os/lock.h> |
5c19dc3a A |
67 | |
68 | #include <libDER/asn1Types.h> | |
69 | #include <libDER/DER_Keys.h> | |
70 | #include <libDER/DER_Encode.h> | |
71 | ||
5c19dc3a | 72 | CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key) |
427c49bc A |
73 | { |
74 | CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; | |
75 | ||
76 | /* encode the public key. */ | |
fa7225c8 A |
77 | require_noerr_quiet(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); |
78 | require_quiet(pubKeyBlob, errOut); | |
5c19dc3a | 79 | |
427c49bc | 80 | /* Calculate the digest of the public key. */ |
fa7225c8 A |
81 | require_quiet(pubKeyDigest = SecSHA1DigestCreate(CFGetAllocator(key), |
82 | CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), | |
427c49bc A |
83 | errOut); |
84 | errOut: | |
85 | CFReleaseNull(pubKeyBlob); | |
86 | return pubKeyDigest; | |
87 | } | |
88 | ||
89 | ||
b1ab9ed8 A |
90 | /* |
91 | */ | |
d8f41ccd A |
92 | static CFDictionaryRef SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key, |
93 | CFTypeRef keyType, | |
94 | CFDataRef privateBlob) | |
b1ab9ed8 A |
95 | { |
96 | CFAllocatorRef allocator = CFGetAllocator(key); | |
97 | DICT_DECLARE(25); | |
98 | CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; | |
99 | CFDictionaryRef dict = NULL; | |
5c19dc3a | 100 | |
b1ab9ed8 A |
101 | size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits); |
102 | CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue); | |
5c19dc3a | 103 | |
b1ab9ed8 | 104 | /* encode the public key. */ |
fa7225c8 A |
105 | require_noerr_quiet(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); |
106 | require_quiet(pubKeyBlob, errOut); | |
5c19dc3a | 107 | |
b1ab9ed8 | 108 | /* Calculate the digest of the public key. */ |
fa7225c8 A |
109 | require_quiet(pubKeyDigest = SecSHA1DigestCreate(allocator, |
110 | CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), | |
111 | errOut); | |
5c19dc3a | 112 | |
b1ab9ed8 A |
113 | DICT_ADDPAIR(kSecClass, kSecClassKey); |
114 | DICT_ADDPAIR(kSecAttrKeyClass, privateBlob ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic); | |
115 | DICT_ADDPAIR(kSecAttrApplicationLabel, pubKeyDigest); | |
116 | DICT_ADDPAIR(kSecAttrIsPermanent, kCFBooleanTrue); | |
117 | DICT_ADDPAIR(kSecAttrIsPrivate, kCFBooleanTrue); | |
118 | DICT_ADDPAIR(kSecAttrIsModifiable, kCFBooleanTrue); | |
119 | DICT_ADDPAIR(kSecAttrKeyType, keyType); | |
120 | DICT_ADDPAIR(kSecAttrKeySizeInBits, sizeInBits); | |
121 | DICT_ADDPAIR(kSecAttrEffectiveKeySize, sizeInBits); | |
122 | DICT_ADDPAIR(kSecAttrIsSensitive, kCFBooleanFalse); | |
123 | DICT_ADDPAIR(kSecAttrWasAlwaysSensitive, kCFBooleanFalse); | |
124 | DICT_ADDPAIR(kSecAttrIsExtractable, kCFBooleanTrue); | |
125 | DICT_ADDPAIR(kSecAttrWasNeverExtractable, kCFBooleanFalse); | |
fa7225c8 A |
126 | DICT_ADDPAIR(kSecAttrCanEncrypt, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); |
127 | DICT_ADDPAIR(kSecAttrCanDecrypt, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); | |
b1ab9ed8 | 128 | DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue); |
fa7225c8 A |
129 | DICT_ADDPAIR(kSecAttrCanSign, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); |
130 | DICT_ADDPAIR(kSecAttrCanVerify, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); | |
b1ab9ed8 A |
131 | DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse); |
132 | DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse); | |
fa7225c8 A |
133 | DICT_ADDPAIR(kSecAttrCanWrap, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); |
134 | DICT_ADDPAIR(kSecAttrCanUnwrap, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); | |
b1ab9ed8 | 135 | DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob); |
866f8763 A |
136 | dict = CFDictionaryCreate(allocator, keys, values, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
137 | ||
b1ab9ed8 A |
138 | errOut: |
139 | // @@@ Zero out key material. | |
140 | CFReleaseSafe(pubKeyDigest); | |
141 | CFReleaseSafe(pubKeyBlob); | |
142 | CFReleaseSafe(sizeInBits); | |
5c19dc3a | 143 | |
b1ab9ed8 A |
144 | return dict; |
145 | } | |
146 | ||
147 | CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key, | |
148 | CFTypeRef keyType, | |
149 | CFDataRef privateBlob) | |
150 | { | |
d8f41ccd | 151 | return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, privateBlob); |
b1ab9ed8 A |
152 | } |
153 | ||
154 | CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType) | |
155 | { | |
d8f41ccd | 156 | return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, NULL); |
b1ab9ed8 A |
157 | } |
158 | ||
427c49bc | 159 | static CFStringRef SecKeyCopyDescription(CFTypeRef cf) { |
b1ab9ed8 | 160 | SecKeyRef key = (SecKeyRef)cf; |
5c19dc3a | 161 | |
427c49bc A |
162 | if(key->key_class->describe) |
163 | return key->key_class->describe(key); | |
164 | else | |
5c19dc3a | 165 | return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecKeyRef: %p>"), key); |
b1ab9ed8 A |
166 | } |
167 | ||
b54c578e A |
168 | #if TARGET_OS_OSX |
169 | static CFMutableDictionaryRef auxilliaryCDSAKeyMap; | |
170 | static struct os_unfair_lock_s auxilliaryCDSAKeyMapLock = OS_UNFAIR_LOCK_INIT; | |
171 | ||
172 | static void SecKeyDestroyAuxilliaryCDSAKeyForKey(CFTypeRef cf) { | |
7fb2cbd2 | 173 | CFTypeRef keyToDestroy = NULL; |
b54c578e A |
174 | os_unfair_lock_lock(&auxilliaryCDSAKeyMapLock); |
175 | if (auxilliaryCDSAKeyMap != NULL) { | |
7fb2cbd2 A |
176 | keyToDestroy = CFDictionaryGetValue(auxilliaryCDSAKeyMap, cf); |
177 | if (keyToDestroy != NULL) { | |
178 | CFRetain(keyToDestroy); | |
179 | CFDictionaryRemoveValue(auxilliaryCDSAKeyMap, cf); | |
180 | } | |
b54c578e A |
181 | } |
182 | os_unfair_lock_unlock(&auxilliaryCDSAKeyMapLock); | |
7fb2cbd2 A |
183 | |
184 | // Actual aux key destruction is performed outside unfair lock to avoid recursive lock. | |
185 | if (keyToDestroy != NULL) { | |
186 | CFRelease(keyToDestroy); | |
187 | } | |
b54c578e A |
188 | } |
189 | ||
190 | void SecKeySetAuxilliaryCDSAKeyForKey(SecKeyRef cf, SecKeyRef auxKey) { | |
191 | os_unfair_lock_lock(&auxilliaryCDSAKeyMapLock); | |
192 | if (auxilliaryCDSAKeyMap == NULL) { | |
193 | // Allocate map with weak (unretained) keys (which are source SecKeys) but strong values (which are held aux CDSA keys). | |
194 | auxilliaryCDSAKeyMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); | |
195 | } | |
196 | CFDictionarySetValue(auxilliaryCDSAKeyMap, cf, auxKey); | |
197 | os_unfair_lock_unlock(&auxilliaryCDSAKeyMapLock); | |
198 | } | |
199 | ||
200 | SecKeyRef SecKeyCopyAuxilliaryCDSAKeyForKey(SecKeyRef cf) { | |
201 | os_unfair_lock_lock(&auxilliaryCDSAKeyMapLock); | |
202 | if (auxilliaryCDSAKeyMap == NULL) { | |
203 | os_unfair_lock_unlock(&auxilliaryCDSAKeyMapLock); | |
204 | return NULL; | |
205 | } | |
206 | SecKeyRef result = (SecKeyRef)CFRetainSafe(CFDictionaryGetValue(auxilliaryCDSAKeyMap, cf)); | |
207 | os_unfair_lock_unlock(&auxilliaryCDSAKeyMapLock); | |
208 | return result; | |
209 | } | |
210 | #endif | |
211 | ||
b1ab9ed8 A |
212 | static void SecKeyDestroy(CFTypeRef cf) { |
213 | SecKeyRef key = (SecKeyRef)cf; | |
79b9da22 | 214 | #if TARGET_OS_OSX |
b54c578e | 215 | SecKeyDestroyAuxilliaryCDSAKeyForKey(cf); |
fa7225c8 | 216 | #endif |
b1ab9ed8 A |
217 | if (key->key_class->destroy) |
218 | key->key_class->destroy(key); | |
219 | } | |
220 | ||
427c49bc A |
221 | static Boolean SecKeyEqual(CFTypeRef cf1, CFTypeRef cf2) |
222 | { | |
b1ab9ed8 A |
223 | SecKeyRef key1 = (SecKeyRef)cf1; |
224 | SecKeyRef key2 = (SecKeyRef)cf2; | |
225 | if (key1 == key2) | |
226 | return true; | |
227 | if (!key2 || key1->key_class != key2->key_class) | |
228 | return false; | |
fa7225c8 A |
229 | if (key1->key_class->version >= 4 && key1->key_class->isEqual) |
230 | return key1->key_class->isEqual(key1, key2); | |
b1ab9ed8 A |
231 | if (key1->key_class->extraBytes) |
232 | return !memcmp(key1->key, key2->key, key1->key_class->extraBytes); | |
5c19dc3a | 233 | |
b1ab9ed8 A |
234 | /* TODO: Won't work when we get reference keys. */ |
235 | CFDictionaryRef d1, d2; | |
236 | d1 = SecKeyCopyAttributeDictionary(key1); | |
237 | d2 = SecKeyCopyAttributeDictionary(key2); | |
fa7225c8 A |
238 | // Returning NULL is an error; bail out of the equality check |
239 | if(!d1 || !d2) { | |
6b200bc3 A |
240 | CFReleaseSafe(d1); |
241 | CFReleaseSafe(d2); | |
fa7225c8 A |
242 | return false; |
243 | } | |
b1ab9ed8 A |
244 | Boolean result = CFEqual(d1, d2); |
245 | CFReleaseSafe(d1); | |
246 | CFReleaseSafe(d2); | |
247 | return result; | |
248 | } | |
249 | ||
d8f41ccd | 250 | struct ccrng_state *ccrng_seckey; |
b1ab9ed8 | 251 | |
d8f41ccd A |
252 | CFGiblisWithFunctions(SecKey, NULL, NULL, SecKeyDestroy, SecKeyEqual, NULL, NULL, SecKeyCopyDescription, NULL, NULL, ^{ |
253 | static struct ccrng_system_state ccrng_system_state_seckey; | |
254 | ccrng_seckey = (struct ccrng_state *)&ccrng_system_state_seckey; | |
255 | ccrng_system_init(&ccrng_system_state_seckey); | |
256 | }) | |
b1ab9ed8 A |
257 | |
258 | static bool getBoolForKey(CFDictionaryRef dict, CFStringRef key, bool default_value) { | |
259 | CFTypeRef value = CFDictionaryGetValue(dict, key); | |
260 | if (value) { | |
261 | if (CFGetTypeID(value) == CFBooleanGetTypeID()) { | |
262 | return CFBooleanGetValue(value); | |
263 | } else { | |
264 | secwarning("Value %@ for key %@ is not bool", value, key); | |
265 | } | |
266 | } | |
5c19dc3a | 267 | |
b1ab9ed8 A |
268 | return default_value; |
269 | } | |
270 | ||
b54c578e A |
271 | static OSStatus add_key(SecKeyRef key, CFMutableDictionaryRef dict) { |
272 | CFDictionarySetValue(dict, kSecValueRef, key); | |
273 | CFDictionaryRef keyAttributes = SecKeyCopyAttributes(key); | |
274 | if (keyAttributes != NULL && CFDictionaryContainsKey(keyAttributes, kSecAttrAccessControl)) { | |
275 | // Avoid overriding ACL from the key with source ACL of the call; ACL of the key might be already processed during key generation and should be preferred to source unprocessed ACL. | |
276 | CFDictionaryRemoveValue(dict, kSecAttrAccessControl); | |
277 | } | |
278 | CFReleaseNull(keyAttributes); | |
279 | return SecItemAdd(dict, NULL); | |
b1ab9ed8 A |
280 | } |
281 | ||
282 | static void merge_params_applier(const void *key, const void *value, | |
283 | void *context) { | |
284 | CFMutableDictionaryRef result = (CFMutableDictionaryRef)context; | |
285 | CFDictionaryAddValue(result, key, value); | |
286 | } | |
287 | ||
288 | /* Create a mutable dictionary that is based on the subdictionary for key | |
289 | with any attributes from the top level dict merged in. */ | |
5c19dc3a A |
290 | static CF_RETURNS_RETAINED CFMutableDictionaryRef merge_params(CFDictionaryRef dict, |
291 | CFStringRef key) { | |
b1ab9ed8 A |
292 | CFDictionaryRef subdict = CFDictionaryGetValue(dict, key); |
293 | CFMutableDictionaryRef result; | |
5c19dc3a | 294 | |
b1ab9ed8 A |
295 | if (subdict) { |
296 | result = CFDictionaryCreateMutableCopy(NULL, 0, subdict); | |
297 | /* Add everything in dict not already in result to result. */ | |
298 | CFDictionaryApplyFunction(dict, merge_params_applier, result); | |
299 | } else { | |
300 | result = CFDictionaryCreateMutableCopy(NULL, 0, dict); | |
301 | } | |
5c19dc3a | 302 | |
b1ab9ed8 A |
303 | /* Remove values that only belong in the top level dict. */ |
304 | CFDictionaryRemoveValue(result, kSecPublicKeyAttrs); | |
305 | CFDictionaryRemoveValue(result, kSecPrivateKeyAttrs); | |
306 | CFDictionaryRemoveValue(result, kSecAttrKeyType); | |
307 | CFDictionaryRemoveValue(result, kSecAttrKeySizeInBits); | |
5c19dc3a | 308 | |
b1ab9ed8 A |
309 | return result; |
310 | } | |
311 | ||
79b9da22 | 312 | CFIndex SecKeyGetAlgorithmId(SecKeyRef key) { |
5c19dc3a A |
313 | if (!key || !key->key_class) { |
314 | // TBD: somehow, a key can be created with a NULL key_class in the | |
315 | // SecCertificateCopyPublicKey -> SecKeyCreatePublicFromDER code path | |
316 | return kSecNullAlgorithmID; | |
317 | } | |
318 | /* This method was added to version 1 keys. */ | |
319 | if (key->key_class->version > 0 && key->key_class->getAlgorithmID) { | |
320 | return key->key_class->getAlgorithmID(key); | |
321 | } | |
fa7225c8 | 322 | /* All version 0 keys were RSA. */ |
5c19dc3a A |
323 | return kSecRSAAlgorithmID; |
324 | } | |
325 | ||
b1ab9ed8 A |
326 | /* Generate a private/public keypair. */ |
327 | OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, | |
328 | SecKeyRef *publicKey, SecKeyRef *privateKey) { | |
b54c578e A |
329 | @autoreleasepool { |
330 | OSStatus result = errSecUnsupportedAlgorithm; | |
331 | SecKeyRef privKey = NULL; | |
332 | SecKeyRef pubKey = NULL; | |
333 | CFMutableDictionaryRef pubParams = merge_params(parameters, kSecPublicKeyAttrs), | |
334 | privParams = merge_params(parameters, kSecPrivateKeyAttrs); | |
335 | CFStringRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); | |
336 | CFStringRef tokenID = CFDictionaryGetValue(parameters, kSecAttrTokenID); | |
337 | ||
338 | require_quiet(ktype, errOut); | |
339 | ||
340 | if (tokenID != NULL) { | |
341 | result = SecCTKKeyGeneratePair(parameters, &pubKey, &privKey); | |
342 | } else if (CFEqual(ktype, kSecAttrKeyTypeECSECPrimeRandom)) { | |
343 | result = SecECKeyGeneratePair(parameters, &pubKey, &privKey); | |
344 | } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { | |
345 | result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey); | |
346 | } | |
5c19dc3a | 347 | |
b54c578e | 348 | require_noerr_quiet(result, errOut); |
5c19dc3a | 349 | |
b54c578e A |
350 | // Store the keys in the keychain if they are marked as permanent. Governed by kSecAttrIsPermanent attribute, with default |
351 | // to 'false' (ephemeral keys), except private token-based keys, in which case the default is 'true' (permanent keys). | |
352 | if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) { | |
353 | CFDictionaryRemoveValue(pubParams, kSecAttrTokenID); | |
354 | require_noerr_quiet(result = add_key(pubKey, pubParams), errOut); | |
355 | } | |
356 | if (getBoolForKey(privParams, kSecAttrIsPermanent, CFDictionaryContainsKey(privParams, kSecAttrTokenID))) { | |
357 | require_noerr_quiet(result = add_key(privKey, privParams), errOut); | |
358 | } | |
5c19dc3a | 359 | |
b54c578e A |
360 | if (publicKey) { |
361 | *publicKey = pubKey; | |
362 | pubKey = NULL; | |
363 | } | |
364 | if (privateKey) { | |
365 | *privateKey = privKey; | |
366 | privKey = NULL; | |
367 | } | |
5c19dc3a | 368 | |
b54c578e A |
369 | errOut: |
370 | CFReleaseSafe(pubParams); | |
371 | CFReleaseSafe(privParams); | |
372 | CFReleaseSafe(pubKey); | |
373 | CFReleaseSafe(privKey); | |
5c19dc3a | 374 | |
b54c578e A |
375 | return result; |
376 | } | |
427c49bc | 377 | } |
b1ab9ed8 | 378 | |
427c49bc | 379 | SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) { |
fa7225c8 | 380 | return SecKeyCopyPublicKey(privateKey); |
b1ab9ed8 A |
381 | } |
382 | ||
5c19dc3a | 383 | CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef) |
427c49bc | 384 | { |
5c19dc3a | 385 | const CFTypeRef refType = (returnPersistentRef) ? kSecReturnPersistentRef: kSecReturnRef; |
fa7225c8 | 386 | |
5c19dc3a A |
387 | CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); |
388 | ||
427c49bc A |
389 | CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, |
390 | kSecClass, kSecClassKey, | |
391 | kSecAttrKeyClass, kSecAttrKeyClassPrivate, | |
392 | kSecAttrSynchronizable, kSecAttrSynchronizableAny, | |
393 | kSecAttrApplicationLabel, public_key_hash, | |
5c19dc3a | 394 | refType, kCFBooleanTrue, |
427c49bc A |
395 | NULL); |
396 | CFReleaseNull(public_key_hash); | |
5c19dc3a | 397 | |
427c49bc A |
398 | return query; |
399 | } | |
400 | ||
401 | CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { | |
402 | CFTypeRef persistentRef = NULL; | |
403 | CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true); | |
404 | ||
405 | require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error , | |
406 | CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail); | |
407 | fail: | |
408 | CFReleaseNull(query); | |
409 | return (CFDataRef)persistentRef; | |
410 | } | |
411 | ||
412 | SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { | |
5c19dc3a A |
413 | SecKeyRef privateKey = NULL; |
414 | CFTypeRef queryResult = NULL; | |
415 | CFDictionaryRef query = NULL; | |
fa7225c8 | 416 | |
822b670c | 417 | require_action_quiet(publicKey != NULL, errOut, SecError(errSecParam, error, CFSTR("Null Public Key"))); |
5c19dc3a A |
418 | |
419 | query = CreatePrivateKeyMatchingQuery(publicKey, false); | |
420 | ||
421 | require_quiet(SecError(SecItemCopyMatching(query, &queryResult), error, | |
422 | CFSTR("Error finding private key from public: %@"), publicKey), errOut); | |
fa7225c8 | 423 | |
5c19dc3a A |
424 | if (CFGetTypeID(queryResult) == SecKeyGetTypeID()) { |
425 | privateKey = (SecKeyRef) queryResult; | |
426 | queryResult = NULL; | |
427 | } | |
428 | ||
429 | errOut: | |
430 | CFReleaseNull(query); | |
431 | CFReleaseNull(queryResult); | |
432 | return privateKey; | |
433 | } | |
434 | ||
435 | OSStatus SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey, CFErrorRef *error) { | |
436 | OSStatus retval = errSecParam; | |
427c49bc | 437 | CFTypeRef private_key = NULL; |
5c19dc3a | 438 | CFDictionaryRef query = NULL; |
fa7225c8 | 439 | |
5c19dc3a A |
440 | require_action_quiet(publicKey != NULL, errOut, SecError(errSecParam, error, NULL, CFSTR("Null Public Key"))); |
441 | ||
442 | query = CreatePrivateKeyMatchingQuery(publicKey, false); | |
fa7225c8 | 443 | |
5c19dc3a | 444 | retval = SecItemCopyMatching(query, &private_key); |
fa7225c8 | 445 | |
5c19dc3a A |
446 | if (!retval && CFGetTypeID(private_key) != SecKeyGetTypeID()) { |
447 | retval = errSecInternalComponent; | |
448 | } | |
fa7225c8 | 449 | |
5c19dc3a | 450 | errOut: |
427c49bc | 451 | CFReleaseNull(query); |
5c19dc3a A |
452 | CFReleaseNull(private_key); |
453 | return retval; | |
427c49bc A |
454 | } |
455 | ||
5c19dc3a | 456 | |
b1ab9ed8 | 457 | SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, |
427c49bc A |
458 | const SecAsn1Oid *oid, const SecAsn1Item *params, |
459 | const SecAsn1Item *keyData) { | |
b1ab9ed8 A |
460 | SecKeyRef publicKey = NULL; |
461 | if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) { | |
462 | /* pkcs1 1 */ | |
fa7225c8 A |
463 | /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of |
464 | SecKeyCreateRSAPublicKey, since on OS X the latter function will return | |
465 | a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here. | |
466 | */ | |
467 | publicKey = SecKeyCreateRSAPublicKey_ios(allocator, | |
427c49bc | 468 | keyData->Data, keyData->Length, kSecKeyEncodingPkcs1); |
b1ab9ed8 A |
469 | } else if (SecAsn1OidCompare(oid, &CSSMOID_ecPublicKey)) { |
470 | SecDERKey derKey = { | |
471 | .oid = oid->Data, | |
472 | .oidLength = oid->Length, | |
473 | .key = keyData->Data, | |
474 | .keyLength = keyData->Length, | |
475 | }; | |
476 | if (params) { | |
477 | derKey.parameters = params->Data; | |
478 | derKey.parametersLength = params->Length; | |
479 | } | |
fa7225c8 | 480 | publicKey = SecKeyCreateECPublicKey(allocator, |
427c49bc | 481 | (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding); |
b1ab9ed8 A |
482 | } else { |
483 | secwarning("Unsupported algorithm oid"); | |
484 | } | |
5c19dc3a | 485 | |
b1ab9ed8 A |
486 | return publicKey; |
487 | } | |
488 | ||
5c19dc3a A |
489 | |
490 | SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, CFDataRef subjectPublicKeyInfoData) | |
491 | { | |
492 | DERReturn drtn; | |
493 | ||
494 | DERItem subjectPublicKeyInfoDER = { | |
495 | .data = (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData), | |
496 | .length = (DERSize)CFDataGetLength(subjectPublicKeyInfoData), | |
497 | }; | |
498 | DERSubjPubKeyInfo subjectPublicKeyInfo; | |
499 | DERAlgorithmId algorithmId; | |
500 | DERItem pubKeyBytes; | |
501 | ||
502 | drtn = DERParseSequence(&subjectPublicKeyInfoDER, | |
503 | DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs, | |
504 | &subjectPublicKeyInfo, sizeof(subjectPublicKeyInfo)); | |
505 | ||
506 | require_noerr_quiet(drtn, out); | |
507 | ||
508 | drtn = DERParseSequenceContent(&subjectPublicKeyInfo.algId, | |
509 | DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, | |
510 | &algorithmId, sizeof(algorithmId)); | |
511 | require_noerr_quiet(drtn, out); | |
512 | ||
513 | DERByte unusedBits; | |
514 | drtn = DERParseBitString(&subjectPublicKeyInfo.pubKey, &pubKeyBytes, &unusedBits); | |
515 | require_noerr_quiet(drtn, out); | |
516 | ||
517 | /* Convert DERItem to SecAsn1Item : */ | |
518 | const SecAsn1Oid oid = { .Data = algorithmId.oid.data, .Length = algorithmId.oid.length }; | |
519 | const SecAsn1Item params = { .Data = algorithmId.params.data, .Length = algorithmId.params.length }; | |
520 | const SecAsn1Item pubKey = { .Data = pubKeyBytes.data, .Length = pubKeyBytes.length }; | |
521 | ||
522 | return SecKeyCreatePublicFromDER(allocator, &oid, ¶ms, &pubKey); | |
523 | ||
524 | out: | |
525 | ||
526 | return NULL; | |
866f8763 A |
527 | } |
528 | ||
529 | static const DERByte oidRSA[] = { | |
530 | 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, | |
531 | }; | |
532 | static const DERByte oidECsecp256[] = { | |
533 | 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, | |
534 | }; | |
535 | static const DERByte oidECsecp384[] = { | |
536 | 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, | |
537 | }; | |
538 | static const DERByte oidECsecp521[] = { | |
539 | 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, | |
540 | }; | |
541 | ||
542 | ||
543 | CFDataRef SecKeyCopySubjectPublicKeyInfo(SecKeyRef key) | |
544 | { | |
545 | CFMutableDataRef data = NULL; | |
546 | CFDataRef publicKey = NULL; | |
547 | CFDataRef dataret = NULL; | |
548 | DERSubjPubKeyInfo spki; | |
549 | DERReturn drtn; | |
550 | size_t zeroPad = 0; | |
551 | ||
552 | memset(&spki, 0, sizeof(spki)); | |
553 | ||
554 | /* encode the public key. */ | |
79b9da22 | 555 | require_noerr_quiet(SecKeyCopyPublicBytes(key, &publicKey), errOut); |
866f8763 A |
556 | require_quiet(publicKey, errOut); |
557 | ||
79b9da22 | 558 | require_quiet(CFDataGetLength(publicKey) != 0, errOut); |
866f8763 A |
559 | |
560 | // Add prefix 00 is needed to avoid creating negative bit strings | |
561 | if (((uint8_t *)CFDataGetBytePtr(publicKey))[0] & 0x80) | |
562 | zeroPad = 1; | |
563 | ||
564 | ||
565 | CFMutableDataRef paddedKey = CFDataCreateMutable(NULL, 0); | |
566 | /* the bit strings bits used field first */ | |
567 | CFDataAppendBytes(paddedKey, (const UInt8 *)"\x00", 1); | |
568 | if (zeroPad) | |
569 | CFDataAppendBytes(paddedKey, (const UInt8 *)"\x00", 1); | |
570 | ||
571 | CFDataAppendBytes(paddedKey, CFDataGetBytePtr(publicKey), CFDataGetLength(publicKey)); | |
572 | CFTransferRetained(publicKey, paddedKey); | |
573 | ||
574 | spki.pubKey.data = (DERByte *)CFDataGetBytePtr(publicKey); | |
575 | spki.pubKey.length = CFDataGetLength(publicKey); | |
576 | ||
577 | // Encode algId according to algorithm used. | |
79b9da22 | 578 | CFIndex algorithm = SecKeyGetAlgorithmId(key); |
866f8763 A |
579 | if (algorithm == kSecRSAAlgorithmID) { |
580 | spki.algId.data = (DERByte *)oidRSA; | |
581 | spki.algId.length = sizeof(oidRSA); | |
582 | } else if (algorithm == kSecECDSAAlgorithmID) { | |
583 | SecECNamedCurve curve = SecECKeyGetNamedCurve(key); | |
584 | switch(curve) { | |
585 | case kSecECCurveSecp256r1: | |
586 | spki.algId.data = (DERByte *)oidECsecp256; | |
587 | spki.algId.length = sizeof(oidECsecp256); | |
588 | break; | |
589 | case kSecECCurveSecp384r1: | |
590 | spki.algId.data = (DERByte *)oidECsecp384; | |
591 | spki.algId.length = sizeof(oidECsecp384); | |
592 | break; | |
593 | case kSecECCurveSecp521r1: | |
594 | spki.algId.data = (DERByte *)oidECsecp521; | |
595 | spki.algId.length = sizeof(oidECsecp521); | |
596 | break; | |
597 | default: | |
598 | goto errOut; | |
599 | } | |
600 | } else { | |
601 | goto errOut; | |
602 | } | |
603 | ||
604 | DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &spki, | |
605 | DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs); | |
606 | data = CFDataCreateMutable(kCFAllocatorDefault, size); | |
607 | CFDataSetLength(data, size); | |
608 | ||
609 | drtn = DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &spki, | |
610 | DERNumSubjPubKeyInfoItemSpecs, | |
611 | DERSubjPubKeyInfoItemSpecs, | |
612 | CFDataGetMutableBytePtr(data), &size); | |
79b9da22 | 613 | require_quiet(drtn == DR_Success, errOut); |
866f8763 | 614 | CFDataSetLength(data, size); |
5c19dc3a | 615 | |
866f8763 A |
616 | dataret = CFRetain(data); |
617 | errOut: | |
618 | CFReleaseNull(data); | |
619 | CFReleaseNull(publicKey); | |
620 | ||
621 | return dataret; | |
5c19dc3a A |
622 | } |
623 | ||
624 | ||
625 | ||
b1ab9ed8 | 626 | SecKeyRef SecKeyCreate(CFAllocatorRef allocator, |
427c49bc A |
627 | const SecKeyDescriptor *key_class, const uint8_t *keyData, |
628 | CFIndex keyDataLength, SecKeyEncoding encoding) { | |
d8f41ccd | 629 | if (!key_class) return NULL; |
b1ab9ed8 A |
630 | size_t size = sizeof(struct __SecKey) + key_class->extraBytes; |
631 | SecKeyRef result = (SecKeyRef)_CFRuntimeCreateInstance(allocator, | |
427c49bc | 632 | SecKeyGetTypeID(), size - sizeof(CFRuntimeBase), NULL); |
b1ab9ed8 A |
633 | if (result) { |
634 | memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base)); | |
635 | result->key_class = key_class; | |
636 | if (key_class->extraBytes) { | |
637 | /* Make result->key point to the extraBytes we allocated. */ | |
638 | result->key = ((char*)result) + sizeof(*result); | |
639 | } | |
640 | if (key_class->init) { | |
641 | OSStatus status; | |
642 | status = key_class->init(result, keyData, keyDataLength, encoding); | |
643 | if (status) { | |
427c49bc | 644 | secwarning("init %s key: %" PRIdOSStatus, key_class->name, status); |
b1ab9ed8 A |
645 | CFRelease(result); |
646 | result = NULL; | |
647 | } | |
648 | } | |
649 | } | |
650 | return result; | |
651 | } | |
652 | ||
fa7225c8 A |
653 | // Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments |
654 | // used by legacy RawSign-style functions. | |
655 | static OSStatus SecKeyPerformLegacyOperation(SecKeyRef key, | |
656 | const uint8_t *in1Ptr, size_t in1Len, | |
657 | const uint8_t *in2Ptr, size_t in2Len, | |
658 | uint8_t *outPtr, size_t *outLen, | |
659 | CFTypeRef (^operation)(CFDataRef in1, CFDataRef in2, CFRange *resultRange, CFErrorRef *error)) { | |
660 | CFErrorRef error = NULL; | |
661 | OSStatus status = errSecSuccess; | |
662 | CFDataRef in1 = CFDataCreateWithBytesNoCopy(NULL, in1Ptr, in1Len, kCFAllocatorNull); | |
6b200bc3 | 663 | CFDataRef in2 = CFDataCreateWithBytesNoCopy(NULL, in2Ptr, in2Len, kCFAllocatorNull); |
fa7225c8 A |
664 | CFRange range = { 0, -1 }; |
665 | CFTypeRef output = operation(in1, in2, &range, &error); | |
666 | require_quiet(output, out); | |
667 | if (CFGetTypeID(output) == CFDataGetTypeID() && outLen != NULL) { | |
668 | if (range.length == -1) { | |
669 | range.length = CFDataGetLength(output); | |
670 | } | |
671 | require_action_quiet((size_t)range.length <= *outLen, out, | |
672 | SecError(errSecParam, &error, CFSTR("buffer too small"))); | |
673 | *outLen = range.length; | |
674 | CFDataGetBytes(output, range, outPtr); | |
b1ab9ed8 | 675 | } |
5c19dc3a | 676 | |
fa7225c8 A |
677 | out: |
678 | CFReleaseSafe(in1); | |
679 | CFReleaseSafe(in2); | |
680 | CFReleaseSafe(output); | |
681 | if (error != NULL) { | |
3a7be6fd | 682 | status = SecErrorGetOSStatus(error); |
fa7225c8 A |
683 | if (status == errSecVerifyFailed) { |
684 | // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed. | |
685 | status = errSSLCrypto; | |
686 | } | |
687 | CFRelease(error); | |
688 | } | |
689 | return status; | |
b1ab9ed8 A |
690 | } |
691 | ||
b54c578e A |
692 | static SecKeyAlgorithm SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key, SecPadding padding) { |
693 | switch (SecKeyGetAlgorithmId(key)) { | |
694 | case kSecRSAAlgorithmID: { | |
695 | switch (padding) { | |
696 | case kSecPaddingNone: | |
697 | return kSecKeyAlgorithmRSASignatureRaw; | |
698 | case kSecPaddingPKCS1: | |
699 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw; | |
700 | case kSecPaddingPKCS1SHA1: | |
701 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1; | |
702 | case kSecPaddingPKCS1SHA224: | |
703 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224; | |
704 | case kSecPaddingPKCS1SHA256: | |
705 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256; | |
706 | case kSecPaddingPKCS1SHA384: | |
707 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384; | |
708 | case kSecPaddingPKCS1SHA512: | |
709 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512; | |
710 | default: | |
711 | return NULL; | |
712 | } | |
713 | } | |
714 | case kSecECDSAAlgorithmID: | |
715 | switch (padding) { | |
716 | case kSecPaddingSigRaw: | |
717 | return kSecKeyAlgorithmECDSASignatureRFC4754; | |
718 | default: | |
719 | // Although it is not very logical, previous SecECKey implementation really considered | |
720 | // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour | |
721 | // for backward compatibility. | |
722 | return kSecKeyAlgorithmECDSASignatureDigestX962; | |
723 | } | |
724 | default: | |
725 | return NULL; | |
726 | } | |
727 | } | |
728 | ||
729 | #if TARGET_OS_OSX | |
730 | static SecKeyAlgorithm SecKeyGetSignatureAlgorithmForPadding_macOS(SecKeyRef key, SecPadding padding) { | |
731 | switch (SecKeyGetAlgorithmId(key)) { | |
732 | case kSecRSAAlgorithmID: { | |
733 | // On CSSM-based implementation, these functions actually did hash its input, | |
734 | // so keep doing that for backward compatibility. | |
735 | switch (padding) { | |
736 | case kSecPaddingNone: | |
737 | return kSecKeyAlgorithmRSASignatureRaw; | |
738 | case kSecPaddingPKCS1: | |
739 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw; | |
740 | case kSecPaddingPKCS1SHA1: | |
741 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1; | |
742 | case kSecPaddingPKCS1SHA224: | |
743 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224; | |
744 | case kSecPaddingPKCS1SHA256: | |
745 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256; | |
746 | case kSecPaddingPKCS1SHA384: | |
747 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384; | |
748 | case kSecPaddingPKCS1SHA512: | |
749 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512; | |
750 | default: | |
751 | return NULL; | |
752 | } | |
753 | } | |
754 | case kSecECDSAAlgorithmID: | |
755 | switch (padding) { | |
756 | case kSecPaddingSigRaw: | |
757 | return kSecKeyAlgorithmECDSASignatureRFC4754; | |
758 | default: | |
759 | // Although it is not very logical, previous SecECKey implementation really considered | |
760 | // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour | |
761 | // for backward compatibility. | |
762 | return kSecKeyAlgorithmECDSASignatureDigestX962; | |
763 | } | |
764 | default: | |
765 | return NULL; | |
766 | } | |
767 | } | |
768 | #endif // TARGET_OS_OSX | |
769 | ||
770 | #undef SecKeyRawSign | |
b1ab9ed8 | 771 | OSStatus SecKeyRawSign( |
427c49bc A |
772 | SecKeyRef key, /* Private key */ |
773 | SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ | |
774 | const uint8_t *dataToSign, /* signature over this data */ | |
775 | size_t dataToSignLen, /* length of dataToSign */ | |
776 | uint8_t *sig, /* signature, RETURNED */ | |
777 | size_t *sigLen) { /* IN/OUT */ | |
fa7225c8 A |
778 | SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding(key, padding); |
779 | if (algorithm == NULL) { | |
780 | return errSecParam; | |
b1ab9ed8 | 781 | } |
fa7225c8 A |
782 | return SecKeyPerformLegacyOperation(key, dataToSign, dataToSignLen, NULL, 0, sig, sigLen, |
783 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
784 | return SecKeyCreateSignature(key, algorithm, in1, error); | |
785 | }); | |
b1ab9ed8 A |
786 | } |
787 | ||
b54c578e A |
788 | #if TARGET_OS_OSX |
789 | OSStatus SecKeyRawSign_macOS( | |
790 | SecKeyRef key, /* Private key */ | |
791 | SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ | |
792 | const uint8_t *dataToSign, /* signature over this data */ | |
793 | size_t dataToSignLen, /* length of dataToSign */ | |
794 | uint8_t *sig, /* signature, RETURNED */ | |
795 | size_t *sigLen) { /* IN/OUT */ | |
796 | SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding_macOS(key, padding); | |
797 | if (algorithm == NULL) { | |
798 | return errSecParam; | |
799 | } | |
800 | return SecKeyPerformLegacyOperation(key, dataToSign, dataToSignLen, NULL, 0, sig, sigLen, | |
801 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
802 | return SecKeyCreateSignature(key, algorithm, in1, error); | |
803 | }); | |
804 | } | |
805 | #endif | |
806 | ||
807 | #undef SecKeyRawVerify | |
b1ab9ed8 | 808 | OSStatus SecKeyRawVerify( |
427c49bc A |
809 | SecKeyRef key, /* Public key */ |
810 | SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ | |
811 | const uint8_t *signedData, /* signature over this data */ | |
812 | size_t signedDataLen, /* length of dataToSign */ | |
813 | const uint8_t *sig, /* signature */ | |
814 | size_t sigLen) { /* length of signature */ | |
fa7225c8 A |
815 | SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding(key, padding); |
816 | if (algorithm == NULL) { | |
817 | return errSecParam; | |
818 | } | |
819 | OSStatus status = SecKeyPerformLegacyOperation(key, signedData, signedDataLen, sig, sigLen, NULL, NULL, | |
820 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
6b200bc3 | 821 | return SecKeyVerifySignature(key, algorithm, in1, in2, error) |
fa7225c8 A |
822 | ? kCFBooleanTrue : NULL; |
823 | }); | |
824 | return status; | |
825 | } | |
5c19dc3a | 826 | |
b54c578e A |
827 | #if TARGET_OS_OSX |
828 | OSStatus SecKeyRawVerify_macOS( | |
829 | SecKeyRef key, /* Public key */ | |
830 | SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ | |
831 | const uint8_t *signedData, /* signature over this data */ | |
832 | size_t signedDataLen, /* length of dataToSign */ | |
833 | const uint8_t *sig, /* signature */ | |
834 | size_t sigLen) { /* length of signature */ | |
835 | SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding_macOS(key, padding); | |
836 | if (algorithm == NULL) { | |
837 | return errSecParam; | |
838 | } | |
839 | OSStatus status = SecKeyPerformLegacyOperation(key, signedData, signedDataLen, sig, sigLen, NULL, NULL, | |
840 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
841 | return SecKeyVerifySignature(key, algorithm, in1, in2, error) | |
842 | ? kCFBooleanTrue : NULL; | |
843 | }); | |
844 | return status; | |
845 | } | |
846 | #endif | |
847 | ||
fa7225c8 | 848 | static SecKeyAlgorithm SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key, SecPadding padding) { |
79b9da22 | 849 | switch (SecKeyGetAlgorithmId(key)) { |
fa7225c8 A |
850 | case kSecRSAAlgorithmID: |
851 | switch (padding) { | |
852 | case kSecPaddingNone: | |
853 | return kSecKeyAlgorithmRSAEncryptionRaw; | |
854 | case kSecPaddingPKCS1: | |
855 | return kSecKeyAlgorithmRSAEncryptionPKCS1; | |
856 | case kSecPaddingOAEP: | |
857 | return kSecKeyAlgorithmRSAEncryptionOAEPSHA1; | |
858 | default: | |
859 | return NULL; | |
860 | } | |
861 | default: | |
862 | return NULL; | |
b1ab9ed8 A |
863 | } |
864 | } | |
865 | ||
866 | OSStatus SecKeyEncrypt( | |
427c49bc A |
867 | SecKeyRef key, /* Public key */ |
868 | SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ | |
869 | const uint8_t *plainText, | |
870 | size_t plainTextLen, /* length of plainText */ | |
871 | uint8_t *cipherText, | |
872 | size_t *cipherTextLen) { /* IN/OUT */ | |
fa7225c8 A |
873 | SecKeyAlgorithm algorithm = SecKeyGetEncryptionAlgorithmForPadding(key, padding); |
874 | if (algorithm == NULL) { | |
875 | return errSecParam; | |
876 | } | |
877 | ||
878 | return SecKeyPerformLegacyOperation(key, plainText, plainTextLen, NULL, 0, cipherText, cipherTextLen, | |
879 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
880 | return SecKeyCreateEncryptedData(key, algorithm, in1, error); | |
881 | }); | |
b1ab9ed8 A |
882 | } |
883 | ||
884 | OSStatus SecKeyDecrypt( | |
427c49bc A |
885 | SecKeyRef key, /* Private key */ |
886 | SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ | |
887 | const uint8_t *cipherText, | |
888 | size_t cipherTextLen, /* length of cipherText */ | |
889 | uint8_t *plainText, | |
890 | size_t *plainTextLen) { /* IN/OUT */ | |
fa7225c8 A |
891 | SecKeyAlgorithm algorithm = SecKeyGetEncryptionAlgorithmForPadding(key, padding); |
892 | if (algorithm == NULL) { | |
893 | return errSecParam; | |
894 | } | |
895 | return SecKeyPerformLegacyOperation(key, cipherText, cipherTextLen, NULL, 0, plainText, plainTextLen, | |
896 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
897 | CFDataRef decrypted = SecKeyCreateDecryptedData(key, algorithm, in1, error); | |
898 | const UInt8 *data; | |
899 | if (decrypted != NULL && algorithm == kSecKeyAlgorithmRSAEncryptionRaw && | |
900 | *(data = CFDataGetBytePtr(decrypted)) == 0x00) { | |
901 | // Strip zero-padding from the beginning of the block, as the contract of this | |
902 | // function says. | |
903 | range->length = CFDataGetLength(decrypted); | |
904 | while (*data == 0x00 && range->length > 0) { | |
905 | range->location++; | |
906 | range->length--; | |
907 | data++; | |
908 | } | |
909 | } | |
910 | return decrypted; | |
911 | }); | |
b1ab9ed8 A |
912 | } |
913 | ||
914 | size_t SecKeyGetBlockSize(SecKeyRef key) { | |
915 | if (key->key_class->blockSize) | |
916 | return key->key_class->blockSize(key); | |
917 | return 0; | |
918 | } | |
919 | ||
920 | /* Private API functions. */ | |
921 | ||
922 | CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) { | |
866f8763 | 923 | return SecKeyCopyAttributes(key); |
b1ab9ed8 A |
924 | } |
925 | ||
926 | SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { | |
fa7225c8 A |
927 | CFErrorRef error = NULL; |
928 | SecKeyRef key = SecKeyCreateWithData(CFDictionaryGetValue(refAttributes, kSecValueData), refAttributes, &error); | |
929 | if (key == NULL) { | |
930 | CFStringRef description = CFErrorCopyDescription(error); | |
931 | secwarning("%@", description); | |
932 | CFRelease(description); | |
933 | CFRelease(error); | |
b1ab9ed8 | 934 | } |
fa7225c8 | 935 | return key; |
b1ab9ed8 A |
936 | } |
937 | ||
fa7225c8 A |
938 | static SecKeyAlgorithm SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key, const SecAsn1AlgId *algId, bool digestData) { |
939 | static const struct TableItem { | |
940 | const SecAsn1Oid *oid1, *oid2; | |
941 | const SecKeyAlgorithm *algorithms[2]; | |
942 | } translationTableRSA[] = { | |
943 | { &CSSMOID_SHA1WithRSA, &CSSMOID_SHA1, { | |
944 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1, | |
945 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1, | |
946 | } }, | |
947 | { &CSSMOID_SHA224WithRSA, &CSSMOID_SHA224, { | |
948 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224, | |
949 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224, | |
950 | } }, | |
951 | { &CSSMOID_SHA256WithRSA, &CSSMOID_SHA256, { | |
952 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256, | |
953 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256, | |
954 | } }, | |
955 | { &CSSMOID_SHA384WithRSA, &CSSMOID_SHA384, { | |
956 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384, | |
957 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384, | |
958 | } }, | |
959 | { &CSSMOID_SHA512WithRSA, &CSSMOID_SHA512, { | |
960 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512, | |
961 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512, | |
962 | } }, | |
963 | { &CSSMOID_MD5, NULL, { | |
964 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5, | |
965 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, | |
966 | } }, | |
79b9da22 A |
967 | { &CSSMOID_MD5WithRSA, NULL, { |
968 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5, | |
969 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, | |
970 | } }, | |
fa7225c8 A |
971 | { NULL }, |
972 | }, translationTableECDSA[] = { | |
973 | { &CSSMOID_ECDSA_WithSHA1, &CSSMOID_SHA1, { | |
974 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
975 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1, | |
976 | } }, | |
977 | { &CSSMOID_ECDSA_WithSHA224, &CSSMOID_SHA224, { | |
978 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
979 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224, | |
980 | } }, | |
981 | { &CSSMOID_ECDSA_WithSHA256, &CSSMOID_SHA256, { | |
982 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
983 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256, | |
984 | } }, | |
985 | { &CSSMOID_ECDSA_WithSHA384, &CSSMOID_SHA384, { | |
986 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
987 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384, | |
988 | } }, | |
989 | { &CSSMOID_ECDSA_WithSHA512, &CSSMOID_SHA512, { | |
990 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
991 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512, | |
992 | } }, | |
993 | { NULL }, | |
994 | }; | |
995 | ||
996 | const struct TableItem *table; | |
79b9da22 | 997 | switch (SecKeyGetAlgorithmId(key)) { |
b1ab9ed8 | 998 | case kSecRSAAlgorithmID: |
fa7225c8 | 999 | table = translationTableRSA; |
b1ab9ed8 A |
1000 | break; |
1001 | case kSecECDSAAlgorithmID: | |
fa7225c8 | 1002 | table = translationTableECDSA; |
b1ab9ed8 A |
1003 | break; |
1004 | default: | |
fa7225c8 | 1005 | return NULL; |
b1ab9ed8 | 1006 | } |
5c19dc3a | 1007 | |
fa7225c8 A |
1008 | for (; table->oid1 != NULL; table++) { |
1009 | if (SecAsn1OidCompare(table->oid1, &algId->algorithm) || | |
1010 | (table->oid2 != NULL && SecAsn1OidCompare(table->oid2, &algId->algorithm))) { | |
1011 | return *table->algorithms[digestData]; | |
1012 | } | |
b1ab9ed8 | 1013 | } |
fa7225c8 | 1014 | return NULL; |
b1ab9ed8 A |
1015 | } |
1016 | ||
1017 | OSStatus SecKeyDigestAndVerify( | |
fa7225c8 | 1018 | SecKeyRef key, /* Private key */ |
427c49bc A |
1019 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
1020 | const uint8_t *dataToDigest, /* signature over this data */ | |
1021 | size_t dataToDigestLen,/* length of dataToDigest */ | |
1022 | const uint8_t *sig, /* signature to verify */ | |
1023 | size_t sigLen) { /* length of sig */ | |
5c19dc3a | 1024 | |
fa7225c8 A |
1025 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, true); |
1026 | if (algorithm == NULL) { | |
1027 | return errSecUnimplemented; | |
1028 | } | |
5c19dc3a | 1029 | |
fa7225c8 A |
1030 | return SecKeyPerformLegacyOperation(key, dataToDigest, dataToDigestLen, sig, sigLen, NULL, NULL, |
1031 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
1032 | return SecKeyVerifySignature(key, algorithm, in1, in2, error) ? | |
1033 | kCFBooleanTrue : NULL; | |
1034 | }); | |
b1ab9ed8 A |
1035 | } |
1036 | ||
1037 | OSStatus SecKeyDigestAndSign( | |
fa7225c8 | 1038 | SecKeyRef key, /* Private key */ |
427c49bc A |
1039 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
1040 | const uint8_t *dataToDigest, /* signature over this data */ | |
1041 | size_t dataToDigestLen,/* length of dataToDigest */ | |
1042 | uint8_t *sig, /* signature, RETURNED */ | |
1043 | size_t *sigLen) { /* IN/OUT */ | |
fa7225c8 A |
1044 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, true); |
1045 | if (algorithm == NULL) { | |
1046 | return errSecUnimplemented; | |
1047 | } | |
1048 | ||
1049 | return SecKeyPerformLegacyOperation(key, dataToDigest, dataToDigestLen, NULL, 0, sig, sigLen, | |
1050 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
1051 | return SecKeyCreateSignature(key, algorithm, in1, error); | |
1052 | }); | |
b1ab9ed8 A |
1053 | } |
1054 | ||
1055 | OSStatus SecKeyVerifyDigest( | |
fa7225c8 | 1056 | SecKeyRef key, /* Private key */ |
427c49bc A |
1057 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
1058 | const uint8_t *digestData, /* signature over this digest */ | |
1059 | size_t digestDataLen,/* length of dataToDigest */ | |
1060 | const uint8_t *sig, /* signature to verify */ | |
1061 | size_t sigLen) { /* length of sig */ | |
fa7225c8 A |
1062 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, false); |
1063 | if (algorithm == NULL) { | |
1064 | return errSecUnimplemented; | |
1065 | } | |
1066 | ||
1067 | return SecKeyPerformLegacyOperation(key, digestData, digestDataLen, sig, sigLen, NULL, NULL, | |
1068 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
1069 | return SecKeyVerifySignature(key, algorithm, in1, in2, error) ? | |
1070 | kCFBooleanTrue : NULL; | |
1071 | }); | |
b1ab9ed8 A |
1072 | } |
1073 | ||
1074 | OSStatus SecKeySignDigest( | |
fa7225c8 | 1075 | SecKeyRef key, /* Private key */ |
427c49bc A |
1076 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
1077 | const uint8_t *digestData, /* signature over this digest */ | |
1078 | size_t digestDataLen,/* length of digestData */ | |
1079 | uint8_t *sig, /* signature, RETURNED */ | |
1080 | size_t *sigLen) { /* IN/OUT */ | |
fa7225c8 A |
1081 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, false); |
1082 | if (algorithm == NULL) { | |
1083 | return errSecUnimplemented; | |
1084 | } | |
1085 | ||
1086 | return SecKeyPerformLegacyOperation(key, digestData, digestDataLen, NULL, 0, sig, sigLen, | |
1087 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
1088 | return SecKeyCreateSignature(key, algorithm, in1, error); | |
1089 | }); | |
b1ab9ed8 A |
1090 | } |
1091 | ||
79b9da22 | 1092 | #if TARGET_OS_OSX |
5c19dc3a A |
1093 | /* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments, |
1094 | with output in the second argument). Therefore, avoid implementing this function here | |
1095 | if compiling for OS X. | |
1096 | */ | |
1097 | #else | |
79b9da22 A |
1098 | // Export original SecKeyGetAlgorithmID symbol for backward binary compatibility. |
1099 | #undef SecKeyGetAlgorithmID | |
1100 | CFIndex SecKeyGetAlgorithmID(SecKeyRef key); | |
5c19dc3a | 1101 | CFIndex SecKeyGetAlgorithmID(SecKeyRef key) { |
79b9da22 | 1102 | return SecKeyGetAlgorithmId(key); |
5c19dc3a A |
1103 | } |
1104 | #endif | |
b1ab9ed8 A |
1105 | |
1106 | OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic) { | |
1107 | if (key->key_class->version > 1 && key->key_class->copyPublic) | |
1108 | return key->key_class->copyPublic(key, serializedPublic); | |
1109 | return errSecUnimplemented; | |
1110 | } | |
1111 | ||
1112 | SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength) | |
1113 | { | |
1114 | switch (algorithmID) | |
1115 | { | |
1116 | case kSecRSAAlgorithmID: | |
1117 | return SecKeyCreateRSAPublicKey(allocator, | |
1118 | keyData, keyDataLength, | |
1119 | kSecKeyEncodingBytes); | |
1120 | case kSecECDSAAlgorithmID: | |
1121 | return SecKeyCreateECPublicKey(allocator, | |
1122 | keyData, keyDataLength, | |
1123 | kSecKeyEncodingBytes); | |
1124 | default: | |
1125 | return NULL; | |
1126 | } | |
1127 | } | |
1128 | ||
1129 | SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized) | |
1130 | { | |
1131 | return SecKeyCreateFromPublicBytes(allocator, algorithmID, CFDataGetBytePtr(serialized), CFDataGetLength(serialized)); | |
1132 | } | |
1133 | ||
1134 | // This is a bit icky hack to avoid changing the vtable for | |
1135 | // SecKey. | |
1136 | size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize) | |
1137 | { | |
1138 | size_t result = SecKeyGetBlockSize(key); | |
5c19dc3a | 1139 | |
79b9da22 A |
1140 | if (whichSize == 0 || whichSize == 10) { |
1141 | // kSecKeyKeySizeInBits is declared as 0 on iOS (SPI) and 10 on macOS (API). Unified implementation | |
1142 | // here deals with both values. | |
1143 | whichSize = kSecKeyKeySizeInBits; | |
1144 | } | |
1145 | ||
1146 | if (kSecECDSAAlgorithmID == SecKeyGetAlgorithmId(key)) { | |
b1ab9ed8 A |
1147 | switch (whichSize) { |
1148 | case kSecKeyEncryptedDataSize: | |
1149 | result = 0; | |
1150 | break; | |
1151 | case kSecKeySignatureSize: | |
427c49bc | 1152 | result = (result >= 66 ? 9 : 8) + 2 * result; |
b1ab9ed8 A |
1153 | break; |
1154 | case kSecKeyKeySizeInBits: | |
1155 | if (result >= 66) | |
1156 | return 521; | |
1157 | } | |
1158 | } | |
5c19dc3a | 1159 | |
b1ab9ed8 | 1160 | if (whichSize == kSecKeyKeySizeInBits) |
427c49bc | 1161 | result *= 8; |
5c19dc3a | 1162 | |
b1ab9ed8 | 1163 | return result; |
5c19dc3a | 1164 | |
427c49bc | 1165 | } |
b1ab9ed8 | 1166 | |
427c49bc A |
1167 | OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData) |
1168 | { | |
1169 | CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, | |
1170 | kSecReturnRef, kCFBooleanTrue, | |
1171 | kSecClass, kSecClassKey, | |
1172 | kSecValuePersistentRef, persistentRef, | |
1173 | NULL); | |
1174 | CFTypeRef foundRef = NULL; | |
1175 | OSStatus status = SecItemCopyMatching(query, &foundRef); | |
5c19dc3a | 1176 | |
427c49bc A |
1177 | if (status == errSecSuccess) { |
1178 | if (CFGetTypeID(foundRef) == SecKeyGetTypeID()) { | |
1179 | *lookedUpData = (SecKeyRef) foundRef; | |
1180 | foundRef = NULL; | |
1181 | status = errSecSuccess; | |
1182 | } else { | |
1183 | status = errSecItemNotFound; | |
1184 | } | |
1185 | } | |
5c19dc3a | 1186 | |
427c49bc A |
1187 | CFReleaseSafe(foundRef); |
1188 | CFReleaseSafe(query); | |
5c19dc3a | 1189 | |
427c49bc | 1190 | return status; |
b1ab9ed8 A |
1191 | } |
1192 | ||
427c49bc A |
1193 | OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef) |
1194 | { | |
29734401 A |
1195 | if (!key) { |
1196 | secerror("SecKeyCopyPersistentRef: Need a key reference for this to work"); | |
1197 | return errSecParam; | |
1198 | } | |
1199 | if (!persistentRef) { | |
1200 | secerror("SecKeyCopyPersistentRef: Need a persistentRef pointer for this to work"); | |
1201 | return errSecParam; | |
d64be36e | 1202 | } |
29734401 | 1203 | |
427c49bc A |
1204 | CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, |
1205 | kSecReturnPersistentRef, kCFBooleanTrue, | |
1206 | kSecValueRef, key, | |
1207 | kSecAttrSynchronizable, kSecAttrSynchronizableAny, | |
1208 | NULL); | |
1209 | CFTypeRef foundRef = NULL; | |
1210 | OSStatus status = SecItemCopyMatching(query, &foundRef); | |
5c19dc3a | 1211 | |
427c49bc A |
1212 | if (status == errSecSuccess) { |
1213 | if (CFGetTypeID(foundRef) == CFDataGetTypeID()) { | |
1214 | *persistentRef = foundRef; | |
1215 | foundRef = NULL; | |
1216 | } else { | |
29734401 | 1217 | secerror("SecKeyCopyPersistentRef: SecItemCopyMatching returned success, but we got type %lu instead of CFData for key %@.", CFGetTypeID(foundRef), key); |
427c49bc A |
1218 | status = errSecItemNotFound; |
1219 | } | |
29734401 A |
1220 | } else { |
1221 | secerror("SecKeyCopyPersistentRef: received status %i for key %@", (int)status, key); | |
1222 | CFStringRef str = CFStringCreateWithFormat(NULL, NULL, CFSTR("Expected to find persistentref for key %@"), key); | |
1223 | __security_stackshotreport(str, (int)status); | |
1224 | CFReleaseNull(str); | |
427c49bc | 1225 | } |
5c19dc3a | 1226 | |
427c49bc A |
1227 | CFReleaseSafe(foundRef); |
1228 | CFReleaseSafe(query); | |
5c19dc3a | 1229 | |
427c49bc A |
1230 | return status; |
1231 | } | |
d8f41ccd A |
1232 | |
1233 | /* | |
1234 | * | |
1235 | */ | |
1236 | ||
5c19dc3a | 1237 | #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); |
d8f41ccd A |
1238 | |
1239 | SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg, "kSecKeyWrapPGPSymAlg"); | |
1240 | SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint, "kSecKeyWrapPGPFingerprint"); | |
1241 | SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg, "kSecKeyWrapPGPWrapAlg"); | |
1242 | SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags, "kSecKeyWrapPGPECFlags"); | |
1243 | SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128"); | |
1244 | SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256"); | |
1245 | ||
1246 | #undef SEC_CONST_DECL | |
1247 | ||
1248 | CFDataRef | |
1249 | _SecKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) | |
1250 | { | |
1251 | if (error) | |
1252 | *error = NULL; | |
1253 | if (outParam) | |
1254 | *outParam = NULL; | |
1255 | if (key->key_class->version > 2 && key->key_class->copyWrapKey) | |
1256 | return key->key_class->copyWrapKey(key, type, unwrappedKey, parameters, outParam, error); | |
1257 | SecError(errSecUnsupportedOperation, error, CFSTR("No key wrap supported for key %@"), key); | |
1258 | return NULL; | |
1259 | } | |
1260 | ||
1261 | CFDataRef | |
1262 | _SecKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) | |
1263 | { | |
1264 | if (error) | |
1265 | *error = NULL; | |
1266 | if (outParam) | |
1267 | *outParam = NULL; | |
1268 | if (key->key_class->version > 2 && key->key_class->copyUnwrapKey) | |
1269 | return key->key_class->copyUnwrapKey(key, type, wrappedKey, parameters, outParam, error); | |
1270 | ||
1271 | SecError(errSecUnsupportedOperation, error, CFSTR("No key unwrap for key %@"), key); | |
1272 | return NULL; | |
1273 | } | |
fa7225c8 | 1274 | |
866f8763 A |
1275 | static CFIndex SecKeyParamsGetCFIndex(CFTypeRef value, CFStringRef errName, CFErrorRef *error) { |
1276 | CFIndex result = -1; | |
1277 | CFNumberRef localValue = NULL; | |
1278 | ||
1279 | if (isString(value)) { | |
1280 | CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, CFLocaleGetSystem(), kCFNumberFormatterDecimalStyle); | |
1281 | localValue = CFNumberFormatterCreateNumberFromString(kCFAllocatorDefault, formatter, value, NULL, kCFNumberFormatterParseIntegersOnly); | |
1282 | CFReleaseSafe(formatter); | |
1283 | ||
1284 | if (localValue) { | |
1285 | CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%@"), localValue); | |
1286 | if (CFEqual(t, value)) { | |
1287 | value = localValue; | |
1288 | } | |
1289 | CFReleaseSafe(t); | |
fa7225c8 | 1290 | } |
866f8763 A |
1291 | } |
1292 | ||
1293 | if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) { | |
1294 | if (!CFNumberGetValue(value, kCFNumberCFIndexType, &result) || result < 0) { | |
fa7225c8 | 1295 | SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); |
fa7225c8 | 1296 | } |
fa7225c8 A |
1297 | } else { |
1298 | SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); | |
1299 | } | |
866f8763 A |
1300 | |
1301 | CFReleaseSafe(localValue); | |
fa7225c8 A |
1302 | return result; |
1303 | } | |
1304 | ||
1305 | SecKeyRef SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef parameters, CFErrorRef *error) { | |
1306 | ||
1307 | SecKeyRef key = NULL; | |
1308 | CFAllocatorRef allocator = NULL; | |
1309 | ||
866f8763 A |
1310 | if (CFDictionaryGetValue(parameters, kSecAttrTokenID) != NULL) { |
1311 | return SecKeyCreateCTKKey(allocator, parameters, error); | |
1312 | } | |
ecaf5866 A |
1313 | else if (!keyData) { |
1314 | SecError(errSecParam, error, CFSTR("Failed to provide key data to SecKeyCreateWithData")); | |
1315 | return NULL; | |
1316 | } | |
fa7225c8 | 1317 | /* First figure out the key type (algorithm). */ |
866f8763 | 1318 | CFIndex algorithm, class; |
fa7225c8 | 1319 | CFTypeRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); |
866f8763 | 1320 | require_quiet((algorithm = SecKeyParamsGetCFIndex(ktype, CFSTR("key type"), error)) >= 0, out); |
fa7225c8 | 1321 | CFTypeRef kclass = CFDictionaryGetValue(parameters, kSecAttrKeyClass); |
866f8763 | 1322 | require_quiet((class = SecKeyParamsGetCFIndex(kclass, CFSTR("key class"), error)) >= 0, out); |
fa7225c8 A |
1323 | |
1324 | switch (class) { | |
1325 | case 0: // kSecAttrKeyClassPublic | |
1326 | switch (algorithm) { | |
1327 | case 42: // kSecAlgorithmRSA | |
1328 | key = SecKeyCreateRSAPublicKey(allocator, | |
1329 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1330 | kSecKeyEncodingBytes); | |
1331 | if (key == NULL) { | |
1332 | SecError(errSecParam, error, CFSTR("RSA public key creation from data failed")); | |
1333 | } | |
1334 | break; | |
1335 | case 43: // kSecAlgorithmECDSA | |
1336 | case 73: // kSecAlgorithmEC | |
1337 | key = SecKeyCreateECPublicKey(allocator, | |
1338 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1339 | kSecKeyEncodingBytes); | |
1340 | if (key == NULL) { | |
1341 | SecError(errSecParam, error, CFSTR("EC public key creation from data failed")); | |
1342 | } | |
1343 | break; | |
1344 | default: | |
1345 | SecError(errSecParam, error, CFSTR("Unsupported public key type: %@"), ktype); | |
1346 | break; | |
1347 | }; | |
1348 | break; | |
1349 | case 1: // kSecAttrKeyClassPrivate | |
fa7225c8 A |
1350 | switch (algorithm) { |
1351 | case 42: // kSecAlgorithmRSA | |
1352 | key = SecKeyCreateRSAPrivateKey(allocator, | |
1353 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1354 | kSecKeyEncodingBytes); | |
1355 | if (key == NULL) { | |
1356 | SecError(errSecParam, error, CFSTR("RSA private key creation from data failed")); | |
1357 | } | |
1358 | break; | |
1359 | case 43: // kSecAlgorithmECDSA | |
1360 | case 73: // kSecAlgorithmEC | |
1361 | key = SecKeyCreateECPrivateKey(allocator, | |
1362 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1363 | kSecKeyEncodingBytes); | |
1364 | if (key == NULL) { | |
b54c578e | 1365 | SecError(errSecParam, error, CFSTR("EC private key creation from data failed")); |
fa7225c8 A |
1366 | } |
1367 | break; | |
1368 | default: | |
1369 | SecError(errSecParam, error, CFSTR("Unsupported private key type: %@"), ktype); | |
1370 | break; | |
1371 | }; | |
1372 | break; | |
1373 | case 2: // kSecAttrKeyClassSymmetric | |
1374 | SecError(errSecUnimplemented, error, CFSTR("Unsupported symmetric key type: %@"), ktype); | |
1375 | break; | |
1376 | default: | |
1377 | SecError(errSecParam, error, CFSTR("Unsupported key class: %@"), kclass); | |
1378 | break; | |
1379 | } | |
1380 | ||
1381 | out: | |
1382 | return key; | |
1383 | } | |
1384 | ||
ecaf5866 A |
1385 | // Similar to CFErrorPropagate, but does not consult input value of *error, it can contain any garbage and if overwritten, previous value is never released. |
1386 | static inline bool SecKeyErrorPropagate(bool succeeded, CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) { | |
1387 | if (succeeded) { | |
1388 | return true; | |
1389 | } else { | |
1390 | if (error) { | |
1391 | *error = possibleError; | |
1392 | } else { | |
1393 | CFRelease(possibleError); | |
1394 | } | |
1395 | return false; | |
1396 | } | |
1397 | } | |
1398 | ||
fa7225c8 A |
1399 | CFDataRef SecKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { |
1400 | if (!key->key_class->copyExternalRepresentation) { | |
ecaf5866 A |
1401 | if (error != NULL) { |
1402 | *error = NULL; | |
1403 | } | |
fa7225c8 A |
1404 | SecError(errSecUnimplemented, error, CFSTR("export not implemented for key %@"), key); |
1405 | return NULL; | |
1406 | } | |
1407 | ||
ecaf5866 A |
1408 | CFErrorRef localError = NULL; |
1409 | CFDataRef result = key->key_class->copyExternalRepresentation(key, &localError); | |
1410 | SecKeyErrorPropagate(result != NULL, localError, error); | |
1411 | return result; | |
fa7225c8 A |
1412 | } |
1413 | ||
1414 | CFDictionaryRef SecKeyCopyAttributes(SecKeyRef key) { | |
866f8763 | 1415 | if (key->key_class->copyDictionary) { |
fa7225c8 | 1416 | return key->key_class->copyDictionary(key); |
866f8763 A |
1417 | } else { |
1418 | // Create dictionary with basic values derived from other known information of the key. | |
1419 | CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); | |
1420 | CFIndex blockSize = SecKeyGetBlockSize(key) * 8; | |
1421 | if (blockSize > 0) { | |
1422 | CFNumberRef blockSizeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &blockSize); | |
1423 | CFDictionarySetValue(dict, kSecAttrKeySizeInBits, blockSizeRef); | |
1424 | CFRelease(blockSizeRef); | |
1425 | } | |
1426 | ||
79b9da22 | 1427 | switch (SecKeyGetAlgorithmId(key)) { |
866f8763 A |
1428 | case kSecRSAAlgorithmID: |
1429 | CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeRSA); | |
1430 | break; | |
1431 | case kSecECDSAAlgorithmID: | |
1432 | CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); | |
1433 | break; | |
1434 | } | |
1435 | ||
1436 | if (key->key_class->rawSign != NULL || key->key_class->decrypt != NULL) { | |
1437 | CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPrivate); | |
1438 | } else if (key->key_class->rawVerify != NULL || key->key_class->encrypt != NULL) { | |
1439 | CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic); | |
1440 | } | |
1441 | ||
1442 | return dict; | |
1443 | } | |
fa7225c8 A |
1444 | } |
1445 | ||
1446 | SecKeyRef SecKeyCopyPublicKey(SecKeyRef key) { | |
1447 | SecKeyRef result = NULL; | |
1448 | if (key->key_class->version >= 4 && key->key_class->copyPublicKey) { | |
1449 | result = key->key_class->copyPublicKey(key); | |
1450 | if (result != NULL) { | |
1451 | return result; | |
1452 | } | |
1453 | } | |
1454 | ||
1455 | CFDataRef serializedPublic = NULL; | |
1456 | ||
1457 | require_noerr_quiet(SecKeyCopyPublicBytes(key, &serializedPublic), fail); | |
1458 | require_quiet(serializedPublic, fail); | |
1459 | ||
79b9da22 | 1460 | result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmId(key), serializedPublic); |
fa7225c8 A |
1461 | |
1462 | fail: | |
1463 | CFReleaseSafe(serializedPublic); | |
1464 | return result; | |
1465 | } | |
1466 | ||
1467 | SecKeyRef SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) { | |
b54c578e A |
1468 | @autoreleasepool { |
1469 | SecKeyRef privKey = NULL, pubKey = NULL; | |
1470 | OSStatus status = SecKeyGeneratePair(parameters, &pubKey, &privKey); | |
1471 | if (status != errSecSuccess) { | |
1472 | if (error != NULL) { | |
1473 | *error = NULL; | |
1474 | } | |
1475 | SecError(status, error, CFSTR("Key generation failed, error %d"), (int)status); | |
ecaf5866 | 1476 | } |
b54c578e A |
1477 | CFReleaseSafe(pubKey); |
1478 | return privKey; | |
ecaf5866 | 1479 | } |
fa7225c8 A |
1480 | } |
1481 | ||
3a7be6fd A |
1482 | SecKeyRef SecKeyCreateDuplicate(SecKeyRef key) { |
1483 | if (key->key_class->version >= 4 && key->key_class->createDuplicate) { | |
1484 | return key->key_class->createDuplicate(key); | |
1485 | } else { | |
1486 | return (SecKeyRef)CFRetain(key); | |
1487 | } | |
1488 | } | |
1489 | ||
b04fe171 | 1490 | Boolean SecKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) { |
dbe77505 A |
1491 | if (key == NULL) { |
1492 | SecCTKKeySetTestMode(name, value); | |
1493 | return true; | |
1494 | } else if (key->key_class->version >= 4 && key->key_class->setParameter) { | |
ecaf5866 A |
1495 | CFErrorRef localError = NULL; |
1496 | Boolean result = key->key_class->setParameter(key, name, value, &localError); | |
1497 | SecKeyErrorPropagate(result, localError, error); | |
1498 | return result; | |
b04fe171 | 1499 | } else { |
ecaf5866 A |
1500 | if (error != NULL) { |
1501 | *error = NULL; | |
1502 | } | |
b04fe171 A |
1503 | return SecError(errSecUnimplemented, error, CFSTR("setParameter not implemented for %@"), key); |
1504 | } | |
1505 | } | |
1506 | ||
fa7225c8 A |
1507 | #pragma mark Generic algorithm adaptor lookup and invocation |
1508 | ||
1509 | static CFTypeRef SecKeyCopyBackendOperationResult(SecKeyOperationContext *context, SecKeyAlgorithm algorithm, | |
1510 | CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
b04fe171 | 1511 | CFTypeRef result = kCFNull; |
fa7225c8 A |
1512 | assert(CFArrayGetCount(context->algorithm) > 0); |
1513 | if (context->key->key_class->version >= 4 && context->key->key_class->copyOperationResult != NULL) { | |
1514 | return context->key->key_class->copyOperationResult(context->key, context->operation, algorithm, | |
1515 | context->algorithm, context->mode, in1, in2, error); | |
1516 | } | |
1517 | ||
1518 | // Mapping from algorithms to legacy SecPadding values. | |
1519 | static const struct { | |
1520 | const SecKeyAlgorithm *algorithm; | |
1521 | CFIndex keyAlg; | |
1522 | SecPadding padding; | |
1523 | } paddingMap[] = { | |
1524 | { &kSecKeyAlgorithmRSASignatureRaw, kSecRSAAlgorithmID, kSecPaddingNone }, | |
1525 | { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw, kSecRSAAlgorithmID, kSecPaddingPKCS1 }, | |
1526 | { &kSecKeyAlgorithmECDSASignatureRFC4754, kSecECDSAAlgorithmID, kSecPaddingSigRaw }, | |
1527 | { &kSecKeyAlgorithmECDSASignatureDigestX962, kSecECDSAAlgorithmID, kSecPaddingPKCS1 }, | |
1528 | { &kSecKeyAlgorithmRSAEncryptionRaw, kSecRSAAlgorithmID, kSecPaddingNone }, | |
1529 | { &kSecKeyAlgorithmRSAEncryptionPKCS1, kSecRSAAlgorithmID, kSecPaddingPKCS1 }, | |
1530 | { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1, kSecRSAAlgorithmID, kSecPaddingOAEP }, | |
1531 | }; | |
1532 | SecPadding padding = (SecPadding)-1; | |
79b9da22 | 1533 | CFIndex keyAlg = SecKeyGetAlgorithmId(context->key); |
fa7225c8 A |
1534 | for (size_t i = 0; i < array_size(paddingMap); ++i) { |
1535 | if (keyAlg == paddingMap[i].keyAlg && CFEqual(algorithm, *paddingMap[i].algorithm)) { | |
1536 | padding = paddingMap[i].padding; | |
1537 | break; | |
1538 | } | |
1539 | } | |
1540 | require_quiet(padding != (SecPadding)-1, out); | |
1541 | ||
1542 | // Check legacy virtual table entries. | |
1543 | size_t size = 0; | |
1544 | OSStatus status = errSecSuccess; | |
1545 | switch (context->operation) { | |
1546 | case kSecKeyOperationTypeSign: | |
1547 | if (context->key->key_class->rawSign != NULL) { | |
1548 | result = kCFBooleanTrue; | |
1549 | if (context->mode == kSecKeyOperationModePerform) { | |
1550 | size = SecKeyGetSize(context->key, kSecKeySignatureSize); | |
1551 | result = CFDataCreateMutableWithScratch(NULL, size); | |
1552 | status = context->key->key_class->rawSign(context->key, padding, | |
1553 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1554 | CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); | |
1555 | } | |
1556 | } | |
1557 | break; | |
1558 | case kSecKeyOperationTypeVerify: | |
1559 | if (context->key->key_class->rawVerify != NULL) { | |
1560 | result = kCFBooleanTrue; | |
1561 | if (context->mode == kSecKeyOperationModePerform) { | |
1562 | status = context->key->key_class->rawVerify(context->key, padding, | |
1563 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1564 | CFDataGetBytePtr(in2), CFDataGetLength(in2)); | |
1565 | } | |
1566 | } | |
1567 | break; | |
1568 | case kSecKeyOperationTypeEncrypt: | |
1569 | if (context->key->key_class->encrypt != NULL) { | |
1570 | result = kCFBooleanTrue; | |
1571 | if (context->mode == kSecKeyOperationModePerform) { | |
1572 | size = SecKeyGetSize(context->key, kSecKeyEncryptedDataSize); | |
1573 | result = CFDataCreateMutableWithScratch(NULL, size); | |
1574 | status = context->key->key_class->encrypt(context->key, padding, | |
1575 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1576 | CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); | |
1577 | } | |
1578 | } | |
1579 | break; | |
1580 | case kSecKeyOperationTypeDecrypt: | |
1581 | if (context->key->key_class->decrypt != NULL) { | |
1582 | result = kCFBooleanTrue; | |
1583 | if (context->mode == kSecKeyOperationModePerform) { | |
1584 | size = SecKeyGetSize(context->key, kSecKeyEncryptedDataSize); | |
1585 | result = CFDataCreateMutableWithScratch(NULL, size); | |
1586 | status = context->key->key_class->decrypt(context->key, padding, | |
1587 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1588 | CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); | |
1589 | } | |
1590 | } | |
1591 | break; | |
1592 | default: | |
1593 | goto out; | |
1594 | } | |
1595 | ||
1596 | if (status == errSecSuccess) { | |
1597 | if (CFGetTypeID(result) == CFDataGetTypeID()) { | |
1598 | CFDataSetLength((CFMutableDataRef)result, size); | |
1599 | } | |
1600 | } else { | |
1601 | SecError(status, error, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context->operation, (int)padding); | |
1602 | CFReleaseNull(result); | |
1603 | } | |
1604 | ||
1605 | out: | |
1606 | return result; | |
1607 | } | |
1608 | ||
1609 | CFTypeRef SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
b54c578e A |
1610 | @autoreleasepool { |
1611 | // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error. | |
1612 | CFIndex algorithmCount = CFArrayGetCount(context->algorithm); | |
1613 | for (CFIndex index = 0; index < algorithmCount - 1; index++) { | |
1614 | SecKeyAlgorithm indexAlgorithm = CFArrayGetValueAtIndex(context->algorithm, index); | |
1615 | for (CFIndex tested = index + 1; tested < algorithmCount; tested++) { | |
1616 | require_quiet(!CFEqual(indexAlgorithm, CFArrayGetValueAtIndex(context->algorithm, tested)), fail); | |
1617 | } | |
fa7225c8 | 1618 | } |
fa7225c8 | 1619 | |
b54c578e A |
1620 | SecKeyAlgorithm algorithm = CFArrayGetValueAtIndex(context->algorithm, algorithmCount - 1); |
1621 | CFTypeRef output = SecKeyCopyBackendOperationResult(context, algorithm, in1, in2, error); | |
1622 | if (output != kCFNull) { | |
1623 | // Backend handled the operation, return result. | |
1624 | return output; | |
1625 | } | |
fa7225c8 | 1626 | |
b54c578e A |
1627 | // To silence static analyzer. |
1628 | CFReleaseSafe(output); | |
fa7225c8 | 1629 | |
b54c578e A |
1630 | // Get adaptor which is able to handle requested algorithm. |
1631 | SecKeyAlgorithmAdaptor adaptor = SecKeyGetAlgorithmAdaptor(context->operation, algorithm); | |
1632 | require_quiet(adaptor != NULL, fail); | |
fa7225c8 | 1633 | |
b54c578e A |
1634 | // Invoke the adaptor and return result. |
1635 | CFTypeRef result = adaptor(context, in1, in2, error); | |
1636 | require_quiet(result != kCFNull, fail); | |
1637 | return result; | |
fa7225c8 | 1638 | |
b54c578e A |
1639 | fail: |
1640 | if (context->mode == kSecKeyOperationModePerform) { | |
1641 | SecError(errSecParam, error, CFSTR("%@: algorithm not supported by the key %@"), | |
1642 | CFArrayGetValueAtIndex(context->algorithm, 0), context->key); | |
1643 | return NULL; | |
1644 | } else { | |
1645 | return kCFNull; | |
1646 | } | |
fa7225c8 A |
1647 | } |
1648 | } | |
1649 | ||
1650 | #pragma mark Algorithm-related SecKey API entry points | |
1651 | ||
1652 | static CFMutableArrayRef SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm) { | |
1653 | CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); | |
1654 | CFArrayAppendValue(result, algorithm); | |
1655 | return result; | |
1656 | } | |
1657 | ||
1658 | CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error) { | |
ecaf5866 | 1659 | CFErrorRef localError = NULL; |
fa7225c8 | 1660 | SecKeyOperationContext context = { key, kSecKeyOperationTypeSign, SecKeyCreateAlgorithmArray(algorithm) }; |
ecaf5866 | 1661 | CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, dataToSign, NULL, &localError); |
fa7225c8 | 1662 | SecKeyOperationContextDestroy(&context); |
ecaf5866 | 1663 | SecKeyErrorPropagate(result != NULL, localError, error); |
fa7225c8 A |
1664 | return result; |
1665 | } | |
1666 | ||
1667 | Boolean SecKeyVerifySignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef signedData, CFDataRef signature, | |
1668 | CFErrorRef *error) { | |
ecaf5866 | 1669 | CFErrorRef localError = NULL; |
fa7225c8 | 1670 | SecKeyOperationContext context = { key, kSecKeyOperationTypeVerify, SecKeyCreateAlgorithmArray(algorithm) }; |
ecaf5866 | 1671 | CFTypeRef res = SecKeyRunAlgorithmAndCopyResult(&context, signedData, signature, &localError); |
fa7225c8 A |
1672 | Boolean result = CFEqualSafe(res, kCFBooleanTrue); |
1673 | CFReleaseSafe(res); | |
1674 | SecKeyOperationContextDestroy(&context); | |
ecaf5866 | 1675 | SecKeyErrorPropagate(result, localError, error); |
fa7225c8 A |
1676 | return result; |
1677 | } | |
1678 | ||
dbe77505 A |
1679 | CFDataRef SecKeyCreateEncryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, |
1680 | CFDictionaryRef parameters, CFErrorRef *error) { | |
ecaf5866 | 1681 | CFErrorRef localError = NULL; |
fa7225c8 | 1682 | SecKeyOperationContext context = { key, kSecKeyOperationTypeEncrypt, SecKeyCreateAlgorithmArray(algorithm) }; |
dbe77505 | 1683 | CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, plaintext, parameters, &localError); |
fa7225c8 | 1684 | SecKeyOperationContextDestroy(&context); |
ecaf5866 | 1685 | SecKeyErrorPropagate(result, localError, error); |
fa7225c8 A |
1686 | return result; |
1687 | } | |
1688 | ||
dbe77505 A |
1689 | CFDataRef SecKeyCreateEncryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, CFErrorRef *error) { |
1690 | return SecKeyCreateEncryptedDataWithParameters(key, algorithm, plaintext, NULL, error); | |
1691 | } | |
1692 | ||
1693 | CFDataRef SecKeyCreateDecryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, | |
1694 | CFDictionaryRef parameters, CFErrorRef *error) { | |
fa7225c8 | 1695 | SecKeyOperationContext context = { key, kSecKeyOperationTypeDecrypt, SecKeyCreateAlgorithmArray(algorithm) }; |
dbe77505 | 1696 | CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, ciphertext, parameters, error); |
fa7225c8 A |
1697 | SecKeyOperationContextDestroy(&context); |
1698 | return result; | |
1699 | } | |
1700 | ||
dbe77505 A |
1701 | CFDataRef SecKeyCreateDecryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, CFErrorRef *error) { |
1702 | return SecKeyCreateDecryptedDataWithParameters(key, algorithm, ciphertext, NULL, error); | |
1703 | } | |
1704 | ||
fa7225c8 A |
1705 | CFDataRef SecKeyCopyKeyExchangeResult(SecKeyRef key, SecKeyAlgorithm algorithm, SecKeyRef publicKey, |
1706 | CFDictionaryRef parameters, CFErrorRef *error) { | |
ecaf5866 | 1707 | CFErrorRef localError = NULL; |
fa7225c8 A |
1708 | CFDataRef publicKeyData = NULL, result = NULL; |
1709 | SecKeyOperationContext context = { key, kSecKeyOperationTypeKeyExchange, SecKeyCreateAlgorithmArray(algorithm) }; | |
1710 | require_quiet(publicKeyData = SecKeyCopyExternalRepresentation(publicKey, error), out); | |
ecaf5866 A |
1711 | result = SecKeyRunAlgorithmAndCopyResult(&context, publicKeyData, parameters, &localError); |
1712 | SecKeyErrorPropagate(result != NULL, localError, error); | |
fa7225c8 A |
1713 | |
1714 | out: | |
1715 | CFReleaseSafe(publicKeyData); | |
1716 | SecKeyOperationContextDestroy(&context); | |
1717 | return result; | |
1718 | } | |
1719 | ||
1720 | Boolean SecKeyIsAlgorithmSupported(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm) { | |
1721 | SecKeyOperationContext context = { key, operation, SecKeyCreateAlgorithmArray(algorithm), kSecKeyOperationModeCheckIfSupported }; | |
1722 | CFErrorRef error = NULL; | |
1723 | CFTypeRef res = SecKeyRunAlgorithmAndCopyResult(&context, NULL, NULL, &error); | |
1724 | Boolean result = CFEqualSafe(res, kCFBooleanTrue); | |
1725 | CFReleaseSafe(res); | |
1726 | CFReleaseSafe(error); | |
1727 | SecKeyOperationContextDestroy(&context); | |
1728 | return result; | |
1729 | } |