]> git.saurik.com Git - apple/security.git/blame - OSX/sec/Security/SecOTRFullIdentity.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / Security / SecOTRFullIdentity.c
CommitLineData
427c49bc 1/*
d8f41ccd 2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
427c49bc 3 *
d8f41ccd
A
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@
427c49bc
A
22 */
23
d8f41ccd 24
427c49bc
A
25#include "SecOTR.h"
26#include "SecOTRIdentityPriv.h"
27#include <utilities/array_size.h>
5c19dc3a 28#include <utilities/SecCFError.h>
427c49bc
A
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>
fa7225c8 38#include <Security/SecItemPriv.h>
427c49bc
A
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
fa7225c8
A
55const SecAsn1AlgId *kOTRSignatureAlgIDPtr;
56
427c49bc
A
57void 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
69static CFStringRef sSigningKeyName = CFSTR("OTR Signing Key");
70
71//
72// SecOTRFullIdentity implementation
73//
74
75CFGiblisFor(SecOTRFullIdentity);
76
d87e1158 77static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
427c49bc
A
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
87static void SecOTRFullIdentityDestroy(CFTypeRef cf) {
88 SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
89
90 CFReleaseNull(requestor->privateSigningKey);
91 CFReleaseNull(requestor->publicSigningKey);
5c19dc3a 92 CFReleaseNull(requestor->privateKeyPersistentRef);
427c49bc
A
93}
94
95
96//
97// Shared statics
98//
99
100static 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
118static 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;
130fail:
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
139static 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
147fail:
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
5c19dc3a
A
152static SecKeyRef SecOTRCreateSigningKey(CFAllocatorRef allocator) {
153 SecKeyRef publicKey = NULL;
154 SecKeyRef fullKey = NULL;
427c49bc 155 CFDictionaryRef keygen_parameters = NULL;
427c49bc 156 const int signing_keySizeLocal = kMessageIdentityECKeyBits;
5c19dc3a 157 CFNumberRef signing_bitsize = CFNumberCreate(allocator, kCFNumberIntType, &signing_keySizeLocal);
427c49bc
A
158
159 const void *signing_keygen_keys[] = { kSecAttrKeyType,
5c19dc3a
A
160 kSecAttrKeySizeInBits,
161 kSecAttrIsPermanent,
162 kSecAttrAccessible,
163 kSecAttrLabel,
164 };
427c49bc
A
165
166 const void *signing_keygen_vals[] = { kSecAttrKeyTypeEC,
5c19dc3a
A
167 signing_bitsize,
168 kCFBooleanTrue,
fa7225c8 169 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
5c19dc3a
A
170 sSigningKeyName
171 };
172 keygen_parameters = CFDictionaryCreate(allocator,
427c49bc
A
173 signing_keygen_keys, signing_keygen_vals, array_size(signing_keygen_vals),
174 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
175 CFReleaseNull(signing_bitsize);
5c19dc3a
A
176 require_noerr_action(SecKeyGeneratePair(keygen_parameters, &publicKey, &fullKey),
177 errOut,
178 secerror("keygen failed"));
179 SecOTRFIPurgeFromKeychainByValue(publicKey, sSigningKeyName);
427c49bc 180
5c19dc3a
A
181 CFReleaseNull(keygen_parameters);
182errOut:
183 return fullKey;
184}
427c49bc 185
5c19dc3a
A
186SecOTRFullIdentityRef SecOTRFullIdentityCreate(CFAllocatorRef allocator, CFErrorRef *error)
187{
188 SecKeyRef signingKey = SecOTRCreateSigningKey(allocator);
d64be36e 189 SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRefSOS(allocator, signingKey, error);
5c19dc3a 190 CFReleaseNull(signingKey);
427c49bc
A
191
192 return newID;
427c49bc
A
193}
194
195
196static
5c19dc3a 197OSStatus SecOTRFICreatePrivateKeyReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef* privateKey, CFDataRef *newPersistentRef)
427c49bc
A
198{
199 OSStatus status = errSecParam;
200 uint16_t dataSize;
5c19dc3a
A
201 CFDataRef foundPersistentRef = NULL;
202
203 require_quiet(newPersistentRef, fail);
427c49bc
A
204
205 require_noerr_quiet(readSize(bytes, size, &dataSize), fail);
206 require_quiet(dataSize <= *size, fail);
207
5c19dc3a
A
208 foundPersistentRef = CFDataCreate(kCFAllocatorDefault, *bytes, dataSize);
209 require_quiet(foundPersistentRef, fail);
427c49bc 210
5c19dc3a 211 require_noerr_quiet(status = SecKeyFindWithPersistentRef(foundPersistentRef, privateKey), fail);
427c49bc
A
212
213 *bytes += dataSize;
214 *size -= dataSize;
215
216 status = errSecSuccess;
217
5c19dc3a
A
218 *newPersistentRef = foundPersistentRef;
219 foundPersistentRef = NULL;
427c49bc 220
5c19dc3a
A
221fail:
222 CFReleaseSafe(foundPersistentRef);
427c49bc
A
223 return status;
224}
225
226static
5c19dc3a 227OSStatus SecOTRFICreateKeysFromReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey, CFDataRef *persistentRef)
427c49bc
A
228{
229 SecKeyRef foundKey = NULL;
5c19dc3a 230 CFDataRef foundRef = NULL;
427c49bc 231
5c19dc3a 232 OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey, &foundRef);
427c49bc 233 require_noerr_quiet(status, fail);
427c49bc 234
5c19dc3a 235 require_action_quiet(*publicKey = SecKeyCreatePublicFromPrivate(foundKey), fail, status = errSecInternalComponent);
427c49bc
A
236
237 *privateKey = foundKey;
238 foundKey = NULL;
5c19dc3a
A
239 *persistentRef = foundRef;
240 foundRef = NULL;
427c49bc
A
241
242fail:
243 CFReleaseSafe(foundKey);
5c19dc3a 244 CFReleaseSafe(foundRef);
427c49bc
A
245 return status;
246}
247
248typedef SecKeyRef (*SecOTRPublicKeyCreateFunction)(CFAllocatorRef allocator, const uint8_t** data, size_t* limit);
249
250static
5c19dc3a 251OSStatus SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey, CFDataRef *persistentRef, SecOTRPublicKeyCreateFunction createPublic)
427c49bc
A
252{
253 SecKeyRef foundKey = NULL;
5c19dc3a 254 CFDataRef foundRef = NULL;
427c49bc 255
5c19dc3a 256 OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey, &foundRef);
427c49bc 257 require_noerr_quiet(status, fail);
427c49bc 258
5c19dc3a 259 require_action_quiet(*publicKey = createPublic(NULL, bytes, size), fail, status = errSecInternalComponent);
427c49bc
A
260
261 *privateKey = foundKey;
5c19dc3a
A
262 foundKey = NULL;
263 *persistentRef = foundRef;
264 foundRef = NULL;
427c49bc
A
265
266fail:
5c19dc3a
A
267 CFReleaseSafe(foundKey);
268 CFReleaseSafe(foundRef);
427c49bc
A
269 return status;
270}
271
272static
273OSStatus SecOTRFIInitFromV1Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
274 const uint8_t **bytes,size_t *size) {
5c19dc3a
A
275 OSStatus status;
276 require_action(**bytes == 1, fail, status = errSecParam);
427c49bc
A
277 ++*bytes;
278 --*size;
279
5c19dc3a 280 require_noerr_quiet(status = SecOTRFICreateKeysFromReadPersistentRef(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &newID->privateKeyPersistentRef), fail);
427c49bc 281
5c19dc3a 282 return status;
427c49bc
A
283
284fail:
285 CFReleaseNull(newID->publicSigningKey);
286 CFReleaseNull(newID->privateSigningKey);
5c19dc3a 287 CFReleaseNull(newID->privateKeyPersistentRef);
427c49bc 288
5c19dc3a 289 return status;
427c49bc
A
290}
291
292static
293OSStatus SecOTRFIInitFromV2Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
294 const uint8_t **bytes,size_t *size) {
5c19dc3a
A
295 OSStatus status;
296 require_action(**bytes == 2, fail, status = errSecParam);
427c49bc
A
297 ++*bytes;
298 --*size;
299
5c19dc3a 300 require_noerr_quiet(status = SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &newID->privateKeyPersistentRef, &CreateECPublicKeyFrom), fail);
d64be36e
A
301 newID->isMessageProtectionKey = false;
302
5c19dc3a 303 return status;
427c49bc
A
304
305fail:
5c19dc3a 306 CFReleaseNull(newID->privateKeyPersistentRef);
427c49bc
A
307 CFReleaseNull(newID->publicSigningKey);
308 CFReleaseNull(newID->privateSigningKey);
309
5c19dc3a
A
310 return status;
311}
312
d64be36e
A
313static
314OSStatus 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
352fail:
353 return status;
354}
355
5c19dc3a
A
356// TODO: Probably move to SecKey
357static 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;
427c49bc
A
363}
364
365SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator, SecKeyRef privateKey,
366 CFErrorRef *error) {
d64be36e
A
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
383SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRefSOS(CFAllocatorRef allocator, SecKeyRef privateKey,
384 CFErrorRef *error) {
385 SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRef(allocator, privateKey, error);
5c19dc3a 386 require(newID->privateKeyPersistentRef = SecKeyCreatePersistentRef(privateKey, error), fail);
d64be36e 387 newID->isMessageProtectionKey = false;
427c49bc
A
388 return newID;
389fail:
5c19dc3a 390 CFReleaseNull(newID);
427c49bc
A
391 return NULL;
392}
393
394SecOTRFullIdentityRef 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);
5c19dc3a 400 OSStatus status;
427c49bc
A
401 switch (**bytes) {
402 case 1:
5c19dc3a 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));
427c49bc
A
404 break;
405 case 2:
5c19dc3a 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));
427c49bc 407 break;
d64be36e
A
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;
427c49bc
A
411 case 0: // Version 0 was used in seeds of 5.0, transition from those seeds unsupported - keys were in exported data.
412 default:
5c19dc3a
A
413 SecError(errSecParam, error, CFSTR("unknown otr session version %hhu"), **bytes);
414 goto fail;
427c49bc
A
415 }
416
417 require(SecOTRFICachePublicHash(newID, error), fail);
418
419 return newID;
420
421fail:
422 if (NULL != newID) {
423 SecOTRFIPurgeFromKeychain(newID, NULL);
424 }
425 CFReleaseSafe(newID);
426 return NULL;
427}
428
429SecOTRFullIdentityRef 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
440bool 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
452static 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
485bool 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
d64be36e
A
496static 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
508fail:
509 CFDataSetLength(serializeInto, start);
510
511 return errSecParam;
512}
427c49bc
A
513
514static 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));
5c19dc3a 520 appendSizeAndData(fullID->privateKeyPersistentRef, serializeInto);
427c49bc
A
521 require(errSecSuccess == appendPublicOctetsAndSize(fullID->publicSigningKey, serializeInto), fail);
522 return errSecSuccess;
523
524fail:
525 CFDataSetLength(serializeInto, start);
526
527 return errSecParam;
528}
529
530
531bool SecOTRFIAppendSerialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto, CFErrorRef *error)
532{
d64be36e
A
533 OSStatus status = errSecParam;
534 if (fullID->isMessageProtectionKey) {
535 status = SecOTRFIAppendV3Serialization(fullID, serializeInto);
536 } else {
537 status = SecOTRFIAppendV2Serialization(fullID, serializeInto);
538 }
539
427c49bc
A
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
548size_t SecOTRFISignatureSize(SecOTRFullIdentityRef fullID)
549{
550 return SecKeyGetSize(fullID->publicSigningKey, kSecKeySignatureSize);
551}
552
fa7225c8
A
553bool SecOTRFICompareToPublicKey(SecOTRFullIdentityRef fullID, SecKeyRef publicKey) {
554 return CFEqualSafe(fullID->publicSigningKey, publicKey);
555}
556
427c49bc
A
557bool 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
588fail:
589 CFDataSetLength(appendTo, start);
590
591 return false;
592}
593
594void SecOTRFIAppendPublicHash(SecOTRFullIdentityRef fullID, CFMutableDataRef appendTo)
595{
596 CFDataAppendBytes(appendTo, fullID->publicIDHash, sizeof(fullID->publicIDHash));
597}
598
599bool SecOTRFIComparePublicHash(SecOTRFullIdentityRef fullID, const uint8_t hash[kMPIDHashSize])
600{
601 return 0 == memcmp(hash, fullID->publicIDHash, kMPIDHashSize);
602}