]>
Commit | Line | Data |
---|---|---|
fa7225c8 A |
1 | // |
2 | // KCJoiningMessages.m | |
3 | // Security | |
4 | // | |
5 | // Created by Mitch Adler on 2/17/16. | |
6 | // | |
7 | // | |
8 | ||
9 | #import <Foundation/Foundation.h> | |
866f8763 | 10 | #import <AssertMacros.h> |
fa7225c8 A |
11 | |
12 | #import <KeychainCircle/KCDer.h> | |
13 | #import <KeychainCircle/KCError.h> | |
14 | #import <KeychainCircle/KCJoiningMessages.h> | |
866f8763 | 15 | #import <utilities/debugging.h> |
fa7225c8 A |
16 | |
17 | #include <corecrypto/ccder.h> | |
18 | ||
19 | ||
20 | @implementation KCJoiningMessage | |
21 | ||
22 | + (nullable instancetype) messageWithDER: (NSData*) message | |
23 | error: (NSError**) error { | |
24 | return [[KCJoiningMessage alloc] initWithDER: message error: nil]; | |
25 | } | |
26 | ||
27 | + (nullable instancetype) messageWithType: (KCJoiningMessageType) type | |
28 | data: (NSData*) firstData | |
29 | error: (NSError**) error { | |
30 | return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:nil error:error]; | |
31 | } | |
32 | ||
33 | + (nullable instancetype) messageWithType: (KCJoiningMessageType) type | |
34 | data: (NSData*) firstData | |
35 | payload: (NSData*) secondData | |
36 | error: (NSError**) error { | |
37 | return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:secondData error:error]; | |
38 | ||
39 | } | |
40 | ||
41 | - (bool) inflatePartsOfEncoding: (NSError**) error { | |
42 | const uint8_t *der = self.der.bytes; | |
43 | const uint8_t *der_end = der + self.der.length; | |
44 | ||
45 | const uint8_t *sequence_end = 0; | |
46 | ||
47 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
48 | ||
49 | if (der == 0) { | |
50 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Not sequence"); | |
51 | return false; | |
52 | } | |
53 | ||
54 | if (sequence_end != der_end) { | |
55 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Extra data at end of message"); | |
56 | return false; | |
57 | } | |
58 | ||
59 | uint64_t type; | |
60 | der = ccder_decode_uint64(&type, der, der_end); | |
61 | ||
62 | self->_type = (type > kLargestMessageType) ? kUnknown : (KCJoiningMessageType) type; | |
63 | ||
64 | NSData* firstData; | |
65 | NSData* secondData; | |
66 | ||
67 | der = kcder_decode_data_nocopy(&firstData, error, der, der_end); | |
68 | ||
69 | if (der != der_end) { | |
70 | der = kcder_decode_data_nocopy(&secondData, error, der, der_end); | |
71 | } | |
72 | ||
73 | self->_firstData = firstData; | |
74 | self->_secondData = secondData; | |
75 | ||
76 | if (der != der_end) { | |
77 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Extra in sequence"); | |
78 | return false; | |
79 | } | |
80 | ||
81 | return true; | |
82 | } | |
83 | ||
84 | + (size_t) encodedSizeType: (KCJoiningMessageType) type | |
85 | data: (NSData*) firstData | |
86 | payload: (nullable NSData*) secondData | |
87 | error: (NSError**) error { | |
88 | size_t type_size = ccder_sizeof_uint64(type); | |
89 | ||
90 | size_t srp_data_size = kcder_sizeof_data(firstData, error); | |
91 | if (srp_data_size == 0) return 0; | |
92 | ||
93 | size_t encrypted_payload_size = 0; | |
94 | ||
95 | if (secondData != nil) { | |
96 | encrypted_payload_size = kcder_sizeof_data(secondData, error); | |
97 | if (srp_data_size == 0) return 0; | |
98 | } | |
99 | ||
100 | ||
101 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, type_size + srp_data_size + encrypted_payload_size); | |
102 | } | |
103 | ||
104 | + (nullable NSData*) encodeToDERType: (KCJoiningMessageType) type | |
105 | data: (NSData*) firstData | |
106 | payload: (nullable NSData*) secondData | |
107 | error: (NSError**) error { | |
108 | ||
109 | size_t length = [KCJoiningMessage encodedSizeType:type | |
110 | data:firstData | |
111 | payload:secondData | |
112 | error: error]; | |
113 | if (length == 0) return nil; | |
114 | ||
115 | NSMutableData* encoded = [NSMutableData dataWithLength: length]; | |
116 | ||
117 | uint8_t* der = encoded.mutableBytes; | |
118 | uint8_t* der_end = der + encoded.length; | |
119 | ||
120 | uint8_t* encode_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
121 | ccder_encode_uint64(type, der, | |
122 | kcder_encode_data(firstData, error, der, | |
123 | kcder_encode_data_optional(secondData, error, der, der_end)))); | |
124 | ||
125 | if (encode_end == NULL) return nil; | |
126 | if (encode_end != der) { | |
127 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"Size didn't match encoding"); | |
128 | return nil; | |
129 | } | |
130 | ||
131 | return encoded; | |
132 | } | |
133 | ||
134 | - (nullable instancetype) initWithDER: (NSData*) message | |
135 | error: (NSError**) error { | |
136 | self = [super init]; | |
137 | ||
138 | self->_der = [NSData dataWithData: message]; | |
139 | ||
140 | return [self inflatePartsOfEncoding: error] ? self : nil; | |
141 | } | |
142 | ||
143 | - (nullable instancetype) initWithType: (KCJoiningMessageType) type | |
144 | data: (NSData*) firstData | |
145 | payload: (nullable NSData*) secondData | |
146 | error: (NSError**) error { | |
147 | self = [super init]; | |
148 | ||
149 | self->_der = [KCJoiningMessage encodeToDERType:type | |
150 | data:firstData | |
151 | payload:secondData | |
152 | error:error]; | |
153 | if (self->_der == nil) return nil; | |
154 | ||
155 | return [self inflatePartsOfEncoding: error] ? self : nil; | |
156 | } | |
157 | ||
158 | @end | |
159 | ||
160 | ||
161 | @implementation NSData(KCJoiningMessages) | |
162 | ||
163 | + (nullable instancetype) dataWithEncodedString: (NSString*) string | |
164 | error: (NSError**) error { | |
165 | size_t result_size = kcder_sizeof_string(string, error); | |
166 | if (result_size == 0) return nil; | |
167 | ||
168 | NSMutableData *result = [NSMutableData dataWithLength: result_size]; | |
169 | ||
170 | uint8_t *der = result.mutableBytes; | |
171 | uint8_t *der_end = der + result.length; | |
172 | ||
173 | uint8_t *encode_done = kcder_encode_string(string, error, | |
174 | der, der_end); | |
175 | ||
176 | if (encode_done != der) { | |
177 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"extra data"); | |
178 | return nil; | |
179 | } | |
180 | ||
181 | return result; | |
182 | } | |
183 | ||
184 | + (nullable instancetype) dataWithEncodedSequenceData: (NSData*) data1 | |
185 | data: (NSData*) data2 | |
186 | error: (NSError**) error { | |
187 | size_t result_size = sizeof_seq_data_data(data1, data2, error); | |
188 | if (result_size == 0) return nil; | |
189 | ||
190 | NSMutableData *result = [NSMutableData dataWithLength: result_size]; | |
191 | ||
192 | uint8_t *der = result.mutableBytes; | |
193 | uint8_t *der_end = der + result.length; | |
194 | ||
195 | uint8_t *encode_done = encode_seq_data_data(data1, data2, error, | |
196 | der, der_end); | |
197 | ||
198 | if (encode_done != der) { | |
199 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"extra data"); | |
200 | return nil; | |
201 | } | |
202 | ||
203 | return result; | |
204 | } | |
205 | ||
206 | - (bool) decodeSequenceData: (NSData* _Nullable * _Nonnull) data1 | |
207 | data: (NSData* _Nullable * _Nonnull) data2 | |
208 | error: (NSError** _Nullable) error { | |
209 | ||
210 | return NULL != decode_seq_data_data(data1, data2, error, self.bytes, self.bytes + self.length); | |
211 | } | |
212 | ||
213 | + (nullable instancetype) dataWithEncodedSequenceString: (NSString*) string | |
214 | data: (NSData*) data | |
215 | error: (NSError**) error { | |
216 | size_t result_size = sizeof_seq_string_data(string, data, error); | |
217 | if (result_size == 0) return nil; | |
218 | ||
219 | NSMutableData *result = [NSMutableData dataWithLength: result_size]; | |
220 | ||
221 | uint8_t *der = result.mutableBytes; | |
222 | uint8_t *der_end = der + result.length; | |
223 | ||
224 | uint8_t *encode_done = encode_seq_string_data(string, data, error, | |
225 | der, der_end); | |
226 | ||
227 | if (encode_done != der) { | |
228 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"extra data"); | |
229 | return nil; | |
230 | } | |
231 | ||
232 | return result; | |
233 | } | |
234 | ||
235 | - (bool) decodeSequenceString: (NSString* _Nullable * _Nonnull) string | |
236 | data: (NSData* _Nullable * _Nonnull) data | |
237 | error: (NSError** _Nullable) error { | |
238 | return NULL != decode_seq_string_data(string, data, error, self.bytes, self.bytes + self.length); | |
239 | } | |
240 | ||
241 | @end | |
242 | ||
243 | @implementation NSString(KCJoiningMessages) | |
244 | + (nullable instancetype) decodeFromDER: (NSData*)der error: (NSError** _Nullable) error { | |
245 | NSString* result = nil; | |
246 | const uint8_t* decode_result = kcder_decode_string(&result, error, der.bytes, der.bytes+der.length); | |
247 | if (decode_result == nil) return nil; | |
248 | if (decode_result != der.bytes + der.length) { | |
249 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"extra data in string"); | |
250 | return nil; | |
251 | } | |
252 | ||
253 | return result; | |
254 | } | |
255 | @end | |
256 | ||
257 | ||
866f8763 | 258 | NSData* extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString** uuidString, NSError** error) { |
fa7225c8 A |
259 | NSData* result = nil; |
260 | const uint8_t *der = [initialMessage bytes]; | |
261 | const uint8_t *der_end = der + [initialMessage length]; | |
262 | const uint8_t *parse_end = decode_initialmessage(&result, error, der, der_end); | |
263 | ||
264 | // Allow extra stuff in here for future start messages. | |
265 | if (parse_end == NULL) { | |
266 | return nil; | |
267 | } | |
866f8763 A |
268 | else if (parse_end != der_end) { |
269 | NSData *extraStuff = nil; | |
270 | NSData *uuid = nil; | |
271 | uint64_t piggy_version = 0; | |
272 | parse_end = decode_version1(&extraStuff, &uuid, &piggy_version, error, parse_end, der_end); | |
273 | require_action_quiet(parse_end != NULL, fail, secerror("decoding piggybacking uuid and version failed (v1)")); | |
274 | *uuidString = [[NSString alloc] initWithData:uuid encoding:NSUTF8StringEncoding]; | |
275 | *version = piggy_version; | |
276 | } | |
277 | fail: | |
fa7225c8 A |
278 | return result; |
279 | ||
280 | } | |
281 | ||
866f8763 A |
282 | const uint8_t* decode_version1(NSData** data, NSData** uuid, uint64_t *piggy_version, NSError** error, |
283 | const uint8_t* der, const uint8_t *der_end) | |
284 | { | |
285 | if (NULL == der) | |
286 | return NULL; | |
287 | ||
288 | uint64_t versionFromBlob = 0; | |
289 | der = ccder_decode_uint64(&versionFromBlob, der, der_end); | |
290 | ||
291 | if (der == NULL) { | |
292 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Version mising"); | |
293 | return nil; | |
294 | } | |
295 | ||
296 | if(versionFromBlob == 1){ //decode uuid | |
297 | size_t payload_size = 0; | |
298 | const uint8_t *payload = ccder_decode_tl(CCDER_OCTET_STRING, &payload_size, der, der_end); | |
299 | ||
300 | *uuid = [NSData dataWithBytes: (void*)payload length: payload_size]; | |
301 | *piggy_version = versionFromBlob; | |
302 | } | |
303 | else{ | |
304 | KCJoiningErrorCreate(kDERUnknownVersion, error, @"Bad version: %llu", versionFromBlob); | |
305 | return nil; | |
306 | } | |
307 | ||
308 | return der; | |
309 | } | |
fa7225c8 A |
310 | const uint8_t* decode_initialmessage(NSData** data, NSError** error, |
311 | const uint8_t* der, const uint8_t *der_end) | |
312 | { | |
313 | if (NULL == der) | |
314 | return NULL; | |
315 | ||
316 | const uint8_t *sequence_end = 0; | |
317 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
318 | ||
319 | if (der == NULL || sequence_end != der_end) { | |
866f8763 | 320 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Decoding failed"); |
fa7225c8 A |
321 | return nil; |
322 | } | |
fa7225c8 A |
323 | uint64_t version = 0; |
324 | der = ccder_decode_uint64(&version, der, der_end); | |
325 | ||
326 | if (der == NULL) { | |
327 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Version mising"); | |
328 | return nil; | |
329 | } | |
330 | ||
331 | if (version != 0) { | |
866f8763 | 332 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad version: %llu", version); |
fa7225c8 A |
333 | return nil; |
334 | } | |
866f8763 | 335 | |
fa7225c8 A |
336 | return kcder_decode_data(data, error, der, der_end); |
337 | } | |
338 | ||
339 | size_t sizeof_initialmessage(NSData*data) { | |
340 | size_t version_size = ccder_sizeof_uint64(0); | |
341 | if (version_size == 0) { | |
342 | return 0; | |
343 | } | |
344 | size_t message_size = kcder_sizeof_data(data, nil); | |
345 | if (message_size == 0) { | |
346 | return 0; | |
347 | } | |
348 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, version_size + message_size); | |
349 | } | |
350 | ||
351 | uint8_t* encode_initialmessage(NSData* data, NSError**error, | |
352 | const uint8_t *der, uint8_t *der_end) | |
353 | { | |
354 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
866f8763 A |
355 | ccder_encode_uint64(0, der, |
356 | kcder_encode_data(data, error, der, der_end))); | |
fa7225c8 A |
357 | } |
358 | ||
866f8763 A |
359 | size_t sizeof_initialmessage_version1(NSData*data, uint64_t version1, NSData *uuid) { |
360 | size_t version_size = ccder_sizeof_uint64(0); | |
361 | if (version_size == 0) { | |
362 | return 0; | |
363 | } | |
364 | size_t message_size = kcder_sizeof_data(data, nil); | |
365 | if (message_size == 0) { | |
366 | return 0; | |
367 | } | |
368 | size_t version1_size = ccder_sizeof_uint64(version1); | |
369 | if (version1_size == 0) { | |
370 | return 0; | |
371 | } | |
372 | size_t uuid_size = kcder_sizeof_data(uuid, nil); | |
373 | if (message_size == 0) { | |
374 | return 0; | |
375 | } | |
376 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, version_size + message_size + version1_size + uuid_size); | |
377 | } | |
378 | ||
379 | ||
380 | uint8_t* encode_initialmessage_version1(NSData* data, NSData* uuidData, uint64_t piggy_version, NSError**error, | |
381 | const uint8_t *der, uint8_t *der_end) | |
382 | { | |
383 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
384 | ccder_encode_uint64(0, der, | |
385 | kcder_encode_data(data, error, der, | |
386 | ccder_encode_uint64(piggy_version, der, | |
387 | kcder_encode_data(uuidData, error, der, der_end))))); | |
388 | ||
389 | } | |
fa7225c8 A |
390 | |
391 | size_t sizeof_seq_data_data(NSData*data1, NSData*data2, NSError**error) { | |
392 | size_t data1_size = kcder_sizeof_data(data1, error); | |
393 | if (data1_size == 0) { | |
394 | return 0; | |
395 | } | |
396 | size_t data2_size = kcder_sizeof_data(data2, error); | |
397 | if (data2_size == 0) { | |
398 | return 0; | |
399 | } | |
400 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, data1_size + data2_size); | |
401 | } | |
402 | ||
403 | uint8_t* encode_seq_data_data(NSData* data1, NSData*data2, NSError**error, | |
404 | const uint8_t *der, uint8_t *der_end) { | |
405 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
406 | kcder_encode_data(data1, error, der, | |
407 | kcder_encode_data(data2, error, der, der_end))); | |
408 | } | |
409 | ||
410 | const uint8_t* decode_seq_data_data(NSData** data1, NSData** data2, NSError** error, | |
411 | const uint8_t* der, const uint8_t *der_end) { | |
412 | if (NULL == der) | |
413 | return NULL; | |
414 | ||
415 | const uint8_t *sequence_end = 0; | |
416 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
417 | ||
418 | if (der == NULL || sequence_end != der_end) { | |
419 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"decode failed"); | |
420 | return nil; | |
421 | } | |
422 | ||
423 | der = kcder_decode_data(data1, error, der, der_end); | |
424 | return kcder_decode_data(data2, error, der, der_end); | |
425 | } | |
426 | ||
427 | size_t sizeof_seq_string_data(NSString*string, NSData*data, NSError** error) { | |
428 | size_t string_size = kcder_sizeof_string(string, error); | |
429 | if (string_size == 0) { | |
430 | return 0; | |
431 | } | |
432 | size_t data_size = kcder_sizeof_data(data, error); | |
433 | if (data_size == 0) { | |
434 | return 0; | |
435 | } | |
436 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, string_size + data_size); | |
437 | } | |
438 | ||
439 | uint8_t* _Nullable encode_seq_string_data(NSString* string, NSData*data, NSError**error, | |
440 | const uint8_t *der, uint8_t *der_end) { | |
441 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
442 | kcder_encode_string(string, error, der, | |
443 | kcder_encode_data(data, error, der, der_end))); | |
444 | } | |
445 | ||
446 | const uint8_t* _Nullable decode_seq_string_data(NSString* _Nonnull * _Nonnull string, NSData* _Nonnull * _Nonnull data, | |
447 | NSError** error, | |
448 | const uint8_t* der, const uint8_t *der_end) { | |
449 | if (NULL == der) | |
450 | return NULL; | |
451 | ||
452 | const uint8_t *sequence_end = 0; | |
453 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
454 | ||
455 | if (der == NULL || sequence_end != der_end) { | |
456 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"decode failed"); | |
457 | return nil; | |
458 | } | |
459 | ||
460 | der = kcder_decode_string(string, error, der, der_end); | |
461 | return kcder_decode_data(data, error, der, der_end); | |
462 | } |