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