Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.4:ARM
erlang.30244
feature-upstream-ocsp.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File feature-upstream-ocsp.patch of Package erlang.30244
From 867d51385bc16fbba198d1d829a8305510ed02f4 Mon Sep 17 00:00:00 2001 From: Ao Song <andy@erlang.org> Date: Mon, 6 Jul 2020 15:24:51 +0200 Subject: [PATCH] ssl: Prototype client OCSP support --- lib/ssl/src/dtls_connection.erl | 7 +- lib/ssl/src/dtls_handshake.erl | 14 +- lib/ssl/src/ssl.erl | 20 +- lib/ssl/src/ssl_connection.erl | 29 +++ lib/ssl/src/ssl_connection.hrl | 3 +- lib/ssl/src/ssl_handshake.erl | 122 +++++++++- lib/ssl/src/ssl_handshake.hrl | 24 +- lib/ssl/src/ssl_internal.hrl | 14 +- lib/ssl/src/ssl_logger.erl | 5 + lib/ssl/src/tls_connection.erl | 119 +++++++--- lib/ssl/src/tls_handshake.erl | 31 ++- lib/ssl/src/tls_handshake_1_3.erl | 27 ++- lib/ssl/test/Makefile | 3 +- lib/ssl/test/ssl_basic_SUITE.erl | 2 +- lib/ssl/test/ssl_ocsp_SUITE.erl | 367 ++++++++++++++++++++++++++++++ 15 files changed, 720 insertions(+), 67 deletions(-) create mode 100644 lib/ssl/test/ssl_ocsp_SUITE.erl Index: otp-OTP-22.2.7/lib/ssl/src/dtls_connection.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/dtls_connection.erl +++ otp-OTP-22.2.7/lib/ssl/src/dtls_connection.erl @@ -524,13 +524,14 @@ hello(internal, #hello_verify_request{co port = Port}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, connection_env = CEnv, - ssl_options = SslOpts, + ssl_options = #{ocsp_stapling := OcspStaplingOpt, + ocsp_nonce := OcspNonceOpt} = SslOpts, session = #session{own_certificate = Cert, session_id = Id}, connection_states = ConnectionStates0 } = State0) -> - + OcspNonce = tls_handshake:ocsp_nonce(OcspNonceOpt, OcspStaplingOpt), Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, - SslOpts, Id, Renegotiation, Cert), + SslOpts, Id, Renegotiation, Cert, OcspNonce), Version = Hello#client_hello.client_version, State1 = prepare_flight(State0#state{handshake_env = HsEnv#handshake_env{tls_handshake_history Index: otp-OTP-22.2.7/lib/ssl/src/dtls_handshake.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/dtls_handshake.erl +++ otp-OTP-22.2.7/lib/ssl/src/dtls_handshake.erl @@ -30,7 +30,7 @@ -include("ssl_alert.hrl"). %% Handshake handling --export([client_hello/7, client_hello/8, cookie/4, hello/4, +-export([client_hello/7, client_hello/9, cookie/4, hello/4, hello_verify_request/2]). %% Handshake encoding @@ -56,11 +56,11 @@ client_hello(Host, Port, ConnectionState Id, Renegotiation, OwnCert) -> %% First client hello (two sent in DTLS ) uses empty Cookie client_hello(Host, Port, <<>>, ConnectionStates, SslOpts, - Id, Renegotiation, OwnCert). + Id, Renegotiation, OwnCert, undefined). %%-------------------------------------------------------------------- -spec client_hello(ssl:host(), inet:port_number(), term(), ssl_record:connection_states(), - ssl_options(), binary(),boolean(), der_cert()) -> + ssl_options(), binary(),boolean(), der_cert(), binary() | undefined) -> #client_hello{}. %% %% Description: Creates a client hello message. @@ -69,7 +69,7 @@ client_hello(_Host, _Port, Cookie, Conne #{versions := Versions, ciphers := UserSuites, fallback := Fallback} = SslOpts, - Id, Renegotiation, _OwnCert) -> + Id, Renegotiation, _OwnCert, OcspNonce) -> Version = dtls_record:highest_protocol_version(Versions), Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = maps:get(security_parameters, Pending), @@ -79,7 +79,7 @@ client_hello(_Host, _Port, Cookie, Conne Extensions = ssl_handshake:client_hello_extensions(TLSVersion, CipherSuites, SslOpts, ConnectionStates, Renegotiation, undefined, - undefined), + undefined, OcspNonce), #client_hello{session_id = Id, client_version = Version, Index: otp-OTP-22.2.7/lib/ssl/src/ssl.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/ssl.erl +++ otp-OTP-22.2.7/lib/ssl/src/ssl.erl @@ -28,7 +28,6 @@ -include("ssl_internal.hrl"). -include("ssl_api.hrl"). --include("ssl_internal.hrl"). -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). -include("ssl_handshake.hrl"). @@ -367,7 +366,11 @@ {server_name_indication, sni()} | {customize_hostname_check, customize_hostname_check()} | {signature_algs, client_signature_algs()} | - {fallback, fallback()}. + {fallback, fallback()}.%% | + %% These were commented out in d542eef20e7a5380511ec27c931e22afe946e73d + %% {ocsp_stapling, ocsp_stapling()} | + %% {ocsp_responder_certs, ocsp_responder_certs()} | + %% {ocsp_nonce, ocsp_nonce()}. -type client_verify_type() :: verify_type(). -type client_reuse_session() :: session_id(). @@ -388,6 +391,10 @@ -type client_signature_algs() :: signature_algs(). -type fallback() :: boolean(). -type ssl_imp() :: new | old. +%% These were commented out in d542eef20e7a5380511ec27c931e22afe946e73d +%%-type ocsp_stapling() :: boolean(). +%%-type ocsp_responder_certs() :: [public_key:der_encoded()]. +%%-type ocsp_nonce() :: boolean(). %% ------------------------------------------------------------------------------------------------------- @@ -2104,6 +2111,17 @@ validate_option(anti_replay, '100k') -> validate_option(anti_replay, Value) when (is_tuple(Value) andalso tuple_size(Value) =:= 3) -> Value; +validate_option(ocsp_stapling, Value) when Value =:= true orelse + Value =:= false -> + Value; +%% The OCSP responders' certificates can be given as a suggestion and +%% will be used to verify the OCSP response. +validate_option(ocsp_responder_certs, Value) when is_list(Value) -> + [public_key:pkix_decode_cert(CertDer, plain) || CertDer <- Value, + is_binary(CertDer)]; +validate_option(ocsp_nonce, Value) when Value =:= true orelse + Value =:= false -> + Value; validate_option(Opt, undefined = Value) -> AllOpts = maps:keys(?RULES), case lists:member(Opt, AllOpts) of Index: otp-OTP-22.2.7/lib/ssl/src/ssl_connection.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/ssl_connection.erl +++ otp-OTP-22.2.7/lib/ssl/src/ssl_connection.erl @@ -1170,6 +1170,35 @@ certify(internal, #client_key_exchange{e #alert{} = Alert -> handle_own_alert(Alert, Version, ?FUNCTION_NAME, State) end; +%% The response will be handled only when a certificate status request has +%% been sent by the client and confirmed by the server. +certify(internal, #certificate_status{response = OcspRespDer}, + #state{ssl_options = #{ + ocsp_stapling := true, + ocsp_responder_certs := ResponderCerts}, + handshake_env = #handshake_env{ + ocsp_stapling_state = #{ + ocsp_negotiated := true, + ocsp_nonce := OcspNonce} = OcspState} = HsEnv, + connection_env = #connection_env{ + negotiated_version = Version}} = State, + Connection) -> + Result = public_key:ocsp_status( + OcspRespDer, ResponderCerts, OcspNonce), + NewOcspState = OcspState#{ + ocsp_stapling_result => Result}, + NewState = State#state{handshake_env = + HsEnv#handshake_env{ocsp_stapling_state = NewOcspState}}, + case Result of + {ok, [#'SingleResponse'{ + certStatus = {revoked, _RevokedInfo}} + ]} -> + Alert = ?ALERT_REC( + ?FATAL, ?BAD_CERTIFICATE_STATUS_RESPONSE, revoked_certificate), + handle_own_alert(Alert, Version, ?FUNCTION_NAME, NewState); + _Other -> + Connection:next_event(?FUNCTION_NAME, no_record, NewState) + end; certify(Type, Msg, State, Connection) -> handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). Index: otp-OTP-22.2.7/lib/ssl/src/ssl_connection.hrl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/ssl_connection.hrl +++ otp-OTP-22.2.7/lib/ssl/src/ssl_connection.hrl @@ -80,7 +80,8 @@ public_key_info :: ssl_handshake:public_key_info() | 'undefined', premaster_secret :: binary() | secret_printout() | 'undefined', server_psk_identity :: binary() | 'undefined', % server psk identity hint - ticket_seed + ticket_seed, + ocsp_stapling_state = #{} }). -record(connection_env, { Index: otp-OTP-22.2.7/lib/ssl/src/ssl_handshake.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/ssl_handshake.erl +++ otp-OTP-22.2.7/lib/ssl/src/ssl_handshake.erl @@ -72,7 +72,7 @@ premaster_secret/2, premaster_secret/3, premaster_secret/4]). %% Extensions handling --export([client_hello_extensions/7, +-export([client_hello_extensions/8, handle_client_hello_extensions/9, %% Returns server hello extensions handle_server_hello_extensions/9, select_curve/2, select_curve/3, select_hashsign/4, select_hashsign/5, @@ -351,10 +351,10 @@ certify(#certificate{asn1_certificates = depth := Depth} = Opts, CRLDbHandle, Role, Host) -> ServerName = server_name(ServerNameIndication, Host, Role), - [PeerCert | ChainCerts ] = ASN1Certs, + [PeerCert | ChainCerts ] = ASN1Certs, try {TrustedCert, CertPath} = - ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef, + ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef, PartialChain), ValidationFunAndState = validation_fun_and_state(VerifyFun, Role, CertDbHandle, CertDbRef, ServerName, @@ -363,11 +363,11 @@ certify(#certificate{asn1_certificates = Options = [{max_path_length, Depth}, {verify_fun, ValidationFunAndState}], case public_key:pkix_path_validation(TrustedCert, CertPath, Options) of - {ok, {PublicKeyInfo,_}} -> - {PeerCert, PublicKeyInfo}; + {ok, {PublicKeyInfo, _}} -> + {PeerCert, PublicKeyInfo}; {error, Reason} -> - handle_path_validation_error(Reason, PeerCert, ChainCerts, Opts, Options, - CertDbHandle, CertDbRef) + handle_path_validation_error(Reason, PeerCert, ChainCerts, Opts, Options, + CertDbHandle, CertDbRef) end catch error:{_,{error, {asn1, Asn1Reason}}} -> @@ -722,6 +722,15 @@ encode_extensions([#psk_key_exchange_mod ExtLen = KEModesLen + 1, encode_extensions(Rest, <<?UINT16(?PSK_KEY_EXCHANGE_MODES_EXT), ?UINT16(ExtLen), ?BYTE(KEModesLen), KEModes/binary, Acc/binary>>); +encode_extensions([ + #certificate_status_request{ + status_type = StatusRequest, + request = Request} | Rest], Acc) -> + CertStatusReq = encode_cert_status_req(StatusRequest, Request), + Len = byte_size(CertStatusReq), + encode_extensions( + Rest, <<?UINT16(?STATUS_REQUEST), ?UINT16(Len), + CertStatusReq/binary, Acc/binary>>); encode_extensions([#pre_shared_key_client_hello{ offered_psks = #offered_psks{ identities = Identities0, @@ -740,6 +749,39 @@ encode_extensions([#pre_shared_key_serve ?UINT16(2), ?UINT16(Identity), Acc/binary>>). +encode_cert_status_req( + StatusType, + #ocsp_status_request{ + responder_id_list = ResponderIDList, + request_extensions = ReqExtns}) -> + ResponderIDListBin = encode_responderID_list(ResponderIDList), + ReqExtnsBin = encode_request_extensions(ReqExtns), + <<?BYTE(StatusType), ResponderIDListBin/binary, ReqExtnsBin/binary>>. + +encode_responderID_list([]) -> + <<?UINT16(0)>>; +encode_responderID_list(List) -> + do_encode_responderID_list(List, <<>>). + +%% ResponderID is DER-encoded ASN.1 type defined in RFC6960. +do_encode_responderID_list([], Acc) -> + Len = byte_size(Acc), + <<?UINT16(Len), Acc/binary>>; +do_encode_responderID_list([Responder | Rest], Acc) + when is_binary(Responder) -> + Len = byte_size(Responder), + do_encode_responderID_list( + Rest, <<Acc/binary, ?UINT16(Len), Responder/binary>>). + +%% Extensions are DER-encoded ASN.1 type defined in RFC6960 following +%% extension model employed in X.509 version 3 certificates(RFC5280). +encode_request_extensions([]) -> + <<?UINT16(0)>>; +encode_request_extensions(Extns) when is_list(Extns) -> + ExtnBin = public_key:der_encode('Extensions', Extns), + Len = byte_size(ExtnBin), + <<?UINT16(Len), ExtnBin/binary>>. + encode_client_protocol_negotiation(undefined, _) -> undefined; encode_client_protocol_negotiation(_, false) -> @@ -751,7 +793,8 @@ encode_protocols_advertised_on_server(un undefined; encode_protocols_advertised_on_server(Protocols) -> - #next_protocol_negotiation{extension_data = lists:foldl(fun encode_protocol/2, <<>>, Protocols)}. + #next_protocol_negotiation{ + extension_data = lists:foldl(fun encode_protocol/2, <<>>, Protocols)}. %%==================================================================== %% Decode handshake @@ -790,6 +833,14 @@ decode_handshake(Version, ?SERVER_HELLO, extensions = HelloExtensions}; decode_handshake(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; +%% RFC 6066, servers return a certificate response along with their certificate +%% by sending a "CertificateStatus" message immediately after the "Certificate" +%% message and before any "ServerKeyExchange" or "CertificateRequest" messages. +decode_handshake(_Version, ?CERTIFICATE_STATUS, <<?BYTE(?CERTIFICATE_STATUS_TYPE_OCSP), + ?UINT24(Len), ASN1OcspResponse:Len/binary>>) -> + #certificate_status{ + status_type = ?CERTIFICATE_STATUS_TYPE_OCSP, + response = ASN1OcspResponse}; decode_handshake(_Version, ?SERVER_KEY_EXCHANGE, Keys) -> #server_key_exchange{exchange_keys = Keys}; decode_handshake({Major, Minor}, ?CERTIFICATE_REQUEST, @@ -1075,10 +1126,11 @@ premaster_secret(EncSecret, #{algorithm %% Extensions handling %%==================================================================== client_hello_extensions(Version, CipherSuites, SslOpts, ConnectionStates, Renegotiation, KeyShare, - TicketData) -> + TicketData, OcspNonce) -> HelloExtensions0 = add_tls12_extensions(Version, SslOpts, ConnectionStates, Renegotiation), HelloExtensions1 = add_common_extensions(Version, HelloExtensions0, CipherSuites, SslOpts), - maybe_add_tls13_extensions(Version, HelloExtensions1, SslOpts, KeyShare, TicketData). + HelloExtensions2 = maybe_add_certificate_status_request(Version, SslOpts, OcspNonce, HelloExtensions1), + maybe_add_tls13_extensions(Version, HelloExtensions2, SslOpts, KeyShare, TicketData). add_tls12_extensions(_Version, @@ -1147,6 +1199,31 @@ 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) -> + OcspResponderList = get_ocsp_responder_list(OcspResponderCerts), + OcspRequestExtns = public_key:ocsp_extensions(OcspNonce), + Req = #ocsp_status_request{responder_id_list = OcspResponderList, + request_extensions = OcspRequestExtns}, + CertStatusReqExtn = #certificate_status_request{ + status_type = ?CERTIFICATE_STATUS_TYPE_OCSP, + request = Req + }, + HelloExtensions#{status_request => CertStatusReqExtn}. + +get_ocsp_responder_list(ResponderCerts) -> + get_ocsp_responder_list(ResponderCerts, []). + +get_ocsp_responder_list([], Acc) -> + Acc; +get_ocsp_responder_list([ResponderCert | T], Acc) -> + get_ocsp_responder_list( + T, [public_key:ocsp_responder_id(ResponderCert) | Acc]). %% TODO: Add support for PSK key establishment @@ -2632,6 +2709,31 @@ decode_extensions(<<?UINT16(?PRE_SHARED_ #pre_shared_key_server_hello{ selected_identity = Identity}}); +%% RFC6066, if a server returns a "CertificateStatus" message, then +%% the server MUST have included an extension of type "status_request" +%% with empty "extension_data" in the extended server hello. +decode_extensions(<<?UINT16(?STATUS_REQUEST), ?UINT16(Len), + _ExtensionData:Len/binary, Rest/binary>>, Version, + MessageType = server_hello, Acc) + when Len =:= 0 -> + decode_extensions(Rest, Version, MessageType, + Acc#{status_request => undefined}); +%% RFC8446 4.4.2.1, In TLS1.3, the body of the "status_request" extension +%% from the server MUST be a CertificateStatus structure as defined in +%% RFC6066. +decode_extensions(<<?UINT16(?STATUS_REQUEST), ?UINT16(Len), + CertStatus:Len/binary, Rest/binary>>, Version, + MessageType, Acc) -> + case CertStatus of + <<?BYTE(?CERTIFICATE_STATUS_TYPE_OCSP), + ?UINT24(OCSPLen), + ASN1OCSPResponse:OCSPLen/binary>> -> + decode_extensions(Rest, Version, MessageType, + Acc#{status_request => ASN1OCSPResponse}); + _Other -> + decode_extensions(Rest, Version, MessageType, Acc) + end; + %% Ignore data following the ClientHello (i.e., %% extensions) if not understood. decode_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len/binary, Rest/binary>>, Version, MessageType, Acc) -> @@ -2746,6 +2848,7 @@ certs_from_list(ACList) -> CertLen = byte_size(Cert), <<?UINT24(CertLen), Cert/binary>> end || Cert <- ACList]). + from_3bytes(Bin3) -> from_3bytes(Bin3, []). Index: otp-OTP-22.2.7/lib/ssl/src/ssl_handshake.hrl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/ssl_handshake.hrl +++ otp-OTP-22.2.7/lib/ssl/src/ssl_handshake.hrl @@ -376,7 +376,7 @@ -define(NAMED_CURVE, 3). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% RFC 6066 Server name indication +%% RFC 6066 TLS Extensions: Extension Definitions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% section 3 @@ -389,12 +389,32 @@ hostname = undefined }). +%% Section 8, Certificate Status Request +-define(STATUS_REQUEST, 5). +-define(CERTIFICATE_STATUS_TYPE_OCSP, 1). +-define(CERTIFICATE_STATUS, 22). + +%% status request record defined in RFC 6066, section 8 +-record(certificate_status_request, { + status_type, + request +}). + +-record(ocsp_status_request, { + responder_id_list = [], + request_extensions = [] +}). + +-record(certificate_status, { + status_type, + response +}). + %% Other possible values from RFC 6066, not supported -define(MAX_FRAGMENT_LENGTH, 1). -define(CLIENT_CERTIFICATE_URL, 2). -define(TRUSTED_CA_KEYS, 3). -define(TRUNCATED_HMAC, 4). --define(STATUS_REQUEST, 5). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% RFC 7250 Using Raw Public Keys in Transport Layer Security (TLS) Index: otp-OTP-22.2.7/lib/ssl/src/ssl_internal.hrl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/ssl_internal.hrl +++ otp-OTP-22.2.7/lib/ssl/src/ssl_internal.hrl @@ -148,6 +148,14 @@ max_handshake_size => {?DEFAULT_MAX_HANDSHAKE_SIZE, [versions]}, next_protocol_selector => {undefined, [versions]}, next_protocols_advertised => {undefined, [versions]}, + %% If enable OCSP stapling + ocsp_stapling => {false, [versions]}, + %% Optional arg, if give suggestion of OCSP responders + ocsp_responder_certs => {[], [versions, + ocsp_stapling]}, + %% Optional arg, if add nonce extension in request + ocsp_nonce => {true, [versions, + ocsp_stapling]}, padding_check => {true, [versions]}, partial_chain => {fun(_) -> unknown_ca end, [versions]}, password => {"", [versions]}, @@ -177,15 +185,15 @@ verify_client_once => {false, [versions]}, verify_fun => { - {fun(_,{bad_cert, _}, UserState) -> + {fun(_, {bad_cert, _}, UserState) -> {valid, UserState}; - (_,{extension, #'Extension'{critical = true}}, UserState) -> + (_, {extension, #'Extension'{critical = true}}, UserState) -> %% This extension is marked as critical, so %% certificate verification should fail if we don't %% understand the extension. However, this is %% `verify_none', so let's accept it anyway. {valid, UserState}; - (_,{extension, _}, UserState) -> + (_, {extension, _}, UserState) -> {unknown, UserState}; (_, valid, UserState) -> {valid, UserState}; Index: otp-OTP-22.2.7/lib/ssl/src/ssl_logger.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/ssl_logger.erl +++ otp-OTP-22.2.7/lib/ssl/src/ssl_logger.erl @@ -180,6 +180,11 @@ parse_handshake(Direction, #certificate{ [header_prefix(Direction)]), Message = io_lib:format("~p", [?rec_info(certificate, Certificate)]), {Header, Message}; +parse_handshake(Direction, #certificate_status{} = CertificateStatus) -> + Header = io_lib:format("~s Handshake, CertificateStatus", + [header_prefix(Direction)]), + Message = io_lib:format("~p", [?rec_info(certificate_status, CertificateStatus)]), + {Header, Message}; parse_handshake(Direction, #server_key_exchange{} = ServerKeyExchange) -> Header = io_lib:format("~s Handshake, ServerKeyExchange", [header_prefix(Direction)]), Index: otp-OTP-22.2.7/lib/ssl/src/tls_connection.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/tls_connection.erl +++ otp-OTP-22.2.7/lib/ssl/src/tls_connection.erl @@ -579,24 +579,28 @@ init({call, From}, {start, Timeout}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv, connection_env = CEnv, ssl_options = #{log_level := LogLevel, - %% Use highest version in initial ClientHello. - %% Versions is a descending list of supported versions. - versions := [HelloVersion|_] = Versions, - session_tickets := SessionTickets} = SslOpts, - session = NewSession, - connection_states = ConnectionStates0 - } = State0) -> + %% Use highest version in initial ClientHello. + %% Versions is a descending list of supported versions. + versions := [HelloVersion|_] = Versions, + session_tickets := SessionTickets, + ocsp_stapling := OcspStaplingOpt, + ocsp_nonce := OcspNonceOpt} = SslOpts, + session = NewSession, + connection_states = ConnectionStates0 + } = State0) -> KeyShare = maybe_generate_client_shares(SslOpts), Session = ssl_session:client_select_session({Host, Port, SslOpts}, Cache, CacheCb, NewSession), %% Update UseTicket in case of automatic session resumption {UseTicket, State1} = tls_handshake_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), Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Session#session.session_id, Renegotiation, Session#session.own_certificate, KeyShare, - TicketData), + TicketData, + OcspNonce), Handshake0 = ssl_handshake:init_handshake_history(), @@ -617,13 +621,16 @@ init({call, From}, {start, Timeout}, %% negotiated_version is also used by the TLS 1.3 state machine and is set after %% ServerHello is processed. RequestedVersion = tls_record:hello_version(Versions), - State = State1#state{connection_states = ConnectionStates, - connection_env = CEnv#connection_env{ - negotiated_version = RequestedVersion}, - session = Session, - handshake_env = HsEnv#handshake_env{tls_handshake_history = Handshake}, - start_or_recv_from = From, - key_share = KeyShare}, + State2 = State1#state{connection_states = ConnectionStates, + connection_env = CEnv#connection_env{ + negotiated_version = RequestedVersion}, + session = Session, + handshake_env = HsEnv#handshake_env{ + tls_handshake_history = Handshake}, + start_or_recv_from = From, + key_share = KeyShare}, + State = tls_handshake_1_3:update_ocsp_state( + OcspStaplingOpt, OcspNonce, State2), next_event(hello, no_record, State, [{{timeout, handshake}, Timeout, close}]); init(Type, Event, State) -> @@ -658,11 +665,23 @@ hello(internal, #client_hello{extensions handshake_env = HsEnv#handshake_env{hello = Hello}}, [{reply, From, {ok, Extensions}}]}; hello(internal, #server_hello{extensions = Extensions} = Hello, - #state{ssl_options = #{handshake := hello}, + #state{ssl_options = #{ + handshake := hello, + ocsp_stapling := OcspStapling}, handshake_env = HsEnv, start_or_recv_from = From} = State) -> - {next_state, user_hello, State#state{start_or_recv_from = undefined, - handshake_env = HsEnv#handshake_env{hello = Hello}}, + %% RFC6066.8, If a server returns a "CertificateStatus" message, + %% then the server MUST have included an extension of type + %% "status_request" with empty "extension_data" in the extended + %% server hello. + OcspState = HsEnv#handshake_env.ocsp_stapling_state, + OcspNegotiated = is_ocsp_stapling_negotiated(OcspStapling, Extensions, State), + {next_state, user_hello, + State#state{start_or_recv_from = undefined, + handshake_env = HsEnv#handshake_env{ + hello = Hello, + ocsp_stapling_state = OcspState#{ + ocsp_negotiated => OcspNegotiated}}}, [{reply, From, {ok, Extensions}}]}; hello(internal, #client_hello{client_version = ClientVersion} = Hello, @@ -712,12 +731,19 @@ hello(internal, #client_hello{client_ver end end; -hello(internal, #server_hello{} = Hello, +hello(internal, #server_hello{extensions = Extensions} = Hello, #state{connection_states = ConnectionStates0, connection_env = #connection_env{negotiated_version = ReqVersion} = CEnv, static_env = #static_env{role = client}, - handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, + handshake_env = #handshake_env{ + renegotiation = {Renegotiation, _}, + ocsp_stapling_state = OcspState} = HsEnv, ssl_options = SslOptions} = State) -> + %% check if server has sent an empty certifucate status message in hello + #{ocsp_stapling := OcspStapling} = SslOptions, + OcspNegotiated = is_ocsp_stapling_negotiated(OcspStapling, Extensions, State), + + case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of #alert{} = Alert -> %%TODO ssl_connection:handle_own_alert(Alert, ReqVersion, hello, @@ -726,14 +752,19 @@ hello(internal, #server_hello{} = Hello, %% Legacy TLS 1.2 and older {Version, NewId, ConnectionStates, ProtoExt, Protocol} -> ssl_connection:handle_session(Hello, - Version, NewId, ConnectionStates, ProtoExt, Protocol, State); + Version, NewId, ConnectionStates, ProtoExt, Protocol, + State#state{handshake_env = HsEnv#handshake_env{ + ocsp_stapling_state = OcspState#{ + ocsp_negotiated => OcspNegotiated}}}); %% TLS 1.3 {next_state, wait_sh, SelectedVersion} -> %% Continue in TLS 1.3 'wait_sh' state {next_state, wait_sh, State#state{ - connection_env = CEnv#connection_env{negotiated_version = SelectedVersion}}, - [{next_event, internal, Hello}]} + connection_env = CEnv#connection_env{negotiated_version = SelectedVersion}, + handshake_env = HsEnv#handshake_env{ + ocsp_stapling_state = OcspState#{ + ocsp_negotiated => OcspNegotiated}}}, [{next_event, internal, Hello}]} end; hello(info, Event, State) -> gen_info(Event, ?FUNCTION_NAME, State); @@ -816,7 +847,9 @@ connection(internal, #hello_request{}, port = Port, session_cache = Cache, session_cache_cb = CacheCb}, - handshake_env = #handshake_env{renegotiation = {Renegotiation, peer}}, + handshake_env = #handshake_env{ + renegotiation = {Renegotiation, peer}, + ocsp_stapling_state = OcspState}, session = #session{own_certificate = Cert} = Session0, ssl_options = SslOpts, protocol_specific = #{sender := Pid}, @@ -827,7 +860,7 @@ connection(internal, #hello_request{}, Hello = tls_handshake:client_hello(Host, Port, ConnectionStates, SslOpts, Session#session.session_id, Renegotiation, Cert, undefined, - undefined), + undefined, maps:get(ocsp_nonce, OcspState, undefined)), {State, Actions} = send_handshake(Hello, State0#state{connection_states = ConnectionStates#{current_write => Write}, session = Session}), next_event(hello, no_record, State, Actions) @@ -839,13 +872,15 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{role = client, host = Host, port = Port}, - handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, + handshake_env = #handshake_env{ + renegotiation = {Renegotiation, _}, + ocsp_stapling_state = OcspState}, session = #session{own_certificate = Cert}, ssl_options = SslOpts, connection_states = ConnectionStates} = State0) -> Hello = tls_handshake:client_hello(Host, Port, ConnectionStates, SslOpts, <<>>, Renegotiation, Cert, undefined, - undefined), + undefined, maps:get(ocsp_nonce, OcspState, undefined)), {State, Actions} = send_handshake(Hello, State0), next_event(hello, no_record, State, Actions); @@ -1447,3 +1482,32 @@ send_ticket_data(User, NewSessionTicket, timestamp => Timestamp, ticket => NewSessionTicket}, User ! {ssl, session_ticket, {SNI, erlang:term_to_binary(TicketData)}}. + +is_ocsp_stapling_negotiated(true, Extensions, + #state{connection_env = + #connection_env{ + negotiated_version = Version} + } = State) -> + case maps:get(status_request, Extensions, false) of + undefined -> %% status_request in server hello is empty + true; + false -> %% status_request is missing (not negotiated) + false; + _Else -> + ssl_connection:handle_own_alert( + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, status_request_not_empty), + Version, hello, State) + end; +is_ocsp_stapling_negotiated(false, Extensions, + #state{connection_env = + #connection_env{ + negotiated_version = Version} + } = State) -> + case maps:get(status_request, Extensions, false) of + false -> %% status_request is missing (not negotiated) + false; + _Else -> %% unsolicited status_request + ssl_connection:handle_own_alert( + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_status_request), + Version, hello, State) + end. Index: otp-OTP-22.2.7/lib/ssl/src/tls_handshake.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/tls_handshake.erl +++ otp-OTP-22.2.7/lib/ssl/src/tls_handshake.erl @@ -36,7 +36,7 @@ -include_lib("kernel/include/logger.hrl"). %% Handshake handling --export([client_hello/9, hello/4]). +-export([client_hello/10, hello/4]). %% Handshake encoding -export([encode_handshake/2]). @@ -44,6 +44,9 @@ %% Handshake decodeing -export([get_tls_handshake/4, decode_handshake/3]). +%% Handshake helper +-export([ocsp_nonce/2]). + -type tls_handshake() :: #client_hello{} | ssl_handshake:ssl_handshake(). %%==================================================================== @@ -52,7 +55,8 @@ %%-------------------------------------------------------------------- -spec client_hello(ssl:host(), inet:port_number(), ssl_record:connection_states(), ssl_options(), binary(), boolean(), der_cert(), - #key_share_client_hello{} | undefined, tuple() | undefined) -> + #key_share_client_hello{} | undefined, tuple() | undefined, + binary() | undefined) -> #client_hello{}. %% %% Description: Creates a client hello message. @@ -62,7 +66,7 @@ client_hello(_Host, _Port, ConnectionSta ciphers := UserSuites, fallback := Fallback } = SslOpts, - Id, Renegotiation, _OwnCert, KeyShare, TicketData) -> + Id, Renegotiation, _OwnCert, KeyShare, TicketData, OcspNonce) -> Version = tls_record:highest_protocol_version(Versions), %% In TLS 1.3, the client indicates its version preferences in the @@ -82,9 +86,10 @@ client_hello(_Host, _Port, ConnectionSta Extensions = ssl_handshake:client_hello_extensions(Version, AvailableCipherSuites, SslOpts, ConnectionStates, - Renegotiation, - KeyShare, - TicketData), + Renegotiation, + KeyShare, + TicketData, + OcspNonce), CipherSuites = ssl_handshake:cipher_suites(AvailableCipherSuites, Renegotiation, Fallback), #client_hello{session_id = Id, client_version = LegacyVersion, @@ -282,6 +287,20 @@ get_tls_handshake(Version, Data, Buffer, get_tls_handshake_aux(Version, list_to_binary([Buffer, Data]), Options, []). %%-------------------------------------------------------------------- +%%% Handshake helper +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +-spec ocsp_nonce(boolean(), boolean()) -> binary() | undefined. +%% +%% Description: Get an OCSP nonce +%%-------------------------------------------------------------------- +ocsp_nonce(true, true) -> + public_key:ocsp_nonce(); +ocsp_nonce(_OcspNonceOpt, _OcspStaplingOpt) -> + undefined. + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- handle_client_hello(Version, Index: otp-OTP-22.2.7/lib/ssl/src/tls_handshake_1_3.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/src/tls_handshake_1_3.erl +++ otp-OTP-22.2.7/lib/ssl/src/tls_handshake_1_3.erl @@ -54,7 +54,8 @@ maybe_add_binders/4, maybe_automatic_session_resumption/1]). --export([is_valid_binder/4]). +-export([is_valid_binder/4, + update_ocsp_state/3]). %% crypto:hash(sha256, "HelloRetryRequest"). -define(HELLO_RETRY_REQUEST_RANDOM, <<207,33,173,116,229,154,97,17, @@ -634,7 +635,9 @@ do_start(#server_hello{cipher_suite = Se supported_groups := ClientGroups0, use_ticket := UseTicket, session_tickets := SessionTickets, - log_level := LogLevel} = SslOpts, + log_level := LogLevel, + ocsp_stapling := OcspStaplingOpt, + ocsp_nonce := OcspNonceOpt} = SslOpts, session = #session{own_certificate = Cert} = Session0, connection_states = ConnectionStates0 } = State0) -> @@ -701,6 +704,19 @@ do_start(#server_hello{cipher_suite = Se end. +%%-------------------------------------------------------------------- +-spec update_ocsp_state(boolean(), binary() | undefined, #state{}) -> #state{}. +%% +%% Description: Update OCSP state in #state{} +%%-------------------------------------------------------------------- +update_ocsp_state(true, OcspNonce, #state{handshake_env = #handshake_env{ + ocsp_stapling_state = OcspState} = HsEnv} = State) -> + State#state{handshake_env = HsEnv#handshake_env{ + ocsp_stapling_state = OcspState#{ocsp_nonce => OcspNonce}}}; +update_ocsp_state(false, _OcspNonce, State) -> + State. + + do_negotiated({start_handshake, PSK0}, #state{connection_states = ConnectionStates0, session = #session{session_id = SessionId, Index: otp-OTP-22.2.7/lib/ssl/test/Makefile =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/test/Makefile +++ otp-OTP-22.2.7/lib/ssl/test/Makefile @@ -87,7 +87,8 @@ MODULES = \ ssl_socket_SUITE\ make_certs \ x509_test \ - inet_crypto_dist + inet_crypto_dist \ + ssl_ocsp_SUITE ERL_FILES = $(MODULES:%=%.erl) Index: otp-OTP-22.2.7/lib/ssl/test/ssl_basic_SUITE.erl =================================================================== --- otp-OTP-22.2.7.orig/lib/ssl/test/ssl_basic_SUITE.erl +++ otp-OTP-22.2.7/lib/ssl/test/ssl_basic_SUITE.erl @@ -76,7 +76,7 @@ init_per_suite(Config0) -> try crypto:start() of ok -> ssl_test_lib:clean_start(), - %% make rsa certs using oppenssl + %% make rsa certs using openssl {ok, _} = make_certs:all(proplists:get_value(data_dir, Config0), proplists:get_value(priv_dir, Config0)), Config1 = ssl_test_lib:make_dsa_cert(Config0), Index: otp-OTP-22.2.7/lib/ssl/test/ssl_ocsp_SUITE.erl =================================================================== --- /dev/null +++ otp-OTP-22.2.7/lib/ssl/test/ssl_ocsp_SUITE.erl @@ -0,0 +1,367 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2020. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(ssl_ocsp_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- +all() -> + [{group, tls1_2}, + {group, tls1_3}, + {group, revoked_1_2}, + {group, revoked_1_3}]. + +groups() -> + [{tls1_2, [], tls1_2_tests()}, + {tls1_3, [], tls1_3_tests()}, + {revoked_1_2, [], tls1_2_revoked_tests()}, + {revoked_1_3, [], tls1_3_revoked_tests()}]. + +tls1_2_tests() -> + [ocsp_stapling_without_nonce_and_responder_certs_tls1_2, + ocsp_stapling_with_nonce_tls1_2, + ocsp_stapling_with_responder_cert_tls1_2]. + +tls1_2_revoked_tests() -> + [ocsp_stapling_revoked_tls1_2]. + +tls1_3_tests() -> + [ocsp_stapling_without_nonce_and_responder_certs_tls1_3, + ocsp_stapling_with_nonce_and_responder_certs_tls1_3]. + +tls1_3_revoked_tests() -> + [ocsp_stapling_revoked_tls1_3]. + +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + catch crypto:stop(), + try crypto:start() of + ok -> + ssl_test_lib:clean_start(), + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), + + %% Prepare certs + {ok, _} = make_certs:all(DataDir, PrivDir), + + ResponderPort = get_free_port(), + Pid = + start_ocsp_responder( + erlang:integer_to_list(ResponderPort), PrivDir), + + NewConfig = + lists:merge( + [{responder_port, ResponderPort}, + {responder_pid, Pid} + ], Config), + + ssl_test_lib:cert_options(NewConfig) + catch _:_ -> + {skip, "Crypto did not start"} + end. + + +end_per_suite(Config) -> + ResponderPid = proplists:get_value(responder_pid, Config), + stop_ocsp_responder(ResponderPid), + ok = ssl:stop(), + application:stop(crypto). + +%%-------------------------------------------------------------------- +init_per_group(tls1_2, Config) -> + setup_tls_server_for_group(tls1_2, Config); +init_per_group(tls1_3, Config) -> + setup_tls_server_for_group(tls1_3, Config); +init_per_group(revoked_1_2, Config) -> + setup_tls_server_for_group(revoked_1_2, Config); +init_per_group(revoked_1_3, Config) -> + setup_tls_server_for_group(revoked_1_3, Config); +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Pid = proplists:get_value(server_pid, Config), + stop_tls_server(Pid), + Config. + +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(_TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +ocsp_stapling_without_nonce_and_responder_certs_tls1_2() -> + [{doc, "Verify OCSP stapling works without nonce " + "and responder certs for tls1.2."}]. +ocsp_stapling_without_nonce_and_responder_certs_tls1_2(Config) + when is_list(Config) -> + Port = proplists:get_value(server_port, Config), + {ok, Sock} = + ssl:connect({127,0,0,1}, Port, proplists:get_value(client_opts, Config) ++ + [{keepalive, true}, + {versions, ['tlsv1.2']}, + {ocsp_stapling, true}, + {ocsp_nonce, false}, + {log_level, debug}], 5000), + ok = ssl:send(Sock, <<"ok">>), + ssl:close(Sock). + +ocsp_stapling_with_nonce_tls1_2() -> + [{doc, "Verify OCSP stapling works with nonce " + "for tls1.2."}]. +ocsp_stapling_with_nonce_tls1_2(Config) + when is_list(Config) -> + Port = proplists:get_value(server_port, Config), + {ok, Sock} = + ssl:connect({127,0,0,1}, Port, proplists:get_value(client_opts, Config) ++ + [{keepalive, true}, + {versions, ['tlsv1.2']}, + {ocsp_stapling, true}, + {log_level, debug}], 5000), + ok = ssl:send(Sock, <<"ok">>), + ssl:close(Sock). + +ocsp_stapling_with_responder_cert_tls1_2() -> + [{doc, "Verify OCSP stapling works with OCSP responder cert " + "for tls1.2."}]. +ocsp_stapling_with_responder_cert_tls1_2(Config) + when is_list(Config) -> + Port = proplists:get_value(server_port, 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), + {ok, Sock} = + ssl:connect({127,0,0,1}, Port, proplists:get_value(client_opts, Config) ++ + [{keepalive, true}, + {versions, ['tlsv1.2']}, + {ocsp_stapling, true}, + {ocsp_responder_certs, [Der]}, + {log_level, debug}], 5000), + ok = ssl:send(Sock, <<"ok">>), + ssl:close(Sock). + +ocsp_stapling_revoked_tls1_2() -> + [{doc, "Verify OCSP stapling works for revoked cert scenario " + "for tls1.2."}]. +ocsp_stapling_revoked_tls1_2(Config) + when is_list(Config) -> + Port = proplists:get_value(server_port, 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), + {error, {tls_alert, {bad_certificate_status_response, _Info}}} = + ssl:connect({127,0,0,1}, Port, proplists:get_value(client_opts, Config) ++ + [{keepalive, true}, + {versions, ['tlsv1.2']}, + {ocsp_stapling, true}, + {ocsp_responder_certs, [Der]}, + {log_level, debug}], 5000). + + +ocsp_stapling_without_nonce_and_responder_certs_tls1_3() -> + [{doc, "Verify OCSP stapling works without nonce " + "and responder certs for tls1.3."}]. +ocsp_stapling_without_nonce_and_responder_certs_tls1_3(Config) + when is_list(Config) -> + Port = proplists:get_value(server_port, Config), + {ok, Sock} = + ssl:connect({127,0,0,1}, Port, proplists:get_value(client_opts, Config) ++ + [{keepalive, true}, + {versions, ['tlsv1.3']}, + {ocsp_stapling, true}, + {ocsp_nonce, false}, + {log_level, debug}], 5000), + ok = ssl:send(Sock, <<"ok">>), + ssl:close(Sock). + +ocsp_stapling_with_nonce_and_responder_certs_tls1_3() -> + [{doc, "Verify OCSP stapling works with nonce " + "and responder certs for tls1.3."}]. +ocsp_stapling_with_nonce_and_responder_certs_tls1_3(Config) + when is_list(Config) -> + Port = proplists:get_value(server_port, 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), + {ok, Sock} = + ssl:connect({127,0,0,1}, Port, proplists:get_value(client_opts, Config) ++ + [{keepalive, true}, + {versions, ['tlsv1.3']}, + {ocsp_stapling, true}, + {ocsp_responder_certs, [Der]}, + {log_level, debug}], 5000), + ok = ssl:send(Sock, <<"ok">>), + ssl:close(Sock). + +ocsp_stapling_revoked_tls1_3() -> + [{doc, "Verify OCSP stapling works for revoked cert scenario " + "for tls1.3."}]. +ocsp_stapling_revoked_tls1_3(Config) + when is_list(Config) -> + Port = proplists:get_value(server_port, Config), + {error, {tls_alert, {bad_certificate_status_response, _Info}}} = + ssl:connect({127,0,0,1}, Port, proplists:get_value(client_opts, Config) ++ + [{keepalive, true}, + {versions, ['tlsv1.3']}, + {ocsp_stapling, true}, + {log_level, debug}], 5000). + +%%-------------------------------------------------------------------- +%% Intrernal functions ----------------------------------------------- +%%-------------------------------------------------------------------- +start_ocsp_responder(ResponderPort, PrivDir) -> + erlang:spawn( + ?MODULE, do_start_ocsp_responder, [ResponderPort, PrivDir]). + +do_start_ocsp_responder(ResponderPort, PrivDir) -> + 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"), + + Args = ["ocsp", "-index", Index, "-CA", CACerts, "-rsigner", Cert, + "-rkey", Key, "-port", ResponderPort], + process_flag(trap_exit, true), + SSLPort = ssl_test_lib:portable_open_port("openssl", Args), + true = port_command(SSLPort, "Hello world"), + ocsp_responder_loop(SSLPort). + +ocsp_responder_loop(SSLPort) -> + receive + stop_ocsp_responder -> + ct:log("Shut down OCSP responder!~n"), + ok = ssl_test_lib:close_port(SSLPort); + {_Port, closed} -> + ct:log("Port Closed~n"), + ok; + {'EXIT', _Port, Reason} -> + ct:log("Port Closed ~p~n",[Reason]), + ok; + Msg -> + ct:log("Port Msg ~p~n",[Msg]), + ocsp_responder_loop(SSLPort) + after 600000 -> + ssl_test_lib:close_port(SSLPort) + end. + +stop_ocsp_responder(Pid) -> + Pid ! stop_ocsp_responder. + +start_tls_server(Version, ResponderPort, ServerPort, PrivDir) -> + erlang:spawn( + ?MODULE, do_start_tls_server, + [Version, ResponderPort, ServerPort, PrivDir]). + +do_start_tls_server(revoked_1_2, ResponderPort, ServerPort, PrivDir) -> + Cert = filename:join(PrivDir, "revoked/cert.pem"), + Key = filename:join(PrivDir, "revoked/key.pem"), + CACerts = filename:join(PrivDir, "revoked/cacerts.pem"), + + Args = ["s_server", "-cert", Cert, "-port", ServerPort, "-key", Key, + "-CAfile", CACerts, "-status_verbose", "-status_url", + "http://127.0.0.1:" ++ ResponderPort, + "-tls1_2"] ++ ["-msg", "-debug"], + process_flag(trap_exit, true), + SSLPort = ssl_test_lib:portable_open_port("openssl", Args), + true = port_command(SSLPort, "Hello world"), + tls_server_loop(SSLPort); +do_start_tls_server(revoked_1_3, ResponderPort, ServerPort, PrivDir) -> + Cert = filename:join(PrivDir, "revoked/cert.pem"), + Key = filename:join(PrivDir, "revoked/key.pem"), + CACerts = filename:join(PrivDir, "revoked/cacerts.pem"), + + Args = ["s_server", "-cert", Cert, "-port", ServerPort, "-key", Key, + "-CAfile", CACerts, "-status_verbose", "-status_url", + "http://127.0.0.1:" ++ ResponderPort, + "-tls1_3"] ++ ["-msg", "-debug"], + process_flag(trap_exit, true), + SSLPort = ssl_test_lib:portable_open_port("openssl", Args), + true = port_command(SSLPort, "Hello world"), + tls_server_loop(SSLPort); +do_start_tls_server(Version, ResponderPort, ServerPort, PrivDir) -> + Cert = filename:join(PrivDir, "a.server/cert.pem"), + Key = filename:join(PrivDir, "a.server/key.pem"), + CACerts = filename:join(PrivDir, "a.server/cacerts.pem"), + + Args = ["s_server", "-cert", Cert, "-port", ServerPort, "-key", Key, + "-CAfile", CACerts, "-status_verbose", "-status_url", + "http://127.0.0.1:" ++ ResponderPort, + "-" ++ atom_to_list(Version)] ++ ["-msg", "-debug"], + process_flag(trap_exit, true), + SSLPort = ssl_test_lib:portable_open_port("openssl", Args), + true = port_command(SSLPort, "Hello world"), + tls_server_loop(SSLPort). + +tls_server_loop(SSLPort) -> + receive + stop_tls_server -> + ct:log("Shut down TLS responder!~n"), + ok = ssl_test_lib:close_port(SSLPort); + {_Port, closed} -> + ct:log("Port Closed~n"), + ok; + {'EXIT', _Port, Reason} -> + ct:log("Port Closed ~p~n",[Reason]), + ok; + Msg -> + ct:log("Port Msg ~p~n",[Msg]), + tls_server_loop(SSLPort) + after 600000 -> + ssl_test_lib:close_port(SSLPort) + end. + +stop_tls_server(Pid) -> + Pid ! stop_tls_server. + +get_free_port() -> + {ok, Listen} = gen_tcp:listen(0, [{reuseaddr, true}]), + {ok, Port} = inet:port(Listen), + ok = gen_tcp:close(Listen), + Port. + +setup_tls_server_for_group(Group, Config) -> + ResponderPort = proplists:get_value(responder_port, Config), + PrivDir = proplists:get_value(priv_dir, Config), + Port = get_free_port(), + Pid = start_tls_server( + Group, erlang:integer_to_list(ResponderPort), + erlang:integer_to_list(Port), PrivDir), + lists:merge( + [{server_port, Port}, + {server_pid, Pid} + ], Config).
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor