]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCTKKey.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / Security / SecCTKKey.c
1 /*
2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <AssertMacros.h>
25 #include <Security/SecFramework.h>
26 #include <Security/SecKeyPriv.h>
27 #include <Security/SecItem.h>
28 #include <Security/SecItemPriv.h>
29 #include <Security/SecItemInternal.h>
30 #include <Security/SecBasePriv.h>
31 #include <utilities/SecCFError.h>
32 #include <utilities/SecCFWrappers.h>
33 #include <ctkclient.h>
34 #include <libaks_acl_cf_keys.h>
35
36 #include "SecECKey.h"
37 #include "SecRSAKey.h"
38 #include "SecCTKKeyPriv.h"
39
40 const CFStringRef kSecUseToken = CFSTR("u_Token");
41 const CFStringRef kSecUseTokenObjectID = CFSTR("u_TokenOID");
42
43 typedef struct {
44 TKTokenRef token;
45 CFStringRef token_id;
46 CFDataRef objectID;
47 SecCFDictionaryCOW auth_params;
48 SecCFDictionaryCOW attributes;
49 } SecCTKKeyData;
50
51 static void SecCTKKeyDestroy(SecKeyRef key) {
52 SecCTKKeyData *kd = key->key;
53 CFReleaseSafe(kd->token);
54 CFReleaseSafe(kd->token_id);
55 CFReleaseSafe(kd->objectID);
56 CFReleaseSafe(kd->auth_params.mutable_dictionary);
57 CFReleaseSafe(kd->attributes.mutable_dictionary);
58 }
59
60 static CFIndex SecCTKGetAlgorithmID(SecKeyRef key) {
61 SecCTKKeyData *kd = key->key;
62 if (CFEqualSafe(CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType), kSecAttrKeyTypeEC))
63 return kSecECDSAAlgorithmID;
64 else
65 return kSecRSAAlgorithmID;
66 }
67
68 static SecItemAuthResult SecCTKProcessError(CFStringRef operation, TKTokenRef token, CFDataRef object_id, CFArrayRef *ac_pairs, CFErrorRef *error) {
69 if (CFEqualSafe(CFErrorGetDomain(*error), CFSTR(kTKErrorDomain)) &&
70 CFErrorGetCode(*error) == kTKErrorCodeAuthenticationFailed) {
71 CFDataRef access_control = TKTokenCopyObjectAccessControl(token, object_id, error);
72 if (access_control != NULL) {
73 CFArrayRef ac_pair = CFArrayCreateForCFTypes(NULL, access_control, operation, NULL);
74 CFAssignRetained(*ac_pairs, CFArrayCreateForCFTypes(NULL, ac_pair, NULL));
75
76 CFReleaseNull(*error);
77 CFRelease(ac_pair);
78 CFRelease(access_control);
79 return kSecItemAuthResultNeedAuth;
80 }
81 }
82 return kSecItemAuthResultError;
83 }
84
85 static OSStatus SecCTKKeyRawSign(SecKeyRef key, SecPadding padding,
86 const uint8_t *dataToSign, size_t dataToSignLen,
87 uint8_t *sig, size_t *sigLen) {
88 OSStatus status = errSecSuccess;
89 CFDataRef digest = CFDataCreateWithBytesNoCopy(NULL, dataToSign, dataToSignLen, kCFAllocatorNull);
90
91 SecCTKKeyData *kd = key->key;
92 __block SecCFDictionaryCOW sign_auth_params = { kd->auth_params.dictionary };
93 __block TKTokenRef token = CFRetainSafe(kd->token);
94
95 status = SecOSStatusWith(^bool(CFErrorRef *error) {
96 return SecItemAuthDo(&sign_auth_params, error, ^SecItemAuthResult(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error) {
97 CFDataRef signature = NULL;
98 SecItemAuthResult auth_result = kSecItemAuthResultOK;
99
100 if (sign_auth_params.mutable_dictionary != NULL) {
101 // auth_params were modified, so reconnect the token in order to update the attributes.
102 TKTokenRef new_token = NULL;
103 require_quiet(new_token = SecTokenCreate(kd->token_id, auth_params, error), out);
104 CFAssignRetained(token, new_token);
105 }
106
107 require_action_quiet(signature = TKTokenCopySignature(token, kd->objectID, padding, digest, error), out,
108 auth_result = SecCTKProcessError(kAKSKeyOpSign, token, kd->objectID, ac_pairs, error));
109 require_action_quiet((CFIndex)*sigLen >= CFDataGetLength(signature), out,
110 SecError(errSecParam, error, CFSTR("signature buffer too small (%ulb required)"),
111 (unsigned long)CFDataGetLength(signature)));
112 *sigLen = CFDataGetLength(signature);
113 CFDataGetBytes(signature, CFRangeMake(0, *sigLen), sig);
114 *sigLen = CFDataGetLength(signature);
115
116 out:
117 CFReleaseSafe(signature);
118 return auth_result;
119 });
120 });
121
122 CFReleaseSafe(sign_auth_params.mutable_dictionary);
123 CFReleaseSafe(digest);
124 CFReleaseSafe(token);
125 return status;
126 }
127
128 static size_t SecCTKKeyBlockSize(SecKeyRef key) {
129 SecCTKKeyData *kd = key->key;
130 CFTypeRef keySize = CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeySizeInBits);
131 if (CFGetTypeID(keySize) == CFNumberGetTypeID()) {
132 CFIndex bitSize;
133 if (CFNumberGetValue(keySize, kCFNumberCFIndexType, &bitSize))
134 return (bitSize + 7) / 8;
135 }
136
137 return 0;
138 }
139
140 static OSStatus SecCTKKeyCopyPublicOctets(SecKeyRef key, CFDataRef *data) {
141 OSStatus status = errSecSuccess;
142 CFErrorRef error = NULL;
143 CFDataRef publicData = NULL;
144
145 SecCTKKeyData *kd = key->key;
146 require_action_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out,
147 status = SecErrorGetOSStatus(error));
148 *data = publicData;
149
150 out:
151 CFReleaseSafe(error);
152 return status;
153 }
154
155 static CFStringRef SecCTKKeyCopyKeyDescription(SecKeyRef key) {
156 SecCTKKeyData *kd = key->key;
157 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecKeyRef:('%@') %p>"),
158 CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrTokenID), key);
159 }
160
161 // Attributes allowed to be exported from all internal key attributes.
162 static const CFStringRef *kSecExportableCTKKeyAttributes[] = {
163 &kSecClass,
164 &kSecAttrTokenID,
165 &kSecAttrKeyClass,
166 &kSecAttrIsPermanent,
167 &kSecAttrIsPrivate,
168 &kSecAttrIsModifiable,
169 &kSecAttrKeyType,
170 &kSecAttrKeySizeInBits,
171 &kSecAttrEffectiveKeySize,
172 &kSecAttrIsSensitive,
173 &kSecAttrWasAlwaysSensitive,
174 &kSecAttrIsExtractable,
175 &kSecAttrWasNeverExtractable,
176 &kSecAttrCanEncrypt,
177 &kSecAttrCanDecrypt,
178 &kSecAttrCanDerive,
179 &kSecAttrCanSign,
180 &kSecAttrCanVerify,
181 &kSecAttrCanSignRecover,
182 &kSecAttrCanVerifyRecover,
183 &kSecAttrCanWrap,
184 &kSecAttrCanUnwrap,
185 NULL
186 };
187
188 static CFDictionaryRef SecCTKKeyCopyAttributeDictionary(SecKeyRef key) {
189 CFMutableDictionaryRef attrs = NULL;
190 CFErrorRef error = NULL;
191 CFDataRef publicData = NULL, digest = NULL;
192 SecCTKKeyData *kd = key->key;
193
194 // Encode ApplicationLabel as SHA1 digest of public key bytes.
195 require_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out);
196
197 /* Calculate the digest of the public key. */
198 require(digest = SecSHA1DigestCreate(NULL, CFDataGetBytePtr(publicData), CFDataGetLength(publicData)), out);
199 attrs = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(key));
200 CFDictionarySetValue(attrs, kSecAttrApplicationLabel, digest);
201
202 for (const CFStringRef **attrKey = &kSecExportableCTKKeyAttributes[0]; *attrKey != NULL; attrKey++) {
203 CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrKey);
204 if (value != NULL) {
205 CFDictionarySetValue(attrs, **attrKey, value);
206 }
207 }
208
209 out:
210 CFReleaseSafe(error);
211 CFReleaseSafe(publicData);
212 CFReleaseSafe(digest);
213 return attrs;
214 }
215
216 SecKeyDescriptor kSecCTKKeyDescriptor = {
217 kSecKeyDescriptorVersion,
218 "CTKKey",
219 sizeof(SecCTKKeyData),
220 NULL, // SecKeyInit
221 SecCTKKeyDestroy,
222 SecCTKKeyRawSign,
223 NULL, // SecKeyRawVerifyMethod
224 NULL, // SecKeyEncryptMethod
225 NULL, // SecKeyRawDecrypt
226 NULL, // SecKeyComputeMethod
227 SecCTKKeyBlockSize,
228 SecCTKKeyCopyAttributeDictionary,
229 SecCTKKeyCopyKeyDescription,
230 SecCTKGetAlgorithmID,
231 SecCTKKeyCopyPublicOctets,
232 NULL, // SecKeyCopyWrapKey
233 NULL, // SecKeyCopyUnwrapKey
234 };
235
236 SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttributes) {
237 SecKeyRef key = SecKeyCreate(allocator, &kSecCTKKeyDescriptor, 0, 0, 0);
238 SecCTKKeyData *kd = key->key;
239 kd->token = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecUseToken));
240 kd->objectID = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecUseTokenObjectID));
241 kd->token_id = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecAttrTokenID));
242 kd->attributes.dictionary = refAttributes;
243 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecUseToken);
244 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecUseTokenObjectID);
245 SecItemAuthCopyParams(&kd->auth_params, &kd->attributes);
246 return key;
247 }
248
249 OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
250 OSStatus status;
251 CFMutableDictionaryRef attrs = NULL;
252 CFDictionaryRef keyAttrs = NULL;
253 CFDataRef publicData = NULL;
254
255 require_action_quiet(publicKey != NULL, out, status = errSecParam);
256 require_action_quiet(privateKey != NULL, out, status = errSecParam);
257
258 // Simply adding key on the token without value will cause the token to generate the key and automatically
259 // add it to the keychain. Prepare dictionary specifying item to add.
260 keyAttrs = CFDictionaryGetValue(parameters, kSecPrivateKeyAttrs);
261 attrs = (keyAttrs == NULL) ? CFDictionaryCreateMutableForCFTypes(NULL) : CFDictionaryCreateMutableCopy(NULL, 0, keyAttrs);
262
263 CFDictionaryForEach(parameters, ^(const void *key, const void *value) {
264 if (!CFEqual(key, kSecPrivateKeyAttrs) && !CFEqual(key, kSecPublicKeyAttrs)) {
265 CFDictionarySetValue(attrs, key, value);
266 }
267 });
268 CFDictionaryRemoveValue(attrs, kSecValueData);
269 CFDictionarySetValue(attrs, kSecClass, kSecClassKey);
270 CFDictionarySetValue(attrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
271 CFDictionarySetValue(attrs, kSecReturnRef, kCFBooleanTrue);
272
273 // Add key from given attributes to the token (having no data will cause the token to actually generate the key).
274 require_noerr_quiet(status = SecItemAdd(attrs, (CFTypeRef *)privateKey), out);
275
276 // Create non-token public key.
277 require_noerr_quiet(status = SecCTKKeyCopyPublicOctets(*privateKey, &publicData), out);
278 if (CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeEC)) {
279 *publicKey = SecKeyCreateECPublicKey(NULL, CFDataGetBytePtr(publicData), CFDataGetLength(publicData),
280 kSecKeyEncodingBytes);
281 } else if (CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeRSA)) {
282 *publicKey = SecKeyCreateRSAPublicKey(NULL, CFDataGetBytePtr(publicData), CFDataGetLength(publicData),
283 kSecKeyEncodingBytes);
284 }
285
286 if (*publicKey != NULL) {
287 status = errSecSuccess;
288 } else {
289 status = errSecInvalidKey;
290 CFReleaseNull(*privateKey);
291 }
292
293 out:
294 CFReleaseSafe(attrs);
295 CFReleaseSafe(publicData);
296 return status;
297 }