summaryrefslogtreecommitdiff
path: root/src/x509.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/x509.erl')
-rw-r--r--src/x509.erl39
1 files changed, 26 insertions, 13 deletions
diff --git a/src/x509.erl b/src/x509.erl
index 9b6b386..a784354 100644
--- a/src/x509.erl
+++ b/src/x509.erl
@@ -6,15 +6,20 @@
-include_lib("public_key/include/public_key.hrl").
--type reason() :: {chain_too_long | root_unknown | chain_broken}.
+-type reason() :: {chain_too_long |
+ root_unknown |
+ chain_broken |
+ signature_mismatch |
+ encoding_invalid}.
-define(MAX_CHAIN_LENGTH, 10).
--spec normalise_chain([binary()], [binary()]) -> [binary()].
+-spec normalise_chain([binary()], [binary()]) -> {ok, [binary()]} |
+ {error, reason()}.
normalise_chain(AcceptableRootCerts, CertChain) ->
case valid_chain_p(AcceptableRootCerts, CertChain, ?MAX_CHAIN_LENGTH) of
{false, Reason} ->
- {Reason, "invalid chain"};
+ {error, Reason};
{true, Root} ->
[Leaf | Chain] = CertChain,
{ok, [detox_precert(Leaf) | Chain] ++ Root}
@@ -49,29 +54,37 @@ valid_chain_p(AcceptableRootCerts, [TopCert], MaxChainLength) ->
end;
valid_chain_p(AcceptableRootCerts, [BottomCert|Rest], MaxChainLength) ->
case signed_by_p(BottomCert, hd(Rest)) of
- false -> {false, chain_broken};
- true -> valid_chain_p(AcceptableRootCerts, Rest, MaxChainLength - 1)
+ true -> valid_chain_p(AcceptableRootCerts, Rest, MaxChainLength - 1);
+ Err -> Err
end.
-%% @doc Return list with first
--spec signer(binary(), [binary()]) -> list().
+%% @doc Return first cert in list signing Cert, or notfound.
+-spec signer(binary(), [binary()]) -> notfound | binary().
signer(_Cert, []) ->
notfound;
signer(Cert, [H|T]) ->
case signed_by_p(Cert, H) of
true -> H;
- false -> signer(Cert, T)
+ {false, _} -> signer(Cert, T)
end.
--spec signed_by_p(binary(), binary()) -> boolean().
+-spec signed_by_p(binary(), binary()) -> true | {false, reason()}.
signed_by_p(Cert, IssuerCert) ->
%% FIXME: Validate presence and contents (against constraints) of
%% names (subject, subjectAltName, emailAddress) too?
- case public_key:pkix_is_issuer(Cert, IssuerCert) of
- true -> % Cert.issuer does match IssuerCert.subject.
- public_key:pkix_verify(Cert, public_key(IssuerCert));
+ case (catch public_key:pkix_is_issuer(Cert, IssuerCert)) of
+ {'EXIT', _Reason} ->
+ %% Invalid ASN.1.
+ {false, encoding_invalid};
+ true ->
+ %% Cert.issuer does match IssuerCert.subject. Now verify
+ %% the signature.
+ case public_key:pkix_verify(Cert, public_key(IssuerCert)) of
+ true -> true;
+ false -> {false, signature_mismatch}
+ end;
false ->
- false
+ {false, chain_broken}
end.
-spec public_key(binary() | #'OTPCertificate'{}) -> public_key:public_key().