2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #ifndef _SECOTRPACKETDATA_H_
26 #define _SECOTRPACKETDATA_H_
28 #include <CoreFoundation/CFBase.h>
29 #include <CoreFoundation/CFRuntime.h>
30 #include <CoreFoundation/CFData.h>
32 #include <corecrypto/ccn.h>
34 #include <CommonCrypto/CommonDigest.h>
36 #include <Security/SecBase.h>
38 #include <utilities/SecCFWrappers.h>
39 #include <Security/SecOTRPackets.h>
41 #include <AssertMacros.h>
45 static OSStatus
ReadAndVerifyByte(const uint8_t**bytes
, size_t*size
, uint8_t expected
);
46 static OSStatus
ReadAndVerifyShort(const uint8_t**bytes
, size_t*size
, uint16_t expected
);
47 static OSStatus
ReadAndVerifyMessageType(const uint8_t**bytes
, size_t*size
, OTRMessageType expected
);
49 static OSStatus
SizeAndSkipDATA(const uint8_t **bytes
, size_t *size
,
50 const uint8_t **dataBytes
, size_t *dataSize
);
51 static OSStatus
SizeAndSkipMPI(const uint8_t **bytes
, size_t *size
,
52 const uint8_t **mpiBytes
, size_t *mpiSize
);
55 static OSStatus
ReadLongLongCompact(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
);
56 static OSStatus
ReadLongLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
);
57 static OSStatus
ReadLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint32_t* value
);
58 static OSStatus
ReadShort(const uint8_t**bytesPtr
, size_t*sizePtr
, uint16_t* value
);
59 static OSStatus
ReadByte(const uint8_t**bytesPtr
, size_t*sizePtr
, uint8_t* value
);
60 static OSStatus
ReadMessageType(const uint8_t**bytesPtr
, size_t*sizePtr
, OTRMessageType
* type
);
61 static OSStatus
ReadMPI(const uint8_t**bytesPtr
, size_t*sizePtr
, cc_size n
, cc_unit
*x
);
62 static OSStatus
ReadDATA(const uint8_t**bytesPtr
, size_t*sizePtr
, size_t* dataSize
, uint8_t* data
);
63 static OSStatus
CreatePublicKey(const uint8_t**bytesPtr
, size_t*sizePtr
, SecOTRPublicIdentityRef
* publicId
);
64 static CFMutableDataRef
CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator
, const uint8_t**bytesPtr
, size_t*sizePtr
);
66 static void AppendLongLongCompact(CFMutableDataRef appendTo
, uint64_t value
);
67 static void AppendLongLong(CFMutableDataRef appendTo
, uint64_t value
);
68 static void AppendLong(CFMutableDataRef appendTo
, uint32_t value
);
69 static void AppendShort(CFMutableDataRef appendTo
, uint16_t value
);
70 static void AppendByte(CFMutableDataRef appendTo
, uint8_t type
);
71 static void AppendMessageType(CFMutableDataRef appendTo
, OTRMessageType type
);
72 static void AppendMPI(CFMutableDataRef appendTo
, cc_size n
, const cc_unit
*x
);
73 static void AppendDATA(CFMutableDataRef appendTo
, size_t size
, const uint8_t*data
);
74 static void AppendPublicKey(CFMutableDataRef appendTo
, SecOTRPublicIdentityRef publicId
);
78 // Inline implementation
81 static uint16_t kCurrentOTRVersion
= 0x2;
83 static inline OSStatus
ReadLongLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
)
85 require(bytesPtr
!= NULL
, fail
);
86 require(sizePtr
!= NULL
, fail
);
87 require(value
!= NULL
, fail
);
88 require(*sizePtr
>= 8, fail
);
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;
102 return errSecSuccess
;
107 static inline OSStatus
ReadLongLongCompact(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
)
109 bool moreBytes
= true;
111 require(bytesPtr
!= NULL
, fail
);
112 require(sizePtr
!= NULL
, fail
);
113 require(value
!= NULL
, fail
);
117 while (moreBytes
&& *sizePtr
> 0) {
118 uint8_t thisByte
= **bytesPtr
;
120 moreBytes
= (0x80 & thisByte
) != 0;
123 *value
|= (thisByte
& 0x7F);
130 return !moreBytes
? errSecSuccess
: errSecDecode
;
133 static inline OSStatus
ReadLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint32_t* value
)
135 require(bytesPtr
!= NULL
, fail
);
136 require(sizePtr
!= NULL
, fail
);
137 require(value
!= NULL
, fail
);
138 require(*sizePtr
>= 4, fail
);
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;
148 return errSecSuccess
;
153 static inline OSStatus
ReadShort(const uint8_t**bytesPtr
, size_t*sizePtr
, uint16_t* value
)
155 require(bytesPtr
!= NULL
, fail
);
156 require(sizePtr
!= NULL
, fail
);
157 require(value
!= NULL
, fail
);
158 require(*sizePtr
>= 2, fail
);
160 *value
= (*bytesPtr
)[0] << 8 |
166 return errSecSuccess
;
171 static inline OSStatus
ReadByte(const uint8_t**bytesPtr
, size_t*sizePtr
, uint8_t* value
)
173 require(bytesPtr
!= NULL
, fail
);
174 require(sizePtr
!= NULL
, fail
);
175 require(value
!= NULL
, fail
);
176 require(*sizePtr
>= 1, fail
);
178 *value
= *bytesPtr
[0];
183 return errSecSuccess
;
188 static inline OSStatus
ReadByteAsBool(const uint8_t**bytesPtr
, size_t*sizePtr
, bool* value
)
192 OSStatus result
= ReadByte(bytesPtr
, sizePtr
, &byte
);
200 static inline OSStatus
ReadMessageType(const uint8_t**bytesPtr
, size_t*sizePtr
, OTRMessageType
* type
)
202 OSStatus result
= errSecParam
;
205 require(type
!= NULL
, fail
);
206 require_noerr(result
= ReadByte(bytesPtr
, sizePtr
, &value
), fail
);
213 static inline OSStatus
ReadMPI(const uint8_t**bytesPtr
, size_t*sizePtr
, cc_size n
, cc_unit
*x
)
215 require(bytesPtr
!= NULL
, fail
);
216 require(sizePtr
!= NULL
, fail
);
217 require(x
!= NULL
, fail
);
218 require(*sizePtr
>= 5, fail
);
222 ReadLong(bytesPtr
, sizePtr
, &mpiLength
);
224 require(mpiLength
<= *sizePtr
, fail
);
226 ccn_read_uint(n
, x
, mpiLength
, *bytesPtr
);
228 *bytesPtr
+= mpiLength
;
229 *sizePtr
-= mpiLength
;
231 return errSecSuccess
;
237 static inline OSStatus
ReadDATA(const uint8_t**bytesPtr
, size_t*sizePtr
, size_t* dataSize
, uint8_t* data
)
239 require(bytesPtr
!= NULL
, fail
);
240 require(sizePtr
!= NULL
, fail
);
241 require(data
!= NULL
, fail
);
242 require(*sizePtr
>= 5, fail
);
246 ReadLong(bytesPtr
, sizePtr
, &dataLength
);
248 require(dataLength
<= *sizePtr
, fail
);
249 memmove(data
, bytesPtr
, dataLength
);
251 *bytesPtr
+= dataLength
;
252 *sizePtr
-= dataLength
;
254 *dataSize
= dataLength
;
256 return errSecSuccess
;
262 static inline OSStatus
CreatePublicKey(const uint8_t**bytesPtr
, size_t*sizePtr
, SecOTRPublicIdentityRef
* publicId
)
264 require(bytesPtr
!= NULL
, fail
);
265 require(sizePtr
!= NULL
, fail
);
266 require(publicId
!= NULL
, fail
);
267 require(*sizePtr
>= 7, fail
);
270 ReadShort(bytesPtr
, sizePtr
, &type
);
272 require(type
== 0xF000, fail
);
273 require(*sizePtr
>= 5, fail
);
275 uint32_t serializedIDLength
= 0;
276 ReadLong(bytesPtr
, sizePtr
, &serializedIDLength
);
278 require(*sizePtr
>= serializedIDLength
, fail
);
279 require(((CFIndex
)serializedIDLength
) >= 0, fail
);
281 CFDataRef serializedBytes
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, *bytesPtr
, (CFIndex
)serializedIDLength
, kCFAllocatorNull
);
283 *publicId
= SecOTRPublicIdentityCreateFromData(kCFAllocatorDefault
, serializedBytes
, NULL
);
285 *bytesPtr
+= serializedIDLength
;
286 *sizePtr
-= serializedIDLength
;
288 CFReleaseNull(serializedBytes
);
290 return errSecSuccess
;
296 static inline CFMutableDataRef
CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator
, const uint8_t**bytesPtr
, size_t*sizePtr
)
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
);
304 result
= CFDataCreateMutable(allocator
, 0);
306 CFDataAppendBytes(result
, *bytesPtr
, (CFIndex
)sizeInStream
);
308 *bytesPtr
+= sizeInStream
;
309 *sizePtr
+= sizeInStream
;
317 // Parse and verify functions
319 static inline OSStatus
ReadAndVerifyByte(const uint8_t**bytes
, size_t*size
, uint8_t expected
)
322 OSStatus result
= ReadByte(bytes
, size
, &found
);
323 require_noerr(result
, exit
);
324 require_action(found
== expected
, exit
, result
= errSecDecode
);
329 static inline OSStatus
ReadAndVerifyShort(const uint8_t**bytes
, size_t*size
, uint16_t expected
)
332 OSStatus result
= ReadShort(bytes
, size
, &found
);
333 require_noerr(result
, exit
);
334 require_action(found
== expected
, exit
, result
= errSecDecode
);
339 static inline OSStatus
ReadAndVerifyMessageType(const uint8_t**bytes
, size_t*size
, OTRMessageType expected
)
341 OTRMessageType found
;
342 OSStatus result
= ReadMessageType(bytes
, size
, &found
);
343 require_noerr(result
, exit
);
344 require_action(found
== expected
, exit
, result
= errSecDecode
);
349 static inline OSStatus
ReadAndVerifyVersion(const uint8_t**bytes
, size_t*size
)
351 return ReadAndVerifyShort(bytes
, size
, kCurrentOTRVersion
);
354 static inline OSStatus
ReadAndVerifyHeader(const uint8_t**bytes
, size_t*size
, OTRMessageType expected
)
356 OSStatus result
= ReadAndVerifyVersion(bytes
, size
);
357 require_noerr(result
, exit
);
359 result
= ReadAndVerifyMessageType(bytes
, size
, expected
);
360 require_noerr(result
, exit
);
366 static inline OSStatus
ReadHeader(const uint8_t**bytes
, size_t*size
, OTRMessageType
*messageType
)
368 OSStatus result
= ReadAndVerifyVersion(bytes
, size
);
369 require_noerr(result
, exit
);
371 result
= ReadMessageType(bytes
, size
, messageType
);
372 require_noerr(result
, exit
);
378 static inline OSStatus
SizeAndSkipDATA(const uint8_t **bytes
, size_t *size
,
379 const uint8_t **dataBytes
, size_t *dataSize
)
383 result
= ReadLong(bytes
, size
, &sizeRead
);
385 require_noerr(result
, exit
);
386 require_action(sizeRead
<= *size
, exit
, result
= errSecDecode
);
388 *dataSize
= sizeRead
;
396 static inline OSStatus
SizeAndSkipMPI(const uint8_t **bytes
, size_t *size
,
397 const uint8_t **mpiBytes
, size_t *mpiSize
)
399 // MPIs looke like data for skipping.
400 return SizeAndSkipDATA(bytes
, size
, mpiBytes
, mpiSize
);
405 // Appending functions
407 static inline void AppendLongLongCompact(CFMutableDataRef appendTo
, uint64_t value
)
409 uint8_t compact
[(sizeof(value
) * 8 + 7) / 7]; // We can only need enough bytes to hold 8/7 expansion.
411 uint8_t *end
= compact
+ sizeof(compact
);
412 uint8_t *lastFilled
= end
;
415 *lastFilled
= (value
& 0x7F);
417 for (value
>>= 7; value
!= 0; value
>>= 7) {
419 *lastFilled
= (value
& 0x7f) | 0x80;
422 CFDataAppendBytes(appendTo
, lastFilled
, end
- lastFilled
);
425 static inline void AppendLongLong(CFMutableDataRef appendTo
, uint64_t value
)
427 uint8_t bigEndian
[sizeof(value
)] = { value
>> 56, value
>> 48, value
>> 40, value
>> 32,
428 value
>> 24, value
>> 16, value
>> 8 , value
>> 0 };
430 CFDataAppendBytes(appendTo
, bigEndian
, sizeof(bigEndian
));
433 static inline void AppendLong(CFMutableDataRef appendTo
, uint32_t value
)
435 uint8_t bigEndian
[sizeof(value
)] = { value
>> 24, value
>> 16, value
>> 8, value
};
437 CFDataAppendBytes(appendTo
, bigEndian
, sizeof(bigEndian
));
440 static inline void AppendShort(CFMutableDataRef appendTo
, uint16_t value
)
442 uint8_t bigEndian
[sizeof(value
)] = { value
>> 8, value
};
444 CFDataAppendBytes(appendTo
, bigEndian
, sizeof(bigEndian
));
447 static inline void AppendByte(CFMutableDataRef appendTo
, uint8_t byte
)
449 CFDataAppendBytes(appendTo
, &byte
, 1);
452 static inline void AppendMessageType(CFMutableDataRef appendTo
, OTRMessageType type
)
454 AppendByte(appendTo
, type
);
457 static inline void AppendMPI(CFMutableDataRef appendTo
, cc_size n
, const cc_unit
*x
)
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
);
469 static inline void AppendDATA(CFMutableDataRef appendTo
, size_t size
, const uint8_t*data
)
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
);
479 static inline void AppendCFDataAsDATA(CFMutableDataRef appendTo
, CFDataRef dataToAppend
)
481 AppendDATA(appendTo
, (size_t)CFDataGetLength(dataToAppend
), CFDataGetBytePtr(dataToAppend
));
484 static inline void AppendPublicKey(CFMutableDataRef appendTo
, SecOTRPublicIdentityRef publicId
)
486 AppendShort(appendTo
, 0xF000); // Custom type reserved by no one
488 CFMutableDataRef serializedID
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
490 SecOTRPIAppendSerialization(publicId
, serializedID
, NULL
);
491 AppendDATA(appendTo
, (size_t)CFDataGetLength(serializedID
), CFDataGetBytePtr(serializedID
));
493 CFReleaseNull(serializedID
);
496 static inline void AppendVersion(CFMutableDataRef appendTo
)
498 AppendShort(appendTo
, kCurrentOTRVersion
);
501 static inline void AppendHeader(CFMutableDataRef appendTo
, OTRMessageType type
)
503 AppendVersion(appendTo
);
504 AppendMessageType(appendTo
, type
);