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