2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include "SecOTRIdentityPriv.h"
27 #include <utilities/array_size.h>
28 #include <utilities/SecCFError.h>
29 #include <utilities/SecCFWrappers.h>
31 #include <AssertMacros.h>
33 #include <CoreFoundation/CFNumber.h>
34 #include <CoreFoundation/CFString.h>
35 #include <CoreFoundation/CFData.h>
37 #include <Security/SecItem.h>
38 #include <Security/SecItemPriv.h>
39 #include <Security/SecKeyPriv.h>
41 #include <Security/oidsalg.h>
42 #include <Security/SecCertificatePriv.h>
44 #include "SecOTRErrors.h"
46 #include <TargetConditionals.h>
49 // Algorthim ID initialization
52 #define kMessageIdentityRSAKeyBits 1280
53 #define kMessageIdentityECKeyBits 256
55 const SecAsn1AlgId
*kOTRSignatureAlgIDPtr
;
57 void EnsureOTRAlgIDInited(void)
59 static dispatch_once_t kSignatureAlgID_ONCE
;
60 static SecAsn1AlgId kOTRECSignatureAlgID
;
62 dispatch_once(&kSignatureAlgID_ONCE
, ^{
63 kOTRECSignatureAlgID
.algorithm
= CSSMOID_ECDSA_WithSHA1
;
64 kOTRSignatureAlgIDPtr
= &kOTRECSignatureAlgID
;
69 static CFStringRef sSigningKeyName
= CFSTR("OTR Signing Key");
72 // SecOTRFullIdentity implementation
75 CFGiblisFor(SecOTRFullIdentity
);
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>"),
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]);
87 static void SecOTRFullIdentityDestroy(CFTypeRef cf
) {
88 SecOTRFullIdentityRef requestor
= (SecOTRFullIdentityRef
)cf
;
90 CFReleaseNull(requestor
->privateSigningKey
);
91 CFReleaseNull(requestor
->publicSigningKey
);
92 CFReleaseNull(requestor
->privateKeyPersistentRef
);
100 static OSStatus
SecOTRFIPurgeFromKeychainByValue(SecKeyRef key
, CFStringRef label
)
103 const void *keys
[] = { kSecClass
,
107 const void *values
[] = { kSecClassKey
,
111 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
, array_size(values
), NULL
, NULL
);
112 status
= SecItemDelete(dict
);
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 */
127 OSStatus status
= SecKeyDigestAndSign(key
, algId
, dataToDigest
, dataToDigestLen
, sig
, sigLen
);
128 require_noerr(status
, fail
);
131 SecOTRCreateError(secOTRErrorOSError
, status
, CFSTR("Error signing message. OSStatus in error code."), NULL
, error
);
136 // SecOTRFullIdentity Functions
139 static bool SecOTRFICachePublicHash(SecOTRFullIdentityRef fullID
, CFErrorRef
*error
)
141 SecOTRPublicIdentityRef pubID
= SecOTRPublicIdentityCopyFromPrivate(NULL
, fullID
, error
);
143 require(pubID
, fail
);
145 SecOTRPICopyHash(pubID
, fullID
->publicIDHash
);
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.
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
);
159 const void *signing_keygen_keys
[] = { kSecAttrKeyType
,
160 kSecAttrKeySizeInBits
,
166 const void *signing_keygen_vals
[] = { kSecAttrKeyTypeEC
,
169 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
,
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
),
178 secerror("keygen failed"));
179 SecOTRFIPurgeFromKeychainByValue(publicKey
, sSigningKeyName
);
181 CFReleaseNull(keygen_parameters
);
186 SecOTRFullIdentityRef
SecOTRFullIdentityCreate(CFAllocatorRef allocator
, CFErrorRef
*error
)
188 SecKeyRef signingKey
= SecOTRCreateSigningKey(allocator
);
189 SecOTRFullIdentityRef newID
= SecOTRFullIdentityCreateFromSecKeyRefSOS(allocator
, signingKey
, error
);
190 CFReleaseNull(signingKey
);
197 OSStatus
SecOTRFICreatePrivateKeyReadPersistentRef(const uint8_t **bytes
, size_t *size
, SecKeyRef
* privateKey
, CFDataRef
*newPersistentRef
)
199 OSStatus status
= errSecParam
;
201 CFDataRef foundPersistentRef
= NULL
;
203 require_quiet(newPersistentRef
, fail
);
205 require_noerr_quiet(readSize(bytes
, size
, &dataSize
), fail
);
206 require_quiet(dataSize
<= *size
, fail
);
208 foundPersistentRef
= CFDataCreate(kCFAllocatorDefault
, *bytes
, dataSize
);
209 require_quiet(foundPersistentRef
, fail
);
211 require_noerr_quiet(status
= SecKeyFindWithPersistentRef(foundPersistentRef
, privateKey
), fail
);
216 status
= errSecSuccess
;
218 *newPersistentRef
= foundPersistentRef
;
219 foundPersistentRef
= NULL
;
222 CFReleaseSafe(foundPersistentRef
);
227 OSStatus
SecOTRFICreateKeysFromReadPersistentRef(const uint8_t **bytes
, size_t *size
, SecKeyRef
*publicKey
, SecKeyRef
* privateKey
, CFDataRef
*persistentRef
)
229 SecKeyRef foundKey
= NULL
;
230 CFDataRef foundRef
= NULL
;
232 OSStatus status
= SecOTRFICreatePrivateKeyReadPersistentRef(bytes
, size
, &foundKey
, &foundRef
);
233 require_noerr_quiet(status
, fail
);
235 require_action_quiet(*publicKey
= SecKeyCreatePublicFromPrivate(foundKey
), fail
, status
= errSecInternalComponent
);
237 *privateKey
= foundKey
;
239 *persistentRef
= foundRef
;
243 CFReleaseSafe(foundKey
);
244 CFReleaseSafe(foundRef
);
248 typedef SecKeyRef (*SecOTRPublicKeyCreateFunction
)(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
);
251 OSStatus
SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(const uint8_t **bytes
, size_t *size
, SecKeyRef
*publicKey
, SecKeyRef
* privateKey
, CFDataRef
*persistentRef
, SecOTRPublicKeyCreateFunction createPublic
)
253 SecKeyRef foundKey
= NULL
;
254 CFDataRef foundRef
= NULL
;
256 OSStatus status
= SecOTRFICreatePrivateKeyReadPersistentRef(bytes
, size
, &foundKey
, &foundRef
);
257 require_noerr_quiet(status
, fail
);
259 require_action_quiet(*publicKey
= createPublic(NULL
, bytes
, size
), fail
, status
= errSecInternalComponent
);
261 *privateKey
= foundKey
;
263 *persistentRef
= foundRef
;
267 CFReleaseSafe(foundKey
);
268 CFReleaseSafe(foundRef
);
273 OSStatus
SecOTRFIInitFromV1Bytes(SecOTRFullIdentityRef newID
, CFAllocatorRef allocator
,
274 const uint8_t **bytes
,size_t *size
) {
276 require_action(**bytes
== 1, fail
, status
= errSecParam
);
280 require_noerr_quiet(status
= SecOTRFICreateKeysFromReadPersistentRef(bytes
, size
, &newID
->publicSigningKey
, &newID
->privateSigningKey
, &newID
->privateKeyPersistentRef
), fail
);
285 CFReleaseNull(newID
->publicSigningKey
);
286 CFReleaseNull(newID
->privateSigningKey
);
287 CFReleaseNull(newID
->privateKeyPersistentRef
);
293 OSStatus
SecOTRFIInitFromV2Bytes(SecOTRFullIdentityRef newID
, CFAllocatorRef allocator
,
294 const uint8_t **bytes
,size_t *size
) {
296 require_action(**bytes
== 2, fail
, status
= errSecParam
);
300 require_noerr_quiet(status
= SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(bytes
, size
, &newID
->publicSigningKey
, &newID
->privateSigningKey
, &newID
->privateKeyPersistentRef
, &CreateECPublicKeyFrom
), fail
);
301 newID
->isMessageProtectionKey
= false;
306 CFReleaseNull(newID
->privateKeyPersistentRef
);
307 CFReleaseNull(newID
->publicSigningKey
);
308 CFReleaseNull(newID
->privateSigningKey
);
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
);
322 require_noerr_quiet(readSize(bytes
, size
, &dataSize
), fail
);
324 int32_t keysz32
= 256;
325 CFNumberRef ksizeNumber
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &keysz32
);
326 CFDataRef keyBytes
= CFDataCreate(allocator
, *bytes
, dataSize
);
328 CFDictionaryRef dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
329 kSecAttrKeyType
, kSecAttrKeyTypeECSECPrimeRandom
,
330 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
331 kSecAttrKeySizeInBits
, ksizeNumber
,
332 kSecAttrIsPermanent
, kCFBooleanFalse
, NULL
);
335 SecKeyRef key
= SecKeyCreateWithData(keyBytes
, dict
, &error
);
338 CFReleaseSafe(keyBytes
);
339 CFReleaseSafe(ksizeNumber
);
343 return errSecInvalidData
;
346 newID
->privateKeyPersistentRef
= NULL
;
347 newID
->isMessageProtectionKey
= true;
348 newID
->privateSigningKey
= key
;
349 newID
->publicSigningKey
= SecKeyCopyPublicKey(newID
->privateSigningKey
);
350 status
= errSecSuccess
;
356 // TODO: Probably move to SecKey
357 static CFDataRef
SecKeyCreatePersistentRef(SecKeyRef theKey
, CFErrorRef
*error
) {
358 CFDataRef persistentRef
= NULL
;
359 OSStatus status
= SecKeyCopyPersistentRef(theKey
, &persistentRef
);
361 SecError(status
, error
, CFSTR("failed to find persistent ref for key: %d"), (int)status
);
362 return persistentRef
;
365 SecOTRFullIdentityRef
SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator
, SecKeyRef privateKey
,
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;
376 require(SecOTRFICachePublicHash(newID
, error
), fail
);
379 CFReleaseNull(newID
);
383 SecOTRFullIdentityRef
SecOTRFullIdentityCreateFromSecKeyRefSOS(CFAllocatorRef allocator
, SecKeyRef privateKey
,
385 SecOTRFullIdentityRef newID
= SecOTRFullIdentityCreateFromSecKeyRef(allocator
, privateKey
, error
);
386 require(newID
->privateKeyPersistentRef
= SecKeyCreatePersistentRef(privateKey
, error
), fail
);
387 newID
->isMessageProtectionKey
= false;
390 CFReleaseNull(newID
);
394 SecOTRFullIdentityRef
SecOTRFullIdentityCreateFromBytes(CFAllocatorRef allocator
, const uint8_t**bytes
, size_t *size
, CFErrorRef
*error
)
396 SecOTRFullIdentityRef newID
= CFTypeAllocate(SecOTRFullIdentity
, struct _SecOTRFullIdentity
, allocator
);
397 EnsureOTRAlgIDInited();
399 require(*size
> 0, fail
);
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
));
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
));
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
));
411 case 0: // Version 0 was used in seeds of 5.0, transition from those seeds unsupported - keys were in exported data.
413 SecError(errSecParam
, error
, CFSTR("unknown otr session version %hhu"), **bytes
);
417 require(SecOTRFICachePublicHash(newID
, error
), fail
);
423 SecOTRFIPurgeFromKeychain(newID
, NULL
);
425 CFReleaseSafe(newID
);
429 SecOTRFullIdentityRef
SecOTRFullIdentityCreateFromData(CFAllocatorRef allocator
, CFDataRef data
, CFErrorRef
*error
)
434 size_t size
= (size_t)CFDataGetLength(data
);
435 const uint8_t* bytes
= CFDataGetBytePtr(data
);
437 return SecOTRFullIdentityCreateFromBytes(allocator
, &bytes
, &size
, error
);
440 bool SecOTRFIPurgeFromKeychain(SecOTRFullIdentityRef thisID
, CFErrorRef
*error
)
442 OSStatus result
= SecOTRFIPurgeFromKeychainByValue(thisID
->privateSigningKey
, sSigningKeyName
);
443 if (errSecSuccess
== result
) {
446 SecOTRCreateError(secOTRErrorOSError
, result
, CFSTR("OSStatus returned in error code"), NULL
, error
);
452 static OSStatus
SecOTRFIPurgeAllFromKeychainByLabel(CFStringRef label
)
455 const void *keys
[] = { kSecClass
,
459 const void *values
[] = { kSecClassKey
,
460 kSecAttrKeyClassPrivate
,
463 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
, array_size(values
), NULL
, NULL
);
464 bool deleteAtLeastOne
= false;
465 int loopLimiter
= 500;
467 status
= SecItemDelete(dict
);
468 if (status
== errSecSuccess
) {
469 deleteAtLeastOne
= true;
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
;
485 bool SecOTRFIPurgeAllFromKeychain(CFErrorRef
*error
)
487 OSStatus result
= SecOTRFIPurgeAllFromKeychainByLabel(sSigningKeyName
);
488 if (errSecSuccess
== result
) {
491 SecOTRCreateError(secOTRErrorOSError
, result
, CFSTR("OSStatus returned in error code"), NULL
, error
);
496 static OSStatus
SecOTRFIAppendV3Serialization(SecOTRFullIdentityRef fullID
, CFMutableDataRef serializeInto
)
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
;
509 CFDataSetLength(serializeInto
, start
);
514 static OSStatus
SecOTRFIAppendV2Serialization(SecOTRFullIdentityRef fullID
, CFMutableDataRef serializeInto
)
516 const uint8_t version
= 2;
517 CFIndex start
= CFDataGetLength(serializeInto
);
519 CFDataAppendBytes(serializeInto
, &version
, sizeof(version
));
520 appendSizeAndData(fullID
->privateKeyPersistentRef
, serializeInto
);
521 require(errSecSuccess
== appendPublicOctetsAndSize(fullID
->publicSigningKey
, serializeInto
), fail
);
522 return errSecSuccess
;
525 CFDataSetLength(serializeInto
, start
);
531 bool SecOTRFIAppendSerialization(SecOTRFullIdentityRef fullID
, CFMutableDataRef serializeInto
, CFErrorRef
*error
)
533 OSStatus status
= errSecParam
;
534 if (fullID
->isMessageProtectionKey
) {
535 status
= SecOTRFIAppendV3Serialization(fullID
, serializeInto
);
537 status
= SecOTRFIAppendV2Serialization(fullID
, serializeInto
);
540 if (errSecSuccess
== status
) {
543 SecOTRCreateError(secOTRErrorOSError
, status
, CFSTR("OSStatus returned in error code"), NULL
, error
);
548 size_t SecOTRFISignatureSize(SecOTRFullIdentityRef fullID
)
550 return SecKeyGetSize(fullID
->publicSigningKey
, kSecKeySignatureSize
);
553 bool SecOTRFICompareToPublicKey(SecOTRFullIdentityRef fullID
, SecKeyRef publicKey
) {
554 return CFEqualSafe(fullID
->publicSigningKey
, publicKey
);
557 bool SecOTRFIAppendSignature(SecOTRFullIdentityRef fullID
,
558 CFDataRef dataToHash
,
559 CFMutableDataRef appendTo
,
562 const size_t signatureSize
= SecOTRFISignatureSize(fullID
);
563 const CFIndex sourceLength
= CFDataGetLength(dataToHash
);
564 const uint8_t* sourceData
= CFDataGetBytePtr(dataToHash
);
566 CFIndex start
= CFDataGetLength(appendTo
);
568 require(((CFIndex
)signatureSize
) >= 0, fail
);
570 CFDataIncreaseLength(appendTo
, (CFIndex
)signatureSize
+ 1);
572 uint8_t *size
= CFDataGetMutableBytePtr(appendTo
) + start
;
573 uint8_t* signatureStart
= size
+ 1;
574 size_t signatureUsed
= signatureSize
;
576 require(SecKeyDigestAndSignWithError(fullID
->privateSigningKey
, kOTRSignatureAlgIDPtr
,
577 sourceData
, (size_t)sourceLength
,
578 signatureStart
, &signatureUsed
, error
), fail
);
580 require(signatureUsed
< 256, fail
);
581 require(((CFIndex
)signatureUsed
) >= 0, fail
);
582 *size
= signatureUsed
;
584 CFDataSetLength(appendTo
, start
+ (CFIndex
)signatureUsed
+ 1);
589 CFDataSetLength(appendTo
, start
);
594 void SecOTRFIAppendPublicHash(SecOTRFullIdentityRef fullID
, CFMutableDataRef appendTo
)
596 CFDataAppendBytes(appendTo
, fullID
->publicIDHash
, sizeof(fullID
->publicIDHash
));
599 bool SecOTRFIComparePublicHash(SecOTRFullIdentityRef fullID
, const uint8_t hash
[kMPIDHashSize
])
601 return 0 == memcmp(hash
, fullID
->publicIDHash
, kMPIDHashSize
);