From 3af2635f117f8da563d180bc1c58702aecb16e0c Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 6 Jul 2017 09:21:36 +0900 Subject: bio: prevent possible GC issue in ossl_obj2bio() Prevent the new object created by StringValue() from being GCed. Luckily, as none of the callers of ossl_obj2bio() reads from the returned BIO after possible triggering GC, this has not been a real problem. As a bonus, ossl_protect_obj2bio() function which is no longer used anywhere is removed. --- ext/openssl/ossl_bio.c | 13 +++---------- ext/openssl/ossl_bio.h | 3 +-- ext/openssl/ossl_config.c | 2 +- ext/openssl/ossl_pkcs12.c | 2 +- ext/openssl/ossl_pkcs7.c | 14 +++++++------- ext/openssl/ossl_pkey.c | 2 +- ext/openssl/ossl_pkey_dh.c | 2 +- ext/openssl/ossl_pkey_dsa.c | 2 +- ext/openssl/ossl_pkey_ec.c | 6 +++--- ext/openssl/ossl_pkey_rsa.c | 2 +- ext/openssl/ossl_ssl_session.c | 2 +- ext/openssl/ossl_x509cert.c | 2 +- ext/openssl/ossl_x509crl.c | 2 +- ext/openssl/ossl_x509req.c | 2 +- 14 files changed, 24 insertions(+), 32 deletions(-) (limited to 'ext/openssl') diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c index 1609b097..ae46ac43 100644 --- a/ext/openssl/ossl_bio.c +++ b/ext/openssl/ossl_bio.c @@ -10,8 +10,9 @@ #include "ossl.h" BIO * -ossl_obj2bio(VALUE obj) +ossl_obj2bio(volatile VALUE *pobj) { + VALUE obj = *pobj; BIO *bio; if (RB_TYPE_P(obj, T_FILE)) { @@ -40,18 +41,10 @@ ossl_obj2bio(VALUE obj) bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj)); if (!bio) ossl_raise(eOSSLError, NULL); } - + *pobj = obj; return bio; } -BIO * -ossl_protect_obj2bio(VALUE obj, int *status) -{ - BIO *ret = NULL; - ret = (BIO*)rb_protect((VALUE (*)(VALUE))ossl_obj2bio, obj, status); - return ret; -} - VALUE ossl_membio2str0(BIO *bio) { diff --git a/ext/openssl/ossl_bio.h b/ext/openssl/ossl_bio.h index 1705d0ac..2c3d952b 100644 --- a/ext/openssl/ossl_bio.h +++ b/ext/openssl/ossl_bio.h @@ -10,8 +10,7 @@ #if !defined(_OSSL_BIO_H_) #define _OSSL_BIO_H_ -BIO *ossl_obj2bio(VALUE); -BIO *ossl_protect_obj2bio(VALUE,int*); +BIO *ossl_obj2bio(volatile VALUE *); VALUE ossl_membio2str0(BIO*); VALUE ossl_membio2str(BIO*); VALUE ossl_protect_membio2str(BIO*,int*); diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c index ebf6ae2a..28392e20 100644 --- a/ext/openssl/ossl_config.c +++ b/ext/openssl/ossl_config.c @@ -41,7 +41,7 @@ DupConfigPtr(VALUE obj) OSSL_Check_Kind(obj, cConfig); str = rb_funcall(obj, rb_intern("to_s"), 0); - bio = ossl_obj2bio(str); + bio = ossl_obj2bio(&str); conf = NCONF_new(NULL); if(!conf){ BIO_free(bio); diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c index 0b9c7816..8502a6de 100644 --- a/ext/openssl/ossl_pkcs12.c +++ b/ext/openssl/ossl_pkcs12.c @@ -178,7 +178,7 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self; passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); d2i_PKCS12_bio(in, &pkcs); DATA_PTR(self) = pkcs; BIO_free(in); diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index 4040355f..40cc5f23 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -209,7 +209,7 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg) VALUE ret, data; ret = NewPKCS7(cPKCS7); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); out = NULL; pkcs7 = SMIME_read_PKCS7(in, &out); BIO_free(in); @@ -241,7 +241,7 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass) SafeGetPKCS7(pkcs7, p7); if(!NIL_P(data) && PKCS7_is_detached(p7)) flg |= PKCS7_DETACHED; - in = NIL_P(data) ? NULL : ossl_obj2bio(data); + in = NIL_P(data) ? NULL : ossl_obj2bio(&data); if(!(out = BIO_new(BIO_s_mem()))){ BIO_free(in); ossl_raise(ePKCS7Error, NULL); @@ -278,7 +278,7 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass) pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); ret = NewPKCS7(cPKCS7); - in = ossl_obj2bio(data); + in = ossl_obj2bio(&data); if(NIL_P(certs)) x509s = NULL; else{ x509s = ossl_protect_x509_ary2sk(certs, &status); @@ -334,7 +334,7 @@ ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass) else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); ret = NewPKCS7(cPKCS7); - in = ossl_obj2bio(data); + in = ossl_obj2bio(&data); x509s = ossl_protect_x509_ary2sk(certs, &status); if(status){ BIO_free(in); @@ -385,7 +385,7 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self) if(rb_scan_args(argc, argv, "01", &arg) == 0) return self; arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); p7 = PEM_read_bio_PKCS7(in, &pkcs, NULL, NULL); if (!p7) { OSSL_BIO_reset(in); @@ -777,7 +777,7 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self) x509st = GetX509StorePtr(store); flg = NIL_P(flags) ? 0 : NUM2INT(flags); if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self); - in = NIL_P(indata) ? NULL : ossl_obj2bio(indata); + in = NIL_P(indata) ? NULL : ossl_obj2bio(&indata); if(NIL_P(certs)) x509s = NULL; else{ x509s = ossl_protect_x509_ary2sk(certs, &status); @@ -844,7 +844,7 @@ ossl_pkcs7_add_data(VALUE self, VALUE data) if(!PKCS7_content_new(pkcs7, NID_pkcs7_data)) ossl_raise(ePKCS7Error, NULL); } - in = ossl_obj2bio(data); + in = ossl_obj2bio(&data); if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err; for(;;){ if((len = BIO_read(in, buf, sizeof(buf))) <= 0) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 6ab1b618..314d1d94 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -144,7 +144,7 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &data, &pass); pass = ossl_pem_passwd_value(pass); - bio = ossl_obj2bio(data); + bio = ossl_obj2bio(&data); if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) { OSSL_BIO_reset(bio); if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) { diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index dd85b7b9..92832710 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -222,7 +222,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) } else { arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); if (!dh){ OSSL_BIO_reset(in); diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index 85085419..cd4313b1 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -229,7 +229,7 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) else { pass = ossl_pem_passwd_value(pass); arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); if (!dsa) { OSSL_BIO_reset(in); diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index 10800d23..5262d3b2 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -217,7 +217,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) BIO *in; pass = ossl_pem_passwd_value(pass); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); if (!ec) { @@ -775,7 +775,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) if ((group = EC_GROUP_dup(arg1_group)) == NULL) ossl_raise(eEC_GROUP, "EC_GROUP_dup"); } else { - BIO *in = ossl_obj2bio(arg1); + BIO *in = ossl_obj2bio(&arg1); group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); if (!group) { @@ -1381,7 +1381,7 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx); } else { - BIO *in = ossl_obj2bio(arg1); + BIO *in = ossl_obj2bio(&arg1); /* BUG: finish me */ diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 5aa09d0d..1fcdd52c 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -236,7 +236,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) else { pass = ossl_pem_passwd_value(pass); arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); if (!rsa) { OSSL_BIO_reset(in); diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c index 1b602a6c..661f53ee 100644 --- a/ext/openssl/ossl_ssl_session.c +++ b/ext/openssl/ossl_ssl_session.c @@ -49,7 +49,7 @@ static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) if ((ctx = SSL_get1_session(ssl)) == NULL) ossl_raise(eSSLSession, "no session available"); } else { - BIO *in = ossl_obj2bio(arg1); + BIO *in = ossl_obj2bio(&arg1); ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL); diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c index cecc3ca0..87086a7c 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -161,7 +161,7 @@ ossl_x509_initialize(int argc, VALUE *argv, VALUE self) return self; } arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); x509 = PEM_read_bio_X509(in, &x, NULL, NULL); DATA_PTR(self) = x; if (!x509) { diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index f9819f58..035025ab 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -115,7 +115,7 @@ ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self) return self; } arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); crl = PEM_read_bio_X509_CRL(in, &x, NULL, NULL); DATA_PTR(self) = x; if (!crl) { diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c index 220d2f40..15bc7052 100644 --- a/ext/openssl/ossl_x509req.c +++ b/ext/openssl/ossl_x509req.c @@ -123,7 +123,7 @@ ossl_x509req_initialize(int argc, VALUE *argv, VALUE self) return self; } arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); + in = ossl_obj2bio(&arg); req = PEM_read_bio_X509_REQ(in, &x, NULL, NULL); DATA_PTR(self) = x; if (!req) { -- cgit v1.2.3 From f842b0d5c5e37527c11954a4b7a98c8d9cc57865 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Tue, 11 Jul 2017 13:25:24 +0900 Subject: bio: do not use the FILE BIO method in ossl_obj2bio() Read everything from an IO object into a String first and use the memory buffer BIO method just as we do for String inputs. For MSVC builds, the FILE BIO method uses the "UPLINK" interface that requires the application to provide OPENSSL_Applink() function. For us, the "application" means ruby.exe, in which we can't do anything. As a workaround, avoid using the FILE BIO method at all. Usually private keys or X.509 certificates aren't that large and the temporarily increased memory usage hopefully won't be an issue. Fixes: https://github.com/ruby/openssl/issues/128 --- ext/openssl/ossl_bio.c | 32 ++++++-------------------------- test/test_x509cert.rb | 9 +++++++++ 2 files changed, 15 insertions(+), 26 deletions(-) (limited to 'ext/openssl') diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c index ae46ac43..8fa0b696 100644 --- a/ext/openssl/ossl_bio.c +++ b/ext/openssl/ossl_bio.c @@ -15,32 +15,12 @@ ossl_obj2bio(volatile VALUE *pobj) VALUE obj = *pobj; BIO *bio; - if (RB_TYPE_P(obj, T_FILE)) { - rb_io_t *fptr; - FILE *fp; - int fd; - - GetOpenFile(obj, fptr); - rb_io_check_readable(fptr); - if ((fd = rb_cloexec_dup(FPTR_TO_FD(fptr))) < 0){ - rb_sys_fail(0); - } - rb_update_max_fd(fd); - if (!(fp = fdopen(fd, "r"))){ - int e = errno; - close(fd); - rb_syserr_fail(e, 0); - } - if (!(bio = BIO_new_fp(fp, BIO_CLOSE))){ - fclose(fp); - ossl_raise(eOSSLError, NULL); - } - } - else { - StringValue(obj); - bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj)); - if (!bio) ossl_raise(eOSSLError, NULL); - } + if (RB_TYPE_P(obj, T_FILE)) + obj = rb_funcallv(obj, rb_intern("read"), 0, NULL); + StringValue(obj); + bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj)); + if (!bio) + ossl_raise(eOSSLError, "BIO_new_mem_buf"); *pobj = obj; return bio; } diff --git a/test/test_x509cert.rb b/test/test_x509cert.rb index 0cfe4402..5b2e712d 100644 --- a/test/test_x509cert.rb +++ b/test/test_x509cert.rb @@ -178,6 +178,15 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase assert_equal(true, cert.check_private_key(@rsa2048)) end + def test_read_from_file + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + Tempfile.create("cert") { |f| + f << cert.to_pem + f.rewind + assert_equal cert.to_der, OpenSSL::X509::Certificate.new(f).to_der + } + end + private def certificate_error_returns_false -- cgit v1.2.3 From a896c3d1dfa090e92dec1abf8ac12843af6af721 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Fri, 21 Jul 2017 14:47:50 +0900 Subject: ossl_pem_passwd_cb: relax passphrase length constraint The minimum passphrase length of 4 bytes is only a limitation of PEM_def_callback() which isn't relevant here. Commit f38501249f33 introduced this bug. --- ext/openssl/ossl.c | 15 +-------------- test/test_pkey_rsa.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'ext/openssl') diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index eb71b643..5a15c9ad 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -129,13 +129,6 @@ ossl_bin2hex(unsigned char *in, char *out, size_t inlen) /* * our default PEM callback */ - -/* - * OpenSSL requires passwords for PEM-encoded files to be at least four - * characters long. See crypto/pem/pem_lib.c (as of 1.0.2h) - */ -#define OSSL_MIN_PWD_LEN 4 - VALUE ossl_pem_passwd_value(VALUE pass) { @@ -144,8 +137,6 @@ ossl_pem_passwd_value(VALUE pass) StringValue(pass); - if (RSTRING_LEN(pass) < OSSL_MIN_PWD_LEN) - ossl_raise(eOSSLError, "password must be at least %d bytes", OSSL_MIN_PWD_LEN); /* PEM_BUFSIZE is currently used as the second argument of pem_password_cb, * that is +max_len+ of ossl_pem_passwd_cb() */ if (RSTRING_LEN(pass) > PEM_BUFSIZE) @@ -178,7 +169,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) * bytes silently if the input is over 1024 bytes */ if (RB_TYPE_P(pass, T_STRING)) { len = RSTRING_LEN(pass); - if (len >= OSSL_MIN_PWD_LEN && len <= max_len) { + if (len <= max_len) { memcpy(buf, RSTRING_PTR(pass), len); return (int)len; } @@ -205,10 +196,6 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) return -1; } len = RSTRING_LEN(pass); - if (len < OSSL_MIN_PWD_LEN) { - rb_warning("password must be at least %d bytes", OSSL_MIN_PWD_LEN); - continue; - } if (len > max_len) { rb_warning("password must not be longer than %d bytes", max_len); continue; diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index b24f1d55..381e7603 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -242,6 +242,14 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase assert_equal pem, dup_public(RSA1024).export end + def test_pem_passwd + key = RSA1024 + pem3c = key.to_pem("aes-128-cbc", "key") + assert_match (/ENCRYPTED/), pem3c + assert_equal key.to_der, OpenSSL::PKey.read(pem3c, "key").to_der + assert_equal key.to_der, OpenSSL::PKey.read(pem3c) { "key" }.to_der + end + def test_dup key = OpenSSL::PKey::RSA.generate(256, 17) key2 = key.dup -- cgit v1.2.3 From 2a5ae3c7a53978145122a163e63a490a6a6c9993 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Fri, 21 Jul 2017 15:22:38 +0900 Subject: ossl_pem_passwd_cb: do not check for taintedness It is perfectly permissible to take passwords from an untrusted source. --- ext/openssl/ossl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/openssl') diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 5a15c9ad..562241c5 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -151,7 +151,7 @@ ossl_pem_passwd_cb0(VALUE flag) VALUE pass; pass = rb_yield(flag); - SafeStringValue(pass); + StringValue(pass); return pass; } -- cgit v1.2.3 From 96211a3e4ed8242832b74f166d6435144438bd43 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Fri, 21 Jul 2017 15:35:46 +0900 Subject: ossl_pem_passwd_cb: handle nil from the block explicitly There is code that returns nil in the passphrase block on purpose (to prevent OpenSSL from prompting on stdin): OpenSSL::PKey.read(File.read("file.pem")) { nil } This is working just by chance because the TypeError from StringValue() is silently ignored. Let's short circuit in that case and save raising a needless exception, as this pattern has become too common. --- ext/openssl/ossl.c | 9 +++++---- test/test_pkey_rsa.rb | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'ext/openssl') diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 562241c5..c22966df 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -148,11 +148,10 @@ ossl_pem_passwd_value(VALUE pass) static VALUE ossl_pem_passwd_cb0(VALUE flag) { - VALUE pass; - - pass = rb_yield(flag); + VALUE pass = rb_yield(flag); + if (NIL_P(pass)) + return Qnil; StringValue(pass); - return pass; } @@ -195,6 +194,8 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) rb_set_errinfo(Qnil); return -1; } + if (NIL_P(pass)) + return -1; len = RSTRING_LEN(pass); if (len > max_len) { rb_warning("password must not be longer than %d bytes", max_len); diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index 381e7603..93760f74 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -248,6 +248,9 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase assert_match (/ENCRYPTED/), pem3c assert_equal key.to_der, OpenSSL::PKey.read(pem3c, "key").to_der assert_equal key.to_der, OpenSSL::PKey.read(pem3c) { "key" }.to_der + assert_raise(OpenSSL::PKey::PKeyError) { + OpenSSL::PKey.read(pem3c) { nil } + } end def test_dup -- cgit v1.2.3 From 3e5a009966bd7f806f7180d82cf830a04be28986 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Tue, 8 Aug 2017 16:39:36 +0900 Subject: ssl: remove unsupported TLS versions from SSLContext::METHODS Check for all version-specific SSL methods. We do check for existence of TLSv1_1_method() and TLSv1_2_method(), but not for TLSv1_method(). This fixes compile error when OpenSSL is configured with no-tls1-method. Also check the OPENSSL_NO_TLS{1,1_1,1_2} macros for whether OpenSSL supports the corresponding versions or not. This prevents :TLSv1 from being in SSLContext::METHODS when OpenSSL is compiled with no-tls1. In particular, Debian sid has disabled TLS 1.0/1.1 support recently. The changes in ext/openssl are partial backport of 4eb4b3297a92 ("Remove support for OpenSSL 0.9.8 and 1.0.0", 2016-11-30). --- ext/openssl/extconf.rb | 14 ++++---------- ext/openssl/ossl_ssl.c | 10 ++++++---- test/test_ssl.rb | 4 ++-- test/test_ssl_session.rb | 6 ++---- 4 files changed, 14 insertions(+), 20 deletions(-) (limited to 'ext/openssl') diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 8f604708..6782c046 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -109,16 +109,10 @@ end Logging::message "=== Checking for OpenSSL features... ===\n" # compile options -# check OPENSSL_NO_{SSL2,SSL3_METHOD} macro: on some environment, these symbols -# exist even if compiled with no-ssl2 or no-ssl3-method. -unless have_macro("OPENSSL_NO_SSL2", "openssl/opensslconf.h") - have_func("SSLv2_method") -end -unless have_macro("OPENSSL_NO_SSL3_METHOD", "openssl/opensslconf.h") - have_func("SSLv3_method") -end -have_func("TLSv1_1_method") -have_func("TLSv1_2_method") +# SSLv2 and SSLv3 may be removed in future versions of OpenSSL, and even macros +# like OPENSSL_NO_SSL2 may not be defined. +have_func("SSLv2_method") +have_func("SSLv3_method") have_func("RAND_egd") engines = %w{builtin_engines openbsd_dev_crypto dynamic 4758cca aep atalla chil cswift nuron sureware ubsec padlock capi gmp gost cryptodev aesni} diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index e2c8eb5e..12b5536c 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -65,17 +65,19 @@ static const struct { { #name"_server", (SSL_METHOD *(*)(void))name##_server_method, version }, \ { #name"_client", (SSL_METHOD *(*)(void))name##_client_method, version } #endif -#if defined(HAVE_SSLV2_METHOD) +#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL2_METHOD) && defined(HAVE_SSLV2_METHOD) OSSL_SSL_METHOD_ENTRY(SSLv2, SSL2_VERSION), #endif -#if defined(HAVE_SSLV3_METHOD) +#if !defined(OPENSSL_NO_SSL3) && !defined(OPENSSL_NO_SSL3_METHOD) && defined(HAVE_SSLV3_METHOD) OSSL_SSL_METHOD_ENTRY(SSLv3, SSL3_VERSION), #endif +#if !defined(OPENSSL_NO_TLS1) && !defined(OPENSSL_NO_TLS1_METHOD) OSSL_SSL_METHOD_ENTRY(TLSv1, TLS1_VERSION), -#if defined(HAVE_TLSV1_1_METHOD) +#endif +#if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_1_METHOD) OSSL_SSL_METHOD_ENTRY(TLSv1_1, TLS1_1_VERSION), #endif -#if defined(HAVE_TLSV1_2_METHOD) +#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_2_METHOD) OSSL_SSL_METHOD_ENTRY(TLSv1_2, TLS1_2_VERSION), #endif OSSL_SSL_METHOD_ENTRY(SSLv23, 0), diff --git a/test/test_ssl.rb b/test/test_ssl.rb index b3efe95a..8c65df95 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -810,7 +810,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) && OpenSSL::SSL::SSLContex end -if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_1 +if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) def test_tls_v1_1 start_server_version(:TLSv1_1) { |server, port| @@ -837,7 +837,7 @@ if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_1 end -if OpenSSL::SSL::SSLContext::METHODS.include? :TLSv1_2 +if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) def test_tls_v1_2 start_server_version(:TLSv1_2) { |server, port| diff --git a/test/test_ssl_session.rb b/test/test_ssl_session.rb index b2643edd..7a99dca5 100644 --- a/test/test_ssl_session.rb +++ b/test/test_ssl_session.rb @@ -48,7 +48,7 @@ tddwpBAEDjcwMzA5NTYzMTU1MzAwpQMCARM= Timeout.timeout(5) do start_server do |server, port| sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new("TLSv1") + ctx = OpenSSL::SSL::SSLContext.new ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true ssl.connect @@ -157,9 +157,7 @@ __EOS__ start_server do |server, port| 2.times do sock = TCPSocket.new("127.0.0.1", port) - # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), - # when use default SSLContext. [ruby-dev:36167] - ctx = OpenSSL::SSL::SSLContext.new("TLSv1") + ctx = OpenSSL::SSL::SSLContext.new ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true ssl.session = last_session if last_session -- cgit v1.2.3 From 1d1be8dc94fcb7894458d4ac1e0ad370141c56fa Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Tue, 8 Aug 2017 18:18:00 +0900 Subject: ssl: fix compile error with OpenSSL 1.0.0 OpenSSL <= 1.0.0 did not support TLS 1.1/1.2, and thus we must still check the existence of the symbols. This fixes the previous commit, 3e5a009966bd ("ssl: remove unsupported TLS versions from SSLContext::METHODS", 2017-08-08). --- ext/openssl/extconf.rb | 2 ++ ext/openssl/ossl_ssl.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'ext/openssl') diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 6782c046..75da65cd 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -113,6 +113,8 @@ Logging::message "=== Checking for OpenSSL features... ===\n" # like OPENSSL_NO_SSL2 may not be defined. have_func("SSLv2_method") have_func("SSLv3_method") +have_func("TLSv1_1_method") +have_func("TLSv1_2_method") have_func("RAND_egd") engines = %w{builtin_engines openbsd_dev_crypto dynamic 4758cca aep atalla chil cswift nuron sureware ubsec padlock capi gmp gost cryptodev aesni} diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 12b5536c..62bffe31 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -74,10 +74,10 @@ static const struct { #if !defined(OPENSSL_NO_TLS1) && !defined(OPENSSL_NO_TLS1_METHOD) OSSL_SSL_METHOD_ENTRY(TLSv1, TLS1_VERSION), #endif -#if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_1_METHOD) +#if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_1_METHOD) && defined(HAVE_TLSV1_1_METHOD) OSSL_SSL_METHOD_ENTRY(TLSv1_1, TLS1_1_VERSION), #endif -#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_2_METHOD) +#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_2_METHOD) && defined(HAVE_TLSV1_2_METHOD) OSSL_SSL_METHOD_ENTRY(TLSv1_2, TLS1_2_VERSION), #endif OSSL_SSL_METHOD_ENTRY(SSLv23, 0), -- cgit v1.2.3 From df37b7a22eb0c70ddba4722630662b4c1e73b009 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Tue, 8 Aug 2017 18:29:07 +0900 Subject: Ruby/OpenSSL 2.0.5 --- History.md | 13 +++++++++++++ ext/openssl/ossl_version.h | 2 +- openssl.gemspec | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'ext/openssl') diff --git a/History.md b/History.md index bb499338..8baa0208 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,16 @@ +Version 2.0.5 +============= + +Bug fixes +--------- + +* Reading a PEM/DER-encoded private key or certificate from an IO object did + not work properly on mswin platforms. + [[ruby/openssl#128]](https://github.com/ruby/openssl/issues/128) +* Broken length check in the PEM passphrase callback is fixed. +* It failed to compile when OpenSSL is configured without TLS 1.0 support. + + Version 2.0.4 ============= diff --git a/ext/openssl/ossl_version.h b/ext/openssl/ossl_version.h index d5b9ac20..be3eebe1 100644 --- a/ext/openssl/ossl_version.h +++ b/ext/openssl/ossl_version.h @@ -10,6 +10,6 @@ #if !defined(_OSSL_VERSION_H_) #define _OSSL_VERSION_H_ -#define OSSL_VERSION "2.0.4" +#define OSSL_VERSION "2.0.5" #endif /* _OSSL_VERSION_H_ */ diff --git a/openssl.gemspec b/openssl.gemspec index ef5fff54..1a305903 100644 --- a/openssl.gemspec +++ b/openssl.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "openssl" - spec.version = "2.0.4" + spec.version = "2.0.5" spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"] spec.email = ["ruby-core@ruby-lang.org"] spec.summary = %q{OpenSSL provides SSL, TLS and general purpose cryptography.} -- cgit v1.2.3