+++ /dev/null
-/*
- * SecOTRFullIdentity.c
- * libsecurity_libSecOTR
- *
- * Created by Mitch Adler on 2/9/11.
- * Copyright 2011 Apple Inc. All rights reserved.
- *
- */
-
-#include "SecOTR.h"
-#include "SecOTRIdentityPriv.h"
-#include <utilities/array_size.h>
-#include <utilities/SecCFWrappers.h>
-
-#include <AssertMacros.h>
-
-#include <CoreFoundation/CFNumber.h>
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CFData.h>
-
-#include <Security/SecItem.h>
-#include <Security/SecKeyPriv.h>
-
-#include <Security/oidsalg.h>
-#include <Security/SecCertificatePriv.h>
-
-#include "SecOTRErrors.h"
-
-#include <TargetConditionals.h>
-
-//
-// Algorthim ID initialization
-//
-
-#define kMessageIdentityRSAKeyBits 1280
-#define kMessageIdentityECKeyBits 256
-
-void EnsureOTRAlgIDInited(void)
-{
- static dispatch_once_t kSignatureAlgID_ONCE;
- static SecAsn1AlgId kOTRECSignatureAlgID;
-
- dispatch_once(&kSignatureAlgID_ONCE, ^{
- kOTRECSignatureAlgID.algorithm = CSSMOID_ECDSA_WithSHA1;
- kOTRSignatureAlgIDPtr = &kOTRECSignatureAlgID;
- });
-}
-
-
-static CFStringRef sSigningKeyName = CFSTR("OTR Signing Key");
-
-//
-// SecOTRFullIdentity implementation
-//
-
-CFGiblisFor(SecOTRFullIdentity);
-
-static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyDescription(CFTypeRef cf) {
- SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
- return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
- requestor,
- requestor->publicIDHash[0], requestor->publicIDHash[1],
- requestor->publicIDHash[2], requestor->publicIDHash[3],
- requestor->publicIDHash[4], requestor->publicIDHash[5],
- requestor->publicIDHash[6], requestor->publicIDHash[7]);
-}
-
-static void SecOTRFullIdentityDestroy(CFTypeRef cf) {
- SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
-
- CFReleaseNull(requestor->privateSigningKey);
- CFReleaseNull(requestor->publicSigningKey);
-}
-
-
-//
-// Shared statics
-//
-
-static OSStatus SecOTRFIPurgeFromKeychainByValue(SecKeyRef key, CFStringRef label)
-{
- OSStatus status;
- const void *keys[] = { kSecClass,
- kSecAttrLabel,
- kSecValueRef,
- };
- const void *values[] = { kSecClassKey,
- label,
- key,
- };
- CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, array_size(values), NULL, NULL);
- status = SecItemDelete(dict);
- CFReleaseSafe(dict);
-
- return status;
-}
-
-static bool SecKeyDigestAndSignWithError(
- SecKeyRef key, /* Private key */
- const SecAsn1AlgId *algId, /* algorithm oid/params */
- const uint8_t *dataToDigest, /* signature over this data */
- size_t dataToDigestLen,/* length of dataToDigest */
- uint8_t *sig, /* signature, RETURNED */
- size_t *sigLen, /* IN/OUT */
- CFErrorRef *error) {
-
- OSStatus status = SecKeyDigestAndSign(key, algId, dataToDigest, dataToDigestLen, sig, sigLen);
- require_noerr(status, fail);
- return true;
-fail:
- SecOTRCreateError(secOTRErrorOSError, status, CFSTR("Error signing message. OSStatus in error code."), NULL, error);
- return false;
-}
-
-//
-// SecOTRFullIdentity Functions
-//
-
-static bool SecOTRFICachePublicHash(SecOTRFullIdentityRef fullID, CFErrorRef *error)
-{
- SecOTRPublicIdentityRef pubID = SecOTRPublicIdentityCopyFromPrivate(NULL, fullID, error);
-
- require(pubID, fail);
-
- SecOTRPICopyHash(pubID, fullID->publicIDHash);
-
-fail:
- CFReleaseSafe(pubID);
- 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.
-}
-
-#if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
-#define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
-SEC_CONST_DECL (kSecAttrAccessible, "pdmn");
-SEC_CONST_DECL (kSecAttrAccessibleAlwaysThisDeviceOnly, "dku");
-#endif
-
-SecOTRFullIdentityRef SecOTRFullIdentityCreate(CFAllocatorRef allocator, CFErrorRef *error)
-{
- CFDictionaryRef keygen_parameters = NULL;
- SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
- SecKeyRef tempSigningKey = NULL;
-
- newID->publicSigningKey = NULL;
- newID->privateSigningKey = NULL;
-
- require(newID, out);
-
- EnsureOTRAlgIDInited();
-
- const int signing_keySizeLocal = kMessageIdentityECKeyBits;
- CFNumberRef signing_bitsize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &signing_keySizeLocal);
-
- const void *signing_keygen_keys[] = { kSecAttrKeyType,
- kSecAttrKeySizeInBits,
- kSecAttrIsPermanent,
- kSecAttrAccessible,
- kSecAttrLabel,
- };
-
- const void *signing_keygen_vals[] = { kSecAttrKeyTypeEC,
- signing_bitsize,
- kCFBooleanTrue,
- kSecAttrAccessibleAlwaysThisDeviceOnly,
- sSigningKeyName
- };
- keygen_parameters = CFDictionaryCreate(kCFAllocatorDefault,
- signing_keygen_keys, signing_keygen_vals, array_size(signing_keygen_vals),
- &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
- CFReleaseNull(signing_bitsize);
- require_noerr(SecKeyGeneratePair(keygen_parameters, &tempSigningKey, &newID->privateSigningKey), out);
- CFReleaseNull(keygen_parameters);
-
- newID->publicSigningKey = SecKeyCreatePublicFromPrivate(tempSigningKey);
-
- (void) SecOTRFIPurgeFromKeychainByValue(tempSigningKey, sSigningKeyName);
- CFReleaseNull(tempSigningKey);
-
- require(SecOTRFICachePublicHash(newID, error), out);
-
- return newID;
-
-out:
- if (NULL != newID) {
- SecOTRFIPurgeFromKeychain(newID, NULL);
- }
- CFReleaseSafe(keygen_parameters);
- CFReleaseSafe(newID);
- CFReleaseSafe(tempSigningKey);
- return NULL;
-}
-
-
-static
-OSStatus SecOTRFICreatePrivateKeyReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef* privateKey)
-{
- OSStatus status = errSecParam;
- uint16_t dataSize;
- CFDataRef persistentRef = NULL;
-
- require_noerr_quiet(readSize(bytes, size, &dataSize), fail);
- require_quiet(dataSize <= *size, fail);
-
- SecKeyRef lookedUpKey = NULL;
- persistentRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, *bytes, dataSize, kCFAllocatorNull);
- require_quiet(persistentRef, fail);
-
- require_noerr_quiet(SecKeyFindWithPersistentRef(persistentRef, &lookedUpKey), fail);
-
- *privateKey = lookedUpKey;
-
- *bytes += dataSize;
- *size -= dataSize;
-
- status = errSecSuccess;
-
-fail:
- CFReleaseSafe(persistentRef);
-
- return status;
-}
-
-static
-OSStatus SecOTRFICreateKeysFromReadPersistentRef(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey)
-{
- SecKeyRef foundKey = NULL;
-
- OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey);
- require_noerr_quiet(status, fail);
- require_quiet(foundKey, fail);
-
- *publicKey = SecKeyCreatePublicFromPrivate(*privateKey);
- require_action_quiet(*publicKey, fail, status = errSecParam);
-
- *privateKey = foundKey;
- foundKey = NULL;
-
- status = errSecSuccess;
-
-fail:
- CFReleaseSafe(foundKey);
- return status;
-}
-
-typedef SecKeyRef (*SecOTRPublicKeyCreateFunction)(CFAllocatorRef allocator, const uint8_t** data, size_t* limit);
-
-static
-OSStatus SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(const uint8_t **bytes, size_t *size, SecKeyRef *publicKey, SecKeyRef* privateKey, SecOTRPublicKeyCreateFunction createPublic)
-{
- SecKeyRef foundKey = NULL;
-
- OSStatus status = SecOTRFICreatePrivateKeyReadPersistentRef(bytes, size, &foundKey);
- require_noerr_quiet(status, fail);
- require_quiet(foundKey, fail);
-
- *publicKey = (*createPublic)(NULL, bytes, size);
- require_action_quiet(*publicKey, fail, status = errSecParam);
-
- *privateKey = foundKey;
-
-fail:
- return status;
-}
-
-static
-OSStatus SecOTRFIInitFromV1Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
- const uint8_t **bytes,size_t *size) {
- require(**bytes == 1, fail);
- ++*bytes;
- --*size;
-
- require_noerr_quiet(SecOTRFICreateKeysFromReadPersistentRef(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey), fail);
-
- return errSecSuccess;
-
-fail:
- CFReleaseNull(newID->publicSigningKey);
- CFReleaseNull(newID->privateSigningKey);
-
- return errSecParam;
-}
-
-static
-OSStatus SecOTRFIInitFromV2Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
- const uint8_t **bytes,size_t *size) {
- require(**bytes == 2, fail);
- ++*bytes;
- --*size;
-
- require_noerr_quiet(SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &CreateECPublicKeyFrom), fail);
-
- return errSecSuccess;
-
-fail:
- CFReleaseNull(newID->publicSigningKey);
- CFReleaseNull(newID->privateSigningKey);
-
- return errSecParam;
-}
-
-SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator, SecKeyRef privateKey,
- CFErrorRef *error) {
- // TODO - make sure this is an appropriate key type
- SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
- newID->privateSigningKey = privateKey;
- CFRetain(newID->privateSigningKey);
- newID->publicSigningKey = SecKeyCreatePublicFromPrivate(privateKey);
- require(SecOTRFICachePublicHash(newID, error), fail);
- return newID;
-fail:
- CFRelease(newID->privateSigningKey);
- CFRelease(newID->publicSigningKey);
- CFReleaseSafe(newID);
- return NULL;
-}
-
-SecOTRFullIdentityRef SecOTRFullIdentityCreateFromBytes(CFAllocatorRef allocator, const uint8_t**bytes, size_t *size, CFErrorRef *error)
-{
- SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
- EnsureOTRAlgIDInited();
-
- require(*size > 0, fail);
-
- switch (**bytes) {
- case 1:
- require_noerr_quiet(SecOTRFIInitFromV1Bytes(newID, allocator, bytes, size), fail);
- break;
- case 2:
- require_noerr_quiet(SecOTRFIInitFromV2Bytes(newID, allocator, bytes, size), fail);
- break;
- case 0: // Version 0 was used in seeds of 5.0, transition from those seeds unsupported - keys were in exported data.
- default:
- require(false, fail);
- break;
- }
-
- require(SecOTRFICachePublicHash(newID, error), fail);
-
- return newID;
-
-fail:
- if (NULL != newID) {
- SecOTRFIPurgeFromKeychain(newID, NULL);
- }
- CFReleaseSafe(newID);
- return NULL;
-}
-
-SecOTRFullIdentityRef SecOTRFullIdentityCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error)
-{
- if (data == NULL)
- return NULL;
-
- size_t size = (size_t)CFDataGetLength(data);
- const uint8_t* bytes = CFDataGetBytePtr(data);
-
- return SecOTRFullIdentityCreateFromBytes(allocator, &bytes, &size, error);
-}
-
-bool SecOTRFIPurgeFromKeychain(SecOTRFullIdentityRef thisID, CFErrorRef *error)
-{
- OSStatus result = SecOTRFIPurgeFromKeychainByValue(thisID->privateSigningKey, sSigningKeyName);
- if (errSecSuccess == result) {
- return true;
- } else {
- SecOTRCreateError(secOTRErrorOSError, result, CFSTR("OSStatus returned in error code"), NULL, error);
- return false;
- }
-}
-
-
-static OSStatus SecOTRFIPurgeAllFromKeychainByLabel(CFStringRef label)
-{
- OSStatus status;
- const void *keys[] = { kSecClass,
- kSecAttrKeyClass,
- kSecAttrLabel,
- };
- const void *values[] = { kSecClassKey,
- kSecAttrKeyClassPrivate,
- label,
- };
- CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, array_size(values), NULL, NULL);
- bool deleteAtLeastOne = false;
- int loopLimiter = 500;
- do {
- status = SecItemDelete(dict);
- if (status == errSecSuccess) {
- deleteAtLeastOne = true;
- }
- loopLimiter--;
- } while ((status == errSecSuccess) && (loopLimiter > 0));
- if ((status == errSecItemNotFound) && (deleteAtLeastOne)) {
- // We've looped until we can't delete any more keys.
- // Since this will produce an expected 'itemNotFound', but we don't want to break the contract above
- // (and also we want to make sense)
- // we muffle the non-error to a success case, which it is.
- status = errSecSuccess;
- }
- CFReleaseSafe(dict);
-
- return status;
-}
-
-bool SecOTRFIPurgeAllFromKeychain(CFErrorRef *error)
-{
- OSStatus result = SecOTRFIPurgeAllFromKeychainByLabel(sSigningKeyName);
- if (errSecSuccess == result) {
- return true;
- } else {
- SecOTRCreateError(secOTRErrorOSError, result, CFSTR("OSStatus returned in error code"), NULL, error);
- return false;
- }
-}
-
-static OSStatus appendPersistentRefData(SecKeyRef theKey, CFMutableDataRef serializeInto, CFStringRef name)
-{
- OSStatus status;
- CFDataRef persistent_ref = NULL;
- require_noerr(status = SecKeyCopyPersistentRef(theKey, &persistent_ref), fail);
-
- status = appendSizeAndData(persistent_ref, serializeInto);
-
-fail:
- CFReleaseSafe(persistent_ref);
-
- return status;
-}
-
-static OSStatus SecOTRFIAppendV2Serialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto)
-{
- const uint8_t version = 2;
- CFIndex start = CFDataGetLength(serializeInto);
-
- CFDataAppendBytes(serializeInto, &version, sizeof(version));
-
- require(errSecSuccess == appendPersistentRefData(fullID->privateSigningKey, serializeInto, sSigningKeyName), fail);
- require(errSecSuccess == appendPublicOctetsAndSize(fullID->publicSigningKey, serializeInto), fail);
- return errSecSuccess;
-
-fail:
- CFDataSetLength(serializeInto, start);
-
- return errSecParam;
-}
-
-
-bool SecOTRFIAppendSerialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto, CFErrorRef *error)
-{
- OSStatus status = SecOTRFIAppendV2Serialization(fullID, serializeInto);
- if (errSecSuccess == status) {
- return true;
- } else {
- SecOTRCreateError(secOTRErrorOSError, status, CFSTR("OSStatus returned in error code"), NULL, error);
- return false;
- }
-}
-
-size_t SecOTRFISignatureSize(SecOTRFullIdentityRef fullID)
-{
- return SecKeyGetSize(fullID->publicSigningKey, kSecKeySignatureSize);
-}
-
-bool SecOTRFIAppendSignature(SecOTRFullIdentityRef fullID,
- CFDataRef dataToHash,
- CFMutableDataRef appendTo,
- CFErrorRef *error)
-{
- const size_t signatureSize = SecOTRFISignatureSize(fullID);
- const CFIndex sourceLength = CFDataGetLength(dataToHash);
- const uint8_t* sourceData = CFDataGetBytePtr(dataToHash);
-
- CFIndex start = CFDataGetLength(appendTo);
-
- require(((CFIndex)signatureSize) >= 0, fail);
-
- CFDataIncreaseLength(appendTo, (CFIndex)signatureSize + 1);
-
- uint8_t *size = CFDataGetMutableBytePtr(appendTo) + start;
- uint8_t* signatureStart = size + 1;
- size_t signatureUsed = signatureSize;
-
- require(SecKeyDigestAndSignWithError(fullID->privateSigningKey, kOTRSignatureAlgIDPtr,
- sourceData, (size_t)sourceLength,
- signatureStart, &signatureUsed, error), fail);
-
- require(signatureUsed < 256, fail);
- require(((CFIndex)signatureUsed) >= 0, fail);
- *size = signatureUsed;
-
- CFDataSetLength(appendTo, start + (CFIndex)signatureUsed + 1);
-
- return true;
-
-fail:
- CFDataSetLength(appendTo, start);
-
- return false;
-}
-
-void SecOTRFIAppendPublicHash(SecOTRFullIdentityRef fullID, CFMutableDataRef appendTo)
-{
- CFDataAppendBytes(appendTo, fullID->publicIDHash, sizeof(fullID->publicIDHash));
-}
-
-bool SecOTRFIComparePublicHash(SecOTRFullIdentityRef fullID, const uint8_t hash[kMPIDHashSize])
-{
- return 0 == memcmp(hash, fullID->publicIDHash, kMPIDHashSize);
-}