28
28
-include("ssl_handshake.hrl").
29
29
-include("ssl_alert.hrl").
30
30
-include("ssl_internal.hrl").
31
-include("ssl_debug.hrl").
31
-include_lib("public_key/include/public_key.hrl").
33
-export([trusted_cert_and_path/3,
33
-export([trusted_cert_and_path/2,
34
34
certificate_chain/2,
35
file_to_certificats/1]).
35
file_to_certificats/1,
37
is_valid_extkey_usage/2,
37
44
%%====================================================================
38
45
%% Internal application API
39
46
%%====================================================================
41
trusted_cert_and_path(CertChain, CertDbRef, Verify) ->
42
[Cert | RestPath] = lists:reverse(CertChain),
43
{ok, OtpCert} = public_key:pkix_decode_cert(Cert, otp),
48
%%--------------------------------------------------------------------
49
-spec trusted_cert_and_path([der_cert()], certdb_ref()) ->
50
{der_cert() | unknown_ca, [der_cert()]}.
52
%% Description: Extracts the root cert (if not presents tries to
53
%% look it up, if not found {bad_cert, unknown_ca} will be added verification
54
%% errors. Returns {RootCert, Path, VerifyErrors}
55
%%--------------------------------------------------------------------
56
trusted_cert_and_path(CertChain, CertDbRef) ->
57
Path = [Cert | _] = lists:reverse(CertChain),
58
OtpCert = public_key:pkix_decode_cert(Cert, otp),
45
60
case public_key:pkix_is_self_signed(OtpCert) of
47
62
{ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self),
50
65
case public_key:pkix_issuer_id(OtpCert, other) of
52
{IssuerId, [Cert | RestPath]};
53
68
{error, issuer_not_found} ->
54
69
case find_issuer(OtpCert, no_candidate) of
56
{IssuerId, [Cert | RestPath]};
64
{{error, issuer_not_found}, _ } ->
65
%% The root CA was not sent and can not be found, we fail if verify = true
66
not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA), Verify, {Cert, RestPath});
67
{{SerialNr, Issuer}, Path} ->
68
case ssl_certificate_db:lookup_trusted_cert(CertDbRef,
78
case SignedAndIssuerID of
79
{error, issuer_not_found} ->
80
%% The root CA was not sent and can not be found.
82
{self, _} when length(Path) == 1 ->
83
{selfsigned_peer, Path};
84
{_ ,{SerialNr, Issuer}} ->
85
case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of
70
86
{ok, {BinCert,_}} ->
73
%% Fail if verify = true
74
not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA),
75
Verify, {Cert, RestPath})
89
%% Root CA could not be verified
94
%%--------------------------------------------------------------------
95
-spec certificate_chain(undefined | binary(), certdb_ref()) ->
96
{error, no_cert} | {ok, [der_cert()]}.
98
%% Description: Return the certificate chain to send to peer.
99
%%--------------------------------------------------------------------
80
100
certificate_chain(undefined, _CertsDbRef) ->
82
102
certificate_chain(OwnCert, CertsDbRef) ->
83
{ok, ErlCert} = public_key:pkix_decode_cert(OwnCert, otp),
103
ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
84
104
certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]).
86
file_to_certificats(File) ->
105
%%--------------------------------------------------------------------
106
-spec file_to_certificats(string()) -> [der_cert()].
108
%% Description: Return list of DER encoded certificates.
109
%%--------------------------------------------------------------------
110
file_to_certificats(File) ->
87
111
{ok, List} = ssl_manager:cache_pem_file(File),
88
[Bin || {cert, Bin, not_encrypted} <- List].
112
[Bin || {'Certificate', Bin, not_encrypted} <- List].
113
%%--------------------------------------------------------------------
114
-spec validate_extension(term(), #'Extension'{} | {bad_cert, atom()} | valid,
115
term()) -> {valid, term()} |
119
%% Description: Validates ssl/tls specific extensions
120
%%--------------------------------------------------------------------
121
validate_extension(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage',
122
extnValue = KeyUse}}, Role) ->
123
case is_valid_extkey_usage(KeyUse, Role) of
127
{fail, {bad_cert, invalid_ext_key_usage}}
129
validate_extension(_, {bad_cert, _} = Reason, _) ->
131
validate_extension(_, {extension, _}, Role) ->
133
validate_extension(_, valid, Role) ->
135
validate_extension(_, valid_peer, Role) ->
138
%%--------------------------------------------------------------------
139
-spec is_valid_key_usage(list(), term()) -> boolean().
141
%% Description: Checks if Use is a valid key usage.
142
%%--------------------------------------------------------------------
143
is_valid_key_usage(KeyUse, Use) ->
144
lists:member(Use, KeyUse).
146
%%--------------------------------------------------------------------
147
-spec select_extension(term(), list()) -> undefined | #'Extension'{}.
149
%% Description: Selects the extension identified by Id if present in
150
%% a list of extensions.
151
%%--------------------------------------------------------------------
152
select_extension(_, []) ->
154
select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
156
select_extension(Id, [_ | Extensions]) ->
157
select_extension(Id, Extensions).
159
%%--------------------------------------------------------------------
160
-spec extensions_list(asn1_NOVALUE | list()) -> list().
162
%% Description: Handles that
163
%%--------------------------------------------------------------------
164
extensions_list(asn1_NOVALUE) ->
166
extensions_list(Extensions) ->
169
%%--------------------------------------------------------------------
170
-spec signature_type(term()) -> rsa | dsa .
173
%%--------------------------------------------------------------------
174
signature_type(RSA) when RSA == ?sha1WithRSAEncryption;
175
RSA == ?md5WithRSAEncryption ->
177
signature_type(?'id-dsa-with-sha1') ->
90
180
%%--------------------------------------------------------------------
91
181
%%% Internal functions