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