Skip to content

Commit

Permalink
Add OpenSSL::SSL::Context#cipher_suites= and OpenSSL::SSL::Context::C…
Browse files Browse the repository at this point in the history
…IPHER_SUITES_* constants (crystal-lang#9814)

* Expose SSL_CTX_set_ciphersuites OpenSSL::SSL::Context#cipher_suites=

* Add OpenSSL::SSL::Context::CIPHER_SUITES_* constants

Use colons instead of spaces for ciphers

The cipher list consists of one or more cipher strings separated by colons. Commas or spaces are also acceptable separators **but colons are normally used**.
Ref: https://www.openssl.org/docs/man1.0.2/man1/ciphers.html

For ciphersuites only colons are allowed as separators, so it's better to use a separator that works for both.

* Add set_modern_ciphers, set_intermediate_ciphers, set_old_ciphers
  • Loading branch information
Brian J. Cardiff authored Oct 16, 2020
1 parent 0e53f6e commit 8738e63
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 20 deletions.
14 changes: 13 additions & 1 deletion scripts/generate_ssl_server_defaults.cr
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,19 @@ File.open(DEFAULTS_FILE, "w") do |file|
# available at #{json["href"]}.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHERS_#{level.upcase} = "#{all_ciphers.join(" ")}"
CIPHERS_#{level.upcase} = "#{all_ciphers.join(":")}"
# The list of secure ciphersuites on **#{level}** compatibility level as per Mozilla
# recommendations.
#
# The oldest clients supported by this configuration are:
# * #{clients.join("\n # * ")}
#
# This list represents version #{json["version"]} of the #{level} configuration
# available at #{json["href"]}.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHER_SUITES_#{level.upcase} = "#{ciphersuites.join(":")}"
CR
end
file.puts "end"
Expand Down
44 changes: 35 additions & 9 deletions spec/std/openssl/ssl/context_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,42 @@ describe OpenSSL::SSL::Context do
expect_raises(OpenSSL::Error) { context.private_key = datapath("test_file.txt") }
end

pending "uses intermediate default ciphers" do
# Can't be checked because `Context#ciphers` is not implemented.
OpenSSL::SSL::Context::Client.new.ciphers.should eq OpenSSL::SSL::Context::CIPHERS_OLD
OpenSSL::SSL::Context::Server.new.ciphers.should eq OpenSSL::SSL::Context::CIPHERS_INTERMEDIATE
end
describe "ciphers" do
pending "uses intermediate default ciphers" do
# Can't be checked because `Context#ciphers` is not implemented.
OpenSSL::SSL::Context::Client.new.ciphers.should eq OpenSSL::SSL::Context::CIPHERS_OLD
OpenSSL::SSL::Context::Server.new.ciphers.should eq OpenSSL::SSL::Context::CIPHERS_INTERMEDIATE
end

it "sets ciphers" do
ciphers = "EDH+aRSA DES-CBC3-SHA !RC4"
context = OpenSSL::SSL::Context::Client.new
(context.ciphers = ciphers).should eq(ciphers)
it "sets ciphers" do
ciphers = "EDH+aRSA DES-CBC3-SHA !RC4"
context = OpenSSL::SSL::Context::Client.new
(context.ciphers = ciphers).should eq(ciphers)
end

it "sets cipher_suites" do
cipher_suites = OpenSSL::SSL::Context::CIPHER_SUITES_MODERN
context = OpenSSL::SSL::Context::Client.new
{% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %}
(context.cipher_suites = cipher_suites).should eq(cipher_suites)
{% else %}
expect_raises(Exception, "SSL_CTX_set_ciphersuites not supported") do
(context.cipher_suites = cipher_suites).should eq(cipher_suites)
end
{% end %}
end

it "sets modern ciphers" do
OpenSSL::SSL::Context::Client.new.set_modern_ciphers
end

it "sets intermediate ciphers" do
OpenSSL::SSL::Context::Client.new.set_intermediate_ciphers
end

it "sets old ciphers" do
OpenSSL::SSL::Context::Client.new.set_old_ciphers
end
end

it "adds temporary ecdh curve (P-256)" do
Expand Down
1 change: 1 addition & 0 deletions src/openssl/lib_ssl.cr
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ lib LibSSL
fun ssl_ctx_get_options = SSL_CTX_get_options(ctx : SSLContext) : ULong
fun ssl_ctx_set_options = SSL_CTX_set_options(ctx : SSLContext, larg : ULong) : ULong
fun ssl_ctx_clear_options = SSL_CTX_clear_options(ctx : SSLContext, larg : ULong) : ULong
fun ssl_ctx_set_ciphersuites = SSL_CTX_set_ciphersuites(ctx : SSLContext, ciphers : Char*) : Int
{% end %}

@[Raises]
Expand Down
41 changes: 41 additions & 0 deletions src/openssl/ssl/context.cr
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,47 @@ abstract class OpenSSL::SSL::Context
ciphers
end

# Specify a list of TLS cipher suites to use or discard.
def cipher_suites=(cipher_suites : String)
{% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %}
ret = LibSSL.ssl_ctx_set_ciphersuites(@handle, cipher_suites)
raise OpenSSL::Error.new("SSL_CTX_set_ciphersuites") if ret == 0
cipher_suites
{% else %}
raise "SSL_CTX_set_ciphersuites not supported"
{% end %}
end

# Sets the current ciphers and ciphers suites to **modern** compatibility level as per Mozilla
# recommendations. See `CIPHERS_MODERN` and `CIPHER_SUITES_MODERN`.
def set_modern_ciphers
{% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %}
self.cipher_suites = CIPHER_SUITES_MODERN
{% else %}
self.ciphers = CIPHERS_MODERN
{% end %}
end

# Sets the current ciphers and ciphers suites to **intermediate** compatibility level as per Mozilla
# recommendations. See `CIPHERS_INTERMEDIATE` and `CIPHER_SUITES_INTERMEDIATE`.
def set_intermediate_ciphers
{% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %}
self.cipher_suites = CIPHER_SUITES_INTERMEDIATE
{% else %}
self.ciphers = CIPHERS_INTERMEDIATE
{% end %}
end

# Sets the current ciphers and ciphers suites to **old** compatibility level as per Mozilla
# recommendations. See `CIPHERS_OLD` and `CIPHER_SUITES_OLD`.
def set_old_ciphers
{% if compare_versions(LibSSL::OPENSSL_VERSION, "1.1.0") >= 0 %}
self.cipher_suites = CIPHER_SUITES_OLD
{% else %}
self.ciphers = CIPHERS_OLD
{% end %}
end

# Adds a temporary ECDH key curve to the TLS context. This is required to
# enable the EECDH cipher suites. By default the prime256 curve will be used.
def set_tmp_ecdh_key(curve = LibCrypto::NID_X9_62_prime256v1)
Expand Down
79 changes: 69 additions & 10 deletions src/openssl/ssl/defaults.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# THIS FILE WAS AUTOMATICALLY GENERATED BY script/ssl_server_defaults.cr
# on 2020-04-10 00:48:06 UTC.
# on 2020-10-09 20:33:59 UTC.

abstract class OpenSSL::SSL::Context
# The list of secure ciphers on **modern** compatibility level as per Mozilla
Expand All @@ -15,11 +15,30 @@ abstract class OpenSSL::SSL::Context
# * Opera 57
# * Safari 12.1
#
# This list represents version 5.4 of the modern configuration
# available at https://ssl-config.mozilla.org/guidelines/5.4.json.
# This list represents version 5.6 of the modern configuration
# available at https://ssl-config.mozilla.org/guidelines/5.6.json.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHERS_MODERN = "TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
CIPHERS_MODERN = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS"

# The list of secure ciphersuites on **modern** compatibility level as per Mozilla
# recommendations.
#
# The oldest clients supported by this configuration are:
# * Firefox 63
# * Android 10.0
# * Chrome 70
# * Edge 75
# * Java 11
# * OpenSSL 1.1.1
# * Opera 57
# * Safari 12.1
#
# This list represents version 5.6 of the modern configuration
# available at https://ssl-config.mozilla.org/guidelines/5.6.json.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHER_SUITES_MODERN = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"

# The list of secure ciphers on **intermediate** compatibility level as per Mozilla
# recommendations.
Expand All @@ -35,11 +54,31 @@ abstract class OpenSSL::SSL::Context
# * Opera 20
# * Safari 9
#
# This list represents version 5.4 of the intermediate configuration
# available at https://ssl-config.mozilla.org/guidelines/5.4.json.
# This list represents version 5.6 of the intermediate configuration
# available at https://ssl-config.mozilla.org/guidelines/5.6.json.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHERS_INTERMEDIATE = "TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
CIPHERS_INTERMEDIATE = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS"

# The list of secure ciphersuites on **intermediate** compatibility level as per Mozilla
# recommendations.
#
# The oldest clients supported by this configuration are:
# * Firefox 27
# * Android 4.4.2
# * Chrome 31
# * Edge
# * IE 11 on Windows 7
# * Java 8u31
# * OpenSSL 1.0.1
# * Opera 20
# * Safari 9
#
# This list represents version 5.6 of the intermediate configuration
# available at https://ssl-config.mozilla.org/guidelines/5.6.json.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHER_SUITES_INTERMEDIATE = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"

# The list of secure ciphers on **old** compatibility level as per Mozilla
# recommendations.
Expand All @@ -55,9 +94,29 @@ abstract class OpenSSL::SSL::Context
# * Opera 5
# * Safari 1
#
# This list represents version 5.4 of the old configuration
# available at https://ssl-config.mozilla.org/guidelines/5.4.json.
# This list represents version 5.6 of the old configuration
# available at https://ssl-config.mozilla.org/guidelines/5.6.json.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHERS_OLD = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS"

# The list of secure ciphersuites on **old** compatibility level as per Mozilla
# recommendations.
#
# The oldest clients supported by this configuration are:
# * Firefox 1
# * Android 2.3
# * Chrome 1
# * Edge 12
# * IE8 on Windows XP
# * Java 6
# * OpenSSL 0.9.8
# * Opera 5
# * Safari 1
#
# This list represents version 5.6 of the old configuration
# available at https://ssl-config.mozilla.org/guidelines/5.6.json.
#
# See https://wiki.mozilla.org/Security/Server_Side_TLS for details.
CIPHERS_OLD = "TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-SHA256 AES256-SHA256 AES128-SHA AES256-SHA DES-CBC3-SHA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
CIPHER_SUITES_OLD = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
end

0 comments on commit 8738e63

Please sign in to comment.