ex_crypto
ex_crypto copied to clipboard
Loading private key from PEM file fails
This is the same issue as reported here: https://stackoverflow.com/questions/41336947/erlang-generate-rsa-keys-from-pem-files
In this case it causes ExPublicKey.load/2
to return an {:error, _} tuple.
Loading the corresponding public key produces the :RSAPublicKey
as expected.
Steps to reproduce
I'm using OpenSSL 1.0.2o
- Generate keys
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out test_private.pem
openssl pkey -pubout -inform PEM -outform PEM -in test_private.pem -out test_public.pem
- Load keys
iex(1)> ExPublicKey.load("test_public.pem")
{:ok, #ExPublicKey.RSAPublicKey<
fingerprint_sha256=
a5...>}
iex(2)> ExPublicKey.load("test_private.pem")
{:error,
"invalid argument, expected one of[ExPublicKey.RSAPublicKey, ExPublicKey.RSAPrivateKey], found: PrivateKeyInfo"}
Possible solution
Use :public_key.der_decode/2
with the data provided from the PrivateKeyInfo
tuple. I'm assuming the the algorithm identifier is contained inside the PrivateKeyInfo
data, but I don't know how to extract it so I've hard-coded :RSAPrivateKey
here.
defmodule Key do
def load_priv_key() do
{:PrivateKeyInfo, :v1, _, private_key_binary, _} =
File.read!("test_private.pem")
|> :public_key.pem_decode() |> hd
|> :public_key.pem_entry_decode()
:public_key.der_decode(:RSAPrivateKey, private_key_binary)
|> ExPublicKey.RSAPrivateKey.from_sequence()
end
end
iex(1)> Key.load_priv_key
#ExPublicKey.RSAPrivateKey<
fingerprint_sha256=
a5...>
I realised the fact that the key is unencrypted is not important. This is the same for encrypted keys.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out priv.pem -des3 -pass pass:foo
def load_priv_key() do
{:PrivateKeyInfo, :v1, _, private_key_binary, _} =
File.read!("priv.pem")
|> :public_key.pem_decode() |> hd
|> :public_key.pem_entry_decode("foo")
:public_key.der_decode(:RSAPrivateKey, private_key_binary)
|> ExPublicKey.RSAPrivateKey.from_sequence()
iex(1)> ExPublicKey.load("priv.pem", "foo")
{:error,
"invalid argument, expected one of[ExPublicKey.RSAPublicKey, ExPublicKey.RSAPrivateKey], found: PrivateKeyInfo"}
iex(2)> Key.load_priv_key
#ExPublicKey.RSAPrivateKey<
fingerprint_sha256=
7a