Right, so I did some more experimenting with both of the keys. Transforming the SecureEnclave key into a SecKey will always generate a new private key in the Secure Enclave, causing the initial Secure Enclave key and the SecKey to be non identical:
let privateKey = try SecureEnclave.P256.Signing.PrivateKey()
let attributes: [CFString: Any] = [
kSecClass: kSecClassKey,
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
kSecAttrTokenID: kSecAttrTokenIDSecureEnclave
]
let secKey = SecKeyCreateWithData(privateKey.dataRepresentation as CFData, attributes as CFDictionary, nil)
// let secKey = SecKeyCreateWithData(Data() as CFData, attributes as CFDictionary, nil)
Interestingly enough, it doesn't really matter what Data you provide to the SecKeyCreateWithData function when you set the kSecAttrTokenID field, odd... We do however get a valid SecKey reference which can be used, but as mentioned, it's a different one from the privateKey we created before. I checked this by comparing the public keys of both of these private keys, which do not match.
Now, normally speaking, the SecKeyCopyExternalRepresentation function will result in an error for Secure Enclave SecKey objects, which makes sense, it's a non extractable key, but the SecureEnclave enum exposes the Data through the dataRepresentation. This appears to simply be an ASN.1 octet stream containing the X9.62 export of the actual Secure Enclave private key. So I decided to do some more digging and found out that we can get the same data through from the SecKey, only at key generation time.
let attributes: [CFString: Any] = [
kSecClass: kSecClassKey,
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
kSecAttrTokenID: kSecAttrTokenIDSecureEnclave
]
let secKey = SecKeyCreateRandomKey(attributes as CFDictionary, nil)
let secAttributes = (SecKeyCopyAttributes(secKey!) as! [CFString: Any])
let secBytes = secAttributes["toid" as CFString] as! Data
let privateKey = try SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: secBytes)
The toid field is available right after we create the key. It exposes the same data as the SecureEnclave enum (dataRepresentation) and we can actually create the SecureEnclave` key if we use this data.
Now I end up with a couple more questions:
Is there no way to convert a SecureEnclave key into a SecKey somehow?
Is the dataRepresentation of the SecureEnclave insecure after all, as one can easily extract X9.62 data from it? (And therefor also the toid field in the attributes)?
Is the toid field something I can use to continue (also in a production app)?