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 时使用 kCFTypeDictionaryKeyCallBackskCFTypeDictionaryValueCallBacks 作为参数。

CFMutableDictionaryRef privateKeyAttrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

CFDictionaryCreateMutable

使用 iOS 14 和 iOS 15 测试。