summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Witczak <u3s@users.noreply.github.com>2023-03-28 15:49:22 +0200
committerGitHub <noreply@github.com>2023-03-28 15:49:22 +0200
commitae9bdb95ff6659b4f52afb65e9c00af8151bd8b3 (patch)
treef1809a87e344460a8671ef3d2cab79879982f162
parent8d0442ed1912bb8cc8b39c81af141e591fd32219 (diff)
parentbfcac10062c4cb8cbde6f197649841ab0cc8d07d (diff)
downloaderlang-ae9bdb95ff6659b4f52afb65e9c00af8151bd8b3.tar.gz
Merge pull request #7033 from u3s/kuba/ssl/exp_ocsp_refactor
Kuba/ssl/exp ocsp refactor
-rw-r--r--lib/public_key/src/pubkey_ocsp.erl117
-rw-r--r--lib/public_key/src/public_key.erl81
-rw-r--r--lib/ssl/src/dtls_connection.erl7
-rw-r--r--lib/ssl/src/ssl.erl54
-rw-r--r--lib/ssl/src/ssl_certificate.erl7
-rw-r--r--lib/ssl/src/ssl_gen_statem.erl16
-rw-r--r--lib/ssl/src/ssl_handshake.erl47
-rw-r--r--lib/ssl/src/ssl_internal.hrl10
-rw-r--r--lib/ssl/src/ssl_trace.erl27
-rw-r--r--lib/ssl/src/tls_dtls_connection.erl12
-rw-r--r--lib/ssl/src/tls_handshake.erl18
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl11
-rw-r--r--lib/ssl/test/openssl_ocsp_SUITE.erl116
-rw-r--r--lib/ssl/test/ssl_api_SUITE.erl21
-rw-r--r--lib/ssl/test/ssl_dist_test_lib.erl8
-rw-r--r--lib/ssl/test/ssl_test_lib.erl27
-rw-r--r--lib/ssl/test/ssl_test_lib.hrl2
-rw-r--r--lib/ssl/test/ssl_trace_SUITE.erl10
18 files changed, 348 insertions, 243 deletions
diff --git a/lib/public_key/src/pubkey_ocsp.erl b/lib/public_key/src/pubkey_ocsp.erl
index ea658f1c5d..6bdb9a563f 100644
--- a/lib/public_key/src/pubkey_ocsp.erl
+++ b/lib/public_key/src/pubkey_ocsp.erl
@@ -19,27 +19,17 @@
%%
-module(pubkey_ocsp).
-
-include("public_key.hrl").
--export([otp_cert/1,
- get_ocsp_responder_id/1,
+-export([find_single_response/3,
+ get_acceptable_response_types_extn/0,
get_nonce_extn/1,
+ get_ocsp_responder_id/1,
+ ocsp_status/1,
verify_ocsp_response/3,
- get_acceptable_response_types_extn/0,
- find_single_response/3,
- ocsp_status/1]).
-
-%% Test related exports
--export([decode_ocsp_response/1]).
-
-otp_cert(#'OTPCertificate'{} = Cert) ->
- Cert;
-otp_cert(#'Certificate'{} = Cert) ->
- public_key:pkix_decode_cert(
- public_key:der_encode('Certificate', Cert), otp);
-otp_cert(CertDer) when is_binary(CertDer) ->
- public_key:pkix_decode_cert(CertDer, otp).
+ decode_ocsp_response/1]).
+%% Tracing
+-export([handle_trace/3]).
-spec get_ocsp_responder_id(#'Certificate'{}) -> binary().
get_ocsp_responder_id(#'Certificate'{tbsCertificate = TbsCert}) ->
@@ -55,11 +45,10 @@ get_nonce_extn(Nonce) when is_binary(Nonce) ->
extnValue = Nonce
}.
--spec verify_ocsp_response(binary(), list(), undefined | binary()) ->
+-spec verify_ocsp_response(#'BasicOCSPResponse'{}, list(), undefined | binary()) ->
{ok, term()} | {error, term()}.
-verify_ocsp_response(OCSPResponseDer, ResponderCerts, Nonce) ->
- do_verify_ocsp_response(
- decode_ocsp_response(OCSPResponseDer), ResponderCerts, Nonce).
+verify_ocsp_response(OCSPResponse, ResponderCerts, Nonce) ->
+ do_verify_ocsp_response(OCSPResponse, ResponderCerts, Nonce).
-spec get_acceptable_response_types_extn() -> #'Extension'{}.
get_acceptable_response_types_extn() ->
@@ -114,8 +103,7 @@ match_single_response(IssuerName, IssuerKey, SerialNum,
match_single_response(IssuerName, IssuerKey, SerialNum, Responses)
end.
-get_serial_num(Cert) ->
- #'OTPCertificate'{tbsCertificate = TbsCert} = otp_cert(Cert),
+get_serial_num(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
TbsCert#'OTPTBSCertificate'.serialNumber.
decode_response_bytes(#'ResponseBytes'{
@@ -125,25 +113,22 @@ decode_response_bytes(#'ResponseBytes'{
decode_response_bytes(#'ResponseBytes'{responseType = RespType}) ->
{error, {ocsp_response_type_not_supported, RespType}}.
-do_verify_ocsp_response({ok, #'BasicOCSPResponse'{
- tbsResponseData = ResponseData,
- signatureAlgorithm = SignatureAlgo,
- signature = Signature,
- certs = Certs}},
+do_verify_ocsp_response(#'BasicOCSPResponse'{
+ tbsResponseData = ResponseData,
+ signatureAlgorithm = SignatureAlgo,
+ signature = Signature},
ResponderCerts, Nonce) ->
#'ResponseData'{responderID = ResponderID} = ResponseData,
case verify_ocsp_signature(
public_key:der_encode('ResponseData', ResponseData),
SignatureAlgo#'AlgorithmIdentifier'.algorithm,
- Signature, Certs ++ ResponderCerts,
+ Signature, ResponderCerts,
ResponderID) of
ok ->
verify_ocsp_nonce(ResponseData, Nonce);
{error, Reason} ->
{error, Reason}
- end;
-do_verify_ocsp_response({error, Reason}, _ResponderCerts, _Nonce) ->
- {error, Reason}.
+ end.
verify_ocsp_nonce(ResponseData, Nonce) ->
#'ResponseData'{responses = Responses, responseExtensions = ResponseExtns} =
@@ -188,18 +173,29 @@ find_responder_cert(ResponderID, [Cert | TCerts]) ->
find_responder_cert(ResponderID, TCerts)
end.
+do_verify_ocsp_signature(ResponseDataDer, Signature, AlgorithmID, Cert) ->
+ {DigestType, _SignatureType} = public_key:pkix_sign_types(AlgorithmID),
+ case public_key:verify(
+ ResponseDataDer, DigestType, Signature,
+ get_public_key_rec(Cert)) of
+ true ->
+ ok;
+ false ->
+ {error, ocsp_response_bad_signature}
+ end.
+
+get_public_key_rec(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
+ PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey.
+
is_responder({byName, Name}, Cert) ->
public_key:der_encode('Name', Name) == get_subject_name(Cert);
is_responder({byKey, Key}, Cert) ->
Key == crypto:hash(sha, get_public_key(Cert)).
-get_subject_name(#'Certificate'{} = Cert) ->
- get_subject_name(otp_cert(Cert));
get_subject_name(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
public_key:pkix_encode('Name', TbsCert#'OTPTBSCertificate'.subject, otp).
-get_public_key(#'Certificate'{} = Cert) ->
- get_public_key(otp_cert(Cert));
get_public_key(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
enc_pub_key(PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey).
@@ -211,20 +207,35 @@ enc_pub_key({DsaInt, #'Dss-Parms'{}}) when is_integer(DsaInt) ->
enc_pub_key({#'ECPoint'{point = Key}, _ECParam}) ->
Key.
-do_verify_ocsp_signature(ResponseDataDer, Signature, AlgorithmID, Cert) ->
- {DigestType, _SignatureType} = public_key:pkix_sign_types(AlgorithmID),
- case public_key:verify(
- ResponseDataDer, DigestType, Signature,
- get_public_key_rec(Cert)) of
- true ->
- ok;
- false ->
- {error, ocsp_response_bad_signature}
- end.
-
-get_public_key_rec(#'Certificate'{} = Cert) ->
- get_public_key_rec(otp_cert(Cert));
-get_public_key_rec(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
- PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
- PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey.
-
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+handle_trace(csp,
+ {call, {?MODULE, do_verify_ocsp_response, [BasicOcspResponse | _]}}, Stack) ->
+ #'BasicOCSPResponse'{
+ tbsResponseData =
+ #'ResponseData'{responderID = ResponderID,
+ producedAt = ProducedAt}} = BasicOcspResponse,
+ {io_lib:format("ResponderId = ~W producedAt = ~p", [ResponderID, 5, ProducedAt]), Stack};
+handle_trace(csp,
+ {call, {?MODULE, match_single_response,
+ [_IssuerName, _IssuerKey, _SerialNum,
+ [#'SingleResponse'{thisUpdate = ThisUpdate,
+ nextUpdate = NextUpdate}]]}}, Stack) ->
+ {io_lib:format("ThisUpdate = ~p NextUpdate = ~p", [ThisUpdate, NextUpdate]), Stack};
+handle_trace(csp,
+ {call, {?MODULE, is_responder, [Id, Cert]}}, Stack) ->
+ {io_lib:format("~nId = ~P~nCert = ~P", [Id, 10, Cert, 10]), Stack};
+handle_trace(csp,
+ {call, {?MODULE, find_single_response, [Cert, IssuerCert | _]}}, Stack) ->
+ {io_lib:format("#2 OCSP validation started~nCert = ~W IssuerCert = ~W",
+ [Cert, 7, IssuerCert, 7]), Stack};
+ %% {io_lib:format("#2 OCSP validation started~nCert = ~s IssuerCert = ~s",
+ %% [ssl_test_lib:format_cert(Cert),
+ %% ssl_test_lib:format_cert(IssuerCert)]), Stack};
+
+handle_trace(csp,
+ {return_from, {?MODULE, is_responder, 2}, Return},
+ Stack) ->
+ {io_lib:format("Return = ~p", [Return]), Stack}.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 77e8b70e96..8c3805c219 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -69,6 +69,8 @@
cacerts_load/1,
cacerts_clear/0
]).
+%% Tracing
+-export([handle_trace/3]).
%%----------------
%% Moved to ssh
@@ -77,7 +79,6 @@
{ssh_hostkey_fingerprint,1, "use ssh:hostkey_fingerprint/1 instead"},
{ssh_hostkey_fingerprint,2, "use ssh:hostkey_fingerprint/2 instead"}
]).
-
-export([ssh_curvename2oid/1, oid2ssh_curvename/1]).
%% When removing for OTP-25.0, remember to also remove
%% - most of pubkey_ssh.erl except
@@ -1382,9 +1383,28 @@ pkix_ocsp_validate(Cert, DerIssuerCert, OcspRespDer, ResponderCerts, NonceExt)
pkix_ocsp_validate(Cert, pkix_decode_cert(DerIssuerCert, otp), OcspRespDer,
ResponderCerts, NonceExt);
pkix_ocsp_validate(Cert, IssuerCert, OcspRespDer, ResponderCerts, NonceExt) ->
- case ocsp_responses(OcspRespDer, ResponderCerts, NonceExt) of
+ OcspResponse = pubkey_ocsp:decode_ocsp_response(OcspRespDer),
+ OcspCertResponses =
+ case OcspResponse of
+ {ok, BasicOcspResponse = #'BasicOCSPResponse'{certs = Certs}} ->
+ OcspResponseCerts = [otp_cert(C) || C <- Certs],
+ UserResponderCerts =
+ [otp_cert(pkix_decode_cert(C, plain)) || C <- ResponderCerts],
+ pubkey_ocsp:verify_ocsp_response(
+ BasicOcspResponse, OcspResponseCerts ++ UserResponderCerts,
+ NonceExt);
+ {error, _} = Error ->
+ Error
+ end,
+ case OcspCertResponses of
{ok, Responses} ->
- ocsp_status(Cert, IssuerCert, Responses);
+ case pubkey_ocsp:find_single_response(
+ otp_cert(Cert), otp_cert(IssuerCert), Responses) of
+ {ok, #'SingleResponse'{certStatus = CertStatus}} ->
+ pubkey_ocsp:ocsp_status(CertStatus);
+ {error, no_matched_response = Reason} ->
+ {bad_cert, {revocation_status_undetermined, Reason}}
+ end;
{error, Reason} ->
{bad_cert, {revocation_status_undetermined, Reason}}
end.
@@ -1399,12 +1419,12 @@ ocsp_extensions(Nonce) ->
erlang:is_record(Extn, 'Extension')].
%%--------------------------------------------------------------------
--spec ocsp_responder_id(#'Certificate'{}) -> binary().
+-spec ocsp_responder_id(binary()) -> binary().
%%
%% Description: Get the OCSP responder ID der
%%--------------------------------------------------------------------
-ocsp_responder_id(Cert) ->
- pubkey_ocsp:get_ocsp_responder_id(Cert).
+ocsp_responder_id(CertDer) ->
+ pubkey_ocsp:get_ocsp_responder_id(pkix_decode_cert(CertDer, plain)).
%%--------------------------------------------------------------------
-spec cacerts_get() -> [combined_cert()].
@@ -1622,7 +1642,9 @@ otp_cert(Der) when is_binary(Der) ->
otp_cert(#'OTPCertificate'{} = Cert) ->
Cert;
otp_cert(#cert{otp = OtpCert}) ->
- OtpCert.
+ OtpCert;
+otp_cert(#'Certificate'{} = Cert) ->
+ pkix_decode_cert(der_encode('Certificate', Cert), otp).
der_cert(#'OTPCertificate'{} = Cert) ->
pkix_encode('OTPCertificate', Cert, otp);
@@ -2031,18 +2053,39 @@ format_details([]) ->
no_relevant_crls;
format_details(Details) ->
Details.
-
-ocsp_status(Cert, IssuerCert, Responses) ->
- case pubkey_ocsp:find_single_response(Cert, IssuerCert, Responses) of
- {ok, #'SingleResponse'{certStatus = CertStatus}} ->
- pubkey_ocsp:ocsp_status(CertStatus);
- {error, no_matched_response = Reason} ->
- {bad_cert, {revocation_status_undetermined, Reason}}
- end.
-
-ocsp_responses(OCSPResponseDer, ResponderCerts, Nonce) ->
- pubkey_ocsp:verify_ocsp_response(OCSPResponseDer,
- ResponderCerts, Nonce).
subject_public_key_info(Alg, PubKey) ->
#'OTPSubjectPublicKeyInfo'{algorithm = Alg, subjectPublicKey = PubKey}.
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+handle_trace(csp,
+ {call, {?MODULE, ocsp_responder_id, [Cert]}}, Stack) ->
+ {io_lib:format("pkix_decode_cert(Cert, plain) = ~W", [Cert, 5]),
+ %% {io_lib:format("pkix_decode_cert(Cert, plain) = ~s", [ssl_test_lib:format_cert(Cert)]),
+ Stack};
+handle_trace(csp,
+ {return_from, {?MODULE, ocsp_responder_id, 1}, Return},
+ Stack) ->
+ {io_lib:format("OCSP Responder ID = ~P", [Return, 10]), Stack};
+handle_trace(crt,
+ {call, {?MODULE, pkix_decode_cert, [Cert, _Type]}}, Stack) ->
+ {io_lib:format("Cert = ~W", [Cert, 5]), Stack};
+ %% {io_lib:format("Cert = ~s", [ssl_test_lib:format_cert(Cert)]), Stack};
+handle_trace(csp,
+ {call, {?MODULE, pkix_ocsp_validate, [Cert, IssuerCert | _]}}, Stack) ->
+ {io_lib:format("#2 OCSP validation started~nCert = ~W IssuerCert = ~W",
+ [Cert, 7, IssuerCert, 7]), Stack};
+ %% {io_lib:format("#2 OCSP validation started~nCert = ~s IssuerCert = ~s",
+ %% [ssl_test_lib:format_cert(Cert),
+ %% ssl_test_lib:format_cert(IssuerCert)]), Stack};
+handle_trace(csp,
+ {call, {?MODULE, otp_cert, [Cert]}}, Stack) ->
+ {io_lib:format("Cert = ~W", [Cert, 5]), Stack};
+ %% {io_lib:format("Cert = ~s", [ssl_test_lib:format_cert(otp_cert(Cert))]), Stack};
+handle_trace(csp,
+ {return_from, {?MODULE, pkix_ocsp_validate, 5}, Return},
+ Stack) ->
+ {io_lib:format("#2 OCSP validation result = ~p", [Return]), Stack}.
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 197d2397bb..a37a72efdc 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -88,7 +88,7 @@
%% | Abbrev Flight 1 to Abbrev Flight 2 part 1
%% |
%% New session | Resumed session
-%% WAIT_OCSP_STAPELING CERTIFY <----------------------------------> ABBRIVIATED
+%% WAIT_OCSP_STAPLING CERTIFY <----------------------------------> ABBREVIATED
%%
%% <- Possibly Receive -- | |
%% OCSP Stapel ------> | Send/ Recv Flight 5 |
@@ -307,13 +307,12 @@ hello(internal, #hello_verify_request{cookie = Cookie},
handshake_env = #handshake_env{renegotiation = {Renegotiation, _},
ocsp_stapling_state = OcspState0} = HsEnv,
connection_env = CEnv,
- ssl_options = #{ocsp_stapling := OcspStaplingOpt,
- ocsp_nonce := OcspNonceOpt} = SslOpts,
+ ssl_options = SslOpts,
session = #session{session_id = Id},
connection_states = ConnectionStates0,
protocol_specific = PS
} = State0) ->
- OcspNonce = tls_handshake:ocsp_nonce(OcspNonceOpt, OcspStaplingOpt),
+ OcspNonce = tls_handshake:ocsp_nonce(SslOpts),
Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0,
SslOpts, Id, Renegotiation, OcspNonce),
Version = Hello#client_hello.client_version,
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 8c87329ce9..29d0cb0a32 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1927,23 +1927,32 @@ opt_tickets(UserOpts, #{versions := Versions} = Opts, #{role := server}) ->
anti_replay => AntiReplay, stateless_tickets_seed => STS}.
opt_ocsp(UserOpts, #{versions := _Versions} = Opts, #{role := Role}) ->
- {_, Stapling} = get_opt_bool(ocsp_stapling, false, UserOpts, Opts),
+ {Stapling, SMap} =
+ case get_opt(ocsp_stapling, ?DEFAULT_OCSP_STAPLING, UserOpts, Opts) of
+ {old, Map} when is_map(Map) -> {true, Map};
+ {_, Bool} when is_boolean(Bool) -> {Bool, #{}};
+ {_, Value} -> option_error(ocsp_stapling, Value)
+ end,
assert_client_only(Role, Stapling, ocsp_stapling),
-
- {_, Nonce} = get_opt_bool(ocsp_nonce, true, UserOpts, Opts),
- option_incompatible(Stapling =:= false andalso Nonce =:= false, [{ocsp_nonce, false}, {ocsp_stapling, false}]),
-
- {_, ORC} = get_opt_list(ocsp_responder_certs, [], UserOpts, Opts),
- option_incompatible(Stapling =:= false andalso ORC =/= [], [ocsp_responder_certs, {ocsp_stapling, false}]),
- %% FIXME should not be decoded in users process !!
- Decode = fun(CertDer) ->
- try public_key:pkix_decode_cert(CertDer, plain)
- catch _:_ -> option_error(ocsp_responder_certs, ORC)
- end
- end,
- Certs = [Decode(CertDer) || CertDer <- ORC],
- %% FIXME make it one option?
- Opts#{ocsp_stapling => Stapling, ocsp_nonce => Nonce, ocsp_responder_certs => Certs}.
+ {_, Nonce} = get_opt_bool(ocsp_nonce, ?DEFAULT_OCSP_NONCE, UserOpts, SMap),
+ option_incompatible(Stapling =:= false andalso Nonce =:= false,
+ [{ocsp_nonce, false}, {ocsp_stapling, false}]),
+ {_, ORC} = get_opt_list(ocsp_responder_certs, ?DEFAULT_OCSP_RESPONDER_CERTS,
+ UserOpts, SMap),
+ CheckBinary = fun(Cert) when is_binary(Cert) -> ok;
+ (_Cert) -> option_error(ocsp_responder_certs, ORC)
+ end,
+ [CheckBinary(C) || C <- ORC],
+ option_incompatible(Stapling =:= false andalso ORC =/= [],
+ [ocsp_responder_certs, {ocsp_stapling, false}]),
+ case Stapling of
+ true ->
+ Opts#{ocsp_stapling =>
+ #{ocsp_nonce => Nonce,
+ ocsp_responder_certs => ORC}};
+ false ->
+ Opts
+ end.
opt_sni(UserOpts, #{versions := _Versions} = Opts, #{role := server}) ->
{_, SniHosts} = get_opt_list(sni_hosts, [], UserOpts, Opts),
@@ -2857,11 +2866,10 @@ unambiguous_path(Value) ->
%%%#
%%%# Tracing
%%%#
+handle_trace(csp, {call, {?MODULE, opt_ocsp, [UserOpts | _]}}, Stack) ->
+ {format_ocsp_params(UserOpts), Stack};
handle_trace(csp, {return_from, {?MODULE, opt_ocsp, 3}, Return}, Stack) ->
- #{ocsp_stapling := Stapling, ocsp_nonce := Nonce,
- ocsp_responder_certs := Certs} = Return,
- {io_lib:format("Stapling = ~w Nonce = ~W Certs = ~W",
- [Stapling, Nonce, 5, Certs, 5]), Stack};
+ {format_ocsp_params(Return), Stack};
handle_trace(rle, {call, {?MODULE, listen, Args}}, Stack0) ->
Role = server,
{io_lib:format("(*~w) Args = ~W", [Role, Args, 10]), [{role, Role} | Stack0]};
@@ -2869,3 +2877,9 @@ handle_trace(rle, {call, {?MODULE, connect, Args}}, Stack0) ->
Role = client,
{io_lib:format("(*~w) Args = ~W", [Role, Args, 10]), [{role, Role} | Stack0]}.
+format_ocsp_params(Map) ->
+ Stapling = maps:get(ocsp_stapling, Map, '?'),
+ Nonce = maps:get(ocsp_nonce, Map, '?'),
+ Certs = maps:get(ocsp_responder_certs, Map, '?'),
+ io_lib:format("Stapling = ~W Nonce = ~W Certs = ~W",
+ [Stapling, 5, Nonce, 5, Certs, 5]).
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 5b45354a9b..cc641ca2f5 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -834,11 +834,14 @@ cert_auth_member(ChainSubjects, CertAuths) ->
handle_trace(crt,
{call, {?MODULE, validate, [Cert, StatusOrExt| _]}}, Stack) ->
{io_lib:format("[~W] StatusOrExt = ~W", [Cert, 3, StatusOrExt, 10]), Stack};
+ %% {io_lib:format("(~s) StatusOrExt = ~W",
+ %% [ssl_test_lib:format_cert(Cert), StatusOrExt, 10]), Stack};
handle_trace(crt, {call, {?MODULE, verify_cert_extensions,
[Cert,
_UserState,
[], _Context]}}, Stack) ->
{io_lib:format(" no more extensions [~W]", [Cert, 3]), Stack};
+ %% {io_lib:format(" no more extensions (~s)", [ssl_test_lib:format_cert(Cert)]), Stack};
handle_trace(crt, {call, {?MODULE, verify_cert_extensions,
[Cert,
#{ocsp_responder_certs := _ResponderCerts,
@@ -849,7 +852,11 @@ handle_trace(crt, {call, {?MODULE, verify_cert_extensions,
{io_lib:format("#2 OcspState = ~W Issuer = [~W] OcspResponsDer = ~W [~W]",
[OcspState, 10, Issuer, 3, OcspResponsDer, 2, Cert, 3]),
Stack};
+ %% {io_lib:format("#2 OcspState = ~W Issuer = (~s) OcspResponsDer = ~W (~s)",
+ %% [OcspState, 10, ssl_test_lib:format_cert(Issuer),
+ %% OcspResponsDer, 2, ssl_test_lib:format_cert(Cert)]),
handle_trace(crt, {return_from,
{ssl_certificate, verify_cert_extensions, 4},
{valid, #{issuer := Issuer}}}, Stack) ->
{io_lib:format(" extensions valid Issuer = ~W", [Issuer, 3]), Stack}.
+ %% {io_lib:format(" extensions valid Issuer = ~s", [ssl_test_lib:format_cert(Issuer)]), Stack}.
diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl
index 139d922172..d0941a9689 100644
--- a/lib/ssl/src/ssl_gen_statem.erl
+++ b/lib/ssl/src/ssl_gen_statem.erl
@@ -489,8 +489,6 @@ initial_hello({call, From}, {start, Timeout},
%% Versions is a descending list of supported versions.
versions := [HelloVersion|_] = Versions,
session_tickets := SessionTickets,
- ocsp_stapling := OcspStaplingOpt,
- ocsp_nonce := OcspNonceOpt,
early_data := EarlyData} = SslOpts,
session = Session,
connection_states = ConnectionStates0
@@ -502,7 +500,7 @@ initial_hello({call, From}, {start, Timeout},
%% the max_early_data_size or if it can only be used for session resumption.
{UseTicket, State1} = tls_client_connection_1_3:maybe_automatic_session_resumption(State0),
TicketData = tls_handshake_1_3:get_ticket_data(self(), SessionTickets, UseTicket),
- OcspNonce = tls_handshake:ocsp_nonce(OcspNonceOpt, OcspStaplingOpt),
+ OcspNonce = tls_handshake:ocsp_nonce(SslOpts),
Hello0 = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Session#session.session_id,
Renegotiation,
@@ -544,13 +542,16 @@ initial_hello({call, From}, {start, Timeout},
{#state{handshake_env = HsEnv1} = State5, _} =
Connection:send_handshake_flight(State4),
+ OcspStaplingKeyPresent = maps:is_key(ocsp_stapling, SslOpts),
State = State5#state{
connection_env = CEnv#connection_env{
negotiated_version = RequestedVersion},
session = Session,
- handshake_env = HsEnv1#handshake_env{
- ocsp_stapling_state = OcspState0#{ocsp_nonce => OcspNonce,
- ocsp_stapling => OcspStaplingOpt}},
+ handshake_env =
+ HsEnv1#handshake_env{
+ ocsp_stapling_state =
+ OcspState0#{ocsp_nonce => OcspNonce,
+ ocsp_stapling => OcspStaplingKeyPresent}},
start_or_recv_from = From,
key_share = KeyShare},
NextState = next_statem_state(Versions, Role),
@@ -2243,6 +2244,9 @@ maybe_generate_client_shares(_) ->
%%%#
%%%# Tracing
%%%#
+handle_trace(api,
+ {call, {?MODULE, connect, [Connection | _]}}, Stack0) ->
+ {io_lib:format("Connection = ~w", [Connection]), Stack0};
handle_trace(rle,
{call, {?MODULE, init, Args = [[Role | _]]}}, Stack0) ->
{io_lib:format("(*~w) Args = ~W", [Role, Args, 3]), [{role, Role} | Stack0]};
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 152d3f16bd..1915b6f10c 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -84,7 +84,6 @@
-export([get_cert_params/1,
select_own_cert/1,
server_name/3,
- path_validate/9,
path_validation/10,
validation_fun_and_state/4,
path_validation_alert/1]).
@@ -1323,13 +1322,9 @@ maybe_add_tls13_extensions({3,4},
maybe_add_tls13_extensions(_, HelloExtensions, _, _, _, _,_) ->
HelloExtensions.
-maybe_add_certificate_status_request(
- _Version, #{ocsp_stapling := false}, _OcspNonce, HelloExtensions) ->
- HelloExtensions;
-maybe_add_certificate_status_request(
- _Version, #{ocsp_stapling := true,
- ocsp_responder_certs := OcspResponderCerts},
- OcspNonce, HelloExtensions) ->
+maybe_add_certificate_status_request(_Version, #{ocsp_stapling := OcspStapling},
+ OcspNonce, HelloExtensions) ->
+ OcspResponderCerts = maps:get(ocsp_responder_certs, OcspStapling),
OcspResponderList = get_ocsp_responder_list(OcspResponderCerts),
OcspRequestExtns = public_key:ocsp_extensions(OcspNonce),
Req = #ocsp_status_request{responder_id_list = OcspResponderList,
@@ -1338,7 +1333,10 @@ maybe_add_certificate_status_request(
status_type = ?CERTIFICATE_STATUS_TYPE_OCSP,
request = Req
},
- HelloExtensions#{status_request => CertStatusReqExtn}.
+ HelloExtensions#{status_request => CertStatusReqExtn};
+maybe_add_certificate_status_request(_Version, _SslOpts, _OcspNonce,
+ HelloExtensions) ->
+ HelloExtensions.
get_ocsp_responder_list(ResponderCerts) ->
get_ocsp_responder_list(ResponderCerts, []).
@@ -1537,8 +1535,8 @@ handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites,
handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
Exts, Version,
- #{secure_renegotiate := SecureRenegotation,
- ocsp_stapling := Stapling} = SslOpts,
+ #{secure_renegotiate := SecureRenegotation} =
+ SslOpts,
ConnectionStates0, Renegotiation, IsNew) ->
ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version,
maps:get(renegotiation_info, Exts, undefined), Random,
@@ -1561,7 +1559,7 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
ok
end,
- case handle_ocsp_extension(Stapling, Exts) of
+ case handle_ocsp_extension(SslOpts, Exts) of
#alert{} = Alert ->
Alert;
OcspState ->
@@ -1956,21 +1954,21 @@ extension_value(#psk_key_exchange_modes{ke_modes = Modes}) ->
extension_value(#cookie{cookie = Cookie}) ->
Cookie.
-handle_ocsp_extension(true = Stapling, Extensions) ->
+handle_ocsp_extension(#{ocsp_stapling := _OcspStapling}, Extensions) ->
case maps:get(status_request, Extensions, false) of
undefined -> %% status_request in server hello is empty
- #{ocsp_stapling => Stapling,
+ #{ocsp_stapling => true,
ocsp_expect => staple};
false -> %% status_request is missing (not negotiated)
- #{ocsp_stapling => Stapling,
+ #{ocsp_stapling => true,
ocsp_expect => no_staple};
_Else ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, status_request_not_empty)
end;
-handle_ocsp_extension(false = Stapling, Extensions) ->
+handle_ocsp_extension(_SslOpts, Extensions) ->
case maps:get(status_request, Extensions, false) of
false -> %% status_request is missing (not negotiated)
- #{ocsp_stapling => Stapling,
+ #{ocsp_stapling => false,
ocsp_expect => no_staple};
_Else -> %% unsolicited status_request
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_status_request)
@@ -2123,8 +2121,7 @@ path_validation_alert({bad_cert, unknown_critical_extension}) ->
path_validation_alert({bad_cert, {revoked, _}}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED);
path_validation_alert({bad_cert, {revocation_status_undetermined, Details}}) ->
- Alert = ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE),
- Alert#alert{reason = Details};
+ ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE, Details);
path_validation_alert({bad_cert, selfsigned_peer}) ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
path_validation_alert({bad_cert, unknown_ca}) ->
@@ -2208,11 +2205,6 @@ cert_status_check(_OtpCert,
ocsp_expect := undetermined}},
_VerifyResult, _CertPath, _LogLevel) ->
{bad_cert, {revocation_status_undetermined, not_stapled}};
-cert_status_check(OtpCert,
- #{ocsp_state := #{ocsp_stapling := best_effort, %% TODO support this ?
- ocsp_expect := undetermined}} = SslState,
- VerifyResult, CertPath, LogLevel) ->
- maybe_check_crl(OtpCert, SslState, VerifyResult, CertPath, LogLevel);
cert_status_check(_OtpCert,
#{ocsp_state := #{ocsp_stapling := true,
ocsp_expect := no_staple}},
@@ -3941,8 +3933,9 @@ path_validation_cb(_) ->
%%%#
handle_trace(csp,
{call, {?MODULE, maybe_add_certificate_status_request,
- [_Version, #{ocsp_stapling := true},
+ [_Version, SslOpts,
_OcspNonce, _HelloExtensions]}},
Stack) ->
- {io_lib:format("#1 ADDING certificate status request",
- []), Stack}.
+ OcspStapling = maps:get(ocsp_stapling, SslOpts, false),
+ {io_lib:format("#1 ADD crt status request / OcspStapling option = ~W",
+ [OcspStapling, 10]), Stack}.
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index d2da9bd6fd..684f2c8530 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -201,11 +201,7 @@
}).
-define(DEFAULT_DEPTH, 10).
-
-
+-define(DEFAULT_OCSP_STAPLING, false).
+-define(DEFAULT_OCSP_NONCE, true).
+-define(DEFAULT_OCSP_RESPONDER_CERTS, []).
-endif. % -ifdef(ssl_internal).
-
-
-
-
-
diff --git a/lib/ssl/src/ssl_trace.erl b/lib/ssl/src/ssl_trace.erl
index 2bbbb79933..c8ac32712e 100644
--- a/lib/ssl/src/ssl_trace.erl
+++ b/lib/ssl/src/ssl_trace.erl
@@ -421,7 +421,9 @@ trace_profiles() ->
[{ssl,
[{listen,2}, {connect,3}, {handshake,2}, {close, 1}]},
{ssl_gen_statem,
- [{initial_hello,3}, {connect, 8}, {close, 2}, {terminate_alert, 1}]}
+ [{initial_hello,3}, {connect, 8}, {close, 2}, {terminate_alert, 1}]},
+ {tls_gen_connection,
+ [{start_connection_tree, 5}, {socket_control, 6}]}
]},
{csp, %% OCSP
fun(M, F, A) -> dbg:tpl(M, F, A, x) end,
@@ -429,27 +431,40 @@ trace_profiles() ->
[{ssl_handshake, [{maybe_add_certificate_status_request, 4},
{client_hello_extensions, 10}, {cert_status_check, 5},
{get_ocsp_responder_list, 1}, {handle_ocsp_extension, 2},
+ {path_validation, 10},
{handle_server_hello_extensions, 10},
{handle_client_hello_extensions, 10},
{cert_status_check, 5}]},
- {public_key, [{ocsp_extensions, 1}, %%{pkix_decode_cert, 2},
- {pkix_ocsp_validate, 5}]},
+ {public_key, [{ocsp_extensions, 1}, {pkix_ocsp_validate, 5},
+ {ocsp_responder_id, 1}, {otp_cert, 1}]},
+ {pubkey_ocsp, [{find_responder_cert, 2}, {do_verify_ocsp_signature, 4},
+ {verify_ocsp_response, 3}, {verify_ocsp_nonce, 2},
+ {verify_ocsp_signature, 5}, {do_verify_ocsp_response, 3},
+ {is_responder, 2}, {find_single_response, 3},
+ {ocsp_status, 1}, {match_single_response, 4}]},
{ssl, [{opt_ocsp, 3}]},
{ssl_certificate, [{verify_cert_extensions, 4}]},
{ssl_test_lib, [{init_openssl_server, 3}, {openssl_server_loop, 3}]},
{tls_connection, [{wait_ocsp_stapling, 3}]},
{dtls_connection, [{initial_hello, 3}, {hello, 3}, {connection, 3}]},
{tls_dtls_connection, [{wait_ocsp_stapling, 3}, {certify, 3}]},
- {tls_handshake, [{ocsp_expect, 1}, {client_hello, 11}]},
+ {tls_handshake, [{ocsp_nonce, 1}, {ocsp_expect, 1}, {client_hello, 11}]},
{dtls_handshake, [{client_hello, 8}]}]},
{crt, %% certificates
fun(M, F, A) -> dbg:tpl(M, F, A, x) end,
fun(M, F, A) -> dbg:ctpl(M, F, A) end,
- [{public_key, [{pkix_path_validation, 3}]},
- {ssl_certificate, [{validate, 3}]},
+ [{public_key, [{pkix_path_validation, 3}, {path_validation, 2},
+ {pkix_decode_cert, 2}]},
+ {ssl_certificate, [{validate, 3}, {trusted_cert_and_paths, 4},
+ {certificate_chain, 3}, {certificate_chain, 5},
+ {issuer, 1}]},
+ {ssl_cipher, [{filter, 3}]},
{ssl_gen_statem, [{initial_hello, 3}]},
{ssl_handshake, [{path_validate, 11}, {path_validation, 10},
+ {select_hashsign, 5}, {get_cert_params, 1},
+ {cert_curve, 3},
{maybe_check_hostname, 3}, {maybe_check_hostname, 3}]},
+ {ssl_pkix_db, [{decode_cert, 2}]},
{tls_handshake_1_3, [{path_validation, 10}]},
{tls_server_connection_1_3, [{init,1}]},
{tls_client_connection_1_3, [{init,1}]},
diff --git a/lib/ssl/src/tls_dtls_connection.erl b/lib/ssl/src/tls_dtls_connection.erl
index c663d1de8f..51bbc79c98 100644
--- a/lib/ssl/src/tls_dtls_connection.erl
+++ b/lib/ssl/src/tls_dtls_connection.erl
@@ -1682,18 +1682,16 @@ ensure_tls({254, _} = Version) ->
ensure_tls(Version) ->
Version.
-ocsp_info(#{ocsp_expect := stapled,
- ocsp_response := CertStatus} = OcspState,
- #{ocsp_responder_certs := OcspResponderCerts}, PeerCert) ->
+ocsp_info(#{ocsp_expect := stapled, ocsp_response := CertStatus} = OcspState,
+ #{ocsp_stapling := OcspStapling} = _SslOpts, PeerCert) ->
+ #{ocsp_responder_certs := OcspResponderCerts} = OcspStapling,
#{cert_ext => #{public_key:pkix_subject_id(PeerCert) => [CertStatus]},
ocsp_responder_certs => OcspResponderCerts,
- ocsp_state => OcspState
- };
+ ocsp_state => OcspState};
ocsp_info(#{ocsp_expect := no_staple} = OcspState, _, PeerCert) ->
#{cert_ext => #{public_key:pkix_subject_id(PeerCert) => []},
ocsp_responder_certs => [],
- ocsp_state => OcspState
- }.
+ ocsp_state => OcspState}.
select_client_cert_key_pair(Session0,_,
[#{private_key := NoKey, certs := [[]] = NoCerts}],
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index e73324eb11..6e2d0fa903 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -45,7 +45,7 @@
-export([get_tls_handshakes/4, decode_handshake/3]).
%% Handshake helper
--export([ocsp_nonce/2]).
+-export([ocsp_nonce/1]).
-type tls_handshake() :: #client_hello{} | ssl_handshake:ssl_handshake().
@@ -161,8 +161,9 @@ hello(#server_hello{server_version = LegacyVersion,
#{server_hello_selected_version :=
#server_hello_selected_version{
selected_version = Version}} = HelloExt},
- #{versions := SupportedVersions, ocsp_stapling := Stapling} = SslOpt,
+ #{versions := SupportedVersions} = SslOpt,
ConnectionStates0, Renegotiation, OldId) ->
+ Stapling = maps:get(ocsp_stapling, SslOpt, ?DEFAULT_OCSP_STAPLING),
%% In TLS 1.3, the TLS server indicates its version using the "supported_versions" extension
%% (Section 4.2.1), and the legacy_version field MUST be set to 0x0303, which is the version
%% number for TLS 1.2.
@@ -307,14 +308,17 @@ get_tls_handshakes(Version, Data, Buffer, Options) ->
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec ocsp_nonce(boolean(), boolean()) -> binary() | undefined.
+-spec ocsp_nonce(map()) -> binary() | undefined.
%%
%% Description: Get an OCSP nonce
%%--------------------------------------------------------------------
-ocsp_nonce(true, true) ->
- public_key:der_encode('Nonce', crypto:strong_rand_bytes(8));
-ocsp_nonce(_OcspNonceOpt, _OcspStaplingOpt) ->
- undefined.
+ocsp_nonce(SslOpts) ->
+ case maps:get(ocsp_stapling, SslOpts, disabled) of
+ #{ocsp_nonce := true} ->
+ public_key:der_encode('Nonce', crypto:strong_rand_bytes(8));
+ _ ->
+ undefined
+ end.
%%--------------------------------------------------------------------
%%% Internal functions
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 70a2691ac4..6f883b7b64 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -814,10 +814,15 @@ update_encryption_state(client, State) ->
validate_certificate_chain(CertEntries, CertDbHandle, CertDbRef,
- #{ocsp_responder_certs := OcspResponderCerts
- } = SslOptions, CRLDbHandle, Role, Host, OcspState0) ->
+ SslOptions, CRLDbHandle, Role, Host, OcspState0) ->
{Certs, CertExt, OcspState} = split_cert_entries(CertEntries, OcspState0),
-
+ OcspResponderCerts =
+ case maps:get(ocsp_stapling, SslOptions, disabled) of
+ #{ocsp_responder_certs := V} ->
+ V;
+ disabled ->
+ ?DEFAULT_OCSP_RESPONDER_CERTS
+ end,
ssl_handshake:certify(#certificate{asn1_certificates = Certs}, CertDbHandle, CertDbRef,
SslOptions, CRLDbHandle, Role, Host, {3,4},
#{cert_ext => CertExt,
diff --git a/lib/ssl/test/openssl_ocsp_SUITE.erl b/lib/ssl/test/openssl_ocsp_SUITE.erl
index a06dcbcb7b..045915cc84 100644
--- a/lib/ssl/test/openssl_ocsp_SUITE.erl
+++ b/lib/ssl/test/openssl_ocsp_SUITE.erl
@@ -35,17 +35,18 @@
end_per_testcase/2]).
%% Testcases
--export([ocsp_stapling_basic/0,ocsp_stapling_basic/1,
- ocsp_stapling_with_nonce/0, ocsp_stapling_with_nonce/1,
- ocsp_stapling_with_responder_cert/0,ocsp_stapling_with_responder_cert/1,
- ocsp_stapling_revoked/0, ocsp_stapling_revoked/1,
- ocsp_stapling_undetermined/0, ocsp_stapling_undetermined/1,
- ocsp_stapling_no_staple/0, ocsp_stapling_no_staple/1
+-export([stapling_basic/0, stapling_basic/1,
+ stapling_with_nonce/0, stapling_with_nonce/1,
+ stapling_with_responder_cert/0, stapling_with_responder_cert/1,
+ stapling_revoked/0, stapling_revoked/1,
+ stapling_undetermined/0, stapling_undetermined/1,
+ stapling_no_staple/0, stapling_no_staple/1
]).
%% spawn export
--export([ocsp_responder_init/3]).
-
+-export([ocsp_responder_init/4]).
+-define(OCSP_RESPONDER_LOG, "ocsp_resp_log.txt").
+-define(DEBUG, false).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -61,17 +62,18 @@ groups() ->
{'dtlsv1.2', [], ocsp_tests()}].
ocsp_tests() ->
- [ocsp_stapling_basic,
- ocsp_stapling_with_nonce,
- ocsp_stapling_with_responder_cert,
- ocsp_stapling_revoked,
- ocsp_stapling_undetermined,
- ocsp_stapling_no_staple
+ [stapling_basic,
+ stapling_with_nonce,
+ stapling_with_responder_cert,
+ stapling_revoked,
+ stapling_undetermined,
+ stapling_no_staple
].
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
- Config = ssl_test_lib:init_per_suite(Config0, openssl),
+ Config = lists:merge([{debug, ?DEBUG}],
+ ssl_test_lib:init_per_suite(Config0, openssl)),
case ssl_test_lib:openssl_ocsp_support(Config) of
true ->
do_init_per_suite(Config);
@@ -87,7 +89,7 @@ do_init_per_suite(Config) ->
{ok, _} = make_certs:all(DataDir, PrivDir),
ResponderPort = get_free_port(),
- Pid = start_ocsp_responder(ResponderPort, PrivDir),
+ Pid = start_ocsp_responder(ResponderPort, PrivDir, ?config(debug, Config)),
NewConfig =
lists:merge(
@@ -97,10 +99,10 @@ do_init_per_suite(Config) ->
ssl_test_lib:cert_options(NewConfig).
-
end_per_suite(Config) ->
ResponderPid = proplists:get_value(responder_pid, Config),
ssl_test_lib:close(ResponderPid),
+ [ssl_test_lib:ct_pal_file(?OCSP_RESPONDER_LOG) || ?config(debug, Config)],
ssl_test_lib:end_per_suite(Config).
%%--------------------------------------------------------------------
@@ -122,31 +124,30 @@ end_per_testcase(_TestCase, Config) ->
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-ocsp_stapling_basic() ->
+stapling_basic() ->
[{doc, "Verify OCSP stapling works without nonce and responder certs."}].
-ocsp_stapling_basic(Config)
+stapling_basic(Config)
when is_list(Config) ->
- ocsp_stapling_helper(Config, [{ocsp_nonce, false}]).
+ stapling_helper(Config, [{ocsp_nonce, false}]).
-ocsp_stapling_with_nonce() ->
+stapling_with_nonce() ->
[{doc, "Verify OCSP stapling works with nonce."}].
-ocsp_stapling_with_nonce(Config)
+stapling_with_nonce(Config)
when is_list(Config) ->
- ocsp_stapling_helper(Config, [{ocsp_nonce, true}]).
+ stapling_helper(Config, [{ocsp_nonce, true}]).
-ocsp_stapling_with_responder_cert() ->
+stapling_with_responder_cert() ->
[{doc, "Verify OCSP stapling works with nonce and responder certs."}].
-ocsp_stapling_with_responder_cert(Config)
+stapling_with_responder_cert(Config)
when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
{ok, ResponderCert} =
file:read_file(filename:join(PrivDir, "b.server/cert.pem")),
[{'Certificate', Der, _IsEncrypted}] =
public_key:pem_decode(ResponderCert),
- ocsp_stapling_helper(Config, [{ocsp_nonce, true},
- {ocsp_responder_certs, [Der]}]).
+ stapling_helper(Config, [{ocsp_nonce, true}, {ocsp_responder_certs, [Der]}]).
-ocsp_stapling_helper(Config, Opts) ->
+stapling_helper(Config, Opts) ->
PrivDir = proplists:get_value(priv_dir, Config),
CACertsFile = filename:join(PrivDir, "a.server/cacerts.pem"),
Data = "ping", %% 4 bytes
@@ -159,7 +160,8 @@ ocsp_stapling_helper(Config, Opts) ->
ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
{cacertfile, CACertsFile},
{server_name_indication, disable},
- {ocsp_stapling, true}] ++ Opts, Config),
+ {ocsp_stapling, true}] ++ Opts,
+ Config),
Client = ssl_test_lib:start_client(erlang,
[{port, Port},
{options, ClientOpts}], Config),
@@ -169,29 +171,29 @@ ocsp_stapling_helper(Config, Opts) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-ocsp_stapling_revoked() ->
+stapling_revoked() ->
[{doc, "Verify OCSP stapling works with revoked certificate."}].
-ocsp_stapling_revoked(Config)
+stapling_revoked(Config)
when is_list(Config) ->
- ocsp_stapling_negative_helper(Config, "revoked/cacerts.pem",
+ stapling_negative_helper(Config, "revoked/cacerts.pem",
openssl_ocsp_revoked, certificate_revoked).
-ocsp_stapling_undetermined() ->
+stapling_undetermined() ->
[{doc, "Verify OCSP stapling works with certificate with undetermined status."}].
-ocsp_stapling_undetermined(Config)
+stapling_undetermined(Config)
when is_list(Config) ->
- ocsp_stapling_negative_helper(Config, "undetermined/cacerts.pem",
+ stapling_negative_helper(Config, "undetermined/cacerts.pem",
openssl_ocsp_undetermined, bad_certificate).
-ocsp_stapling_no_staple() ->
+stapling_no_staple() ->
[{doc, "Verify OCSP stapling works with a missing OCSP response."}].
-ocsp_stapling_no_staple(Config)
+stapling_no_staple(Config)
when is_list(Config) ->
%% Start a server that will not include an OCSP response.
- ocsp_stapling_negative_helper(Config, "a.server/cacerts.pem",
+ stapling_negative_helper(Config, "a.server/cacerts.pem",
openssl, bad_certificate).
-ocsp_stapling_negative_helper(Config, CACertsPath, ServerVariant, ExpectedError) ->
+stapling_negative_helper(Config, CACertsPath, ServerVariant, ExpectedError) ->
PrivDir = proplists:get_value(priv_dir, Config),
CACertsFile = filename:join(PrivDir, CACertsPath),
GroupName = undefined,
@@ -214,12 +216,13 @@ ocsp_stapling_negative_helper(Config, CACertsPath, ServerVariant, ExpectedError)
ssl_test_lib:check_client_alert(Client, ExpectedError).
%%--------------------------------------------------------------------
-%% Intrernal functions -----------------------------------------------
+%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
-start_ocsp_responder(ResponderPort, PrivDir) ->
+start_ocsp_responder(ResponderPort, PrivDir, Debug) ->
Starter = self(),
- Pid = erlang:spawn_link(
- ?MODULE, ocsp_responder_init, [ResponderPort, PrivDir, Starter]),
+ Pid = erlang:spawn(
+ ?MODULE, ocsp_responder_init,
+ [ResponderPort, PrivDir, Starter, Debug]),
receive
{started, Pid} ->
Pid;
@@ -227,31 +230,40 @@ start_ocsp_responder(ResponderPort, PrivDir) ->
throw({unable_to_start_ocsp_service, Reason})
end.
-ocsp_responder_init(ResponderPort, PrivDir, Starter) ->
+ocsp_responder_init(ResponderPort, PrivDir, Starter, Debug) ->
Index = filename:join(PrivDir, "otpCA/index.txt"),
CACerts = filename:join(PrivDir, "b.server/cacerts.pem"),
Cert = filename:join(PrivDir, "b.server/cert.pem"),
Key = filename:join(PrivDir, "b.server/key.pem"),
-
+ DebugArgs = case Debug of
+ true -> ["-text", "-out", ?OCSP_RESPONDER_LOG];
+ _ -> []
+ end,
Args = ["ocsp", "-index", Index, "-CA", CACerts, "-rsigner", Cert,
- "-rkey", Key, "-port", erlang:integer_to_list(ResponderPort)],
+ "-rkey", Key, "-port", erlang:integer_to_list(ResponderPort)] ++
+ DebugArgs,
process_flag(trap_exit, true),
Port = ssl_test_lib:portable_open_port("openssl", Args),
+ ?CT_LOG("OCSP responder: Started Port = ~p", [Port]),
ocsp_responder_loop(Port, {new, Starter}).
ocsp_responder_loop(Port, {Status, Starter} = State) ->
receive
- {_Port, closed} ->
- ?CT_LOG("Port Closed"),
+ close ->
+ ?CT_LOG("OCSP responder: received close", []),
+ ok;
+ {Port, closed} ->
+ ?CT_LOG("OCSP responder: Port = ~p Closed", [Port]),
ok;
- {'EXIT', _Port, Reason} ->
- ?CT_LOG("Port Closed ~p",[Reason]),
+ {'EXIT', Sender, _Reason} ->
+ ?CT_LOG("OCSP responder: Sender = ~p Closed",[Sender]),
ok;
- {Port, {data, _Msg}} when Status == new ->
+ {Port, {data, Msg}} when Status == new ->
+ ?CT_LOG("OCSP responder: Msg = ~p", [Msg]),
Starter ! {started, self()},
ocsp_responder_loop(Port, {started, undefined});
{Port, {data, Msg}} ->
- ?CT_PAL("Responder Msg ~p",[Msg]),
+ ?CT_LOG("OCSP responder: Responder Msg = ~p",[Msg]),
ocsp_responder_loop(Port, State)
after 1000 ->
case Status of
diff --git a/lib/ssl/test/ssl_api_SUITE.erl b/lib/ssl/test/ssl_api_SUITE.erl
index 5cd25ae352..664f59a47d 100644
--- a/lib/ssl/test/ssl_api_SUITE.erl
+++ b/lib/ssl/test/ssl_api_SUITE.erl
@@ -2839,14 +2839,19 @@ options_frag_len(_Config) -> %% max_fragment_length
ok.
options_oscp(Config) ->
- Cert = proplists:get_value(cert, ssl_test_lib:ssl_options(server_rsa_der_opts, Config)),
- ?OK(#{ocsp_stapling := false, ocsp_nonce := true, ocsp_responder_certs := []},
- [], client),
- ?OK(#{ocsp_stapling := true},
- [{ocsp_stapling, true}], client),
- ?OK(#{ocsp_stapling := true, ocsp_nonce := false, ocsp_responder_certs := [_,_]},
- [{ocsp_stapling, true}, {ocsp_nonce, false}, {ocsp_responder_certs, [Cert,Cert]}],
- client),
+ Cert = proplists:get_value(
+ cert, ssl_test_lib:ssl_options(server_rsa_der_opts, Config)),
+ NoOcspOption = [ocsp_stapling, ocsp_nonce, ocsp_responder_certs],
+
+ ?OK(#{}, [], client, NoOcspOption),
+ ?OK(#{}, [{ocsp_stapling, false}], client, NoOcspOption),
+ ?OK(#{ocsp_stapling := #{ocsp_nonce := true, ocsp_responder_certs := []}},
+ [{ocsp_stapling, true}], client, [ocsp_nonce, ocsp_responder_certs]),
+ ?OK(#{ocsp_stapling :=
+ #{ocsp_nonce := false, ocsp_responder_certs := [_, _]}},
+ [{ocsp_stapling, true}, {ocsp_nonce, false},
+ {ocsp_responder_certs, [Cert,Cert]}],
+ client, [ocsp_nonce, ocsp_responder_certs]),
%% Errors
?ERR({ocsp_stapling, foo}, [{ocsp_stapling, 'foo'}], client),
?ERR({ocsp_nonce, foo}, [{ocsp_nonce, 'foo'}], client),
diff --git a/lib/ssl/test/ssl_dist_test_lib.erl b/lib/ssl/test/ssl_dist_test_lib.erl
index 8740aa2a47..78f99477a8 100644
--- a/lib/ssl/test/ssl_dist_test_lib.erl
+++ b/lib/ssl/test/ssl_dist_test_lib.erl
@@ -94,13 +94,7 @@ stop_ssl_node(#node_handle{connection_handler = Handler,
erlang:demonitor(Mon, [flush]),
ct:pal("stop_ssl_node/1 ~s Warning ~p ~n", [Name,Error])
end,
- case file:read_file(LogPath) of
- {ok, Binary} ->
- ct:pal("LogPath(~pB) = ~p~n~s", [filelib:file_size(LogPath), LogPath,
- Binary]);
- _ ->
- ok
- end,
+ ssl_test_lib:ct_pal_file(LogPath),
ct:pal("DumpPath(~pB) = ~p~n", [filelib:file_size(DumpPath), DumpPath]).
start_ssl_node(Name, Args) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index ec90a616d0..eda86fe936 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -118,7 +118,6 @@
session_id/1,
update_keys/2,
sanity_check/2,
- oscp_responder/6,
supported_eccs/1,
no_result/1,
receive_tickets/1,
@@ -222,7 +221,8 @@
portable_open_port/2,
close_port/1,
verify_early_data/1,
- trace/0
+ trace/0,
+ ct_pal_file/1
]).
%% Tracing
-export([handle_trace/3]).
@@ -925,15 +925,6 @@ init_openssl_server(Mode, ResponderPort, Options) when Mode == openssl_ocsp orel
Pid ! {self(), {port, Port}},
openssl_server_loop(Pid, SslPort, Args).
-oscp_responder(Port, Index, CACerts, Cert, Key, Starter) ->
- Args = ["ocsp", "-index", Index, "-CA", CACerts, "-rsigner", Cert,
- "-rkey", Key, "-port", erlang:integer_to_list(Port)],
- Responder = portable_open_port("openssl", Args),
- wait_for_openssl_server(Port, tls),
-
- openssl_server_loop(Starter, Responder, []).
-
-
openssl_dtls_opt('dtlsv1.2') ->
["-dtls"];
openssl_dtls_opt(_Other) ->
@@ -1464,7 +1455,9 @@ format_cert(#'OTPCertificate'{tbsCertificate = Cert} = OtpCert) ->
{error, _} ->
io_lib:format("~.3w:~s -> :~s", [Nr, format_subject(Subject), format_subject(Issuer)])
end
- end.
+ end;
+format_cert(Cert) ->
+ io_lib:format("Format failed for ~p", [Cert]).
format_subject({rdnSequence, Seq}) ->
format_subject(Seq);
@@ -4265,3 +4258,13 @@ ktls_set_cipher(Socket, OS, TxRx, Seed) ->
key = TLS_KEY,
iv = <<TLS_SALT/binary, TLS_IV/binary>> },
inet_tls_dist:set_ktls_cipher(KtlsInfo, OS, CipherState, 0, TxRx).
+
+ct_pal_file(FilePath) ->
+ case file:read_file(FilePath) of
+ {ok, Binary} ->
+ ?CT_PAL("~s ~pB~n~s",
+ [FilePath, filelib:file_size(FilePath), Binary]);
+ _ ->
+ ?CT_PAL("Failed to log ~s", [FilePath]),
+ ok
+ end.
diff --git a/lib/ssl/test/ssl_test_lib.hrl b/lib/ssl/test/ssl_test_lib.hrl
index 947c765c2a..d6d928610e 100644
--- a/lib/ssl/test/ssl_test_lib.hrl
+++ b/lib/ssl/test/ssl_test_lib.hrl
@@ -8,6 +8,8 @@
?SSL_TEST_LIB_FORMAT ++ F,
?SSL_TEST_LIB_ARGS ++ Args,
[esc_chars]))).
+-define(CT_PAL(F),
+ (ct:pal(?SSL_TEST_LIB_FORMAT ++ F, ?SSL_TEST_LIB_ARGS))).
-define(CT_PAL(F, Args),
(ct:pal(?SSL_TEST_LIB_FORMAT ++ F, ?SSL_TEST_LIB_ARGS ++ Args))).
-define(CT_FAIL(F, Args),
diff --git a/lib/ssl/test/ssl_trace_SUITE.erl b/lib/ssl/test/ssl_trace_SUITE.erl
index 8c8dc240ce..c33b29e90c 100644
--- a/lib/ssl/test/ssl_trace_SUITE.erl
+++ b/lib/ssl/test/ssl_trace_SUITE.erl
@@ -138,7 +138,6 @@ tc_api_profile(Config) ->
#{
call =>
[{" (server) -> ssl:handshake/2", ssl, handshake},
- {" (client) -> ssl_gen_statem:connect/8", ssl_gen_statem, connect},
{" (server) -> ssl_gen_statem:initial_hello/3",
ssl_gen_statem, initial_hello},
{" (client) -> ssl_gen_statem:initial_hello/3",
@@ -161,7 +160,8 @@ tc_api_profile(Config) ->
"rle ('?') -> ssl:listen/2 (*server) Args",
"rle ('?') -> ssl:connect/3 (*client) Args",
"rle ('?') -> tls_sender:init/3 (*server)",
- "rle ('?') -> tls_sender:init/3 (*client)"]},
+ "rle ('?') -> tls_sender:init/3 (*client)",
+ "api (client) -> ssl_gen_statem:connect/8"]},
TracesAfterDisconnect =
#{
call =>
@@ -197,8 +197,8 @@ tc_api_profile(Config) ->
{ok, Delta} = ssl_trace:off(Off),
[Server, Client] = ssl_connect(Config),
UnhandledTraceCnt1 =
- #{call => 0, processed => 0, exception_from => no_trace_received,
- return_from => 0},
+ #{call => 2, processed => 0, exception_from => no_trace_received,
+ return_from => 2},
check_trace_map(Ref, TracesAfterConnect, UnhandledTraceCnt1),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
@@ -370,7 +370,7 @@ receive_map(Ref,
check_trace_map(Ref, ExpectedTraces) ->
Received = receive_map(Ref),
L = [check_key(Type, ExpectedTraces, maps:get(Type, Received)) ||
- Type <- maps:keys(Received)],
+ Type <- maps:keys(Received)],
maps:from_list(L).
check_trace_map(Ref, ExpectedTraces, ExpectedRemainders) ->