mirror of
https://github.com/darlinghq/darling-security.git
synced 2024-11-23 12:09:41 +00:00
191 lines
8.0 KiB
Objective-C
191 lines
8.0 KiB
Objective-C
/*
|
|
* Copyright (c) 2016 Apple Inc. All Rights Reserved.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*/
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
#include "shared_regressions.h"
|
|
|
|
static void create_random_key_worker(id keyType, int keySize, bool permPub, bool permPriv) {
|
|
NSDictionary *params = nil;
|
|
NSError *error = nil;
|
|
|
|
params = @{
|
|
(id)kSecAttrKeyType: keyType,
|
|
(id)kSecAttrKeySizeInBits: @(keySize),
|
|
(id)kSecAttrLabel: @"si-44-seckey-gen:0",
|
|
(id)kSecPublicKeyAttrs: @{
|
|
(id)kSecAttrIsPermanent: @(permPub),
|
|
},
|
|
(id)kSecPrivateKeyAttrs: @{
|
|
(id)kSecAttrIsPermanent: @(permPriv),
|
|
},
|
|
};
|
|
|
|
id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error));
|
|
ok(privateKey != nil, "generating key (type:%@, size:%d, permPub:%d, permPriv:%d) : %@", keyType, keySize, (int)permPub, (int)permPriv, error);
|
|
|
|
id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey));
|
|
ok(publicKey != nil, "got public key from generated private key");
|
|
|
|
error = nil;
|
|
NSData *pubKeyData = CFBridgingRelease(SecKeyCopyExternalRepresentation((SecKeyRef)publicKey, (void *)&error));
|
|
ok(pubKeyData != nil, "get public key data, error %@", error);
|
|
|
|
params = @{
|
|
(id)kSecClass: (id)kSecClassKey,
|
|
(id)kSecAttrKeyType: keyType,
|
|
(id)kSecAttrKeySizeInBits: @(keySize),
|
|
(id)kSecAttrLabel: @"si-44-seckey-gen:0",
|
|
(id)kSecMatchLimit: (id)kSecMatchLimitAll,
|
|
(id)kSecReturnAttributes: @YES,
|
|
};
|
|
NSArray *items = nil;
|
|
OSStatus expected = (permPub || permPriv) ? errSecSuccess : errSecItemNotFound;
|
|
is_status(SecItemCopyMatching((CFDictionaryRef)params, (void *)&items), expected, "keychain query for generated keys");
|
|
is((int)items.count, (permPub ? 1 : 0) + (permPriv ? 1 : 0), "found keys in the keychain");
|
|
|
|
if (!permPub) {
|
|
// Store public key into keychain explicitly.
|
|
NSDictionary *add = @{
|
|
(id)kSecValueRef: (id)publicKey,
|
|
(id)kSecAttrLabel: @"si-44-seckey-gen:0",
|
|
(id)kSecReturnPersistentRef: @YES,
|
|
};
|
|
NSData *pRef;
|
|
ok_status(SecItemAdd((CFDictionaryRef)add, (void *)&pRef), "Add public key");
|
|
ok([pRef isKindOfClass:NSData.class] || [pRef isKindOfClass:NSArray.class] , "got persistent ref");
|
|
} else {
|
|
ok(true);
|
|
ok(true);
|
|
}
|
|
|
|
if (!permPriv) {
|
|
// Store public key into keychain explicitly.
|
|
NSDictionary *add = @{
|
|
(id)kSecValueRef: (id)privateKey,
|
|
(id)kSecAttrLabel: @"si-44-seckey-gen:0",
|
|
(id)kSecReturnPersistentRef: @YES,
|
|
};
|
|
NSData *pRef;
|
|
ok_status(SecItemAdd((CFDictionaryRef)add, (void *)&pRef), "Add private key");
|
|
ok([pRef isKindOfClass:NSData.class] || [pRef isKindOfClass:NSArray.class] , "got persistent ref");
|
|
} else {
|
|
ok(true);
|
|
ok(true);
|
|
}
|
|
|
|
items = nil;
|
|
ok_status(SecItemCopyMatching((CFDictionaryRef)params, (void *)&items), "keychain query for generated keys");
|
|
is((int)items.count, 2, "keypair is in the keychain");
|
|
|
|
params = @{
|
|
(id)kSecClass: (id)kSecClassKey,
|
|
(id)kSecAttrKeyType: keyType,
|
|
(id)kSecAttrKeySizeInBits: @(keySize),
|
|
#if TARGET_OS_OSX
|
|
// Despite headerdoc and other docs, SecItemDelete on macOS deletes only first found item, we need to persuade
|
|
// it to delete everything passing the query. On the other hand, iOS implementation errs out when
|
|
// kSecMatchLimit is given, so we need to add it only for macOS.
|
|
(id)kSecMatchLimit: (id)kSecMatchLimitAll,
|
|
#endif
|
|
(id)kSecAttrLabel: @"si-44-seckey-gen:0",
|
|
};
|
|
ok_status(SecItemDelete((CFDictionaryRef)params), "clear generated pair from keychain");
|
|
}
|
|
|
|
static void test_create_random_key() {
|
|
create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, false, false);
|
|
create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, false, true);
|
|
create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, true, true);
|
|
create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, false, false);
|
|
create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, false, true);
|
|
create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, true, true);
|
|
|
|
// Create pair with pub-permanent&priv-nonpermanent currently does not work well, created
|
|
// pub key has some strange ACL which prevents it from sensible use. However, this combination
|
|
// also does not make sense at all from usage point of view.
|
|
// create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, true, false);
|
|
// create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, true, false);
|
|
}
|
|
static const int TestCountCreateRandomKey = (3 * 12) * 2;
|
|
|
|
static void test_create_key_with_attrs_run(NSDictionary *attrs) {
|
|
NSMutableDictionary *params = attrs.mutableCopy;
|
|
params[(id)kSecAttrKeyType] = (id)kSecAttrKeyTypeRSA;
|
|
params[(id)kSecAttrKeySizeInBits] = @1024;
|
|
params[(id)kSecAttrIsPermanent] = @YES;
|
|
|
|
NSError *error;
|
|
id privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error));
|
|
ok(privKey != nil, "generatekey: %@", privKey);
|
|
|
|
id pubKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privKey));
|
|
ok(pubKey != nil, "get pub key");
|
|
|
|
NSDictionary *result;
|
|
ok_status(SecItemCopyMatching((CFDictionaryRef)@{(id)kSecValueRef: privKey, (id)kSecReturnAttributes: @YES}, (void *)&result), "copymatching create privkey");
|
|
__block BOOL failed = NO;
|
|
[attrs enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
|
|
failed = failed || ![result[key] isEqual:obj];
|
|
}];
|
|
ok(!failed, "retrieved attributes differ (privkey): expected: %@ - got: %@", attrs, result);
|
|
|
|
result = nil;
|
|
ok_status(SecItemCopyMatching((CFDictionaryRef)@{(id)kSecValueRef: pubKey, (id)kSecReturnAttributes: @YES}, (void *)&result), "copymatching create privkey");
|
|
failed = NO;
|
|
[attrs enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
|
|
failed = failed || ![result[key] isEqual:obj];
|
|
}];
|
|
ok(!failed, "retrieved attributes differ (pubkey): expected: %@ - got: %@", attrs, result);
|
|
|
|
// Cleanup of the keys.
|
|
ok_status(SecItemDelete((CFDictionaryRef)@{(id)kSecValueRef: privKey}));
|
|
ok_status(SecItemDelete((CFDictionaryRef)@{(id)kSecValueRef: pubKey}));
|
|
}
|
|
static const int TestCountCreateKeyWithAttrsRun = 8;
|
|
|
|
static void test_create_key_with_attrs() {
|
|
test_create_key_with_attrs_run(@{(id)kSecAttrLabel:@"Label"});
|
|
test_create_key_with_attrs_run(@{(id)kSecAttrApplicationTag:[@"AppTag" dataUsingEncoding:NSUTF8StringEncoding]});
|
|
test_create_key_with_attrs_run(@{(id)kSecAttrLabel:@"Label",
|
|
(id)kSecAttrApplicationTag:[@"AppTag" dataUsingEncoding:NSUTF8StringEncoding]});
|
|
}
|
|
static const int TestCountCreateKeyWithAttrs = 3 * TestCountCreateKeyWithAttrsRun;
|
|
|
|
static const int TestCount =
|
|
TestCountCreateRandomKey +
|
|
TestCountCreateKeyWithAttrs
|
|
;
|
|
|
|
int si_44_seckey_gen(int argc, char *const *argv) {
|
|
plan_tests(TestCount);
|
|
|
|
@autoreleasepool {
|
|
test_create_random_key();
|
|
test_create_key_with_attrs();
|
|
}
|
|
|
|
return 0;
|
|
}
|