]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecEMCS.m
Security-57740.20.22.tar.gz
[apple/security.git] / OSX / sec / Security / SecEMCS.m
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 #define __KEYCHAINCORE__ 1
25
26 #include <Foundation/Foundation.h>
27 #include <Security/SecBase.h>
28 #include <Security/SecBasePriv.h>
29 #include <Security/SecCFAllocator.h>
30 #include <corecrypto/ccpbkdf2.h>
31 #include <corecrypto/ccsha2.h>
32 #include <corecrypto/ccaes.h>
33 #include <corecrypto/ccmode.h>
34 #include <corecrypto/ccwrap.h>
35
36 #include <utilities/SecCFWrappers.h>
37 #include <AssertMacros.h>
38
39 #include "SecEMCSPriv.h"
40
41 static CFStringRef kiDMSSalt = CFSTR("salt");
42 static CFStringRef kiDMSIterrations = CFSTR("iter");
43 static CFStringRef kiDMSWrapEMCSKey = CFSTR("wkey");
44
45 #define MIN_ITERATIONS 1000
46 #define MIN_SALTLEN 16
47 #define KEY_LENGTH 16
48
49 /*
50 *
51 */
52
53 static CFDataRef
54 CopyWrappedKey(CFDataRef wrappingKey, CFDataRef unwrappedKey)
55 {
56 const struct ccmode_ecb *ecb_mode = ccaes_ecb_encrypt_mode();
57 ccecb_ctx_decl(ccecb_context_size(ecb_mode), key);
58 CFMutableDataRef wrappedKey = NULL;
59
60 require(CFDataGetLength(wrappingKey) == KEY_LENGTH, out);
61
62 ccecb_init(ecb_mode, key, CFDataGetLength(wrappingKey), CFDataGetBytePtr(wrappingKey));
63
64 wrappedKey = CFDataCreateMutableWithScratch(NULL, ccwrap_wrapped_size(CFDataGetLength(unwrappedKey)));
65 require(wrappingKey, out);
66
67 size_t obytes = 0;
68 int wrap_status = ccwrap_auth_encrypt(ecb_mode, key, CFDataGetLength(unwrappedKey), CFDataGetBytePtr(unwrappedKey),
69 &obytes, CFDataGetMutableBytePtr(wrappedKey));
70 if (wrap_status == 0) {
71 assert(obytes == (size_t)CFDataGetLength(wrappedKey));
72 } else {
73 CFReleaseNull(wrappedKey);
74 goto out;
75 }
76
77 out:
78 ccecb_ctx_clear(ccecb_context_size(ecb_mode), key);
79 return wrappedKey;
80 }
81
82 static CFDataRef
83 CopyUnwrappedKey(CFDataRef wrappingKey, CFDataRef wrappedKey)
84 {
85 const struct ccmode_ecb *ecb_mode = ccaes_ecb_decrypt_mode();
86 ccecb_ctx_decl(ccecb_context_size(ecb_mode), key);
87 CFMutableDataRef unwrappedKey = NULL;
88
89 require(CFDataGetLength(wrappedKey) >= CCWRAP_SEMIBLOCK, out);
90 require(CFDataGetLength(wrappingKey) == KEY_LENGTH, out);
91
92 ccecb_init(ecb_mode, key, CFDataGetLength(wrappingKey), CFDataGetBytePtr(wrappingKey));
93
94 unwrappedKey = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), ccwrap_unwrapped_size(CFDataGetLength(wrappedKey)));
95 require(unwrappedKey, out);
96
97 size_t obytes = 0;
98 int unwrap_status = ccwrap_auth_decrypt(ecb_mode, key, CFDataGetLength(wrappedKey), CFDataGetBytePtr(wrappedKey),
99 &obytes, CFDataGetMutableBytePtr(unwrappedKey));
100 if (unwrap_status == 0) {
101 assert(obytes == (size_t)CFDataGetLength(unwrappedKey));
102 } else {
103 CFReleaseNull(unwrappedKey);
104 goto out;
105 }
106
107 out:
108 ccecb_ctx_clear(ccecb_context_size(ecb_mode), key);
109 return unwrappedKey;
110 }
111
112 /*
113 *
114 */
115
116 static CFDataRef
117 CreateDerivedKey(CFDataRef salt, long iterations, NSString *managedCredential)
118 {
119 if (iterations < MIN_ITERATIONS || CFDataGetLength(salt) < MIN_SALTLEN)
120 return NULL;
121
122 /*
123 * Assume users use the same normalization rules always
124 */
125
126 CFIndex strLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength((__bridge CFStringRef)managedCredential), kCFStringEncodingUTF8);
127 strLength += 1;
128 char buffer[strLength];
129 if (!CFStringGetCString((__bridge CFStringRef)managedCredential, buffer, strLength, kCFStringEncodingUTF8)) {
130 return NULL;
131 }
132
133
134 CFMutableDataRef key = CFDataCreateMutable(SecCFAllocatorZeroize(), KEY_LENGTH);
135 if (key == NULL) {
136 memset_s(buffer, strLength, 0, strLength);
137 return NULL;
138 }
139
140 CFDataSetLength(key, KEY_LENGTH);
141
142 int ret;
143 ret = ccpbkdf2_hmac(ccsha256_di(),
144 strlen(buffer), buffer,
145 CFDataGetLength(salt), CFDataGetBytePtr(salt),
146 iterations,
147 KEY_LENGTH, CFDataGetMutableBytePtr(key));
148 memset_s(buffer, strLength, 0, strLength);
149 if (ret) {
150 CFRelease(key);
151 return NULL;
152 }
153 return key;
154 }
155
156
157 /*
158 * Given a dictionary stored in iDMS and a passcode, return a crypto key
159 */
160
161 NSData *
162 SecEMCSCreateDerivedEMCSKey(NSDictionary *iDMSData, NSString *managedCredential, NSError **error)
163 {
164 CFDataRef key = NULL, emcsKey = NULL;
165 CFDataRef userDerivedKey = NULL;
166 CFNumberRef number = NULL;
167 CFDataRef salt = NULL;
168 long iterations;
169
170 salt = CFDictionaryGetValue((__bridge CFDictionaryRef)iDMSData, kiDMSSalt);
171 number = CFDictionaryGetValue((__bridge CFDictionaryRef)iDMSData, kiDMSIterrations);
172 emcsKey = CFDictionaryGetValue((__bridge CFDictionaryRef)iDMSData, kiDMSWrapEMCSKey);
173
174 /* validate parameters */
175 if (!isData(salt) || !isNumber(number) || !isData(emcsKey))
176 return NULL;
177
178 if (!CFNumberGetValue(number, kCFNumberLongType, &iterations))
179 return NULL;
180
181 userDerivedKey = CreateDerivedKey(salt, iterations, managedCredential);
182 if (userDerivedKey == NULL)
183 return NULL;
184
185 key = CopyUnwrappedKey(userDerivedKey, emcsKey);
186 CFRelease(userDerivedKey);
187
188 return (__bridge NSData *)key;
189 }
190
191 /*
192 * Return a dictionary to be stored in iDMS
193 */
194
195 NSDictionary *
196 SecEMCSCreateNewiDMSKey(NSDictionary *options,
197 NSData *oldEMCSKey,
198 NSString *managedCredential,
199 NSData **emcsKey,
200 NSError **error)
201 {
202 CFMutableDataRef salt = NULL;
203 const long iter = MIN_ITERATIONS;
204 CFDataRef wrappedEMCSKey = NULL;
205 CFMutableDataRef localEmcsKey = NULL;
206 CFNumberRef iterations = NULL;
207 CFDataRef userDerivedKey = NULL;
208 CFDictionaryRef key = NULL;
209
210 if (emcsKey)
211 *emcsKey = NULL;
212
213 if (oldEMCSKey) {
214 if (CFGetTypeID(oldEMCSKey) != CFDataGetTypeID())
215 return NULL;
216 if (CFDataGetLength((__bridge CFDataRef)oldEMCSKey) != KEY_LENGTH)
217 return NULL;
218 }
219
220 salt = CFDataCreateMutableWithScratch(NULL, MIN_SALTLEN);
221 if (salt == NULL)
222 goto out;
223
224 if (SecRandomCopyBytes(NULL, CFDataGetLength(salt), CFDataGetMutableBytePtr(salt)) != 0)
225 goto out;
226
227
228 iterations = CFNumberCreate(NULL, kCFNumberLongType, &iter);
229 if (iterations == NULL)
230 goto out;
231
232 if (oldEMCSKey) {
233 localEmcsKey = CFDataCreateMutableCopy(SecCFAllocatorZeroize(), 0, (__bridge CFDataRef)oldEMCSKey);
234 } else {
235 localEmcsKey = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), KEY_LENGTH);
236 if (localEmcsKey == NULL)
237 goto out;
238 if (SecRandomCopyBytes(NULL, CFDataGetLength(localEmcsKey), CFDataGetMutableBytePtr(localEmcsKey)) != 0)
239 goto out;
240 }
241
242 userDerivedKey = CreateDerivedKey(salt, iter, managedCredential);
243 if (userDerivedKey == NULL)
244 goto out;
245
246 wrappedEMCSKey = CopyWrappedKey(userDerivedKey, localEmcsKey);
247 CFRelease(userDerivedKey);
248 if (wrappedEMCSKey == NULL)
249 goto out;
250
251 const void *keys[] = {
252 kiDMSSalt,
253 kiDMSIterrations,
254 kiDMSWrapEMCSKey,
255 };
256 const void *values[] = {
257 salt,
258 iterations,
259 wrappedEMCSKey,
260 };
261 _Static_assert(sizeof(keys)/sizeof(keys[0]) == sizeof(values)/sizeof(values[0]), "keys != values");
262
263 key = CFDictionaryCreate(NULL, keys, values, sizeof(keys)/sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
264 if (key && emcsKey)
265 *emcsKey = CFRetain(localEmcsKey);
266
267 out:
268 CFReleaseNull(salt);
269 CFReleaseNull(iterations);
270 CFReleaseNull(localEmcsKey);
271 CFReleaseNull(wrappedEMCSKey);
272
273 return (__bridge NSDictionary *)key;
274 }