Export an elliptic curve key from iOS to work with

2019-07-14 05:28发布

问题:

I have a private/public key pair generated and stored inside Secure Enclave.

It is 256-bit elliptic curve key. (The only key type that can be stored in Secure Enclave).

I use SecKeyCreateWithData and SecKeyCopyExternalRepresentation to import/export the public key between iOS devices, and it works.

However, the exported key doesn't seem to work with OpenSSL. Because it always show 'unable to load Key' on this command.

openssl ec -pubin -in public_key_file -text

What's the way to export the key ? So I can use it with OpenSSL.

回答1:

To work with OpenSSL, you need subject public key info (SPKI), either DER or PEM format.

SPKI contains essential information, for example, key.type, key.parameters, key.value.

SecKeyCopyExternalRepresentation only returns raw key binary which is only key.value part.

You have to create SPKI from that key.value. The normal way to do this is to read https://tools.ietf.org/html/rfc5480, and encode ASN.1 structure to binary-encoded DER format.


But here is a shortcut.

Secure Enclave only supports one key type, 256-bit EC key secp256r1 (equivalent to prime256v1 in OpenSSL).

The SPKI in DER format is a binary encoded data, for example,

3059301306072a8648ce3d020106082a8648ce3d03010703420004fad2e70b0f70f0bf80d7f7cbe8dd4237ca9e59357647e7a7cb90d71a71f6b57869069bcdd24272932c6bdd51895fe2180ea0748c737adecc1cefa3a02022164d

It always consist of two parts

  1. fixed schema header 3059301306072a8648ce3d020106082a8648ce3d030107034200

  2. raw key value 04.......

You can create SPKI by combining these two parts.

spki = fixed_schema_header + SecKeyCopyExternalRepresentation(...)


func createSubjectPublicKeyInfo(rawPublicKeyData: Data) -> Data {
    let secp256r1Header = Data(bytes: [
        0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
        0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00
        ])
    return secp256r1Header + rawPublicKeyData
}

// Usage
let rawPublicKeyData = SecKeyCopyExternalRepresentation(...)!
let publicKeyDER = createSubjectPublicKeyInfo(rawPublicKeyData: rawPublicKeyData)
write(publicKeyDER, to: "public_key.der")

// Test with OpenSSL
// openssl ec -pubin -in public_key.der -text -inform der