My goal is:
- Generate a public and private key pair
- Add the private key to the keychain and protect it with the secure enclave
- Create a self-signed certificate with the public key and send it to a server
- Add the certificate to the keychain
- When I communicate with the server I want to create a
SecIdentity
during the client challenge which is basically aSecCertificate
+SecKey
combo.
For the certificate generation I would like to use the swift-certificates
library to not have to compose manually the certificate fields and signature.
My problem is that the swift-certificates
during the Certificate
initialisation needs a SecureEnclave.P256.Signing.PrivateKey
private key and to add a key to the keychain we need a SecKey
object. And unfortunately there is no clean way to create from one of them the other one. I read several threads here about this, but I haven't found a clean solution for it.
I tried to approach the problem from two directions:
First:
- Create the key with the
SecKeyCreateRandomKey
, mark in the attributes that I want to protect the key with secure enclave and also mark that I want the private key to bekSecAttrIsPermanent
so it is automatically saved in the keychain - The
SecKeyCreateRandomKey
returns aSecKey
which is a reference to the private key from the keychain - (!) Unfortunately I haven't found a clean way to convert a
SecKey
to a ->SecureEnclave.P256.Signing.PrivateKey
- There is a workaround to
SecKeyCopyAttributes
of the private key and to extract the bytes from theattributes["toid"]
, but I guess it's not safe to use an undocumented key ("toid"
) if there is no constant defined to it (the name could be changed in future releases)
Second approach:
- Create a
SecureEnclave.P256.Signing.PrivateKey
- Create the
Certificate
using theswift-certificates
- The created private key is protected by the secure enclave but it's not added automatically to the keychain so we should add it to can query after that the
SecIdentity
- (!) Unfortunately I haven't found a way to convert the
SecureEnclave.P256.Signing.PrivateKey
to ->SecKey
. - There are threads which say that the
SecKeyCreateWithData(...)
helps us, but unfortunately if we set thekSecAttrTokenIDSecureEnclave
in the attribute dictionary, the method creates a brand new key for us, regardless the passed data. So the initial key will never be the same as the newly createdSecKey
. This we can see in the method's implementation.
So I got stuck with both approaches because seemingly there is no clean way to switch between SecureEnclave.P256.Signing.PrivateKey
and SecKey
.
One solution would be to compose manually the certificate, without swift-certificates
because like that we would not need a SecureEnclave.P256.Signing.PrivateKey
object. But I would like to avoid the manual composition and signature calculation...
Anybody has any idea?