/ OSX / sec / Security / SecOTRPacketData.h
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