I'am trying to implement a Secure Enclave based authentication with a server. During the registration flow the server expects a JWK (RFC7517) containing the public key in the following format:
{
"kty":"EC",
"crv":"P-256",
"x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
}
During the login process the server sends a challenge string to the client. This challenge needs to be signed using the private key in the Secure Enclave and sent back so the server. The server verifies the signature with the previousely sent public Key.
I generate the Key Pair using the following code:
let attributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: keyTag,
kSecAttrAccessControl as String: access
]
]
var error: Unmanaged??
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
throw error!.takeRetainedValue() as Error
}
guard let pubKey = SecKeyCopyPublicKey(privateKey) else {
throw AccountStorageError.publicKeyCreationFailed
}
guard let externalRep = SecKeyCopyExternalRepresentation(publicKey, &error) else {
throw error!.takeRetainedValue() as Error
}
If I debug print the public key I get the following information:
<SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPublicKey, version: 4, block size: 256 bits, y: FBCA97607E4F5B2A97B404F5E14B4650ABC5261F4CB811C36F96BFC7A70829BF, x: 7790A8263CCF5DD26BDB06B6D697AE8C31D747A89241099363FE666831D2856F, addr: 0x108001d30>
The variable externalRep has the following format (looks to me like Octet representation):
<047790a8 263ccf5d d26bdb06 b6d697ae 8c31d747 a8924109 9363fe66 6831d285 6ffbca97 607e4f5b 2a97b404 f5e14b46 50abc526 1f4cb811 c36f96bf c7a70829 bf>
So my question is the following: How do I transform this externalRepresentation into the format expected by JWK (EC Point representation)?. Of course I can find all the math behind that conversion in the Internet (e.g. here: https://web.archive.org/web/20140701131201/http://www.secg.org/collateral/sec1_final.pdf,Chapter 2.3.4) but I am wondering if iOS APIs can help me with this task. Under the hood this seems to be implemented (to me the debug printout of the SecKey is exactly in the representation I am targeting). How can I do this the easiest way?
I did find the solution by myself after a while and it was that easy:
I do not need any further API calls, the only thing I did was converting the externalRep (octett format) from hex to binary in order to base64 encode the two values for x and y. The base64 encrypted representation is exactly what JWK expects as format.