%%%------------------------------------------------------------------- %% @doc Development certificate trust store. %%%------------------------------------------------------------------- -module(vpn_trust_store). -export([load/1, verify/2]). load(CaPath) -> case file:read_file(CaPath) of {ok, CaPem} -> load_pem(CaPath, CaPem); {error, Reason} -> {error, {ca_certificate_read_failed, CaPath, Reason}} end. verify(#{ca_certificate := CaCertificate}, Certificate) -> case public_key:pkix_is_self_signed(Certificate) of true -> {error, self_signed_certificate}; false -> verify_issuer(CaCertificate, Certificate) end; verify(_TrustStore, _Certificate) -> {error, invalid_trust_store}. load_pem(CaPath, CaPem) -> try case public_key:pem_decode(CaPem) of [{_, Der, _} | _] -> {ok, #{ca_path => CaPath, ca_pem => CaPem, ca_certificate => public_key:pkix_decode_cert(Der, otp)}}; [] -> {error, no_pem_entry} end catch Class:Reason -> {error, {ca_certificate_parse_failed, CaPath, {Class, Reason}}} end. verify_issuer(CaCertificate, Certificate) -> case public_key:pkix_is_issuer(Certificate, CaCertificate) of true -> verify_path(CaCertificate, Certificate); false -> {error, issuer_mismatch} end. verify_path(CaCertificate, Certificate) -> case public_key:pkix_path_validation(CaCertificate, [Certificate], []) of {ok, _} -> ok; {error, Reason} -> {error, {signature_verification_failed, Reason}} end.