diff options
author | Fred Hebert <[email protected]> | 2016-08-19 08:46:48 -0400 |
---|---|---|
committer | Fred Hebert <[email protected]> | 2016-08-19 15:52:54 -0400 |
commit | 59ec0761d69608a6d4be2db1967e71efdb9f535d (patch) | |
tree | 171ac09fea4f3149cc2602361aea847cfda1c005 /lib/ssl/src/ssl_certificate.erl | |
parent | 7b1cda1f97cd3ec91e7111b22aeffa3b5a6812f1 (diff) | |
download | otp-59ec0761d69608a6d4be2db1967e71efdb9f535d.tar.gz otp-59ec0761d69608a6d4be2db1967e71efdb9f535d.tar.bz2 otp-59ec0761d69608a6d4be2db1967e71efdb9f535d.zip |
Add option to bypass SSL PEM cache
The current SSL implementation has a PEM cache running through the ssl
manager process, whose primary role is caching CA chains from files on
disk. This is intended as a way to save on disk operation when the
requested certificates are often the same, and those cache values are
both time-bound and reference-counted. The code path also includes
caching the Erlang-formatted certificate as decoded by the public_key
application
The same code path is used for DER-encoded certificates, which are
passed in memory and do not require file access. These certificates are
cached, but not reference-counted and also not shared across
connections.
For heavy usage of DER-encoded certificates, the PEM cache becomes a
central bottleneck for a server, forcing the decoding of every one of
them individually through a single critical process. It is also not
clear if the cache remains useful for disk certificates in all cases.
This commit adds a configuration variable for the ssl application
(bypass_pem_cache = true | false) which allows to open files and decode
certificates in the calling connection process rather than the manager.
When this action takes place, the operations to cache and return data
are replaced to strictly return data.
To provide a transparent behaviour, the 'CacheDbRef' used to keep track
of the certificates in the cache is replaced by the certificates itself,
and all further lookup functions or folds can be done locally.
This has proven under benchmark to more than triple the performance of
the SSL application under load (once the session cache had also been
disabled).
Diffstat (limited to 'lib/ssl/src/ssl_certificate.erl')
-rw-r--r-- | lib/ssl/src/ssl_certificate.erl | 34 |
1 files changed, 23 insertions, 11 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 -> |