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