]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKS.m
324de08c451e081c3e3e7c0f5c93db97444fae12
[apple/security.git] / keychain / ckks / CKKS.m
1 /*
2 * Copyright (c) 2016 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 <dispatch/dispatch.h>
25 #import <Foundation/Foundation.h>
26 #if OCTAGON
27 #import <CloudKit/CloudKit.h>
28 #endif
29
30 #include <utilities/debugging.h>
31 #include <securityd/SecItemServer.h>
32 #include <Security/SecItemPriv.h>
33
34 #import <Foundation/Foundation.h>
35 #import "keychain/ckks/CKKS.h"
36 #import "keychain/ckks/CKKSKeychainView.h"
37 #import "keychain/ckks/CKKSViewManager.h"
38 #import "keychain/ckks/CKKSKey.h"
39
40 const SecCKKSItemEncryptionVersion currentCKKSItemEncryptionVersion = CKKSItemEncryptionVersion2;
41
42 NSString* const SecCKKSActionAdd = @"add";
43 NSString* const SecCKKSActionDelete = @"delete";
44 NSString* const SecCKKSActionModify = @"modify";
45
46 CKKSItemState* const SecCKKSStateNew = (CKKSItemState*) @"new";
47 CKKSItemState* const SecCKKSStateUnauthenticated = (CKKSItemState*) @"unauthenticated";
48 CKKSItemState* const SecCKKSStateInFlight = (CKKSItemState*) @"inflight";
49 CKKSItemState* const SecCKKSStateReencrypt = (CKKSItemState*) @"reencrypt";
50 CKKSItemState* const SecCKKSStateError = (CKKSItemState*) @"error";
51 CKKSItemState* const SecCKKSStateDeleted = (CKKSItemState*) @"deleted";
52
53 CKKSProcessedState* const SecCKKSProcessedStateLocal = (CKKSProcessedState*) @"local";
54 CKKSProcessedState* const SecCKKSProcessedStateRemote = (CKKSProcessedState*) @"remote";
55
56 CKKSKeyClass* const SecCKKSKeyClassTLK = (CKKSKeyClass*) @"tlk";
57 CKKSKeyClass* const SecCKKSKeyClassA = (CKKSKeyClass*) @"classA";
58 CKKSKeyClass* const SecCKKSKeyClassC = (CKKSKeyClass*) @"classC";
59
60 NSString* const SecCKKSContainerName = @"com.apple.security.keychain";
61 bool SecCKKSContainerUsePCS = false;
62
63 NSString* const SecCKKSSubscriptionID = @"keychain-changes";
64 NSString* const SecCKKSAPSNamedPort = @"com.apple.securityd.aps";
65
66 NSString* const SecCKRecordItemType = @"item";
67 NSString* const SecCKRecordVersionKey = @"uploadver";
68 NSString* const SecCKRecordEncryptionVersionKey = @"encver";
69 NSString* const SecCKRecordDataKey = @"data";
70 NSString* const SecCKRecordParentKeyRefKey = @"parentkeyref";
71 NSString* const SecCKRecordWrappedKeyKey = @"wrappedkey";
72 NSString* const SecCKRecordGenerationCountKey = @"gen";
73
74 NSString* const SecCKRecordPCSServiceIdentifier = @"pcsservice";
75 NSString* const SecCKRecordPCSPublicKey = @"pcspublickey";
76 NSString* const SecCKRecordPCSPublicIdentity = @"pcspublicidentity";
77 NSString* const SecCKRecordServerWasCurrent = @"server_wascurrent";
78
79 NSString* const SecCKRecordIntermediateKeyType = @"synckey";
80 NSString* const SecCKRecordKeyClassKey = @"class";
81
82 NSString* const SecCKRecordCurrentKeyType = @"currentkey";
83
84 NSString* const SecCKRecordCurrentItemType = @"currentitem";
85 NSString* const SecCKRecordItemRefKey = @"item";
86
87 NSString* const SecCKRecordDeviceStateType = @"devicestate";
88 NSString* const SecCKRecordCirclePeerID = @"peerid";
89 NSString* const SecCKRecordCircleStatus = @"circle";
90 NSString* const SecCKRecordKeyState = @"keystate";
91 NSString* const SecCKRecordCurrentTLK = @"currentTLK";
92 NSString* const SecCKRecordCurrentClassA = @"currentClassA";
93 NSString* const SecCKRecordCurrentClassC = @"currentClassC";
94
95 NSString* const SecCKRecordManifestType = @"manifest";
96 NSString* const SecCKRecordManifestDigestValueKey = @"digest_value";
97 NSString* const SecCKRecordManifestGenerationCountKey = @"generation_count";
98 NSString* const SecCKRecordManifestLeafRecordIDsKey = @"leaf_records";
99 NSString* const SecCKRecordManifestPeerManifestRecordIDsKey = @"peer_manifests";
100 NSString* const SecCKRecordManifestCurrentItemsKey = @"current_items";
101 NSString* const SecCKRecordManifestSignaturesKey = @"signatures";
102 NSString* const SecCKRecordManifestSignerIDKey = @"signer_id";
103 NSString* const SecCKRecordManifestSchemaKey = @"schema";
104
105 NSString* const SecCKRecordManifestLeafType = @"manifest_leaf";
106 NSString* const SecCKRecordManifestLeafDERKey = @"der";
107 NSString* const SecCKRecordManifestLeafDigestKey = @"digest";
108
109 CKKSZoneKeyState* const SecCKKSZoneKeyStateReady = (CKKSZoneKeyState*) @"ready";
110 CKKSZoneKeyState* const SecCKKSZoneKeyStateError = (CKKSZoneKeyState*) @"error";
111 CKKSZoneKeyState* const SecCKKSZoneKeyStateCancelled = (CKKSZoneKeyState*) @"cancelled";
112
113 CKKSZoneKeyState* const SecCKKSZoneKeyStateInitializing = (CKKSZoneKeyState*) @"initializing";
114 CKKSZoneKeyState* const SecCKKSZoneKeyStateInitialized = (CKKSZoneKeyState*) @"initialized";
115 CKKSZoneKeyState* const SecCKKSZoneKeyStateFetchComplete = (CKKSZoneKeyState*) @"fetchcomplete";
116 CKKSZoneKeyState* const SecCKKSZoneKeyStateNeedFullRefetch = (CKKSZoneKeyState*) @"needrefetch";
117 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLK = (CKKSZoneKeyState*) @"waitfortlk";
118 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForUnlock = (CKKSZoneKeyState*) @"waitforunlock";
119 CKKSZoneKeyState* const SecCKKSZoneKeyStateUnhealthy = (CKKSZoneKeyState*) @"unhealthy";
120 CKKSZoneKeyState* const SecCKKSZoneKeyStateBadCurrentPointers = (CKKSZoneKeyState*) @"badcurrentpointers";
121 CKKSZoneKeyState* const SecCKKSZoneKeyStateNewTLKsFailed = (CKKSZoneKeyState*) @"newtlksfailed";
122
123 NSDictionary<CKKSZoneKeyState*, NSNumber*>* CKKSZoneKeyStateMap(void) {
124 static NSDictionary<CKKSZoneKeyState*, NSNumber*>* map = nil;
125 static dispatch_once_t onceToken;
126 dispatch_once(&onceToken, ^{
127 map = @{
128 SecCKKSZoneKeyStateReady: [NSNumber numberWithUnsignedInt: 0],
129 SecCKKSZoneKeyStateError: [NSNumber numberWithUnsignedInt: 1],
130 SecCKKSZoneKeyStateCancelled: [NSNumber numberWithUnsignedInt: 2],
131
132 SecCKKSZoneKeyStateInitializing: [NSNumber numberWithUnsignedInt: 3],
133 SecCKKSZoneKeyStateInitialized: [NSNumber numberWithUnsignedInt: 4],
134 SecCKKSZoneKeyStateFetchComplete: [NSNumber numberWithUnsignedInt: 5],
135 SecCKKSZoneKeyStateWaitForTLK: [NSNumber numberWithUnsignedInt: 6],
136 SecCKKSZoneKeyStateWaitForUnlock: [NSNumber numberWithUnsignedInt: 7],
137 SecCKKSZoneKeyStateUnhealthy: [NSNumber numberWithUnsignedInt: 8],
138 SecCKKSZoneKeyStateBadCurrentPointers: [NSNumber numberWithUnsignedInt: 9],
139 SecCKKSZoneKeyStateNewTLKsFailed: [NSNumber numberWithUnsignedInt:10],
140 };
141 });
142 return map;
143 }
144
145 NSDictionary<NSNumber*, CKKSZoneKeyState*>* CKKSZoneKeyStateInverseMap(void) {
146 static NSDictionary<NSNumber*, CKKSZoneKeyState*>* backwardMap = nil;
147 static dispatch_once_t onceToken;
148 dispatch_once(&onceToken, ^{
149 NSDictionary<CKKSZoneKeyState*, NSNumber*>* forwardMap = CKKSZoneKeyStateMap();
150 backwardMap = [NSDictionary dictionaryWithObjects:[forwardMap allKeys] forKeys:[forwardMap allValues]];
151 });
152 return backwardMap;
153 }
154
155 NSNumber* CKKSZoneKeyToNumber(CKKSZoneKeyState* state) {
156 if(!state) {
157 return CKKSZoneKeyStateMap()[SecCKKSZoneKeyStateError];
158 }
159 NSNumber* result = CKKSZoneKeyStateMap()[state];
160 if(result) {
161 return result;
162 }
163 return CKKSZoneKeyStateMap()[SecCKKSZoneKeyStateError];
164 }
165 CKKSZoneKeyState* CKKSZoneKeyRecover(NSNumber* stateNumber) {
166 if(!stateNumber) {
167 return SecCKKSZoneKeyStateError;
168 }
169 CKKSZoneKeyState* result = CKKSZoneKeyStateInverseMap()[stateNumber];
170 if(result) {
171 return result;
172 }
173 return SecCKKSZoneKeyStateError;
174 }
175
176 const NSUInteger SecCKKSItemPaddingBlockSize = 20;
177
178 NSString* const SecCKKSAggdPropagationDelay = @"com.apple.security.ckks.propagationdelay";
179 NSString* const SecCKKSAggdPrimaryKeyConflict = @"com.apple.security.ckks.pkconflict";
180 NSString* const SecCKKSAggdViewKeyCount = @"com.apple.security.ckks.keycount";
181 NSString* const SecCKKSAggdItemReencryption = @"com.apple.security.ckks.reencrypt";
182
183 NSString* const SecCKKSUserDefaultsSuite = @"com.apple.security.ckks";
184
185 #if OCTAGON
186 static bool enableCKKS = true;
187 static bool testCKKS = false;
188
189 bool SecCKKSIsEnabled(void) {
190 if([CKDatabase class] == nil) {
191 // CloudKit is not linked. We cannot bring CKKS up; disable it with prejudice.
192 secerror("CKKS: CloudKit.framework appears to not be linked. Cannot enable CKKS (on pain of crash).");
193 return false;
194 }
195
196 return enableCKKS;
197 }
198
199 bool SecCKKSEnable() {
200 enableCKKS = true;
201 return enableCKKS;
202 }
203
204 bool SecCKKSDisable() {
205 enableCKKS = false;
206 return enableCKKS;
207 }
208
209 bool SecCKKSResetSyncing(void) {
210 [CKKSViewManager resetManager: true setTo: nil];
211 return SecCKKSIsEnabled();
212 }
213
214 bool SecCKKSTestsEnabled(void) {
215 return testCKKS;
216 }
217
218 bool SecCKKSTestsEnable(void) {
219 if([CKDatabase class] == nil) {
220 // CloudKit is not linked. We cannot bring CKKS up; disable it with prejudice.
221 secerror("CKKS: CloudKit.framework appears to not be linked. Cannot enable CKKS testing.");
222 testCKKS = false;
223 return false;
224 }
225
226 testCKKS = true;
227 return testCKKS;
228 }
229
230 bool SecCKKSTestsDisable(void) {
231 testCKKS = false;
232 return testCKKS;
233 }
234
235 // Feature flags to twiddle behavior
236 static bool CKKSSyncManifests = false;
237 bool SecCKKSSyncManifests(void) {
238 return CKKSSyncManifests;
239 }
240 bool SecCKKSEnableSyncManifests() {
241 CKKSSyncManifests = true;
242 return CKKSSyncManifests;
243 }
244 bool SecCKKSSetSyncManifests(bool value) {
245 CKKSSyncManifests = value;
246 return CKKSSyncManifests;
247 }
248
249 static bool CKKSEnforceManifests = false;
250 bool SecCKKSEnforceManifests(void) {
251 return CKKSEnforceManifests;
252 }
253 bool SecCKKSEnableEnforceManifests() {
254 CKKSEnforceManifests = true;
255 return CKKSEnforceManifests;
256 }
257 bool SecCKKSSetEnforceManifests(bool value) {
258 CKKSEnforceManifests = value;
259 return CKKSEnforceManifests;
260 }
261
262 // Feature flags to twiddle behavior for tests
263 static bool CKKSDisableAutomaticUUID = false;
264 bool SecCKKSTestDisableAutomaticUUID(void) {
265 #if DEBUG
266 return CKKSDisableAutomaticUUID;
267 #else
268 return false;
269 #endif
270 }
271 void SecCKKSTestSetDisableAutomaticUUID(bool set) {
272 CKKSDisableAutomaticUUID = set;
273 }
274
275 static bool CKKSDisableSOS = false;
276 bool SecCKKSTestDisableSOS(void) {
277 #if DEBUG
278 return CKKSDisableSOS;
279 #else
280 return false;
281 #endif
282 }
283 void SecCKKSTestSetDisableSOS(bool set) {
284 CKKSDisableSOS = set;
285 }
286
287
288 static bool CKKSDisableKeyNotifications = false;
289 bool SecCKKSTestDisableKeyNotifications(void) {
290 #if DEBUG
291 return CKKSDisableKeyNotifications;
292 #else
293 return false;
294 #endif
295 }
296 void SecCKKSTestSetDisableKeyNotifications(bool set) {
297 CKKSDisableKeyNotifications = set;
298 }
299
300 void SecCKKSTestResetFlags(void) {
301 SecCKKSTestSetDisableAutomaticUUID(false);
302 SecCKKSTestSetDisableSOS(false);
303 SecCKKSTestSetDisableKeyNotifications(false);
304 }
305
306 XPC_RETURNS_RETAINED xpc_endpoint_t
307 SecServerCreateCKKSEndpoint(void)
308 {
309 if (SecCKKSIsEnabled()) {
310 return [[CKKSViewManager manager] xpcControlEndpoint];
311 } else {
312 return NULL;
313 }
314 }
315
316 #else /* NO OCTAGON */
317
318 bool SecCKKSIsEnabled(void) {
319 secerror("CKKS was disabled at compile time.");
320 return false;
321 }
322
323 bool SecCKKSEnable() {
324 return false;
325 }
326
327 bool SecCKKSDisable() {
328 return false;
329 }
330
331 bool SecCKKSResetSyncing(void) {
332 return SecCKKSIsEnabled();
333 }
334
335 XPC_RETURNS_RETAINED xpc_endpoint_t
336 SecServerCreateCKKSEndpoint(void)
337 {
338 return NULL;
339 }
340 #endif /* OCTAGON */
341
342
343
344 void SecCKKSInitialize(SecDbRef db) {
345 #if OCTAGON
346 CKKSViewManager* manager = [CKKSViewManager manager];
347 [manager initializeZones];
348
349 SecDbAddNotifyPhaseBlock(db, ^(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) {
350 SecCKKSNotifyBlock(dbconn, phase, source, changes);
351 });
352
353 [manager.completedSecCKKSInitialize fulfill];
354 #endif
355 }
356
357 void SecCKKSNotifyBlock(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) {
358 #if OCTAGON
359 if(phase == kSecDbTransactionDidRollback) {
360 return;
361 }
362
363 // Ignore our own changes, otherwise we'd infinite-loop.
364 if(source == kSecDbCKKSTransaction) {
365 secinfo("ckks", "Ignoring kSecDbCKKSTransaction notification");
366 return;
367 }
368
369 CFArrayForEach(changes, ^(CFTypeRef r) {
370 SecDbItemRef deleted = NULL;
371 SecDbItemRef added = NULL;
372
373 SecDbEventTranslateComponents(r, (CFTypeRef*) &deleted, (CFTypeRef*) &added);
374
375 if(!added && !deleted) {
376 secerror("CKKS: SecDbEvent gave us garbage: %@", r);
377 return;
378 }
379
380 [[CKKSViewManager manager] handleKeychainEventDbConnection: dbconn source:source added: added deleted: deleted];
381 });
382 #endif
383 }
384
385 void SecCKKS24hrNotification() {
386 #if OCTAGON
387 @autoreleasepool {
388 [[CKKSViewManager manager] xpc24HrNotification];
389 }
390 #endif
391 }
392
393 void CKKSRegisterSyncStatusCallback(CFStringRef cfuuid, SecBoolCFErrorCallback cfcallback) {
394 #if OCTAGON
395 // Keep plumbing, but transition to NS.
396 SecBoolNSErrorCallback nscallback = ^(bool result, NSError* err) {
397 cfcallback(result, (__bridge CFErrorRef) err);
398 };
399
400 [[CKKSViewManager manager] registerSyncStatusCallback: (__bridge NSString*) cfuuid callback:nscallback];
401 #endif
402 }