3 * libsecurity_libSecOTR
5 * Created by Mitch Adler on 2/9/11.
6 * Copyright 2011 Apple Inc. All rights reserved.
11 #include "SecOTRIdentityPriv.h"
12 #include <utilities/array_size.h>
13 #include <utilities/SecCFWrappers.h>
15 #include <AssertMacros.h>
17 #include <CoreFoundation/CFNumber.h>
18 #include <CoreFoundation/CFString.h>
19 #include <CoreFoundation/CFData.h>
21 #include <Security/SecItem.h>
22 #include <Security/SecKeyPriv.h>
24 #include <Security/oidsalg.h>
25 #include <Security/SecCertificatePriv.h>
27 #include "SecOTRErrors.h"
29 #include <TargetConditionals.h>
32 // Algorthim ID initialization
35 #define kMessageIdentityRSAKeyBits 1280
36 #define kMessageIdentityECKeyBits 256
38 void EnsureOTRAlgIDInited(void)
40 static dispatch_once_t kSignatureAlgID_ONCE
;
41 static SecAsn1AlgId kOTRECSignatureAlgID
;
43 dispatch_once(&kSignatureAlgID_ONCE
, ^{
44 kOTRECSignatureAlgID
.algorithm
= CSSMOID_ECDSA_WithSHA1
;
45 kOTRSignatureAlgIDPtr
= &kOTRECSignatureAlgID
;
50 static CFStringRef sSigningKeyName
= CFSTR("OTR Signing Key");
53 // SecOTRFullIdentity implementation
56 CFGiblisFor(SecOTRFullIdentity
);
58 static CF_RETURNS_RETAINED CFStringRef
SecOTRFullIdentityCopyDescription(CFTypeRef cf
) {
59 SecOTRFullIdentityRef requestor
= (SecOTRFullIdentityRef
)cf
;
60 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
62 requestor
->publicIDHash
[0], requestor
->publicIDHash
[1],
63 requestor
->publicIDHash
[2], requestor
->publicIDHash
[3],
64 requestor
->publicIDHash
[4], requestor
->publicIDHash
[5],
65 requestor
->publicIDHash
[6], requestor
->publicIDHash
[7]);
68 static void SecOTRFullIdentityDestroy(CFTypeRef cf
) {
69 SecOTRFullIdentityRef requestor
= (SecOTRFullIdentityRef
)cf
;
71 CFReleaseNull(requestor
->privateSigningKey
);
72 CFReleaseNull(requestor
->publicSigningKey
);
80 static OSStatus
SecOTRFIPurgeFromKeychainByValue(SecKeyRef key
, CFStringRef label
)
83 const void *keys
[] = { kSecClass
,
87 const void *values
[] = { kSecClassKey
,
91 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
, array_size(values
), NULL
, NULL
);
92 status
= SecItemDelete(dict
);
98 static bool SecKeyDigestAndSignWithError(
99 SecKeyRef key
, /* Private key */
100 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
101 const uint8_t *dataToDigest
, /* signature over this data */
102 size_t dataToDigestLen
,/* length of dataToDigest */
103 uint8_t *sig
, /* signature, RETURNED */
104 size_t *sigLen
, /* IN/OUT */
107 OSStatus status
= SecKeyDigestAndSign(key
, algId
, dataToDigest
, dataToDigestLen
, sig
, sigLen
);
108 require_noerr(status
, fail
);
111 SecOTRCreateError(secOTRErrorOSError
, status
, CFSTR("Error signing message. OSStatus in error code."), NULL
, error
);
116 // SecOTRFullIdentity Functions
119 static bool SecOTRFICachePublicHash(SecOTRFullIdentityRef fullID
, CFErrorRef
*error
)
121 SecOTRPublicIdentityRef pubID
= SecOTRPublicIdentityCopyFromPrivate(NULL
, fullID
, error
);
123 require(pubID
, fail
);
125 SecOTRPICopyHash(pubID
, fullID
->publicIDHash
);
128 CFReleaseSafe(pubID
);
129 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.
132 #if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
133 #define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
134 SEC_CONST_DECL (kSecAttrAccessible
, "pdmn");
135 SEC_CONST_DECL (kSecAttrAccessibleAlwaysThisDeviceOnly
, "dku");
138 SecOTRFullIdentityRef
SecOTRFullIdentityCreate(CFAllocatorRef allocator
, CFErrorRef
*error
)
140 CFDictionaryRef keygen_parameters
= NULL
;
141 SecOTRFullIdentityRef newID
= CFTypeAllocate(SecOTRFullIdentity
, struct _SecOTRFullIdentity
, allocator
);
142 SecKeyRef tempSigningKey
= NULL
;
144 newID
->publicSigningKey
= NULL
;
145 newID
->privateSigningKey
= NULL
;
149 EnsureOTRAlgIDInited();
151 const int signing_keySizeLocal
= kMessageIdentityECKeyBits
;
152 CFNumberRef signing_bitsize
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &signing_keySizeLocal
);
154 const void *signing_keygen_keys
[] = { kSecAttrKeyType
,
155 kSecAttrKeySizeInBits
,
161 const void *signing_keygen_vals
[] = { kSecAttrKeyTypeEC
,
164 kSecAttrAccessibleAlwaysThisDeviceOnly
,
167 keygen_parameters
= CFDictionaryCreate(kCFAllocatorDefault
,
168 signing_keygen_keys
, signing_keygen_vals
, array_size(signing_keygen_vals
),
169 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
170 CFReleaseNull(signing_bitsize
);
171 require_noerr(SecKeyGeneratePair(keygen_parameters
, &tempSigningKey
, &newID
->privateSigningKey
), out
);
172 CFReleaseNull(keygen_parameters
);
174 newID
->publicSigningKey
= SecKeyCreatePublicFromPrivate(tempSigningKey
);
176 (void) SecOTRFIPurgeFromKeychainByValue(tempSigningKey
, sSigningKeyName
);
177 CFReleaseNull(tempSigningKey
);
179 require(SecOTRFICachePublicHash(newID
, error
), out
);
185 SecOTRFIPurgeFromKeychain(newID
, NULL
);
187 CFReleaseSafe(keygen_parameters
);
188 CFReleaseSafe(newID
);
189 CFReleaseSafe(tempSigningKey
);
195 OSStatus
SecOTRFICreatePrivateKeyReadPersistentRef(const uint8_t **bytes
, size_t *size
, SecKeyRef
* privateKey
)
197 OSStatus status
= errSecParam
;
199 CFDataRef persistentRef
= NULL
;
201 require_noerr_quiet(readSize(bytes
, size
, &dataSize
), fail
);
202 require_quiet(dataSize
<= *size
, fail
);
204 SecKeyRef lookedUpKey
= NULL
;
205 persistentRef
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, *bytes
, dataSize
, kCFAllocatorNull
);
206 require_quiet(persistentRef
, fail
);
208 require_noerr_quiet(SecKeyFindWithPersistentRef(persistentRef
, &lookedUpKey
), fail
);
210 *privateKey
= lookedUpKey
;
215 status
= errSecSuccess
;
218 CFReleaseSafe(persistentRef
);
224 OSStatus
SecOTRFICreateKeysFromReadPersistentRef(const uint8_t **bytes
, size_t *size
, SecKeyRef
*publicKey
, SecKeyRef
* privateKey
)
226 SecKeyRef foundKey
= NULL
;
228 OSStatus status
= SecOTRFICreatePrivateKeyReadPersistentRef(bytes
, size
, &foundKey
);
229 require_noerr_quiet(status
, fail
);
230 require_quiet(foundKey
, fail
);
232 *publicKey
= SecKeyCreatePublicFromPrivate(*privateKey
);
233 require_action_quiet(*publicKey
, fail
, status
= errSecParam
);
235 *privateKey
= foundKey
;
238 status
= errSecSuccess
;
241 CFReleaseSafe(foundKey
);
245 typedef SecKeyRef (*SecOTRPublicKeyCreateFunction
)(CFAllocatorRef allocator
, const uint8_t** data
, size_t* limit
);
248 OSStatus
SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(const uint8_t **bytes
, size_t *size
, SecKeyRef
*publicKey
, SecKeyRef
* privateKey
, SecOTRPublicKeyCreateFunction createPublic
)
250 SecKeyRef foundKey
= NULL
;
252 OSStatus status
= SecOTRFICreatePrivateKeyReadPersistentRef(bytes
, size
, &foundKey
);
253 require_noerr_quiet(status
, fail
);
254 require_quiet(foundKey
, fail
);
256 *publicKey
= (*createPublic
)(NULL
, bytes
, size
);
257 require_action_quiet(*publicKey
, fail
, status
= errSecParam
);
259 *privateKey
= foundKey
;
266 OSStatus
SecOTRFIInitFromV1Bytes(SecOTRFullIdentityRef newID
, CFAllocatorRef allocator
,
267 const uint8_t **bytes
,size_t *size
) {
268 require(**bytes
== 1, fail
);
272 require_noerr_quiet(SecOTRFICreateKeysFromReadPersistentRef(bytes
, size
, &newID
->publicSigningKey
, &newID
->privateSigningKey
), fail
);
274 return errSecSuccess
;
277 CFReleaseNull(newID
->publicSigningKey
);
278 CFReleaseNull(newID
->privateSigningKey
);
284 OSStatus
SecOTRFIInitFromV2Bytes(SecOTRFullIdentityRef newID
, CFAllocatorRef allocator
,
285 const uint8_t **bytes
,size_t *size
) {
286 require(**bytes
== 2, fail
);
290 require_noerr_quiet(SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(bytes
, size
, &newID
->publicSigningKey
, &newID
->privateSigningKey
, &CreateECPublicKeyFrom
), fail
);
292 return errSecSuccess
;
295 CFReleaseNull(newID
->publicSigningKey
);
296 CFReleaseNull(newID
->privateSigningKey
);
301 SecOTRFullIdentityRef
SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator
, SecKeyRef privateKey
,
303 // TODO - make sure this is an appropriate key type
304 SecOTRFullIdentityRef newID
= CFTypeAllocate(SecOTRFullIdentity
, struct _SecOTRFullIdentity
, allocator
);
305 newID
->privateSigningKey
= privateKey
;
306 CFRetain(newID
->privateSigningKey
);
307 newID
->publicSigningKey
= SecKeyCreatePublicFromPrivate(privateKey
);
308 require(SecOTRFICachePublicHash(newID
, error
), fail
);
311 CFRelease(newID
->privateSigningKey
);
312 CFRelease(newID
->publicSigningKey
);
313 CFReleaseSafe(newID
);
317 SecOTRFullIdentityRef
SecOTRFullIdentityCreateFromBytes(CFAllocatorRef allocator
, const uint8_t**bytes
, size_t *size
, CFErrorRef
*error
)
319 SecOTRFullIdentityRef newID
= CFTypeAllocate(SecOTRFullIdentity
, struct _SecOTRFullIdentity
, allocator
);
320 EnsureOTRAlgIDInited();
322 require(*size
> 0, fail
);
326 require_noerr_quiet(SecOTRFIInitFromV1Bytes(newID
, allocator
, bytes
, size
), fail
);
329 require_noerr_quiet(SecOTRFIInitFromV2Bytes(newID
, allocator
, bytes
, size
), fail
);
331 case 0: // Version 0 was used in seeds of 5.0, transition from those seeds unsupported - keys were in exported data.
333 require(false, fail
);
337 require(SecOTRFICachePublicHash(newID
, error
), fail
);
343 SecOTRFIPurgeFromKeychain(newID
, NULL
);
345 CFReleaseSafe(newID
);
349 SecOTRFullIdentityRef
SecOTRFullIdentityCreateFromData(CFAllocatorRef allocator
, CFDataRef data
, CFErrorRef
*error
)
354 size_t size
= (size_t)CFDataGetLength(data
);
355 const uint8_t* bytes
= CFDataGetBytePtr(data
);
357 return SecOTRFullIdentityCreateFromBytes(allocator
, &bytes
, &size
, error
);
360 bool SecOTRFIPurgeFromKeychain(SecOTRFullIdentityRef thisID
, CFErrorRef
*error
)
362 OSStatus result
= SecOTRFIPurgeFromKeychainByValue(thisID
->privateSigningKey
, sSigningKeyName
);
363 if (errSecSuccess
== result
) {
366 SecOTRCreateError(secOTRErrorOSError
, result
, CFSTR("OSStatus returned in error code"), NULL
, error
);
372 static OSStatus
SecOTRFIPurgeAllFromKeychainByLabel(CFStringRef label
)
375 const void *keys
[] = { kSecClass
,
379 const void *values
[] = { kSecClassKey
,
380 kSecAttrKeyClassPrivate
,
383 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
, array_size(values
), NULL
, NULL
);
384 bool deleteAtLeastOne
= false;
385 int loopLimiter
= 500;
387 status
= SecItemDelete(dict
);
388 if (status
== errSecSuccess
) {
389 deleteAtLeastOne
= true;
392 } while ((status
== errSecSuccess
) && (loopLimiter
> 0));
393 if ((status
== errSecItemNotFound
) && (deleteAtLeastOne
)) {
394 // We've looped until we can't delete any more keys.
395 // Since this will produce an expected 'itemNotFound', but we don't want to break the contract above
396 // (and also we want to make sense)
397 // we muffle the non-error to a success case, which it is.
398 status
= errSecSuccess
;
405 bool SecOTRFIPurgeAllFromKeychain(CFErrorRef
*error
)
407 OSStatus result
= SecOTRFIPurgeAllFromKeychainByLabel(sSigningKeyName
);
408 if (errSecSuccess
== result
) {
411 SecOTRCreateError(secOTRErrorOSError
, result
, CFSTR("OSStatus returned in error code"), NULL
, error
);
416 static OSStatus
appendPersistentRefData(SecKeyRef theKey
, CFMutableDataRef serializeInto
, CFStringRef name
)
419 CFDataRef persistent_ref
= NULL
;
420 require_noerr(status
= SecKeyCopyPersistentRef(theKey
, &persistent_ref
), fail
);
422 status
= appendSizeAndData(persistent_ref
, serializeInto
);
425 CFReleaseSafe(persistent_ref
);
430 static OSStatus
SecOTRFIAppendV2Serialization(SecOTRFullIdentityRef fullID
, CFMutableDataRef serializeInto
)
432 const uint8_t version
= 2;
433 CFIndex start
= CFDataGetLength(serializeInto
);
435 CFDataAppendBytes(serializeInto
, &version
, sizeof(version
));
437 require(errSecSuccess
== appendPersistentRefData(fullID
->privateSigningKey
, serializeInto
, sSigningKeyName
), fail
);
438 require(errSecSuccess
== appendPublicOctetsAndSize(fullID
->publicSigningKey
, serializeInto
), fail
);
439 return errSecSuccess
;
442 CFDataSetLength(serializeInto
, start
);
448 bool SecOTRFIAppendSerialization(SecOTRFullIdentityRef fullID
, CFMutableDataRef serializeInto
, CFErrorRef
*error
)
450 OSStatus status
= SecOTRFIAppendV2Serialization(fullID
, serializeInto
);
451 if (errSecSuccess
== status
) {
454 SecOTRCreateError(secOTRErrorOSError
, status
, CFSTR("OSStatus returned in error code"), NULL
, error
);
459 size_t SecOTRFISignatureSize(SecOTRFullIdentityRef fullID
)
461 return SecKeyGetSize(fullID
->publicSigningKey
, kSecKeySignatureSize
);
464 bool SecOTRFIAppendSignature(SecOTRFullIdentityRef fullID
,
465 CFDataRef dataToHash
,
466 CFMutableDataRef appendTo
,
469 const size_t signatureSize
= SecOTRFISignatureSize(fullID
);
470 const CFIndex sourceLength
= CFDataGetLength(dataToHash
);
471 const uint8_t* sourceData
= CFDataGetBytePtr(dataToHash
);
473 CFIndex start
= CFDataGetLength(appendTo
);
475 require(((CFIndex
)signatureSize
) >= 0, fail
);
477 CFDataIncreaseLength(appendTo
, (CFIndex
)signatureSize
+ 1);
479 uint8_t *size
= CFDataGetMutableBytePtr(appendTo
) + start
;
480 uint8_t* signatureStart
= size
+ 1;
481 size_t signatureUsed
= signatureSize
;
483 require(SecKeyDigestAndSignWithError(fullID
->privateSigningKey
, kOTRSignatureAlgIDPtr
,
484 sourceData
, (size_t)sourceLength
,
485 signatureStart
, &signatureUsed
, error
), fail
);
487 require(signatureUsed
< 256, fail
);
488 require(((CFIndex
)signatureUsed
) >= 0, fail
);
489 *size
= signatureUsed
;
491 CFDataSetLength(appendTo
, start
+ (CFIndex
)signatureUsed
+ 1);
496 CFDataSetLength(appendTo
, start
);
501 void SecOTRFIAppendPublicHash(SecOTRFullIdentityRef fullID
, CFMutableDataRef appendTo
)
503 CFDataAppendBytes(appendTo
, fullID
->publicIDHash
, sizeof(fullID
->publicIDHash
));
506 bool SecOTRFIComparePublicHash(SecOTRFullIdentityRef fullID
, const uint8_t hash
[kMPIDHashSize
])
508 return 0 == memcmp(hash
, fullID
->publicIDHash
, kMPIDHashSize
);