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 <Security/SecOTRPackets.h>
40 #include <AssertMacros.h>
44 static CC_NONNULL((1,2))
45 OSStatus
ReadAndVerifyByte(const uint8_t**bytes
, size_t*size
, uint8_t expected
);
47 static CC_NONNULL((1,2))
48 OSStatus
ReadAndVerifyShort(const uint8_t**bytes
, size_t*size
, uint16_t expected
);
50 static CC_NONNULL((1,2))
51 OSStatus
ReadAndVerifyMessageType(const uint8_t**bytes
, size_t*size
, OTRMessageType expected
);
53 static CC_NONNULL((1,2,3,4))
54 OSStatus
SizeAndSkipDATA(const uint8_t **bytes
, size_t *size
,
55 const uint8_t **dataBytes
, size_t *dataSize
);
56 static CC_NONNULL((1,2,3,4))
57 OSStatus
SizeAndSkipMPI(const uint8_t **bytes
, size_t *size
,
58 const uint8_t **mpiBytes
, size_t *mpiSize
);
61 static CC_NONNULL((1,2,3))
62 OSStatus
ReadLongLongCompact(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
);
64 static CC_NONNULL((1,2,3))
65 OSStatus
ReadLongLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
);
67 static CC_NONNULL((1,2,3))
68 OSStatus
ReadLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint32_t* value
);
70 static CC_NONNULL((1,2,3))
71 OSStatus
ReadShort(const uint8_t**bytesPtr
, size_t*sizePtr
, uint16_t* value
);
73 static CC_NONNULL((1,2,3))
74 OSStatus
ReadByte(const uint8_t**bytesPtr
, size_t*sizePtr
, uint8_t* value
);
76 static CC_NONNULL((1,2,3))
77 OSStatus
ReadMessageType(const uint8_t**bytesPtr
, size_t*sizePtr
, OTRMessageType
* type
);
79 static CC_NONNULL((1,2,4))
80 OSStatus
ReadMPI(const uint8_t**bytesPtr
, size_t*sizePtr
, cc_size n
, cc_unit
*x
);
82 static CC_NONNULL((1,2,3,4))
83 OSStatus
ReadDATA(const uint8_t**bytesPtr
, size_t*sizePtr
, size_t* dataSize
, uint8_t* data
);
85 static CC_NONNULL((1,2,3))
86 OSStatus
CreatePublicKey(const uint8_t**bytesPtr
, size_t*sizePtr
, SecOTRPublicIdentityRef
* publicId
);
88 static CC_NONNULL((1,2,3))
89 CFMutableDataRef
CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator
, const uint8_t**bytesPtr
, size_t*sizePtr
);
91 static CC_NONNULL((1))
92 void AppendLongLongCompact(CFMutableDataRef appendTo
, uint64_t value
);
94 static CC_NONNULL((1))
95 void AppendLongLong(CFMutableDataRef appendTo
, uint64_t value
);
97 static CC_NONNULL((1))
98 void AppendLong(CFMutableDataRef appendTo
, uint32_t value
);
100 static CC_NONNULL((1))
101 void AppendShort(CFMutableDataRef appendTo
, uint16_t value
);
103 static CC_NONNULL((1))
104 void AppendByte(CFMutableDataRef appendTo
, uint8_t type
);
106 static CC_NONNULL((1))
107 void AppendMessageType(CFMutableDataRef appendTo
, OTRMessageType type
);
109 static CC_NONNULL((1,3))
110 void AppendMPI(CFMutableDataRef appendTo
, cc_size n
, const cc_unit
*x
);
112 static CC_NONNULL((1,3))
113 void AppendDATA(CFMutableDataRef appendTo
, size_t size
, const uint8_t*data
);
115 static CC_NONNULL((1,2))
116 void AppendPublicKey(CFMutableDataRef appendTo
, SecOTRPublicIdentityRef publicId
);
120 // Inline implementation
123 static uint16_t kCurrentOTRVersion
= 0x2;
125 static inline OSStatus
ReadLongLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
)
127 require(bytesPtr
!= NULL
, fail
);
128 require(sizePtr
!= NULL
, fail
);
129 require(value
!= NULL
, fail
);
130 require(*sizePtr
>= 8, fail
);
132 *value
= ((uint64_t)(*bytesPtr
)[0]) << 56 |
133 ((uint64_t)(*bytesPtr
)[1]) << 48 |
134 ((uint64_t)(*bytesPtr
)[2]) << 40 |
135 ((uint64_t)(*bytesPtr
)[3]) << 32 |
136 ((uint64_t)(*bytesPtr
)[4]) << 24 |
137 ((uint64_t)(*bytesPtr
)[5]) << 16 |
138 ((uint64_t)(*bytesPtr
)[6]) << 8 |
139 ((uint64_t)(*bytesPtr
)[7]) << 0;
144 return errSecSuccess
;
149 static inline OSStatus
ReadLongLongCompact(const uint8_t**bytesPtr
, size_t*sizePtr
, uint64_t* value
)
151 bool moreBytes
= true;
153 require(bytesPtr
!= NULL
, fail
);
154 require(sizePtr
!= NULL
, fail
);
155 require(value
!= NULL
, fail
);
159 while (moreBytes
&& *sizePtr
> 0) {
160 uint8_t thisByte
= **bytesPtr
;
162 moreBytes
= (0x80 & thisByte
) != 0;
165 *value
|= (thisByte
& 0x7F);
172 return !moreBytes
? errSecSuccess
: errSecDecode
;
175 static inline OSStatus
ReadLong(const uint8_t**bytesPtr
, size_t*sizePtr
, uint32_t* value
)
177 require(bytesPtr
!= NULL
, fail
);
178 require(sizePtr
!= NULL
, fail
);
179 require(value
!= NULL
, fail
);
180 require(*sizePtr
>= 4, fail
);
182 *value
= (uint32_t)(*bytesPtr
)[0] << 24 |
183 (uint32_t)(*bytesPtr
)[1] << 16 |
184 (uint32_t)(*bytesPtr
)[2] << 8 |
185 (uint32_t)(*bytesPtr
)[3] << 0;
190 return errSecSuccess
;
195 static inline OSStatus
ReadShort(const uint8_t**bytesPtr
, size_t*sizePtr
, uint16_t* value
)
197 require(bytesPtr
!= NULL
, fail
);
198 require(sizePtr
!= NULL
, fail
);
199 require(value
!= NULL
, fail
);
200 require(*sizePtr
>= 2, fail
);
202 *value
= (*bytesPtr
)[0] << 8 |
208 return errSecSuccess
;
213 static inline OSStatus
ReadByte(const uint8_t**bytesPtr
, size_t*sizePtr
, uint8_t* value
)
215 require(bytesPtr
!= NULL
, fail
);
216 require(sizePtr
!= NULL
, fail
);
217 require(value
!= NULL
, fail
);
218 require(*sizePtr
>= 1, fail
);
220 *value
= *bytesPtr
[0];
225 return errSecSuccess
;
230 static inline OSStatus
ReadByteAsBool(const uint8_t**bytesPtr
, size_t*sizePtr
, bool* value
)
234 OSStatus result
= ReadByte(bytesPtr
, sizePtr
, &byte
);
242 static inline OSStatus
ReadMessageType(const uint8_t**bytesPtr
, size_t*sizePtr
, OTRMessageType
* type
)
244 OSStatus result
= errSecParam
;
247 require(type
!= NULL
, fail
);
248 require_noerr_quiet(result
= ReadByte(bytesPtr
, sizePtr
, &value
), fail
);
255 static inline OSStatus
ReadMPI(const uint8_t**bytesPtr
, size_t*sizePtr
, cc_size n
, cc_unit
*x
)
257 require(bytesPtr
!= NULL
, fail
);
258 require(sizePtr
!= NULL
, fail
);
259 require(x
!= NULL
, fail
);
260 require_quiet(*sizePtr
>= 5, fail
);
264 ReadLong(bytesPtr
, sizePtr
, &mpiLength
);
266 require_quiet(mpiLength
<= *sizePtr
, fail
);
268 ccn_read_uint(n
, x
, mpiLength
, *bytesPtr
);
270 *bytesPtr
+= mpiLength
;
271 *sizePtr
-= mpiLength
;
273 return errSecSuccess
;
279 static inline OSStatus
ReadDATA(const uint8_t**bytesPtr
, size_t*sizePtr
, size_t* dataSize
, uint8_t* data
)
281 require(bytesPtr
!= NULL
, fail
);
282 require(sizePtr
!= NULL
, fail
);
283 require(data
!= NULL
, fail
);
284 require_quiet(*sizePtr
>= 5, fail
);
288 ReadLong(bytesPtr
, sizePtr
, &dataLength
);
290 require_quiet(dataLength
<= *sizePtr
, fail
);
291 memmove(data
, bytesPtr
, dataLength
);
293 *bytesPtr
+= dataLength
;
294 *sizePtr
-= dataLength
;
296 *dataSize
= dataLength
;
298 return errSecSuccess
;
304 static inline OSStatus
CreatePublicKey(const uint8_t**bytesPtr
, size_t*sizePtr
, SecOTRPublicIdentityRef
* publicId
)
306 require(bytesPtr
!= NULL
, fail
);
307 require(sizePtr
!= NULL
, fail
);
308 require(publicId
!= NULL
, fail
);
309 require(*sizePtr
>= 7, fail
);
312 ReadShort(bytesPtr
, sizePtr
, &type
);
314 require_quiet(type
== 0xF000, fail
);
315 require_quiet(*sizePtr
>= 5, fail
);
317 uint32_t serializedIDLength
= 0;
318 ReadLong(bytesPtr
, sizePtr
, &serializedIDLength
);
320 require_quiet(*sizePtr
>= serializedIDLength
, fail
);
321 require_quiet(((CFIndex
)serializedIDLength
) >= 0, fail
);
323 CFDataRef serializedBytes
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, *bytesPtr
, (CFIndex
)serializedIDLength
, kCFAllocatorNull
);
325 *publicId
= SecOTRPublicIdentityCreateFromData(kCFAllocatorDefault
, serializedBytes
, NULL
);
327 *bytesPtr
+= serializedIDLength
;
328 *sizePtr
-= serializedIDLength
;
331 CFRelease(serializedBytes
);
333 return errSecSuccess
;
339 static inline CFMutableDataRef
CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator
, const uint8_t**bytesPtr
, size_t*sizePtr
)
341 CFMutableDataRef result
= NULL
;
342 uint32_t sizeInStream
;
343 require_noerr_quiet(ReadLong(bytesPtr
, sizePtr
, &sizeInStream
), exit
);
344 require_quiet(sizeInStream
<= *sizePtr
, exit
);
345 require_quiet(((CFIndex
)sizeInStream
) >= 0, exit
);
347 result
= CFDataCreateMutable(allocator
, 0);
349 CFDataAppendBytes(result
, *bytesPtr
, (CFIndex
)sizeInStream
);
351 *bytesPtr
+= sizeInStream
;
352 *sizePtr
-= sizeInStream
;
360 // Parse and verify functions
362 static inline OSStatus
ReadAndVerifyByte(const uint8_t**bytes
, size_t*size
, uint8_t expected
)
365 OSStatus result
= ReadByte(bytes
, size
, &found
);
366 require_noerr_quiet(result
, exit
);
367 require_action_quiet(found
== expected
, exit
, result
= errSecDecode
);
372 static inline OSStatus
ReadAndVerifyShort(const uint8_t**bytes
, size_t*size
, uint16_t expected
)
375 OSStatus result
= ReadShort(bytes
, size
, &found
);
376 require_noerr_quiet(result
, exit
);
377 require_action_quiet(found
== expected
, exit
, result
= errSecDecode
);
382 static inline OSStatus
ReadAndVerifyMessageType(const uint8_t**bytes
, size_t*size
, OTRMessageType expected
)
384 OTRMessageType found
;
385 OSStatus result
= ReadMessageType(bytes
, size
, &found
);
386 require_noerr_quiet(result
, exit
);
387 require_action_quiet(found
== expected
, exit
, result
= errSecDecode
);
392 static inline OSStatus
ReadAndVerifyVersion(const uint8_t**bytes
, size_t*size
)
394 return ReadAndVerifyShort(bytes
, size
, kCurrentOTRVersion
);
397 static inline OSStatus
ReadAndVerifyHeader(const uint8_t**bytes
, size_t*size
, OTRMessageType expected
)
399 OSStatus result
= ReadAndVerifyVersion(bytes
, size
);
400 require_noerr_quiet(result
, exit
);
402 result
= ReadAndVerifyMessageType(bytes
, size
, expected
);
403 require_noerr_quiet(result
, exit
);
409 static inline OSStatus
ReadHeader(const uint8_t**bytes
, size_t*size
, OTRMessageType
*messageType
)
411 OSStatus result
= ReadAndVerifyVersion(bytes
, size
);
412 require_noerr_quiet(result
, exit
);
414 result
= ReadMessageType(bytes
, size
, messageType
);
415 require_noerr_quiet(result
, exit
);
421 static inline OSStatus
SizeAndSkipDATA(const uint8_t **bytes
, size_t *size
,
422 const uint8_t **dataBytes
, size_t *dataSize
)
426 result
= ReadLong(bytes
, size
, &sizeRead
);
428 require_noerr_quiet(result
, exit
);
429 require_action_quiet(sizeRead
<= *size
, exit
, result
= errSecDecode
);
431 *dataSize
= sizeRead
;
439 static inline OSStatus
SizeAndSkipMPI(const uint8_t **bytes
, size_t *size
,
440 const uint8_t **mpiBytes
, size_t *mpiSize
)
442 // MPIs looke like data for skipping.
443 return SizeAndSkipDATA(bytes
, size
, mpiBytes
, mpiSize
);
448 // Appending functions
450 static inline void AppendLongLongCompact(CFMutableDataRef appendTo
, uint64_t value
)
452 uint8_t compact
[(sizeof(value
) * 8 + 7) / 7]; // We can only need enough bytes to hold 8/7 expansion.
454 uint8_t *end
= compact
+ sizeof(compact
);
455 uint8_t *lastFilled
= end
;
458 *lastFilled
= (value
& 0x7F);
460 for (value
>>= 7; value
!= 0; value
>>= 7) {
462 *lastFilled
= (value
& 0x7f) | 0x80;
465 CFDataAppendBytes(appendTo
, lastFilled
, end
- lastFilled
);
468 static inline void AppendLongLong(CFMutableDataRef appendTo
, uint64_t value
)
470 uint8_t bigEndian
[sizeof(value
)] = { value
>> 56, value
>> 48, value
>> 40, value
>> 32,
471 value
>> 24, value
>> 16, value
>> 8 , value
>> 0 };
473 CFDataAppendBytes(appendTo
, bigEndian
, sizeof(bigEndian
));
476 static inline void AppendLong(CFMutableDataRef appendTo
, uint32_t value
)
478 uint8_t bigEndian
[sizeof(value
)] = { value
>> 24, value
>> 16, value
>> 8, value
};
480 CFDataAppendBytes(appendTo
, bigEndian
, sizeof(bigEndian
));
483 static inline void AppendShort(CFMutableDataRef appendTo
, uint16_t value
)
485 uint8_t bigEndian
[sizeof(value
)] = { value
>> 8, value
};
487 CFDataAppendBytes(appendTo
, bigEndian
, sizeof(bigEndian
));
490 static inline void AppendByte(CFMutableDataRef appendTo
, uint8_t byte
)
492 CFDataAppendBytes(appendTo
, &byte
, 1);
495 static inline void AppendMessageType(CFMutableDataRef appendTo
, OTRMessageType type
)
497 AppendByte(appendTo
, type
);
500 static inline void AppendMPI(CFMutableDataRef appendTo
, cc_size n
, const cc_unit
*x
)
502 size_t size
= ccn_write_uint_size(n
, x
);
503 /* 64 bits cast: we are appending an identity, whose size is hardcoded and less then 2^32 bytes */
504 /* Worst case is we encoded a truncated length. No security issue. */
505 assert(size
<UINT32_MAX
); /* Debug check */
506 AppendLong(appendTo
, (uint32_t)size
);
507 assert(((CFIndex
)size
) >= 0);
508 CFIndex startOffset
= CFDataGetLength(appendTo
);
509 CFDataIncreaseLength(appendTo
, (CFIndex
)size
);
510 uint8_t* insertionPtr
= CFDataGetMutableBytePtr(appendTo
) + startOffset
;
511 ccn_write_uint(n
, x
, size
, insertionPtr
);
514 static inline void AppendDATA(CFMutableDataRef appendTo
, size_t size
, const uint8_t*data
)
516 /* 64 bits cast: we are appending Public Key or Signature, whose sizes are hardcoded and less then 2^32 bytes */
517 /* Worst case is we encoded a truncated length. No security issue. */
518 assert(size
<=UINT32_MAX
); /* Debug check */
519 AppendLong(appendTo
, (uint32_t)size
);
520 assert(((CFIndex
)size
) >= 0);
521 CFDataAppendBytes(appendTo
, data
, (CFIndex
)size
);
524 static inline void AppendCFDataAsDATA(CFMutableDataRef appendTo
, CFDataRef dataToAppend
)
526 AppendDATA(appendTo
, (size_t)CFDataGetLength(dataToAppend
), CFDataGetBytePtr(dataToAppend
));
529 static inline void AppendPublicKey(CFMutableDataRef appendTo
, SecOTRPublicIdentityRef publicId
)
531 AppendShort(appendTo
, 0xF000); // Custom type reserved by no one
533 CFMutableDataRef serializedID
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
535 SecOTRPIAppendSerialization(publicId
, serializedID
, NULL
);
536 AppendDATA(appendTo
, (size_t)CFDataGetLength(serializedID
), CFDataGetBytePtr(serializedID
));
539 CFRelease(serializedID
);
542 static inline void AppendVersion(CFMutableDataRef appendTo
)
544 AppendShort(appendTo
, kCurrentOTRVersion
);
547 static inline void AppendHeader(CFMutableDataRef appendTo
, OTRMessageType type
)
549 AppendVersion(appendTo
);
550 AppendMessageType(appendTo
, type
);