]> git.saurik.com Git - apple/security.git/blob - KeychainCircle/KCJoiningRequestSession.m
Security-57740.1.18.tar.gz
[apple/security.git] / KeychainCircle / KCJoiningRequestSession.m
1 //
2 // KCJoiningSession.m
3 // Security
4 //
5 //
6
7 #import <Foundation/Foundation.h>
8
9 #import <KeychainCircle/KCJoiningSession.h>
10
11 #import <KeychainCircle/KCError.h>
12 #import <KeychainCircle/KCDer.h>
13 #import <KeychainCircle/KCSRPContext.h>
14
15 #import <KeychainCircle/KCJoiningMessages.h>
16
17 #include <corecrypto/ccrng.h>
18 #include <corecrypto/ccsha2.h>
19 #include <corecrypto/ccdh_gp.h>
20 #include <corecrypto/ccder.h>
21 #include <CommonCrypto/CommonRandomSPI.h>
22
23 #include <utilities/debugging.h>
24
25 #import <KeychainCircle/NSError+KCCreationHelpers.h>
26
27 typedef enum {
28 kExpectingB,
29 kExpectingHAMK,
30 kRequestSecretDone
31 } KCJoiningRequestSecretSessionState;
32
33 typedef enum {
34 kExpectingCircleBlob,
35 kRequestCircleDone
36 } KCJoiningRequestCircleSessionState;
37
38 @interface KCJoiningRequestSecretSession ()
39 @property (readonly) NSObject<KCJoiningRequestSecretDelegate>* secretDelegate;
40 @property (readonly) KCSRPClientContext* context;
41 @property (readonly) uint64_t dsid;
42 @property (readonly) KCJoiningRequestSecretSessionState state;
43
44 @property (readwrite) NSData* challenge;
45 @property (readwrite) NSData* salt;
46 @end
47
48 @implementation KCJoiningRequestSecretSession : NSObject
49
50 - (nullable NSData*) initialMessage: (NSError**) error {
51 NSData* start = [self->_context copyStart: error];
52 if (start == nil) return nil;
53
54 NSMutableData* initialMessage = [NSMutableData dataWithLength: sizeof_initialmessage(start)];
55
56 if (NULL == encode_initialmessage(start, error, initialMessage.mutableBytes, initialMessage.mutableBytes + initialMessage.length))
57 return nil;
58
59 return initialMessage;
60 }
61
62 - (bool) isDone {
63 return self->_state == kRequestSecretDone;
64 }
65
66 - (bool) setupSession: (NSError**) error {
67 NSData* key = [self->_context getKey];
68
69 if (key == nil) {
70 KCJoiningErrorCreate(kInternalError, error, @"No session key available");
71 return nil;
72 }
73
74 self->_session = [KCAESGCMDuplexSession sessionAsSender:key context:self.dsid];
75
76 return self.session != nil;
77 }
78
79 - (nullable NSData*) copyResponseForChallenge:(NSData*) challenge
80 salt:(NSData*) salt
81 secret: (NSString*) password
82 error: (NSError**) error {
83 NSData* response = [self->_context copyResposeToChallenge:challenge
84 password:password
85 salt:salt
86 error:error];
87
88 if (!response) {
89 // @@@ return error to other side???
90 return nil;
91 } else {
92 if (![self setupSession: error]) return nil;
93
94 self.challenge = challenge;
95 self.salt = salt;
96
97 self->_state = kExpectingHAMK;
98 return [[KCJoiningMessage messageWithType:kResponse
99 data:response
100 error:error] der];
101 }
102 }
103
104
105 - (nullable NSData*) copyResponseForSecret: (NSString*) password
106 error: (NSError**) error {
107 return [self copyResponseForChallenge:self.challenge salt:self.salt secret:password error:error];
108 }
109
110 - (nullable NSData*) handleChallengeData: (NSData*) challengeData
111 secret: (NSString*) password
112 error: (NSError**) error {
113 NSData* challenge = nil;
114 NSData* salt = nil;
115
116 if (![challengeData decodeSequenceData:&salt data:&challenge error:error]) return nil;
117
118 return [self copyResponseForChallenge:challenge salt:salt secret:password error:error];
119
120 }
121
122 - (nullable NSData*) handleChallenge: (KCJoiningMessage*) message
123 secret: (NSString*) password
124 error: (NSError**)error {
125 // Parse the challenge message
126 // Salt and Challenge packet
127 if ([message type] != kChallenge) {
128 KCJoiningErrorCreate(kUnexpectedMessage, error, @"Expected challenge!");
129 return nil;
130 }
131
132 return [self handleChallengeData:[message firstData] secret:password error:error];
133 }
134
135 - (NSData*) handleChallenge: (KCJoiningMessage*) message error: (NSError**)error {
136 return [self handleChallenge:message
137 secret:[self.secretDelegate secret]
138 error:error];
139
140 }
141
142 - (NSData*) handleVerification: (KCJoiningMessage*) message error: (NSError**) error {
143 if ([message type] == kError) {
144 bool newCode = [[message firstData] length] == 0;
145 NSString* nextSecret = [self.secretDelegate verificationFailed: newCode];
146
147 if (nextSecret) {
148 if (newCode) {
149 return [self copyResponseForSecret:nextSecret error:error];
150 } else {
151 return [self handleChallengeData:[message firstData] secret:nextSecret error:error];
152 }
153 } else {
154 return nil;
155 }
156 }
157
158 if ([message type] != kVerification) {
159 KCJoiningErrorCreate(kUnexpectedMessage, error, @"Expected verification!");
160 return nil;
161 }
162
163 if (![self.context verifyConfirmation:[message firstData] error:error]) {
164 // Sender thought we had it right, but he can't prove he has it right!
165 KCJoiningErrorCreate(kInternalError, error, @"Got verification but acceptor doesn't have matching secret: %@", self);
166 secnotice("request-session", "Verification failed: %@", self);
167 return nil;
168 }
169
170 {
171 NSData* payload = [self.session decryptAndVerify:[message secondData] error:error];
172 if (payload == nil) return nil;
173
174 NSString* accountCode = [NSString decodeFromDER:payload error:error];
175 if (accountCode == nil) return nil;
176
177 if (![self.secretDelegate processAccountCode:accountCode error:error]) return nil;
178 }
179
180 self->_state = kRequestSecretDone;
181
182 return [NSData data];
183 }
184
185
186
187
188 // [self.delegate processCircleJoinData:circleData error:error];
189
190 - (NSData*) processMessage: (NSData*) incomingMessage error: (NSError**) error {
191 NSData* result = nil;
192 KCJoiningMessage* message = [KCJoiningMessage messageWithDER: incomingMessage error: error];
193 if (message == nil) return nil;
194
195 switch(self->_state) {
196 case kExpectingB:
197 return [self handleChallenge:message error: error];
198 break;
199 case kExpectingHAMK:
200 return [self handleVerification:message error:error];
201 break;
202 case kRequestSecretDone:
203 KCJoiningErrorCreate(kUnexpectedMessage, error, @"Done, no messages expected.");
204 break;
205 }
206
207 return result;
208 }
209
210 + (nullable instancetype)sessionWithSecretDelegate: (NSObject<KCJoiningRequestSecretDelegate>*) secretDelegate
211 dsid: (uint64_t)dsid
212 error: (NSError**) error {
213 return [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:secretDelegate
214 dsid:dsid
215 error:error];
216 }
217
218 - (nullable instancetype)initWithSecretDelegate: (NSObject<KCJoiningRequestSecretDelegate>*) secretDelegate
219 dsid: (uint64_t)dsid
220 error: (NSError**)error {
221 int cc_error = 0;
222 struct ccrng_state * rng = ccrng(&cc_error);
223
224 if (rng == nil) {
225 CoreCryptoError(cc_error, error, @"RNG fetch failed");
226 return nil;
227 }
228
229 return [self initWithSecretDelegate: secretDelegate
230 dsid: dsid
231 rng: rng
232 error: error];
233 }
234
235 - (nullable instancetype)initWithSecretDelegate: (NSObject<KCJoiningRequestSecretDelegate>*) secretDelegate
236 dsid: (uint64_t)dsid
237 rng: (struct ccrng_state *)rng
238 error: (NSError**)error {
239
240 self = [super init];
241
242 self->_secretDelegate = secretDelegate;
243 self->_state = kExpectingB;
244 self->_dsid = dsid;
245
246 NSString* name = [NSString stringWithFormat: @"%llu", dsid];
247
248 self->_context = [[KCSRPClientContext alloc] initWithUser: name
249 digestInfo: ccsha256_di()
250 group: ccsrp_gp_rfc5054_3072()
251 randomSource: rng];
252
253 return self;
254 }
255
256 - (NSString*) stateString {
257 switch (self.state) {
258 case kExpectingB: return @"→B";
259 case kExpectingHAMK: return @"→HAMK";
260 case kRequestSecretDone: return @"SecretDone";
261 default: return [NSString stringWithFormat:@"%d", self.state];
262 }
263 }
264
265 - (NSString *)description {
266 return [NSString stringWithFormat: @"<KCJoiningAcceptSession@%p %lld %@ %@>", self, self.dsid, [self stateString], self.context];
267 }
268
269 @end
270
271 @interface KCJoiningRequestCircleSession ()
272 @property (readonly) NSObject<KCJoiningRequestCircleDelegate>* circleDelegate;
273 @property (readonly) KCAESGCMDuplexSession* session;
274 @property (readwrite) KCJoiningRequestCircleSessionState state;
275 @end
276
277 @implementation KCJoiningRequestCircleSession
278 - (nullable NSData*) encryptedPeerInfo: (NSError**) error {
279 // Get our peer info and send it along:
280 if (self->_session == nil) {
281 KCJoiningErrorCreate(kInternalError, error, @"Attempt to encrypt with no session");
282 return nil;
283 }
284
285 SOSPeerInfoRef us = [self.circleDelegate copyPeerInfoError:error];
286 if (us == NULL) return nil;
287 CFErrorRef cfError = NULL;
288 NSData* piEncoded = (__bridge_transfer NSData*) SOSPeerInfoCopyEncodedData(us, NULL, &cfError);
289
290 if (piEncoded == nil) {
291 if (error != nil) {
292 *error = (__bridge_transfer NSError*) cfError;
293 }
294 return nil;
295 }
296
297 return [self->_session encrypt:piEncoded error:error];
298 }
299
300 - (nullable NSData*) initialMessage: (NSError**) error {
301 NSData* encryptedPi = [self encryptedPeerInfo:error];
302 if (encryptedPi == nil) return nil;
303
304 self->_state = kExpectingCircleBlob;
305
306 return [[KCJoiningMessage messageWithType:kPeerInfo
307 data:encryptedPi
308 error:error] der];
309
310 }
311
312 - (NSData*) handleCircleBlob: (KCJoiningMessage*) message error: (NSError**) error {
313 if ([message type] != kCircleBlob) {
314 KCJoiningErrorCreate(kUnexpectedMessage, error, @"Expected CircleBlob!");
315 return nil;
316 }
317
318 NSData* circleBlob = [self.session decryptAndVerify:message.firstData error:error];
319 if (circleBlob == nil) return nil;
320
321 if (![self.circleDelegate processCircleJoinData: circleBlob error:error])
322 return nil;
323
324 self->_state = kRequestCircleDone;
325
326 return [NSData data]; // Success, an empty message.
327 }
328
329 - (NSData*) processMessage: (NSData*) incomingMessage error: (NSError**) error {
330 NSData* result = nil;
331 KCJoiningMessage* message = [KCJoiningMessage messageWithDER: incomingMessage error: error];
332 if (message == nil) return nil;
333
334 switch(self.state) {
335 case kExpectingCircleBlob:
336 return [self handleCircleBlob:message error:error];
337 case kRequestCircleDone:
338 KCJoiningErrorCreate(kUnexpectedMessage, error, @"Done, no messages expected.");
339 break;
340 }
341
342 return result;
343 }
344
345 - (bool) isDone {
346 return self.state = kRequestCircleDone;
347 }
348
349 + (instancetype) sessionWithCircleDelegate: (NSObject<KCJoiningRequestCircleDelegate>*) circleDelegate
350 session: (KCAESGCMDuplexSession*) session
351 error: (NSError**) error {
352 return [[KCJoiningRequestCircleSession alloc] initWithCircleDelegate:circleDelegate
353 session:session
354 error:error];
355 }
356
357 - (instancetype) initWithCircleDelegate: (NSObject<KCJoiningRequestCircleDelegate>*) circleDelegate
358 session: (KCAESGCMDuplexSession*) session
359 error: (NSError**) error {
360 self = [super init];
361
362 self->_circleDelegate = circleDelegate;
363 self->_session = session;
364 self.state = kExpectingCircleBlob;
365
366 return self;
367 }
368
369 @end
370