4
%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
4
%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
6
6
%% The contents of this file are subject to the Erlang Public License,
7
7
%% Version 1.1, (the "License"); you may not use this file except in
30
30
-include("ssl_internal.hrl").
31
31
-include_lib("public_key/include/public_key.hrl").
33
-export([trusted_cert_and_path/2,
35
file_to_certificats/1,
33
-export([trusted_cert_and_path/3,
35
file_to_certificats/2,
36
36
validate_extension/3,
37
37
is_valid_extkey_usage/2,
38
38
is_valid_key_usage/2,
46
46
%%====================================================================
48
48
%%--------------------------------------------------------------------
49
-spec trusted_cert_and_path([der_cert()], certdb_ref()) ->
49
-spec trusted_cert_and_path([der_cert()], db_handle(), certdb_ref()) ->
50
50
{der_cert() | unknown_ca, [der_cert()]}.
52
52
%% Description: Extracts the root cert (if not presents tries to
53
53
%% look it up, if not found {bad_cert, unknown_ca} will be added verification
54
54
%% errors. Returns {RootCert, Path, VerifyErrors}
55
55
%%--------------------------------------------------------------------
56
trusted_cert_and_path(CertChain, CertDbRef) ->
56
trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef) ->
57
57
Path = [Cert | _] = lists:reverse(CertChain),
58
58
OtpCert = public_key:pkix_decode_cert(Cert, otp),
59
59
SignedAndIssuerID =
82
82
{self, _} when length(Path) == 1 ->
83
83
{selfsigned_peer, Path};
84
84
{_ ,{SerialNr, Issuer}} ->
85
case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of
85
case ssl_manager:lookup_trusted_cert(CertDbHandle, CertDbRef, SerialNr, Issuer) of
86
86
{ok, {BinCert,_}} ->
94
94
%%--------------------------------------------------------------------
95
-spec certificate_chain(undefined | binary(), certdb_ref()) ->
95
-spec certificate_chain(undefined | binary(), db_handle(), certdb_ref()) ->
96
96
{error, no_cert} | {ok, [der_cert()]}.
98
98
%% Description: Return the certificate chain to send to peer.
99
99
%%--------------------------------------------------------------------
100
certificate_chain(undefined, _CertsDbRef) ->
100
certificate_chain(undefined, _, _) ->
101
101
{error, no_cert};
102
certificate_chain(OwnCert, CertsDbRef) ->
102
certificate_chain(OwnCert, CertDbHandle, CertsDbRef) ->
103
103
ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
104
certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]).
104
certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert]).
105
105
%%--------------------------------------------------------------------
106
-spec file_to_certificats(string()) -> [der_cert()].
106
-spec file_to_certificats(string(), term()) -> [der_cert()].
108
108
%% Description: Return list of DER encoded certificates.
109
109
%%--------------------------------------------------------------------
110
file_to_certificats(File) ->
111
{ok, List} = ssl_manager:cache_pem_file(File),
110
file_to_certificats(File, DbHandle) ->
111
{ok, List} = ssl_manager:cache_pem_file(File, DbHandle),
112
112
[Bin || {'Certificate', Bin, not_encrypted} <- List].
113
113
%%--------------------------------------------------------------------
114
114
-spec validate_extension(term(), #'Extension'{} | {bad_cert, atom()} | valid,
180
180
%%--------------------------------------------------------------------
181
181
%%% Internal functions
182
182
%%--------------------------------------------------------------------
183
certificate_chain(OtpCert, _Cert, CertsDbRef, Chain) ->
183
certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) ->
184
184
IssuerAndSelfSigned =
185
185
case public_key:pkix_is_self_signed(OtpCert) of
192
192
case IssuerAndSelfSigned of
193
193
{_, true = SelfSigned} ->
194
certificate_chain(CertsDbRef, Chain, ignore, ignore, SelfSigned);
194
certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned);
195
195
{{error, issuer_not_found}, SelfSigned} ->
196
case find_issuer(OtpCert, no_candidate) of
196
case find_issuer(OtpCert, CertDbHandle) of
197
197
{ok, {SerialNr, Issuer}} ->
198
certificate_chain(CertsDbRef, Chain,
198
certificate_chain(CertDbHandle, CertsDbRef, Chain,
199
199
SerialNr, Issuer, SelfSigned);
201
201
%% Guess the the issuer must be the root
205
205
{ok, lists:reverse(Chain)}
207
207
{{ok, {SerialNr, Issuer}}, SelfSigned} ->
208
certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, SelfSigned)
208
certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned)
211
certificate_chain(_CertsDbRef, Chain, _SerialNr, _Issuer, true) ->
211
certificate_chain(_,_, Chain, _SerialNr, _Issuer, true) ->
212
212
{ok, lists:reverse(Chain)};
214
certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
215
case ssl_manager:lookup_trusted_cert(CertsDbRef,
214
certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
215
case ssl_manager:lookup_trusted_cert(CertDbHandle, CertsDbRef,
216
216
SerialNr, Issuer) of
217
217
{ok, {IssuerCert, ErlCert}} ->
218
218
ErlCert = public_key:pkix_decode_cert(IssuerCert, otp),
219
219
certificate_chain(ErlCert, IssuerCert,
220
CertsDbRef, [IssuerCert | Chain]);
220
CertDbHandle, CertsDbRef, [IssuerCert | Chain]);
222
222
%% The trusted cert may be obmitted from the chain as the
223
223
%% counter part needs to have it anyway to be able to
227
227
{ok, lists:reverse(Chain)}
230
find_issuer(OtpCert, PrevCandidateKey) ->
231
case ssl_manager:issuer_candidate(PrevCandidateKey) of
232
no_more_candidates ->
233
{error, issuer_not_found};
234
{Key, {_Cert, ErlCertCandidate}} ->
235
case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
237
public_key:pkix_issuer_id(ErlCertCandidate, self);
239
find_issuer(OtpCert, Key)
230
find_issuer(OtpCert, CertDbHandle) ->
231
IsIssuerFun = fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) ->
232
case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
234
throw(public_key:pkix_issuer_id(ErlCertCandidate, self));
242
try ssl_certificate_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
244
{error, issuer_not_found}
246
{ok, _IssuerId} = Return ->
243
250
is_valid_extkey_usage(KeyUse, client) ->