SecKeyCreateSignature iOS11 Error - CryptoTokenKit Code=-3

Hello,


I'm getting the following error when attempting to generate a signature on phones running iOS >= 11.0:


CryptoTokenKit Code=-3 "setoken: unable to sign digest"


Here's the code I'm using to generate the signature:


      var error: Unmanaged<CFError>?
      guard let signData = SecKeyCreateSignature(
        privateKey,
        SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256,
        data as CFData, &error) else {
          logger?.error("Unable to generate signature for data: \(base64Data) with private key ref: \(privateKey). Error is: \(error!.takeRetainedValue())")
          return nil
      }


I've also tried sending in a digest of the data instead and using SecKeyAlgorithm.ecdsaSignatureDigestX962SHA256 but the same issue occurs.


Here's the code I use to generate the keypair:


if let access = SecAccessControlCreateWithFlags(nil,
                                                    kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
                                                    [.privateKeyUsage],
                                                    nil) {

      let privateKeyAttrs = [kSecAttrIsPermanent : 1,
                            kSecAttrApplicationTag as String: applicationTag as AnyObject,
                            kSecAttrLabel as String: keyId,
                            kSecAttrAccessControl as String: access
        ] as NSDictionary

      let publicKeyAttrs = [kSecAttrIsPermanent : 0,
                            kSecAttrLabel as String: keyId,
                            kSecAttrApplicationTag as String: applicationTag as AnyObject
        ] as NSDictionary

      let keyPairAttrs = [kSecAttrKeySizeInBits : 256,
                          kSecAttrKeyType : kSecAttrKeyTypeEC,
                          kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
                          kSecPrivateKeyAttrs : privateKeyAttrs,
                          kSecPublicKeyAttrs : publicKeyAttrs] as NSDictionary

      var error: Unmanaged<CFError>?
      guard let privateKey = SecKeyCreateRandomKey(keyPairAttrs as CFDictionary, &error) else {
        logger?.debug("Unabled to generate ECC Keypair. Error is: \(error!.takeRetainedValue())")
        throw KeypairError.generateFailed
      }
  }


This same code works fine for phones running iOS 10. I've tried setting keySecAttrKeyType to kSecAttrKeyTypeECSECPrimeRandom but that didn't seem to do anything.


Any suggestions?


EDIT: After trying a few more things I noticed that by either changing the kSecAttrApplicationTag value to something different or by deleting all keys with that value, the operation succeeds. This provides me with a workaround, though I'm still not sure why that is.

Replies

After trying a few more things I noticed that by either changing the

kSecAttrApplicationTag
value to something different …

What do you mean by “something different”? What were you previousyl setting it to?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Meaning I changed the value portion of that key/value pair to something different from what it was previously set to, ie:


let applicationTag = "testKeyPair"

let privateKeyAttrs = [kSecAttrIsPermanent : 1,
                            kSecAttrApplicationTag as String: applicationTag as AnyObject,
                            kSecAttrLabel as String: keyId,
                            kSecAttrAccessControl as String: access


I changed "testKeyPair" to "testKeyPair1" and then the signing operations began working again.

First up, two references:

There’s one ‘obvious’ issue here, namely that you’re setting

kSecAttrApplicationTag
to a string instead of a
Data
value. This is not surprising because there’s much confusion about the type of this attribute — in fact, the OS is actively misleading on this front (r. 35389419). You should fix this but, honestly, I don’t think that’s the cause of your actual issue.

I suspect what’s going on here is relates to key uniqueness. If a key already exists with the same

kSecAttrApplicationTag
value, you’re relying on other keychain attributes to avoid duplicates. All the other uniqueness attributes will be the same except
kSecAttrApplicationLabel
. It’s possible that something is going wrong with the system setting that value, and hence you’re getting a collision. This could be exacerbated by your use of the Secure Enclave.

How you proceed here is really up to you:

  • On the one hand, you could give the key a unique

    kSecAttrApplicationTag
    value and avoid this issue completely. That’s what I tend to do.
  • If, however, you want to get to the bottom of it, you should look at dumping all the attributes of all the keys in the keychain to see if you can spot what’s gone wrong.

Regardless, if you have a small test project that reproduces the problem I’d appreciate you filing a bug report about this. Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

On iphone x, ios11.2.1, the first use of faceid, click not allowed, SecKeyCreateSignature method returns error, get NSError code, the program flashes back; but there is no problem on iphone x, ios12, 13 mobile phone

I’m not sure what’s going on here, but I’m quite certain that you should start a new thread for this because I don’t see any connection to the original issue.

When you create your new thread, consider adding some extra details, like snippets of code and details of the error you get.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

closes the lock screen password and reopens ,SecKeyCreateSignature error report unable to sign digest


NSData *signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)data, (void *)&signatureError));



Printing description of signatureError:

Error Domain=CryptoTokenKit Code=-3 "setoken: unable to sign digest" UserInfo={NSLocalizedDescription=setoken: unable to sign digest, AKSError=-536363001}


After replacing kSecAttrLabel, the problem disappeared, but this change will definitely not work. The next time someone closes the password and reopens it will still have this problem. I tested it with the official keychaindemo. The test steps are as follows:

1. run keychaindemo project,click Add protected key, Turn off the lock screen password

2. Open the lock screen password, there will be deleted fingerprint prompts, click to keep

3. Open keychaindemo app, and then click Use protected key to reproduce the problem.