@@ -69,6 +69,7 @@ $(RUBY_DIR)/: build/$(RUBY_NAME).tar.gz | |||
$(RUBY_OPENSSL_EXT_DIR)/Makefile: libs | $(RUBY_DIR)/ | |||
patch -d $(RUBY_DIR)/ -p1 < tmp_key.patch | |||
patch -d $(RUBY_DIR)/ -p1 < set_ecdh_curves.patch | |||
patch -d $(RUBY_DIR)/ -p1 < fallback_scsv.patch | |||
cd $(RUBY_OPENSSL_EXT_DIR) && ruby extconf.rb | |||
$(RUBY_OPENSSL_EXT_DIR)/openssl.so: libs $(RUBY_OPENSSL_EXT_DIR)/Makefile |
@@ -0,0 +1,62 @@ | |||
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb | |||
index 57519f2..c5b0c8b 100644 | |||
--- a/ext/openssl/lib/openssl/ssl.rb | |||
+++ b/ext/openssl/lib/openssl/ssl.rb | |||
@@ -105,11 +105,12 @@ class SSLContext | |||
# SSLContext.new("SSLv23_client") => ctx | |||
# | |||
# You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS | |||
- def initialize(version = nil) | |||
+ def initialize(version = nil, fallback_scsv = false) | |||
INIT_VARS.each { |v| instance_variable_set v, nil } | |||
self.options = self.options | OpenSSL::SSL::OP_ALL | |||
return unless version | |||
self.ssl_version = version | |||
+ self.enable_fallback_scsv if fallback_scsv | |||
end | |||
## | |||
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c | |||
index bcc624f..0c1780b 100644 | |||
--- a/ext/openssl/ossl_ssl.c | |||
+++ b/ext/openssl/ossl_ssl.c | |||
@@ -978,6 +978,31 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) | |||
return v; | |||
} | |||
+/* | |||
+ * call-seq: | |||
+ * ctx.enable_fallback_scsv() => nil | |||
+ * | |||
+ * Activate TLS_FALLBACK_SCSV for this context. | |||
+ * See RFC 7507. | |||
+ */ | |||
+static VALUE | |||
+ossl_sslctx_enable_fallback_scsv(VALUE self) | |||
+{ | |||
+ SSL_CTX *ctx; | |||
+ | |||
+ GetSSLCTX(self, ctx); | |||
+ if(!ctx){ | |||
+ rb_warning("SSL_CTX is not initialized."); | |||
+ return Qnil; | |||
+ } | |||
+ | |||
+ long modes = SSL_CTX_get_mode(ctx); | |||
+ modes |= SSL_MODE_SEND_FALLBACK_SCSV; | |||
+ SSL_CTX_set_mode(ctx, modes); | |||
+ | |||
+ return Qnil; | |||
+} | |||
+ | |||
#if !defined(OPENSSL_NO_EC) | |||
/* | |||
* call-seq: | |||
@@ -2330,6 +2355,7 @@ Init_ossl_ssl(void) | |||
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0); | |||
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1); | |||
rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1); | |||
+ rb_define_method(cSSLContext, "enable_fallback_scsv", ossl_sslctx_enable_fallback_scsv, 0); | |||
rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0); | |||
@@ -119,7 +119,14 @@ module CryptCheck | |||
] | |||
def checks | |||
CHECKS | |||
checks = CHECKS | |||
unless @server.fallback_scsv? == nil | |||
checks += [ | |||
[:no_fallback_scsv, Proc.new { |s| not s.fallback_scsv? }, :error], | |||
[:fallback_scsv, Proc.new { |s| s.fallback_scsv? }, :good] | |||
] | |||
end | |||
checks | |||
end | |||
def calculate_states |
@@ -1,7 +1,6 @@ | |||
require 'socket' | |||
require 'openssl' | |||
require 'httparty' | |||
require 'awesome_print' | |||
module CryptCheck | |||
module Tls | |||
@@ -41,6 +40,7 @@ module CryptCheck | |||
Logger.info { "Key : #{Tls.key_to_s self.key}" } | |||
fetch_prefered_ciphers | |||
check_supported_cipher | |||
check_fallback_scsv | |||
uniq_dh | |||
end | |||
@@ -174,6 +174,10 @@ module CryptCheck | |||
supported_ciphers.any? { |c| c.sweet32? } | |||
end | |||
def fallback_scsv? | |||
@fallback_scsv | |||
end | |||
private | |||
def name | |||
name = "#@ip:#@port" | |||
@@ -229,6 +233,8 @@ module CryptCheck | |||
when /state=error: no ciphers available$/, | |||
/state=SSLv.* read server hello A: sslv.* alert handshake failure$/ | |||
raise CipherNotAvailable, e | |||
when /state=SSLv.* read server hello A: tlsv.* alert inappropriate fallback$/ | |||
raise InappropriateFallback, e | |||
end | |||
raise | |||
rescue ::SystemCallError => e | |||
@@ -350,6 +356,34 @@ module CryptCheck | |||
end | |||
end | |||
def check_fallback_scsv | |||
@fallback_scsv = false | |||
methods = @supported_ciphers.keys | |||
if methods.size > 1 | |||
# We will try to connect to the not better supported method | |||
method = methods[1] | |||
begin | |||
ssl_client method, fallback: true | |||
rescue InappropriateFallback | |||
@fallback_scsv = true | |||
end | |||
else | |||
@fallback_scsv = nil | |||
end | |||
text, color = case @fallback_scsv | |||
when true | |||
['Supported', :good] | |||
when false | |||
['Not supported', :error] | |||
when nil | |||
['Not applicable', :unknown] | |||
end | |||
Logger.info { "Fallback SCSV : #{text.colorize color}" } | |||
end | |||
def verify_trust(chain, cert) | |||
store = ::OpenSSL::X509::Store.new | |||
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT |