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, ×_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 }