]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.m
Security-58286.60.28.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSInternal.m
1 /*
2 * Copyright (c) 2012-2014 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
25 #include <Security/SecureObjectSync/SOSInternal.h>
26 #include <Security/SecureObjectSync/SOSCircle.h>
27 #include <Security/SecureObjectSync/SOSCloudCircle.h>
28 #include <Security/SecureObjectSync/SOSKVSKeys.h>
29 #include "utilities/SecCFError.h"
30 #include "utilities/SecCFRelease.h"
31 #include "utilities/SecCFWrappers.h"
32 #include "utilities/iOSforOSX.h"
33
34 #include <CoreFoundation/CoreFoundation.h>
35
36 #include <Security/SecKey.h>
37 #include <Security/SecKeyPriv.h>
38 #include <Security/SecItem.h>
39 #include <securityd/SecDbItem.h> // For SecError
40 #include "utilities/iOSforOSX.h"
41
42 #include <Security/SecBase64.h>
43 #include <utilities/der_plist.h>
44 #include <utilities/der_plist_internal.h>
45 #include <corecrypto/ccder.h>
46 #include <utilities/der_date.h>
47
48 #include <corecrypto/ccrng.h>
49 #include <corecrypto/ccrng_pbkdf2_prng.h>
50
51 #include <CommonCrypto/CommonRandomSPI.h>
52
53 #include <AssertMacros.h>
54
55 const CFStringRef kSecIDSErrorDomain = CFSTR("com.apple.security.ids.error");
56 const CFStringRef kIDSOperationType = CFSTR("IDSMessageOperation");
57 const CFStringRef kIDSMessageToSendKey = CFSTR("MessageToSendKey");
58 const CFStringRef kIDSMessageUniqueID = CFSTR("MessageID");
59 const CFStringRef kIDSMessageRecipientPeerID = CFSTR("RecipientPeerID");
60 const CFStringRef kIDSMessageRecipientDeviceID = CFSTR("RecipientDeviceID");
61 const CFStringRef kIDSMessageSenderDeviceID = CFSTR("SendersDeviceID");
62
63 const CFStringRef kIDSMessageUsesAckModel = CFSTR("UsesAckModel");
64 const CFStringRef kSOSErrorDomain = CFSTR("com.apple.security.sos.error");
65 const CFStringRef kSOSDSIDKey = CFSTR("AccountDSID");
66 const CFStringRef SOSTransportMessageTypeIDSV2 = CFSTR("IDS2.0");
67 const CFStringRef SOSTransportMessageTypeKVS = CFSTR("KVS");
68
69 bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef format, ...)
70 CF_FORMAT_FUNCTION(4, 5);
71
72
73 bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef format, ...) {
74 if (!errorCode) return true;
75 if (error && !*error) {
76 va_list va;
77 va_start(va, format);
78 SecCFCreateErrorWithFormatAndArguments(errorCode, kSOSErrorDomain, NULL, error, formatOptions, format, va);
79 va_end(va);
80 }
81 return false;
82 }
83
84 bool SOSCreateError(CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError) {
85 SOSCreateErrorWithFormat(errorCode, previousError, newError, NULL, CFSTR("%@"), descriptionString);
86 return false;
87 }
88
89 bool SOSCreateErrorWithFormat(CFIndex errorCode, CFErrorRef previousError, CFErrorRef *newError,
90 CFDictionaryRef formatOptions, CFStringRef format, ...) {
91 va_list va;
92 va_start(va, format);
93 bool res = SOSCreateErrorWithFormatAndArguments(errorCode, previousError, newError, formatOptions, format, va);
94 va_end(va);
95 return res;
96 }
97
98 bool SOSCreateErrorWithFormatAndArguments(CFIndex errorCode, CFErrorRef previousError, CFErrorRef *newError,
99 CFDictionaryRef formatOptions, CFStringRef format, va_list args) {
100 return SecCFCreateErrorWithFormatAndArguments(errorCode, kSOSErrorDomain, previousError, newError, formatOptions, format, args);
101 }
102
103
104 //
105 // Utility Functions
106 //
107
108 static OSStatus GenerateECPairImp(int keySize, CFBooleanRef permanent, SecKeyRef* public, SecKeyRef *full)
109 {
110 static const CFStringRef sTempNameToUse = CFSTR("GenerateECPair Temporary Key - Shouldn't be live");
111
112 CFNumberRef signing_bitsize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
113
114 CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
115 kSecAttrKeyType, kSecAttrKeyTypeEC,
116 kSecAttrKeySizeInBits, signing_bitsize,
117 kSecAttrIsPermanent, permanent,
118 kSecAttrLabel, sTempNameToUse,
119 NULL);
120 CFReleaseNull(signing_bitsize);
121 OSStatus result = SecKeyGeneratePair(keygen_parameters, public, full);
122 CFReleaseNull(keygen_parameters);
123
124 return result;
125 }
126
127 OSStatus GenerateECPair(int keySize, SecKeyRef* public, SecKeyRef *full)
128 {
129 return GenerateECPairImp(keySize, kCFBooleanFalse, public, full);
130 }
131
132 OSStatus GeneratePermanentECPair(int keySize, SecKeyRef* public, SecKeyRef *full)
133 {
134 return GenerateECPairImp(keySize, kCFBooleanTrue, public, full);
135 }
136
137 static CFStringRef SOSCircleCopyDescriptionFromData(CFDataRef data)
138 {
139 CFErrorRef error = NULL;
140 CFStringRef result = NULL;
141
142 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, data, &error);
143
144 if (circle)
145 result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), circle);
146
147 CFReleaseSafe(circle);
148
149 return result;
150 }
151
152 CFStringRef SOSItemsChangedCopyDescription(CFDictionaryRef changes, bool is_sender)
153 {
154 CFMutableStringRef string = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("<Changes: {\n"));
155
156 CFDictionaryForEach(changes, ^(const void *key, const void *value) {
157 CFStringRef value_description = NULL;
158 if (isString(key) && isData(value)) {
159 CFDataRef value_data = (CFDataRef) value;
160 switch (SOSKVSKeyGetKeyType(key)) {
161 case kCircleKey:
162 value_description = SOSCircleCopyDescriptionFromData(value_data);
163 break;
164 case kMessageKey:
165 value_description = CFCopyDescription(value_data);
166 break;
167 default:
168 break;
169 }
170
171 }
172 CFStringAppendFormat(string, NULL, CFSTR(" '%@' %s %@\n"),
173 key,
174 is_sender ? "<=" : "=>",
175 value_description ? value_description : value);
176
177 CFReleaseNull(value_description);
178 });
179
180 CFStringAppendFormat(string, NULL, CFSTR("}"));
181
182 return string;
183 }
184
185
186 CFStringRef SOSCopyIDOfDataBuffer(CFDataRef data, CFErrorRef *error) {
187 const struct ccdigest_info * di = ccsha1_di();
188 uint8_t digest[di->output_size];
189 char encoded[2 * di->output_size]; // Big enough for base64 encoding.
190
191 ccdigest(di, CFDataGetLength(data), CFDataGetBytePtr(data), digest);
192
193 size_t length = SecBase64Encode(digest, sizeof(digest), encoded, sizeof(encoded));
194 assert(length && length < sizeof(encoded));
195 if (length > kSOSPeerIDLengthMax)
196 length = kSOSPeerIDLengthMax;
197 encoded[length] = 0;
198 return CFStringCreateWithCString(kCFAllocatorDefault, encoded, kCFStringEncodingASCII);
199 }
200
201 CFStringRef SOSCopyIDOfDataBufferWithLength(CFDataRef data, CFIndex len, CFErrorRef *error) {
202 CFStringRef retval = NULL;
203 CFStringRef tmp = SOSCopyIDOfDataBuffer(data, error);
204 if(tmp) retval = CFStringCreateWithSubstring(kCFAllocatorDefault, tmp, CFRangeMake(0, len));
205 CFReleaseNull(tmp);
206 return retval;
207 }
208
209 CFStringRef SOSCopyIDOfKey(SecKeyRef key, CFErrorRef *error) {
210 CFDataRef publicBytes = NULL;
211 CFStringRef result = NULL;
212 require_quiet(SecError(SecKeyCopyPublicBytes(key, &publicBytes), error, CFSTR("Failed to export public bytes %@"), key), fail);
213 result = SOSCopyIDOfDataBuffer(publicBytes, error);
214 fail:
215 CFReleaseNull(publicBytes);
216 return result;
217 }
218
219 CFStringRef SOSCopyIDOfKeyWithLength(SecKeyRef key, CFIndex len, CFErrorRef *error) {
220 CFStringRef retval = NULL;
221 CFStringRef tmp = SOSCopyIDOfKey(key, error);
222 if(tmp) retval = CFStringCreateWithSubstring(kCFAllocatorDefault, tmp, CFRangeMake(0, len));
223 CFReleaseNull(tmp);
224 return retval;
225 }
226
227
228 CFGiblisGetSingleton(ccec_const_cp_t, SOSGetBackupKeyCurveParameters, sBackupKeyCurveParameters, ^{
229 *sBackupKeyCurveParameters = ccec_cp_256();
230 });
231
232
233 //
234 // We're expecting full entropy here, so we just need to stretch
235 // via the PBKDF entropy rng. We'll choose a few iterations and no salt
236 // since we don't get sent any.
237 //
238 const int kBackupKeyIterations = 20;
239 const uint8_t sBackupKeySalt[] = { 0 };
240
241 bool SOSPerformWithDeviceBackupFullKey(ccec_const_cp_t cp, CFDataRef entropy, CFErrorRef *error, void (^operation)(ccec_full_ctx_t fullKey))
242 {
243 bool result = false;
244 ccec_full_ctx_decl_cp(cp, fullKey);
245
246 require_quiet(SOSGenerateDeviceBackupFullKey(fullKey, cp, entropy, error), exit);
247
248 operation(fullKey);
249
250 result = true;
251 exit:
252 ccec_full_ctx_clear_cp(cp, fullKey);
253
254 return result;
255 }
256
257
258 bool SOSGenerateDeviceBackupFullKey(ccec_full_ctx_t generatedKey, ccec_const_cp_t cp, CFDataRef entropy, CFErrorRef* error)
259 {
260 bool result = false;
261 int cc_result = 0;
262 struct ccrng_pbkdf2_prng_state pbkdf2_prng;
263 const int kBackupKeyMaxBytes = 1024; // This may be a function of the cp but will be updated when we use a formally deterministic key generation.
264
265 cc_result = ccrng_pbkdf2_prng_init(&pbkdf2_prng, kBackupKeyMaxBytes,
266 CFDataGetLength(entropy), CFDataGetBytePtr(entropy),
267 sizeof(sBackupKeySalt), sBackupKeySalt,
268 kBackupKeyIterations);
269 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("pbkdf rng init failed: %d"), cc_result));
270
271 cc_result = ccec_compact_generate_key(cp, (struct ccrng_state *) &pbkdf2_prng, generatedKey);
272 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("Generate key failed: %d"), cc_result));
273
274 result = true;
275 exit:
276 bzero(&pbkdf2_prng, sizeof(pbkdf2_prng));
277 return result;
278
279 }
280
281 CFDataRef SOSCopyDeviceBackupPublicKey(CFDataRef entropy, CFErrorRef *error)
282 {
283 CFDataRef result = NULL;
284 CFMutableDataRef publicKeyData = NULL;
285
286 ccec_full_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), fullKey);
287
288 require_quiet(SOSGenerateDeviceBackupFullKey(fullKey, SOSGetBackupKeyCurveParameters(), entropy, error), exit);
289
290 size_t space = ccec_compact_export_size(false, ccec_ctx_pub(fullKey));
291 publicKeyData = CFDataCreateMutableWithScratch(kCFAllocatorDefault, space);
292 require_quiet(SecAllocationError(publicKeyData, error, CFSTR("Mutable data allocation")), exit);
293
294 ccec_compact_export(false, CFDataGetMutableBytePtr(publicKeyData), fullKey);
295
296 CFTransferRetained(result, publicKeyData);
297
298 exit:
299 CFReleaseNull(publicKeyData);
300 return result;
301 }
302
303
304 CFDataRef SOSDateCreate(void) {
305 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
306 size_t bufsiz = der_sizeof_date(now, NULL);
307 uint8_t buf[bufsiz];
308 der_encode_date(now, NULL, buf, buf+bufsiz);
309 CFReleaseNull(now);
310 return CFDataCreate(NULL, buf, bufsiz);
311 }
312
313
314 CFDataRef CFDataCreateWithDER(CFAllocatorRef allocator, CFIndex size, uint8_t*(^operation)(size_t size, uint8_t *buffer)) {
315 __block CFMutableDataRef result = NULL;
316 if(!size) return NULL;
317 if((result = CFDataCreateMutableWithScratch(allocator, size)) == NULL) return NULL;
318 uint8_t *ptr = CFDataGetMutableBytePtr(result);
319 uint8_t *derptr = operation(size, ptr);
320 if(derptr == ptr) return result; // most probable case
321 if(!derptr || derptr < ptr) { // DER op failed - or derptr ended up prior to allocated buffer
322 CFReleaseNull(result);
323 } else if(derptr > ptr) { // This is a possible case where we don't end up using the entire allocated buffer
324 size_t diff = derptr - ptr; // The unused space ends up being the beginning of the allocation
325 CFDataDeleteBytes(result, CFRangeMake(0, diff));
326 }
327 return result;
328 }