From d75456a5584373d55967cbcd8f97555cbbf434e0 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Wed, 25 Sep 2019 15:03:09 -0700 Subject: Fix keyword argument separation issues in OpenSSL::SSL::SSLSocket#sys{read,write}_nonblock [ Originally landed on ruby.git as commit 3959469f240e, then was merged into ruby/openssl.git as commit b4e96fc4abc3. This is a backport to the 2.0 branch. ] It's unlikely anyone would actually hit these. The methods are private, you only hit this code path if calling these methods before performing the SSL connection, and there is already a verbose warning issued. --- ext/openssl/ossl_ssl.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'ext') diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index c6bfb831..4ddf0ad6 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1740,8 +1740,13 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); rb_warning("SSL session is not started yet."); - if (nonblock) - return rb_funcall(io, meth, 3, len, str, opts); + if (nonblock) { + VALUE argv[3]; + argv[0] = len; + argv[1] = str; + argv[2] = opts; + return rb_funcallv_kw(io, meth, 3, argv, RB_PASS_KEYWORDS); + } else return rb_funcall(io, meth, 2, len, str); } @@ -1831,8 +1836,12 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) rb_intern("write_nonblock") : rb_intern("syswrite"); rb_warning("SSL session is not started yet."); - if (nonblock) - return rb_funcall(io, meth, 2, str, opts); + if (nonblock) { + VALUE argv[2]; + argv[0] = str; + argv[1] = opts; + return rb_funcallv_kw(io, meth, 2, argv, RB_PASS_KEYWORDS); + } else return rb_funcall(io, meth, 1, str); } -- cgit v1.2.3 From 9cfe51cc5ce4cb1b09366299f059dee949235541 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 27 Nov 2019 11:43:30 +0900 Subject: Restore compatibility with older versions of Ruby. [ Originally landed on as commit b4e96fc4abc3. This is a backport to the 2.0 branch. ] `RB_PASS_KEYWORDS` is not always available. --- ext/openssl/ossl_ssl.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'ext') diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 4ddf0ad6..6a3e21b2 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1737,18 +1737,24 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) } } else { - ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); + ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); - rb_warning("SSL session is not started yet."); - if (nonblock) { + rb_warning("SSL session is not started yet."); +#if defined(RB_PASS_KEYWORDS) + if (nonblock) { VALUE argv[3]; argv[0] = len; argv[1] = str; argv[2] = opts; return rb_funcallv_kw(io, meth, 3, argv, RB_PASS_KEYWORDS); } - else - return rb_funcall(io, meth, 2, len, str); +#else + if (nonblock) { + return rb_funcall(io, meth, 3, len, str, opts); + } +#endif + else + return rb_funcall(io, meth, 2, len, str); } end: @@ -1835,15 +1841,21 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) ID meth = nonblock ? rb_intern("write_nonblock") : rb_intern("syswrite"); - rb_warning("SSL session is not started yet."); - if (nonblock) { + rb_warning("SSL session is not started yet."); +#if defined(RB_PASS_KEYWORDS) + if (nonblock) { VALUE argv[2]; argv[0] = str; argv[1] = opts; return rb_funcallv_kw(io, meth, 2, argv, RB_PASS_KEYWORDS); } - else - return rb_funcall(io, meth, 1, str); +#else + if (nonblock) { + return rb_funcall(io, meth, 2, str, opts); + } +#endif + else + return rb_funcall(io, meth, 1, str); } end: -- cgit v1.2.3 From 9604d20e5d0be1334a057b1c97ad533e1c7db904 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 18 Oct 2019 12:28:44 -0700 Subject: Remove taint support [ This is a backport to the 2.0 branch. ] Ruby 2.7 deprecates taint and it no longer has an effect. The lack of taint support should not cause a problem in previous Ruby versions. (cherry picked from commit e7ed01b580a139ad0fb320ad5f29bbb40ef2ddc2) --- ext/openssl/ossl_rand.c | 8 -------- ext/openssl/ossl_ssl.c | 1 - ext/openssl/ossl_x509store.c | 2 -- 3 files changed, 11 deletions(-) (limited to 'ext') diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c index 688c525a..1b2ec964 100644 --- a/ext/openssl/ossl_rand.c +++ b/ext/openssl/ossl_rand.c @@ -67,8 +67,6 @@ ossl_rand_add(VALUE self, VALUE str, VALUE entropy) static VALUE ossl_rand_load_file(VALUE self, VALUE filename) { - rb_check_safe_obj(filename); - if(!RAND_load_file(StringValueCStr(filename), -1)) { ossl_raise(eRandomError, NULL); } @@ -86,8 +84,6 @@ ossl_rand_load_file(VALUE self, VALUE filename) static VALUE ossl_rand_write_file(VALUE self, VALUE filename) { - rb_check_safe_obj(filename); - if (RAND_write_file(StringValueCStr(filename)) == -1) { ossl_raise(eRandomError, NULL); } @@ -164,8 +160,6 @@ ossl_rand_pseudo_bytes(VALUE self, VALUE len) static VALUE ossl_rand_egd(VALUE self, VALUE filename) { - rb_check_safe_obj(filename); - if (RAND_egd(StringValueCStr(filename)) == -1) { ossl_raise(eRandomError, NULL); } @@ -186,8 +180,6 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len) { int n = NUM2INT(len); - rb_check_safe_obj(filename); - if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) { ossl_raise(eRandomError, NULL); } diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 6a3e21b2..5422e699 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1688,7 +1688,6 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) else rb_str_modify_expand(str, ilen - RSTRING_LEN(str)); } - OBJ_TAINT(str); rb_str_set_len(str, 0); if (ilen == 0) return str; diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 3cddcc49..a3b6b823 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -333,7 +333,6 @@ ossl_x509store_add_file(VALUE self, VALUE file) char *path = NULL; if(file != Qnil){ - rb_check_safe_obj(file); path = StringValueCStr(file); } GetX509Store(self, store); @@ -369,7 +368,6 @@ ossl_x509store_add_path(VALUE self, VALUE dir) char *path = NULL; if(dir != Qnil){ - rb_check_safe_obj(dir); path = StringValueCStr(dir); } GetX509Store(self, store); -- cgit v1.2.3 From 65ea09c403cc216d8e14d966b78fbc1bea16810d Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Mon, 24 Feb 2020 20:58:21 +0900 Subject: x509: add error code and verify flags constants Add missing constant declarations for certificate verification flags and the error codes, to match with OpenSSL 1.1.1. --- ext/openssl/ossl_x509.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'ext') diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c index 19ec274a..6ead8310 100644 --- a/ext/openssl/ossl_x509.c +++ b/ext/openssl/ossl_x509.c @@ -49,7 +49,13 @@ Init_ossl_x509(void) Init_ossl_x509revoked(); Init_ossl_x509store(); + /* Constants are up-to-date with 1.1.1. */ + + /* Certificate verification error code */ DefX509Const(V_OK); +#if defined(X509_V_ERR_UNSPECIFIED) /* 1.0.1r, 1.0.2f, 1.1.0 */ + DefX509Const(V_ERR_UNSPECIFIED); +#endif DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT); DefX509Const(V_ERR_UNABLE_TO_GET_CRL); DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); @@ -81,8 +87,73 @@ Init_ossl_x509(void) DefX509Const(V_ERR_AKID_SKID_MISMATCH); DefX509Const(V_ERR_AKID_ISSUER_SERIAL_MISMATCH); DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN); + DefX509Const(V_ERR_UNABLE_TO_GET_CRL_ISSUER); + DefX509Const(V_ERR_UNHANDLED_CRITICAL_EXTENSION); + DefX509Const(V_ERR_KEYUSAGE_NO_CRL_SIGN); + DefX509Const(V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); + DefX509Const(V_ERR_INVALID_NON_CA); + DefX509Const(V_ERR_PROXY_PATH_LENGTH_EXCEEDED); + DefX509Const(V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); + DefX509Const(V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); + DefX509Const(V_ERR_INVALID_EXTENSION); + DefX509Const(V_ERR_INVALID_POLICY_EXTENSION); + DefX509Const(V_ERR_NO_EXPLICIT_POLICY); + DefX509Const(V_ERR_DIFFERENT_CRL_SCOPE); + DefX509Const(V_ERR_UNSUPPORTED_EXTENSION_FEATURE); + DefX509Const(V_ERR_UNNESTED_RESOURCE); + DefX509Const(V_ERR_PERMITTED_VIOLATION); + DefX509Const(V_ERR_EXCLUDED_VIOLATION); + DefX509Const(V_ERR_SUBTREE_MINMAX); DefX509Const(V_ERR_APPLICATION_VERIFICATION); + DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); + DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); + DefX509Const(V_ERR_UNSUPPORTED_NAME_SYNTAX); + DefX509Const(V_ERR_CRL_PATH_VALIDATION_ERROR); +#if defined(X509_V_ERR_PATH_LOOP) + DefX509Const(V_ERR_PATH_LOOP); +#endif +#if defined(X509_V_ERR_SUITE_B_INVALID_VERSION) + DefX509Const(V_ERR_SUITE_B_INVALID_VERSION); + DefX509Const(V_ERR_SUITE_B_INVALID_ALGORITHM); + DefX509Const(V_ERR_SUITE_B_INVALID_CURVE); + DefX509Const(V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM); + DefX509Const(V_ERR_SUITE_B_LOS_NOT_ALLOWED); + DefX509Const(V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256); +#endif +#if defined(X509_V_ERR_HOSTNAME_MISMATCH) + DefX509Const(V_ERR_HOSTNAME_MISMATCH); + DefX509Const(V_ERR_EMAIL_MISMATCH); + DefX509Const(V_ERR_IP_ADDRESS_MISMATCH); +#endif +#if defined(X509_V_ERR_DANE_NO_MATCH) + DefX509Const(V_ERR_DANE_NO_MATCH); +#endif +#if defined(X509_V_ERR_EE_KEY_TOO_SMALL) + DefX509Const(V_ERR_EE_KEY_TOO_SMALL); + DefX509Const(V_ERR_CA_KEY_TOO_SMALL); + DefX509Const(V_ERR_CA_MD_TOO_WEAK); +#endif +#if defined(X509_V_ERR_INVALID_CALL) + DefX509Const(V_ERR_INVALID_CALL); +#endif +#if defined(X509_V_ERR_STORE_LOOKUP) + DefX509Const(V_ERR_STORE_LOOKUP); +#endif +#if defined(X509_V_ERR_NO_VALID_SCTS) + DefX509Const(V_ERR_NO_VALID_SCTS); +#endif +#if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION) + DefX509Const(V_ERR_PROXY_SUBJECT_NAME_VIOLATION); +#endif +#if defined(X509_V_ERR_OCSP_VERIFY_NEEDED) + DefX509Const(V_ERR_OCSP_VERIFY_NEEDED); + DefX509Const(V_ERR_OCSP_VERIFY_FAILED); + DefX509Const(V_ERR_OCSP_CERT_UNKNOWN); +#endif + /* Certificate verify flags */ + /* Set by Store#flags= and StoreContext#flags=. */ + DefX509Const(V_FLAG_USE_CHECK_TIME); /* Set by Store#flags= and StoreContext#flags=. Enables CRL checking for the * certificate chain leaf. */ DefX509Const(V_FLAG_CRL_CHECK); @@ -133,6 +204,26 @@ Init_ossl_x509(void) * Enabled by default in OpenSSL >= 1.1.0. */ DefX509Const(V_FLAG_TRUSTED_FIRST); #endif +#if defined(X509_V_FLAG_SUITEB_128_LOS_ONLY) + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 128 bit only mode. */ + DefX509Const(V_FLAG_SUITEB_128_LOS_ONLY); +#endif +#if defined(X509_V_FLAG_SUITEB_192_LOS) + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 192 bit only mode. */ + DefX509Const(V_FLAG_SUITEB_192_LOS); +#endif +#if defined(X509_V_FLAG_SUITEB_128_LOS) + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 128 bit mode allowing 192 bit algorithms. */ + DefX509Const(V_FLAG_SUITEB_128_LOS); +#endif +#if defined(X509_V_FLAG_PARTIAL_CHAIN) + /* Set by Store#flags= and StoreContext#flags=. + * Allows partial chains if at least one certificate is in trusted store. */ + DefX509Const(V_FLAG_PARTIAL_CHAIN); +#endif #if defined(X509_V_FLAG_NO_ALT_CHAINS) /* Set by Store#flags= and StoreContext#flags=. Suppresses searching for * a alternative chain. No effect in OpenSSL >= 1.1.0. */ -- cgit v1.2.3 From 74ef8c0cc56b840b772240f2ee2b0fc0aafa2743 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Mon, 24 Feb 2020 21:12:22 +0900 Subject: ssl: set verify error code in the case of verify_hostname failure When the verify_hostname option is enabled, the hostname verification is done before calling verify_callback provided by the user. The callback should be notified of the hostname verification failure. OpenSSL::X509::StoreContext's error code must be set to an appropriate value rather than OpenSSL::X509::V_OK. If the constant X509_V_ERR_HOSTNAME_MISMATCH is available (OpenSSL >= 1.0.2), use it. Otherwise use the generic X509_V_ERR_CERT_REJECTED. Reference: https://github.com/ruby/openssl/issues/244 Fixes: 028e495734e9 ("ssl: add verify_hostname option to SSLContext", 2016-06-27) --- ext/openssl/ossl_ssl.c | 9 ++++++++- test/test_ssl.rb | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'ext') diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 5422e699..3d076633 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -350,7 +350,14 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status)); return 0; } - preverify_ok = ret == Qtrue; + if (ret != Qtrue) { + preverify_ok = 0; +#if defined(X509_V_ERR_HOSTNAME_MISMATCH) + X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH); +#else + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); +#endif + } } return ossl_verify_cb_call(cb, preverify_ok, ctx); diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 408c7d82..8263e58a 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -752,6 +752,46 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end + def test_verify_hostname_failure_error_code + ctx_proc = proc { |ctx| + exts = [ + ["keyUsage", "keyEncipherment,digitalSignature", true], + ["subjectAltName", "DNS:a.example.com"], + ] + ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) + ctx.key = @svr_key + } + + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| + verify_callback_ok = verify_callback_err = nil + + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_hostname = true + ctx.cert_store = OpenSSL::X509::Store.new + ctx.cert_store.add_cert(@ca_cert) + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ctx.verify_callback = -> (preverify_ok, store_ctx) { + verify_callback_ok = preverify_ok + verify_callback_err = store_ctx.error + preverify_ok + } + + begin + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.hostname = "b.example.com" + assert_handshake_error { ssl.connect } + assert_equal false, verify_callback_ok + code_expected = openssl?(1, 0, 2) || defined?(OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH) ? + OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH : + OpenSSL::X509::V_ERR_CERT_REJECTED + assert_equal code_expected, verify_callback_err + ensure + sock&.close + end + end + end + def test_unset_OP_ALL ctx_proc = Proc.new { |ctx| # If OP_DONT_INSERT_EMPTY_FRAGMENTS is not defined, this test is -- cgit v1.2.3