]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.c
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSInternal.c
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 CFStringRef kSOSErrorDomain = CFSTR("com.apple.security.sos.error");
56
57 bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef format, ...) {
58 if (!errorCode) return true;
59 if (error && !*error) {
60 va_list va;
61 va_start(va, format);
62 SecCFCreateErrorWithFormatAndArguments(errorCode, kSOSErrorDomain, NULL, error, formatOptions, format, va);
63 va_end(va);
64 }
65 return false;
66 }
67
68 bool SOSCreateError(CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError) {
69 SOSCreateErrorWithFormat(errorCode, previousError, newError, NULL, CFSTR("%@"), descriptionString);
70 return true;
71 }
72
73 bool SOSCreateErrorWithFormat(CFIndex errorCode, CFErrorRef previousError, CFErrorRef *newError,
74 CFDictionaryRef formatOptions, CFStringRef format, ...) {
75 va_list va;
76 va_start(va, format);
77 bool res = SOSCreateErrorWithFormatAndArguments(errorCode, previousError, newError, formatOptions, format, va);
78 va_end(va);
79 return res;
80 }
81
82 bool SOSCreateErrorWithFormatAndArguments(CFIndex errorCode, CFErrorRef previousError, CFErrorRef *newError,
83 CFDictionaryRef formatOptions, CFStringRef format, va_list args) {
84 SecCFCreateErrorWithFormatAndArguments(errorCode, kSOSErrorDomain, previousError, newError, formatOptions, format, args);
85 return true;
86 }
87
88
89 //
90 // Utility Functions
91 //
92
93 static OSStatus GenerateECPairImp(int keySize, CFBooleanRef permanent, SecKeyRef* public, SecKeyRef *full)
94 {
95 static const CFStringRef sTempNameToUse = CFSTR("GenerateECPair Temporary Key - Shouldn't be live");
96
97 CFNumberRef signing_bitsize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
98
99 CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
100 kSecAttrKeyType, kSecAttrKeyTypeEC,
101 kSecAttrKeySizeInBits, signing_bitsize,
102 kSecAttrIsPermanent, permanent,
103 kSecAttrLabel, sTempNameToUse,
104 NULL);
105 CFReleaseNull(signing_bitsize);
106 OSStatus result = SecKeyGeneratePair(keygen_parameters, public, full);
107 CFReleaseNull(keygen_parameters);
108
109 return result;
110 }
111
112 OSStatus GenerateECPair(int keySize, SecKeyRef* public, SecKeyRef *full)
113 {
114 return GenerateECPairImp(keySize, kCFBooleanFalse, public, full);
115 }
116
117 OSStatus GeneratePermanentECPair(int keySize, SecKeyRef* public, SecKeyRef *full)
118 {
119 return GenerateECPairImp(keySize, kCFBooleanTrue, public, full);
120 }
121
122 static CFStringRef SOSCircleCopyDescriptionFromData(CFDataRef data)
123 {
124 CFErrorRef error = NULL;
125 CFStringRef result = NULL;
126
127 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, data, &error);
128
129 if (circle)
130 result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), circle);
131
132 CFReleaseSafe(circle);
133
134 return result;
135 }
136
137 CFStringRef SOSItemsChangedCopyDescription(CFDictionaryRef changes, bool is_sender)
138 {
139 CFMutableStringRef string = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("<Changes: {\n"));
140
141 CFDictionaryForEach(changes, ^(const void *key, const void *value) {
142 CFStringRef value_description = NULL;
143 if (isString(key) && isData(value)) {
144 CFDataRef value_data = (CFDataRef) value;
145 switch (SOSKVSKeyGetKeyType(key)) {
146 case kCircleKey:
147 value_description = SOSCircleCopyDescriptionFromData(value_data);
148 break;
149 case kMessageKey:
150 value_description = CFCopyDescription(value_data);
151 break;
152 default:
153 break;
154 }
155
156 }
157 CFStringAppendFormat(string, NULL, CFSTR(" '%@' %s %@\n"),
158 key,
159 is_sender ? "<=" : "=>",
160 value_description ? value_description : value);
161
162 CFReleaseNull(value_description);
163 });
164
165 CFStringAppendFormat(string, NULL, CFSTR("}"));
166
167 return string;
168 }
169
170 CFStringRef SOSCopyIDOfKey(SecKeyRef key, CFErrorRef *error)
171 {
172 const struct ccdigest_info * di = ccsha1_di();
173 CFDataRef publicBytes = NULL;
174 CFStringRef result = NULL;
175
176 uint8_t digest[di->output_size];
177 char encoded[2 * di->output_size]; // Big enough for base64 encoding.
178
179 require_quiet(SecError(SecKeyCopyPublicBytes(key, &publicBytes), error, CFSTR("Failed to export public bytes %@"), key), fail);
180
181 ccdigest(di, CFDataGetLength(publicBytes), CFDataGetBytePtr(publicBytes), digest);
182
183 size_t length = SecBase64Encode(digest, sizeof(digest), encoded, sizeof(encoded));
184 assert(length && length < sizeof(encoded));
185 if (length > 26)
186 length = 26;
187 encoded[length] = 0;
188 CFReleaseNull(publicBytes);
189 return CFStringCreateWithCString(kCFAllocatorDefault, encoded, kCFStringEncodingASCII);
190
191 fail:
192 CFReleaseNull(publicBytes);
193 return result;
194 }
195
196 CFGiblisGetSingleton(ccec_const_cp_t, SOSGetBackupKeyCurveParameters, sBackupKeyCurveParameters, ^{
197 *sBackupKeyCurveParameters = ccec_cp_256();
198 });
199
200
201 //
202 // We're expecting full entropy here, so we just need to stretch
203 // via the PBKDF entropy rng. We'll choose a few iterations and no salt
204 // since we don't get sent any.
205 //
206 const int kBackupKeyIterations = 20;
207 const uint8_t sBackupKeySalt[] = { 0 };
208 const int kBackupKeyMaxBytes = 256;
209
210 bool SOSPerformWithDeviceBackupFullKey(ccec_const_cp_t cp, CFDataRef entropy, CFErrorRef *error, void (^operation)(ccec_full_ctx_t fullKey))
211 {
212 bool result = false;
213 ccec_full_ctx_decl_cp(cp, fullKey);
214
215 require_quiet(SOSGenerateDeviceBackupFullKey(fullKey, cp, entropy, error), exit);
216
217 operation(fullKey);
218
219 result = true;
220 exit:
221 ccec_full_ctx_clear_cp(cp, fullKey);
222
223 return result;
224 }
225
226
227 bool SOSGenerateDeviceBackupFullKey(ccec_full_ctx_t generatedKey, ccec_const_cp_t cp, CFDataRef entropy, CFErrorRef* error)
228 {
229 bool result = false;
230 int cc_result = 0;
231 struct ccrng_pbkdf2_prng_state pbkdf2_prng;
232
233 cc_result = ccrng_pbkdf2_prng_init(&pbkdf2_prng, kBackupKeyMaxBytes,
234 CFDataGetLength(entropy), CFDataGetBytePtr(entropy),
235 sizeof(sBackupKeySalt), sBackupKeySalt,
236 kBackupKeyIterations);
237 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("pbkdf rng init failed: %d"), cc_result));
238
239 cc_result = ccec_compact_generate_key(cp, (struct ccrng_state *) &pbkdf2_prng, generatedKey);
240 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("Generate key failed: %d"), cc_result));
241
242 result = true;
243 exit:
244 bzero(&pbkdf2_prng, sizeof(pbkdf2_prng));
245 return result;
246
247 }
248
249 CFDataRef SOSCopyDeviceBackupPublicKey(CFDataRef entropy, CFErrorRef *error)
250 {
251 CFDataRef result = NULL;
252 CFMutableDataRef publicKeyData = NULL;
253
254 ccec_full_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), fullKey);
255
256 require_quiet(SOSGenerateDeviceBackupFullKey(fullKey, SOSGetBackupKeyCurveParameters(), entropy, error), exit);
257
258 size_t space = ccec_compact_export_size(false, fullKey);
259 publicKeyData = CFDataCreateMutableWithScratch(kCFAllocatorDefault, space);
260 require_quiet(SecAllocationError(publicKeyData, error, CFSTR("Mutable data allocation")), exit);
261
262 ccec_compact_export(false, CFDataGetMutableBytePtr(publicKeyData), fullKey);
263
264 CFTransferRetained(result, publicKeyData);
265
266 exit:
267 CFReleaseNull(publicKeyData);
268 return result;
269 }
270
271
272 CFDataRef SOSDateCreate(void) {
273 CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
274 size_t bufsiz = der_sizeof_date(now, NULL);
275 uint8_t buf[bufsiz];
276 der_encode_date(now, NULL, buf, buf+bufsiz);
277 CFReleaseNull(now);
278 return CFDataCreate(NULL, buf, bufsiz);
279 }
280