iOS CFMutableDictionaryRef 在 iOS 15 及更高版本上崩溃,但仍可在 iOS14 上运行
iOS CFMutableDictionaryRef crashes on iOS 15 and newer but still work on iOS14
我在 Objective-C 中写了两个函数来生成密钥对,方法是 SecKeyCreateRandomKey。在一个中,我在另一个 CFMutableDictionaryRef 中使用 NSDictionary。
我使用 NSDictionary 的功能在 iOS 14 和 15 上完美运行。代码如下。
- (SecKeyRef) generateKeyPair:(NSString*) tag {
NSLog(@"NativeCrypto: Start");
CFErrorRef error = NULL;
SecAccessControlRef access =
SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlocked,
kSecAccessControlPrivateKeyUsage,
nil);
NSDictionary *attributes =
@{
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom,
(id)kSecAttrTokenID: (id)kSecAttrTokenIDSecureEnclave,
(id)kSecAttrKeySizeInBits: @(256), // secure enclave *ONLY* support 256 elliptic (secp256r1)
(id)kSecPrivateKeyAttrs:
@{ (id)kSecAttrIsPermanent: @(YES),
(id)kSecAttrApplicationTag: tag,
(id)kSecAttrAccessControl: (__bridge id)access}
};
SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error);
NSLog(@"NativeCrypto: privateKey %@", privateKey);
NSLog(@"NativeCrypto: error %@", error);
NSLog(@"NativeCrypto: End");
return privateKey;}@end
但是我使用 CFMutableDictionaryRef 的函数在 iOS15 上不起作用。代码如下。
void bar() {
NSString* keyTag = [NSBundle.mainBundle.bundleIdentifier stringByAppendingString:@".private"];
// Secure Enclave store ONLY 256-bit elliptic curve private keys.
//
// It means that we can generate ONLY kSecAttrKeyTypeEC and kSecAttrKeySizeInBits = 256.
SecAccessControlRef access = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, kSecAccessControlPrivateKeyUsage, NULL);
CFMutableDictionaryRef privateKeyAttrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, NULL, NULL);
CFDictionaryAddValue(privateKeyAttrs, kSecAttrIsPermanent, kCFBooleanTrue);
CFDictionaryAddValue(privateKeyAttrs, kSecAttrApplicationTag, CFBridgingRetain([keyTag dataUsingEncoding:NSUTF8StringEncoding]));
CFDictionaryAddValue(privateKeyAttrs, kSecAttrAccessControl, access);
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, NULL, NULL);
CFDictionaryAddValue(attributes, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom);
CFDictionaryAddValue(attributes, kSecAttrKeySizeInBits, CFBridgingRetain([NSNumber numberWithInt:256]));
CFDictionaryAddValue(attributes, kSecAttrTokenID, kSecAttrTokenIDSecureEnclave);
CFDictionaryAddValue(attributes, kSecPrivateKeyAttrs, privateKeyAttrs);
CFErrorRef error;
SecKeyCreateRandomKey(attributes, &error);
if (error == NULL) {
NSLog(@"generateKeyToSecureEnclave() - error is null");
} else {
NSError* nsError = (NSError*)CFBridgingRelease(error);
NSLog(@"generateKeyToSecureEnclave() - error not null %d", (int)nsError.code);
}
CFBridgingRelease(attributes);
NSLog(@"==Keys generated success==");}
告诉我为什么第二个版本的代码可能无法在 iOS 15 上运行,因为它可以在 iOS 14 上运行?有必要了解不兼容的原因。
堆栈跟踪
#0 0x00007fff2019fc38 in objc_retain ()
#1 0x00007fff5a7684c3 in -[TKSEPKey
initWithAttributes:authContext:error:] ()
#2 0x00007fff5a77136a in -[TKSEPClientTokenSession
createObjectWithAttributes:error:] ()
#3 0x00007fff211f1a01 in -[SecCTKKey initWithAttributes:error:]()
#4 0x00007fff21214f45 in SecKeyGeneratePair ()
#5 0x00007fff21218884 in SecKeyCreateRandomKey ()
#6 0x000000010c101cac in bar at test.m:33
应用程序崩溃的行:
在创建 CFDictionaryCreateMutable
时使用 kCFTypeDictionaryKeyCallBacks
、kCFTypeDictionaryValueCallBacks
作为参数。
CFMutableDictionaryRef privateKeyAttrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
使用 iOS 14 和 iOS 15 测试。
我在 Objective-C 中写了两个函数来生成密钥对,方法是 SecKeyCreateRandomKey。在一个中,我在另一个 CFMutableDictionaryRef 中使用 NSDictionary。
我使用 NSDictionary 的功能在 iOS 14 和 15 上完美运行。代码如下。
- (SecKeyRef) generateKeyPair:(NSString*) tag {
NSLog(@"NativeCrypto: Start");
CFErrorRef error = NULL;
SecAccessControlRef access =
SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlocked,
kSecAccessControlPrivateKeyUsage,
nil);
NSDictionary *attributes =
@{
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom,
(id)kSecAttrTokenID: (id)kSecAttrTokenIDSecureEnclave,
(id)kSecAttrKeySizeInBits: @(256), // secure enclave *ONLY* support 256 elliptic (secp256r1)
(id)kSecPrivateKeyAttrs:
@{ (id)kSecAttrIsPermanent: @(YES),
(id)kSecAttrApplicationTag: tag,
(id)kSecAttrAccessControl: (__bridge id)access}
};
SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error);
NSLog(@"NativeCrypto: privateKey %@", privateKey);
NSLog(@"NativeCrypto: error %@", error);
NSLog(@"NativeCrypto: End");
return privateKey;}@end
但是我使用 CFMutableDictionaryRef 的函数在 iOS15 上不起作用。代码如下。
void bar() {
NSString* keyTag = [NSBundle.mainBundle.bundleIdentifier stringByAppendingString:@".private"];
// Secure Enclave store ONLY 256-bit elliptic curve private keys.
//
// It means that we can generate ONLY kSecAttrKeyTypeEC and kSecAttrKeySizeInBits = 256.
SecAccessControlRef access = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, kSecAccessControlPrivateKeyUsage, NULL);
CFMutableDictionaryRef privateKeyAttrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, NULL, NULL);
CFDictionaryAddValue(privateKeyAttrs, kSecAttrIsPermanent, kCFBooleanTrue);
CFDictionaryAddValue(privateKeyAttrs, kSecAttrApplicationTag, CFBridgingRetain([keyTag dataUsingEncoding:NSUTF8StringEncoding]));
CFDictionaryAddValue(privateKeyAttrs, kSecAttrAccessControl, access);
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, NULL, NULL);
CFDictionaryAddValue(attributes, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom);
CFDictionaryAddValue(attributes, kSecAttrKeySizeInBits, CFBridgingRetain([NSNumber numberWithInt:256]));
CFDictionaryAddValue(attributes, kSecAttrTokenID, kSecAttrTokenIDSecureEnclave);
CFDictionaryAddValue(attributes, kSecPrivateKeyAttrs, privateKeyAttrs);
CFErrorRef error;
SecKeyCreateRandomKey(attributes, &error);
if (error == NULL) {
NSLog(@"generateKeyToSecureEnclave() - error is null");
} else {
NSError* nsError = (NSError*)CFBridgingRelease(error);
NSLog(@"generateKeyToSecureEnclave() - error not null %d", (int)nsError.code);
}
CFBridgingRelease(attributes);
NSLog(@"==Keys generated success==");}
告诉我为什么第二个版本的代码可能无法在 iOS 15 上运行,因为它可以在 iOS 14 上运行?有必要了解不兼容的原因。
堆栈跟踪
#0 0x00007fff2019fc38 in objc_retain ()
#1 0x00007fff5a7684c3 in -[TKSEPKey
initWithAttributes:authContext:error:] ()
#2 0x00007fff5a77136a in -[TKSEPClientTokenSession
createObjectWithAttributes:error:] ()
#3 0x00007fff211f1a01 in -[SecCTKKey initWithAttributes:error:]()
#4 0x00007fff21214f45 in SecKeyGeneratePair ()
#5 0x00007fff21218884 in SecKeyCreateRandomKey ()
#6 0x000000010c101cac in bar at test.m:33
应用程序崩溃的行:
在创建 CFDictionaryCreateMutable
时使用 kCFTypeDictionaryKeyCallBacks
、kCFTypeDictionaryValueCallBacks
作为参数。
CFMutableDictionaryRef privateKeyAttrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
使用 iOS 14 和 iOS 15 测试。