SecOTRPacketData.h
1 /* 2 * Copyright (c) 2011-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 #ifndef _SECOTRPACKETDATA_H_ 26 #define _SECOTRPACKETDATA_H_ 27 28 #include <CoreFoundation/CFBase.h> 29 #include <CoreFoundation/CFRuntime.h> 30 #include <CoreFoundation/CFData.h> 31 32 #include <corecrypto/ccn.h> 33 34 #include <CommonCrypto/CommonDigest.h> 35 36 #include <Security/SecBase.h> 37 38 #include <Security/SecOTRPackets.h> 39 40 #include <AssertMacros.h> 41 42 #include <security_utilities/simulatecrash_assert.h> 43 44 __BEGIN_DECLS 45 46 CF_ASSUME_NONNULL_BEGIN 47 48 static 49 OSStatus ReadAndVerifyByte(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint8_t expected); 50 51 static 52 OSStatus ReadAndVerifyShort(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint16_t expected); 53 54 static 55 OSStatus ReadAndVerifyMessageType(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType expected); 56 57 static 58 OSStatus SizeAndSkipDATA(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size, 59 const uint8_t *_Nonnull *_Nonnull dataBytes, size_t *dataSize); 60 static 61 OSStatus SizeAndSkipMPI(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size, 62 const uint8_t *_Nonnull *_Nonnull mpiBytes, size_t *mpiSize); 63 64 65 static 66 OSStatus ReadLongLongCompact(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value); 67 68 static 69 OSStatus ReadLongLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value); 70 71 static 72 OSStatus ReadLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint32_t* value); 73 74 static 75 OSStatus ReadShort(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint16_t* value); 76 77 static 78 OSStatus ReadByte(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint8_t* value); 79 80 static 81 OSStatus ReadMessageType(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, OTRMessageType* type); 82 83 static 84 OSStatus ReadMPI(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x); 85 86 static 87 OSStatus ReadDATA(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data); 88 89 static 90 OSStatus CreatePublicKey(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, _Nonnull SecOTRPublicIdentityRef *_Nonnull publicId); 91 92 static 93 CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef _Nullable allocator, const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr); 94 95 static 96 void AppendLongLongCompact(CFMutableDataRef appendTo, uint64_t value); 97 98 static 99 void AppendLongLong(CFMutableDataRef appendTo, uint64_t value); 100 101 static 102 void AppendLong(CFMutableDataRef appendTo, uint32_t value); 103 104 static 105 void AppendShort(CFMutableDataRef appendTo, uint16_t value); 106 107 static 108 void AppendByte(CFMutableDataRef appendTo, uint8_t type); 109 110 static 111 void AppendMessageType(CFMutableDataRef appendTo, OTRMessageType type); 112 113 static 114 void AppendMPI(CFMutableDataRef appendTo, cc_size n, const cc_unit *x); 115 116 static 117 void AppendDATA(CFMutableDataRef appendTo, size_t size, const uint8_t*data); 118 119 static 120 void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId); 121 122 123 // 124 // Inline implementation 125 // 126 127 static uint16_t kCurrentOTRVersion = 0x2; 128 129 static inline OSStatus ReadLongLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value) 130 { 131 require(bytesPtr != NULL, fail); 132 require(sizePtr != NULL, fail); 133 require(value != NULL, fail); 134 require(*sizePtr >= 8, fail); 135 136 *value = ((uint64_t)(*bytesPtr)[0]) << 56 | 137 ((uint64_t)(*bytesPtr)[1]) << 48 | 138 ((uint64_t)(*bytesPtr)[2]) << 40 | 139 ((uint64_t)(*bytesPtr)[3]) << 32 | 140 ((uint64_t)(*bytesPtr)[4]) << 24 | 141 ((uint64_t)(*bytesPtr)[5]) << 16 | 142 ((uint64_t)(*bytesPtr)[6]) << 8 | 143 ((uint64_t)(*bytesPtr)[7]) << 0; 144 145 *bytesPtr += 8; 146 *sizePtr -= 8; 147 148 return errSecSuccess; 149 fail: 150 return errSecParam; 151 } 152 153 static inline OSStatus ReadLongLongCompact(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value) 154 { 155 bool moreBytes = true; 156 157 require(bytesPtr != NULL, fail); 158 require(sizePtr != NULL, fail); 159 require(value != NULL, fail); 160 161 *value = 0; 162 163 while (moreBytes && *sizePtr > 0) { 164 uint8_t thisByte = **bytesPtr; 165 166 moreBytes = (0x80 & thisByte) != 0; 167 168 *value <<= 7; 169 *value |= (thisByte & 0x7F); 170 171 ++*bytesPtr; 172 --*sizePtr; 173 } 174 175 fail: 176 return !moreBytes ? errSecSuccess : errSecDecode; 177 } 178 179 static inline OSStatus ReadLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint32_t* value) 180 { 181 require(bytesPtr != NULL, fail); 182 require(sizePtr != NULL, fail); 183 require(value != NULL, fail); 184 require(*sizePtr >= 4, fail); 185 186 *value = (uint32_t)(*bytesPtr)[0] << 24 | 187 (uint32_t)(*bytesPtr)[1] << 16 | 188 (uint32_t)(*bytesPtr)[2] << 8 | 189 (uint32_t)(*bytesPtr)[3] << 0; 190 191 *bytesPtr += 4; 192 *sizePtr -= 4; 193 194 return errSecSuccess; 195 fail: 196 return errSecParam; 197 } 198 199 static inline OSStatus ReadShort(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint16_t* value) 200 { 201 require(bytesPtr != NULL, fail); 202 require(sizePtr != NULL, fail); 203 require(value != NULL, fail); 204 require(*sizePtr >= 2, fail); 205 206 *value = (*bytesPtr)[0] << 8 | 207 (*bytesPtr)[1] << 0; 208 209 *bytesPtr += 2; 210 *sizePtr -= 2; 211 212 return errSecSuccess; 213 fail: 214 return errSecParam; 215 } 216 217 static inline OSStatus ReadByte(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint8_t* value) 218 { 219 require(bytesPtr != NULL, fail); 220 require(sizePtr != NULL, fail); 221 require(value != NULL, fail); 222 require(*sizePtr >= 1, fail); 223 224 *value = *bytesPtr[0]; 225 226 *bytesPtr += 1; 227 *sizePtr -= 1; 228 229 return errSecSuccess; 230 fail: 231 return errSecParam; 232 } 233 234 static inline OSStatus ReadByteAsBool(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, bool* value) 235 { 236 uint8_t byte = 0; 237 238 OSStatus result = ReadByte(bytesPtr, sizePtr, &byte); 239 240 if (result == noErr) 241 *value = byte != 0; 242 243 return result; 244 } 245 246 static inline OSStatus ReadMessageType(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, OTRMessageType* type) 247 { 248 OSStatus result = errSecParam; 249 uint8_t value; 250 251 require(type != NULL, fail); 252 require_noerr_quiet(result = ReadByte(bytesPtr, sizePtr, &value), fail); 253 254 *type = value; 255 fail: 256 return result; 257 } 258 259 static inline OSStatus ReadMPI(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x) 260 { 261 require(bytesPtr != NULL, fail); 262 require(sizePtr != NULL, fail); 263 require(x != NULL, fail); 264 require_quiet(*sizePtr >= 5, fail); 265 266 uint32_t mpiLength; 267 268 ReadLong(bytesPtr, sizePtr, &mpiLength); 269 270 require_quiet(mpiLength <= *sizePtr, fail); 271 272 ccn_read_uint(n, x, mpiLength, *bytesPtr); 273 274 *bytesPtr += mpiLength; 275 *sizePtr -= mpiLength; 276 277 return errSecSuccess; 278 fail: 279 return errSecParam; 280 281 } 282 283 static inline OSStatus ReadDATA(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data) 284 { 285 require(bytesPtr != NULL, fail); 286 require(sizePtr != NULL, fail); 287 require(data != NULL, fail); 288 require_quiet(*sizePtr >= 5, fail); 289 290 uint32_t dataLength; 291 292 ReadLong(bytesPtr, sizePtr, &dataLength); 293 294 require_quiet(dataLength <= *sizePtr, fail); 295 memmove(data, bytesPtr, dataLength); 296 297 *bytesPtr += dataLength; 298 *sizePtr -= dataLength; 299 300 *dataSize = dataLength; 301 302 return errSecSuccess; 303 fail: 304 return errSecParam; 305 306 } 307 308 static inline OSStatus CreatePublicKey(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, _Nonnull SecOTRPublicIdentityRef *_Nonnull publicId) 309 { 310 require(bytesPtr != NULL, fail); 311 require(sizePtr != NULL, fail); 312 require(publicId != NULL, fail); 313 require(*sizePtr >= 7, fail); 314 315 uint16_t type = 0; 316 ReadShort(bytesPtr, sizePtr, &type); 317 318 require_quiet(type == 0xF000, fail); 319 require_quiet(*sizePtr >= 5, fail); 320 321 uint32_t serializedIDLength = 0; 322 ReadLong(bytesPtr, sizePtr, &serializedIDLength); 323 324 require_quiet(*sizePtr >= serializedIDLength, fail); 325 require_quiet(((CFIndex)serializedIDLength) >= 0, fail); 326 327 CFDataRef serializedBytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, *bytesPtr, (CFIndex)serializedIDLength, kCFAllocatorNull); 328 329 *publicId = SecOTRPublicIdentityCreateFromData(kCFAllocatorDefault, serializedBytes, NULL); 330 331 *bytesPtr += serializedIDLength; 332 *sizePtr -= serializedIDLength; 333 334 if(serializedBytes) 335 CFRelease(serializedBytes); 336 337 return errSecSuccess; 338 fail: 339 return errSecParam; 340 341 } 342 343 static inline CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef _Nullable allocator, const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr) 344 { 345 CFMutableDataRef result = NULL; 346 uint32_t sizeInStream; 347 require_noerr_quiet(ReadLong(bytesPtr, sizePtr, &sizeInStream), exit); 348 require_quiet(sizeInStream <= *sizePtr, exit); 349 require_quiet(((CFIndex)sizeInStream) >= 0, exit); 350 351 result = CFDataCreateMutable(allocator, 0); 352 353 CFDataAppendBytes(result, *bytesPtr, (CFIndex)sizeInStream); 354 355 *bytesPtr += sizeInStream; 356 *sizePtr -= sizeInStream; 357 358 exit: 359 return result; 360 } 361 362 363 // 364 // Parse and verify functions 365 // 366 static inline OSStatus ReadAndVerifyByte(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint8_t expected) 367 { 368 uint8_t found; 369 OSStatus result = ReadByte(bytes, size, &found); 370 require_noerr_quiet(result, exit); 371 require_action_quiet(found == expected, exit, result = errSecDecode); 372 exit: 373 return result; 374 } 375 376 static inline OSStatus ReadAndVerifyShort(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint16_t expected) 377 { 378 uint16_t found; 379 OSStatus result = ReadShort(bytes, size, &found); 380 require_noerr_quiet(result, exit); 381 require_action_quiet(found == expected, exit, result = errSecDecode); 382 exit: 383 return result; 384 } 385 386 static inline OSStatus ReadAndVerifyMessageType(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType expected) 387 { 388 OTRMessageType found; 389 OSStatus result = ReadMessageType(bytes, size, &found); 390 require_noerr_quiet(result, exit); 391 require_action_quiet(found == expected, exit, result = errSecDecode); 392 exit: 393 return result; 394 } 395 396 static inline OSStatus ReadAndVerifyVersion(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size) 397 { 398 return ReadAndVerifyShort(bytes, size, kCurrentOTRVersion); 399 } 400 401 static inline OSStatus ReadAndVerifyHeader(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType expected) 402 { 403 OSStatus result = ReadAndVerifyVersion(bytes, size); 404 require_noerr_quiet(result, exit); 405 406 result = ReadAndVerifyMessageType(bytes, size, expected); 407 require_noerr_quiet(result, exit); 408 409 exit: 410 return result; 411 } 412 413 static inline OSStatus ReadHeader(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType *messageType) 414 { 415 OSStatus result = ReadAndVerifyVersion(bytes, size); 416 require_noerr_quiet(result, exit); 417 418 result = ReadMessageType(bytes, size, messageType); 419 require_noerr_quiet(result, exit); 420 421 exit: 422 return result; 423 } 424 425 static inline OSStatus SizeAndSkipDATA(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size, 426 const uint8_t *_Nonnull *_Nonnull dataBytes, size_t *dataSize) 427 { 428 OSStatus result; 429 uint32_t sizeRead; 430 result = ReadLong(bytes, size, &sizeRead); 431 432 require_noerr_quiet(result, exit); 433 require_action_quiet(sizeRead <= *size, exit, result = errSecDecode); 434 435 *dataSize = sizeRead; 436 *dataBytes = *bytes; 437 *bytes += sizeRead; 438 *size -= sizeRead; 439 exit: 440 return result; 441 } 442 443 static inline OSStatus SizeAndSkipMPI(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size, 444 const uint8_t *_Nonnull *_Nonnull mpiBytes, size_t *mpiSize) 445 { 446 // MPIs looke like data for skipping. 447 return SizeAndSkipDATA(bytes, size, mpiBytes, mpiSize); 448 } 449 450 451 // 452 // Appending functions 453 // 454 static inline void AppendLongLongCompact(CFMutableDataRef appendTo, uint64_t value) 455 { 456 uint8_t compact[(sizeof(value) * 8 + 7) / 7]; // We can only need enough bytes to hold 8/7 expansion. 457 458 uint8_t *end = compact + sizeof(compact); 459 uint8_t *lastFilled = end; 460 461 --lastFilled; 462 *lastFilled = (value & 0x7F); 463 464 for (value >>= 7; value != 0; value >>= 7) { 465 --lastFilled; 466 *lastFilled = (value & 0x7f) | 0x80; 467 } 468 469 CFDataAppendBytes(appendTo, lastFilled, end - lastFilled); 470 } 471 472 static inline void AppendLongLong(CFMutableDataRef appendTo, uint64_t value) 473 { 474 uint8_t bigEndian[sizeof(value)] = { value >> 56, value >> 48, value >> 40, value >> 32, 475 value >> 24, value >> 16, value >> 8 , value >> 0 }; 476 477 CFDataAppendBytes(appendTo, bigEndian, sizeof(bigEndian)); 478 } 479 480 static inline void AppendLong(CFMutableDataRef appendTo, uint32_t value) 481 { 482 uint8_t bigEndian[sizeof(value)] = { value >> 24, value >> 16, value >> 8, value }; 483 484 CFDataAppendBytes(appendTo, bigEndian, sizeof(bigEndian)); 485 } 486 487 static inline void AppendShort(CFMutableDataRef appendTo, uint16_t value) 488 { 489 uint8_t bigEndian[sizeof(value)] = { value >> 8, value }; 490 491 CFDataAppendBytes(appendTo, bigEndian, sizeof(bigEndian)); 492 } 493 494 static inline void AppendByte(CFMutableDataRef appendTo, uint8_t byte) 495 { 496 CFDataAppendBytes(appendTo, &byte, 1); 497 } 498 499 static inline void AppendMessageType(CFMutableDataRef appendTo, OTRMessageType type) 500 { 501 AppendByte(appendTo, type); 502 } 503 504 static inline void AppendMPI(CFMutableDataRef appendTo, cc_size n, const cc_unit *x) 505 { 506 size_t size = ccn_write_uint_size(n, x); 507 /* 64 bits cast: we are appending an identity, whose size is hardcoded and less then 2^32 bytes */ 508 /* Worst case is we encoded a truncated length. No security issue. */ 509 assert(size<UINT32_MAX); /* Debug check */ 510 AppendLong(appendTo, (uint32_t)size); 511 assert(((CFIndex)size) >= 0); 512 CFIndex startOffset = CFDataGetLength(appendTo); 513 CFDataIncreaseLength(appendTo, (CFIndex)size); 514 uint8_t* insertionPtr = CFDataGetMutableBytePtr(appendTo) + startOffset; 515 ccn_write_uint(n, x, size, insertionPtr); 516 } 517 518 static inline void AppendDATA(CFMutableDataRef appendTo, size_t size, const uint8_t*data) 519 { 520 /* 64 bits cast: we are appending Public Key or Signature, whose sizes are hardcoded and less then 2^32 bytes */ 521 /* Worst case is we encoded a truncated length. No security issue. */ 522 assert(size<=UINT32_MAX); /* Debug check */ 523 AppendLong(appendTo, (uint32_t)size); 524 assert(((CFIndex)size) >= 0); 525 CFDataAppendBytes(appendTo, data, (CFIndex)size); 526 } 527 528 static inline void AppendCFDataAsDATA(CFMutableDataRef appendTo, CFDataRef dataToAppend) 529 { 530 AppendDATA(appendTo, (size_t)CFDataGetLength(dataToAppend), CFDataGetBytePtr(dataToAppend)); 531 } 532 533 static inline void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId) 534 { 535 AppendShort(appendTo, 0xF000); // Custom type reserved by no one 536 537 CFMutableDataRef serializedID = CFDataCreateMutable(kCFAllocatorDefault, 0); 538 539 SecOTRPIAppendSerialization(publicId, serializedID, NULL); 540 AppendDATA(appendTo, (size_t)CFDataGetLength(serializedID), CFDataGetBytePtr(serializedID)); 541 542 if(serializedID) 543 CFRelease(serializedID); 544 } 545 546 static inline void AppendVersion(CFMutableDataRef appendTo) 547 { 548 AppendShort(appendTo, kCurrentOTRVersion); 549 } 550 551 static inline void AppendHeader(CFMutableDataRef appendTo, OTRMessageType type) 552 { 553 AppendVersion(appendTo); 554 AppendMessageType(appendTo, type); 555 } 556 557 CF_ASSUME_NONNULL_END 558 559 __END_DECLS 560 561 #endif