2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * SOSMessage.c - Creation and decoding of SOSMessage objects.
29 #include <Security/SecureObjectSync/SOSMessage.h>
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>
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>
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>
53 #if defined(SOSMessageFormatSpecification) && 0
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
.
60 SOSMessage
:= SEQUENCE
{
62 v0 V0
-MESSAGE
-BODY
-CLASS
69 V0
-MESSAGE
-BODY
-CLASS ::= CLASS
71 &messageType
INTEGER (manifestDigest
, manifest
, manifestDeltaAndObjects
)
72 &version INTEGER OPTIONAL
default v0
75 WITH SYNTAX
{&Type IDENTIFIED BY
&messageType
}
77 ManifestDigest ::= OCTECT
STRING (length
20)
79 Manifest ::= OCTECT STRING
-- (length
20 * number of entries
)
81 manifestDigestBody ::=
82 { ManifestDigest IDENTIFIED BY
{manifestDigest
}}
85 { Manifest IDENTIFIED BY
{manifest
}}
87 manifestDeltaAndObjectsBody ::=
88 { ManifestDeltaAndObjects IDENTIFIED BY
{manifestDeltaAndObjects
}}
90 SOSV1MessageBody ::= MESSAGE
-BODY
-CLASS
92 ManifestDeltaAndObjects ::= SEQUENCE
{
93 manfestDigest ManifestDigest
96 addedObjects SEQUENCE OF SOSObject
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
-- }
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
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
127 messageFlags BIT STRING
{
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
-- }
147 SOSMessageVersion ::= INTEGER
{ v0(0), v2(2), v3(3) }
149 SOSSequenceNumber ::= INTEGER
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
159 digestAlgorithms SET OF AlgorithmIdentifier
160 -- Same as AlgorithmIdentifier from X
.509 -- } }
162 SOSManifestDeltas ::= SEQUENCE
{
164 additions SOSManifest
}
166 SOSExtensions ::= SEQUENCE
SIZE (1..MAX
) OF SOSExtension
168 SOSExtension ::= SEQUENCE
{
169 extnID OBJECT IDENTIFIER
,
170 critical BOOLEAN DEFAULT FALSE
,
171 extnValue OCTET STRING
}
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
179 SOSManifestDigest ::= OCTET STRING
181 SOSObject ::= SEQUENCE
{
182 [0] conflict OCTECT STRING OPTIONAL
183 [1] change OCTECT STRING OPTIONAL
184 object SecDictionary
}
186 SecDictionary ::= SET of SecKVPair
188 SecKVPair ::= SEQUENCE
{
192 SecValue ::= CHOICE
{
201 SecArray ::= SEQUENCE of SecValue
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
211 #endif // defined(SOSMessageFormatSpecification) && 0
215 static inline bool SecMallocOk(const void *ptr
) {
216 if (ptr
) return true;
222 static void appendObjects(CFMutableStringRef desc
, CFArrayRef objects
) {
223 __block
bool needComma
= false;
224 CFArrayForEach(objects
, ^(const void *value
) {
226 CFStringAppend(desc
, CFSTR(","));
230 SecItemServerAppendItemDescription(desc
, value
);
238 // MARK: SOSMessage implementation.
241 // Legacy v1 message type numbers
242 enum SOSMessageType
{
243 SOSManifestInvalidMessageType
= 0,
244 SOSManifestDigestMessageType
= 1,
245 SOSManifestMessageType
= 2,
246 SOSManifestDeltaAndObjectsMessageType
= 3,
249 struct __OpaqueSOSMessage
{
253 const uint8_t *objectsDer
;
256 CFDataRef senderDigest
;
257 CFDataRef baseDigest
;
258 CFDataRef proposedDigest
;
259 SOSManifestRef removals
;
260 SOSManifestRef additions
;
262 CFMutableArrayRef objects
;
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.
271 CFGiblisWithCompareFor(SOSMessage
)
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;
286 // TODO Compare Objects if present.
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
);
302 // TODO: Remove this layer violation!
303 #include <securityd/SecItemServer.h>
305 static uint64_t SOSMessageInferType(SOSMessageRef message
, CFErrorRef
*error
);
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
);
315 CFMutableStringRef objects
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
317 // TODO: Remove this layer violation!
318 SOSDataSourceFactoryRef dsf
= SecItemDataSourceFactoryGetDefault();
319 SOSDataSourceRef ds
= SOSDataSourceFactoryCreateDataSource(dsf
, kSecAttrAccessibleWhenUnlocked
, NULL
);
322 __block
size_t maxEntries
= 16;
323 CFStringAppendFormat(objects
, NULL
, CFSTR("{[%zu]"), SOSMessageCountObjects(message
));
324 SOSMessageWithSOSObjects(message
, ds
, NULL
, ^(SOSObjectRef object
, bool *stop
) {
325 CFDataRef digest
= SOSObjectCopyDigest(ds
, object
, NULL
);
326 const uint8_t *O
= CFDataGetBytePtr(digest
);
327 CFStringAppendFormat(objects
, NULL
, CFSTR(" %02X%02X%02X%02X"), O
[0],O
[1],O
[2],O
[3]);
328 CFReleaseSafe(digest
);
330 CFStringAppend(objects
, CFSTR("..."));
334 CFStringAppend(objects
, CFSTR("}"));
336 CFStringAppend(objects
, CFSTR("{NO DATASOURCE}"));
339 CFStringRef desc
= NULL
;
340 if (message
->version
== 0) {
341 switch (SOSMessageInferType(message
, NULL
)) {
342 case SOSManifestInvalidMessageType
:
343 desc
= CFStringCreateWithFormat(CFGetAllocator(message
), NULL
, CFSTR("<MSGInvalid %"PRIu64
" >"), message
->sequenceNumber
);
345 case SOSManifestDigestMessageType
:
346 desc
= CFStringCreateWithFormat(CFGetAllocator(message
), NULL
, CFSTR("<MSGDigest %"PRIu64
" %02X%02X%02X%02X>"), message
->sequenceNumber
, S
[0],S
[1],S
[2],S
[3]);
348 case SOSManifestMessageType
:
349 desc
= CFStringCreateWithFormat(CFGetAllocator(message
), NULL
, CFSTR("<MSGManifest %"PRIu64
" %@>"), message
->sequenceNumber
, message
->additions
);
351 case SOSManifestDeltaAndObjectsMessageType
:
352 desc
= CFStringCreateWithFormat(CFGetAllocator(message
), NULL
, CFSTR("<MSGObjects %"PRIu64
" %02X%02X%02X%02X %@ %@ %@"),
353 message
->sequenceNumber
,
355 message
->removals
, message
->additions
,
360 desc
= CFStringCreateWithFormat
361 (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>"),
362 message
->sequenceNumber
,
367 message
->removals
, message
->additions
,
369 (message
->flags
& kSOSMessageGetObjects
) ? "G" : "g",
370 (message
->flags
& kSOSMessageJoinRequest
) ? "J" : "j",
371 (message
->flags
& kSOSMessagePartial
) ? "P" : "p",
372 (message
->flags
& kSOSMessageDigestTypesProposed
) ? "D" : "d",
373 (message
->flags
& kSOSMessageClearGetObjects
) ? "K" : "k",
374 (message
->flags
& kSOSMessageDidClearGetObjectsSinceLastDelta
) ? "Z" : "z",
375 (message
->flags
& kSOSMessageSkipHello
) ? "H" : "h");
377 CFReleaseSafe(creationDate
);
378 CFReleaseSafe(objects
);
383 // MARK: SOSMessage encoding
386 // Create an SOSMessage ready to be encoded.
387 SOSMessageRef
SOSMessageCreate(CFAllocatorRef allocator
, uint64_t version
, CFErrorRef
*error
) {
388 SOSMessageRef message
= CFTypeAllocate(SOSMessage
, struct __OpaqueSOSMessage
, allocator
);
389 message
->version
= version
;
393 // TODO: Remove me this is for testing only, tests should use the real thing.
394 SOSMessageRef
SOSMessageCreateWithManifests(CFAllocatorRef allocator
, SOSManifestRef sender
,
395 SOSManifestRef base
, SOSManifestRef proposed
,
396 bool includeManifestDeltas
, CFErrorRef
*error
) {
397 SOSMessageRef message
= SOSMessageCreate(allocator
, kEngineMessageProtocolVersion
, error
);
398 if (!SOSMessageSetManifests(message
, sender
, base
, proposed
, includeManifestDeltas
, NULL
, error
))
399 CFReleaseNull(message
);
403 bool SOSMessageSetManifests(SOSMessageRef message
, SOSManifestRef sender
,
404 SOSManifestRef base
, SOSManifestRef proposed
,
405 bool includeManifestDeltas
, SOSManifestRef objectsSent
,
407 if (!message
) return true;
409 // TODO: Check at v2 encoding time
410 // if (!sender) return (SOSMessageRef)SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("no sender manifest specified for SOSMessage"));
411 message
->baseDigest
= CFRetainSafe(SOSManifestGetDigest(base
, NULL
));
412 secinfo("engine", "SOSMessageSetManifests: setting base digest to %@ %zu", message
->baseDigest
, SOSManifestGetCount(base
));
413 message
->proposedDigest
= CFRetainSafe(SOSManifestGetDigest(proposed
, NULL
));
414 secinfo("engine", "SOSMessageSetManifests: setting proposed digest to %@ %zu", message
->proposedDigest
, SOSManifestGetCount(proposed
));
415 message
->senderDigest
= CFRetainSafe(SOSManifestGetDigest(sender
, NULL
));
416 secinfo("engine", "SOSMessageSetManifests: setting sender digest to %@ %zu", message
->senderDigest
, SOSManifestGetCount(sender
));
418 if (includeManifestDeltas
) {
419 SOSManifestRef additions
= NULL
;
420 ok
= SOSManifestDiff(base
, proposed
, &message
->removals
, &additions
, error
);
421 if (message
->version
== 0) {
422 message
->additions
= additions
;
424 message
->additions
= SOSManifestCreateComplement(objectsSent
, additions
, error
);
425 CFReleaseSafe(additions
);
431 void SOSMessageSetFlags(SOSMessageRef message
, SOSMessageFlags flags
) {
432 message
->flags
= flags
;
435 // Add an extension to this message
436 void SOSMessageAddExtension(SOSMessageRef message
, CFDataRef oid
, bool isCritical
, CFDataRef extension
) {
438 secerror("not implemented yet!");
441 static bool SecMessageIsObjectValid(CFDataRef object
, CFErrorRef
*error
) {
442 const uint8_t *der
= CFDataGetBytePtr(object
);
443 const uint8_t *der_end
= der
+ CFDataGetLength(object
);
446 der
= ccder_decode_tag(&tag
, der
, der_end
);
448 return SOSErrorCreate(kSOSErrorBadFormat
, error
, NULL
, CFSTR("Invalid DER, no tag found"));
449 if (tag
== CCDER_EOL
)
450 return SOSErrorCreate(kSOSErrorBadFormat
, error
, NULL
, CFSTR("Object has EOL tag"));
451 der
= ccder_decode_len(&len
, der
, der_end
);
453 return SOSErrorCreate(kSOSErrorBadFormat
, error
, NULL
, CFSTR("Object with tag %lu has no valid DER length"), tag
);
456 return SOSErrorCreate(kSOSErrorBadFormat
, error
, NULL
, CFSTR("Object has %td trailing unused bytes"), der_end
- der
);
460 bool SOSMessageAppendObject(SOSMessageRef message
, CFDataRef object
, CFErrorRef
*error
) {
461 if (!SecMessageIsObjectValid(object
, error
)) return false;
462 if (!message
->objects
)
463 message
->objects
= CFArrayCreateMutableForCFTypes(CFGetAllocator(message
));
464 if (message
->objects
)
465 CFArrayAppendValue(message
->objects
, object
);
469 static CC_NONNULL_ALL
470 size_t ccder_sizeof_bit_string(cc_size n
, const cc_unit
*s
) {
471 return ccder_sizeof(CCDER_BIT_STRING
, ccn_sizeof(ccn_bitlen(n
, s
)) + 1);
474 static CC_NONNULL_ALL
475 uint8_t *ccder_encode_bit_string(cc_size n
, const cc_unit
*s
, const uint8_t *der
, uint8_t *der_end
) {
476 size_t bits
= ccn_bitlen(n
, s
);
477 size_t out_size
= ccn_sizeof(bits
) + 1;
478 der_end
= ccder_encode_body_nocopy(out_size
, der
, der_end
);
480 ccn_write_uint_padded(n
, s
, out_size
, der_end
);
481 return ccder_encode_tl(CCDER_BIT_STRING
, out_size
, der
, der_end
);
486 size_t der_sizeof_implicit_data(ccder_tag tag
, CFDataRef data
) {
489 return ccder_sizeof_implicit_raw_octet_string(tag
, CFDataGetLength(data
));
493 static CC_NONNULL((3, 4))
494 uint8_t *der_encode_implicit_data(ccder_tag tag
, CFDataRef data
, const uint8_t *der
, uint8_t *der_end
) {
497 return ccder_encode_implicit_raw_octet_string(tag
, CFDataGetLength(data
), CFDataGetBytePtr(data
), der
, der_end
);
500 static size_t der_sizeof_message_header(SOSMessageRef message
, CFErrorRef
*error
) {
501 if (!message
->senderDigest
) {
502 // TODO: Create Error.
506 flags
[0] = (cc_unit
)message
->flags
; // TODO Fix cast or something
508 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
509 der_sizeof_generalizedtime(message
->creationTime
, error
) +
510 ccder_sizeof_uint64(message
->sequenceNumber
) +
511 ccder_sizeof_bit_string(array_size(flags
), flags
) +
512 der_sizeof_implicit_data(CCDER_OCTET_STRING
, message
->senderDigest
) +
513 der_sizeof_implicit_data(0 | CCDER_CONTEXT_SPECIFIC
, message
->baseDigest
) +
514 der_sizeof_implicit_data(1 | CCDER_CONTEXT_SPECIFIC
, message
->proposedDigest
));
517 static uint8_t *der_encode_message_header(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
518 if (!message
->senderDigest
) {
519 // TODO: Create Error.
523 flags
[0] = (cc_unit
)message
->flags
; // TODO Fix cast or something
524 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
525 der_encode_generalizedtime(message
->creationTime
, error
, der
,
526 ccder_encode_uint64(message
->sequenceNumber
, der
,
527 ccder_encode_bit_string(array_size(flags
), flags
, der
,
528 der_encode_implicit_data(CCDER_OCTET_STRING
, message
->senderDigest
, der
,
529 der_encode_implicit_data(0 | CCDER_CONTEXT_SPECIFIC
, message
->baseDigest
, der
,
530 der_encode_implicit_data(1 | CCDER_CONTEXT_SPECIFIC
, message
->proposedDigest
, der
, der_end
)))))));
533 static size_t der_sizeof_deltas(SOSMessageRef message
) {
534 if (!message
->additions
&& !message
->removals
) return 0;
535 if (message
->version
== 0) {
536 return ccder_sizeof(CCDER_OCTET_STRING
, SOSManifestGetSize(message
->removals
))+
537 ccder_sizeof(CCDER_OCTET_STRING
, SOSManifestGetSize(message
->additions
));
539 return ccder_sizeof(0 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
,
540 ccder_sizeof(CCDER_OCTET_STRING
, SOSManifestGetSize(message
->removals
))+
541 ccder_sizeof(CCDER_OCTET_STRING
, SOSManifestGetSize(message
->additions
)));
545 static uint8_t *der_encode_deltas(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
546 if (!message
->additions
&& !message
->removals
) return der_end
;
547 if (message
->version
== 0) {
548 return der_encode_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->removals
), der
,
549 der_encode_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->additions
), der
, der_end
));
551 return ccder_encode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
, der_end
, der
,
552 der_encode_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->removals
), der
,
553 der_encode_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->additions
), der
, der_end
)));
557 static size_t der_sizeof_extensions(SOSMessageRef message
) {
558 // We don't support any yet.
562 static uint8_t *der_encode_extensions(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
563 // We don't support any yet.
567 static size_t der_sizeof_objects(SOSMessageRef message
) {
569 if (message
->objects
) {
571 CFArrayForEachC(message
->objects
, data
) {
572 len
+= (size_t)CFDataGetLength(data
);
574 } else if (message
->version
!= 0)
577 if (message
->indefiniteLength
)
580 return ccder_sizeof(2 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
, len
);
583 static uint8_t *der_encode_objects(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
584 if (!message
->objects
&& message
->version
!= 0) return der_end
;
585 const uint8_t *original_der_end
= der_end
;
586 if (message
->indefiniteLength
)
587 der_end
= ccder_encode_tl(CCDER_EOL
, 0, der
, der_end
);
589 for (CFIndex position
= (message
->objects
? CFArrayGetCount(message
->objects
) : 0) - 1; position
>= 0; --position
) {
590 CFDataRef object
= CFArrayGetValueAtIndex(message
->objects
, position
);
591 der_end
= ccder_encode_body(CFDataGetLength(object
), CFDataGetBytePtr(object
), der
, der_end
);
593 if (message
->indefiniteLength
) {
594 return ccder_encode_tag(2 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
, der
,
595 ccder_encode_len(0, der
, der_end
));
597 ccder_tag otag
= message
->version
== 0 ? CCDER_CONSTRUCTED_SEQUENCE
: 2 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
;
598 return ccder_encode_constructed_tl(otag
, original_der_end
, der
, der_end
);
602 static size_t der_sizeof_v2_message(SOSMessageRef message
, CFErrorRef
*error
) {
603 size_t body_size
= (der_sizeof_message_header(message
, error
) +
604 der_sizeof_deltas(message
) +
605 der_sizeof_extensions(message
) +
606 der_sizeof_objects(message
));
607 if (message
->indefiniteLength
)
608 return body_size
+ 4;
610 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, body_size
);
614 static uint8_t *der_encode_v2_message(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
615 const uint8_t *original_der_end
= der_end
;
616 if (message
->indefiniteLength
)
617 der_end
= ccder_encode_tl(CCDER_EOL
, 0, der
, der_end
);
619 der_end
= der_encode_message_header(message
, error
, der
,
620 der_encode_deltas(message
, error
, der
,
621 der_encode_extensions(message
, error
, der
,
622 der_encode_objects(message
, error
, der
, der_end
))));
624 if (message
->indefiniteLength
) {
625 return ccder_encode_tag(CCDER_CONSTRUCTED_SEQUENCE
, der
,
626 ccder_encode_len(0, der
, der_end
));
628 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, original_der_end
, der
, der_end
);
632 //------------------------------------------------------------------------------------------------------------------------------------
634 //------------------------------------------------------------------------------------------------------------------------------------
636 /* ManifestDigest message */
637 static size_t der_sizeof_manifest_digest_message(SOSMessageRef message
, CFErrorRef
*error
) {
638 if (!message
->senderDigest
|| CFDataGetLength(message
->senderDigest
) != SOSDigestSize
) {
639 SOSErrorCreate(kSOSErrorProcessingFailure
, error
, NULL
, CFSTR("digest length mismatch"));
642 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
643 (ccder_sizeof_uint64(SOSManifestDigestMessageType
) +
644 ccder_sizeof_raw_octet_string(SOSDigestSize
)));
647 static uint8_t *der_encode_manifest_digest_message(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
648 secinfo("engine", "der_encode_manifest_digest_message: encoded sender digest as %@", message
->senderDigest
);
649 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
650 ccder_encode_uint64(SOSManifestDigestMessageType
, der
,
651 ccder_encode_raw_octet_string(SOSDigestSize
, CFDataGetBytePtr(message
->senderDigest
), der
, der_end
)));
654 /* Manifest message */
655 static size_t der_sizeof_manifest_message(SOSMessageRef message
, CFErrorRef
*error
) {
656 if (!message
->additions
) {
657 SOSErrorCreate(kSOSErrorProcessingFailure
, error
, NULL
, CFSTR("no manifest for manifest message"));
660 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
661 (ccder_sizeof_uint64(SOSManifestMessageType
) +
662 der_sizeof_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->additions
))));
665 static uint8_t *der_encode_manifest_message(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
666 secinfo("engine", "der_encode_manifest_message: encoded message additions as (%zu, %@)", SOSManifestGetCount(message
->additions
), SOSManifestGetDigest(message
->additions
, NULL
));
667 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
668 ccder_encode_uint64(SOSManifestMessageType
, der
,
669 der_encode_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->additions
), der
, der_end
)));
672 /* ManifestDeltaAndObjects message */
673 static size_t der_sizeof_manifest_and_objects_message(SOSMessageRef message
, CFErrorRef
*error
) {
674 if (!message
->baseDigest
|| CFDataGetLength(message
->baseDigest
) != SOSDigestSize
) {
675 SOSErrorCreate(kSOSErrorProcessingFailure
, error
, NULL
, CFSTR("digest length mismatch"));
679 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
680 (ccder_sizeof_uint64(SOSManifestDeltaAndObjectsMessageType
) +
681 ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
682 (ccder_sizeof_raw_octet_string(SOSDigestSize
) +
683 der_sizeof_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->removals
)) +
684 der_sizeof_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->additions
)) +
685 der_sizeof_objects(message
)))));
688 static uint8_t *der_encode_manifest_and_objects_message(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
689 secinfo("engine", "der_encode_manifest_and_objects_message: encoded base digest as %@", message
->baseDigest
);
690 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
691 ccder_encode_uint64(SOSManifestDeltaAndObjectsMessageType
, der
,
692 ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
693 ccder_encode_raw_octet_string(SOSDigestSize
, CFDataGetBytePtr(message
->baseDigest
), der
,
694 der_encode_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->removals
), der
,
695 der_encode_implicit_data(CCDER_OCTET_STRING
, SOSManifestGetData(message
->additions
), der
,
696 der_encode_objects(message
, error
, der
, der_end
)))))));
699 static uint64_t SOSMessageInferType(SOSMessageRef message
, CFErrorRef
*error
) {
700 if (message
->baseDigest
) {
701 // TODO: Assert that we don't have senderDigest or proposedDigest
702 if (SOSManifestGetCount(message
->removals
) || SOSManifestGetCount(message
->additions
) || SOSMessageCountObjects(message
)) {
703 return SOSManifestDeltaAndObjectsMessageType
;
705 // NOTE: If we force a SOSManifestDeltaAndObjectsMessageType instead then
706 // true v0 peers will overwrite their last objects message to us. However this
707 // implements the current v0 behaviour
708 return SOSManifestDigestMessageType
;
710 } else if (message
->additions
) {
711 // TODO: Assert that we don't have senderDigest, proposedDigest, additions, removals or objects
712 return SOSManifestMessageType
;
713 } else if (message
->senderDigest
) {
714 // TODO: Assert that we don't have proposedDigest, removals or objects
715 return SOSManifestDigestMessageType
;
717 // TODO: Create error.
718 return SOSManifestInvalidMessageType
;
721 static size_t der_sizeof_message(SOSMessageRef message
, uint64_t messageType
, CFErrorRef
*error
) {
722 switch (messageType
) {
723 case SOSManifestInvalidMessageType
:
724 return der_sizeof_v2_message(message
, error
);
725 case SOSManifestDigestMessageType
:
726 return der_sizeof_manifest_digest_message(message
, error
);
727 case SOSManifestMessageType
:
728 return der_sizeof_manifest_message(message
, error
);
729 case SOSManifestDeltaAndObjectsMessageType
:
730 return der_sizeof_manifest_and_objects_message(message
, error
);
735 static uint8_t *der_encode_message(SOSMessageRef message
, uint64_t messageType
, CFErrorRef
*error
, const uint8_t *der
, uint8_t *der_end
) {
736 switch (messageType
) {
737 case SOSManifestInvalidMessageType
:
738 return der_encode_v2_message(message
, error
, der
, der_end
);
739 case SOSManifestDigestMessageType
:
740 return der_encode_manifest_digest_message(message
, error
, der
, der_end
);
741 case SOSManifestMessageType
:
742 return der_encode_manifest_message(message
, error
, der
, der_end
);
743 case SOSManifestDeltaAndObjectsMessageType
:
744 return der_encode_manifest_and_objects_message(message
, error
, der
, der_end
);
749 // Encode an SOSMessage, calls addObject callback and appends returned objects
750 // one by one, until addObject returns NULL.
751 CFDataRef
SOSMessageCreateData(SOSMessageRef message
, uint64_t sequenceNumber
, CFErrorRef
*error
) {
752 // Version 2 message have sequence numbers, version 0 messages do not.
753 uint64_t messageType
= SOSManifestInvalidMessageType
;
754 message
->sequenceNumber
= sequenceNumber
;
755 if (message
->version
== 0) {
756 message
->indefiniteLength
= false;
757 messageType
= SOSMessageInferType(message
, error
);
763 message
->creationTime
= floor(CFAbsoluteTimeGetCurrent());
765 size_t der_size
= der_sizeof_message(message
, messageType
, error
);
766 CFMutableDataRef data
= CFDataCreateMutable(NULL
, der_size
);
771 CFDataSetLength(data
, der_size
);
772 uint8_t *der_end
= CFDataGetMutableBytePtr(data
);
773 const uint8_t *der
= der_end
;
776 der_end
= der_encode_message(message
, messageType
, error
, der
, der_end
);
777 if (der
!= der_end
) {
778 secwarning("internal error %td bytes unused in der buffer", der_end
- der
);
784 // MARK: SOSMessage decoding
787 #define CCBER_LEN_INDEFINITE ((size_t)-1)
789 // Decode BER length field. Sets *lenp to ccber_indefinite_len if this is an indefinite length encoded object.
790 // Behaves like ccder_decode_len in every other way.
791 static CC_NONNULL((1, 3))
792 const uint8_t *ccber_decode_len(size_t *lenp
, const uint8_t *der
, const uint8_t *der_end
) {
793 if (der
&& der
< der_end
) {
796 *lenp
= CCBER_LEN_INDEFINITE
;
799 der
= ccder_decode_len(lenp
, der
, der_end
);
804 static const uint8_t *der_decode_generalizedtime(CFAbsoluteTime
*at
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
805 const uint8_t *times_end
= NULL
;
806 der
= ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME
, ×_end
, der
, der_end
);
807 der
= der_decode_generalizedtime_body(at
, error
, der
, times_end
);
808 if (times_end
!= der
) {
809 secwarning("internal error %td bytes unused in generalizedtime DER buffer", times_end
- der
);
814 static const uint8_t *der_decode_optional_generalizedtime(CFAbsoluteTime
*at
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
815 const uint8_t *times_end
= der_decode_generalizedtime(at
, error
, der
, der_end
);
816 return times_end
? times_end
: der
;
819 static CC_NONNULL((2, 4))
820 const uint8_t *ccder_decode_implicit_uint64(ccder_tag expected_tag
, uint64_t* r
, const uint8_t *der
, const uint8_t *der_end
) {
822 der
= ccder_decode_tl(expected_tag
, &len
, der
, der_end
);
823 if (der
&& len
&& (*der
& 0x80) != 0x80) {
824 if (ccn_read_uint(ccn_nof_size(sizeof(*r
)), (cc_unit
*)r
, len
, der
) >= 0)
830 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
) {
831 const uint8_t *ui64_end
= ccder_decode_implicit_uint64(expected_tag
, value
, der
, der_end
);
832 return ui64_end
? ui64_end
: der
;
836 static const uint8_t *ccder_decode_optional_uint64(uint64_t *value
, const uint8_t *der
, const uint8_t *der_end
) {
837 const uint8_t *ui64_end
= ccder_decode_uint64(value
, der
, der_end
);
838 return ui64_end
? ui64_end
: der
;
841 static const uint8_t *ccder_decode_digest_types(SOSMessageRef message
, const uint8_t *der
, const uint8_t *der_end
) {
842 const uint8_t *dt_end
;
843 der
= ccder_decode_sequence_tl(&dt_end
, der
, der_end
);
844 if (!der
) return NULL
;
845 // Skip over digestType body for now.
846 // TODO: Support DigestType
850 static const uint8_t *ccder_decode_optional_digest_types(SOSMessageRef message
, const uint8_t *der
, const uint8_t *der_end
) {
851 const uint8_t *dt_end
= ccder_decode_digest_types(message
, der
, der_end
);
852 return dt_end
? dt_end
: der
;
855 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
) {
857 const uint8_t *body
= ccder_decode_tl(CCDER_BIT_STRING
, &len
, der
, der_end
);
858 if (!body
|| len
< 1)
861 if (r_bitlen
) *r_bitlen
= (len
- 1) * 8 - (body
[0] & 7);
862 ccn_read_uint(1, r
, len
- 1, body
+ 1);
866 static const uint8_t *der_decode_implicit_data(ccder_tag expected_tag
, CFDataRef
*data
, const uint8_t *der
, const uint8_t *der_end
) {
868 der
= ccder_decode_tl(expected_tag
, &len
, der
, der_end
);
870 *data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, der
, len
, kCFAllocatorNull
);
879 static const uint8_t *der_decode_optional_implicit_data(ccder_tag expected_tag
, CFDataRef
*data
, const uint8_t *der
, const uint8_t *der_end
) {
880 const uint8_t *data_end
= der_decode_implicit_data(expected_tag
, data
, der
, der_end
);
881 return data_end
? data_end
: der
;
884 static const uint8_t *der_decode_deltas_body(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
885 CFDataRef removals
= NULL
, additions
= NULL
;
886 der
= der_decode_implicit_data(CCDER_OCTET_STRING
, &removals
, der
, der_end
);
887 der
= der_decode_implicit_data(CCDER_OCTET_STRING
, &additions
, der
, der_end
);
889 message
->removals
= SOSManifestCreateWithData(removals
, error
);
890 message
->additions
= SOSManifestCreateWithData(additions
, error
);
891 if (!message
->removals
|| !message
->additions
) {
892 CFReleaseNull(message
->removals
);
893 CFReleaseNull(message
->additions
);
897 CFReleaseSafe(removals
);
898 CFReleaseSafe(additions
);
903 static const uint8_t *der_decode_deltas(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
904 const uint8_t *deltas_end
= NULL
;
905 der
= ccder_decode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
, &deltas_end
, der
, der_end
);
906 return der_decode_deltas_body(message
, error
, der
, deltas_end
);
909 static const uint8_t *der_decode_optional_deltas(SOSMessageRef message
, const uint8_t *der
, const uint8_t *der_end
) {
910 const uint8_t *seq_end
= der_decode_deltas(message
, NULL
, der
, der_end
);
911 return seq_end
? seq_end
: der
;
914 static const uint8_t *der_decode_extensions(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
915 const uint8_t *extensions_end
;
916 der
= ccder_decode_constructed_tl(1 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
, &extensions_end
, der
, der_end
);
917 if (!der
) return NULL
;
918 // Skip over extensions for now.
919 return extensions_end
;
922 static const uint8_t *der_decode_optional_extensions(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
923 const uint8_t *extensions_end
= der_decode_extensions(message
, NULL
, der
, der_end
);
924 return extensions_end
? extensions_end
: der
;
927 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
)) {
930 // Look ahead at the tag
931 while (!stop
&& ccder_decode_tag(&tag
, der
, der_end
) && tag
!= CCDER_EOL
) {
932 const uint8_t *object_end
= NULL
;
933 if (!ccder_decode_constructed_tl(tag
, &object_end
, der
, der_end
)) {
934 SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("failed to decode object header"));
938 CFDataRef object
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, der
, object_end
- der
, kCFAllocatorNull
);
939 withObject(object
, &stop
);
940 CFReleaseSafe(object
);
944 if (length
== CCBER_LEN_INDEFINITE
) {
946 der
= ccder_decode_tl(CCDER_EOL
, &len
, der
, der_end
);
948 secwarning("%td length ", der_end
- der
);
951 if (!stop
&& der
!= der_end
)
952 secwarning("%td trailing bytes after objects DER", der_end
- der
);
957 static const uint8_t *der_decode_objects(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
959 size_t objects_len
= 0;
960 der
= ccder_decode_tag(&tag
, der
, der_end
);
961 if (tag
!= (2 | CCDER_CONTEXT_SPECIFIC
| CCDER_CONSTRUCTED
)) return NULL
;
962 der
= ccber_decode_len(&objects_len
, der
, der_end
);
963 if (objects_len
!= CCBER_LEN_INDEFINITE
&& der_end
- der
!= (ptrdiff_t)objects_len
) {
964 secwarning("%td trailing bytes after SOSMessage DER", (der_end
- der
) - (ptrdiff_t)objects_len
);
966 // Remember a pointer into message->der where objects starts.
967 message
->objectsDer
= der
;
968 message
->objectsLen
= objects_len
;
970 return der
+ objects_len
;
973 static const uint8_t *der_decode_optional_objects(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
974 const uint8_t *seq_end
= der_decode_objects(message
, NULL
, der
, der_end
);
975 return seq_end
? seq_end
: der
;
979 // Move to ccder and possibly refactor ccder_decode_constructed_tl to call this.
980 #ifdef CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER
981 CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER
983 inline CC_NONNULL((1, 3))
985 ccder_decode_constructed_len(const uint8_t **body_end
,
986 const uint8_t *der
, const uint8_t *der_end
) {
988 der
= ccder_decode_len(&len
, der
, der_end
);
989 *body_end
= der
+ len
;
994 static const uint8_t *der_decode_message_header(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
995 cc_unit flags
[1] = {};
996 der
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &der_end
, der
, der_end
);
997 message
->version
= 2;
998 der
= ccder_decode_optional_implicit_uint64(0 | CCDER_CONTEXT_SPECIFIC
, &message
->version
, der
, der_end
);
999 der
= der_decode_optional_generalizedtime(&message
->creationTime
, error
, der
, der_end
);
1000 der
= ccder_decode_optional_uint64(&message
->sequenceNumber
, der
, der_end
);
1001 der
= ccder_decode_optional_digest_types(message
, der
, der_end
);
1002 der
= ccder_decode_bit_string(array_size(flags
), NULL
, flags
, der
, der_end
);
1003 message
->flags
= flags
[0];
1005 der
= der_decode_implicit_data(CCDER_OCTET_STRING
, &message
->senderDigest
, der
, der_end
);
1006 secinfo("engine", "der_decode_message_header: decoded sender digest as %@", message
->senderDigest
);
1008 der
= der_decode_optional_implicit_data(0 | CCDER_CONTEXT_SPECIFIC
, &message
->baseDigest
, der
, der_end
);
1009 secinfo("engine", "der_decode_message_header: decoded base digest as %@", message
->baseDigest
);
1011 der
= der_decode_optional_implicit_data(1 | CCDER_CONTEXT_SPECIFIC
, &message
->proposedDigest
, der
, der_end
);
1012 secinfo("engine", "der_decode_message_header: decoded proposed digest as %@", message
->proposedDigest
);
1017 static const uint8_t *
1018 der_decode_manifest_and_objects_message(SOSMessageRef message
,
1019 CFErrorRef
*error
, const uint8_t *der
,
1020 const uint8_t *der_end
) {
1021 size_t objects_len
= 0;
1022 const uint8_t *body_end
;
1023 der
= ccder_decode_sequence_tl(&body_end
, der
, der_end
);
1024 if (body_end
!= der_end
) {
1025 SOSErrorCreate(kSOSErrorInvalidMessage
, error
, NULL
, CFSTR("Trailing garbage at end of message"));
1028 der
= der_decode_implicit_data(CCDER_OCTET_STRING
, &message
->baseDigest
, der
, body_end
);
1029 secinfo("engine", "der_decode_manifest_and_objects_message: decoded base digest as %@", message
->baseDigest
);
1031 der
= der_decode_deltas_body(message
, error
, der
, body_end
);
1032 // Remember a pointer into message->der where objects starts.
1033 der
= message
->objectsDer
= ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE
, &objects_len
, der
, body_end
);
1034 message
->objectsLen
= objects_len
;
1036 return der
? der
+ objects_len
: NULL
;
1039 static const uint8_t *der_decode_v0_message_body(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
1040 uint64_t messageType
= 0;
1041 der
= ccder_decode_uint64(&messageType
, der
, der_end
);
1042 if (der
) switch (messageType
) {
1043 case SOSManifestDigestMessageType
:
1045 der
= der_decode_implicit_data(CCDER_OCTET_STRING
, &message
->senderDigest
, der
, der_end
);
1046 secinfo("engine", "der_decode_v0_message_body: received a DigestMessage with sender digest: %@", message
->senderDigest
);
1049 case SOSManifestMessageType
:
1051 CFDataRef manifestBody
= NULL
;
1052 der
= der_decode_implicit_data(CCDER_OCTET_STRING
, &manifestBody
, der
, der_end
);
1053 if (!der
) return NULL
;
1054 if (der
!= der_end
) {
1055 secwarning("%td trailing bytes after deltas DER", der_end
- der
);
1057 message
->additions
= SOSManifestCreateWithData(manifestBody
, error
);
1058 secinfo("engine", "der_decode_v0_message_body: received a ManifestMessage with (%zu, %@)", SOSManifestGetCount(message
->additions
), SOSManifestGetDigest(message
->additions
, NULL
));
1059 CFReleaseSafe(manifestBody
);
1062 case SOSManifestDeltaAndObjectsMessageType
:
1064 der
= der_decode_manifest_and_objects_message(message
, error
, der
, der_end
);
1068 SOSErrorCreate(kSOSErrorInvalidMessage
, error
, NULL
, CFSTR("Invalid message type %llu"), messageType
);
1074 static const uint8_t *der_decode_message(SOSMessageRef message
, CFErrorRef
*error
, const uint8_t *der
, const uint8_t *der_end
) {
1076 size_t body_len
= 0;
1078 der
= ccder_decode_tag(&tag
, der
, der_end
);
1079 if (tag
!= CCDER_CONSTRUCTED_SEQUENCE
) return NULL
;
1080 der
= ccber_decode_len(&body_len
, der
, der_end
);
1081 if (der
&& body_len
&& body_len
!= CCBER_LEN_INDEFINITE
&& (der_end
- der
) != (ptrdiff_t)body_len
) {
1082 secwarning("%td trailing bytes after SOSMessage DER", (der_end
- der
) - (ptrdiff_t)body_len
);
1083 der_end
= der
+ body_len
;
1086 if (ccder_decode_tag(&tag
, der
, der_end
)) switch (tag
) {
1087 case CCDER_INTEGER
: // v0
1088 if (body_len
== CCBER_LEN_INDEFINITE
)
1089 der
= NULL
; // Not supported for v0 messages
1091 der
= der_decode_v0_message_body(message
, error
, der
, der_end
);
1093 case CCDER_CONSTRUCTED_SEQUENCE
: //v2
1094 der
= der_decode_message_header(message
, error
, der
, der_end
);
1095 der
= der_decode_optional_deltas(message
, der
, der_end
);
1096 der
= der_decode_optional_extensions(message
, error
, der
, der_end
);
1097 der
= der_decode_optional_objects(message
, error
, der
, der_end
);
1103 // Decode a SOSMessage
1104 SOSMessageRef
SOSMessageCreateWithData(CFAllocatorRef allocator
, CFDataRef derData
, CFErrorRef
*error
) {
1106 return (SOSMessageRef
)SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("NULL data => no SOSMessage"));
1107 SOSMessageRef message
= CFTypeAllocate(SOSMessage
, struct __OpaqueSOSMessage
, allocator
);
1109 return (SOSMessageRef
)SOSErrorCreate(kSOSErrorAllocationFailure
, error
, NULL
, CFSTR("failed to alloc SOSMessage"));
1110 message
->der
= CFRetainSafe(derData
);
1111 const uint8_t *der
= CFDataGetBytePtr(derData
);
1112 const uint8_t *der_end
= der
+ CFDataGetLength(derData
);
1113 der
= der_decode_message(message
, error
, der
, der_end
);
1114 if (!der_end
|| der
!= der_end
) {
1115 if (error
&& !*error
)
1116 SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("SOSMessage DER decoding failure %td bytes left"), der_end
- der
);
1117 return CFReleaseSafe(message
);
1122 // Read values from a decoded messgage
1124 CFDataRef
SOSMessageGetBaseDigest(SOSMessageRef message
) {
1125 return message
->baseDigest
;
1128 CFDataRef
SOSMessageGetProposedDigest(SOSMessageRef message
) {
1129 return message
->proposedDigest
;
1132 CFDataRef
SOSMessageGetSenderDigest(SOSMessageRef message
) {
1133 return message
->senderDigest
;
1136 SOSMessageFlags
SOSMessageGetFlags(SOSMessageRef message
) {
1137 return message
->flags
;
1140 uint64_t SOSMessageGetSequenceNumber(SOSMessageRef message
) {
1141 return message
->sequenceNumber
;
1144 SOSManifestRef
SOSMessageGetRemovals(SOSMessageRef message
) {
1145 return message
->removals
;
1148 SOSManifestRef
SOSMessageGetAdditions(SOSMessageRef message
) {
1149 return message
->additions
;
1152 // Iterate though the extensions in a decoded SOSMessage. If criticalOnly is
1153 // true all non critical extensions are skipped.
1154 void SOSMessageWithExtensions(SOSMessageRef message
, bool criticalOnly
, void(^withExtension
)(CFDataRef oid
, bool isCritical
, CFDataRef extension
, bool *stop
)) {
1158 size_t SOSMessageCountObjects(SOSMessageRef message
) {
1159 if (message
->objects
)
1160 return CFArrayGetCount(message
->objects
);
1161 if (!message
->objectsDer
)
1163 const uint8_t *der
= CFDataGetBytePtr(message
->der
);
1164 const uint8_t *der_end
= der
+ CFDataGetLength(message
->der
);
1165 __block
size_t count
= 0;
1166 der_foreach_objects(message
->objectsLen
, message
->objectsDer
, der_end
, NULL
, ^(CFDataRef object
, bool *stop
){ ++count
; });
1170 // Iterate though the objects in a decoded SOSMessage.
1171 bool SOSMessageWithObjects(SOSMessageRef message
, CFErrorRef
*error
,
1172 void(^withObject
)(CFDataRef object
, bool *stop
)) {
1173 if (message
->objects
) {
1175 CFArrayForEachC(message
->objects
, object
) {
1177 withObject(object
, &stop
);
1183 if (!message
->objectsDer
)
1185 const uint8_t *der
= CFDataGetBytePtr(message
->der
);
1186 const uint8_t *der_end
= der
+ CFDataGetLength(message
->der
);
1187 return der_foreach_objects(message
->objectsLen
, message
->objectsDer
, der_end
, error
, withObject
);
1190 bool SOSMessageWithSOSObjects(SOSMessageRef message
, SOSDataSourceRef dataSource
, CFErrorRef
*error
,
1191 void(^withObject
)(SOSObjectRef object
, bool *stop
)) {
1192 return SOSMessageWithObjects(message
, error
, ^(CFDataRef object
, bool *stop
) {
1193 CFDictionaryRef plist
= NULL
;
1194 const uint8_t *der
= CFDataGetBytePtr(object
);
1195 const uint8_t *der_end
= der
+ CFDataGetLength(object
);
1196 // TODO Remove intermediate plist format
1197 der
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &plist
, error
, der
, der_end
);
1199 SOSObjectRef peersObject
= SOSObjectCreateWithPropertyList(dataSource
, plist
, error
);
1200 withObject(peersObject
, stop
);
1201 CFReleaseSafe(peersObject
);
1203 CFReleaseSafe(plist
);