EXC_BREAKPOINT (SIGTRAP) in SecItemDelete

Hello,

I am experiencing an issue with the SecItemDelete() function using iPhone 13Pro with iOS 15.1.

A call to SecItemDelete() crashes with EXC_BREAKPOINT under certain conditions outlined below:

  • Make sure Iphone has a passcode set.
  • Call SecKeyGeneratePair() to create an EC key pair with kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly and kSecAttrTokenIDSecureEnclave.
  • Remove passcode from iPhone
  • Set a new passcode for iPhone.
  • Call SecItemDelete() to delete private key from SecureEnclave. This call fails with -26275 (errSecInvalidKey) which is expected as the key is destroyed already
  • Call SecItemDelete() to delete public key from KeyChain.
  • SecItemDelete causes a trace trap and app crashes.

I can not see any obvious problems in the code that should generate this behaviour. I am in urgent need to fix this problem and would really appreciate some help or pointers.

The backtrace for the crashing thread below.

More info can be provided if necessary.

To me it seems to be related to situations where SecItemDelete() has returned an error (where secure enclave is involved) and that the next call generates the trap.

Kind regards, Steffen

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x18067911c)
  frame #0: 0x000000018067911c CoreFoundation`CFRelease + 88
  frame #1: 0x00000001894420f0 Security`SetLastError + 76
  frame #2: 0x000000018943ee18 Security`SecOSStatusWith + 140
  frame #3: 0x00000001894436d4 Security`SecItemDelete + 524
 * frame #4: 0x000000010076d3bc TheApp`-[TheAppCrypto deleteKey:isRSA:useSecureEnclave:keychainGroup:error:](self=0x00000002833ec160
Answered by SteffenFiksdal in 692425022

See below

Accepted Answer

See below

Code to reproduce below:

Generate Key Pair:

    NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
    SecKeyRef publicKey = NULL;
    SecKeyRef privateKey = NULL;

    [keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeECSECPrimeRandom forKey:(__bridge id)kSecAttrKeyType];
    [keyPairAttr setObject:[NSNumber numberWithInt:256] forKey:(__bridge id)kSecAttrKeySizeInBits];
    [keyPairAttr setObject:(id)kSecAttrTokenIDSecureEnclave forKey:(__bridge id)kSecAttrTokenID];
    [privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
    [privateKeyAttr setObject:@"priv" forKey:(__bridge id)kSecAttrLabel];
    SecAccessControlRef privAccess = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence|kSecAccessControlPrivateKeyUsage , NULL);
    [privateKeyAttr setObject:(__bridge id)privAccess forKey:(__bridge id)kSecAttrAccessControl];
    [keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];

    OSStatus err = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);

Now remove passcode from iPhone and add passcode to iPhone.

Try to delete private key and then public key. The last SecItemDelete crashes:

    [searchPrivAttr setObject:@"priv" forKey:(__bridge id)kSecAttrLabel];
    [searchPrivAttr setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [searchPrivAttr setObject:(__bridge id)kSecAttrKeyClassPrivate forKey:(__bridge id)kSecAttrKeyClass];
    [searchPrivAttr setObject:(__bridge id)kSecAttrTokenIDSecureEnclave forKey:(__bridge id)kSecAttrTokenID];
    OSStatus err = SecItemDelete((__bridge CFDictionaryRef)searchPrivAttr);

    NSMutableDictionary *searchPubAttr = [[NSMutableDictionary alloc] init];
    [searchPubAttr setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [searchPubAttr setObject:(__bridge id)kSecAttrKeyClassPublic forKey:(__bridge id)kSecAttrKeyClass];
    err = SecItemDelete((__bridge CFDictionaryRef)searchPubAttr);

I filed a bug-report with an example project to reproduce the crash

I grabbed this project and it didn’t compile out of the box )-:

It might be easier for me to look at a crash report. Please reproduce the problem on a device and then post the resulting crash report here.

See Posting a Crash Report for advice on how to do that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for looking into this!

It compiled on my box. It should have compiled. I'm sorry.

Anyway: Attached is the crash-report from the project running on my iPhone (Had to rename from ips->txt to be allowed attaching the file).

The ips file is now also attached to the bug report.

Kind Regards, Steffen

Had to rename from ips->txt to be allowed attaching the file

Yeah, that’s annoying. I’ve filed a bug to allow .ips text attachments (r. 84656849) but, for the moment, renaming to .txt is fine.

The ips file is now also attached to the bug report.

Thanks.

I dug into this some more today and I’m almost certain this is an over-release bug in the OS. If you run your test app under the Zombies instrument, step 2 will trigger a zombie crash and the object is only retained and release by system frameworks (Security and CryptoTokenKit).

I’ve added my results to your bug report.

I’m not sure if there’s any way for you to work around this. If you need help with that, open a DTS tech support incident so that I can allocate more time to that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for your help :)

I think I have a specific app work around where I do not specify attribute kSecAttrTokenIDSecureEnclave when calling SecItemDelete.

This will avoid the code where setLastError (from previous error) causes CFRelease crash, but it should still work as my query is less specified and should not cause any accidental item deletion from the keychain.

Kind Regards, Steffen

EXC_BREAKPOINT (SIGTRAP) in SecItemDelete
 
 
Q