summaryrefslogtreecommitdiff
path: root/ext/openssl
diff options
context:
space:
mode:
authorrhe <rhe@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-11-25 14:12:08 (GMT)
committerrhe <rhe@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-11-25 14:12:08 (GMT)
commita55320b0933cbcfd05d427fe3712bc519c713deb (patch)
treeedcad6f717f8d75a70bdcfbf4ac47ea21e5c2fe0 /ext/openssl
parent55953e374db2193ffb6ca84e2cb83d480ecd68ac (diff)
openssl: import v2.1.0.beta2
Import Ruby/OpenSSL 2.1.0.beta2. The full commit log since commit e72d960db262 which was imported by r60013 can be found at: https://github.com/ruby/openssl/compare/e72d960db262...v2.1.0.beta2 ---------------------------------------------------------------- Kazuki Yamaguchi (26): bn: use ALLOCV() macro instead of xmalloc() appveyor.yml: remove 'openssl version' line test/test_ssl_session: skip tests for session_remove_cb x509ext: implement X509::Extension#== x509attr: implement X509::Attribute#== x509cert: implement X509::Certificate#== x509revoked: add missing X509::Revoked#to_der x509crl, x509revoked: implement X509::{CRL,Revoked}#== x509req: implement X509::Request#== ssl: extract rb_intern("call") cipher: disallow setting AAD for non-AEAD ciphers test/test_cipher: fix test_non_aead_cipher_set_auth_data failure ssl: fix conflict of options in SSLContext#set_params buffering: let #write accept multiple arguments pkey: make pkey_check_public_key() non-static x509cert, x509crl, x509req, ns_spki: check sanity of public key test/envutil: port assert_warning from Ruby trunk test/utils: remove a pointless .public_key call in issue_cert ssl: add SSLContext#add_certificate test/test_ssl: fix test_security_level Drop support for LibreSSL 2.4 kdf: add HKDF support test/test_x509cert: fix flaky test test/test_x509crl: fix random failure History.md: fix a typo Ruby/OpenSSL 2.1.0.beta2 Mark Wright (1): Fix build failure against OpenSSL 1.1 built with no-deprecated Thanks rhenium for the code review and fixes. Peter Karman (1): Add RSA sign_pss() and verify_pss() methods aeris (1): TLS Fallback Signaling Cipher Suite Value kazu (1): Use caller with length to reduce unused strings git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60907 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/openssl')
-rw-r--r--ext/openssl/History.md35
-rw-r--r--ext/openssl/lib/openssl/buffering.rb7
-rw-r--r--ext/openssl/lib/openssl/x509.rb33
-rw-r--r--ext/openssl/openssl.gemspec8
-rw-r--r--ext/openssl/openssl_missing.h4
-rw-r--r--ext/openssl/ossl.c23
-rw-r--r--ext/openssl/ossl.h5
-rw-r--r--ext/openssl/ossl_bn.c10
-rw-r--r--ext/openssl/ossl_cipher.c16
-rw-r--r--ext/openssl/ossl_engine.c54
-rw-r--r--ext/openssl/ossl_kdf.c98
-rw-r--r--ext/openssl/ossl_ns_spki.c24
-rw-r--r--ext/openssl/ossl_pkey.c9
-rw-r--r--ext/openssl/ossl_pkey.h1
-rw-r--r--ext/openssl/ossl_pkey_rsa.c192
-rw-r--r--ext/openssl/ossl_ssl.c164
-rw-r--r--ext/openssl/ossl_x509cert.c40
-rw-r--r--ext/openssl/ossl_x509crl.c9
-rw-r--r--ext/openssl/ossl_x509req.c12
-rw-r--r--ext/openssl/ossl_x509revoked.c21
20 files changed, 662 insertions, 103 deletions
diff --git a/ext/openssl/History.md b/ext/openssl/History.md
index 4e12682..f83f523 100644
--- a/ext/openssl/History.md
+++ b/ext/openssl/History.md
@@ -1,18 +1,21 @@
-Version 2.1.0.beta1
+Version 2.1.0.beta2
===================
Notable changes
---------------
-* Support for OpenSSL versions before 1.0.1 is removed.
+* Support for OpenSSL versions before 1.0.1 and LibreSSL versions before 2.5
+ is removed.
[[GitHub #86]](https://github.com/ruby/openssl/pull/86)
* OpenSSL::BN#negative?, #+@, and #-@ are added.
* OpenSSL::SSL::SSLSocket#connect raises a more informative exception when
certificate verification fails.
[[GitHub #99]](https://github.com/ruby/openssl/pull/99)
-* OpenSSL::KDF module is newly added. Support for scrypt is added.
+* OpenSSL::KDF module is newly added. In addition to PBKDF2-HMAC that has moved
+ from OpenSSL::PKCS5, scrypt and HKDF are supported.
[[GitHub #109]](https://github.com/ruby/openssl/pull/109)
-* OpenSSL.fips_mode is added. We have had the setter, but not the getter.
+ [[GitHub #173]](https://github.com/ruby/openssl/pull/173)
+* OpenSSL.fips_mode is added. We had the setter, but not the getter.
[[GitHub #125]](https://github.com/ruby/openssl/pull/125)
* OpenSSL::OCSP::Request#signed? is added.
* OpenSSL::ASN1 handles the indefinite length form better. OpenSSL::ASN1.decode
@@ -22,11 +25,31 @@ Notable changes
* OpenSSL::X509::Name#add_entry now accepts two additional keyword arguments
'loc' and 'set'.
[[GitHub #94]](https://github.com/ruby/openssl/issues/94)
-* OpenSSL::SSL::SSLContext#min_version= and #max_version= are added.
+* OpenSSL::SSL::SSLContext#min_version= and #max_version= are added to replace
+ #ssl_version= that was built on top of the deprecated OpenSSL C API. Use of
+ that method and the constant OpenSSL::SSL::SSLContext::METHODS is now
+ deprecated.
[[GitHub #142]](https://github.com/ruby/openssl/pull/142)
* OpenSSL::X509::Name#to_utf8 is added.
[[GitHub #26]](https://github.com/ruby/openssl/issues/26)
[[GitHub #143]](https://github.com/ruby/openssl/pull/143)
+* OpenSSL::X509::{Extension,Attribute,Certificate,CRL,Revoked,Request} can be
+ compared with == operator.
+ [[GitHub #161]](https://github.com/ruby/openssl/pull/161)
+* TLS Fallback Signaling Cipher Suite Value (SCSV) support is added.
+ [[GitHub #165]](https://github.com/ruby/openssl/pull/165)
+* Build failure with OpenSSL 1.1 built with no-deprecated is fixed.
+ [[GitHub #160]](https://github.com/ruby/openssl/pull/160)
+* OpenSSL::Buffering#write accepts an arbitrary number of arguments.
+ [[Feature #9323]](https://bugs.ruby-lang.org/issues/9323)
+ [[GitHub #162]](https://github.com/ruby/openssl/pull/162)
+* OpenSSL::PKey::RSA#sign_pss and #verify_pss are added. They perform RSA-PSS
+ signature and verification.
+ [[GitHub #75]](https://github.com/ruby/openssl/issues/75)
+ [[GitHub #76]](https://github.com/ruby/openssl/pull/76)
+ [[GitHub #169]](https://github.com/ruby/openssl/pull/169)
+* OpenSSL::SSL::SSLContext#add_certificate is added.
+ [[GitHub #167]](https://github.com/ruby/openssl/pull/167)
Version 2.0.6
@@ -201,7 +224,7 @@ Notable changes
- A new option 'verify_hostname' is added to OpenSSL::SSL::SSLContext. When it
is enabled, and the SNI hostname is also set, the hostname verification on
the server certificate is automatically performed. It is now enabled by
- OpenSSL::SSL::Context#set_params.
+ OpenSSL::SSL::SSLContext#set_params.
[[GH ruby/openssl#60]](https://github.com/ruby/openssl/pull/60)
Removals
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb
index f328c00..935f61f 100644
--- a/ext/openssl/lib/openssl/buffering.rb
+++ b/ext/openssl/lib/openssl/buffering.rb
@@ -340,9 +340,10 @@ module OpenSSL::Buffering
# converted using +.to_s+ method. Returns the number of bytes written.
def write(*s)
- s = s.size == 1 ? s[0] : s.join("")
- do_write(s)
- s.bytesize
+ s.inject(0) do |written, str|
+ do_write(str)
+ written + str.bytesize
+ end
end
##
diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb
index 6d31b98..98358f9 100644
--- a/ext/openssl/lib/openssl/x509.rb
+++ b/ext/openssl/lib/openssl/x509.rb
@@ -41,6 +41,11 @@ module OpenSSL
end
class Extension
+ def ==(other)
+ return false unless Extension === other
+ to_der == other.to_der
+ end
+
def to_s # "oid = critical, value"
str = self.oid
str << " = "
@@ -160,6 +165,13 @@ module OpenSSL
end
end
+ class Attribute
+ def ==(other)
+ return false unless Attribute === other
+ to_der == other.to_der
+ end
+ end
+
class StoreContext
def cleanup
warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
@@ -178,5 +190,26 @@ module OpenSSL
}
end
end
+
+ class CRL
+ def ==(other)
+ return false unless CRL === other
+ to_der == other.to_der
+ end
+ end
+
+ class Revoked
+ def ==(other)
+ return false unless Revoked === other
+ to_der == other.to_der
+ end
+ end
+
+ class Request
+ def ==(other)
+ return false unless Request === other
+ to_der == other.to_der
+ end
+ end
end
end
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec
index a8b21a5..b60b535 100644
--- a/ext/openssl/openssl.gemspec
+++ b/ext/openssl/openssl.gemspec
@@ -1,16 +1,16 @@
# -*- encoding: utf-8 -*-
-# stub: openssl 2.1.0.beta1 ruby lib
+# stub: openssl 2.1.0.beta2 ruby lib
# stub: ext/openssl/extconf.rb
Gem::Specification.new do |s|
s.name = "openssl".freeze
- s.version = "2.1.0.beta1"
+ s.version = "2.1.0.beta2"
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1".freeze) if s.respond_to? :required_rubygems_version=
s.metadata = { "msys2_mingw_dependencies" => "openssl" } if s.respond_to? :metadata=
s.require_paths = ["lib".freeze]
s.authors = ["Martin Bosslet".freeze, "SHIBATA Hiroshi".freeze, "Zachary Scott".freeze, "Kazuki Yamaguchi".freeze]
- s.date = "2017-09-24"
+ s.date = "2017-11-25"
s.description = "It wraps the OpenSSL library.".freeze
s.email = ["ruby-core@ruby-lang.org".freeze]
s.extensions = ["ext/openssl/extconf.rb".freeze]
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
s.licenses = ["Ruby".freeze]
s.rdoc_options = ["--main".freeze, "README.md".freeze]
s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze)
- s.rubygems_version = "2.6.13".freeze
+ s.rubygems_version = "2.7.2".freeze
s.summary = "OpenSSL provides SSL, TLS and general purpose cryptography.".freeze
if s.respond_to? :specification_version then
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index cc31f6a..debd25a 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -209,6 +209,10 @@ IMPL_PKEY_GETTER(EC_KEY, ec)
# define X509_get0_notAfter(x) X509_get_notAfter(x)
# define X509_CRL_get0_lastUpdate(x) X509_CRL_get_lastUpdate(x)
# define X509_CRL_get0_nextUpdate(x) X509_CRL_get_nextUpdate(x)
+# define X509_set1_notBefore(x, t) X509_set_notBefore(x, t)
+# define X509_set1_notAfter(x, t) X509_set_notAfter(x, t)
+# define X509_CRL_set1_lastUpdate(x, t) X509_CRL_set_lastUpdate(x, t)
+# define X509_CRL_set1_nextUpdate(x, t) X509_CRL_set_nextUpdate(x, t)
#endif
#if !defined(HAVE_SSL_SESSION_GET_PROTOCOL_VERSION)
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 93ecc7d..245385e 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -1109,25 +1109,14 @@ Init_openssl(void)
/*
* Init all digests, ciphers
*/
- /* CRYPTO_malloc_init(); */
- /* ENGINE_load_builtin_engines(); */
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
+ if (!OPENSSL_init_ssl(0, NULL))
+ rb_raise(rb_eRuntimeError, "OPENSSL_init_ssl");
+#else
OpenSSL_add_ssl_algorithms();
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
SSL_load_error_strings();
-
- /*
- * FIXME:
- * On unload do:
- */
-#if 0
- CONF_modules_unload(1);
- destroy_ui_method();
- EVP_cleanup();
- ENGINE_cleanup();
- CRYPTO_cleanup_all_ex_data();
- ERR_remove_state(0);
- ERR_free_strings();
#endif
/*
@@ -1149,7 +1138,11 @@ Init_openssl(void)
/*
* Version of OpenSSL the ruby OpenSSL extension is running with
*/
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
+ rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
+#else
rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
+#endif
/*
* Version number of OpenSSL the ruby OpenSSL extension was built with
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index f08889b..5a15839 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -35,6 +35,11 @@
#if !defined(OPENSSL_NO_OCSP)
# include <openssl/ocsp.h>
#endif
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/evp.h>
+#include <openssl/dh.h>
/*
* Common Module
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index d337d50..4666ce6 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -979,20 +979,20 @@ static VALUE
ossl_bn_hash(VALUE self)
{
BIGNUM *bn;
- VALUE hash;
+ VALUE tmp, hash;
unsigned char *buf;
int len;
GetBN(self, bn);
len = BN_num_bytes(bn);
- buf = xmalloc(len);
+ buf = ALLOCV(tmp, len);
if (BN_bn2bin(bn, buf) != len) {
- xfree(buf);
- ossl_raise(eBNError, NULL);
+ ALLOCV_END(tmp);
+ ossl_raise(eBNError, "BN_bn2bin");
}
hash = ST2FIX(rb_memhash(buf, len));
- xfree(buf);
+ ALLOCV_END(tmp);
return hash;
}
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index bfa76c1..3038a76 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -508,7 +508,7 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
StringValue(iv);
GetCipher(self, ctx);
- if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!iv_len)
iv_len = EVP_CIPHER_CTX_iv_length(ctx);
@@ -535,7 +535,7 @@ ossl_cipher_is_authenticated(VALUE self)
GetCipher(self, ctx);
- return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
+ return (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
}
/*
@@ -569,6 +569,8 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
in_len = RSTRING_LEN(data);
GetCipher(self, ctx);
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
ossl_raise(eCipherError, "couldn't set additional authenticated data");
@@ -606,7 +608,7 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
ret = rb_str_new(NULL, tag_len);
@@ -641,7 +643,7 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
tag_len = RSTRING_LENINT(vtag);
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "authentication tag not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
@@ -668,7 +670,7 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
@@ -695,7 +697,7 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
- if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
ossl_raise(eCipherError, "cipher does not support AEAD");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
@@ -786,7 +788,7 @@ ossl_cipher_iv_length(VALUE self)
int len = 0;
GetCipher(self, ctx);
- if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!len)
len = EVP_CIPHER_CTX_iv_length(ctx);
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index d69b5dc..5ca0d4c 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -46,13 +46,25 @@ VALUE eEngineError;
/*
* Private
*/
-#define OSSL_ENGINE_LOAD_IF_MATCH(x) \
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
+#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
do{\
- if(!strcmp(#x, RSTRING_PTR(name))){\
- ENGINE_load_##x();\
+ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
+ if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
+ return Qtrue;\
+ else\
+ ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
+ }\
+}while(0)
+#else
+#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
+do{\
+ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
+ ENGINE_load_##engine_name();\
return Qtrue;\
}\
}while(0)
+#endif
static void
ossl_engine_free(void *engine)
@@ -94,55 +106,55 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
StringValueCStr(name);
#ifndef OPENSSL_NO_STATIC_ENGINE
#if HAVE_ENGINE_LOAD_DYNAMIC
- OSSL_ENGINE_LOAD_IF_MATCH(dynamic);
+ OSSL_ENGINE_LOAD_IF_MATCH(dynamic, DYNAMIC);
#endif
#if HAVE_ENGINE_LOAD_4758CCA
- OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
+ OSSL_ENGINE_LOAD_IF_MATCH(4758cca, 4758CCA);
#endif
#if HAVE_ENGINE_LOAD_AEP
- OSSL_ENGINE_LOAD_IF_MATCH(aep);
+ OSSL_ENGINE_LOAD_IF_MATCH(aep, AEP);
#endif
#if HAVE_ENGINE_LOAD_ATALLA
- OSSL_ENGINE_LOAD_IF_MATCH(atalla);
+ OSSL_ENGINE_LOAD_IF_MATCH(atalla, ATALLA);
#endif
#if HAVE_ENGINE_LOAD_CHIL
- OSSL_ENGINE_LOAD_IF_MATCH(chil);
+ OSSL_ENGINE_LOAD_IF_MATCH(chil, CHIL);
#endif
#if HAVE_ENGINE_LOAD_CSWIFT
- OSSL_ENGINE_LOAD_IF_MATCH(cswift);
+ OSSL_ENGINE_LOAD_IF_MATCH(cswift, CSWIFT);
#endif
#if HAVE_ENGINE_LOAD_NURON
- OSSL_ENGINE_LOAD_IF_MATCH(nuron);
+ OSSL_ENGINE_LOAD_IF_MATCH(nuron, NURON);
#endif
#if HAVE_ENGINE_LOAD_SUREWARE
- OSSL_ENGINE_LOAD_IF_MATCH(sureware);
+ OSSL_ENGINE_LOAD_IF_MATCH(sureware, SUREWARE);
#endif
#if HAVE_ENGINE_LOAD_UBSEC
- OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
+ OSSL_ENGINE_LOAD_IF_MATCH(ubsec, UBSEC);
#endif
#if HAVE_ENGINE_LOAD_PADLOCK
- OSSL_ENGINE_LOAD_IF_MATCH(padlock);
+ OSSL_ENGINE_LOAD_IF_MATCH(padlock, PADLOCK);
#endif
#if HAVE_ENGINE_LOAD_CAPI
- OSSL_ENGINE_LOAD_IF_MATCH(capi);
+ OSSL_ENGINE_LOAD_IF_MATCH(capi, CAPI);
#endif
#if HAVE_ENGINE_LOAD_GMP
- OSSL_ENGINE_LOAD_IF_MATCH(gmp);
+ OSSL_ENGINE_LOAD_IF_MATCH(gmp, GMP);
#endif
#if HAVE_ENGINE_LOAD_GOST
- OSSL_ENGINE_LOAD_IF_MATCH(gost);
+ OSSL_ENGINE_LOAD_IF_MATCH(gost, GOST);
#endif
#if HAVE_ENGINE_LOAD_CRYPTODEV
- OSSL_ENGINE_LOAD_IF_MATCH(cryptodev);
+ OSSL_ENGINE_LOAD_IF_MATCH(cryptodev, CRYPTODEV);
#endif
#if HAVE_ENGINE_LOAD_AESNI
- OSSL_ENGINE_LOAD_IF_MATCH(aesni);
+ OSSL_ENGINE_LOAD_IF_MATCH(aesni, AESNI);
#endif
#endif
#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
- OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
+ OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto, OPENBSD_DEV_CRYPTO);
#endif
- OSSL_ENGINE_LOAD_IF_MATCH(openssl);
+ OSSL_ENGINE_LOAD_IF_MATCH(openssl, OPENSSL);
rb_warning("no such builtin loader for `%"PRIsVALUE"'", name);
return Qnil;
#endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
@@ -160,7 +172,9 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
static VALUE
ossl_engine_s_cleanup(VALUE self)
{
+#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000
ENGINE_cleanup();
+#endif
return Qnil;
}
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index 9fa42e1..ee12471 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -3,6 +3,9 @@
* Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
*/
#include "ossl.h"
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+# include <openssl/kdf.h>
+#endif
static VALUE mKDF, eKDF;
@@ -138,6 +141,97 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ * call-seq:
+ * KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String
+ *
+ * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in
+ * {RFC 5869}[https://tools.ietf.org/html/rfc5869].
+ *
+ * New in OpenSSL 1.1.0.
+ *
+ * === Parameters
+ * _ikm_::
+ * The input keying material.
+ * _salt_::
+ * The salt.
+ * _info_::
+ * The context and application specific information.
+ * _length_::
+ * The output length in octets. Must be <= <tt>255 * HashLen</tt>, where
+ * HashLen is the length of the hash function output in octets.
+ * _hash_::
+ * The hash function.
+ */
+static VALUE
+kdf_hkdf(int argc, VALUE *argv, VALUE self)
+{
+ VALUE ikm, salt, info, opts, kwargs[4], str;
+ static ID kwargs_ids[4];
+ int saltlen, ikmlen, infolen;
+ size_t len;
+ const EVP_MD *md;
+ EVP_PKEY_CTX *pctx;
+
+ if (!kwargs_ids[0]) {
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("info");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
+ }
+ rb_scan_args(argc, argv, "1:", &ikm, &opts);
+ rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
+
+ StringValue(ikm);
+ ikmlen = RSTRING_LENINT(ikm);
+ salt = StringValue(kwargs[0]);
+ saltlen = RSTRING_LENINT(salt);
+ info = StringValue(kwargs[1]);
+ infolen = RSTRING_LENINT(info);
+ len = (size_t)NUM2LONG(kwargs[2]);
+ if (len > LONG_MAX)
+ rb_raise(rb_eArgError, "length must be non-negative");
+ md = ossl_evp_get_digestbyname(kwargs[3]);
+
+ str = rb_str_new(NULL, (long)len);
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+ if (!pctx)
+ ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
+ if (EVP_PKEY_derive_init(pctx) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive_init");
+ }
+ if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
+ }
+ if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
+ saltlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
+ }
+ if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
+ ikmlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
+ }
+ if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
+ infolen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
+ }
+ if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive");
+ }
+ rb_str_set_len(str, (long)len);
+ EVP_PKEY_CTX_free(pctx);
+
+ return str;
+}
+#endif
+
void
Init_ossl_kdf(void)
{
@@ -162,6 +256,7 @@ Init_ossl_kdf(void)
* * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
* combination with HMAC
* * scrypt
+ * * HKDF
*
* == Examples
* === Generating a 128 bit key for a Cipher (e.g. AES)
@@ -218,4 +313,7 @@ Init_ossl_kdf(void)
#if defined(HAVE_EVP_PBE_SCRYPT)
rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+ rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
+#endif
}
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index f17b950..6f61e61 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -208,12 +208,13 @@ static VALUE
ossl_spki_set_public_key(VALUE self, VALUE key)
{
NETSCAPE_SPKI *spki;
+ EVP_PKEY *pkey;
GetSPKI(self, spki);
- if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
- ossl_raise(eSPKIError, NULL);
- }
-
+ pkey = GetPKeyPtr(key);
+ ossl_pkey_check_public_key(pkey);
+ if (!NETSCAPE_SPKI_set_pubkey(spki, pkey))
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
return key;
}
@@ -307,17 +308,20 @@ static VALUE
ossl_spki_verify(VALUE self, VALUE key)
{
NETSCAPE_SPKI *spki;
+ EVP_PKEY *pkey;
GetSPKI(self, spki);
- switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
- case 0:
+ pkey = GetPKeyPtr(key);
+ ossl_pkey_check_public_key(pkey);
+ switch (NETSCAPE_SPKI_verify(spki, pkey)) {
+ case 0:
+ ossl_clear_error();
return Qfalse;
- case 1:
+ case 1:
return Qtrue;
- default:
- ossl_raise(eSPKIError, NULL);
+ default:
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
}
- return Qnil; /* dummy */
}
/* Document-class: OpenSSL::Netscape::SPKI
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 23e2115..2b96ece 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -163,8 +163,8 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
return ossl_pkey_new(pkey);
}
-static void
-pkey_check_public_key(EVP_PKEY *pkey)
+void
+ossl_pkey_check_public_key(const EVP_PKEY *pkey)
{
void *ptr;
const BIGNUM *n, *e, *pubkey;
@@ -172,7 +172,8 @@ pkey_check_public_key(EVP_PKEY *pkey)
if (EVP_PKEY_missing_parameters(pkey))
ossl_raise(ePKeyError, "parameters missing");
- ptr = EVP_PKEY_get0(pkey);
+ /* OpenSSL < 1.1.0 takes non-const pointer */
+ ptr = EVP_PKEY_get0((EVP_PKEY *)pkey);
switch (EVP_PKEY_base_id(pkey)) {
case EVP_PKEY_RSA:
RSA_get0_key(ptr, &n, &e, NULL);
@@ -352,7 +353,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
int siglen, result;
GetPKey(self, pkey);
- pkey_check_public_key(pkey);
+ ossl_pkey_check_public_key(pkey);
md = ossl_evp_get_digestbyname(digest);
StringValue(sig);
siglen = RSTRING_LENINT(sig);
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index a87472a..2b17bf5 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -44,6 +44,7 @@ int ossl_generate_cb_2(int p, int n, BN_GENCB *cb);
void ossl_generate_cb_stop(void *ptr);
VALUE ossl_pkey_new(EVP_PKEY *);
+void ossl_pkey_check_public_key(const EVP_PKEY *);
EVP_PKEY *GetPKeyPtr(VALUE);
EVP_PKEY *DupPKeyPtr(VALUE);
EVP_PKEY *GetPrivPKeyPtr(VALUE);
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 26397bd..4800fb2 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -538,6 +538,196 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
+ * rsa.sign_pss(digest, data, salt_length:, mgf1_hash:) -> String
+ *
+ * Signs _data_ using the Probabilistic Signature Scheme (RSA-PSS) and returns
+ * the calculated signature.
+ *
+ * RSAError will be raised if an error occurs.
+ *
+ * See #verify_pss for the verification operation.
+ *
+ * === Parameters
+ * _digest_::
+ * A String containing the message digest algorithm name.
+ * _data_::
+ * A String. The data to be signed.
+ * _salt_length_::
+ * The length in octets of the salt. Two special values are reserved:
+ * +:digest+ means the digest length, and +:max+ means the maximum possible
+ * length for the combination of the private key and the selected message
+ * digest algorithm.
+ * _mgf1_hash_::
+ * The hash algorithm used in MGF1 (the currently supported mask generation
+ * function (MGF)).
+ *
+ * === Example
+ * data = "Sign me!"
+ * pkey = OpenSSL::PKey::RSA.new(2048)
+ * signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256")
+ * pub_key = pkey.public_key
+ * puts pub_key.verify_pss("SHA256", signature, data,
+ * salt_length: :auto, mgf1_hash: "SHA256") # => true
+ */
+static VALUE
+ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
+{
+ VALUE digest, data, options, kwargs[2], signature;
+ static ID kwargs_ids[2];
+ EVP_PKEY *pkey;
+ EVP_PKEY_CTX *pkey_ctx;
+ const EVP_MD *md, *mgf1md;
+ EVP_MD_CTX *md_ctx;
+ size_t buf_len;
+ int salt_len;
+
+ if (!kwargs_ids[0]) {
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ }
+ rb_scan_args(argc, argv, "2:", &digest, &data, &options);
+ rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
+ if (kwargs[0] == ID2SYM(rb_intern("max")))
+ salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
+ else if (kwargs[0] == ID2SYM(rb_intern("digest")))
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ else
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+
+ pkey = GetPrivPKeyPtr(self);
+ buf_len = EVP_PKEY_size(pkey);
+ md = ossl_evp_get_digestbyname(digest);
+ StringValue(data);
+ signature = rb_str_new(NULL, (long)buf_len);
+
+ md_ctx = EVP_MD_CTX_new();
+ if (!md_ctx)
+ goto err;
+
+ if (EVP_DigestSignInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
+ goto err;
+
+ if (EVP_DigestSignUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
+ goto err;
+
+ if (EVP_DigestSignFinal(md_ctx, (unsigned char *)RSTRING_PTR(signature), &buf_len) != 1)
+ goto err;
+
+ rb_str_set_len(signature, (long)buf_len);
+
+ EVP_MD_CTX_free(md_ctx);
+ return signature;
+
+ err:
+ EVP_MD_CTX_free(md_ctx);
+ ossl_raise(eRSAError, NULL);
+}
+
+/*
+ * call-seq:
+ * rsa.verify_pss(digest, signature, data, salt_length:, mgf1_hash:) -> true | false
+ *
+ * Verifies _data_ using the Probabilistic Signature Scheme (RSA-PSS).
+ *
+ * The return value is +true+ if the signature is valid, +false+ otherwise.
+ * RSAError will be raised if an error occurs.
+ *
+ * See #sign_pss for the signing operation and an example code.
+ *
+ * === Parameters
+ * _digest_::
+ * A String containing the message digest algorithm name.
+ * _data_::
+ * A String. The data to be signed.
+ * _salt_length_::
+ * The length in octets of the salt. Two special values are reserved:
+ * +:digest+ means the digest length, and +:auto+ means automatically
+ * determining the length based on the signature.
+ * _mgf1_hash_::
+ * The hash algorithm used in MGF1.
+ */
+static VALUE
+ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
+{
+ VALUE digest, signature, data, options, kwargs[2];
+ static ID kwargs_ids[2];
+ EVP_PKEY *pkey;
+ EVP_PKEY_CTX *pkey_ctx;
+ const EVP_MD *md, *mgf1md;
+ EVP_MD_CTX *md_ctx;
+ int result, salt_len;
+
+ if (!kwargs_ids[0]) {
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ }
+ rb_scan_args(argc, argv, "3:", &digest, &signature, &data, &options);
+ rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
+ if (kwargs[0] == ID2SYM(rb_intern("auto")))
+ salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
+ else if (kwargs[0] == ID2SYM(rb_intern("digest")))
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ else
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+
+ GetPKey(self, pkey);
+ md = ossl_evp_get_digestbyname(digest);
+ StringValue(signature);
+ StringValue(data);
+
+ md_ctx = EVP_MD_CTX_new();
+ if (!md_ctx)
+ goto err;
+
+ if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
+ goto err;
+
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
+ goto err;
+
+ if (EVP_DigestVerifyUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
+ goto err;
+
+ result = EVP_DigestVerifyFinal(md_ctx,
+ (unsigned char *)RSTRING_PTR(signature),
+ RSTRING_LEN(signature));
+
+ switch (result) {
+ case 0:
+ ossl_clear_error();
+ EVP_MD_CTX_free(md_ctx);
+ return Qfalse;
+ case 1:
+ EVP_MD_CTX_free(md_ctx);
+ return Qtrue;
+ default:
+ goto err;
+ }
+
+ err:
+ EVP_MD_CTX_free(md_ctx);
+ ossl_raise(eRSAError, NULL);
+}
+
+/*
+ * call-seq:
* rsa.params => hash
*
* THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
@@ -731,6 +921,8 @@ Init_ossl_rsa(void)
rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1);
rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1);
rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1);
+ rb_define_method(cRSA, "sign_pss", ossl_rsa_sign_pss, -1);
+ rb_define_method(cRSA, "verify_pss", ossl_rsa_verify_pss, -1);
DEF_OSSL_PKEY_BN(cRSA, rsa, n);
DEF_OSSL_PKEY_BN(cRSA, rsa, e);
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 32ae2df..8cdb973 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -32,7 +32,7 @@ VALUE cSSLSocket;
static VALUE eSSLErrorWaitReadable;
static VALUE eSSLErrorWaitWritable;
-static ID ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback,
+static ID id_call, ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback,
id_npn_protocols_encoded;
static VALUE sym_exception, sym_wait_readable, sym_wait_writable;
@@ -205,7 +205,7 @@ ossl_call_client_cert_cb(VALUE obj)
if (NIL_P(cb))
return Qnil;
- ary = rb_funcall(cb, rb_intern("call"), 1, obj);
+ ary = rb_funcallv(cb, id_call, 1, &obj);
Check_Type(ary, T_ARRAY);
GetX509CertPtr(cert = rb_ary_entry(ary, 0));
GetPrivPKeyPtr(key = rb_ary_entry(ary, 1));
@@ -248,8 +248,8 @@ ossl_call_tmp_dh_callback(struct tmp_dh_callback_args *args)
cb = rb_funcall(args->ssl_obj, args->id, 0);
if (NIL_P(cb))
return NULL;
- dh = rb_funcall(cb, rb_intern("call"), 3,
- args->ssl_obj, INT2NUM(args->is_export), INT2NUM(args->keylength));
+ dh = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
+ INT2NUM(args->keylength));
pkey = GetPKeyPtr(dh);
if (EVP_PKEY_base_id(pkey) != args->type)
return NULL;
@@ -374,12 +374,12 @@ ossl_call_session_get_cb(VALUE ary)
cb = rb_funcall(ssl_obj, rb_intern("session_get_cb"), 0);
if (NIL_P(cb)) return Qnil;
- return rb_funcall(cb, rb_intern("call"), 1, ary);
+ return rb_funcallv(cb, id_call, 1, &ary);
}
/* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */
static SSL_SESSION *
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
ossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy)
#else
ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy)
@@ -420,7 +420,7 @@ ossl_call_session_new_cb(VALUE ary)
cb = rb_funcall(ssl_obj, rb_intern("session_new_cb"), 0);
if (NIL_P(cb)) return Qnil;
- return rb_funcall(cb, rb_intern("call"), 1, ary);
+ return rb_funcallv(cb, id_call, 1, &ary);
}
/* return 1 normal. return 0 removes the session */
@@ -467,7 +467,7 @@ ossl_call_session_remove_cb(VALUE ary)
cb = rb_attr_get(sslctx_obj, id_i_session_remove_cb);
if (NIL_P(cb)) return Qnil;
- return rb_funcall(cb, rb_intern("call"), 1, ary);
+ return rb_funcallv(cb, id_call, 1, &ary);
}
static void
@@ -533,7 +533,7 @@ ossl_call_servername_cb(VALUE ary)
cb = rb_attr_get(sslctx_obj, id_i_servername_cb);
if (NIL_P(cb)) return Qnil;
- ret_obj = rb_funcall(cb, rb_intern("call"), 1, ary);
+ ret_obj = rb_funcallv(cb, id_call, 1, &ary);
if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
SSL *ssl;
SSL_CTX *ctx2;
@@ -585,7 +585,7 @@ ssl_renegotiation_cb(const SSL *ssl)
cb = rb_attr_get(sslctx_obj, id_i_renegotiation_cb);
if (NIL_P(cb)) return;
- (void) rb_funcall(cb, rb_intern("call"), 1, ssl_obj);
+ rb_funcallv(cb, id_call, 1, &ssl_obj);
}
#if !defined(OPENSSL_NO_NEXTPROTONEG) || \
@@ -635,7 +635,7 @@ npn_select_cb_common_i(VALUE tmp)
in += l;
}
- selected = rb_funcall(args->cb, rb_intern("call"), 1, protocols);
+ selected = rb_funcallv(args->cb, id_call, 1, &protocols);
StringValue(selected);
len = RSTRING_LEN(selected);
if (len < 1 || len >= 256) {
@@ -1193,6 +1193,134 @@ ossl_sslctx_set_security_level(VALUE self, VALUE value)
return value;
}
+#ifdef SSL_MODE_SEND_FALLBACK_SCSV
+/*
+ * 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);
+ SSL_CTX_set_mode(ctx, SSL_MODE_SEND_FALLBACK_SCSV);
+
+ return Qnil;
+}
+#endif
+
+/*
+ * call-seq:
+ * ctx.add_certificate(certiticate, pkey [, extra_certs]) -> self
+ *
+ * Adds a certificate to the context. _pkey_ must be a corresponding private
+ * key with _certificate_.
+ *
+ * Multiple certificates with different public key type can be added by
+ * repeated calls of this method, and OpenSSL will choose the most appropriate
+ * certificate during the handshake.
+ *
+ * #cert=, #key=, and #extra_chain_cert= are old accessor methods for setting
+ * certificate and internally call this method.
+ *
+ * === Parameters
+ * _certificate_::
+ * A certificate. An instance of OpenSSL::X509::Certificate.
+ * _pkey_::
+ * The private key for _certificate_. An instance of OpenSSL::PKey::PKey.
+ * _extra_certs_::
+ * Optional. An array of OpenSSL::X509::Certificate. When sending a
+ * certificate chain, the certificates specified by this are sent following
+ * _certificate_, in the order in the array.
+ *
+ * === Example
+ * rsa_cert = OpenSSL::X509::Certificate.new(...)
+ * rsa_pkey = OpenSSL::PKey.read(...)
+ * ca_intermediate_cert = OpenSSL::X509::Certificate.new(...)
+ * ctx.add_certificate(rsa_cert, rsa_pkey, [ca_intermediate_cert])
+ *
+ * ecdsa_cert = ...
+ * ecdsa_pkey = ...
+ * another_ca_cert = ...
+ * ctx.add_certificate(ecdsa_cert, ecdsa_pkey, [another_ca_cert])
+ *
+ * === Note
+ * OpenSSL before the version 1.0.2 could handle only one extra chain across
+ * all key types. Calling this method discards the chain set previously.
+ */
+static VALUE
+ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)
+{
+ VALUE cert, key, extra_chain_ary;
+ SSL_CTX *ctx;
+ X509 *x509;
+ STACK_OF(X509) *extra_chain = NULL;
+ EVP_PKEY *pkey, *pub_pkey;
+
+ GetSSLCTX(self, ctx);
+ rb_scan_args(argc, argv, "21", &cert, &key, &extra_chain_ary);
+ rb_check_frozen(self);
+ x509 = GetX509CertPtr(cert);
+ pkey = GetPrivPKeyPtr(key);
+
+ /*
+ * The reference counter is bumped, and decremented immediately.
+ * X509_get0_pubkey() is only available in OpenSSL >= 1.1.0.
+ */
+ pub_pkey = X509_get_pubkey(x509);
+ EVP_PKEY_free(pub_pkey);
+ if (!pub_pkey)
+ rb_raise(rb_eArgError, "certificate does not contain public key");
+ if (EVP_PKEY_cmp(pub_pkey, pkey) != 1)
+ rb_raise(rb_eArgError, "public key mismatch");
+
+ if (argc >= 3)
+ extra_chain = ossl_x509_ary2sk(extra_chain_ary);
+
+ if (!SSL_CTX_use_certificate(ctx, x509)) {
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_certificate");
+ }
+ if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
+ }
+
+ if (extra_chain) {
+#if OPENSSL_VERSION_NUMBER >= 0x10002000 && !defined(LIBRESSL_VERSION_NUMBER)
+ if (!SSL_CTX_set0_chain(ctx, extra_chain)) {
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_set0_chain");
+ }
+#else
+ STACK_OF(X509) *orig_extra_chain;
+ X509 *x509_tmp;
+
+ /* First, clear the existing chain */
+ SSL_CTX_get_extra_chain_certs(ctx, &orig_extra_chain);
+ if (orig_extra_chain && sk_X509_num(orig_extra_chain)) {
+ rb_warning("SSL_CTX_set0_chain() is not available; " \
+ "clearing previously set certificate chain");
+ SSL_CTX_clear_extra_chain_certs(ctx);
+ }
+ while ((x509_tmp = sk_X509_shift(extra_chain))) {
+ /* Transfers ownership */
+ if (!SSL_CTX_add_extra_chain_cert(ctx, x509_tmp)) {
+ X509_free(x509_tmp);
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_add_extra_chain_cert");
+ }
+ }
+ sk_X509_free(extra_chain);
+#endif
+ }
+ return self;
+}
+
/*
* call-seq:
* ctx.session_add(session) -> true | false
@@ -2261,6 +2389,7 @@ Init_ossl_ssl(void)
rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
#endif
+ id_call = rb_intern("call");
ID_callback_state = rb_intern("callback_state");
ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_vcb_idx", 0, 0, 0);
@@ -2324,11 +2453,17 @@ Init_ossl_ssl(void)
/*
* Context certificate
+ *
+ * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.
+ * It is recommended to use #add_certificate instead.
*/
rb_attr(cSSLContext, rb_intern("cert"), 1, 1, Qfalse);
/*
* Context private key
+ *
+ * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.
+ * It is recommended to use #add_certificate instead.
*/
rb_attr(cSSLContext, rb_intern("key"), 1, 1, Qfalse);
@@ -2402,6 +2537,9 @@ Init_ossl_ssl(void)
/*
* An Array of extra X509 certificates to be added to the certificate
* chain.
+ *
+ * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.
+ * It is recommended to use #add_certificate instead.
*/
rb_attr(cSSLContext, rb_intern("extra_chain_cert"), 1, 1, Qfalse);
@@ -2561,6 +2699,10 @@ Init_ossl_ssl(void)
rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0);
rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1);
+#ifdef SSL_MODE_SEND_FALLBACK_SCSV
+ rb_define_method(cSSLContext, "enable_fallback_scsv", ossl_sslctx_enable_fallback_scsv, 0);
+#endif
+ rb_define_method(cSSLContext, "add_certificate", ossl_sslctx_add_certificate, -1);
rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
rb_define_alias(cSSLContext, "freeze", "setup");
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index 003a9c1..40542c4 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -440,7 +440,7 @@ ossl_x509_set_not_before(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_set_notBefore(x509, asn1time)) {
+ if (!X509_set1_notBefore(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notBefore");
}
@@ -479,7 +479,7 @@ ossl_x509_set_not_after(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_set_notAfter(x509, asn1time)) {
+ if (!X509_set1_notAfter(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notAfter");
}
@@ -508,18 +508,19 @@ ossl_x509_get_public_key(VALUE self)
/*
* call-seq:
- * cert.public_key = key => key
+ * cert.public_key = key
*/
static VALUE
ossl_x509_set_public_key(VALUE self, VALUE key)
{
X509 *x509;
+ EVP_PKEY *pkey;
GetX509(self, x509);
- if (!X509_set_pubkey(x509, GetPKeyPtr(key))) { /* DUPs pkey */
- ossl_raise(eX509CertError, NULL);
- }
-
+ pkey = GetPKeyPtr(key);
+ ossl_pkey_check_public_key(pkey);
+ if (!X509_set_pubkey(x509, pkey))
+ ossl_raise(eX509CertError, "X509_set_pubkey");
return key;
}
@@ -557,9 +558,9 @@ ossl_x509_verify(VALUE self, VALUE key)
X509 *x509;
EVP_PKEY *pkey;
- pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
GetX509(self, x509);
-
+ pkey = GetPKeyPtr(key);
+ ossl_pkey_check_public_key(pkey);
switch (X509_verify(x509, pkey)) {
case 1:
return Qtrue;
@@ -684,6 +685,26 @@ ossl_x509_inspect(VALUE self)
}
/*
+ * call-seq:
+ * cert1 == cert2 -> true | false
+ *
+ * Compares the two certificates. Note that this takes into account all fields,
+ * not just the issuer name and the serial number.
+ */
+static VALUE
+ossl_x509_eq(VALUE self, VALUE other)
+{
+ X509 *a, *b;
+
+ GetX509(self, a);
+ if (!rb_obj_is_kind_of(other, cX509Cert))
+ return Qfalse;
+ GetX509(other, b);
+
+ return !X509_cmp(a, b) ? Qtrue : Qfalse;
+}
+
+/*
* INIT
*/
void
@@ -821,4 +842,5 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
+ rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
}
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 5ecd7ea..b0badf4 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -226,7 +226,7 @@ ossl_x509crl_set_last_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_CRL_set_lastUpdate(crl, asn1time)) {
+ if (!X509_CRL_set1_lastUpdate(crl, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
}
@@ -257,7 +257,7 @@ ossl_x509crl_set_next_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
- if (!X509_CRL_set_nextUpdate(crl, asn1time)) {
+ if (!X509_CRL_set1_nextUpdate(crl, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
}
@@ -359,9 +359,12 @@ static VALUE
ossl_x509crl_verify(VALUE self, VALUE key)
{
X509_CRL *crl;
+ EVP_PKEY *pkey;
GetX509CRL(self, crl);
- switch (X509_CRL_verify(crl, GetPKeyPtr(key))) {
+ pkey = GetPKeyPtr(key);
+ ossl_pkey_check_public_key(pkey);
+ switch (X509_CRL_verify(crl, pkey)) {
case 1:
return Qtrue;
case 0:
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index 9f20dba..2c20042 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -293,11 +293,10 @@ ossl_x509req_set_public_key(VALUE self, VALUE key)
EVP_PKEY *pkey;
GetX509Req(self, req);
- pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
- if (!X509_REQ_set_pubkey(req, pkey)) {
- ossl_raise(eX509ReqError, NULL);
- }
-
+ pkey = GetPKeyPtr(key);
+ ossl_pkey_check_public_key(pkey);
+ if (!X509_REQ_set_pubkey(req, pkey))
+ ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
return key;
}
@@ -328,7 +327,8 @@ ossl_x509req_verify(VALUE self, VALUE key)
EVP_PKEY *pkey;
GetX509Req(self, req);
- pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
+ pkey = GetPKeyPtr(key);
+ ossl_pkey_check_public_key(pkey);
switch (X509_REQ_verify(req, pkey)) {
case 1:
return Qtrue;
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index 85489ef..5fe6853 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -249,6 +249,26 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
return ext;
}
+static VALUE
+ossl_x509revoked_to_der(VALUE self)
+{
+ X509_REVOKED *rev;
+ VALUE str;
+ int len;
+ unsigned char *p;
+
+ GetX509Rev(self, rev);
+ len = i2d_X509_REVOKED(rev, NULL);
+ if (len <= 0)
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ str = rb_str_new(NULL, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ if (i2d_X509_REVOKED(rev, &p) <= 0)
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_str_adjust(str, p);
+ return str;
+}
+
/*
* INIT
*/
@@ -276,4 +296,5 @@ Init_ossl_x509revoked(void)
rb_define_method(cX509Rev, "extensions", ossl_x509revoked_get_extensions, 0);
rb_define_method(cX509Rev, "extensions=", ossl_x509revoked_set_extensions, 1);
rb_define_method(cX509Rev, "add_extension", ossl_x509revoked_add_extension, 1);
+ rb_define_method(cX509Rev, "to_der", ossl_x509revoked_to_der, 0);
}