Created
December 8, 2019 07:02
-
-
Save rdp/35bec8cd7e8349985bd560f243d93dca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
iff --git a/spec/std/openssl/ssl/socket_spec.cr b/spec/std/openssl/ssl/socket_spec.cr | |
index 1b6675327..9ba587f1f 100644 | |
--- a/spec/std/openssl/ssl/socket_spec.cr | |
+++ b/spec/std/openssl/ssl/socket_spec.cr | |
@@ -20,6 +20,27 @@ describe OpenSSL::SSL::Socket do | |
end | |
end | |
+ it "accepts clients that don't read anything and close the connection" do | |
+ tcp_server = TCPServer.new(0) | |
+ server_context, client_context = ssl_context_pair | |
+ # in tls 1.3, if clients don't read anything and close the connection | |
+ # the server might still try and send it a ticket, resulting in a pipe failure | |
+ server_context.disable_session_resume_tickets | |
+ | |
+ OpenSSL::SSL::Server.open(tcp_server, server_context) do |server| | |
+ spawn do | |
+ # the :sync_close portion, as implemented, effects a socket close from the client | |
+ OpenSSL::SSL::Socket::Client.open(TCPSocket.new(tcp_server.local_address.address, tcp_server.local_address.port), client_context, hostname: "example.com", sync_close: true) do |socket| | |
+ # doesn't read anything, just write and close connection immediately | |
+ socket.puts "hello" | |
+ end | |
+ end | |
+ | |
+ client = server.accept # shouldn't raise | |
+ client.close | |
+ end | |
+ end | |
+ | |
it "returns the TLS version" do | |
tcp_server = TCPServer.new(0) | |
server_context, client_context = ssl_context_pair | |
@@ -39,6 +60,7 @@ describe OpenSSL::SSL::Socket do | |
it "closes connection to server that doesn't properly terminate SSL session" do | |
tcp_server = TCPServer.new(0) | |
server_context, client_context = ssl_context_pair | |
+ server_context.disable_session_resume_tickets | |
client_successfully_closed_socket = Channel(Nil).new | |
spawn do | |
diff --git a/src/openssl/lib_ssl.cr b/src/openssl/lib_ssl.cr | |
index f663c3ea4..455e83c41 100644 | |
--- a/src/openssl/lib_ssl.cr | |
+++ b/src/openssl/lib_ssl.cr | |
@@ -206,6 +206,12 @@ lib LibSSL | |
# Hostname validation for OpenSSL <= 1.0.1 | |
fun ssl_ctx_set_cert_verify_callback = SSL_CTX_set_cert_verify_callback(ctx : SSLContext, callback : CertVerifyCallback, arg : Void*) | |
+ # control TLS 1.3 session ticket generation | |
+ {% if compare_versions(OPENSSL_VERSION, "1.1.1") >= 0 %} | |
+ fun ssl_ctx_set_num_tickets = SSL_CTX_set_num_tickets(ctx : SSLContext, larg : LibC::SizeT) : Int | |
+ fun ssl_set_num_tickets = SSL_set_num_tickets(ctx : SSL, larg : LibC::SizeT) : Int | |
+ {% end %} | |
+ | |
{% if compare_versions(OPENSSL_VERSION, "1.1.0") >= 0 %} | |
fun tls_method = TLS_method : SSLMethod | |
{% else %} | |
diff --git a/src/openssl/ssl/context.cr b/src/openssl/ssl/context.cr | |
index cad1934b6..e0eea9e6f 100644 | |
--- a/src/openssl/ssl/context.cr | |
+++ b/src/openssl/ssl/context.cr | |
@@ -191,6 +191,20 @@ abstract class OpenSSL::SSL::Context | |
def self.from_hash(params) : self | |
super(params) | |
end | |
+ | |
+ # Disables all session ticket generation for this context. | |
+ # Tickets are used to resume earlier sessions more quickly, | |
+ # but in TLS 1.3 if the client connects, sends data, and closes the connection | |
+ # unidirectionally, the server connects, then sends a ticket | |
+ # after the connect handshake, the ticket send can fail with Broken Pipe. | |
+ # So if you have that kind of behavior (clients that never read) call this method. | |
+ def disable_session_resume_tickets | |
+ add_options(OpenSSL::SSL::Options::NO_TICKET) # TLS v1.2 and below | |
+ {% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.1") >= 0 %} | |
+ out = LibSSL.ssl_ctx_set_num_tickets(self, 0) # TLS v1.3 | |
+ raise OpenSSL::Error.new("SSL_CTX_set_num_tickets") if out != 1 | |
+ {% end %} | |
+ end | |
end | |
protected def initialize(method : LibSSL::SSLMethod) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment