1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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:

	e72d960db2...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
This commit is contained in:
rhe 2017-11-25 14:12:08 +00:00
parent 55953e374d
commit a55320b093
32 changed files with 1020 additions and 116 deletions

View file

@ -1,18 +1,21 @@
Version 2.1.0.beta1 Version 2.1.0.beta2
=================== ===================
Notable changes 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) [[GitHub #86]](https://github.com/ruby/openssl/pull/86)
* OpenSSL::BN#negative?, #+@, and #-@ are added. * OpenSSL::BN#negative?, #+@, and #-@ are added.
* OpenSSL::SSL::SSLSocket#connect raises a more informative exception when * OpenSSL::SSL::SSLSocket#connect raises a more informative exception when
certificate verification fails. certificate verification fails.
[[GitHub #99]](https://github.com/ruby/openssl/pull/99) [[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) [[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) [[GitHub #125]](https://github.com/ruby/openssl/pull/125)
* OpenSSL::OCSP::Request#signed? is added. * OpenSSL::OCSP::Request#signed? is added.
* OpenSSL::ASN1 handles the indefinite length form better. OpenSSL::ASN1.decode * 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 * OpenSSL::X509::Name#add_entry now accepts two additional keyword arguments
'loc' and 'set'. 'loc' and 'set'.
[[GitHub #94]](https://github.com/ruby/openssl/issues/94) [[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) [[GitHub #142]](https://github.com/ruby/openssl/pull/142)
* OpenSSL::X509::Name#to_utf8 is added. * OpenSSL::X509::Name#to_utf8 is added.
[[GitHub #26]](https://github.com/ruby/openssl/issues/26) [[GitHub #26]](https://github.com/ruby/openssl/issues/26)
[[GitHub #143]](https://github.com/ruby/openssl/pull/143) [[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 Version 2.0.6
@ -201,7 +224,7 @@ Notable changes
- A new option 'verify_hostname' is added to OpenSSL::SSL::SSLContext. When it - 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 is enabled, and the SNI hostname is also set, the hostname verification on
the server certificate is automatically performed. It is now enabled by 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) [[GH ruby/openssl#60]](https://github.com/ruby/openssl/pull/60)
Removals Removals

View file

@ -340,9 +340,10 @@ module OpenSSL::Buffering
# converted using +.to_s+ method. Returns the number of bytes written. # converted using +.to_s+ method. Returns the number of bytes written.
def write(*s) def write(*s)
s = s.size == 1 ? s[0] : s.join("") s.inject(0) do |written, str|
do_write(s) do_write(str)
s.bytesize written + str.bytesize
end
end end
## ##

View file

@ -41,6 +41,11 @@ module OpenSSL
end end
class Extension class Extension
def ==(other)
return false unless Extension === other
to_der == other.to_der
end
def to_s # "oid = critical, value" def to_s # "oid = critical, value"
str = self.oid str = self.oid
str << " = " str << " = "
@ -160,6 +165,13 @@ module OpenSSL
end end
end end
class Attribute
def ==(other)
return false unless Attribute === other
to_der == other.to_der
end
end
class StoreContext class StoreContext
def cleanup def cleanup
warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
@ -178,5 +190,26 @@ module OpenSSL
} }
end end
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
end end

View file

@ -1,16 +1,16 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
# stub: openssl 2.1.0.beta1 ruby lib # stub: openssl 2.1.0.beta2 ruby lib
# stub: ext/openssl/extconf.rb # stub: ext/openssl/extconf.rb
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "openssl".freeze 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.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.metadata = { "msys2_mingw_dependencies" => "openssl" } if s.respond_to? :metadata=
s.require_paths = ["lib".freeze] s.require_paths = ["lib".freeze]
s.authors = ["Martin Bosslet".freeze, "SHIBATA Hiroshi".freeze, "Zachary Scott".freeze, "Kazuki Yamaguchi".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.description = "It wraps the OpenSSL library.".freeze
s.email = ["ruby-core@ruby-lang.org".freeze] s.email = ["ruby-core@ruby-lang.org".freeze]
s.extensions = ["ext/openssl/extconf.rb".freeze] s.extensions = ["ext/openssl/extconf.rb".freeze]
@ -20,7 +20,7 @@ Gem::Specification.new do |s|
s.licenses = ["Ruby".freeze] s.licenses = ["Ruby".freeze]
s.rdoc_options = ["--main".freeze, "README.md".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze]
s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".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 s.summary = "OpenSSL provides SSL, TLS and general purpose cryptography.".freeze
if s.respond_to? :specification_version then if s.respond_to? :specification_version then

View file

@ -209,6 +209,10 @@ IMPL_PKEY_GETTER(EC_KEY, ec)
# define X509_get0_notAfter(x) X509_get_notAfter(x) # define X509_get0_notAfter(x) X509_get_notAfter(x)
# define X509_CRL_get0_lastUpdate(x) X509_CRL_get_lastUpdate(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_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 #endif
#if !defined(HAVE_SSL_SESSION_GET_PROTOCOL_VERSION) #if !defined(HAVE_SSL_SESSION_GET_PROTOCOL_VERSION)

View file

@ -1109,25 +1109,14 @@ Init_openssl(void)
/* /*
* Init all digests, ciphers * Init all digests, ciphers
*/ */
/* CRYPTO_malloc_init(); */ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
/* ENGINE_load_builtin_engines(); */ if (!OPENSSL_init_ssl(0, NULL))
rb_raise(rb_eRuntimeError, "OPENSSL_init_ssl");
#else
OpenSSL_add_ssl_algorithms(); OpenSSL_add_ssl_algorithms();
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
SSL_load_error_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 #endif
/* /*
@ -1149,7 +1138,11 @@ Init_openssl(void)
/* /*
* Version of OpenSSL the ruby OpenSSL extension is running with * 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))); 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 * Version number of OpenSSL the ruby OpenSSL extension was built with

View file

@ -35,6 +35,11 @@
#if !defined(OPENSSL_NO_OCSP) #if !defined(OPENSSL_NO_OCSP)
# include <openssl/ocsp.h> # include <openssl/ocsp.h>
#endif #endif
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include <openssl/dh.h>
/* /*
* Common Module * Common Module

View file

@ -979,20 +979,20 @@ static VALUE
ossl_bn_hash(VALUE self) ossl_bn_hash(VALUE self)
{ {
BIGNUM *bn; BIGNUM *bn;
VALUE hash; VALUE tmp, hash;
unsigned char *buf; unsigned char *buf;
int len; int len;
GetBN(self, bn); GetBN(self, bn);
len = BN_num_bytes(bn); len = BN_num_bytes(bn);
buf = xmalloc(len); buf = ALLOCV(tmp, len);
if (BN_bn2bin(bn, buf) != len) { if (BN_bn2bin(bn, buf) != len) {
xfree(buf); ALLOCV_END(tmp);
ossl_raise(eBNError, NULL); ossl_raise(eBNError, "BN_bn2bin");
} }
hash = ST2FIX(rb_memhash(buf, len)); hash = ST2FIX(rb_memhash(buf, len));
xfree(buf); ALLOCV_END(tmp);
return hash; return hash;
} }

View file

@ -508,7 +508,7 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
StringValue(iv); StringValue(iv);
GetCipher(self, 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)
iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!iv_len) if (!iv_len)
iv_len = EVP_CIPHER_CTX_iv_length(ctx); iv_len = EVP_CIPHER_CTX_iv_length(ctx);
@ -535,7 +535,7 @@ ossl_cipher_is_authenticated(VALUE self)
GetCipher(self, ctx); 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); in_len = RSTRING_LEN(data);
GetCipher(self, ctx); 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)) if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
ossl_raise(eCipherError, "couldn't set additional authenticated data"); 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); 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"); ossl_raise(eCipherError, "authentication tag not supported by this cipher");
ret = rb_str_new(NULL, tag_len); 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); tag_len = RSTRING_LENINT(vtag);
GetCipher(self, 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, "authentication tag not supported by this 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)) 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; EVP_CIPHER_CTX *ctx;
GetCipher(self, 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"); ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL)) 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; EVP_CIPHER_CTX *ctx;
GetCipher(self, 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"); ossl_raise(eCipherError, "cipher does not support AEAD");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL)) 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; int len = 0;
GetCipher(self, 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)
len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!len) if (!len)
len = EVP_CIPHER_CTX_iv_length(ctx); len = EVP_CIPHER_CTX_iv_length(ctx);

View file

@ -46,13 +46,25 @@ VALUE eEngineError;
/* /*
* Private * 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{\ do{\
if(!strcmp(#x, RSTRING_PTR(name))){\ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
ENGINE_load_##x();\ 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;\ return Qtrue;\
}\ }\
}while(0) }while(0)
#endif
static void static void
ossl_engine_free(void *engine) ossl_engine_free(void *engine)
@ -94,55 +106,55 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
StringValueCStr(name); StringValueCStr(name);
#ifndef OPENSSL_NO_STATIC_ENGINE #ifndef OPENSSL_NO_STATIC_ENGINE
#if HAVE_ENGINE_LOAD_DYNAMIC #if HAVE_ENGINE_LOAD_DYNAMIC
OSSL_ENGINE_LOAD_IF_MATCH(dynamic); OSSL_ENGINE_LOAD_IF_MATCH(dynamic, DYNAMIC);
#endif #endif
#if HAVE_ENGINE_LOAD_4758CCA #if HAVE_ENGINE_LOAD_4758CCA
OSSL_ENGINE_LOAD_IF_MATCH(4758cca); OSSL_ENGINE_LOAD_IF_MATCH(4758cca, 4758CCA);
#endif #endif
#if HAVE_ENGINE_LOAD_AEP #if HAVE_ENGINE_LOAD_AEP
OSSL_ENGINE_LOAD_IF_MATCH(aep); OSSL_ENGINE_LOAD_IF_MATCH(aep, AEP);
#endif #endif
#if HAVE_ENGINE_LOAD_ATALLA #if HAVE_ENGINE_LOAD_ATALLA
OSSL_ENGINE_LOAD_IF_MATCH(atalla); OSSL_ENGINE_LOAD_IF_MATCH(atalla, ATALLA);
#endif #endif
#if HAVE_ENGINE_LOAD_CHIL #if HAVE_ENGINE_LOAD_CHIL
OSSL_ENGINE_LOAD_IF_MATCH(chil); OSSL_ENGINE_LOAD_IF_MATCH(chil, CHIL);
#endif #endif
#if HAVE_ENGINE_LOAD_CSWIFT #if HAVE_ENGINE_LOAD_CSWIFT
OSSL_ENGINE_LOAD_IF_MATCH(cswift); OSSL_ENGINE_LOAD_IF_MATCH(cswift, CSWIFT);
#endif #endif
#if HAVE_ENGINE_LOAD_NURON #if HAVE_ENGINE_LOAD_NURON
OSSL_ENGINE_LOAD_IF_MATCH(nuron); OSSL_ENGINE_LOAD_IF_MATCH(nuron, NURON);
#endif #endif
#if HAVE_ENGINE_LOAD_SUREWARE #if HAVE_ENGINE_LOAD_SUREWARE
OSSL_ENGINE_LOAD_IF_MATCH(sureware); OSSL_ENGINE_LOAD_IF_MATCH(sureware, SUREWARE);
#endif #endif
#if HAVE_ENGINE_LOAD_UBSEC #if HAVE_ENGINE_LOAD_UBSEC
OSSL_ENGINE_LOAD_IF_MATCH(ubsec); OSSL_ENGINE_LOAD_IF_MATCH(ubsec, UBSEC);
#endif #endif
#if HAVE_ENGINE_LOAD_PADLOCK #if HAVE_ENGINE_LOAD_PADLOCK
OSSL_ENGINE_LOAD_IF_MATCH(padlock); OSSL_ENGINE_LOAD_IF_MATCH(padlock, PADLOCK);
#endif #endif
#if HAVE_ENGINE_LOAD_CAPI #if HAVE_ENGINE_LOAD_CAPI
OSSL_ENGINE_LOAD_IF_MATCH(capi); OSSL_ENGINE_LOAD_IF_MATCH(capi, CAPI);
#endif #endif
#if HAVE_ENGINE_LOAD_GMP #if HAVE_ENGINE_LOAD_GMP
OSSL_ENGINE_LOAD_IF_MATCH(gmp); OSSL_ENGINE_LOAD_IF_MATCH(gmp, GMP);
#endif #endif
#if HAVE_ENGINE_LOAD_GOST #if HAVE_ENGINE_LOAD_GOST
OSSL_ENGINE_LOAD_IF_MATCH(gost); OSSL_ENGINE_LOAD_IF_MATCH(gost, GOST);
#endif #endif
#if HAVE_ENGINE_LOAD_CRYPTODEV #if HAVE_ENGINE_LOAD_CRYPTODEV
OSSL_ENGINE_LOAD_IF_MATCH(cryptodev); OSSL_ENGINE_LOAD_IF_MATCH(cryptodev, CRYPTODEV);
#endif #endif
#if HAVE_ENGINE_LOAD_AESNI #if HAVE_ENGINE_LOAD_AESNI
OSSL_ENGINE_LOAD_IF_MATCH(aesni); OSSL_ENGINE_LOAD_IF_MATCH(aesni, AESNI);
#endif #endif
#endif #endif
#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO #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 #endif
OSSL_ENGINE_LOAD_IF_MATCH(openssl); OSSL_ENGINE_LOAD_IF_MATCH(openssl, OPENSSL);
rb_warning("no such builtin loader for `%"PRIsVALUE"'", name); rb_warning("no such builtin loader for `%"PRIsVALUE"'", name);
return Qnil; return Qnil;
#endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
@ -160,7 +172,9 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
static VALUE static VALUE
ossl_engine_s_cleanup(VALUE self) ossl_engine_s_cleanup(VALUE self)
{ {
#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000
ENGINE_cleanup(); ENGINE_cleanup();
#endif
return Qnil; return Qnil;
} }

View file

@ -3,6 +3,9 @@
* Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors * Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
*/ */
#include "ossl.h" #include "ossl.h"
#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
# include <openssl/kdf.h>
#endif
static VALUE mKDF, eKDF; static VALUE mKDF, eKDF;
@ -138,6 +141,97 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
} }
#endif #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 void
Init_ossl_kdf(void) Init_ossl_kdf(void)
{ {
@ -162,6 +256,7 @@ Init_ossl_kdf(void)
* * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in * * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
* combination with HMAC * combination with HMAC
* * scrypt * * scrypt
* * HKDF
* *
* == Examples * == Examples
* === Generating a 128 bit key for a Cipher (e.g. AES) * === 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) #if defined(HAVE_EVP_PBE_SCRYPT)
rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1); rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
#endif #endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
#endif
} }

View file

@ -208,12 +208,13 @@ static VALUE
ossl_spki_set_public_key(VALUE self, VALUE key) ossl_spki_set_public_key(VALUE self, VALUE key)
{ {
NETSCAPE_SPKI *spki; NETSCAPE_SPKI *spki;
EVP_PKEY *pkey;
GetSPKI(self, spki); GetSPKI(self, spki);
if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ pkey = GetPKeyPtr(key);
ossl_raise(eSPKIError, NULL); ossl_pkey_check_public_key(pkey);
} if (!NETSCAPE_SPKI_set_pubkey(spki, pkey))
ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
return key; return key;
} }
@ -307,17 +308,20 @@ static VALUE
ossl_spki_verify(VALUE self, VALUE key) ossl_spki_verify(VALUE self, VALUE key)
{ {
NETSCAPE_SPKI *spki; NETSCAPE_SPKI *spki;
EVP_PKEY *pkey;
GetSPKI(self, spki); GetSPKI(self, spki);
switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ pkey = GetPKeyPtr(key);
case 0: ossl_pkey_check_public_key(pkey);
switch (NETSCAPE_SPKI_verify(spki, pkey)) {
case 0:
ossl_clear_error();
return Qfalse; return Qfalse;
case 1: case 1:
return Qtrue; return Qtrue;
default: default:
ossl_raise(eSPKIError, NULL); ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
} }
return Qnil; /* dummy */
} }
/* Document-class: OpenSSL::Netscape::SPKI /* Document-class: OpenSSL::Netscape::SPKI

View file

@ -163,8 +163,8 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
return ossl_pkey_new(pkey); return ossl_pkey_new(pkey);
} }
static void void
pkey_check_public_key(EVP_PKEY *pkey) ossl_pkey_check_public_key(const EVP_PKEY *pkey)
{ {
void *ptr; void *ptr;
const BIGNUM *n, *e, *pubkey; const BIGNUM *n, *e, *pubkey;
@ -172,7 +172,8 @@ pkey_check_public_key(EVP_PKEY *pkey)
if (EVP_PKEY_missing_parameters(pkey)) if (EVP_PKEY_missing_parameters(pkey))
ossl_raise(ePKeyError, "parameters missing"); 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)) { switch (EVP_PKEY_base_id(pkey)) {
case EVP_PKEY_RSA: case EVP_PKEY_RSA:
RSA_get0_key(ptr, &n, &e, NULL); 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; int siglen, result;
GetPKey(self, pkey); GetPKey(self, pkey);
pkey_check_public_key(pkey); ossl_pkey_check_public_key(pkey);
md = ossl_evp_get_digestbyname(digest); md = ossl_evp_get_digestbyname(digest);
StringValue(sig); StringValue(sig);
siglen = RSTRING_LENINT(sig); siglen = RSTRING_LENINT(sig);

View file

@ -44,6 +44,7 @@ int ossl_generate_cb_2(int p, int n, BN_GENCB *cb);
void ossl_generate_cb_stop(void *ptr); void ossl_generate_cb_stop(void *ptr);
VALUE ossl_pkey_new(EVP_PKEY *); VALUE ossl_pkey_new(EVP_PKEY *);
void ossl_pkey_check_public_key(const EVP_PKEY *);
EVP_PKEY *GetPKeyPtr(VALUE); EVP_PKEY *GetPKeyPtr(VALUE);
EVP_PKEY *DupPKeyPtr(VALUE); EVP_PKEY *DupPKeyPtr(VALUE);
EVP_PKEY *GetPrivPKeyPtr(VALUE); EVP_PKEY *GetPrivPKeyPtr(VALUE);

View file

@ -536,6 +536,196 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
return str; return str;
} }
/*
* 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: * call-seq:
* rsa.params => hash * rsa.params => hash
@ -731,6 +921,8 @@ Init_ossl_rsa(void)
rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1); 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_encrypt", ossl_rsa_private_encrypt, -1);
rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -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, n);
DEF_OSSL_PKEY_BN(cRSA, rsa, e); DEF_OSSL_PKEY_BN(cRSA, rsa, e);

View file

@ -32,7 +32,7 @@ VALUE cSSLSocket;
static VALUE eSSLErrorWaitReadable; static VALUE eSSLErrorWaitReadable;
static VALUE eSSLErrorWaitWritable; 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; id_npn_protocols_encoded;
static VALUE sym_exception, sym_wait_readable, sym_wait_writable; 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)) if (NIL_P(cb))
return Qnil; return Qnil;
ary = rb_funcall(cb, rb_intern("call"), 1, obj); ary = rb_funcallv(cb, id_call, 1, &obj);
Check_Type(ary, T_ARRAY); Check_Type(ary, T_ARRAY);
GetX509CertPtr(cert = rb_ary_entry(ary, 0)); GetX509CertPtr(cert = rb_ary_entry(ary, 0));
GetPrivPKeyPtr(key = rb_ary_entry(ary, 1)); 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); cb = rb_funcall(args->ssl_obj, args->id, 0);
if (NIL_P(cb)) if (NIL_P(cb))
return NULL; return NULL;
dh = rb_funcall(cb, rb_intern("call"), 3, dh = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
args->ssl_obj, INT2NUM(args->is_export), INT2NUM(args->keylength)); INT2NUM(args->keylength));
pkey = GetPKeyPtr(dh); pkey = GetPKeyPtr(dh);
if (EVP_PKEY_base_id(pkey) != args->type) if (EVP_PKEY_base_id(pkey) != args->type)
return NULL; return NULL;
@ -374,12 +374,12 @@ ossl_call_session_get_cb(VALUE ary)
cb = rb_funcall(ssl_obj, rb_intern("session_get_cb"), 0); cb = rb_funcall(ssl_obj, rb_intern("session_get_cb"), 0);
if (NIL_P(cb)) return Qnil; 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) */ /* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */
static SSL_SESSION * 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) ossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy)
#else #else
ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy) 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); cb = rb_funcall(ssl_obj, rb_intern("session_new_cb"), 0);
if (NIL_P(cb)) return Qnil; 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 */ /* 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); cb = rb_attr_get(sslctx_obj, id_i_session_remove_cb);
if (NIL_P(cb)) return Qnil; 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 static void
@ -533,7 +533,7 @@ ossl_call_servername_cb(VALUE ary)
cb = rb_attr_get(sslctx_obj, id_i_servername_cb); cb = rb_attr_get(sslctx_obj, id_i_servername_cb);
if (NIL_P(cb)) return Qnil; 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)) { if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
SSL *ssl; SSL *ssl;
SSL_CTX *ctx2; SSL_CTX *ctx2;
@ -585,7 +585,7 @@ ssl_renegotiation_cb(const SSL *ssl)
cb = rb_attr_get(sslctx_obj, id_i_renegotiation_cb); cb = rb_attr_get(sslctx_obj, id_i_renegotiation_cb);
if (NIL_P(cb)) return; 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) || \ #if !defined(OPENSSL_NO_NEXTPROTONEG) || \
@ -635,7 +635,7 @@ npn_select_cb_common_i(VALUE tmp)
in += l; in += l;
} }
selected = rb_funcall(args->cb, rb_intern("call"), 1, protocols); selected = rb_funcallv(args->cb, id_call, 1, &protocols);
StringValue(selected); StringValue(selected);
len = RSTRING_LEN(selected); len = RSTRING_LEN(selected);
if (len < 1 || len >= 256) { if (len < 1 || len >= 256) {
@ -1193,6 +1193,134 @@ ossl_sslctx_set_security_level(VALUE self, VALUE value)
return 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: * call-seq:
* ctx.session_add(session) -> true | false * ctx.session_add(session) -> true | false
@ -2261,6 +2389,7 @@ Init_ossl_ssl(void)
rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable"); rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
#endif #endif
id_call = rb_intern("call");
ID_callback_state = rb_intern("callback_state"); 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); 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 * 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); rb_attr(cSSLContext, rb_intern("cert"), 1, 1, Qfalse);
/* /*
* Context private key * 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); 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 * An Array of extra X509 certificates to be added to the certificate
* chain. * 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); 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, "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_get_security_level, 0);
rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1); 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_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
rb_define_alias(cSSLContext, "freeze", "setup"); rb_define_alias(cSSLContext, "freeze", "setup");

View file

@ -440,7 +440,7 @@ ossl_x509_set_not_before(VALUE self, VALUE time)
GetX509(self, x509); GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time); asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set_notBefore(x509, asn1time)) { if (!X509_set1_notBefore(x509, asn1time)) {
ASN1_TIME_free(asn1time); ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notBefore"); ossl_raise(eX509CertError, "X509_set_notBefore");
} }
@ -479,7 +479,7 @@ ossl_x509_set_not_after(VALUE self, VALUE time)
GetX509(self, x509); GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time); asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set_notAfter(x509, asn1time)) { if (!X509_set1_notAfter(x509, asn1time)) {
ASN1_TIME_free(asn1time); ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notAfter"); ossl_raise(eX509CertError, "X509_set_notAfter");
} }
@ -508,18 +508,19 @@ ossl_x509_get_public_key(VALUE self)
/* /*
* call-seq: * call-seq:
* cert.public_key = key => key * cert.public_key = key
*/ */
static VALUE static VALUE
ossl_x509_set_public_key(VALUE self, VALUE key) ossl_x509_set_public_key(VALUE self, VALUE key)
{ {
X509 *x509; X509 *x509;
EVP_PKEY *pkey;
GetX509(self, x509); GetX509(self, x509);
if (!X509_set_pubkey(x509, GetPKeyPtr(key))) { /* DUPs pkey */ pkey = GetPKeyPtr(key);
ossl_raise(eX509CertError, NULL); ossl_pkey_check_public_key(pkey);
} if (!X509_set_pubkey(x509, pkey))
ossl_raise(eX509CertError, "X509_set_pubkey");
return key; return key;
} }
@ -557,9 +558,9 @@ ossl_x509_verify(VALUE self, VALUE key)
X509 *x509; X509 *x509;
EVP_PKEY *pkey; EVP_PKEY *pkey;
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
GetX509(self, x509); GetX509(self, x509);
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
switch (X509_verify(x509, pkey)) { switch (X509_verify(x509, pkey)) {
case 1: case 1:
return Qtrue; return Qtrue;
@ -683,6 +684,26 @@ ossl_x509_inspect(VALUE self)
ossl_x509_get_not_after(self)); ossl_x509_get_not_after(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 * INIT
*/ */
@ -821,4 +842,5 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1); 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, "add_extension", ossl_x509_add_extension, 1);
rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0); rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
} }

View file

@ -226,7 +226,7 @@ ossl_x509crl_set_last_update(VALUE self, VALUE time)
GetX509CRL(self, crl); GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time); 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); ASN1_TIME_free(asn1time);
ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate"); ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
} }
@ -257,7 +257,7 @@ ossl_x509crl_set_next_update(VALUE self, VALUE time)
GetX509CRL(self, crl); GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time); 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); ASN1_TIME_free(asn1time);
ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate"); ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
} }
@ -359,9 +359,12 @@ static VALUE
ossl_x509crl_verify(VALUE self, VALUE key) ossl_x509crl_verify(VALUE self, VALUE key)
{ {
X509_CRL *crl; X509_CRL *crl;
EVP_PKEY *pkey;
GetX509CRL(self, crl); 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: case 1:
return Qtrue; return Qtrue;
case 0: case 0:

View file

@ -293,11 +293,10 @@ ossl_x509req_set_public_key(VALUE self, VALUE key)
EVP_PKEY *pkey; EVP_PKEY *pkey;
GetX509Req(self, req); GetX509Req(self, req);
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ pkey = GetPKeyPtr(key);
if (!X509_REQ_set_pubkey(req, pkey)) { ossl_pkey_check_public_key(pkey);
ossl_raise(eX509ReqError, NULL); if (!X509_REQ_set_pubkey(req, pkey))
} ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
return key; return key;
} }
@ -328,7 +327,8 @@ ossl_x509req_verify(VALUE self, VALUE key)
EVP_PKEY *pkey; EVP_PKEY *pkey;
GetX509Req(self, req); 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)) { switch (X509_REQ_verify(req, pkey)) {
case 1: case 1:
return Qtrue; return Qtrue;

View file

@ -249,6 +249,26 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
return 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 * 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_get_extensions, 0);
rb_define_method(cX509Rev, "extensions=", ossl_x509revoked_set_extensions, 1); 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, "add_extension", ossl_x509revoked_add_extension, 1);
rb_define_method(cX509Rev, "to_der", ossl_x509revoked_to_der, 0);
} }

View file

@ -295,6 +295,13 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
assert_equal tag1, tag2 assert_equal tag1, tag2
end end
def test_non_aead_cipher_set_auth_data
assert_raise(OpenSSL::Cipher::CipherError) {
cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt
cipher.auth_data = "123"
}
end
private private
def new_encryptor(algo, **kwargs) def new_encryptor(algo, **kwargs)

View file

@ -131,6 +131,48 @@ class OpenSSL::TestKDF < OpenSSL::TestCase
assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen))
end end
def test_hkdf_rfc5869_test_case_1
pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0
hash = "sha256"
ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
salt = B("000102030405060708090a0b0c")
info = B("f0f1f2f3f4f5f6f7f8f9")
l = 42
okm = B("3cb25f25faacd57a90434f64d0362f2a" \
"2d2d0a90cf1a5a4c5db02d56ecc4c5bf" \
"34007208d5b887185865")
assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))
end
def test_hkdf_rfc5869_test_case_3
pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0
hash = "sha256"
ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
salt = B("")
info = B("")
l = 42
okm = B("8da4e775a563c18f715f802a063c5a31" \
"b8a11f5c5ee1879ec3454e5f3c738d2d" \
"9d201395faa4b61a96c8")
assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))
end
def test_hkdf_rfc5869_test_case_4
pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0
hash = "sha1"
ikm = B("0b0b0b0b0b0b0b0b0b0b0b")
salt = B("000102030405060708090a0b0c")
info = B("f0f1f2f3f4f5f6f7f8f9")
l = 42
okm = B("085a01ea1b10f36933068b56efa5ad81" \
"a4f14b822f5b091568a9cdd4f155fda2" \
"c22e422478d305f3f896")
assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))
end
private private
def B(ary) def B(ary)

View file

@ -122,12 +122,12 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN)
ret = req.verify([@cert], store) ret = req.verify([@cert], store)
if ret || openssl?(1, 0, 2) || libressl?(2, 4, 2) if ret || openssl?(1, 0, 2)
assert_equal true, ret assert_equal true, ret
else else
# RT2560; OCSP_request_verify() does not find signer cert from 'certs' when # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when
# OCSP_NOINTERN is not specified. # OCSP_NOINTERN is not specified.
# fixed by OpenSSL 1.0.1j, 1.0.2 and LibreSSL 2.4.2 # fixed by OpenSSL 1.0.1j, 1.0.2
pend "RT2560: ocsp_req_find_signer" pend "RT2560: ocsp_req_find_signer"
end end
@ -262,11 +262,6 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, []) bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, [])
bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil) bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil)
if bres.responses[2].check_validity # thisUpdate is in future; must fail
# LibreSSL bug; skip for now
pend "OCSP_check_validity() is broken"
end
single1 = bres.responses[0] single1 = bres.responses[0]
assert_equal false, single1.check_validity assert_equal false, single1.check_validity
assert_equal false, single1.check_validity(30) assert_equal false, single1.check_validity(30)
@ -275,6 +270,8 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
assert_equal true, single2.check_validity assert_equal true, single2.check_validity
assert_equal true, single2.check_validity(0, 500) assert_equal true, single2.check_validity(0, 500)
assert_equal false, single2.check_validity(0, 200) assert_equal false, single2.check_validity(0, 200)
single3 = bres.responses[2]
assert_equal false, single3.check_validity
end end
def test_response def test_response

View file

@ -362,6 +362,15 @@ module OpenSSL::TestPairM
} }
end end
def test_write_multiple_arguments
ssl_pair {|s1, s2|
str1 = "foo"; str2 = "bar"
assert_equal 6, s1.write(str1, str2)
s1.close
assert_equal "foobar", s2.read
}
end
def test_partial_tls_record_read_nonblock def test_partial_tls_record_read_nonblock
ssl_pair { |s1, s2| ssl_pair { |s1, s2|
# the beginning of a TLS record # the beginning of a TLS record

View file

@ -113,6 +113,39 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
} }
end end
def test_sign_verify_pss
key = Fixtures.pkey("rsa1024")
data = "Sign me!"
invalid_data = "Sign me?"
signature = key.sign_pss("SHA256", data, salt_length: 20, mgf1_hash: "SHA1")
assert_equal 128, signature.bytesize
assert_equal true,
key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1")
assert_equal true,
key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1")
assert_equal false,
key.verify_pss("SHA256", signature, invalid_data, salt_length: 20, mgf1_hash: "SHA1")
signature = key.sign_pss("SHA256", data, salt_length: :digest, mgf1_hash: "SHA1")
assert_equal true,
key.verify_pss("SHA256", signature, data, salt_length: 32, mgf1_hash: "SHA1")
assert_equal true,
key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1")
assert_equal false,
key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1")
signature = key.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA1")
assert_equal true,
key.verify_pss("SHA256", signature, data, salt_length: 94, mgf1_hash: "SHA1")
assert_equal true,
key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1")
assert_raise(OpenSSL::PKey::RSAError) {
key.sign_pss("SHA256", data, salt_length: 95, mgf1_hash: "SHA1")
}
end
def test_RSAPrivateKey def test_RSAPrivateKey
rsa1024 = Fixtures.pkey("rsa1024") rsa1024 = Fixtures.pkey("rsa1024")
asn1 = OpenSSL::ASN1::Sequence([ asn1 = OpenSSL::ASN1::Sequence([

View file

@ -54,6 +54,87 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
} }
end end
def test_add_certificate
ctx_proc = -> ctx {
# Unset values set by start_server
ctx.cert = ctx.key = ctx.extra_chain_cert = nil
ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA
}
start_server(ctx_proc: ctx_proc) do |port|
server_connect(port) { |ssl|
assert_equal @svr_cert.subject, ssl.peer_cert.subject
assert_equal [@svr_cert.subject, @ca_cert.subject],
ssl.peer_cert_chain.map(&:subject)
}
end
end
def test_add_certificate_multiple_certs
pend "EC is not supported" unless defined?(OpenSSL::PKey::EC)
pend "TLS 1.2 is not supported" unless tls12_supported?
# SSL_CTX_set0_chain() is needed for setting multiple certificate chains
add0_chain_supported = openssl?(1, 0, 2)
if add0_chain_supported
ca2_key = Fixtures.pkey("rsa1024")
ca2_exts = [
["basicConstraints", "CA:TRUE", true],
["keyUsage", "cRLSign, keyCertSign", true],
]
ca2_dn = OpenSSL::X509::Name.parse_rfc2253("CN=CA2")
ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil)
else
# Use the same CA as @svr_cert
ca2_key = @ca_key; ca2_cert = @ca_cert
end
ecdsa_key = Fixtures.pkey("p256")
exts = [
["keyUsage", "digitalSignature", false],
]
ecdsa_dn = OpenSSL::X509::Name.parse_rfc2253("CN=localhost2")
ecdsa_cert = issue_cert(ecdsa_dn, ecdsa_key, 456, exts, ca2_cert, ca2_key)
if !add0_chain_supported
# Testing the warning emitted when 'extra' chain is replaced
tctx = OpenSSL::SSL::SSLContext.new
tctx.add_certificate(@svr_cert, @svr_key, [@ca_cert])
assert_warning(/set0_chain/) {
tctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert])
}
end
ctx_proc = -> ctx {
# Unset values set by start_server
ctx.cert = ctx.key = ctx.extra_chain_cert = nil
ctx.ecdh_curves = "P-256" unless openssl?(1, 0, 2)
ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA
EnvUtil.suppress_warning do # !add0_chain_supported
ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert])
end
}
start_server(ctx_proc: ctx_proc) do |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.max_version = :TLS1_2 # TODO: We need this to force certificate type
ctx.ciphers = "aECDSA"
server_connect(port, ctx) { |ssl|
assert_equal ecdsa_cert.subject, ssl.peer_cert.subject
assert_equal [ecdsa_cert.subject, ca2_cert.subject],
ssl.peer_cert_chain.map(&:subject)
}
ctx = OpenSSL::SSL::SSLContext.new
ctx.max_version = :TLS1_2
ctx.ciphers = "aRSA"
server_connect(port, ctx) { |ssl|
assert_equal @svr_cert.subject, ssl.peer_cert.subject
assert_equal [@svr_cert.subject, @ca_cert.subject],
ssl.peer_cert_chain.map(&:subject)
}
end
end
def test_sysread_and_syswrite def test_sysread_and_syswrite
start_server { |port| start_server { |port|
server_connect(port) { |ssl| server_connect(port) { |ssl|
@ -1222,6 +1303,59 @@ end
end end
end end
def test_fallback_scsv
pend "Fallback SCSV is not supported" unless OpenSSL::SSL::SSLContext.method_defined?( :enable_fallback_scsv)
start_server do |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
# Here is OK
# TLS1.2 supported and this is what we ask the first time
server_connect(port, ctx)
end
ctx_proc = proc { |ctx|
ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION
}
start_server(ctx_proc: ctx_proc) do |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.enable_fallback_scsv
ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION
# Here is OK too
# TLS1.2 not supported, fallback to TLS1.1 and signaling the fallback
# Server doesn't support better, so connection OK
server_connect(port, ctx)
end
# Here is not OK
# TLS1.2 is supported, fallback to TLS1.1 (downgrade attack) and signaling the fallback
# Server support better, so refuse the connection
sock1, sock2 = socketpair
begin
ctx1 = OpenSSL::SSL::SSLContext.new
s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.enable_fallback_scsv
ctx2.max_version = OpenSSL::SSL::TLS1_1_VERSION
s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
t = Thread.new {
assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) {
s2.connect
}
}
assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) {
s1.accept
}
assert t.join
ensure
sock1.close
sock2.close
end
end
def test_dh_callback def test_dh_callback
pend "TLS 1.2 is not supported" unless tls12_supported? pend "TLS 1.2 is not supported" unless tls12_supported?
@ -1336,11 +1470,24 @@ end
return return
end end
assert_equal(1, ctx.security_level) assert_equal(1, ctx.security_level)
# assert_raise(OpenSSL::SSL::SSLError) { ctx.key = Fixtures.pkey("dsa512") }
# ctx.key = Fixtures.pkey("rsa1024") dsa512 = Fixtures.pkey("dsa512")
# ctx.security_level = 2 dsa512_cert = issue_cert(@svr, dsa512, 50, [], @ca_cert, @ca_key)
# assert_raise(OpenSSL::SSL::SSLError) { ctx.key = Fixtures.pkey("rsa1024") } rsa1024 = Fixtures.pkey("rsa1024")
pend "FIXME: SSLContext#key= currently does not raise because SSL_CTX_use_certificate() is delayed" rsa1024_cert = issue_cert(@svr, rsa1024, 51, [], @ca_cert, @ca_key)
assert_raise(OpenSSL::SSL::SSLError) {
# 512 bit DSA key is rejected because it offers < 80 bits of security
ctx.add_certificate(dsa512_cert, dsa512)
}
assert_nothing_raised {
ctx.add_certificate(rsa1024_cert, rsa1024)
}
ctx.security_level = 2
assert_raise(OpenSSL::SSL::SSLError) {
# < 112 bits of security
ctx.add_certificate(rsa1024_cert, rsa1024)
}
end end
def test_dup def test_dup

View file

@ -62,6 +62,23 @@ class OpenSSL::TestX509Attribute < OpenSSL::TestCase
attr = OpenSSL::X509::Attribute.new("challengePassword", val) attr = OpenSSL::X509::Attribute.new("challengePassword", val)
assert_equal(attr.to_der, attr.dup.to_der) assert_equal(attr.to_der, attr.dup.to_der)
end end
def test_eq
val1 = OpenSSL::ASN1::Set([
OpenSSL::ASN1::UTF8String("abc123")
])
attr1 = OpenSSL::X509::Attribute.new("challengePassword", val1)
attr2 = OpenSSL::X509::Attribute.new("challengePassword", val1)
ef = OpenSSL::X509::ExtensionFactory.new
val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([
ef.create_extension("keyUsage", "keyCertSign", true)
])])
attr3 = OpenSSL::X509::Attribute.new("extReq", val2)
assert_equal false, attr1 == 12345
assert_equal true, attr1 == attr2
assert_equal false, attr1 == attr3
end
end end
end end

View file

@ -169,6 +169,26 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
} }
end end
def test_eq
now = Time.now
cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil,
not_before: now, not_after: now + 3600)
cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024,
not_before: now, not_after: now + 3600)
cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024,
not_before: now, not_after: now + 3600)
cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024,
not_before: now, not_after: now + 3600)
cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024,
digest: "sha512", not_before: now, not_after: now + 3600)
assert_equal false, cert1 == 12345
assert_equal true, cert1 == cert2
assert_equal false, cert1 == cert3
assert_equal false, cert1 == cert4
assert_equal false, cert3 == cert4
end
private private
def certificate_error_returns_false def certificate_error_returns_false

View file

@ -197,6 +197,58 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
assert_equal(false, crl.verify(@dsa512)) assert_equal(false, crl.verify(@dsa512))
end end
def test_revoked_to_der
# revokedCertificates SEQUENCE OF SEQUENCE {
# userCertificate CertificateSerialNumber,
# revocationDate Time,
# crlEntryExtensions Extensions OPTIONAL
# -- if present, version MUST be v2
# } OPTIONAL,
now = Time.utc(2000, 1, 1)
rev1 = OpenSSL::X509::Revoked.new
rev1.serial = 123
rev1.time = now
ext = OpenSSL::X509::Extension.new("CRLReason", OpenSSL::ASN1::Enumerated(1))
rev1.extensions = [ext]
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(123),
OpenSSL::ASN1::UTCTime(now),
OpenSSL::ASN1::Sequence([ext.to_der])
])
assert_equal asn1.to_der, rev1.to_der
end
def test_eq
now = Time.now
cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil)
crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256")
rev1 = OpenSSL::X509::Revoked.new.tap { |rev|
rev.serial = 1
rev.time = now
}
crl1.add_revoked(rev1)
crl2 = OpenSSL::X509::CRL.new(crl1.to_der)
# CRL
assert_equal false, crl1 == 12345
assert_equal true, crl1 == crl2
rev2 = OpenSSL::X509::Revoked.new.tap { |rev|
rev.serial = 2
rev.time = now
}
crl2.add_revoked(rev2)
assert_equal false, crl1 == crl2
# Revoked
assert_equal false, rev1 == 12345
assert_equal true, rev1 == crl2.revoked[0]
assert_equal false, rev1 == crl2.revoked[1]
assert_equal true, rev2 == crl2.revoked[1]
end
private private
def crl_error_returns_false def crl_error_returns_false

View file

@ -75,6 +75,17 @@ class OpenSSL::TestX509Extension < OpenSSL::TestCase
assert_equal(@basic_constraints.to_der, ext.to_der) assert_equal(@basic_constraints.to_der, ext.to_der)
assert_equal(ext.to_der, ext.dup.to_der) assert_equal(ext.to_der, ext.dup.to_der)
end end
def test_eq
ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der)
ef = OpenSSL::X509::ExtensionFactory.new
ext2 = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2")
ext3 = ef.create_extension("basicConstraints", "critical, CA:TRUE")
assert_equal false, ext1 == 12345
assert_equal true, ext1 == ext2
assert_equal false, ext1 == ext3
end
end end
end end

View file

@ -141,6 +141,16 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
assert_equal(req.to_der, req.dup.to_der) assert_equal(req.to_der, req.dup.to_der)
end end
def test_eq
req1 = issue_csr(0, @dn, @rsa1024, "sha1")
req2 = issue_csr(0, @dn, @rsa1024, "sha1")
req3 = issue_csr(0, @dn, @rsa1024, "sha256")
assert_equal false, req1 == 12345
assert_equal true, req1 == req2
assert_equal false, req1 == req3
end
private private
def request_error_returns_false def request_error_returns_false

View file

@ -67,7 +67,7 @@ module OpenSSL::TestUtils
cert.serial = serial cert.serial = serial
cert.subject = dn cert.subject = dn
cert.issuer = issuer.subject cert.issuer = issuer.subject
cert.public_key = key.public_key cert.public_key = key
now = Time.now now = Time.now
cert.not_before = not_before || now - 3600 cert.not_before = not_before || now - 3600
cert.not_after = not_after || now + 3600 cert.not_after = not_after || now + 3600