]>
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> |
b54c578e | 16 | #import <Security/SecureObjectSync/SOSTypes.h> |
fa7225c8 A |
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 | ||
b54c578e A |
33 | + (nullable instancetype) messageWithType: (KCJoiningMessageType) type |
34 | data: (NSData*) firstData | |
d64be36e | 35 | secondData: (nullable NSData*) secondData |
b54c578e A |
36 | error: (NSError**) error { |
37 | return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:secondData error:error]; | |
38 | } | |
39 | ||
fa7225c8 A |
40 | + (nullable instancetype) messageWithType: (KCJoiningMessageType) type |
41 | data: (NSData*) firstData | |
d64be36e | 42 | payload: (nullable NSData*) secondData |
fa7225c8 A |
43 | error: (NSError**) error { |
44 | return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:secondData error:error]; | |
45 | ||
46 | } | |
47 | ||
48 | - (bool) inflatePartsOfEncoding: (NSError**) error { | |
49 | const uint8_t *der = self.der.bytes; | |
50 | const uint8_t *der_end = der + self.der.length; | |
51 | ||
52 | const uint8_t *sequence_end = 0; | |
53 | ||
54 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
55 | ||
56 | if (der == 0) { | |
57 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Not sequence"); | |
58 | return false; | |
59 | } | |
60 | ||
61 | if (sequence_end != der_end) { | |
62 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Extra data at end of message"); | |
63 | return false; | |
64 | } | |
65 | ||
66 | uint64_t type; | |
67 | der = ccder_decode_uint64(&type, der, der_end); | |
68 | ||
69 | self->_type = (type > kLargestMessageType) ? kUnknown : (KCJoiningMessageType) type; | |
70 | ||
71 | NSData* firstData; | |
72 | NSData* secondData; | |
73 | ||
74 | der = kcder_decode_data_nocopy(&firstData, error, der, der_end); | |
75 | ||
76 | if (der != der_end) { | |
77 | der = kcder_decode_data_nocopy(&secondData, error, der, der_end); | |
78 | } | |
79 | ||
80 | self->_firstData = firstData; | |
81 | self->_secondData = secondData; | |
82 | ||
83 | if (der != der_end) { | |
84 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Extra in sequence"); | |
85 | return false; | |
86 | } | |
87 | ||
88 | return true; | |
89 | } | |
90 | ||
91 | + (size_t) encodedSizeType: (KCJoiningMessageType) type | |
92 | data: (NSData*) firstData | |
93 | payload: (nullable NSData*) secondData | |
94 | error: (NSError**) error { | |
95 | size_t type_size = ccder_sizeof_uint64(type); | |
96 | ||
97 | size_t srp_data_size = kcder_sizeof_data(firstData, error); | |
98 | if (srp_data_size == 0) return 0; | |
99 | ||
100 | size_t encrypted_payload_size = 0; | |
101 | ||
102 | if (secondData != nil) { | |
103 | encrypted_payload_size = kcder_sizeof_data(secondData, error); | |
104 | if (srp_data_size == 0) return 0; | |
105 | } | |
106 | ||
107 | ||
108 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, type_size + srp_data_size + encrypted_payload_size); | |
109 | } | |
110 | ||
111 | + (nullable NSData*) encodeToDERType: (KCJoiningMessageType) type | |
112 | data: (NSData*) firstData | |
113 | payload: (nullable NSData*) secondData | |
114 | error: (NSError**) error { | |
115 | ||
116 | size_t length = [KCJoiningMessage encodedSizeType:type | |
117 | data:firstData | |
118 | payload:secondData | |
119 | error: error]; | |
120 | if (length == 0) return nil; | |
121 | ||
122 | NSMutableData* encoded = [NSMutableData dataWithLength: length]; | |
123 | ||
124 | uint8_t* der = encoded.mutableBytes; | |
125 | uint8_t* der_end = der + encoded.length; | |
126 | ||
127 | uint8_t* encode_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
128 | ccder_encode_uint64(type, der, | |
129 | kcder_encode_data(firstData, error, der, | |
130 | kcder_encode_data_optional(secondData, error, der, der_end)))); | |
131 | ||
132 | if (encode_end == NULL) return nil; | |
133 | if (encode_end != der) { | |
134 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"Size didn't match encoding"); | |
135 | return nil; | |
136 | } | |
137 | ||
138 | return encoded; | |
139 | } | |
140 | ||
141 | - (nullable instancetype) initWithDER: (NSData*) message | |
142 | error: (NSError**) error { | |
d64be36e A |
143 | if ((self = [super init])) { |
144 | self->_der = [NSData dataWithData: message]; | |
145 | } | |
fa7225c8 A |
146 | return [self inflatePartsOfEncoding: error] ? self : nil; |
147 | } | |
148 | ||
149 | - (nullable instancetype) initWithType: (KCJoiningMessageType) type | |
150 | data: (NSData*) firstData | |
151 | payload: (nullable NSData*) secondData | |
152 | error: (NSError**) error { | |
d64be36e A |
153 | if ((self = [super init])) { |
154 | self->_der = [KCJoiningMessage encodeToDERType:type | |
155 | data:firstData | |
156 | payload:secondData | |
157 | error:error]; | |
158 | if (self->_der == nil) return nil; | |
159 | } | |
fa7225c8 A |
160 | return [self inflatePartsOfEncoding: error] ? self : nil; |
161 | } | |
162 | ||
163 | @end | |
164 | ||
165 | ||
166 | @implementation NSData(KCJoiningMessages) | |
167 | ||
168 | + (nullable instancetype) dataWithEncodedString: (NSString*) string | |
169 | error: (NSError**) error { | |
170 | size_t result_size = kcder_sizeof_string(string, error); | |
171 | if (result_size == 0) return nil; | |
172 | ||
173 | NSMutableData *result = [NSMutableData dataWithLength: result_size]; | |
174 | ||
175 | uint8_t *der = result.mutableBytes; | |
176 | uint8_t *der_end = der + result.length; | |
177 | ||
178 | uint8_t *encode_done = kcder_encode_string(string, error, | |
179 | der, der_end); | |
180 | ||
181 | if (encode_done != der) { | |
182 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"extra data"); | |
183 | return nil; | |
184 | } | |
185 | ||
186 | return result; | |
187 | } | |
188 | ||
189 | + (nullable instancetype) dataWithEncodedSequenceData: (NSData*) data1 | |
190 | data: (NSData*) data2 | |
191 | error: (NSError**) error { | |
192 | size_t result_size = sizeof_seq_data_data(data1, data2, error); | |
193 | if (result_size == 0) return nil; | |
194 | ||
195 | NSMutableData *result = [NSMutableData dataWithLength: result_size]; | |
196 | ||
197 | uint8_t *der = result.mutableBytes; | |
198 | uint8_t *der_end = der + result.length; | |
199 | ||
200 | uint8_t *encode_done = encode_seq_data_data(data1, data2, error, | |
201 | der, der_end); | |
202 | ||
203 | if (encode_done != der) { | |
204 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"extra data"); | |
205 | return nil; | |
206 | } | |
207 | ||
208 | return result; | |
209 | } | |
210 | ||
211 | - (bool) decodeSequenceData: (NSData* _Nullable * _Nonnull) data1 | |
212 | data: (NSData* _Nullable * _Nonnull) data2 | |
213 | error: (NSError** _Nullable) error { | |
214 | ||
215 | return NULL != decode_seq_data_data(data1, data2, error, self.bytes, self.bytes + self.length); | |
216 | } | |
217 | ||
218 | + (nullable instancetype) dataWithEncodedSequenceString: (NSString*) string | |
219 | data: (NSData*) data | |
220 | error: (NSError**) error { | |
221 | size_t result_size = sizeof_seq_string_data(string, data, error); | |
222 | if (result_size == 0) return nil; | |
223 | ||
224 | NSMutableData *result = [NSMutableData dataWithLength: result_size]; | |
225 | ||
226 | uint8_t *der = result.mutableBytes; | |
227 | uint8_t *der_end = der + result.length; | |
228 | ||
229 | uint8_t *encode_done = encode_seq_string_data(string, data, error, | |
230 | der, der_end); | |
231 | ||
232 | if (encode_done != der) { | |
233 | KCJoiningErrorCreate(kDEREncodingFailed, error, @"extra data"); | |
234 | return nil; | |
235 | } | |
236 | ||
237 | return result; | |
238 | } | |
239 | ||
240 | - (bool) decodeSequenceString: (NSString* _Nullable * _Nonnull) string | |
241 | data: (NSData* _Nullable * _Nonnull) data | |
242 | error: (NSError** _Nullable) error { | |
243 | return NULL != decode_seq_string_data(string, data, error, self.bytes, self.bytes + self.length); | |
244 | } | |
245 | ||
246 | @end | |
247 | ||
248 | @implementation NSString(KCJoiningMessages) | |
249 | + (nullable instancetype) decodeFromDER: (NSData*)der error: (NSError** _Nullable) error { | |
250 | NSString* result = nil; | |
251 | const uint8_t* decode_result = kcder_decode_string(&result, error, der.bytes, der.bytes+der.length); | |
252 | if (decode_result == nil) return nil; | |
253 | if (decode_result != der.bytes + der.length) { | |
254 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"extra data in string"); | |
255 | return nil; | |
256 | } | |
257 | ||
258 | return result; | |
259 | } | |
260 | @end | |
261 | ||
262 | ||
b54c578e | 263 | NSData* extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString** uuidString, NSData** octagon, NSError** error) { |
fa7225c8 A |
264 | NSData* result = nil; |
265 | const uint8_t *der = [initialMessage bytes]; | |
266 | const uint8_t *der_end = der + [initialMessage length]; | |
267 | const uint8_t *parse_end = decode_initialmessage(&result, error, der, der_end); | |
268 | ||
269 | // Allow extra stuff in here for future start messages. | |
270 | if (parse_end == NULL) { | |
271 | return nil; | |
272 | } | |
866f8763 A |
273 | else if (parse_end != der_end) { |
274 | NSData *extraStuff = nil; | |
b54c578e | 275 | NSData *uuidData = nil; |
866f8763 | 276 | uint64_t piggy_version = 0; |
b54c578e A |
277 | NSData* octagonData = nil; |
278 | ||
279 | parse_end = decode_version2(&extraStuff, &uuidData, &octagonData, &piggy_version, error, parse_end, der_end); | |
280 | require_action_quiet(parse_end != NULL, fail, secerror("decoding piggybacking message failed for version (%llu)", piggy_version)); | |
281 | ||
282 | switch(piggy_version){ | |
283 | case kPiggyV2: | |
284 | *octagon = octagonData; | |
285 | //fall through to pick up v1 | |
286 | case kPiggyV1:{ | |
287 | NSUUID *uuid = [[NSUUID alloc]initWithUUIDBytes:uuidData.bytes]; | |
288 | *uuidString = uuid.UUIDString; | |
289 | *version = piggy_version; | |
290 | break; | |
291 | } | |
292 | case kPiggyV0: | |
293 | *version = kPiggyV0; | |
294 | break; | |
295 | default: | |
296 | secerror("unsupported version"); | |
297 | break; | |
298 | } | |
866f8763 A |
299 | } |
300 | fail: | |
fa7225c8 A |
301 | return result; |
302 | ||
303 | } | |
304 | ||
866f8763 A |
305 | const uint8_t* decode_version1(NSData** data, NSData** uuid, uint64_t *piggy_version, NSError** error, |
306 | const uint8_t* der, const uint8_t *der_end) | |
307 | { | |
308 | if (NULL == der) | |
309 | return NULL; | |
310 | ||
311 | uint64_t versionFromBlob = 0; | |
312 | der = ccder_decode_uint64(&versionFromBlob, der, der_end); | |
313 | ||
314 | if (der == NULL) { | |
315 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Version mising"); | |
316 | return nil; | |
317 | } | |
318 | ||
319 | if(versionFromBlob == 1){ //decode uuid | |
b54c578e A |
320 | size_t payloadSize = 0; |
321 | const uint8_t *payload = ccder_decode_tl(CCDER_OCTET_STRING, &payloadSize, der, der_end); | |
866f8763 | 322 | |
b54c578e | 323 | *uuid = [NSData dataWithBytes: (void*)payload length: payloadSize]; |
866f8763 | 324 | *piggy_version = versionFromBlob; |
b54c578e | 325 | der = payload + payloadSize; |
866f8763 A |
326 | } |
327 | else{ | |
328 | KCJoiningErrorCreate(kDERUnknownVersion, error, @"Bad version: %llu", versionFromBlob); | |
329 | return nil; | |
330 | } | |
331 | ||
332 | return der; | |
333 | } | |
b54c578e A |
334 | |
335 | const uint8_t* decode_version2(NSData** data, NSData** uuid, NSData** octagon, uint64_t *piggy_version, NSError** error, | |
336 | const uint8_t* der, const uint8_t *der_end) | |
337 | { | |
338 | const uint8_t* end = nil; | |
339 | ||
340 | const uint8_t* parse_version1 = decode_version1(data, uuid, piggy_version, error, der, der_end); | |
341 | ||
342 | if(parse_version1 == NULL){ | |
343 | secerror("error parsing version 1"); | |
344 | return NULL; | |
345 | } | |
346 | else if (parse_version1 == der_end){ | |
347 | secnotice("octagon", "first message is piggybacking v1, no more data"); | |
348 | return parse_version1; | |
349 | } | |
350 | else{ | |
351 | end = kcder_decode_data(octagon, error, parse_version1, der_end); | |
352 | ||
353 | if(end == NULL){ | |
354 | secerror("failed to decode v2"); | |
355 | return NULL; | |
356 | } | |
357 | else if(*octagon && [*octagon length] != 0){ | |
358 | *piggy_version = kPiggyV2; | |
359 | } | |
360 | else{ | |
361 | secerror("no octagon version set"); | |
362 | return NULL; | |
363 | } | |
364 | } | |
365 | ||
366 | return end; | |
367 | } | |
368 | ||
fa7225c8 A |
369 | const uint8_t* decode_initialmessage(NSData** data, NSError** error, |
370 | const uint8_t* der, const uint8_t *der_end) | |
371 | { | |
372 | if (NULL == der) | |
373 | return NULL; | |
374 | ||
375 | const uint8_t *sequence_end = 0; | |
376 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
377 | ||
378 | if (der == NULL || sequence_end != der_end) { | |
866f8763 | 379 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Decoding failed"); |
fa7225c8 A |
380 | return nil; |
381 | } | |
fa7225c8 A |
382 | uint64_t version = 0; |
383 | der = ccder_decode_uint64(&version, der, der_end); | |
384 | ||
385 | if (der == NULL) { | |
386 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Version mising"); | |
387 | return nil; | |
388 | } | |
389 | ||
390 | if (version != 0) { | |
866f8763 | 391 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad version: %llu", version); |
fa7225c8 A |
392 | return nil; |
393 | } | |
866f8763 | 394 | |
fa7225c8 A |
395 | return kcder_decode_data(data, error, der, der_end); |
396 | } | |
397 | ||
398 | size_t sizeof_initialmessage(NSData*data) { | |
399 | size_t version_size = ccder_sizeof_uint64(0); | |
400 | if (version_size == 0) { | |
401 | return 0; | |
402 | } | |
403 | size_t message_size = kcder_sizeof_data(data, nil); | |
404 | if (message_size == 0) { | |
405 | return 0; | |
406 | } | |
407 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, version_size + message_size); | |
408 | } | |
409 | ||
410 | uint8_t* encode_initialmessage(NSData* data, NSError**error, | |
411 | const uint8_t *der, uint8_t *der_end) | |
412 | { | |
413 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
866f8763 A |
414 | ccder_encode_uint64(0, der, |
415 | kcder_encode_data(data, error, der, der_end))); | |
fa7225c8 A |
416 | } |
417 | ||
b54c578e A |
418 | size_t sizeof_initialmessage_version2(NSData*data, uint64_t version1, NSData *uuid, NSData* octagon) |
419 | { | |
866f8763 A |
420 | size_t version_size = ccder_sizeof_uint64(0); |
421 | if (version_size == 0) { | |
422 | return 0; | |
423 | } | |
424 | size_t message_size = kcder_sizeof_data(data, nil); | |
425 | if (message_size == 0) { | |
426 | return 0; | |
427 | } | |
428 | size_t version1_size = ccder_sizeof_uint64(version1); | |
429 | if (version1_size == 0) { | |
430 | return 0; | |
431 | } | |
432 | size_t uuid_size = kcder_sizeof_data(uuid, nil); | |
b54c578e A |
433 | if (uuid_size == 0) { |
434 | return 0; | |
435 | } | |
436 | size_t octagon_size = kcder_sizeof_data(octagon, nil); | |
437 | if (octagon_size == 0) { | |
438 | return 0; | |
439 | } | |
440 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, version_size + message_size + | |
441 | version1_size + uuid_size + | |
442 | octagon_size); | |
443 | } | |
444 | ||
445 | size_t sizeof_initialmessage_version1(NSData*data, uint64_t version1, NSData *uuid) { | |
446 | size_t version_size = ccder_sizeof_uint64(0); | |
447 | if (version_size == 0) { | |
448 | return 0; | |
449 | } | |
450 | size_t message_size = kcder_sizeof_data(data, nil); | |
866f8763 A |
451 | if (message_size == 0) { |
452 | return 0; | |
453 | } | |
b54c578e A |
454 | size_t version1_size = ccder_sizeof_uint64(version1); |
455 | if (version1_size == 0) { | |
456 | return 0; | |
457 | } | |
458 | size_t uuid_size = kcder_sizeof_data(uuid, nil); | |
459 | if (uuid_size == 0) { | |
460 | return 0; | |
461 | } | |
866f8763 A |
462 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, version_size + message_size + version1_size + uuid_size); |
463 | } | |
464 | ||
465 | ||
466 | uint8_t* encode_initialmessage_version1(NSData* data, NSData* uuidData, uint64_t piggy_version, NSError**error, | |
467 | const uint8_t *der, uint8_t *der_end) | |
468 | { | |
469 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
470 | ccder_encode_uint64(0, der, | |
471 | kcder_encode_data(data, error, der, | |
472 | ccder_encode_uint64(piggy_version, der, | |
473 | kcder_encode_data(uuidData, error, der, der_end))))); | |
474 | ||
475 | } | |
fa7225c8 | 476 | |
b54c578e A |
477 | uint8_t* encode_initialmessage_version2(NSData* data, NSData* uuidData, NSData* octagon_version, NSError**error, |
478 | const uint8_t *der, uint8_t *der_end) | |
479 | { | |
480 | ||
481 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
482 | ccder_encode_uint64(0, der, | |
483 | kcder_encode_data(data, error, der, | |
484 | ccder_encode_uint64(kPiggyV1, der, | |
485 | kcder_encode_data(uuidData, error, der, kcder_encode_data(octagon_version, error, der, der_end)))))); | |
486 | } | |
487 | ||
fa7225c8 A |
488 | size_t sizeof_seq_data_data(NSData*data1, NSData*data2, NSError**error) { |
489 | size_t data1_size = kcder_sizeof_data(data1, error); | |
490 | if (data1_size == 0) { | |
491 | return 0; | |
492 | } | |
493 | size_t data2_size = kcder_sizeof_data(data2, error); | |
494 | if (data2_size == 0) { | |
495 | return 0; | |
496 | } | |
497 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, data1_size + data2_size); | |
498 | } | |
499 | ||
500 | uint8_t* encode_seq_data_data(NSData* data1, NSData*data2, NSError**error, | |
501 | const uint8_t *der, uint8_t *der_end) { | |
502 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
503 | kcder_encode_data(data1, error, der, | |
504 | kcder_encode_data(data2, error, der, der_end))); | |
505 | } | |
506 | ||
507 | const uint8_t* decode_seq_data_data(NSData** data1, NSData** data2, NSError** error, | |
508 | const uint8_t* der, const uint8_t *der_end) { | |
509 | if (NULL == der) | |
510 | return NULL; | |
511 | ||
512 | const uint8_t *sequence_end = 0; | |
513 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
514 | ||
515 | if (der == NULL || sequence_end != der_end) { | |
516 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"decode failed"); | |
517 | return nil; | |
518 | } | |
519 | ||
520 | der = kcder_decode_data(data1, error, der, der_end); | |
521 | return kcder_decode_data(data2, error, der, der_end); | |
522 | } | |
523 | ||
524 | size_t sizeof_seq_string_data(NSString*string, NSData*data, NSError** error) { | |
525 | size_t string_size = kcder_sizeof_string(string, error); | |
526 | if (string_size == 0) { | |
527 | return 0; | |
528 | } | |
529 | size_t data_size = kcder_sizeof_data(data, error); | |
530 | if (data_size == 0) { | |
531 | return 0; | |
532 | } | |
533 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, string_size + data_size); | |
534 | } | |
535 | ||
536 | uint8_t* _Nullable encode_seq_string_data(NSString* string, NSData*data, NSError**error, | |
537 | const uint8_t *der, uint8_t *der_end) { | |
538 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, | |
539 | kcder_encode_string(string, error, der, | |
540 | kcder_encode_data(data, error, der, der_end))); | |
541 | } | |
542 | ||
543 | const uint8_t* _Nullable decode_seq_string_data(NSString* _Nonnull * _Nonnull string, NSData* _Nonnull * _Nonnull data, | |
544 | NSError** error, | |
545 | const uint8_t* der, const uint8_t *der_end) { | |
546 | if (NULL == der) | |
547 | return NULL; | |
548 | ||
549 | const uint8_t *sequence_end = 0; | |
550 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); | |
551 | ||
552 | if (der == NULL || sequence_end != der_end) { | |
553 | KCJoiningErrorCreate(kDERUnknownEncoding, error, @"decode failed"); | |
554 | return nil; | |
555 | } | |
556 | ||
557 | der = kcder_decode_string(string, error, der, der_end); | |
558 | return kcder_decode_data(data, error, der, der_end); | |
559 | } |