]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSMessage.c
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSMessage.c
1 /*
2 * Copyright (c) 2013-2014 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
25 /*
26 * SOSMessage.c - Creation and decoding of SOSMessage objects.
27 */
28
29 #include <Security/SecureObjectSync/SOSMessage.h>
30
31 #include <AssertMacros.h>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <Security/SecureObjectSync/SOSDigestVector.h>
34 #include <Security/SecureObjectSync/SOSManifest.h>
35 #include <Security/SecureObjectSync/SOSInternal.h>
36 #include <corecrypto/ccder.h>
37 #include <stdlib.h>
38 #include <stdbool.h>
39 #include <utilities/SecCFError.h>
40 #include <utilities/SecCFRelease.h>
41 #include <utilities/SecCFWrappers.h>
42 #include <utilities/array_size.h>
43 #include <utilities/der_date.h>
44 #include <utilities/der_plist.h>
45 #include <utilities/der_plist_internal.h>
46 #include <utilities/debugging.h>
47 #include <utilities/iCloudKeychainTrace.h>
48
49 // TODO: This is a layer violation, we need a better way to do this
50 // Currently it's only used for logging.
51 #include <securityd/SecItemDataSource.h>
52
53 #if defined(SOSMessageFormatSpecification) && 0
54
55 -- Secure Object Syncing Peer to Peer Message format ASN.1 definition
56 -- Everything MUST be DER encoded unless otherwise noted. These exceptions
57 -- Allow us to stream messages on a streamy network, without loading more
58 -- than one object into memory at once.
59
60 SOSMessage := SEQUENCE {
61 CHOICE {
62 v0 V0-MESSAGE-BODY-CLASS
63 v2 SOSV2MessageBody
64 }
65 }
66
67 -- v0 Message
68
69 V0-MESSAGE-BODY-CLASS ::= CLASS
70 {
71 &messageType INTEGER (manifestDigest, manifest, manifestDeltaAndObjects)
72 &version INTEGER OPTIONAL default v0
73 &Type
74 }
75 WITH SYNTAX {&Type IDENTIFIED BY &messageType}
76
77 ManifestDigest ::= OCTECT STRING (length 20)
78
79 Manifest ::= OCTECT STRING -- (length 20 * number of entries)
80
81 manifestDigestBody ::=
82 { ManifestDigest IDENTIFIED BY {manifestDigest}}
83
84 manifestBody ::=
85 { Manifest IDENTIFIED BY {manifest}}
86
87 manifestDeltaAndObjectsBody ::=
88 { ManifestDeltaAndObjects IDENTIFIED BY {manifestDeltaAndObjects}}
89
90 SOSV1MessageBody ::= MESSAGE-BODY-CLASS
91
92 ManifestDeltaAndObjects ::= SEQUENCE {
93 manfestDigest ManifestDigest
94 removals Manifest
95 additions Manifest
96 addedObjects SEQUENCE OF SOSObject
97 }
98
99 -- v2 Message
100
101 SOSMessageBody := {
102 -- top level SEQUENCE may be Constructed, indefinite-length BER encoded
103 header SOSMessageHeader,
104 deltas [0] IMPLICIT SOSManifestDeltas OPTIONAL,
105 extensions [1] IMPLICIT SOSExtensions OPTIONAL,
106 objects [2] IMPLICIT SEQUENCE OF SOSObject OPTIONAL
107 -- [2] IMPLICIT SEQUENCE OF SOSObject may be Constructed,
108 -- indefinite-length BER encoded -- }
109
110 SOSMessageHeader ::= SEQUENCE {
111 version [0] IMPLICIT SOSMessageVersion DEFAULT v2,
112 creationTime GeneralizedTime OPTIONAL,
113 -- When this message was created by the sender for tracking latency
114 sequenceNumber SOSSequenceNumber OPTIONAL,
115 -- Message Sequence Number for tracking packet loss in transport
116 digestTypes SOSDigestTypes OPTIONAL,
117 -- Determines the size and format of each SOSManifestDigest and the
118 -- elements of each SOSManifest.
119 -- We send the intersection our desired SOSDigestTypes and our peers
120 -- last received SOSDigestType. If we never received a message from our
121 -- peer we send our entire desired set and set the digestTypesProposed
122 -- messageFlag.
123 -- If the intersection is the empty set we fallback to sha1
124 -- Each digest and manifest entry is constructed by appending the
125 -- agreed upon digests in the order they are listed in the DER encoded
126 -- digestTypes.
127 messageFlags BIT STRING {
128 getObjects (0),
129 joinRequest (1),
130 partial (2),
131 digestTypesProposed (3),
132 -- This is a partial update and might not contain accurate manifest deltas (check this against spec --mb), only objects
133 clearGetObjects (4), -- WIP mb ignore
134 -- Stop sending me objects for this delta update, I will send you mine instead if you give me a full manifest delta
135 didClearGetObjectsSinceLastDelta (5) -- WIP mb ignore
136 -- clearGetObjects was set during this delta update, do not
137 -- set it again (STICKY until either peer clears delta) -- }
138 skipHello (6) -- Respond with at least a manifest
139 senderDigest SOSManifestDigest,
140 -- The senders manifest digest at the time of sending this message.
141 baseDigest [0] IMPLICIT SOSManifestDigest,
142 -- What this message is based on, if it contains deltas. If missing we assume the empty set
143 proposedDigest [1] IMPLICIT SOSManifestDigest,
144 -- What the receiver should have after patching baseDigest with
145 -- additions and removals -- }
146
147 SOSMessageVersion ::= INTEGER { v0(0), v2(2), v3(3) }
148
149 SOSSequenceNumber ::= INTEGER
150
151 -- Note this is not implemented in v2 it only supports sha1
152 SOSDigestTypes ::= SEQUENCE {
153 messageFlags BIT STRING {
154 sha1(0) -- implied if SOSDigestTypes is not present
155 sha224(1)
156 sha256(2)
157 sha384(3)
158 sha512(4)
159 digestAlgorithms SET OF AlgorithmIdentifier
160 -- Same as AlgorithmIdentifier from X.509 -- } }
161
162 SOSManifestDeltas ::= SEQUENCE {
163 removals SOSManifest
164 additions SOSManifest }
165
166 SOSExtensions ::= SEQUENCE SIZE (1..MAX) OF SOSExtension
167
168 SOSExtension ::= SEQUENCE {
169 extnID OBJECT IDENTIFIER,
170 critical BOOLEAN DEFAULT FALSE,
171 extnValue OCTET STRING }
172
173 SOSManifest ::= OCTET STRING
174 -- DER encoding is sorted and ready to merge.
175 -- All SOSDigest entries in a SOSManifest /must/ be the same size
176 -- As the negotiated SOSManifestEntry. Se comment in SOSMessageBody
177 -- on digestTypes
178
179 SOSManifestDigest ::= OCTET STRING
180
181 SOSObject ::= SEQUENCE {
182 [0] conflict OCTECT STRING OPTIONAL
183 [1] change OCTECT STRING OPTIONAL
184 object SecDictionary }
185
186 SecDictionary ::= SET of SecKVPair
187
188 SecKVPair ::= SEQUENCE {
189 key UTF8String
190 value Value }
191
192 SecValue ::= CHOICE {
193 bool Boolean
194 number INTEGER
195 string UTF8String
196 data OCTECT STRING
197 date GENERAL TIME
198 dictionary Object
199 array Array }
200
201 SecArray ::= SEQUENCE of SecValue
202
203 -- For reference:
204 AlgorithmIdentifier ::= SEQUENCE {
205 algorithm OBJECT IDENTIFIER,
206 parameters ANY DEFINED BY algorithm OPTIONAL }
207 -- contains a value of the type
208 -- registered for use with the
209 -- algorithm object identifier value
210
211 #endif // defined(SOSMessageFormatSpecification) && 0
212
213
214 #if 0
215 static inline bool SecMallocOk(const void *ptr) {
216 if (ptr) return true;
217
218 return false;
219 }
220 #endif
221 #if 0
222 static void appendObjects(CFMutableStringRef desc, CFArrayRef objects) {
223 __block bool needComma = false;
224 CFArrayForEach(objects, ^(const void *value) {
225 if (needComma)
226 CFStringAppend(desc, CFSTR(","));
227 else
228 needComma = true;
229
230 SecItemServerAppendItemDescription(desc, value);
231 });
232 }
233 #endif
234
235
236
237 //
238 // MARK: SOSMessage implementation.
239 //
240
241 // Legacy v1 message type numbers
242 enum SOSMessageType {
243 SOSManifestInvalidMessageType = 0,
244 SOSManifestDigestMessageType = 1,
245 SOSManifestMessageType = 2,
246 SOSManifestDeltaAndObjectsMessageType = 3,
247 };
248
249 struct __OpaqueSOSMessage {
250 CFRuntimeBase _base;
251
252 CFDataRef der;
253 const uint8_t *objectsDer;
254 size_t objectsLen;
255
256 CFDataRef senderDigest;
257 CFDataRef baseDigest;
258 CFDataRef proposedDigest;
259 SOSManifestRef removals;
260 SOSManifestRef additions;
261
262 CFMutableArrayRef objects;
263
264 SOSMessageFlags flags;
265 uint64_t sequenceNumber;
266 CFAbsoluteTime creationTime;
267 uint64_t version; // Message version (currently always 2)
268 bool indefiniteLength; // If set to true the top SEQUENCE and the OBJECTS SEQUENCE are written indefinite length.
269 };
270
271 CFGiblisWithCompareFor(SOSMessage)
272
273 static Boolean SOSMessageCompare(CFTypeRef cf1, CFTypeRef cf2) {
274 SOSMessageRef M = (SOSMessageRef)cf1;
275 SOSMessageRef P = (SOSMessageRef)cf2;
276 if (M->flags != P->flags) return false;
277 if (M->sequenceNumber != P->sequenceNumber) return false;
278 if (M->creationTime != P->creationTime) return false;
279 //if (!CFEqualSafe(M->der, P->der)) return false;
280 if (!CFEqualSafe(M->senderDigest, P->senderDigest)) return false;
281 if (!CFEqualSafe(M->baseDigest, P->baseDigest)) return false;
282 if (!CFEqualSafe(M->proposedDigest, P->proposedDigest)) return false;
283 if (!CFEqualSafe(M->removals, P->removals)) return false;
284 if (!CFEqualSafe(M->additions, P->additions)) return false;
285
286 // TODO Compare Objects if present.
287
288 return true;
289 }
290
291 static void SOSMessageDestroy(CFTypeRef cf) {
292 SOSMessageRef message = (SOSMessageRef)cf;
293 CFReleaseNull(message->der);
294 CFReleaseNull(message->senderDigest);
295 CFReleaseNull(message->baseDigest);
296 CFReleaseNull(message->proposedDigest);
297 CFReleaseNull(message->additions);
298 CFReleaseNull(message->removals);
299 CFReleaseNull(message->objects);
300 }
301
302 // TODO: Remove this layer violation!
303 #include <securityd/SecItemServer.h>
304
305 static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error);
306
307 static CFStringRef SOSMessageCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
308 SOSMessageRef message = (SOSMessageRef)cf;
309 static const uint8_t zero[4] = {};
310 const uint8_t *S = message->senderDigest ? CFDataGetBytePtr(message->senderDigest) : zero;
311 const uint8_t *B = message->baseDigest ? CFDataGetBytePtr(message->baseDigest) : zero;
312 const uint8_t *P = message->proposedDigest ? CFDataGetBytePtr(message->proposedDigest) : zero;
313 CFDateRef creationDate = CFDateCreate(CFGetAllocator(message), message->creationTime);
314
315 CFMutableStringRef objects = CFStringCreateMutable(kCFAllocatorDefault, 0);
316
317 // TODO: Remove this layer violation!
318 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
319 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, NULL);
320
321 __block size_t maxEntries = 16;
322 CFStringAppendFormat(objects, NULL, CFSTR("{[%zu]"), SOSMessageCountObjects(message));
323 SOSMessageWithSOSObjects(message, ds, NULL, ^(SOSObjectRef object, bool *stop) {
324 CFDataRef digest = SOSObjectCopyDigest(ds, object, NULL);
325 const uint8_t *O = CFDataGetBytePtr(digest);
326 CFStringAppendFormat(objects, NULL, CFSTR(" %02X%02X%02X%02X"), O[0],O[1],O[2],O[3]);
327 CFReleaseSafe(digest);
328 if (!--maxEntries) {
329 CFStringAppend(objects, CFSTR("..."));
330 *stop = true;
331 }
332 });
333 CFStringAppend(objects, CFSTR("}"));
334
335 CFStringRef desc;
336 if (message->version == 0) {
337 switch (SOSMessageInferType(message, NULL)) {
338 case SOSManifestInvalidMessageType:
339 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGInvalid %"PRIu64" >"), message->sequenceNumber);
340 break;
341 case SOSManifestDigestMessageType:
342 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGDigest %"PRIu64" %02X%02X%02X%02X>"), message->sequenceNumber, S[0],S[1],S[2],S[3]);
343 break;
344 case SOSManifestMessageType:
345 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGManifest %"PRIu64" %@>"), message->sequenceNumber, message->additions);
346 break;
347 case SOSManifestDeltaAndObjectsMessageType:
348 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGObjects %"PRIu64" %02X%02X%02X%02X %@ %@ %@"),
349 message->sequenceNumber,
350 B[0],B[1],B[2],B[3],
351 message->removals, message->additions,
352 objects);
353 break;
354 }
355 } else {
356 desc = CFStringCreateWithFormat
357 (CFGetAllocator(message), NULL, CFSTR("<MSG %"PRIu64" %@ %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %@ %@ %@ %s%s%s%s%s%s%s>"),
358 message->sequenceNumber,
359 creationDate,
360 S[0],S[1],S[2],S[3],
361 B[0],B[1],B[2],B[3],
362 P[0],P[1],P[2],P[3],
363 message->removals, message->additions,
364 objects,
365 (message->flags & kSOSMessageGetObjects) ? "G" : "g",
366 (message->flags & kSOSMessageJoinRequest) ? "J" : "j",
367 (message->flags & kSOSMessagePartial) ? "P" : "p",
368 (message->flags & kSOSMessageDigestTypesProposed) ? "D" : "d",
369 (message->flags & kSOSMessageClearGetObjects) ? "K" : "k",
370 (message->flags & kSOSMessageDidClearGetObjectsSinceLastDelta) ? "Z" : "z",
371 (message->flags & kSOSMessageSkipHello) ? "H" : "h");
372 }
373 CFReleaseSafe(creationDate);
374 CFReleaseSafe(objects);
375 return desc;
376 }
377
378 //
379 // MARK: SOSMessage encoding
380 //
381
382 // Create an SOSMessage ready to be encoded.
383 SOSMessageRef SOSMessageCreate(CFAllocatorRef allocator, uint64_t version, CFErrorRef *error) {
384 SOSMessageRef message = CFTypeAllocate(SOSMessage, struct __OpaqueSOSMessage, allocator);
385 message->version = version;
386 return message;
387 }
388
389 // TODO: Remove me this is for testing only, tests should use the real thing.
390 SOSMessageRef SOSMessageCreateWithManifests(CFAllocatorRef allocator, SOSManifestRef sender,
391 SOSManifestRef base, SOSManifestRef proposed,
392 bool includeManifestDeltas, CFErrorRef *error) {
393 SOSMessageRef message = SOSMessageCreate(allocator, kEngineMessageProtocolVersion, error);
394 if (!SOSMessageSetManifests(message, sender, base, proposed, includeManifestDeltas, NULL, error))
395 CFReleaseNull(message);
396 return message;
397 }
398
399 bool SOSMessageSetManifests(SOSMessageRef message, SOSManifestRef sender,
400 SOSManifestRef base, SOSManifestRef proposed,
401 bool includeManifestDeltas, SOSManifestRef objectsSent,
402 CFErrorRef *error) {
403 if (!message) return true;
404 bool ok = true;
405 // TODO: Check at v2 encoding time
406 // if (!sender) return (SOSMessageRef)SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("no sender manifest specified for SOSMessage"));
407 message->baseDigest = CFRetainSafe(SOSManifestGetDigest(base, NULL));
408 message->proposedDigest = CFRetainSafe(SOSManifestGetDigest(proposed, NULL));
409 message->senderDigest = CFRetainSafe(SOSManifestGetDigest(sender, NULL));
410 if (includeManifestDeltas) {
411 SOSManifestRef additions = NULL;
412 ok = SOSManifestDiff(base, proposed, &message->removals, &additions, error);
413 if (message->version == 0) {
414 message->additions = additions;
415 } else {
416 message->additions = SOSManifestCreateComplement(objectsSent, additions, error);
417 CFReleaseSafe(additions);
418 }
419 }
420 return ok;
421 }
422
423 void SOSMessageSetFlags(SOSMessageRef message, SOSMessageFlags flags) {
424 message->flags = flags;
425 }
426
427 // Add an extension to this message
428 void SOSMessageAddExtension(SOSMessageRef message, CFDataRef oid, bool isCritical, CFDataRef extension) {
429 // TODO: Implement
430 secerror("not implemented yet!");
431 }
432
433 static bool SecMessageIsObjectValid(CFDataRef object, CFErrorRef *error) {
434 const uint8_t *der = CFDataGetBytePtr(object);
435 const uint8_t *der_end = der + CFDataGetLength(object);
436 ccder_tag tag = 0;
437 size_t len = 0;
438 der = ccder_decode_tag(&tag, der, der_end);
439 if (!der )
440 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Invalid DER, no tag found"));
441 if (tag == CCDER_EOL)
442 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object has EOL tag"));
443 der = ccder_decode_len(&len, der, der_end);
444 if (!der)
445 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object with tag %lu has no valid DER length"), tag);
446 der += len;
447 if (der_end - der)
448 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object has %td trailing unused bytes"), der_end - der);
449 return true;
450 }
451
452 bool SOSMessageAppendObject(SOSMessageRef message, CFDataRef object, CFErrorRef *error) {
453 if (!SecMessageIsObjectValid(object, error)) return false;
454 if (!message->objects)
455 message->objects = CFArrayCreateMutableForCFTypes(CFGetAllocator(message));
456 if (message->objects)
457 CFArrayAppendValue(message->objects, object);
458 return true;
459 }
460
461 static CC_NONNULL_ALL
462 size_t ccder_sizeof_bit_string(cc_size n, const cc_unit *s) {
463 return ccder_sizeof(CCDER_BIT_STRING, ccn_sizeof(ccn_bitlen(n, s)) + 1);
464 }
465
466 static CC_NONNULL_ALL
467 uint8_t *ccder_encode_bit_string(cc_size n, const cc_unit *s, const uint8_t *der, uint8_t *der_end) {
468 size_t bits = ccn_bitlen(n, s);
469 size_t out_size = ccn_sizeof(bits) + 1;
470 der_end = ccder_encode_body_nocopy(out_size, der, der_end);
471 if (der_end)
472 ccn_write_uint_padded(n, s, out_size, der_end);
473 return ccder_encode_tl(CCDER_BIT_STRING, out_size, der, der_end);
474 }
475
476
477 static
478 size_t der_sizeof_implicit_data(ccder_tag tag, CFDataRef data) {
479 if (!data)
480 return 0;
481 return ccder_sizeof_implicit_raw_octet_string(tag, CFDataGetLength(data));
482 }
483
484
485 static CC_NONNULL((3, 4))
486 uint8_t *der_encode_implicit_data(ccder_tag tag, CFDataRef data, const uint8_t *der, uint8_t *der_end) {
487 if (!data)
488 return der_end;
489 return ccder_encode_implicit_raw_octet_string(tag, CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end);
490 }
491
492 static size_t der_sizeof_message_header(SOSMessageRef message, CFErrorRef *error) {
493 if (!message->senderDigest) {
494 // TODO: Create Error.
495 return 0;
496 }
497 cc_unit flags[1];
498 flags[0] = (cc_unit)message->flags; // TODO Fix cast or something
499
500 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
501 der_sizeof_generalizedtime(message->creationTime, error) +
502 ccder_sizeof_uint64(message->sequenceNumber) +
503 ccder_sizeof_bit_string(array_size(flags), flags) +
504 der_sizeof_implicit_data(CCDER_OCTET_STRING, message->senderDigest) +
505 der_sizeof_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, message->baseDigest) +
506 der_sizeof_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, message->proposedDigest));
507 }
508
509 static uint8_t *der_encode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
510 if (!message->senderDigest) {
511 // TODO: Create Error.
512 return NULL;
513 }
514 cc_unit flags[1];
515 flags[0] = (cc_unit)message->flags; // TODO Fix cast or something
516 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
517 der_encode_generalizedtime(message->creationTime, error, der,
518 ccder_encode_uint64(message->sequenceNumber, der,
519 ccder_encode_bit_string(array_size(flags), flags, der,
520 der_encode_implicit_data(CCDER_OCTET_STRING, message->senderDigest, der,
521 der_encode_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, message->baseDigest, der,
522 der_encode_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, message->proposedDigest, der, der_end)))))));
523 }
524
525 static size_t der_sizeof_deltas(SOSMessageRef message) {
526 if (!message->additions && !message->removals) return 0;
527 if (message->version == 0) {
528 return ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->removals))+
529 ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->additions));
530 } else {
531 return ccder_sizeof(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED,
532 ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->removals))+
533 ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->additions)));
534 }
535 }
536
537 static uint8_t *der_encode_deltas(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
538 if (!message->additions && !message->removals) return der_end;
539 if (message->version == 0) {
540 return der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der,
541 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end));
542 } else {
543 return ccder_encode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, der_end, der,
544 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der,
545 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end)));
546 }
547 }
548
549 static size_t der_sizeof_extensions(SOSMessageRef message) {
550 // We don't support any yet.
551 return 0;
552 }
553
554 static uint8_t *der_encode_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
555 // We don't support any yet.
556 return der_end;
557 }
558
559 static size_t der_sizeof_objects(SOSMessageRef message) {
560 size_t len = 0;
561 if (message->objects) {
562 CFDataRef data;
563 CFArrayForEachC(message->objects, data) {
564 len += (size_t)CFDataGetLength(data);
565 }
566 } else if (message->version != 0)
567 return 0;
568
569 if (message->indefiniteLength)
570 return len + 4;
571 else
572 return ccder_sizeof(2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, len);
573 }
574
575 static uint8_t *der_encode_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
576 if (!message->objects && message->version != 0) return der_end;
577 const uint8_t *original_der_end = der_end;
578 if (message->indefiniteLength)
579 der_end = ccder_encode_tl(CCDER_EOL, 0, der, der_end);
580
581 for (CFIndex position = (message->objects ? CFArrayGetCount(message->objects) : 0) - 1; position >= 0; --position) {
582 CFDataRef object = CFArrayGetValueAtIndex(message->objects, position);
583 der_end = ccder_encode_body(CFDataGetLength(object), CFDataGetBytePtr(object), der, der_end);
584 }
585 if (message->indefiniteLength) {
586 return ccder_encode_tag(2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, der,
587 ccder_encode_len(0, der, der_end));
588 } else {
589 ccder_tag otag = message->version == 0 ? CCDER_CONSTRUCTED_SEQUENCE : 2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED;
590 return ccder_encode_constructed_tl(otag, original_der_end, der, der_end);
591 }
592 }
593
594 static size_t der_sizeof_v2_message(SOSMessageRef message, CFErrorRef *error) {
595 size_t body_size = (der_sizeof_message_header(message, error) +
596 der_sizeof_deltas(message) +
597 der_sizeof_extensions(message) +
598 der_sizeof_objects(message));
599 if (message->indefiniteLength)
600 return body_size + 4;
601 else
602 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, body_size);
603 }
604
605
606 static uint8_t *der_encode_v2_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
607 const uint8_t *original_der_end = der_end;
608 if (message->indefiniteLength)
609 der_end = ccder_encode_tl(CCDER_EOL, 0, der, der_end);
610
611 der_end = der_encode_message_header(message, error, der,
612 der_encode_deltas(message, error, der,
613 der_encode_extensions(message, error, der,
614 der_encode_objects(message, error, der, der_end))));
615
616 if (message->indefiniteLength) {
617 return ccder_encode_tag(CCDER_CONSTRUCTED_SEQUENCE, der,
618 ccder_encode_len(0, der, der_end));
619 } else {
620 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der, der_end);
621 }
622 }
623
624 //------------------------------------------------------------------------------------------------------------------------------------
625 // V1 support
626 //------------------------------------------------------------------------------------------------------------------------------------
627
628 /* ManifestDigest message */
629 static size_t der_sizeof_manifest_digest_message(SOSMessageRef message, CFErrorRef *error) {
630 if (!message->senderDigest || CFDataGetLength(message->senderDigest) != SOSDigestSize) {
631 SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("digest length mismatch"));
632 return 0;
633 }
634 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
635 (ccder_sizeof_uint64(SOSManifestDigestMessageType) +
636 ccder_sizeof_raw_octet_string(SOSDigestSize)));
637 }
638
639 static uint8_t *der_encode_manifest_digest_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
640 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
641 ccder_encode_uint64(SOSManifestDigestMessageType, der,
642 ccder_encode_raw_octet_string(SOSDigestSize, CFDataGetBytePtr(message->senderDigest), der, der_end)));
643 }
644
645 /* Manifest message */
646 static size_t der_sizeof_manifest_message(SOSMessageRef message, CFErrorRef *error) {
647 if (!message->additions) {
648 SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("no manifest for manifest message"));
649 return 0;
650 }
651 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
652 (ccder_sizeof_uint64(SOSManifestMessageType) +
653 der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions))));
654 }
655
656 static uint8_t *der_encode_manifest_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
657 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
658 ccder_encode_uint64(SOSManifestMessageType, der,
659 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end)));
660 }
661
662 /* ManifestDeltaAndObjects message */
663 static size_t der_sizeof_manifest_and_objects_message(SOSMessageRef message, CFErrorRef *error) {
664 if (!message->baseDigest || CFDataGetLength(message->baseDigest) != SOSDigestSize) {
665 SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("digest length mismatch"));
666 return 0;
667 }
668
669 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
670 (ccder_sizeof_uint64(SOSManifestDeltaAndObjectsMessageType) +
671 ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
672 (ccder_sizeof_raw_octet_string(SOSDigestSize) +
673 der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals)) +
674 der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions)) +
675 der_sizeof_objects(message)))));
676 }
677
678 static uint8_t *der_encode_manifest_and_objects_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
679 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
680 ccder_encode_uint64(SOSManifestDeltaAndObjectsMessageType, der,
681 ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
682 ccder_encode_raw_octet_string(SOSDigestSize, CFDataGetBytePtr(message->baseDigest), der,
683 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der,
684 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der,
685 der_encode_objects(message, error, der, der_end)))))));
686 }
687
688 static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error) {
689 if (message->baseDigest) {
690 // TODO: Assert that we don't have senderDigest or proposedDigest
691 if (SOSManifestGetCount(message->removals) || SOSManifestGetCount(message->additions) || SOSMessageCountObjects(message)) {
692 return SOSManifestDeltaAndObjectsMessageType;
693 } else {
694 // NOTE: If we force a SOSManifestDeltaAndObjectsMessageType instead then
695 // true v0 peers will overwrite their last objects message to us. However this
696 // implements the current v0 behaviour
697 return SOSManifestDigestMessageType;
698 }
699 } else if (message->additions) {
700 // TODO: Assert that we don't have senderDigest, proposedDigest, additions, removals or objects
701 return SOSManifestMessageType;
702 } else if (message->senderDigest) {
703 // TODO: Assert that we don't have proposedDigest, removals or objects
704 return SOSManifestDigestMessageType;
705 }
706 // TODO: Create error.
707 return SOSManifestInvalidMessageType;
708 }
709
710 static size_t der_sizeof_message(SOSMessageRef message, uint64_t messageType, CFErrorRef *error) {
711 switch (messageType) {
712 case SOSManifestInvalidMessageType:
713 return der_sizeof_v2_message(message, error);
714 case SOSManifestDigestMessageType:
715 return der_sizeof_manifest_digest_message(message, error);
716 case SOSManifestMessageType:
717 return der_sizeof_manifest_message(message, error);
718 case SOSManifestDeltaAndObjectsMessageType:
719 return der_sizeof_manifest_and_objects_message(message, error);
720 }
721 return 0;
722 }
723
724 static uint8_t *der_encode_message(SOSMessageRef message, uint64_t messageType, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
725 switch (messageType) {
726 case SOSManifestInvalidMessageType:
727 return der_encode_v2_message(message, error, der, der_end);
728 case SOSManifestDigestMessageType:
729 return der_encode_manifest_digest_message(message, error, der, der_end);
730 case SOSManifestMessageType:
731 return der_encode_manifest_message(message, error, der, der_end);
732 case SOSManifestDeltaAndObjectsMessageType:
733 return der_encode_manifest_and_objects_message(message, error, der, der_end);
734 }
735 return der_end;
736 }
737
738 // Encode an SOSMessage, calls addObject callback and appends returned objects
739 // one by one, until addObject returns NULL.
740 CFDataRef SOSMessageCreateData(SOSMessageRef message, uint64_t sequenceNumber, CFErrorRef *error) {
741 // Version 2 message have sequence numbers, version 0 messages do not.
742 uint64_t messageType = SOSManifestInvalidMessageType;
743 message->sequenceNumber = sequenceNumber;
744 if (message->version == 0) {
745 message->indefiniteLength = false;
746 messageType = SOSMessageInferType(message, error);
747 if (!messageType) {
748 // Propagate error
749 return NULL;
750 }
751 } else {
752 message->creationTime = floor(CFAbsoluteTimeGetCurrent());
753 }
754 size_t der_size = der_sizeof_message(message, messageType, error);
755 CFMutableDataRef data = CFDataCreateMutable(NULL, der_size);
756 if (data == NULL) {
757 // TODO Error.
758 return NULL;
759 }
760 CFDataSetLength(data, der_size);
761 uint8_t *der_end = CFDataGetMutableBytePtr(data);
762 const uint8_t *der = der_end;
763 der_end += der_size;
764
765 der_end = der_encode_message(message, messageType, error, der, der_end);
766 if (der != der_end) {
767 secwarning("internal error %td bytes unused in der buffer", der_end - der);
768 }
769 return data;
770 }
771
772 //
773 // MARK: SOSMessage decoding
774 //
775
776 #define CCBER_LEN_INDEFINITE ((size_t)-1)
777
778 // Decode BER length field. Sets *lenp to ccber_indefinite_len if this is an indefinite length encoded object.
779 // Behaves like ccder_decode_len in every other way.
780 static CC_NONNULL((1, 3))
781 const uint8_t *ccber_decode_len(size_t *lenp, const uint8_t *der, const uint8_t *der_end) {
782 if (der && der < der_end) {
783 if (*der == 0x80) {
784 der++;
785 *lenp = CCBER_LEN_INDEFINITE;
786 }
787 else
788 der = ccder_decode_len(lenp, der, der_end);
789 }
790 return der;
791 }
792
793 static const uint8_t *der_decode_generalizedtime(CFAbsoluteTime *at, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
794 const uint8_t *times_end = NULL;
795 der = ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME, &times_end, der, der_end);
796 der = der_decode_generalizedtime_body(at, error, der, times_end);
797 if (times_end != der) {
798 secwarning("internal error %td bytes unused in generalizedtime DER buffer", times_end - der);
799 }
800 return der;
801 }
802
803 static const uint8_t *der_decode_optional_generalizedtime(CFAbsoluteTime *at, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
804 const uint8_t *times_end = der_decode_generalizedtime(at, error, der, der_end);
805 return times_end ? times_end : der;
806 }
807
808 static CC_NONNULL((2, 4))
809 const uint8_t *ccder_decode_implicit_uint64(ccder_tag expected_tag, uint64_t* r, const uint8_t *der, const uint8_t *der_end) {
810 size_t len;
811 der = ccder_decode_tl(expected_tag, &len, der, der_end);
812 if (der && len && (*der & 0x80) != 0x80) {
813 if (ccn_read_uint(ccn_nof_size(sizeof(*r)), (cc_unit*)r, len, der) >= 0)
814 return der + len;
815 }
816 return NULL;
817 }
818
819 static const uint8_t *ccder_decode_optional_implicit_uint64(ccder_tag expected_tag, uint64_t *value, const uint8_t *der, const uint8_t *der_end) {
820 const uint8_t *ui64_end = ccder_decode_implicit_uint64(expected_tag, value, der, der_end);
821 return ui64_end ? ui64_end : der;
822 }
823
824
825 static const uint8_t *ccder_decode_optional_uint64(uint64_t *value, const uint8_t *der, const uint8_t *der_end) {
826 const uint8_t *ui64_end = ccder_decode_uint64(value, der, der_end);
827 return ui64_end ? ui64_end : der;
828 }
829
830 static const uint8_t *ccder_decode_digest_types(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) {
831 const uint8_t *dt_end;
832 der = ccder_decode_sequence_tl(&dt_end, der, der_end);
833 if (!der) return NULL;
834 // Skip over digestType body for now.
835 // TODO: Support DigestType
836 return dt_end;
837 }
838
839 static const uint8_t *ccder_decode_optional_digest_types(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) {
840 const uint8_t *dt_end = ccder_decode_digest_types(message, der, der_end);
841 return dt_end ? dt_end : der;
842 }
843
844 static const uint8_t *ccder_decode_bit_string(cc_size n, size_t *r_bitlen, cc_unit *r, const uint8_t *der, const uint8_t *der_end) {
845 size_t len;
846 const uint8_t *body = ccder_decode_tl(CCDER_BIT_STRING, &len, der, der_end);
847 if (!body || len < 1)
848 return NULL;
849
850 if (r_bitlen) *r_bitlen = (len - 1) * 8 - (body[0] & 7);
851 ccn_read_uint(1, r, len - 1, body + 1);
852 return body + len;
853 }
854
855 static const uint8_t *der_decode_implicit_data(ccder_tag expected_tag, CFDataRef *data, const uint8_t *der, const uint8_t *der_end) {
856 size_t len = 0;
857 der = ccder_decode_tl(expected_tag, &len, der, der_end);
858 if (der && data) {
859 *data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, len, kCFAllocatorNull);
860 if (*data)
861 der += len;
862 else
863 der = NULL;
864 }
865 return der;
866 }
867
868 static const uint8_t *der_decode_optional_implicit_data(ccder_tag expected_tag, CFDataRef *data, const uint8_t *der, const uint8_t *der_end) {
869 const uint8_t *data_end = der_decode_implicit_data(expected_tag, data, der, der_end);
870 return data_end ? data_end : der;
871 }
872
873 static const uint8_t *der_decode_deltas_body(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
874 CFDataRef removals = NULL, additions = NULL;
875 der = der_decode_implicit_data(CCDER_OCTET_STRING, &removals, der, der_end);
876 der = der_decode_implicit_data(CCDER_OCTET_STRING, &additions, der, der_end);
877 if (der) {
878 message->removals = SOSManifestCreateWithData(removals, error);
879 message->additions = SOSManifestCreateWithData(additions, error);
880 if (!message->removals || !message->additions) {
881 CFReleaseNull(message->removals);
882 CFReleaseNull(message->additions);
883 der = NULL;
884 }
885 }
886 CFReleaseSafe(removals);
887 CFReleaseSafe(additions);
888
889 return der;
890 }
891
892 static const uint8_t *der_decode_deltas(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
893 const uint8_t *deltas_end = NULL;
894 der = ccder_decode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, &deltas_end, der, der_end);
895 return der_decode_deltas_body(message, error, der, deltas_end);
896 }
897
898 static const uint8_t *der_decode_optional_deltas(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) {
899 const uint8_t *seq_end = der_decode_deltas(message, NULL, der, der_end);
900 return seq_end ? seq_end : der;
901 }
902
903 static const uint8_t *der_decode_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
904 const uint8_t *extensions_end;
905 der = ccder_decode_constructed_tl(1 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, &extensions_end, der, der_end);
906 if (!der) return NULL;
907 // Skip over extensions for now.
908 return extensions_end;
909 }
910
911 static const uint8_t *der_decode_optional_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
912 const uint8_t *extensions_end = der_decode_extensions(message, NULL, der, der_end);
913 return extensions_end ? extensions_end : der;
914 }
915
916 static const uint8_t *der_foreach_objects(size_t length, const uint8_t *der, const uint8_t *der_end, CFErrorRef *error, void(^withObject)(CFDataRef object, bool *stop)) {
917 bool stop = false;
918 ccder_tag tag;
919 // Look ahead at the tag
920 while (!stop && ccder_decode_tag(&tag, der, der_end) && tag != CCDER_EOL) {
921 const uint8_t *object_end = NULL;
922 if (!ccder_decode_constructed_tl(tag, &object_end, der, der_end)) {
923 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("failed to decode object header"));
924 return NULL;
925 }
926 if (withObject) {
927 CFDataRef object = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, object_end - der, kCFAllocatorNull);
928 withObject(object, &stop);
929 CFReleaseSafe(object);
930 }
931 der = object_end;
932 }
933 if (length == CCBER_LEN_INDEFINITE) {
934 size_t len = 0;
935 der = ccder_decode_tl(CCDER_EOL, &len, der, der_end);
936 if (len != 0) {
937 secwarning("%td length ", der_end - der);
938 }
939 }
940 if (!stop && der != der_end)
941 secwarning("%td trailing bytes after objects DER", der_end - der);
942
943 return der;
944 }
945
946 static const uint8_t *der_decode_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
947 ccder_tag tag = 0;
948 size_t objects_len = 0;
949 der = ccder_decode_tag(&tag, der, der_end);
950 if (tag != (2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED)) return NULL;
951 der = ccber_decode_len(&objects_len, der, der_end);
952 if (objects_len != CCBER_LEN_INDEFINITE && der_end - der != (ptrdiff_t)objects_len) {
953 secwarning("%td trailing bytes after SOSMessage DER", (der_end - der) - (ptrdiff_t)objects_len);
954 }
955 // Remember a pointer into message->der where objects starts.
956 message->objectsDer = der;
957 message->objectsLen = objects_len;
958
959 return der + objects_len;
960 }
961
962 static const uint8_t *der_decode_optional_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
963 const uint8_t *seq_end = der_decode_objects(message, NULL, der, der_end);
964 return seq_end ? seq_end : der;
965 }
966
967 #if 0
968 // Move to ccder and possibly refactor ccder_decode_constructed_tl to call this.
969 #ifdef CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER
970 CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER
971 #endif
972 inline CC_NONNULL((1, 3))
973 const uint8_t *
974 ccder_decode_constructed_len(const uint8_t **body_end,
975 const uint8_t *der, const uint8_t *der_end) {
976 size_t len;
977 der = ccder_decode_len(&len, der, der_end);
978 *body_end = der + len;
979 return der;
980 }
981 #endif
982
983 static const uint8_t *der_decode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
984 cc_unit flags[1] = {};
985 der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end);
986 message->version = 2;
987 der = ccder_decode_optional_implicit_uint64(0 | CCDER_CONTEXT_SPECIFIC, &message->version, der, der_end);
988 der = der_decode_optional_generalizedtime(&message->creationTime, error, der, der_end);
989 der = ccder_decode_optional_uint64(&message->sequenceNumber, der, der_end);
990 der = ccder_decode_optional_digest_types(message, der, der_end);
991 der = ccder_decode_bit_string(array_size(flags), NULL, flags, der, der_end);
992 message->flags = flags[0];
993
994 der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->senderDigest, der, der_end);
995 der = der_decode_optional_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, &message->baseDigest, der, der_end);
996 der = der_decode_optional_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, &message->proposedDigest, der, der_end);
997 return der;
998 }
999
1000 static const uint8_t *
1001 der_decode_manifest_and_objects_message(SOSMessageRef message,
1002 CFErrorRef *error, const uint8_t *der,
1003 const uint8_t *der_end) {
1004 size_t objects_len = 0;
1005 const uint8_t *body_end;
1006 der = ccder_decode_sequence_tl(&body_end, der, der_end);
1007 if (body_end != der_end) {
1008 SOSErrorCreate(kSOSErrorInvalidMessage, error, NULL, CFSTR("Trailing garbage at end of message"));
1009 return NULL;
1010 }
1011 der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->baseDigest, der, body_end);
1012 der = der_decode_deltas_body(message, error, der, body_end);
1013 // Remember a pointer into message->der where objects starts.
1014 der = message->objectsDer = ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &objects_len, der, body_end);
1015 message->objectsLen = objects_len;
1016
1017 return der ? der + objects_len : NULL;
1018 }
1019
1020 static const uint8_t *der_decode_v0_message_body(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
1021 uint64_t messageType = 0;
1022 der = ccder_decode_uint64(&messageType, der, der_end);
1023 if (der) switch (messageType) {
1024 case SOSManifestDigestMessageType:
1025 {
1026 der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->senderDigest, der, der_end);
1027 break;
1028 }
1029 case SOSManifestMessageType:
1030 {
1031 CFDataRef manifestBody = NULL;
1032 der = der_decode_implicit_data(CCDER_OCTET_STRING, &manifestBody, der, der_end);
1033 if (!der) return NULL;
1034 if (der != der_end) {
1035 secwarning("%td trailing bytes after deltas DER", der_end - der);
1036 }
1037 message->additions = SOSManifestCreateWithData(manifestBody, error);
1038 CFReleaseSafe(manifestBody);
1039 break;
1040 }
1041 case SOSManifestDeltaAndObjectsMessageType:
1042 {
1043 der = der_decode_manifest_and_objects_message(message, error, der, der_end);
1044 break;
1045 }
1046 default:
1047 SOSErrorCreate(kSOSErrorInvalidMessage, error, NULL, CFSTR("Invalid message type %llu"), messageType);
1048 break;
1049 }
1050 return der;
1051 }
1052
1053 static const uint8_t *der_decode_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
1054 ccder_tag tag = 0;
1055 size_t body_len = 0;
1056
1057 der = ccder_decode_tag(&tag, der, der_end);
1058 if (tag != CCDER_CONSTRUCTED_SEQUENCE) return NULL;
1059 der = ccber_decode_len(&body_len, der, der_end);
1060 if (der && body_len && body_len != CCBER_LEN_INDEFINITE && (der_end - der) != (ptrdiff_t)body_len) {
1061 secwarning("%td trailing bytes after SOSMessage DER", (der_end - der) - (ptrdiff_t)body_len);
1062 der_end = der + body_len;
1063 }
1064
1065 if (ccder_decode_tag(&tag, der, der_end)) switch (tag) {
1066 case CCDER_INTEGER: // v0
1067 if (body_len == CCBER_LEN_INDEFINITE)
1068 der = NULL; // Not supported for v0 messages
1069 else
1070 der = der_decode_v0_message_body(message, error, der, der_end);
1071 break;
1072 case CCDER_CONSTRUCTED_SEQUENCE: //v2
1073 der = der_decode_message_header(message, error, der, der_end);
1074 der = der_decode_optional_deltas(message, der, der_end);
1075 der = der_decode_optional_extensions(message, error, der, der_end);
1076 der = der_decode_optional_objects(message, error, der, der_end);
1077 break;
1078 }
1079 return der;
1080 }
1081
1082 // Decode a SOSMessage
1083 SOSMessageRef SOSMessageCreateWithData(CFAllocatorRef allocator, CFDataRef derData, CFErrorRef *error) {
1084 if (!derData)
1085 return (SOSMessageRef)SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("NULL data => no SOSMessage"));
1086 SOSMessageRef message = CFTypeAllocate(SOSMessage, struct __OpaqueSOSMessage, allocator);
1087 if (!message)
1088 return (SOSMessageRef)SOSErrorCreate(kSOSErrorAllocationFailure, error, NULL, CFSTR("failed to alloc SOSMessage"));
1089 message->der = CFRetainSafe(derData);
1090 const uint8_t *der = CFDataGetBytePtr(derData);
1091 const uint8_t *der_end = der + CFDataGetLength(derData);
1092 der = der_decode_message(message, error, der, der_end);
1093 if (!der_end || der != der_end) {
1094 if (error && !*error)
1095 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("SOSMessage DER decoding failure %td bytes left"), der_end - der);
1096 return CFReleaseSafe(message);
1097 }
1098 return message;
1099 }
1100
1101 // Read values from a decoded messgage
1102
1103 CFDataRef SOSMessageGetBaseDigest(SOSMessageRef message) {
1104 return message->baseDigest;
1105 }
1106
1107 CFDataRef SOSMessageGetProposedDigest(SOSMessageRef message) {
1108 return message->proposedDigest;
1109 }
1110
1111 CFDataRef SOSMessageGetSenderDigest(SOSMessageRef message) {
1112 return message->senderDigest;
1113 }
1114
1115 SOSMessageFlags SOSMessageGetFlags(SOSMessageRef message) {
1116 return message->flags;
1117 }
1118
1119 uint64_t SOSMessageGetSequenceNumber(SOSMessageRef message) {
1120 return message->sequenceNumber;
1121 }
1122
1123 SOSManifestRef SOSMessageGetRemovals(SOSMessageRef message) {
1124 return message->removals;
1125 }
1126
1127 SOSManifestRef SOSMessageGetAdditions(SOSMessageRef message) {
1128 return message->additions;
1129 }
1130
1131 // Iterate though the extensions in a decoded SOSMessage. If criticalOnly is
1132 // true all non critical extensions are skipped.
1133 void SOSMessageWithExtensions(SOSMessageRef message, bool criticalOnly, void(^withExtension)(CFDataRef oid, bool isCritical, CFDataRef extension, bool *stop)) {
1134 // TODO
1135 }
1136
1137 size_t SOSMessageCountObjects(SOSMessageRef message) {
1138 if (message->objects)
1139 return CFArrayGetCount(message->objects);
1140 if (!message->objectsDer)
1141 return 0;
1142 const uint8_t *der = CFDataGetBytePtr(message->der);
1143 const uint8_t *der_end = der + CFDataGetLength(message->der);
1144 __block size_t count = 0;
1145 der_foreach_objects(message->objectsLen, message->objectsDer, der_end, NULL, ^(CFDataRef object, bool *stop){ ++count; });
1146 return count;
1147 }
1148
1149 // Iterate though the objects in a decoded SOSMessage.
1150 bool SOSMessageWithObjects(SOSMessageRef message, CFErrorRef *error,
1151 void(^withObject)(CFDataRef object, bool *stop)) {
1152 if (message->objects) {
1153 CFDataRef object;
1154 CFArrayForEachC(message->objects, object) {
1155 bool stop = false;
1156 withObject(object, &stop);
1157 if (stop)
1158 break;
1159 }
1160 return true;
1161 }
1162 if (!message->objectsDer)
1163 return true;
1164 const uint8_t *der = CFDataGetBytePtr(message->der);
1165 const uint8_t *der_end = der + CFDataGetLength(message->der);
1166 return der_foreach_objects(message->objectsLen, message->objectsDer, der_end, error, withObject);
1167 }
1168
1169 bool SOSMessageWithSOSObjects(SOSMessageRef message, SOSDataSourceRef dataSource, CFErrorRef *error,
1170 void(^withObject)(SOSObjectRef object, bool *stop)) {
1171 return SOSMessageWithObjects(message, error, ^(CFDataRef object, bool *stop) {
1172 CFDictionaryRef plist = NULL;
1173 const uint8_t *der = CFDataGetBytePtr(object);
1174 const uint8_t *der_end = der + CFDataGetLength(object);
1175 // TODO Remove intermediate plist format
1176 der = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &plist, error, der, der_end);
1177 if (der) {
1178 SOSObjectRef peersObject = SOSObjectCreateWithPropertyList(dataSource, plist, error);
1179 withObject(peersObject, stop);
1180 CFReleaseSafe(peersObject);
1181 }
1182 CFReleaseSafe(plist);
1183 });
1184 }