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