Reputation: 3370
I have a use case where the certificate chain has to be validated for PKI. I have two certs, one is the device cert and the other is the certificate_chain. Both are in pem format. The:public_key.pkix_path_validation/3 seems promising but I don’t know how to give the chain in der format. I am converting the device cert to der using X509.Certificate.to_der but how will I convert the chain to der, since it has 3 certificates( Root_CA, Intermediate_CA, Signing_CA) and when I convert it using the X509 library and give it to :public_key.pkix_path_validation/3 . Basically I want to achieve the alternative to “openssl verify -CAfile certs/root_ca.pem -untrusted cert_chain.pem certs/device_cert.pem” in elixir.
I made some progress and wrote a method to read the certificate and pass it for validation my method to read the certificate for chain validation is
defmodule Cert do
def stubChainValidation do
certRaw = File.read!("software_signing.pem")
{:ok, certEncoded} = X509.Certificate.from_pem(certRaw)
certChainRaw = File.read!("chain.pem")
certChain = :public_key.pem_decode(certChainRaw)
cert_chain_decoded =
Enum.map(
cert_chain,
fn {_, bin, _} -> bin end
)
:public_key.pkix_path_validation(certEncoded,
cert_chain_decoded, [{:max_path_length, 0}])
end
end
When I run this function I get the output of Invalid issuer
{:error, {:bad_cert, :invalid_issuer}}
Upvotes: 1
Views: 713
Reputation: 3370
After spending nearly one complete week I Figured out what I was doing wrong, Erlang expects the parameters in a different way, you need to pass the root and then the chain which contains the intermediate and signing certificate.
I am attaching a sample implementation for the Erlang Community just in case someone gets stuck doing the validation in the future.
defmodule Cert do
def verify_fun(_, {:extension, _}, state) do
{:unknown, state}
end
def verify_fun(_, {:bad_cert, reason}, _state) do
{:fail, reason}
end
def verify_fun(_, {:revoked, _}, _state) do
{:fail, :revoked}
end
def verify_fun(_cert, _event, state) do
{:unknown, state}
end
def stubChainValidation do
Application.ensure_all_started(:inets)
Application.ensure_all_started(:ssl)
Application.ensure_all_started(:public_key)
certRaw = File.read!("./certs/root_ca.pem")
{:ok, certEncoded} = X509.Certificate.from_pem(certRaw)
certChainRaw = File.read!("./certs/chain_2.pem")
certChain = :public_key.pem_decode(certChainRaw)
cert_chain_decoded =
Enum.map(
certChain,
fn {_, bin, _} -> bin end
)
case :public_key.pkix_path_validation(certEncoded, cert_chain_decoded, [
{:verify_fun, {&verify_fun/3, {}}}
]) do
{:ok, {_public_key_info, _policy_tree}} ->
{:ok, cert_chain_decoded}
{:error, {:bad_cert, reason}} ->
{:error, reason}
end
end
end
Upvotes: 2