aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src/ssl_certificate.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/ssl_certificate.erl')
-rw-r--r--lib/ssl/src/ssl_certificate.erl177
1 files changed, 114 insertions, 63 deletions
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 686e90a70c..a4c54afb27 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -31,88 +31,152 @@
-include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([trusted_cert_and_path/3,
+-export([trusted_cert_and_path/2,
certificate_chain/2,
file_to_certificats/1,
- validate_extensions/6]).
+ validate_extension/3,
+ is_valid_extkey_usage/2,
+ is_valid_key_usage/2,
+ select_extension/2,
+ extensions_list/1,
+ signature_type/1
+ ]).
%%====================================================================
%% Internal application API
%%====================================================================
-trusted_cert_and_path(CertChain, CertDbRef, Verify) ->
- [Cert | RestPath] = lists:reverse(CertChain),
- {ok, OtpCert} = public_key:pkix_decode_cert(Cert, otp),
- IssuerAnPath =
+%%--------------------------------------------------------------------
+-spec trusted_cert_and_path([der_cert()], certdb_ref()) ->
+ {der_cert() | unknown_ca, [der_cert()]}.
+%%
+%% Description: Extracts the root cert (if not presents tries to
+%% look it up, if not found {bad_cert, unknown_ca} will be added verification
+%% errors. Returns {RootCert, Path, VerifyErrors}
+%%--------------------------------------------------------------------
+trusted_cert_and_path(CertChain, CertDbRef) ->
+ Path = [Cert | _] = lists:reverse(CertChain),
+ OtpCert = public_key:pkix_decode_cert(Cert, otp),
+ SignedAndIssuerID =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
{ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self),
- {IssuerId, RestPath};
- false ->
+ {self, IssuerId};
+ false ->
case public_key:pkix_issuer_id(OtpCert, other) of
{ok, IssuerId} ->
- {IssuerId, [Cert | RestPath]};
+ {other, IssuerId};
{error, issuer_not_found} ->
case find_issuer(OtpCert, no_candidate) of
{ok, IssuerId} ->
- {IssuerId, [Cert | RestPath]};
+ {other, IssuerId};
Other ->
- {Other, RestPath}
+ Other
end
end
end,
- case IssuerAnPath of
- {{error, issuer_not_found}, _ } ->
- %% The root CA was not sent and can not be found, we fail if verify = true
- not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA), Verify, {Cert, RestPath});
- {{SerialNr, Issuer}, Path} ->
- case ssl_certificate_db:lookup_trusted_cert(CertDbRef,
- SerialNr, Issuer) of
+ case SignedAndIssuerID of
+ {error, issuer_not_found} ->
+ %% The root CA was not sent and can not be found.
+ {unknown_ca, Path};
+ {self, _} when length(Path) == 1 ->
+ {selfsigned_peer, Path};
+ {_ ,{SerialNr, Issuer}} ->
+ case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of
{ok, {BinCert,_}} ->
- {BinCert, Path, []};
+ {BinCert, Path};
_ ->
- %% Fail if verify = true
- not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA),
- Verify, {Cert, RestPath})
+ %% Root CA could not be verified
+ {unknown_ca, Path}
end
end.
-
+%%--------------------------------------------------------------------
+-spec certificate_chain(undefined | binary(), certdb_ref()) ->
+ {error, no_cert} | {ok, [der_cert()]}.
+%%
+%% Description: Return the certificate chain to send to peer.
+%%--------------------------------------------------------------------
certificate_chain(undefined, _CertsDbRef) ->
{error, no_cert};
certificate_chain(OwnCert, CertsDbRef) ->
- {ok, ErlCert} = public_key:pkix_decode_cert(OwnCert, otp),
+ ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]).
-
-file_to_certificats(File) ->
+%%--------------------------------------------------------------------
+-spec file_to_certificats(string()) -> [der_cert()].
+%%
+%% Description: Return list of DER encoded certificates.
+%%--------------------------------------------------------------------
+file_to_certificats(File) ->
{ok, List} = ssl_manager:cache_pem_file(File),
- [Bin || {cert, Bin, not_encrypted} <- List].
-
-
-%% Validates ssl/tls specific extensions
-validate_extensions([], ValidationState, UnknownExtensions, _, AccErr, _) ->
- {UnknownExtensions, ValidationState, AccErr};
-
-validate_extensions([#'Extension'{extnID = ?'id-ce-extKeyUsage',
- extnValue = KeyUse,
- critical = true} | Rest],
- ValidationState, UnknownExtensions, Verify, AccErr0, Role) ->
+ [Bin || {'Certificate', Bin, not_encrypted} <- List].
+%%--------------------------------------------------------------------
+-spec validate_extension(term(), #'Extension'{}, term()) -> {valid, term()} |
+ {fail, tuple()} |
+ {unknown, term()}.
+%%
+%% Description: Validates ssl/tls specific extensions
+%%--------------------------------------------------------------------
+validate_extension(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage',
+ extnValue = KeyUse}}, Role) ->
case is_valid_extkey_usage(KeyUse, Role) of
true ->
- validate_extensions(Rest, ValidationState, UnknownExtensions,
- Verify, AccErr0, Role);
+ {valid, Role};
false ->
- AccErr =
- not_valid_extension({bad_cert, invalid_ext_key_usage}, Verify, AccErr0),
- validate_extensions(Rest, ValidationState, UnknownExtensions, Verify, AccErr, Role)
+ {fail, {bad_cert, invalid_ext_key_usage}}
end;
+validate_extension(_, {bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+validate_extension(_, {extension, _}, Role) ->
+ {unknown, Role};
+validate_extension(_, valid, Role) ->
+ {valid, Role};
+validate_extension(_, valid_peer, Role) ->
+ {valid, Role}.
+
+%%--------------------------------------------------------------------
+-spec is_valid_key_usage(list(), term()) -> boolean().
+%%
+%% Description: Checks if Use is a valid key usage.
+%%--------------------------------------------------------------------
+is_valid_key_usage(KeyUse, Use) ->
+ lists:member(Use, KeyUse).
+
+%%--------------------------------------------------------------------
+-spec select_extension(term(), list()) -> undefined | #'Extension'{}.
+%%
+%% Description: Selects the extension identified by Id if present in
+%% a list of extensions.
+%%--------------------------------------------------------------------
+select_extension(_, []) ->
+ undefined;
+select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
+ Extension;
+select_extension(Id, [_ | Extensions]) ->
+ select_extension(Id, Extensions).
+
+%%--------------------------------------------------------------------
+-spec extensions_list(asn1_NOVALUE | list()) -> list().
+%%
+%% Description: Handles that
+%%--------------------------------------------------------------------
+extensions_list(asn1_NOVALUE) ->
+ [];
+extensions_list(Extensions) ->
+ Extensions.
+
+%%--------------------------------------------------------------------
+-spec signature_type(term()) -> rsa | dsa .
+%%
+%% Description:
+%%--------------------------------------------------------------------
+signature_type(RSA) when RSA == ?sha1WithRSAEncryption;
+ RSA == ?md5WithRSAEncryption ->
+ rsa;
+signature_type(?'id-dsa-with-sha1') ->
+ dsa.
-validate_extensions([Extension | Rest], ValidationState, UnknownExtensions,
- Verify, AccErr, Role) ->
- validate_extensions(Rest, ValidationState, [Extension | UnknownExtensions],
- Verify, AccErr, Role).
-
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -148,10 +212,10 @@ certificate_chain(_CertsDbRef, Chain, _SerialNr, _Issuer, true) ->
{ok, lists:reverse(Chain)};
certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
- case ssl_certificate_db:lookup_trusted_cert(CertsDbRef,
+ case ssl_manager:lookup_trusted_cert(CertsDbRef,
SerialNr, Issuer) of
{ok, {IssuerCert, ErlCert}} ->
- {ok, ErlCert} = public_key:pkix_decode_cert(IssuerCert, otp),
+ ErlCert = public_key:pkix_decode_cert(IssuerCert, otp),
certificate_chain(ErlCert, IssuerCert,
CertsDbRef, [IssuerCert | Chain]);
_ ->
@@ -164,7 +228,7 @@ certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
end.
find_issuer(OtpCert, PrevCandidateKey) ->
- case ssl_certificate_db:issuer_candidate(PrevCandidateKey) of
+ case ssl_manager:issuer_candidate(PrevCandidateKey) of
no_more_candidates ->
{error, issuer_not_found};
{Key, {_Cert, ErlCertCandidate}} ->
@@ -176,22 +240,9 @@ find_issuer(OtpCert, PrevCandidateKey) ->
end
end.
-not_valid(Alert, true, _) ->
- throw(Alert);
-not_valid(_, false, {ErlCert, Path}) ->
- {ErlCert, Path, [{bad_cert, unknown_ca}]}.
-
is_valid_extkey_usage(KeyUse, client) ->
%% Client wants to verify server
is_valid_key_usage(KeyUse,?'id-kp-serverAuth');
is_valid_extkey_usage(KeyUse, server) ->
%% Server wants to verify client
is_valid_key_usage(KeyUse, ?'id-kp-clientAuth').
-
-is_valid_key_usage(KeyUse, Use) ->
- lists:member(Use, KeyUse).
-
-not_valid_extension(Error, true, _) ->
- throw(Error);
-not_valid_extension(Error, false, AccErrors) ->
- [Error | AccErrors].