]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKS.m
Security-58286.31.2.tar.gz
[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 SecCKRecordHostOSVersionKey = @"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 SecCKRecordTLKShareType = @"tlkshare";
83 NSString* const SecCKRecordSenderPeerID = @"sender";
84 NSString* const SecCKRecordReceiverPeerID = @"receiver";
85 NSString* const SecCKRecordReceiverPublicEncryptionKey = @"receiverPublicEncryptionKey";
86 NSString* const SecCKRecordCurve = @"curve";
87 NSString* const SecCKRecordEpoch = @"epoch";
88 NSString* const SecCKRecordPoisoned = @"poisoned";
89 NSString* const SecCKRecordSignature = @"signature";
90 NSString* const SecCKRecordVersion = @"version";
91
92 NSString* const SecCKRecordCurrentKeyType = @"currentkey";
93
94 NSString* const SecCKRecordCurrentItemType = @"currentitem";
95 NSString* const SecCKRecordItemRefKey = @"item";
96
97 NSString* const SecCKRecordDeviceStateType = @"devicestate";
98 NSString* const SecCKRecordCirclePeerID = @"peerid";
99 NSString* const SecCKRecordCircleStatus = @"circle";
100 NSString* const SecCKRecordKeyState = @"keystate";
101 NSString* const SecCKRecordCurrentTLK = @"currentTLK";
102 NSString* const SecCKRecordCurrentClassA = @"currentClassA";
103 NSString* const SecCKRecordCurrentClassC = @"currentClassC";
104
105 NSString* const SecCKRecordManifestType = @"manifest";
106 NSString* const SecCKRecordManifestDigestValueKey = @"digest_value";
107 NSString* const SecCKRecordManifestGenerationCountKey = @"generation_count";
108 NSString* const SecCKRecordManifestLeafRecordIDsKey = @"leaf_records";
109 NSString* const SecCKRecordManifestPeerManifestRecordIDsKey = @"peer_manifests";
110 NSString* const SecCKRecordManifestCurrentItemsKey = @"current_items";
111 NSString* const SecCKRecordManifestSignaturesKey = @"signatures";
112 NSString* const SecCKRecordManifestSignerIDKey = @"signer_id";
113 NSString* const SecCKRecordManifestSchemaKey = @"schema";
114
115 NSString* const SecCKRecordManifestLeafType = @"manifest_leaf";
116 NSString* const SecCKRecordManifestLeafDERKey = @"der";
117 NSString* const SecCKRecordManifestLeafDigestKey = @"digest";
118
119 CKKSZoneKeyState* const SecCKKSZoneKeyStateReady = (CKKSZoneKeyState*) @"ready";
120 CKKSZoneKeyState* const SecCKKSZoneKeyStateError = (CKKSZoneKeyState*) @"error";
121 CKKSZoneKeyState* const SecCKKSZoneKeyStateCancelled = (CKKSZoneKeyState*) @"cancelled";
122
123 CKKSZoneKeyState* const SecCKKSZoneKeyStateInitializing = (CKKSZoneKeyState*) @"initializing";
124 CKKSZoneKeyState* const SecCKKSZoneKeyStateInitialized = (CKKSZoneKeyState*) @"initialized";
125 CKKSZoneKeyState* const SecCKKSZoneKeyStateFetchComplete = (CKKSZoneKeyState*) @"fetchcomplete";
126 CKKSZoneKeyState* const SecCKKSZoneKeyStateNeedFullRefetch = (CKKSZoneKeyState*) @"needrefetch";
127 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLK = (CKKSZoneKeyState*) @"waitfortlk";
128 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForUnlock = (CKKSZoneKeyState*) @"waitforunlock";
129 CKKSZoneKeyState* const SecCKKSZoneKeyStateUnhealthy = (CKKSZoneKeyState*) @"unhealthy";
130 CKKSZoneKeyState* const SecCKKSZoneKeyStateBadCurrentPointers = (CKKSZoneKeyState*) @"badcurrentpointers";
131 CKKSZoneKeyState* const SecCKKSZoneKeyStateNewTLKsFailed = (CKKSZoneKeyState*) @"newtlksfailed";
132 CKKSZoneKeyState* const SecCKKSZoneKeyStateHealTLKShares = (CKKSZoneKeyState*) @"healtlkshares";
133 CKKSZoneKeyState* const SecCKKSZoneKeyStateHealTLKSharesFailed = (CKKSZoneKeyState*) @"healtlksharesfailed";
134 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForFixupOperation = (CKKSZoneKeyState*) @"waitforfixupoperation";
135
136 NSDictionary<CKKSZoneKeyState*, NSNumber*>* CKKSZoneKeyStateMap(void) {
137 static NSDictionary<CKKSZoneKeyState*, NSNumber*>* map = nil;
138 static dispatch_once_t onceToken;
139 dispatch_once(&onceToken, ^{
140 map = @{
141 SecCKKSZoneKeyStateReady: @0U,
142 SecCKKSZoneKeyStateError: @1U,
143 SecCKKSZoneKeyStateCancelled: @2U,
144
145 SecCKKSZoneKeyStateInitializing: @3U,
146 SecCKKSZoneKeyStateInitialized: @4U,
147 SecCKKSZoneKeyStateFetchComplete: @5U,
148 SecCKKSZoneKeyStateWaitForTLK: @6U,
149 SecCKKSZoneKeyStateWaitForUnlock: @7U,
150 SecCKKSZoneKeyStateUnhealthy: @8U,
151 SecCKKSZoneKeyStateBadCurrentPointers: @9U,
152 SecCKKSZoneKeyStateNewTLKsFailed: @10U,
153 SecCKKSZoneKeyStateNeedFullRefetch: @11U,
154 SecCKKSZoneKeyStateHealTLKShares: @12U,
155 SecCKKSZoneKeyStateHealTLKSharesFailed:@13U,
156 SecCKKSZoneKeyStateWaitForFixupOperation:@14U,
157 };
158 });
159 return map;
160 }
161
162 NSDictionary<NSNumber*, CKKSZoneKeyState*>* CKKSZoneKeyStateInverseMap(void) {
163 static NSDictionary<NSNumber*, CKKSZoneKeyState*>* backwardMap = nil;
164 static dispatch_once_t onceToken;
165 dispatch_once(&onceToken, ^{
166 NSDictionary<CKKSZoneKeyState*, NSNumber*>* forwardMap = CKKSZoneKeyStateMap();
167 backwardMap = [NSDictionary dictionaryWithObjects:[forwardMap allKeys] forKeys:[forwardMap allValues]];
168 });
169 return backwardMap;
170 }
171
172 NSNumber* CKKSZoneKeyToNumber(CKKSZoneKeyState* state) {
173 if(!state) {
174 return CKKSZoneKeyStateMap()[SecCKKSZoneKeyStateError];
175 }
176 NSNumber* result = CKKSZoneKeyStateMap()[state];
177 if(result) {
178 return result;
179 }
180 return CKKSZoneKeyStateMap()[SecCKKSZoneKeyStateError];
181 }
182 CKKSZoneKeyState* CKKSZoneKeyRecover(NSNumber* stateNumber) {
183 if(!stateNumber) {
184 return SecCKKSZoneKeyStateError;
185 }
186 CKKSZoneKeyState* result = CKKSZoneKeyStateInverseMap()[stateNumber];
187 if(result) {
188 return result;
189 }
190 return SecCKKSZoneKeyStateError;
191 }
192
193 const NSUInteger SecCKKSItemPaddingBlockSize = 20;
194
195 NSString* const SecCKKSAggdPropagationDelay = @"com.apple.security.ckks.propagationdelay";
196 NSString* const SecCKKSAggdPrimaryKeyConflict = @"com.apple.security.ckks.pkconflict";
197 NSString* const SecCKKSAggdViewKeyCount = @"com.apple.security.ckks.keycount";
198 NSString* const SecCKKSAggdItemReencryption = @"com.apple.security.ckks.reencrypt";
199
200 NSString* const SecCKKSUserDefaultsSuite = @"com.apple.security.ckks";
201
202 NSString* const CKKSErrorDomain = @"CKKSErrorDomain";
203 NSString* const CKKSServerExtensionErrorDomain = @"CKKSServerExtensionErrorDomain";
204
205 #if OCTAGON
206 static bool enableCKKS = true;
207 static bool testCKKS = false;
208
209 bool SecCKKSIsEnabled(void) {
210 if([CKDatabase class] == nil) {
211 // CloudKit is not linked. We cannot bring CKKS up; disable it with prejudice.
212 secerror("CKKS: CloudKit.framework appears to not be linked. Cannot enable CKKS (on pain of crash).");
213 return false;
214 }
215
216 return enableCKKS;
217 }
218
219 bool SecCKKSEnable() {
220 enableCKKS = true;
221 return enableCKKS;
222 }
223
224 bool SecCKKSDisable() {
225 enableCKKS = false;
226 return enableCKKS;
227 }
228
229 bool SecCKKSResetSyncing(void) {
230 [CKKSViewManager resetManager: true setTo: nil];
231 return SecCKKSIsEnabled();
232 }
233
234 bool SecCKKSTestsEnabled(void) {
235 return testCKKS;
236 }
237
238 bool SecCKKSTestsEnable(void) {
239 if([CKDatabase class] == nil) {
240 // CloudKit is not linked. We cannot bring CKKS up; disable it with prejudice.
241 secerror("CKKS: CloudKit.framework appears to not be linked. Cannot enable CKKS testing.");
242 testCKKS = false;
243 return false;
244 }
245
246 testCKKS = true;
247 return testCKKS;
248 }
249
250 bool SecCKKSTestsDisable(void) {
251 testCKKS = false;
252 return testCKKS;
253 }
254
255 // Feature flags to twiddle behavior
256 static bool CKKSSyncManifests = false;
257 bool SecCKKSSyncManifests(void) {
258 return CKKSSyncManifests;
259 }
260 bool SecCKKSEnableSyncManifests() {
261 CKKSSyncManifests = true;
262 return CKKSSyncManifests;
263 }
264 bool SecCKKSSetSyncManifests(bool value) {
265 CKKSSyncManifests = value;
266 return CKKSSyncManifests;
267 }
268
269 static bool CKKSEnforceManifests = false;
270 bool SecCKKSEnforceManifests(void) {
271 return CKKSEnforceManifests;
272 }
273 bool SecCKKSEnableEnforceManifests() {
274 CKKSEnforceManifests = true;
275 return CKKSEnforceManifests;
276 }
277 bool SecCKKSSetEnforceManifests(bool value) {
278 CKKSEnforceManifests = value;
279 return CKKSEnforceManifests;
280 }
281
282 static bool CKKSShareTLKs = true;
283 bool SecCKKSShareTLKs(void) {
284 static dispatch_once_t onceToken;
285 dispatch_once(&onceToken, ^{
286 // Use the default value as above, or apply the preferences value if it exists
287 NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:SecCKKSUserDefaultsSuite];
288 [defaults registerDefaults: @{@"tlksharing": CKKSShareTLKs ? @YES : @NO}];
289
290 CKKSShareTLKs = !![defaults boolForKey:@"tlksharing"];
291 secnotice("ckksshare", "TLK sharing is %@", CKKSShareTLKs ? @"on" : @"off");
292 });
293
294 return CKKSShareTLKs;
295 }
296 bool SecCKKSEnableShareTLKs(void) {
297 return SecCKKSSetShareTLKs(true);
298 }
299 bool SecCKKSSetShareTLKs(bool value) {
300 // Call this to do the dispatch_once first
301 SecCKKSShareTLKs();
302
303 CKKSShareTLKs = value;
304 return CKKSShareTLKs;
305 }
306
307 // Feature flags to twiddle behavior for tests
308 static bool CKKSDisableAutomaticUUID = false;
309 bool SecCKKSTestDisableAutomaticUUID(void) {
310 #if DEBUG
311 return CKKSDisableAutomaticUUID;
312 #else
313 return false;
314 #endif
315 }
316 void SecCKKSTestSetDisableAutomaticUUID(bool set) {
317 CKKSDisableAutomaticUUID = set;
318 }
319
320 static bool CKKSDisableSOS = false;
321 bool SecCKKSTestDisableSOS(void) {
322 #if DEBUG
323 return CKKSDisableSOS;
324 #else
325 return false;
326 #endif
327 }
328 void SecCKKSTestSetDisableSOS(bool set) {
329 CKKSDisableSOS = set;
330 }
331
332
333 static bool CKKSDisableKeyNotifications = false;
334 bool SecCKKSTestDisableKeyNotifications(void) {
335 #if DEBUG
336 return CKKSDisableKeyNotifications;
337 #else
338 return false;
339 #endif
340 }
341 void SecCKKSTestSetDisableKeyNotifications(bool set) {
342 CKKSDisableKeyNotifications = set;
343 }
344
345 void SecCKKSTestResetFlags(void) {
346 SecCKKSTestSetDisableAutomaticUUID(false);
347 SecCKKSTestSetDisableSOS(false);
348 SecCKKSTestSetDisableKeyNotifications(false);
349 }
350
351 XPC_RETURNS_RETAINED xpc_endpoint_t
352 SecServerCreateCKKSEndpoint(void)
353 {
354 if (SecCKKSIsEnabled()) {
355 return [[CKKSViewManager manager] xpcControlEndpoint];
356 } else {
357 return NULL;
358 }
359 }
360
361 #else /* NO OCTAGON */
362
363 bool SecCKKSIsEnabled(void) {
364 secerror("CKKS was disabled at compile time.");
365 return false;
366 }
367
368 bool SecCKKSEnable() {
369 return false;
370 }
371
372 bool SecCKKSDisable() {
373 return false;
374 }
375
376 bool SecCKKSResetSyncing(void) {
377 return SecCKKSIsEnabled();
378 }
379
380 XPC_RETURNS_RETAINED xpc_endpoint_t
381 SecServerCreateCKKSEndpoint(void)
382 {
383 return NULL;
384 }
385 #endif /* OCTAGON */
386
387
388
389 void SecCKKSInitialize(SecDbRef db) {
390 #if OCTAGON
391 CKKSViewManager* manager = [CKKSViewManager manager];
392 [manager initializeZones];
393
394 SecDbAddNotifyPhaseBlock(db, ^(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) {
395 SecCKKSNotifyBlock(dbconn, phase, source, changes);
396 });
397
398 [manager.completedSecCKKSInitialize fulfill];
399 #endif
400 }
401
402 void SecCKKSNotifyBlock(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) {
403 #if OCTAGON
404 if(phase == kSecDbTransactionDidRollback) {
405 return;
406 }
407
408 // Ignore our own changes, otherwise we'd infinite-loop.
409 if(source == kSecDbCKKSTransaction) {
410 secinfo("ckks", "Ignoring kSecDbCKKSTransaction notification");
411 return;
412 }
413
414 CFArrayForEach(changes, ^(CFTypeRef r) {
415 SecDbItemRef deleted = NULL;
416 SecDbItemRef added = NULL;
417
418 SecDbEventTranslateComponents(r, (CFTypeRef*) &deleted, (CFTypeRef*) &added);
419
420 if(!added && !deleted) {
421 secerror("CKKS: SecDbEvent gave us garbage: %@", r);
422 return;
423 }
424
425 [[CKKSViewManager manager] handleKeychainEventDbConnection: dbconn source:source added: added deleted: deleted];
426 });
427 #endif
428 }
429
430 void SecCKKS24hrNotification() {
431 #if OCTAGON
432 @autoreleasepool {
433 [[CKKSViewManager manager] xpc24HrNotification];
434 }
435 #endif
436 }
437
438 void CKKSRegisterSyncStatusCallback(CFStringRef cfuuid, SecBoolCFErrorCallback cfcallback) {
439 #if OCTAGON
440 // Keep plumbing, but transition to NS.
441 SecBoolNSErrorCallback nscallback = ^(bool result, NSError* err) {
442 cfcallback(result, (__bridge CFErrorRef) err);
443 };
444
445 [[CKKSViewManager manager] registerSyncStatusCallback: (__bridge NSString*) cfuuid callback:nscallback];
446 #endif
447 }