]>
Commit | Line | Data |
---|---|---|
427c49bc A |
1 | // |
2 | // SecOTRPacketData.h | |
3 | // libsecurity_libSecOTR | |
4 | // | |
5 | // Created by Mitch Adler on 2/26/11. | |
6 | // Copyright 2011 Apple Inc. All rights reserved. | |
7 | // | |
8 | ||
9 | #ifndef _SECOTRPACKETDATA_H_ | |
10 | #define _SECOTRPACKETDATA_H_ | |
11 | ||
12 | #include <CoreFoundation/CFBase.h> | |
13 | #include <CoreFoundation/CFRuntime.h> | |
14 | #include <CoreFoundation/CFData.h> | |
15 | ||
16 | #include <corecrypto/ccn.h> | |
17 | ||
18 | #include <CommonCrypto/CommonDigest.h> | |
19 | ||
20 | #include <Security/SecBase.h> | |
21 | ||
22 | #include <utilities/SecCFWrappers.h> | |
23 | #include <Security/SecOTRPackets.h> | |
24 | ||
25 | #include <AssertMacros.h> | |
26 | ||
27 | __BEGIN_DECLS | |
28 | ||
29 | static OSStatus ReadAndVerifyByte(const uint8_t**bytes, size_t*size, uint8_t expected); | |
30 | static OSStatus ReadAndVerifyShort(const uint8_t**bytes, size_t*size, uint16_t expected); | |
31 | static OSStatus ReadAndVerifyMessageType(const uint8_t**bytes, size_t*size, OTRMessageType expected); | |
32 | ||
33 | static OSStatus SizeAndSkipDATA(const uint8_t **bytes, size_t *size, | |
34 | const uint8_t **dataBytes, size_t *dataSize); | |
35 | static OSStatus SizeAndSkipMPI(const uint8_t **bytes, size_t *size, | |
36 | const uint8_t **mpiBytes, size_t *mpiSize); | |
37 | ||
38 | ||
39 | static OSStatus ReadLongLong(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value); | |
40 | static OSStatus ReadLong(const uint8_t**bytesPtr, size_t*sizePtr, uint32_t* value); | |
41 | static OSStatus ReadShort(const uint8_t**bytesPtr, size_t*sizePtr, uint16_t* value); | |
42 | static OSStatus ReadByte(const uint8_t**bytesPtr, size_t*sizePtr, uint8_t* value); | |
43 | static OSStatus ReadMessageType(const uint8_t**bytesPtr, size_t*sizePtr, OTRMessageType* type); | |
44 | static OSStatus ReadMPI(const uint8_t**bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x); | |
45 | static OSStatus ReadDATA(const uint8_t**bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data); | |
46 | static OSStatus CreatePublicKey(const uint8_t**bytesPtr, size_t*sizePtr, SecOTRPublicIdentityRef* publicId); | |
47 | static CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator, const uint8_t**bytesPtr, size_t*sizePtr); | |
48 | ||
49 | static void AppendLongLong(CFMutableDataRef appendTo, uint64_t value); | |
50 | static void AppendLong(CFMutableDataRef appendTo, uint32_t value); | |
51 | static void AppendShort(CFMutableDataRef appendTo, uint16_t value); | |
52 | static void AppendByte(CFMutableDataRef appendTo, uint8_t type); | |
53 | static void AppendMessageType(CFMutableDataRef appendTo, OTRMessageType type); | |
54 | static void AppendMPI(CFMutableDataRef appendTo, cc_size n, const cc_unit *x); | |
55 | static void AppendDATA(CFMutableDataRef appendTo, size_t size, const uint8_t*data); | |
56 | static void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId); | |
57 | ||
58 | ||
59 | // | |
60 | // Inline implementation | |
61 | // | |
62 | ||
63 | static uint16_t kCurrentOTRVersion = 0x2; | |
64 | ||
65 | static inline OSStatus ReadLongLong(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value) | |
66 | { | |
67 | require(bytesPtr != NULL, fail); | |
68 | require(sizePtr != NULL, fail); | |
69 | require(value != NULL, fail); | |
70 | require(*sizePtr >= 4, fail); | |
71 | ||
72 | *value = ((uint64_t)(*bytesPtr)[0]) << 56 | | |
73 | ((uint64_t)(*bytesPtr)[1]) << 48 | | |
74 | ((uint64_t)(*bytesPtr)[2]) << 40 | | |
75 | ((uint64_t)(*bytesPtr)[3]) << 32 | | |
76 | ((uint64_t)(*bytesPtr)[4]) << 24 | | |
77 | ((uint64_t)(*bytesPtr)[5]) << 16 | | |
78 | ((uint64_t)(*bytesPtr)[6]) << 8 | | |
79 | ((uint64_t)(*bytesPtr)[7]) << 0; | |
80 | ||
81 | *bytesPtr += 8; | |
82 | *sizePtr -= 8; | |
83 | ||
84 | return errSecSuccess; | |
85 | fail: | |
86 | return errSecParam; | |
87 | } | |
88 | ||
89 | static inline OSStatus ReadLong(const uint8_t**bytesPtr, size_t*sizePtr, uint32_t* value) | |
90 | { | |
91 | require(bytesPtr != NULL, fail); | |
92 | require(sizePtr != NULL, fail); | |
93 | require(value != NULL, fail); | |
94 | require(*sizePtr >= 4, fail); | |
95 | ||
96 | *value = (uint32_t)(*bytesPtr)[0] << 24 | | |
97 | (uint32_t)(*bytesPtr)[1] << 16 | | |
98 | (uint32_t)(*bytesPtr)[2] << 8 | | |
99 | (uint32_t)(*bytesPtr)[3] << 0; | |
100 | ||
101 | *bytesPtr += 4; | |
102 | *sizePtr -= 4; | |
103 | ||
104 | return errSecSuccess; | |
105 | fail: | |
106 | return errSecParam; | |
107 | } | |
108 | ||
109 | static inline OSStatus ReadShort(const uint8_t**bytesPtr, size_t*sizePtr, uint16_t* value) | |
110 | { | |
111 | require(bytesPtr != NULL, fail); | |
112 | require(sizePtr != NULL, fail); | |
113 | require(value != NULL, fail); | |
114 | require(*sizePtr >= 2, fail); | |
115 | ||
116 | *value = (*bytesPtr)[0] << 8 | | |
117 | (*bytesPtr)[1] << 0; | |
118 | ||
119 | *bytesPtr += 2; | |
120 | *sizePtr -= 2; | |
121 | ||
122 | return errSecSuccess; | |
123 | fail: | |
124 | return errSecParam; | |
125 | } | |
126 | ||
127 | static inline OSStatus ReadByte(const uint8_t**bytesPtr, size_t*sizePtr, uint8_t* value) | |
128 | { | |
129 | require(bytesPtr != NULL, fail); | |
130 | require(sizePtr != NULL, fail); | |
131 | require(value != NULL, fail); | |
132 | require(*sizePtr >= 1, fail); | |
133 | ||
134 | *value = *bytesPtr[0]; | |
135 | ||
136 | *bytesPtr += 1; | |
137 | *sizePtr -= 1; | |
138 | ||
139 | return errSecSuccess; | |
140 | fail: | |
141 | return errSecParam; | |
142 | } | |
143 | ||
144 | static inline OSStatus ReadMessageType(const uint8_t**bytesPtr, size_t*sizePtr, OTRMessageType* type) | |
145 | { | |
146 | OSStatus result = errSecParam; | |
147 | uint8_t value; | |
148 | ||
149 | require(type != NULL, fail); | |
150 | require_noerr(result = ReadByte(bytesPtr, sizePtr, &value), fail); | |
151 | ||
152 | *type = value; | |
153 | fail: | |
154 | return result; | |
155 | } | |
156 | ||
157 | static inline OSStatus ReadMPI(const uint8_t**bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x) | |
158 | { | |
159 | require(bytesPtr != NULL, fail); | |
160 | require(sizePtr != NULL, fail); | |
161 | require(x != NULL, fail); | |
162 | require(*sizePtr >= 5, fail); | |
163 | ||
164 | uint32_t mpiLength; | |
165 | ||
166 | ReadLong(bytesPtr, sizePtr, &mpiLength); | |
167 | ||
168 | require(mpiLength <= *sizePtr, fail); | |
169 | ||
170 | ccn_read_uint(n, x, mpiLength, *bytesPtr); | |
171 | ||
172 | *bytesPtr += mpiLength; | |
173 | *sizePtr -= mpiLength; | |
174 | ||
175 | return errSecSuccess; | |
176 | fail: | |
177 | return errSecParam; | |
178 | ||
179 | } | |
180 | ||
181 | static inline OSStatus ReadDATA(const uint8_t**bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data) | |
182 | { | |
183 | require(bytesPtr != NULL, fail); | |
184 | require(sizePtr != NULL, fail); | |
185 | require(data != NULL, fail); | |
186 | require(*sizePtr >= 5, fail); | |
187 | ||
188 | uint32_t dataLength; | |
189 | ||
190 | ReadLong(bytesPtr, sizePtr, &dataLength); | |
191 | ||
192 | require(dataLength <= *sizePtr, fail); | |
193 | memmove(data, bytesPtr, dataLength); | |
194 | ||
195 | *bytesPtr += dataLength; | |
196 | *sizePtr -= dataLength; | |
197 | ||
198 | *dataSize = dataLength; | |
199 | ||
200 | return errSecSuccess; | |
201 | fail: | |
202 | return errSecParam; | |
203 | ||
204 | } | |
205 | ||
206 | static inline OSStatus CreatePublicKey(const uint8_t**bytesPtr, size_t*sizePtr, SecOTRPublicIdentityRef* publicId) | |
207 | { | |
208 | require(bytesPtr != NULL, fail); | |
209 | require(sizePtr != NULL, fail); | |
210 | require(publicId != NULL, fail); | |
211 | require(*sizePtr >= 7, fail); | |
212 | ||
213 | uint16_t type = 0; | |
214 | ReadShort(bytesPtr, sizePtr, &type); | |
215 | ||
216 | require(type == 0xF000, fail); | |
217 | require(*sizePtr >= 5, fail); | |
218 | ||
219 | uint32_t serializedIDLength = 0; | |
220 | ReadLong(bytesPtr, sizePtr, &serializedIDLength); | |
221 | ||
222 | require(*sizePtr >= serializedIDLength, fail); | |
223 | require(((CFIndex)serializedIDLength) >= 0, fail); | |
224 | ||
225 | CFDataRef serializedBytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, *bytesPtr, (CFIndex)serializedIDLength, kCFAllocatorNull); | |
226 | ||
227 | *publicId = SecOTRPublicIdentityCreateFromData(kCFAllocatorDefault, serializedBytes, NULL); | |
228 | ||
229 | *bytesPtr += serializedIDLength; | |
230 | *sizePtr -= serializedIDLength; | |
231 | ||
232 | CFReleaseNull(serializedBytes); | |
233 | ||
234 | return errSecSuccess; | |
235 | fail: | |
236 | return errSecParam; | |
237 | ||
238 | } | |
239 | ||
240 | static inline CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator, const uint8_t**bytesPtr, size_t*sizePtr) | |
241 | { | |
242 | CFMutableDataRef result = NULL; | |
243 | uint32_t sizeInStream; | |
244 | require_noerr(ReadLong(bytesPtr, sizePtr, &sizeInStream), exit); | |
245 | require(sizeInStream <= *sizePtr, exit); | |
246 | require(((CFIndex)sizeInStream) >= 0, exit); | |
247 | ||
248 | result = CFDataCreateMutable(allocator, 0); | |
249 | ||
250 | CFDataAppendBytes(result, *bytesPtr, (CFIndex)sizeInStream); | |
251 | ||
252 | *bytesPtr += sizeInStream; | |
253 | *sizePtr += sizeInStream; | |
254 | ||
255 | exit: | |
256 | return result; | |
257 | } | |
258 | ||
259 | ||
260 | // | |
261 | // Parse and verify functions | |
262 | // | |
263 | static inline OSStatus ReadAndVerifyByte(const uint8_t**bytes, size_t*size, uint8_t expected) | |
264 | { | |
265 | uint8_t found; | |
266 | OSStatus result = ReadByte(bytes, size, &found); | |
267 | require_noerr(result, exit); | |
268 | require_action(found == expected, exit, result = errSecDecode); | |
269 | exit: | |
270 | return result; | |
271 | } | |
272 | ||
273 | static inline OSStatus ReadAndVerifyShort(const uint8_t**bytes, size_t*size, uint16_t expected) | |
274 | { | |
275 | uint16_t found; | |
276 | OSStatus result = ReadShort(bytes, size, &found); | |
277 | require_noerr(result, exit); | |
278 | require_action(found == expected, exit, result = errSecDecode); | |
279 | exit: | |
280 | return result; | |
281 | } | |
282 | ||
283 | static inline OSStatus ReadAndVerifyMessageType(const uint8_t**bytes, size_t*size, OTRMessageType expected) | |
284 | { | |
285 | OTRMessageType found; | |
286 | OSStatus result = ReadMessageType(bytes, size, &found); | |
287 | require_noerr(result, exit); | |
288 | require_action(found == expected, exit, result = errSecDecode); | |
289 | exit: | |
290 | return result; | |
291 | } | |
292 | ||
293 | static inline OSStatus ReadAndVerifyVersion(const uint8_t**bytes, size_t*size) | |
294 | { | |
295 | return ReadAndVerifyShort(bytes, size, kCurrentOTRVersion); | |
296 | } | |
297 | ||
298 | static inline OSStatus ReadAndVerifyHeader(const uint8_t**bytes, size_t*size, OTRMessageType expected) | |
299 | { | |
300 | OSStatus result = ReadAndVerifyVersion(bytes, size); | |
301 | require_noerr(result, exit); | |
302 | ||
303 | result = ReadAndVerifyMessageType(bytes, size, expected); | |
304 | require_noerr(result, exit); | |
305 | ||
306 | exit: | |
307 | return result; | |
308 | } | |
309 | ||
310 | static inline OSStatus ReadHeader(const uint8_t**bytes, size_t*size, OTRMessageType *messageType) | |
311 | { | |
312 | OSStatus result = ReadAndVerifyVersion(bytes, size); | |
313 | require_noerr(result, exit); | |
314 | ||
315 | result = ReadMessageType(bytes, size, messageType); | |
316 | require_noerr(result, exit); | |
317 | ||
318 | exit: | |
319 | return result; | |
320 | } | |
321 | ||
322 | static inline OSStatus SizeAndSkipDATA(const uint8_t **bytes, size_t *size, | |
323 | const uint8_t **dataBytes, size_t *dataSize) | |
324 | { | |
325 | OSStatus result; | |
326 | uint32_t sizeRead; | |
327 | result = ReadLong(bytes, size, &sizeRead); | |
328 | ||
329 | require_noerr(result, exit); | |
330 | require_action(sizeRead <= *size, exit, result = errSecDecode); | |
331 | ||
332 | *dataSize = sizeRead; | |
333 | *dataBytes = *bytes; | |
334 | *bytes += sizeRead; | |
335 | *size -= sizeRead; | |
336 | exit: | |
337 | return result; | |
338 | } | |
339 | ||
340 | static inline OSStatus SizeAndSkipMPI(const uint8_t **bytes, size_t *size, | |
341 | const uint8_t **mpiBytes, size_t *mpiSize) | |
342 | { | |
343 | // MPIs looke like data for skipping. | |
344 | return SizeAndSkipDATA(bytes, size, mpiBytes, mpiSize); | |
345 | } | |
346 | ||
347 | ||
348 | // | |
349 | // Appending functions | |
350 | // | |
351 | static inline void AppendLongLong(CFMutableDataRef appendTo, uint64_t value) | |
352 | { | |
353 | uint8_t bigEndian[sizeof(value)] = { value >> 56, value >> 48, value >> 40, value >> 32, | |
354 | value >> 24, value >> 16, value >> 8 , value >> 0 }; | |
355 | ||
356 | CFDataAppendBytes(appendTo, bigEndian, sizeof(bigEndian)); | |
357 | } | |
358 | ||
359 | static inline void AppendLong(CFMutableDataRef appendTo, uint32_t value) | |
360 | { | |
361 | uint8_t bigEndian[sizeof(value)] = { value >> 24, value >> 16, value >> 8, value }; | |
362 | ||
363 | CFDataAppendBytes(appendTo, bigEndian, sizeof(bigEndian)); | |
364 | } | |
365 | ||
366 | static inline void AppendShort(CFMutableDataRef appendTo, uint16_t value) | |
367 | { | |
368 | uint8_t bigEndian[sizeof(value)] = { value >> 8, value }; | |
369 | ||
370 | CFDataAppendBytes(appendTo, bigEndian, sizeof(bigEndian)); | |
371 | } | |
372 | ||
373 | static inline void AppendByte(CFMutableDataRef appendTo, uint8_t byte) | |
374 | { | |
375 | CFDataAppendBytes(appendTo, &byte, 1); | |
376 | } | |
377 | ||
378 | static inline void AppendMessageType(CFMutableDataRef appendTo, OTRMessageType type) | |
379 | { | |
380 | AppendByte(appendTo, type); | |
381 | } | |
382 | ||
383 | static inline void AppendMPI(CFMutableDataRef appendTo, cc_size n, const cc_unit *x) | |
384 | { | |
385 | size_t size = ccn_write_uint_size(n, x); | |
386 | /* 64 bits cast: we are appending an identity, whose size is hardcoded and less then 2^32 bytes */ | |
387 | /* Worst case is we encoded a truncated length. No security issue. */ | |
388 | assert(size<UINT32_MAX); /* Debug check */ | |
389 | AppendLong(appendTo, (uint32_t)size); | |
390 | assert(((CFIndex)size) >= 0); | |
391 | uint8_t* insertionPtr = CFDataIncreaseLengthAndGetMutableBytes(appendTo, (CFIndex)size); | |
392 | ccn_write_uint(n, x, size, insertionPtr); | |
393 | } | |
394 | ||
395 | static inline void AppendDATA(CFMutableDataRef appendTo, size_t size, const uint8_t*data) | |
396 | { | |
397 | /* 64 bits cast: we are appending Public Key or Signature, whose sizes are hardcoded and less then 2^32 bytes */ | |
398 | /* Worst case is we encoded a truncated length. No security issue. */ | |
399 | assert(size<=UINT32_MAX); /* Debug check */ | |
400 | AppendLong(appendTo, (uint32_t)size); | |
401 | assert(((CFIndex)size) >= 0); | |
402 | CFDataAppendBytes(appendTo, data, (CFIndex)size); | |
403 | } | |
404 | ||
405 | static inline void AppendCFDataAsDATA(CFMutableDataRef appendTo, CFDataRef dataToAppend) | |
406 | { | |
407 | AppendDATA(appendTo, (size_t)CFDataGetLength(dataToAppend), CFDataGetBytePtr(dataToAppend)); | |
408 | } | |
409 | ||
410 | static inline void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId) | |
411 | { | |
412 | AppendShort(appendTo, 0xF000); // Custom type reserved by no one | |
413 | ||
414 | CFMutableDataRef serializedID = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
415 | ||
416 | SecOTRPIAppendSerialization(publicId, serializedID, NULL); | |
417 | AppendDATA(appendTo, (size_t)CFDataGetLength(serializedID), CFDataGetBytePtr(serializedID)); | |
418 | ||
419 | CFReleaseNull(serializedID); | |
420 | } | |
421 | ||
422 | static inline void AppendVersion(CFMutableDataRef appendTo) | |
423 | { | |
424 | AppendShort(appendTo, kCurrentOTRVersion); | |
425 | } | |
426 | ||
427 | static inline void AppendHeader(CFMutableDataRef appendTo, OTRMessageType type) | |
428 | { | |
429 | AppendVersion(appendTo); | |
430 | AppendMessageType(appendTo, type); | |
431 | } | |
432 | ||
433 | __END_DECLS | |
434 | ||
435 | #endif |