aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2016-09-12 16:26:12 +0200
committerIngela Anderton Andin <[email protected]>2016-09-12 16:26:12 +0200
commit9f12c01ed52555a2a6218b86929a2b2f36c93a0e (patch)
tree25ad3b5501650fc9db8b2f72dcfd990a682643bf /lib/ssl/src
parent44aba0af8d1ddbccf8a7911f307681fc0d726d77 (diff)
parent3cad56eb508fb703d036e704bae77a3b3ae05086 (diff)
downloadotp-9f12c01ed52555a2a6218b86929a2b2f36c93a0e.tar.gz
otp-9f12c01ed52555a2a6218b86929a2b2f36c93a0e.tar.bz2
otp-9f12c01ed52555a2a6218b86929a2b2f36c93a0e.zip
Merge branch 'ferd/bypass-pem-cache/PR-1143/OTP-13883' into maint
* ferd/bypass-pem-cache/PR-1143/OTP-13883: ssl: Add documentation of bypass_pem_cache application environment configuration ssl: Add new benchmarks to skip file for normal testing Adding PEM cache bypass benchmark entries Fixing CRL searching in cache bypass Add option to bypass SSL PEM cache
Diffstat (limited to 'lib/ssl/src')
-rw-r--r--lib/ssl/src/ssl_certificate.erl34
-rw-r--r--lib/ssl/src/ssl_crl.erl28
-rw-r--r--lib/ssl/src/ssl_handshake.erl9
-rw-r--r--lib/ssl/src/ssl_manager.erl43
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl67
5 files changed, 147 insertions, 34 deletions
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 3ec3f50e05..f359655d85 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -64,7 +64,7 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
{ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self),
{self, IssuerId};
false ->
- other_issuer(OtpCert, BinCert, CertDbHandle)
+ other_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef)
end,
case SignedAndIssuerID of
@@ -200,7 +200,7 @@ certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
{_, true = SelfSigned} ->
certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned);
{{error, issuer_not_found}, SelfSigned} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) of
{ok, {SerialNr, Issuer}} ->
certificate_chain(CertDbHandle, CertsDbRef, Chain,
SerialNr, Issuer, SelfSigned);
@@ -232,7 +232,7 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned
{ok, undefined, lists:reverse(Chain)}
end.
-find_issuer(OtpCert, BinCert, CertDbHandle) ->
+find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) ->
IsIssuerFun =
fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) ->
case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
@@ -250,12 +250,24 @@ find_issuer(OtpCert, BinCert, CertDbHandle) ->
Acc
end,
- try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _IssuerId} = Return ->
- Return
+ if is_reference(CertsDbRef) -> % actual DB exists
+ try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _IssuerId} = Return ->
+ Return
+ end;
+ is_tuple(CertsDbRef), element(1,CertsDbRef) =:= extracted -> % cache bypass byproduct
+ {extracted, CertsData} = CertsDbRef,
+ DB = [Entry || {decoded, Entry} <- CertsData],
+ try lists:foldl(IsIssuerFun, issuer_not_found, DB) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _IssuerId} = Return ->
+ Return
+ end
end.
is_valid_extkey_usage(KeyUse, client) ->
@@ -281,12 +293,12 @@ public_key(#'OTPSubjectPublicKeyInfo'{algorithm = #'PublicKeyAlgorithm'{algorith
subjectPublicKey = Key}) ->
{Key, Params}.
-other_issuer(OtpCert, BinCert, CertDbHandle) ->
+other_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) ->
case public_key:pkix_issuer_id(OtpCert, other) of
{ok, IssuerId} ->
{other, IssuerId};
{error, issuer_not_found} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) of
{ok, IssuerId} ->
{other, IssuerId};
Other ->
diff --git a/lib/ssl/src/ssl_crl.erl b/lib/ssl/src/ssl_crl.erl
index d9f21e04ac..01be1fb9ab 100644
--- a/lib/ssl/src/ssl_crl.erl
+++ b/lib/ssl/src/ssl_crl.erl
@@ -47,7 +47,7 @@ trusted_cert_and_path(CRL, issuer_not_found, {Db, DbRef} = DbHandle) ->
{ok, unknown_crl_ca, []}
end.
-find_issuer(CRL, {Db,_}) ->
+find_issuer(CRL, {Db,DbRef}) ->
Issuer = public_key:pkix_normalize_name(public_key:pkix_crl_issuer(CRL)),
IsIssuerFun =
fun({_Key, {_Der,ErlCertCandidate}}, Acc) ->
@@ -55,15 +55,27 @@ find_issuer(CRL, {Db,_}) ->
(_, Acc) ->
Acc
end,
-
- try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, Db) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _} = Result ->
- Result
+ if is_reference(DbRef) -> % actual DB exists
+ try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, Db) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _} = Result ->
+ Result
+ end;
+ is_tuple(DbRef), element(1,DbRef) =:= extracted -> % cache bypass byproduct
+ {extracted, CertsData} = DbRef,
+ Certs = [Entry || {decoded, Entry} <- CertsData],
+ try lists:foldl(IsIssuerFun, issuer_not_found, Certs) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _} = Result ->
+ Result
+ end
end.
+
verify_crl_issuer(CRL, ErlCertCandidate, Issuer, NotIssuer) ->
TBSCert = ErlCertCandidate#'OTPCertificate'.tbsCertificate,
case public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.subject) of
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 36d533cd4e..5b51ac0916 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1216,13 +1216,18 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
end,
list_to_binary([Enc(Cert) || {_, Cert} <- Authorities]).
-certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
+certificate_authorities_from_db(CertDbHandle, CertDbRef) when is_reference(CertDbRef) ->
ConnectionCerts = fun({{Ref, _, _}, Cert}, Acc) when Ref == CertDbRef ->
[Cert | Acc];
(_, Acc) ->
Acc
end,
- ssl_pkix_db:foldl(ConnectionCerts, [], CertDbHandle).
+ ssl_pkix_db:foldl(ConnectionCerts, [], CertDbHandle);
+certificate_authorities_from_db(_CertDbHandle, {extracted, CertDbData}) ->
+ %% Cache disabled, Ref contains data
+ lists:foldl(fun({decoded, {_Key,Cert}}, Acc) -> [Cert | Acc] end,
+ [], CertDbData).
+
%%-------------Extension handling --------------------------------
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index c7dcbaabe9..5bd9521de7 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -115,13 +115,25 @@ start_link_dist(Opts) ->
%% Description: Do necessary initializations for a new connection.
%%--------------------------------------------------------------------
connection_init({der, _} = Trustedcerts, Role, CRLCache) ->
- call({connection_init, Trustedcerts, Role, CRLCache});
+ case bypass_pem_cache() of
+ true ->
+ {ok, Extracted} = ssl_pkix_db:extract_trusted_certs(Trustedcerts),
+ call({connection_init, Extracted, Role, CRLCache});
+ false ->
+ call({connection_init, Trustedcerts, Role, CRLCache})
+ end;
connection_init(<<>> = Trustedcerts, Role, CRLCache) ->
call({connection_init, Trustedcerts, Role, CRLCache});
connection_init(Trustedcerts, Role, CRLCache) ->
- call({connection_init, Trustedcerts, Role, CRLCache}).
+ case bypass_pem_cache() of
+ true ->
+ {ok, Extracted} = ssl_pkix_db:extract_trusted_certs(Trustedcerts),
+ call({connection_init, Extracted, Role, CRLCache});
+ false ->
+ call({connection_init, Trustedcerts, Role, CRLCache})
+ end.
%%--------------------------------------------------------------------
-spec cache_pem_file(binary(), term()) -> {ok, term()} | {error, reason()}.
@@ -129,13 +141,18 @@ connection_init(Trustedcerts, Role, CRLCache) ->
%% Description: Cache a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- case ssl_pkix_db:lookup_cached_pem(DbHandle, File) of
- [{Content,_}] ->
- {ok, Content};
- [Content] ->
- {ok, Content};
- undefined ->
- call({cache_pem, File})
+ case bypass_pem_cache() of
+ true ->
+ ssl_pkix_db:decode_pem_file(File);
+ false ->
+ case ssl_pkix_db:lookup_cached_pem(DbHandle, File) of
+ [{Content,_}] ->
+ {ok, Content};
+ [Content] ->
+ {ok, Content};
+ undefined ->
+ call({cache_pem, File})
+ end
end.
%%--------------------------------------------------------------------
@@ -506,6 +523,14 @@ delay_time() ->
?CLEAN_SESSION_DB
end.
+bypass_pem_cache() ->
+ case application:get_env(ssl, bypass_pem_cache) of
+ {ok, Bool} when is_boolean(Bool) ->
+ Bool;
+ _ ->
+ false
+ end.
+
max_session_cache_size(CacheType) ->
case application:get_env(ssl, CacheType) of
{ok, Size} when is_integer(Size) ->
diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index b16903d7c7..0006ce14d9 100644
--- a/lib/ssl/src/ssl_pkix_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -29,10 +29,11 @@
-include_lib("kernel/include/file.hrl").
-export([create/0, add_crls/3, remove_crls/2, remove/1, add_trusted_certs/3,
+ extract_trusted_certs/1,
remove_trusted_certs/2, insert/3, remove/2, clear/1, db_size/1,
ref_count/3, lookup_trusted_cert/4, foldl/3, select_cert_by_issuer/2,
lookup_cached_pem/2, cache_pem_file/2, cache_pem_file/3,
- lookup/2]).
+ decode_pem_file/1, lookup/2]).
%%====================================================================
%% Internal application API
@@ -82,12 +83,22 @@ remove(Dbs) ->
%% <SerialNumber, Issuer>. Ref is used as it is specified
%% for each connection which certificates are trusted.
%%--------------------------------------------------------------------
-lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
+lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) when is_reference(Ref) ->
case lookup({Ref, SerialNumber, Issuer}, DbHandle) of
undefined ->
undefined;
[Certs] ->
{ok, Certs}
+ end;
+lookup_trusted_cert(_DbHandle, {extracted,Certs}, SerialNumber, Issuer) ->
+ try
+ [throw(Cert)
+ || {decoded, {{_Ref,CertSerial,CertIssuer}, Cert}} <- Certs,
+ CertSerial =:= SerialNumber, CertIssuer =:= Issuer],
+ undefined
+ catch
+ Cert ->
+ {ok, Cert}
end.
lookup_cached_pem([_, _, PemChache | _], File) ->
@@ -103,6 +114,9 @@ lookup_cached_pem(PemChache, File) ->
%% runtime database. Returns Ref that should be handed to lookup_trusted_cert
%% together with the cert serialnumber and issuer.
%%--------------------------------------------------------------------
+add_trusted_certs(_Pid, {extracted, _} = Certs, _) ->
+ {ok, Certs};
+
add_trusted_certs(_Pid, {der, DerList}, [CertDb, _,_ | _]) ->
NewRef = make_ref(),
add_certs_from_der(DerList, NewRef, CertDb),
@@ -122,6 +136,21 @@ add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache | _] = Db) ->
undefined ->
new_trusted_cert_entry(File, Db)
end.
+
+extract_trusted_certs({der, DerList}) ->
+ {ok, {extracted, certs_from_der(DerList)}};
+extract_trusted_certs(File) ->
+ case file:read_file(File) of
+ {ok, PemBin} ->
+ Content = public_key:pem_decode(PemBin),
+ DerList = [Cert || {'Certificate', Cert, not_encrypted} <- Content],
+ {ok, {extracted, certs_from_der(DerList)}};
+ Error ->
+ %% Have to simulate a failure happening in a server for
+ %% external handlers.
+ {error, {badmatch, Error}}
+ end.
+
%%--------------------------------------------------------------------
%%
%% Description: Cache file as binary in DB
@@ -141,6 +170,18 @@ cache_pem_file(Ref, File, [_CertsDb, _RefDb, PemChache| _]) ->
insert(File, {Content, Ref}, PemChache),
{ok, Content}.
+-spec decode_pem_file(binary()) -> {ok, term()}.
+decode_pem_file(File) ->
+ case file:read_file(File) of
+ {ok, PemBin} ->
+ Content = public_key:pem_decode(PemBin),
+ {ok, Content};
+ Error ->
+ %% Have to simulate a failure happening in a server for
+ %% external handlers.
+ {error, {badmatch, Error}}
+ end.
+
%%--------------------------------------------------------------------
-spec remove_trusted_certs(reference(), db_handle()) -> ok.
%%
@@ -203,6 +244,8 @@ select_cert_by_issuer(Cache, Issuer) ->
%%
%% Description: Updates a reference counter in a <Db>.
%%--------------------------------------------------------------------
+ref_count({extracted, _}, _Db, _N) ->
+ not_cached;
ref_count(Key, Db, N) ->
ets:update_counter(Db,Key,N).
@@ -248,23 +291,39 @@ add_certs_from_der(DerList, Ref, CertsDb) ->
[Add(Cert) || Cert <- DerList],
ok.
+certs_from_der(DerList) ->
+ Ref = make_ref(),
+ [Decoded || Cert <- DerList,
+ Decoded <- [decode_certs(Ref, Cert)],
+ Decoded =/= undefined].
+
add_certs_from_pem(PemEntries, Ref, CertsDb) ->
Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end,
[Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries],
ok.
add_certs(Cert, Ref, CertsDb) ->
+ try
+ {decoded, {Key, Val}} = decode_certs(Ref, Cert),
+ insert(Key, Val, CertsDb)
+ catch
+ error:_ ->
+ ok
+ end.
+
+decode_certs(Ref, Cert) ->
try ErlCert = public_key:pkix_decode_cert(Cert, otp),
TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
Issuer = public_key:pkix_normalize_name(
TBSCertificate#'OTPTBSCertificate'.issuer),
- insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb)
+ {decoded, {{Ref, SerialNumber, Issuer}, {Cert, ErlCert}}}
catch
error:_ ->
Report = io_lib:format("SSL WARNING: Ignoring a CA cert as "
"it could not be correctly decoded.~n", []),
- error_logger:info_report(Report)
+ error_logger:info_report(Report),
+ undefined
end.
new_trusted_cert_entry(File, [CertsDb, RefDb, _ | _] = Db) ->