]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecOTRPacketData.h
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / sec / Security / 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