]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTPrepareOperation.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / ot / OTPrepareOperation.m
1 /*
2 * Copyright (c) 2018 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 #if OCTAGON
25
26 #import "utilities/debugging.h"
27 #import <Security/SecKey.h>
28 #import <Security/SecKeyPriv.h>
29
30 #import "keychain/ot/OTCuttlefishContext.h"
31 #import "keychain/ot/OTFetchViewsOperation.h"
32 #import "keychain/ot/OTOperationDependencies.h"
33 #import "keychain/ot/OTPrepareOperation.h"
34
35 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
36 #import "keychain/ot/ObjCImprovements.h"
37
38 @interface OTPrepareOperation ()
39 @property OTOperationDependencies* deps;
40 @property NSOperation* finishedOp;
41 @end
42
43 @implementation OTPrepareOperation
44 @synthesize intendedState = _intendedState;
45 @synthesize nextState = _nextState;
46
47 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
48 intendedState:(OctagonState*)intendedState
49 errorState:(OctagonState*)errorState
50 deviceInfo:(OTDeviceInformation*)deviceInfo
51 epoch:(uint64_t)epoch
52 {
53 if((self = [super init])) {
54 _deps = dependencies;
55
56 _deviceInfo = deviceInfo;
57 _epoch = epoch;
58
59 _intendedState = intendedState;
60 _nextState = errorState;
61 }
62 return self;
63 }
64
65 - (void)groupStart
66 {
67 secnotice("octagon", "preparing an identity");
68
69 self.finishedOp = [[NSOperation alloc] init];
70 [self dependOnBeforeGroupFinished:self.finishedOp];
71
72 NSString* bottleSalt = nil;
73
74 if(self.deps.authKitAdapter.primaryiCloudAccountAltDSID){
75 bottleSalt = self.deps.authKitAdapter.primaryiCloudAccountAltDSID;
76 }
77 else {
78 NSError* accountError = nil;
79 OTAccountMetadataClassC* account = [self.deps.stateHolder loadOrCreateAccountMetadata:&accountError];
80
81 if(account && !accountError) {
82 secnotice("octagon", "retrieved account, altdsid is: %@", account.altDSID);
83 bottleSalt = account.altDSID;
84 }
85 if(accountError || !account){
86 secerror("failed to rerieve account object: %@", accountError);
87 }
88 }
89 WEAKIFY(self);
90
91 // But, if this device is SOS-enabled and SOS is present, use the SOS octagon keys (if present)
92 NSData* signingKeyPersistRef = nil;
93 NSData* encryptionKeyPersistRef = nil;
94 if(self.deps.sosAdapter.sosEnabled) {
95 secnotice("octagon-sos", "Investigating use of Octagon keys from SOS identity");
96
97 NSError* error = nil;
98 id<CKKSSelfPeer> sosSelf = [self.deps.sosAdapter currentSOSSelf:&error];
99
100 if(!sosSelf || error) {
101 secnotice("octagon-sos", "Failed to get the current SOS self: %@", error);
102 } else {
103 // Fetch the persistent references for our signing and encryption keys
104 OSStatus status = errSecSuccess;
105 CFDataRef cfSigningKeyPersistRef = NULL;
106 status = SecKeyCopyPersistentRef(sosSelf.signingKey.secKey, &cfSigningKeyPersistRef);
107 if(status != errSecSuccess || !cfSigningKeyPersistRef) {
108 secnotice("octagon-sos", "Failed to get the persistent ref for our SOS signing key: %d", (int)status);
109 } else {
110 CFDataRef cfEncryptionKeyPersistRef = NULL;
111 status = SecKeyCopyPersistentRef(sosSelf.encryptionKey.secKey, &cfEncryptionKeyPersistRef);
112 if(status != errSecSuccess || !cfEncryptionKeyPersistRef) {
113 secnotice("octagon-sos", "Failed to get the persistent ref for our SOS encryption key: %d", (int)status);
114 CFReleaseNull(cfSigningKeyPersistRef);
115 CFReleaseNull(cfEncryptionKeyPersistRef);
116 } else {
117 // We only want to use these keys if we successfully have both
118 signingKeyPersistRef = CFBridgingRelease(cfSigningKeyPersistRef);
119 encryptionKeyPersistRef = CFBridgingRelease(cfEncryptionKeyPersistRef);
120 }
121 }
122 }
123 }
124
125 NSError* persistError = nil;
126 BOOL persisted = [self.deps.stateHolder persistOctagonJoinAttempt:OTAccountMetadataClassC_AttemptedAJoinState_ATTEMPTED error:&persistError];
127 if(!persisted || persistError) {
128 secerror("octagon: failed to save 'attempted join' state: %@", persistError);
129 }
130
131 [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
132 STRONGIFY(self);
133 secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
134 [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventPrepareIdentity withAttributes:nil];
135 self.error = error;
136 [self runBeforeGroupFinished:self.finishedOp];
137
138 }] prepareWithContainer:self.deps.containerName
139 context:self.deps.contextID
140 epoch:self.epoch
141 machineID:self.deviceInfo.machineID
142 bottleSalt:bottleSalt
143 bottleID:[NSUUID UUID].UUIDString
144 modelID:self.deviceInfo.modelID
145 deviceName:self.deviceInfo.deviceName
146 serialNumber:self.deviceInfo.serialNumber
147 osVersion:self.deviceInfo.osVersion
148 policyVersion:nil
149 policySecrets:nil
150 signingPrivKeyPersistentRef:signingKeyPersistRef
151 encPrivKeyPersistentRef:encryptionKeyPersistRef
152 reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) {
153 STRONGIFY(self);
154 [[CKKSAnalytics logger] logResultForEvent:OctagonEventPrepareIdentity hardFailure:true result:error];
155 if(error) {
156 secerror("octagon: Error preparing identity: %@", error);
157 self.error = error;
158 [self runBeforeGroupFinished:self.finishedOp];
159 } else {
160 secnotice("octagon", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig);
161 self.peerID = peerID;
162 self.permanentInfo = permanentInfo;
163 self.permanentInfoSig = permanentInfoSig;
164 self.stableInfo = stableInfo;
165 self.stableInfoSig = stableInfoSig;
166
167 NSError* localError = nil;
168 BOOL persisted = [self.deps.stateHolder persistNewEgoPeerID:peerID error:&localError];
169 if(!persisted || localError) {
170 secnotice("octagon", "Couldn't persist peer ID: %@", localError);
171 self.error = localError;
172 [self runBeforeGroupFinished:self.finishedOp];
173 } else {
174 WEAKIFY(self);
175
176 CKKSResultOperation *doneOp = [CKKSResultOperation named:@"ot-prepare"
177 withBlock:^{
178 STRONGIFY(self);
179 self.nextState = self.intendedState;
180 }];
181
182 OTFetchViewsOperation *fetchViewsOp = [[OTFetchViewsOperation alloc] initWithDependencies:self.deps];
183 [self runBeforeGroupFinished:fetchViewsOp];
184 [doneOp addDependency:fetchViewsOp];
185 [self runBeforeGroupFinished:doneOp];
186 [self.finishedOp addDependency:doneOp];
187 [self runBeforeGroupFinished:self.finishedOp];
188 }
189 }
190 }];
191 }
192
193 @end
194
195 #endif // OCTAGON