]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecOTRFullIdentity.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / sec / Security / SecOTRFullIdentity.c
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 #include "SecOTR.h"
26 #include "SecOTRIdentityPriv.h"
27 #include <utilities/array_size.h>
28 #include <utilities/SecCFError.h>
29 #include <utilities/SecCFWrappers.h>
30
31 #include <AssertMacros.h>
32
33 #include <CoreFoundation/CFNumber.h>
34 #include <CoreFoundation/CFString.h>
35 #include <CoreFoundation/CFData.h>
36
37 #include <Security/SecItem.h>
38 #include <Security/SecItemPriv.h>
39 #include <Security/SecKeyPriv.h>
40
41 #include <Security/oidsalg.h>
42 #include <Security/SecCertificatePriv.h>
43
44 #include "SecOTRErrors.h"
45
46 #include <TargetConditionals.h>
47
48 //
49 // Algorthim ID initialization
50 //
51
52 #define kMessageIdentityRSAKeyBits 1280
53 #define kMessageIdentityECKeyBits 256
54
55 const SecAsn1AlgId *kOTRSignatureAlgIDPtr;
56
57 void EnsureOTRAlgIDInited(void)
58 {
59 static dispatch_once_t kSignatureAlgID_ONCE;
60 static SecAsn1AlgId kOTRECSignatureAlgID;
61
62 dispatch_once(&kSignatureAlgID_ONCE, ^{
63 kOTRECSignatureAlgID.algorithm = CSSMOID_ECDSA_WithSHA1;
64 kOTRSignatureAlgIDPtr = &kOTRECSignatureAlgID;
65 });
66 }
67
68
69 static CFStringRef sSigningKeyName = CFSTR("OTR Signing Key");
70
71 //
72 // SecOTRFullIdentity implementation
73 //
74
75 CFGiblisFor(SecOTRFullIdentity);
76
77 static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
78 SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
79 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
80 requestor,
81 requestor->publicIDHash[0], requestor->publicIDHash[1],
82 requestor->publicIDHash[2], requestor->publicIDHash[3],
83 requestor->publicIDHash[4], requestor->publicIDHash[5],
84 requestor->publicIDHash[6], requestor->publicIDHash[7]);
85 }
86
87 static void SecOTRFullIdentityDestroy(CFTypeRef cf) {
88 SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
89
90 CFReleaseNull(requestor->privateSigningKey);
91 CFReleaseNull(requestor->publicSigningKey);
92 CFReleaseNull(requestor->privateKeyPersistentRef);
93 }
94
95
96 //
97 // Shared statics
98 //
99
100 static OSStatus SecOTRFIPurgeFromKeychainByValue(SecKeyRef key, CFStringRef label)
101 {
102 OSStatus status;
103 const void *keys[] = { kSecClass,
104 kSecAttrLabel,
105 kSecValueRef,
106 };
107 const void *values[] = { kSecClassKey,
108 label,
109 key,
110 };
111 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, array_size(values), NULL, NULL);
112 status = SecItemDelete(dict);
113 CFReleaseSafe(dict);
114
115 return status;
116 }
117
118 static bool SecKeyDigestAndSignWithError(
119 SecKeyRef key, /* Private key */
120 const SecAsn1AlgId *algId, /* algorithm oid/params */
121 const uint8_t *dataToDigest, /* signature over this data */
122 size_t dataToDigestLen,/* length of dataToDigest */
123 uint8_t *sig, /* signature, RETURNED */
124 size_t *sigLen, /* IN/OUT */
125 CFErrorRef *error) {
126
127 OSStatus status = SecKeyDigestAndSign(key, algId, dataToDigest, dataToDigestLen, sig, sigLen);
128 require_noerr(status, fail);
129 return true;
130 fail:
131 SecOTRCreateError(secOTRErrorOSError, status, CFSTR("Error signing message. OSStatus in error code."), NULL, error);
132 return false;
133 }
134
135 //
136 // SecOTRFullIdentity Functions
137 //
138
139 static bool SecOTRFICachePublicHash(SecOTRFullIdentityRef fullID, CFErrorRef *error)
140 {
141 SecOTRPublicIdentityRef pubID = SecOTRPublicIdentityCopyFromPrivate(NULL, fullID, error);
142
143 require(pubID, fail);
144
145 SecOTRPICopyHash(pubID, fullID->publicIDHash);
146
147 fail:
148 CFReleaseSafe(pubID);
149 return (pubID != NULL); // This is safe because we're not accessing the value after release, just checking if it ever had a value of some nature.
150 }
151
152 static SecKeyRef SecOTRCreateSigningKey(CFAllocatorRef allocator) {
153 SecKeyRef publicKey = NULL;
154 SecKeyRef fullKey = NULL;
155 CFDictionaryRef keygen_parameters = NULL;
156 const int signing_keySizeLocal = kMessageIdentityECKeyBits;
157 CFNumberRef signing_bitsize = CFNumberCreate(allocator, kCFNumberIntType, &signing_keySizeLocal);
158
159 const void *signing_keygen_keys[] = { kSecAttrKeyType,
160 kSecAttrKeySizeInBits,
161 kSecAttrIsPermanent,
162 kSecAttrAccessible,
163 kSecAttrLabel,
164 };
165
166 const void *signing_keygen_vals[] = { kSecAttrKeyTypeEC,
167 signing_bitsize,
168 kCFBooleanTrue,
169 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
170 sSigningKeyName
171 };
172 keygen_parameters = CFDictionaryCreate(allocator,
173 signing_keygen_keys, signing_keygen_vals, array_size(signing_keygen_vals),
174 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
175 CFReleaseNull(signing_bitsize);
176 require_noerr_action(SecKeyGeneratePair(keygen_parameters, &publicKey, &fullKey),
177 errOut,
178 secerror("keygen failed"));
179 SecOTRFIPurgeFromKeychainByValue(publicKey, sSigningKeyName);
180
181 CFReleaseNull(keygen_parameters);
182 errOut:
183 return fullKey;
184 }
185
186 SecOTRFullIdentityRef SecOTRFullIdentityCreate(CFAllocatorRef allocator, CFErrorRef *error)
187 {
188 SecKeyRef signingKey = SecOTRCreateSigningKey(allocator);
189 SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRefSOS(allocator, signingKey, error);
190 CFReleaseNull(signingKey);
191
192 return newID;
193 }
194
195
196 static
197 OSStatus SecOTRFICreatePrivateKeyReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef* privateKey, CFDataRef *newPersistentRef)
198 {
199 OSStatus status = errSecParam;
200 uint16_t dataSize;
201 CFDataRef foundPersistentRef = NULL;
202
203 require_quiet(newPersistentRef, fail);
204
205 require_noerr_quiet(readSize(bytes, size, &dataSize), fail);
206 require_quiet(dataSize <= *size, fail);
207
208 foundPersistentRef = CFDataCreate(kCFAllocatorDefault, *bytes, dataSize);
209 require_quiet(foundPersistentRef, fail);
210
211 require_noerr_quiet(status = SecKeyFindWithPersistentRef(foundPersistentRef, privateKey), fail);
212
213 *bytes += dataSize;
214 *size -= dataSize;
215
216 status = errSecSuccess;
217
218 *newPersistentRef = foundPersistentRef;
219 foundPersistentRef = NULL;
220
221 fail:
222 CFReleaseSafe(foundPersistentRef);
223 return status;
224 }
225
226 static
227 OSStatus SecOTRFICreateKeysFromReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey, CFDataRef *persistentRef)
228 {
229 SecKeyRef foundKey = NULL;
230 CFDataRef foundRef = NULL;
231
232 OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey, &foundRef);
233 require_noerr_quiet(status, fail);
234
235 require_action_quiet(*publicKey = SecKeyCreatePublicFromPrivate(foundKey), fail, status = errSecInternalComponent);
236
237 *privateKey = foundKey;
238 foundKey = NULL;
239 *persistentRef = foundRef;
240 foundRef = NULL;
241
242 fail:
243 CFReleaseSafe(foundKey);
244 CFReleaseSafe(foundRef);
245 return status;
246 }
247
248 typedef SecKeyRef (*SecOTRPublicKeyCreateFunction)(CFAllocatorRef allocator, const uint8_t** data, size_t* limit);
249
250 static
251 OSStatus SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey, CFDataRef *persistentRef, SecOTRPublicKeyCreateFunction createPublic)
252 {
253 SecKeyRef foundKey = NULL;
254 CFDataRef foundRef = NULL;
255
256 OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey, &foundRef);
257 require_noerr_quiet(status, fail);
258
259 require_action_quiet(*publicKey = createPublic(NULL, bytes, size), fail, status = errSecInternalComponent);
260
261 *privateKey = foundKey;
262 foundKey = NULL;
263 *persistentRef = foundRef;
264 foundRef = NULL;
265
266 fail:
267 CFReleaseSafe(foundKey);
268 CFReleaseSafe(foundRef);
269 return status;
270 }
271
272 static
273 OSStatus SecOTRFIInitFromV1Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
274 const uint8_t **bytes,size_t *size) {
275 OSStatus status;
276 require_action(**bytes == 1, fail, status = errSecParam);
277 ++*bytes;
278 --*size;
279
280 require_noerr_quiet(status = SecOTRFICreateKeysFromReadPersistentRef(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &newID->privateKeyPersistentRef), fail);
281
282 return status;
283
284 fail:
285 CFReleaseNull(newID->publicSigningKey);
286 CFReleaseNull(newID->privateSigningKey);
287 CFReleaseNull(newID->privateKeyPersistentRef);
288
289 return status;
290 }
291
292 static
293 OSStatus SecOTRFIInitFromV2Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
294 const uint8_t **bytes,size_t *size) {
295 OSStatus status;
296 require_action(**bytes == 2, fail, status = errSecParam);
297 ++*bytes;
298 --*size;
299
300 require_noerr_quiet(status = SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &newID->privateKeyPersistentRef, &CreateECPublicKeyFrom), fail);
301 newID->isMessageProtectionKey = false;
302
303 return status;
304
305 fail:
306 CFReleaseNull(newID->privateKeyPersistentRef);
307 CFReleaseNull(newID->publicSigningKey);
308 CFReleaseNull(newID->privateSigningKey);
309
310 return status;
311 }
312
313 static
314 OSStatus SecOTRFIInitFromV3Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
315 const uint8_t **bytes,size_t *size) {
316 OSStatus status = errSecInvalidData;
317 require_action(**bytes == 3, fail, status = errSecParam);
318 ++*bytes;
319 --*size;
320
321 uint16_t dataSize;
322 require_noerr_quiet(readSize(bytes, size, &dataSize), fail);
323
324 int32_t keysz32 = 256;
325 CFNumberRef ksizeNumber = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
326 CFDataRef keyBytes = CFDataCreate(allocator, *bytes, dataSize);
327
328 CFDictionaryRef dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
329 kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom,
330 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
331 kSecAttrKeySizeInBits, ksizeNumber,
332 kSecAttrIsPermanent, kCFBooleanFalse, NULL);
333
334 CFErrorRef error;
335 SecKeyRef key = SecKeyCreateWithData(keyBytes, dict, &error);
336
337 CFReleaseSafe(dict);
338 CFReleaseSafe(keyBytes);
339 CFReleaseSafe(ksizeNumber);
340
341 if (key == NULL) {
342 CFRelease(error);
343 return errSecInvalidData;
344 }
345
346 newID->privateKeyPersistentRef = NULL;
347 newID->isMessageProtectionKey = true;
348 newID->privateSigningKey = key;
349 newID->publicSigningKey = SecKeyCopyPublicKey(newID->privateSigningKey);
350 status = errSecSuccess;
351
352 fail:
353 return status;
354 }
355
356 // TODO: Probably move to SecKey
357 static CFDataRef SecKeyCreatePersistentRef(SecKeyRef theKey, CFErrorRef *error) {
358 CFDataRef persistentRef = NULL;
359 OSStatus status = SecKeyCopyPersistentRef(theKey, &persistentRef);
360 if (status)
361 SecError(status, error, CFSTR("failed to find persistent ref for key: %d"), (int)status);
362 return persistentRef;
363 }
364
365 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator, SecKeyRef privateKey,
366 CFErrorRef *error) {
367 // TODO - make sure this is an appropriate key type
368 SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
369 CFRetainAssign(newID->privateSigningKey, privateKey);
370 require_action(newID->publicSigningKey = SecKeyCreatePublicFromPrivate(privateKey), fail,
371 SecError(errSecInternalComponent, error, CFSTR("Failed to extract public key from private key")));
372 // MessageProtection keys are no longer having persistent references.
373 newID->privateKeyPersistentRef = NULL;
374 newID->isMessageProtectionKey = true;
375
376 require(SecOTRFICachePublicHash(newID, error), fail);
377 return newID;
378 fail:
379 CFReleaseNull(newID);
380 return NULL;
381 }
382
383 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRefSOS(CFAllocatorRef allocator, SecKeyRef privateKey,
384 CFErrorRef *error) {
385 SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRef(allocator, privateKey, error);
386 require(newID->privateKeyPersistentRef = SecKeyCreatePersistentRef(privateKey, error), fail);
387 newID->isMessageProtectionKey = false;
388 return newID;
389 fail:
390 CFReleaseNull(newID);
391 return NULL;
392 }
393
394 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromBytes(CFAllocatorRef allocator, const uint8_t**bytes, size_t *size, CFErrorRef *error)
395 {
396 SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
397 EnsureOTRAlgIDInited();
398
399 require(*size > 0, fail);
400 OSStatus status;
401 switch (**bytes) {
402 case 1:
403 require_noerr_action_quiet(status = SecOTRFIInitFromV1Bytes(newID, allocator, bytes, size), fail, SecError(status, error, CFSTR("failed to decode v1 otr session: %d"), (int)status));
404 break;
405 case 2:
406 require_noerr_action_quiet(status = SecOTRFIInitFromV2Bytes(newID, allocator, bytes, size), fail, SecError(status, error, CFSTR("failed to decode v2 otr session: %d"), (int)status));
407 break;
408 case 3:
409 require_noerr_action_quiet(status = SecOTRFIInitFromV3Bytes(newID, allocator, bytes, size), fail, SecError(status, error, CFSTR("failed to decode v3 otr session: %d"), (int)status));
410 break;
411 case 0: // Version 0 was used in seeds of 5.0, transition from those seeds unsupported - keys were in exported data.
412 default:
413 SecError(errSecParam, error, CFSTR("unknown otr session version %hhu"), **bytes);
414 goto fail;
415 }
416
417 require(SecOTRFICachePublicHash(newID, error), fail);
418
419 return newID;
420
421 fail:
422 if (NULL != newID) {
423 SecOTRFIPurgeFromKeychain(newID, NULL);
424 }
425 CFReleaseSafe(newID);
426 return NULL;
427 }
428
429 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error)
430 {
431 if (data == NULL)
432 return NULL;
433
434 size_t size = (size_t)CFDataGetLength(data);
435 const uint8_t* bytes = CFDataGetBytePtr(data);
436
437 return SecOTRFullIdentityCreateFromBytes(allocator, &bytes, &size, error);
438 }
439
440 bool SecOTRFIPurgeFromKeychain(SecOTRFullIdentityRef thisID, CFErrorRef *error)
441 {
442 OSStatus result = SecOTRFIPurgeFromKeychainByValue(thisID->privateSigningKey, sSigningKeyName);
443 if (errSecSuccess == result) {
444 return true;
445 } else {
446 SecOTRCreateError(secOTRErrorOSError, result, CFSTR("OSStatus returned in error code"), NULL, error);
447 return false;
448 }
449 }
450
451
452 static OSStatus SecOTRFIPurgeAllFromKeychainByLabel(CFStringRef label)
453 {
454 OSStatus status;
455 const void *keys[] = { kSecClass,
456 kSecAttrKeyClass,
457 kSecAttrLabel,
458 };
459 const void *values[] = { kSecClassKey,
460 kSecAttrKeyClassPrivate,
461 label,
462 };
463 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, array_size(values), NULL, NULL);
464 bool deleteAtLeastOne = false;
465 int loopLimiter = 500;
466 do {
467 status = SecItemDelete(dict);
468 if (status == errSecSuccess) {
469 deleteAtLeastOne = true;
470 }
471 loopLimiter--;
472 } while ((status == errSecSuccess) && (loopLimiter > 0));
473 if ((status == errSecItemNotFound) && (deleteAtLeastOne)) {
474 // We've looped until we can't delete any more keys.
475 // Since this will produce an expected 'itemNotFound', but we don't want to break the contract above
476 // (and also we want to make sense)
477 // we muffle the non-error to a success case, which it is.
478 status = errSecSuccess;
479 }
480 CFReleaseSafe(dict);
481
482 return status;
483 }
484
485 bool SecOTRFIPurgeAllFromKeychain(CFErrorRef *error)
486 {
487 OSStatus result = SecOTRFIPurgeAllFromKeychainByLabel(sSigningKeyName);
488 if (errSecSuccess == result) {
489 return true;
490 } else {
491 SecOTRCreateError(secOTRErrorOSError, result, CFSTR("OSStatus returned in error code"), NULL, error);
492 return false;
493 }
494 }
495
496 static OSStatus SecOTRFIAppendV3Serialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto)
497 {
498 const uint8_t version = 3;
499 CFIndex start = CFDataGetLength(serializeInto);
500 CFDataAppendBytes(serializeInto, &version, sizeof(version));
501 CFErrorRef error = nil;
502 CFDataRef privKeyBytes = SecKeyCopyExternalRepresentation(fullID->privateSigningKey, &error);
503 require(privKeyBytes != nil, fail);
504 appendSizeAndData(privKeyBytes, serializeInto);
505 CFReleaseSafe(privKeyBytes);
506 return errSecSuccess;
507
508 fail:
509 CFDataSetLength(serializeInto, start);
510
511 return errSecParam;
512 }
513
514 static OSStatus SecOTRFIAppendV2Serialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto)
515 {
516 const uint8_t version = 2;
517 CFIndex start = CFDataGetLength(serializeInto);
518
519 CFDataAppendBytes(serializeInto, &version, sizeof(version));
520 appendSizeAndData(fullID->privateKeyPersistentRef, serializeInto);
521 require(errSecSuccess == appendPublicOctetsAndSize(fullID->publicSigningKey, serializeInto), fail);
522 return errSecSuccess;
523
524 fail:
525 CFDataSetLength(serializeInto, start);
526
527 return errSecParam;
528 }
529
530
531 bool SecOTRFIAppendSerialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto, CFErrorRef *error)
532 {
533 OSStatus status = errSecParam;
534 if (fullID->isMessageProtectionKey) {
535 status = SecOTRFIAppendV3Serialization(fullID, serializeInto);
536 } else {
537 status = SecOTRFIAppendV2Serialization(fullID, serializeInto);
538 }
539
540 if (errSecSuccess == status) {
541 return true;
542 } else {
543 SecOTRCreateError(secOTRErrorOSError, status, CFSTR("OSStatus returned in error code"), NULL, error);
544 return false;
545 }
546 }
547
548 size_t SecOTRFISignatureSize(SecOTRFullIdentityRef fullID)
549 {
550 return SecKeyGetSize(fullID->publicSigningKey, kSecKeySignatureSize);
551 }
552
553 bool SecOTRFICompareToPublicKey(SecOTRFullIdentityRef fullID, SecKeyRef publicKey) {
554 return CFEqualSafe(fullID->publicSigningKey, publicKey);
555 }
556
557 bool SecOTRFIAppendSignature(SecOTRFullIdentityRef fullID,
558 CFDataRef dataToHash,
559 CFMutableDataRef appendTo,
560 CFErrorRef *error)
561 {
562 const size_t signatureSize = SecOTRFISignatureSize(fullID);
563 const CFIndex sourceLength = CFDataGetLength(dataToHash);
564 const uint8_t* sourceData = CFDataGetBytePtr(dataToHash);
565
566 CFIndex start = CFDataGetLength(appendTo);
567
568 require(((CFIndex)signatureSize) >= 0, fail);
569
570 CFDataIncreaseLength(appendTo, (CFIndex)signatureSize + 1);
571
572 uint8_t *size = CFDataGetMutableBytePtr(appendTo) + start;
573 uint8_t* signatureStart = size + 1;
574 size_t signatureUsed = signatureSize;
575
576 require(SecKeyDigestAndSignWithError(fullID->privateSigningKey, kOTRSignatureAlgIDPtr,
577 sourceData, (size_t)sourceLength,
578 signatureStart, &signatureUsed, error), fail);
579
580 require(signatureUsed < 256, fail);
581 require(((CFIndex)signatureUsed) >= 0, fail);
582 *size = signatureUsed;
583
584 CFDataSetLength(appendTo, start + (CFIndex)signatureUsed + 1);
585
586 return true;
587
588 fail:
589 CFDataSetLength(appendTo, start);
590
591 return false;
592 }
593
594 void SecOTRFIAppendPublicHash(SecOTRFullIdentityRef fullID, CFMutableDataRef appendTo)
595 {
596 CFDataAppendBytes(appendTo, fullID->publicIDHash, sizeof(fullID->publicIDHash));
597 }
598
599 bool SecOTRFIComparePublicHash(SecOTRFullIdentityRef fullID, const uint8_t hash[kMPIDHashSize])
600 {
601 return 0 == memcmp(hash, fullID->publicIDHash, kMPIDHashSize);
602 }