aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-06-14 12:14:21 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-06-14 12:39:53 +0900
commit805882145bde3286d8fcfa1e6254be1522979ee7 (patch)
tree3692f46152026baac95905beb282c4c7ef072533
parentf1dc4ce49c408708f256a3e3c6c75bbee49e2d6b (diff)
downloadruby-openssl-805882145bde3286d8fcfa1e6254be1522979ee7.tar.gz
x509store: clear error queue after calling X509_LOOKUP_load_file()
X509_LOOKUP_load_file(), which ends up calling X509_load_cert_crl_file() internally, may leave error entries in the queue even when it returns non-zero value (which indicates success). This will be fixed by OpenSSL 1.1.1, but can be worked around by clearing the error queue ourselves. Fixes: https://bugs.ruby-lang.org/issues/11033
-rw-r--r--ext/openssl/ossl_x509store.c9
-rw-r--r--test/test_x509store.rb23
2 files changed, 32 insertions, 0 deletions
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index eb81e0d4..4becc8e3 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -342,6 +342,15 @@ ossl_x509store_add_file(VALUE self, VALUE file)
if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){
ossl_raise(eX509StoreError, NULL);
}
+#if OPENSSL_VERSION_NUMBER < 0x10101000 || defined(LIBRESSL_VERSION_NUMBER)
+ /*
+ * X509_load_cert_crl_file() which is called from X509_LOOKUP_load_file()
+ * did not check the return value of X509_STORE_add_{cert,crl}(), leaking
+ * "cert already in hash table" errors on the error queue, if duplicate
+ * certificates are found. This will be fixed by OpenSSL 1.1.1.
+ */
+ ossl_clear_error();
+#endif
return self;
}
diff --git a/test/test_x509store.rb b/test/test_x509store.rb
index a5dfa206..c45233aa 100644
--- a/test/test_x509store.rb
+++ b/test/test_x509store.rb
@@ -34,6 +34,29 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase
OpenSSL::TestUtils.issue_crl(*args)
end
+ def test_add_file
+ ca_exts = [
+ ["basicConstraints", "CA:TRUE", true],
+ ["keyUsage", "cRLSign,keyCertSign", true],
+ ]
+ cert1 = issue_cert(@ca1, @rsa1024, 1, ca_exts, nil, nil)
+ cert2 = issue_cert(@ca2, @rsa2048, 1, ca_exts, nil, nil)
+ tmpfile = Tempfile.open { |f| f << cert1.to_pem << cert2.to_pem; f }
+
+ store = OpenSSL::X509::Store.new
+ assert_equal false, store.verify(cert1)
+ assert_equal false, store.verify(cert2)
+ store.add_file(tmpfile.path)
+ assert_equal true, store.verify(cert1)
+ assert_equal true, store.verify(cert2)
+
+ # OpenSSL < 1.1.1 leaks an error on a duplicate certificate
+ assert_nothing_raised { store.add_file(tmpfile.path) }
+ assert_equal [], OpenSSL.errors
+ ensure
+ tmpfile and tmpfile.close!
+ end
+
def test_verify
# OpenSSL uses time(2) while Time.now uses clock_gettime(CLOCK_REALTIME),
# and there may be difference.