diff options
Diffstat (limited to 'src/x509.erl')
-rw-r--r-- | src/x509.erl | 39 |
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(). |