]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSMessage.c
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / 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 "keychain/SecureObjectSync/SOSMessage.h"
30
31 #include <AssertMacros.h>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include "keychain/SecureObjectSync/SOSDigestVector.h"
34 #include "keychain/SecureObjectSync/SOSManifest.h"
35 #include "keychain/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 "keychain/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 //
215 // MARK: SOSMessage implementation.
216 //
217
218 // Legacy v1 message type numbers
219 enum SOSMessageType {
220 SOSManifestInvalidMessageType = 0,
221 SOSManifestDigestMessageType = 1,
222 SOSManifestMessageType = 2,
223 SOSManifestDeltaAndObjectsMessageType = 3,
224 };
225
226 struct __OpaqueSOSMessage {
227 CFRuntimeBase _base;
228
229 CFDataRef der;
230 const uint8_t *objectsDer;
231 size_t objectsLen;
232
233 CFDataRef senderDigest;
234 CFDataRef baseDigest;
235 CFDataRef proposedDigest;
236 SOSManifestRef removals;
237 SOSManifestRef additions;
238
239 CFMutableArrayRef objects;
240
241 SOSMessageFlags flags;
242 uint64_t sequenceNumber;
243 CFAbsoluteTime creationTime;
244 uint64_t version; // Message version (currently always 2)
245 bool indefiniteLength; // If set to true the top SEQUENCE and the OBJECTS SEQUENCE are written indefinite length.
246 };
247
248 CFGiblisWithCompareFor(SOSMessage)
249
250 static Boolean SOSMessageCompare(CFTypeRef cf1, CFTypeRef cf2) {
251 SOSMessageRef M = (SOSMessageRef)cf1;
252 SOSMessageRef P = (SOSMessageRef)cf2;
253 if (M->flags != P->flags) return false;
254 if (M->sequenceNumber != P->sequenceNumber) return false;
255 if (M->creationTime != P->creationTime) return false;
256 //if (!CFEqualSafe(M->der, P->der)) return false;
257 if (!CFEqualSafe(M->senderDigest, P->senderDigest)) return false;
258 if (!CFEqualSafe(M->baseDigest, P->baseDigest)) return false;
259 if (!CFEqualSafe(M->proposedDigest, P->proposedDigest)) return false;
260 if (!CFEqualSafe(M->removals, P->removals)) return false;
261 if (!CFEqualSafe(M->additions, P->additions)) return false;
262
263 // TODO Compare Objects if present.
264
265 return true;
266 }
267
268 static void SOSMessageDestroy(CFTypeRef cf) {
269 SOSMessageRef message = (SOSMessageRef)cf;
270 CFReleaseNull(message->der);
271 CFReleaseNull(message->senderDigest);
272 CFReleaseNull(message->baseDigest);
273 CFReleaseNull(message->proposedDigest);
274 CFReleaseNull(message->additions);
275 CFReleaseNull(message->removals);
276 CFReleaseNull(message->objects);
277 }
278
279 // TODO: Remove this layer violation!
280 #include "keychain/securityd/SecItemServer.h"
281
282 static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error);
283
284 static CFStringRef SOSMessageCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
285 SOSMessageRef message = (SOSMessageRef)cf;
286 static const uint8_t zero[4] = {};
287 const uint8_t *S = message->senderDigest ? CFDataGetBytePtr(message->senderDigest) : zero;
288 const uint8_t *B = message->baseDigest ? CFDataGetBytePtr(message->baseDigest) : zero;
289 const uint8_t *P = message->proposedDigest ? CFDataGetBytePtr(message->proposedDigest) : zero;
290 CFDateRef creationDate = CFDateCreate(CFGetAllocator(message), message->creationTime);
291
292 CFMutableStringRef objects = CFStringCreateMutable(kCFAllocatorDefault, 0);
293
294 // TODO: Remove this layer violation!
295 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
296 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, NULL);
297
298 if (ds) {
299 __block size_t maxEntries = 16;
300 CFStringAppendFormat(objects, NULL, CFSTR("{[%zu]"), SOSMessageCountObjects(message));
301 SOSMessageWithSOSObjects(message, ds, NULL, ^(SOSObjectRef object, bool *stop) {
302 CFDataRef digest = SOSObjectCopyDigest(ds, object, NULL);
303 const uint8_t *O = CFDataGetBytePtr(digest);
304 CFStringAppendFormat(objects, NULL, CFSTR(" %02X%02X%02X%02X"), O[0],O[1],O[2],O[3]);
305 CFReleaseSafe(digest);
306 if (!--maxEntries) {
307 CFStringAppend(objects, CFSTR("..."));
308 *stop = true;
309 }
310 });
311 CFStringAppend(objects, CFSTR("}"));
312 } else {
313 CFStringAppend(objects, CFSTR("{NO DATASOURCE}"));
314 }
315
316 CFStringRef desc = NULL;
317 if (message->version == 0) {
318 switch (SOSMessageInferType(message, NULL)) {
319 case SOSManifestInvalidMessageType:
320 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGInvalid %"PRIu64" >"), message->sequenceNumber);
321 break;
322 case SOSManifestDigestMessageType:
323 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGDigest %"PRIu64" %02X%02X%02X%02X>"), message->sequenceNumber, S[0],S[1],S[2],S[3]);
324 break;
325 case SOSManifestMessageType:
326 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGManifest %"PRIu64" %@>"), message->sequenceNumber, message->additions);
327 break;
328 case SOSManifestDeltaAndObjectsMessageType:
329 desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("<MSGObjects %"PRIu64" %02X%02X%02X%02X %@ %@ %@"),
330 message->sequenceNumber,
331 B[0],B[1],B[2],B[3],
332 message->removals, message->additions,
333 objects);
334 break;
335 }
336 } else {
337 desc = CFStringCreateWithFormat
338 (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>"),
339 message->sequenceNumber,
340 creationDate,
341 S[0],S[1],S[2],S[3],
342 B[0],B[1],B[2],B[3],
343 P[0],P[1],P[2],P[3],
344 message->removals, message->additions,
345 objects,
346 (message->flags & kSOSMessageGetObjects) ? "G" : "g",
347 (message->flags & kSOSMessageJoinRequest) ? "J" : "j",
348 (message->flags & kSOSMessagePartial) ? "P" : "p",
349 (message->flags & kSOSMessageDigestTypesProposed) ? "D" : "d",
350 (message->flags & kSOSMessageClearGetObjects) ? "K" : "k",
351 (message->flags & kSOSMessageDidClearGetObjectsSinceLastDelta) ? "Z" : "z",
352 (message->flags & kSOSMessageSkipHello) ? "H" : "h");
353 }
354 CFReleaseSafe(creationDate);
355 CFReleaseSafe(objects);
356 return desc;
357 }
358
359 //
360 // MARK: SOSMessage encoding
361 //
362
363 // Create an SOSMessage ready to be encoded.
364 SOSMessageRef SOSMessageCreate(CFAllocatorRef allocator, uint64_t version, CFErrorRef *error) {
365 SOSMessageRef message = CFTypeAllocate(SOSMessage, struct __OpaqueSOSMessage, allocator);
366 message->version = version;
367 return message;
368 }
369
370 // TODO: Remove me this is for testing only, tests should use the real thing.
371 SOSMessageRef SOSMessageCreateWithManifests(CFAllocatorRef allocator, SOSManifestRef sender,
372 SOSManifestRef base, SOSManifestRef proposed,
373 bool includeManifestDeltas, CFErrorRef *error) {
374 SOSMessageRef message = SOSMessageCreate(allocator, kEngineMessageProtocolVersion, error);
375 if (!SOSMessageSetManifests(message, sender, base, proposed, includeManifestDeltas, NULL, error))
376 CFReleaseNull(message);
377 return message;
378 }
379
380 bool SOSMessageSetManifests(SOSMessageRef message, SOSManifestRef sender,
381 SOSManifestRef base, SOSManifestRef proposed,
382 bool includeManifestDeltas, SOSManifestRef objectsSent,
383 CFErrorRef *error) {
384 if (!message) return true;
385 bool ok = true;
386 // TODO: Check at v2 encoding time
387 // if (!sender) return (SOSMessageRef)SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("no sender manifest specified for SOSMessage"));
388 message->baseDigest = CFRetainSafe(SOSManifestGetDigest(base, NULL));
389 secinfo("engine", "SOSMessageSetManifests: setting base digest to %@ %zu", message->baseDigest, SOSManifestGetCount(base));
390 message->proposedDigest = CFRetainSafe(SOSManifestGetDigest(proposed, NULL));
391 secinfo("engine", "SOSMessageSetManifests: setting proposed digest to %@ %zu", message->proposedDigest, SOSManifestGetCount(proposed));
392 message->senderDigest = CFRetainSafe(SOSManifestGetDigest(sender, NULL));
393 secinfo("engine", "SOSMessageSetManifests: setting sender digest to %@ %zu", message->senderDigest, SOSManifestGetCount(sender));
394
395 if (includeManifestDeltas) {
396 SOSManifestRef additions = NULL;
397 ok = SOSManifestDiff(base, proposed, &message->removals, &additions, error);
398 if (message->version == 0) {
399 message->additions = additions;
400 } else {
401 message->additions = SOSManifestCreateComplement(objectsSent, additions, error);
402 CFReleaseSafe(additions);
403 }
404 }
405 return ok;
406 }
407
408 void SOSMessageSetFlags(SOSMessageRef message, SOSMessageFlags flags) {
409 message->flags = flags;
410 }
411
412 // Add an extension to this message
413 void SOSMessageAddExtension(SOSMessageRef message, CFDataRef oid, bool isCritical, CFDataRef extension) {
414 // TODO: Implement
415 secerror("not implemented yet!");
416 }
417
418 static bool SecMessageIsObjectValid(CFDataRef object, CFErrorRef *error) {
419 const uint8_t *der = CFDataGetBytePtr(object);
420 const uint8_t *der_end = der + CFDataGetLength(object);
421 ccder_tag tag = 0;
422 size_t len = 0;
423 der = ccder_decode_tag(&tag, der, der_end);
424 if (!der )
425 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Invalid DER, no tag found"));
426 if (tag == CCDER_EOL)
427 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object has EOL tag"));
428 der = ccder_decode_len(&len, der, der_end);
429 if (!der)
430 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object with tag %lu has no valid DER length"), tag);
431 der += len;
432 if (der_end - der)
433 return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object has %td trailing unused bytes"), der_end - der);
434 return true;
435 }
436
437 bool SOSMessageAppendObject(SOSMessageRef message, CFDataRef object, CFErrorRef *error) {
438 if (!SecMessageIsObjectValid(object, error)) return false;
439 if (!message->objects)
440 message->objects = CFArrayCreateMutableForCFTypes(CFGetAllocator(message));
441 if (message->objects)
442 CFArrayAppendValue(message->objects, object);
443 return true;
444 }
445
446 static
447 size_t ccder_sizeof_bit_string(cc_size n, const cc_unit *_Nonnull s) {
448 return ccder_sizeof(CCDER_BIT_STRING, ccn_sizeof(ccn_bitlen(n, s)) + 1);
449 }
450
451 static
452 uint8_t *ccder_encode_bit_string(cc_size n, const cc_unit *_Nonnull s, const uint8_t *_Nonnull der, uint8_t *_Nonnull der_end) {
453 size_t bits = ccn_bitlen(n, s);
454 size_t out_size = ccn_sizeof(bits) + 1;
455 der_end = ccder_encode_body_nocopy(out_size, der, der_end);
456 if (der_end)
457 ccn_write_uint_padded(n, s, out_size, der_end);
458 return ccder_encode_tl(CCDER_BIT_STRING, out_size, der, der_end);
459 }
460
461
462 static
463 size_t der_sizeof_implicit_data(ccder_tag tag, CFDataRef data) {
464 if (!data)
465 return 0;
466 return ccder_sizeof_implicit_raw_octet_string(tag, CFDataGetLength(data));
467 }
468
469
470 static
471 uint8_t *der_encode_implicit_data(ccder_tag tag, CFDataRef data, const uint8_t *_Nonnull der, uint8_t *_Nonnull der_end) {
472 if (!data)
473 return der_end;
474 return ccder_encode_implicit_raw_octet_string(tag, CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end);
475 }
476
477 static size_t der_sizeof_message_header(SOSMessageRef message, CFErrorRef *error) {
478 if (!message->senderDigest) {
479 // TODO: Create Error.
480 return 0;
481 }
482 cc_unit flags[1];
483 flags[0] = (cc_unit)message->flags; // TODO Fix cast or something
484
485 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
486 der_sizeof_generalizedtime(message->creationTime, error) +
487 ccder_sizeof_uint64(message->sequenceNumber) +
488 ccder_sizeof_bit_string(array_size(flags), flags) +
489 der_sizeof_implicit_data(CCDER_OCTET_STRING, message->senderDigest) +
490 der_sizeof_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, message->baseDigest) +
491 der_sizeof_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, message->proposedDigest));
492 }
493
494 static uint8_t *der_encode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
495 if (!message->senderDigest) {
496 // TODO: Create Error.
497 return NULL;
498 }
499 cc_unit flags[1];
500 flags[0] = (cc_unit)message->flags; // TODO Fix cast or something
501 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
502 der_encode_generalizedtime(message->creationTime, error, der,
503 ccder_encode_uint64(message->sequenceNumber, der,
504 ccder_encode_bit_string(array_size(flags), flags, der,
505 der_encode_implicit_data(CCDER_OCTET_STRING, message->senderDigest, der,
506 der_encode_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, message->baseDigest, der,
507 der_encode_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, message->proposedDigest, der, der_end)))))));
508 }
509
510 static size_t der_sizeof_deltas(SOSMessageRef message) {
511 if (!message->additions && !message->removals) return 0;
512 if (message->version == 0) {
513 return ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->removals))+
514 ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->additions));
515 } else {
516 return ccder_sizeof(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED,
517 ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->removals))+
518 ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->additions)));
519 }
520 }
521
522 static uint8_t *der_encode_deltas(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
523 if (!message->additions && !message->removals) return der_end;
524 if (message->version == 0) {
525 return der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der,
526 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end));
527 } else {
528 return ccder_encode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, der_end, der,
529 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der,
530 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end)));
531 }
532 }
533
534 static size_t der_sizeof_extensions(SOSMessageRef message) {
535 // We don't support any yet.
536 return 0;
537 }
538
539 static uint8_t *der_encode_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
540 // We don't support any yet.
541 return der_end;
542 }
543
544 static size_t der_sizeof_objects(SOSMessageRef message) {
545 size_t len = 0;
546 if (message->objects) {
547 CFDataRef data;
548 CFArrayForEachC(message->objects, data) {
549 len += (size_t)CFDataGetLength(data);
550 }
551 } else if (message->version != 0)
552 return 0;
553
554 if (message->indefiniteLength)
555 return len + 4;
556 else
557 return ccder_sizeof(2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, len);
558 }
559
560 static uint8_t *der_encode_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
561 if (!message->objects && message->version != 0) return der_end;
562 const uint8_t *original_der_end = der_end;
563 if (message->indefiniteLength)
564 der_end = ccder_encode_tl(CCDER_EOL, 0, der, der_end);
565
566 for (CFIndex position = (message->objects ? CFArrayGetCount(message->objects) : 0) - 1; position >= 0; --position) {
567 CFDataRef object = CFArrayGetValueAtIndex(message->objects, position);
568 der_end = ccder_encode_body(CFDataGetLength(object), CFDataGetBytePtr(object), der, der_end);
569 }
570 if (message->indefiniteLength) {
571 return ccder_encode_tag(2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, der,
572 ccder_encode_len(0, der, der_end));
573 } else {
574 ccder_tag otag = message->version == 0 ? CCDER_CONSTRUCTED_SEQUENCE : 2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED;
575 return ccder_encode_constructed_tl(otag, original_der_end, der, der_end);
576 }
577 }
578
579 static size_t der_sizeof_v2_message(SOSMessageRef message, CFErrorRef *error) {
580 size_t body_size = (der_sizeof_message_header(message, error) +
581 der_sizeof_deltas(message) +
582 der_sizeof_extensions(message) +
583 der_sizeof_objects(message));
584 if (message->indefiniteLength)
585 return body_size + 4;
586 else
587 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, body_size);
588 }
589
590
591 static uint8_t *der_encode_v2_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
592 const uint8_t *original_der_end = der_end;
593 if (message->indefiniteLength)
594 der_end = ccder_encode_tl(CCDER_EOL, 0, der, der_end);
595
596 der_end = der_encode_message_header(message, error, der,
597 der_encode_deltas(message, error, der,
598 der_encode_extensions(message, error, der,
599 der_encode_objects(message, error, der, der_end))));
600
601 if (message->indefiniteLength) {
602 return ccder_encode_tag(CCDER_CONSTRUCTED_SEQUENCE, der,
603 ccder_encode_len(0, der, der_end));
604 } else {
605 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der, der_end);
606 }
607 }
608
609 //------------------------------------------------------------------------------------------------------------------------------------
610 // V1 support
611 //------------------------------------------------------------------------------------------------------------------------------------
612
613 /* ManifestDigest message */
614 static size_t der_sizeof_manifest_digest_message(SOSMessageRef message, CFErrorRef *error) {
615 if (!message->senderDigest || CFDataGetLength(message->senderDigest) != SOSDigestSize) {
616 SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("digest length mismatch"));
617 return 0;
618 }
619 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
620 (ccder_sizeof_uint64(SOSManifestDigestMessageType) +
621 ccder_sizeof_raw_octet_string(SOSDigestSize)));
622 }
623
624 static uint8_t *der_encode_manifest_digest_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
625 secinfo("engine", "der_encode_manifest_digest_message: encoded sender digest as %@", message->senderDigest);
626 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
627 ccder_encode_uint64(SOSManifestDigestMessageType, der,
628 ccder_encode_raw_octet_string(SOSDigestSize, CFDataGetBytePtr(message->senderDigest), der, der_end)));
629 }
630
631 /* Manifest message */
632 static size_t der_sizeof_manifest_message(SOSMessageRef message, CFErrorRef *error) {
633 if (!message->additions) {
634 SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("no manifest for manifest message"));
635 return 0;
636 }
637 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
638 (ccder_sizeof_uint64(SOSManifestMessageType) +
639 der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions))));
640 }
641
642 static uint8_t *der_encode_manifest_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
643 secinfo("engine", "der_encode_manifest_message: encoded message additions as (%zu, %@)", SOSManifestGetCount(message->additions), SOSManifestGetDigest(message->additions, NULL));
644 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
645 ccder_encode_uint64(SOSManifestMessageType, der,
646 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end)));
647 }
648
649 /* ManifestDeltaAndObjects message */
650 static size_t der_sizeof_manifest_and_objects_message(SOSMessageRef message, CFErrorRef *error) {
651 if (!message->baseDigest || CFDataGetLength(message->baseDigest) != SOSDigestSize) {
652 SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("digest length mismatch"));
653 return 0;
654 }
655
656 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
657 (ccder_sizeof_uint64(SOSManifestDeltaAndObjectsMessageType) +
658 ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
659 (ccder_sizeof_raw_octet_string(SOSDigestSize) +
660 der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals)) +
661 der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions)) +
662 der_sizeof_objects(message)))));
663 }
664
665 static uint8_t *der_encode_manifest_and_objects_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
666 secinfo("engine", "der_encode_manifest_and_objects_message: encoded base digest as %@", message->baseDigest);
667 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
668 ccder_encode_uint64(SOSManifestDeltaAndObjectsMessageType, der,
669 ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
670 ccder_encode_raw_octet_string(SOSDigestSize, CFDataGetBytePtr(message->baseDigest), der,
671 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der,
672 der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der,
673 der_encode_objects(message, error, der, der_end)))))));
674 }
675
676 static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error) {
677 if (message->baseDigest) {
678 // TODO: Assert that we don't have senderDigest or proposedDigest
679 if (SOSManifestGetCount(message->removals) || SOSManifestGetCount(message->additions) || SOSMessageCountObjects(message)) {
680 return SOSManifestDeltaAndObjectsMessageType;
681 } else {
682 // NOTE: If we force a SOSManifestDeltaAndObjectsMessageType instead then
683 // true v0 peers will overwrite their last objects message to us. However this
684 // implements the current v0 behaviour
685 return SOSManifestDigestMessageType;
686 }
687 } else if (message->additions) {
688 // TODO: Assert that we don't have senderDigest, proposedDigest, additions, removals or objects
689 return SOSManifestMessageType;
690 } else if (message->senderDigest) {
691 // TODO: Assert that we don't have proposedDigest, removals or objects
692 return SOSManifestDigestMessageType;
693 }
694 // TODO: Create error.
695 return SOSManifestInvalidMessageType;
696 }
697
698 static size_t der_sizeof_message(SOSMessageRef message, uint64_t messageType, CFErrorRef *error) {
699 switch (messageType) {
700 case SOSManifestInvalidMessageType:
701 return der_sizeof_v2_message(message, error);
702 case SOSManifestDigestMessageType:
703 return der_sizeof_manifest_digest_message(message, error);
704 case SOSManifestMessageType:
705 return der_sizeof_manifest_message(message, error);
706 case SOSManifestDeltaAndObjectsMessageType:
707 return der_sizeof_manifest_and_objects_message(message, error);
708 }
709 return 0;
710 }
711
712 static uint8_t *der_encode_message(SOSMessageRef message, uint64_t messageType, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) {
713 switch (messageType) {
714 case SOSManifestInvalidMessageType:
715 return der_encode_v2_message(message, error, der, der_end);
716 case SOSManifestDigestMessageType:
717 return der_encode_manifest_digest_message(message, error, der, der_end);
718 case SOSManifestMessageType:
719 return der_encode_manifest_message(message, error, der, der_end);
720 case SOSManifestDeltaAndObjectsMessageType:
721 return der_encode_manifest_and_objects_message(message, error, der, der_end);
722 }
723 return der_end;
724 }
725
726 // Encode an SOSMessage, calls addObject callback and appends returned objects
727 // one by one, until addObject returns NULL.
728 CFDataRef SOSMessageCreateData(SOSMessageRef message, uint64_t sequenceNumber, CFErrorRef *error) {
729 // Version 2 message have sequence numbers, version 0 messages do not.
730 uint64_t messageType = SOSManifestInvalidMessageType;
731 message->sequenceNumber = sequenceNumber;
732 if (message->version == 0) {
733 message->indefiniteLength = false;
734 messageType = SOSMessageInferType(message, error);
735 if (!messageType) {
736 // Propagate error
737 return NULL;
738 }
739 } else {
740 message->creationTime = floor(CFAbsoluteTimeGetCurrent());
741 }
742 size_t der_size = der_sizeof_message(message, messageType, error);
743 CFMutableDataRef data = CFDataCreateMutable(NULL, der_size);
744 if (data == NULL) {
745 // TODO Error.
746 return NULL;
747 }
748 CFDataSetLength(data, der_size);
749 uint8_t *der_end = CFDataGetMutableBytePtr(data);
750 const uint8_t *der = der_end;
751 der_end += der_size;
752
753 der_end = der_encode_message(message, messageType, error, der, der_end);
754 if (der != der_end) {
755 secwarning("internal error %td bytes unused in der buffer", der_end - der);
756 }
757 return data;
758 }
759
760 //
761 // MARK: SOSMessage decoding
762 //
763
764 #define CCBER_LEN_INDEFINITE ((size_t)-1)
765
766 // Decode BER length field. Sets *lenp to ccber_indefinite_len if this is an indefinite length encoded object.
767 // Behaves like ccder_decode_len in every other way.
768 static
769 const uint8_t *ccber_decode_len(size_t *_Nonnull lenp, const uint8_t *_Nullable der, const uint8_t *_Nonnull der_end) {
770 if (der && der < der_end) {
771 if (*der == 0x80) {
772 der++;
773 *lenp = CCBER_LEN_INDEFINITE;
774 }
775 else
776 der = ccder_decode_len(lenp, der, der_end);
777 }
778 return der;
779 }
780
781 static const uint8_t *der_decode_generalizedtime(CFAbsoluteTime *at, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
782 const uint8_t *times_end = NULL;
783 der = ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME, &times_end, der, der_end);
784 der = der_decode_generalizedtime_body(at, error, der, times_end);
785 if (times_end != der) {
786 secwarning("internal error %td bytes unused in generalizedtime DER buffer", times_end - der);
787 }
788 return der;
789 }
790
791 static const uint8_t *der_decode_optional_generalizedtime(CFAbsoluteTime *at, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
792 const uint8_t *times_end = der_decode_generalizedtime(at, error, der, der_end);
793 return times_end ? times_end : der;
794 }
795
796 static
797 const uint8_t *ccder_decode_implicit_uint64(ccder_tag expected_tag, uint64_t *_Nonnull r, const uint8_t *_Nullable der, const uint8_t *_Nonnull der_end) {
798 size_t len;
799 der = ccder_decode_tl(expected_tag, &len, der, der_end);
800 if (der && len && (*der & 0x80) != 0x80) {
801 if (ccn_read_uint(ccn_nof_size(sizeof(*r)), (cc_unit*)r, len, der) >= 0)
802 return der + len;
803 }
804 return NULL;
805 }
806
807 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) {
808 const uint8_t *ui64_end = ccder_decode_implicit_uint64(expected_tag, value, der, der_end);
809 return ui64_end ? ui64_end : der;
810 }
811
812
813 static const uint8_t *ccder_decode_optional_uint64(uint64_t *value, const uint8_t *der, const uint8_t *der_end) {
814 const uint8_t *ui64_end = ccder_decode_uint64(value, der, der_end);
815 return ui64_end ? ui64_end : der;
816 }
817
818 static const uint8_t *ccder_decode_digest_types(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) {
819 const uint8_t *dt_end;
820 der = ccder_decode_sequence_tl(&dt_end, der, der_end);
821 if (!der) return NULL;
822 // Skip over digestType body for now.
823 // TODO: Support DigestType
824 return dt_end;
825 }
826
827 static const uint8_t *ccder_decode_optional_digest_types(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) {
828 const uint8_t *dt_end = ccder_decode_digest_types(message, der, der_end);
829 return dt_end ? dt_end : der;
830 }
831
832 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) {
833 size_t len;
834 const uint8_t *body = ccder_decode_tl(CCDER_BIT_STRING, &len, der, der_end);
835 if (!body || len < 1)
836 return NULL;
837
838 if (r_bitlen) *r_bitlen = (len - 1) * 8 - (body[0] & 7);
839 ccn_read_uint(1, r, len - 1, body + 1);
840 return body + len;
841 }
842
843 static const uint8_t *der_decode_implicit_data(ccder_tag expected_tag, CFDataRef *data, const uint8_t *der, const uint8_t *der_end) {
844 size_t len = 0;
845 der = ccder_decode_tl(expected_tag, &len, der, der_end);
846 if (der && data) {
847 *data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, len, kCFAllocatorNull);
848 if (*data)
849 der += len;
850 else
851 der = NULL;
852 }
853 return der;
854 }
855
856 static const uint8_t *der_decode_optional_implicit_data(ccder_tag expected_tag, CFDataRef *data, const uint8_t *der, const uint8_t *der_end) {
857 const uint8_t *data_end = der_decode_implicit_data(expected_tag, data, der, der_end);
858 return data_end ? data_end : der;
859 }
860
861 static const uint8_t *der_decode_deltas_body(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
862 CFDataRef removals = NULL, additions = NULL;
863 der = der_decode_implicit_data(CCDER_OCTET_STRING, &removals, der, der_end);
864 der = der_decode_implicit_data(CCDER_OCTET_STRING, &additions, der, der_end);
865 if (der) {
866 message->removals = SOSManifestCreateWithData(removals, error);
867 message->additions = SOSManifestCreateWithData(additions, error);
868 if (!message->removals || !message->additions) {
869 CFReleaseNull(message->removals);
870 CFReleaseNull(message->additions);
871 der = NULL;
872 }
873 }
874 CFReleaseSafe(removals);
875 CFReleaseSafe(additions);
876
877 return der;
878 }
879
880 static const uint8_t *der_decode_deltas(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
881 const uint8_t *deltas_end = NULL;
882 der = ccder_decode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, &deltas_end, der, der_end);
883 return der_decode_deltas_body(message, error, der, deltas_end);
884 }
885
886 static const uint8_t *der_decode_optional_deltas(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) {
887 const uint8_t *seq_end = der_decode_deltas(message, NULL, der, der_end);
888 return seq_end ? seq_end : der;
889 }
890
891 static const uint8_t *der_decode_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
892 const uint8_t *extensions_end;
893 der = ccder_decode_constructed_tl(1 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, &extensions_end, der, der_end);
894 if (!der) return NULL;
895 // Skip over extensions for now.
896 return extensions_end;
897 }
898
899 static const uint8_t *der_decode_optional_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
900 const uint8_t *extensions_end = der_decode_extensions(message, NULL, der, der_end);
901 return extensions_end ? extensions_end : der;
902 }
903
904 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)) {
905 bool stop = false;
906 ccder_tag tag;
907 // Look ahead at the tag
908 while (!stop && ccder_decode_tag(&tag, der, der_end) && tag != CCDER_EOL) {
909 const uint8_t *object_end = NULL;
910 if (!ccder_decode_constructed_tl(tag, &object_end, der, der_end)) {
911 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("failed to decode object header"));
912 return NULL;
913 }
914 if (withObject) {
915 CFDataRef object = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, object_end - der, kCFAllocatorNull);
916 withObject(object, &stop);
917 CFReleaseSafe(object);
918 }
919 der = object_end;
920 }
921 if (length == CCBER_LEN_INDEFINITE) {
922 size_t len = 0;
923 der = ccder_decode_tl(CCDER_EOL, &len, der, der_end);
924 if (len != 0) {
925 secwarning("%td length ", der_end - der);
926 }
927 }
928 if (!stop && der != der_end)
929 secwarning("%td trailing bytes after objects DER", der_end - der);
930
931 return der;
932 }
933
934 static const uint8_t *der_decode_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
935 ccder_tag tag = 0;
936 size_t objects_len = 0;
937 der = ccder_decode_tag(&tag, der, der_end);
938 if (tag != (2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED)) return NULL;
939 der = ccber_decode_len(&objects_len, der, der_end);
940 if (objects_len != CCBER_LEN_INDEFINITE && der_end - der != (ptrdiff_t)objects_len) {
941 secwarning("%td trailing bytes after SOSMessage DER", (der_end - der) - (ptrdiff_t)objects_len);
942 }
943 // Remember a pointer into message->der where objects starts.
944 message->objectsDer = der;
945 message->objectsLen = objects_len;
946
947 return der + objects_len;
948 }
949
950 static const uint8_t *der_decode_optional_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
951 const uint8_t *seq_end = der_decode_objects(message, NULL, der, der_end);
952 return seq_end ? seq_end : der;
953 }
954
955 static const uint8_t *der_decode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
956 cc_unit flags[1] = {};
957 der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end);
958 message->version = 2;
959 der = ccder_decode_optional_implicit_uint64(0 | CCDER_CONTEXT_SPECIFIC, &message->version, der, der_end);
960 der = der_decode_optional_generalizedtime(&message->creationTime, error, der, der_end);
961 der = ccder_decode_optional_uint64(&message->sequenceNumber, der, der_end);
962 der = ccder_decode_optional_digest_types(message, der, der_end);
963 der = ccder_decode_bit_string(array_size(flags), NULL, flags, der, der_end);
964 message->flags = flags[0];
965
966 der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->senderDigest, der, der_end);
967 secinfo("engine", "der_decode_message_header: decoded sender digest as %@", message->senderDigest);
968
969 der = der_decode_optional_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, &message->baseDigest, der, der_end);
970 secinfo("engine", "der_decode_message_header: decoded base digest as %@", message->baseDigest);
971
972 der = der_decode_optional_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, &message->proposedDigest, der, der_end);
973 secinfo("engine", "der_decode_message_header: decoded proposed digest as %@", message->proposedDigest);
974
975 return der;
976 }
977
978 static const uint8_t *
979 der_decode_manifest_and_objects_message(SOSMessageRef message,
980 CFErrorRef *error, const uint8_t *der,
981 const uint8_t *der_end) {
982 size_t objects_len = 0;
983 const uint8_t *body_end;
984 der = ccder_decode_sequence_tl(&body_end, der, der_end);
985 if (body_end != der_end) {
986 SOSErrorCreate(kSOSErrorInvalidMessage, error, NULL, CFSTR("Trailing garbage at end of message"));
987 return NULL;
988 }
989 der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->baseDigest, der, body_end);
990 secinfo("engine", "der_decode_manifest_and_objects_message: decoded base digest as %@", message->baseDigest);
991
992 der = der_decode_deltas_body(message, error, der, body_end);
993 // Remember a pointer into message->der where objects starts.
994 der = message->objectsDer = ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &objects_len, der, body_end);
995 message->objectsLen = objects_len;
996
997 return der ? der + objects_len : NULL;
998 }
999
1000 static const uint8_t *der_decode_v0_message_body(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
1001 uint64_t messageType = 0;
1002 der = ccder_decode_uint64(&messageType, der, der_end);
1003 if (der) switch (messageType) {
1004 case SOSManifestDigestMessageType:
1005 {
1006 der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->senderDigest, der, der_end);
1007 secinfo("engine", "der_decode_v0_message_body: received a DigestMessage with sender digest: %@", message->senderDigest);
1008 break;
1009 }
1010 case SOSManifestMessageType:
1011 {
1012 CFDataRef manifestBody = NULL;
1013 der = der_decode_implicit_data(CCDER_OCTET_STRING, &manifestBody, der, der_end);
1014 if (!der) return NULL;
1015 if (der != der_end) {
1016 secwarning("%td trailing bytes after deltas DER", der_end - der);
1017 }
1018 message->additions = SOSManifestCreateWithData(manifestBody, error);
1019 secinfo("engine", "der_decode_v0_message_body: received a ManifestMessage with (%zu, %@)", SOSManifestGetCount(message->additions), SOSManifestGetDigest(message->additions, NULL));
1020 CFReleaseSafe(manifestBody);
1021 break;
1022 }
1023 case SOSManifestDeltaAndObjectsMessageType:
1024 {
1025 der = der_decode_manifest_and_objects_message(message, error, der, der_end);
1026 break;
1027 }
1028 default:
1029 SOSErrorCreate(kSOSErrorInvalidMessage, error, NULL, CFSTR("Invalid message type %llu"), messageType);
1030 break;
1031 }
1032 return der;
1033 }
1034
1035 static const uint8_t *der_decode_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) {
1036 ccder_tag tag = 0;
1037 size_t body_len = 0;
1038
1039 der = ccder_decode_tag(&tag, der, der_end);
1040 if (tag != CCDER_CONSTRUCTED_SEQUENCE) return NULL;
1041 der = ccber_decode_len(&body_len, der, der_end);
1042 if (der && body_len && body_len != CCBER_LEN_INDEFINITE && (der_end - der) != (ptrdiff_t)body_len) {
1043 secwarning("%td trailing bytes after SOSMessage DER", (der_end - der) - (ptrdiff_t)body_len);
1044 der_end = der + body_len;
1045 }
1046
1047 if (ccder_decode_tag(&tag, der, der_end)) switch (tag) {
1048 case CCDER_INTEGER: // v0
1049 if (body_len == CCBER_LEN_INDEFINITE)
1050 der = NULL; // Not supported for v0 messages
1051 else
1052 der = der_decode_v0_message_body(message, error, der, der_end);
1053 break;
1054 case CCDER_CONSTRUCTED_SEQUENCE: //v2
1055 der = der_decode_message_header(message, error, der, der_end);
1056 der = der_decode_optional_deltas(message, der, der_end);
1057 der = der_decode_optional_extensions(message, error, der, der_end);
1058 der = der_decode_optional_objects(message, error, der, der_end);
1059 break;
1060 }
1061 return der;
1062 }
1063
1064 // Decode a SOSMessage
1065 SOSMessageRef SOSMessageCreateWithData(CFAllocatorRef allocator, CFDataRef derData, CFErrorRef *error) {
1066 if (!derData)
1067 return (SOSMessageRef)SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("NULL data => no SOSMessage"));
1068 SOSMessageRef message = CFTypeAllocate(SOSMessage, struct __OpaqueSOSMessage, allocator);
1069 if (!message)
1070 return (SOSMessageRef)SOSErrorCreate(kSOSErrorAllocationFailure, error, NULL, CFSTR("failed to alloc SOSMessage"));
1071 message->der = CFRetainSafe(derData);
1072 const uint8_t *der = CFDataGetBytePtr(derData);
1073 const uint8_t *der_end = der + CFDataGetLength(derData);
1074 der = der_decode_message(message, error, der, der_end);
1075 if (!der_end || der != der_end) {
1076 if (error && !*error)
1077 SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("SOSMessage DER decoding failure %td bytes left"), der_end - der);
1078 return CFReleaseSafe(message);
1079 }
1080 return message;
1081 }
1082
1083 // Read values from a decoded messgage
1084
1085 CFDataRef SOSMessageGetBaseDigest(SOSMessageRef message) {
1086 return message->baseDigest;
1087 }
1088
1089 CFDataRef SOSMessageGetProposedDigest(SOSMessageRef message) {
1090 return message->proposedDigest;
1091 }
1092
1093 CFDataRef SOSMessageGetSenderDigest(SOSMessageRef message) {
1094 return message->senderDigest;
1095 }
1096
1097 SOSMessageFlags SOSMessageGetFlags(SOSMessageRef message) {
1098 return message->flags;
1099 }
1100
1101 uint64_t SOSMessageGetSequenceNumber(SOSMessageRef message) {
1102 return message->sequenceNumber;
1103 }
1104
1105 SOSManifestRef SOSMessageGetRemovals(SOSMessageRef message) {
1106 return message->removals;
1107 }
1108
1109 SOSManifestRef SOSMessageGetAdditions(SOSMessageRef message) {
1110 return message->additions;
1111 }
1112
1113 // Iterate though the extensions in a decoded SOSMessage. If criticalOnly is
1114 // true all non critical extensions are skipped.
1115 void SOSMessageWithExtensions(SOSMessageRef message, bool criticalOnly, void(^withExtension)(CFDataRef oid, bool isCritical, CFDataRef extension, bool *stop)) {
1116 // TODO
1117 }
1118
1119 size_t SOSMessageCountObjects(SOSMessageRef message) {
1120 if (message->objects)
1121 return CFArrayGetCount(message->objects);
1122 if (!message->objectsDer)
1123 return 0;
1124 const uint8_t *der = CFDataGetBytePtr(message->der);
1125 const uint8_t *der_end = der + CFDataGetLength(message->der);
1126 __block size_t count = 0;
1127 der_foreach_objects(message->objectsLen, message->objectsDer, der_end, NULL, ^(CFDataRef object, bool *stop){ ++count; });
1128 return count;
1129 }
1130
1131 // Iterate though the objects in a decoded SOSMessage.
1132 bool SOSMessageWithObjects(SOSMessageRef message, CFErrorRef *error,
1133 void(^withObject)(CFDataRef object, bool *stop)) {
1134 if (message->objects) {
1135 CFDataRef object;
1136 CFArrayForEachC(message->objects, object) {
1137 bool stop = false;
1138 withObject(object, &stop);
1139 if (stop)
1140 break;
1141 }
1142 return true;
1143 }
1144 if (!message->objectsDer)
1145 return true;
1146 const uint8_t *der = CFDataGetBytePtr(message->der);
1147 const uint8_t *der_end = der + CFDataGetLength(message->der);
1148 return der_foreach_objects(message->objectsLen, message->objectsDer, der_end, error, withObject);
1149 }
1150
1151 bool SOSMessageWithSOSObjects(SOSMessageRef message, SOSDataSourceRef dataSource, CFErrorRef *error,
1152 void(^withObject)(SOSObjectRef object, bool *stop)) {
1153 return SOSMessageWithObjects(message, error, ^(CFDataRef object, bool *stop) {
1154 CFDictionaryRef plist = NULL;
1155 const uint8_t *der = CFDataGetBytePtr(object);
1156 const uint8_t *der_end = der + CFDataGetLength(object);
1157 // TODO Remove intermediate plist format
1158 der = der_decode_dictionary(kCFAllocatorDefault, &plist, error, der, der_end);
1159 if (der) {
1160 SOSObjectRef peersObject = SOSObjectCreateWithPropertyList(dataSource, plist, error);
1161 withObject(peersObject, stop);
1162 CFReleaseSafe(peersObject);
1163 }
1164 CFReleaseSafe(plist);
1165 });
1166 }