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