X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/84aacf34eae6543be9f0280b2015385f91e5c2c6..b54c578e17e9bcbd74aa30ea75e25e955b9a6205:/OSX/sec/SOSCircle/SecureObjectSync/SOSMessage.c?ds=inline diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSMessage.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSMessage.c deleted file mode 100644 index 4bc308db..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSMessage.c +++ /dev/null @@ -1,1205 +0,0 @@ -/* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -/* - * SOSMessage.c - Creation and decoding of SOSMessage objects. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// TODO: This is a layer violation, we need a better way to do this -// Currently it's only used for logging. -#include - -#if defined(SOSMessageFormatSpecification) && 0 - --- Secure Object Syncing Peer to Peer Message format ASN.1 definition --- Everything MUST be DER encoded unless otherwise noted. These exceptions --- Allow us to stream messages on a streamy network, without loading more --- than one object into memory at once. - -SOSMessage := SEQUENCE { - CHOICE { - v0 V0-MESSAGE-BODY-CLASS - v2 SOSV2MessageBody - } -} - --- v0 Message - -V0-MESSAGE-BODY-CLASS ::= CLASS - { - &messageType INTEGER (manifestDigest, manifest, manifestDeltaAndObjects) - &version INTEGER OPTIONAL default v0 - &Type - } - WITH SYNTAX {&Type IDENTIFIED BY &messageType} - -ManifestDigest ::= OCTECT STRING (length 20) - -Manifest ::= OCTECT STRING -- (length 20 * number of entries) - -manifestDigestBody ::= - { ManifestDigest IDENTIFIED BY {manifestDigest}} - -manifestBody ::= - { Manifest IDENTIFIED BY {manifest}} - - manifestDeltaAndObjectsBody ::= - { ManifestDeltaAndObjects IDENTIFIED BY {manifestDeltaAndObjects}} - -SOSV1MessageBody ::= MESSAGE-BODY-CLASS - -ManifestDeltaAndObjects ::= SEQUENCE { - manfestDigest ManifestDigest - removals Manifest - additions Manifest - addedObjects SEQUENCE OF SOSObject -} - --- v2 Message - -SOSMessageBody := { - -- top level SEQUENCE may be Constructed, indefinite-length BER encoded - header SOSMessageHeader, - deltas [0] IMPLICIT SOSManifestDeltas OPTIONAL, - extensions [1] IMPLICIT SOSExtensions OPTIONAL, - objects [2] IMPLICIT SEQUENCE OF SOSObject OPTIONAL - -- [2] IMPLICIT SEQUENCE OF SOSObject may be Constructed, - -- indefinite-length BER encoded -- } - -SOSMessageHeader ::= SEQUENCE { - version [0] IMPLICIT SOSMessageVersion DEFAULT v2, - creationTime GeneralizedTime OPTIONAL, - -- When this message was created by the sender for tracking latency - sequenceNumber SOSSequenceNumber OPTIONAL, - -- Message Sequence Number for tracking packet loss in transport - digestTypes SOSDigestTypes OPTIONAL, - -- Determines the size and format of each SOSManifestDigest and the - -- elements of each SOSManifest. - -- We send the intersection our desired SOSDigestTypes and our peers - -- last received SOSDigestType. If we never received a message from our - -- peer we send our entire desired set and set the digestTypesProposed - -- messageFlag. - -- If the intersection is the empty set we fallback to sha1 - -- Each digest and manifest entry is constructed by appending the - -- agreed upon digests in the order they are listed in the DER encoded - -- digestTypes. - messageFlags BIT STRING { - getObjects (0), - joinRequest (1), - partial (2), - digestTypesProposed (3), - -- This is a partial update and might not contain accurate manifest deltas (check this against spec --mb), only objects - clearGetObjects (4), -- WIP mb ignore - -- Stop sending me objects for this delta update, I will send you mine instead if you give me a full manifest delta - didClearGetObjectsSinceLastDelta (5) -- WIP mb ignore - -- clearGetObjects was set during this delta update, do not - -- set it again (STICKY until either peer clears delta) -- } - skipHello (6) -- Respond with at least a manifest - senderDigest SOSManifestDigest, - -- The senders manifest digest at the time of sending this message. - baseDigest [0] IMPLICIT SOSManifestDigest, - -- What this message is based on, if it contains deltas. If missing we assume the empty set - proposedDigest [1] IMPLICIT SOSManifestDigest, - -- What the receiver should have after patching baseDigest with - -- additions and removals -- } - -SOSMessageVersion ::= INTEGER { v0(0), v2(2), v3(3) } - -SOSSequenceNumber ::= INTEGER - --- Note this is not implemented in v2 it only supports sha1 -SOSDigestTypes ::= SEQUENCE { - messageFlags BIT STRING { - sha1(0) -- implied if SOSDigestTypes is not present - sha224(1) - sha256(2) - sha384(3) - sha512(4) - digestAlgorithms SET OF AlgorithmIdentifier - -- Same as AlgorithmIdentifier from X.509 -- } } - -SOSManifestDeltas ::= SEQUENCE { - removals SOSManifest - additions SOSManifest } - -SOSExtensions ::= SEQUENCE SIZE (1..MAX) OF SOSExtension - -SOSExtension ::= SEQUENCE { - extnID OBJECT IDENTIFIER, - critical BOOLEAN DEFAULT FALSE, - extnValue OCTET STRING } - -SOSManifest ::= OCTET STRING - -- DER encoding is sorted and ready to merge. - -- All SOSDigest entries in a SOSManifest /must/ be the same size - -- As the negotiated SOSManifestEntry. Se comment in SOSMessageBody - -- on digestTypes - -SOSManifestDigest ::= OCTET STRING - -SOSObject ::= SEQUENCE { - [0] conflict OCTECT STRING OPTIONAL - [1] change OCTECT STRING OPTIONAL - object SecDictionary } - -SecDictionary ::= SET of SecKVPair - -SecKVPair ::= SEQUENCE { - key UTF8String - value Value } - -SecValue ::= CHOICE { - bool Boolean - number INTEGER - string UTF8String - data OCTECT STRING - date GENERAL TIME - dictionary Object - array Array } - -SecArray ::= SEQUENCE of SecValue - --- For reference: -AlgorithmIdentifier ::= SEQUENCE { -algorithm OBJECT IDENTIFIER, -parameters ANY DEFINED BY algorithm OPTIONAL } --- contains a value of the type --- registered for use with the --- algorithm object identifier value - -#endif // defined(SOSMessageFormatSpecification) && 0 - - -#if 0 -static inline bool SecMallocOk(const void *ptr) { - if (ptr) return true; - - return false; -} -#endif -#if 0 -static void appendObjects(CFMutableStringRef desc, CFArrayRef objects) { - __block bool needComma = false; - CFArrayForEach(objects, ^(const void *value) { - if (needComma) - CFStringAppend(desc, CFSTR(",")); - else - needComma = true; - - SecItemServerAppendItemDescription(desc, value); - }); -} -#endif - - - -// -// MARK: SOSMessage implementation. -// - -// Legacy v1 message type numbers -enum SOSMessageType { - SOSManifestInvalidMessageType = 0, - SOSManifestDigestMessageType = 1, - SOSManifestMessageType = 2, - SOSManifestDeltaAndObjectsMessageType = 3, -}; - -struct __OpaqueSOSMessage { - CFRuntimeBase _base; - - CFDataRef der; - const uint8_t *objectsDer; - size_t objectsLen; - - CFDataRef senderDigest; - CFDataRef baseDigest; - CFDataRef proposedDigest; - SOSManifestRef removals; - SOSManifestRef additions; - - CFMutableArrayRef objects; - - SOSMessageFlags flags; - uint64_t sequenceNumber; - CFAbsoluteTime creationTime; - uint64_t version; // Message version (currently always 2) - bool indefiniteLength; // If set to true the top SEQUENCE and the OBJECTS SEQUENCE are written indefinite length. -}; - -CFGiblisWithCompareFor(SOSMessage) - -static Boolean SOSMessageCompare(CFTypeRef cf1, CFTypeRef cf2) { - SOSMessageRef M = (SOSMessageRef)cf1; - SOSMessageRef P = (SOSMessageRef)cf2; - if (M->flags != P->flags) return false; - if (M->sequenceNumber != P->sequenceNumber) return false; - if (M->creationTime != P->creationTime) return false; - //if (!CFEqualSafe(M->der, P->der)) return false; - if (!CFEqualSafe(M->senderDigest, P->senderDigest)) return false; - if (!CFEqualSafe(M->baseDigest, P->baseDigest)) return false; - if (!CFEqualSafe(M->proposedDigest, P->proposedDigest)) return false; - if (!CFEqualSafe(M->removals, P->removals)) return false; - if (!CFEqualSafe(M->additions, P->additions)) return false; - - // TODO Compare Objects if present. - - return true; -} - -static void SOSMessageDestroy(CFTypeRef cf) { - SOSMessageRef message = (SOSMessageRef)cf; - CFReleaseNull(message->der); - CFReleaseNull(message->senderDigest); - CFReleaseNull(message->baseDigest); - CFReleaseNull(message->proposedDigest); - CFReleaseNull(message->additions); - CFReleaseNull(message->removals); - CFReleaseNull(message->objects); -} - -// TODO: Remove this layer violation! -#include - -static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error); - -static CFStringRef SOSMessageCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - SOSMessageRef message = (SOSMessageRef)cf; - static const uint8_t zero[4] = {}; - const uint8_t *S = message->senderDigest ? CFDataGetBytePtr(message->senderDigest) : zero; - const uint8_t *B = message->baseDigest ? CFDataGetBytePtr(message->baseDigest) : zero; - const uint8_t *P = message->proposedDigest ? CFDataGetBytePtr(message->proposedDigest) : zero; - CFDateRef creationDate = CFDateCreate(CFGetAllocator(message), message->creationTime); - - CFMutableStringRef objects = CFStringCreateMutable(kCFAllocatorDefault, 0); - - // TODO: Remove this layer violation! - SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); - SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, NULL); - - if (ds) { - __block size_t maxEntries = 16; - CFStringAppendFormat(objects, NULL, CFSTR("{[%zu]"), SOSMessageCountObjects(message)); - SOSMessageWithSOSObjects(message, ds, NULL, ^(SOSObjectRef object, bool *stop) { - CFDataRef digest = SOSObjectCopyDigest(ds, object, NULL); - const uint8_t *O = CFDataGetBytePtr(digest); - CFStringAppendFormat(objects, NULL, CFSTR(" %02X%02X%02X%02X"), O[0],O[1],O[2],O[3]); - CFReleaseSafe(digest); - if (!--maxEntries) { - CFStringAppend(objects, CFSTR("...")); - *stop = true; - } - }); - CFStringAppend(objects, CFSTR("}")); - } else { - CFStringAppend(objects, CFSTR("{NO DATASOURCE}")); - } - - CFStringRef desc = NULL; - if (message->version == 0) { - switch (SOSMessageInferType(message, NULL)) { - case SOSManifestInvalidMessageType: - desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR(""), message->sequenceNumber); - break; - case SOSManifestDigestMessageType: - desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR(""), message->sequenceNumber, S[0],S[1],S[2],S[3]); - break; - case SOSManifestMessageType: - desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR(""), message->sequenceNumber, message->additions); - break; - case SOSManifestDeltaAndObjectsMessageType: - desc = CFStringCreateWithFormat(CFGetAllocator(message), NULL, CFSTR("sequenceNumber, - B[0],B[1],B[2],B[3], - message->removals, message->additions, - objects); - break; - } - } else { - desc = CFStringCreateWithFormat - (CFGetAllocator(message), NULL, CFSTR(""), - message->sequenceNumber, - creationDate, - S[0],S[1],S[2],S[3], - B[0],B[1],B[2],B[3], - P[0],P[1],P[2],P[3], - message->removals, message->additions, - objects, - (message->flags & kSOSMessageGetObjects) ? "G" : "g", - (message->flags & kSOSMessageJoinRequest) ? "J" : "j", - (message->flags & kSOSMessagePartial) ? "P" : "p", - (message->flags & kSOSMessageDigestTypesProposed) ? "D" : "d", - (message->flags & kSOSMessageClearGetObjects) ? "K" : "k", - (message->flags & kSOSMessageDidClearGetObjectsSinceLastDelta) ? "Z" : "z", - (message->flags & kSOSMessageSkipHello) ? "H" : "h"); - } - CFReleaseSafe(creationDate); - CFReleaseSafe(objects); - return desc; -} - -// -// MARK: SOSMessage encoding -// - -// Create an SOSMessage ready to be encoded. -SOSMessageRef SOSMessageCreate(CFAllocatorRef allocator, uint64_t version, CFErrorRef *error) { - SOSMessageRef message = CFTypeAllocate(SOSMessage, struct __OpaqueSOSMessage, allocator); - message->version = version; - return message; -} - -// TODO: Remove me this is for testing only, tests should use the real thing. -SOSMessageRef SOSMessageCreateWithManifests(CFAllocatorRef allocator, SOSManifestRef sender, - SOSManifestRef base, SOSManifestRef proposed, - bool includeManifestDeltas, CFErrorRef *error) { - SOSMessageRef message = SOSMessageCreate(allocator, kEngineMessageProtocolVersion, error); - if (!SOSMessageSetManifests(message, sender, base, proposed, includeManifestDeltas, NULL, error)) - CFReleaseNull(message); - return message; -} - -bool SOSMessageSetManifests(SOSMessageRef message, SOSManifestRef sender, - SOSManifestRef base, SOSManifestRef proposed, - bool includeManifestDeltas, SOSManifestRef objectsSent, - CFErrorRef *error) { - if (!message) return true; - bool ok = true; - // TODO: Check at v2 encoding time - // if (!sender) return (SOSMessageRef)SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("no sender manifest specified for SOSMessage")); - message->baseDigest = CFRetainSafe(SOSManifestGetDigest(base, NULL)); - secinfo("engine", "SOSMessageSetManifests: setting base digest to %@ %zu", message->baseDigest, SOSManifestGetCount(base)); - message->proposedDigest = CFRetainSafe(SOSManifestGetDigest(proposed, NULL)); - secinfo("engine", "SOSMessageSetManifests: setting proposed digest to %@ %zu", message->proposedDigest, SOSManifestGetCount(proposed)); - message->senderDigest = CFRetainSafe(SOSManifestGetDigest(sender, NULL)); - secinfo("engine", "SOSMessageSetManifests: setting sender digest to %@ %zu", message->senderDigest, SOSManifestGetCount(sender)); - - if (includeManifestDeltas) { - SOSManifestRef additions = NULL; - ok = SOSManifestDiff(base, proposed, &message->removals, &additions, error); - if (message->version == 0) { - message->additions = additions; - } else { - message->additions = SOSManifestCreateComplement(objectsSent, additions, error); - CFReleaseSafe(additions); - } - } - return ok; -} - -void SOSMessageSetFlags(SOSMessageRef message, SOSMessageFlags flags) { - message->flags = flags; -} - -// Add an extension to this message -void SOSMessageAddExtension(SOSMessageRef message, CFDataRef oid, bool isCritical, CFDataRef extension) { - // TODO: Implement - secerror("not implemented yet!"); -} - -static bool SecMessageIsObjectValid(CFDataRef object, CFErrorRef *error) { - const uint8_t *der = CFDataGetBytePtr(object); - const uint8_t *der_end = der + CFDataGetLength(object); - ccder_tag tag = 0; - size_t len = 0; - der = ccder_decode_tag(&tag, der, der_end); - if (!der ) - return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Invalid DER, no tag found")); - if (tag == CCDER_EOL) - return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object has EOL tag")); - der = ccder_decode_len(&len, der, der_end); - if (!der) - return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object with tag %lu has no valid DER length"), tag); - der += len; - if (der_end - der) - return SOSErrorCreate(kSOSErrorBadFormat, error, NULL, CFSTR("Object has %td trailing unused bytes"), der_end - der); - return true; -} - -bool SOSMessageAppendObject(SOSMessageRef message, CFDataRef object, CFErrorRef *error) { - if (!SecMessageIsObjectValid(object, error)) return false; - if (!message->objects) - message->objects = CFArrayCreateMutableForCFTypes(CFGetAllocator(message)); - if (message->objects) - CFArrayAppendValue(message->objects, object); - return true; -} - -static CC_NONNULL_ALL -size_t ccder_sizeof_bit_string(cc_size n, const cc_unit *s) { - return ccder_sizeof(CCDER_BIT_STRING, ccn_sizeof(ccn_bitlen(n, s)) + 1); -} - -static CC_NONNULL_ALL -uint8_t *ccder_encode_bit_string(cc_size n, const cc_unit *s, const uint8_t *der, uint8_t *der_end) { - size_t bits = ccn_bitlen(n, s); - size_t out_size = ccn_sizeof(bits) + 1; - der_end = ccder_encode_body_nocopy(out_size, der, der_end); - if (der_end) - ccn_write_uint_padded(n, s, out_size, der_end); - return ccder_encode_tl(CCDER_BIT_STRING, out_size, der, der_end); -} - - -static -size_t der_sizeof_implicit_data(ccder_tag tag, CFDataRef data) { - if (!data) - return 0; - return ccder_sizeof_implicit_raw_octet_string(tag, CFDataGetLength(data)); -} - - -static CC_NONNULL((3, 4)) -uint8_t *der_encode_implicit_data(ccder_tag tag, CFDataRef data, const uint8_t *der, uint8_t *der_end) { - if (!data) - return der_end; - return ccder_encode_implicit_raw_octet_string(tag, CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end); -} - -static size_t der_sizeof_message_header(SOSMessageRef message, CFErrorRef *error) { - if (!message->senderDigest) { - // TODO: Create Error. - return 0; - } - cc_unit flags[1]; - flags[0] = (cc_unit)message->flags; // TODO Fix cast or something - - return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, - der_sizeof_generalizedtime(message->creationTime, error) + - ccder_sizeof_uint64(message->sequenceNumber) + - ccder_sizeof_bit_string(array_size(flags), flags) + - der_sizeof_implicit_data(CCDER_OCTET_STRING, message->senderDigest) + - der_sizeof_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, message->baseDigest) + - der_sizeof_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, message->proposedDigest)); -} - -static uint8_t *der_encode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - if (!message->senderDigest) { - // TODO: Create Error. - return NULL; - } - cc_unit flags[1]; - flags[0] = (cc_unit)message->flags; // TODO Fix cast or something - return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - der_encode_generalizedtime(message->creationTime, error, der, - ccder_encode_uint64(message->sequenceNumber, der, - ccder_encode_bit_string(array_size(flags), flags, der, - der_encode_implicit_data(CCDER_OCTET_STRING, message->senderDigest, der, - der_encode_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, message->baseDigest, der, - der_encode_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, message->proposedDigest, der, der_end))))))); -} - -static size_t der_sizeof_deltas(SOSMessageRef message) { - if (!message->additions && !message->removals) return 0; - if (message->version == 0) { - return ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->removals))+ - ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->additions)); - } else { - return ccder_sizeof(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, - ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->removals))+ - ccder_sizeof(CCDER_OCTET_STRING, SOSManifestGetSize(message->additions))); - } -} - -static uint8_t *der_encode_deltas(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - if (!message->additions && !message->removals) return der_end; - if (message->version == 0) { - return der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der, - der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end)); - } else { - return ccder_encode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, der_end, der, - der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der, - der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end))); - } -} - -static size_t der_sizeof_extensions(SOSMessageRef message) { - // We don't support any yet. - return 0; -} - -static uint8_t *der_encode_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - // We don't support any yet. - return der_end; -} - -static size_t der_sizeof_objects(SOSMessageRef message) { - size_t len = 0; - if (message->objects) { - CFDataRef data; - CFArrayForEachC(message->objects, data) { - len += (size_t)CFDataGetLength(data); - } - } else if (message->version != 0) - return 0; - - if (message->indefiniteLength) - return len + 4; - else - return ccder_sizeof(2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, len); -} - -static uint8_t *der_encode_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - if (!message->objects && message->version != 0) return der_end; - const uint8_t *original_der_end = der_end; - if (message->indefiniteLength) - der_end = ccder_encode_tl(CCDER_EOL, 0, der, der_end); - - for (CFIndex position = (message->objects ? CFArrayGetCount(message->objects) : 0) - 1; position >= 0; --position) { - CFDataRef object = CFArrayGetValueAtIndex(message->objects, position); - der_end = ccder_encode_body(CFDataGetLength(object), CFDataGetBytePtr(object), der, der_end); - } - if (message->indefiniteLength) { - return ccder_encode_tag(2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, der, - ccder_encode_len(0, der, der_end)); - } else { - ccder_tag otag = message->version == 0 ? CCDER_CONSTRUCTED_SEQUENCE : 2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED; - return ccder_encode_constructed_tl(otag, original_der_end, der, der_end); - } -} - -static size_t der_sizeof_v2_message(SOSMessageRef message, CFErrorRef *error) { - size_t body_size = (der_sizeof_message_header(message, error) + - der_sizeof_deltas(message) + - der_sizeof_extensions(message) + - der_sizeof_objects(message)); - if (message->indefiniteLength) - return body_size + 4; - else - return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, body_size); -} - - -static uint8_t *der_encode_v2_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - const uint8_t *original_der_end = der_end; - if (message->indefiniteLength) - der_end = ccder_encode_tl(CCDER_EOL, 0, der, der_end); - - der_end = der_encode_message_header(message, error, der, - der_encode_deltas(message, error, der, - der_encode_extensions(message, error, der, - der_encode_objects(message, error, der, der_end)))); - - if (message->indefiniteLength) { - return ccder_encode_tag(CCDER_CONSTRUCTED_SEQUENCE, der, - ccder_encode_len(0, der, der_end)); - } else { - return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der, der_end); - } -} - -//------------------------------------------------------------------------------------------------------------------------------------ -// V1 support -//------------------------------------------------------------------------------------------------------------------------------------ - -/* ManifestDigest message */ -static size_t der_sizeof_manifest_digest_message(SOSMessageRef message, CFErrorRef *error) { - if (!message->senderDigest || CFDataGetLength(message->senderDigest) != SOSDigestSize) { - SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("digest length mismatch")); - return 0; - } - return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, - (ccder_sizeof_uint64(SOSManifestDigestMessageType) + - ccder_sizeof_raw_octet_string(SOSDigestSize))); -} - -static uint8_t *der_encode_manifest_digest_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - secinfo("engine", "der_encode_manifest_digest_message: encoded sender digest as %@", message->senderDigest); - return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - ccder_encode_uint64(SOSManifestDigestMessageType, der, - ccder_encode_raw_octet_string(SOSDigestSize, CFDataGetBytePtr(message->senderDigest), der, der_end))); -} - -/* Manifest message */ -static size_t der_sizeof_manifest_message(SOSMessageRef message, CFErrorRef *error) { - if (!message->additions) { - SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("no manifest for manifest message")); - return 0; - } - return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, - (ccder_sizeof_uint64(SOSManifestMessageType) + - der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions)))); -} - -static uint8_t *der_encode_manifest_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - secinfo("engine", "der_encode_manifest_message: encoded message additions as (%zu, %@)", SOSManifestGetCount(message->additions), SOSManifestGetDigest(message->additions, NULL)); - return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - ccder_encode_uint64(SOSManifestMessageType, der, - der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, der_end))); -} - -/* ManifestDeltaAndObjects message */ -static size_t der_sizeof_manifest_and_objects_message(SOSMessageRef message, CFErrorRef *error) { - if (!message->baseDigest || CFDataGetLength(message->baseDigest) != SOSDigestSize) { - SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("digest length mismatch")); - return 0; - } - - return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, - (ccder_sizeof_uint64(SOSManifestDeltaAndObjectsMessageType) + - ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, - (ccder_sizeof_raw_octet_string(SOSDigestSize) + - der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals)) + - der_sizeof_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions)) + - der_sizeof_objects(message))))); -} - -static uint8_t *der_encode_manifest_and_objects_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - secinfo("engine", "der_encode_manifest_and_objects_message: encoded base digest as %@", message->baseDigest); - return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - ccder_encode_uint64(SOSManifestDeltaAndObjectsMessageType, der, - ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - ccder_encode_raw_octet_string(SOSDigestSize, CFDataGetBytePtr(message->baseDigest), der, - der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->removals), der, - der_encode_implicit_data(CCDER_OCTET_STRING, SOSManifestGetData(message->additions), der, - der_encode_objects(message, error, der, der_end))))))); -} - -static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error) { - if (message->baseDigest) { - // TODO: Assert that we don't have senderDigest or proposedDigest - if (SOSManifestGetCount(message->removals) || SOSManifestGetCount(message->additions) || SOSMessageCountObjects(message)) { - return SOSManifestDeltaAndObjectsMessageType; - } else { - // NOTE: If we force a SOSManifestDeltaAndObjectsMessageType instead then - // true v0 peers will overwrite their last objects message to us. However this - // implements the current v0 behaviour - return SOSManifestDigestMessageType; - } - } else if (message->additions) { - // TODO: Assert that we don't have senderDigest, proposedDigest, additions, removals or objects - return SOSManifestMessageType; - } else if (message->senderDigest) { - // TODO: Assert that we don't have proposedDigest, removals or objects - return SOSManifestDigestMessageType; - } - // TODO: Create error. - return SOSManifestInvalidMessageType; -} - -static size_t der_sizeof_message(SOSMessageRef message, uint64_t messageType, CFErrorRef *error) { - switch (messageType) { - case SOSManifestInvalidMessageType: - return der_sizeof_v2_message(message, error); - case SOSManifestDigestMessageType: - return der_sizeof_manifest_digest_message(message, error); - case SOSManifestMessageType: - return der_sizeof_manifest_message(message, error); - case SOSManifestDeltaAndObjectsMessageType: - return der_sizeof_manifest_and_objects_message(message, error); - } - return 0; -} - -static uint8_t *der_encode_message(SOSMessageRef message, uint64_t messageType, CFErrorRef *error, const uint8_t *der, uint8_t *der_end) { - switch (messageType) { - case SOSManifestInvalidMessageType: - return der_encode_v2_message(message, error, der, der_end); - case SOSManifestDigestMessageType: - return der_encode_manifest_digest_message(message, error, der, der_end); - case SOSManifestMessageType: - return der_encode_manifest_message(message, error, der, der_end); - case SOSManifestDeltaAndObjectsMessageType: - return der_encode_manifest_and_objects_message(message, error, der, der_end); - } - return der_end; -} - -// Encode an SOSMessage, calls addObject callback and appends returned objects -// one by one, until addObject returns NULL. -CFDataRef SOSMessageCreateData(SOSMessageRef message, uint64_t sequenceNumber, CFErrorRef *error) { - // Version 2 message have sequence numbers, version 0 messages do not. - uint64_t messageType = SOSManifestInvalidMessageType; - message->sequenceNumber = sequenceNumber; - if (message->version == 0) { - message->indefiniteLength = false; - messageType = SOSMessageInferType(message, error); - if (!messageType) { - // Propagate error - return NULL; - } - } else { - message->creationTime = floor(CFAbsoluteTimeGetCurrent()); - } - size_t der_size = der_sizeof_message(message, messageType, error); - CFMutableDataRef data = CFDataCreateMutable(NULL, der_size); - if (data == NULL) { - // TODO Error. - return NULL; - } - CFDataSetLength(data, der_size); - uint8_t *der_end = CFDataGetMutableBytePtr(data); - const uint8_t *der = der_end; - der_end += der_size; - - der_end = der_encode_message(message, messageType, error, der, der_end); - if (der != der_end) { - secwarning("internal error %td bytes unused in der buffer", der_end - der); - } - return data; -} - -// -// MARK: SOSMessage decoding -// - -#define CCBER_LEN_INDEFINITE ((size_t)-1) - -// Decode BER length field. Sets *lenp to ccber_indefinite_len if this is an indefinite length encoded object. -// Behaves like ccder_decode_len in every other way. -static CC_NONNULL((1, 3)) -const uint8_t *ccber_decode_len(size_t *lenp, const uint8_t *der, const uint8_t *der_end) { - if (der && der < der_end) { - if (*der == 0x80) { - der++; - *lenp = CCBER_LEN_INDEFINITE; - } - else - der = ccder_decode_len(lenp, der, der_end); - } - return der; -} - -static const uint8_t *der_decode_generalizedtime(CFAbsoluteTime *at, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *times_end = NULL; - der = ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME, ×_end, der, der_end); - der = der_decode_generalizedtime_body(at, error, der, times_end); - if (times_end != der) { - secwarning("internal error %td bytes unused in generalizedtime DER buffer", times_end - der); - } - return der; -} - -static const uint8_t *der_decode_optional_generalizedtime(CFAbsoluteTime *at, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *times_end = der_decode_generalizedtime(at, error, der, der_end); - return times_end ? times_end : der; -} - -static CC_NONNULL((2, 4)) -const uint8_t *ccder_decode_implicit_uint64(ccder_tag expected_tag, uint64_t* r, const uint8_t *der, const uint8_t *der_end) { - size_t len; - der = ccder_decode_tl(expected_tag, &len, der, der_end); - if (der && len && (*der & 0x80) != 0x80) { - if (ccn_read_uint(ccn_nof_size(sizeof(*r)), (cc_unit*)r, len, der) >= 0) - return der + len; - } - return NULL; -} - -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) { - const uint8_t *ui64_end = ccder_decode_implicit_uint64(expected_tag, value, der, der_end); - return ui64_end ? ui64_end : der; -} - - -static const uint8_t *ccder_decode_optional_uint64(uint64_t *value, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *ui64_end = ccder_decode_uint64(value, der, der_end); - return ui64_end ? ui64_end : der; -} - -static const uint8_t *ccder_decode_digest_types(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *dt_end; - der = ccder_decode_sequence_tl(&dt_end, der, der_end); - if (!der) return NULL; - // Skip over digestType body for now. - // TODO: Support DigestType - return dt_end; -} - -static const uint8_t *ccder_decode_optional_digest_types(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *dt_end = ccder_decode_digest_types(message, der, der_end); - return dt_end ? dt_end : der; -} - -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) { - size_t len; - const uint8_t *body = ccder_decode_tl(CCDER_BIT_STRING, &len, der, der_end); - if (!body || len < 1) - return NULL; - - if (r_bitlen) *r_bitlen = (len - 1) * 8 - (body[0] & 7); - ccn_read_uint(1, r, len - 1, body + 1); - return body + len; -} - -static const uint8_t *der_decode_implicit_data(ccder_tag expected_tag, CFDataRef *data, const uint8_t *der, const uint8_t *der_end) { - size_t len = 0; - der = ccder_decode_tl(expected_tag, &len, der, der_end); - if (der && data) { - *data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, len, kCFAllocatorNull); - if (*data) - der += len; - else - der = NULL; - } - return der; -} - -static const uint8_t *der_decode_optional_implicit_data(ccder_tag expected_tag, CFDataRef *data, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *data_end = der_decode_implicit_data(expected_tag, data, der, der_end); - return data_end ? data_end : der; -} - -static const uint8_t *der_decode_deltas_body(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - CFDataRef removals = NULL, additions = NULL; - der = der_decode_implicit_data(CCDER_OCTET_STRING, &removals, der, der_end); - der = der_decode_implicit_data(CCDER_OCTET_STRING, &additions, der, der_end); - if (der) { - message->removals = SOSManifestCreateWithData(removals, error); - message->additions = SOSManifestCreateWithData(additions, error); - if (!message->removals || !message->additions) { - CFReleaseNull(message->removals); - CFReleaseNull(message->additions); - der = NULL; - } - } - CFReleaseSafe(removals); - CFReleaseSafe(additions); - - return der; -} - -static const uint8_t *der_decode_deltas(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *deltas_end = NULL; - der = ccder_decode_constructed_tl(0 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, &deltas_end, der, der_end); - return der_decode_deltas_body(message, error, der, deltas_end); -} - -static const uint8_t *der_decode_optional_deltas(SOSMessageRef message, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *seq_end = der_decode_deltas(message, NULL, der, der_end); - return seq_end ? seq_end : der; -} - -static const uint8_t *der_decode_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *extensions_end; - der = ccder_decode_constructed_tl(1 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED, &extensions_end, der, der_end); - if (!der) return NULL; - // Skip over extensions for now. - return extensions_end; -} - -static const uint8_t *der_decode_optional_extensions(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *extensions_end = der_decode_extensions(message, NULL, der, der_end); - return extensions_end ? extensions_end : der; -} - -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)) { - bool stop = false; - ccder_tag tag; - // Look ahead at the tag - while (!stop && ccder_decode_tag(&tag, der, der_end) && tag != CCDER_EOL) { - const uint8_t *object_end = NULL; - if (!ccder_decode_constructed_tl(tag, &object_end, der, der_end)) { - SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("failed to decode object header")); - return NULL; - } - if (withObject) { - CFDataRef object = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, object_end - der, kCFAllocatorNull); - withObject(object, &stop); - CFReleaseSafe(object); - } - der = object_end; - } - if (length == CCBER_LEN_INDEFINITE) { - size_t len = 0; - der = ccder_decode_tl(CCDER_EOL, &len, der, der_end); - if (len != 0) { - secwarning("%td length ", der_end - der); - } - } - if (!stop && der != der_end) - secwarning("%td trailing bytes after objects DER", der_end - der); - - return der; -} - -static const uint8_t *der_decode_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - ccder_tag tag = 0; - size_t objects_len = 0; - der = ccder_decode_tag(&tag, der, der_end); - if (tag != (2 | CCDER_CONTEXT_SPECIFIC | CCDER_CONSTRUCTED)) return NULL; - der = ccber_decode_len(&objects_len, der, der_end); - if (objects_len != CCBER_LEN_INDEFINITE && der_end - der != (ptrdiff_t)objects_len) { - secwarning("%td trailing bytes after SOSMessage DER", (der_end - der) - (ptrdiff_t)objects_len); - } - // Remember a pointer into message->der where objects starts. - message->objectsDer = der; - message->objectsLen = objects_len; - - return der + objects_len; -} - -static const uint8_t *der_decode_optional_objects(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - const uint8_t *seq_end = der_decode_objects(message, NULL, der, der_end); - return seq_end ? seq_end : der; -} - -#if 0 -// Move to ccder and possibly refactor ccder_decode_constructed_tl to call this. -#ifdef CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER -CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER -#endif -inline CC_NONNULL((1, 3)) -const uint8_t * -ccder_decode_constructed_len(const uint8_t **body_end, - const uint8_t *der, const uint8_t *der_end) { - size_t len; - der = ccder_decode_len(&len, der, der_end); - *body_end = der + len; - return der; -} -#endif - -static const uint8_t *der_decode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - cc_unit flags[1] = {}; - der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end); - message->version = 2; - der = ccder_decode_optional_implicit_uint64(0 | CCDER_CONTEXT_SPECIFIC, &message->version, der, der_end); - der = der_decode_optional_generalizedtime(&message->creationTime, error, der, der_end); - der = ccder_decode_optional_uint64(&message->sequenceNumber, der, der_end); - der = ccder_decode_optional_digest_types(message, der, der_end); - der = ccder_decode_bit_string(array_size(flags), NULL, flags, der, der_end); - message->flags = flags[0]; - - der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->senderDigest, der, der_end); - secinfo("engine", "der_decode_message_header: decoded sender digest as %@", message->senderDigest); - - der = der_decode_optional_implicit_data(0 | CCDER_CONTEXT_SPECIFIC, &message->baseDigest, der, der_end); - secinfo("engine", "der_decode_message_header: decoded base digest as %@", message->baseDigest); - - der = der_decode_optional_implicit_data(1 | CCDER_CONTEXT_SPECIFIC, &message->proposedDigest, der, der_end); - secinfo("engine", "der_decode_message_header: decoded proposed digest as %@", message->proposedDigest); - - return der; -} - -static const uint8_t * -der_decode_manifest_and_objects_message(SOSMessageRef message, - CFErrorRef *error, const uint8_t *der, - const uint8_t *der_end) { - size_t objects_len = 0; - const uint8_t *body_end; - der = ccder_decode_sequence_tl(&body_end, der, der_end); - if (body_end != der_end) { - SOSErrorCreate(kSOSErrorInvalidMessage, error, NULL, CFSTR("Trailing garbage at end of message")); - return NULL; - } - der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->baseDigest, der, body_end); - secinfo("engine", "der_decode_manifest_and_objects_message: decoded base digest as %@", message->baseDigest); - - der = der_decode_deltas_body(message, error, der, body_end); - // Remember a pointer into message->der where objects starts. - der = message->objectsDer = ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &objects_len, der, body_end); - message->objectsLen = objects_len; - - return der ? der + objects_len : NULL; -} - -static const uint8_t *der_decode_v0_message_body(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - uint64_t messageType = 0; - der = ccder_decode_uint64(&messageType, der, der_end); - if (der) switch (messageType) { - case SOSManifestDigestMessageType: - { - der = der_decode_implicit_data(CCDER_OCTET_STRING, &message->senderDigest, der, der_end); - secinfo("engine", "der_decode_v0_message_body: received a DigestMessage with sender digest: %@", message->senderDigest); - break; - } - case SOSManifestMessageType: - { - CFDataRef manifestBody = NULL; - der = der_decode_implicit_data(CCDER_OCTET_STRING, &manifestBody, der, der_end); - if (!der) return NULL; - if (der != der_end) { - secwarning("%td trailing bytes after deltas DER", der_end - der); - } - message->additions = SOSManifestCreateWithData(manifestBody, error); - secinfo("engine", "der_decode_v0_message_body: received a ManifestMessage with (%zu, %@)", SOSManifestGetCount(message->additions), SOSManifestGetDigest(message->additions, NULL)); - CFReleaseSafe(manifestBody); - break; - } - case SOSManifestDeltaAndObjectsMessageType: - { - der = der_decode_manifest_and_objects_message(message, error, der, der_end); - break; - } - default: - SOSErrorCreate(kSOSErrorInvalidMessage, error, NULL, CFSTR("Invalid message type %llu"), messageType); - break; - } - return der; -} - -static const uint8_t *der_decode_message(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { - ccder_tag tag = 0; - size_t body_len = 0; - - der = ccder_decode_tag(&tag, der, der_end); - if (tag != CCDER_CONSTRUCTED_SEQUENCE) return NULL; - der = ccber_decode_len(&body_len, der, der_end); - if (der && body_len && body_len != CCBER_LEN_INDEFINITE && (der_end - der) != (ptrdiff_t)body_len) { - secwarning("%td trailing bytes after SOSMessage DER", (der_end - der) - (ptrdiff_t)body_len); - der_end = der + body_len; - } - - if (ccder_decode_tag(&tag, der, der_end)) switch (tag) { - case CCDER_INTEGER: // v0 - if (body_len == CCBER_LEN_INDEFINITE) - der = NULL; // Not supported for v0 messages - else - der = der_decode_v0_message_body(message, error, der, der_end); - break; - case CCDER_CONSTRUCTED_SEQUENCE: //v2 - der = der_decode_message_header(message, error, der, der_end); - der = der_decode_optional_deltas(message, der, der_end); - der = der_decode_optional_extensions(message, error, der, der_end); - der = der_decode_optional_objects(message, error, der, der_end); - break; - } - return der; -} - -// Decode a SOSMessage -SOSMessageRef SOSMessageCreateWithData(CFAllocatorRef allocator, CFDataRef derData, CFErrorRef *error) { - if (!derData) - return (SOSMessageRef)SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("NULL data => no SOSMessage")); - SOSMessageRef message = CFTypeAllocate(SOSMessage, struct __OpaqueSOSMessage, allocator); - if (!message) - return (SOSMessageRef)SOSErrorCreate(kSOSErrorAllocationFailure, error, NULL, CFSTR("failed to alloc SOSMessage")); - message->der = CFRetainSafe(derData); - const uint8_t *der = CFDataGetBytePtr(derData); - const uint8_t *der_end = der + CFDataGetLength(derData); - der = der_decode_message(message, error, der, der_end); - if (!der_end || der != der_end) { - if (error && !*error) - SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("SOSMessage DER decoding failure %td bytes left"), der_end - der); - return CFReleaseSafe(message); - } - return message; -} - -// Read values from a decoded messgage - -CFDataRef SOSMessageGetBaseDigest(SOSMessageRef message) { - return message->baseDigest; -} - -CFDataRef SOSMessageGetProposedDigest(SOSMessageRef message) { - return message->proposedDigest; -} - -CFDataRef SOSMessageGetSenderDigest(SOSMessageRef message) { - return message->senderDigest; -} - -SOSMessageFlags SOSMessageGetFlags(SOSMessageRef message) { - return message->flags; -} - -uint64_t SOSMessageGetSequenceNumber(SOSMessageRef message) { - return message->sequenceNumber; -} - -SOSManifestRef SOSMessageGetRemovals(SOSMessageRef message) { - return message->removals; -} - -SOSManifestRef SOSMessageGetAdditions(SOSMessageRef message) { - return message->additions; -} - -// Iterate though the extensions in a decoded SOSMessage. If criticalOnly is -// true all non critical extensions are skipped. -void SOSMessageWithExtensions(SOSMessageRef message, bool criticalOnly, void(^withExtension)(CFDataRef oid, bool isCritical, CFDataRef extension, bool *stop)) { - // TODO -} - -size_t SOSMessageCountObjects(SOSMessageRef message) { - if (message->objects) - return CFArrayGetCount(message->objects); - if (!message->objectsDer) - return 0; - const uint8_t *der = CFDataGetBytePtr(message->der); - const uint8_t *der_end = der + CFDataGetLength(message->der); - __block size_t count = 0; - der_foreach_objects(message->objectsLen, message->objectsDer, der_end, NULL, ^(CFDataRef object, bool *stop){ ++count; }); - return count; -} - -// Iterate though the objects in a decoded SOSMessage. -bool SOSMessageWithObjects(SOSMessageRef message, CFErrorRef *error, - void(^withObject)(CFDataRef object, bool *stop)) { - if (message->objects) { - CFDataRef object; - CFArrayForEachC(message->objects, object) { - bool stop = false; - withObject(object, &stop); - if (stop) - break; - } - return true; - } - if (!message->objectsDer) - return true; - const uint8_t *der = CFDataGetBytePtr(message->der); - const uint8_t *der_end = der + CFDataGetLength(message->der); - return der_foreach_objects(message->objectsLen, message->objectsDer, der_end, error, withObject); -} - -bool SOSMessageWithSOSObjects(SOSMessageRef message, SOSDataSourceRef dataSource, CFErrorRef *error, - void(^withObject)(SOSObjectRef object, bool *stop)) { - return SOSMessageWithObjects(message, error, ^(CFDataRef object, bool *stop) { - CFDictionaryRef plist = NULL; - const uint8_t *der = CFDataGetBytePtr(object); - const uint8_t *der_end = der + CFDataGetLength(object); - // TODO Remove intermediate plist format - der = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &plist, error, der, der_end); - if (der) { - SOSObjectRef peersObject = SOSObjectCreateWithPropertyList(dataSource, plist, error); - withObject(peersObject, stop); - CFReleaseSafe(peersObject); - } - CFReleaseSafe(plist); - }); -}