Created
April 17, 2024 13:06
-
-
Save eloyesp/b9d4e66be6b3df4217c3e6ff141e88ce to your computer and use it in GitHub Desktop.
Patch for Ruby v2.3.8 with compatibility with OpenSSL 1.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/ext/openssl/History.md b/ext/openssl/History.md | |
new file mode 100644 | |
index 0000000000..029426fb8c | |
--- /dev/null | |
+++ b/ext/openssl/History.md | |
@@ -0,0 +1,137 @@ | |
+Version 2.0.0 | |
+============= | |
+ | |
+This is the first release of openssl gem, formerly a standard library of Ruby, | |
+ext/openssl. This is the successor of the version included in Ruby 2.3. | |
+ | |
+Compatibility notes | |
+------------------- | |
+ | |
+* Support for OpenSSL version 0.9.6 and 0.9.7 is completely removed. openssl gem | |
+ still works with OpenSSL 0.9.8, but users are strongly encouraged to upgrade | |
+ to at least 1.0.1, as OpenSSL < 1.0.1 will not receive any security fixes from | |
+ the OpenSSL development team. | |
+ | |
+Supported platforms | |
+------------------- | |
+ | |
+* OpenSSL 1.0.0, 1.0.1, 1.0.2, 1.1.0 | |
+* OpenSSL < 0.9.8 is no longer supported. | |
+* LibreSSL 2.3, 2.4, 2.5 | |
+* Ruby 2.3, 2.4 | |
+ | |
+Notable changes | |
+--------------- | |
+ | |
+* Add support for OpenSSL 1.1.0. [[Feature #12324]](https://bugs.ruby-lang.org/issues/12324) | |
+* Add support for LibreSSL | |
+ | |
+* OpenSSL::Cipher | |
+ | |
+ - OpenSSL::Cipher#key= and #iv= reject too long inputs. They used to truncate | |
+ silently. [[Bug #12561]](https://bugs.ruby-lang.org/issues/12561) | |
+ | |
+ - OpenSSL::Cipher#iv_len= is added. It allows changing IV (nonce) length if | |
+ using AEAD ciphers. | |
+ [[Bug #8667]](https://bugs.ruby-lang.org/issues/8667), | |
+ [[Bug #10420]](https://bugs.ruby-lang.org/issues/10420), | |
+ [[GH ruby/ruby#569]](https://github.com/ruby/ruby/pull/569), | |
+ [[GH ruby/openssl#58]](https://github.com/ruby/openssl/pull/58) | |
+ | |
+ - OpenSSL::Cipher#auth_tag_len= is added. This sets the authentication tag | |
+ length to be generated by an AEAD cipher. | |
+ | |
+* OpenSSL::OCSP | |
+ | |
+ - Accessor methods are added to OpenSSL::OCSP::CertificateId. | |
+ [[Feature #7181]](https://bugs.ruby-lang.org/issues/7181) | |
+ | |
+ - OpenSSL::OCSP::Request and BasicResponse can be signed with non-SHA-1 hash | |
+ algorithm. [[Feature #11552]](https://bugs.ruby-lang.org/issues/11552) | |
+ | |
+ - OpenSSL::OCSP::CertificateId and BasicResponse can be encoded into DER. | |
+ | |
+ - A new class OpenSSL::OCSP::SingleResponse is added for convenience. | |
+ | |
+ - OpenSSL::OCSP::BasicResponse#add_status accepts absolute times. They used to | |
+ accept only relative seconds from the current time. | |
+ | |
+* OpenSSL::PKey | |
+ | |
+ - OpenSSL::PKey::EC follows the general PKey interface. | |
+ [[Bug #6567]](https://bugs.ruby-lang.org/issues/6567) | |
+ | |
+ - OpenSSL::PKey.read raises OpenSSL::PKey::PKeyError instead of ArgumentError | |
+ for consistency with OpenSSL::PKey::{DH,DSA,RSA,EC}#new. | |
+ [[Bug #11774]](https://bugs.ruby-lang.org/issues/11774), | |
+ [[GH ruby/openssl#55]](https://github.com/ruby/openssl/pull/55) | |
+ | |
+ - OpenSSL::PKey::EC::Group retrieved by OpenSSL::PKey::EC#group is no longer | |
+ linked with the EC key. Modifications to the EC::Group have no effect on the | |
+ key. [[GH ruby/openssl#71]](https://github.com/ruby/openssl/pull/71) | |
+ | |
+ - OpenSSL::PKey::EC::Point#to_bn allows specifying the point conversion form | |
+ by the optional argument. | |
+ | |
+* OpenSSL::SSL | |
+ | |
+ - OpenSSL::SSL::SSLSocket#tmp_key is added. A client can call it after the | |
+ connection is established to retrieve the ephemeral key. | |
+ [[GH ruby/ruby#1318]](https://github.com/ruby/ruby/pull/1318) | |
+ | |
+ - The automatic ephemeral ECDH curve selection is enabled by default when | |
+ built with OpenSSL >= 1.0.2 or LibreSSL. | |
+ | |
+ - OpenSSL::SSL::SSLContext#security_level= is added. You can set the "security | |
+ level" of the SSL context. This is effective only when built with OpenSSL | |
+ 1.1.0. | |
+ | |
+ - 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. | |
+ [[GH ruby/openssl#60]](https://github.com/ruby/openssl/pull/60) | |
+ | |
+Removals | |
+-------- | |
+ | |
+* OpenSSL::Engine | |
+ | |
+ - OpenSSL::Engine.cleanup does nothing when built with OpenSSL 1.1.0. | |
+ | |
+* OpenSSL::SSL | |
+ | |
+ - OpenSSL::PKey::DH::DEFAULT_512 is removed. Hence servers no longer use | |
+ 512-bit DH group by default. It is considered too weak nowadays. | |
+ [[Bug #11968]](https://bugs.ruby-lang.org/issues/11968), | |
+ [[GH ruby/ruby#1196]](https://github.com/ruby/ruby/pull/1196) | |
+ | |
+ - RC4 cipher suites are removed from OpenSSL::SSL::SSLContext::DEFAULT_PARAMS. | |
+ RC4 is now considered to be weak. | |
+ [[GH ruby/openssl#50]](https://github.com/ruby/openssl/pull/50) | |
+ | |
+Deprecations | |
+------------ | |
+ | |
+* OpenSSL::PKey | |
+ | |
+ - OpenSSL::PKey::RSA#n=, #e=, #d=, #p=, #q=, #dmp1=, #dmq1=, #iqmp=, | |
+ OpenSSL::PKey::DSA#p=, #q=, #g=, #priv_key=, #pub_key=, | |
+ OpenSSL::PKey::DH#p=, #g=, #priv_key= and #pub_key= are deprecated. They are | |
+ disabled when built with OpenSSL 1.1.0, due to its API change. Instead, | |
+ OpenSSL::PKey::RSA#set_key, #set_factors, #set_crt_params, | |
+ OpenSSL::PKey::DSA#set_pqg, #set_key, OpenSSL::PKey::DH#set_pqg and #set_key | |
+ are added. | |
+ | |
+* OpenSSL::Random | |
+ | |
+ - OpenSSL::Random.pseudo_bytes is deprecated, and not defined when built with | |
+ OpenSSL 1.1.0. Use OpenSSL::Random.random_bytes instead. | |
+ | |
+* OpenSSL::SSL | |
+ | |
+ - OpenSSL::SSL::SSLContext#tmp_ecdh_callback is deprecated, as the underlying | |
+ API SSL_CTX_set_tmp_ecdh_callback() is removed in OpenSSL 1.1.0. It was | |
+ first added in Ruby 2.3.0. To specify the curve to be used in ephemeral | |
+ ECDH, use OpenSSL::SSL::SSLContext#ecdh_curves=. The automatic curve | |
+ selection is also now enabled by default when built with a capable OpenSSL. | |
diff --git a/ext/openssl/deprecation.rb b/ext/openssl/deprecation.rb | |
index d77353678a..7dfc87c1c6 100644 | |
--- a/ext/openssl/deprecation.rb | |
+++ b/ext/openssl/deprecation.rb | |
@@ -16,7 +16,11 @@ def self.deprecated_warning_flag | |
end | |
def self.check_func(func, header) | |
- have_func(func, header, deprecated_warning_flag) and | |
- have_header(header, nil, deprecated_warning_flag) | |
+ have_func(func, header, deprecated_warning_flag) | |
+ end | |
+ | |
+ def self.check_func_or_macro(func, header) | |
+ check_func(func, header) or | |
+ have_macro(func, header) && $defs.push("-DHAVE_#{func.upcase}") | |
end | |
end | |
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb | |
index 0b7fa2aaf9..60132b352f 100644 | |
--- a/ext/openssl/extconf.rb | |
+++ b/ext/openssl/extconf.rb | |
@@ -19,31 +19,27 @@ | |
Logging::message "=== OpenSSL for Ruby configurator ===\n" | |
+# Add -Werror=deprecated-declarations to $warnflags if available | |
+OpenSSL.deprecated_warning_flag | |
+ | |
## | |
# Adds -DOSSL_DEBUG for compilation and some more targets when GCC is used | |
# To turn it on, use: --with-debug or --enable-debug | |
# | |
if with_config("debug") or enable_config("debug") | |
- $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG" | |
+ $defs.push("-DOSSL_DEBUG") | |
end | |
Logging::message "=== Checking for system dependent stuff... ===\n" | |
have_library("nsl", "t_open") | |
have_library("socket", "socket") | |
-have_header("assert.h") | |
Logging::message "=== Checking for required stuff... ===\n" | |
-if $mingw | |
- have_library("wsock32") | |
- have_library("gdi32") | |
-end | |
- | |
result = pkg_config("openssl") && have_header("openssl/ssl.h") | |
- | |
unless result | |
result = have_header("openssl/ssl.h") | |
- result &&= %w[crypto libeay32].any? {|lib| have_library(lib, "OpenSSL_add_all_digests")} | |
- result &&= %w[ssl ssleay32].any? {|lib| have_library(lib, "SSL_library_init")} | |
+ result &&= %w[crypto libeay32].any? {|lib| have_library(lib, "CRYPTO_malloc")} | |
+ result &&= %w[ssl ssleay32].any? {|lib| have_library(lib, "SSL_new")} | |
unless result | |
Logging::message "=== Checking for required stuff failed. ===\n" | |
Logging::message "Makefile wasn't created. Fix the errors above.\n" | |
@@ -51,111 +47,105 @@ | |
end | |
end | |
-unless have_header("openssl/conf_api.h") | |
- raise "OpenSSL 0.9.6 or later required." | |
+result = checking_for("OpenSSL version is 0.9.8 or later") { | |
+ try_static_assert("OPENSSL_VERSION_NUMBER >= 0x00908000L", "openssl/opensslv.h") | |
+} | |
+unless result | |
+ raise "OpenSSL 0.9.8 or later required." | |
end | |
+ | |
unless OpenSSL.check_func("SSL_library_init()", "openssl/ssl.h") | |
raise "Ignore OpenSSL broken by Apple.\nPlease use another openssl. (e.g. using `configure --with-openssl-dir=/path/to/openssl')" | |
end | |
Logging::message "=== Checking for OpenSSL features... ===\n" | |
-have_func("ERR_peek_last_error") | |
-have_func("ASN1_put_eoc") | |
-have_func("BN_mod_add") | |
-have_func("BN_mod_sqr") | |
-have_func("BN_mod_sub") | |
-have_func("BN_pseudo_rand_range") | |
-have_func("BN_rand_range") | |
-have_func("CONF_get1_default_config_file") | |
+# compile options | |
+ | |
+# check OPENSSL_NO_{SSL2,SSL3_METHOD} macro: on some environment, these symbols | |
+# exist even if compiled with no-ssl2 or no-ssl3-method. | |
+unless have_macro("OPENSSL_NO_SSL2", "openssl/opensslconf.h") | |
+ have_func("SSLv2_method") | |
+end | |
+unless have_macro("OPENSSL_NO_SSL3_METHOD", "openssl/opensslconf.h") | |
+ have_func("SSLv3_method") | |
+end | |
+have_func("TLSv1_1_method") | |
+have_func("TLSv1_2_method") | |
+have_func("RAND_egd") | |
+engines = %w{builtin_engines openbsd_dev_crypto dynamic 4758cca aep atalla chil | |
+ cswift nuron sureware ubsec padlock capi gmp gost cryptodev aesni} | |
+engines.each { |name| | |
+ OpenSSL.check_func_or_macro("ENGINE_load_#{name}", "openssl/engine.h") | |
+} | |
+ | |
+# added in 0.9.8X | |
+have_func("EVP_CIPHER_CTX_new") | |
+have_func("EVP_CIPHER_CTX_free") | |
+ | |
+# added in 1.0.0 | |
+have_func("ASN1_TIME_adj") | |
have_func("EVP_CIPHER_CTX_copy") | |
-have_func("EVP_CIPHER_CTX_set_padding") | |
-have_func("EVP_CipherFinal_ex") | |
-have_func("EVP_CipherInit_ex") | |
-have_func("EVP_DigestFinal_ex") | |
-have_func("EVP_DigestInit_ex") | |
-have_func("EVP_MD_CTX_cleanup") | |
-have_func("EVP_MD_CTX_create") | |
-have_func("EVP_MD_CTX_destroy") | |
-have_func("EVP_MD_CTX_init") | |
-have_func("HMAC_CTX_cleanup") | |
+have_func("EVP_PKEY_base_id") | |
have_func("HMAC_CTX_copy") | |
-have_func("HMAC_CTX_init") | |
-have_func("PEM_def_callback") | |
have_func("PKCS5_PBKDF2_HMAC") | |
-have_func("PKCS5_PBKDF2_HMAC_SHA1") | |
-have_func("RAND_egd") | |
-have_func("X509V3_set_nconf") | |
-have_func("X509V3_EXT_nconf_nid") | |
-have_func("X509_CRL_add0_revoked") | |
-have_func("X509_CRL_set_issuer_name") | |
-have_func("X509_CRL_set_version") | |
-have_func("X509_CRL_sort") | |
have_func("X509_NAME_hash_old") | |
-have_func("X509_STORE_get_ex_data") | |
-have_func("X509_STORE_set_ex_data") | |
-have_func("OBJ_NAME_do_all_sorted") | |
-have_func("SSL_SESSION_get_id") | |
-have_func("SSL_SESSION_cmp") | |
-have_func("OPENSSL_cleanse") | |
-have_func("SSLv2_method") | |
-have_func("SSLv2_server_method") | |
-have_func("SSLv2_client_method") | |
-have_func("SSLv3_method") | |
-have_func("SSLv3_server_method") | |
-have_func("SSLv3_client_method") | |
-have_func("TLSv1_1_method") | |
-have_func("TLSv1_1_server_method") | |
-have_func("TLSv1_1_client_method") | |
-have_func("TLSv1_2_method") | |
-have_func("TLSv1_2_server_method") | |
-have_func("TLSv1_2_client_method") | |
-have_func("SSL_CTX_set_alpn_select_cb") | |
-have_func("SSL_CTX_set_next_proto_select_cb") | |
-unless have_func("SSL_set_tlsext_host_name", ['openssl/ssl.h']) | |
- have_macro("SSL_set_tlsext_host_name", ['openssl/ssl.h']) && $defs.push("-DHAVE_SSL_SET_TLSEXT_HOST_NAME") | |
-end | |
-if have_header("openssl/engine.h") | |
- have_func("ENGINE_add") | |
- have_func("ENGINE_load_builtin_engines") | |
- have_func("ENGINE_load_openbsd_dev_crypto") | |
- have_func("ENGINE_get_digest") | |
- have_func("ENGINE_get_cipher") | |
- have_func("ENGINE_cleanup") | |
- have_func("ENGINE_load_dynamic") | |
- have_func("ENGINE_load_4758cca") | |
- have_func("ENGINE_load_aep") | |
- have_func("ENGINE_load_atalla") | |
- have_func("ENGINE_load_chil") | |
- have_func("ENGINE_load_cswift") | |
- have_func("ENGINE_load_nuron") | |
- have_func("ENGINE_load_sureware") | |
- have_func("ENGINE_load_ubsec") | |
- have_func("ENGINE_load_padlock") | |
- have_func("ENGINE_load_capi") | |
- have_func("ENGINE_load_gmp") | |
- have_func("ENGINE_load_gost") | |
- have_func("ENGINE_load_cryptodev") | |
- have_func("ENGINE_load_aesni") | |
-end | |
-have_func("DH_generate_parameters_ex") | |
-have_func("DSA_generate_parameters_ex") | |
-have_func("RSA_generate_key_ex") | |
-if checking_for('OpenSSL version is 0.9.7 or later') { | |
- try_static_assert('OPENSSL_VERSION_NUMBER >= 0x00907000L', 'openssl/opensslv.h') | |
- } | |
- have_header("openssl/ocsp.h") | |
-end | |
+have_func("X509_STORE_CTX_get0_current_crl") | |
+have_func("X509_STORE_set_verify_cb") | |
+have_func("i2d_ASN1_SET_ANY") | |
+have_func("SSL_SESSION_cmp") # removed | |
+OpenSSL.check_func_or_macro("SSL_set_tlsext_host_name", "openssl/ssl.h") | |
have_struct_member("CRYPTO_THREADID", "ptr", "openssl/crypto.h") | |
-have_struct_member("EVP_CIPHER_CTX", "flags", "openssl/evp.h") | |
-have_struct_member("EVP_CIPHER_CTX", "engine", "openssl/evp.h") | |
-have_struct_member("X509_ATTRIBUTE", "single", "openssl/x509.h") | |
-have_macro("OPENSSL_FIPS", ['openssl/opensslconf.h']) && $defs.push("-DHAVE_OPENSSL_FIPS") | |
+have_func("EVP_PKEY_get0") | |
+ | |
+# added in 1.0.1 | |
+have_func("SSL_CTX_set_next_proto_select_cb") | |
have_macro("EVP_CTRL_GCM_GET_TAG", ['openssl/evp.h']) && $defs.push("-DHAVE_AUTHENTICATED_ENCRYPTION") | |
+# added in 1.0.2 | |
+have_func("EC_curve_nist2nid") | |
+have_func("X509_REVOKED_dup") | |
+have_func("X509_STORE_CTX_get0_store") | |
+have_func("SSL_CTX_set_alpn_select_cb") | |
+OpenSSL.check_func_or_macro("SSL_CTX_set1_curves_list", "openssl/ssl.h") | |
+OpenSSL.check_func_or_macro("SSL_CTX_set_ecdh_auto", "openssl/ssl.h") | |
+OpenSSL.check_func_or_macro("SSL_get_server_tmp_key", "openssl/ssl.h") | |
+have_func("SSL_is_server") | |
+ | |
+# added in 1.1.0 | |
+have_func("CRYPTO_lock") || $defs.push("-DHAVE_OPENSSL_110_THREADING_API") | |
+have_struct_member("SSL", "ctx", "openssl/ssl.h") || $defs.push("-DHAVE_OPAQUE_OPENSSL") | |
+have_func("BN_GENCB_new") | |
+have_func("BN_GENCB_free") | |
+have_func("BN_GENCB_get_arg") | |
+have_func("EVP_MD_CTX_new") | |
+have_func("EVP_MD_CTX_free") | |
+have_func("HMAC_CTX_new") | |
+have_func("HMAC_CTX_free") | |
+OpenSSL.check_func("RAND_pseudo_bytes", "openssl/rand.h") # deprecated | |
+have_func("X509_STORE_get_ex_data") | |
+have_func("X509_STORE_set_ex_data") | |
+have_func("X509_CRL_get0_signature") | |
+have_func("X509_REQ_get0_signature") | |
+have_func("X509_REVOKED_get0_serialNumber") | |
+have_func("X509_REVOKED_get0_revocationDate") | |
+have_func("X509_get0_tbs_sigalg") | |
+have_func("X509_STORE_CTX_get0_untrusted") | |
+have_func("X509_STORE_CTX_get0_cert") | |
+have_func("X509_STORE_CTX_get0_chain") | |
+have_func("OCSP_SINGLERESP_get0_id") | |
+have_func("SSL_CTX_get_ciphers") | |
+have_func("X509_up_ref") | |
+have_func("X509_CRL_up_ref") | |
+have_func("X509_STORE_up_ref") | |
+have_func("SSL_SESSION_up_ref") | |
+have_func("EVP_PKEY_up_ref") | |
+OpenSSL.check_func_or_macro("SSL_CTX_set_tmp_ecdh_callback", "openssl/ssl.h") # removed | |
+OpenSSL.check_func_or_macro("SSL_CTX_set_min_proto_version", "openssl/ssl.h") | |
+have_func("SSL_CTX_get_security_level") | |
+have_func("X509_get0_notBefore") | |
+ | |
Logging::message "=== Checking done. ===\n" | |
create_header | |
-create_makefile("openssl") {|conf| | |
- conf << "THREAD_MODEL = #{CONFIG["THREAD_MODEL"]}\n" | |
-} | |
+create_makefile("openssl") | |
Logging::message "Done.\n" | |
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb | |
index d082199000..7fd647caad 100644 | |
--- a/ext/openssl/lib/openssl/buffering.rb | |
+++ b/ext/openssl/lib/openssl/buffering.rb | |
@@ -132,7 +132,6 @@ def readpartial(maxlen, buf=nil) | |
buf.replace(ret) | |
ret = buf | |
end | |
- raise EOFError if ret.empty? | |
ret | |
end | |
@@ -164,6 +163,10 @@ def readpartial(maxlen, buf=nil) | |
# Note that one reason that read_nonblock writes to the underlying IO is | |
# when the peer requests a new TLS/SSL handshake. See openssl the FAQ for | |
# more details. http://www.openssl.org/support/faq.html | |
+ # | |
+ # By specifying `exception: false`, the options hash allows you to indicate | |
+ # that read_nonblock should not raise an IO::Wait*able exception, but | |
+ # return the symbol :wait_writable or :wait_readable instead. | |
def read_nonblock(maxlen, buf=nil, exception: true) | |
if maxlen == 0 | |
@@ -182,7 +185,6 @@ def read_nonblock(maxlen, buf=nil, exception: true) | |
buf.replace(ret) | |
ret = buf | |
end | |
- raise EOFError if ret.empty? | |
ret | |
end | |
@@ -373,6 +375,10 @@ def write(s) | |
# Note that one reason that write_nonblock reads from the underlying IO | |
# is when the peer requests a new TLS/SSL handshake. See the openssl FAQ | |
# for more details. http://www.openssl.org/support/faq.html | |
+ # | |
+ # By specifying `exception: false`, the options hash allows you to indicate | |
+ # that write_nonblock should not raise an IO::Wait*able exception, but | |
+ # return the symbol :wait_writable or :wait_readable instead. | |
def write_nonblock(s, exception: true) | |
flush | |
@@ -383,7 +389,7 @@ def write_nonblock(s, exception: true) | |
# Writes +s+ to the stream. +s+ will be converted to a String using | |
# String#to_s. | |
- def << (s) | |
+ def <<(s) | |
do_write(s) | |
self | |
end | |
diff --git a/ext/openssl/lib/openssl/cipher.rb b/ext/openssl/lib/openssl/cipher.rb | |
index a69d5ac827..af721b3a80 100644 | |
--- a/ext/openssl/lib/openssl/cipher.rb | |
+++ b/ext/openssl/lib/openssl/cipher.rb | |
@@ -18,7 +18,7 @@ class Cipher | |
klass = Class.new(Cipher){ | |
define_method(:initialize){|*args| | |
cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } | |
- super(cipher_name) | |
+ super(cipher_name.downcase) | |
} | |
} | |
const_set(name, klass) | |
@@ -26,34 +26,42 @@ class Cipher | |
%w(128 192 256).each{|keylen| | |
klass = Class.new(Cipher){ | |
- define_method(:initialize){|mode| | |
- mode ||= "CBC" | |
- cipher_name = "AES-#{keylen}-#{mode}" | |
- super(cipher_name) | |
+ define_method(:initialize){|mode = "CBC"| | |
+ super("aes-#{keylen}-#{mode}".downcase) | |
} | |
} | |
const_set("AES#{keylen}", klass) | |
} | |
- # Generate, set, and return a random key. | |
- # You must call cipher.encrypt or cipher.decrypt before calling this method. | |
+ # call-seq: | |
+ # cipher.random_key -> key | |
+ # | |
+ # Generate a random key with OpenSSL::Random.random_bytes and sets it to | |
+ # the cipher, and returns it. | |
+ # | |
+ # You must call #encrypt or #decrypt before calling this method. | |
def random_key | |
str = OpenSSL::Random.random_bytes(self.key_len) | |
self.key = str | |
- return str | |
end | |
- # Generate, set, and return a random iv. | |
- # You must call cipher.encrypt or cipher.decrypt before calling this method. | |
+ # call-seq: | |
+ # cipher.random_iv -> iv | |
+ # | |
+ # Generate a random IV with OpenSSL::Random.random_bytes and sets it to the | |
+ # cipher, and returns it. | |
+ # | |
+ # You must call #encrypt or #decrypt before calling this method. | |
def random_iv | |
str = OpenSSL::Random.random_bytes(self.iv_len) | |
self.iv = str | |
- return str | |
end | |
- # This class is only provided for backwards compatibility. Use OpenSSL::Cipher in the future. | |
- class Cipher < Cipher | |
- # add warning | |
- end | |
+ # Deprecated. | |
+ # | |
+ # This class is only provided for backwards compatibility. | |
+ # Use OpenSSL::Cipher. | |
+ class Cipher < Cipher; end | |
+ deprecate_constant :Cipher | |
end # Cipher | |
end # OpenSSL | |
diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb | |
index 1240bf596b..97ccbc9569 100644 | |
--- a/ext/openssl/lib/openssl/digest.rb | |
+++ b/ext/openssl/lib/openssl/digest.rb | |
@@ -15,7 +15,10 @@ | |
module OpenSSL | |
class Digest | |
- alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) | |
+ alg = %w(MD2 MD4 MD5 MDC2 RIPEMD160 SHA1) | |
+ if OPENSSL_VERSION_NUMBER < 0x10100000 | |
+ alg += %w(DSS DSS1 SHA) | |
+ end | |
if OPENSSL_VERSION_NUMBER > 0x00908000 | |
alg += %w(SHA224 SHA256 SHA384 SHA512) | |
end | |
@@ -50,15 +53,9 @@ def self.digest(name, data) | |
# Deprecated. | |
# | |
# This class is only provided for backwards compatibility. | |
- class Digest < Digest # :nodoc: | |
- # Deprecated. | |
- # | |
- # See OpenSSL::Digest.new | |
- def initialize(*args) | |
- warn('Digest::Digest is deprecated; use Digest') | |
- super(*args) | |
- end | |
- end | |
+ # Use OpenSSL::Digest instead. | |
+ class Digest < Digest; end # :nodoc: | |
+ deprecate_constant :Digest | |
end # Digest | |
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb | |
index 3f65adadb5..9af5f781f9 100644 | |
--- a/ext/openssl/lib/openssl/pkey.rb | |
+++ b/ext/openssl/lib/openssl/pkey.rb | |
@@ -4,27 +4,34 @@ module PKey | |
if defined?(OpenSSL::PKey::DH) | |
class DH | |
- DEFAULT_512 = new <<-_end_of_pem_ | |
------BEGIN DH PARAMETERS----- | |
-MEYCQQD0zXHljRg/mJ9PYLACLv58Cd8VxBxxY7oEuCeURMiTqEhMym16rhhKgZG2 | |
-zk2O9uUIBIxSj+NKMURHGaFKyIvLAgEC | |
------END DH PARAMETERS----- | |
- _end_of_pem_ | |
- | |
+ # :nodoc: | |
DEFAULT_1024 = new <<-_end_of_pem_ | |
-----BEGIN DH PARAMETERS----- | |
MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ | |
AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR | |
T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC | |
+-----END DH PARAMETERS----- | |
+ _end_of_pem_ | |
+ | |
+ # :nodoc: | |
+ DEFAULT_2048 = new <<-_end_of_pem_ | |
+-----BEGIN DH PARAMETERS----- | |
+MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY | |
+JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab | |
+VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6 | |
+YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3 | |
+1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD | |
+7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg== | |
-----END DH PARAMETERS----- | |
_end_of_pem_ | |
end | |
+ # :nodoc: | |
DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| | |
warn "using default DH parameters." if $VERBOSE | |
case keylen | |
- when 512 then OpenSSL::PKey::DH::DEFAULT_512 | |
when 1024 then OpenSSL::PKey::DH::DEFAULT_1024 | |
+ when 2048 then OpenSSL::PKey::DH::DEFAULT_2048 | |
else | |
nil | |
end | |
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb | |
index 9893757011..f40a451439 100644 | |
--- a/ext/openssl/lib/openssl/ssl.rb | |
+++ b/ext/openssl/lib/openssl/ssl.rb | |
@@ -16,68 +16,60 @@ | |
module OpenSSL | |
module SSL | |
class SSLContext | |
- DEFAULT_PARAMS = { | |
+ DEFAULT_PARAMS = { # :nodoc: | |
:ssl_version => "SSLv23", | |
:verify_mode => OpenSSL::SSL::VERIFY_PEER, | |
- :ciphers => %w{ | |
- ECDHE-ECDSA-AES128-GCM-SHA256 | |
- ECDHE-RSA-AES128-GCM-SHA256 | |
- ECDHE-ECDSA-AES256-GCM-SHA384 | |
- ECDHE-RSA-AES256-GCM-SHA384 | |
- DHE-RSA-AES128-GCM-SHA256 | |
- DHE-DSS-AES128-GCM-SHA256 | |
- DHE-RSA-AES256-GCM-SHA384 | |
- DHE-DSS-AES256-GCM-SHA384 | |
- ECDHE-ECDSA-AES128-SHA256 | |
- ECDHE-RSA-AES128-SHA256 | |
- ECDHE-ECDSA-AES128-SHA | |
- ECDHE-RSA-AES128-SHA | |
- ECDHE-ECDSA-AES256-SHA384 | |
- ECDHE-RSA-AES256-SHA384 | |
- ECDHE-ECDSA-AES256-SHA | |
- ECDHE-RSA-AES256-SHA | |
- DHE-RSA-AES128-SHA256 | |
- DHE-RSA-AES256-SHA256 | |
- DHE-RSA-AES128-SHA | |
- DHE-RSA-AES256-SHA | |
- DHE-DSS-AES128-SHA256 | |
- DHE-DSS-AES256-SHA256 | |
- DHE-DSS-AES128-SHA | |
- DHE-DSS-AES256-SHA | |
- AES128-GCM-SHA256 | |
- AES256-GCM-SHA384 | |
- AES128-SHA256 | |
- AES256-SHA256 | |
- AES128-SHA | |
- AES256-SHA | |
- ECDHE-ECDSA-RC4-SHA | |
- ECDHE-RSA-RC4-SHA | |
- RC4-SHA | |
- }.join(":"), | |
+ :verify_hostname => true, | |
:options => -> { | |
opts = OpenSSL::SSL::OP_ALL | |
- opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS) | |
+ opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS | |
opts |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) | |
- opts |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2) | |
- opts |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3) | |
+ opts |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | |
opts | |
}.call | |
} | |
- DEFAULT_CERT_STORE = OpenSSL::X509::Store.new | |
- DEFAULT_CERT_STORE.set_default_paths | |
- if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL) | |
- DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL | |
+ if !(OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") && | |
+ OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000) | |
+ DEFAULT_PARAMS.merge!( | |
+ ciphers: %w{ | |
+ ECDHE-ECDSA-AES128-GCM-SHA256 | |
+ ECDHE-RSA-AES128-GCM-SHA256 | |
+ ECDHE-ECDSA-AES256-GCM-SHA384 | |
+ ECDHE-RSA-AES256-GCM-SHA384 | |
+ DHE-RSA-AES128-GCM-SHA256 | |
+ DHE-DSS-AES128-GCM-SHA256 | |
+ DHE-RSA-AES256-GCM-SHA384 | |
+ DHE-DSS-AES256-GCM-SHA384 | |
+ ECDHE-ECDSA-AES128-SHA256 | |
+ ECDHE-RSA-AES128-SHA256 | |
+ ECDHE-ECDSA-AES128-SHA | |
+ ECDHE-RSA-AES128-SHA | |
+ ECDHE-ECDSA-AES256-SHA384 | |
+ ECDHE-RSA-AES256-SHA384 | |
+ ECDHE-ECDSA-AES256-SHA | |
+ ECDHE-RSA-AES256-SHA | |
+ DHE-RSA-AES128-SHA256 | |
+ DHE-RSA-AES256-SHA256 | |
+ DHE-RSA-AES128-SHA | |
+ DHE-RSA-AES256-SHA | |
+ DHE-DSS-AES128-SHA256 | |
+ DHE-DSS-AES256-SHA256 | |
+ DHE-DSS-AES128-SHA | |
+ DHE-DSS-AES256-SHA | |
+ AES128-GCM-SHA256 | |
+ AES256-GCM-SHA384 | |
+ AES128-SHA256 | |
+ AES256-SHA256 | |
+ AES128-SHA | |
+ AES256-SHA | |
+ }.join(":"), | |
+ ) | |
end | |
- INIT_VARS = ["cert", "key", "client_ca", "ca_file", "ca_path", | |
- "timeout", "verify_mode", "verify_depth", "renegotiation_cb", | |
- "verify_callback", "cert_store", "extra_chain_cert", | |
- "client_cert_cb", "session_id_context", "tmp_dh_callback", | |
- "session_get_cb", "session_new_cb", "session_remove_cb", | |
- "tmp_ecdh_callback", "servername_cb", "npn_protocols", | |
- "alpn_protocols", "alpn_select_cb", | |
- "npn_select_cb"].map { |x| "@#{x}" } | |
+ DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc: | |
+ DEFAULT_CERT_STORE.set_default_paths | |
+ DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL | |
# A callback invoked when DH parameters are required. | |
# | |
@@ -90,14 +82,12 @@ class SSLContext | |
attr_accessor :tmp_dh_callback | |
- if ExtConfig::HAVE_TLSEXT_HOST_NAME | |
- # A callback invoked at connect time to distinguish between multiple | |
- # server names. | |
- # | |
- # The callback is invoked with an SSLSocket and a server name. The | |
- # callback must return an SSLContext for the server name or nil. | |
- attr_accessor :servername_cb | |
- end | |
+ # A callback invoked at connect time to distinguish between multiple | |
+ # server names. | |
+ # | |
+ # The callback is invoked with an SSLSocket and a server name. The | |
+ # callback must return an SSLContext for the server name or nil. | |
+ attr_accessor :servername_cb if ExtConfig::HAVE_TLSEXT_HOST_NAME | |
# call-seq: | |
# SSLContext.new => ctx | |
@@ -106,20 +96,22 @@ class SSLContext | |
# | |
# You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS | |
def initialize(version = nil) | |
- INIT_VARS.each { |v| instance_variable_set v, nil } | |
- self.options = self.options | OpenSSL::SSL::OP_ALL | |
- return unless version | |
- self.ssl_version = version | |
+ self.options |= OpenSSL::SSL::OP_ALL | |
+ self.ssl_version = version if version | |
end | |
## | |
- # Sets the parameters for this SSL context to the values in +params+. | |
+ # call-seq: | |
+ # ctx.set_params(params = {}) -> params | |
+ # | |
+ # Sets saner defaults optimized for the use with HTTP-like protocols. | |
+ # | |
+ # If a Hash +params+ is given, the parameters are overridden with it. | |
# The keys in +params+ must be assignment methods on SSLContext. | |
# | |
# If the verify_mode is not VERIFY_NONE and ca_file, ca_path and | |
# cert_store are not set then the system default certificate store is | |
# used. | |
- | |
def set_params(params={}) | |
params = DEFAULT_PARAMS.merge(params) | |
params.each{|name, value| self.__send__("#{name}=", value) } | |
@@ -250,43 +242,21 @@ class SSLSocket | |
include Buffering | |
include SocketForwarder | |
- if ExtConfig::OPENSSL_NO_SOCK | |
- def initialize(io, ctx = nil); raise NotImplementedError; end | |
- else | |
- if ExtConfig::HAVE_TLSEXT_HOST_NAME | |
- attr_accessor :hostname | |
- end | |
- | |
- attr_reader :io, :context | |
- attr_accessor :sync_close | |
- alias :to_io :io | |
- | |
- # call-seq: | |
- # SSLSocket.new(io) => aSSLSocket | |
- # SSLSocket.new(io, ctx) => aSSLSocket | |
- # | |
- # Creates a new SSL socket from +io+ which must be a real ruby object (not an | |
- # IO-like object that responds to read/write). | |
- # | |
- # If +ctx+ is provided the SSL Sockets initial params will be taken from | |
- # the context. | |
- # | |
- # The OpenSSL::Buffering module provides additional IO methods. | |
- # | |
- # This method will freeze the SSLContext if one is provided; | |
- # however, session management is still allowed in the frozen SSLContext. | |
- | |
- def initialize(io, context = OpenSSL::SSL::SSLContext.new) | |
- @io = io | |
- @context = context | |
- @sync_close = false | |
- @hostname = nil | |
- @io.nonblock = true if @io.respond_to?(:nonblock=) | |
- context.setup | |
- super() | |
- end | |
+ if ExtConfig::HAVE_TLSEXT_HOST_NAME | |
+ attr_reader :hostname | |
end | |
+ # The underlying IO object. | |
+ attr_reader :io | |
+ alias :to_io :io | |
+ | |
+ # The SSLContext object used in this connection. | |
+ attr_reader :context | |
+ | |
+ # Whether to close the underlying socket as well, when the SSL/TLS | |
+ # connection is shut down. This defaults to +false+. | |
+ attr_accessor :sync_close | |
+ | |
# call-seq: | |
# ssl.sysclose => nil | |
# | |
@@ -300,8 +270,10 @@ def sysclose | |
io.close if sync_close | |
end | |
- ## | |
- # Perform hostname verification after an SSL connection is established | |
+ # call-seq: | |
+ # ssl.post_connection_check(hostname) -> true | |
+ # | |
+ # Perform hostname verification following RFC 6125. | |
# | |
# This method MUST be called after calling #connect to ensure that the | |
# hostname of a remote peer has been verified. | |
@@ -309,7 +281,8 @@ def post_connection_check(hostname) | |
if peer_cert.nil? | |
msg = "Peer verification enabled, but no certificate received." | |
if using_anon_cipher? | |
- msg += " Anonymous cipher suite #{cipher[0]} was negotiated. Anonymous suites must be disabled to use peer verification." | |
+ msg += " Anonymous cipher suite #{cipher[0]} was negotiated. " \ | |
+ "Anonymous suites must be disabled to use peer verification." | |
end | |
raise SSLError, msg | |
end | |
@@ -320,6 +293,11 @@ def post_connection_check(hostname) | |
return true | |
end | |
+ # call-seq: | |
+ # ssl.session -> aSession | |
+ # | |
+ # Returns the SSLSession object currently used, or nil if the session is | |
+ # not established. | |
def session | |
SSL::Session.new(self) | |
rescue SSL::Session::SessionError | |
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec | |
new file mode 100644 | |
index 0000000000..e8fd20f94e | |
--- /dev/null | |
+++ b/ext/openssl/openssl.gemspec | |
@@ -0,0 +1,45 @@ | |
+# -*- encoding: utf-8 -*- | |
+# stub: openssl 2.0.1 ruby lib | |
+# stub: ext/openssl/extconf.rb | |
+ | |
+Gem::Specification.new do |s| | |
+ s.name = "openssl".freeze | |
+ s.version = "2.0.1" | |
+ | |
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= | |
+ s.require_paths = ["lib".freeze] | |
+ s.authors = ["Martin Bosslet".freeze, "SHIBATA Hiroshi".freeze, "Zachary Scott".freeze, "Kazuki Yamaguchi".freeze] | |
+ s.date = "2016-12-10" | |
+ s.description = "It wraps the OpenSSL library.".freeze | |
+ s.email = ["[email protected]".freeze] | |
+ s.extensions = ["ext/openssl/extconf.rb".freeze] | |
+ s.extra_rdoc_files = ["CONTRIBUTING.md".freeze, "README.md".freeze, "History.md".freeze] | |
+ s.files = ["BSDL".freeze, "CONTRIBUTING.md".freeze, "History.md".freeze, "LICENSE.txt".freeze, "README.md".freeze, "ext/openssl/deprecation.rb".freeze, "ext/openssl/extconf.rb".freeze, "ext/openssl/openssl_missing.c".freeze, "ext/openssl/openssl_missing.h".freeze, "ext/openssl/ossl.c".freeze, "ext/openssl/ossl.h".freeze, "ext/openssl/ossl_asn1.c".freeze, "ext/openssl/ossl_asn1.h".freeze, "ext/openssl/ossl_bio.c".freeze, "ext/openssl/ossl_bio.h".freeze, "ext/openssl/ossl_bn.c".freeze, "ext/openssl/ossl_bn.h".freeze, "ext/openssl/ossl_cipher.c".freeze, "ext/openssl/ossl_cipher.h".freeze, "ext/openssl/ossl_config.c".freeze, "ext/openssl/ossl_config.h".freeze, "ext/openssl/ossl_digest.c".freeze, "ext/openssl/ossl_digest.h".freeze, "ext/openssl/ossl_engine.c".freeze, "ext/openssl/ossl_engine.h".freeze, "ext/openssl/ossl_hmac.c".freeze, "ext/openssl/ossl_hmac.h".freeze, "ext/openssl/ossl_ns_spki.c".freeze, "ext/openssl/ossl_ns_spki.h".freeze, "ext/openssl/ossl_ocsp.c".freeze, "ext/openssl/ossl_ocsp.h".freeze, "ext/openssl/ossl_pkcs12.c".freeze, "ext/openssl/ossl_pkcs12.h".freeze, "ext/openssl/ossl_pkcs5.c".freeze, "ext/openssl/ossl_pkcs5.h".freeze, "ext/openssl/ossl_pkcs7.c".freeze, "ext/openssl/ossl_pkcs7.h".freeze, "ext/openssl/ossl_pkey.c".freeze, "ext/openssl/ossl_pkey.h".freeze, "ext/openssl/ossl_pkey_dh.c".freeze, "ext/openssl/ossl_pkey_dsa.c".freeze, "ext/openssl/ossl_pkey_ec.c".freeze, "ext/openssl/ossl_pkey_rsa.c".freeze, "ext/openssl/ossl_rand.c".freeze, "ext/openssl/ossl_rand.h".freeze, "ext/openssl/ossl_ssl.c".freeze, "ext/openssl/ossl_ssl.h".freeze, "ext/openssl/ossl_ssl_session.c".freeze, "ext/openssl/ossl_version.h".freeze, "ext/openssl/ossl_x509.c".freeze, "ext/openssl/ossl_x509.h".freeze, "ext/openssl/ossl_x509attr.c".freeze, "ext/openssl/ossl_x509cert.c".freeze, "ext/openssl/ossl_x509crl.c".freeze, "ext/openssl/ossl_x509ext.c".freeze, "ext/openssl/ossl_x509name.c".freeze, "ext/openssl/ossl_x509req.c".freeze, "ext/openssl/ossl_x509revoked.c".freeze, "ext/openssl/ossl_x509store.c".freeze, "ext/openssl/ruby_missing.h".freeze, "lib/openssl.rb".freeze, "lib/openssl/bn.rb".freeze, "lib/openssl/buffering.rb".freeze, "lib/openssl/cipher.rb".freeze, "lib/openssl/config.rb".freeze, "lib/openssl/digest.rb".freeze, "lib/openssl/pkey.rb".freeze, "lib/openssl/ssl.rb".freeze, "lib/openssl/x509.rb".freeze] | |
+ s.homepage = "https://www.ruby-lang.org/".freeze | |
+ 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.8".freeze | |
+ s.summary = "OpenSSL provides SSL, TLS and general purpose cryptography.".freeze | |
+ | |
+ if s.respond_to? :specification_version then | |
+ s.specification_version = 4 | |
+ | |
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then | |
+ s.add_development_dependency(%q<rake>.freeze, [">= 0"]) | |
+ s.add_development_dependency(%q<rake-compiler>.freeze, [">= 0"]) | |
+ s.add_development_dependency(%q<test-unit>.freeze, ["~> 3.0"]) | |
+ s.add_development_dependency(%q<rdoc>.freeze, [">= 0"]) | |
+ else | |
+ s.add_dependency(%q<rake>.freeze, [">= 0"]) | |
+ s.add_dependency(%q<rake-compiler>.freeze, [">= 0"]) | |
+ s.add_dependency(%q<test-unit>.freeze, ["~> 3.0"]) | |
+ s.add_dependency(%q<rdoc>.freeze, [">= 0"]) | |
+ end | |
+ else | |
+ s.add_dependency(%q<rake>.freeze, [">= 0"]) | |
+ s.add_dependency(%q<rake-compiler>.freeze, [">= 0"]) | |
+ s.add_dependency(%q<test-unit>.freeze, ["~> 3.0"]) | |
+ s.add_dependency(%q<rdoc>.freeze, [">= 0"]) | |
+ end | |
+end | |
diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c | |
index 31f2d0a5f9..cc13b7a3a5 100644 | |
--- a/ext/openssl/openssl_missing.c | |
+++ b/ext/openssl/openssl_missing.c | |
@@ -9,93 +9,42 @@ | |
*/ | |
#include RUBY_EXTCONF_H | |
-#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_EVP_CIPHER_CTX_ENGINE) | |
+#include <string.h> /* memcpy() */ | |
+#if !defined(OPENSSL_NO_ENGINE) | |
# include <openssl/engine.h> | |
#endif | |
-#include <openssl/x509_vfy.h> | |
- | |
#if !defined(OPENSSL_NO_HMAC) | |
-#include <string.h> /* memcpy() */ | |
-#include <openssl/hmac.h> | |
+# include <openssl/hmac.h> | |
+#endif | |
+#include <openssl/x509_vfy.h> | |
#include "openssl_missing.h" | |
-#if !defined(HAVE_HMAC_CTX_COPY) | |
-void | |
-HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in) | |
-{ | |
- if (!out || !in) return; | |
- memcpy(out, in, sizeof(HMAC_CTX)); | |
- | |
- EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx); | |
- EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx); | |
- EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx); | |
-} | |
-#endif /* HAVE_HMAC_CTX_COPY */ | |
-#endif /* NO_HMAC */ | |
- | |
-#if !defined(HAVE_EVP_MD_CTX_CREATE) | |
-EVP_MD_CTX * | |
-EVP_MD_CTX_create(void) | |
+/* added in 0.9.8X */ | |
+#if !defined(HAVE_EVP_CIPHER_CTX_NEW) | |
+EVP_CIPHER_CTX * | |
+EVP_CIPHER_CTX_new(void) | |
{ | |
- EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX)); | |
- if (!ctx) return NULL; | |
- | |
- memset(ctx, 0, sizeof(EVP_MD_CTX)); | |
- | |
+ EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX)); | |
+ if (!ctx) | |
+ return NULL; | |
+ EVP_CIPHER_CTX_init(ctx); | |
return ctx; | |
} | |
#endif | |
-#if !defined(HAVE_EVP_MD_CTX_CLEANUP) | |
-int | |
-EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) | |
-{ | |
- /* FIXME!!! */ | |
- memset(ctx, 0, sizeof(EVP_MD_CTX)); | |
- | |
- return 1; | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_EVP_MD_CTX_DESTROY) | |
+#if !defined(HAVE_EVP_CIPHER_CTX_FREE) | |
void | |
-EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) | |
+EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) | |
{ | |
- EVP_MD_CTX_cleanup(ctx); | |
- OPENSSL_free(ctx); | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_EVP_MD_CTX_INIT) | |
-void | |
-EVP_MD_CTX_init(EVP_MD_CTX *ctx) | |
-{ | |
- memset(ctx, 0, sizeof(EVP_MD_CTX)); | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_HMAC_CTX_INIT) | |
-void | |
-HMAC_CTX_init(HMAC_CTX *ctx) | |
-{ | |
- EVP_MD_CTX_init(&ctx->i_ctx); | |
- EVP_MD_CTX_init(&ctx->o_ctx); | |
- EVP_MD_CTX_init(&ctx->md_ctx); | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_HMAC_CTX_CLEANUP) | |
-void | |
-HMAC_CTX_cleanup(HMAC_CTX *ctx) | |
-{ | |
- EVP_MD_CTX_cleanup(&ctx->i_ctx); | |
- EVP_MD_CTX_cleanup(&ctx->o_ctx); | |
- EVP_MD_CTX_cleanup(&ctx->md_ctx); | |
- memset(ctx, 0, sizeof(HMAC_CTX)); | |
+ if (ctx) { | |
+ EVP_CIPHER_CTX_cleanup(ctx); | |
+ OPENSSL_free(ctx); | |
+ } | |
} | |
#endif | |
+/* added in 1.0.0 */ | |
#if !defined(HAVE_EVP_CIPHER_CTX_COPY) | |
/* | |
* this function does not exist in OpenSSL yet... or ever?. | |
@@ -103,11 +52,11 @@ HMAC_CTX_cleanup(HMAC_CTX *ctx) | |
* tested on 0.9.7d. | |
*/ | |
int | |
-EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in) | |
+EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) | |
{ | |
memcpy(out, in, sizeof(EVP_CIPHER_CTX)); | |
-#if defined(HAVE_ENGINE_ADD) && defined(HAVE_EVP_CIPHER_CTX_ENGINE) | |
+#if !defined(OPENSSL_NO_ENGINE) | |
if (in->engine) ENGINE_add(out->engine); | |
if (in->cipher_data) { | |
out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size); | |
@@ -119,222 +68,106 @@ EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in) | |
} | |
#endif | |
-#if !defined(HAVE_X509_CRL_SET_VERSION) | |
-int | |
-X509_CRL_set_version(X509_CRL *x, long version) | |
-{ | |
- if (x == NULL || x->crl == NULL) return 0; | |
- if (x->crl->version == NULL) { | |
- x->crl->version = M_ASN1_INTEGER_new(); | |
- if (x->crl->version == NULL) return 0; | |
- } | |
- return ASN1_INTEGER_set(x->crl->version, version); | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME) | |
-int | |
-X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name) | |
-{ | |
- if (x == NULL || x->crl == NULL) return 0; | |
- return X509_NAME_set(&x->crl->issuer, name); | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_X509_CRL_SORT) | |
+#if !defined(OPENSSL_NO_HMAC) | |
+#if !defined(HAVE_HMAC_CTX_COPY) | |
int | |
-X509_CRL_sort(X509_CRL *c) | |
+HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in) | |
{ | |
- int i; | |
- X509_REVOKED *r; | |
- /* sort the data so it will be written in serial | |
- * number order */ | |
- sk_X509_REVOKED_sort(c->crl->revoked); | |
- for (i=0; i<sk_X509_REVOKED_num(c->crl->revoked); i++) { | |
- r=sk_X509_REVOKED_value(c->crl->revoked, i); | |
- r->sequence=i; | |
- } | |
- return 1; | |
-} | |
-#endif | |
+ if (!out || !in) | |
+ return 0; | |
-#if !defined(HAVE_X509_CRL_ADD0_REVOKED) | |
-static int | |
-OSSL_X509_REVOKED_cmp(const X509_REVOKED * const *a, const X509_REVOKED * const *b) | |
-{ | |
- return(ASN1_STRING_cmp( | |
- (ASN1_STRING *)(*a)->serialNumber, | |
- (ASN1_STRING *)(*b)->serialNumber)); | |
-} | |
+ memcpy(out, in, sizeof(HMAC_CTX)); | |
-int | |
-X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev) | |
-{ | |
- X509_CRL_INFO *inf; | |
+ EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx); | |
+ EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx); | |
+ EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx); | |
- inf = crl->crl; | |
- if (!inf->revoked) | |
- inf->revoked = sk_X509_REVOKED_new(OSSL_X509_REVOKED_cmp); | |
- if (!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev)) | |
- return 0; | |
return 1; | |
} | |
-#endif | |
- | |
-#if !defined(HAVE_BN_MOD_SQR) | |
-int | |
-BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) | |
-{ | |
- if (!BN_sqr(r, (BIGNUM*)a, ctx)) return 0; | |
- return BN_mod(r, r, m, ctx); | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_BN_MOD_ADD) || !defined(HAVE_BN_MOD_SUB) | |
-int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) | |
-{ | |
- if (!BN_mod(r,m,d,ctx)) return 0; | |
- if (!r->neg) return 1; | |
- return (d->neg ? BN_sub : BN_add)(r, r, d); | |
-} | |
-#endif | |
+#endif /* HAVE_HMAC_CTX_COPY */ | |
+#endif /* NO_HMAC */ | |
-#if !defined(HAVE_BN_MOD_ADD) | |
-int | |
-BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) | |
-{ | |
- if (!BN_add(r, a, b)) return 0; | |
- return BN_nnmod(r, r, m, ctx); | |
-} | |
-#endif | |
+/* added in 1.0.2 */ | |
+#if !defined(OPENSSL_NO_EC) | |
+#if !defined(HAVE_EC_CURVE_NIST2NID) | |
+static struct { | |
+ const char *name; | |
+ int nid; | |
+} nist_curves[] = { | |
+ {"B-163", NID_sect163r2}, | |
+ {"B-233", NID_sect233r1}, | |
+ {"B-283", NID_sect283r1}, | |
+ {"B-409", NID_sect409r1}, | |
+ {"B-571", NID_sect571r1}, | |
+ {"K-163", NID_sect163k1}, | |
+ {"K-233", NID_sect233k1}, | |
+ {"K-283", NID_sect283k1}, | |
+ {"K-409", NID_sect409k1}, | |
+ {"K-571", NID_sect571k1}, | |
+ {"P-192", NID_X9_62_prime192v1}, | |
+ {"P-224", NID_secp224r1}, | |
+ {"P-256", NID_X9_62_prime256v1}, | |
+ {"P-384", NID_secp384r1}, | |
+ {"P-521", NID_secp521r1} | |
+}; | |
-#if !defined(HAVE_BN_MOD_SUB) | |
int | |
-BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) | |
+EC_curve_nist2nid(const char *name) | |
{ | |
- if (!BN_sub(r, a, b)) return 0; | |
- return BN_nnmod(r, r, m, ctx); | |
-} | |
-#endif | |
- | |
-#if !defined(HAVE_BN_RAND_RANGE) || !defined(HAVE_BN_PSEUDO_RAND_RANGE) | |
-static int | |
-bn_rand_range(int pseudo, BIGNUM *r, BIGNUM *range) | |
-{ | |
- int (*bn_rand)(BIGNUM *, int, int, int) = pseudo ? BN_pseudo_rand : BN_rand; | |
- int n; | |
- | |
- if (range->neg || BN_is_zero(range)) return 0; | |
- | |
- n = BN_num_bits(range); | |
- | |
- if (n == 1) { | |
- if (!BN_zero(r)) return 0; | |
- } else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) { | |
- do { | |
- if (!bn_rand(r, n + 1, -1, 0)) return 0; | |
- if (BN_cmp(r ,range) >= 0) { | |
- if (!BN_sub(r, r, range)) return 0; | |
- if (BN_cmp(r, range) >= 0) | |
- if (!BN_sub(r, r, range)) return 0; | |
- } | |
- } while (BN_cmp(r, range) >= 0); | |
- } else { | |
- do { | |
- if (!bn_rand(r, n, -1, 0)) return 0; | |
- } while (BN_cmp(r, range) >= 0); | |
+ size_t i; | |
+ for (i = 0; i < (sizeof(nist_curves) / sizeof(nist_curves[0])); i++) { | |
+ if (!strcmp(nist_curves[i].name, name)) | |
+ return nist_curves[i].nid; | |
} | |
- | |
- return 1; | |
+ return NID_undef; | |
} | |
#endif | |
- | |
-#if !defined(HAVE_BN_RAND_RANGE) | |
-int | |
-BN_rand_range(BIGNUM *r, BIGNUM *range) | |
-{ | |
- return bn_rand_range(0, r, range); | |
-} | |
#endif | |
-#if !defined(HAVE_BN_PSEUDO_RAND_RANGE) | |
-int | |
-BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range) | |
+/*** added in 1.1.0 ***/ | |
+#if !defined(HAVE_HMAC_CTX_NEW) | |
+HMAC_CTX * | |
+HMAC_CTX_new(void) | |
{ | |
- return bn_rand_range(1, r, range); | |
+ HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX)); | |
+ if (!ctx) | |
+ return NULL; | |
+ HMAC_CTX_init(ctx); | |
+ return ctx; | |
} | |
#endif | |
-#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE) | |
-#define OPENSSL_CONF "openssl.cnf" | |
-char * | |
-CONF_get1_default_config_file(void) | |
+#if !defined(HAVE_HMAC_CTX_FREE) | |
+void | |
+HMAC_CTX_free(HMAC_CTX *ctx) | |
{ | |
- char *file; | |
- int len; | |
- | |
- file = getenv("OPENSSL_CONF"); | |
- if (file) return BUF_strdup(file); | |
- len = strlen(X509_get_default_cert_area()); | |
-#ifndef OPENSSL_SYS_VMS | |
- len++; | |
-#endif | |
- len += strlen(OPENSSL_CONF); | |
- file = OPENSSL_malloc(len + 1); | |
- if (!file) return NULL; | |
- strcpy(file,X509_get_default_cert_area()); | |
-#ifndef OPENSSL_SYS_VMS | |
- strcat(file,"/"); | |
-#endif | |
- strcat(file,OPENSSL_CONF); | |
- | |
- return file; | |
+ if (ctx) { | |
+ HMAC_CTX_cleanup(ctx); | |
+ OPENSSL_free(ctx); | |
+ } | |
} | |
#endif | |
-#if !defined(HAVE_PEM_DEF_CALLBACK) | |
-#define OSSL_PASS_MIN_LENGTH 4 | |
-int | |
-PEM_def_callback(char *buf, int num, int w, void *key) | |
+#if !defined(HAVE_X509_CRL_GET0_SIGNATURE) | |
+void | |
+X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig, | |
+ const X509_ALGOR **palg) | |
{ | |
- int i,j; | |
- const char *prompt; | |
- | |
- if (key) { | |
- i = strlen(key); | |
- i = (i > num) ? num : i; | |
- memcpy(buf, key, i); | |
- return i; | |
- } | |
- | |
- prompt = EVP_get_pw_prompt(); | |
- if (prompt == NULL) prompt = "Enter PEM pass phrase:"; | |
- for (;;) { | |
- i = EVP_read_pw_string(buf, num, prompt, w); | |
- if (i != 0) { | |
- memset(buf, 0, (unsigned int)num); | |
- return(-1); | |
- } | |
- j = strlen(buf); | |
- if (j < OSSL_PASS_MIN_LENGTH) { | |
- fprintf(stderr, | |
- "phrase is too short, needs to be at least %d chars\n", | |
- OSSL_PASS_MIN_LENGTH); | |
- } | |
- else break; | |
- } | |
- return j; | |
+ if (psig != NULL) | |
+ *psig = crl->signature; | |
+ if (palg != NULL) | |
+ *palg = crl->sig_alg; | |
} | |
#endif | |
-#if !defined(HAVE_ASN1_PUT_EOC) | |
-int | |
-ASN1_put_eoc(unsigned char **pp) | |
+#if !defined(HAVE_X509_REQ_GET0_SIGNATURE) | |
+void | |
+X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig, | |
+ const X509_ALGOR **palg) | |
{ | |
- unsigned char *p = *pp; | |
- *p++ = 0; | |
- *p++ = 0; | |
- *pp = p; | |
- return 2; | |
+ if (psig != NULL) | |
+ *psig = req->signature; | |
+ if (palg != NULL) | |
+ *palg = req->sig_alg; | |
} | |
#endif | |
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h | |
index 955579cf9f..df27b1a858 100644 | |
--- a/ext/openssl/openssl_missing.h | |
+++ b/ext/openssl/openssl_missing.h | |
@@ -10,192 +10,239 @@ | |
#if !defined(_OSSL_OPENSSL_MISSING_H_) | |
#define _OSSL_OPENSSL_MISSING_H_ | |
-#if defined(__cplusplus) | |
-extern "C" { | |
-#endif | |
+#include "ruby/config.h" | |
-#ifndef TYPEDEF_D2I_OF | |
-typedef char *d2i_of_void(); | |
-#endif | |
-#ifndef TYPEDEF_I2D_OF | |
-typedef int i2d_of_void(); | |
+/* added in 0.9.8X */ | |
+#if !defined(HAVE_EVP_CIPHER_CTX_NEW) | |
+EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); | |
#endif | |
-/* | |
- * These functions are not included in headers of OPENSSL <= 0.9.6b | |
- */ | |
+#if !defined(HAVE_EVP_CIPHER_CTX_FREE) | |
+void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx); | |
+#endif | |
-#if !defined(PEM_read_bio_DSAPublicKey) | |
-# define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ | |
- (d2i_of_void *)d2i_DSAPublicKey,PEM_STRING_DSA_PUBLIC,(bp),(void **)(x),(cb),(u)) | |
+/* added in 1.0.0 */ | |
+#if !defined(HAVE_EVP_PKEY_BASE_ID) | |
+# define EVP_PKEY_base_id(pkey) EVP_PKEY_type((pkey)->type) | |
#endif | |
-#if !defined(PEM_write_bio_DSAPublicKey) | |
-# define PEM_write_bio_DSAPublicKey(bp,x) \ | |
- PEM_ASN1_write_bio((i2d_of_void *)i2d_DSAPublicKey,\ | |
- PEM_STRING_DSA_PUBLIC,\ | |
- (bp),(char *)(x), NULL, NULL, 0, NULL, NULL) | |
+#if !defined(HAVE_EVP_CIPHER_CTX_COPY) | |
+int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in); | |
#endif | |
-#if !defined(DSAPrivateKey_dup) | |
-# define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, \ | |
- (d2i_of_void *)d2i_DSAPrivateKey,(char *)(dsa)) | |
+#if !defined(HAVE_HMAC_CTX_COPY) | |
+int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in); | |
#endif | |
-#if !defined(DSAPublicKey_dup) | |
-# define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPublicKey, \ | |
- (d2i_of_void *)d2i_DSAPublicKey,(char *)(dsa)) | |
+#if !defined(HAVE_X509_STORE_CTX_GET0_CURRENT_CRL) | |
+# define X509_STORE_CTX_get0_current_crl(x) ((x)->current_crl) | |
#endif | |
-#if !defined(X509_REVOKED_dup) | |
-# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((i2d_of_void *)i2d_X509_REVOKED, \ | |
- (d2i_of_void *)d2i_X509_REVOKED, (char *)(rev)) | |
+#if !defined(HAVE_X509_STORE_SET_VERIFY_CB) | |
+# define X509_STORE_set_verify_cb X509_STORE_set_verify_cb_func | |
#endif | |
-#if !defined(PKCS7_SIGNER_INFO_dup) | |
-# define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO, \ | |
- (d2i_of_void *)d2i_PKCS7_SIGNER_INFO, (char *)(si)) | |
+#if !defined(HAVE_I2D_ASN1_SET_ANY) | |
+# define i2d_ASN1_SET_ANY(sk, x) i2d_ASN1_SET_OF_ASN1_TYPE((sk), (x), \ | |
+ i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0) | |
#endif | |
-#if !defined(PKCS7_RECIP_INFO_dup) | |
-# define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO, \ | |
- (d2i_of_void *)d2i_PKCS7_RECIP_INFO, (char *)(ri)) | |
+#if !defined(HAVE_EVP_PKEY_GET0) | |
+# define EVP_PKEY_get0(pk) (pk->pkey.ptr) | |
#endif | |
-#if !defined(HAVE_HMAC_CTX_INIT) | |
-void HMAC_CTX_init(HMAC_CTX *ctx); | |
+/* added in 1.0.2 */ | |
+#if !defined(OPENSSL_NO_EC) | |
+#if !defined(HAVE_EC_CURVE_NIST2NID) | |
+int EC_curve_nist2nid(const char *); | |
+#endif | |
#endif | |
-#if !defined(HAVE_HMAC_CTX_COPY) | |
-void HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in); | |
+#if !defined(HAVE_X509_REVOKED_DUP) | |
+# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((i2d_of_void *)i2d_X509_REVOKED, \ | |
+ (d2i_of_void *)d2i_X509_REVOKED, (char *)(rev)) | |
#endif | |
-#if !defined(HAVE_HMAC_CTX_CLEANUP) | |
-void HMAC_CTX_cleanup(HMAC_CTX *ctx); | |
+#if !defined(HAVE_X509_STORE_CTX_GET0_STORE) | |
+# define X509_STORE_CTX_get0_store(x) ((x)->ctx) | |
#endif | |
-#if !defined(HAVE_EVP_MD_CTX_CREATE) | |
-EVP_MD_CTX *EVP_MD_CTX_create(void); | |
+#if !defined(HAVE_SSL_IS_SERVER) | |
+# define SSL_is_server(s) ((s)->server) | |
#endif | |
-#if !defined(HAVE_EVP_MD_CTX_INIT) | |
-void EVP_MD_CTX_init(EVP_MD_CTX *ctx); | |
+/* added in 1.1.0 */ | |
+#if !defined(HAVE_BN_GENCB_NEW) | |
+# define BN_GENCB_new() ((BN_GENCB *)OPENSSL_malloc(sizeof(BN_GENCB))) | |
#endif | |
-#if !defined(HAVE_EVP_MD_CTX_CLEANUP) | |
-int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); | |
+#if !defined(HAVE_BN_GENCB_FREE) | |
+# define BN_GENCB_free(cb) OPENSSL_free(cb) | |
#endif | |
-#if !defined(HAVE_EVP_MD_CTX_DESTROY) | |
-void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); | |
+#if !defined(HAVE_BN_GENCB_GET_ARG) | |
+# define BN_GENCB_get_arg(cb) (cb)->arg | |
#endif | |
-#if !defined(HAVE_EVP_CIPHER_CTX_COPY) | |
-int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in); | |
+#if !defined(HAVE_EVP_MD_CTX_NEW) | |
+# define EVP_MD_CTX_new EVP_MD_CTX_create | |
#endif | |
-#if !defined(HAVE_EVP_DIGESTINIT_EX) | |
-# define EVP_DigestInit_ex(ctx, md, engine) EVP_DigestInit((ctx), (md)) | |
+#if !defined(HAVE_EVP_MD_CTX_FREE) | |
+# define EVP_MD_CTX_free EVP_MD_CTX_destroy | |
#endif | |
-#if !defined(HAVE_EVP_DIGESTFINAL_EX) | |
-# define EVP_DigestFinal_ex(ctx, buf, len) EVP_DigestFinal((ctx), (buf), (len)) | |
+ | |
+#if !defined(HAVE_HMAC_CTX_NEW) | |
+HMAC_CTX *HMAC_CTX_new(void); | |
#endif | |
-#if !defined(HAVE_EVP_CIPHERINIT_EX) | |
-# define EVP_CipherInit_ex(ctx, type, impl, key, iv, enc) EVP_CipherInit((ctx), (type), (key), (iv), (enc)) | |
+#if !defined(HAVE_HMAC_CTX_FREE) | |
+void HMAC_CTX_free(HMAC_CTX *ctx); | |
#endif | |
-#if !defined(HAVE_EVP_CIPHERFINAL_EX) | |
-# define EVP_CipherFinal_ex(ctx, outm, outl) EVP_CipherFinal((ctx), (outm), (outl)) | |
+ | |
+#if !defined(HAVE_X509_STORE_GET_EX_DATA) | |
+# define X509_STORE_get_ex_data(x, idx) \ | |
+ CRYPTO_get_ex_data(&(x)->ex_data, (idx)) | |
#endif | |
-#if !defined(EVP_CIPHER_name) | |
-# define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e)) | |
+#if !defined(HAVE_X509_STORE_SET_EX_DATA) | |
+# define X509_STORE_set_ex_data(x, idx, data) \ | |
+ CRYPTO_set_ex_data(&(x)->ex_data, (idx), (data)) | |
+# define X509_STORE_get_ex_new_index(l, p, newf, dupf, freef) \ | |
+ CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, (l), (p), \ | |
+ (newf), (dupf), (freef)) | |
#endif | |
-#if !defined(EVP_MD_name) | |
-# define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e)) | |
+#if !defined(HAVE_X509_CRL_GET0_SIGNATURE) | |
+void X509_CRL_get0_signature(const X509_CRL *, const ASN1_BIT_STRING **, const X509_ALGOR **); | |
#endif | |
-#if !defined(HAVE_EVP_HMAC_INIT_EX) | |
-# define HMAC_Init_ex(ctx, key, len, digest, engine) HMAC_Init((ctx), (key), (len), (digest)) | |
+#if !defined(HAVE_X509_REQ_GET0_SIGNATURE) | |
+void X509_REQ_get0_signature(const X509_REQ *, const ASN1_BIT_STRING **, const X509_ALGOR **); | |
#endif | |
-#if !defined(PKCS7_is_detached) | |
-# define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7)) | |
+#if !defined(HAVE_X509_REVOKED_GET0_SERIALNUMBER) | |
+# define X509_REVOKED_get0_serialNumber(x) ((x)->serialNumber) | |
#endif | |
-#if !defined(PKCS7_type_is_encrypted) | |
-# define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted) | |
+#if !defined(HAVE_X509_REVOKED_GET0_REVOCATIONDATE) | |
+# define X509_REVOKED_get0_revocationDate(x) ((x)->revocationDate) | |
#endif | |
-#if !defined(HAVE_OPENSSL_CLEANSE) | |
-#define OPENSSL_cleanse(p, l) memset((p), 0, (l)) | |
+#if !defined(HAVE_X509_GET0_TBS_SIGALG) | |
+# define X509_get0_tbs_sigalg(x) ((x)->cert_info->signature) | |
#endif | |
-#if !defined(HAVE_X509_STORE_GET_EX_DATA) | |
-# define X509_STORE_get_ex_data(x, idx) \ | |
- CRYPTO_get_ex_data(&(x)->ex_data, (idx)) | |
+#if !defined(HAVE_X509_STORE_CTX_GET0_UNTRUSTED) | |
+# define X509_STORE_CTX_get0_untrusted(x) ((x)->untrusted) | |
#endif | |
-#if !defined(HAVE_X509_STORE_SET_EX_DATA) | |
-# define X509_STORE_set_ex_data(x, idx, data) \ | |
- CRYPTO_set_ex_data(&(x)->ex_data, (idx), (data)) | |
-# define X509_STORE_get_ex_new_index(l, p, newf, dupf, freef) \ | |
- CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, (l), (p), \ | |
- (newf), (dupf), (freef)) | |
+#if !defined(HAVE_X509_STORE_CTX_GET0_CERT) | |
+# define X509_STORE_CTX_get0_cert(x) ((x)->cert) | |
#endif | |
-#if !defined(HAVE_X509_CRL_SET_VERSION) | |
-int X509_CRL_set_version(X509_CRL *x, long version); | |
+#if !defined(HAVE_X509_STORE_CTX_GET0_CHAIN) | |
+# define X509_STORE_CTX_get0_chain(ctx) X509_STORE_CTX_get_chain(ctx) | |
#endif | |
-#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME) | |
-int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); | |
+#if !defined(HAVE_OCSP_SINGLERESP_GET0_ID) | |
+# define OCSP_SINGLERESP_get0_id(s) ((s)->certId) | |
#endif | |
-#if !defined(HAVE_X509_CRL_SORT) | |
-int X509_CRL_sort(X509_CRL *c); | |
+#if !defined(HAVE_SSL_CTX_GET_CIPHERS) | |
+# define SSL_CTX_get_ciphers(ctx) ((ctx)->cipher_list) | |
#endif | |
-#if !defined(HAVE_X509_CRL_ADD0_REVOKED) | |
-int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); | |
+#if !defined(HAVE_X509_UP_REF) | |
+# define X509_up_ref(x) \ | |
+ CRYPTO_add(&(x)->references, 1, CRYPTO_LOCK_X509) | |
#endif | |
-#if !defined(HAVE_BN_MOD_SQR) | |
-int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); | |
+#if !defined(HAVE_X509_CRL_UP_REF) | |
+# define X509_CRL_up_ref(x) \ | |
+ CRYPTO_add(&(x)->references, 1, CRYPTO_LOCK_X509_CRL); | |
#endif | |
-#if !defined(HAVE_BN_MOD_ADD) | |
-int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); | |
+#if !defined(HAVE_X509_STORE_UP_REF) | |
+# define X509_STORE_up_ref(x) \ | |
+ CRYPTO_add(&(x)->references, 1, CRYPTO_LOCK_X509_STORE); | |
#endif | |
-#if !defined(HAVE_BN_MOD_SUB) | |
-int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); | |
+#if !defined(HAVE_SSL_SESSION_UP_REF) | |
+# define SSL_SESSION_up_ref(x) \ | |
+ CRYPTO_add(&(x)->references, 1, CRYPTO_LOCK_SSL_SESSION); | |
#endif | |
-#if !defined(HAVE_BN_RAND_RANGE) | |
-int BN_rand_range(BIGNUM *r, BIGNUM *range); | |
+#if !defined(HAVE_EVP_PKEY_UP_REF) | |
+# define EVP_PKEY_up_ref(x) \ | |
+ CRYPTO_add(&(x)->references, 1, CRYPTO_LOCK_EVP_PKEY); | |
#endif | |
-#if !defined(HAVE_BN_PSEUDO_RAND_RANGE) | |
-int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range); | |
+#if !defined(HAVE_OPAQUE_OPENSSL) | |
+#define IMPL_PKEY_GETTER(_type, _name) \ | |
+static inline _type *EVP_PKEY_get0_##_type(EVP_PKEY *pkey) { \ | |
+ return pkey->pkey._name; } | |
+#define IMPL_KEY_ACCESSOR2(_type, _group, a1, a2, _fail_cond) \ | |
+static inline void _type##_get0_##_group(_type *obj, const BIGNUM **a1, const BIGNUM **a2) { \ | |
+ if (a1) *a1 = obj->a1; \ | |
+ if (a2) *a2 = obj->a2; } \ | |
+static inline int _type##_set0_##_group(_type *obj, BIGNUM *a1, BIGNUM *a2) { \ | |
+ if (_fail_cond) return 0; \ | |
+ BN_clear_free(obj->a1); obj->a1 = a1; \ | |
+ BN_clear_free(obj->a2); obj->a2 = a2; \ | |
+ return 1; } | |
+#define IMPL_KEY_ACCESSOR3(_type, _group, a1, a2, a3, _fail_cond) \ | |
+static inline void _type##_get0_##_group(_type *obj, const BIGNUM **a1, const BIGNUM **a2, const BIGNUM **a3) { \ | |
+ if (a1) *a1 = obj->a1; \ | |
+ if (a2) *a2 = obj->a2; \ | |
+ if (a3) *a3 = obj->a3; } \ | |
+static inline int _type##_set0_##_group(_type *obj, BIGNUM *a1, BIGNUM *a2, BIGNUM *a3) { \ | |
+ if (_fail_cond) return 0; \ | |
+ BN_clear_free(obj->a1); obj->a1 = a1; \ | |
+ BN_clear_free(obj->a2); obj->a2 = a2; \ | |
+ BN_clear_free(obj->a3); obj->a3 = a3; \ | |
+ return 1; } | |
+ | |
+#if !defined(OPENSSL_NO_RSA) | |
+IMPL_PKEY_GETTER(RSA, rsa) | |
+IMPL_KEY_ACCESSOR3(RSA, key, n, e, d, (n == obj->n || e == obj->e || (obj->d && d == obj->d))) | |
+IMPL_KEY_ACCESSOR2(RSA, factors, p, q, (p == obj->p || q == obj->q)) | |
+IMPL_KEY_ACCESSOR3(RSA, crt_params, dmp1, dmq1, iqmp, (dmp1 == obj->dmp1 || dmq1 == obj->dmq1 || iqmp == obj->iqmp)) | |
#endif | |
-#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE) | |
-char *CONF_get1_default_config_file(void); | |
+#if !defined(OPENSSL_NO_DSA) | |
+IMPL_PKEY_GETTER(DSA, dsa) | |
+IMPL_KEY_ACCESSOR2(DSA, key, pub_key, priv_key, (pub_key == obj->pub_key || (obj->priv_key && priv_key == obj->priv_key))) | |
+IMPL_KEY_ACCESSOR3(DSA, pqg, p, q, g, (p == obj->p || q == obj->q || g == obj->g)) | |
#endif | |
-#if !defined(HAVE_PEM_DEF_CALLBACK) | |
-int PEM_def_callback(char *buf, int num, int w, void *key); | |
+#if !defined(OPENSSL_NO_DH) | |
+IMPL_PKEY_GETTER(DH, dh) | |
+IMPL_KEY_ACCESSOR2(DH, key, pub_key, priv_key, (pub_key == obj->pub_key || (obj->priv_key && priv_key == obj->priv_key))) | |
+IMPL_KEY_ACCESSOR3(DH, pqg, p, q, g, (p == obj->p || obj->q && q == obj->q || g == obj->g)) | |
+static inline ENGINE *DH_get0_engine(DH *dh) { return dh->engine; } | |
#endif | |
-#if !defined(HAVE_ASN1_PUT_EOC) | |
-int ASN1_put_eoc(unsigned char **pp); | |
+#if !defined(OPENSSL_NO_EC) | |
+IMPL_PKEY_GETTER(EC_KEY, ec) | |
#endif | |
-#if defined(__cplusplus) | |
-} | |
+#undef IMPL_PKEY_GETTER | |
+#undef IMPL_KEY_ACCESSOR2 | |
+#undef IMPL_KEY_ACCESSOR3 | |
+#endif /* HAVE_OPAQUE_OPENSSL */ | |
+ | |
+#if defined(HAVE_AUTHENTICATED_ENCRYPTION) && !defined(EVP_CTRL_AEAD_GET_TAG) | |
+# define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG | |
+# define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG | |
+# define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN | |
#endif | |
+#if !defined(HAVE_X509_GET0_NOTBEFORE) | |
+# define X509_get0_notBefore(x) X509_get_notBefore(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_nextUpdate(x) X509_CRL_get_nextUpdate(x) | |
+#endif | |
#endif /* _OSSL_OPENSSL_MISSING_H_ */ | |
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c | |
index 0ee380507a..eb71b643bf 100644 | |
--- a/ext/openssl/ossl.c | |
+++ b/ext/openssl/ossl.c | |
@@ -9,40 +9,7 @@ | |
*/ | |
#include "ossl.h" | |
#include <stdarg.h> /* for ossl_raise */ | |
- | |
-/* | |
- * String to HEXString conversion | |
- */ | |
-int | |
-string2hex(const unsigned char *buf, int buf_len, char **hexbuf, int *hexbuf_len) | |
-{ | |
- static const char hex[]="0123456789abcdef"; | |
- int i, len; | |
- | |
- if (buf_len < 0 || buf_len > INT_MAX / 2) { /* PARANOIA? */ | |
- return -1; | |
- } | |
- len = 2 * buf_len; | |
- if (!hexbuf) { /* if no buf, return calculated len */ | |
- if (hexbuf_len) { | |
- *hexbuf_len = len; | |
- } | |
- return len; | |
- } | |
- if (!(*hexbuf = OPENSSL_malloc(len + 1))) { | |
- return -1; | |
- } | |
- for (i = 0; i < buf_len; i++) { | |
- (*hexbuf)[2 * i] = hex[((unsigned char)buf[i]) >> 4]; | |
- (*hexbuf)[2 * i + 1] = hex[buf[i] & 0x0f]; | |
- } | |
- (*hexbuf)[2 * i] = '\0'; | |
- | |
- if (hexbuf_len) { | |
- *hexbuf_len = len; | |
- } | |
- return len; | |
-} | |
+#include <ruby/thread_native.h> /* for OpenSSL < 1.1.0 locks */ | |
/* | |
* Data Conversion | |
@@ -77,7 +44,7 @@ STACK_OF(type) * \ | |
ossl_protect_##name##_ary2sk(VALUE ary, int *status) \ | |
{ \ | |
return (STACK_OF(type)*)rb_protect( \ | |
- (VALUE(*)_((VALUE)))ossl_##name##_ary2sk0, \ | |
+ (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \ | |
ary, \ | |
status); \ | |
} \ | |
@@ -97,7 +64,7 @@ OSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr) | |
#define OSSL_IMPL_SK2ARY(name, type) \ | |
VALUE \ | |
-ossl_##name##_sk2ary(STACK_OF(type) *sk) \ | |
+ossl_##name##_sk2ary(const STACK_OF(type) *sk) \ | |
{ \ | |
type *t; \ | |
int i, num; \ | |
@@ -136,7 +103,7 @@ ossl_buf2str(char *buf, int len) | |
VALUE str; | |
int status = 0; | |
- str = rb_protect((VALUE(*)_((VALUE)))ossl_str_new, len, &status); | |
+ str = rb_protect((VALUE (*)(VALUE))ossl_str_new, len, &status); | |
if(!NIL_P(str)) memcpy(RSTRING_PTR(str), buf, len); | |
OPENSSL_free(buf); | |
if(status) rb_jump_tag(status); | |
@@ -144,9 +111,49 @@ ossl_buf2str(char *buf, int len) | |
return str; | |
} | |
+void | |
+ossl_bin2hex(unsigned char *in, char *out, size_t inlen) | |
+{ | |
+ const char *hex = "0123456789abcdef"; | |
+ size_t i; | |
+ | |
+ assert(inlen <= LONG_MAX / 2); | |
+ for (i = 0; i < inlen; i++) { | |
+ unsigned char p = in[i]; | |
+ | |
+ out[i * 2 + 0] = hex[p >> 4]; | |
+ out[i * 2 + 1] = hex[p & 0x0f]; | |
+ } | |
+} | |
+ | |
/* | |
* our default PEM callback | |
*/ | |
+ | |
+/* | |
+ * OpenSSL requires passwords for PEM-encoded files to be at least four | |
+ * characters long. See crypto/pem/pem_lib.c (as of 1.0.2h) | |
+ */ | |
+#define OSSL_MIN_PWD_LEN 4 | |
+ | |
+VALUE | |
+ossl_pem_passwd_value(VALUE pass) | |
+{ | |
+ if (NIL_P(pass)) | |
+ return Qnil; | |
+ | |
+ StringValue(pass); | |
+ | |
+ if (RSTRING_LEN(pass) < OSSL_MIN_PWD_LEN) | |
+ ossl_raise(eOSSLError, "password must be at least %d bytes", OSSL_MIN_PWD_LEN); | |
+ /* PEM_BUFSIZE is currently used as the second argument of pem_password_cb, | |
+ * that is +max_len+ of ossl_pem_passwd_cb() */ | |
+ if (RSTRING_LEN(pass) > PEM_BUFSIZE) | |
+ ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE); | |
+ | |
+ return pass; | |
+} | |
+ | |
static VALUE | |
ossl_pem_passwd_cb0(VALUE flag) | |
{ | |
@@ -159,13 +166,30 @@ ossl_pem_passwd_cb0(VALUE flag) | |
} | |
int | |
-ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd) | |
+ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) | |
{ | |
- int len, status = 0; | |
- VALUE rflag, pass; | |
+ long len; | |
+ int status; | |
+ VALUE rflag, pass = (VALUE)pwd_; | |
+ | |
+ if (RTEST(pass)) { | |
+ /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not | |
+ * work because it does not allow NUL characters and truncates to 1024 | |
+ * bytes silently if the input is over 1024 bytes */ | |
+ if (RB_TYPE_P(pass, T_STRING)) { | |
+ len = RSTRING_LEN(pass); | |
+ if (len >= OSSL_MIN_PWD_LEN && len <= max_len) { | |
+ memcpy(buf, RSTRING_PTR(pass), len); | |
+ return (int)len; | |
+ } | |
+ } | |
+ OSSL_Debug("passed data is not valid String???"); | |
+ return -1; | |
+ } | |
- if (pwd || !rb_block_given_p()) | |
- return PEM_def_callback(buf, max_len, flag, pwd); | |
+ if (!rb_block_given_p()) { | |
+ return PEM_def_callback(buf, max_len, flag, NULL); | |
+ } | |
while (1) { | |
/* | |
@@ -180,78 +204,19 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd) | |
rb_set_errinfo(Qnil); | |
return -1; | |
} | |
- len = RSTRING_LENINT(pass); | |
- if (len < 4) { /* 4 is OpenSSL hardcoded limit */ | |
- rb_warning("password must be longer than 4 bytes"); | |
+ len = RSTRING_LEN(pass); | |
+ if (len < OSSL_MIN_PWD_LEN) { | |
+ rb_warning("password must be at least %d bytes", OSSL_MIN_PWD_LEN); | |
continue; | |
} | |
if (len > max_len) { | |
- rb_warning("password must be shorter then %d bytes", max_len-1); | |
+ rb_warning("password must not be longer than %d bytes", max_len); | |
continue; | |
} | |
memcpy(buf, RSTRING_PTR(pass), len); | |
break; | |
} | |
- return len; | |
-} | |
- | |
-/* | |
- * Verify callback | |
- */ | |
-int ossl_store_ctx_ex_verify_cb_idx; | |
-int ossl_store_ex_verify_cb_idx; | |
- | |
-VALUE | |
-ossl_call_verify_cb_proc(struct ossl_verify_cb_args *args) | |
-{ | |
- return rb_funcall(args->proc, rb_intern("call"), 2, | |
- args->preverify_ok, args->store_ctx); | |
-} | |
- | |
-int | |
-ossl_verify_cb(int ok, X509_STORE_CTX *ctx) | |
-{ | |
- VALUE proc, rctx, ret; | |
- struct ossl_verify_cb_args args; | |
- int state = 0; | |
- | |
- proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_store_ctx_ex_verify_cb_idx); | |
- if (!proc) | |
- proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_store_ex_verify_cb_idx); | |
- if (!proc) | |
- return ok; | |
- if (!NIL_P(proc)) { | |
- ret = Qfalse; | |
- rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new, | |
- (VALUE)ctx, &state); | |
- if (state) { | |
- rb_set_errinfo(Qnil); | |
- rb_warn("StoreContext initialization failure"); | |
- } | |
- else { | |
- args.proc = proc; | |
- args.preverify_ok = ok ? Qtrue : Qfalse; | |
- args.store_ctx = rctx; | |
- ret = rb_protect((VALUE(*)(VALUE))ossl_call_verify_cb_proc, (VALUE)&args, &state); | |
- if (state) { | |
- rb_set_errinfo(Qnil); | |
- rb_warn("exception in verify_callback is ignored"); | |
- } | |
- ossl_x509stctx_clear_ptr(rctx); | |
- } | |
- if (ret == Qtrue) { | |
- X509_STORE_CTX_set_error(ctx, X509_V_OK); | |
- ok = 1; | |
- } | |
- else{ | |
- if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) { | |
- X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); | |
- } | |
- ok = 0; | |
- } | |
- } | |
- | |
- return ok; | |
+ return (int)len; | |
} | |
/* | |
@@ -298,11 +263,7 @@ ossl_make_error(VALUE exc, const char *fmt, va_list args) | |
const char *msg; | |
long e; | |
-#ifdef HAVE_ERR_PEEK_LAST_ERROR | |
e = ERR_peek_last_error(); | |
-#else | |
- e = ERR_peek_error(); | |
-#endif | |
if (fmt) { | |
str = rb_vsprintf(fmt, args); | |
} | |
@@ -319,12 +280,7 @@ ossl_make_error(VALUE exc, const char *fmt, va_list args) | |
rb_str_cat2(str, msg ? msg : "(null)"); | |
} | |
} | |
- if (dOSSL == Qtrue){ /* show all errors on the stack */ | |
- while ((e = ERR_get_error()) != 0){ | |
- rb_warn("error on stack: %s", ERR_error_string(e, NULL)); | |
- } | |
- } | |
- ERR_clear_error(); | |
+ ossl_clear_error(); | |
if (NIL_P(str)) str = rb_str_new(0, 0); | |
return rb_exc_new3(exc, str); | |
@@ -341,15 +297,32 @@ ossl_raise(VALUE exc, const char *fmt, ...) | |
rb_exc_raise(err); | |
} | |
-VALUE | |
-ossl_exc_new(VALUE exc, const char *fmt, ...) | |
+void | |
+ossl_clear_error(void) | |
{ | |
- va_list args; | |
- VALUE err; | |
- va_start(args, fmt); | |
- err = ossl_make_error(exc, fmt, args); | |
- va_end(args); | |
- return err; | |
+ if (dOSSL == Qtrue) { | |
+ unsigned long e; | |
+ const char *file, *data, *errstr; | |
+ int line, flags; | |
+ | |
+ while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) { | |
+ errstr = ERR_error_string(e, NULL); | |
+ if (!errstr) | |
+ errstr = "(null)"; | |
+ | |
+ if (flags & ERR_TXT_STRING) { | |
+ if (!data) | |
+ data = "(null)"; | |
+ rb_warn("error on stack: %s (%s)", errstr, data); | |
+ } | |
+ else { | |
+ rb_warn("error on stack: %s", errstr); | |
+ } | |
+ } | |
+ } | |
+ else { | |
+ ERR_clear_error(); | |
+ } | |
} | |
/* | |
@@ -409,24 +382,14 @@ ossl_debug_get(VALUE self) | |
* call-seq: | |
* OpenSSL.debug = boolean -> boolean | |
* | |
- * Turns on or off CRYPTO_MEM_CHECK. | |
- * Also shows some debugging message on stderr. | |
+ * Turns on or off debug mode. With debug mode, all erros added to the OpenSSL | |
+ * error queue will be printed to stderr. | |
*/ | |
static VALUE | |
ossl_debug_set(VALUE self, VALUE val) | |
{ | |
- VALUE old = dOSSL; | |
- dOSSL = val; | |
- | |
- if (old != dOSSL) { | |
- if (dOSSL == Qtrue) { | |
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); | |
- fprintf(stderr, "OSSL_DEBUG: IS NOW ON!\n"); | |
- } else if (old == Qtrue) { | |
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF); | |
- fprintf(stderr, "OSSL_DEBUG: IS NOW OFF!\n"); | |
- } | |
- } | |
+ dOSSL = RTEST(val) ? Qtrue : Qfalse; | |
+ | |
return val; | |
} | |
@@ -439,15 +402,14 @@ ossl_debug_set(VALUE self, VALUE val) | |
* so otherwise will result in an error. | |
* | |
* === Examples | |
- * | |
- * OpenSSL.fips_mode = true # turn FIPS mode on | |
- * OpenSSL.fips_mode = false # and off again | |
+ * OpenSSL.fips_mode = true # turn FIPS mode on | |
+ * OpenSSL.fips_mode = false # and off again | |
*/ | |
static VALUE | |
ossl_fips_mode_set(VALUE self, VALUE enabled) | |
{ | |
-#ifdef HAVE_OPENSSL_FIPS | |
+#ifdef OPENSSL_FIPS | |
if (RTEST(enabled)) { | |
int mode = FIPS_mode(); | |
if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */ | |
@@ -464,50 +426,36 @@ ossl_fips_mode_set(VALUE self, VALUE enabled) | |
#endif | |
} | |
+#if !defined(HAVE_OPENSSL_110_THREADING_API) | |
/** | |
* Stores locks needed for OpenSSL thread safety | |
*/ | |
-#include "ruby/thread_native.h" | |
-struct CRYPTO_dynlock_value { | |
- rb_nativethread_lock_t lock; | |
- rb_nativethread_id_t owner; | |
- size_t count; | |
-}; | |
+static rb_nativethread_lock_t *ossl_locks; | |
static void | |
-ossl_lock_init(struct CRYPTO_dynlock_value *l) | |
+ossl_lock_unlock(int mode, rb_nativethread_lock_t *lock) | |
{ | |
- rb_nativethread_lock_initialize(&l->lock); | |
- l->count = 0; | |
+ if (mode & CRYPTO_LOCK) { | |
+ rb_nativethread_lock_lock(lock); | |
+ } else { | |
+ rb_nativethread_lock_unlock(lock); | |
+ } | |
} | |
static void | |
-ossl_lock_unlock(int mode, struct CRYPTO_dynlock_value *l) | |
+ossl_lock_callback(int mode, int type, const char *file, int line) | |
{ | |
- if (mode & CRYPTO_LOCK) { | |
- /* TODO: rb_nativethread_id_t is not necessarily compared with ==. */ | |
- rb_nativethread_id_t tid = rb_nativethread_self(); | |
- if (l->count && l->owner == tid) { | |
- l->count++; | |
- return; | |
- } | |
- rb_nativethread_lock_lock(&l->lock); | |
- l->owner = tid; | |
- l->count = 1; | |
- } else { | |
- if (!--l->count) | |
- rb_nativethread_lock_unlock(&l->lock); | |
- } | |
+ ossl_lock_unlock(mode, &ossl_locks[type]); | |
} | |
+struct CRYPTO_dynlock_value { | |
+ rb_nativethread_lock_t lock; | |
+}; | |
+ | |
static struct CRYPTO_dynlock_value * | |
ossl_dyn_create_callback(const char *file, int line) | |
{ | |
- /* Do not use xmalloc() here, since it may raise NoMemoryError */ | |
- struct CRYPTO_dynlock_value *dynlock = | |
- OPENSSL_malloc(sizeof(struct CRYPTO_dynlock_value)); | |
- if (dynlock) | |
- ossl_lock_init(dynlock); | |
+ struct CRYPTO_dynlock_value *dynlock = (struct CRYPTO_dynlock_value *)OPENSSL_malloc((int)sizeof(struct CRYPTO_dynlock_value)); | |
rb_nativethread_lock_initialize(&dynlock->lock); | |
return dynlock; | |
} | |
@@ -515,7 +463,7 @@ ossl_dyn_create_callback(const char *file, int line) | |
static void | |
ossl_dyn_lock_callback(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line) | |
{ | |
- ossl_lock_unlock(mode, l); | |
+ ossl_lock_unlock(mode, &l->lock); | |
} | |
static void | |
@@ -539,22 +487,21 @@ static unsigned long ossl_thread_id(void) | |
} | |
#endif | |
-static struct CRYPTO_dynlock_value *ossl_locks; | |
- | |
-static void | |
-ossl_lock_callback(int mode, int type, const char *file, int line) | |
-{ | |
- ossl_lock_unlock(mode, &ossl_locks[type]); | |
-} | |
- | |
static void Init_ossl_locks(void) | |
{ | |
int i; | |
int num_locks = CRYPTO_num_locks(); | |
- ossl_locks = ALLOC_N(struct CRYPTO_dynlock_value, num_locks); | |
- for (i = 0; i < num_locks; i++) | |
- ossl_lock_init(&ossl_locks[i]); | |
+ if ((unsigned)num_locks >= INT_MAX / (int)sizeof(VALUE)) { | |
+ rb_raise(rb_eRuntimeError, "CRYPTO_num_locks() is too big: %d", num_locks); | |
+ } | |
+ ossl_locks = (rb_nativethread_lock_t *) OPENSSL_malloc(num_locks * (int)sizeof(rb_nativethread_lock_t)); | |
+ if (!ossl_locks) { | |
+ rb_raise(rb_eNoMemError, "CRYPTO_num_locks() is too big: %d", num_locks); | |
+ } | |
+ for (i = 0; i < num_locks; i++) { | |
+ rb_nativethread_lock_initialize(&ossl_locks[i]); | |
+ } | |
#ifdef HAVE_CRYPTO_THREADID_PTR | |
CRYPTO_THREADID_set_callback(ossl_threadid_func); | |
@@ -566,25 +513,12 @@ static void Init_ossl_locks(void) | |
CRYPTO_set_dynlock_lock_callback(ossl_dyn_lock_callback); | |
CRYPTO_set_dynlock_destroy_callback(ossl_dyn_destroy_callback); | |
} | |
+#endif /* !HAVE_OPENSSL_110_THREADING_API */ | |
/* | |
* OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the | |
* OpenSSL[http://www.openssl.org/] library. | |
* | |
- * = Install | |
- * | |
- * OpenSSL comes bundled with the Standard Library of Ruby. | |
- * | |
- * This means the OpenSSL extension is compiled with Ruby and packaged on | |
- * build. During compile time, Ruby will need to link against the OpenSSL | |
- * library on your system. However, you cannot use openssl provided by Apple to | |
- * build standard library openssl. | |
- * | |
- * If you use OSX, you should install another openssl and run ```./configure | |
- * --with-openssl-dir=/path/to/another-openssl```. For Homebrew user, run `brew | |
- * install openssl` and then ```./configure --with-openssl-dir=`brew --prefix | |
- * openssl` ```. | |
- * | |
* = Examples | |
* | |
* All examples assume you have loaded OpenSSL with: | |
@@ -629,10 +563,12 @@ static void Init_ossl_locks(void) | |
* | |
* key2 = OpenSSL::PKey::RSA.new File.read 'private_key.pem' | |
* key2.public? # => true | |
+ * key2.private? # => true | |
* | |
* or | |
* | |
* key3 = OpenSSL::PKey::RSA.new File.read 'public_key.pem' | |
+ * key3.public? # => true | |
* key3.private? # => false | |
* | |
* === Loading an Encrypted Key | |
@@ -642,6 +578,7 @@ static void Init_ossl_locks(void) | |
* loading the key: | |
* | |
* key4_pem = File.read 'private.secure.pem' | |
+ * pass_phrase = 'my secure pass phrase goes here' | |
* key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase | |
* | |
* == RSA Encryption | |
@@ -806,6 +743,7 @@ static void Init_ossl_locks(void) | |
* This example creates a self-signed certificate using an RSA key and a SHA1 | |
* signature. | |
* | |
+ * key = OpenSSL::PKey::RSA.new 2048 | |
* name = OpenSSL::X509::Name.parse 'CN=nobody/DC=example' | |
* | |
* cert = OpenSSL::X509::Certificate.new | |
@@ -875,8 +813,9 @@ static void Init_ossl_locks(void) | |
* not readable by other users. | |
* | |
* ca_key = OpenSSL::PKey::RSA.new 2048 | |
+ * pass_phrase = 'my secure pass phrase goes here' | |
* | |
- * cipher = OpenSSL::Cipher::Cipher.new 'AES-128-CBC' | |
+ * cipher = OpenSSL::Cipher.new 'AES-128-CBC' | |
* | |
* open 'ca_key.pem', 'w', 0400 do |io| | |
* io.write ca_key.export(cipher, pass_phrase) | |
@@ -1029,15 +968,21 @@ static void Init_ossl_locks(void) | |
* SSLSocket#connect must be called to initiate the SSL handshake and start | |
* encryption. A key and certificate are not required for the client socket. | |
* | |
+ * Note that SSLSocket#close doesn't close the underlying socket by default. Set | |
+ * SSLSocket#sync_close to true if you want. | |
+ * | |
* require 'socket' | |
* | |
- * tcp_client = TCPSocket.new 'localhost', 5000 | |
- * ssl_client = OpenSSL::SSL::SSLSocket.new client_socket, context | |
+ * tcp_socket = TCPSocket.new 'localhost', 5000 | |
+ * ssl_client = OpenSSL::SSL::SSLSocket.new tcp_socket, context | |
+ * ssl_client.sync_close = true | |
* ssl_client.connect | |
* | |
* ssl_client.puts "hello server!" | |
* puts ssl_client.gets | |
* | |
+ * ssl_client.close # shutdown the TLS connection and close tcp_socket | |
+ * | |
* === Peer Verification | |
* | |
* An unverified SSL connection does not provide much security. For enhanced | |
@@ -1051,8 +996,8 @@ static void Init_ossl_locks(void) | |
* | |
* require 'socket' | |
* | |
- * tcp_client = TCPSocket.new 'localhost', 5000 | |
- * ssl_client = OpenSSL::SSL::SSLSocket.new client_socket, context | |
+ * tcp_socket = TCPSocket.new 'localhost', 5000 | |
+ * ssl_client = OpenSSL::SSL::SSLSocket.new tcp_socket, context | |
* ssl_client.connect | |
* | |
* ssl_client.puts "hello server!" | |
@@ -1126,11 +1071,14 @@ Init_openssl(void) | |
/* | |
* Boolean indicating whether OpenSSL is FIPS-enabled or not | |
*/ | |
-#ifdef HAVE_OPENSSL_FIPS | |
- rb_define_const(mOSSL, "OPENSSL_FIPS", Qtrue); | |
+ rb_define_const(mOSSL, "OPENSSL_FIPS", | |
+#ifdef OPENSSL_FIPS | |
+ Qtrue | |
#else | |
- rb_define_const(mOSSL, "OPENSSL_FIPS", Qfalse); | |
+ Qfalse | |
#endif | |
+ ); | |
+ | |
rb_define_module_function(mOSSL, "fips_mode=", ossl_fips_mode_set, 1); | |
/* | |
@@ -1140,14 +1088,6 @@ Init_openssl(void) | |
eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError); | |
rb_global_variable(&eOSSLError); | |
- /* | |
- * Verify callback Proc index for ext-data | |
- */ | |
- if ((ossl_store_ctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"ossl_store_ctx_ex_verify_cb_idx", 0, 0, 0)) < 0) | |
- ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); | |
- if ((ossl_store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)"ossl_store_ex_verify_cb_idx", 0, 0, 0)) < 0) | |
- ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index"); | |
- | |
/* | |
* Init debug core | |
*/ | |
@@ -1163,7 +1103,9 @@ Init_openssl(void) | |
*/ | |
ossl_s_to_der = rb_intern("to_der"); | |
+#if !defined(HAVE_OPENSSL_110_THREADING_API) | |
Init_ossl_locks(); | |
+#endif | |
/* | |
* Init components | |
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h | |
index 8e6f2ce7e3..78eddd09b4 100644 | |
--- a/ext/openssl/ossl.h | |
+++ b/ext/openssl/ossl.h | |
@@ -12,49 +12,14 @@ | |
#include RUBY_EXTCONF_H | |
-#if defined(__cplusplus) | |
-extern "C" { | |
-#endif | |
- | |
-#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); | |
- mX509 = rb_define_module_under(mOSSL, "X509"); | |
-#endif | |
- | |
-/* | |
-* OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it! | |
-*/ | |
-#if defined(RFILE) /*&& !defined(OSSL_DEBUG)*/ | |
-# undef RFILE | |
-#endif | |
+#include <assert.h> | |
+#include <errno.h> | |
#include <ruby.h> | |
#include <ruby/io.h> | |
#include <ruby/thread.h> | |
- | |
-/* | |
- * Check the OpenSSL version | |
- * The only supported are: | |
- * OpenSSL >= 0.9.7 | |
- */ | |
#include <openssl/opensslv.h> | |
- | |
-#ifdef HAVE_ASSERT_H | |
-# include <assert.h> | |
-#else | |
-# define assert(condition) | |
-#endif | |
- | |
-#if defined(_WIN32) && !defined(LIBRESSL_VERSION_NUMBER) | |
-# include <openssl/e_os2.h> | |
-# define OSSL_NO_CONF_API 1 | |
-# if !defined(OPENSSL_SYS_WIN32) | |
-# define OPENSSL_SYS_WIN32 1 | |
-# endif | |
-# include <winsock2.h> | |
-#endif | |
-#include <errno.h> | |
#include <openssl/err.h> | |
-#include <openssl/asn1_mac.h> | |
+#include <openssl/asn1.h> | |
#include <openssl/x509v3.h> | |
#include <openssl/ssl.h> | |
#include <openssl/pkcs12.h> | |
@@ -63,25 +28,14 @@ extern "C" { | |
#include <openssl/rand.h> | |
#include <openssl/conf.h> | |
#include <openssl/conf_api.h> | |
-#if !defined(_WIN32) | |
-# include <openssl/crypto.h> | |
-#endif | |
-#undef X509_NAME | |
-#undef PKCS7_SIGNER_INFO | |
-#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_EVP_CIPHER_CTX_ENGINE) | |
-# define OSSL_ENGINE_ENABLED | |
+#include <openssl/crypto.h> | |
+#if !defined(OPENSSL_NO_ENGINE) | |
# include <openssl/engine.h> | |
#endif | |
-#if defined(HAVE_OPENSSL_OCSP_H) | |
-# define OSSL_OCSP_ENABLED | |
+#if !defined(OPENSSL_NO_OCSP) | |
# include <openssl/ocsp.h> | |
#endif | |
-/* OpenSSL requires passwords for PEM-encoded files to be at least four | |
- * characters long | |
- */ | |
-#define OSSL_MIN_PWD_LEN 4 | |
- | |
/* | |
* Common Module | |
*/ | |
@@ -115,27 +69,15 @@ extern VALUE eOSSLError; | |
}\ | |
} while (0) | |
-/* | |
- * Compatibility | |
- */ | |
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L | |
-#define STACK _STACK | |
-#endif | |
- | |
-/* | |
- * String to HEXString conversion | |
- */ | |
-int string2hex(const unsigned char *, int, char **, int *); | |
- | |
/* | |
* Data Conversion | |
*/ | |
STACK_OF(X509) *ossl_x509_ary2sk0(VALUE); | |
STACK_OF(X509) *ossl_x509_ary2sk(VALUE); | |
STACK_OF(X509) *ossl_protect_x509_ary2sk(VALUE,int*); | |
-VALUE ossl_x509_sk2ary(STACK_OF(X509) *certs); | |
-VALUE ossl_x509crl_sk2ary(STACK_OF(X509_CRL) *crl); | |
-VALUE ossl_x509name_sk2ary(STACK_OF(X509_NAME) *names); | |
+VALUE ossl_x509_sk2ary(const STACK_OF(X509) *certs); | |
+VALUE ossl_x509crl_sk2ary(const STACK_OF(X509_CRL) *crl); | |
+VALUE ossl_x509name_sk2ary(const STACK_OF(X509_NAME) *names); | |
VALUE ossl_buf2str(char *buf, int len); | |
#define ossl_str_adjust(str, p) \ | |
do{\ | |
@@ -144,40 +86,39 @@ do{\ | |
assert(newlen <= len);\ | |
rb_str_set_len((str), newlen);\ | |
}while(0) | |
+/* | |
+ * Convert binary string to hex string. The caller is responsible for | |
+ * ensuring out has (2 * len) bytes of capacity. | |
+ */ | |
+void ossl_bin2hex(unsigned char *in, char *out, size_t len); | |
/* | |
- * our default PEM callback | |
+ * Our default PEM callback | |
*/ | |
+/* Convert the argument to String and validate the length. Note this may raise. */ | |
+VALUE ossl_pem_passwd_value(VALUE); | |
+/* Can be casted to pem_password_cb. If a password (String) is passed as the | |
+ * "arbitrary data" (typically the last parameter of PEM_{read,write}_ | |
+ * functions), uses the value. If not, but a block is given, yields to it. | |
+ * If not either, fallbacks to PEM_def_callback() which reads from stdin. */ | |
int ossl_pem_passwd_cb(char *, int, int, void *); | |
/* | |
* Clear BIO* with this in PEM/DER fallback scenarios to avoid decoding | |
* errors piling up in OpenSSL::Errors | |
*/ | |
-#define OSSL_BIO_reset(bio) (void)BIO_reset((bio)); \ | |
- ERR_clear_error(); | |
+#define OSSL_BIO_reset(bio) do { \ | |
+ (void)BIO_reset((bio)); \ | |
+ ossl_clear_error(); \ | |
+} while (0) | |
/* | |
* ERRor messages | |
*/ | |
#define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error()) | |
NORETURN(void ossl_raise(VALUE, const char *, ...)); | |
-VALUE ossl_exc_new(VALUE, const char *, ...); | |
- | |
-/* | |
- * Verify callback | |
- */ | |
-extern int ossl_store_ctx_ex_verify_cb_idx; | |
-extern int ossl_store_ex_verify_cb_idx; | |
- | |
-struct ossl_verify_cb_args { | |
- VALUE proc; | |
- VALUE preverify_ok; | |
- VALUE store_ctx; | |
-}; | |
- | |
-VALUE ossl_call_verify_cb_proc(struct ossl_verify_cb_args *); | |
-int ossl_verify_cb(int, X509_STORE_CTX *); | |
+/* Clear OpenSSL error queue. If dOSSL is set, rb_warn() them. */ | |
+void ossl_clear_error(void); | |
/* | |
* String to DER String | |
@@ -242,8 +183,4 @@ void ossl_debug(const char *, ...); | |
void Init_openssl(void); | |
-#if defined(__cplusplus) | |
-} | |
-#endif | |
- | |
#endif /* _OSSL_H_ */ | |
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c | |
index 444440125c..534796f52a 100644 | |
--- a/ext/openssl/ossl_asn1.c | |
+++ b/ext/openssl/ossl_asn1.c | |
@@ -9,15 +9,6 @@ | |
*/ | |
#include "ossl.h" | |
-#if defined(HAVE_SYS_TIME_H) | |
-# include <sys/time.h> | |
-#elif !defined(NT) && !defined(_WIN32) | |
-struct timeval { | |
- long tv_sec; /* seconds */ | |
- long tv_usec; /* and microseconds */ | |
-}; | |
-#endif | |
- | |
static VALUE join_der(VALUE enumerable); | |
static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset, | |
int depth, int yield, long *num_read); | |
@@ -28,7 +19,7 @@ static VALUE ossl_asn1eoc_initialize(VALUE self); | |
* DATE conversion | |
*/ | |
VALUE | |
-asn1time_to_time(ASN1_TIME *time) | |
+asn1time_to_time(const ASN1_TIME *time) | |
{ | |
struct tm tm; | |
VALUE argv[6]; | |
@@ -56,9 +47,15 @@ asn1time_to_time(ASN1_TIME *time) | |
} | |
break; | |
case V_ASN1_GENERALIZEDTIME: | |
- if (sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon, | |
- &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { | |
- ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format" ); | |
+ count = sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ", | |
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, | |
+ &tm.tm_sec); | |
+ if (count == 5) { | |
+ tm.tm_sec = 0; | |
+ } | |
+ else if (count != 6) { | |
+ ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format: \"%s\"", | |
+ time->data); | |
} | |
break; | |
default: | |
@@ -75,83 +72,65 @@ asn1time_to_time(ASN1_TIME *time) | |
return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv); | |
} | |
-/* | |
- * This function is not exported in Ruby's *.h | |
- */ | |
-extern struct timeval rb_time_timeval(VALUE); | |
+#if defined(HAVE_ASN1_TIME_ADJ) | |
+void | |
+ossl_time_split(VALUE time, time_t *sec, int *days) | |
+{ | |
+ VALUE num = rb_Integer(time); | |
+ if (FIXNUM_P(num)) { | |
+ time_t t = FIX2LONG(num); | |
+ *sec = t % 86400; | |
+ *days = rb_long2int(t / 86400); | |
+ } | |
+ else { | |
+ *days = NUM2INT(rb_funcall(num, rb_intern("/"), 1, INT2FIX(86400))); | |
+ *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400))); | |
+ } | |
+} | |
+#else | |
time_t | |
time_to_time_t(VALUE time) | |
{ | |
- return (time_t)NUM2LONG(rb_Integer(time)); | |
+ return (time_t)NUM2TIMET(rb_Integer(time)); | |
} | |
+#endif | |
/* | |
* STRING conversion | |
*/ | |
VALUE | |
-asn1str_to_str(ASN1_STRING *str) | |
+asn1str_to_str(const ASN1_STRING *str) | |
{ | |
return rb_str_new((const char *)str->data, str->length); | |
} | |
/* | |
* ASN1_INTEGER conversions | |
- * TODO: Make a decision what's the right way to do this. | |
*/ | |
-#define DO_IT_VIA_RUBY 0 | |
VALUE | |
-asn1integer_to_num(ASN1_INTEGER *ai) | |
+asn1integer_to_num(const ASN1_INTEGER *ai) | |
{ | |
BIGNUM *bn; | |
-#if DO_IT_VIA_RUBY | |
- char *txt; | |
-#endif | |
VALUE num; | |
if (!ai) { | |
ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!"); | |
} | |
- if (!(bn = ASN1_INTEGER_to_BN(ai, NULL))) { | |
- ossl_raise(eOSSLError, NULL); | |
- } | |
-#if DO_IT_VIA_RUBY | |
- if (!(txt = BN_bn2dec(bn))) { | |
- BN_free(bn); | |
+ if (ai->type == V_ASN1_ENUMERATED) | |
+ /* const_cast: workaround for old OpenSSL */ | |
+ bn = ASN1_ENUMERATED_to_BN((ASN1_ENUMERATED *)ai, NULL); | |
+ else | |
+ bn = ASN1_INTEGER_to_BN(ai, NULL); | |
+ | |
+ if (!bn) | |
ossl_raise(eOSSLError, NULL); | |
- } | |
- num = rb_cstr_to_inum(txt, 10, Qtrue); | |
- OPENSSL_free(txt); | |
-#else | |
num = ossl_bn_new(bn); | |
-#endif | |
BN_free(bn); | |
return num; | |
} | |
-#if DO_IT_VIA_RUBY | |
-ASN1_INTEGER * | |
-num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) | |
-{ | |
- BIGNUM *bn = NULL; | |
- | |
- if (RTEST(rb_obj_is_kind_of(obj, cBN))) { | |
- bn = GetBNPtr(obj); | |
- } else { | |
- obj = rb_String(obj); | |
- if (!BN_dec2bn(&bn, StringValuePtr(obj))) { | |
- ossl_raise(eOSSLError, NULL); | |
- } | |
- } | |
- if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) { | |
- BN_free(bn); | |
- ossl_raise(eOSSLError, NULL); | |
- } | |
- BN_free(bn); | |
- return ai; | |
-} | |
-#else | |
ASN1_INTEGER * | |
num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) | |
{ | |
@@ -167,7 +146,6 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) | |
return ai; | |
} | |
-#endif | |
/********/ | |
/* | |
@@ -207,22 +185,10 @@ VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */ | |
VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */ | |
VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */ | |
-static ID sIMPLICIT, sEXPLICIT; | |
-static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE; | |
+static VALUE sym_IMPLICIT, sym_EXPLICIT; | |
+static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE; | |
static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINFINITE_LENGTH, sivUNUSED_BITS; | |
- | |
-/* | |
- * We need to implement these for backward compatibility | |
- * reasons, behavior of ASN1_put_object and ASN1_object_size | |
- * for infinite length values is different in OpenSSL <= 0.9.7 | |
- */ | |
-#if OPENSSL_VERSION_NUMBER < 0x00908000L | |
-#define ossl_asn1_object_size(cons, len, tag) (cons) == 2 ? (len) + ASN1_object_size((cons), 0, (tag)) : ASN1_object_size((cons), (len), (tag)) | |
-#define ossl_asn1_put_object(pp, cons, len, tag, xc) (cons) == 2 ? ASN1_put_object((pp), (cons), 0, (tag), (xc)) : ASN1_put_object((pp), (cons), (len), (tag), (xc)) | |
-#else | |
-#define ossl_asn1_object_size(cons, len, tag) ASN1_object_size((cons), (len), (tag)) | |
-#define ossl_asn1_put_object(pp, cons, len, tag, xc) ASN1_put_object((pp), (cons), (len), (tag), (xc)) | |
-#endif | |
+static ID id_each; | |
/* | |
* Ruby to ASN1 converters | |
@@ -233,11 +199,7 @@ obj_to_asn1bool(VALUE obj) | |
if (NIL_P(obj)) | |
ossl_raise(rb_eTypeError, "Can't convert nil into Boolean"); | |
-#if OPENSSL_VERSION_NUMBER < 0x00907000L | |
- return RTEST(obj) ? 0xff : 0x100; | |
-#else | |
return RTEST(obj) ? 0xff : 0x0; | |
-#endif | |
} | |
static ASN1_INTEGER* | |
@@ -293,36 +255,50 @@ obj_to_asn1obj(VALUE obj) | |
{ | |
ASN1_OBJECT *a1obj; | |
- StringValue(obj); | |
+ StringValueCStr(obj); | |
a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0); | |
if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1); | |
- if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID"); | |
+ if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID %"PRIsVALUE, obj); | |
return a1obj; | |
} | |
-static ASN1_UTCTIME* | |
+static ASN1_UTCTIME * | |
obj_to_asn1utime(VALUE time) | |
{ | |
time_t sec; | |
ASN1_UTCTIME *t; | |
+#if defined(HAVE_ASN1_TIME_ADJ) | |
+ int off_days; | |
+ | |
+ ossl_time_split(time, &sec, &off_days); | |
+ if (!(t = ASN1_UTCTIME_adj(NULL, sec, off_days, 0))) | |
+#else | |
sec = time_to_time_t(time); | |
- if(!(t = ASN1_UTCTIME_set(NULL, sec))) | |
- ossl_raise(eASN1Error, NULL); | |
+ if (!(t = ASN1_UTCTIME_set(NULL, sec))) | |
+#endif | |
+ ossl_raise(eASN1Error, NULL); | |
return t; | |
} | |
-static ASN1_GENERALIZEDTIME* | |
+static ASN1_GENERALIZEDTIME * | |
obj_to_asn1gtime(VALUE time) | |
{ | |
time_t sec; | |
ASN1_GENERALIZEDTIME *t; | |
+#if defined(HAVE_ASN1_TIME_ADJ) | |
+ int off_days; | |
+ | |
+ ossl_time_split(time, &sec, &off_days); | |
+ if (!(t = ASN1_GENERALIZEDTIME_adj(NULL, sec, off_days, 0))) | |
+#else | |
sec = time_to_time_t(time); | |
- if(!(t =ASN1_GENERALIZEDTIME_set(NULL, sec))) | |
- ossl_raise(eASN1Error, NULL); | |
+ if (!(t = ASN1_GENERALIZEDTIME_set(NULL, sec))) | |
+#endif | |
+ ossl_raise(eASN1Error, NULL); | |
return t; | |
} | |
@@ -347,14 +323,14 @@ obj_to_asn1derstr(VALUE obj) | |
static VALUE | |
decode_bool(unsigned char* der, long length) | |
{ | |
- int val; | |
- const unsigned char *p; | |
+ const unsigned char *p = der; | |
- p = der; | |
- if((val = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0) | |
- ossl_raise(eASN1Error, NULL); | |
+ if (length != 3) | |
+ ossl_raise(eASN1Error, "invalid length for BOOLEAN"); | |
+ if (p[0] != 1 || p[1] != 1) | |
+ ossl_raise(eASN1Error, "invalid BOOLEAN"); | |
- return val ? Qtrue : Qfalse; | |
+ return p[2] ? Qtrue : Qfalse; | |
} | |
static VALUE | |
@@ -368,7 +344,7 @@ decode_int(unsigned char* der, long length) | |
p = der; | |
if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length))) | |
ossl_raise(eASN1Error, NULL); | |
- ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num, | |
+ ret = rb_protect((VALUE (*)(VALUE))asn1integer_to_num, | |
(VALUE)ai, &status); | |
ASN1_INTEGER_free(ai); | |
if(status) rb_jump_tag(status); | |
@@ -408,7 +384,7 @@ decode_enum(unsigned char* der, long length) | |
p = der; | |
if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length))) | |
ossl_raise(eASN1Error, NULL); | |
- ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num, | |
+ ret = rb_protect((VALUE (*)(VALUE))asn1integer_to_num, | |
(VALUE)ai, &status); | |
ASN1_ENUMERATED_free(ai); | |
if(status) rb_jump_tag(status); | |
@@ -470,7 +446,7 @@ decode_time(unsigned char* der, long length) | |
p = der; | |
if(!(time = d2i_ASN1_TIME(NULL, &p, length))) | |
ossl_raise(eASN1Error, NULL); | |
- ret = rb_protect((VALUE(*)_((VALUE)))asn1time_to_time, | |
+ ret = rb_protect((VALUE (*)(VALUE))asn1time_to_time, | |
(VALUE)time, &status); | |
ASN1_TIME_free(time); | |
if(status) rb_jump_tag(status); | |
@@ -616,17 +592,14 @@ ossl_asn1_default_tag(VALUE obj) | |
VALUE tmp_class, tag; | |
tmp_class = CLASS_OF(obj); | |
- while (tmp_class) { | |
+ while (!NIL_P(tmp_class)) { | |
tag = rb_hash_lookup(class_tag_map, tmp_class); | |
- if (tag != Qnil) { | |
- return NUM2INT(tag); | |
- } | |
- tmp_class = rb_class_superclass(tmp_class); | |
+ if (tag != Qnil) | |
+ return NUM2INT(tag); | |
+ tmp_class = rb_class_superclass(tmp_class); | |
} | |
ossl_raise(eASN1Error, "universal tag for %"PRIsVALUE" not found", | |
rb_obj_class(obj)); | |
- | |
- return -1; /* dummy */ | |
} | |
static int | |
@@ -645,59 +618,45 @@ static int | |
ossl_asn1_is_explicit(VALUE obj) | |
{ | |
VALUE s; | |
- int ret = -1; | |
s = ossl_asn1_get_tagging(obj); | |
- if(NIL_P(s)) return 0; | |
- else if(SYMBOL_P(s)){ | |
- if (SYM2ID(s) == sIMPLICIT) | |
- ret = 0; | |
- else if (SYM2ID(s) == sEXPLICIT) | |
- ret = 1; | |
- } | |
- if(ret < 0){ | |
+ if (NIL_P(s) || s == sym_IMPLICIT) | |
+ return 0; | |
+ else if (s == sym_EXPLICIT) | |
+ return 1; | |
+ else | |
ossl_raise(eASN1Error, "invalid tag default"); | |
- } | |
- | |
- return ret; | |
} | |
static int | |
ossl_asn1_tag_class(VALUE obj) | |
{ | |
VALUE s; | |
- int ret = -1; | |
s = ossl_asn1_get_tag_class(obj); | |
- if(NIL_P(s)) ret = V_ASN1_UNIVERSAL; | |
- else if(SYMBOL_P(s)){ | |
- if (SYM2ID(s) == sUNIVERSAL) | |
- ret = V_ASN1_UNIVERSAL; | |
- else if (SYM2ID(s) == sAPPLICATION) | |
- ret = V_ASN1_APPLICATION; | |
- else if (SYM2ID(s) == sCONTEXT_SPECIFIC) | |
- ret = V_ASN1_CONTEXT_SPECIFIC; | |
- else if (SYM2ID(s) == sPRIVATE) | |
- ret = V_ASN1_PRIVATE; | |
- } | |
- if(ret < 0){ | |
+ if (NIL_P(s) || s == sym_UNIVERSAL) | |
+ return V_ASN1_UNIVERSAL; | |
+ else if (s == sym_APPLICATION) | |
+ return V_ASN1_APPLICATION; | |
+ else if (s == sym_CONTEXT_SPECIFIC) | |
+ return V_ASN1_CONTEXT_SPECIFIC; | |
+ else if (s == sym_PRIVATE) | |
+ return V_ASN1_PRIVATE; | |
+ else | |
ossl_raise(eASN1Error, "invalid tag class"); | |
- } | |
- | |
- return ret; | |
} | |
static VALUE | |
ossl_asn1_class2sym(int tc) | |
{ | |
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) | |
- return ID2SYM(sPRIVATE); | |
+ return sym_PRIVATE; | |
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) | |
- return ID2SYM(sCONTEXT_SPECIFIC); | |
+ return sym_CONTEXT_SPECIFIC; | |
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) | |
- return ID2SYM(sAPPLICATION); | |
+ return sym_APPLICATION; | |
else | |
- return ID2SYM(sUNIVERSAL); | |
+ return sym_UNIVERSAL; | |
} | |
/* | |
@@ -721,7 +680,7 @@ ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class) | |
{ | |
if(!SYMBOL_P(tag_class)) | |
ossl_raise(eASN1Error, "invalid tag class"); | |
- if((SYM2ID(tag_class) == sUNIVERSAL) && NUM2INT(tag) > 31) | |
+ if (tag_class == sym_UNIVERSAL && NUM2INT(tag) > 31) | |
ossl_raise(eASN1Error, "tag number for Universal too large"); | |
ossl_asn1_set_tag(self, tag); | |
ossl_asn1_set_value(self, value); | |
@@ -744,7 +703,7 @@ static VALUE | |
join_der(VALUE enumerable) | |
{ | |
VALUE str = rb_str_new(0, 0); | |
- rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str); | |
+ rb_block_call(enumerable, id_each, 0, 0, join_der_i, str); | |
return str; | |
} | |
@@ -778,11 +737,11 @@ ossl_asn1data_to_der(VALUE self) | |
if (inf_length == Qtrue) { | |
is_cons = 2; | |
} | |
- if((length = ossl_asn1_object_size(is_cons, RSTRING_LENINT(value), tag)) <= 0) | |
+ if((length = ASN1_object_size(is_cons, RSTRING_LENINT(value), tag)) <= 0) | |
ossl_raise(eASN1Error, NULL); | |
der = rb_str_new(0, length); | |
p = (unsigned char *)RSTRING_PTR(der); | |
- ossl_asn1_put_object(&p, is_cons, RSTRING_LENINT(value), tag, tag_class); | |
+ ASN1_put_object(&p, is_cons, RSTRING_LENINT(value), tag, tag_class); | |
memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); | |
p += RSTRING_LEN(value); | |
ossl_str_adjust(der, p); | |
@@ -800,7 +759,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, | |
p = *pp; | |
- if(tc == sUNIVERSAL && tag < ossl_asn1_info_size) { | |
+ if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) { | |
switch(tag){ | |
case V_ASN1_EOC: | |
value = decode_eoc(p, hlen+length); | |
@@ -842,13 +801,14 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, | |
*pp += hlen + length; | |
*num_read = hlen + length; | |
- if (tc == sUNIVERSAL && tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) { | |
+ if (tc == sym_UNIVERSAL && | |
+ tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) { | |
VALUE klass = *ossl_asn1_info[tag].klass; | |
VALUE args[4]; | |
args[0] = value; | |
args[1] = INT2NUM(tag); | |
args[2] = Qnil; | |
- args[3] = ID2SYM(tc); | |
+ args[3] = tc; | |
asn1data = rb_obj_alloc(klass); | |
ossl_asn1_initialize(4, args, asn1data); | |
if(tag == V_ASN1_BIT_STRING){ | |
@@ -857,7 +817,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, | |
} | |
else { | |
asn1data = rb_obj_alloc(cASN1Data); | |
- ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), ID2SYM(tc)); | |
+ ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc); | |
} | |
return asn1data; | |
@@ -885,12 +845,12 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, | |
if (infinite && | |
NUM2INT(ossl_asn1_get_tag(value)) == V_ASN1_EOC && | |
- SYM2ID(ossl_asn1_get_tag_class(value)) == sUNIVERSAL) { | |
+ ossl_asn1_get_tag_class(value) == sym_UNIVERSAL) { | |
break; | |
} | |
} | |
- if (tc == sUNIVERSAL) { | |
+ if (tc == sym_UNIVERSAL) { | |
VALUE args[4]; | |
int not_sequence_or_set; | |
@@ -912,12 +872,12 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, | |
args[0] = ary; | |
args[1] = INT2NUM(tag); | |
args[2] = Qnil; | |
- args[3] = ID2SYM(tc); | |
+ args[3] = tc; | |
ossl_asn1_initialize(4, args, asn1data); | |
} | |
else { | |
asn1data = rb_obj_alloc(cASN1Data); | |
- ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), ID2SYM(tc)); | |
+ ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc); | |
} | |
if (infinite) | |
@@ -947,13 +907,13 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, | |
if(j & 0x80) ossl_raise(eASN1Error, NULL); | |
if(len > length) ossl_raise(eASN1Error, "value is too short"); | |
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) | |
- tag_class = sPRIVATE; | |
+ tag_class = sym_PRIVATE; | |
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) | |
- tag_class = sCONTEXT_SPECIFIC; | |
+ tag_class = sym_CONTEXT_SPECIFIC; | |
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) | |
- tag_class = sAPPLICATION; | |
+ tag_class = sym_APPLICATION; | |
else | |
- tag_class = sUNIVERSAL; | |
+ tag_class = sym_UNIVERSAL; | |
hlen = p - start; | |
@@ -1145,19 +1105,19 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) | |
ossl_raise(eASN1Error, "invalid tagging method"); | |
if(NIL_P(tag_class)) { | |
if (NIL_P(tagging)) | |
- tag_class = ID2SYM(sUNIVERSAL); | |
+ tag_class = sym_UNIVERSAL; | |
else | |
- tag_class = ID2SYM(sCONTEXT_SPECIFIC); | |
+ tag_class = sym_CONTEXT_SPECIFIC; | |
} | |
if(!SYMBOL_P(tag_class)) | |
ossl_raise(eASN1Error, "invalid tag class"); | |
- if(!NIL_P(tagging) && SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31) | |
+ if (tagging == sym_IMPLICIT && NUM2INT(tag) > 31) | |
ossl_raise(eASN1Error, "tag number for Universal too large"); | |
} | |
else{ | |
tag = INT2NUM(ossl_asn1_default_tag(self)); | |
tagging = Qnil; | |
- tag_class = ID2SYM(sUNIVERSAL); | |
+ tag_class = sym_UNIVERSAL; | |
} | |
ossl_asn1_set_tag(self, tag); | |
ossl_asn1_set_value(self, value); | |
@@ -1173,7 +1133,7 @@ ossl_asn1eoc_initialize(VALUE self) { | |
VALUE tag, tagging, tag_class, value; | |
tag = INT2NUM(ossl_asn1_default_tag(self)); | |
tagging = Qnil; | |
- tag_class = ID2SYM(sUNIVERSAL); | |
+ tag_class = sym_UNIVERSAL; | |
value = rb_str_new("", 0); | |
ossl_asn1_set_tag(self, tag); | |
ossl_asn1_set_value(self, value); | |
@@ -1183,30 +1143,6 @@ ossl_asn1eoc_initialize(VALUE self) { | |
return self; | |
} | |
-static int | |
-ossl_i2d_ASN1_TYPE(ASN1_TYPE *a, unsigned char **pp) | |
-{ | |
-#if OPENSSL_VERSION_NUMBER < 0x00907000L | |
- if(!a) return 0; | |
- if(a->type == V_ASN1_BOOLEAN) | |
- return i2d_ASN1_BOOLEAN(a->value.boolean, pp); | |
-#endif | |
- return i2d_ASN1_TYPE(a, pp); | |
-} | |
- | |
-static void | |
-ossl_ASN1_TYPE_free(ASN1_TYPE *a) | |
-{ | |
-#if OPENSSL_VERSION_NUMBER < 0x00907000L | |
- if(!a) return; | |
- if(a->type == V_ASN1_BOOLEAN){ | |
- OPENSSL_free(a); | |
- return; | |
- } | |
-#endif | |
- ASN1_TYPE_free(a); | |
-} | |
- | |
/* | |
* call-seq: | |
* asn1.to_der => DER-encoded String | |
@@ -1227,22 +1163,22 @@ ossl_asn1prim_to_der(VALUE self) | |
explicit = ossl_asn1_is_explicit(self); | |
asn1 = ossl_asn1_get_asn1type(self); | |
- len = ossl_asn1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn); | |
+ len = ASN1_object_size(1, i2d_ASN1_TYPE(asn1, NULL), tn); | |
if(!(buf = OPENSSL_malloc(len))){ | |
- ossl_ASN1_TYPE_free(asn1); | |
+ ASN1_TYPE_free(asn1); | |
ossl_raise(eASN1Error, "cannot alloc buffer"); | |
} | |
p = buf; | |
if (tc == V_ASN1_UNIVERSAL) { | |
- ossl_i2d_ASN1_TYPE(asn1, &p); | |
+ i2d_ASN1_TYPE(asn1, &p); | |
} else if (explicit) { | |
- ossl_asn1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc); | |
- ossl_i2d_ASN1_TYPE(asn1, &p); | |
+ ASN1_put_object(&p, 1, i2d_ASN1_TYPE(asn1, NULL), tn, tc); | |
+ i2d_ASN1_TYPE(asn1, &p); | |
} else { | |
- ossl_i2d_ASN1_TYPE(asn1, &p); | |
+ i2d_ASN1_TYPE(asn1, &p); | |
*buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED); | |
} | |
- ossl_ASN1_TYPE_free(asn1); | |
+ ASN1_TYPE_free(asn1); | |
reallen = p - buf; | |
assert(reallen <= len); | |
str = ossl_buf2str((char *)buf, rb_long2int(reallen)); /* buf will be free in ossl_buf2str */ | |
@@ -1271,8 +1207,8 @@ ossl_asn1cons_to_der(VALUE self) | |
if (inf_length == Qtrue) { | |
VALUE ary, example; | |
constructed = 2; | |
- if (CLASS_OF(self) == cASN1Sequence || | |
- CLASS_OF(self) == cASN1Set) { | |
+ if (rb_obj_class(self) == cASN1Sequence || | |
+ rb_obj_class(self) == cASN1Set) { | |
tag = ossl_asn1_default_tag(self); | |
} | |
else { /* must be a constructive encoding of a primitive value */ | |
@@ -1301,26 +1237,26 @@ ossl_asn1cons_to_der(VALUE self) | |
} | |
} | |
else { | |
- if (CLASS_OF(self) == cASN1Constructive) | |
+ if (rb_obj_class(self) == cASN1Constructive) | |
ossl_raise(eASN1Error, "Constructive shall only be used with infinite length"); | |
tag = ossl_asn1_default_tag(self); | |
} | |
explicit = ossl_asn1_is_explicit(self); | |
value = join_der(ossl_asn1_get_value(self)); | |
- seq_len = ossl_asn1_object_size(constructed, RSTRING_LENINT(value), tag); | |
- length = ossl_asn1_object_size(constructed, seq_len, tn); | |
+ seq_len = ASN1_object_size(constructed, RSTRING_LENINT(value), tag); | |
+ length = ASN1_object_size(constructed, seq_len, tn); | |
str = rb_str_new(0, length); | |
p = (unsigned char *)RSTRING_PTR(str); | |
if(tc == V_ASN1_UNIVERSAL) | |
- ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc); | |
+ ASN1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc); | |
else{ | |
if(explicit){ | |
- ossl_asn1_put_object(&p, constructed, seq_len, tn, tc); | |
- ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tag, V_ASN1_UNIVERSAL); | |
+ ASN1_put_object(&p, constructed, seq_len, tn, tc); | |
+ ASN1_put_object(&p, constructed, RSTRING_LENINT(value), tag, V_ASN1_UNIVERSAL); | |
} | |
else{ | |
- ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc); | |
+ ASN1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc); | |
} | |
} | |
memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); | |
@@ -1355,7 +1291,8 @@ ossl_asn1cons_to_der(VALUE self) | |
static VALUE | |
ossl_asn1cons_each(VALUE self) | |
{ | |
- rb_ary_each(ossl_asn1_get_value(self)); | |
+ rb_funcall(ossl_asn1_get_value(self), id_each, 0); | |
+ | |
return self; | |
} | |
@@ -1373,9 +1310,9 @@ ossl_asn1cons_each(VALUE self) | |
static VALUE | |
ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln) | |
{ | |
- StringValue(oid); | |
- StringValue(sn); | |
- StringValue(ln); | |
+ StringValueCStr(oid); | |
+ StringValueCStr(sn); | |
+ StringValueCStr(ln); | |
if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln))) | |
ossl_raise(eASN1Error, NULL); | |
@@ -1398,7 +1335,7 @@ ossl_asn1obj_get_sn(VALUE self) | |
int nid; | |
val = ossl_asn1_get_value(self); | |
- if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef) | |
+ if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef) | |
ret = rb_str_new2(OBJ_nid2sn(nid)); | |
return ret; | |
@@ -1419,7 +1356,7 @@ ossl_asn1obj_get_ln(VALUE self) | |
int nid; | |
val = ossl_asn1_get_value(self); | |
- if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef) | |
+ if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef) | |
ret = rb_str_new2(OBJ_nid2ln(nid)); | |
return ret; | |
@@ -1479,15 +1416,16 @@ Init_ossl_asn1(void) | |
int i; | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
- sUNIVERSAL = rb_intern("UNIVERSAL"); | |
- sCONTEXT_SPECIFIC = rb_intern("CONTEXT_SPECIFIC"); | |
- sAPPLICATION = rb_intern("APPLICATION"); | |
- sPRIVATE = rb_intern("PRIVATE"); | |
- sEXPLICIT = rb_intern("EXPLICIT"); | |
- sIMPLICIT = rb_intern("IMPLICIT"); | |
+ sym_UNIVERSAL = ID2SYM(rb_intern_const("UNIVERSAL")); | |
+ sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const("CONTEXT_SPECIFIC")); | |
+ sym_APPLICATION = ID2SYM(rb_intern_const("APPLICATION")); | |
+ sym_PRIVATE = ID2SYM(rb_intern_const("PRIVATE")); | |
+ sym_EXPLICIT = ID2SYM(rb_intern_const("EXPLICIT")); | |
+ sym_IMPLICIT = ID2SYM(rb_intern_const("IMPLICIT")); | |
sivVALUE = rb_intern("@value"); | |
sivTAG = rb_intern("@tag"); | |
@@ -1814,10 +1752,6 @@ Init_ossl_asn1(void) | |
* it is not typically allocated this way, but rather that are received from | |
* parsed ASN1 encodings. | |
* | |
- * While OpenSSL::ASN1::ObjectId.new will allocate a new ObjectId, it is | |
- * not typically allocated this way, but rather that are received from | |
- * parsed ASN1 encodings. | |
- * | |
* === Additional attributes | |
* * +sn+: the short name as defined in <openssl/objects.h>. | |
* * +ln+: the long name as defined in <openssl/objects.h>. | |
@@ -1999,4 +1933,6 @@ do{\ | |
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING)); | |
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING)); | |
rb_global_variable(&class_tag_map); | |
+ | |
+ id_each = rb_intern_const("each"); | |
} | |
diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h | |
index 8250746c79..d6a170c86c 100644 | |
--- a/ext/openssl/ossl_asn1.h | |
+++ b/ext/openssl/ossl_asn1.h | |
@@ -13,18 +13,26 @@ | |
/* | |
* ASN1_DATE conversions | |
*/ | |
-VALUE asn1time_to_time(ASN1_TIME *); | |
+VALUE asn1time_to_time(const ASN1_TIME *); | |
+#if defined(HAVE_ASN1_TIME_ADJ) | |
+/* Splits VALUE to seconds and offset days. VALUE is typically a Time or an | |
+ * Integer. This is used when updating ASN1_*TIME with ASN1_TIME_adj() or | |
+ * X509_time_adj_ex(). We can't use ASN1_TIME_set() and X509_time_adj() because | |
+ * they have the Year 2038 issue on sizeof(time_t) == 4 environment */ | |
+void ossl_time_split(VALUE, time_t *, int *); | |
+#else | |
time_t time_to_time_t(VALUE); | |
+#endif | |
/* | |
* ASN1_STRING conversions | |
*/ | |
-VALUE asn1str_to_str(ASN1_STRING *); | |
+VALUE asn1str_to_str(const ASN1_STRING *); | |
/* | |
* ASN1_INTEGER conversions | |
*/ | |
-VALUE asn1integer_to_num(ASN1_INTEGER *); | |
+VALUE asn1integer_to_num(const ASN1_INTEGER *); | |
ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *); | |
/* | |
diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c | |
index 285d0533e7..1609b097c0 100644 | |
--- a/ext/openssl/ossl_bio.c | |
+++ b/ext/openssl/ossl_bio.c | |
@@ -8,27 +8,50 @@ | |
* (See the file 'LICENCE'.) | |
*/ | |
#include "ossl.h" | |
-#ifdef HAVE_UNISTD_H | |
-#include <unistd.h> | |
-#endif | |
BIO * | |
-ossl_obj2bio(volatile VALUE *pobj) | |
+ossl_obj2bio(VALUE obj) | |
{ | |
- VALUE obj = *pobj; | |
BIO *bio; | |
- if (RB_TYPE_P(obj, T_FILE)) | |
- obj = rb_funcallv(obj, rb_intern("read"), 0, NULL); | |
- StringValue(obj); | |
- bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj)); | |
- if (!bio) | |
- ossl_raise(eOSSLError, "BIO_new_mem_buf"); | |
- *pobj = obj; | |
+ if (RB_TYPE_P(obj, T_FILE)) { | |
+ rb_io_t *fptr; | |
+ FILE *fp; | |
+ int fd; | |
+ | |
+ GetOpenFile(obj, fptr); | |
+ rb_io_check_readable(fptr); | |
+ if ((fd = rb_cloexec_dup(FPTR_TO_FD(fptr))) < 0){ | |
+ rb_sys_fail(0); | |
+ } | |
+ rb_update_max_fd(fd); | |
+ if (!(fp = fdopen(fd, "r"))){ | |
+ int e = errno; | |
+ close(fd); | |
+ rb_syserr_fail(e, 0); | |
+ } | |
+ if (!(bio = BIO_new_fp(fp, BIO_CLOSE))){ | |
+ fclose(fp); | |
+ ossl_raise(eOSSLError, NULL); | |
+ } | |
+ } | |
+ else { | |
+ StringValue(obj); | |
+ bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj)); | |
+ if (!bio) ossl_raise(eOSSLError, NULL); | |
+ } | |
return bio; | |
} | |
+BIO * | |
+ossl_protect_obj2bio(VALUE obj, int *status) | |
+{ | |
+ BIO *ret = NULL; | |
+ ret = (BIO*)rb_protect((VALUE (*)(VALUE))ossl_obj2bio, obj, status); | |
+ return ret; | |
+} | |
+ | |
VALUE | |
ossl_membio2str0(BIO *bio) | |
{ | |
@@ -44,7 +67,7 @@ ossl_membio2str0(BIO *bio) | |
VALUE | |
ossl_protect_membio2str(BIO *bio, int *status) | |
{ | |
- return rb_protect((VALUE(*)_((VALUE)))ossl_membio2str0, (VALUE)bio, status); | |
+ return rb_protect((VALUE (*)(VALUE))ossl_membio2str0, (VALUE)bio, status); | |
} | |
VALUE | |
diff --git a/ext/openssl/ossl_bio.h b/ext/openssl/ossl_bio.h | |
index 2c3d952b38..1705d0ac89 100644 | |
--- a/ext/openssl/ossl_bio.h | |
+++ b/ext/openssl/ossl_bio.h | |
@@ -10,7 +10,8 @@ | |
#if !defined(_OSSL_BIO_H_) | |
#define _OSSL_BIO_H_ | |
-BIO *ossl_obj2bio(volatile VALUE *); | |
+BIO *ossl_obj2bio(VALUE); | |
+BIO *ossl_protect_obj2bio(VALUE,int*); | |
VALUE ossl_membio2str0(BIO*); | |
VALUE ossl_membio2str(BIO*); | |
VALUE ossl_protect_membio2str(BIO*,int*); | |
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c | |
index 57bb68099a..4e371cb201 100644 | |
--- a/ext/openssl/ossl_bn.c | |
+++ b/ext/openssl/ossl_bn.c | |
@@ -37,17 +37,12 @@ ossl_bn_free(void *ptr) | |
BN_clear_free(ptr); | |
} | |
-static size_t | |
-ossl_bn_size(const void *ptr) | |
-{ | |
- return sizeof(BIGNUM); | |
-} | |
- | |
static const rb_data_type_t ossl_bn_type = { | |
"OpenSSL/BN", | |
- {0, ossl_bn_free, ossl_bn_size,}, | |
- 0, 0, | |
- RUBY_TYPED_FREE_IMMEDIATELY, | |
+ { | |
+ 0, ossl_bn_free, | |
+ }, | |
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
}; | |
/* | |
@@ -56,8 +51,6 @@ static const rb_data_type_t ossl_bn_type = { | |
VALUE cBN; | |
/* Document-class: OpenSSL::BNError | |
- * | |
- * BNError < OpenSSLError | |
* | |
* Generic Error for all of OpenSSL::BN (big num) | |
*/ | |
@@ -83,33 +76,78 @@ ossl_bn_new(const BIGNUM *bn) | |
} | |
static BIGNUM * | |
-try_convert_to_bnptr(VALUE obj) | |
+integer_to_bnptr(VALUE obj, BIGNUM *orig) | |
{ | |
- BIGNUM *bn = NULL; | |
- VALUE newobj; | |
+ BIGNUM *bn; | |
- if (RTEST(rb_obj_is_kind_of(obj, cBN))) { | |
- GetBN(obj, bn); | |
- } else switch (TYPE(obj)) { | |
- case T_FIXNUM: | |
- case T_BIGNUM: | |
- obj = rb_String(obj); | |
- newobj = NewBN(cBN); /* GC bug */ | |
- if (!BN_dec2bn(&bn, StringValuePtr(obj))) { | |
- ossl_raise(eBNError, NULL); | |
+ if (FIXNUM_P(obj)) { | |
+ long i; | |
+ unsigned char bin[sizeof(long)]; | |
+ long n = FIX2LONG(obj); | |
+ unsigned long un = labs(n); | |
+ | |
+ for (i = sizeof(long) - 1; 0 <= i; i--) { | |
+ bin[i] = un & 0xff; | |
+ un >>= 8; | |
} | |
- SetBN(newobj, bn); /* Handle potencial mem leaks */ | |
- break; | |
+ | |
+ bn = BN_bin2bn(bin, sizeof(bin), orig); | |
+ if (!bn) | |
+ ossl_raise(eBNError, "BN_bin2bn"); | |
+ if (n < 0) | |
+ BN_set_negative(bn, 1); | |
+ } | |
+ else { /* assuming Bignum */ | |
+ size_t len = rb_absint_size(obj, NULL); | |
+ unsigned char *bin; | |
+ VALUE buf; | |
+ int sign; | |
+ | |
+ if (INT_MAX < len) { | |
+ rb_raise(eBNError, "bignum too long"); | |
+ } | |
+ bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len); | |
+ sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN); | |
+ | |
+ bn = BN_bin2bn(bin, (int)len, orig); | |
+ ALLOCV_END(buf); | |
+ if (!bn) | |
+ ossl_raise(eBNError, "BN_bin2bn"); | |
+ if (sign < 0) | |
+ BN_set_negative(bn, 1); | |
} | |
+ | |
return bn; | |
} | |
+static VALUE | |
+try_convert_to_bn(VALUE obj) | |
+{ | |
+ BIGNUM *bn; | |
+ VALUE newobj = Qnil; | |
+ | |
+ if (rb_obj_is_kind_of(obj, cBN)) | |
+ return obj; | |
+ if (RB_INTEGER_TYPE_P(obj)) { | |
+ newobj = NewBN(cBN); /* Handle potencial mem leaks */ | |
+ bn = integer_to_bnptr(obj, NULL); | |
+ SetBN(newobj, bn); | |
+ } | |
+ | |
+ return newobj; | |
+} | |
+ | |
BIGNUM * | |
-GetBNPtr(VALUE obj) | |
+ossl_bn_value_ptr(volatile VALUE *ptr) | |
{ | |
- BIGNUM *bn = try_convert_to_bnptr(obj); | |
- if (!bn) | |
+ VALUE tmp; | |
+ BIGNUM *bn; | |
+ | |
+ tmp = try_convert_to_bn(*ptr); | |
+ if (NIL_P(tmp)) | |
ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN"); | |
+ GetBN(tmp, bn); | |
+ *ptr = tmp; | |
return bn; | |
} | |
@@ -140,6 +178,7 @@ ossl_bn_alloc(VALUE klass) | |
/* Document-method: OpenSSL::BN.new | |
* | |
+ * call-seq: | |
* OpenSSL::BN.new => aBN | |
* OpenSSL::BN.new(bn) => aBN | |
* OpenSSL::BN.new(integer) => aBN | |
@@ -159,45 +198,13 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) | |
base = NUM2INT(bs); | |
} | |
- if (RB_TYPE_P(str, T_FIXNUM)) { | |
- long i; | |
- unsigned char bin[sizeof(long)]; | |
- long n = FIX2LONG(str); | |
- unsigned long un = labs(n); | |
- | |
- for (i = sizeof(long) - 1; 0 <= i; i--) { | |
- bin[i] = un&0xff; | |
- un >>= 8; | |
- } | |
- | |
+ if (RB_INTEGER_TYPE_P(str)) { | |
GetBN(self, bn); | |
- if (!BN_bin2bn(bin, sizeof(bin), bn)) { | |
- ossl_raise(eBNError, NULL); | |
- } | |
- if (n < 0) BN_set_negative(bn, 1); | |
- return self; | |
- } | |
- else if (RB_TYPE_P(str, T_BIGNUM)) { | |
- size_t len = rb_absint_size(str, NULL); | |
- unsigned char *bin; | |
- VALUE buf; | |
- int sign; | |
- | |
- if (INT_MAX < len) { | |
- rb_raise(eBNError, "bignum too long"); | |
- } | |
- bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len); | |
- sign = rb_integer_pack(str, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN); | |
+ integer_to_bnptr(str, bn); | |
- GetBN(self, bn); | |
- if (!BN_bin2bn(bin, (int)len, bn)) { | |
- ALLOCV_END(buf); | |
- ossl_raise(eBNError, NULL); | |
- } | |
- ALLOCV_END(buf); | |
- if (sign < 0) BN_set_negative(bn, 1); | |
return self; | |
} | |
+ | |
if (RTEST(rb_obj_is_kind_of(str, cBN))) { | |
BIGNUM *other; | |
@@ -209,26 +216,25 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
- StringValue(str); | |
GetBN(self, bn); | |
switch (base) { | |
case 0: | |
- if (!BN_mpi2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) { | |
+ if (!BN_mpi2bn((unsigned char *)StringValuePtr(str), RSTRING_LENINT(str), bn)) { | |
ossl_raise(eBNError, NULL); | |
} | |
break; | |
case 2: | |
- if (!BN_bin2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) { | |
+ if (!BN_bin2bn((unsigned char *)StringValuePtr(str), RSTRING_LENINT(str), bn)) { | |
ossl_raise(eBNError, NULL); | |
} | |
break; | |
case 10: | |
- if (!BN_dec2bn(&bn, RSTRING_PTR(str))) { | |
+ if (!BN_dec2bn(&bn, StringValueCStr(str))) { | |
ossl_raise(eBNError, NULL); | |
} | |
break; | |
case 16: | |
- if (!BN_hex2bn(&bn, RSTRING_PTR(str))) { | |
+ if (!BN_hex2bn(&bn, StringValueCStr(str))) { | |
ossl_raise(eBNError, NULL); | |
} | |
break; | |
@@ -245,11 +251,11 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) | |
* | |
* === Parameters | |
* * +base+ - integer | |
- * * * Valid values: | |
- * * * * 0 - MPI | |
- * * * * 2 - binary | |
- * * * * 10 - the default | |
- * * * * 16 - hex | |
+ * Valid values: | |
+ * * 0 - MPI | |
+ * * 2 - binary | |
+ * * 10 - the default | |
+ * * 16 - hex | |
*/ | |
static VALUE | |
ossl_bn_to_s(int argc, VALUE *argv, VALUE self) | |
@@ -352,18 +358,21 @@ ossl_bn_coerce(VALUE self, VALUE other) | |
/* | |
* Document-method: OpenSSL::BN#zero? | |
+ * call-seq: | |
* bn.zero? => true | false | |
*/ | |
BIGNUM_BOOL1(is_zero) | |
/* | |
* Document-method: OpenSSL::BN#one? | |
+ * call-seq: | |
* bn.one? => true | false | |
*/ | |
BIGNUM_BOOL1(is_one) | |
/* | |
* Document-method: OpenSSL::BN#odd? | |
+ * call-seq: | |
* bn.odd? => true | false | |
*/ | |
BIGNUM_BOOL1(is_odd) | |
@@ -375,7 +384,7 @@ BIGNUM_BOOL1(is_odd) | |
BIGNUM *bn, *result; \ | |
VALUE obj; \ | |
GetBN(self, bn); \ | |
- obj = NewBN(CLASS_OF(self)); \ | |
+ obj = NewBN(rb_obj_class(self)); \ | |
if (!(result = BN_new())) { \ | |
ossl_raise(eBNError, NULL); \ | |
} \ | |
@@ -389,6 +398,7 @@ BIGNUM_BOOL1(is_odd) | |
/* | |
* Document-method: OpenSSL::BN#sqr | |
+ * call-seq: | |
* bn.sqr => aBN | |
*/ | |
BIGNUM_1c(sqr) | |
@@ -400,7 +410,7 @@ BIGNUM_1c(sqr) | |
BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ | |
VALUE obj; \ | |
GetBN(self, bn1); \ | |
- obj = NewBN(CLASS_OF(self)); \ | |
+ obj = NewBN(rb_obj_class(self)); \ | |
if (!(result = BN_new())) { \ | |
ossl_raise(eBNError, NULL); \ | |
} \ | |
@@ -414,12 +424,14 @@ BIGNUM_1c(sqr) | |
/* | |
* Document-method: OpenSSL::BN#+ | |
+ * call-seq: | |
* bn + bn2 => aBN | |
*/ | |
BIGNUM_2(add) | |
/* | |
* Document-method: OpenSSL::BN#- | |
+ * call-seq: | |
* bn - bn2 => aBN | |
*/ | |
BIGNUM_2(sub) | |
@@ -431,7 +443,7 @@ BIGNUM_2(sub) | |
BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ | |
VALUE obj; \ | |
GetBN(self, bn1); \ | |
- obj = NewBN(CLASS_OF(self)); \ | |
+ obj = NewBN(rb_obj_class(self)); \ | |
if (!(result = BN_new())) { \ | |
ossl_raise(eBNError, NULL); \ | |
} \ | |
@@ -445,42 +457,49 @@ BIGNUM_2(sub) | |
/* | |
* Document-method: OpenSSL::BN#* | |
+ * call-seq: | |
* bn * bn2 => aBN | |
*/ | |
BIGNUM_2c(mul) | |
/* | |
* Document-method: OpenSSL::BN#% | |
+ * call-seq: | |
* bn % bn2 => aBN | |
*/ | |
BIGNUM_2c(mod) | |
/* | |
* Document-method: OpenSSL::BN#** | |
+ * call-seq: | |
* bn ** bn2 => aBN | |
*/ | |
BIGNUM_2c(exp) | |
/* | |
* Document-method: OpenSSL::BN#gcd | |
+ * call-seq: | |
* bn.gcd(bn2) => aBN | |
*/ | |
BIGNUM_2c(gcd) | |
/* | |
* Document-method: OpenSSL::BN#mod_sqr | |
+ * call-seq: | |
* bn.mod_sqr(bn2) => aBN | |
*/ | |
BIGNUM_2c(mod_sqr) | |
/* | |
* Document-method: OpenSSL::BN#mod_inverse | |
+ * call-seq: | |
* bn.mod_inverse(bn2) => aBN | |
*/ | |
BIGNUM_2c(mod_inverse) | |
/* | |
* Document-method: OpenSSL::BN#/ | |
+ * call-seq: | |
* bn1 / bn2 => [result, remainder] | |
* | |
* Division of OpenSSL::BN instances | |
@@ -489,12 +508,13 @@ static VALUE | |
ossl_bn_div(VALUE self, VALUE other) | |
{ | |
BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2; | |
- VALUE obj1, obj2; | |
+ VALUE klass, obj1, obj2; | |
GetBN(self, bn1); | |
- obj1 = NewBN(CLASS_OF(self)); | |
- obj2 = NewBN(CLASS_OF(self)); | |
+ klass = rb_obj_class(self); | |
+ obj1 = NewBN(klass); | |
+ obj2 = NewBN(klass); | |
if (!(r1 = BN_new())) { | |
ossl_raise(eBNError, NULL); | |
} | |
@@ -521,7 +541,7 @@ ossl_bn_div(VALUE self, VALUE other) | |
BIGNUM *bn3 = GetBNPtr(other2), *result; \ | |
VALUE obj; \ | |
GetBN(self, bn1); \ | |
- obj = NewBN(CLASS_OF(self)); \ | |
+ obj = NewBN(rb_obj_class(self)); \ | |
if (!(result = BN_new())) { \ | |
ossl_raise(eBNError, NULL); \ | |
} \ | |
@@ -535,24 +555,28 @@ ossl_bn_div(VALUE self, VALUE other) | |
/* | |
* Document-method: OpenSSL::BN#mod_add | |
+ * call-seq: | |
* bn.mod_add(bn1, bn2) -> aBN | |
*/ | |
BIGNUM_3c(mod_add) | |
/* | |
* Document-method: OpenSSL::BN#mod_sub | |
+ * call-seq: | |
* bn.mod_sub(bn1, bn2) -> aBN | |
*/ | |
BIGNUM_3c(mod_sub) | |
/* | |
* Document-method: OpenSSL::BN#mod_mul | |
+ * call-seq: | |
* bn.mod_mul(bn1, bn2) -> aBN | |
*/ | |
BIGNUM_3c(mod_mul) | |
/* | |
* Document-method: OpenSSL::BN#mod_exp | |
+ * call-seq: | |
* bn.mod_exp(bn1, bn2) -> aBN | |
*/ | |
BIGNUM_3c(mod_exp) | |
@@ -571,29 +595,31 @@ BIGNUM_3c(mod_exp) | |
/* | |
* Document-method: OpenSSL::BN#set_bit! | |
+ * call-seq: | |
* bn.set_bit!(bit) -> self | |
*/ | |
BIGNUM_BIT(set_bit) | |
/* | |
* Document-method: OpenSSL::BN#clear_bit! | |
+ * call-seq: | |
* bn.clear_bit!(bit) -> self | |
*/ | |
BIGNUM_BIT(clear_bit) | |
/* | |
* Document-method: OpenSSL::BN#mask_bit! | |
+ * call-seq: | |
* bn.mask_bit!(bit) -> self | |
*/ | |
BIGNUM_BIT(mask_bits) | |
/* Document-method: OpenSSL::BN#bit_set? | |
+ * call-seq: | |
+ * bn.bit_set?(bit) => true | false | |
* | |
* Returns boolean of whether +bit+ is set. | |
* Bitwise operations for openssl BIGNUMs. | |
- * | |
- * bn.bit_set?(bit) => true | false | |
- * | |
*/ | |
static VALUE | |
ossl_bn_is_bit_set(VALUE self, VALUE bit) | |
@@ -618,7 +644,7 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit) | |
VALUE obj; \ | |
b = NUM2INT(bits); \ | |
GetBN(self, bn); \ | |
- obj = NewBN(CLASS_OF(self)); \ | |
+ obj = NewBN(rb_obj_class(self)); \ | |
if (!(result = BN_new())) { \ | |
ossl_raise(eBNError, NULL); \ | |
} \ | |
@@ -659,12 +685,14 @@ BIGNUM_SHIFT(rshift) | |
/* | |
* Document-method: OpenSSL::BN#lshift! | |
+ * call-seq: | |
* bn.lshift!(bits) -> self | |
*/ | |
BIGNUM_SELF_SHIFT(lshift) | |
/* | |
* Document-method: OpenSSL::BN#rshift! | |
+ * call-seq: | |
* bn.rshift!(bits) -> self | |
*/ | |
BIGNUM_SELF_SHIFT(rshift) | |
@@ -728,6 +756,7 @@ BIGNUM_RAND(pseudo_rand) | |
/* | |
* Document-method: OpenSSL::BN.rand_range | |
+ * call-seq: | |
* BN.rand_range(range) -> aBN | |
* | |
*/ | |
@@ -735,6 +764,7 @@ BIGNUM_RAND_RANGE(rand) | |
/* | |
* Document-method: OpenSSL::BN.pseudo_rand_range | |
+ * call-seq: | |
* BN.pseudo_rand_range(range) -> aBN | |
* | |
*/ | |
@@ -744,6 +774,10 @@ BIGNUM_RAND_RANGE(pseudo_rand) | |
* call-seq: | |
* BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn | |
* | |
+ * Generates a random prime number of bit length +bits+. If +safe+ is true, | |
+ * generates a safe prime. If +add+ is specified, generates a prime that | |
+ * fulfills condition <tt>p % add = rem</tt>. | |
+ * | |
* === Parameters | |
* * +bits+ - integer | |
* * +safe+ - boolean | |
@@ -772,7 +806,7 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) | |
if (!(result = BN_new())) { | |
ossl_raise(eBNError, NULL); | |
} | |
- if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) { | |
+ if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) { | |
BN_free(result); | |
ossl_raise(eBNError, NULL); | |
} | |
@@ -787,17 +821,19 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) | |
{ \ | |
BIGNUM *bn; \ | |
GetBN(self, bn); \ | |
- return INT2FIX(BN_##func(bn)); \ | |
+ return INT2NUM(BN_##func(bn)); \ | |
} | |
/* | |
* Document-method: OpenSSL::BN#num_bytes | |
+ * call-seq: | |
* bn.num_bytes => integer | |
*/ | |
BIGNUM_NUM(num_bytes) | |
/* | |
* Document-method: OpenSSL::BN#num_bits | |
+ * call-seq: | |
* bn.num_bits => integer | |
*/ | |
BIGNUM_NUM(num_bits) | |
@@ -826,21 +862,24 @@ ossl_bn_copy(VALUE self, VALUE other) | |
{ \ | |
BIGNUM *bn1, *bn2 = GetBNPtr(other); \ | |
GetBN(self, bn1); \ | |
- return INT2FIX(BN_##func(bn1, bn2)); \ | |
+ return INT2NUM(BN_##func(bn1, bn2)); \ | |
} | |
/* | |
* Document-method: OpenSSL::BN#cmp | |
+ * call-seq: | |
* bn.cmp(bn2) => integer | |
*/ | |
/* | |
* Document-method: OpenSSL::BN#<=> | |
+ * call-seq: | |
* bn <=> bn2 => integer | |
*/ | |
BIGNUM_CMP(cmp) | |
/* | |
* Document-method: OpenSSL::BN#ucmp | |
+ * call-seq: | |
* bn.ucmp(bn2) => integer | |
*/ | |
BIGNUM_CMP(ucmp) | |
@@ -858,10 +897,12 @@ ossl_bn_eq(VALUE self, VALUE other) | |
BIGNUM *bn1, *bn2; | |
GetBN(self, bn1); | |
- /* BNPtr may raise, so we can't use here */ | |
- bn2 = try_convert_to_bnptr(other); | |
+ other = try_convert_to_bn(other); | |
+ if (NIL_P(other)) | |
+ return Qfalse; | |
+ GetBN(other, bn2); | |
- if (bn2 && !BN_cmp(bn1, bn2)) { | |
+ if (!BN_cmp(bn1, bn2)) { | |
return Qtrue; | |
} | |
return Qfalse; | |
@@ -912,7 +953,7 @@ ossl_bn_hash(VALUE self) | |
ossl_raise(eBNError, NULL); | |
} | |
- hash = LONG2FIX((long)rb_memhash(buf, len)); | |
+ hash = INT2FIX(rb_memhash(buf, len)); | |
xfree(buf); | |
return hash; | |
@@ -923,6 +964,10 @@ ossl_bn_hash(VALUE self) | |
* bn.prime? => true | false | |
* bn.prime?(checks) => true | false | |
* | |
+ * Performs a Miller-Rabin probabilistic primality test with +checks+ | |
+ * iterations. If +nchecks+ is not specified, a number of iterations is used | |
+ * that yields a false positive rate of at most 2^-80 for random input. | |
+ * | |
* === Parameters | |
* * +checks+ - integer | |
*/ | |
@@ -937,7 +982,7 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) | |
checks = NUM2INT(vchecks); | |
} | |
GetBN(self, bn); | |
- switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) { | |
+ switch (BN_is_prime_ex(bn, checks, ossl_bn_ctx, NULL)) { | |
case 1: | |
return Qtrue; | |
case 0: | |
@@ -955,6 +1000,9 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) | |
* bn.prime_fasttest?(checks) => true | false | |
* bn.prime_fasttest?(checks, trial_div) => true | false | |
* | |
+ * Performs a Miller-Rabin primality test. This is same as #prime? except this | |
+ * first attempts trial divisions with some small primes. | |
+ * | |
* === Parameters | |
* * +checks+ - integer | |
* * +trial_div+ - boolean | |
@@ -976,7 +1024,7 @@ ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self) | |
if (vtrivdiv == Qfalse) { | |
do_trial_division = 0; | |
} | |
- switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) { | |
+ switch (BN_is_prime_fasttest_ex(bn, checks, ossl_bn_ctx, do_trial_division, NULL)) { | |
case 1: | |
return Qtrue; | |
case 0: | |
@@ -996,7 +1044,8 @@ void | |
Init_ossl_bn(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
if (!(ossl_bn_ctx = BN_CTX_new())) { | |
@@ -1066,6 +1115,7 @@ Init_ossl_bn(void) | |
rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1); | |
rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1); | |
+ rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1); | |
rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1); | |
rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1); | |
@@ -1107,10 +1157,4 @@ Init_ossl_bn(void) | |
/* RECiProcal | |
* MONTgomery */ | |
- | |
- /* | |
- * TODO: | |
- * Where to belong these? | |
- */ | |
- rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1); | |
} | |
diff --git a/ext/openssl/ossl_bn.h b/ext/openssl/ossl_bn.h | |
index 4cd9d0600a..a19ba19487 100644 | |
--- a/ext/openssl/ossl_bn.h | |
+++ b/ext/openssl/ossl_bn.h | |
@@ -15,8 +15,10 @@ extern VALUE eBNError; | |
extern BN_CTX *ossl_bn_ctx; | |
+#define GetBNPtr(obj) ossl_bn_value_ptr(&(obj)) | |
+ | |
VALUE ossl_bn_new(const BIGNUM *); | |
-BIGNUM *GetBNPtr(VALUE); | |
+BIGNUM *ossl_bn_value_ptr(volatile VALUE *); | |
void Init_ossl_bn(void); | |
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c | |
index e167995d49..73b667b2c3 100644 | |
--- a/ext/openssl/ossl_cipher.c | |
+++ b/ext/openssl/ossl_cipher.c | |
@@ -11,10 +11,12 @@ | |
#define NewCipher(klass) \ | |
TypedData_Wrap_Struct((klass), &ossl_cipher_type, 0) | |
-#define MakeCipher(obj, klass, ctx) \ | |
- (obj) = TypedData_Make_Struct((klass), EVP_CIPHER_CTX, &ossl_cipher_type, (ctx)) | |
-#define AllocCipher(obj, ctx) \ | |
- (DATA_PTR(obj) = (ctx) = ZALLOC(EVP_CIPHER_CTX)) | |
+#define AllocCipher(obj, ctx) do { \ | |
+ (ctx) = EVP_CIPHER_CTX_new(); \ | |
+ if (!(ctx)) \ | |
+ ossl_raise(rb_eRuntimeError, NULL); \ | |
+ RTYPEDDATA_DATA(obj) = (ctx); \ | |
+} while (0) | |
#define GetCipherInit(obj, ctx) do { \ | |
TypedData_Get_Struct((obj), EVP_CIPHER_CTX, &ossl_cipher_type, (ctx)); \ | |
} while (0) | |
@@ -34,17 +36,17 @@ | |
*/ | |
VALUE cCipher; | |
VALUE eCipherError; | |
-static ID id_key_set; | |
+static ID id_auth_tag_len, id_key_set; | |
static VALUE ossl_cipher_alloc(VALUE klass); | |
static void ossl_cipher_free(void *ptr); | |
-static size_t ossl_cipher_memsize(const void *ptr); | |
static const rb_data_type_t ossl_cipher_type = { | |
"OpenSSL/Cipher", | |
- {0, ossl_cipher_free, ossl_cipher_memsize,}, | |
- 0, 0, | |
- RUBY_TYPED_FREE_IMMEDIATELY, | |
+ { | |
+ 0, ossl_cipher_free, | |
+ }, | |
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
}; | |
/* | |
@@ -53,11 +55,24 @@ static const rb_data_type_t ossl_cipher_type = { | |
const EVP_CIPHER * | |
GetCipherPtr(VALUE obj) | |
{ | |
- EVP_CIPHER_CTX *ctx; | |
+ if (rb_obj_is_kind_of(obj, cCipher)) { | |
+ EVP_CIPHER_CTX *ctx; | |
+ | |
+ GetCipher(obj, ctx); | |
- SafeGetCipher(obj, ctx); | |
+ return EVP_CIPHER_CTX_cipher(ctx); | |
+ } | |
+ else { | |
+ const EVP_CIPHER *cipher; | |
- return EVP_CIPHER_CTX_cipher(ctx); | |
+ StringValueCStr(obj); | |
+ cipher = EVP_get_cipherbyname(RSTRING_PTR(obj)); | |
+ if (!cipher) | |
+ ossl_raise(rb_eArgError, | |
+ "unsupported cipher algorithm: %"PRIsVALUE, obj); | |
+ | |
+ return cipher; | |
+ } | |
} | |
VALUE | |
@@ -68,7 +83,6 @@ ossl_cipher_new(const EVP_CIPHER *cipher) | |
ret = ossl_cipher_alloc(cCipher); | |
AllocCipher(ret, ctx); | |
- EVP_CIPHER_CTX_init(ctx); | |
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) | |
ossl_raise(eCipherError, NULL); | |
@@ -81,18 +95,7 @@ ossl_cipher_new(const EVP_CIPHER *cipher) | |
static void | |
ossl_cipher_free(void *ptr) | |
{ | |
- EVP_CIPHER_CTX *ctx = ptr; | |
- if (ctx) { | |
- EVP_CIPHER_CTX_cleanup(ctx); | |
- ruby_xfree(ctx); | |
- } | |
-} | |
- | |
-static size_t | |
-ossl_cipher_memsize(const void *ptr) | |
-{ | |
- const EVP_CIPHER_CTX *ctx = ptr; | |
- return sizeof(*ctx); | |
+ EVP_CIPHER_CTX_free(ptr); | |
} | |
static VALUE | |
@@ -116,15 +119,14 @@ ossl_cipher_initialize(VALUE self, VALUE str) | |
const EVP_CIPHER *cipher; | |
char *name; | |
- name = StringValuePtr(str); | |
+ name = StringValueCStr(str); | |
GetCipherInit(self, ctx); | |
if (ctx) { | |
ossl_raise(rb_eRuntimeError, "Cipher already inititalized!"); | |
} | |
AllocCipher(self, ctx); | |
- EVP_CIPHER_CTX_init(ctx); | |
if (!(cipher = EVP_get_cipherbyname(name))) { | |
- ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name); | |
+ ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str); | |
} | |
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) | |
ossl_raise(eCipherError, NULL); | |
@@ -151,16 +153,13 @@ ossl_cipher_copy(VALUE self, VALUE other) | |
return self; | |
} | |
-#ifdef HAVE_OBJ_NAME_DO_ALL_SORTED | |
static void* | |
add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary) | |
{ | |
rb_ary_push(ary, rb_str_new2(name->name)); | |
return NULL; | |
} | |
-#endif | |
-#ifdef HAVE_OBJ_NAME_DO_ALL_SORTED | |
/* | |
* call-seq: | |
* OpenSSL::Cipher.ciphers -> array[string...] | |
@@ -179,9 +178,6 @@ ossl_s_ciphers(VALUE self) | |
return ary; | |
} | |
-#else | |
-#define ossl_s_ciphers rb_f_notimplement | |
-#endif | |
/* | |
* call-seq: | |
@@ -259,7 +255,7 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) | |
* | |
* Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the | |
* following methods: | |
- * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] | |
+ * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen] | |
* | |
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1). | |
*/ | |
@@ -277,7 +273,7 @@ ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self) | |
* | |
* Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the | |
* following methods: | |
- * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] | |
+ * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen] | |
* | |
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0). | |
*/ | |
@@ -289,20 +285,20 @@ ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self) | |
/* | |
* call-seq: | |
- * cipher.pkcs5_keyivgen(pass [, salt [, iterations [, digest]]] ) -> nil | |
+ * cipher.pkcs5_keyivgen(pass, salt = nil, iterations = 2048, digest = "MD5") -> nil | |
* | |
* Generates and sets the key/IV based on a password. | |
* | |
- * WARNING: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40, | |
+ * *WARNING*: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40, | |
* or DES with MD5 or SHA1. Using anything else (like AES) will generate the | |
* key/iv using an OpenSSL specific method. This method is deprecated and | |
* should no longer be used. Use a PKCS5 v2 key generation method from | |
* OpenSSL::PKCS5 instead. | |
* | |
* === Parameters | |
- * +salt+ must be an 8 byte string if provided. | |
- * +iterations+ is a integer with a default of 2048. | |
- * +digest+ is a Digest object that defaults to 'MD5' | |
+ * * +salt+ must be an 8 byte string if provided. | |
+ * * +iterations+ is an integer with a default of 2048. | |
+ * * +digest+ is a Digest object that defaults to 'MD5' | |
* | |
* A minimum of 1000 iterations is recommended. | |
* | |
@@ -344,25 +340,23 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p | |
const unsigned char *in, long in_len) | |
{ | |
int out_part_len; | |
+ int limit = INT_MAX / 2 + 1; | |
long out_len = 0; | |
-#define UPDATE_LENGTH_LIMIT INT_MAX | |
- | |
-#if SIZEOF_LONG > UPDATE_LENGTH_LIMIT | |
- if (in_len > UPDATE_LENGTH_LIMIT) { | |
- const int in_part_len = (UPDATE_LENGTH_LIMIT / 2 + 1) & ~1; | |
- do { | |
- if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0, | |
- &out_part_len, in, in_part_len)) | |
- return 0; | |
- out_len += out_part_len; | |
- in += in_part_len; | |
- } while ((in_len -= in_part_len) > UPDATE_LENGTH_LIMIT); | |
- } | |
-#endif | |
- if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0, | |
- &out_part_len, in, (int)in_len)) | |
- return 0; | |
- if (out_len_ptr) *out_len_ptr = out_len += out_part_len; | |
+ | |
+ do { | |
+ int in_part_len = in_len > limit ? limit : (int)in_len; | |
+ | |
+ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0, | |
+ &out_part_len, in, in_part_len)) | |
+ return 0; | |
+ | |
+ out_len += out_part_len; | |
+ in += in_part_len; | |
+ } while ((in_len -= limit) > 0); | |
+ | |
+ if (out_len_ptr) | |
+ *out_len_ptr = out_len; | |
+ | |
return 1; | |
} | |
@@ -375,9 +369,8 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p | |
* data chunk. When done, the output of Cipher#final should be additionally | |
* added to the result. | |
* | |
- * === Parameters | |
- * +data+ is a nonempty string. | |
- * +buffer+ is an optional string to store the result. | |
+ * If +buffer+ is given, the encryption/decryption result will be written to | |
+ * it. +buffer+ will be resized automatically. | |
*/ | |
static VALUE | |
ossl_cipher_update(int argc, VALUE *argv, VALUE self) | |
@@ -481,15 +474,17 @@ static VALUE | |
ossl_cipher_set_key(VALUE self, VALUE key) | |
{ | |
EVP_CIPHER_CTX *ctx; | |
+ int key_len; | |
StringValue(key); | |
GetCipher(self, ctx); | |
- if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx)) | |
- ossl_raise(eCipherError, "key length too short"); | |
+ key_len = EVP_CIPHER_CTX_key_length(ctx); | |
+ if (RSTRING_LEN(key) != key_len) | |
+ ossl_raise(rb_eArgError, "key must be %d bytes", key_len); | |
if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1) | |
- ossl_raise(eCipherError, NULL); | |
+ ossl_raise(eCipherError, NULL); | |
rb_ivar_set(self, id_key_set, Qtrue); | |
@@ -507,20 +502,24 @@ ossl_cipher_set_key(VALUE self, VALUE key) | |
* Cipher#random_iv to create a secure random IV. | |
* | |
* Only call this method after calling Cipher#encrypt or Cipher#decrypt. | |
- * | |
- * If not explicitly set, the OpenSSL default of an all-zeroes ("\\0") IV is | |
- * used. | |
*/ | |
static VALUE | |
ossl_cipher_set_iv(VALUE self, VALUE iv) | |
{ | |
EVP_CIPHER_CTX *ctx; | |
+ int iv_len = 0; | |
StringValue(iv); | |
GetCipher(self, ctx); | |
- if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx)) | |
- ossl_raise(eCipherError, "iv length too short"); | |
+#if defined(HAVE_AUTHENTICATED_ENCRYPTION) | |
+ if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) | |
+ iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); | |
+#endif | |
+ if (!iv_len) | |
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx); | |
+ if (RSTRING_LEN(iv) != iv_len) | |
+ ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len); | |
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1) | |
ossl_raise(eCipherError, NULL); | |
@@ -528,6 +527,27 @@ ossl_cipher_set_iv(VALUE self, VALUE iv) | |
return iv; | |
} | |
+/* | |
+ * call-seq: | |
+ * cipher.authenticated? -> true | false | |
+ * | |
+ * Indicated whether this Cipher instance uses an Authenticated Encryption | |
+ * mode. | |
+ */ | |
+static VALUE | |
+ossl_cipher_is_authenticated(VALUE self) | |
+{ | |
+ EVP_CIPHER_CTX *ctx; | |
+ | |
+ GetCipher(self, ctx); | |
+ | |
+#if defined(HAVE_AUTHENTICATED_ENCRYPTION) | |
+ return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse; | |
+#else | |
+ return Qfalse; | |
+#endif | |
+} | |
+ | |
#ifdef HAVE_AUTHENTICATED_ENCRYPTION | |
/* | |
* call-seq: | |
@@ -560,8 +580,6 @@ 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"); | |
@@ -569,69 +587,44 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data) | |
return data; | |
} | |
-#define ossl_is_gcm(nid) (nid) == NID_aes_128_gcm || \ | |
- (nid) == NID_aes_192_gcm || \ | |
- (nid) == NID_aes_256_gcm | |
- | |
-static VALUE | |
-ossl_get_gcm_auth_tag(EVP_CIPHER_CTX *ctx, int len) | |
-{ | |
- unsigned char *tag; | |
- VALUE ret; | |
- | |
- tag = ALLOC_N(unsigned char, len); | |
- | |
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, len, tag)) | |
- ossl_raise(eCipherError, "retrieving the authentication tag failed"); | |
- | |
- ret = rb_str_new((const char *) tag, len); | |
- xfree(tag); | |
- return ret; | |
-} | |
- | |
/* | |
* call-seq: | |
- * cipher.auth_tag([ tag_len ] -> string | |
+ * cipher.auth_tag(tag_len = 16) -> String | |
* | |
* Gets the authentication tag generated by Authenticated Encryption Cipher | |
* modes (GCM for example). This tag may be stored along with the ciphertext, | |
* then set on the decryption cipher to authenticate the contents of the | |
* ciphertext against changes. If the optional integer parameter +tag_len+ is | |
* given, the returned tag will be +tag_len+ bytes long. If the parameter is | |
- * omitted, the maximum length of 16 bytes will be returned. For maximum | |
- * security, the default of 16 bytes should be chosen. | |
+ * omitted, the default length of 16 bytes or the length previously set by | |
+ * #auth_tag_len= will be used. For maximum security, the longest possible | |
+ * should be chosen. | |
* | |
* The tag may only be retrieved after calling Cipher#final. | |
*/ | |
static VALUE | |
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self) | |
{ | |
- VALUE vtag_len; | |
+ VALUE vtag_len, ret; | |
EVP_CIPHER_CTX *ctx; | |
- int nid, tag_len; | |
+ int tag_len = 16; | |
- if (rb_scan_args(argc, argv, "01", &vtag_len) == 0) { | |
- tag_len = 16; | |
- } else { | |
+ rb_scan_args(argc, argv, "01", &vtag_len); | |
+ if (NIL_P(vtag_len)) | |
+ vtag_len = rb_attr_get(self, id_auth_tag_len); | |
+ if (!NIL_P(vtag_len)) | |
tag_len = NUM2INT(vtag_len); | |
- } | |
GetCipher(self, ctx); | |
- nid = EVP_CIPHER_CTX_nid(ctx); | |
- if (ossl_is_gcm(nid)) { | |
- return ossl_get_gcm_auth_tag(ctx, tag_len); | |
- } else { | |
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)) | |
ossl_raise(eCipherError, "authentication tag not supported by this cipher"); | |
- return Qnil; /* dummy */ | |
- } | |
-} | |
-static inline void | |
-ossl_set_gcm_auth_tag(EVP_CIPHER_CTX *ctx, unsigned char *tag, int tag_len) | |
-{ | |
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag)) | |
- ossl_raise(eCipherError, "unable to set GCM tag"); | |
+ ret = rb_str_new(NULL, tag_len); | |
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret))) | |
+ ossl_raise(eCipherError, "retrieving the authentication tag failed"); | |
+ | |
+ return ret; | |
} | |
/* | |
@@ -645,12 +638,14 @@ ossl_set_gcm_auth_tag(EVP_CIPHER_CTX *ctx, unsigned char *tag, int tag_len) | |
* decrypting any of the ciphertext. After all decryption is | |
* performed, the tag is verified automatically in the call to | |
* Cipher#final. | |
+ * | |
+ * For OCB mode, the tag length must be supplied with #auth_tag_len= | |
+ * beforehand. | |
*/ | |
static VALUE | |
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag) | |
{ | |
EVP_CIPHER_CTX *ctx; | |
- int nid; | |
unsigned char *tag; | |
int tag_len; | |
@@ -659,44 +654,80 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag) | |
tag_len = RSTRING_LENINT(vtag); | |
GetCipher(self, ctx); | |
- nid = EVP_CIPHER_CTX_nid(ctx); | |
- | |
- if (ossl_is_gcm(nid)) { | |
- ossl_set_gcm_auth_tag(ctx, tag, tag_len); | |
- } else { | |
+ if (!(EVP_CIPHER_CTX_flags(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)) | |
+ ossl_raise(eCipherError, "unable to set AEAD tag"); | |
return vtag; | |
} | |
/* | |
* call-seq: | |
- * cipher.authenticated? -> boolean | |
+ * cipher.auth_tag_len = Integer -> Integer | |
* | |
- * Indicated whether this Cipher instance uses an Authenticated Encryption | |
- * mode. | |
+ * Sets the length of the authentication tag to be generated or to be given for | |
+ * AEAD ciphers that requires it as in input parameter. Note that not all AEAD | |
+ * ciphers support this method. | |
+ * | |
+ * In OCB mode, the length must be supplied both when encrypting and when | |
+ * decrypting, and must be before specifying an IV. | |
*/ | |
static VALUE | |
-ossl_cipher_is_authenticated(VALUE self) | |
+ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen) | |
{ | |
+ int tag_len = NUM2INT(vlen); | |
EVP_CIPHER_CTX *ctx; | |
- int nid; | |
GetCipher(self, ctx); | |
- nid = EVP_CIPHER_CTX_nid(ctx); | |
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER)) | |
+ ossl_raise(eCipherError, "AEAD not supported by this cipher"); | |
- if (ossl_is_gcm(nid)) { | |
- return Qtrue; | |
- } else { | |
- return Qfalse; | |
- } | |
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL)) | |
+ ossl_raise(eCipherError, "unable to set authentication tag length"); | |
+ | |
+ /* for #auth_tag */ | |
+ rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len)); | |
+ | |
+ return vlen; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * cipher.iv_len = integer -> integer | |
+ * | |
+ * Sets the IV/nonce length of the Cipher. Normally block ciphers don't allow | |
+ * changing the IV length, but some make use of IV for 'nonce'. You may need | |
+ * this for interoperability with other applications. | |
+ */ | |
+static VALUE | |
+ossl_cipher_set_iv_length(VALUE self, VALUE iv_length) | |
+{ | |
+ int len = NUM2INT(iv_length); | |
+ EVP_CIPHER_CTX *ctx; | |
+ | |
+ GetCipher(self, ctx); | |
+ if (!(EVP_CIPHER_CTX_flags(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)) | |
+ ossl_raise(eCipherError, "unable to set IV length"); | |
+ | |
+ /* | |
+ * EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save | |
+ * the length somewhere. Luckily currently we aren't using app_data. | |
+ */ | |
+ EVP_CIPHER_CTX_set_app_data(ctx, (void *)(VALUE)len); | |
+ | |
+ return iv_length; | |
} | |
#else | |
#define ossl_cipher_set_auth_data rb_f_notimplement | |
#define ossl_cipher_get_auth_tag rb_f_notimplement | |
#define ossl_cipher_set_auth_tag rb_f_notimplement | |
-#define ossl_cipher_is_authenticated rb_f_notimplement | |
+#define ossl_cipher_set_auth_tag_len rb_f_notimplement | |
+#define ossl_cipher_set_iv_length rb_f_notimplement | |
#endif | |
/* | |
@@ -724,7 +755,6 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length) | |
return key_length; | |
} | |
-#if defined(HAVE_EVP_CIPHER_CTX_SET_PADDING) | |
/* | |
* call-seq: | |
* cipher.padding = integer -> integer | |
@@ -746,18 +776,6 @@ ossl_cipher_set_padding(VALUE self, VALUE padding) | |
ossl_raise(eCipherError, NULL); | |
return padding; | |
} | |
-#else | |
-#define ossl_cipher_set_padding rb_f_notimplement | |
-#endif | |
- | |
-#define CIPHER_0ARG_INT(func) \ | |
- static VALUE \ | |
- ossl_cipher_##func(VALUE self) \ | |
- { \ | |
- EVP_CIPHER_CTX *ctx; \ | |
- GetCipher(self, ctx); \ | |
- return INT2NUM(EVP_CIPHER_##func(EVP_CIPHER_CTX_cipher(ctx))); \ | |
- } | |
/* | |
* call-seq: | |
@@ -765,21 +783,54 @@ ossl_cipher_set_padding(VALUE self, VALUE padding) | |
* | |
* Returns the key length in bytes of the Cipher. | |
*/ | |
-CIPHER_0ARG_INT(key_length) | |
+static VALUE | |
+ossl_cipher_key_length(VALUE self) | |
+{ | |
+ EVP_CIPHER_CTX *ctx; | |
+ | |
+ GetCipher(self, ctx); | |
+ | |
+ return INT2NUM(EVP_CIPHER_CTX_key_length(ctx)); | |
+} | |
+ | |
/* | |
* call-seq: | |
* cipher.iv_len -> integer | |
* | |
* Returns the expected length in bytes for an IV for this Cipher. | |
*/ | |
-CIPHER_0ARG_INT(iv_length) | |
+static VALUE | |
+ossl_cipher_iv_length(VALUE self) | |
+{ | |
+ EVP_CIPHER_CTX *ctx; | |
+ int len = 0; | |
+ | |
+ GetCipher(self, ctx); | |
+#if defined(HAVE_AUTHENTICATED_ENCRYPTION) | |
+ if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) | |
+ len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); | |
+#endif | |
+ if (!len) | |
+ len = EVP_CIPHER_CTX_iv_length(ctx); | |
+ | |
+ return INT2NUM(len); | |
+} | |
+ | |
/* | |
* call-seq: | |
* cipher.block_size -> integer | |
* | |
* Returns the size in bytes of the blocks on which this Cipher operates on. | |
*/ | |
-CIPHER_0ARG_INT(block_size) | |
+static VALUE | |
+ossl_cipher_block_size(VALUE self) | |
+{ | |
+ EVP_CIPHER_CTX *ctx; | |
+ | |
+ GetCipher(self, ctx); | |
+ | |
+ return INT2NUM(EVP_CIPHER_CTX_block_size(ctx)); | |
+} | |
/* | |
* INIT | |
@@ -788,7 +839,8 @@ void | |
Init_ossl_cipher(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
/* Document-class: OpenSSL::Cipher | |
@@ -887,12 +939,10 @@ Init_ossl_cipher(void) | |
* you absolutely need it</b> | |
* | |
* Because of this, you will end up with a mode that explicitly requires | |
- * an IV in any case. Note that for backwards compatibility reasons, | |
- * setting an IV is not explicitly mandated by the Cipher API. If not | |
- * set, OpenSSL itself defaults to an all-zeroes IV ("\\0", not the | |
- * character). Although the IV can be seen as public information, i.e. | |
- * it may be transmitted in public once generated, it should still stay | |
- * unpredictable to prevent certain kinds of attacks. Therefore, ideally | |
+ * an IV in any case. Although the IV can be seen as public information, | |
+ * i.e. it may be transmitted in public once generated, it should still | |
+ * stay unpredictable to prevent certain kinds of attacks. Therefore, | |
+ * ideally | |
* | |
* <b>Always create a secure random IV for every encryption of your | |
* Cipher</b> | |
@@ -901,16 +951,16 @@ Init_ossl_cipher(void) | |
* of the IV as a nonce (number used once) - it's public but random and | |
* unpredictable. A secure random IV can be created as follows | |
* | |
- * cipher = ... | |
- * cipher.encrypt | |
- * key = cipher.random_key | |
- * iv = cipher.random_iv # also sets the generated IV on the Cipher | |
+ * cipher = ... | |
+ * cipher.encrypt | |
+ * key = cipher.random_key | |
+ * iv = cipher.random_iv # also sets the generated IV on the Cipher | |
* | |
- * Although the key is generally a random value, too, it is a bad choice | |
- * as an IV. There are elaborate ways how an attacker can take advantage | |
- * of such an IV. As a general rule of thumb, exposing the key directly | |
- * or indirectly should be avoided at all cost and exceptions only be | |
- * made with good reason. | |
+ * Although the key is generally a random value, too, it is a bad choice | |
+ * as an IV. There are elaborate ways how an attacker can take advantage | |
+ * of such an IV. As a general rule of thumb, exposing the key directly | |
+ * or indirectly should be avoided at all cost and exceptions only be | |
+ * made with good reason. | |
* | |
* === Calling Cipher#final | |
* | |
@@ -964,29 +1014,42 @@ Init_ossl_cipher(void) | |
* could otherwise be exploited to modify ciphertexts in ways beneficial to | |
* potential attackers. | |
* | |
- * If no associated data is needed for encryption and later decryption, | |
- * the OpenSSL library still requires a value to be set - "" may be used in | |
- * case none is available. An example using the GCM (Galois Counter Mode): | |
+ * An associated data is used where there is additional information, such as | |
+ * headers or some metadata, that must be also authenticated but not | |
+ * necessarily need to be encrypted. If no associated data is needed for | |
+ * encryption and later decryption, the OpenSSL library still requires a | |
+ * value to be set - "" may be used in case none is available. | |
* | |
- * cipher = OpenSSL::Cipher::AES.new(128, :GCM) | |
- * cipher.encrypt | |
- * key = cipher.random_key | |
- * iv = cipher.random_iv | |
- * cipher.auth_data = "" | |
+ * An example using the GCM (Galois/Counter Mode). You have 16 bytes +key+, | |
+ * 12 bytes (96 bits) +nonce+ and the associated data +auth_data+. Be sure | |
+ * not to reuse the +key+ and +nonce+ pair. Reusing an nonce ruins the | |
+ * security gurantees of GCM mode. | |
+ * | |
+ * cipher = OpenSSL::Cipher::AES.new(128, :GCM).encrypt | |
+ * cipher.key = key | |
+ * cipher.iv = nonce | |
+ * cipher.auth_data = auth_data | |
* | |
* encrypted = cipher.update(data) + cipher.final | |
- * tag = cipher.auth_tag | |
+ * tag = cipher.auth_tag # produces 16 bytes tag by default | |
* | |
- * decipher = OpenSSL::Cipher::AES.new(128, :GCM) | |
- * decipher.decrypt | |
+ * Now you are the receiver. You know the +key+ and have received +nonce+, | |
+ * +auth_data+, +encrypted+ and +tag+ through an untrusted network. Note | |
+ * that GCM accepts an arbitrary length tag between 1 and 16 bytes. You may | |
+ * additionally need to check that the received tag has the correct length, | |
+ * or you allow attackers to forge a valid single byte tag for the tampered | |
+ * ciphertext with a probability of 1/256. | |
+ * | |
+ * raise "tag is truncated!" unless tag.bytesize == 16 | |
+ * decipher = OpenSSL::Cipher::AES.new(128, :GCM).decrypt | |
* decipher.key = key | |
- * decipher.iv = iv | |
+ * decipher.iv = nonce | |
* decipher.auth_tag = tag | |
- * decipher.auth_data = "" | |
+ * decipher.auth_data = auth_data | |
* | |
- * plain = decipher.update(encrypted) + decipher.final | |
+ * decrypted = decipher.update(encrypted) + decipher.final | |
* | |
- * puts data == plain #=> true | |
+ * puts data == decrypted #=> true | |
*/ | |
cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject); | |
eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError); | |
@@ -1006,13 +1069,16 @@ Init_ossl_cipher(void) | |
rb_define_method(cCipher, "auth_data=", ossl_cipher_set_auth_data, 1); | |
rb_define_method(cCipher, "auth_tag=", ossl_cipher_set_auth_tag, 1); | |
rb_define_method(cCipher, "auth_tag", ossl_cipher_get_auth_tag, -1); | |
+ rb_define_method(cCipher, "auth_tag_len=", ossl_cipher_set_auth_tag_len, 1); | |
rb_define_method(cCipher, "authenticated?", ossl_cipher_is_authenticated, 0); | |
rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1); | |
rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0); | |
rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1); | |
+ rb_define_method(cCipher, "iv_len=", ossl_cipher_set_iv_length, 1); | |
rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0); | |
rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0); | |
rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1); | |
+ id_auth_tag_len = rb_intern_const("auth_tag_len"); | |
id_key_set = rb_intern_const("key_set"); | |
} | |
diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c | |
index 5748d514dd..ebf6ae2a3d 100644 | |
--- a/ext/openssl/ossl_config.c | |
+++ b/ext/openssl/ossl_config.c | |
@@ -41,7 +41,7 @@ DupConfigPtr(VALUE obj) | |
OSSL_Check_Kind(obj, cConfig); | |
str = rb_funcall(obj, rb_intern("to_s"), 0); | |
- bio = ossl_obj2bio(&str); | |
+ bio = ossl_obj2bio(str); | |
conf = NCONF_new(NULL); | |
if(!conf){ | |
BIO_free(bio); | |
@@ -72,6 +72,12 @@ void | |
Init_ossl_config(void) | |
{ | |
char *default_config_file; | |
+ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+#endif | |
+ | |
eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); | |
cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject); | |
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c | |
index 44968dd9e5..fdafda0074 100644 | |
--- a/ext/openssl/ossl_digest.c | |
+++ b/ext/openssl/ossl_digest.c | |
@@ -61,7 +61,7 @@ GetDigestPtr(VALUE obj) | |
ASN1_OBJECT_free(oid); | |
} | |
if(!md) | |
- ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name); | |
+ ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%"PRIsVALUE").", obj); | |
} else { | |
EVP_MD_CTX *ctx; | |
@@ -80,10 +80,13 @@ ossl_digest_new(const EVP_MD *md) | |
EVP_MD_CTX *ctx; | |
ret = ossl_digest_alloc(cDigest); | |
- GetDigest(ret, ctx); | |
- if (EVP_DigestInit_ex(ctx, md, NULL) != 1) { | |
- ossl_raise(eDigestError, "Digest initialization failed."); | |
- } | |
+ ctx = EVP_MD_CTX_new(); | |
+ if (!ctx) | |
+ ossl_raise(eDigestError, "EVP_MD_CTX_new"); | |
+ RTYPEDDATA_DATA(ret) = ctx; | |
+ | |
+ if (!EVP_DigestInit_ex(ctx, md, NULL)) | |
+ ossl_raise(eDigestError, "Digest initialization failed"); | |
return ret; | |
} | |
@@ -94,13 +97,7 @@ ossl_digest_new(const EVP_MD *md) | |
static VALUE | |
ossl_digest_alloc(VALUE klass) | |
{ | |
- VALUE obj = TypedData_Wrap_Struct(klass, &ossl_digest_type, 0); | |
- EVP_MD_CTX *ctx = EVP_MD_CTX_create(); | |
- if (ctx == NULL) | |
- ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed"); | |
- RTYPEDDATA_DATA(obj) = ctx; | |
- | |
- return obj; | |
+ return TypedData_Wrap_Struct(klass, &ossl_digest_type, 0); | |
} | |
VALUE ossl_digest_update(VALUE, VALUE); | |
@@ -111,17 +108,16 @@ VALUE ossl_digest_update(VALUE, VALUE); | |
* | |
* Creates a Digest instance based on +string+, which is either the ln | |
* (long name) or sn (short name) of a supported digest algorithm. | |
+ * | |
* If +data+ (a +String+) is given, it is used as the initial input to the | |
* Digest instance, i.e. | |
+ * | |
* digest = OpenSSL::Digest.new('sha256', 'digestdata') | |
+ * | |
* is equal to | |
+ * | |
* digest = OpenSSL::Digest.new('sha256') | |
* digest.update('digestdata') | |
- * | |
- * === Example | |
- * digest = OpenSSL::Digest.new('sha1') | |
- * | |
- * | |
*/ | |
static VALUE | |
ossl_digest_initialize(int argc, VALUE *argv, VALUE self) | |
@@ -134,11 +130,16 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self) | |
md = GetDigestPtr(type); | |
if (!NIL_P(data)) StringValue(data); | |
- GetDigest(self, ctx); | |
- if (EVP_DigestInit_ex(ctx, md, NULL) != 1) { | |
- ossl_raise(eDigestError, "Digest initialization failed."); | |
+ TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx); | |
+ if (!ctx) { | |
+ RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new(); | |
+ if (!ctx) | |
+ ossl_raise(eDigestError, "EVP_MD_CTX_new"); | |
} | |
+ if (!EVP_DigestInit_ex(ctx, md, NULL)) | |
+ ossl_raise(eDigestError, "Digest initialization failed"); | |
+ | |
if (!NIL_P(data)) return ossl_digest_update(self, data); | |
return self; | |
} | |
@@ -151,7 +152,12 @@ ossl_digest_copy(VALUE self, VALUE other) | |
rb_check_frozen(self); | |
if (self == other) return self; | |
- GetDigest(self, ctx1); | |
+ TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1); | |
+ if (!ctx1) { | |
+ RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new(); | |
+ if (!ctx1) | |
+ ossl_raise(eDigestError, "EVP_MD_CTX_new"); | |
+ } | |
SafeGetDigest(other, ctx2); | |
if (!EVP_MD_CTX_copy(ctx1, ctx2)) { | |
@@ -203,7 +209,9 @@ ossl_digest_update(VALUE self, VALUE data) | |
StringValue(data); | |
GetDigest(self, ctx); | |
- EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); | |
+ | |
+ if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) | |
+ ossl_raise(eDigestError, "EVP_DigestUpdate"); | |
return self; | |
} | |
@@ -218,19 +226,21 @@ ossl_digest_finish(int argc, VALUE *argv, VALUE self) | |
{ | |
EVP_MD_CTX *ctx; | |
VALUE str; | |
- | |
- rb_scan_args(argc, argv, "01", &str); | |
+ int out_len; | |
GetDigest(self, ctx); | |
+ rb_scan_args(argc, argv, "01", &str); | |
+ out_len = EVP_MD_CTX_size(ctx); | |
if (NIL_P(str)) { | |
- str = rb_str_new(NULL, EVP_MD_CTX_size(ctx)); | |
+ str = rb_str_new(NULL, out_len); | |
} else { | |
StringValue(str); | |
- rb_str_resize(str, EVP_MD_CTX_size(ctx)); | |
+ rb_str_resize(str, out_len); | |
} | |
- EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL); | |
+ if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL)) | |
+ ossl_raise(eDigestError, "EVP_DigestFinal_ex"); | |
return str; | |
} | |
@@ -239,7 +249,7 @@ ossl_digest_finish(int argc, VALUE *argv, VALUE self) | |
* call-seq: | |
* digest.name -> string | |
* | |
- * Returns the sn of this Digest instance. | |
+ * Returns the sn of this Digest algorithm. | |
* | |
* === Example | |
* digest = OpenSSL::Digest::SHA512.new | |
@@ -310,7 +320,8 @@ Init_ossl_digest(void) | |
rb_require("digest"); | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
/* Document-class: OpenSSL::Digest | |
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c | |
index 890ec724e5..e840bfd92c 100644 | |
--- a/ext/openssl/ossl_engine.c | |
+++ b/ext/openssl/ossl_engine.c | |
@@ -9,7 +9,7 @@ | |
*/ | |
#include "ossl.h" | |
-#if defined(OSSL_ENGINE_ENABLED) | |
+#if !defined(OPENSSL_NO_ENGINE) | |
#define NewEngine(klass) \ | |
TypedData_Wrap_Struct((klass), &ossl_engine_type, 0) | |
@@ -96,7 +96,7 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) | |
ENGINE_load_builtin_engines(); | |
return Qtrue; | |
} | |
- StringValue(name); | |
+ StringValueCStr(name); | |
#ifndef OPENSSL_NO_STATIC_ENGINE | |
#if HAVE_ENGINE_LOAD_DYNAMIC | |
OSSL_ENGINE_LOAD_IF_MATCH(dynamic); | |
@@ -148,7 +148,7 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) | |
OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto); | |
#endif | |
OSSL_ENGINE_LOAD_IF_MATCH(openssl); | |
- rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name)); | |
+ rb_warning("no such builtin loader for `%"PRIsVALUE"'", name); | |
return Qnil; | |
#endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ | |
} | |
@@ -160,14 +160,12 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) | |
* It is only necessary to run cleanup when engines are loaded via | |
* OpenSSL::Engine.load. However, running cleanup before exit is recommended. | |
* | |
- * See also, https://www.openssl.org/docs/crypto/engine.html | |
+ * Note that this is needed and works only in OpenSSL < 1.1.0. | |
*/ | |
static VALUE | |
ossl_engine_s_cleanup(VALUE self) | |
{ | |
-#if defined(HAVE_ENGINE_CLEANUP) | |
ENGINE_cleanup(); | |
-#endif | |
return Qnil; | |
} | |
@@ -213,7 +211,7 @@ ossl_engine_s_by_id(VALUE klass, VALUE id) | |
ENGINE *e; | |
VALUE obj; | |
- StringValue(id); | |
+ StringValueCStr(id); | |
ossl_engine_s_load(1, &id, klass); | |
obj = NewEngine(klass); | |
if(!(e = ENGINE_by_id(RSTRING_PTR(id)))) | |
@@ -224,22 +222,7 @@ ossl_engine_s_by_id(VALUE klass, VALUE id) | |
ossl_raise(eEngineError, NULL); | |
ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK, | |
0, NULL, (void(*)(void))ossl_pem_passwd_cb); | |
- ERR_clear_error(); | |
- | |
- return obj; | |
-} | |
- | |
-static VALUE | |
-ossl_engine_s_alloc(VALUE klass) | |
-{ | |
- ENGINE *e; | |
- VALUE obj; | |
- | |
- obj = NewEngine(klass); | |
- if (!(e = ENGINE_new())) { | |
- ossl_raise(eEngineError, NULL); | |
- } | |
- SetEngine(obj, e); | |
+ ossl_clear_error(); | |
return obj; | |
} | |
@@ -296,7 +279,6 @@ ossl_engine_finish(VALUE self) | |
return Qnil; | |
} | |
-#if defined(HAVE_ENGINE_GET_CIPHER) | |
/* Document-method: OpenSSL::Engine#cipher | |
* | |
* call-seq: | |
@@ -305,7 +287,7 @@ ossl_engine_finish(VALUE self) | |
* This returns an OpenSSL::Cipher by +name+, if it is available in this | |
* engine. | |
* | |
- * A EngineError will be raised if the cipher is unavailable. | |
+ * An EngineError will be raised if the cipher is unavailable. | |
* | |
* e = OpenSSL::Engine.by_id("openssl") | |
* => #<OpenSSL::Engine id="openssl" name="Software engine support"> | |
@@ -318,12 +300,10 @@ ossl_engine_get_cipher(VALUE self, VALUE name) | |
{ | |
ENGINE *e; | |
const EVP_CIPHER *ciph, *tmp; | |
- char *s; | |
int nid; | |
- s = StringValuePtr(name); | |
- tmp = EVP_get_cipherbyname(s); | |
- if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s); | |
+ tmp = EVP_get_cipherbyname(StringValueCStr(name)); | |
+ if(!tmp) ossl_raise(eEngineError, "no such cipher `%"PRIsVALUE"'", name); | |
nid = EVP_CIPHER_nid(tmp); | |
GetEngine(self, e); | |
ciph = ENGINE_get_cipher(e, nid); | |
@@ -331,11 +311,7 @@ ossl_engine_get_cipher(VALUE self, VALUE name) | |
return ossl_cipher_new(ciph); | |
} | |
-#else | |
-#define ossl_engine_get_cipher rb_f_notimplement | |
-#endif | |
-#if defined(HAVE_ENGINE_GET_DIGEST) | |
/* Document-method: OpenSSL::Engine#digest | |
* | |
* call-seq: | |
@@ -357,12 +333,10 @@ ossl_engine_get_digest(VALUE self, VALUE name) | |
{ | |
ENGINE *e; | |
const EVP_MD *md, *tmp; | |
- char *s; | |
int nid; | |
- s = StringValuePtr(name); | |
- tmp = EVP_get_digestbyname(s); | |
- if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s); | |
+ tmp = EVP_get_digestbyname(StringValueCStr(name)); | |
+ if(!tmp) ossl_raise(eEngineError, "no such digest `%"PRIsVALUE"'", name); | |
nid = EVP_MD_nid(tmp); | |
GetEngine(self, e); | |
md = ENGINE_get_digest(e, nid); | |
@@ -370,9 +344,6 @@ ossl_engine_get_digest(VALUE self, VALUE name) | |
return ossl_digest_new(md); | |
} | |
-#else | |
-#define ossl_engine_get_digest rb_f_notimplement | |
-#endif | |
/* Document-method: OpenSSL::Engine#load_private_key | |
* | |
@@ -393,14 +364,10 @@ ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self) | |
char *sid, *sdata; | |
rb_scan_args(argc, argv, "02", &id, &data); | |
- sid = NIL_P(id) ? NULL : StringValuePtr(id); | |
- sdata = NIL_P(data) ? NULL : StringValuePtr(data); | |
+ sid = NIL_P(id) ? NULL : StringValueCStr(id); | |
+ sdata = NIL_P(data) ? NULL : StringValueCStr(data); | |
GetEngine(self, e); | |
-#if OPENSSL_VERSION_NUMBER < 0x00907000L | |
- pkey = ENGINE_load_private_key(e, sid, sdata); | |
-#else | |
pkey = ENGINE_load_private_key(e, sid, NULL, sdata); | |
-#endif | |
if (!pkey) ossl_raise(eEngineError, NULL); | |
obj = ossl_pkey_new(pkey); | |
OSSL_PKEY_SET_PRIVATE(obj); | |
@@ -427,14 +394,10 @@ ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self) | |
char *sid, *sdata; | |
rb_scan_args(argc, argv, "02", &id, &data); | |
- sid = NIL_P(id) ? NULL : StringValuePtr(id); | |
- sdata = NIL_P(data) ? NULL : StringValuePtr(data); | |
+ sid = NIL_P(id) ? NULL : StringValueCStr(id); | |
+ sdata = NIL_P(data) ? NULL : StringValueCStr(data); | |
GetEngine(self, e); | |
-#if OPENSSL_VERSION_NUMBER < 0x00907000L | |
- pkey = ENGINE_load_public_key(e, sid, sdata); | |
-#else | |
pkey = ENGINE_load_public_key(e, sid, NULL, sdata); | |
-#endif | |
if (!pkey) ossl_raise(eEngineError, NULL); | |
return ossl_pkey_new(pkey); | |
@@ -487,10 +450,8 @@ ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self) | |
GetEngine(self, e); | |
rb_scan_args(argc, argv, "11", &cmd, &val); | |
- StringValue(cmd); | |
- if (!NIL_P(val)) StringValue(val); | |
- ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd), | |
- NIL_P(val) ? NULL : RSTRING_PTR(val), 0); | |
+ ret = ENGINE_ctrl_cmd_string(e, StringValueCStr(cmd), | |
+ NIL_P(val) ? NULL : StringValueCStr(val), 0); | |
if (!ret) ossl_raise(eEngineError, NULL); | |
return self; | |
@@ -553,15 +514,19 @@ ossl_engine_inspect(VALUE self) | |
void | |
Init_ossl_engine(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+#endif | |
+ | |
cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject); | |
eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError); | |
- rb_define_alloc_func(cEngine, ossl_engine_s_alloc); | |
+ rb_undef_alloc_func(cEngine); | |
rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1); | |
rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0); | |
rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0); | |
rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1); | |
- rb_undef_method(CLASS_OF(cEngine), "new"); | |
rb_define_method(cEngine, "id", ossl_engine_get_id, 0); | |
rb_define_method(cEngine, "name", ossl_engine_get_name, 0); | |
@@ -585,12 +550,8 @@ Init_ossl_engine(void) | |
#ifdef ENGINE_METHOD_BN_MOD_EXP_CRT | |
DefEngineConst(METHOD_BN_MOD_EXP_CRT); | |
#endif | |
-#ifdef ENGINE_METHOD_CIPHERS | |
DefEngineConst(METHOD_CIPHERS); | |
-#endif | |
-#ifdef ENGINE_METHOD_DIGESTS | |
DefEngineConst(METHOD_DIGESTS); | |
-#endif | |
DefEngineConst(METHOD_ALL); | |
DefEngineConst(METHOD_NONE); | |
} | |
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c | |
index 5513cb20de..270979ed92 100644 | |
--- a/ext/openssl/ossl_hmac.c | |
+++ b/ext/openssl/ossl_hmac.c | |
@@ -11,8 +11,8 @@ | |
#include "ossl.h" | |
-#define MakeHMAC(obj, klass, ctx) \ | |
- (obj) = TypedData_Make_Struct((klass), HMAC_CTX, &ossl_hmac_type, (ctx)) | |
+#define NewHMAC(klass) \ | |
+ TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0) | |
#define GetHMAC(obj, ctx) do { \ | |
TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \ | |
if (!(ctx)) { \ | |
@@ -40,8 +40,7 @@ VALUE eHMACError; | |
static void | |
ossl_hmac_free(void *ctx) | |
{ | |
- HMAC_CTX_cleanup(ctx); | |
- ruby_xfree(ctx); | |
+ HMAC_CTX_free(ctx); | |
} | |
static const rb_data_type_t ossl_hmac_type = { | |
@@ -55,11 +54,14 @@ static const rb_data_type_t ossl_hmac_type = { | |
static VALUE | |
ossl_hmac_alloc(VALUE klass) | |
{ | |
- HMAC_CTX *ctx; | |
VALUE obj; | |
+ HMAC_CTX *ctx; | |
- MakeHMAC(obj, klass, ctx); | |
- HMAC_CTX_init(ctx); | |
+ obj = NewHMAC(klass); | |
+ ctx = HMAC_CTX_new(); | |
+ if (!ctx) | |
+ ossl_raise(eHMACError, NULL); | |
+ RTYPEDDATA_DATA(obj) = ctx; | |
return obj; | |
} | |
@@ -107,8 +109,8 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) | |
StringValue(key); | |
GetHMAC(self, ctx); | |
- HMAC_Init(ctx, RSTRING_PTR(key), RSTRING_LENINT(key), | |
- GetDigestPtr(digest)); | |
+ HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key), | |
+ GetDigestPtr(digest), NULL); | |
return self; | |
} | |
@@ -124,7 +126,8 @@ ossl_hmac_copy(VALUE self, VALUE other) | |
GetHMAC(self, ctx1); | |
SafeGetHMAC(other, ctx2); | |
- HMAC_CTX_copy(ctx1, ctx2); | |
+ if (!HMAC_CTX_copy(ctx1, ctx2)) | |
+ ossl_raise(eHMACError, "HMAC_CTX_copy"); | |
return self; | |
} | |
@@ -159,18 +162,21 @@ ossl_hmac_update(VALUE self, VALUE data) | |
} | |
static void | |
-hmac_final(HMAC_CTX *ctx, unsigned char **buf, unsigned int *buf_len) | |
+hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len) | |
{ | |
- HMAC_CTX final; | |
+ HMAC_CTX *final; | |
- HMAC_CTX_copy(&final, ctx); | |
- if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) { | |
- HMAC_CTX_cleanup(&final); | |
- OSSL_Debug("Allocating %d mem", HMAC_size(&final)); | |
- ossl_raise(eHMACError, "Cannot allocate memory for hmac"); | |
+ final = HMAC_CTX_new(); | |
+ if (!final) | |
+ ossl_raise(eHMACError, "HMAC_CTX_new"); | |
+ | |
+ if (!HMAC_CTX_copy(final, ctx)) { | |
+ HMAC_CTX_free(final); | |
+ ossl_raise(eHMACError, "HMAC_CTX_copy"); | |
} | |
- HMAC_Final(&final, *buf, buf_len); | |
- HMAC_CTX_cleanup(&final); | |
+ | |
+ HMAC_Final(final, buf, buf_len); | |
+ HMAC_CTX_free(final); | |
} | |
/* | |
@@ -180,26 +186,25 @@ hmac_final(HMAC_CTX *ctx, unsigned char **buf, unsigned int *buf_len) | |
* Returns the authentication code an instance represents as a binary string. | |
* | |
* === Example | |
- * | |
- * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1')) | |
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f | |
- * instance.digest | |
- * #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?" | |
- * | |
+ * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1')) | |
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f | |
+ * instance.digest | |
+ * #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?" | |
*/ | |
static VALUE | |
ossl_hmac_digest(VALUE self) | |
{ | |
HMAC_CTX *ctx; | |
- unsigned char *buf; | |
unsigned int buf_len; | |
- VALUE digest; | |
+ VALUE ret; | |
GetHMAC(self, ctx); | |
- hmac_final(ctx, &buf, &buf_len); | |
- digest = ossl_buf2str((char *)buf, buf_len); | |
+ ret = rb_str_new(NULL, EVP_MAX_MD_SIZE); | |
+ hmac_final(ctx, (unsigned char *)RSTRING_PTR(ret), &buf_len); | |
+ assert(buf_len <= EVP_MAX_MD_SIZE); | |
+ rb_str_set_len(ret, buf_len); | |
- return digest; | |
+ return ret; | |
} | |
/* | |
@@ -208,27 +213,21 @@ ossl_hmac_digest(VALUE self) | |
* | |
* Returns the authentication code an instance represents as a hex-encoded | |
* string. | |
- * | |
*/ | |
static VALUE | |
ossl_hmac_hexdigest(VALUE self) | |
{ | |
HMAC_CTX *ctx; | |
- unsigned char *buf; | |
- char *hexbuf; | |
+ unsigned char buf[EVP_MAX_MD_SIZE]; | |
unsigned int buf_len; | |
- VALUE hexdigest; | |
+ VALUE ret; | |
GetHMAC(self, ctx); | |
- hmac_final(ctx, &buf, &buf_len); | |
- if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) { | |
- OPENSSL_free(buf); | |
- ossl_raise(eHMACError, "Memory alloc error"); | |
- } | |
- OPENSSL_free(buf); | |
- hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); | |
+ hmac_final(ctx, buf, &buf_len); | |
+ ret = rb_str_new(NULL, buf_len * 2); | |
+ ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len); | |
- return hexdigest; | |
+ return ret; | |
} | |
/* | |
@@ -256,7 +255,7 @@ ossl_hmac_reset(VALUE self) | |
HMAC_CTX *ctx; | |
GetHMAC(self, ctx); | |
- HMAC_Init(ctx, NULL, 0, NULL); | |
+ HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); | |
return self; | |
} | |
@@ -312,22 +311,22 @@ ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) | |
static VALUE | |
ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) | |
{ | |
- unsigned char *buf; | |
- char *hexbuf; | |
+ unsigned char buf[EVP_MAX_MD_SIZE]; | |
unsigned int buf_len; | |
- VALUE hexdigest; | |
+ VALUE ret; | |
StringValue(key); | |
StringValue(data); | |
- buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), | |
- (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); | |
- if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) { | |
- ossl_raise(eHMACError, "Cannot convert buf to hexbuf"); | |
- } | |
- hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); | |
+ if (!HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), | |
+ (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), | |
+ buf, &buf_len)) | |
+ ossl_raise(eHMACError, "HMAC"); | |
+ | |
+ ret = rb_str_new(NULL, buf_len * 2); | |
+ ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len); | |
- return hexdigest; | |
+ return ret; | |
} | |
/* | |
@@ -337,10 +336,38 @@ void | |
Init_ossl_hmac(void) | |
{ | |
#if 0 | |
- /* :nodoc: */ | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
+ /* | |
+ * Document-class: OpenSSL::HMAC | |
+ * | |
+ * OpenSSL::HMAC allows computing Hash-based Message Authentication Code | |
+ * (HMAC). It is a type of message authentication code (MAC) involving a | |
+ * hash function in combination with a key. HMAC can be used to verify the | |
+ * integrity of a message as well as the authenticity. | |
+ * | |
+ * OpenSSL::HMAC has a similar interface to OpenSSL::Digest. | |
+ * | |
+ * === HMAC-SHA256 using one-shot interface | |
+ * | |
+ * key = "key" | |
+ * data = "message-to-be-authenticated" | |
+ * mac = OpenSSL::HMAC.hexdigest("SHA256", key, data) | |
+ * #=> "cddb0db23f469c8bf072b21fd837149bd6ace9ab771cceef14c9e517cc93282e" | |
+ * | |
+ * === HMAC-SHA256 using incremental interface | |
+ * | |
+ * data1 = File.read("file1") | |
+ * data2 = File.read("file2") | |
+ * key = "key" | |
+ * digest = OpenSSL::Digest::SHA256.new | |
+ * hmac = OpenSSL::HMAC.new(key, digest) | |
+ * hmac << data1 | |
+ * hmac << data2 | |
+ * mac = hmac.digest | |
+ */ | |
eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError); | |
cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject); | |
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c | |
index 35c2e3e542..98f6552ec7 100644 | |
--- a/ext/openssl/ossl_ns_spki.c | |
+++ b/ext/openssl/ossl_ns_spki.c | |
@@ -86,15 +86,15 @@ ossl_spki_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
StringValue(buffer); | |
- if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), -1))) { | |
+ if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), RSTRING_LENINT(buffer)))) { | |
+ ossl_clear_error(); | |
p = (unsigned char *)RSTRING_PTR(buffer); | |
if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) { | |
ossl_raise(eSPKIError, NULL); | |
} | |
} | |
NETSCAPE_SPKI_free(DATA_PTR(self)); | |
- DATA_PTR(self) = spki; | |
- ERR_clear_error(); | |
+ SetSPKI(self, spki); | |
return self; | |
} | |
@@ -159,8 +159,6 @@ ossl_spki_print(VALUE self) | |
{ | |
NETSCAPE_SPKI *spki; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetSPKI(self, spki); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
@@ -170,11 +168,8 @@ ossl_spki_print(VALUE self) | |
BIO_free(out); | |
ossl_raise(eSPKIError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
/* | |
@@ -380,7 +375,8 @@ void | |
Init_ossl_ns_spki(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
mNetscape = rb_define_module_under(mOSSL, "Netscape"); | |
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c | |
index b97e26cf92..a8b3503d2a 100644 | |
--- a/ext/openssl/ossl_ocsp.c | |
+++ b/ext/openssl/ossl_ocsp.c | |
@@ -10,7 +10,7 @@ | |
*/ | |
#include "ossl.h" | |
-#if defined(OSSL_OCSP_ENABLED) | |
+#if !defined(OPENSSL_NO_OCSP) | |
#define NewOCSPReq(klass) \ | |
TypedData_Wrap_Struct((klass), &ossl_ocsp_request_type, 0) | |
@@ -57,6 +57,21 @@ | |
GetOCSPBasicRes((obj), (res)); \ | |
} while (0) | |
+#define NewOCSPSingleRes(klass) \ | |
+ TypedData_Wrap_Struct((klass), &ossl_ocsp_singleresp_type, 0) | |
+#define SetOCSPSingleRes(obj, res) do { \ | |
+ if(!(res)) ossl_raise(rb_eRuntimeError, "SingleResponse wasn't initialized!"); \ | |
+ RTYPEDDATA_DATA(obj) = (res); \ | |
+} while (0) | |
+#define GetOCSPSingleRes(obj, res) do { \ | |
+ TypedData_Get_Struct((obj), OCSP_SINGLERESP, &ossl_ocsp_singleresp_type, (res)); \ | |
+ if(!(res)) ossl_raise(rb_eRuntimeError, "SingleResponse wasn't initialized!"); \ | |
+} while (0) | |
+#define SafeGetOCSPSingleRes(obj, res) do { \ | |
+ OSSL_Check_Kind((obj), cOCSPSingleRes); \ | |
+ GetOCSPSingleRes((obj), (res)); \ | |
+} while (0) | |
+ | |
#define NewOCSPCertId(klass) \ | |
TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, 0) | |
#define SetOCSPCertId(obj, cid) do { \ | |
@@ -77,6 +92,7 @@ VALUE eOCSPError; | |
VALUE cOCSPReq; | |
VALUE cOCSPRes; | |
VALUE cOCSPBasicRes; | |
+VALUE cOCSPSingleRes; | |
VALUE cOCSPCertId; | |
static void | |
@@ -121,6 +137,20 @@ static const rb_data_type_t ossl_ocsp_basicresp_type = { | |
0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
}; | |
+static void | |
+ossl_ocsp_singleresp_free(void *ptr) | |
+{ | |
+ OCSP_SINGLERESP_free(ptr); | |
+} | |
+ | |
+static const rb_data_type_t ossl_ocsp_singleresp_type = { | |
+ "OpenSSL/OCSP/SINGLERESP", | |
+ { | |
+ 0, ossl_ocsp_singleresp_free, | |
+ }, | |
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
+}; | |
+ | |
static void | |
ossl_ocsp_certid_free(void *ptr) | |
{ | |
@@ -163,6 +193,25 @@ ossl_ocspreq_alloc(VALUE klass) | |
return obj; | |
} | |
+static VALUE | |
+ossl_ocspreq_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ OCSP_REQUEST *req, *req_old, *req_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetOCSPReq(self, req_old); | |
+ SafeGetOCSPReq(other, req); | |
+ | |
+ req_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_REQUEST), req); | |
+ if (!req_new) | |
+ ossl_raise(eOCSPError, "ASN1_item_dup"); | |
+ | |
+ SetOCSPReq(self, req_new); | |
+ OCSP_REQUEST_free(req_old); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* OpenSSL::OCSP::Request.new -> request | |
@@ -176,19 +225,20 @@ static VALUE | |
ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
VALUE arg; | |
+ OCSP_REQUEST *req, *req_new; | |
const unsigned char *p; | |
rb_scan_args(argc, argv, "01", &arg); | |
if(!NIL_P(arg)){ | |
- OCSP_REQUEST *req = DATA_PTR(self), *x; | |
+ GetOCSPReq(self, req); | |
arg = ossl_to_der_if_possible(arg); | |
StringValue(arg); | |
- p = (unsigned char*)RSTRING_PTR(arg); | |
- x = d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg)); | |
- DATA_PTR(self) = req; | |
- if(!x){ | |
- ossl_raise(eOCSPError, "cannot load DER encoded request"); | |
- } | |
+ p = (unsigned char *)RSTRING_PTR(arg); | |
+ req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg)); | |
+ if (!req_new) | |
+ ossl_raise(eOCSPError, "d2i_OCSP_REQUEST"); | |
+ SetOCSPReq(self, req_new); | |
+ OCSP_REQUEST_free(req); | |
} | |
return self; | |
@@ -319,49 +369,61 @@ ossl_ocspreq_get_certid(VALUE self) | |
/* | |
* call-seq: | |
- * request.sign(signer_cert, signer_key) -> self | |
- * request.sign(signer_cert, signer_key, certificates) -> self | |
- * request.sign(signer_cert, signer_key, certificates, flags) -> self | |
+ * request.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self | |
* | |
- * Signs this OCSP request using +signer_cert+ and +signer_key+. | |
- * +certificates+ is an optional Array of certificates that may be included in | |
- * the request. | |
+ * Signs this OCSP request using +cert+, +key+ and optional +digest+. If | |
+ * +digest+ is not specified, SHA-1 is used. +certs+ is an optional Array of | |
+ * additional certificates which are included in the request in addition to | |
+ * the signer certificate. Note that if +certs+ is nil or not given, flag | |
+ * OpenSSL::OCSP::NOCERTS is enabled. Pass an empty array to include only the | |
+ * signer certificate. | |
+ * | |
+ * +flags+ can be a bitwise OR of the following constants: | |
+ * | |
+ * OpenSSL::OCSP::NOCERTS:: | |
+ * Don't include any certificates in the request. +certs+ will be ignored. | |
*/ | |
- | |
static VALUE | |
ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self) | |
{ | |
- VALUE signer_cert, signer_key, certs, flags; | |
+ VALUE signer_cert, signer_key, certs, flags, digest; | |
OCSP_REQUEST *req; | |
X509 *signer; | |
EVP_PKEY *key; | |
- STACK_OF(X509) *x509s; | |
- unsigned long flg; | |
+ STACK_OF(X509) *x509s = NULL; | |
+ unsigned long flg = 0; | |
+ const EVP_MD *md; | |
int ret; | |
- rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags); | |
+ rb_scan_args(argc, argv, "23", &signer_cert, &signer_key, &certs, &flags, &digest); | |
+ GetOCSPReq(self, req); | |
signer = GetX509CertPtr(signer_cert); | |
key = GetPrivPKeyPtr(signer_key); | |
- flg = NIL_P(flags) ? 0 : NUM2INT(flags); | |
- if(NIL_P(certs)){ | |
- x509s = sk_X509_new_null(); | |
- flags |= OCSP_NOCERTS; | |
- } | |
- else x509s = ossl_x509_ary2sk(certs); | |
- GetOCSPReq(self, req); | |
- ret = OCSP_request_sign(req, signer, key, EVP_sha1(), x509s, flg); | |
+ if (!NIL_P(flags)) | |
+ flg = NUM2INT(flags); | |
+ if (NIL_P(digest)) | |
+ md = EVP_sha1(); | |
+ else | |
+ md = GetDigestPtr(digest); | |
+ if (NIL_P(certs)) | |
+ flg |= OCSP_NOCERTS; | |
+ else | |
+ x509s = ossl_x509_ary2sk(certs); | |
+ | |
+ ret = OCSP_request_sign(req, signer, key, md, x509s, flg); | |
sk_X509_pop_free(x509s, X509_free); | |
- if(!ret) ossl_raise(eOCSPError, NULL); | |
+ if (!ret) ossl_raise(eOCSPError, NULL); | |
return self; | |
} | |
/* | |
* call-seq: | |
- * request.verify(certificates, store) -> true or false | |
- * request.verify(certificates, store, flags) -> true or false | |
+ * request.verify(certificates, store, flags = 0) -> true or false | |
* | |
- * Verifies this request using the given +certificates+ and X509 +store+. | |
+ * Verifies this request using the given +certificates+ and +store+. | |
+ * +certificates+ is an array of OpenSSL::X509::Certificate, +store+ is an | |
+ * OpenSSL::X509::Store. | |
*/ | |
static VALUE | |
@@ -374,15 +436,16 @@ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self) | |
int flg, result; | |
rb_scan_args(argc, argv, "21", &certs, &store, &flags); | |
+ GetOCSPReq(self, req); | |
x509st = GetX509StorePtr(store); | |
flg = NIL_P(flags) ? 0 : NUM2INT(flags); | |
x509s = ossl_x509_ary2sk(certs); | |
- GetOCSPReq(self, req); | |
result = OCSP_request_verify(req, x509s, x509st, flg); | |
sk_X509_pop_free(x509s, X509_free); | |
- if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL)); | |
+ if (result <= 0) | |
+ ossl_clear_error(); | |
- return result ? Qtrue : Qfalse; | |
+ return result > 0 ? Qtrue : Qfalse; | |
} | |
/* | |
@@ -451,6 +514,25 @@ ossl_ocspres_alloc(VALUE klass) | |
return obj; | |
} | |
+static VALUE | |
+ossl_ocspres_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ OCSP_RESPONSE *res, *res_old, *res_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetOCSPRes(self, res_old); | |
+ SafeGetOCSPRes(other, res); | |
+ | |
+ res_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_RESPONSE), res); | |
+ if (!res_new) | |
+ ossl_raise(eOCSPError, "ASN1_item_dup"); | |
+ | |
+ SetOCSPRes(self, res_new); | |
+ OCSP_RESPONSE_free(res_old); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* OpenSSL::OCSP::Response.new -> response | |
@@ -464,19 +546,20 @@ static VALUE | |
ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
VALUE arg; | |
+ OCSP_RESPONSE *res, *res_new; | |
const unsigned char *p; | |
rb_scan_args(argc, argv, "01", &arg); | |
if(!NIL_P(arg)){ | |
- OCSP_RESPONSE *res = DATA_PTR(self), *x; | |
+ GetOCSPRes(self, res); | |
arg = ossl_to_der_if_possible(arg); | |
StringValue(arg); | |
p = (unsigned char *)RSTRING_PTR(arg); | |
- x = d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg)); | |
- DATA_PTR(self) = res; | |
- if(!x){ | |
- ossl_raise(eOCSPError, "cannot load DER encoded response"); | |
- } | |
+ res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg)); | |
+ if (!res_new) | |
+ ossl_raise(eOCSPError, "d2i_OCSP_RESPONSE"); | |
+ SetOCSPRes(self, res_new); | |
+ OCSP_RESPONSE_free(res); | |
} | |
return self; | |
@@ -587,16 +670,53 @@ ossl_ocspbres_alloc(VALUE klass) | |
return obj; | |
} | |
+static VALUE | |
+ossl_ocspbres_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ OCSP_BASICRESP *bs, *bs_old, *bs_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetOCSPBasicRes(self, bs_old); | |
+ SafeGetOCSPBasicRes(other, bs); | |
+ | |
+ bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs); | |
+ if (!bs_new) | |
+ ossl_raise(eOCSPError, "ASN1_item_dup"); | |
+ | |
+ SetOCSPBasicRes(self, bs_new); | |
+ OCSP_BASICRESP_free(bs_old); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
- * OpenSSL::OCSP::BasicResponse.new(*) -> basic_response | |
+ * OpenSSL::OCSP::BasicResponse.new(der_string = nil) -> basic_response | |
* | |
- * Creates a new BasicResponse and ignores all arguments. | |
+ * Creates a new BasicResponse. If +der_string+ is given, decodes +der_string+ | |
+ * as DER. | |
*/ | |
static VALUE | |
ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
+ VALUE arg; | |
+ OCSP_BASICRESP *res, *res_new; | |
+ const unsigned char *p; | |
+ | |
+ rb_scan_args(argc, argv, "01", &arg); | |
+ if (!NIL_P(arg)) { | |
+ GetOCSPBasicRes(self, res); | |
+ arg = ossl_to_der_if_possible(arg); | |
+ StringValue(arg); | |
+ p = (unsigned char *)RSTRING_PTR(arg); | |
+ res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg)); | |
+ if (!res_new) | |
+ ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP"); | |
+ SetOCSPBasicRes(self, res_new); | |
+ OCSP_BASICRESP_free(res); | |
+ } | |
+ | |
return self; | |
} | |
@@ -652,22 +772,49 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+add_status_convert_time(VALUE obj) | |
+{ | |
+ ASN1_TIME *time; | |
+ | |
+ if (RB_INTEGER_TYPE_P(obj)) | |
+ time = X509_gmtime_adj(NULL, NUM2INT(obj)); | |
+ else | |
+ time = ossl_x509_time_adjust(NULL, obj); | |
+ | |
+ if (!time) | |
+ ossl_raise(eOCSPError, NULL); | |
+ | |
+ return (VALUE)time; | |
+} | |
+ | |
/* | |
* call-seq: | |
* basic_response.add_status(certificate_id, status, reason, revocation_time, this_update, next_update, extensions) -> basic_response | |
* | |
- * Adds a validation +status+ (0 for good, 1 for revoked, 2 for unknown) to this | |
- * response for +certificate_id+. +reason+ describes the reason for the | |
- * revocation, if any. | |
+ * Adds a certificate status for +certificate_id+. +status+ is the status, and | |
+ * must be one of these: | |
* | |
- * The +revocation_time+, +this_update+ and +next_update+ are times for the | |
- * certificate's revocation time, the time of this status and the next update | |
- * time for a new status, respectively. | |
+ * - OpenSSL::OCSP::V_CERTSTATUS_GOOD | |
+ * - OpenSSL::OCSP::V_CERTSTATUS_REVOKED | |
+ * - OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN | |
* | |
- * +extensions+ may be an Array of OpenSSL::X509::Extension that will | |
- * be added to this response or nil. | |
+ * +reason+ and +revocation_time+ can be given only when +status+ is | |
+ * OpenSSL::OCSP::V_CERTSTATUS_REVOKED. +reason+ describes the reason for the | |
+ * revocation, and must be one of OpenSSL::OCSP::REVOKED_STATUS_* constants. | |
+ * +revocation_time+ is the time when the certificate is revoked. | |
+ * | |
+ * +this_update+ and +next_update+ indicate the time at which ths status is | |
+ * verified to be correct and the time at or before which newer information | |
+ * will be available, respectively. +next_update+ is optional. | |
+ * | |
+ * +extensions+ is an Array of OpenSSL::X509::Extension to be included in the | |
+ * SingleResponse. This is also optional. | |
+ * | |
+ * Note that the times, +revocation_time+, +this_update+ and +next_update+ | |
+ * can be specified in either of Integer or Time object. If they are Integer, it | |
+ * is treated as the relative seconds from the current time. | |
*/ | |
- | |
static VALUE | |
ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, | |
VALUE reason, VALUE revtime, | |
@@ -676,36 +823,37 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, | |
OCSP_BASICRESP *bs; | |
OCSP_SINGLERESP *single; | |
OCSP_CERTID *id; | |
- ASN1_TIME *ths, *nxt, *rev; | |
- int st, rsn, error, rstatus = 0; | |
+ ASN1_TIME *ths = NULL, *nxt = NULL, *rev = NULL; | |
+ int st, rsn = 0, error = 0, rstatus = 0; | |
long i; | |
VALUE tmp; | |
+ GetOCSPBasicRes(self, bs); | |
+ SafeGetOCSPCertId(cid, id); | |
st = NUM2INT(status); | |
- rsn = NIL_P(status) ? 0 : NUM2INT(reason); | |
- if(!NIL_P(ext)){ | |
- /* All ary's members should be X509Extension */ | |
- Check_Type(ext, T_ARRAY); | |
+ if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */ | |
+ ext = rb_check_array_type(ext); | |
for (i = 0; i < RARRAY_LEN(ext); i++) | |
OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext); | |
} | |
- error = 0; | |
- ths = nxt = rev = NULL; | |
- if(!NIL_P(revtime)){ | |
- tmp = rb_protect(rb_Integer, revtime, &rstatus); | |
- if(rstatus) goto err; | |
- rev = X509_gmtime_adj(NULL, NUM2INT(tmp)); | |
+ if (st == V_OCSP_CERTSTATUS_REVOKED) { | |
+ rsn = NUM2INT(reason); | |
+ tmp = rb_protect(add_status_convert_time, revtime, &rstatus); | |
+ if (rstatus) goto err; | |
+ rev = (ASN1_TIME *)tmp; | |
+ } | |
+ | |
+ tmp = rb_protect(add_status_convert_time, thisupd, &rstatus); | |
+ if (rstatus) goto err; | |
+ ths = (ASN1_TIME *)tmp; | |
+ | |
+ if (!NIL_P(nextupd)) { | |
+ tmp = rb_protect(add_status_convert_time, nextupd, &rstatus); | |
+ if (rstatus) goto err; | |
+ nxt = (ASN1_TIME *)tmp; | |
} | |
- tmp = rb_protect(rb_Integer, thisupd, &rstatus); | |
- if(rstatus) goto err; | |
- ths = X509_gmtime_adj(NULL, NUM2INT(tmp)); | |
- tmp = rb_protect(rb_Integer, nextupd, &rstatus); | |
- if(rstatus) goto err; | |
- nxt = X509_gmtime_adj(NULL, NUM2INT(tmp)); | |
- GetOCSPBasicRes(self, bs); | |
- SafeGetOCSPCertId(cid, id); | |
if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){ | |
error = 1; | |
goto err; | |
@@ -713,16 +861,13 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, | |
if(!NIL_P(ext)){ | |
X509_EXTENSION *x509ext; | |
- sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free); | |
- single->singleExtensions = NULL; | |
+ | |
for(i = 0; i < RARRAY_LEN(ext); i++){ | |
- x509ext = DupX509ExtPtr(RARRAY_AREF(ext, i)); | |
+ x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i)); | |
if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){ | |
- X509_EXTENSION_free(x509ext); | |
error = 1; | |
goto err; | |
} | |
- X509_EXTENSION_free(x509ext); | |
} | |
} | |
@@ -741,11 +886,13 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, | |
* basic_response.status -> statuses | |
* | |
* Returns an Array of statuses for this response. Each status contains a | |
- * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the reason for | |
- * the status, the revocation time, the time of this update, the time for the | |
- * next update and a list of OpenSSL::X509::Extensions. | |
+ * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the | |
+ * reason for the status, the revocation time, the time of this update, the time | |
+ * for the next update and a list of OpenSSL::X509::Extensions. | |
+ * | |
+ * This should be superseded by BasicResponse#responses and #find_response that | |
+ * return SingleResponse. | |
*/ | |
- | |
static VALUE | |
ossl_ocspbres_get_status(VALUE self) | |
{ | |
@@ -769,7 +916,7 @@ ossl_ocspbres_get_status(VALUE self) | |
status = OCSP_single_get0_status(single, &reason, &revtime, | |
&thisupd, &nextupd); | |
if(status < 0) continue; | |
- if(!(cid = OCSP_CERTID_dup(single->certId))) | |
+ if(!(cid = OCSP_CERTID_dup((OCSP_CERTID *)OCSP_SINGLERESP_get0_id(single)))) /* FIXME */ | |
ossl_raise(eOCSPError, NULL); | |
ary = rb_ary_new(); | |
rb_ary_push(ary, ossl_ocspcertid_new(cid)); | |
@@ -791,75 +938,512 @@ ossl_ocspbres_get_status(VALUE self) | |
return ret; | |
} | |
+static VALUE ossl_ocspsres_new(OCSP_SINGLERESP *); | |
+ | |
/* | |
* call-seq: | |
- * basic_response.sign(signer_cert, signer_key) -> self | |
- * basic_response.sign(signer_cert, signer_key, certificates) -> self | |
- * basic_response.sign(signer_cert, signer_key, certificates, flags) -> self | |
+ * basic_response.responses -> Array of SingleResponse | |
* | |
- * Signs this response using the +signer_cert+ and +signer_key+. Additional | |
- * +certificates+ may be added to the signature along with a set of +flags+. | |
+ * Returns an Array of SingleResponse for this BasicResponse. | |
+ */ | |
+ | |
+static VALUE | |
+ossl_ocspbres_get_responses(VALUE self) | |
+{ | |
+ OCSP_BASICRESP *bs; | |
+ VALUE ret; | |
+ int count, i; | |
+ | |
+ GetOCSPBasicRes(self, bs); | |
+ count = OCSP_resp_count(bs); | |
+ ret = rb_ary_new2(count); | |
+ | |
+ for (i = 0; i < count; i++) { | |
+ OCSP_SINGLERESP *sres, *sres_new; | |
+ | |
+ sres = OCSP_resp_get0(bs, i); | |
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres); | |
+ if (!sres_new) | |
+ ossl_raise(eOCSPError, "ASN1_item_dup"); | |
+ | |
+ rb_ary_push(ret, ossl_ocspsres_new(sres_new)); | |
+ } | |
+ | |
+ return ret; | |
+} | |
+ | |
+ | |
+/* | |
+ * call-seq: | |
+ * basic_response.find_response(certificate_id) -> SingleResponse | nil | |
+ * | |
+ * Returns a SingleResponse whose CertId matches with +certificate_id+, or nil | |
+ * if this BasicResponse does not contain it. | |
+ */ | |
+static VALUE | |
+ossl_ocspbres_find_response(VALUE self, VALUE target) | |
+{ | |
+ OCSP_BASICRESP *bs; | |
+ OCSP_SINGLERESP *sres, *sres_new; | |
+ OCSP_CERTID *id; | |
+ int n; | |
+ | |
+ SafeGetOCSPCertId(target, id); | |
+ GetOCSPBasicRes(self, bs); | |
+ | |
+ if ((n = OCSP_resp_find(bs, id, -1)) == -1) | |
+ return Qnil; | |
+ | |
+ sres = OCSP_resp_get0(bs, n); | |
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres); | |
+ if (!sres_new) | |
+ ossl_raise(eOCSPError, "ASN1_item_dup"); | |
+ | |
+ return ossl_ocspsres_new(sres_new); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * basic_response.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self | |
+ * | |
+ * Signs this OCSP response using the +cert+, +key+ and optional +digest+. This | |
+ * behaves in the similar way as OpenSSL::OCSP::Request#sign. | |
+ * | |
+ * +flags+ can include: | |
+ * OpenSSL::OCSP::NOCERTS:: don't include certificates | |
+ * OpenSSL::OCSP::NOTIME:: don't set producedAt | |
+ * OpenSSL::OCSP::RESPID_KEY:: use signer's public key hash as responderID | |
*/ | |
static VALUE | |
ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self) | |
{ | |
- VALUE signer_cert, signer_key, certs, flags; | |
+ VALUE signer_cert, signer_key, certs, flags, digest; | |
OCSP_BASICRESP *bs; | |
X509 *signer; | |
EVP_PKEY *key; | |
- STACK_OF(X509) *x509s; | |
- unsigned long flg; | |
+ STACK_OF(X509) *x509s = NULL; | |
+ unsigned long flg = 0; | |
+ const EVP_MD *md; | |
int ret; | |
- rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags); | |
+ rb_scan_args(argc, argv, "23", &signer_cert, &signer_key, &certs, &flags, &digest); | |
+ GetOCSPBasicRes(self, bs); | |
signer = GetX509CertPtr(signer_cert); | |
key = GetPrivPKeyPtr(signer_key); | |
- flg = NIL_P(flags) ? 0 : NUM2INT(flags); | |
- if(NIL_P(certs)){ | |
- x509s = sk_X509_new_null(); | |
+ if (!NIL_P(flags)) | |
+ flg = NUM2INT(flags); | |
+ if (NIL_P(digest)) | |
+ md = EVP_sha1(); | |
+ else | |
+ md = GetDigestPtr(digest); | |
+ if (NIL_P(certs)) | |
flg |= OCSP_NOCERTS; | |
- } | |
- else{ | |
+ else | |
x509s = ossl_x509_ary2sk(certs); | |
- } | |
- GetOCSPBasicRes(self, bs); | |
- ret = OCSP_basic_sign(bs, signer, key, EVP_sha1(), x509s, flg); | |
+ | |
+ ret = OCSP_basic_sign(bs, signer, key, md, x509s, flg); | |
sk_X509_pop_free(x509s, X509_free); | |
- if(!ret) ossl_raise(eOCSPError, NULL); | |
+ if (!ret) ossl_raise(eOCSPError, NULL); | |
return self; | |
} | |
/* | |
* call-seq: | |
- * basic_response.verify(certificates, store) -> true or false | |
- * basic_response.verify(certificates, store, flags) -> true or false | |
+ * basic_response.verify(certificates, store, flags = 0) -> true or false | |
* | |
- * Verifies the signature of the response using the given +certificates+, | |
- * +store+ and +flags+. | |
+ * Verifies the signature of the response using the given +certificates+ and | |
+ * +store+. This works in the similar way as OpenSSL::OCSP::Request#verify. | |
*/ | |
static VALUE | |
ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self) | |
{ | |
- VALUE certs, store, flags, result; | |
+ VALUE certs, store, flags; | |
OCSP_BASICRESP *bs; | |
STACK_OF(X509) *x509s; | |
X509_STORE *x509st; | |
- int flg; | |
+ int flg, result; | |
rb_scan_args(argc, argv, "21", &certs, &store, &flags); | |
+ GetOCSPBasicRes(self, bs); | |
x509st = GetX509StorePtr(store); | |
flg = NIL_P(flags) ? 0 : NUM2INT(flags); | |
x509s = ossl_x509_ary2sk(certs); | |
- GetOCSPBasicRes(self, bs); | |
- result = OCSP_basic_verify(bs, x509s, x509st, flg) > 0 ? Qtrue : Qfalse; | |
+#if (OPENSSL_VERSION_NUMBER < 0x1000202fL) || defined(LIBRESSL_VERSION_NUMBER) | |
+ /* | |
+ * OpenSSL had a bug that it doesn't use the certificates in x509s for | |
+ * verifying the chain. This can be a problem when the response is signed by | |
+ * a certificate issued by an intermediate CA. | |
+ * | |
+ * root_ca | |
+ * | | |
+ * intermediate_ca | |
+ * |-------------| | |
+ * end_entity ocsp_signer | |
+ * | |
+ * When the certificate hierarchy is like this, and the response contains | |
+ * only ocsp_signer certificate, the following code wrongly fails. | |
+ * | |
+ * store = OpenSSL::X509::Store.new; store.add_cert(root_ca) | |
+ * basic_response.verify([intermediate_ca], store) | |
+ * | |
+ * So add the certificates in x509s to the embedded certificates list first. | |
+ * | |
+ * This is fixed in OpenSSL 0.9.8zg, 1.0.0s, 1.0.1n, 1.0.2b. But it still | |
+ * exists in LibreSSL 2.1.10, 2.2.9, 2.3.6, 2.4.1. | |
+ */ | |
+ if (!(flg & (OCSP_NOCHAIN | OCSP_NOVERIFY)) && | |
+ sk_X509_num(x509s) && sk_X509_num(bs->certs)) { | |
+ int i; | |
+ | |
+ bs = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs); | |
+ if (!bs) { | |
+ sk_X509_pop_free(x509s, X509_free); | |
+ ossl_raise(eOCSPError, "ASN1_item_dup"); | |
+ } | |
+ | |
+ for (i = 0; i < sk_X509_num(x509s); i++) { | |
+ if (!OCSP_basic_add1_cert(bs, sk_X509_value(x509s, i))) { | |
+ sk_X509_pop_free(x509s, X509_free); | |
+ OCSP_BASICRESP_free(bs); | |
+ ossl_raise(eOCSPError, "OCSP_basic_add1_cert"); | |
+ } | |
+ } | |
+ result = OCSP_basic_verify(bs, x509s, x509st, flg); | |
+ OCSP_BASICRESP_free(bs); | |
+ } | |
+ else { | |
+ result = OCSP_basic_verify(bs, x509s, x509st, flg); | |
+ } | |
+#else | |
+ result = OCSP_basic_verify(bs, x509s, x509st, flg); | |
+#endif | |
sk_X509_pop_free(x509s, X509_free); | |
- if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL)); | |
+ if (result <= 0) | |
+ ossl_clear_error(); | |
+ | |
+ return result > 0 ? Qtrue : Qfalse; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * basic_response.to_der -> String | |
+ * | |
+ * Encodes this basic response into a DER-encoded string. | |
+ */ | |
+static VALUE | |
+ossl_ocspbres_to_der(VALUE self) | |
+{ | |
+ OCSP_BASICRESP *res; | |
+ VALUE str; | |
+ long len; | |
+ unsigned char *p; | |
- return result; | |
+ GetOCSPBasicRes(self, res); | |
+ if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0) | |
+ ossl_raise(eOCSPError, NULL); | |
+ str = rb_str_new(0, len); | |
+ p = (unsigned char *)RSTRING_PTR(str); | |
+ if (i2d_OCSP_BASICRESP(res, &p) <= 0) | |
+ ossl_raise(eOCSPError, NULL); | |
+ ossl_str_adjust(str, p); | |
+ | |
+ return str; | |
} | |
+/* | |
+ * OCSP::SingleResponse | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_new(OCSP_SINGLERESP *sres) | |
+{ | |
+ VALUE obj; | |
+ | |
+ obj = NewOCSPSingleRes(cOCSPSingleRes); | |
+ SetOCSPSingleRes(obj, sres); | |
+ | |
+ return obj; | |
+} | |
+ | |
+static VALUE | |
+ossl_ocspsres_alloc(VALUE klass) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ VALUE obj; | |
+ | |
+ obj = NewOCSPSingleRes(klass); | |
+ if (!(sres = OCSP_SINGLERESP_new())) | |
+ ossl_raise(eOCSPError, NULL); | |
+ SetOCSPSingleRes(obj, sres); | |
+ | |
+ return obj; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * OpenSSL::OCSP::SingleResponse.new(der_string) -> SingleResponse | |
+ * | |
+ * Creates a new SingleResponse from +der_string+. | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_initialize(VALUE self, VALUE arg) | |
+{ | |
+ OCSP_SINGLERESP *res, *res_new; | |
+ const unsigned char *p; | |
+ | |
+ arg = ossl_to_der_if_possible(arg); | |
+ StringValue(arg); | |
+ GetOCSPSingleRes(self, res); | |
+ | |
+ p = (unsigned char*)RSTRING_PTR(arg); | |
+ res_new = d2i_OCSP_SINGLERESP(NULL, &p, RSTRING_LEN(arg)); | |
+ if (!res_new) | |
+ ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP"); | |
+ SetOCSPSingleRes(self, res_new); | |
+ OCSP_SINGLERESP_free(res); | |
+ | |
+ return self; | |
+} | |
+ | |
+static VALUE | |
+ossl_ocspsres_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ OCSP_SINGLERESP *sres, *sres_old, *sres_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetOCSPSingleRes(self, sres_old); | |
+ SafeGetOCSPSingleRes(other, sres); | |
+ | |
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres); | |
+ if (!sres_new) | |
+ ossl_raise(eOCSPError, "ASN1_item_dup"); | |
+ | |
+ SetOCSPSingleRes(self, sres_new); | |
+ OCSP_SINGLERESP_free(sres_old); | |
+ | |
+ return self; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.check_validity(nsec = 0, maxsec = -1) -> true | false | |
+ * | |
+ * Checks the validity of thisUpdate and nextUpdate fields of this | |
+ * SingleResponse. This checks the current time is within the range thisUpdate | |
+ * to nextUpdate. | |
+ * | |
+ * It is possible that the OCSP request takes a few seconds or the time is not | |
+ * accurate. To avoid rejecting a valid response, this method allows the times | |
+ * to be within +nsec+ of the current time. | |
+ * | |
+ * Some responders don't set the nextUpdate field. This may cause a very old | |
+ * response to be considered valid. The +maxsec+ parameter can be used to limit | |
+ * the age of responses. | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_check_validity(int argc, VALUE *argv, VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ ASN1_GENERALIZEDTIME *this_update, *next_update; | |
+ VALUE nsec_v, maxsec_v; | |
+ int nsec, maxsec, status, ret; | |
+ | |
+ rb_scan_args(argc, argv, "02", &nsec_v, &maxsec_v); | |
+ nsec = NIL_P(nsec_v) ? 0 : NUM2INT(nsec_v); | |
+ maxsec = NIL_P(maxsec_v) ? -1 : NUM2INT(maxsec_v); | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ status = OCSP_single_get0_status(sres, NULL, NULL, &this_update, &next_update); | |
+ if (status < 0) | |
+ ossl_raise(eOCSPError, "OCSP_single_get0_status"); | |
+ | |
+ ret = OCSP_check_validity(this_update, next_update, nsec, maxsec); | |
+ | |
+ if (ret) | |
+ return Qtrue; | |
+ else { | |
+ ossl_clear_error(); | |
+ return Qfalse; | |
+ } | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.certid -> CertificateId | |
+ * | |
+ * Returns the CertificateId for which this SingleResponse is. | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_get_certid(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ OCSP_CERTID *id; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ id = OCSP_CERTID_dup((OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sres)); /* FIXME */ | |
+ | |
+ return ossl_ocspcertid_new(id); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.cert_status -> Integer | |
+ * | |
+ * Returns the status of the certificate identified by the certid. | |
+ * The return value may be one of these constant: | |
+ * | |
+ * - V_CERTSTATUS_GOOD | |
+ * - V_CERTSTATUS_REVOKED | |
+ * - V_CERTSTATUS_UNKNOWN | |
+ * | |
+ * When the status is V_CERTSTATUS_REVOKED, the time at which the certificate | |
+ * was revoked can be retrieved by #revocation_time. | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_get_cert_status(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ int status; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ status = OCSP_single_get0_status(sres, NULL, NULL, NULL, NULL); | |
+ if (status < 0) | |
+ ossl_raise(eOCSPError, "OCSP_single_get0_status"); | |
+ | |
+ return INT2NUM(status); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.this_update -> Time | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_get_this_update(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ int status; | |
+ ASN1_GENERALIZEDTIME *time; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ status = OCSP_single_get0_status(sres, NULL, NULL, &time, NULL); | |
+ if (status < 0) | |
+ ossl_raise(eOCSPError, "OCSP_single_get0_status"); | |
+ | |
+ return asn1time_to_time(time); /* will handle NULL */ | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.next_update -> Time | nil | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_get_next_update(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ int status; | |
+ ASN1_GENERALIZEDTIME *time; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ status = OCSP_single_get0_status(sres, NULL, NULL, NULL, &time); | |
+ if (status < 0) | |
+ ossl_raise(eOCSPError, "OCSP_single_get0_status"); | |
+ | |
+ return asn1time_to_time(time); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.revocation_time -> Time | nil | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_get_revocation_time(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ int status; | |
+ ASN1_GENERALIZEDTIME *time; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ status = OCSP_single_get0_status(sres, NULL, &time, NULL, NULL); | |
+ if (status < 0) | |
+ ossl_raise(eOCSPError, "OCSP_single_get0_status"); | |
+ if (status != V_OCSP_CERTSTATUS_REVOKED) | |
+ ossl_raise(eOCSPError, "certificate is not revoked"); | |
+ | |
+ return asn1time_to_time(time); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.revocation_reason -> Integer | nil | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_get_revocation_reason(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ int status, reason; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ status = OCSP_single_get0_status(sres, &reason, NULL, NULL, NULL); | |
+ if (status < 0) | |
+ ossl_raise(eOCSPError, "OCSP_single_get0_status"); | |
+ if (status != V_OCSP_CERTSTATUS_REVOKED) | |
+ ossl_raise(eOCSPError, "certificate is not revoked"); | |
+ | |
+ return INT2NUM(reason); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.extensions -> Array of X509::Extension | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_get_extensions(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ X509_EXTENSION *ext; | |
+ int count, i; | |
+ VALUE ary; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ | |
+ count = OCSP_SINGLERESP_get_ext_count(sres); | |
+ ary = rb_ary_new2(count); | |
+ for (i = 0; i < count; i++) { | |
+ ext = OCSP_SINGLERESP_get_ext(sres, i); | |
+ rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */ | |
+ } | |
+ | |
+ return ary; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * single_response.to_der -> String | |
+ * | |
+ * Encodes this SingleResponse into a DER-encoded string. | |
+ */ | |
+static VALUE | |
+ossl_ocspsres_to_der(VALUE self) | |
+{ | |
+ OCSP_SINGLERESP *sres; | |
+ VALUE str; | |
+ long len; | |
+ unsigned char *p; | |
+ | |
+ GetOCSPSingleRes(self, sres); | |
+ if ((len = i2d_OCSP_SINGLERESP(sres, NULL)) <= 0) | |
+ ossl_raise(eOCSPError, NULL); | |
+ str = rb_str_new(0, len); | |
+ p = (unsigned char *)RSTRING_PTR(str); | |
+ if (i2d_OCSP_SINGLERESP(sres, &p) <= 0) | |
+ ossl_raise(eOCSPError, NULL); | |
+ ossl_str_adjust(str, p); | |
+ | |
+ return str; | |
+} | |
+ | |
+ | |
/* | |
* OCSP::CertificateId | |
*/ | |
@@ -877,41 +1461,71 @@ ossl_ocspcid_alloc(VALUE klass) | |
return obj; | |
} | |
+static VALUE | |
+ossl_ocspcid_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ OCSP_CERTID *cid, *cid_old, *cid_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetOCSPCertId(self, cid_old); | |
+ SafeGetOCSPCertId(other, cid); | |
+ | |
+ cid_new = OCSP_CERTID_dup(cid); | |
+ if (!cid_new) | |
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup"); | |
+ | |
+ SetOCSPCertId(self, cid_new); | |
+ OCSP_CERTID_free(cid_old); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* OpenSSL::OCSP::CertificateId.new(subject, issuer, digest = nil) -> certificate_id | |
+ * OpenSSL::OCSP::CertificateId.new(der_string) -> certificate_id | |
* | |
* Creates a new OpenSSL::OCSP::CertificateId for the given +subject+ and | |
* +issuer+ X509 certificates. The +digest+ is used to compute the | |
* certificate ID and must be an OpenSSL::Digest instance. | |
+ * | |
+ * If only one argument is given, decodes it as DER representation of a | |
+ * certificate ID. | |
*/ | |
static VALUE | |
ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
OCSP_CERTID *id, *newid; | |
- X509 *x509s, *x509i; | |
VALUE subject, issuer, digest; | |
- const EVP_MD *md; | |
- if (rb_scan_args(argc, argv, "21", &subject, &issuer, &digest) == 0) { | |
- return self; | |
+ GetOCSPCertId(self, id); | |
+ if (rb_scan_args(argc, argv, "12", &subject, &issuer, &digest) == 1) { | |
+ VALUE arg; | |
+ const unsigned char *p; | |
+ | |
+ arg = ossl_to_der_if_possible(subject); | |
+ StringValue(arg); | |
+ p = (unsigned char *)RSTRING_PTR(arg); | |
+ newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg)); | |
+ if (!newid) | |
+ ossl_raise(eOCSPError, "d2i_OCSP_CERTID"); | |
} | |
+ else { | |
+ X509 *x509s, *x509i; | |
+ const EVP_MD *md; | |
- x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */ | |
- x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */ | |
+ x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */ | |
+ x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */ | |
+ md = !NIL_P(digest) ? GetDigestPtr(digest) : NULL; | |
- if (!NIL_P(digest)) { | |
- md = GetDigestPtr(digest); | |
newid = OCSP_cert_to_id(md, x509s, x509i); | |
- } else { | |
- newid = OCSP_cert_to_id(NULL, x509s, x509i); | |
+ if (!newid) | |
+ ossl_raise(eOCSPError, "OCSP_cert_to_id"); | |
} | |
- if(!newid) | |
- ossl_raise(eOCSPError, NULL); | |
- GetOCSPCertId(self, id); | |
+ | |
+ SetOCSPCertId(self, newid); | |
OCSP_CERTID_free(id); | |
- RDATA(self)->data = newid; | |
return self; | |
} | |
@@ -959,24 +1573,130 @@ ossl_ocspcid_cmp_issuer(VALUE self, VALUE other) | |
/* | |
* call-seq: | |
- * certificate_id.get_serial -> Integer | |
+ * certificate_id.serial -> Integer | |
* | |
- * Returns the serial number of the issuing certificate. | |
+ * Returns the serial number of the certificate for which status is being | |
+ * requested. | |
*/ | |
- | |
static VALUE | |
ossl_ocspcid_get_serial(VALUE self) | |
{ | |
OCSP_CERTID *id; | |
+ ASN1_INTEGER *serial; | |
+ | |
+ GetOCSPCertId(self, id); | |
+ OCSP_id_get0_info(NULL, NULL, NULL, &serial, id); | |
+ | |
+ return asn1integer_to_num(serial); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * certificate_id.issuer_name_hash -> String | |
+ * | |
+ * Returns the issuerNameHash of this certificate ID, the hash of the | |
+ * issuer's distinguished name calculated with the hashAlgorithm. | |
+ */ | |
+static VALUE | |
+ossl_ocspcid_get_issuer_name_hash(VALUE self) | |
+{ | |
+ OCSP_CERTID *id; | |
+ ASN1_OCTET_STRING *name_hash; | |
+ VALUE ret; | |
GetOCSPCertId(self, id); | |
+ OCSP_id_get0_info(&name_hash, NULL, NULL, NULL, id); | |
+ | |
+ ret = rb_str_new(NULL, name_hash->length * 2); | |
+ ossl_bin2hex(name_hash->data, RSTRING_PTR(ret), name_hash->length); | |
- return asn1integer_to_num(id->serialNumber); | |
+ return ret; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * certificate_id.issuer_key_hash -> String | |
+ * | |
+ * Returns the issuerKeyHash of this certificate ID, the hash of the issuer's | |
+ * public key. | |
+ */ | |
+static VALUE | |
+ossl_ocspcid_get_issuer_key_hash(VALUE self) | |
+{ | |
+ OCSP_CERTID *id; | |
+ ASN1_OCTET_STRING *key_hash; | |
+ VALUE ret; | |
+ | |
+ GetOCSPCertId(self, id); | |
+ OCSP_id_get0_info(NULL, NULL, &key_hash, NULL, id); | |
+ | |
+ ret = rb_str_new(NULL, key_hash->length * 2); | |
+ ossl_bin2hex(key_hash->data, RSTRING_PTR(ret), key_hash->length); | |
+ | |
+ return ret; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * certificate_id.hash_algorithm -> String | |
+ * | |
+ * Returns the ln (long name) of the hash algorithm used to generate | |
+ * the issuerNameHash and the issuerKeyHash values. | |
+ */ | |
+static VALUE | |
+ossl_ocspcid_get_hash_algorithm(VALUE self) | |
+{ | |
+ OCSP_CERTID *id; | |
+ ASN1_OBJECT *oid; | |
+ BIO *out; | |
+ | |
+ GetOCSPCertId(self, id); | |
+ OCSP_id_get0_info(NULL, &oid, NULL, NULL, id); | |
+ | |
+ if (!(out = BIO_new(BIO_s_mem()))) | |
+ ossl_raise(eOCSPError, "BIO_new"); | |
+ | |
+ if (!i2a_ASN1_OBJECT(out, oid)) { | |
+ BIO_free(out); | |
+ ossl_raise(eOCSPError, "i2a_ASN1_OBJECT"); | |
+ } | |
+ return ossl_membio2str(out); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * certificate_id.to_der -> String | |
+ * | |
+ * Encodes this certificate identifier into a DER-encoded string. | |
+ */ | |
+static VALUE | |
+ossl_ocspcid_to_der(VALUE self) | |
+{ | |
+ OCSP_CERTID *id; | |
+ VALUE str; | |
+ long len; | |
+ unsigned char *p; | |
+ | |
+ GetOCSPCertId(self, id); | |
+ if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0) | |
+ ossl_raise(eOCSPError, NULL); | |
+ str = rb_str_new(0, len); | |
+ p = (unsigned char *)RSTRING_PTR(str); | |
+ if (i2d_OCSP_CERTID(id, &p) <= 0) | |
+ ossl_raise(eOCSPError, NULL); | |
+ ossl_str_adjust(str, p); | |
+ | |
+ return str; | |
} | |
void | |
Init_ossl_ocsp(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+#endif | |
+ | |
/* | |
* OpenSSL::OCSP implements Online Certificate Status Protocol requests | |
* and responses. | |
@@ -1046,7 +1766,7 @@ Init_ossl_ocsp(void) | |
* store = OpenSSL::X509::Store.new | |
* store.set_default_paths | |
* | |
- * unless response.verify [], store then | |
+ * unless response_basic.verify [], store then | |
* raise 'response is not signed by a trusted certificate' | |
* end | |
* | |
@@ -1062,27 +1782,28 @@ Init_ossl_ocsp(void) | |
* | |
* p request.check_nonce basic_response #=> value from -1 to 3 | |
* | |
- * Then extract the status information from the basic response. (You can | |
- * check multiple certificates in a request, but for this example we only | |
- * submitted one.) | |
- * | |
- * response_certificate_id, status, reason, revocation_time, | |
- * this_update, next_update, extensions = basic_response.status | |
+ * Then extract the status information for the certificate from the basic | |
+ * response. | |
* | |
- * Then check the various fields. | |
+ * single_response = basic_response.find_response(certificate_id) | |
* | |
- * unless response_certificate_id == certificate_id then | |
- * raise 'certificate id mismatch' | |
+ * unless single_response | |
+ * raise 'basic_response does not have the status for the certificiate' | |
* end | |
* | |
- * now = Time.now | |
+ * Then check the validity. A status issued in the future must be rejected. | |
* | |
- * if this_update > now then | |
- * raise 'update date is in the future' | |
+ * unless single_response.check_validity | |
+ * raise 'this_update is in the future or next_update time has passed' | |
* end | |
* | |
- * if now > next_update then | |
- * raise 'next update time has passed' | |
+ * case single_response.cert_status | |
+ * when OpenSSL::OCSP::V_CERTSTATUS_GOOD | |
+ * puts 'certificate is still valid' | |
+ * when OpenSSL::OCSP::V_CERTSTATUS_REVOKED | |
+ * puts "certificate has been revoked at #{single_response.revocation_time}" | |
+ * when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN | |
+ * puts 'responder doesn't know about the certificate' | |
* end | |
*/ | |
@@ -1103,6 +1824,7 @@ Init_ossl_ocsp(void) | |
cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject); | |
rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc); | |
+ rb_define_copy_func(cOCSPReq, ossl_ocspreq_initialize_copy); | |
rb_define_method(cOCSPReq, "initialize", ossl_ocspreq_initialize, -1); | |
rb_define_method(cOCSPReq, "add_nonce", ossl_ocspreq_add_nonce, -1); | |
rb_define_method(cOCSPReq, "check_nonce", ossl_ocspreq_check_nonce, 1); | |
@@ -1120,6 +1842,7 @@ Init_ossl_ocsp(void) | |
cOCSPRes = rb_define_class_under(mOCSP, "Response", rb_cObject); | |
rb_define_singleton_method(cOCSPRes, "create", ossl_ocspres_s_create, 2); | |
rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc); | |
+ rb_define_copy_func(cOCSPRes, ossl_ocspres_initialize_copy); | |
rb_define_method(cOCSPRes, "initialize", ossl_ocspres_initialize, -1); | |
rb_define_method(cOCSPRes, "status", ossl_ocspres_status, 0); | |
rb_define_method(cOCSPRes, "status_string", ossl_ocspres_status_string, 0); | |
@@ -1134,13 +1857,36 @@ Init_ossl_ocsp(void) | |
cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject); | |
rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc); | |
+ rb_define_copy_func(cOCSPBasicRes, ossl_ocspbres_initialize_copy); | |
rb_define_method(cOCSPBasicRes, "initialize", ossl_ocspbres_initialize, -1); | |
rb_define_method(cOCSPBasicRes, "copy_nonce", ossl_ocspbres_copy_nonce, 1); | |
rb_define_method(cOCSPBasicRes, "add_nonce", ossl_ocspbres_add_nonce, -1); | |
rb_define_method(cOCSPBasicRes, "add_status", ossl_ocspbres_add_status, 7); | |
rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0); | |
+ rb_define_method(cOCSPBasicRes, "responses", ossl_ocspbres_get_responses, 0); | |
+ rb_define_method(cOCSPBasicRes, "find_response", ossl_ocspbres_find_response, 1); | |
rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1); | |
rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1); | |
+ rb_define_method(cOCSPBasicRes, "to_der", ossl_ocspbres_to_der, 0); | |
+ | |
+ /* | |
+ * An OpenSSL::OCSP::SingleResponse represents an OCSP SingleResponse | |
+ * structure, which contains the basic information of the status of the | |
+ * certificate. | |
+ */ | |
+ cOCSPSingleRes = rb_define_class_under(mOCSP, "SingleResponse", rb_cObject); | |
+ rb_define_alloc_func(cOCSPSingleRes, ossl_ocspsres_alloc); | |
+ rb_define_copy_func(cOCSPSingleRes, ossl_ocspsres_initialize_copy); | |
+ rb_define_method(cOCSPSingleRes, "initialize", ossl_ocspsres_initialize, 1); | |
+ rb_define_method(cOCSPSingleRes, "check_validity", ossl_ocspsres_check_validity, -1); | |
+ rb_define_method(cOCSPSingleRes, "certid", ossl_ocspsres_get_certid, 0); | |
+ rb_define_method(cOCSPSingleRes, "cert_status", ossl_ocspsres_get_cert_status, 0); | |
+ rb_define_method(cOCSPSingleRes, "this_update", ossl_ocspsres_get_this_update, 0); | |
+ rb_define_method(cOCSPSingleRes, "next_update", ossl_ocspsres_get_next_update, 0); | |
+ rb_define_method(cOCSPSingleRes, "revocation_time", ossl_ocspsres_get_revocation_time, 0); | |
+ rb_define_method(cOCSPSingleRes, "revocation_reason", ossl_ocspsres_get_revocation_reason, 0); | |
+ rb_define_method(cOCSPSingleRes, "extensions", ossl_ocspsres_get_extensions, 0); | |
+ rb_define_method(cOCSPSingleRes, "to_der", ossl_ocspsres_to_der, 0); | |
/* | |
* An OpenSSL::OCSP::CertificateId identifies a certificate to the CA so | |
@@ -1149,10 +1895,15 @@ Init_ossl_ocsp(void) | |
cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject); | |
rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc); | |
+ rb_define_copy_func(cOCSPCertId, ossl_ocspcid_initialize_copy); | |
rb_define_method(cOCSPCertId, "initialize", ossl_ocspcid_initialize, -1); | |
rb_define_method(cOCSPCertId, "cmp", ossl_ocspcid_cmp, 1); | |
rb_define_method(cOCSPCertId, "cmp_issuer", ossl_ocspcid_cmp_issuer, 1); | |
rb_define_method(cOCSPCertId, "serial", ossl_ocspcid_get_serial, 0); | |
+ rb_define_method(cOCSPCertId, "issuer_name_hash", ossl_ocspcid_get_issuer_name_hash, 0); | |
+ rb_define_method(cOCSPCertId, "issuer_key_hash", ossl_ocspcid_get_issuer_key_hash, 0); | |
+ rb_define_method(cOCSPCertId, "hash_algorithm", ossl_ocspcid_get_hash_algorithm, 0); | |
+ rb_define_method(cOCSPCertId, "to_der", ossl_ocspcid_to_der, 0); | |
/* Internal error in issuer */ | |
rb_define_const(mOCSP, "RESPONSE_STATUS_INTERNALERROR", INT2NUM(OCSP_RESPONSE_STATUS_INTERNALERROR)); | |
@@ -1254,8 +2005,7 @@ Init_ossl_ocsp(void) | |
/* The responder ID is based on the public key. */ | |
rb_define_const(mOCSP, "V_RESPID_KEY", INT2NUM(V_OCSP_RESPID_KEY)); | |
} | |
- | |
-#else /* ! OSSL_OCSP_ENABLED */ | |
+#else | |
void | |
Init_ossl_ocsp(void) | |
{ | |
diff --git a/ext/openssl/ossl_ocsp.h b/ext/openssl/ossl_ocsp.h | |
index c5064fbc85..21e2c99a2e 100644 | |
--- a/ext/openssl/ossl_ocsp.h | |
+++ b/ext/openssl/ossl_ocsp.h | |
@@ -11,7 +11,7 @@ | |
#if !defined(_OSSL_OCSP_H_) | |
#define _OSSL_OCSP_H_ | |
-#if defined(OSSL_OCSP_ENABLED) | |
+#if !defined(OPENSSL_NO_OCSP) | |
extern VALUE mOCSP; | |
extern VALUE cOPCSReq; | |
extern VALUE cOPCSRes; | |
diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c | |
index f2edd99057..0b9c7816b5 100644 | |
--- a/ext/openssl/ossl_pkcs12.c | |
+++ b/ext/openssl/ossl_pkcs12.c | |
@@ -65,6 +65,25 @@ ossl_pkcs12_s_allocate(VALUE klass) | |
return obj; | |
} | |
+static VALUE | |
+ossl_pkcs12_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ PKCS12 *p12, *p12_old, *p12_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetPKCS12(self, p12_old); | |
+ SafeGetPKCS12(other, p12); | |
+ | |
+ p12_new = ASN1_dup((i2d_of_void *)i2d_PKCS12, (d2i_of_void *)d2i_PKCS12, (char *)p12); | |
+ if (!p12_new) | |
+ ossl_raise(ePKCS12Error, "ASN1_dup"); | |
+ | |
+ SetPKCS12(self, p12_new); | |
+ PKCS12_free(p12_old); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* PKCS12.create(pass, name, key, cert [, ca, [, key_pbe [, cert_pbe [, key_iter [, mac_iter [, keytype]]]]]]) | |
@@ -74,8 +93,8 @@ ossl_pkcs12_s_allocate(VALUE klass) | |
* * +name+ - A string describing the key. | |
* * +key+ - Any PKey. | |
* * +cert+ - A X509::Certificate. | |
- * * * The public_key portion of the certificate must contain a valid public key. | |
- * * * The not_before and not_after fields must be filled in. | |
+ * * The public_key portion of the certificate must contain a valid public key. | |
+ * * The not_before and not_after fields must be filled in. | |
* * +ca+ - An optional array of X509::Certificate's. | |
* * +key_pbe+ - string | |
* * +cert_pbe+ - string | |
@@ -100,18 +119,18 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) | |
PKCS12 *p12; | |
rb_scan_args(argc, argv, "46", &pass, &name, &pkey, &cert, &ca, &key_nid, &cert_nid, &key_iter, &mac_iter, &keytype); | |
- passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass); | |
- friendlyname = NIL_P(name) ? NULL : StringValuePtr(name); | |
+ passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass); | |
+ friendlyname = NIL_P(name) ? NULL : StringValueCStr(name); | |
key = GetPKeyPtr(pkey); | |
x509 = GetX509CertPtr(cert); | |
/* TODO: make a VALUE to nid function */ | |
if (!NIL_P(key_nid)) { | |
- if ((nkey = OBJ_txt2nid(StringValuePtr(key_nid))) == NID_undef) | |
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(key_nid)); | |
+ if ((nkey = OBJ_txt2nid(StringValueCStr(key_nid))) == NID_undef) | |
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, key_nid); | |
} | |
if (!NIL_P(cert_nid)) { | |
- if ((ncert = OBJ_txt2nid(StringValuePtr(cert_nid))) == NID_undef) | |
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(cert_nid)); | |
+ if ((ncert = OBJ_txt2nid(StringValueCStr(cert_nid))) == NID_undef) | |
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, cert_nid); | |
} | |
if (!NIL_P(key_iter)) | |
kiter = NUM2INT(key_iter); | |
@@ -158,8 +177,8 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) | |
PKCS12 *pkcs = DATA_PTR(self); | |
if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self; | |
- passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass); | |
- in = ossl_obj2bio(&arg); | |
+ passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass); | |
+ in = ossl_obj2bio(arg); | |
d2i_PKCS12_bio(in, &pkcs); | |
DATA_PTR(self) = pkcs; | |
BIO_free(in); | |
@@ -171,15 +190,17 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) | |
if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s)) | |
ossl_raise(ePKCS12Error, "PKCS12_parse"); | |
ERR_pop_to_mark(); | |
- pkey = rb_protect((VALUE(*)_((VALUE)))ossl_pkey_new, (VALUE)key, | |
- &st); /* NO DUP */ | |
- if(st) goto err; | |
- cert = rb_protect((VALUE(*)_((VALUE)))ossl_x509_new, (VALUE)x509, &st); | |
- if(st) goto err; | |
- if(x509s){ | |
- ca = | |
- rb_protect((VALUE(*)_((VALUE)))ossl_x509_sk2ary, (VALUE)x509s, &st); | |
- if(st) goto err; | |
+ if (key) { | |
+ pkey = rb_protect((VALUE (*)(VALUE))ossl_pkey_new, (VALUE)key, &st); | |
+ if (st) goto err; | |
+ } | |
+ if (x509) { | |
+ cert = rb_protect((VALUE (*)(VALUE))ossl_x509_new, (VALUE)x509, &st); | |
+ if (st) goto err; | |
+ } | |
+ if (x509s) { | |
+ ca = rb_protect((VALUE (*)(VALUE))ossl_x509_sk2ary, (VALUE)x509s, &st); | |
+ if (st) goto err; | |
} | |
err: | |
@@ -216,6 +237,11 @@ ossl_pkcs12_to_der(VALUE self) | |
void | |
Init_ossl_pkcs12(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+#endif | |
+ | |
/* | |
* Defines a file format commonly used to store private keys with | |
* accompanying public key certificates, protected with a password-based | |
@@ -226,6 +252,7 @@ Init_ossl_pkcs12(void) | |
rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1); | |
rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate); | |
+ rb_define_copy_func(cPKCS12, ossl_pkcs12_initialize_copy); | |
rb_attr(cPKCS12, rb_intern("key"), 1, 0, Qfalse); | |
rb_attr(cPKCS12, rb_intern("certificate"), 1, 0, Qfalse); | |
rb_attr(cPKCS12, rb_intern("ca_certs"), 1, 0, Qfalse); | |
diff --git a/ext/openssl/ossl_pkcs5.c b/ext/openssl/ossl_pkcs5.c | |
index 73d989e164..47c5bfa3b8 100644 | |
--- a/ext/openssl/ossl_pkcs5.c | |
+++ b/ext/openssl/ossl_pkcs5.c | |
@@ -18,7 +18,7 @@ VALUE ePKCS5; | |
* * +keylen+ - integer | |
* * +digest+ - a string or OpenSSL::Digest object. | |
* | |
- * Available in OpenSSL 0.9.4. | |
+ * Available in OpenSSL >= 1.0.0. | |
* | |
* Digests other than SHA1 may not be supported by other cryptography libraries. | |
*/ | |
@@ -48,7 +48,6 @@ ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE key | |
#endif | |
-#ifdef HAVE_PKCS5_PBKDF2_HMAC_SHA1 | |
/* | |
* call-seq: | |
* PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, keylen) => string | |
@@ -61,7 +60,7 @@ ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE key | |
* | |
* This method is available in almost any version of OpenSSL. | |
* | |
- * Conforms to rfc2898. | |
+ * Conforms to RFC 2898. | |
*/ | |
static VALUE | |
ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen) | |
@@ -81,21 +80,14 @@ ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALU | |
return str; | |
} | |
-#else | |
-#define ossl_pkcs5_pbkdf2_hmac_sha1 rb_f_notimplement | |
-#endif | |
void | |
Init_ossl_pkcs5(void) | |
{ | |
- /* | |
- * Password-based Encryption | |
- * | |
- */ | |
- | |
- #if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
- #endif | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+#endif | |
/* Document-class: OpenSSL::PKCS5 | |
* | |
@@ -108,7 +100,7 @@ Init_ossl_pkcs5(void) | |
* | |
* PKCS5 offers support for PBKDF2 with an OpenSSL::Digest::SHA1-based | |
* HMAC, or an arbitrary Digest if the underlying version of OpenSSL | |
- * already supports it (>= 0.9.4). | |
+ * already supports it (>= 1.0.0). | |
* | |
* === Parameters | |
* ==== Password | |
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c | |
index 62570a443a..4040355f99 100644 | |
--- a/ext/openssl/ossl_pkcs7.c | |
+++ b/ext/openssl/ossl_pkcs7.c | |
@@ -127,6 +127,22 @@ static const rb_data_type_t ossl_pkcs7_recip_info_type = { | |
* Public | |
* (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM) | |
*/ | |
+static PKCS7_SIGNER_INFO * | |
+ossl_PKCS7_SIGNER_INFO_dup(const PKCS7_SIGNER_INFO *si) | |
+{ | |
+ return (PKCS7_SIGNER_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO, | |
+ (d2i_of_void *)d2i_PKCS7_SIGNER_INFO, | |
+ (char *)si); | |
+} | |
+ | |
+static PKCS7_RECIP_INFO * | |
+ossl_PKCS7_RECIP_INFO_dup(const PKCS7_RECIP_INFO *si) | |
+{ | |
+ return (PKCS7_RECIP_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO, | |
+ (d2i_of_void *)d2i_PKCS7_RECIP_INFO, | |
+ (char *)si); | |
+} | |
+ | |
static VALUE | |
ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si) | |
{ | |
@@ -134,7 +150,7 @@ ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si) | |
VALUE obj; | |
obj = NewPKCS7si(cPKCS7Signer); | |
- pkcs7 = p7si ? PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new(); | |
+ pkcs7 = p7si ? ossl_PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new(); | |
if (!pkcs7) ossl_raise(ePKCS7Error, NULL); | |
SetPKCS7si(obj, pkcs7); | |
@@ -147,7 +163,7 @@ DupPKCS7SignerPtr(VALUE obj) | |
PKCS7_SIGNER_INFO *p7si, *pkcs7; | |
SafeGetPKCS7si(obj, p7si); | |
- if (!(pkcs7 = PKCS7_SIGNER_INFO_dup(p7si))) { | |
+ if (!(pkcs7 = ossl_PKCS7_SIGNER_INFO_dup(p7si))) { | |
ossl_raise(ePKCS7Error, NULL); | |
} | |
@@ -161,7 +177,7 @@ ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri) | |
VALUE obj; | |
obj = NewPKCS7ri(cPKCS7Recipient); | |
- pkcs7 = p7ri ? PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new(); | |
+ pkcs7 = p7ri ? ossl_PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new(); | |
if (!pkcs7) ossl_raise(ePKCS7Error, NULL); | |
SetPKCS7ri(obj, pkcs7); | |
@@ -174,7 +190,7 @@ DupPKCS7RecipientPtr(VALUE obj) | |
PKCS7_RECIP_INFO *p7ri, *pkcs7; | |
SafeGetPKCS7ri(obj, p7ri); | |
- if (!(pkcs7 = PKCS7_RECIP_INFO_dup(p7ri))) { | |
+ if (!(pkcs7 = ossl_PKCS7_RECIP_INFO_dup(p7ri))) { | |
ossl_raise(ePKCS7Error, NULL); | |
} | |
@@ -193,7 +209,7 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg) | |
VALUE ret, data; | |
ret = NewPKCS7(cPKCS7); | |
- in = ossl_obj2bio(&arg); | |
+ in = ossl_obj2bio(arg); | |
out = NULL; | |
pkcs7 = SMIME_read_PKCS7(in, &out); | |
BIO_free(in); | |
@@ -225,7 +241,7 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass) | |
SafeGetPKCS7(pkcs7, p7); | |
if(!NIL_P(data) && PKCS7_is_detached(p7)) | |
flg |= PKCS7_DETACHED; | |
- in = NIL_P(data) ? NULL : ossl_obj2bio(&data); | |
+ in = NIL_P(data) ? NULL : ossl_obj2bio(data); | |
if(!(out = BIO_new(BIO_s_mem()))){ | |
BIO_free(in); | |
ossl_raise(ePKCS7Error, NULL); | |
@@ -262,7 +278,7 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass) | |
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ | |
flg = NIL_P(flags) ? 0 : NUM2INT(flags); | |
ret = NewPKCS7(cPKCS7); | |
- in = ossl_obj2bio(&data); | |
+ in = ossl_obj2bio(data); | |
if(NIL_P(certs)) x509s = NULL; | |
else{ | |
x509s = ossl_protect_x509_ary2sk(certs, &status); | |
@@ -318,7 +334,7 @@ ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass) | |
else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */ | |
flg = NIL_P(flags) ? 0 : NUM2INT(flags); | |
ret = NewPKCS7(cPKCS7); | |
- in = ossl_obj2bio(&data); | |
+ in = ossl_obj2bio(data); | |
x509s = ossl_protect_x509_ary2sk(certs, &status); | |
if(status){ | |
BIO_free(in); | |
@@ -369,7 +385,7 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self) | |
if(rb_scan_args(argc, argv, "01", &arg) == 0) | |
return self; | |
arg = ossl_to_der_if_possible(arg); | |
- in = ossl_obj2bio(&arg); | |
+ in = ossl_obj2bio(arg); | |
p7 = PEM_read_bio_PKCS7(in, &pkcs, NULL, NULL); | |
if (!p7) { | |
OSSL_BIO_reset(in); | |
@@ -429,12 +445,13 @@ ossl_pkcs7_sym2typeid(VALUE sym) | |
{ "digest", NID_pkcs7_digest }, | |
}; | |
- if (RB_TYPE_P(sym, T_SYMBOL)) sym = rb_sym2str(sym); | |
+ if (SYMBOL_P(sym)) sym = rb_sym2str(sym); | |
else StringValue(sym); | |
RSTRING_GETMEM(sym, s, l); | |
+ | |
for(i = 0; ; i++){ | |
if(i == numberof(p7_type_tab)) | |
- ossl_raise(ePKCS7Error, "unknown type \"%s\"", s); | |
+ ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym); | |
if(strlen(p7_type_tab[i].name) != l) continue; | |
if(strcmp(p7_type_tab[i].name, s) == 0){ | |
ret = p7_type_tab[i].nid; | |
@@ -760,7 +777,7 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self) | |
x509st = GetX509StorePtr(store); | |
flg = NIL_P(flags) ? 0 : NUM2INT(flags); | |
if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self); | |
- in = NIL_P(indata) ? NULL : ossl_obj2bio(&indata); | |
+ in = NIL_P(indata) ? NULL : ossl_obj2bio(indata); | |
if(NIL_P(certs)) x509s = NULL; | |
else{ | |
x509s = ossl_protect_x509_ary2sk(certs, &status); | |
@@ -778,9 +795,9 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self) | |
BIO_free(in); | |
sk_X509_pop_free(x509s, X509_free); | |
if (ok < 0) ossl_raise(ePKCS7Error, "PKCS7_verify"); | |
- msg = ERR_reason_error_string(ERR_get_error()); | |
+ msg = ERR_reason_error_string(ERR_peek_error()); | |
ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil); | |
- ERR_clear_error(); | |
+ ossl_clear_error(); | |
data = ossl_membio2str(out); | |
ossl_pkcs7_set_data(self, data); | |
@@ -827,7 +844,7 @@ ossl_pkcs7_add_data(VALUE self, VALUE data) | |
if(!PKCS7_content_new(pkcs7, NID_pkcs7_data)) | |
ossl_raise(ePKCS7Error, NULL); | |
} | |
- in = ossl_obj2bio(&data); | |
+ in = ossl_obj2bio(data); | |
if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err; | |
for(;;){ | |
if((len = BIO_read(in, buf, sizeof(buf))) <= 0) | |
@@ -1037,6 +1054,11 @@ ossl_pkcs7ri_get_enc_key(VALUE self) | |
void | |
Init_ossl_pkcs7(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+#endif | |
+ | |
cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject); | |
ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError); | |
rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1); | |
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c | |
index c551a7d775..9e6c615781 100644 | |
--- a/ext/openssl/ossl_pkey.c | |
+++ b/ext/openssl/ossl_pkey.c | |
@@ -15,25 +15,11 @@ | |
VALUE mPKey; | |
VALUE cPKey; | |
VALUE ePKeyError; | |
-ID id_private_q; | |
+static ID id_private_q; | |
/* | |
* callback for generating keys | |
*/ | |
-void | |
-ossl_generate_cb(int p, int n, void *arg) | |
-{ | |
- VALUE ary; | |
- | |
- ary = rb_ary_new2(2); | |
- rb_ary_store(ary, 0, INT2NUM(p)); | |
- rb_ary_store(ary, 1, INT2NUM(n)); | |
- | |
- rb_yield(ary); | |
-} | |
- | |
-#if HAVE_BN_GENCB | |
-/* OpenSSL 2nd version of GN generation callback */ | |
int | |
ossl_generate_cb_2(int p, int n, BN_GENCB *cb) | |
{ | |
@@ -41,7 +27,7 @@ ossl_generate_cb_2(int p, int n, BN_GENCB *cb) | |
struct ossl_generate_cb_arg *arg; | |
int state; | |
- arg = (struct ossl_generate_cb_arg *)cb->arg; | |
+ arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb); | |
if (arg->yield) { | |
ary = rb_ary_new2(2); | |
rb_ary_store(ary, 0, INT2NUM(p)); | |
@@ -66,7 +52,6 @@ ossl_generate_cb_stop(void *ptr) | |
struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr; | |
arg->stop = 1; | |
} | |
-#endif | |
static void | |
ossl_evp_pkey_free(void *ptr) | |
@@ -85,13 +70,13 @@ const rb_data_type_t ossl_evp_pkey_type = { | |
0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
}; | |
-VALUE | |
-ossl_pkey_new(EVP_PKEY *pkey) | |
+static VALUE | |
+pkey_new0(EVP_PKEY *pkey) | |
{ | |
- if (!pkey) { | |
- ossl_raise(ePKeyError, "Cannot make new key from NULL."); | |
- } | |
- switch (EVP_PKEY_type(pkey->type)) { | |
+ if (!pkey) | |
+ ossl_raise(ePKeyError, "cannot make new key from NULL"); | |
+ | |
+ switch (EVP_PKEY_base_id(pkey)) { | |
#if !defined(OPENSSL_NO_RSA) | |
case EVP_PKEY_RSA: | |
return ossl_rsa_new(pkey); | |
@@ -111,78 +96,107 @@ ossl_pkey_new(EVP_PKEY *pkey) | |
default: | |
ossl_raise(ePKeyError, "unsupported key type"); | |
} | |
- | |
- UNREACHABLE; | |
} | |
VALUE | |
-ossl_pkey_new_from_file(VALUE filename) | |
+ossl_pkey_new(EVP_PKEY *pkey) | |
{ | |
- FILE *fp; | |
- EVP_PKEY *pkey; | |
- | |
- SafeStringValue(filename); | |
- if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { | |
- ossl_raise(ePKeyError, "%s", strerror(errno)); | |
- } | |
- rb_fd_fix_cloexec(fileno(fp)); | |
+ VALUE obj; | |
+ int status; | |
- pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL); | |
- fclose(fp); | |
- if (!pkey) { | |
- ossl_raise(ePKeyError, NULL); | |
+ obj = rb_protect((VALUE (*)(VALUE))pkey_new0, (VALUE)pkey, &status); | |
+ if (status) { | |
+ EVP_PKEY_free(pkey); | |
+ rb_jump_tag(status); | |
} | |
- return ossl_pkey_new(pkey); | |
+ return obj; | |
} | |
/* | |
* call-seq: | |
- * OpenSSL::PKey.read(string [, pwd ] ) -> PKey | |
- * OpenSSL::PKey.read(file [, pwd ]) -> PKey | |
+ * OpenSSL::PKey.read(string [, pwd ]) -> PKey | |
+ * OpenSSL::PKey.read(io [, pwd ]) -> PKey | |
+ * | |
+ * Reads a DER or PEM encoded string from +string+ or +io+ and returns an | |
+ * instance of the appropriate PKey class. | |
* | |
* === Parameters | |
* * +string+ is a DER- or PEM-encoded string containing an arbitrary private | |
- * or public key. | |
- * * +file+ is an instance of +File+ containing a DER- or PEM-encoded | |
- * arbitrary private or public key. | |
+ * or public key. | |
+ * * +io+ is an instance of +IO+ containing a DER- or PEM-encoded | |
+ * arbitrary private or public key. | |
* * +pwd+ is an optional password in case +string+ or +file+ is an encrypted | |
- * PEM resource. | |
+ * PEM resource. | |
*/ | |
static VALUE | |
ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
- BIO *bio; | |
- VALUE data, pass; | |
- char *passwd = NULL; | |
+ EVP_PKEY *pkey; | |
+ BIO *bio; | |
+ VALUE data, pass; | |
- rb_scan_args(argc, argv, "11", &data, &pass); | |
+ rb_scan_args(argc, argv, "11", &data, &pass); | |
+ pass = ossl_pem_passwd_value(pass); | |
- bio = ossl_obj2bio(&data); | |
- if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) { | |
+ bio = ossl_obj2bio(data); | |
+ if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) { | |
OSSL_BIO_reset(bio); | |
- if (!NIL_P(pass)) { | |
- passwd = StringValuePtr(pass); | |
- } | |
- if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, passwd))) { | |
+ if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) { | |
OSSL_BIO_reset(bio); | |
if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) { | |
OSSL_BIO_reset(bio); | |
- if (!NIL_P(pass)) { | |
- passwd = StringValuePtr(pass); | |
- } | |
- pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, passwd); | |
+ pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, (void *)pass); | |
} | |
} | |
} | |
BIO_free(bio); | |
if (!pkey) | |
- ossl_raise(rb_eArgError, "Could not parse PKey"); | |
+ ossl_raise(ePKeyError, "Could not parse PKey"); | |
+ | |
return ossl_pkey_new(pkey); | |
} | |
+static void | |
+pkey_check_public_key(EVP_PKEY *pkey) | |
+{ | |
+ void *ptr; | |
+ const BIGNUM *n, *e, *pubkey; | |
+ | |
+ if (EVP_PKEY_missing_parameters(pkey)) | |
+ ossl_raise(ePKeyError, "parameters missing"); | |
+ | |
+ ptr = EVP_PKEY_get0(pkey); | |
+ switch (EVP_PKEY_base_id(pkey)) { | |
+ case EVP_PKEY_RSA: | |
+ RSA_get0_key(ptr, &n, &e, NULL); | |
+ if (n && e) | |
+ return; | |
+ break; | |
+ case EVP_PKEY_DSA: | |
+ DSA_get0_key(ptr, &pubkey, NULL); | |
+ if (pubkey) | |
+ return; | |
+ break; | |
+ case EVP_PKEY_DH: | |
+ DH_get0_key(ptr, &pubkey, NULL); | |
+ if (pubkey) | |
+ return; | |
+ break; | |
+#if !defined(OPENSSL_NO_EC) | |
+ case EVP_PKEY_EC: | |
+ if (EC_KEY_get0_public_key(ptr)) | |
+ return; | |
+ break; | |
+#endif | |
+ default: | |
+ /* unsupported type; assuming ok */ | |
+ return; | |
+ } | |
+ ossl_raise(ePKeyError, "public key missing"); | |
+} | |
+ | |
EVP_PKEY * | |
GetPKeyPtr(VALUE obj) | |
{ | |
@@ -212,21 +226,7 @@ DupPKeyPtr(VALUE obj) | |
EVP_PKEY *pkey; | |
SafeGetPKey(obj, pkey); | |
- CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); | |
- | |
- return pkey; | |
-} | |
- | |
-EVP_PKEY * | |
-DupPrivPKeyPtr(VALUE obj) | |
-{ | |
- EVP_PKEY *pkey; | |
- | |
- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) { | |
- ossl_raise(rb_eArgError, "Private key is needed."); | |
- } | |
- SafeGetPKey(obj, pkey); | |
- CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); | |
+ EVP_PKEY_up_ref(pkey); | |
return pkey; | |
} | |
@@ -286,24 +286,32 @@ static VALUE | |
ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) | |
{ | |
EVP_PKEY *pkey; | |
- EVP_MD_CTX ctx; | |
+ const EVP_MD *md; | |
+ EVP_MD_CTX *ctx; | |
unsigned int buf_len; | |
VALUE str; | |
int result; | |
- if (rb_funcallv(self, id_private_q, 0, NULL) != Qtrue) { | |
- ossl_raise(rb_eArgError, "Private key is needed."); | |
- } | |
- GetPKey(self, pkey); | |
- EVP_SignInit(&ctx, GetDigestPtr(digest)); | |
+ pkey = GetPrivPKeyPtr(self); | |
+ md = GetDigestPtr(digest); | |
StringValue(data); | |
- EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); | |
- str = rb_str_new(0, EVP_PKEY_size(pkey)+16); | |
- result = EVP_SignFinal(&ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey); | |
- EVP_MD_CTX_cleanup(&ctx); | |
+ str = rb_str_new(0, EVP_PKEY_size(pkey)); | |
+ | |
+ ctx = EVP_MD_CTX_new(); | |
+ if (!ctx) | |
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); | |
+ if (!EVP_SignInit_ex(ctx, md, NULL)) { | |
+ EVP_MD_CTX_free(ctx); | |
+ ossl_raise(ePKeyError, "EVP_SignInit_ex"); | |
+ } | |
+ if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { | |
+ EVP_MD_CTX_free(ctx); | |
+ ossl_raise(ePKeyError, "EVP_SignUpdate"); | |
+ } | |
+ result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey); | |
+ EVP_MD_CTX_free(ctx); | |
if (!result) | |
- ossl_raise(ePKeyError, NULL); | |
- assert((long)buf_len <= RSTRING_LEN(str)); | |
+ ossl_raise(ePKeyError, "EVP_SignFinal"); | |
rb_str_set_len(str, buf_len); | |
return str; | |
@@ -334,25 +342,39 @@ static VALUE | |
ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) | |
{ | |
EVP_PKEY *pkey; | |
- EVP_MD_CTX ctx; | |
- int result; | |
+ const EVP_MD *md; | |
+ EVP_MD_CTX *ctx; | |
+ int siglen, result; | |
GetPKey(self, pkey); | |
+ pkey_check_public_key(pkey); | |
+ md = GetDigestPtr(digest); | |
StringValue(sig); | |
+ siglen = RSTRING_LENINT(sig); | |
StringValue(data); | |
- EVP_VerifyInit(&ctx, GetDigestPtr(digest)); | |
- EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); | |
- result = EVP_VerifyFinal(&ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey); | |
- EVP_MD_CTX_cleanup(&ctx); | |
+ | |
+ ctx = EVP_MD_CTX_new(); | |
+ if (!ctx) | |
+ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); | |
+ if (!EVP_VerifyInit_ex(ctx, md, NULL)) { | |
+ EVP_MD_CTX_free(ctx); | |
+ ossl_raise(ePKeyError, "EVP_VerifyInit_ex"); | |
+ } | |
+ if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { | |
+ EVP_MD_CTX_free(ctx); | |
+ ossl_raise(ePKeyError, "EVP_VerifyUpdate"); | |
+ } | |
+ result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey); | |
+ EVP_MD_CTX_free(ctx); | |
switch (result) { | |
case 0: | |
+ ossl_clear_error(); | |
return Qfalse; | |
case 1: | |
return Qtrue; | |
default: | |
- ossl_raise(ePKeyError, NULL); | |
+ ossl_raise(ePKeyError, "EVP_VerifyFinal"); | |
} | |
- return Qnil; /* dummy */ | |
} | |
/* | |
@@ -362,7 +384,8 @@ void | |
Init_ossl_pkey(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
/* Document-module: OpenSSL::PKey | |
@@ -374,7 +397,7 @@ Init_ossl_pkey(void) | |
* algorithm consists of two parts: a public key that may be distributed | |
* to others and a private key that needs to remain secret. | |
* | |
- * Messages encrypted with a public key can only be encrypted by | |
+ * Messages encrypted with a public key can only be decrypted by | |
* recipients that are in possession of the associated private key. | |
* Since public key algorithms are considerably slower than symmetric | |
* key algorithms (cf. OpenSSL::Cipher) they are often used to establish | |
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h | |
index 7288d5af7f..e3b723cd68 100644 | |
--- a/ext/openssl/ossl_pkey.h | |
+++ b/ext/openssl/ossl_pkey.h | |
@@ -13,7 +13,6 @@ | |
extern VALUE mPKey; | |
extern VALUE cPKey; | |
extern VALUE ePKeyError; | |
-extern ID id_private_q; | |
extern const rb_data_type_t ossl_evp_pkey_type; | |
#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue) | |
@@ -40,9 +39,6 @@ extern const rb_data_type_t ossl_evp_pkey_type; | |
GetPKey((obj), (pkey)); \ | |
} while (0) | |
-void ossl_generate_cb(int, int, void *); | |
-#define HAVE_BN_GENCB defined(HAVE_RSA_GENERATE_KEY_EX) || defined(HAVE_DH_GENERATE_PARAMETERS_EX) || defined(HAVE_DSA_GENERATE_PARAMETERS_EX) | |
-#if HAVE_BN_GENCB | |
struct ossl_generate_cb_arg { | |
int yield; | |
int stop; | |
@@ -50,14 +46,11 @@ struct ossl_generate_cb_arg { | |
}; | |
int ossl_generate_cb_2(int p, int n, BN_GENCB *cb); | |
void ossl_generate_cb_stop(void *ptr); | |
-#endif | |
VALUE ossl_pkey_new(EVP_PKEY *); | |
-VALUE ossl_pkey_new_from_file(VALUE); | |
EVP_PKEY *GetPKeyPtr(VALUE); | |
EVP_PKEY *DupPKeyPtr(VALUE); | |
EVP_PKEY *GetPrivPKeyPtr(VALUE); | |
-EVP_PKEY *DupPrivPKeyPtr(VALUE); | |
void Init_ossl_pkey(void); | |
/* | |
@@ -99,53 +92,153 @@ extern VALUE eEC_POINT; | |
VALUE ossl_ec_new(EVP_PKEY *); | |
void Init_ossl_ec(void); | |
- | |
-#define OSSL_PKEY_BN(keytype, name) \ | |
+#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \ | |
/* \ | |
* call-seq: \ | |
- * key.##name -> aBN \ | |
+ * _keytype##.##_name -> aBN \ | |
*/ \ | |
-static VALUE ossl_##keytype##_get_##name(VALUE self) \ | |
+static VALUE ossl_##_keytype##_get_##_name(VALUE self) \ | |
{ \ | |
- EVP_PKEY *pkey; \ | |
- BIGNUM *bn; \ | |
+ _type *obj; \ | |
+ const BIGNUM *bn; \ | |
\ | |
- GetPKey(self, pkey); \ | |
- bn = pkey->pkey.keytype->name; \ | |
+ Get##_type(self, obj); \ | |
+ _get; \ | |
if (bn == NULL) \ | |
return Qnil; \ | |
return ossl_bn_new(bn); \ | |
-} \ | |
+} | |
+ | |
+#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \ | |
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \ | |
+ _type##_get0_##_group(obj, &bn, NULL, NULL)) \ | |
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \ | |
+ _type##_get0_##_group(obj, NULL, &bn, NULL)) \ | |
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3, \ | |
+ _type##_get0_##_group(obj, NULL, NULL, &bn)) | |
+ | |
+#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \ | |
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \ | |
+ _type##_get0_##_group(obj, &bn, NULL)) \ | |
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \ | |
+ _type##_get0_##_group(obj, NULL, &bn)) | |
+ | |
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \ | |
+/* \ | |
+ * call-seq: \ | |
+ * _keytype##.set_##_group(a1, a2, a3) -> self \ | |
+ */ \ | |
+static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \ | |
+{ \ | |
+ _type *obj; \ | |
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\ | |
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ | |
+ BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\ | |
+ \ | |
+ Get##_type(self, obj); \ | |
+ if (orig_bn1 && !(bn1 = BN_dup(orig_bn1)) || \ | |
+ orig_bn2 && !(bn2 = BN_dup(orig_bn2)) || \ | |
+ orig_bn3 && !(bn3 = BN_dup(orig_bn3))) { \ | |
+ BN_clear_free(bn1); \ | |
+ BN_clear_free(bn2); \ | |
+ BN_clear_free(bn3); \ | |
+ ossl_raise(eBNError, NULL); \ | |
+ } \ | |
+ \ | |
+ if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) { \ | |
+ BN_clear_free(bn1); \ | |
+ BN_clear_free(bn2); \ | |
+ BN_clear_free(bn3); \ | |
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \ | |
+ } \ | |
+ return self; \ | |
+} | |
+ | |
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \ | |
+/* \ | |
+ * call-seq: \ | |
+ * _keytype##.set_##_group(a1, a2) -> self \ | |
+ */ \ | |
+static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \ | |
+{ \ | |
+ _type *obj; \ | |
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\ | |
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ | |
+ \ | |
+ Get##_type(self, obj); \ | |
+ if (orig_bn1 && !(bn1 = BN_dup(orig_bn1)) || \ | |
+ orig_bn2 && !(bn2 = BN_dup(orig_bn2))) { \ | |
+ BN_clear_free(bn1); \ | |
+ BN_clear_free(bn2); \ | |
+ ossl_raise(eBNError, NULL); \ | |
+ } \ | |
+ \ | |
+ if (!_type##_set0_##_group(obj, bn1, bn2)) { \ | |
+ BN_clear_free(bn1); \ | |
+ BN_clear_free(bn2); \ | |
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \ | |
+ } \ | |
+ return self; \ | |
+} | |
+ | |
+#define OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, _name) \ | |
/* \ | |
* call-seq: \ | |
- * key.##name = bn -> bn \ | |
+ * _keytype##.##_name = bn -> bn \ | |
*/ \ | |
-static VALUE ossl_##keytype##_set_##name(VALUE self, VALUE bignum) \ | |
+static VALUE ossl_##_keytype##_set_##_name(VALUE self, VALUE bignum) \ | |
{ \ | |
- EVP_PKEY *pkey; \ | |
+ _type *obj; \ | |
BIGNUM *bn; \ | |
\ | |
- GetPKey(self, pkey); \ | |
+ rb_warning("#"#_name"= is deprecated; use #set_"#_group); \ | |
+ Get##_type(self, obj); \ | |
if (NIL_P(bignum)) { \ | |
- BN_clear_free(pkey->pkey.keytype->name); \ | |
- pkey->pkey.keytype->name = NULL; \ | |
+ BN_clear_free(obj->_name); \ | |
+ obj->_name = NULL; \ | |
return Qnil; \ | |
} \ | |
\ | |
bn = GetBNPtr(bignum); \ | |
- if (pkey->pkey.keytype->name == NULL) \ | |
- pkey->pkey.keytype->name = BN_new(); \ | |
- if (pkey->pkey.keytype->name == NULL) \ | |
+ if (obj->_name == NULL) \ | |
+ obj->_name = BN_new(); \ | |
+ if (obj->_name == NULL) \ | |
ossl_raise(eBNError, NULL); \ | |
- if (BN_copy(pkey->pkey.keytype->name, bn) == NULL) \ | |
+ if (BN_copy(obj->_name, bn) == NULL) \ | |
ossl_raise(eBNError, NULL); \ | |
return bignum; \ | |
} | |
+#if defined(HAVE_OPAQUE_OPENSSL) /* OpenSSL 1.1.0 */ | |
+#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \ | |
+ OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \ | |
+ OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) | |
+ | |
+#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \ | |
+ OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \ | |
+ OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) | |
+ | |
#define DEF_OSSL_PKEY_BN(class, keytype, name) \ | |
-do { \ | |
- rb_define_method((class), #name, ossl_##keytype##_get_##name, 0); \ | |
+ rb_define_method((class), #name, ossl_##keytype##_get_##name, 0) | |
+ | |
+#else | |
+#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \ | |
+ OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \ | |
+ OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \ | |
+ OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a1) \ | |
+ OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a2) \ | |
+ OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a3) | |
+ | |
+#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \ | |
+ OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \ | |
+ OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \ | |
+ OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a1) \ | |
+ OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a2) | |
+ | |
+#define DEF_OSSL_PKEY_BN(class, keytype, name) do { \ | |
+ rb_define_method((class), #name, ossl_##keytype##_get_##name, 0);\ | |
rb_define_method((class), #name "=", ossl_##keytype##_set_##name, 1);\ | |
} while (0) | |
+#endif /* HAVE_OPAQUE_OPENSSL */ | |
#endif /* _OSSL_PKEY_H_ */ | |
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c | |
index e1cf425bf9..dd85b7b9b6 100644 | |
--- a/ext/openssl/ossl_pkey_dh.c | |
+++ b/ext/openssl/ossl_pkey_dh.c | |
@@ -7,25 +7,21 @@ | |
* This program is licensed under the same licence as Ruby. | |
* (See the file 'LICENCE'.) | |
*/ | |
-#if !defined(OPENSSL_NO_DH) | |
- | |
#include "ossl.h" | |
+#if !defined(OPENSSL_NO_DH) | |
+ | |
#define GetPKeyDH(obj, pkey) do { \ | |
GetPKey((obj), (pkey)); \ | |
- if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_DH) { /* PARANOIA? */ \ | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { /* PARANOIA? */ \ | |
ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \ | |
} \ | |
} while (0) | |
- | |
-#define DH_HAS_PRIVATE(dh) ((dh)->priv_key) | |
- | |
-#ifdef OSSL_ENGINE_ENABLED | |
-# define DH_PRIVATE(dh) (DH_HAS_PRIVATE(dh) || (dh)->engine) | |
-#else | |
-# define DH_PRIVATE(dh) DH_HAS_PRIVATE(dh) | |
-#endif | |
- | |
+#define GetDH(obj, dh) do { \ | |
+ EVP_PKEY *_pkey; \ | |
+ GetPKeyDH((obj), _pkey); \ | |
+ (dh) = EVP_PKEY_get0_DH(_pkey); \ | |
+} while (0) | |
/* | |
* Classes | |
@@ -67,7 +63,7 @@ ossl_dh_new(EVP_PKEY *pkey) | |
obj = dh_instance(cDH, DH_new()); | |
} else { | |
obj = NewPKey(cDH); | |
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) { | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { | |
ossl_raise(rb_eTypeError, "Not a DH key!"); | |
} | |
SetPKey(obj, pkey); | |
@@ -82,7 +78,6 @@ ossl_dh_new(EVP_PKEY *pkey) | |
/* | |
* Private | |
*/ | |
-#if defined(HAVE_DH_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB | |
struct dh_blocking_gen_arg { | |
DH *dh; | |
int size; | |
@@ -98,27 +93,28 @@ dh_blocking_gen(void *arg) | |
gen->result = DH_generate_parameters_ex(gen->dh, gen->size, gen->gen, gen->cb); | |
return 0; | |
} | |
-#endif | |
static DH * | |
dh_generate(int size, int gen) | |
{ | |
-#if defined(HAVE_DH_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB | |
- BN_GENCB cb; | |
- struct ossl_generate_cb_arg cb_arg; | |
+ struct ossl_generate_cb_arg cb_arg = { 0 }; | |
struct dh_blocking_gen_arg gen_arg; | |
DH *dh = DH_new(); | |
+ BN_GENCB *cb = BN_GENCB_new(); | |
- if (!dh) return 0; | |
+ if (!dh || !cb) { | |
+ DH_free(dh); | |
+ BN_GENCB_free(cb); | |
+ return NULL; | |
+ } | |
- memset(&cb_arg, 0, sizeof(struct ossl_generate_cb_arg)); | |
if (rb_block_given_p()) | |
cb_arg.yield = 1; | |
- BN_GENCB_set(&cb, ossl_generate_cb_2, &cb_arg); | |
+ BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); | |
gen_arg.dh = dh; | |
gen_arg.size = size; | |
gen_arg.gen = gen; | |
- gen_arg.cb = &cb; | |
+ gen_arg.cb = cb; | |
if (cb_arg.yield == 1) { | |
/* we cannot release GVL when callback proc is supplied */ | |
dh_blocking_gen(&gen_arg); | |
@@ -127,21 +123,20 @@ dh_generate(int size, int gen) | |
rb_thread_call_without_gvl(dh_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); | |
} | |
+ BN_GENCB_free(cb); | |
if (!gen_arg.result) { | |
DH_free(dh); | |
- if (cb_arg.state) rb_jump_tag(cb_arg.state); | |
- return 0; | |
+ if (cb_arg.state) { | |
+ /* Clear OpenSSL error queue before re-raising. */ | |
+ ossl_clear_error(); | |
+ rb_jump_tag(cb_arg.state); | |
+ } | |
+ return NULL; | |
} | |
-#else | |
- DH *dh; | |
- | |
- dh = DH_generate_parameters(size, gen, rb_block_given_p() ? ossl_generate_cb : NULL, NULL); | |
- if (!dh) return 0; | |
-#endif | |
if (!DH_generate_key(dh)) { | |
DH_free(dh); | |
- return 0; | |
+ return NULL; | |
} | |
return dh; | |
@@ -180,8 +175,10 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) | |
} | |
/* | |
- * call-seq: | |
- * DH.new([size [, generator] | string]) -> dh | |
+ * call-seq: | |
+ * DH.new -> dh | |
+ * DH.new(string) -> dh | |
+ * DH.new(size [, generator]) -> dh | |
* | |
* Either generates a DH instance from scratch or by reading already existing | |
* DH parameters from +string+. Note that when reading a DH instance from | |
@@ -215,17 +212,17 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) | |
if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) { | |
dh = DH_new(); | |
} | |
- else if (FIXNUM_P(arg)) { | |
+ else if (RB_INTEGER_TYPE_P(arg)) { | |
if (!NIL_P(gen)) { | |
g = NUM2INT(gen); | |
} | |
- if (!(dh = dh_generate(FIX2INT(arg), g))) { | |
+ if (!(dh = dh_generate(NUM2INT(arg), g))) { | |
ossl_raise(eDHError, NULL); | |
} | |
} | |
else { | |
arg = ossl_to_der_if_possible(arg); | |
- in = ossl_obj2bio(&arg); | |
+ in = ossl_obj2bio(arg); | |
dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); | |
if (!dh){ | |
OSSL_BIO_reset(in); | |
@@ -243,6 +240,39 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+ossl_dh_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ EVP_PKEY *pkey; | |
+ DH *dh, *dh_other; | |
+ const BIGNUM *pub, *priv; | |
+ | |
+ GetPKey(self, pkey); | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) | |
+ ossl_raise(eDHError, "DH already initialized"); | |
+ GetDH(other, dh_other); | |
+ | |
+ dh = DHparams_dup(dh_other); | |
+ if (!dh) | |
+ ossl_raise(eDHError, "DHparams_dup"); | |
+ EVP_PKEY_assign_DH(pkey, dh); | |
+ | |
+ DH_get0_key(dh_other, &pub, &priv); | |
+ if (pub) { | |
+ BIGNUM *pub2 = BN_dup(pub); | |
+ BIGNUM *priv2 = BN_dup(priv); | |
+ | |
+ if (!pub2 || priv && !priv2) { | |
+ BN_clear_free(pub2); | |
+ BN_clear_free(priv2); | |
+ ossl_raise(eDHError, "BN_dup"); | |
+ } | |
+ DH_set0_key(dh, pub2, priv2); | |
+ } | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* dh.public? -> true | false | |
@@ -253,11 +283,13 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_dh_is_public(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DH *dh; | |
+ const BIGNUM *bn; | |
- GetPKeyDH(self, pkey); | |
+ GetDH(self, dh); | |
+ DH_get0_key(dh, &bn, NULL); | |
- return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse; | |
+ return bn ? Qtrue : Qfalse; | |
} | |
/* | |
@@ -270,11 +302,17 @@ ossl_dh_is_public(VALUE self) | |
static VALUE | |
ossl_dh_is_private(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DH *dh; | |
+ const BIGNUM *bn; | |
- GetPKeyDH(self, pkey); | |
+ GetDH(self, dh); | |
+ DH_get0_key(dh, NULL, &bn); | |
- return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse; | |
+#if !defined(OPENSSL_NO_ENGINE) | |
+ return (bn || DH_get0_engine(dh)) ? Qtrue : Qfalse; | |
+#else | |
+ return bn ? Qtrue : Qfalse; | |
+#endif | |
} | |
/* | |
@@ -290,15 +328,15 @@ ossl_dh_is_private(VALUE self) | |
static VALUE | |
ossl_dh_export(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DH *dh; | |
BIO *out; | |
VALUE str; | |
- GetPKeyDH(self, pkey); | |
+ GetDH(self, dh); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eDHError, NULL); | |
} | |
- if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) { | |
+ if (!PEM_write_bio_DHparams(out, dh)) { | |
BIO_free(out); | |
ossl_raise(eDHError, NULL); | |
} | |
@@ -319,17 +357,17 @@ ossl_dh_export(VALUE self) | |
static VALUE | |
ossl_dh_to_der(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DH *dh; | |
unsigned char *p; | |
long len; | |
VALUE str; | |
- GetPKeyDH(self, pkey); | |
- if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0) | |
+ GetDH(self, dh); | |
+ if((len = i2d_DHparams(dh, NULL)) <= 0) | |
ossl_raise(eDHError, NULL); | |
str = rb_str_new(0, len); | |
p = (unsigned char *)RSTRING_PTR(str); | |
- if(i2d_DHparams(pkey->pkey.dh, &p) < 0) | |
+ if(i2d_DHparams(dh, &p) < 0) | |
ossl_raise(eDHError, NULL); | |
ossl_str_adjust(str, p); | |
@@ -347,17 +385,20 @@ ossl_dh_to_der(VALUE self) | |
static VALUE | |
ossl_dh_get_params(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DH *dh; | |
VALUE hash; | |
+ const BIGNUM *p, *q, *g, *pub_key, *priv_key; | |
- GetPKeyDH(self, pkey); | |
+ GetDH(self, dh); | |
+ DH_get0_pqg(dh, &p, &q, &g); | |
+ DH_get0_key(dh, &pub_key, &priv_key); | |
hash = rb_hash_new(); | |
- | |
- rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dh->p)); | |
- rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dh->g)); | |
- rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dh->pub_key)); | |
- rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dh->priv_key)); | |
+ rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p)); | |
+ rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q)); | |
+ rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g)); | |
+ rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key)); | |
+ rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key)); | |
return hash; | |
} | |
@@ -373,15 +414,15 @@ ossl_dh_get_params(VALUE self) | |
static VALUE | |
ossl_dh_to_text(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DH *dh; | |
BIO *out; | |
VALUE str; | |
- GetPKeyDH(self, pkey); | |
+ GetDH(self, dh); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eDHError, NULL); | |
} | |
- if (!DHparams_print(out, pkey->pkey.dh)) { | |
+ if (!DHparams_print(out, dh)) { | |
BIO_free(out); | |
ossl_raise(eDHError, NULL); | |
} | |
@@ -414,13 +455,12 @@ ossl_dh_to_text(VALUE self) | |
static VALUE | |
ossl_dh_to_public_key(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
- DH *dh; | |
+ DH *orig_dh, *dh; | |
VALUE obj; | |
- GetPKeyDH(self, pkey); | |
- dh = DHparams_dup(pkey->pkey.dh); /* err check perfomed by dh_instance */ | |
- obj = dh_instance(CLASS_OF(self), dh); | |
+ GetDH(self, orig_dh); | |
+ dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */ | |
+ obj = dh_instance(rb_obj_class(self), dh); | |
if (obj == Qfalse) { | |
DH_free(dh); | |
ossl_raise(eDHError, NULL); | |
@@ -441,12 +481,9 @@ static VALUE | |
ossl_dh_check_params(VALUE self) | |
{ | |
DH *dh; | |
- EVP_PKEY *pkey; | |
int codes; | |
- GetPKeyDH(self, pkey); | |
- dh = pkey->pkey.dh; | |
- | |
+ GetDH(self, dh); | |
if (!DH_check(dh, &codes)) { | |
return Qfalse; | |
} | |
@@ -474,11 +511,8 @@ static VALUE | |
ossl_dh_generate_key(VALUE self) | |
{ | |
DH *dh; | |
- EVP_PKEY *pkey; | |
- | |
- GetPKeyDH(self, pkey); | |
- dh = pkey->pkey.dh; | |
+ GetDH(self, dh); | |
if (!DH_generate_key(dh)) | |
ossl_raise(eDHError, "Failed to generate key"); | |
return self; | |
@@ -493,20 +527,19 @@ ossl_dh_generate_key(VALUE self) | |
* | |
* === Parameters | |
* * +pub_bn+ is a OpenSSL::BN, *not* the DH instance returned by | |
- * DH#public_key as that contains the DH parameters only. | |
+ * DH#public_key as that contains the DH parameters only. | |
*/ | |
static VALUE | |
ossl_dh_compute_key(VALUE self, VALUE pub) | |
{ | |
DH *dh; | |
- EVP_PKEY *pkey; | |
- BIGNUM *pub_key; | |
+ const BIGNUM *pub_key, *dh_p; | |
VALUE str; | |
int len; | |
- GetPKeyDH(self, pkey); | |
- dh = pkey->pkey.dh; | |
- if (!dh->p) | |
+ GetDH(self, dh); | |
+ DH_get0_pqg(dh, &dh_p, NULL, NULL); | |
+ if (!dh_p) | |
ossl_raise(eDHError, "incomplete DH"); | |
pub_key = GetBNPtr(pub); | |
len = DH_size(dh); | |
@@ -519,10 +552,22 @@ ossl_dh_compute_key(VALUE self, VALUE pub) | |
return str; | |
} | |
-OSSL_PKEY_BN(dh, p) | |
-OSSL_PKEY_BN(dh, g) | |
-OSSL_PKEY_BN(dh, pub_key) | |
-OSSL_PKEY_BN(dh, priv_key) | |
+/* | |
+ * Document-method: OpenSSL::PKey::DH#set_pqg | |
+ * call-seq: | |
+ * dh.set_pqg(p, q, g) -> self | |
+ * | |
+ * Sets +p+, +q+, +g+ for the DH instance. | |
+ */ | |
+OSSL_PKEY_BN_DEF3(dh, DH, pqg, p, q, g) | |
+/* | |
+ * Document-method: OpenSSL::PKey::DH#set_key | |
+ * call-seq: | |
+ * dh.set_key(pub_key, priv_key) -> self | |
+ * | |
+ * Sets +pub_key+ and +priv_key+ for the DH instance. +priv_key+ may be nil. | |
+ */ | |
+OSSL_PKEY_BN_DEF2(dh, DH, key, pub_key, priv_key) | |
/* | |
* INIT | |
@@ -531,8 +576,9 @@ void | |
Init_ossl_dh(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */ | |
mPKey = rb_define_module_under(mOSSL, "PKey"); | |
+ cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); | |
+ ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); | |
#endif | |
/* Document-class: OpenSSL::PKey::DHError | |
@@ -549,15 +595,15 @@ Init_ossl_dh(void) | |
* on. | |
* | |
* === Accessor methods for the Diffie-Hellman parameters | |
- * * DH#p | |
- * The prime (an OpenSSL::BN) of the Diffie-Hellman parameters. | |
- * * DH#g | |
- * The generator (an OpenSSL::BN) g of the Diffie-Hellman parameters. | |
- * * DH#pub_key | |
- * The per-session public key (an OpenSSL::BN) matching the private key. | |
- * This needs to be passed to DH#compute_key. | |
- * * DH#priv_key | |
- * The per-session private key, an OpenSSL::BN. | |
+ * DH#p:: | |
+ * The prime (an OpenSSL::BN) of the Diffie-Hellman parameters. | |
+ * DH#g:: | |
+ * The generator (an OpenSSL::BN) g of the Diffie-Hellman parameters. | |
+ * DH#pub_key:: | |
+ * The per-session public key (an OpenSSL::BN) matching the private key. | |
+ * This needs to be passed to DH#compute_key. | |
+ * DH#priv_key:: | |
+ * The per-session private key, an OpenSSL::BN. | |
* | |
* === Example of a key exchange | |
* dh1 = OpenSSL::PKey::DH.new(2048) | |
@@ -572,6 +618,7 @@ Init_ossl_dh(void) | |
cDH = rb_define_class_under(mPKey, "DH", cPKey); | |
rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1); | |
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); | |
+ rb_define_copy_func(cDH, ossl_dh_initialize_copy); | |
rb_define_method(cDH, "public?", ossl_dh_is_public, 0); | |
rb_define_method(cDH, "private?", ossl_dh_is_private, 0); | |
rb_define_method(cDH, "to_text", ossl_dh_to_text, 0); | |
@@ -585,9 +632,13 @@ Init_ossl_dh(void) | |
rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1); | |
DEF_OSSL_PKEY_BN(cDH, dh, p); | |
+ DEF_OSSL_PKEY_BN(cDH, dh, q); | |
DEF_OSSL_PKEY_BN(cDH, dh, g); | |
DEF_OSSL_PKEY_BN(cDH, dh, pub_key); | |
DEF_OSSL_PKEY_BN(cDH, dh, priv_key); | |
+ rb_define_method(cDH, "set_pqg", ossl_dh_set_pqg, 3); | |
+ rb_define_method(cDH, "set_key", ossl_dh_set_key, 2); | |
+ | |
rb_define_method(cDH, "params", ossl_dh_get_params, 0); | |
} | |
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c | |
index 2f0b43e26c..85085419c6 100644 | |
--- a/ext/openssl/ossl_pkey_dsa.c | |
+++ b/ext/openssl/ossl_pkey_dsa.c | |
@@ -7,19 +7,35 @@ | |
* This program is licensed under the same licence as Ruby. | |
* (See the file 'LICENCE'.) | |
*/ | |
-#if !defined(OPENSSL_NO_DSA) | |
- | |
#include "ossl.h" | |
+#if !defined(OPENSSL_NO_DSA) | |
+ | |
#define GetPKeyDSA(obj, pkey) do { \ | |
GetPKey((obj), (pkey)); \ | |
- if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \ | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { /* PARANOIA? */ \ | |
ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \ | |
} \ | |
} while (0) | |
+#define GetDSA(obj, dsa) do { \ | |
+ EVP_PKEY *_pkey; \ | |
+ GetPKeyDSA((obj), _pkey); \ | |
+ (dsa) = EVP_PKEY_get0_DSA(_pkey); \ | |
+} while (0) | |
+ | |
+static inline int | |
+DSA_HAS_PRIVATE(DSA *dsa) | |
+{ | |
+ const BIGNUM *bn; | |
+ DSA_get0_key(dsa, NULL, &bn); | |
+ return !!bn; | |
+} | |
-#define DSA_HAS_PRIVATE(dsa) ((dsa)->priv_key) | |
-#define DSA_PRIVATE(obj,dsa) (DSA_HAS_PRIVATE(dsa)||OSSL_PKEY_IS_PRIVATE(obj)) | |
+static inline int | |
+DSA_PRIVATE(VALUE obj, DSA *dsa) | |
+{ | |
+ return DSA_HAS_PRIVATE(dsa) || OSSL_PKEY_IS_PRIVATE(obj); | |
+} | |
/* | |
* Classes | |
@@ -61,7 +77,7 @@ ossl_dsa_new(EVP_PKEY *pkey) | |
obj = dsa_instance(cDSA, DSA_new()); | |
} else { | |
obj = NewPKey(cDSA); | |
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { | |
ossl_raise(rb_eTypeError, "Not a DSA key!"); | |
} | |
SetPKey(obj, pkey); | |
@@ -76,12 +92,9 @@ ossl_dsa_new(EVP_PKEY *pkey) | |
/* | |
* Private | |
*/ | |
-#if defined(HAVE_DSA_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB | |
struct dsa_blocking_gen_arg { | |
DSA *dsa; | |
int size; | |
- unsigned char* seed; | |
- int seed_len; | |
int *counter; | |
unsigned long *h; | |
BN_GENCB *cb; | |
@@ -92,40 +105,35 @@ static void * | |
dsa_blocking_gen(void *arg) | |
{ | |
struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg; | |
- gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, gen->seed, gen->seed_len, gen->counter, gen->h, gen->cb); | |
+ gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, NULL, 0, | |
+ gen->counter, gen->h, gen->cb); | |
return 0; | |
} | |
-#endif | |
static DSA * | |
dsa_generate(int size) | |
{ | |
-#if defined(HAVE_DSA_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB | |
- BN_GENCB cb; | |
- struct ossl_generate_cb_arg cb_arg; | |
+ struct ossl_generate_cb_arg cb_arg = { 0 }; | |
struct dsa_blocking_gen_arg gen_arg; | |
DSA *dsa = DSA_new(); | |
- unsigned char seed[20]; | |
- int seed_len = 20, counter; | |
+ BN_GENCB *cb = BN_GENCB_new(); | |
+ int counter; | |
unsigned long h; | |
- if (!dsa) return 0; | |
- if (RAND_bytes(seed, seed_len) <= 0) { | |
+ if (!dsa || !cb) { | |
DSA_free(dsa); | |
- return 0; | |
+ BN_GENCB_free(cb); | |
+ return NULL; | |
} | |
- memset(&cb_arg, 0, sizeof(struct ossl_generate_cb_arg)); | |
if (rb_block_given_p()) | |
cb_arg.yield = 1; | |
- BN_GENCB_set(&cb, ossl_generate_cb_2, &cb_arg); | |
+ BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); | |
gen_arg.dsa = dsa; | |
gen_arg.size = size; | |
- gen_arg.seed = seed; | |
- gen_arg.seed_len = seed_len; | |
gen_arg.counter = &counter; | |
gen_arg.h = &h; | |
- gen_arg.cb = &cb; | |
+ gen_arg.cb = cb; | |
if (cb_arg.yield == 1) { | |
/* we cannot release GVL when callback proc is supplied */ | |
dsa_blocking_gen(&gen_arg); | |
@@ -133,28 +141,24 @@ dsa_generate(int size) | |
/* there's a chance to unblock */ | |
rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); | |
} | |
+ | |
+ BN_GENCB_free(cb); | |
if (!gen_arg.result) { | |
DSA_free(dsa); | |
- if (cb_arg.state) rb_jump_tag(cb_arg.state); | |
- return 0; | |
- } | |
-#else | |
- DSA *dsa; | |
- unsigned char seed[20]; | |
- int seed_len = 20, counter; | |
- unsigned long h; | |
- | |
- if (RAND_bytes(seed, seed_len) <= 0) { | |
- return 0; | |
+ if (cb_arg.state) { | |
+ /* Clear OpenSSL error queue before re-raising. By the way, the | |
+ * documentation of DSA_generate_parameters_ex() says the error code | |
+ * can be obtained by ERR_get_error(), but the default | |
+ * implementation, dsa_builtin_paramgen() doesn't put any error... */ | |
+ ossl_clear_error(); | |
+ rb_jump_tag(cb_arg.state); | |
+ } | |
+ return NULL; | |
} | |
- dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h, | |
- rb_block_given_p() ? ossl_generate_cb : NULL, NULL); | |
- if(!dsa) return 0; | |
-#endif | |
if (!DSA_generate_key(dsa)) { | |
DSA_free(dsa); | |
- return 0; | |
+ return NULL; | |
} | |
return dsa; | |
@@ -187,7 +191,9 @@ ossl_dsa_s_generate(VALUE klass, VALUE size) | |
/* | |
* call-seq: | |
- * DSA.new([size | string [, pass]) -> dsa | |
+ * DSA.new -> dsa | |
+ * DSA.new(size) -> dsa | |
+ * DSA.new(string [, pass]) -> dsa | |
* | |
* Creates a new DSA instance by reading an existing key from +string+. | |
* | |
@@ -209,23 +215,22 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) | |
EVP_PKEY *pkey; | |
DSA *dsa; | |
BIO *in; | |
- char *passwd = NULL; | |
VALUE arg, pass; | |
GetPKey(self, pkey); | |
if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { | |
dsa = DSA_new(); | |
} | |
- else if (FIXNUM_P(arg)) { | |
- if (!(dsa = dsa_generate(FIX2INT(arg)))) { | |
+ else if (RB_INTEGER_TYPE_P(arg)) { | |
+ if (!(dsa = dsa_generate(NUM2INT(arg)))) { | |
ossl_raise(eDSAError, NULL); | |
} | |
} | |
else { | |
- if (!NIL_P(pass)) passwd = StringValuePtr(pass); | |
+ pass = ossl_pem_passwd_value(pass); | |
arg = ossl_to_der_if_possible(arg); | |
- in = ossl_obj2bio(&arg); | |
- dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); | |
+ in = ossl_obj2bio(arg); | |
+ dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); | |
if (!dsa) { | |
OSSL_BIO_reset(in); | |
dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); | |
@@ -240,11 +245,14 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) | |
} | |
if (!dsa) { | |
OSSL_BIO_reset(in); | |
+#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ | |
+ (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u)) | |
dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); | |
+#undef PEM_read_bio_DSAPublicKey | |
} | |
BIO_free(in); | |
if (!dsa) { | |
- ERR_clear_error(); | |
+ ossl_clear_error(); | |
ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); | |
} | |
} | |
@@ -256,6 +264,26 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+ossl_dsa_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ EVP_PKEY *pkey; | |
+ DSA *dsa, *dsa_new; | |
+ | |
+ GetPKey(self, pkey); | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) | |
+ ossl_raise(eDSAError, "DSA already initialized"); | |
+ GetDSA(other, dsa); | |
+ | |
+ dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa); | |
+ if (!dsa_new) | |
+ ossl_raise(eDSAError, "ASN1_dup"); | |
+ | |
+ EVP_PKEY_assign_DSA(pkey, dsa_new); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* dsa.public? -> true | false | |
@@ -266,11 +294,13 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_dsa_is_public(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DSA *dsa; | |
+ const BIGNUM *bn; | |
- GetPKeyDSA(self, pkey); | |
+ GetDSA(self, dsa); | |
+ DSA_get0_key(dsa, &bn, NULL); | |
- return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse; | |
+ return bn ? Qtrue : Qfalse; | |
} | |
/* | |
@@ -283,11 +313,11 @@ ossl_dsa_is_public(VALUE self) | |
static VALUE | |
ossl_dsa_is_private(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DSA *dsa; | |
- GetPKeyDSA(self, pkey); | |
+ GetDSA(self, dsa); | |
- return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse; | |
+ return DSA_PRIVATE(self, dsa) ? Qtrue : Qfalse; | |
} | |
/* | |
@@ -310,34 +340,28 @@ ossl_dsa_is_private(VALUE self) | |
static VALUE | |
ossl_dsa_export(int argc, VALUE *argv, VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DSA *dsa; | |
BIO *out; | |
const EVP_CIPHER *ciph = NULL; | |
- char *passwd = NULL; | |
VALUE cipher, pass, str; | |
- GetPKeyDSA(self, pkey); | |
+ GetDSA(self, dsa); | |
rb_scan_args(argc, argv, "02", &cipher, &pass); | |
if (!NIL_P(cipher)) { | |
ciph = GetCipherPtr(cipher); | |
- if (!NIL_P(pass)) { | |
- StringValue(pass); | |
- if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN) | |
- ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long"); | |
- passwd = RSTRING_PTR(pass); | |
- } | |
+ pass = ossl_pem_passwd_value(pass); | |
} | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eDSAError, NULL); | |
} | |
- if (DSA_HAS_PRIVATE(pkey->pkey.dsa)) { | |
- if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph, | |
- NULL, 0, ossl_pem_passwd_cb, passwd)){ | |
+ if (DSA_HAS_PRIVATE(dsa)) { | |
+ if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0, | |
+ ossl_pem_passwd_cb, (void *)pass)){ | |
BIO_free(out); | |
ossl_raise(eDSAError, NULL); | |
} | |
} else { | |
- if (!PEM_write_bio_DSA_PUBKEY(out, pkey->pkey.dsa)) { | |
+ if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) { | |
BIO_free(out); | |
ossl_raise(eDSAError, NULL); | |
} | |
@@ -357,28 +381,29 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_dsa_to_der(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
- int (*i2d_func)_((DSA*, unsigned char**)); | |
+ DSA *dsa; | |
+ int (*i2d_func)(DSA *, unsigned char **); | |
unsigned char *p; | |
long len; | |
VALUE str; | |
- GetPKeyDSA(self, pkey); | |
- if(DSA_HAS_PRIVATE(pkey->pkey.dsa)) | |
- i2d_func = (int(*)_((DSA*,unsigned char**)))i2d_DSAPrivateKey; | |
+ GetDSA(self, dsa); | |
+ if(DSA_HAS_PRIVATE(dsa)) | |
+ i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey; | |
else | |
i2d_func = i2d_DSA_PUBKEY; | |
- if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0) | |
+ if((len = i2d_func(dsa, NULL)) <= 0) | |
ossl_raise(eDSAError, NULL); | |
str = rb_str_new(0, len); | |
p = (unsigned char *)RSTRING_PTR(str); | |
- if(i2d_func(pkey->pkey.dsa, &p) < 0) | |
+ if(i2d_func(dsa, &p) < 0) | |
ossl_raise(eDSAError, NULL); | |
ossl_str_adjust(str, p); | |
return str; | |
} | |
+ | |
/* | |
* call-seq: | |
* dsa.params -> hash | |
@@ -390,18 +415,20 @@ ossl_dsa_to_der(VALUE self) | |
static VALUE | |
ossl_dsa_get_params(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DSA *dsa; | |
VALUE hash; | |
+ const BIGNUM *p, *q, *g, *pub_key, *priv_key; | |
- GetPKeyDSA(self, pkey); | |
+ GetDSA(self, dsa); | |
+ DSA_get0_pqg(dsa, &p, &q, &g); | |
+ DSA_get0_key(dsa, &pub_key, &priv_key); | |
hash = rb_hash_new(); | |
- | |
- rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dsa->p)); | |
- rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.dsa->q)); | |
- rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g)); | |
- rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key)); | |
- rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key)); | |
+ rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p)); | |
+ rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q)); | |
+ rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g)); | |
+ rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key)); | |
+ rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key)); | |
return hash; | |
} | |
@@ -417,15 +444,15 @@ ossl_dsa_get_params(VALUE self) | |
static VALUE | |
ossl_dsa_to_text(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ DSA *dsa; | |
BIO *out; | |
VALUE str; | |
- GetPKeyDSA(self, pkey); | |
+ GetDSA(self, dsa); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eDSAError, NULL); | |
} | |
- if (!DSA_print(out, pkey->pkey.dsa, 0)) { /* offset = 0 */ | |
+ if (!DSA_print(out, dsa, 0)) { /* offset = 0 */ | |
BIO_free(out); | |
ossl_raise(eDSAError, NULL); | |
} | |
@@ -460,8 +487,11 @@ ossl_dsa_to_public_key(VALUE self) | |
GetPKeyDSA(self, pkey); | |
/* err check performed by dsa_instance */ | |
- dsa = DSAPublicKey_dup(pkey->pkey.dsa); | |
- obj = dsa_instance(CLASS_OF(self), dsa); | |
+#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \ | |
+ (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa)) | |
+ dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey)); | |
+#undef DSAPublicKey_dup | |
+ obj = dsa_instance(rb_obj_class(self), dsa); | |
if (obj == Qfalse) { | |
DSA_free(dsa); | |
ossl_raise(eDSAError, NULL); | |
@@ -469,8 +499,6 @@ ossl_dsa_to_public_key(VALUE self) | |
return obj; | |
} | |
-#define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16) | |
- | |
/* | |
* call-seq: | |
* dsa.syssign(string) -> aString | |
@@ -493,20 +521,22 @@ ossl_dsa_to_public_key(VALUE self) | |
static VALUE | |
ossl_dsa_sign(VALUE self, VALUE data) | |
{ | |
- EVP_PKEY *pkey; | |
+ DSA *dsa; | |
+ const BIGNUM *dsa_q; | |
unsigned int buf_len; | |
VALUE str; | |
- GetPKeyDSA(self, pkey); | |
- if (!pkey->pkey.dsa->q) | |
+ GetDSA(self, dsa); | |
+ DSA_get0_pqg(dsa, NULL, &dsa_q, NULL); | |
+ if (!dsa_q) | |
ossl_raise(eDSAError, "incomplete DSA"); | |
- if (!DSA_PRIVATE(self, pkey->pkey.dsa)) | |
+ if (!DSA_PRIVATE(self, dsa)) | |
ossl_raise(eDSAError, "Private DSA key needed!"); | |
StringValue(data); | |
- str = rb_str_new(0, ossl_dsa_buf_size(pkey)); | |
+ str = rb_str_new(0, DSA_size(dsa)); | |
if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), | |
(unsigned char *)RSTRING_PTR(str), | |
- &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */ | |
+ &buf_len, dsa)) { /* type is ignored (0) */ | |
ossl_raise(eDSAError, NULL); | |
} | |
rb_str_set_len(str, buf_len); | |
@@ -536,15 +566,15 @@ ossl_dsa_sign(VALUE self, VALUE data) | |
static VALUE | |
ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) | |
{ | |
- EVP_PKEY *pkey; | |
+ DSA *dsa; | |
int ret; | |
- GetPKeyDSA(self, pkey); | |
+ GetDSA(self, dsa); | |
StringValue(digest); | |
StringValue(sig); | |
/* type is ignored (0) */ | |
ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest), | |
- (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey->pkey.dsa); | |
+ (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), dsa); | |
if (ret < 0) { | |
ossl_raise(eDSAError, NULL); | |
} | |
@@ -555,11 +585,22 @@ ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) | |
return Qfalse; | |
} | |
-OSSL_PKEY_BN(dsa, p) | |
-OSSL_PKEY_BN(dsa, q) | |
-OSSL_PKEY_BN(dsa, g) | |
-OSSL_PKEY_BN(dsa, pub_key) | |
-OSSL_PKEY_BN(dsa, priv_key) | |
+/* | |
+ * Document-method: OpenSSL::PKey::DSA#set_pqg | |
+ * call-seq: | |
+ * dsa.set_pqg(p, q, g) -> self | |
+ * | |
+ * Sets +p+, +q+, +g+ for the DSA instance. | |
+ */ | |
+OSSL_PKEY_BN_DEF3(dsa, DSA, pqg, p, q, g) | |
+/* | |
+ * Document-method: OpenSSL::PKey::DSA#set_key | |
+ * call-seq: | |
+ * dsa.set_key(pub_key, priv_key) -> self | |
+ * | |
+ * Sets +pub_key+ and +priv_key+ for the DSA instance. +priv_key+ may be nil. | |
+ */ | |
+OSSL_PKEY_BN_DEF2(dsa, DSA, key, pub_key, priv_key) | |
/* | |
* INIT | |
@@ -568,8 +609,9 @@ void | |
Init_ossl_dsa(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */ | |
mPKey = rb_define_module_under(mOSSL, "PKey"); | |
+ cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); | |
+ ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); | |
#endif | |
/* Document-class: OpenSSL::PKey::DSAError | |
@@ -596,6 +638,7 @@ Init_ossl_dsa(void) | |
rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); | |
rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); | |
+ rb_define_copy_func(cDSA, ossl_dsa_initialize_copy); | |
rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); | |
rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); | |
@@ -613,6 +656,8 @@ Init_ossl_dsa(void) | |
DEF_OSSL_PKEY_BN(cDSA, dsa, g); | |
DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key); | |
DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key); | |
+ rb_define_method(cDSA, "set_pqg", ossl_dsa_set_pqg, 3); | |
+ rb_define_method(cDSA, "set_key", ossl_dsa_set_key, 2); | |
rb_define_method(cDSA, "params", ossl_dsa_get_params, 0); | |
} | |
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c | |
index a41c48d9c3..fc3f034a39 100644 | |
--- a/ext/openssl/ossl_pkey_ec.c | |
+++ b/ext/openssl/ossl_pkey_ec.c | |
@@ -6,17 +6,6 @@ | |
#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) | |
-typedef struct { | |
- EC_GROUP *group; | |
- int dont_free; | |
-} ossl_ec_group; | |
- | |
-typedef struct { | |
- EC_POINT *point; | |
- int dont_free; | |
-} ossl_ec_point; | |
- | |
- | |
#define EXPORT_PEM 0 | |
#define EXPORT_DER 1 | |
@@ -25,70 +14,43 @@ static const rb_data_type_t ossl_ec_point_type; | |
#define GetPKeyEC(obj, pkey) do { \ | |
GetPKey((obj), (pkey)); \ | |
- if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_EC) { \ | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { \ | |
ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \ | |
} \ | |
} while (0) | |
- | |
-#define SafeGet_ec_group(obj, group) do { \ | |
- OSSL_Check_Kind((obj), cEC_GROUP); \ | |
- TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, (group)); \ | |
-} while(0) | |
- | |
-#define Get_EC_KEY(obj, key) do { \ | |
- EVP_PKEY *pkey; \ | |
- GetPKeyEC((obj), pkey); \ | |
- (key) = pkey->pkey.ec; \ | |
-} while(0) | |
- | |
-#define Require_EC_KEY(obj, key) do { \ | |
- Get_EC_KEY((obj), (key)); \ | |
- if ((key) == NULL) \ | |
- ossl_raise(eECError, "EC_KEY is not initialized"); \ | |
-} while(0) | |
- | |
-#define SafeRequire_EC_KEY(obj, key) do { \ | |
- OSSL_Check_Kind((obj), cEC); \ | |
- Require_EC_KEY((obj), (key)); \ | |
+#define GetEC(obj, key) do { \ | |
+ EVP_PKEY *_pkey; \ | |
+ GetPKeyEC(obj, _pkey); \ | |
+ (key) = EVP_PKEY_get0_EC_KEY(_pkey); \ | |
+} while (0) | |
+#define SafeGetEC(obj, key) do { \ | |
+ OSSL_Check_Kind(obj, cEC); \ | |
+ GetEC(obj, key); \ | |
} while (0) | |
-#define Get_EC_GROUP(obj, g) do { \ | |
- ossl_ec_group *ec_group; \ | |
- TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, ec_group); \ | |
- if (ec_group == NULL) \ | |
- ossl_raise(eEC_GROUP, "missing ossl_ec_group structure"); \ | |
- (g) = ec_group->group; \ | |
-} while(0) | |
- | |
-#define Require_EC_GROUP(obj, group) do { \ | |
- Get_EC_GROUP((obj), (group)); \ | |
+#define GetECGroup(obj, group) do { \ | |
+ TypedData_Get_Struct(obj, EC_GROUP, &ossl_ec_group_type, group); \ | |
if ((group) == NULL) \ | |
- ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \ | |
-} while(0) | |
- | |
-#define SafeRequire_EC_GROUP(obj, group) do { \ | |
+ ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \ | |
+} while (0) | |
+#define SafeGetECGroup(obj, group) do { \ | |
OSSL_Check_Kind((obj), cEC_GROUP); \ | |
- Require_EC_GROUP((obj), (group)); \ | |
-} while(0) | |
- | |
-#define Get_EC_POINT(obj, p) do { \ | |
- ossl_ec_point *ec_point; \ | |
- TypedData_Get_Struct((obj), ossl_ec_point, &ossl_ec_point_type, ec_point); \ | |
- if (ec_point == NULL) \ | |
- ossl_raise(eEC_POINT, "missing ossl_ec_point structure"); \ | |
- (p) = ec_point->point; \ | |
-} while(0) | |
+ GetECGroup(obj, group); \ | |
+} while (0) | |
-#define Require_EC_POINT(obj, point) do { \ | |
- Get_EC_POINT((obj), (point)); \ | |
+#define GetECPoint(obj, point) do { \ | |
+ TypedData_Get_Struct(obj, EC_POINT, &ossl_ec_point_type, point); \ | |
if ((point) == NULL) \ | |
- ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \ | |
-} while(0) | |
- | |
-#define SafeRequire_EC_POINT(obj, point) do { \ | |
+ ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \ | |
+} while (0) | |
+#define SafeGetECPoint(obj, point) do { \ | |
OSSL_Check_Kind((obj), cEC_POINT); \ | |
- Require_EC_POINT((obj), (point)); \ | |
+ GetECPoint(obj, point); \ | |
} while(0) | |
+#define GetECPointGroup(obj, group) do { \ | |
+ VALUE _group = rb_attr_get(obj, id_i_group); \ | |
+ SafeGetECGroup(_group, group); \ | |
+} while (0) | |
VALUE cEC; | |
VALUE eECError; | |
@@ -108,6 +70,11 @@ static ID ID_uncompressed; | |
static ID ID_compressed; | |
static ID ID_hybrid; | |
+static ID id_i_group; | |
+ | |
+static VALUE ec_group_new(const EC_GROUP *group); | |
+static VALUE ec_point_new(const EC_POINT *point, const EC_GROUP *group); | |
+ | |
static VALUE ec_instance(VALUE klass, EC_KEY *ec) | |
{ | |
EVP_PKEY *pkey; | |
@@ -137,7 +104,7 @@ VALUE ossl_ec_new(EVP_PKEY *pkey) | |
obj = ec_instance(cEC, EC_KEY_new()); | |
} else { | |
obj = NewPKey(cEC); | |
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { | |
ossl_raise(rb_eTypeError, "Not a EC key!"); | |
} | |
SetPKey(obj, pkey); | |
@@ -149,168 +116,196 @@ VALUE ossl_ec_new(EVP_PKEY *pkey) | |
return obj; | |
} | |
+/* | |
+ * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String | |
+ * representing an OID. | |
+ */ | |
+static EC_KEY * | |
+ec_key_new_from_group(VALUE arg) | |
+{ | |
+ EC_KEY *ec; | |
+ | |
+ if (rb_obj_is_kind_of(arg, cEC_GROUP)) { | |
+ EC_GROUP *group; | |
+ | |
+ SafeGetECGroup(arg, group); | |
+ if (!(ec = EC_KEY_new())) | |
+ ossl_raise(eECError, NULL); | |
+ | |
+ if (!EC_KEY_set_group(ec, group)) { | |
+ EC_KEY_free(ec); | |
+ ossl_raise(eECError, NULL); | |
+ } | |
+ } else { | |
+ int nid = OBJ_sn2nid(StringValueCStr(arg)); | |
+ | |
+ if (nid == NID_undef) | |
+ ossl_raise(eECError, "invalid curve name"); | |
-/* call-seq: | |
- * OpenSSL::PKey::EC.new() | |
- * OpenSSL::PKey::EC.new(ec_key) | |
- * OpenSSL::PKey::EC.new(ec_group) | |
- * OpenSSL::PKey::EC.new("secp112r1") | |
- * OpenSSL::PKey::EC.new(pem_string) | |
- * OpenSSL::PKey::EC.new(pem_string [, pwd]) | |
- * OpenSSL::PKey::EC.new(der_string) | |
+ if (!(ec = EC_KEY_new_by_curve_name(nid))) | |
+ ossl_raise(eECError, NULL); | |
+ | |
+ EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); | |
+ EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); | |
+ } | |
+ | |
+ return ec; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * EC.generate(ec_group) -> ec | |
+ * EC.generate(string) -> ec | |
* | |
- * See the OpenSSL documentation for: | |
- * EC_KEY_* | |
+ * Creates a new EC instance with a new random private and public key. | |
+ */ | |
+static VALUE | |
+ossl_ec_key_s_generate(VALUE klass, VALUE arg) | |
+{ | |
+ EC_KEY *ec; | |
+ VALUE obj; | |
+ | |
+ ec = ec_key_new_from_group(arg); | |
+ | |
+ obj = ec_instance(klass, ec); | |
+ if (obj == Qfalse) { | |
+ EC_KEY_free(ec); | |
+ ossl_raise(eECError, NULL); | |
+ } | |
+ | |
+ if (!EC_KEY_generate_key(ec)) | |
+ ossl_raise(eECError, "EC_KEY_generate_key"); | |
+ | |
+ return obj; | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * OpenSSL::PKey::EC.new | |
+ * OpenSSL::PKey::EC.new(ec_key) | |
+ * OpenSSL::PKey::EC.new(ec_group) | |
+ * OpenSSL::PKey::EC.new("secp112r1") | |
+ * OpenSSL::PKey::EC.new(pem_string [, pwd]) | |
+ * OpenSSL::PKey::EC.new(der_string) | |
+ * | |
+ * Creates a new EC object from given arguments. | |
*/ | |
static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
EVP_PKEY *pkey; | |
- EC_KEY *ec = NULL; | |
+ EC_KEY *ec; | |
VALUE arg, pass; | |
- VALUE group = Qnil; | |
- char *passwd = NULL; | |
GetPKey(self, pkey); | |
- if (pkey->pkey.ec) | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) | |
ossl_raise(eECError, "EC_KEY already initialized"); | |
rb_scan_args(argc, argv, "02", &arg, &pass); | |
if (NIL_P(arg)) { | |
- ec = EC_KEY_new(); | |
+ if (!(ec = EC_KEY_new())) | |
+ ossl_raise(eECError, NULL); | |
+ } else if (rb_obj_is_kind_of(arg, cEC)) { | |
+ EC_KEY *other_ec = NULL; | |
+ | |
+ SafeGetEC(arg, other_ec); | |
+ if (!(ec = EC_KEY_dup(other_ec))) | |
+ ossl_raise(eECError, NULL); | |
+ } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { | |
+ ec = ec_key_new_from_group(arg); | |
} else { | |
- if (rb_obj_is_kind_of(arg, cEC)) { | |
- EC_KEY *other_ec = NULL; | |
- | |
- SafeRequire_EC_KEY(arg, other_ec); | |
- ec = EC_KEY_dup(other_ec); | |
- } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { | |
- ec = EC_KEY_new(); | |
- group = arg; | |
- } else { | |
- BIO *in = ossl_obj2bio(&arg); | |
- | |
- if (!NIL_P(pass)) { | |
- passwd = StringValuePtr(pass); | |
- } | |
- ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); | |
- if (!ec) { | |
- OSSL_BIO_reset(in); | |
- ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, passwd); | |
- } | |
- if (!ec) { | |
- OSSL_BIO_reset(in); | |
- ec = d2i_ECPrivateKey_bio(in, NULL); | |
- } | |
- if (!ec) { | |
- OSSL_BIO_reset(in); | |
- ec = d2i_EC_PUBKEY_bio(in, NULL); | |
- } | |
- | |
- BIO_free(in); | |
- | |
- if (ec == NULL) { | |
- const char *name = StringValueCStr(arg); | |
- int nid = OBJ_sn2nid(name); | |
+ BIO *in; | |
- (void)ERR_get_error(); | |
- if (nid == NID_undef) | |
- ossl_raise(eECError, "unknown curve name (%s)\n", name); | |
+ pass = ossl_pem_passwd_value(pass); | |
+ in = ossl_obj2bio(arg); | |
- if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL) | |
- ossl_raise(eECError, "unable to create curve (%s)\n", name); | |
+ ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); | |
+ if (!ec) { | |
+ OSSL_BIO_reset(in); | |
+ ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass); | |
+ } | |
+ if (!ec) { | |
+ OSSL_BIO_reset(in); | |
+ ec = d2i_ECPrivateKey_bio(in, NULL); | |
+ } | |
+ if (!ec) { | |
+ OSSL_BIO_reset(in); | |
+ ec = d2i_EC_PUBKEY_bio(in, NULL); | |
+ } | |
+ BIO_free(in); | |
- EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); | |
- EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); | |
- } | |
- } | |
+ if (!ec) { | |
+ ossl_clear_error(); | |
+ ec = ec_key_new_from_group(arg); | |
+ } | |
} | |
- if (ec == NULL) | |
- ossl_raise(eECError, NULL); | |
- | |
if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { | |
EC_KEY_free(ec); | |
ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); | |
} | |
- rb_iv_set(self, "@group", Qnil); | |
+ return self; | |
+} | |
- if (!NIL_P(group)) | |
- rb_funcall(self, rb_intern("group="), 1, arg); | |
+static VALUE | |
+ossl_ec_key_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ EVP_PKEY *pkey; | |
+ EC_KEY *ec, *ec_new; | |
+ | |
+ GetPKey(self, pkey); | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) | |
+ ossl_raise(eECError, "EC already initialized"); | |
+ SafeGetEC(other, ec); | |
+ | |
+ ec_new = EC_KEY_dup(ec); | |
+ if (!ec_new) | |
+ ossl_raise(eECError, "EC_KEY_dup"); | |
+ if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) { | |
+ EC_KEY_free(ec_new); | |
+ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); | |
+ } | |
return self; | |
} | |
/* | |
- * call-seq: | |
- * key.group => group | |
+ * call-seq: | |
+ * key.group => group | |
* | |
- * Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key. | |
- * Modifying the returned group can make the key invalid. | |
+ * Returns the EC::Group that the key is associated with. Modifying the returned | |
+ * group does not affect +key+. | |
*/ | |
-static VALUE ossl_ec_key_get_group(VALUE self) | |
+static VALUE | |
+ossl_ec_key_get_group(VALUE self) | |
{ | |
- VALUE group_v; | |
EC_KEY *ec; | |
- ossl_ec_group *ec_group; | |
- EC_GROUP *group; | |
- | |
- Require_EC_KEY(self, ec); | |
- | |
- group_v = rb_iv_get(self, "@group"); | |
- if (!NIL_P(group_v)) | |
- return group_v; | |
+ const EC_GROUP *group; | |
- if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) { | |
- group_v = rb_obj_alloc(cEC_GROUP); | |
- SafeGet_ec_group(group_v, ec_group); | |
- ec_group->group = group; | |
- ec_group->dont_free = 1; | |
- rb_iv_set(group_v, "@key", self); | |
- rb_iv_set(self, "@group", group_v); | |
- return group_v; | |
- } | |
+ GetEC(self, ec); | |
+ group = EC_KEY_get0_group(ec); | |
+ if (!group) | |
+ return Qnil; | |
- return Qnil; | |
+ return ec_group_new(group); | |
} | |
/* | |
- * call-seq: | |
- * key.group = group => group | |
- * | |
- * Returns the same object passed, not the group object associated with the key. | |
- * If you wish to access the group object tied to the key call key.group after setting | |
- * the group. | |
+ * call-seq: | |
+ * key.group = group | |
* | |
- * Setting the group will immediately destroy any previously assigned group object. | |
- * The group is internally copied by OpenSSL. Modifying the original group after | |
- * assignment will not effect the internal key structure. | |
- * (your changes may be lost). BE CAREFUL. | |
- * | |
- * EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy. | |
- * This documentation is accurate for OpenSSL 0.9.8b. | |
+ * Sets the EC::Group for the key. The group structure is internally copied so | |
+ * modifition to +group+ after assigning to a key has no effect on the key. | |
*/ | |
-static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v) | |
+static VALUE | |
+ossl_ec_key_set_group(VALUE self, VALUE group_v) | |
{ | |
- VALUE old_group_v; | |
EC_KEY *ec; | |
EC_GROUP *group; | |
- Require_EC_KEY(self, ec); | |
- SafeRequire_EC_GROUP(group_v, group); | |
- | |
- old_group_v = rb_iv_get(self, "@group"); | |
- if (!NIL_P(old_group_v)) { | |
- ossl_ec_group *old_ec_group; | |
- SafeGet_ec_group(old_group_v, old_ec_group); | |
- | |
- old_ec_group->group = NULL; | |
- old_ec_group->dont_free = 0; | |
- rb_iv_set(old_group_v, "@key", Qnil); | |
- } | |
- | |
- rb_iv_set(self, "@group", Qnil); | |
+ GetEC(self, ec); | |
+ SafeGetECGroup(group_v, group); | |
if (EC_KEY_set_group(ec, group) != 1) | |
ossl_raise(eECError, "EC_KEY_set_group"); | |
@@ -329,8 +324,7 @@ static VALUE ossl_ec_key_get_private_key(VALUE self) | |
EC_KEY *ec; | |
const BIGNUM *bn; | |
- Require_EC_KEY(self, ec); | |
- | |
+ GetEC(self, ec); | |
if ((bn = EC_KEY_get0_private_key(ec)) == NULL) | |
return Qnil; | |
@@ -348,7 +342,7 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) | |
EC_KEY *ec; | |
BIGNUM *bn = NULL; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
if (!NIL_P(private_key)) | |
bn = GetBNPtr(private_key); | |
@@ -365,26 +359,6 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) | |
return private_key; | |
} | |
- | |
-static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v) | |
-{ | |
- VALUE obj; | |
- const EC_GROUP *group; | |
- ossl_ec_point *new_point; | |
- | |
- obj = rb_obj_alloc(cEC_POINT); | |
- TypedData_Get_Struct(obj, ossl_ec_point, &ossl_ec_point_type, new_point); | |
- | |
- SafeRequire_EC_GROUP(group_v, group); | |
- | |
- new_point->point = EC_POINT_dup(point, group); | |
- if (new_point->point == NULL) | |
- ossl_raise(eEC_POINT, "EC_POINT_dup"); | |
- rb_iv_set(obj, "@group", group_v); | |
- | |
- return obj; | |
-} | |
- | |
/* | |
* call-seq: | |
* key.public_key => OpenSSL::PKey::EC::Point | |
@@ -395,18 +369,12 @@ static VALUE ossl_ec_key_get_public_key(VALUE self) | |
{ | |
EC_KEY *ec; | |
const EC_POINT *point; | |
- VALUE group; | |
- | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
if ((point = EC_KEY_get0_public_key(ec)) == NULL) | |
return Qnil; | |
- group = rb_funcall(self, rb_intern("group"), 0); | |
- if (NIL_P(group)) | |
- ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???"); | |
- | |
- return ossl_ec_point_dup(point, group); | |
+ return ec_point_new(point, EC_KEY_get0_group(ec)); | |
} | |
/* | |
@@ -420,9 +388,9 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) | |
EC_KEY *ec; | |
EC_POINT *point = NULL; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
if (!NIL_P(public_key)) | |
- SafeRequire_EC_POINT(public_key, point); | |
+ SafeGetECPoint(public_key, point); | |
switch (EC_KEY_set_public_key(ec, point)) { | |
case 1: | |
@@ -439,32 +407,34 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) | |
/* | |
* call-seq: | |
- * key.public_key? => true or false | |
+ * key.public? => true or false | |
* | |
- * Both public_key? and private_key? may return false at the same time unlike other PKey classes. | |
+ * Returns whether this EC instance has a public key. The public key | |
+ * (EC::Point) can be retrieved with EC#public_key. | |
*/ | |
-static VALUE ossl_ec_key_is_public_key(VALUE self) | |
+static VALUE ossl_ec_key_is_public(VALUE self) | |
{ | |
EC_KEY *ec; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
- return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse); | |
+ return EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse; | |
} | |
/* | |
* call-seq: | |
- * key.private_key? => true or false | |
+ * key.private? => true or false | |
* | |
- * Both public_key? and private_key? may return false at the same time unlike other PKey classes. | |
+ * Returns whether this EC instance has a private key. The private key (BN) can | |
+ * be retrieved with EC#private_key. | |
*/ | |
-static VALUE ossl_ec_key_is_private_key(VALUE self) | |
+static VALUE ossl_ec_key_is_private(VALUE self) | |
{ | |
EC_KEY *ec; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
- return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse); | |
+ return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse; | |
} | |
static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format) | |
@@ -473,11 +443,10 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma | |
BIO *out; | |
int i = -1; | |
int private = 0; | |
- char *password = NULL; | |
VALUE str; | |
const EVP_CIPHER *cipher = NULL; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
if (EC_KEY_get0_public_key(ec) == NULL) | |
ossl_raise(eECError, "can't export - no public key set"); | |
@@ -490,12 +459,7 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma | |
if (!NIL_P(ciph)) { | |
cipher = GetCipherPtr(ciph); | |
- if (!NIL_P(pass)) { | |
- StringValue(pass); | |
- if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN) | |
- ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long"); | |
- password = RSTRING_PTR(pass); | |
- } | |
+ pass = ossl_pem_passwd_value(pass); | |
} | |
if (!(out = BIO_new(BIO_s_mem()))) | |
@@ -504,7 +468,7 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma | |
switch(format) { | |
case EXPORT_PEM: | |
if (private) { | |
- i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password); | |
+ i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, ossl_pem_passwd_cb, (void *)pass); | |
} else { | |
i = PEM_write_bio_EC_PUBKEY(out, ec); | |
} | |
@@ -538,12 +502,10 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma | |
* key.export([cipher, pass_phrase]) => String | |
* key.to_pem([cipher, pass_phrase]) => String | |
* | |
- * Outputs the EC key in PEM encoding. If +cipher+ and +pass_phrase+ are | |
- * given they will be used to encrypt the key. +cipher+ must be an | |
- * OpenSSL::Cipher::Cipher instance. Note that encryption will only be | |
- * effective for a private key, public keys will always be encoded in plain | |
- * text. | |
- * | |
+ * Outputs the EC key in PEM encoding. If +cipher+ and +pass_phrase+ are given | |
+ * they will be used to encrypt the key. +cipher+ must be an OpenSSL::Cipher | |
+ * instance. Note that encryption will only be effective for a private key, | |
+ * public keys will always be encoded in plain text. | |
*/ | |
static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self) | |
{ | |
@@ -575,7 +537,7 @@ static VALUE ossl_ec_key_to_text(VALUE self) | |
BIO *out; | |
VALUE str; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eECError, "BIO_new(BIO_s_mem())"); | |
} | |
@@ -590,16 +552,23 @@ static VALUE ossl_ec_key_to_text(VALUE self) | |
/* | |
* call-seq: | |
- * key.generate_key => self | |
+ * key.generate_key! => self | |
+ * | |
+ * Generates a new random private and public key. | |
* | |
- * See the OpenSSL documentation for EC_KEY_generate_key() | |
+ * See also the OpenSSL documentation for EC_KEY_generate_key() | |
+ * | |
+ * === Example | |
+ * ec = OpenSSL::PKey::EC.new("prime256v1") | |
+ * p ec.private_key # => nil | |
+ * ec.generate_key! | |
+ * p ec.private_key # => #<OpenSSL::BN XXXXXX> | |
*/ | |
static VALUE ossl_ec_key_generate_key(VALUE self) | |
{ | |
EC_KEY *ec; | |
- Require_EC_KEY(self, ec); | |
- | |
+ GetEC(self, ec); | |
if (EC_KEY_generate_key(ec) != 1) | |
ossl_raise(eECError, "EC_KEY_generate_key"); | |
@@ -618,8 +587,7 @@ static VALUE ossl_ec_key_check_key(VALUE self) | |
{ | |
EC_KEY *ec; | |
- Require_EC_KEY(self, ec); | |
- | |
+ GetEC(self, ec); | |
if (EC_KEY_check_key(ec) != 1) | |
ossl_raise(eECError, "EC_KEY_check_key"); | |
@@ -639,8 +607,8 @@ static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) | |
int buf_len; | |
VALUE str; | |
- Require_EC_KEY(self, ec); | |
- SafeRequire_EC_POINT(pubkey, point); | |
+ GetEC(self, ec); | |
+ SafeGetECPoint(pubkey, point); | |
/* BUG: need a way to figure out the maximum string size */ | |
buf_len = 1024; | |
@@ -669,17 +637,16 @@ static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) | |
unsigned int buf_len; | |
VALUE str; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
StringValue(data); | |
if (EC_KEY_get0_private_key(ec) == NULL) | |
ossl_raise(eECError, "Private EC key needed!"); | |
- str = rb_str_new(0, ECDSA_size(ec) + 16); | |
+ str = rb_str_new(0, ECDSA_size(ec)); | |
if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) | |
- ossl_raise(eECError, "ECDSA_sign"); | |
- | |
- rb_str_resize(str, buf_len); | |
+ ossl_raise(eECError, "ECDSA_sign"); | |
+ rb_str_set_len(str, buf_len); | |
return str; | |
} | |
@@ -694,7 +661,7 @@ static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) | |
{ | |
EC_KEY *ec; | |
- Require_EC_KEY(self, ec); | |
+ GetEC(self, ec); | |
StringValue(data); | |
StringValue(sig); | |
@@ -709,12 +676,13 @@ static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) | |
UNREACHABLE; | |
} | |
-static void ossl_ec_group_free(void *ptr) | |
+/* | |
+ * OpenSSL::PKey::EC::Group | |
+ */ | |
+static void | |
+ossl_ec_group_free(void *ptr) | |
{ | |
- ossl_ec_group *ec_group = ptr; | |
- if (!ec_group->dont_free && ec_group->group) | |
- EC_GROUP_clear_free(ec_group->group); | |
- ruby_xfree(ec_group); | |
+ EC_GROUP_clear_free(ptr); | |
} | |
static const rb_data_type_t ossl_ec_group_type = { | |
@@ -725,40 +693,55 @@ static const rb_data_type_t ossl_ec_group_type = { | |
0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
}; | |
-static VALUE ossl_ec_group_alloc(VALUE klass) | |
+static VALUE | |
+ossl_ec_group_alloc(VALUE klass) | |
+{ | |
+ return TypedData_Wrap_Struct(klass, &ossl_ec_group_type, NULL); | |
+} | |
+ | |
+static VALUE | |
+ec_group_new(const EC_GROUP *group) | |
{ | |
- ossl_ec_group *ec_group; | |
VALUE obj; | |
+ EC_GROUP *group_new; | |
- obj = TypedData_Make_Struct(klass, ossl_ec_group, &ossl_ec_group_type, ec_group); | |
+ obj = ossl_ec_group_alloc(cEC_GROUP); | |
+ group_new = EC_GROUP_dup(group); | |
+ if (!group_new) | |
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup"); | |
+ RTYPEDDATA_DATA(obj) = group_new; | |
return obj; | |
} | |
-/* call-seq: | |
- * OpenSSL::PKey::EC::Group.new("secp112r1") | |
- * OpenSSL::PKey::EC::Group.new(ec_group) | |
- * OpenSSL::PKey::EC::Group.new(pem_string) | |
- * OpenSSL::PKey::EC::Group.new(der_string) | |
- * OpenSSL::PKey::EC::Group.new(pem_file) | |
- * OpenSSL::PKey::EC::Group.new(der_file) | |
- * OpenSSL::PKey::EC::Group.new(:GFp_simple) | |
- * OpenSSL::PKey::EC::Group.new(:GFp_mult) | |
- * OpenSSL::PKey::EC::Group.new(:GFp_nist) | |
- * OpenSSL::PKey::EC::Group.new(:GF2m_simple) | |
- * OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b) | |
- * OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b) | |
+/* | |
+ * call-seq: | |
+ * OpenSSL::PKey::EC::Group.new(ec_group) | |
+ * OpenSSL::PKey::EC::Group.new(pem_or_der_encoded) | |
+ * OpenSSL::PKey::EC::Group.new(ec_method) | |
+ * OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b) | |
+ * OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b) | |
+ * | |
+ * Creates a new EC::Group object. | |
+ * | |
+ * +ec_method+ is a symbol that represents an EC_METHOD. Currently the following | |
+ * are supported: | |
+ * | |
+ * * :GFp_simple | |
+ * * :GFp_mont | |
+ * * :GFp_nist | |
+ * * :GF2m_simple | |
* | |
- * See the OpenSSL documentation for EC_GROUP_* | |
+ * If the first argument is :GFp or :GF2m, creates a new curve with given | |
+ * parameters. | |
*/ | |
static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
VALUE arg1, arg2, arg3, arg4; | |
- ossl_ec_group *ec_group; | |
- EC_GROUP *group = NULL; | |
+ EC_GROUP *group; | |
- TypedData_Get_Struct(self, ossl_ec_group, &ossl_ec_group_type, ec_group); | |
- if (ec_group->group != NULL) | |
+ TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group); | |
+ if (group) | |
ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized"); | |
switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) { | |
@@ -788,11 +771,11 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) | |
} else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { | |
const EC_GROUP *arg1_group; | |
- SafeRequire_EC_GROUP(arg1, arg1_group); | |
+ SafeGetECGroup(arg1, arg1_group); | |
if ((group = EC_GROUP_dup(arg1_group)) == NULL) | |
ossl_raise(eEC_GROUP, "EC_GROUP_dup"); | |
} else { | |
- BIO *in = ossl_obj2bio(&arg1); | |
+ BIO *in = ossl_obj2bio(arg1); | |
group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); | |
if (!group) { | |
@@ -806,13 +789,13 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) | |
const char *name = StringValueCStr(arg1); | |
int nid = OBJ_sn2nid(name); | |
- (void)ERR_get_error(); | |
+ ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */ | |
if (nid == NID_undef) | |
- ossl_raise(eEC_GROUP, "unknown curve name (%s)", name); | |
+ ossl_raise(eEC_GROUP, "unknown curve name (%"PRIsVALUE")", arg1); | |
group = EC_GROUP_new_by_curve_name(nid); | |
if (group == NULL) | |
- ossl_raise(eEC_GROUP, "unable to create curve (%s)", name); | |
+ ossl_raise(eEC_GROUP, "unable to create curve (%"PRIsVALUE")", arg1); | |
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); | |
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED); | |
@@ -851,23 +834,43 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) | |
if (group == NULL) | |
ossl_raise(eEC_GROUP, ""); | |
+ RTYPEDDATA_DATA(self) = group; | |
+ | |
+ return self; | |
+} | |
+ | |
+static VALUE | |
+ossl_ec_group_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ EC_GROUP *group, *group_new; | |
+ | |
+ TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group_new); | |
+ if (group_new) | |
+ ossl_raise(eEC_GROUP, "EC::Group already initialized"); | |
+ SafeGetECGroup(other, group); | |
- ec_group->group = group; | |
+ group_new = EC_GROUP_dup(group); | |
+ if (!group_new) | |
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup"); | |
+ RTYPEDDATA_DATA(self) = group_new; | |
return self; | |
} | |
-/* call-seq: | |
- * group1.eql?(group2) => true | false | |
- * group1 == group2 => true | false | |
+/* | |
+ * call-seq: | |
+ * group1.eql?(group2) => true | false | |
+ * group1 == group2 => true | false | |
* | |
+ * Returns true if the two groups use the same curve and have the same | |
+ * parameters, false otherwise. | |
*/ | |
static VALUE ossl_ec_group_eql(VALUE a, VALUE b) | |
{ | |
EC_GROUP *group1 = NULL, *group2 = NULL; | |
- Require_EC_GROUP(a, group1); | |
- SafeRequire_EC_GROUP(b, group2); | |
+ GetECGroup(a, group1); | |
+ SafeGetECGroup(b, group2); | |
if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1) | |
return Qfalse; | |
@@ -875,27 +878,35 @@ static VALUE ossl_ec_group_eql(VALUE a, VALUE b) | |
return Qtrue; | |
} | |
-/* call-seq: | |
- * group.generator => ec_point | |
+/* | |
+ * call-seq: | |
+ * group.generator => ec_point | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get0_generator() | |
+ * Returns the generator of the group. | |
+ * | |
+ * See the OpenSSL documentation for EC_GROUP_get0_generator() | |
*/ | |
static VALUE ossl_ec_group_get_generator(VALUE self) | |
{ | |
- VALUE point_obj; | |
- EC_GROUP *group = NULL; | |
- | |
- Require_EC_GROUP(self, group); | |
+ EC_GROUP *group; | |
+ const EC_POINT *generator; | |
- point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self); | |
+ GetECGroup(self, group); | |
+ generator = EC_GROUP_get0_generator(group); | |
+ if (!generator) | |
+ return Qnil; | |
- return point_obj; | |
+ return ec_point_new(generator, group); | |
} | |
-/* call-seq: | |
- * group.set_generator(generator, order, cofactor) => self | |
+/* | |
+ * call-seq: | |
+ * group.set_generator(generator, order, cofactor) => self | |
* | |
- * See the OpenSSL documentation for EC_GROUP_set_generator() | |
+ * Sets the curve parameters. +generator+ must be an instance of EC::Point that | |
+ * is on the curve. +order+ and +cofactor+ are integers. | |
+ * | |
+ * See the OpenSSL documentation for EC_GROUP_set_generator() | |
*/ | |
static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor) | |
{ | |
@@ -903,8 +914,8 @@ static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE orde | |
const EC_POINT *point; | |
const BIGNUM *o, *co; | |
- Require_EC_GROUP(self, group); | |
- SafeRequire_EC_POINT(generator, point); | |
+ GetECGroup(self, group); | |
+ SafeGetECPoint(generator, point); | |
o = GetBNPtr(order); | |
co = GetBNPtr(cofactor); | |
@@ -914,10 +925,13 @@ static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE orde | |
return self; | |
} | |
-/* call-seq: | |
- * group.get_order => order_bn | |
+/* | |
+ * call-seq: | |
+ * group.get_order => order_bn | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get_order() | |
+ * Returns the order of the group. | |
+ * | |
+ * See the OpenSSL documentation for EC_GROUP_get_order() | |
*/ | |
static VALUE ossl_ec_group_get_order(VALUE self) | |
{ | |
@@ -925,7 +939,7 @@ static VALUE ossl_ec_group_get_order(VALUE self) | |
BIGNUM *bn; | |
EC_GROUP *group = NULL; | |
- Require_EC_GROUP(self, group); | |
+ GetECGroup(self, group); | |
bn_obj = ossl_bn_new(NULL); | |
bn = GetBNPtr(bn_obj); | |
@@ -936,10 +950,13 @@ static VALUE ossl_ec_group_get_order(VALUE self) | |
return bn_obj; | |
} | |
-/* call-seq: | |
- * group.get_cofactor => cofactor_bn | |
+/* | |
+ * call-seq: | |
+ * group.get_cofactor => cofactor_bn | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get_cofactor() | |
+ * Returns the cofactor of the group. | |
+ * | |
+ * See the OpenSSL documentation for EC_GROUP_get_cofactor() | |
*/ | |
static VALUE ossl_ec_group_get_cofactor(VALUE self) | |
{ | |
@@ -947,7 +964,7 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self) | |
BIGNUM *bn; | |
EC_GROUP *group = NULL; | |
- Require_EC_GROUP(self, group); | |
+ GetECGroup(self, group); | |
bn_obj = ossl_bn_new(NULL); | |
bn = GetBNPtr(bn_obj); | |
@@ -958,17 +975,20 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self) | |
return bn_obj; | |
} | |
-/* call-seq: | |
- * group.curve_name => String | |
+/* | |
+ * call-seq: | |
+ * group.curve_name => String | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get_curve_name() | |
+ * Returns the curve name (sn). | |
+ * | |
+ * See the OpenSSL documentation for EC_GROUP_get_curve_name() | |
*/ | |
static VALUE ossl_ec_group_get_curve_name(VALUE self) | |
{ | |
EC_GROUP *group = NULL; | |
int nid; | |
- Get_EC_GROUP(self, group); | |
+ GetECGroup(self, group); | |
if (group == NULL) | |
return Qnil; | |
@@ -978,10 +998,14 @@ static VALUE ossl_ec_group_get_curve_name(VALUE self) | |
return rb_str_new2(OBJ_nid2sn(nid)); | |
} | |
-/* call-seq: | |
- * EC.builtin_curves => [[name, comment], ...] | |
+/* | |
+ * call-seq: | |
+ * EC.builtin_curves => [[sn, comment], ...] | |
* | |
- * See the OpenSSL documentation for EC_builtin_curves() | |
+ * Obtains a list of all predefined curves by the OpenSSL. Curve names are | |
+ * returned as sn. | |
+ * | |
+ * See the OpenSSL documentation for EC_get_builtin_curves(). | |
*/ | |
static VALUE ossl_s_builtin_curves(VALUE self) | |
{ | |
@@ -1011,43 +1035,56 @@ static VALUE ossl_s_builtin_curves(VALUE self) | |
return ret; | |
} | |
-/* call-seq: | |
- * group.asn1_flag => Fixnum | |
+/* | |
+ * call-seq: | |
+ * group.asn1_flag -> Integer | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get_asn1_flag() | |
+ * Returns the flags set on the group. | |
+ * | |
+ * See also #asn1_flag=. | |
*/ | |
static VALUE ossl_ec_group_get_asn1_flag(VALUE self) | |
{ | |
EC_GROUP *group = NULL; | |
int flag; | |
- Require_EC_GROUP(self, group); | |
- | |
+ GetECGroup(self, group); | |
flag = EC_GROUP_get_asn1_flag(group); | |
- return INT2FIX(flag); | |
+ return INT2NUM(flag); | |
} | |
-/* call-seq: | |
- * group.asn1_flag = Fixnum => Fixnum | |
+/* | |
+ * call-seq: | |
+ * group.asn1_flag = flags | |
+ * | |
+ * Sets flags on the group. The flag value is used to determine how to encode | |
+ * the group: encode explicit parameters or named curve using an OID. | |
+ * | |
+ * The flag value can be either of: | |
* | |
- * See the OpenSSL documentation for EC_GROUP_set_asn1_flag() | |
+ * * EC::NAMED_CURVE | |
+ * * EC::EXPLICIT_CURVE | |
+ * | |
+ * See the OpenSSL documentation for EC_GROUP_set_asn1_flag(). | |
*/ | |
static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v) | |
{ | |
EC_GROUP *group = NULL; | |
- Require_EC_GROUP(self, group); | |
- | |
+ GetECGroup(self, group); | |
EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v)); | |
return flag_v; | |
} | |
-/* call-seq: | |
- * group.point_conversion_form => :uncompressed | :compressed | :hybrid | |
+/* | |
+ * call-seq: | |
+ * group.point_conversion_form -> Symbol | |
+ * | |
+ * Returns the form how EC::Point data is encoded as ASN.1. | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form() | |
+ * See also #point_conversion_form=. | |
*/ | |
static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) | |
{ | |
@@ -1055,8 +1092,7 @@ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) | |
point_conversion_form_t form; | |
VALUE ret; | |
- Require_EC_GROUP(self, group); | |
- | |
+ GetECGroup(self, group); | |
form = EC_GROUP_get_point_conversion_form(group); | |
switch (form) { | |
@@ -1069,46 +1105,67 @@ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) | |
return ID2SYM(ret); | |
} | |
-/* call-seq: | |
- * group.point_conversion_form = form => form | |
+static point_conversion_form_t | |
+parse_point_conversion_form_symbol(VALUE sym) | |
+{ | |
+ ID id = SYM2ID(sym); | |
+ | |
+ if (id == ID_uncompressed) | |
+ return POINT_CONVERSION_UNCOMPRESSED; | |
+ else if (id == ID_compressed) | |
+ return POINT_CONVERSION_COMPRESSED; | |
+ else if (id == ID_hybrid) | |
+ return POINT_CONVERSION_HYBRID; | |
+ else | |
+ ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE | |
+ " (expected :compressed, :uncompressed, or :hybrid)", sym); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * group.point_conversion_form = form | |
+ * | |
+ * Sets the form how EC::Point data is encoded as ASN.1 as defined in X9.62. | |
+ * | |
+ * +format+ can be one of these: | |
+ * | |
+ * :compressed:: | |
+ * Encoded as z||x, where z is an octet indicating which solution of the | |
+ * equation y is. z will be 0x02 or 0x03. | |
+ * :uncompressed:: | |
+ * Encoded as z||x||y, where z is an octet 0x04. | |
+ * :hybrid:: | |
+ * Encodes as z||x||y, where z is an octet indicating which solution of the | |
+ * equation y is. z will be 0x06 or 0x07. | |
* | |
- * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form() | |
+ * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form() | |
*/ | |
-static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v) | |
+static VALUE | |
+ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v) | |
{ | |
- EC_GROUP *group = NULL; | |
+ EC_GROUP *group; | |
point_conversion_form_t form; | |
- ID form_id = SYM2ID(form_v); | |
- | |
- Require_EC_GROUP(self, group); | |
- if (form_id == ID_uncompressed) { | |
- form = POINT_CONVERSION_UNCOMPRESSED; | |
- } else if (form_id == ID_compressed) { | |
- form = POINT_CONVERSION_COMPRESSED; | |
- } else if (form_id == ID_hybrid) { | |
- form = POINT_CONVERSION_HYBRID; | |
- } else { | |
- ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid"); | |
- } | |
+ GetECGroup(self, group); | |
+ form = parse_point_conversion_form_symbol(form_v); | |
EC_GROUP_set_point_conversion_form(group, form); | |
return form_v; | |
} | |
-/* call-seq: | |
- * group.seed => String or nil | |
+/* | |
+ * call-seq: | |
+ * group.seed => String or nil | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get0_seed() | |
+ * See the OpenSSL documentation for EC_GROUP_get0_seed() | |
*/ | |
static VALUE ossl_ec_group_get_seed(VALUE self) | |
{ | |
EC_GROUP *group = NULL; | |
size_t seed_len; | |
- Require_EC_GROUP(self, group); | |
- | |
+ GetECGroup(self, group); | |
seed_len = EC_GROUP_get_seed_len(group); | |
if (seed_len == 0) | |
@@ -1117,16 +1174,17 @@ static VALUE ossl_ec_group_get_seed(VALUE self) | |
return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len); | |
} | |
-/* call-seq: | |
- * group.seed = seed => seed | |
+/* | |
+ * call-seq: | |
+ * group.seed = seed => seed | |
* | |
- * See the OpenSSL documentation for EC_GROUP_set_seed() | |
+ * See the OpenSSL documentation for EC_GROUP_set_seed() | |
*/ | |
static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed) | |
{ | |
EC_GROUP *group = NULL; | |
- Require_EC_GROUP(self, group); | |
+ GetECGroup(self, group); | |
StringValue(seed); | |
if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed)) | |
@@ -1137,16 +1195,17 @@ static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed) | |
/* get/set curve GFp, GF2m */ | |
-/* call-seq: | |
- * group.degree => Fixnum | |
+/* | |
+ * call-seq: | |
+ * group.degree => integer | |
* | |
- * See the OpenSSL documentation for EC_GROUP_get_degree() | |
+ * See the OpenSSL documentation for EC_GROUP_get_degree() | |
*/ | |
static VALUE ossl_ec_group_get_degree(VALUE self) | |
{ | |
EC_GROUP *group = NULL; | |
- Require_EC_GROUP(self, group); | |
+ GetECGroup(self, group); | |
return INT2NUM(EC_GROUP_get_degree(group)); | |
} | |
@@ -1158,7 +1217,7 @@ static VALUE ossl_ec_group_to_string(VALUE self, int format) | |
int i = -1; | |
VALUE str; | |
- Get_EC_GROUP(self, group); | |
+ GetECGroup(self, group); | |
if (!(out = BIO_new(BIO_s_mem()))) | |
ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); | |
@@ -1185,8 +1244,9 @@ static VALUE ossl_ec_group_to_string(VALUE self, int format) | |
return str; | |
} | |
-/* call-seq: | |
- * group.to_pem => String | |
+/* | |
+ * call-seq: | |
+ * group.to_pem => String | |
* | |
* See the OpenSSL documentation for PEM_write_bio_ECPKParameters() | |
*/ | |
@@ -1195,20 +1255,22 @@ static VALUE ossl_ec_group_to_pem(VALUE self) | |
return ossl_ec_group_to_string(self, EXPORT_PEM); | |
} | |
-/* call-seq: | |
- * group.to_der => String | |
+/* | |
+ * call-seq: | |
+ * group.to_der => String | |
* | |
- * See the OpenSSL documentation for i2d_ECPKParameters_bio() | |
+ * See the OpenSSL documentation for i2d_ECPKParameters_bio() | |
*/ | |
static VALUE ossl_ec_group_to_der(VALUE self) | |
{ | |
return ossl_ec_group_to_string(self, EXPORT_DER); | |
} | |
-/* call-seq: | |
- * group.to_text => String | |
+/* | |
+ * call-seq: | |
+ * group.to_text => String | |
* | |
- * See the OpenSSL documentation for ECPKParameters_print() | |
+ * See the OpenSSL documentation for ECPKParameters_print() | |
*/ | |
static VALUE ossl_ec_group_to_text(VALUE self) | |
{ | |
@@ -1216,7 +1278,7 @@ static VALUE ossl_ec_group_to_text(VALUE self) | |
BIO *out; | |
VALUE str; | |
- Require_EC_GROUP(self, group); | |
+ GetECGroup(self, group); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); | |
} | |
@@ -1230,50 +1292,62 @@ static VALUE ossl_ec_group_to_text(VALUE self) | |
} | |
-static void ossl_ec_point_free(void *ptr) | |
+/* | |
+ * OpenSSL::PKey::EC::Point | |
+ */ | |
+static void | |
+ossl_ec_point_free(void *ptr) | |
{ | |
- ossl_ec_point *ec_point = ptr; | |
- if (!ec_point->dont_free && ec_point->point) | |
- EC_POINT_clear_free(ec_point->point); | |
- ruby_xfree(ec_point); | |
+ EC_POINT_clear_free(ptr); | |
} | |
static const rb_data_type_t ossl_ec_point_type = { | |
- "OpenSSL/ec_point", | |
+ "OpenSSL/EC_POINT", | |
{ | |
0, ossl_ec_point_free, | |
}, | |
0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
}; | |
-static VALUE ossl_ec_point_alloc(VALUE klass) | |
+static VALUE | |
+ossl_ec_point_alloc(VALUE klass) | |
+{ | |
+ return TypedData_Wrap_Struct(klass, &ossl_ec_point_type, NULL); | |
+} | |
+ | |
+static VALUE | |
+ec_point_new(const EC_POINT *point, const EC_GROUP *group) | |
{ | |
- ossl_ec_point *ec_point; | |
+ EC_POINT *point_new; | |
VALUE obj; | |
- obj = TypedData_Make_Struct(klass, ossl_ec_point, &ossl_ec_point_type, ec_point); | |
+ obj = ossl_ec_point_alloc(cEC_POINT); | |
+ point_new = EC_POINT_dup(point, group); | |
+ if (!point_new) | |
+ ossl_raise(eEC_POINT, "EC_POINT_dup"); | |
+ RTYPEDDATA_DATA(obj) = point_new; | |
+ rb_ivar_set(obj, id_i_group, ec_group_new(group)); | |
return obj; | |
} | |
/* | |
- * call-seq: | |
- * OpenSSL::PKey::EC::Point.new(point) | |
- * OpenSSL::PKey::EC::Point.new(group) | |
- * OpenSSL::PKey::EC::Point.new(group, bn) | |
+ * call-seq: | |
+ * OpenSSL::PKey::EC::Point.new(point) | |
+ * OpenSSL::PKey::EC::Point.new(group) | |
+ * OpenSSL::PKey::EC::Point.new(group, bn) | |
* | |
- * See the OpenSSL documentation for EC_POINT_* | |
+ * See the OpenSSL documentation for EC_POINT_* | |
*/ | |
static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
- ossl_ec_point *ec_point; | |
- EC_POINT *point = NULL; | |
+ EC_POINT *point; | |
VALUE arg1, arg2; | |
VALUE group_v = Qnil; | |
const EC_GROUP *group = NULL; | |
- TypedData_Get_Struct(self, ossl_ec_point, &ossl_ec_point_type, ec_point); | |
- if (ec_point->point) | |
+ TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point); | |
+ if (point) | |
ossl_raise(eEC_POINT, "EC_POINT already initialized"); | |
switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) { | |
@@ -1281,14 +1355,14 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) | |
if (rb_obj_is_kind_of(arg1, cEC_POINT)) { | |
const EC_POINT *arg_point; | |
- group_v = rb_iv_get(arg1, "@group"); | |
- SafeRequire_EC_GROUP(group_v, group); | |
- SafeRequire_EC_POINT(arg1, arg_point); | |
+ group_v = rb_attr_get(arg1, id_i_group); | |
+ SafeGetECGroup(group_v, group); | |
+ SafeGetECPoint(arg1, arg_point); | |
point = EC_POINT_dup(arg_point, group); | |
} else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { | |
group_v = arg1; | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ SafeGetECGroup(group_v, group); | |
point = EC_POINT_new(group); | |
} else { | |
@@ -1300,14 +1374,14 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) | |
if (!rb_obj_is_kind_of(arg1, cEC_GROUP)) | |
ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group"); | |
group_v = arg1; | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ SafeGetECGroup(group_v, group); | |
if (rb_obj_is_kind_of(arg2, cBN)) { | |
const BIGNUM *bn = GetBNPtr(arg2); | |
point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx); | |
} else { | |
- BIO *in = ossl_obj2bio(&arg1); | |
+ BIO *in = ossl_obj2bio(arg1); | |
/* BUG: finish me */ | |
@@ -1328,32 +1402,54 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) | |
if (NIL_P(group_v)) | |
ossl_raise(rb_eRuntimeError, "missing group (internal error)"); | |
- ec_point->point = point; | |
+ RTYPEDDATA_DATA(self) = point; | |
+ rb_ivar_set(self, id_i_group, group_v); | |
+ | |
+ return self; | |
+} | |
+ | |
+static VALUE | |
+ossl_ec_point_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ EC_POINT *point, *point_new; | |
+ EC_GROUP *group; | |
+ VALUE group_v; | |
- rb_iv_set(self, "@group", group_v); | |
+ TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point_new); | |
+ if (point_new) | |
+ ossl_raise(eEC_POINT, "EC::Point already initialized"); | |
+ SafeGetECPoint(other, point); | |
+ | |
+ group_v = rb_obj_dup(rb_attr_get(other, id_i_group)); | |
+ SafeGetECGroup(group_v, group); | |
+ | |
+ point_new = EC_POINT_dup(point, group); | |
+ if (!point_new) | |
+ ossl_raise(eEC_POINT, "EC_POINT_dup"); | |
+ RTYPEDDATA_DATA(self) = point_new; | |
+ rb_ivar_set(self, id_i_group, group_v); | |
return self; | |
} | |
/* | |
- * call-seq: | |
- * point1.eql?(point2) => true | false | |
- * point1 == point2 => true | false | |
- * | |
+ * call-seq: | |
+ * point1.eql?(point2) => true | false | |
+ * point1 == point2 => true | false | |
*/ | |
static VALUE ossl_ec_point_eql(VALUE a, VALUE b) | |
{ | |
EC_POINT *point1, *point2; | |
- VALUE group_v1 = rb_iv_get(a, "@group"); | |
- VALUE group_v2 = rb_iv_get(b, "@group"); | |
+ VALUE group_v1 = rb_attr_get(a, id_i_group); | |
+ VALUE group_v2 = rb_attr_get(b, id_i_group); | |
const EC_GROUP *group; | |
if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse) | |
return Qfalse; | |
- Require_EC_POINT(a, point1); | |
- SafeRequire_EC_POINT(b, point2); | |
- SafeRequire_EC_GROUP(group_v1, group); | |
+ GetECPoint(a, point1); | |
+ SafeGetECPoint(b, point2); | |
+ SafeGetECGroup(group_v1, group); | |
if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1) | |
return Qfalse; | |
@@ -1362,18 +1458,16 @@ static VALUE ossl_ec_point_eql(VALUE a, VALUE b) | |
} | |
/* | |
- * call-seq: | |
- * point.infinity? => true | false | |
- * | |
+ * call-seq: | |
+ * point.infinity? => true | false | |
*/ | |
static VALUE ossl_ec_point_is_at_infinity(VALUE self) | |
{ | |
EC_POINT *point; | |
- VALUE group_v = rb_iv_get(self, "@group"); | |
const EC_GROUP *group; | |
- Require_EC_POINT(self, point); | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ GetECPoint(self, point); | |
+ GetECPointGroup(self, group); | |
switch (EC_POINT_is_at_infinity(group, point)) { | |
case 1: return Qtrue; | |
@@ -1385,18 +1479,16 @@ static VALUE ossl_ec_point_is_at_infinity(VALUE self) | |
} | |
/* | |
- * call-seq: | |
- * point.on_curve? => true | false | |
- * | |
+ * call-seq: | |
+ * point.on_curve? => true | false | |
*/ | |
static VALUE ossl_ec_point_is_on_curve(VALUE self) | |
{ | |
EC_POINT *point; | |
- VALUE group_v = rb_iv_get(self, "@group"); | |
const EC_GROUP *group; | |
- Require_EC_POINT(self, point); | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ GetECPoint(self, point); | |
+ GetECPointGroup(self, group); | |
switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) { | |
case 1: return Qtrue; | |
@@ -1408,18 +1500,16 @@ static VALUE ossl_ec_point_is_on_curve(VALUE self) | |
} | |
/* | |
- * call-seq: | |
- * point.make_affine! => self | |
- * | |
+ * call-seq: | |
+ * point.make_affine! => self | |
*/ | |
static VALUE ossl_ec_point_make_affine(VALUE self) | |
{ | |
EC_POINT *point; | |
- VALUE group_v = rb_iv_get(self, "@group"); | |
const EC_GROUP *group; | |
- Require_EC_POINT(self, point); | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ GetECPoint(self, point); | |
+ GetECPointGroup(self, group); | |
if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1) | |
ossl_raise(cEC_POINT, "EC_POINT_make_affine"); | |
@@ -1428,18 +1518,16 @@ static VALUE ossl_ec_point_make_affine(VALUE self) | |
} | |
/* | |
- * call-seq: | |
- * point.invert! => self | |
- * | |
+ * call-seq: | |
+ * point.invert! => self | |
*/ | |
static VALUE ossl_ec_point_invert(VALUE self) | |
{ | |
EC_POINT *point; | |
- VALUE group_v = rb_iv_get(self, "@group"); | |
const EC_GROUP *group; | |
- Require_EC_POINT(self, point); | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ GetECPoint(self, point); | |
+ GetECPointGroup(self, group); | |
if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1) | |
ossl_raise(cEC_POINT, "EC_POINT_invert"); | |
@@ -1448,18 +1536,16 @@ static VALUE ossl_ec_point_invert(VALUE self) | |
} | |
/* | |
- * call-seq: | |
- * point.set_to_infinity! => self | |
- * | |
+ * call-seq: | |
+ * point.set_to_infinity! => self | |
*/ | |
static VALUE ossl_ec_point_set_to_infinity(VALUE self) | |
{ | |
EC_POINT *point; | |
- VALUE group_v = rb_iv_get(self, "@group"); | |
const EC_GROUP *group; | |
- Require_EC_POINT(self, point); | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ GetECPoint(self, point); | |
+ GetECPointGroup(self, group); | |
if (EC_POINT_set_to_infinity(group, point) != 1) | |
ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity"); | |
@@ -1468,24 +1554,31 @@ static VALUE ossl_ec_point_set_to_infinity(VALUE self) | |
} | |
/* | |
- * call-seq: | |
- * point.to_bn => OpenSSL::BN | |
+ * call-seq: | |
+ * point.to_bn(conversion_form = nil) => OpenSSL::BN | |
* | |
- * See the OpenSSL documentation for EC_POINT_point2bn() | |
+ * Convert the EC point into an octet string and store in an OpenSSL::BN. If | |
+ * +conversion_form+ is given, the point data is converted using the specified | |
+ * form. If not given, the default form set in the EC::Group object is used. | |
+ * | |
+ * See also EC::Point#point_conversion_form=. | |
*/ | |
-static VALUE ossl_ec_point_to_bn(VALUE self) | |
+static VALUE | |
+ossl_ec_point_to_bn(int argc, VALUE *argv, VALUE self) | |
{ | |
EC_POINT *point; | |
- VALUE bn_obj; | |
- VALUE group_v = rb_iv_get(self, "@group"); | |
+ VALUE form_obj, bn_obj; | |
const EC_GROUP *group; | |
point_conversion_form_t form; | |
BIGNUM *bn; | |
- Require_EC_POINT(self, point); | |
- SafeRequire_EC_GROUP(group_v, group); | |
- | |
- form = EC_GROUP_get_point_conversion_form(group); | |
+ GetECPoint(self, point); | |
+ GetECPointGroup(self, group); | |
+ rb_scan_args(argc, argv, "01", &form_obj); | |
+ if (NIL_P(form_obj)) | |
+ form = EC_GROUP_get_point_conversion_form(group); | |
+ else | |
+ form = parse_point_conversion_form_symbol(form_obj); | |
bn_obj = rb_obj_alloc(cBN); | |
bn = GetBNPtr(bn_obj); | |
@@ -1497,94 +1590,116 @@ static VALUE ossl_ec_point_to_bn(VALUE self) | |
} | |
/* | |
- * call-seq: | |
- * point.mul(bn) => point | |
- * point.mul(bn, bn) => point | |
- * point.mul([bn], [point]) => point | |
- * point.mul([bn], [point], bn) => point | |
+ * call-seq: | |
+ * point.mul(bn1 [, bn2]) => point | |
+ * point.mul(bns, points [, bn2]) => point | |
+ * | |
+ * Performs elliptic curve point multiplication. | |
+ * | |
+ * The first form calculates <tt>bn1 * point + bn2 * G</tt>, where +G+ is the | |
+ * generator of the group of +point+. +bn2+ may be ommitted, and in that case, | |
+ * the result is just <tt>bn1 * point</tt>. | |
+ * | |
+ * The second form calculates <tt>bns[0] * point + bns[1] * points[0] + ... | |
+ * + bns[-1] * points[-1] + bn2 * G</tt>. +bn2+ may be ommitted. +bns+ must be | |
+ * an array of OpenSSL::BN. +points+ must be an array of | |
+ * OpenSSL::PKey::EC::Point. Please note that <tt>points[0]</tt> is not | |
+ * multiplied by <tt>bns[0]</tt>, but <tt>bns[1]</tt>. | |
*/ | |
static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self) | |
{ | |
- EC_POINT *point1, *point2; | |
+ EC_POINT *point_self, *point_result; | |
const EC_GROUP *group; | |
- VALUE group_v = rb_iv_get(self, "@group"); | |
- VALUE bn_v1, bn_v2, r, points_v; | |
- BIGNUM *bn1 = NULL, *bn2 = NULL; | |
+ VALUE group_v = rb_attr_get(self, id_i_group); | |
+ VALUE arg1, arg2, arg3, result; | |
+ const BIGNUM *bn_g = NULL; | |
- Require_EC_POINT(self, point1); | |
- SafeRequire_EC_GROUP(group_v, group); | |
+ GetECPoint(self, point_self); | |
+ SafeGetECGroup(group_v, group); | |
- r = rb_obj_alloc(cEC_POINT); | |
- ossl_ec_point_initialize(1, &group_v, r); | |
- Require_EC_POINT(r, point2); | |
+ result = rb_obj_alloc(cEC_POINT); | |
+ ossl_ec_point_initialize(1, &group_v, result); | |
+ GetECPoint(result, point_result); | |
- argc = rb_scan_args(argc, argv, "12", &bn_v1, &points_v, &bn_v2); | |
+ rb_scan_args(argc, argv, "12", &arg1, &arg2, &arg3); | |
+ if (!RB_TYPE_P(arg1, T_ARRAY)) { | |
+ BIGNUM *bn = GetBNPtr(arg1); | |
- if (rb_obj_is_kind_of(bn_v1, cBN)) { | |
- bn1 = GetBNPtr(bn_v1); | |
- if (argc >= 2) { | |
- bn2 = GetBNPtr(points_v); | |
- } | |
- if (EC_POINT_mul(group, point2, bn2, point1, bn1, ossl_bn_ctx) != 1) | |
- ossl_raise(eEC_POINT, "Multiplication failed"); | |
+ if (!NIL_P(arg2)) | |
+ bn_g = GetBNPtr(arg2); | |
+ if (EC_POINT_mul(group, point_result, bn_g, point_self, bn, ossl_bn_ctx) != 1) | |
+ ossl_raise(eEC_POINT, NULL); | |
} else { | |
- size_t i, points_len, bignums_len; | |
- const EC_POINT **points; | |
- const BIGNUM **bignums; | |
- | |
- Check_Type(bn_v1, T_ARRAY); | |
- bignums_len = RARRAY_LEN(bn_v1); | |
- bignums = (const BIGNUM **)OPENSSL_malloc(bignums_len * (int)sizeof(BIGNUM *)); | |
- | |
- for (i = 0; i < bignums_len; ++i) { | |
- bignums[i] = GetBNPtr(rb_ary_entry(bn_v1, i)); | |
- } | |
+ /* | |
+ * bignums | arg1[0] | arg1[1] | arg1[2] | ... | |
+ * points | self | arg2[0] | arg2[1] | ... | |
+ */ | |
+ long i, num; | |
+ VALUE bns_tmp, tmp_p, tmp_b; | |
+ const EC_POINT **points; | |
+ const BIGNUM **bignums; | |
+ | |
+ Check_Type(arg1, T_ARRAY); | |
+ Check_Type(arg2, T_ARRAY); | |
+ if (RARRAY_LEN(arg1) != RARRAY_LEN(arg2) + 1) /* arg2 must be 1 larger */ | |
+ ossl_raise(rb_eArgError, "bns must be 1 longer than points; see the documentation"); | |
+ | |
+ num = RARRAY_LEN(arg1); | |
+ bns_tmp = rb_ary_tmp_new(num); | |
+ bignums = ALLOCV_N(const BIGNUM *, tmp_b, num); | |
+ for (i = 0; i < num; i++) { | |
+ VALUE item = RARRAY_AREF(arg1, i); | |
+ bignums[i] = GetBNPtr(item); | |
+ rb_ary_push(bns_tmp, item); | |
+ } | |
- if (!rb_obj_is_kind_of(points_v, rb_cArray)) { | |
- OPENSSL_free((void *)bignums); | |
- rb_raise(rb_eTypeError, "Argument2 must be an array"); | |
- } | |
+ points = ALLOCV_N(const EC_POINT *, tmp_p, num); | |
+ points[0] = point_self; /* self */ | |
+ for (i = 0; i < num - 1; i++) | |
+ SafeGetECPoint(RARRAY_AREF(arg2, i), points[i + 1]); | |
- rb_ary_unshift(points_v, self); | |
- points_len = RARRAY_LEN(points_v); | |
- points = (const EC_POINT **)OPENSSL_malloc(points_len * (int)sizeof(EC_POINT *)); | |
+ if (!NIL_P(arg3)) | |
+ bn_g = GetBNPtr(arg3); | |
- for (i = 0; i < points_len; ++i) { | |
- Get_EC_POINT(rb_ary_entry(points_v, i), points[i]); | |
- } | |
+ if (EC_POINTs_mul(group, point_result, bn_g, num, points, bignums, ossl_bn_ctx) != 1) { | |
+ ALLOCV_END(tmp_b); | |
+ ALLOCV_END(tmp_p); | |
+ ossl_raise(eEC_POINT, NULL); | |
+ } | |
- if (argc >= 3) { | |
- bn2 = GetBNPtr(bn_v2); | |
- } | |
- if (EC_POINTs_mul(group, point2, bn2, points_len, points, bignums, ossl_bn_ctx) != 1) { | |
- OPENSSL_free((void *)bignums); | |
- OPENSSL_free((void *)points); | |
- ossl_raise(eEC_POINT, "Multiplication failed"); | |
- } | |
- OPENSSL_free((void *)bignums); | |
- OPENSSL_free((void *)points); | |
+ ALLOCV_END(tmp_b); | |
+ ALLOCV_END(tmp_p); | |
} | |
- return r; | |
-} | |
- | |
-static void no_copy(VALUE klass) | |
-{ | |
- rb_undef_method(klass, "copy"); | |
- rb_undef_method(klass, "clone"); | |
- rb_undef_method(klass, "dup"); | |
- rb_undef_method(klass, "initialize_copy"); | |
+ return result; | |
} | |
void Init_ossl_ec(void) | |
{ | |
-#ifdef DONT_NEED_RDOC_WORKAROUND | |
- mOSSL = rb_define_module("OpenSSL"); | |
+#if 0 | |
mPKey = rb_define_module_under(mOSSL, "PKey"); | |
+ cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); | |
#endif | |
eECError = rb_define_class_under(mPKey, "ECError", ePKeyError); | |
+ /* | |
+ * Document-class: OpenSSL::PKey::EC | |
+ * | |
+ * OpenSSL::PKey::EC provides access to Elliptic Curve Digital Signature | |
+ * Algorithm (ECDSA) and Elliptic Curve Diffie-Hellman (ECDH). | |
+ * | |
+ * === Key exchange | |
+ * ec1 = OpenSSL::PKey::EC.generate("prime256v1") | |
+ * ec2 = OpenSSL::PKey::EC.generate("prime256v1") | |
+ * # ec1 and ec2 have own private key respectively | |
+ * shared_key1 = ec1.dh_compute_key(ec2.public_key) | |
+ * shared_key2 = ec2.dh_compute_key(ec1.public_key) | |
+ * | |
+ * p shared_key1 == shared_key2 #=> true | |
+ */ | |
cEC = rb_define_class_under(mPKey, "EC", cPKey); | |
cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject); | |
cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject); | |
@@ -1602,13 +1717,16 @@ void Init_ossl_ec(void) | |
ID_compressed = rb_intern("compressed"); | |
ID_hybrid = rb_intern("hybrid"); | |
-#ifdef OPENSSL_EC_NAMED_CURVE | |
- rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE)); | |
+ rb_define_const(cEC, "NAMED_CURVE", INT2NUM(OPENSSL_EC_NAMED_CURVE)); | |
+#if defined(OPENSSL_EC_EXPLICIT_CURVE) | |
+ rb_define_const(cEC, "EXPLICIT_CURVE", INT2NUM(OPENSSL_EC_EXPLICIT_CURVE)); | |
#endif | |
rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0); | |
+ rb_define_singleton_method(cEC, "generate", ossl_ec_key_s_generate, 1); | |
rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1); | |
+ rb_define_copy_func(cEC, ossl_ec_key_initialize_copy); | |
/* copy/dup/cmp */ | |
rb_define_method(cEC, "group", ossl_ec_key_get_group, 0); | |
@@ -1617,8 +1735,10 @@ void Init_ossl_ec(void) | |
rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1); | |
rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0); | |
rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1); | |
- rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0); | |
- rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0); | |
+ rb_define_method(cEC, "private?", ossl_ec_key_is_private, 0); | |
+ rb_define_method(cEC, "public?", ossl_ec_key_is_public, 0); | |
+ rb_define_alias(cEC, "private_key?", "private?"); | |
+ rb_define_alias(cEC, "public_key?", "public?"); | |
/* rb_define_method(cEC, "", ossl_ec_key_get_, 0); | |
rb_define_method(cEC, "=", ossl_ec_key_set_ 1); | |
set/get enc_flags | |
@@ -1626,7 +1746,8 @@ void Init_ossl_ec(void) | |
set/get asn1_flag (can use ruby to call self.group.asn1_flag) | |
set/get precompute_mult | |
*/ | |
- rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0); | |
+ rb_define_method(cEC, "generate_key!", ossl_ec_key_generate_key, 0); | |
+ rb_define_alias(cEC, "generate_key", "generate_key!"); | |
rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); | |
rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); | |
@@ -1642,6 +1763,7 @@ void Init_ossl_ec(void) | |
rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); | |
rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1); | |
+ rb_define_copy_func(cEC_GROUP, ossl_ec_group_initialize_copy); | |
rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1); | |
rb_define_alias(cEC_GROUP, "==", "eql?"); | |
/* copy/dup/cmp */ | |
@@ -1677,6 +1799,7 @@ void Init_ossl_ec(void) | |
rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc); | |
rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1); | |
+ rb_define_copy_func(cEC_POINT, ossl_ec_point_initialize_copy); | |
rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0); | |
rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1); | |
rb_define_alias(cEC_POINT, "==", "eql?"); | |
@@ -1688,12 +1811,10 @@ void Init_ossl_ec(void) | |
rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0); | |
/* all the other methods */ | |
- rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0); | |
+ rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, -1); | |
rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1); | |
- no_copy(cEC); | |
- no_copy(cEC_GROUP); | |
- no_copy(cEC_POINT); | |
+ id_i_group = rb_intern("@group"); | |
} | |
#else /* defined NO_EC */ | |
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c | |
index 0262fdafdc..cea228d6d8 100644 | |
--- a/ext/openssl/ossl_pkey_rsa.c | |
+++ b/ext/openssl/ossl_pkey_rsa.c | |
@@ -7,19 +7,36 @@ | |
* This program is licensed under the same licence as Ruby. | |
* (See the file 'LICENCE'.) | |
*/ | |
-#if !defined(OPENSSL_NO_RSA) | |
- | |
#include "ossl.h" | |
+#if !defined(OPENSSL_NO_RSA) | |
+ | |
#define GetPKeyRSA(obj, pkey) do { \ | |
GetPKey((obj), (pkey)); \ | |
- if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_RSA) { /* PARANOIA? */ \ | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { /* PARANOIA? */ \ | |
ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \ | |
} \ | |
} while (0) | |
+#define GetRSA(obj, rsa) do { \ | |
+ EVP_PKEY *_pkey; \ | |
+ GetPKeyRSA((obj), _pkey); \ | |
+ (rsa) = EVP_PKEY_get0_RSA(_pkey); \ | |
+} while (0) | |
-#define RSA_HAS_PRIVATE(rsa) ((rsa)->p && (rsa)->q) | |
-#define RSA_PRIVATE(obj,rsa) (RSA_HAS_PRIVATE(rsa)||OSSL_PKEY_IS_PRIVATE(obj)) | |
+static inline int | |
+RSA_HAS_PRIVATE(RSA *rsa) | |
+{ | |
+ const BIGNUM *p, *q; | |
+ | |
+ RSA_get0_factors(rsa, &p, &q); | |
+ return p && q; /* d? why? */ | |
+} | |
+ | |
+static inline int | |
+RSA_PRIVATE(VALUE obj, RSA *rsa) | |
+{ | |
+ return RSA_HAS_PRIVATE(rsa) || OSSL_PKEY_IS_PRIVATE(obj); | |
+} | |
/* | |
* Classes | |
@@ -62,7 +79,7 @@ ossl_rsa_new(EVP_PKEY *pkey) | |
} | |
else { | |
obj = NewPKey(cRSA); | |
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { | |
ossl_raise(rb_eTypeError, "Not a RSA key!"); | |
} | |
SetPKey(obj, pkey); | |
@@ -77,7 +94,6 @@ ossl_rsa_new(EVP_PKEY *pkey) | |
/* | |
* Private | |
*/ | |
-#if defined(HAVE_RSA_GENERATE_KEY_EX) && HAVE_BN_GENCB | |
struct rsa_blocking_gen_arg { | |
RSA *rsa; | |
BIGNUM *e; | |
@@ -93,42 +109,41 @@ rsa_blocking_gen(void *arg) | |
gen->result = RSA_generate_key_ex(gen->rsa, gen->size, gen->e, gen->cb); | |
return 0; | |
} | |
-#endif | |
static RSA * | |
rsa_generate(int size, unsigned long exp) | |
{ | |
-#if defined(HAVE_RSA_GENERATE_KEY_EX) && HAVE_BN_GENCB | |
int i; | |
- BN_GENCB cb; | |
- struct ossl_generate_cb_arg cb_arg; | |
+ struct ossl_generate_cb_arg cb_arg = { 0 }; | |
struct rsa_blocking_gen_arg gen_arg; | |
RSA *rsa = RSA_new(); | |
BIGNUM *e = BN_new(); | |
+ BN_GENCB *cb = BN_GENCB_new(); | |
- if (!rsa || !e) { | |
- if (e) BN_free(e); | |
- if (rsa) RSA_free(rsa); | |
- return 0; | |
+ if (!rsa || !e || !cb) { | |
+ RSA_free(rsa); | |
+ BN_free(e); | |
+ BN_GENCB_free(cb); | |
+ return NULL; | |
} | |
for (i = 0; i < (int)sizeof(exp) * 8; ++i) { | |
if (exp & (1UL << i)) { | |
if (BN_set_bit(e, i) == 0) { | |
BN_free(e); | |
RSA_free(rsa); | |
- return 0; | |
+ BN_GENCB_free(cb); | |
+ return NULL; | |
} | |
} | |
} | |
- memset(&cb_arg, 0, sizeof(struct ossl_generate_cb_arg)); | |
if (rb_block_given_p()) | |
cb_arg.yield = 1; | |
- BN_GENCB_set(&cb, ossl_generate_cb_2, &cb_arg); | |
+ BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); | |
gen_arg.rsa = rsa; | |
gen_arg.e = e; | |
gen_arg.size = size; | |
- gen_arg.cb = &cb; | |
+ gen_arg.cb = cb; | |
if (cb_arg.yield == 1) { | |
/* we cannot release GVL when callback proc is supplied */ | |
rsa_blocking_gen(&gen_arg); | |
@@ -136,18 +151,20 @@ rsa_generate(int size, unsigned long exp) | |
/* there's a chance to unblock */ | |
rb_thread_call_without_gvl(rsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); | |
} | |
+ | |
+ BN_GENCB_free(cb); | |
+ BN_free(e); | |
if (!gen_arg.result) { | |
- BN_free(e); | |
RSA_free(rsa); | |
- if (cb_arg.state) rb_jump_tag(cb_arg.state); | |
- return 0; | |
+ if (cb_arg.state) { | |
+ /* must clear OpenSSL error stack */ | |
+ ossl_clear_error(); | |
+ rb_jump_tag(cb_arg.state); | |
+ } | |
+ return NULL; | |
} | |
- BN_free(e); | |
return rsa; | |
-#else | |
- return RSA_generate_key(size, exp, rb_block_given_p() ? ossl_generate_cb : NULL, NULL); | |
-#endif | |
} | |
/* | |
@@ -206,22 +223,21 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) | |
EVP_PKEY *pkey; | |
RSA *rsa; | |
BIO *in; | |
- char *passwd = NULL; | |
VALUE arg, pass; | |
GetPKey(self, pkey); | |
if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { | |
rsa = RSA_new(); | |
} | |
- else if (FIXNUM_P(arg)) { | |
- rsa = rsa_generate(FIX2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); | |
+ else if (RB_INTEGER_TYPE_P(arg)) { | |
+ rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); | |
if (!rsa) ossl_raise(eRSAError, NULL); | |
} | |
else { | |
- if (!NIL_P(pass)) passwd = StringValuePtr(pass); | |
+ pass = ossl_pem_passwd_value(pass); | |
arg = ossl_to_der_if_possible(arg); | |
- in = ossl_obj2bio(&arg); | |
- rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); | |
+ in = ossl_obj2bio(arg); | |
+ rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); | |
if (!rsa) { | |
OSSL_BIO_reset(in); | |
rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL); | |
@@ -255,6 +271,26 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+ossl_rsa_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ EVP_PKEY *pkey; | |
+ RSA *rsa, *rsa_new; | |
+ | |
+ GetPKey(self, pkey); | |
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) | |
+ ossl_raise(eRSAError, "RSA already initialized"); | |
+ GetRSA(other, rsa); | |
+ | |
+ rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa); | |
+ if (!rsa_new) | |
+ ossl_raise(eRSAError, "ASN1_dup"); | |
+ | |
+ EVP_PKEY_assign_RSA(pkey, rsa_new); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* rsa.public? => true | |
@@ -265,12 +301,13 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_rsa_is_public(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
- GetPKeyRSA(self, pkey); | |
+ GetRSA(self, rsa); | |
/* | |
* This method should check for n and e. BUG. | |
*/ | |
+ (void)rsa; | |
return Qtrue; | |
} | |
@@ -283,11 +320,11 @@ ossl_rsa_is_public(VALUE self) | |
static VALUE | |
ossl_rsa_is_private(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
- GetPKeyRSA(self, pkey); | |
+ GetRSA(self, rsa); | |
- return (RSA_PRIVATE(self, pkey->pkey.rsa)) ? Qtrue : Qfalse; | |
+ return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse; | |
} | |
/* | |
@@ -298,41 +335,35 @@ ossl_rsa_is_private(VALUE self) | |
* | |
* Outputs this keypair in PEM encoding. If +cipher+ and +pass_phrase+ are | |
* given they will be used to encrypt the key. +cipher+ must be an | |
- * OpenSSL::Cipher::Cipher instance. | |
+ * OpenSSL::Cipher instance. | |
*/ | |
static VALUE | |
ossl_rsa_export(int argc, VALUE *argv, VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
BIO *out; | |
const EVP_CIPHER *ciph = NULL; | |
- char *passwd = NULL; | |
VALUE cipher, pass, str; | |
- GetPKeyRSA(self, pkey); | |
+ GetRSA(self, rsa); | |
rb_scan_args(argc, argv, "02", &cipher, &pass); | |
if (!NIL_P(cipher)) { | |
ciph = GetCipherPtr(cipher); | |
- if (!NIL_P(pass)) { | |
- StringValue(pass); | |
- if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN) | |
- ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long"); | |
- passwd = RSTRING_PTR(pass); | |
- } | |
+ pass = ossl_pem_passwd_value(pass); | |
} | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eRSAError, NULL); | |
} | |
- if (RSA_HAS_PRIVATE(pkey->pkey.rsa)) { | |
- if (!PEM_write_bio_RSAPrivateKey(out, pkey->pkey.rsa, ciph, | |
- NULL, 0, ossl_pem_passwd_cb, passwd)) { | |
+ if (RSA_HAS_PRIVATE(rsa)) { | |
+ if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0, | |
+ ossl_pem_passwd_cb, (void *)pass)) { | |
BIO_free(out); | |
ossl_raise(eRSAError, NULL); | |
} | |
} else { | |
- if (!PEM_write_bio_RSA_PUBKEY(out, pkey->pkey.rsa)) { | |
+ if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) { | |
BIO_free(out); | |
ossl_raise(eRSAError, NULL); | |
} | |
@@ -351,30 +382,28 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_rsa_to_der(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
- int (*i2d_func)_((const RSA*, unsigned char**)); | |
+ RSA *rsa; | |
+ int (*i2d_func)(const RSA *, unsigned char **); | |
unsigned char *p; | |
long len; | |
VALUE str; | |
- GetPKeyRSA(self, pkey); | |
- if(RSA_HAS_PRIVATE(pkey->pkey.rsa)) | |
+ GetRSA(self, rsa); | |
+ if (RSA_HAS_PRIVATE(rsa)) | |
i2d_func = i2d_RSAPrivateKey; | |
else | |
- i2d_func = (int (*)(const RSA*, unsigned char**))i2d_RSA_PUBKEY; | |
- if((len = i2d_func(pkey->pkey.rsa, NULL)) <= 0) | |
+ i2d_func = (int (*)(const RSA *, unsigned char **))i2d_RSA_PUBKEY; | |
+ if((len = i2d_func(rsa, NULL)) <= 0) | |
ossl_raise(eRSAError, NULL); | |
str = rb_str_new(0, len); | |
p = (unsigned char *)RSTRING_PTR(str); | |
- if(i2d_func(pkey->pkey.rsa, &p) < 0) | |
+ if(i2d_func(rsa, &p) < 0) | |
ossl_raise(eRSAError, NULL); | |
ossl_str_adjust(str, p); | |
return str; | |
} | |
-#define ossl_rsa_buf_size(pkey) (RSA_size((pkey)->pkey.rsa)+16) | |
- | |
/* | |
* call-seq: | |
* rsa.public_encrypt(string) => String | |
@@ -386,20 +415,21 @@ ossl_rsa_to_der(VALUE self) | |
static VALUE | |
ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
+ const BIGNUM *rsa_n; | |
int buf_len, pad; | |
VALUE str, buffer, padding; | |
- GetPKeyRSA(self, pkey); | |
- if (!pkey->pkey.rsa->n) | |
+ GetRSA(self, rsa); | |
+ RSA_get0_key(rsa, &rsa_n, NULL, NULL); | |
+ if (!rsa_n) | |
ossl_raise(eRSAError, "incomplete RSA"); | |
rb_scan_args(argc, argv, "11", &buffer, &padding); | |
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); | |
StringValue(buffer); | |
- str = rb_str_new(0, ossl_rsa_buf_size(pkey)); | |
+ str = rb_str_new(0, RSA_size(rsa)); | |
buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), | |
- (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa, | |
- pad); | |
+ (unsigned char *)RSTRING_PTR(str), rsa, pad); | |
if (buf_len < 0) ossl_raise(eRSAError, NULL); | |
rb_str_set_len(str, buf_len); | |
@@ -417,20 +447,21 @@ ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
+ const BIGNUM *rsa_n; | |
int buf_len, pad; | |
VALUE str, buffer, padding; | |
- GetPKeyRSA(self, pkey); | |
- if (!pkey->pkey.rsa->n) | |
+ GetRSA(self, rsa); | |
+ RSA_get0_key(rsa, &rsa_n, NULL, NULL); | |
+ if (!rsa_n) | |
ossl_raise(eRSAError, "incomplete RSA"); | |
rb_scan_args(argc, argv, "11", &buffer, &padding); | |
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); | |
StringValue(buffer); | |
- str = rb_str_new(0, ossl_rsa_buf_size(pkey)); | |
+ str = rb_str_new(0, RSA_size(rsa)); | |
buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), | |
- (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa, | |
- pad); | |
+ (unsigned char *)RSTRING_PTR(str), rsa, pad); | |
if (buf_len < 0) ossl_raise(eRSAError, NULL); | |
rb_str_set_len(str, buf_len); | |
@@ -448,22 +479,23 @@ ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
+ const BIGNUM *rsa_n; | |
int buf_len, pad; | |
VALUE str, buffer, padding; | |
- GetPKeyRSA(self, pkey); | |
- if (!pkey->pkey.rsa->n) | |
+ GetRSA(self, rsa); | |
+ RSA_get0_key(rsa, &rsa_n, NULL, NULL); | |
+ if (!rsa_n) | |
ossl_raise(eRSAError, "incomplete RSA"); | |
- if (!RSA_PRIVATE(self, pkey->pkey.rsa)) | |
- ossl_raise(eRSAError, "private key needed"); | |
+ if (!RSA_PRIVATE(self, rsa)) | |
+ ossl_raise(eRSAError, "private key needed."); | |
rb_scan_args(argc, argv, "11", &buffer, &padding); | |
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); | |
StringValue(buffer); | |
- str = rb_str_new(0, ossl_rsa_buf_size(pkey)); | |
+ str = rb_str_new(0, RSA_size(rsa)); | |
buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), | |
- (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa, | |
- pad); | |
+ (unsigned char *)RSTRING_PTR(str), rsa, pad); | |
if (buf_len < 0) ossl_raise(eRSAError, NULL); | |
rb_str_set_len(str, buf_len); | |
@@ -481,22 +513,23 @@ ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
+ const BIGNUM *rsa_n; | |
int buf_len, pad; | |
VALUE str, buffer, padding; | |
- GetPKeyRSA(self, pkey); | |
- if (!pkey->pkey.rsa->n) | |
+ GetRSA(self, rsa); | |
+ RSA_get0_key(rsa, &rsa_n, NULL, NULL); | |
+ if (!rsa_n) | |
ossl_raise(eRSAError, "incomplete RSA"); | |
- if (!RSA_PRIVATE(self, pkey->pkey.rsa)) | |
- ossl_raise(eRSAError, "private key needed"); | |
+ if (!RSA_PRIVATE(self, rsa)) | |
+ ossl_raise(eRSAError, "private key needed."); | |
rb_scan_args(argc, argv, "11", &buffer, &padding); | |
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); | |
StringValue(buffer); | |
- str = rb_str_new(0, ossl_rsa_buf_size(pkey)); | |
+ str = rb_str_new(0, RSA_size(rsa)); | |
buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), | |
- (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa, | |
- pad); | |
+ (unsigned char *)RSTRING_PTR(str), rsa, pad); | |
if (buf_len < 0) ossl_raise(eRSAError, NULL); | |
rb_str_set_len(str, buf_len); | |
@@ -517,21 +550,24 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) | |
static VALUE | |
ossl_rsa_get_params(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
VALUE hash; | |
+ const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; | |
- GetPKeyRSA(self, pkey); | |
+ GetRSA(self, rsa); | |
+ RSA_get0_key(rsa, &n, &e, &d); | |
+ RSA_get0_factors(rsa, &p, &q); | |
+ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); | |
hash = rb_hash_new(); | |
- | |
- rb_hash_aset(hash, rb_str_new2("n"), ossl_bn_new(pkey->pkey.rsa->n)); | |
- rb_hash_aset(hash, rb_str_new2("e"), ossl_bn_new(pkey->pkey.rsa->e)); | |
- rb_hash_aset(hash, rb_str_new2("d"), ossl_bn_new(pkey->pkey.rsa->d)); | |
- rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.rsa->p)); | |
- rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.rsa->q)); | |
- rb_hash_aset(hash, rb_str_new2("dmp1"), ossl_bn_new(pkey->pkey.rsa->dmp1)); | |
- rb_hash_aset(hash, rb_str_new2("dmq1"), ossl_bn_new(pkey->pkey.rsa->dmq1)); | |
- rb_hash_aset(hash, rb_str_new2("iqmp"), ossl_bn_new(pkey->pkey.rsa->iqmp)); | |
+ rb_hash_aset(hash, rb_str_new2("n"), ossl_bn_new(n)); | |
+ rb_hash_aset(hash, rb_str_new2("e"), ossl_bn_new(e)); | |
+ rb_hash_aset(hash, rb_str_new2("d"), ossl_bn_new(d)); | |
+ rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p)); | |
+ rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q)); | |
+ rb_hash_aset(hash, rb_str_new2("dmp1"), ossl_bn_new(dmp1)); | |
+ rb_hash_aset(hash, rb_str_new2("dmq1"), ossl_bn_new(dmq1)); | |
+ rb_hash_aset(hash, rb_str_new2("iqmp"), ossl_bn_new(iqmp)); | |
return hash; | |
} | |
@@ -549,15 +585,15 @@ ossl_rsa_get_params(VALUE self) | |
static VALUE | |
ossl_rsa_to_text(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
BIO *out; | |
VALUE str; | |
- GetPKeyRSA(self, pkey); | |
+ GetRSA(self, rsa); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eRSAError, NULL); | |
} | |
- if (!RSA_print(out, pkey->pkey.rsa, 0)) { /* offset = 0 */ | |
+ if (!RSA_print(out, rsa, 0)) { /* offset = 0 */ | |
BIO_free(out); | |
ossl_raise(eRSAError, NULL); | |
} | |
@@ -581,8 +617,8 @@ ossl_rsa_to_public_key(VALUE self) | |
GetPKeyRSA(self, pkey); | |
/* err check performed by rsa_instance */ | |
- rsa = RSAPublicKey_dup(pkey->pkey.rsa); | |
- obj = rsa_instance(CLASS_OF(self), rsa); | |
+ rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); | |
+ obj = rsa_instance(rb_obj_class(self), rsa); | |
if (obj == Qfalse) { | |
RSA_free(rsa); | |
ossl_raise(eRSAError, NULL); | |
@@ -596,11 +632,11 @@ ossl_rsa_to_public_key(VALUE self) | |
static VALUE | |
ossl_rsa_blinding_on(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
- GetPKeyRSA(self, pkey); | |
+ GetRSA(self, rsa); | |
- if (RSA_blinding_on(pkey->pkey.rsa, ossl_bn_ctx) != 1) { | |
+ if (RSA_blinding_on(rsa, ossl_bn_ctx) != 1) { | |
ossl_raise(eRSAError, NULL); | |
} | |
return self; | |
@@ -609,35 +645,54 @@ ossl_rsa_blinding_on(VALUE self) | |
static VALUE | |
ossl_rsa_blinding_off(VALUE self) | |
{ | |
- EVP_PKEY *pkey; | |
+ RSA *rsa; | |
- GetPKeyRSA(self, pkey); | |
- RSA_blinding_off(pkey->pkey.rsa); | |
+ GetRSA(self, rsa); | |
+ RSA_blinding_off(rsa); | |
return self; | |
} | |
*/ | |
-OSSL_PKEY_BN(rsa, n) | |
-OSSL_PKEY_BN(rsa, e) | |
-OSSL_PKEY_BN(rsa, d) | |
-OSSL_PKEY_BN(rsa, p) | |
-OSSL_PKEY_BN(rsa, q) | |
-OSSL_PKEY_BN(rsa, dmp1) | |
-OSSL_PKEY_BN(rsa, dmq1) | |
-OSSL_PKEY_BN(rsa, iqmp) | |
+/* | |
+ * Document-method: OpenSSL::PKey::RSA#set_key | |
+ * call-seq: | |
+ * rsa.set_key(n, e, d) -> self | |
+ * | |
+ * Sets +n+, +e+, +d+ for the RSA instance. | |
+ */ | |
+OSSL_PKEY_BN_DEF3(rsa, RSA, key, n, e, d) | |
+/* | |
+ * Document-method: OpenSSL::PKey::RSA#set_factors | |
+ * call-seq: | |
+ * rsa.set_factors(p, q) -> self | |
+ * | |
+ * Sets +p+, +q+ for the RSA instance. | |
+ */ | |
+OSSL_PKEY_BN_DEF2(rsa, RSA, factors, p, q) | |
+/* | |
+ * Document-method: OpenSSL::PKey::RSA#set_crt_params | |
+ * call-seq: | |
+ * rsa.set_crt_params(dmp1, dmq1, iqmp) -> self | |
+ * | |
+ * Sets +dmp1+, +dmq1+, +iqmp+ for the RSA instance. They are calculated by | |
+ * <tt>d mod (p - 1)</tt>, <tt>d mod (q - 1)</tt> and <tt>q^(-1) mod p</tt> | |
+ * respectively. | |
+ */ | |
+OSSL_PKEY_BN_DEF3(rsa, RSA, crt_params, dmp1, dmq1, iqmp) | |
/* | |
* INIT | |
*/ | |
-#define DefRSAConst(x) rb_define_const(cRSA, #x,INT2FIX(RSA_##x)) | |
+#define DefRSAConst(x) rb_define_const(cRSA, #x, INT2NUM(RSA_##x)) | |
void | |
Init_ossl_rsa(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */ | |
mPKey = rb_define_module_under(mOSSL, "PKey"); | |
+ cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); | |
+ ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); | |
#endif | |
/* Document-class: OpenSSL::PKey::RSAError | |
@@ -662,6 +717,7 @@ Init_ossl_rsa(void) | |
rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1); | |
rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); | |
+ rb_define_copy_func(cRSA, ossl_rsa_initialize_copy); | |
rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0); | |
rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0); | |
@@ -684,6 +740,9 @@ Init_ossl_rsa(void) | |
DEF_OSSL_PKEY_BN(cRSA, rsa, dmp1); | |
DEF_OSSL_PKEY_BN(cRSA, rsa, dmq1); | |
DEF_OSSL_PKEY_BN(cRSA, rsa, iqmp); | |
+ rb_define_method(cRSA, "set_key", ossl_rsa_set_key, 3); | |
+ rb_define_method(cRSA, "set_factors", ossl_rsa_set_factors, 2); | |
+ rb_define_method(cRSA, "set_crt_params", ossl_rsa_set_crt_params, 3); | |
rb_define_method(cRSA, "params", ossl_rsa_get_params, 0); | |
diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c | |
index daf866d772..688c525afa 100644 | |
--- a/ext/openssl/ossl_rand.c | |
+++ b/ext/openssl/ossl_rand.c | |
@@ -41,13 +41,13 @@ ossl_rand_seed(VALUE self, VALUE str) | |
* The +entropy+ argument is (the lower bound of) an estimate of how much | |
* randomness is contained in +str+, measured in bytes. | |
* | |
- * Example: | |
+ * === Example | |
* | |
* pid = $$ | |
* now = Time.now | |
* ary = [now.to_i, now.nsec, 1000, pid] | |
- * OpenSSL::Random.add(ary.join("").to_s, 0.0) | |
- * OpenSSL::Random.seed(ary.join("").to_s) | |
+ * OpenSSL::Random.add(ary.join, 0.0) | |
+ * OpenSSL::Random.seed(ary.join) | |
*/ | |
static VALUE | |
ossl_rand_add(VALUE self, VALUE str, VALUE entropy) | |
@@ -67,9 +67,9 @@ ossl_rand_add(VALUE self, VALUE str, VALUE entropy) | |
static VALUE | |
ossl_rand_load_file(VALUE self, VALUE filename) | |
{ | |
- SafeStringValue(filename); | |
+ rb_check_safe_obj(filename); | |
- if(!RAND_load_file(RSTRING_PTR(filename), -1)) { | |
+ if(!RAND_load_file(StringValueCStr(filename), -1)) { | |
ossl_raise(eRandomError, NULL); | |
} | |
return Qtrue; | |
@@ -86,8 +86,9 @@ ossl_rand_load_file(VALUE self, VALUE filename) | |
static VALUE | |
ossl_rand_write_file(VALUE self, VALUE filename) | |
{ | |
- SafeStringValue(filename); | |
- if (RAND_write_file(RSTRING_PTR(filename)) == -1) { | |
+ rb_check_safe_obj(filename); | |
+ | |
+ if (RAND_write_file(StringValueCStr(filename)) == -1) { | |
ossl_raise(eRandomError, NULL); | |
} | |
return Qtrue; | |
@@ -100,10 +101,10 @@ ossl_rand_write_file(VALUE self, VALUE filename) | |
* Generates +string+ with +length+ number of cryptographically strong | |
* pseudo-random bytes. | |
* | |
- * Example: | |
+ * === Example | |
* | |
* OpenSSL::Random.random_bytes(12) | |
- * => "..." | |
+ * #=> "..." | |
*/ | |
static VALUE | |
ossl_rand_bytes(VALUE self, VALUE len) | |
@@ -114,10 +115,8 @@ ossl_rand_bytes(VALUE self, VALUE len) | |
str = rb_str_new(0, n); | |
ret = RAND_bytes((unsigned char *)RSTRING_PTR(str), n); | |
- if (ret == 0){ | |
- char buf[256]; | |
- ERR_error_string_n(ERR_get_error(), buf, 256); | |
- ossl_raise(eRandomError, "RAND_bytes error: %s", buf); | |
+ if (ret == 0) { | |
+ ossl_raise(eRandomError, "RAND_bytes"); | |
} else if (ret == -1) { | |
ossl_raise(eRandomError, "RAND_bytes is not supported"); | |
} | |
@@ -125,6 +124,7 @@ ossl_rand_bytes(VALUE self, VALUE len) | |
return str; | |
} | |
+#if defined(HAVE_RAND_PSEUDO_BYTES) | |
/* | |
* call-seq: | |
* pseudo_bytes(length) -> string | |
@@ -134,10 +134,10 @@ ossl_rand_bytes(VALUE self, VALUE len) | |
* Pseudo-random byte sequences generated by ::pseudo_bytes will be unique if | |
* they are of sufficient length, but are not necessarily unpredictable. | |
* | |
- * Example: | |
+ * === Example | |
* | |
* OpenSSL::Random.pseudo_bytes(12) | |
- * => "..." | |
+ * #=> "..." | |
*/ | |
static VALUE | |
ossl_rand_pseudo_bytes(VALUE self, VALUE len) | |
@@ -146,12 +146,13 @@ ossl_rand_pseudo_bytes(VALUE self, VALUE len) | |
int n = NUM2INT(len); | |
str = rb_str_new(0, n); | |
- if (!RAND_pseudo_bytes((unsigned char *)RSTRING_PTR(str), n)) { | |
+ if (RAND_pseudo_bytes((unsigned char *)RSTRING_PTR(str), n) < 1) { | |
ossl_raise(eRandomError, NULL); | |
} | |
return str; | |
} | |
+#endif | |
#ifdef HAVE_RAND_EGD | |
/* | |
@@ -163,9 +164,9 @@ ossl_rand_pseudo_bytes(VALUE self, VALUE len) | |
static VALUE | |
ossl_rand_egd(VALUE self, VALUE filename) | |
{ | |
- SafeStringValue(filename); | |
+ rb_check_safe_obj(filename); | |
- if(!RAND_egd(RSTRING_PTR(filename))) { | |
+ if (RAND_egd(StringValueCStr(filename)) == -1) { | |
ossl_raise(eRandomError, NULL); | |
} | |
return Qtrue; | |
@@ -185,9 +186,9 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len) | |
{ | |
int n = NUM2INT(len); | |
- SafeStringValue(filename); | |
+ rb_check_safe_obj(filename); | |
- if (!RAND_egd_bytes(RSTRING_PTR(filename), n)) { | |
+ if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) { | |
ossl_raise(eRandomError, NULL); | |
} | |
return Qtrue; | |
@@ -213,7 +214,8 @@ void | |
Init_ossl_rand(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
mRandom = rb_define_module_under(mOSSL, "Random"); | |
@@ -225,7 +227,9 @@ Init_ossl_rand(void) | |
rb_define_module_function(mRandom, "load_random_file", ossl_rand_load_file, 1); | |
rb_define_module_function(mRandom, "write_random_file", ossl_rand_write_file, 1); | |
rb_define_module_function(mRandom, "random_bytes", ossl_rand_bytes, 1); | |
+#if defined(HAVE_RAND_PSEUDO_BYTES) | |
rb_define_module_function(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1); | |
+#endif | |
#ifdef HAVE_RAND_EGD | |
rb_define_module_function(mRandom, "egd", ossl_rand_egd, 1); | |
rb_define_module_function(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2); | |
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c | |
index cd35ee3771..eef7dbece6 100644 | |
--- a/ext/openssl/ossl_ssl.c | |
+++ b/ext/openssl/ossl_ssl.c | |
@@ -11,10 +11,6 @@ | |
*/ | |
#include "ossl.h" | |
-#if defined(HAVE_UNISTD_H) | |
-# include <unistd.h> /* for read(), and write() */ | |
-#endif | |
- | |
#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0])) | |
#ifdef _WIN32 | |
@@ -36,87 +32,53 @@ VALUE cSSLSocket; | |
static VALUE eSSLErrorWaitReadable; | |
static VALUE eSSLErrorWaitWritable; | |
-#define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v)) | |
-#define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v)) | |
-#define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v)) | |
-#define ossl_sslctx_set_ca_file(o,v) rb_iv_set((o),"@ca_file",(v)) | |
-#define ossl_sslctx_set_ca_path(o,v) rb_iv_set((o),"@ca_path",(v)) | |
-#define ossl_sslctx_set_timeout(o,v) rb_iv_set((o),"@timeout",(v)) | |
-#define ossl_sslctx_set_verify_mode(o,v) rb_iv_set((o),"@verify_mode",(v)) | |
-#define ossl_sslctx_set_verify_dep(o,v) rb_iv_set((o),"@verify_depth",(v)) | |
-#define ossl_sslctx_set_verify_cb(o,v) rb_iv_set((o),"@verify_callback",(v)) | |
-#define ossl_sslctx_set_cert_store(o,v) rb_iv_set((o),"@cert_store",(v)) | |
-#define ossl_sslctx_set_extra_cert(o,v) rb_iv_set((o),"@extra_chain_cert",(v)) | |
-#define ossl_sslctx_set_client_cert_cb(o,v) rb_iv_set((o),"@client_cert_cb",(v)) | |
-#define ossl_sslctx_set_sess_id_ctx(o, v) rb_iv_set((o),"@session_id_context",(v)) | |
- | |
-#define ossl_sslctx_get_cert(o) rb_iv_get((o),"@cert") | |
-#define ossl_sslctx_get_key(o) rb_iv_get((o),"@key") | |
-#define ossl_sslctx_get_client_ca(o) rb_iv_get((o),"@client_ca") | |
-#define ossl_sslctx_get_ca_file(o) rb_iv_get((o),"@ca_file") | |
-#define ossl_sslctx_get_ca_path(o) rb_iv_get((o),"@ca_path") | |
-#define ossl_sslctx_get_timeout(o) rb_iv_get((o),"@timeout") | |
-#define ossl_sslctx_get_verify_mode(o) rb_iv_get((o),"@verify_mode") | |
-#define ossl_sslctx_get_verify_dep(o) rb_iv_get((o),"@verify_depth") | |
-#define ossl_sslctx_get_verify_cb(o) rb_iv_get((o),"@verify_callback") | |
-#define ossl_sslctx_get_cert_store(o) rb_iv_get((o),"@cert_store") | |
-#define ossl_sslctx_get_extra_cert(o) rb_iv_get((o),"@extra_chain_cert") | |
-#define ossl_sslctx_get_client_cert_cb(o) rb_iv_get((o),"@client_cert_cb") | |
-#define ossl_sslctx_get_tmp_ecdh_cb(o) rb_iv_get((o),"@tmp_ecdh_callback") | |
-#define ossl_sslctx_get_sess_id_ctx(o) rb_iv_get((o),"@session_id_context") | |
- | |
-#define ossl_ssl_get_io(o) rb_iv_get((o),"@io") | |
-#define ossl_ssl_get_ctx(o) rb_iv_get((o),"@context") | |
-#define ossl_ssl_get_x509(o) rb_iv_get((o),"@x509") | |
-#define ossl_ssl_get_key(o) rb_iv_get((o),"@key") | |
- | |
-#define ossl_ssl_set_x509(o,v) rb_iv_set((o),"@x509",(v)) | |
-#define ossl_ssl_set_key(o,v) rb_iv_set((o),"@key",(v)) | |
-#define ossl_ssl_set_tmp_dh(o,v) rb_iv_set((o),"@tmp_dh",(v)) | |
-#define ossl_ssl_set_tmp_ecdh(o,v) rb_iv_set((o),"@tmp_ecdh",(v)) | |
- | |
-static ID ID_callback_state; | |
- | |
+static ID 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; | |
+static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode, | |
+ id_i_verify_depth, id_i_verify_callback, id_i_client_ca, | |
+ id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert, | |
+ id_i_client_cert_cb, id_i_tmp_ecdh_callback, id_i_timeout, | |
+ id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb, | |
+ id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols, | |
+ id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb, | |
+ id_i_verify_hostname; | |
+static ID id_i_io, id_i_context, id_i_hostname; | |
+ | |
/* | |
* SSLContext class | |
*/ | |
static const struct { | |
const char *name; | |
- SSL_METHOD *(*func)(void); | |
+ SSL_METHOD *(*func)(void); /* FIXME: constify when dropping 0.9.8 */ | |
+ int version; | |
} ossl_ssl_method_tab[] = { | |
-#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method } | |
- OSSL_SSL_METHOD_ENTRY(TLSv1), | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_server), | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_client), | |
-#if defined(HAVE_TLSV1_2_METHOD) && defined(HAVE_TLSV1_2_SERVER_METHOD) && \ | |
- defined(HAVE_TLSV1_2_CLIENT_METHOD) | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_2), | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_2_server), | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_2_client), | |
+#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) | |
+#define OSSL_SSL_METHOD_ENTRY(name, version) \ | |
+ { #name, (SSL_METHOD *(*)(void))TLS_method, version }, \ | |
+ { #name"_server", (SSL_METHOD *(*)(void))TLS_server_method, version }, \ | |
+ { #name"_client", (SSL_METHOD *(*)(void))TLS_client_method, version } | |
+#else | |
+#define OSSL_SSL_METHOD_ENTRY(name, version) \ | |
+ { #name, (SSL_METHOD *(*)(void))name##_method, version }, \ | |
+ { #name"_server", (SSL_METHOD *(*)(void))name##_server_method, version }, \ | |
+ { #name"_client", (SSL_METHOD *(*)(void))name##_client_method, version } | |
#endif | |
-#if defined(HAVE_TLSV1_1_METHOD) && defined(HAVE_TLSV1_1_SERVER_METHOD) && \ | |
- defined(HAVE_TLSV1_1_CLIENT_METHOD) | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_1), | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_1_server), | |
- OSSL_SSL_METHOD_ENTRY(TLSv1_1_client), | |
+#if defined(HAVE_SSLV2_METHOD) | |
+ OSSL_SSL_METHOD_ENTRY(SSLv2, SSL2_VERSION), | |
#endif | |
-#if defined(HAVE_SSLV2_METHOD) && defined(HAVE_SSLV2_SERVER_METHOD) && \ | |
- defined(HAVE_SSLV2_CLIENT_METHOD) | |
- OSSL_SSL_METHOD_ENTRY(SSLv2), | |
- OSSL_SSL_METHOD_ENTRY(SSLv2_server), | |
- OSSL_SSL_METHOD_ENTRY(SSLv2_client), | |
+#if defined(HAVE_SSLV3_METHOD) | |
+ OSSL_SSL_METHOD_ENTRY(SSLv3, SSL3_VERSION), | |
#endif | |
-#if defined(HAVE_SSLV3_METHOD) && defined(HAVE_SSLV3_SERVER_METHOD) && \ | |
- defined(HAVE_SSLV3_CLIENT_METHOD) | |
- OSSL_SSL_METHOD_ENTRY(SSLv3), | |
- OSSL_SSL_METHOD_ENTRY(SSLv3_server), | |
- OSSL_SSL_METHOD_ENTRY(SSLv3_client), | |
+ OSSL_SSL_METHOD_ENTRY(TLSv1, TLS1_VERSION), | |
+#if defined(HAVE_TLSV1_1_METHOD) | |
+ OSSL_SSL_METHOD_ENTRY(TLSv1_1, TLS1_1_VERSION), | |
#endif | |
- OSSL_SSL_METHOD_ENTRY(SSLv23), | |
- OSSL_SSL_METHOD_ENTRY(SSLv23_server), | |
- OSSL_SSL_METHOD_ENTRY(SSLv23_client), | |
+#if defined(HAVE_TLSV1_2_METHOD) | |
+ OSSL_SSL_METHOD_ENTRY(TLSv1_2, TLS1_2_VERSION), | |
+#endif | |
+ OSSL_SSL_METHOD_ENTRY(SSLv23, 0), | |
#undef OSSL_SSL_METHOD_ENTRY | |
}; | |
@@ -128,8 +90,10 @@ static void | |
ossl_sslctx_free(void *ptr) | |
{ | |
SSL_CTX *ctx = ptr; | |
+#if !defined(HAVE_X509_STORE_UP_REF) | |
if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1) | |
ctx->cert_store = NULL; | |
+#endif | |
SSL_CTX_free(ctx); | |
} | |
@@ -145,7 +109,8 @@ static VALUE | |
ossl_sslctx_s_alloc(VALUE klass) | |
{ | |
SSL_CTX *ctx; | |
- long mode = SSL_MODE_ENABLE_PARTIAL_WRITE; | |
+ long mode = SSL_MODE_ENABLE_PARTIAL_WRITE | | |
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; | |
VALUE obj; | |
#ifdef SSL_MODE_RELEASE_BUFFERS | |
@@ -161,6 +126,18 @@ ossl_sslctx_s_alloc(VALUE klass) | |
RTYPEDDATA_DATA(obj) = ctx; | |
SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)obj); | |
+#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_ECDH_AUTO) | |
+ /* We use SSL_CTX_set1_curves_list() to specify the curve used in ECDH. It | |
+ * allows to specify multiple curve names and OpenSSL will select | |
+ * automatically from them. In OpenSSL 1.0.2, the automatic selection has to | |
+ * be enabled explicitly. But OpenSSL 1.1.0 removed the knob and it is | |
+ * always enabled. To uniform the behavior, we enable the automatic | |
+ * selection also in 1.0.2. Users can still disable ECDH by removing ECDH | |
+ * cipher suites by SSLContext#ciphers=. */ | |
+ if (!SSL_CTX_set_ecdh_auto(ctx, 1)) | |
+ ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto"); | |
+#endif | |
+ | |
return obj; | |
} | |
@@ -169,146 +146,212 @@ ossl_sslctx_s_alloc(VALUE klass) | |
* ctx.ssl_version = :TLSv1 | |
* ctx.ssl_version = "SSLv23_client" | |
* | |
+ * Sets the SSL/TLS protocol version for the context. This forces connections to | |
+ * use only the specified protocol version. | |
+ * | |
* You can get a list of valid versions with OpenSSL::SSL::SSLContext::METHODS | |
*/ | |
static VALUE | |
ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method) | |
{ | |
- SSL_METHOD *method = NULL; | |
+ SSL_CTX *ctx; | |
const char *s; | |
VALUE m = ssl_method; | |
int i; | |
- SSL_CTX *ctx; | |
+ GetSSLCTX(self, ctx); | |
if (RB_TYPE_P(ssl_method, T_SYMBOL)) | |
m = rb_sym2str(ssl_method); | |
s = StringValueCStr(m); | |
for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { | |
if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) { | |
- method = ossl_ssl_method_tab[i].func(); | |
- break; | |
+#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) | |
+ int version = ossl_ssl_method_tab[i].version; | |
+#endif | |
+ SSL_METHOD *method = ossl_ssl_method_tab[i].func(); | |
+ | |
+ if (SSL_CTX_set_ssl_version(ctx, method) != 1) | |
+ ossl_raise(eSSLError, "SSL_CTX_set_ssl_version"); | |
+ | |
+#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) | |
+ if (!SSL_CTX_set_min_proto_version(ctx, version)) | |
+ ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version"); | |
+ if (!SSL_CTX_set_max_proto_version(ctx, version)) | |
+ ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version"); | |
+#endif | |
+ return ssl_method; | |
} | |
} | |
- if (!method) { | |
- ossl_raise(rb_eArgError, "unknown SSL method `%"PRIsVALUE"'.", m); | |
- } | |
- GetSSLCTX(self, ctx); | |
- if (SSL_CTX_set_ssl_version(ctx, method) != 1) { | |
- ossl_raise(eSSLError, "SSL_CTX_set_ssl_version"); | |
- } | |
- return ssl_method; | |
+ ossl_raise(rb_eArgError, "unknown SSL method `%"PRIsVALUE"'.", m); | |
} | |
static VALUE | |
ossl_call_client_cert_cb(VALUE obj) | |
{ | |
- VALUE cb, ary, cert, key; | |
+ VALUE ctx_obj, cb, ary, cert, key; | |
+ | |
+ ctx_obj = rb_attr_get(obj, id_i_context); | |
+ cb = rb_attr_get(ctx_obj, id_i_client_cert_cb); | |
+ if (NIL_P(cb)) | |
+ return Qnil; | |
- cb = rb_funcall(obj, rb_intern("client_cert_cb"), 0); | |
- if (NIL_P(cb)) return Qfalse; | |
ary = rb_funcall(cb, rb_intern("call"), 1, obj); | |
Check_Type(ary, T_ARRAY); | |
GetX509CertPtr(cert = rb_ary_entry(ary, 0)); | |
- GetPKeyPtr(key = rb_ary_entry(ary, 1)); | |
- ossl_ssl_set_x509(obj, cert); | |
- ossl_ssl_set_key(obj, key); | |
+ GetPrivPKeyPtr(key = rb_ary_entry(ary, 1)); | |
- return Qtrue; | |
+ return rb_ary_new3(2, cert, key); | |
} | |
static int | |
ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) | |
{ | |
- VALUE obj, success; | |
+ VALUE obj, ret; | |
obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); | |
- success = rb_protect(ossl_call_client_cert_cb, obj, NULL); | |
- if (!RTEST(success)) return 0; | |
- *x509 = DupX509CertPtr(ossl_ssl_get_x509(obj)); | |
- *pkey = DupPKeyPtr(ossl_ssl_get_key(obj)); | |
+ ret = rb_protect(ossl_call_client_cert_cb, obj, NULL); | |
+ if (NIL_P(ret)) | |
+ return 0; | |
+ | |
+ *x509 = DupX509CertPtr(RARRAY_AREF(ret, 0)); | |
+ *pkey = DupPKeyPtr(RARRAY_AREF(ret, 1)); | |
return 1; | |
} | |
-#if !defined(OPENSSL_NO_DH) | |
-static VALUE | |
-ossl_call_tmp_dh_callback(VALUE args) | |
+#if !defined(OPENSSL_NO_DH) || \ | |
+ !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK) | |
+struct tmp_dh_callback_args { | |
+ VALUE ssl_obj; | |
+ ID id; | |
+ int type; | |
+ int is_export; | |
+ int keylength; | |
+}; | |
+ | |
+static EVP_PKEY * | |
+ossl_call_tmp_dh_callback(struct tmp_dh_callback_args *args) | |
{ | |
VALUE cb, dh; | |
EVP_PKEY *pkey; | |
- cb = rb_funcall(rb_ary_entry(args, 0), rb_intern("tmp_dh_callback"), 0); | |
- | |
- if (NIL_P(cb)) return Qfalse; | |
- dh = rb_apply(cb, rb_intern("call"), 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)); | |
pkey = GetPKeyPtr(dh); | |
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) return Qfalse; | |
+ if (EVP_PKEY_base_id(pkey) != args->type) | |
+ return NULL; | |
- return dh; | |
+ return pkey; | |
} | |
+#endif | |
-static DH* | |
+#if !defined(OPENSSL_NO_DH) | |
+static DH * | |
ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength) | |
{ | |
- VALUE args, dh, rb_ssl; | |
+ VALUE rb_ssl; | |
+ EVP_PKEY *pkey; | |
+ struct tmp_dh_callback_args args; | |
+ int state; | |
rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); | |
+ args.ssl_obj = rb_ssl; | |
+ args.id = id_tmp_dh_callback; | |
+ args.is_export = is_export; | |
+ args.keylength = keylength; | |
+ args.type = EVP_PKEY_DH; | |
+ | |
+ pkey = (EVP_PKEY *)rb_protect((VALUE (*)(VALUE))ossl_call_tmp_dh_callback, | |
+ (VALUE)&args, &state); | |
+ if (state) { | |
+ rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state)); | |
+ return NULL; | |
+ } | |
+ if (!pkey) | |
+ return NULL; | |
- args = rb_ary_new_from_args(3, rb_ssl, INT2FIX(is_export), INT2FIX(keylength)); | |
- | |
- dh = rb_protect(ossl_call_tmp_dh_callback, args, NULL); | |
- if (!RTEST(dh)) return NULL; | |
- ossl_ssl_set_tmp_dh(rb_ssl, dh); | |
- | |
- return GetPKeyPtr(dh)->pkey.dh; | |
+ return EVP_PKEY_get0_DH(pkey); | |
} | |
#endif /* OPENSSL_NO_DH */ | |
-#if !defined(OPENSSL_NO_EC) | |
-static VALUE | |
-ossl_call_tmp_ecdh_callback(VALUE args) | |
+#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK) | |
+static EC_KEY * | |
+ossl_tmp_ecdh_callback(SSL *ssl, int is_export, int keylength) | |
{ | |
- VALUE cb, ecdh; | |
+ VALUE rb_ssl; | |
EVP_PKEY *pkey; | |
+ struct tmp_dh_callback_args args; | |
+ int state; | |
- cb = rb_funcall(rb_ary_entry(args, 0), rb_intern("tmp_ecdh_callback"), 0); | |
- | |
- if (NIL_P(cb)) return Qfalse; | |
- ecdh = rb_apply(cb, rb_intern("call"), args); | |
- pkey = GetPKeyPtr(ecdh); | |
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) return Qfalse; | |
+ rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); | |
+ args.ssl_obj = rb_ssl; | |
+ args.id = id_tmp_ecdh_callback; | |
+ args.is_export = is_export; | |
+ args.keylength = keylength; | |
+ args.type = EVP_PKEY_EC; | |
+ | |
+ pkey = (EVP_PKEY *)rb_protect((VALUE (*)(VALUE))ossl_call_tmp_dh_callback, | |
+ (VALUE)&args, &state); | |
+ if (state) { | |
+ rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state)); | |
+ return NULL; | |
+ } | |
+ if (!pkey) | |
+ return NULL; | |
- return ecdh; | |
+ return EVP_PKEY_get0_EC_KEY(pkey); | |
} | |
+#endif | |
-static EC_KEY* | |
-ossl_tmp_ecdh_callback(SSL *ssl, int is_export, int keylength) | |
+static VALUE | |
+call_verify_certificate_identity(VALUE ctx_v) | |
{ | |
- VALUE args, ecdh, rb_ssl; | |
- | |
- rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); | |
+ X509_STORE_CTX *ctx = (X509_STORE_CTX *)ctx_v; | |
+ SSL *ssl; | |
+ VALUE ssl_obj, hostname, cert_obj; | |
- args = rb_ary_new_from_args(3, rb_ssl, INT2FIX(is_export), INT2FIX(keylength)); | |
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); | |
+ ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); | |
+ hostname = rb_attr_get(ssl_obj, id_i_hostname); | |
- ecdh = rb_protect(ossl_call_tmp_ecdh_callback, args, NULL); | |
- if (!RTEST(ecdh)) return NULL; | |
- ossl_ssl_set_tmp_ecdh(rb_ssl, ecdh); | |
+ if (!RTEST(hostname)) { | |
+ rb_warning("verify_hostname requires hostname to be set"); | |
+ return Qtrue; | |
+ } | |
- return GetPKeyPtr(ecdh)->pkey.ec; | |
+ cert_obj = ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx)); | |
+ return rb_funcall(mSSL, rb_intern("verify_certificate_identity"), 2, | |
+ cert_obj, hostname); | |
} | |
-#endif | |
static int | |
ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) | |
{ | |
- VALUE cb; | |
+ VALUE cb, ssl_obj, sslctx_obj, verify_hostname, ret; | |
SSL *ssl; | |
+ int status; | |
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); | |
cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx); | |
- X509_STORE_CTX_set_ex_data(ctx, ossl_store_ctx_ex_verify_cb_idx, (void *)cb); | |
- return ossl_verify_cb(preverify_ok, ctx); | |
+ ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); | |
+ sslctx_obj = rb_attr_get(ssl_obj, id_i_context); | |
+ verify_hostname = rb_attr_get(sslctx_obj, id_i_verify_hostname); | |
+ | |
+ if (preverify_ok && RTEST(verify_hostname) && !SSL_is_server(ssl) && | |
+ !X509_STORE_CTX_get_error_depth(ctx)) { | |
+ ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status); | |
+ if (status) { | |
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status)); | |
+ return 0; | |
+ } | |
+ preverify_ok = ret == Qtrue; | |
+ } | |
+ | |
+ return ossl_verify_cb_call(cb, preverify_ok, ctx); | |
} | |
static VALUE | |
@@ -327,7 +370,11 @@ ossl_call_session_get_cb(VALUE 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) | |
+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) | |
+#endif | |
{ | |
VALUE ary, ssl_obj, ret_obj; | |
SSL_SESSION *sess; | |
@@ -384,7 +431,7 @@ ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess) | |
return 1; | |
ssl_obj = (VALUE)ptr; | |
sess_obj = rb_obj_alloc(cSSLSession); | |
- CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); | |
+ SSL_SESSION_up_ref(sess); | |
DATA_PTR(sess_obj) = sess; | |
ary = rb_ary_new2(2); | |
@@ -414,7 +461,7 @@ ossl_call_session_remove_cb(VALUE ary) | |
Check_Type(ary, T_ARRAY); | |
sslctx_obj = rb_ary_entry(ary, 0); | |
- cb = rb_iv_get(sslctx_obj, "@session_remove_cb"); | |
+ 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); | |
@@ -427,27 +474,20 @@ ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) | |
void *ptr; | |
int state = 0; | |
- /* | |
- * This callback is also called for all sessions in the internal store | |
- * when SSL_CTX_free() is called. | |
- */ | |
- if (rb_during_gc()) | |
- return; | |
- | |
OSSL_Debug("SSL SESSION remove callback entered"); | |
if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL) | |
return; | |
sslctx_obj = (VALUE)ptr; | |
sess_obj = rb_obj_alloc(cSSLSession); | |
- CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); | |
+ SSL_SESSION_up_ref(sess); | |
DATA_PTR(sess_obj) = sess; | |
ary = rb_ary_new2(2); | |
rb_ary_push(ary, sslctx_obj); | |
rb_ary_push(ary, sess_obj); | |
- rb_protect((VALUE(*)_((VALUE)))ossl_call_session_remove_cb, ary, &state); | |
+ rb_protect(ossl_call_session_remove_cb, ary, &state); | |
if (state) { | |
/* | |
the SSL_CTX is frozen, nowhere to save state. | |
@@ -483,9 +523,8 @@ ossl_call_servername_cb(VALUE ary) | |
Check_Type(ary, T_ARRAY); | |
ssl_obj = rb_ary_entry(ary, 0); | |
- sslctx_obj = rb_iv_get(ssl_obj, "@context"); | |
- if (NIL_P(sslctx_obj)) return Qnil; | |
- cb = rb_iv_get(sslctx_obj, "@servername_cb"); | |
+ sslctx_obj = rb_attr_get(ssl_obj, id_i_context); | |
+ 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); | |
@@ -497,9 +536,10 @@ ossl_call_servername_cb(VALUE ary) | |
GetSSL(ssl_obj, ssl); | |
GetSSLCTX(ret_obj, ctx2); | |
SSL_set_SSL_CTX(ssl, ctx2); | |
- rb_iv_set(ssl_obj, "@context", ret_obj); | |
+ rb_ivar_set(ssl_obj, id_i_context, ret_obj); | |
} else if (!NIL_P(ret_obj)) { | |
- ossl_raise(rb_eArgError, "servername_cb must return an OpenSSL::SSL::SSLContext object or nil"); | |
+ ossl_raise(rb_eArgError, "servername_cb must return an " | |
+ "OpenSSL::SSL::SSLContext object or nil"); | |
} | |
return ret_obj; | |
@@ -523,7 +563,7 @@ ssl_servername_cb(SSL *ssl, int *ad, void *arg) | |
rb_ary_push(ary, ssl_obj); | |
rb_ary_push(ary, rb_str_new2(servername)); | |
- rb_protect((VALUE(*)_((VALUE)))ossl_call_servername_cb, ary, &state); | |
+ rb_protect(ossl_call_servername_cb, ary, &state); | |
if (state) { | |
rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); | |
return SSL_TLSEXT_ERR_ALERT_FATAL; | |
@@ -543,15 +583,15 @@ ssl_renegotiation_cb(const SSL *ssl) | |
ossl_raise(eSSLError, "SSL object could not be retrieved"); | |
ssl_obj = (VALUE)ptr; | |
- sslctx_obj = rb_iv_get(ssl_obj, "@context"); | |
- if (NIL_P(sslctx_obj)) return; | |
- cb = rb_iv_get(sslctx_obj, "@renegotiation_cb"); | |
+ sslctx_obj = rb_attr_get(ssl_obj, id_i_context); | |
+ 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); | |
} | |
-#if defined(HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB) || defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) | |
+#if defined(HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB) || \ | |
+ defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) | |
static VALUE | |
ssl_npn_encode_protocol_i(VALUE cur, VALUE encoded) | |
{ | |
@@ -569,20 +609,25 @@ ssl_npn_encode_protocol_i(VALUE cur, VALUE encoded) | |
static VALUE | |
ssl_encode_npn_protocols(VALUE protocols) | |
{ | |
- VALUE encoded = rb_str_new2(""); | |
+ VALUE encoded = rb_str_new(NULL, 0); | |
rb_iterate(rb_each, protocols, ssl_npn_encode_protocol_i, encoded); | |
- StringValueCStr(encoded); | |
return encoded; | |
} | |
-static int | |
-ssl_npn_select_cb_common(VALUE cb, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen) | |
+struct npn_select_cb_common_args { | |
+ VALUE cb; | |
+ const unsigned char *in; | |
+ unsigned inlen; | |
+}; | |
+ | |
+static VALUE | |
+npn_select_cb_common_i(VALUE tmp) | |
{ | |
- VALUE selected; | |
- long len; | |
- VALUE protocols = rb_ary_new(); | |
+ struct npn_select_cb_common_args *args = (void *)tmp; | |
+ const unsigned char *in = args->in, *in_end = in + args->inlen; | |
unsigned char l; | |
- const unsigned char *in_end = in + inlen; | |
+ long len; | |
+ VALUE selected, protocols = rb_ary_new(); | |
/* assume OpenSSL verifies this format */ | |
/* The format is len_1|proto_1|...|len_n|proto_n */ | |
@@ -592,24 +637,50 @@ ssl_npn_select_cb_common(VALUE cb, const unsigned char **out, unsigned char *out | |
in += l; | |
} | |
- selected = rb_funcall(cb, rb_intern("call"), 1, protocols); | |
+ selected = rb_funcall(args->cb, rb_intern("call"), 1, protocols); | |
StringValue(selected); | |
len = RSTRING_LEN(selected); | |
if (len < 1 || len >= 256) { | |
ossl_raise(eSSLError, "Selected protocol name must have length 1..255"); | |
} | |
+ | |
+ return selected; | |
+} | |
+ | |
+static int | |
+ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out, | |
+ unsigned char *outlen, const unsigned char *in, | |
+ unsigned int inlen) | |
+{ | |
+ VALUE selected; | |
+ int status; | |
+ struct npn_select_cb_common_args args; | |
+ | |
+ args.cb = cb; | |
+ args.in = in; | |
+ args.inlen = inlen; | |
+ | |
+ selected = rb_protect(npn_select_cb_common_i, (VALUE)&args, &status); | |
+ if (status) { | |
+ VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); | |
+ | |
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status)); | |
+ return SSL_TLSEXT_ERR_ALERT_FATAL; | |
+ } | |
+ | |
*out = (unsigned char *)RSTRING_PTR(selected); | |
- *outlen = (unsigned char)len; | |
+ *outlen = (unsigned char)RSTRING_LEN(selected); | |
return SSL_TLSEXT_ERR_OK; | |
} | |
+#endif | |
#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB | |
static int | |
-ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) | |
+ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen, | |
+ void *arg) | |
{ | |
- VALUE sslctx_obj = (VALUE) arg; | |
- VALUE protocols = rb_iv_get(sslctx_obj, "@_protocols"); | |
+ VALUE protocols = (VALUE)arg; | |
*out = (const unsigned char *) RSTRING_PTR(protocols); | |
*outlen = RSTRING_LENINT(protocols); | |
@@ -618,40 +689,40 @@ ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen, | |
} | |
static int | |
-ssl_npn_select_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) | |
+ssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen, | |
+ const unsigned char *in, unsigned int inlen, void *arg) | |
{ | |
VALUE sslctx_obj, cb; | |
sslctx_obj = (VALUE) arg; | |
- cb = rb_iv_get(sslctx_obj, "@npn_select_cb"); | |
+ cb = rb_attr_get(sslctx_obj, id_i_npn_select_cb); | |
- return ssl_npn_select_cb_common(cb, (const unsigned char **)out, outlen, in, inlen); | |
+ return ssl_npn_select_cb_common(ssl, cb, (const unsigned char **)out, | |
+ outlen, in, inlen); | |
} | |
#endif | |
#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB | |
static int | |
-ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) | |
+ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, | |
+ const unsigned char *in, unsigned int inlen, void *arg) | |
{ | |
VALUE sslctx_obj, cb; | |
sslctx_obj = (VALUE) arg; | |
- cb = rb_iv_get(sslctx_obj, "@alpn_select_cb"); | |
+ cb = rb_attr_get(sslctx_obj, id_i_alpn_select_cb); | |
- return ssl_npn_select_cb_common(cb, out, outlen, in, inlen); | |
+ return ssl_npn_select_cb_common(ssl, cb, out, outlen, in, inlen); | |
} | |
#endif | |
-#endif /* HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB || HAVE_SSL_CTX_SET_ALPN_SELECT_CB */ | |
-/* This function may serve as the entry point to support further | |
- * callbacks. */ | |
+/* This function may serve as the entry point to support further callbacks. */ | |
static void | |
ssl_info_cb(const SSL *ssl, int where, int val) | |
{ | |
- int state = SSL_state(ssl); | |
+ int is_server = SSL_is_server((SSL *)ssl); | |
- if ((where & SSL_CB_HANDSHAKE_START) && | |
- (state & SSL_ST_ACCEPT)) { | |
+ if (is_server && where & SSL_CB_HANDSHAKE_START) { | |
ssl_renegotiation_cb(ssl); | |
} | |
} | |
@@ -703,7 +774,6 @@ ossl_sslctx_setup(VALUE self) | |
{ | |
SSL_CTX *ctx; | |
X509 *cert = NULL, *client_ca = NULL; | |
- X509_STORE *store; | |
EVP_PKEY *key = NULL; | |
char *ca_path = NULL, *ca_file = NULL; | |
int verify_mode; | |
@@ -718,34 +788,52 @@ ossl_sslctx_setup(VALUE self) | |
#endif | |
#if !defined(OPENSSL_NO_EC) | |
- if (RTEST(ossl_sslctx_get_tmp_ecdh_cb(self))){ | |
+ /* We added SSLContext#tmp_ecdh_callback= in Ruby 2.3.0, | |
+ * but SSL_CTX_set_tmp_ecdh_callback() was removed in OpenSSL 1.1.0. */ | |
+ if (RTEST(rb_attr_get(self, id_i_tmp_ecdh_callback))) { | |
+# if defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK) | |
+ rb_warn("#tmp_ecdh_callback= is deprecated; use #ecdh_curves= instead"); | |
SSL_CTX_set_tmp_ecdh_callback(ctx, ossl_tmp_ecdh_callback); | |
+# if defined(HAVE_SSL_CTX_SET_ECDH_AUTO) | |
+ /* tmp_ecdh_callback and ecdh_auto conflict; OpenSSL ignores | |
+ * tmp_ecdh_callback. So disable ecdh_auto. */ | |
+ if (!SSL_CTX_set_ecdh_auto(ctx, 0)) | |
+ ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto"); | |
+# endif | |
+# else | |
+ ossl_raise(eSSLError, "OpenSSL does not support tmp_ecdh_callback; " | |
+ "use #ecdh_curves= instead"); | |
+# endif | |
} | |
-#endif | |
+#endif /* OPENSSL_NO_EC */ | |
- val = ossl_sslctx_get_cert_store(self); | |
- if(!NIL_P(val)){ | |
+ val = rb_attr_get(self, id_i_cert_store); | |
+ if (!NIL_P(val)) { | |
+ X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */ | |
+ SSL_CTX_set_cert_store(ctx, store); | |
+#if !defined(HAVE_X509_STORE_UP_REF) | |
/* | |
* WORKAROUND: | |
* X509_STORE can count references, but | |
* X509_STORE_free() doesn't care it. | |
* So we won't increment it but mark it by ex_data. | |
*/ | |
- store = GetX509StorePtr(val); /* NO NEED TO DUP */ | |
- SSL_CTX_set_cert_store(ctx, store); | |
- SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); | |
+ SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void *)1); | |
+#else /* Fixed in OpenSSL 1.0.2; bff9ce4db38b (master), 5b4b9ce976fc (1.0.2) */ | |
+ X509_STORE_up_ref(store); | |
+#endif | |
} | |
- val = ossl_sslctx_get_extra_cert(self); | |
+ val = rb_attr_get(self, id_i_extra_chain_cert); | |
if(!NIL_P(val)){ | |
rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); | |
} | |
/* private key may be bundled in certificate file. */ | |
- val = ossl_sslctx_get_cert(self); | |
+ val = rb_attr_get(self, id_i_cert); | |
cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ | |
- val = ossl_sslctx_get_key(self); | |
- key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ | |
+ val = rb_attr_get(self, id_i_key); | |
+ key = NIL_P(val) ? NULL : GetPrivPKeyPtr(val); /* NO DUP NEEDED */ | |
if (cert && key) { | |
if (!SSL_CTX_use_certificate(ctx, cert)) { | |
/* Adds a ref => Safe to FREE */ | |
@@ -760,7 +848,7 @@ ossl_sslctx_setup(VALUE self) | |
} | |
} | |
- val = ossl_sslctx_get_client_ca(self); | |
+ val = rb_attr_get(self, id_i_client_ca); | |
if(!NIL_P(val)){ | |
if (RB_TYPE_P(val, T_ARRAY)) { | |
for(i = 0; i < RARRAY_LEN(val); i++){ | |
@@ -780,48 +868,53 @@ ossl_sslctx_setup(VALUE self) | |
} | |
} | |
- val = ossl_sslctx_get_ca_file(self); | |
- ca_file = NIL_P(val) ? NULL : StringValuePtr(val); | |
- val = ossl_sslctx_get_ca_path(self); | |
- ca_path = NIL_P(val) ? NULL : StringValuePtr(val); | |
+ val = rb_attr_get(self, id_i_ca_file); | |
+ ca_file = NIL_P(val) ? NULL : StringValueCStr(val); | |
+ val = rb_attr_get(self, id_i_ca_path); | |
+ ca_path = NIL_P(val) ? NULL : StringValueCStr(val); | |
if(ca_file || ca_path){ | |
if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) | |
rb_warning("can't set verify locations"); | |
} | |
- val = ossl_sslctx_get_verify_mode(self); | |
+ val = rb_attr_get(self, id_i_verify_mode); | |
verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val); | |
SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback); | |
- if (RTEST(ossl_sslctx_get_client_cert_cb(self))) | |
+ if (RTEST(rb_attr_get(self, id_i_client_cert_cb))) | |
SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); | |
- val = ossl_sslctx_get_timeout(self); | |
+ val = rb_attr_get(self, id_i_timeout); | |
if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val)); | |
- val = ossl_sslctx_get_verify_dep(self); | |
+ val = rb_attr_get(self, id_i_verify_depth); | |
if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val)); | |
#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB | |
- val = rb_iv_get(self, "@npn_protocols"); | |
+ val = rb_attr_get(self, id_i_npn_protocols); | |
if (!NIL_P(val)) { | |
- rb_iv_set(self, "@_protocols", ssl_encode_npn_protocols(val)); | |
- SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *) self); | |
+ VALUE encoded = ssl_encode_npn_protocols(val); | |
+ rb_ivar_set(self, id_npn_protocols_encoded, encoded); | |
+ SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)encoded); | |
OSSL_Debug("SSL NPN advertise callback added"); | |
} | |
- if (RTEST(rb_iv_get(self, "@npn_select_cb"))) { | |
+ if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) { | |
SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self); | |
OSSL_Debug("SSL NPN select callback added"); | |
} | |
#endif | |
#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB | |
- val = rb_iv_get(self, "@alpn_protocols"); | |
+ val = rb_attr_get(self, id_i_alpn_protocols); | |
if (!NIL_P(val)) { | |
VALUE rprotos = ssl_encode_npn_protocols(val); | |
- SSL_CTX_set_alpn_protos(ctx, (const unsigned char *)StringValueCStr(rprotos), RSTRING_LENINT(rprotos)); | |
+ | |
+ /* returns 0 on success */ | |
+ if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos), | |
+ RSTRING_LENINT(rprotos))) | |
+ ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos"); | |
OSSL_Debug("SSL ALPN values added"); | |
} | |
- if (RTEST(rb_iv_get(self, "@alpn_select_cb"))) { | |
+ if (RTEST(rb_attr_get(self, id_i_alpn_select_cb))) { | |
SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self); | |
OSSL_Debug("SSL ALPN select callback added"); | |
} | |
@@ -829,7 +922,7 @@ ossl_sslctx_setup(VALUE self) | |
rb_obj_freeze(self); | |
- val = ossl_sslctx_get_sess_id_ctx(self); | |
+ val = rb_attr_get(self, id_i_session_id_context); | |
if (!NIL_P(val)){ | |
StringValue(val); | |
if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val), | |
@@ -838,21 +931,21 @@ ossl_sslctx_setup(VALUE self) | |
} | |
} | |
- if (RTEST(rb_iv_get(self, "@session_get_cb"))) { | |
+ if (RTEST(rb_attr_get(self, id_i_session_get_cb))) { | |
SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); | |
OSSL_Debug("SSL SESSION get callback added"); | |
} | |
- if (RTEST(rb_iv_get(self, "@session_new_cb"))) { | |
+ if (RTEST(rb_attr_get(self, id_i_session_new_cb))) { | |
SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); | |
OSSL_Debug("SSL SESSION new callback added"); | |
} | |
- if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { | |
+ if (RTEST(rb_attr_get(self, id_i_session_remove_cb))) { | |
SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); | |
OSSL_Debug("SSL SESSION remove callback added"); | |
} | |
#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME | |
- val = rb_iv_get(self, "@servername_cb"); | |
+ val = rb_attr_get(self, id_i_servername_cb); | |
if (!NIL_P(val)) { | |
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); | |
OSSL_Debug("SSL TLSEXT servername callback added"); | |
@@ -863,7 +956,7 @@ ossl_sslctx_setup(VALUE self) | |
} | |
static VALUE | |
-ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) | |
+ossl_ssl_cipher_to_ary(const SSL_CIPHER *cipher) | |
{ | |
VALUE ary; | |
int bits, alg_bits; | |
@@ -872,8 +965,8 @@ ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) | |
rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher))); | |
rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher))); | |
bits = SSL_CIPHER_get_bits(cipher, &alg_bits); | |
- rb_ary_push(ary, INT2FIX(bits)); | |
- rb_ary_push(ary, INT2FIX(alg_bits)); | |
+ rb_ary_push(ary, INT2NUM(bits)); | |
+ rb_ary_push(ary, INT2NUM(alg_bits)); | |
return ary; | |
} | |
@@ -882,14 +975,14 @@ ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) | |
* call-seq: | |
* ctx.ciphers => [[name, version, bits, alg_bits], ...] | |
* | |
- * The list of ciphers configured for this context. | |
+ * The list of cipher suites configured for this context. | |
*/ | |
static VALUE | |
ossl_sslctx_get_ciphers(VALUE self) | |
{ | |
SSL_CTX *ctx; | |
STACK_OF(SSL_CIPHER) *ciphers; | |
- SSL_CIPHER *cipher; | |
+ const SSL_CIPHER *cipher; | |
VALUE ary; | |
int i, num; | |
@@ -898,7 +991,7 @@ ossl_sslctx_get_ciphers(VALUE self) | |
rb_warning("SSL_CTX is not initialized."); | |
return Qnil; | |
} | |
- ciphers = ctx->cipher_list; | |
+ ciphers = SSL_CTX_get_ciphers(ctx); | |
if (!ciphers) | |
return rb_ary_new(); | |
@@ -918,11 +1011,9 @@ ossl_sslctx_get_ciphers(VALUE self) | |
* ctx.ciphers = [name, ...] | |
* ctx.ciphers = [[name, version, bits, alg_bits], ...] | |
* | |
- * Sets the list of available ciphers for this context. Note in a server | |
+ * Sets the list of available cipher suites for this context. Note in a server | |
* context some ciphers require the appropriate certificates. For example, an | |
- * RSA cipher can only be chosen when an RSA certificate is available. | |
- * | |
- * See also OpenSSL::Cipher and OpenSSL::Cipher::ciphers | |
+ * RSA cipher suite can only be chosen when an RSA certificate is available. | |
*/ | |
static VALUE | |
ossl_sslctx_set_ciphers(VALUE self, VALUE v) | |
@@ -953,18 +1044,165 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) | |
ossl_raise(eSSLError, "SSL_CTX is not initialized."); | |
return Qnil; | |
} | |
- if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) { | |
+ if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) { | |
ossl_raise(eSSLError, "SSL_CTX_set_cipher_list"); | |
} | |
return v; | |
} | |
+#if !defined(OPENSSL_NO_EC) | |
+/* | |
+ * call-seq: | |
+ * ctx.ecdh_curves = curve_list -> curve_list | |
+ * | |
+ * Sets the list of "supported elliptic curves" for this context. | |
+ * | |
+ * For a TLS client, the list is directly used in the Supported Elliptic Curves | |
+ * Extension. For a server, the list is used by OpenSSL to determine the set of | |
+ * shared curves. OpenSSL will pick the most appropriate one from it. | |
+ * | |
+ * Note that this works differently with old OpenSSL (<= 1.0.1). Only one curve | |
+ * can be set, and this has no effect for TLS clients. | |
+ * | |
+ * === Example | |
+ * ctx1 = OpenSSL::SSL::SSLContext.new | |
+ * ctx1.ecdh_curves = "X25519:P-256:P-224" | |
+ * svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1) | |
+ * Thread.new { svr.accept } | |
+ * | |
+ * ctx2 = OpenSSL::SSL::SSLContext.new | |
+ * ctx2.ecdh_curves = "P-256" | |
+ * cli = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx2) | |
+ * cli.connect | |
+ * | |
+ * p cli.tmp_key.group.curve_name | |
+ * # => "prime256v1" (is an alias for NIST P-256) | |
+ */ | |
+static VALUE | |
+ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg) | |
+{ | |
+ SSL_CTX *ctx; | |
+ | |
+ rb_check_frozen(self); | |
+ GetSSLCTX(self, ctx); | |
+ StringValueCStr(arg); | |
+ | |
+#if defined(HAVE_SSL_CTX_SET1_CURVES_LIST) | |
+ if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg))) | |
+ ossl_raise(eSSLError, NULL); | |
+#else | |
+ /* OpenSSL does not have SSL_CTX_set1_curves_list()... Fallback to | |
+ * SSL_CTX_set_tmp_ecdh(). So only the first curve is used. */ | |
+ { | |
+ VALUE curve, splitted; | |
+ EC_KEY *ec; | |
+ int nid; | |
+ | |
+ splitted = rb_str_split(arg, ":"); | |
+ if (!RARRAY_LEN(splitted)) | |
+ ossl_raise(eSSLError, "invalid input format"); | |
+ curve = RARRAY_AREF(splitted, 0); | |
+ StringValueCStr(curve); | |
+ | |
+ /* SSL_CTX_set1_curves_list() accepts NIST names */ | |
+ nid = EC_curve_nist2nid(RSTRING_PTR(curve)); | |
+ if (nid == NID_undef) | |
+ nid = OBJ_txt2nid(RSTRING_PTR(curve)); | |
+ if (nid == NID_undef) | |
+ ossl_raise(eSSLError, "unknown curve name"); | |
+ | |
+ ec = EC_KEY_new_by_curve_name(nid); | |
+ if (!ec) | |
+ ossl_raise(eSSLError, NULL); | |
+ EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); | |
+ if (!SSL_CTX_set_tmp_ecdh(ctx, ec)) { | |
+ EC_KEY_free(ec); | |
+ ossl_raise(eSSLError, "SSL_CTX_set_tmp_ecdh"); | |
+ } | |
+ EC_KEY_free(ec); | |
+# if defined(HAVE_SSL_CTX_SET_ECDH_AUTO) | |
+ /* tmp_ecdh and ecdh_auto conflict. tmp_ecdh is ignored when ecdh_auto | |
+ * is enabled. So disable ecdh_auto. */ | |
+ if (!SSL_CTX_set_ecdh_auto(ctx, 0)) | |
+ ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto"); | |
+# endif | |
+ } | |
+#endif | |
+ | |
+ return arg; | |
+} | |
+#else | |
+#define ossl_sslctx_set_ecdh_curves rb_f_notimplement | |
+#endif | |
+ | |
+/* | |
+ * call-seq: | |
+ * ctx.security_level -> Integer | |
+ * | |
+ * Returns the security level for the context. | |
+ * | |
+ * See also OpenSSL::SSL::SSLContext#security_level=. | |
+ */ | |
+static VALUE | |
+ossl_sslctx_get_security_level(VALUE self) | |
+{ | |
+ SSL_CTX *ctx; | |
+ | |
+ GetSSLCTX(self, ctx); | |
+ | |
+#if defined(HAVE_SSL_CTX_GET_SECURITY_LEVEL) | |
+ return INT2NUM(SSL_CTX_get_security_level(ctx)); | |
+#else | |
+ (void)ctx; | |
+ return INT2FIX(0); | |
+#endif | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * ctx.security_level = integer | |
+ * | |
+ * Sets the security level for the context. OpenSSL limits parameters according | |
+ * to the level. The "parameters" include: ciphersuites, curves, key sizes, | |
+ * certificate signature algorithms, protocol version and so on. For example, | |
+ * level 1 rejects parameters offering below 80 bits of security, such as | |
+ * ciphersuites using MD5 for the MAC or RSA keys shorter than 1024 bits. | |
+ * | |
+ * Note that attempts to set such parameters with insufficient security are | |
+ * also blocked. You need to lower the level first. | |
+ * | |
+ * This feature is not supported in OpenSSL < 1.1.0, and setting the level to | |
+ * other than 0 will raise NotImplementedError. Level 0 means everything is | |
+ * permitted, the same behavior as previous versions of OpenSSL. | |
+ * | |
+ * See the manpage of SSL_CTX_set_security_level(3) for details. | |
+ */ | |
+static VALUE | |
+ossl_sslctx_set_security_level(VALUE self, VALUE value) | |
+{ | |
+ SSL_CTX *ctx; | |
+ | |
+ rb_check_frozen(self); | |
+ GetSSLCTX(self, ctx); | |
+ | |
+#if defined(HAVE_SSL_CTX_GET_SECURITY_LEVEL) | |
+ SSL_CTX_set_security_level(ctx, NUM2INT(value)); | |
+#else | |
+ (void)ctx; | |
+ if (NUM2INT(value) != 0) | |
+ ossl_raise(rb_eNotImpError, "setting security level to other than 0 is " | |
+ "not supported in this version of OpenSSL"); | |
+#endif | |
+ | |
+ return value; | |
+} | |
+ | |
/* | |
* call-seq: | |
* ctx.session_add(session) -> true | false | |
* | |
- * Adds +session+ to the session cache | |
+ * Adds +session+ to the session cache. | |
*/ | |
static VALUE | |
ossl_sslctx_session_add(VALUE self, VALUE arg) | |
@@ -982,7 +1220,7 @@ ossl_sslctx_session_add(VALUE self, VALUE arg) | |
* call-seq: | |
* ctx.session_remove(session) -> true | false | |
* | |
- * Removes +session+ from the session cache | |
+ * Removes +session+ from the session cache. | |
*/ | |
static VALUE | |
ossl_sslctx_session_remove(VALUE self, VALUE arg) | |
@@ -1150,25 +1388,11 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) | |
* SSLSocket class | |
*/ | |
#ifndef OPENSSL_NO_SOCK | |
-static void | |
-ossl_ssl_shutdown(SSL *ssl) | |
-{ | |
- int i, rc; | |
- | |
- if (ssl) { | |
- /* 4 is from SSL_smart_shutdown() of mod_ssl.c (v2.2.19) */ | |
- /* It says max 2x pending + 2x data = 4 */ | |
- for (i = 0; i < 4; ++i) { | |
- /* | |
- * Ignore the case SSL_shutdown returns -1. Empty handshake_func | |
- * must not happen. | |
- */ | |
- if ((rc = SSL_shutdown(ssl)) != 0) | |
- break; | |
- } | |
- SSL_clear(ssl); | |
- ERR_clear_error(); | |
- } | |
+static inline int | |
+ssl_started(SSL *ssl) | |
+{ | |
+ /* the FD is set in ossl_ssl_setup(), called by #connect or #accept */ | |
+ return SSL_get_fd(ssl) >= 0; | |
} | |
static void | |
@@ -1191,45 +1415,75 @@ ossl_ssl_s_alloc(VALUE klass) | |
return TypedData_Wrap_Struct(klass, &ossl_ssl_type, NULL); | |
} | |
+/* | |
+ * call-seq: | |
+ * SSLSocket.new(io) => aSSLSocket | |
+ * SSLSocket.new(io, ctx) => aSSLSocket | |
+ * | |
+ * Creates a new SSL socket from +io+ which must be a real IO object (not an | |
+ * IO-like object that responds to read/write). | |
+ * | |
+ * If +ctx+ is provided the SSL Sockets initial params will be taken from | |
+ * the context. | |
+ * | |
+ * The OpenSSL::Buffering module provides additional IO methods. | |
+ * | |
+ * This method will freeze the SSLContext if one is provided; | |
+ * however, session management is still allowed in the frozen SSLContext. | |
+ */ | |
static VALUE | |
-ossl_ssl_setup(VALUE self) | |
+ossl_ssl_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
- VALUE io, v_ctx, cb; | |
+ VALUE io, v_ctx, verify_cb; | |
+ SSL *ssl; | |
SSL_CTX *ctx; | |
+ | |
+ TypedData_Get_Struct(self, SSL, &ossl_ssl_type, ssl); | |
+ if (ssl) | |
+ ossl_raise(eSSLError, "SSL already initialized"); | |
+ | |
+ if (rb_scan_args(argc, argv, "11", &io, &v_ctx) == 1) | |
+ v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0); | |
+ | |
+ GetSSLCTX(v_ctx, ctx); | |
+ rb_ivar_set(self, id_i_context, v_ctx); | |
+ ossl_sslctx_setup(v_ctx); | |
+ | |
+ if (rb_respond_to(io, rb_intern("nonblock="))) | |
+ rb_funcall(io, rb_intern("nonblock="), 1, Qtrue); | |
+ rb_ivar_set(self, id_i_io, io); | |
+ | |
+ ssl = SSL_new(ctx); | |
+ if (!ssl) | |
+ ossl_raise(eSSLError, NULL); | |
+ RTYPEDDATA_DATA(self) = ssl; | |
+ | |
+ SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self); | |
+ SSL_set_info_callback(ssl, ssl_info_cb); | |
+ verify_cb = rb_attr_get(v_ctx, id_i_verify_callback); | |
+ SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)verify_cb); | |
+ | |
+ rb_call_super(0, NULL); | |
+ | |
+ return self; | |
+} | |
+ | |
+static VALUE | |
+ossl_ssl_setup(VALUE self) | |
+{ | |
+ VALUE io; | |
SSL *ssl; | |
rb_io_t *fptr; | |
GetSSL(self, ssl); | |
- if(!ssl){ | |
-#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME | |
- VALUE hostname = rb_iv_get(self, "@hostname"); | |
-#endif | |
- | |
- v_ctx = ossl_ssl_get_ctx(self); | |
- GetSSLCTX(v_ctx, ctx); | |
+ if (ssl_started(ssl)) | |
+ return Qtrue; | |
- ssl = SSL_new(ctx); | |
- if (!ssl) { | |
- ossl_raise(eSSLError, "SSL_new"); | |
- } | |
- DATA_PTR(self) = ssl; | |
- | |
-#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME | |
- if (!NIL_P(hostname)) { | |
- if (SSL_set_tlsext_host_name(ssl, StringValuePtr(hostname)) != 1) | |
- ossl_raise(eSSLError, "SSL_set_tlsext_host_name"); | |
- } | |
-#endif | |
- io = ossl_ssl_get_io(self); | |
- GetOpenFile(io, fptr); | |
- rb_io_check_readable(fptr); | |
- rb_io_check_writable(fptr); | |
- SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr))); | |
- SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self); | |
- cb = ossl_sslctx_get_verify_cb(v_ctx); | |
- SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb); | |
- SSL_set_info_callback(ssl, ssl_info_cb); | |
- } | |
+ io = rb_attr_get(self, id_i_io); | |
+ GetOpenFile(io, fptr); | |
+ rb_io_check_readable(fptr); | |
+ rb_io_check_writable(fptr); | |
+ SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr))); | |
return Qtrue; | |
} | |
@@ -1240,31 +1494,18 @@ ossl_ssl_setup(VALUE self) | |
#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret)) | |
#endif | |
-#define ossl_ssl_data_get_struct(v, ssl) \ | |
-do { \ | |
- GetSSL((v), (ssl)); \ | |
- if (!(ssl)) { \ | |
- rb_warning("SSL session is not started yet."); \ | |
- return Qnil; \ | |
- } \ | |
-} while (0) | |
- | |
static void | |
write_would_block(int nonblock) | |
{ | |
- if (nonblock) { | |
- VALUE exc = ossl_exc_new(eSSLErrorWaitWritable, "write would block"); | |
- rb_exc_raise(exc); | |
- } | |
+ if (nonblock) | |
+ ossl_raise(eSSLErrorWaitWritable, "write would block"); | |
} | |
static void | |
read_would_block(int nonblock) | |
{ | |
- if (nonblock) { | |
- VALUE exc = ossl_exc_new(eSSLErrorWaitReadable, "read would block"); | |
- rb_exc_raise(exc); | |
- } | |
+ if (nonblock) | |
+ ossl_raise(eSSLErrorWaitReadable, "read would block"); | |
} | |
static int | |
@@ -1287,15 +1528,18 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) | |
rb_ivar_set(self, ID_callback_state, Qnil); | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
- GetOpenFile(ossl_ssl_get_io(self), fptr); | |
+ GetOpenFile(rb_attr_get(self, id_i_io), fptr); | |
for(;;){ | |
ret = func(ssl); | |
- cb_state = rb_ivar_get(self, ID_callback_state); | |
- if (!NIL_P(cb_state)) | |
- rb_jump_tag(NUM2INT(cb_state)); | |
+ cb_state = rb_attr_get(self, ID_callback_state); | |
+ if (!NIL_P(cb_state)) { | |
+ /* must cleanup OpenSSL error stack before re-raising */ | |
+ ossl_clear_error(); | |
+ rb_jump_tag(NUM2INT(cb_state)); | |
+ } | |
if (ret > 0) | |
break; | |
@@ -1425,7 +1669,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) | |
int ilen, nread = 0; | |
VALUE len, str; | |
rb_io_t *fptr; | |
- VALUE opts = Qnil; | |
+ VALUE io, opts = Qnil; | |
if (nonblock) { | |
rb_scan_args(argc, argv, "11:", &len, &str, &opts); | |
@@ -1434,25 +1678,22 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) | |
} | |
ilen = NUM2INT(len); | |
- if (NIL_P(str)) | |
- str = rb_str_new(0, ilen); | |
- else { | |
- StringValue(str); | |
- if (RSTRING_LEN(str) >= ilen) | |
- rb_str_modify(str); | |
- else | |
- rb_str_modify_expand(str, ilen - RSTRING_LEN(str)); | |
+ if(NIL_P(str)) str = rb_str_new(0, ilen); | |
+ else{ | |
+ StringValue(str); | |
+ rb_str_modify(str); | |
+ rb_str_resize(str, ilen); | |
} | |
- OBJ_TAINT(str); | |
- rb_str_set_len(str, 0); | |
- if (ilen == 0) | |
- return str; | |
+ if(ilen == 0) return str; | |
GetSSL(self, ssl); | |
- GetOpenFile(ossl_ssl_get_io(self), fptr); | |
- if (ssl) { | |
+ io = rb_attr_get(self, id_i_io); | |
+ GetOpenFile(io, fptr); | |
+ if (ssl_started(ssl)) { | |
+ if(!nonblock && SSL_pending(ssl) <= 0) | |
+ rb_thread_wait_fd(FPTR_TO_FD(fptr)); | |
for (;;){ | |
- nread = SSL_read(ssl, RSTRING_PTR(str), ilen); | |
+ nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LENINT(str)); | |
switch(ssl_get_error(ssl, nread)){ | |
case SSL_ERROR_NONE: | |
goto end; | |
@@ -1470,28 +1711,40 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) | |
rb_io_wait_readable(FPTR_TO_FD(fptr)); | |
continue; | |
case SSL_ERROR_SYSCALL: | |
- if(ERR_peek_error() == 0 && nread == 0) { | |
- if (no_exception_p(opts)) { return Qnil; } | |
- rb_eof_error(); | |
+ if (!ERR_peek_error()) { | |
+ if (errno) | |
+ rb_sys_fail(0); | |
+ else { | |
+ /* | |
+ * The underlying BIO returned 0. This is actually a | |
+ * protocol error. But unfortunately, not all | |
+ * implementations cleanly shutdown the TLS connection | |
+ * but just shutdown/close the TCP connection. So report | |
+ * EOF for now... | |
+ */ | |
+ if (no_exception_p(opts)) { return Qnil; } | |
+ rb_eof_error(); | |
+ } | |
} | |
- rb_sys_fail(0); | |
default: | |
ossl_raise(eSSLError, "SSL_read"); | |
} | |
} | |
} | |
else { | |
- ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); | |
- rb_warning("SSL session is not started yet."); | |
- if (nonblock) { | |
- return rb_funcall(ossl_ssl_get_io(self), meth, 3, len, str, opts); | |
- } else { | |
- return rb_funcall(ossl_ssl_get_io(self), meth, 2, len, str); | |
- } | |
+ ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); | |
+ | |
+ rb_warning("SSL session is not started yet."); | |
+ if (nonblock) | |
+ return rb_funcall(io, meth, 3, len, str, opts); | |
+ else | |
+ return rb_funcall(io, meth, 2, len, str); | |
} | |
end: | |
rb_str_set_len(str, nread); | |
+ OBJ_TAINT(str); | |
+ | |
return str; | |
} | |
@@ -1535,12 +1788,13 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) | |
int nwrite = 0; | |
rb_io_t *fptr; | |
int nonblock = opts != Qfalse; | |
+ VALUE io; | |
StringValue(str); | |
GetSSL(self, ssl); | |
- GetOpenFile(ossl_ssl_get_io(self), fptr); | |
- | |
- if (ssl) { | |
+ io = rb_attr_get(self, id_i_io); | |
+ GetOpenFile(io, fptr); | |
+ if (ssl_started(ssl)) { | |
for (;;){ | |
int num = RSTRING_LENINT(str); | |
@@ -1570,9 +1824,14 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) | |
} | |
} | |
else { | |
- ID id_syswrite = rb_intern("syswrite"); | |
- rb_warning("SSL session is not started yet."); | |
- return rb_funcall(ossl_ssl_get_io(self), id_syswrite, 1, str); | |
+ ID meth = nonblock ? | |
+ rb_intern("write_nonblock") : rb_intern("syswrite"); | |
+ | |
+ rb_warning("SSL session is not started yet."); | |
+ if (nonblock) | |
+ return rb_funcall(io, meth, 2, str, opts); | |
+ else | |
+ return rb_funcall(io, meth, 1, str); | |
} | |
end: | |
@@ -1619,11 +1878,24 @@ static VALUE | |
ossl_ssl_stop(VALUE self) | |
{ | |
SSL *ssl; | |
+ int ret; | |
- ossl_ssl_data_get_struct(self, ssl); | |
- | |
- ossl_ssl_shutdown(ssl); | |
+ GetSSL(self, ssl); | |
+ if (!ssl_started(ssl)) | |
+ return Qnil; | |
+ ret = SSL_shutdown(ssl); | |
+ if (ret == 1) /* Have already received close_notify */ | |
+ return Qnil; | |
+ if (ret == 0) /* Sent close_notify, but we don't wait for reply */ | |
+ return Qnil; | |
+ /* | |
+ * XXX: Something happened. Possibly it failed because the underlying socket | |
+ * is not writable/readable, since it is in non-blocking mode. We should do | |
+ * some proper error handling using SSL_get_error() and maybe retry, but we | |
+ * can't block here. Give up for now. | |
+ */ | |
+ ossl_clear_error(); | |
return Qnil; | |
} | |
@@ -1639,7 +1911,7 @@ ossl_ssl_get_cert(VALUE self) | |
SSL *ssl; | |
X509 *cert = NULL; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
/* | |
* Is this OpenSSL bug? Should add a ref? | |
@@ -1666,7 +1938,7 @@ ossl_ssl_get_peer_cert(VALUE self) | |
X509 *cert = NULL; | |
VALUE obj; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */ | |
@@ -1694,7 +1966,7 @@ ossl_ssl_get_peer_cert_chain(VALUE self) | |
VALUE ary; | |
int i, num; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
chain = SSL_get_peer_cert_chain(ssl); | |
if(!chain) return Qnil; | |
@@ -1720,7 +1992,7 @@ ossl_ssl_get_version(VALUE self) | |
{ | |
SSL *ssl; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
return rb_str_new2(SSL_get_version(ssl)); | |
} | |
@@ -1737,7 +2009,7 @@ ossl_ssl_get_cipher(VALUE self) | |
SSL *ssl; | |
SSL_CIPHER *cipher; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
cipher = (SSL_CIPHER *)SSL_get_current_cipher(ssl); | |
@@ -1748,7 +2020,8 @@ ossl_ssl_get_cipher(VALUE self) | |
* call-seq: | |
* ssl.state => string | |
* | |
- * A description of the current connection state. | |
+ * A description of the current connection state. This is for diagnostic | |
+ * purposes only. | |
*/ | |
static VALUE | |
ossl_ssl_get_state(VALUE self) | |
@@ -1756,7 +2029,7 @@ ossl_ssl_get_state(VALUE self) | |
SSL *ssl; | |
VALUE ret; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
ret = rb_str_new2(SSL_state_string(ssl)); | |
if (ruby_verbose) { | |
@@ -1770,14 +2043,14 @@ ossl_ssl_get_state(VALUE self) | |
* call-seq: | |
* ssl.pending => Integer | |
* | |
- * The number of bytes that are immediately available for reading | |
+ * The number of bytes that are immediately available for reading. | |
*/ | |
static VALUE | |
ossl_ssl_pending(VALUE self) | |
{ | |
SSL *ssl; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
return INT2NUM(SSL_pending(ssl)); | |
} | |
@@ -1793,15 +2066,9 @@ ossl_ssl_session_reused(VALUE self) | |
{ | |
SSL *ssl; | |
- ossl_ssl_data_get_struct(self, ssl); | |
- | |
- switch(SSL_session_reused(ssl)) { | |
- case 1: return Qtrue; | |
- case 0: return Qfalse; | |
- default: ossl_raise(eSSLError, "SSL_session_reused"); | |
- } | |
+ GetSSL(self, ssl); | |
- UNREACHABLE; | |
+ return SSL_session_reused(ssl) ? Qtrue : Qfalse; | |
} | |
/* | |
@@ -1816,11 +2083,7 @@ ossl_ssl_set_session(VALUE self, VALUE arg1) | |
SSL *ssl; | |
SSL_SESSION *sess; | |
-/* why is ossl_ssl_setup delayed? */ | |
- ossl_ssl_setup(self); | |
- | |
- ossl_ssl_data_get_struct(self, ssl); | |
- | |
+ GetSSL(self, ssl); | |
SafeGetSSLSession(arg1, sess); | |
if (SSL_set_session(ssl, sess) != 1) | |
@@ -1829,6 +2092,35 @@ ossl_ssl_set_session(VALUE self, VALUE arg1) | |
return arg1; | |
} | |
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME | |
+/* | |
+ * call-seq: | |
+ * ssl.hostname = hostname -> hostname | |
+ * | |
+ * Sets the server hostname used for SNI. This needs to be set before | |
+ * SSLSocket#connect. | |
+ */ | |
+static VALUE | |
+ossl_ssl_set_hostname(VALUE self, VALUE arg) | |
+{ | |
+ SSL *ssl; | |
+ char *hostname = NULL; | |
+ | |
+ GetSSL(self, ssl); | |
+ | |
+ if (!NIL_P(arg)) | |
+ hostname = StringValueCStr(arg); | |
+ | |
+ if (!SSL_set_tlsext_host_name(ssl, hostname)) | |
+ ossl_raise(eSSLError, NULL); | |
+ | |
+ /* for SSLSocket#hostname */ | |
+ rb_ivar_set(self, id_i_hostname, arg); | |
+ | |
+ return arg; | |
+} | |
+#endif | |
+ | |
/* | |
* call-seq: | |
* ssl.verify_result => Integer | |
@@ -1843,9 +2135,9 @@ ossl_ssl_get_verify_result(VALUE self) | |
{ | |
SSL *ssl; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
- return INT2FIX(SSL_get_verify_result(ssl)); | |
+ return INT2NUM(SSL_get_verify_result(ssl)); | |
} | |
/* | |
@@ -1865,7 +2157,7 @@ ossl_ssl_get_client_ca_list(VALUE self) | |
SSL *ssl; | |
STACK_OF(X509_NAME) *ca; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
ca = SSL_get_client_CA_list(ssl); | |
return ossl_x509name_sk2ary(ca); | |
@@ -1874,7 +2166,7 @@ ossl_ssl_get_client_ca_list(VALUE self) | |
# ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB | |
/* | |
* call-seq: | |
- * ssl.npn_protocol => String | |
+ * ssl.npn_protocol => String | nil | |
* | |
* Returns the protocol string that was finally selected by the client | |
* during the handshake. | |
@@ -1886,7 +2178,7 @@ ossl_ssl_npn_protocol(VALUE self) | |
const unsigned char *out; | |
unsigned int outlen; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
SSL_get0_next_proto_negotiated(ssl, &out, &outlen); | |
if (!outlen) | |
@@ -1899,9 +2191,9 @@ ossl_ssl_npn_protocol(VALUE self) | |
# ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB | |
/* | |
* call-seq: | |
- * ssl.alpn_protocol => String | |
+ * ssl.alpn_protocol => String | nil | |
* | |
- * Returns the ALPN protocol string that was finally selected by the client | |
+ * Returns the ALPN protocol string that was finally selected by the server | |
* during the handshake. | |
*/ | |
static VALUE | |
@@ -1911,7 +2203,7 @@ ossl_ssl_alpn_protocol(VALUE self) | |
const unsigned char *out; | |
unsigned int outlen; | |
- ossl_ssl_data_get_struct(self, ssl); | |
+ GetSSL(self, ssl); | |
SSL_get0_alpn_selected(ssl, &out, &outlen); | |
if (!outlen) | |
@@ -1920,8 +2212,30 @@ ossl_ssl_alpn_protocol(VALUE self) | |
return rb_str_new((const char *) out, outlen); | |
} | |
# endif | |
+ | |
+# ifdef HAVE_SSL_GET_SERVER_TMP_KEY | |
+/* | |
+ * call-seq: | |
+ * ssl.tmp_key => PKey or nil | |
+ * | |
+ * Returns the ephemeral key used in case of forward secrecy cipher. | |
+ */ | |
+static VALUE | |
+ossl_ssl_tmp_key(VALUE self) | |
+{ | |
+ SSL *ssl; | |
+ EVP_PKEY *key; | |
+ | |
+ GetSSL(self, ssl); | |
+ if (!SSL_get_server_tmp_key(ssl, &key)) | |
+ return Qnil; | |
+ return ossl_pkey_new(key); | |
+} | |
+# endif /* defined(HAVE_SSL_GET_SERVER_TMP_KEY) */ | |
#endif /* !defined(OPENSSL_NO_SOCK) */ | |
+#undef rb_intern | |
+#define rb_intern(s) rb_intern_const(s) | |
void | |
Init_ossl_ssl(void) | |
{ | |
@@ -1929,10 +2243,13 @@ Init_ossl_ssl(void) | |
VALUE ary; | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable"); | |
+ rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable"); | |
#endif | |
- 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_store_p = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_store_p",0,0,0); | |
@@ -1977,14 +2294,10 @@ Init_ossl_ssl(void) | |
* | |
* All attributes must be set before creating an SSLSocket as the | |
* SSLContext will be frozen afterward. | |
- * | |
- * The following attributes are available but don't show up in rdoc: | |
- * * ssl_version, cert, key, client_ca, ca_file, ca_path, timeout, | |
- * * verify_mode, verify_depth client_cert_cb, tmp_dh_callback, | |
- * * session_id_context, session_add_cb, session_new_cb, session_remove_cb | |
*/ | |
cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject); | |
rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc); | |
+ rb_undef_method(cSSLContext, "initialize_copy"); | |
/* | |
* Context certificate | |
@@ -2014,7 +2327,7 @@ Init_ossl_ssl(void) | |
rb_attr(cSSLContext, rb_intern("ca_path"), 1, 1, Qfalse); | |
/* | |
- * Maximum session lifetime. | |
+ * Maximum session lifetime in seconds. | |
*/ | |
rb_attr(cSSLContext, rb_intern("timeout"), 1, 1, Qfalse); | |
@@ -2023,6 +2336,11 @@ Init_ossl_ssl(void) | |
* | |
* Valid modes are VERIFY_NONE, VERIFY_PEER, VERIFY_CLIENT_ONCE, | |
* VERIFY_FAIL_IF_NO_PEER_CERT and defined on OpenSSL::SSL | |
+ * | |
+ * The default mode is VERIFY_NONE, which does not perform any verification | |
+ * at all. | |
+ * | |
+ * See SSL_CTX_set_verify(3) for details. | |
*/ | |
rb_attr(cSSLContext, rb_intern("verify_mode"), 1, 1, Qfalse); | |
@@ -2040,12 +2358,21 @@ Init_ossl_ssl(void) | |
* +store_context+ is an OpenSSL::X509::StoreContext containing the | |
* context used for certificate verification. | |
* | |
- * If the callback returns false verification is stopped. | |
+ * If the callback returns false, the chain verification is immediately | |
+ * stopped and a bad_certificate alert is then sent. | |
*/ | |
rb_attr(cSSLContext, rb_intern("verify_callback"), 1, 1, Qfalse); | |
/* | |
- * An OpenSSL::X509::Store used for certificate verification | |
+ * Whether to check the server certificate is valid for the hostname. | |
+ * | |
+ * In order to make this work, verify_mode must be set to VERIFY_PEER and | |
+ * the server hostname must be given by OpenSSL::SSL::SSLSocket#hostname=. | |
+ */ | |
+ rb_attr(cSSLContext, rb_intern("verify_hostname"), 1, 1, Qfalse); | |
+ | |
+ /* | |
+ * An OpenSSL::X509::Store used for certificate verification. | |
*/ | |
rb_attr(cSSLContext, rb_intern("cert_store"), 1, 1, Qfalse); | |
@@ -2065,6 +2392,7 @@ Init_ossl_ssl(void) | |
*/ | |
rb_attr(cSSLContext, rb_intern("client_cert_cb"), 1, 1, Qfalse); | |
+#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK) | |
/* | |
* A callback invoked when ECDH parameters are required. | |
* | |
@@ -2072,10 +2400,11 @@ Init_ossl_ssl(void) | |
* flag indicating the use of an export cipher and the keylength | |
* required. | |
* | |
- * The callback must return an OpenSSL::PKey::EC instance of the correct | |
- * key length. | |
+ * The callback is deprecated. This does not work with recent versions of | |
+ * OpenSSL. Use OpenSSL::SSL::SSLContext#ecdh_curves= instead. | |
*/ | |
rb_attr(cSSLContext, rb_intern("tmp_ecdh_callback"), 1, 1, Qfalse); | |
+#endif | |
/* | |
* Sets the context in which a session can be reused. This allows | |
@@ -2167,7 +2496,7 @@ Init_ossl_ssl(void) | |
* === Example | |
* | |
* ctx.npn_select_cb = lambda do |protocols| | |
- * #inspect the protocols and select one | |
+ * # inspect the protocols and select one | |
* protocols.first | |
* end | |
*/ | |
@@ -2177,10 +2506,10 @@ Init_ossl_ssl(void) | |
#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB | |
/* | |
* An Enumerable of Strings. Each String represents a protocol to be | |
- * advertised as the list of supported protocols for Application-Layer Protocol | |
- * Negotiation. Supported in OpenSSL 1.0.1 and higher. Has no effect | |
- * on the client side. If not set explicitly, the NPN extension will | |
- * not be sent by the server in the handshake. | |
+ * advertised as the list of supported protocols for Application-Layer | |
+ * Protocol Negotiation. Supported in OpenSSL 1.0.2 and higher. Has no | |
+ * effect on the server side. If not set explicitly, the ALPN extension will | |
+ * not be included in the handshake. | |
* | |
* === Example | |
* | |
@@ -2190,16 +2519,16 @@ Init_ossl_ssl(void) | |
/* | |
* A callback invoked on the server side when the server needs to select | |
* a protocol from the list sent by the client. Supported in OpenSSL 1.0.2 | |
- * and higher. The server MUST select a protocol of those advertised by | |
+ * and higher. The callback must return a protocol of those advertised by | |
* the client. If none is acceptable, raising an error in the callback | |
* will cause the handshake to fail. Not setting this callback explicitly | |
- * means not supporting the ALPN extension on the client - any protocols | |
- * advertised by the server will be ignored. | |
+ * means not supporting the ALPN extension on the server - any protocols | |
+ * advertised by the client will be ignored. | |
* | |
* === Example | |
* | |
* ctx.alpn_select_cb = lambda do |protocols| | |
- * #inspect the protocols and select one | |
+ * # inspect the protocols and select one | |
* protocols.first | |
* end | |
*/ | |
@@ -2211,28 +2540,32 @@ Init_ossl_ssl(void) | |
rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1); | |
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0); | |
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 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_set_security_level, 1); | |
rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0); | |
+ rb_define_alias(cSSLContext, "freeze", "setup"); | |
/* | |
* No session caching for client or server | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF)); | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2NUM(SSL_SESS_CACHE_OFF)); | |
/* | |
* Client sessions are added to the session cache | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */ | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2NUM(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */ | |
/* | |
* Server sessions are added to the session cache | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER)); | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2NUM(SSL_SESS_CACHE_SERVER)); | |
/* | |
* Both client and server sessions are added to the session cache | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */ | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2NUM(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */ | |
/* | |
* Normally the session cache is checked for expired sessions every 255 | |
@@ -2240,7 +2573,7 @@ Init_ossl_ssl(void) | |
* the automatic flushing may be disabled and #flush_sessions can be | |
* called explicitly. | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR)); | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2NUM(SSL_SESS_CACHE_NO_AUTO_CLEAR)); | |
/* | |
* Always perform external lookups of sessions even if they are in the | |
@@ -2248,18 +2581,18 @@ Init_ossl_ssl(void) | |
* | |
* This flag has no effect on clients | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)); | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)); | |
/* | |
* Never automatically store sessions in the internal store. | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE)); | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL_STORE)); | |
/* | |
* Enables both SESSION_CACHE_NO_INTERNAL_LOOKUP and | |
* SESSION_CACHE_NO_INTERNAL_STORE. | |
*/ | |
- rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL)); | |
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL)); | |
rb_define_method(cSSLContext, "session_add", ossl_sslctx_session_add, 1); | |
rb_define_method(cSSLContext, "session_remove", ossl_sslctx_session_remove, 1); | |
@@ -2282,17 +2615,16 @@ Init_ossl_ssl(void) | |
/* | |
* Document-class: OpenSSL::SSL::SSLSocket | |
- * | |
- * The following attributes are available but don't show up in rdoc. | |
- * * io, context, sync_close | |
- * | |
*/ | |
cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject); | |
#ifdef OPENSSL_NO_SOCK | |
rb_define_const(mSSLExtConfig, "OPENSSL_NO_SOCK", Qtrue); | |
+ rb_define_method(cSSLSocket, "initialize", rb_f_notimplement, -1); | |
#else | |
rb_define_const(mSSLExtConfig, "OPENSSL_NO_SOCK", Qfalse); | |
rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc); | |
+ rb_define_method(cSSLSocket, "initialize", ossl_ssl_initialize, -1); | |
+ rb_undef_method(cSSLSocket, "initialize_copy"); | |
rb_define_method(cSSLSocket, "connect", ossl_ssl_connect, 0); | |
rb_define_method(cSSLSocket, "connect_nonblock", ossl_ssl_connect_nonblock, -1); | |
rb_define_method(cSSLSocket, "accept", ossl_ssl_accept, 0); | |
@@ -2314,6 +2646,13 @@ Init_ossl_ssl(void) | |
rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1); | |
rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0); | |
rb_define_method(cSSLSocket, "client_ca", ossl_ssl_get_client_ca_list, 0); | |
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME | |
+ /* #hostname is defined in lib/openssl/ssl.rb */ | |
+ rb_define_method(cSSLSocket, "hostname=", ossl_ssl_set_hostname, 1); | |
+#endif | |
+# ifdef HAVE_SSL_GET_SERVER_TMP_KEY | |
+ rb_define_method(cSSLSocket, "tmp_key", ossl_ssl_tmp_key, 0); | |
+# endif | |
# ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB | |
rb_define_method(cSSLSocket, "alpn_protocol", ossl_ssl_alpn_protocol, 0); | |
# endif | |
@@ -2337,25 +2676,17 @@ Init_ossl_ssl(void) | |
ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); | |
ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG); | |
ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER); | |
-#if defined(SSL_OP_MSIE_SSLV2_RSA_PADDING) | |
ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING); | |
-#endif | |
ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG); | |
ossl_ssl_def_const(OP_TLS_D5_BUG); | |
ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG); | |
ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS); | |
ossl_ssl_def_const(OP_ALL); | |
-#if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) | |
ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); | |
-#endif | |
-#if defined(SSL_OP_SINGLE_ECDH_USE) | |
ossl_ssl_def_const(OP_SINGLE_ECDH_USE); | |
-#endif | |
ossl_ssl_def_const(OP_SINGLE_DH_USE); | |
ossl_ssl_def_const(OP_EPHEMERAL_RSA); | |
-#if defined(SSL_OP_CIPHER_SERVER_PREFERENCE) | |
ossl_ssl_def_const(OP_CIPHER_SERVER_PREFERENCE); | |
-#endif | |
ossl_ssl_def_const(OP_TLS_ROLLBACK_BUG); | |
ossl_ssl_def_const(OP_NO_SSLv2); | |
ossl_ssl_def_const(OP_NO_SSLv3); | |
@@ -2377,8 +2708,43 @@ Init_ossl_ssl(void) | |
ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG); | |
ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); | |
-#undef rb_intern | |
sym_exception = ID2SYM(rb_intern("exception")); | |
sym_wait_readable = ID2SYM(rb_intern("wait_readable")); | |
sym_wait_writable = ID2SYM(rb_intern("wait_writable")); | |
+ | |
+ id_tmp_dh_callback = rb_intern("tmp_dh_callback"); | |
+ id_tmp_ecdh_callback = rb_intern("tmp_ecdh_callback"); | |
+ id_npn_protocols_encoded = rb_intern("npn_protocols_encoded"); | |
+ | |
+#define DefIVarID(name) do \ | |
+ id_i_##name = rb_intern("@"#name); while (0) | |
+ | |
+ DefIVarID(cert_store); | |
+ DefIVarID(ca_file); | |
+ DefIVarID(ca_path); | |
+ DefIVarID(verify_mode); | |
+ DefIVarID(verify_depth); | |
+ DefIVarID(verify_callback); | |
+ DefIVarID(client_ca); | |
+ DefIVarID(renegotiation_cb); | |
+ DefIVarID(cert); | |
+ DefIVarID(key); | |
+ DefIVarID(extra_chain_cert); | |
+ DefIVarID(client_cert_cb); | |
+ DefIVarID(tmp_ecdh_callback); | |
+ DefIVarID(timeout); | |
+ DefIVarID(session_id_context); | |
+ DefIVarID(session_get_cb); | |
+ DefIVarID(session_new_cb); | |
+ DefIVarID(session_remove_cb); | |
+ DefIVarID(npn_select_cb); | |
+ DefIVarID(npn_protocols); | |
+ DefIVarID(alpn_protocols); | |
+ DefIVarID(alpn_select_cb); | |
+ DefIVarID(servername_cb); | |
+ DefIVarID(verify_hostname); | |
+ | |
+ DefIVarID(io); | |
+ DefIVarID(context); | |
+ DefIVarID(hostname); | |
} | |
diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h | |
index 909f6798c4..c1a3cd6c1d 100644 | |
--- a/ext/openssl/ossl_ssl.h | |
+++ b/ext/openssl/ossl_ssl.h | |
@@ -12,6 +12,9 @@ | |
#define GetSSL(obj, ssl) do { \ | |
TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \ | |
+ if (!(ssl)) { \ | |
+ ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \ | |
+ } \ | |
} while (0) | |
#define GetSSLSession(obj, sess) do { \ | |
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c | |
index 360f9161ec..7abb8671f8 100644 | |
--- a/ext/openssl/ossl_ssl_session.c | |
+++ b/ext/openssl/ossl_ssl_session.c | |
@@ -28,12 +28,12 @@ static VALUE ossl_ssl_session_alloc(VALUE klass) | |
/* | |
* call-seq: | |
- * Session.new(SSLSocket | string) => session | |
+ * Session.new(ssl_socket) -> Session | |
+ * Session.new(string) -> Session | |
* | |
- * === Parameters | |
- * +SSLSocket+ is an OpenSSL::SSL::SSLSocket | |
- * +string+ must be a DER or PEM encoded Session. | |
-*/ | |
+ * Creates a new Session object from an instance of SSLSocket or DER/PEM encoded | |
+ * String. | |
+ */ | |
static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) | |
{ | |
SSL_SESSION *ctx = NULL; | |
@@ -46,10 +46,10 @@ static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) | |
GetSSL(arg1, ssl); | |
- if (!ssl || (ctx = SSL_get1_session(ssl)) == NULL) | |
+ if ((ctx = SSL_get1_session(ssl)) == NULL) | |
ossl_raise(eSSLSession, "no session available"); | |
} else { | |
- BIO *in = ossl_obj2bio(&arg1); | |
+ BIO *in = ossl_obj2bio(arg1); | |
ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL); | |
@@ -73,25 +73,51 @@ static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) | |
return self; | |
} | |
+static VALUE | |
+ossl_ssl_session_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ SSL_SESSION *sess, *sess_other, *sess_new; | |
+ | |
+ rb_check_frozen(self); | |
+ sess = RTYPEDDATA_DATA(self); /* XXX */ | |
+ SafeGetSSLSession(other, sess_other); | |
+ | |
+ sess_new = ASN1_dup((i2d_of_void *)i2d_SSL_SESSION, (d2i_of_void *)d2i_SSL_SESSION, | |
+ (char *)sess_other); | |
+ if (!sess_new) | |
+ ossl_raise(eSSLSession, "ASN1_dup"); | |
+ | |
+ RTYPEDDATA_DATA(self) = sess_new; | |
+ SSL_SESSION_free(sess); | |
+ | |
+ return self; | |
+} | |
+ | |
#if HAVE_SSL_SESSION_CMP == 0 | |
int SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b) | |
{ | |
- if (a->ssl_version != b->ssl_version || | |
- a->session_id_length != b->session_id_length) | |
+ unsigned int a_len; | |
+ const unsigned char *a_sid = SSL_SESSION_get_id(a, &a_len); | |
+ unsigned int b_len; | |
+ const unsigned char *b_sid = SSL_SESSION_get_id(b, &b_len); | |
+ | |
+#if !defined(HAVE_OPAQUE_OPENSSL) /* missing SSL_SESSION_get_ssl_version() ? */ | |
+ if (a->ssl_version != b->ssl_version) | |
return 1; | |
-#if defined(_WIN32) | |
- return memcmp(a->session_id, b->session_id, a->session_id_length); | |
-#else | |
- return CRYPTO_memcmp(a->session_id, b->session_id, a->session_id_length); | |
#endif | |
+ if (a_len != b_len) | |
+ return 1; | |
+ | |
+ return CRYPTO_memcmp(a_sid, b_sid, a_len); | |
} | |
#endif | |
/* | |
* call-seq: | |
- * session1 == session2 -> boolean | |
+ * session1 == session2 -> boolean | |
* | |
-*/ | |
+ * Returns true if the two Session is the same, false if not. | |
+ */ | |
static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2) | |
{ | |
SSL_SESSION *ctx1, *ctx2; | |
@@ -109,51 +135,50 @@ static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2) | |
* call-seq: | |
* session.time -> Time | |
* | |
- * Gets start time of the session. | |
- * | |
-*/ | |
-static VALUE ossl_ssl_session_get_time(VALUE self) | |
+ * Returns the time at which the session was established. | |
+ */ | |
+static VALUE | |
+ossl_ssl_session_get_time(VALUE self) | |
{ | |
- SSL_SESSION *ctx; | |
- time_t t; | |
+ SSL_SESSION *ctx; | |
+ long t; | |
- GetSSLSession(self, ctx); | |
- | |
- t = SSL_SESSION_get_time(ctx); | |
- | |
- if (t == 0) | |
- return Qnil; | |
+ GetSSLSession(self, ctx); | |
+ t = SSL_SESSION_get_time(ctx); | |
+ if (t == 0) | |
+ return Qnil; | |
- return rb_funcall(rb_cTime, rb_intern("at"), 1, TIMET2NUM(t)); | |
+ return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t)); | |
} | |
/* | |
* call-seq: | |
- * session.timeout -> integer | |
+ * session.timeout -> Integer | |
* | |
- * Gets how long until the session expires in seconds. | |
+ * Returns the timeout value set for the session, in seconds from the | |
+ * established time. | |
* | |
-*/ | |
-static VALUE ossl_ssl_session_get_timeout(VALUE self) | |
+ */ | |
+static VALUE | |
+ossl_ssl_session_get_timeout(VALUE self) | |
{ | |
- SSL_SESSION *ctx; | |
- time_t t; | |
- | |
- GetSSLSession(self, ctx); | |
+ SSL_SESSION *ctx; | |
+ long t; | |
- t = SSL_SESSION_get_timeout(ctx); | |
+ GetSSLSession(self, ctx); | |
+ t = SSL_SESSION_get_timeout(ctx); | |
- return TIMET2NUM(t); | |
+ return LONG2NUM(t); | |
} | |
/* | |
* call-seq: | |
- * session.time=(Time) -> Time | |
- * session.time=(integer) -> Time | |
+ * session.time = time | |
+ * session.time = integer | |
* | |
* Sets start time of the session. Time resolution is in seconds. | |
* | |
-*/ | |
+ */ | |
static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v) | |
{ | |
SSL_SESSION *ctx; | |
@@ -170,11 +195,10 @@ static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v) | |
/* | |
* call-seq: | |
- * session.timeout=(integer) -> integer | |
+ * session.timeout = integer | |
* | |
* Sets how long until the session expires in seconds. | |
- * | |
-*/ | |
+ */ | |
static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v) | |
{ | |
SSL_SESSION *ctx; | |
@@ -186,10 +210,9 @@ static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v) | |
return ossl_ssl_session_get_timeout(self); | |
} | |
-#ifdef HAVE_SSL_SESSION_GET_ID | |
/* | |
* call-seq: | |
- * session.id -> aString | |
+ * session.id -> String | |
* | |
* Returns the Session ID. | |
*/ | |
@@ -205,14 +228,13 @@ static VALUE ossl_ssl_session_get_id(VALUE self) | |
return rb_str_new((const char *) p, i); | |
} | |
-#endif | |
/* | |
* call-seq: | |
- * session.to_der -> aString | |
+ * session.to_der -> String | |
* | |
* Returns an ASN1 encoded String that contains the Session object. | |
-*/ | |
+ */ | |
static VALUE ossl_ssl_session_to_der(VALUE self) | |
{ | |
SSL_SESSION *ctx; | |
@@ -238,14 +260,11 @@ static VALUE ossl_ssl_session_to_der(VALUE self) | |
* session.to_pem -> String | |
* | |
* Returns a PEM encoded String that contains the Session object. | |
-*/ | |
+ */ | |
static VALUE ossl_ssl_session_to_pem(VALUE self) | |
{ | |
SSL_SESSION *ctx; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
- int i; | |
GetSSLSession(self, ctx); | |
@@ -253,16 +272,13 @@ static VALUE ossl_ssl_session_to_pem(VALUE self) | |
ossl_raise(eSSLSession, "BIO_s_mem()"); | |
} | |
- if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) { | |
+ if (!PEM_write_bio_SSL_SESSION(out, ctx)) { | |
BIO_free(out); | |
ossl_raise(eSSLSession, "SSL_SESSION_print()"); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
@@ -270,14 +286,12 @@ static VALUE ossl_ssl_session_to_pem(VALUE self) | |
* call-seq: | |
* session.to_text -> String | |
* | |
- * Shows everything in the Session object. | |
-*/ | |
+ * Shows everything in the Session object. This is for diagnostic purposes. | |
+ */ | |
static VALUE ossl_ssl_session_to_text(VALUE self) | |
{ | |
SSL_SESSION *ctx; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetSSLSession(self, ctx); | |
@@ -290,25 +304,23 @@ static VALUE ossl_ssl_session_to_text(VALUE self) | |
ossl_raise(eSSLSession, "SSL_SESSION_print()"); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
void Init_ossl_ssl_session(void) | |
{ | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
- mSSL = rb_define_module_under(mOSSL, "SSL"); | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ mSSL = rb_define_module_under(mOSSL, "SSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
#endif | |
cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject); | |
eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError); | |
rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc); | |
rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1); | |
+ rb_define_copy_func(cSSLSession, ossl_ssl_session_initialize_copy); | |
rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1); | |
@@ -316,12 +328,7 @@ void Init_ossl_ssl_session(void) | |
rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1); | |
rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0); | |
rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1); | |
- | |
-#ifdef HAVE_SSL_SESSION_GET_ID | |
rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0); | |
-#else | |
- rb_undef_method(cSSLSession, "id"); | |
-#endif | |
rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0); | |
rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0); | |
rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0); | |
diff --git a/ext/openssl/ossl_version.h b/ext/openssl/ossl_version.h | |
index db5d6dc2d4..2566b67a50 100644 | |
--- a/ext/openssl/ossl_version.h | |
+++ b/ext/openssl/ossl_version.h | |
@@ -10,6 +10,6 @@ | |
#if !defined(_OSSL_VERSION_H_) | |
#define _OSSL_VERSION_H_ | |
-#define OSSL_VERSION "1.1.1" | |
+#define OSSL_VERSION "2.0.1" | |
#endif /* _OSSL_VERSION_H_ */ | |
diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c | |
index 2fd14566cd..19ec274ae1 100644 | |
--- a/ext/openssl/ossl_x509.c | |
+++ b/ext/openssl/ossl_x509.c | |
@@ -11,13 +11,33 @@ | |
VALUE mX509; | |
-#define DefX509Const(x) rb_define_const(mX509, #x,INT2FIX(X509_##x)) | |
+#define DefX509Const(x) rb_define_const(mX509, #x, INT2NUM(X509_##x)) | |
#define DefX509Default(x,i) \ | |
rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i())) | |
+ASN1_TIME * | |
+ossl_x509_time_adjust(ASN1_TIME *s, VALUE time) | |
+{ | |
+ time_t sec; | |
+ | |
+#if defined(HAVE_ASN1_TIME_ADJ) | |
+ int off_days; | |
+ | |
+ ossl_time_split(time, &sec, &off_days); | |
+ return X509_time_adj_ex(s, off_days, 0, &sec); | |
+#else | |
+ sec = time_to_time_t(time); | |
+ return X509_time_adj(s, 0, &sec); | |
+#endif | |
+} | |
+ | |
void | |
Init_ossl_x509(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+#endif | |
+ | |
mX509 = rb_define_module_under(mOSSL, "X509"); | |
Init_ossl_x509attr(); | |
@@ -63,22 +83,87 @@ Init_ossl_x509(void) | |
DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN); | |
DefX509Const(V_ERR_APPLICATION_VERIFICATION); | |
-#if defined(X509_V_FLAG_CRL_CHECK) | |
+ /* Set by Store#flags= and StoreContext#flags=. Enables CRL checking for the | |
+ * certificate chain leaf. */ | |
DefX509Const(V_FLAG_CRL_CHECK); | |
-#endif | |
-#if defined(X509_V_FLAG_CRL_CHECK_ALL) | |
+ /* Set by Store#flags= and StoreContext#flags=. Enables CRL checking for all | |
+ * certificates in the certificate chain */ | |
DefX509Const(V_FLAG_CRL_CHECK_ALL); | |
+ /* Set by Store#flags= and StoreContext#flags=. Disables critical extension | |
+ * checking. */ | |
+ DefX509Const(V_FLAG_IGNORE_CRITICAL); | |
+ /* Set by Store#flags= and StoreContext#flags=. Disables workarounds for | |
+ * broken certificates. */ | |
+ DefX509Const(V_FLAG_X509_STRICT); | |
+ /* Set by Store#flags= and StoreContext#flags=. Enables proxy certificate | |
+ * verification. */ | |
+ DefX509Const(V_FLAG_ALLOW_PROXY_CERTS); | |
+ /* Set by Store#flags= and StoreContext#flags=. Enables certificate policy | |
+ * constraints checking. */ | |
+ DefX509Const(V_FLAG_POLICY_CHECK); | |
+ /* Set by Store#flags= and StoreContext#flags=. | |
+ * Implies V_FLAG_POLICY_CHECK */ | |
+ DefX509Const(V_FLAG_EXPLICIT_POLICY); | |
+ /* Set by Store#flags= and StoreContext#flags=. | |
+ * Implies V_FLAG_POLICY_CHECK */ | |
+ DefX509Const(V_FLAG_INHIBIT_ANY); | |
+ /* Set by Store#flags= and StoreContext#flags=. | |
+ * Implies V_FLAG_POLICY_CHECK */ | |
+ DefX509Const(V_FLAG_INHIBIT_MAP); | |
+ /* Set by Store#flags= and StoreContext#flags=. */ | |
+ DefX509Const(V_FLAG_NOTIFY_POLICY); | |
+#if defined(X509_V_FLAG_EXTENDED_CRL_SUPPORT) | |
+ /* Set by Store#flags= and StoreContext#flags=. Enables some additional | |
+ * features including support for indirect signed CRLs. */ | |
+ DefX509Const(V_FLAG_EXTENDED_CRL_SUPPORT); | |
+#endif | |
+#if defined(X509_V_FLAG_USE_DELTAS) | |
+ /* Set by Store#flags= and StoreContext#flags=. Uses delta CRLs. If not | |
+ * specified, deltas are ignored. */ | |
+ DefX509Const(V_FLAG_USE_DELTAS); | |
+#endif | |
+#if defined(X509_V_FLAG_CHECK_SS_SIGNATURE) | |
+ /* Set by Store#flags= and StoreContext#flags=. Enables checking of the | |
+ * signature of the root self-signed CA. */ | |
+ DefX509Const(V_FLAG_CHECK_SS_SIGNATURE); | |
+#endif | |
+#if defined(X509_V_FLAG_TRUSTED_FIRST) | |
+ /* Set by Store#flags= and StoreContext#flags=. When constructing a | |
+ * certificate chain, search the Store first for the issuer certificate. | |
+ * Enabled by default in OpenSSL >= 1.1.0. */ | |
+ DefX509Const(V_FLAG_TRUSTED_FIRST); | |
+#endif | |
+#if defined(X509_V_FLAG_NO_ALT_CHAINS) | |
+ /* Set by Store#flags= and StoreContext#flags=. Suppresses searching for | |
+ * a alternative chain. No effect in OpenSSL >= 1.1.0. */ | |
+ DefX509Const(V_FLAG_NO_ALT_CHAINS); | |
+#endif | |
+#if defined(X509_V_FLAG_NO_CHECK_TIME) | |
+ /* Set by Store#flags= and StoreContext#flags=. Suppresses checking the | |
+ * validity period of certificates and CRLs. No effect when the current | |
+ * time is explicitly set by Store#time= or StoreContext#time=. */ | |
+ DefX509Const(V_FLAG_NO_CHECK_TIME); | |
#endif | |
+ /* Set by Store#purpose=. SSL/TLS client. */ | |
DefX509Const(PURPOSE_SSL_CLIENT); | |
+ /* Set by Store#purpose=. SSL/TLS server. */ | |
DefX509Const(PURPOSE_SSL_SERVER); | |
+ /* Set by Store#purpose=. Netscape SSL server. */ | |
DefX509Const(PURPOSE_NS_SSL_SERVER); | |
+ /* Set by Store#purpose=. S/MIME signing. */ | |
DefX509Const(PURPOSE_SMIME_SIGN); | |
+ /* Set by Store#purpose=. S/MIME encryption. */ | |
DefX509Const(PURPOSE_SMIME_ENCRYPT); | |
+ /* Set by Store#purpose=. CRL signing */ | |
DefX509Const(PURPOSE_CRL_SIGN); | |
+ /* Set by Store#purpose=. No checks. */ | |
DefX509Const(PURPOSE_ANY); | |
-#if defined(X509_PURPOSE_OCSP_HELPER) | |
+ /* Set by Store#purpose=. OCSP helper. */ | |
DefX509Const(PURPOSE_OCSP_HELPER); | |
+#if defined(X509_PURPOSE_TIMESTAMP_SIGN) | |
+ /* Set by Store#purpose=. Time stamps signer. */ | |
+ DefX509Const(PURPOSE_TIMESTAMP_SIGN); | |
#endif | |
DefX509Const(TRUST_COMPAT); | |
@@ -86,11 +171,10 @@ Init_ossl_x509(void) | |
DefX509Const(TRUST_SSL_SERVER); | |
DefX509Const(TRUST_EMAIL); | |
DefX509Const(TRUST_OBJECT_SIGN); | |
-#if defined(X509_TRUST_OCSP_SIGN) | |
DefX509Const(TRUST_OCSP_SIGN); | |
-#endif | |
-#if defined(X509_TRUST_OCSP_REQUEST) | |
DefX509Const(TRUST_OCSP_REQUEST); | |
+#if defined(X509_TRUST_TSA) | |
+ DefX509Const(TRUST_TSA); | |
#endif | |
DefX509Default(CERT_AREA, cert_area); | |
diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h | |
index 9dedb9a49a..a60f7c3da3 100644 | |
--- a/ext/openssl/ossl_x509.h | |
+++ b/ext/openssl/ossl_x509.h | |
@@ -15,6 +15,13 @@ | |
*/ | |
extern VALUE mX509; | |
+/* | |
+ * Converts the VALUE into Integer and set it to the ASN1_TIME. This is a | |
+ * wrapper for X509_time_adj_ex() so passing NULL creates a new ASN1_TIME. | |
+ * Note that the caller must check the NULL return. | |
+ */ | |
+ASN1_TIME *ossl_x509_time_adjust(ASN1_TIME *, VALUE); | |
+ | |
void Init_ossl_x509(void); | |
/* | |
@@ -59,7 +66,6 @@ extern VALUE eX509ExtError; | |
VALUE ossl_x509ext_new(X509_EXTENSION *); | |
X509_EXTENSION *GetX509ExtPtr(VALUE); | |
-X509_EXTENSION *DupX509ExtPtr(VALUE); | |
void Init_ossl_x509ext(void); | |
/* | |
@@ -104,10 +110,13 @@ VALUE ossl_x509store_new(X509_STORE *); | |
X509_STORE *GetX509StorePtr(VALUE); | |
X509_STORE *DupX509StorePtr(VALUE); | |
-VALUE ossl_x509stctx_new(X509_STORE_CTX *); | |
-VALUE ossl_x509stctx_clear_ptr(VALUE); | |
X509_STORE_CTX *GetX509StCtxtPtr(VALUE); | |
- | |
void Init_ossl_x509store(void); | |
+/* | |
+ * Calls the verify callback Proc (the first parameter) with given pre-verify | |
+ * result and the X509_STORE_CTX. | |
+ */ | |
+int ossl_verify_cb_call(VALUE, int, X509_STORE_CTX *); | |
+ | |
#endif /* _OSSL_X509_H_ */ | |
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c | |
index b5a2441807..ae0b347b5f 100644 | |
--- a/ext/openssl/ossl_x509attr.c | |
+++ b/ext/openssl/ossl_x509attr.c | |
@@ -127,6 +127,25 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+ossl_x509attr_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ X509_ATTRIBUTE *attr, *attr_other, *attr_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetX509Attr(self, attr); | |
+ SafeGetX509Attr(other, attr_other); | |
+ | |
+ attr_new = X509_ATTRIBUTE_dup(attr_other); | |
+ if (!attr_new) | |
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup"); | |
+ | |
+ SetX509Attr(self, attr_new); | |
+ X509_ATTRIBUTE_free(attr); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* attr.oid = string => string | |
@@ -178,14 +197,6 @@ ossl_x509attr_get_oid(VALUE self) | |
return ret; | |
} | |
-#if defined(HAVE_ST_X509_ATTRIBUTE_SINGLE) || defined(HAVE_ST_SINGLE) | |
-# define OSSL_X509ATTR_IS_SINGLE(attr) ((attr)->single) | |
-# define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->single = 1) | |
-#else | |
-# define OSSL_X509ATTR_IS_SINGLE(attr) (!(attr)->value.set) | |
-# define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->value.set = 0) | |
-#endif | |
- | |
/* | |
* call-seq: | |
* attr.value = asn1 => asn1 | |
@@ -194,21 +205,37 @@ static VALUE | |
ossl_x509attr_set_value(VALUE self, VALUE value) | |
{ | |
X509_ATTRIBUTE *attr; | |
- ASN1_TYPE *a1type; | |
+ VALUE asn1_value; | |
+ int i, asn1_tag; | |
+ | |
+ OSSL_Check_Kind(value, cASN1Data); | |
+ asn1_tag = NUM2INT(rb_attr_get(value, rb_intern("@tag"))); | |
+ asn1_value = rb_attr_get(value, rb_intern("@value")); | |
+ if (asn1_tag != V_ASN1_SET) | |
+ ossl_raise(eASN1Error, "argument must be ASN1::Set"); | |
+ if (!RB_TYPE_P(asn1_value, T_ARRAY)) | |
+ ossl_raise(eASN1Error, "ASN1::Set has non-array value"); | |
- if(!(a1type = ossl_asn1_get_asn1type(value))) | |
- ossl_raise(eASN1Error, "could not get ASN1_TYPE"); | |
- if(ASN1_TYPE_get(a1type) == V_ASN1_SEQUENCE){ | |
- ASN1_TYPE_free(a1type); | |
- ossl_raise(eASN1Error, "couldn't set SEQUENCE for attribute value."); | |
- } | |
GetX509Attr(self, attr); | |
- if(attr->value.set){ | |
- if(OSSL_X509ATTR_IS_SINGLE(attr)) ASN1_TYPE_free(attr->value.single); | |
- else sk_ASN1_TYPE_free(attr->value.set); | |
+ if (X509_ATTRIBUTE_count(attr)) { /* populated, reset first */ | |
+ ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr); | |
+ X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, 0, NULL, -1); | |
+ if (!new_attr) | |
+ ossl_raise(eX509AttrError, NULL); | |
+ SetX509Attr(self, new_attr); | |
+ X509_ATTRIBUTE_free(attr); | |
+ attr = new_attr; | |
+ } | |
+ | |
+ for (i = 0; i < RARRAY_LEN(asn1_value); i++) { | |
+ ASN1_TYPE *a1type = ossl_asn1_get_asn1type(RARRAY_AREF(asn1_value, i)); | |
+ if (!X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type), | |
+ a1type->value.ptr, -1)) { | |
+ ASN1_TYPE_free(a1type); | |
+ ossl_raise(eX509AttrError, NULL); | |
+ } | |
+ ASN1_TYPE_free(a1type); | |
} | |
- OSSL_X509ATTR_SET_SINGLE(attr); | |
- attr->value.single = a1type; | |
return value; | |
} | |
@@ -221,32 +248,34 @@ static VALUE | |
ossl_x509attr_get_value(VALUE self) | |
{ | |
X509_ATTRIBUTE *attr; | |
- VALUE str, asn1; | |
- long length; | |
+ STACK_OF(ASN1_TYPE) *sk; | |
+ VALUE str; | |
+ int i, count, len; | |
unsigned char *p; | |
GetX509Attr(self, attr); | |
- if(attr->value.ptr == NULL) return Qnil; | |
- if(OSSL_X509ATTR_IS_SINGLE(attr)){ | |
- length = i2d_ASN1_TYPE(attr->value.single, NULL); | |
- str = rb_str_new(0, length); | |
- p = (unsigned char *)RSTRING_PTR(str); | |
- i2d_ASN1_TYPE(attr->value.single, &p); | |
- ossl_str_adjust(str, p); | |
+ /* there is no X509_ATTRIBUTE_get0_set() :( */ | |
+ if (!(sk = sk_ASN1_TYPE_new_null())) | |
+ ossl_raise(eX509AttrError, "sk_new"); | |
+ | |
+ count = X509_ATTRIBUTE_count(attr); | |
+ for (i = 0; i < count; i++) | |
+ sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i)); | |
+ | |
+ if ((len = i2d_ASN1_SET_ANY(sk, NULL)) <= 0) { | |
+ sk_ASN1_TYPE_free(sk); | |
+ ossl_raise(eX509AttrError, NULL); | |
} | |
- else{ | |
- length = i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, | |
- (unsigned char **) NULL, i2d_ASN1_TYPE, | |
- V_ASN1_SET, V_ASN1_UNIVERSAL, 0); | |
- str = rb_str_new(0, length); | |
- p = (unsigned char *)RSTRING_PTR(str); | |
- i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, &p, | |
- i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0); | |
- ossl_str_adjust(str, p); | |
+ str = rb_str_new(0, len); | |
+ p = (unsigned char *)RSTRING_PTR(str); | |
+ if (i2d_ASN1_SET_ANY(sk, &p) <= 0) { | |
+ sk_ASN1_TYPE_free(sk); | |
+ ossl_raise(eX509AttrError, NULL); | |
} | |
- asn1 = rb_funcall(mASN1, rb_intern("decode"), 1, str); | |
+ ossl_str_adjust(str, p); | |
+ sk_ASN1_TYPE_free(sk); | |
- return asn1; | |
+ return rb_funcall(mASN1, rb_intern("decode"), 1, str); | |
} | |
/* | |
@@ -268,7 +297,7 @@ ossl_x509attr_to_der(VALUE self) | |
p = (unsigned char *)RSTRING_PTR(str); | |
if(i2d_X509_ATTRIBUTE(attr, &p) <= 0) | |
ossl_raise(eX509AttrError, NULL); | |
- rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str)); | |
+ ossl_str_adjust(str, p); | |
return str; | |
} | |
@@ -279,11 +308,18 @@ ossl_x509attr_to_der(VALUE self) | |
void | |
Init_ossl_x509attr(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ mX509 = rb_define_module_under(mOSSL, "X509"); | |
+#endif | |
+ | |
eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError); | |
cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject); | |
rb_define_alloc_func(cX509Attr, ossl_x509attr_alloc); | |
rb_define_method(cX509Attr, "initialize", ossl_x509attr_initialize, -1); | |
+ rb_define_copy_func(cX509Attr, ossl_x509attr_initialize_copy); | |
rb_define_method(cX509Attr, "oid=", ossl_x509attr_set_oid, 1); | |
rb_define_method(cX509Attr, "oid", ossl_x509attr_get_oid, 0); | |
rb_define_method(cX509Attr, "value=", ossl_x509attr_set_value, 1); | |
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c | |
index 9cf7405256..cecc3ca09a 100644 | |
--- a/ext/openssl/ossl_x509cert.c | |
+++ b/ext/openssl/ossl_x509cert.c | |
@@ -78,9 +78,9 @@ ossl_x509_new_from_file(VALUE filename) | |
FILE *fp; | |
VALUE obj; | |
- SafeStringValue(filename); | |
+ rb_check_safe_obj(filename); | |
obj = NewX509(cX509Cert); | |
- if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { | |
+ if (!(fp = fopen(StringValueCStr(filename), "r"))) { | |
ossl_raise(eX509CertError, "%s", strerror(errno)); | |
} | |
rb_fd_fix_cloexec(fileno(fp)); | |
@@ -122,7 +122,7 @@ DupX509CertPtr(VALUE obj) | |
SafeGetX509(obj, x509); | |
- CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); | |
+ X509_up_ref(x509); | |
return x509; | |
} | |
@@ -161,7 +161,7 @@ ossl_x509_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
arg = ossl_to_der_if_possible(arg); | |
- in = ossl_obj2bio(&arg); | |
+ in = ossl_obj2bio(arg); | |
x509 = PEM_read_bio_X509(in, &x, NULL, NULL); | |
DATA_PTR(self) = x; | |
if (!x509) { | |
@@ -349,9 +349,7 @@ ossl_x509_set_serial(VALUE self, VALUE num) | |
X509 *x509; | |
GetX509(self, x509); | |
- | |
- x509->cert_info->serialNumber = | |
- num_to_asn1integer(num, X509_get_serialNumber(x509)); | |
+ X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509))); | |
return num; | |
} | |
@@ -371,7 +369,7 @@ ossl_x509_get_signature_algorithm(VALUE self) | |
out = BIO_new(BIO_s_mem()); | |
if (!out) ossl_raise(eX509CertError, NULL); | |
- if (!i2a_ASN1_OBJECT(out, x509->cert_info->signature->algorithm)) { | |
+ if (!i2a_ASN1_OBJECT(out, X509_get0_tbs_sigalg(x509)->algorithm)) { | |
BIO_free(out); | |
ossl_raise(eX509CertError, NULL); | |
} | |
@@ -458,10 +456,10 @@ static VALUE | |
ossl_x509_get_not_before(VALUE self) | |
{ | |
X509 *x509; | |
- ASN1_UTCTIME *asn1time; | |
+ const ASN1_TIME *asn1time; | |
GetX509(self, x509); | |
- if (!(asn1time = X509_get_notBefore(x509))) { /* NO DUP - don't free! */ | |
+ if (!(asn1time = X509_get0_notBefore(x509))) { | |
ossl_raise(eX509CertError, NULL); | |
} | |
@@ -476,13 +474,15 @@ static VALUE | |
ossl_x509_set_not_before(VALUE self, VALUE time) | |
{ | |
X509 *x509; | |
- time_t sec; | |
+ ASN1_TIME *asn1time; | |
- sec = time_to_time_t(time); | |
GetX509(self, x509); | |
- if (!X509_time_adj(X509_get_notBefore(x509), 0, &sec)) { | |
- ossl_raise(eX509CertError, NULL); | |
+ asn1time = ossl_x509_time_adjust(NULL, time); | |
+ if (!X509_set_notBefore(x509, asn1time)) { | |
+ ASN1_TIME_free(asn1time); | |
+ ossl_raise(eX509CertError, "X509_set_notBefore"); | |
} | |
+ ASN1_TIME_free(asn1time); | |
return time; | |
} | |
@@ -495,10 +495,10 @@ static VALUE | |
ossl_x509_get_not_after(VALUE self) | |
{ | |
X509 *x509; | |
- ASN1_TIME *asn1time; | |
+ const ASN1_TIME *asn1time; | |
GetX509(self, x509); | |
- if (!(asn1time = X509_get_notAfter(x509))) { /* NO DUP - don't free! */ | |
+ if (!(asn1time = X509_get0_notAfter(x509))) { | |
ossl_raise(eX509CertError, NULL); | |
} | |
@@ -513,13 +513,15 @@ static VALUE | |
ossl_x509_set_not_after(VALUE self, VALUE time) | |
{ | |
X509 *x509; | |
- time_t sec; | |
+ ASN1_TIME *asn1time; | |
- sec = time_to_time_t(time); | |
GetX509(self, x509); | |
- if (!X509_time_adj(X509_get_notAfter(x509), 0, &sec)) { | |
- ossl_raise(eX509CertError, NULL); | |
+ asn1time = ossl_x509_time_adjust(NULL, time); | |
+ if (!X509_set_notAfter(x509, asn1time)) { | |
+ ASN1_TIME_free(asn1time); | |
+ ossl_raise(eX509CertError, "X509_set_notAfter"); | |
} | |
+ ASN1_TIME_free(asn1time); | |
return time; | |
} | |
@@ -591,18 +593,19 @@ ossl_x509_verify(VALUE self, VALUE key) | |
{ | |
X509 *x509; | |
EVP_PKEY *pkey; | |
- int i; | |
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ | |
GetX509(self, x509); | |
- if ((i = X509_verify(x509, pkey)) < 0) { | |
- ossl_raise(eX509CertError, NULL); | |
- } | |
- if (i > 0) { | |
+ | |
+ switch (X509_verify(x509, pkey)) { | |
+ case 1: | |
return Qtrue; | |
+ case 0: | |
+ ossl_clear_error(); | |
+ return Qfalse; | |
+ default: | |
+ ossl_raise(eX509CertError, NULL); | |
} | |
- | |
- return Qfalse; | |
} | |
/* | |
@@ -621,7 +624,7 @@ ossl_x509_check_private_key(VALUE self, VALUE key) | |
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ | |
GetX509(self, x509); | |
if (!X509_check_private_key(x509, pkey)) { | |
- OSSL_Warning("Check private key:%s", OSSL_ErrMsg()); | |
+ ossl_clear_error(); | |
return Qfalse; | |
} | |
@@ -671,16 +674,13 @@ ossl_x509_set_extensions(VALUE self, VALUE ary) | |
OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext); | |
} | |
GetX509(self, x509); | |
- sk_X509_EXTENSION_pop_free(x509->cert_info->extensions, X509_EXTENSION_free); | |
- x509->cert_info->extensions = NULL; | |
+ while ((ext = X509_delete_ext(x509, 0))) | |
+ X509_EXTENSION_free(ext); | |
for (i=0; i<RARRAY_LEN(ary); i++) { | |
- ext = DupX509ExtPtr(RARRAY_AREF(ary, i)); | |
- | |
- if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */ | |
- X509_EXTENSION_free(ext); | |
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); | |
+ if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */ | |
ossl_raise(eX509CertError, NULL); | |
} | |
- X509_EXTENSION_free(ext); | |
} | |
return ary; | |
@@ -697,12 +697,10 @@ ossl_x509_add_extension(VALUE self, VALUE extension) | |
X509_EXTENSION *ext; | |
GetX509(self, x509); | |
- ext = DupX509ExtPtr(extension); | |
+ ext = GetX509ExtPtr(extension); | |
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */ | |
- X509_EXTENSION_free(ext); | |
ossl_raise(eX509CertError, NULL); | |
} | |
- X509_EXTENSION_free(ext); | |
return extension; | |
} | |
@@ -727,9 +725,9 @@ ossl_x509_inspect(VALUE self) | |
void | |
Init_ossl_x509cert(void) | |
{ | |
- | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
mX509 = rb_define_module_under(mOSSL, "X509"); | |
#endif | |
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c | |
index e5a5c6b183..f9819f5824 100644 | |
--- a/ext/openssl/ossl_x509crl.c | |
+++ b/ext/openssl/ossl_x509crl.c | |
@@ -67,7 +67,7 @@ DupX509CRLPtr(VALUE obj) | |
X509_CRL *crl; | |
SafeGetX509CRL(obj, crl); | |
- CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL); | |
+ X509_CRL_up_ref(crl); | |
return crl; | |
} | |
@@ -115,7 +115,7 @@ ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
arg = ossl_to_der_if_possible(arg); | |
- in = ossl_obj2bio(&arg); | |
+ in = ossl_obj2bio(arg); | |
crl = PEM_read_bio_X509_CRL(in, &x, NULL, NULL); | |
DATA_PTR(self) = x; | |
if (!crl) { | |
@@ -180,22 +180,20 @@ static VALUE | |
ossl_x509crl_get_signature_algorithm(VALUE self) | |
{ | |
X509_CRL *crl; | |
+ const X509_ALGOR *alg; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetX509CRL(self, crl); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eX509CRLError, NULL); | |
} | |
- if (!i2a_ASN1_OBJECT(out, crl->sig_alg->algorithm)) { | |
+ X509_CRL_get0_signature(crl, NULL, &alg); | |
+ if (!i2a_ASN1_OBJECT(out, alg->algorithm)) { | |
BIO_free(out); | |
ossl_raise(eX509CRLError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ | |
+ return ossl_membio2str(out); | |
} | |
static VALUE | |
@@ -228,20 +226,22 @@ ossl_x509crl_get_last_update(VALUE self) | |
GetX509CRL(self, crl); | |
- return asn1time_to_time(X509_CRL_get_lastUpdate(crl)); | |
+ return asn1time_to_time(X509_CRL_get0_lastUpdate(crl)); | |
} | |
static VALUE | |
ossl_x509crl_set_last_update(VALUE self, VALUE time) | |
{ | |
X509_CRL *crl; | |
- time_t sec; | |
+ ASN1_TIME *asn1time; | |
- sec = time_to_time_t(time); | |
GetX509CRL(self, crl); | |
- if (!X509_time_adj(crl->crl->lastUpdate, 0, &sec)) { | |
- ossl_raise(eX509CRLError, NULL); | |
+ asn1time = ossl_x509_time_adjust(NULL, time); | |
+ if (!X509_CRL_set_lastUpdate(crl, asn1time)) { | |
+ ASN1_TIME_free(asn1time); | |
+ ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate"); | |
} | |
+ ASN1_TIME_free(asn1time); | |
return time; | |
} | |
@@ -253,21 +253,22 @@ ossl_x509crl_get_next_update(VALUE self) | |
GetX509CRL(self, crl); | |
- return asn1time_to_time(X509_CRL_get_nextUpdate(crl)); | |
+ return asn1time_to_time(X509_CRL_get0_nextUpdate(crl)); | |
} | |
static VALUE | |
ossl_x509crl_set_next_update(VALUE self, VALUE time) | |
{ | |
X509_CRL *crl; | |
- time_t sec; | |
+ ASN1_TIME *asn1time; | |
- sec = time_to_time_t(time); | |
GetX509CRL(self, crl); | |
- /* This must be some thinko in OpenSSL */ | |
- if (!(crl->crl->nextUpdate = X509_time_adj(crl->crl->nextUpdate, 0, &sec))){ | |
- ossl_raise(eX509CRLError, NULL); | |
+ asn1time = ossl_x509_time_adjust(NULL, time); | |
+ if (!X509_CRL_set_nextUpdate(crl, asn1time)) { | |
+ ASN1_TIME_free(asn1time); | |
+ ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate"); | |
} | |
+ ASN1_TIME_free(asn1time); | |
return time; | |
} | |
@@ -302,6 +303,7 @@ ossl_x509crl_set_revoked(VALUE self, VALUE ary) | |
{ | |
X509_CRL *crl; | |
X509_REVOKED *rev; | |
+ STACK_OF(X509_REVOKED) *sk; | |
long i; | |
Check_Type(ary, T_ARRAY); | |
@@ -310,8 +312,10 @@ ossl_x509crl_set_revoked(VALUE self, VALUE ary) | |
OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev); | |
} | |
GetX509CRL(self, crl); | |
- sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free); | |
- crl->crl->revoked = NULL; | |
+ if ((sk = X509_CRL_get_REVOKED(crl))) { | |
+ while ((rev = sk_X509_REVOKED_pop(sk))) | |
+ X509_REVOKED_free(rev); | |
+ } | |
for (i=0; i<RARRAY_LEN(ary); i++) { | |
rev = DupX509RevokedPtr(RARRAY_AREF(ary, i)); | |
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */ | |
@@ -362,17 +366,17 @@ static VALUE | |
ossl_x509crl_verify(VALUE self, VALUE key) | |
{ | |
X509_CRL *crl; | |
- int ret; | |
GetX509CRL(self, crl); | |
- if ((ret = X509_CRL_verify(crl, GetPKeyPtr(key))) < 0) { | |
- ossl_raise(eX509CRLError, NULL); | |
- } | |
- if (ret == 1) { | |
+ switch (X509_CRL_verify(crl, GetPKeyPtr(key))) { | |
+ case 1: | |
return Qtrue; | |
+ case 0: | |
+ ossl_clear_error(); | |
+ return Qfalse; | |
+ default: | |
+ ossl_raise(eX509CRLError, NULL); | |
} | |
- | |
- return Qfalse; | |
} | |
static VALUE | |
@@ -380,8 +384,6 @@ ossl_x509crl_to_der(VALUE self) | |
{ | |
X509_CRL *crl; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetX509CRL(self, crl); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
@@ -391,11 +393,8 @@ ossl_x509crl_to_der(VALUE self) | |
BIO_free(out); | |
ossl_raise(eX509CRLError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
static VALUE | |
@@ -403,8 +402,6 @@ ossl_x509crl_to_pem(VALUE self) | |
{ | |
X509_CRL *crl; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetX509CRL(self, crl); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
@@ -414,11 +411,8 @@ ossl_x509crl_to_pem(VALUE self) | |
BIO_free(out); | |
ossl_raise(eX509CRLError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
static VALUE | |
@@ -426,8 +420,6 @@ ossl_x509crl_to_text(VALUE self) | |
{ | |
X509_CRL *crl; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetX509CRL(self, crl); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
@@ -437,11 +429,8 @@ ossl_x509crl_to_text(VALUE self) | |
BIO_free(out); | |
ossl_raise(eX509CRLError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
/* | |
@@ -486,15 +475,13 @@ ossl_x509crl_set_extensions(VALUE self, VALUE ary) | |
OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext); | |
} | |
GetX509CRL(self, crl); | |
- sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free); | |
- crl->crl->extensions = NULL; | |
+ while ((ext = X509_CRL_delete_ext(crl, 0))) | |
+ X509_EXTENSION_free(ext); | |
for (i=0; i<RARRAY_LEN(ary); i++) { | |
- ext = DupX509ExtPtr(RARRAY_AREF(ary, i)); | |
- if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */ | |
- X509_EXTENSION_free(ext); | |
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */ | |
+ if (!X509_CRL_add_ext(crl, ext, -1)) { | |
ossl_raise(eX509CRLError, NULL); | |
} | |
- X509_EXTENSION_free(ext); | |
} | |
return ary; | |
@@ -507,12 +494,10 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension) | |
X509_EXTENSION *ext; | |
GetX509CRL(self, crl); | |
- ext = DupX509ExtPtr(extension); | |
- if (!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */ | |
- X509_EXTENSION_free(ext); | |
+ ext = GetX509ExtPtr(extension); | |
+ if (!X509_CRL_add_ext(crl, ext, -1)) { | |
ossl_raise(eX509CRLError, NULL); | |
} | |
- X509_EXTENSION_free(ext); | |
return extension; | |
} | |
@@ -523,6 +508,12 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension) | |
void | |
Init_ossl_x509crl(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ mX509 = rb_define_module_under(mOSSL, "X509"); | |
+#endif | |
+ | |
eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError); | |
cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject); | |
diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c | |
index f1058a0c1f..b92b0786b2 100644 | |
--- a/ext/openssl/ossl_x509ext.c | |
+++ b/ext/openssl/ossl_x509ext.c | |
@@ -95,19 +95,6 @@ GetX509ExtPtr(VALUE obj) | |
return ext; | |
} | |
-X509_EXTENSION * | |
-DupX509ExtPtr(VALUE obj) | |
-{ | |
- X509_EXTENSION *ext, *new; | |
- | |
- SafeGetX509Ext(obj, ext); | |
- if (!(new = X509_EXTENSION_dup(ext))) { | |
- ossl_raise(eX509ExtError, NULL); | |
- } | |
- | |
- return new; | |
-} | |
- | |
/* | |
* Private | |
*/ | |
@@ -211,12 +198,11 @@ ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self) | |
} | |
/* | |
- * Array to X509_EXTENSION | |
- * Structure: | |
- * ["ln", "value", bool_critical] or | |
- * ["sn", "value", bool_critical] or | |
- * ["ln", "critical,value"] or the same for sn | |
- * ["ln", "value"] => not critical | |
+ * call-seq: | |
+ * ef.create_ext(ln_or_sn, "value", critical = false) -> X509::Extension | |
+ * ef.create_ext(ln_or_sn, "critical,value") -> X509::Extension | |
+ * | |
+ * Creates a new X509::Extension with passed values. See also x509v3_config(5). | |
*/ | |
static VALUE | |
ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self) | |
@@ -225,39 +211,32 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self) | |
X509_EXTENSION *ext; | |
VALUE oid, value, critical, valstr, obj; | |
int nid; | |
-#ifdef HAVE_X509V3_EXT_NCONF_NID | |
VALUE rconf; | |
CONF *conf; | |
-#else | |
- static LHASH *empty_lhash; | |
-#endif | |
rb_scan_args(argc, argv, "21", &oid, &value, &critical); | |
- StringValue(oid); | |
+ StringValueCStr(oid); | |
StringValue(value); | |
if(NIL_P(critical)) critical = Qfalse; | |
nid = OBJ_ln2nid(RSTRING_PTR(oid)); | |
if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid)); | |
- if(!nid) ossl_raise(eX509ExtError, "unknown OID `%s'", RSTRING_PTR(oid)); | |
+ if(!nid) ossl_raise(eX509ExtError, "unknown OID `%"PRIsVALUE"'", oid); | |
+ | |
valstr = rb_str_new2(RTEST(critical) ? "critical," : ""); | |
rb_str_append(valstr, value); | |
+ StringValueCStr(valstr); | |
+ | |
GetX509ExtFactory(self, ctx); | |
obj = NewX509Ext(cX509Ext); | |
-#ifdef HAVE_X509V3_EXT_NCONF_NID | |
rconf = rb_iv_get(self, "@config"); | |
conf = NIL_P(rconf) ? NULL : DupConfigPtr(rconf); | |
X509V3_set_nconf(ctx, conf); | |
ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr)); | |
X509V3_set_ctx_nodb(ctx); | |
NCONF_free(conf); | |
-#else | |
- if (!empty_lhash) empty_lhash = lh_new(NULL, NULL); | |
- ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING_PTR(valstr)); | |
-#endif | |
if (!ext){ | |
- ossl_raise(eX509ExtError, "%s = %s", | |
- RSTRING_PTR(oid), RSTRING_PTR(value)); | |
+ ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr); | |
} | |
SetX509Ext(obj, ext); | |
@@ -319,6 +298,25 @@ ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+ossl_x509ext_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ X509_EXTENSION *ext, *ext_other, *ext_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetX509Ext(self, ext); | |
+ SafeGetX509Ext(other, ext_other); | |
+ | |
+ ext_new = X509_EXTENSION_dup(ext_other); | |
+ if (!ext_new) | |
+ ossl_raise(eX509ExtError, "X509_EXTENSION_dup"); | |
+ | |
+ SetX509Ext(self, ext_new); | |
+ X509_EXTENSION_free(ext); | |
+ | |
+ return self; | |
+} | |
+ | |
static VALUE | |
ossl_x509ext_set_oid(VALUE self, VALUE oid) | |
{ | |
@@ -402,7 +400,7 @@ ossl_x509ext_get_value(VALUE obj) | |
if (!(out = BIO_new(BIO_s_mem()))) | |
ossl_raise(eX509ExtError, NULL); | |
if (!X509V3_EXT_print(out, ext, 0, 0)) | |
- M_ASN1_OCTET_STRING_print(out, ext->value); | |
+ ASN1_STRING_print(out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); | |
ret = ossl_membio2str(out); | |
return ret; | |
@@ -443,6 +441,12 @@ ossl_x509ext_to_der(VALUE obj) | |
void | |
Init_ossl_x509ext(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ mX509 = rb_define_module_under(mOSSL, "X509"); | |
+#endif | |
+ | |
eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError); | |
cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject); | |
@@ -465,6 +469,7 @@ Init_ossl_x509ext(void) | |
cX509Ext = rb_define_class_under(mX509, "Extension", rb_cObject); | |
rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc); | |
rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1); | |
+ rb_define_copy_func(cX509Ext, ossl_x509ext_initialize_copy); | |
rb_define_method(cX509Ext, "oid=", ossl_x509ext_set_oid, 1); | |
rb_define_method(cX509Ext, "value=", ossl_x509ext_set_value, 1); | |
rb_define_method(cX509Ext, "critical=", ossl_x509ext_set_critical, 1); | |
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c | |
index d4e85a80b7..4523e0d71e 100644 | |
--- a/ext/openssl/ossl_x509name.c | |
+++ b/ext/openssl/ossl_x509name.c | |
@@ -181,6 +181,25 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+ossl_x509name_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ X509_NAME *name, *name_other, *name_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetX509Name(self, name); | |
+ SafeGetX509Name(other, name_other); | |
+ | |
+ name_new = X509_NAME_dup(name_other); | |
+ if (!name_new) | |
+ ossl_raise(eX509NameError, "X509_NAME_dup"); | |
+ | |
+ SetX509Name(self, name_new); | |
+ X509_NAME_free(name); | |
+ | |
+ return self; | |
+} | |
+ | |
/* | |
* call-seq: | |
* name.add_entry(oid, value [, type]) => self | |
@@ -282,6 +301,7 @@ ossl_x509name_to_a(VALUE self) | |
char long_name[512]; | |
const char *short_name; | |
VALUE ary, vname, ret; | |
+ ASN1_STRING *value; | |
GetX509Name(self, name); | |
entries = X509_NAME_entry_count(name); | |
@@ -294,7 +314,8 @@ ossl_x509name_to_a(VALUE self) | |
if (!(entry = X509_NAME_get_entry(name, i))) { | |
ossl_raise(eX509NameError, NULL); | |
} | |
- if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name), entry->object)) { | |
+ if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name), | |
+ X509_NAME_ENTRY_get_object(entry))) { | |
ossl_raise(eX509NameError, NULL); | |
} | |
nid = OBJ_ln2nid(long_name); | |
@@ -304,10 +325,8 @@ ossl_x509name_to_a(VALUE self) | |
short_name = OBJ_nid2sn(nid); | |
vname = rb_str_new2(short_name); /*do not free*/ | |
} | |
- ary = rb_ary_new3(3, | |
- vname, | |
- rb_str_new((const char *)entry->value->data, entry->value->length), | |
- INT2FIX(entry->value->type)); | |
+ value = X509_NAME_ENTRY_get_data(entry); | |
+ ary = rb_ary_new3(3, vname, asn1str_to_str(value), INT2NUM(value->type)); | |
rb_ary_push(ret, ary); | |
} | |
return ret; | |
@@ -339,7 +358,7 @@ ossl_x509name_cmp(VALUE self, VALUE other) | |
result = ossl_x509name_cmp0(self, other); | |
if (result < 0) return INT2FIX(-1); | |
- if (result > 0) return INT2FIX(1); | |
+ if (result > 1) return INT2FIX(1); | |
return INT2FIX(0); | |
} | |
@@ -353,12 +372,10 @@ ossl_x509name_cmp(VALUE self, VALUE other) | |
static VALUE | |
ossl_x509name_eql(VALUE self, VALUE other) | |
{ | |
- int result; | |
+ if (!rb_obj_is_kind_of(other, cX509Name)) | |
+ return Qfalse; | |
- if(CLASS_OF(other) != cX509Name) return Qfalse; | |
- result = ossl_x509name_cmp0(self, other); | |
- | |
- return (result == 0) ? Qtrue : Qfalse; | |
+ return ossl_x509name_cmp0(self, other) ? Qtrue : Qfalse; | |
} | |
/* | |
@@ -447,6 +464,12 @@ Init_ossl_x509name(void) | |
{ | |
VALUE utf8str, ptrstr, ia5str, hash; | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ mX509 = rb_define_module_under(mOSSL, "X509"); | |
+#endif | |
+ | |
id_aref = rb_intern("[]"); | |
eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError); | |
cX509Name = rb_define_class_under(mX509, "Name", rb_cObject); | |
@@ -455,6 +478,7 @@ Init_ossl_x509name(void) | |
rb_define_alloc_func(cX509Name, ossl_x509name_alloc); | |
rb_define_method(cX509Name, "initialize", ossl_x509name_initialize, -1); | |
+ rb_define_copy_func(cX509Name, ossl_x509name_initialize_copy); | |
rb_define_method(cX509Name, "add_entry", ossl_x509name_add_entry, -1); | |
rb_define_method(cX509Name, "to_s", ossl_x509name_to_s, -1); | |
rb_define_method(cX509Name, "to_a", ossl_x509name_to_a, 0); | |
@@ -471,8 +495,7 @@ Init_ossl_x509name(void) | |
ptrstr = INT2NUM(V_ASN1_PRINTABLESTRING); | |
ia5str = INT2NUM(V_ASN1_IA5STRING); | |
- /* Document-const: DEFAULT_OBJECT_TYPE | |
- * | |
+ /* | |
* The default object type for name entries. | |
*/ | |
rb_define_const(cX509Name, "DEFAULT_OBJECT_TYPE", utf8str); | |
@@ -486,14 +509,12 @@ Init_ossl_x509name(void) | |
rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str); | |
rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str); | |
- /* Document-const: OBJECT_TYPE_TEMPLATE | |
- * | |
+ /* | |
* The default object type template for name entries. | |
*/ | |
rb_define_const(cX509Name, "OBJECT_TYPE_TEMPLATE", hash); | |
- /* Document-const: COMPAT | |
- * | |
+ /* | |
* A flag for #to_s. | |
* | |
* Breaks the name returned into multiple lines if longer than 80 | |
@@ -501,24 +522,21 @@ Init_ossl_x509name(void) | |
*/ | |
rb_define_const(cX509Name, "COMPAT", ULONG2NUM(XN_FLAG_COMPAT)); | |
- /* Document-const: RFC2253 | |
- * | |
+ /* | |
* A flag for #to_s. | |
* | |
* Returns an RFC2253 format name. | |
*/ | |
rb_define_const(cX509Name, "RFC2253", ULONG2NUM(XN_FLAG_RFC2253)); | |
- /* Document-const: ONELINE | |
- * | |
+ /* | |
* A flag for #to_s. | |
* | |
* Returns a more readable format than RFC2253. | |
*/ | |
rb_define_const(cX509Name, "ONELINE", ULONG2NUM(XN_FLAG_ONELINE)); | |
- /* Document-const: MULTILINE | |
- * | |
+ /* | |
* A flag for #to_s. | |
* | |
* Returns a multiline format. | |
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c | |
index 71a7e0120c..220d2f40d5 100644 | |
--- a/ext/openssl/ossl_x509req.c | |
+++ b/ext/openssl/ossl_x509req.c | |
@@ -123,7 +123,7 @@ ossl_x509req_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
arg = ossl_to_der_if_possible(arg); | |
- in = ossl_obj2bio(&arg); | |
+ in = ossl_obj2bio(arg); | |
req = PEM_read_bio_X509_REQ(in, &x, NULL, NULL); | |
DATA_PTR(self) = x; | |
if (!req) { | |
@@ -160,8 +160,6 @@ ossl_x509req_to_pem(VALUE self) | |
{ | |
X509_REQ *req; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetX509Req(self, req); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
@@ -171,11 +169,8 @@ ossl_x509req_to_pem(VALUE self) | |
BIO_free(out); | |
ossl_raise(eX509ReqError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
static VALUE | |
@@ -203,8 +198,6 @@ ossl_x509req_to_text(VALUE self) | |
{ | |
X509_REQ *req; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetX509Req(self, req); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
@@ -214,11 +207,8 @@ ossl_x509req_to_text(VALUE self) | |
BIO_free(out); | |
ossl_raise(eX509ReqError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ return ossl_membio2str(out); | |
} | |
#if 0 | |
@@ -250,7 +240,7 @@ ossl_x509req_get_version(VALUE self) | |
GetX509Req(self, req); | |
version = X509_REQ_get_version(req); | |
- return LONG2FIX(version); | |
+ return LONG2NUM(version); | |
} | |
static VALUE | |
@@ -259,12 +249,12 @@ ossl_x509req_set_version(VALUE self, VALUE version) | |
X509_REQ *req; | |
long ver; | |
- if ((ver = FIX2LONG(version)) < 0) { | |
+ if ((ver = NUM2LONG(version)) < 0) { | |
ossl_raise(eX509ReqError, "version must be >= 0!"); | |
} | |
GetX509Req(self, req); | |
if (!X509_REQ_set_version(req, ver)) { | |
- ossl_raise(eX509ReqError, NULL); | |
+ ossl_raise(eX509ReqError, "X509_REQ_set_version"); | |
} | |
return version; | |
@@ -302,23 +292,21 @@ static VALUE | |
ossl_x509req_get_signature_algorithm(VALUE self) | |
{ | |
X509_REQ *req; | |
+ const X509_ALGOR *alg; | |
BIO *out; | |
- BUF_MEM *buf; | |
- VALUE str; | |
GetX509Req(self, req); | |
if (!(out = BIO_new(BIO_s_mem()))) { | |
ossl_raise(eX509ReqError, NULL); | |
} | |
- if (!i2a_ASN1_OBJECT(out, req->sig_alg->algorithm)) { | |
+ X509_REQ_get0_signature(req, NULL, &alg); | |
+ if (!i2a_ASN1_OBJECT(out, alg->algorithm)) { | |
BIO_free(out); | |
ossl_raise(eX509ReqError, NULL); | |
} | |
- BIO_get_mem_ptr(out, &buf); | |
- str = rb_str_new(buf->data, buf->length); | |
- BIO_free(out); | |
- return str; | |
+ | |
+ return ossl_membio2str(out); | |
} | |
static VALUE | |
@@ -375,18 +363,18 @@ ossl_x509req_verify(VALUE self, VALUE key) | |
{ | |
X509_REQ *req; | |
EVP_PKEY *pkey; | |
- int i; | |
GetX509Req(self, req); | |
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ | |
- if ((i = X509_REQ_verify(req, pkey)) < 0) { | |
- ossl_raise(eX509ReqError, NULL); | |
- } | |
- if (i > 0) { | |
+ switch (X509_REQ_verify(req, pkey)) { | |
+ case 1: | |
return Qtrue; | |
+ case 0: | |
+ ossl_clear_error(); | |
+ return Qfalse; | |
+ default: | |
+ ossl_raise(eX509ReqError, NULL); | |
} | |
- | |
- return Qfalse; | |
} | |
static VALUE | |
@@ -426,8 +414,8 @@ ossl_x509req_set_attributes(VALUE self, VALUE ary) | |
OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr); | |
} | |
GetX509Req(self, req); | |
- sk_X509_ATTRIBUTE_pop_free(req->req_info->attributes, X509_ATTRIBUTE_free); | |
- req->req_info->attributes = NULL; | |
+ while ((attr = X509_REQ_delete_attr(req, 0))) | |
+ X509_ATTRIBUTE_free(attr); | |
for (i=0;i<RARRAY_LEN(ary); i++) { | |
item = RARRAY_AREF(ary, i); | |
attr = GetX509AttrPtr(item); | |
@@ -457,6 +445,12 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr) | |
void | |
Init_ossl_x509req(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ mX509 = rb_define_module_under(mOSSL, "X509"); | |
+#endif | |
+ | |
eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError); | |
cX509Req = rb_define_class_under(mX509, "Request", rb_cObject); | |
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c | |
index 4691d507d3..7960ea349e 100644 | |
--- a/ext/openssl/ossl_x509revoked.c | |
+++ b/ext/openssl/ossl_x509revoked.c | |
@@ -109,6 +109,25 @@ ossl_x509revoked_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+static VALUE | |
+ossl_x509revoked_initialize_copy(VALUE self, VALUE other) | |
+{ | |
+ X509_REVOKED *rev, *rev_other, *rev_new; | |
+ | |
+ rb_check_frozen(self); | |
+ GetX509Rev(self, rev); | |
+ SafeGetX509Rev(other, rev_other); | |
+ | |
+ rev_new = X509_REVOKED_dup(rev_other); | |
+ if (!rev_new) | |
+ ossl_raise(eX509RevError, "X509_REVOKED_dup"); | |
+ | |
+ SetX509Rev(self, rev_new); | |
+ X509_REVOKED_free(rev); | |
+ | |
+ return self; | |
+} | |
+ | |
static VALUE | |
ossl_x509revoked_get_serial(VALUE self) | |
{ | |
@@ -116,16 +135,22 @@ ossl_x509revoked_get_serial(VALUE self) | |
GetX509Rev(self, rev); | |
- return asn1integer_to_num(rev->serialNumber); | |
+ return asn1integer_to_num(X509_REVOKED_get0_serialNumber(rev)); | |
} | |
static VALUE | |
ossl_x509revoked_set_serial(VALUE self, VALUE num) | |
{ | |
X509_REVOKED *rev; | |
+ ASN1_INTEGER *asn1int; | |
GetX509Rev(self, rev); | |
- rev->serialNumber = num_to_asn1integer(num, rev->serialNumber); | |
+ asn1int = num_to_asn1integer(num, NULL); | |
+ if (!X509_REVOKED_set_serialNumber(rev, asn1int)) { | |
+ ASN1_INTEGER_free(asn1int); | |
+ ossl_raise(eX509RevError, "X509_REVOKED_set_serialNumber"); | |
+ } | |
+ ASN1_INTEGER_free(asn1int); | |
return num; | |
} | |
@@ -137,20 +162,22 @@ ossl_x509revoked_get_time(VALUE self) | |
GetX509Rev(self, rev); | |
- return asn1time_to_time(rev->revocationDate); | |
+ return asn1time_to_time(X509_REVOKED_get0_revocationDate(rev)); | |
} | |
static VALUE | |
ossl_x509revoked_set_time(VALUE self, VALUE time) | |
{ | |
X509_REVOKED *rev; | |
- time_t sec; | |
+ ASN1_TIME *asn1time; | |
- sec = time_to_time_t(time); | |
GetX509Rev(self, rev); | |
- if (!X509_time_adj(rev->revocationDate, 0, &sec)) { | |
- ossl_raise(eX509RevError, NULL); | |
+ asn1time = ossl_x509_time_adjust(NULL, time); | |
+ if (!X509_REVOKED_set_revocationDate(rev, asn1time)) { | |
+ ASN1_TIME_free(asn1time); | |
+ ossl_raise(eX509RevError, "X509_REVOKED_set_revocationDate"); | |
} | |
+ ASN1_TIME_free(asn1time); | |
return time; | |
} | |
@@ -196,8 +223,8 @@ ossl_x509revoked_set_extensions(VALUE self, VALUE ary) | |
OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext); | |
} | |
GetX509Rev(self, rev); | |
- sk_X509_EXTENSION_pop_free(rev->extensions, X509_EXTENSION_free); | |
- rev->extensions = NULL; | |
+ while ((ext = X509_REVOKED_delete_ext(rev, 0))) | |
+ X509_EXTENSION_free(ext); | |
for (i=0; i<RARRAY_LEN(ary); i++) { | |
item = RARRAY_AREF(ary, i); | |
ext = GetX509ExtPtr(item); | |
@@ -228,12 +255,19 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext) | |
void | |
Init_ossl_x509revoked(void) | |
{ | |
+#if 0 | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
+ mX509 = rb_define_module_under(mOSSL, "X509"); | |
+#endif | |
+ | |
eX509RevError = rb_define_class_under(mX509, "RevokedError", eOSSLError); | |
cX509Rev = rb_define_class_under(mX509, "Revoked", rb_cObject); | |
rb_define_alloc_func(cX509Rev, ossl_x509revoked_alloc); | |
rb_define_method(cX509Rev, "initialize", ossl_x509revoked_initialize, -1); | |
+ rb_define_copy_func(cX509Rev, ossl_x509revoked_initialize_copy); | |
rb_define_method(cX509Rev, "serial", ossl_x509revoked_get_serial, 0); | |
rb_define_method(cX509Rev, "serial=", ossl_x509revoked_set_serial, 1); | |
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c | |
index cec9dbbb44..eb81e0d473 100644 | |
--- a/ext/openssl/ossl_x509store.c | |
+++ b/ext/openssl/ossl_x509store.c | |
@@ -47,6 +47,65 @@ | |
GetX509Store((obj), (ctx)); \ | |
} while (0) | |
+/* | |
+ * Verify callback stuff | |
+ */ | |
+static int stctx_ex_verify_cb_idx, store_ex_verify_cb_idx; | |
+static VALUE ossl_x509stctx_new(X509_STORE_CTX *); | |
+ | |
+struct ossl_verify_cb_args { | |
+ VALUE proc; | |
+ VALUE preverify_ok; | |
+ VALUE store_ctx; | |
+}; | |
+ | |
+static VALUE | |
+call_verify_cb_proc(struct ossl_verify_cb_args *args) | |
+{ | |
+ return rb_funcall(args->proc, rb_intern("call"), 2, | |
+ args->preverify_ok, args->store_ctx); | |
+} | |
+ | |
+int | |
+ossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx) | |
+{ | |
+ VALUE rctx, ret; | |
+ struct ossl_verify_cb_args args; | |
+ int state; | |
+ | |
+ if (NIL_P(proc)) | |
+ return ok; | |
+ | |
+ ret = Qfalse; | |
+ rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new, (VALUE)ctx, &state); | |
+ if (state) { | |
+ rb_set_errinfo(Qnil); | |
+ rb_warn("StoreContext initialization failure"); | |
+ } | |
+ else { | |
+ args.proc = proc; | |
+ args.preverify_ok = ok ? Qtrue : Qfalse; | |
+ args.store_ctx = rctx; | |
+ ret = rb_protect((VALUE(*)(VALUE))call_verify_cb_proc, (VALUE)&args, &state); | |
+ if (state) { | |
+ rb_set_errinfo(Qnil); | |
+ rb_warn("exception in verify_callback is ignored"); | |
+ } | |
+ RTYPEDDATA_DATA(rctx) = NULL; | |
+ } | |
+ if (ret == Qtrue) { | |
+ X509_STORE_CTX_set_error(ctx, X509_V_OK); | |
+ ok = 1; | |
+ } | |
+ else { | |
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) | |
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); | |
+ ok = 0; | |
+ } | |
+ | |
+ return ok; | |
+} | |
+ | |
/* | |
* Classes | |
*/ | |
@@ -98,7 +157,7 @@ DupX509StorePtr(VALUE obj) | |
X509_STORE *store; | |
SafeGetX509Store(obj, store); | |
- CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); | |
+ X509_STORE_up_ref(store); | |
return store; | |
} | |
@@ -106,6 +165,21 @@ DupX509StorePtr(VALUE obj) | |
/* | |
* Private functions | |
*/ | |
+static int | |
+x509store_verify_cb(int ok, X509_STORE_CTX *ctx) | |
+{ | |
+ VALUE proc; | |
+ | |
+ proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx); | |
+ if (!proc) | |
+ proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx), | |
+ store_ex_verify_cb_idx); | |
+ if (!proc) | |
+ return ok; | |
+ | |
+ return ossl_verify_cb_call(proc, ok, ctx); | |
+} | |
+ | |
static VALUE | |
ossl_x509store_alloc(VALUE klass) | |
{ | |
@@ -130,7 +204,7 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb) | |
X509_STORE *store; | |
GetX509Store(self, store); | |
- X509_STORE_set_ex_data(store, ossl_store_ex_verify_cb_idx, (void *)cb); | |
+ X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb); | |
rb_iv_set(self, "@verify_callback", cb); | |
return cb; | |
@@ -141,6 +215,7 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb) | |
* call-seq: | |
* X509::Store.new => store | |
* | |
+ * Creates a new X509::Store. | |
*/ | |
static VALUE | |
ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) | |
@@ -149,15 +224,12 @@ ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) | |
/* BUG: This method takes any number of arguments but appears to ignore them. */ | |
GetX509Store(self, store); | |
+#if !defined(HAVE_OPAQUE_OPENSSL) | |
+ /* [Bug #405] [Bug #1678] [Bug #3000]; already fixed? */ | |
store->ex_data.sk = NULL; | |
- X509_STORE_set_verify_cb_func(store, ossl_verify_cb); | |
- ossl_x509store_set_vfy_cb(self, Qnil); | |
- | |
-#if (OPENSSL_VERSION_NUMBER < 0x00907000L) | |
- rb_iv_set(self, "@flags", INT2FIX(0)); | |
- rb_iv_set(self, "@purpose", INT2FIX(0)); | |
- rb_iv_set(self, "@trust", INT2FIX(0)); | |
#endif | |
+ X509_STORE_set_verify_cb(store, x509store_verify_cb); | |
+ ossl_x509store_set_vfy_cb(self, Qnil); | |
/* last verification status */ | |
rb_iv_set(self, "@error", Qnil); | |
@@ -168,54 +240,77 @@ ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+/* | |
+ * call-seq: | |
+ * store.flags = flag | |
+ * | |
+ * Sets +flag+ to the Store. +flag+ consists of zero or more of the constants | |
+ * defined in with name V_FLAG_* or'ed together. | |
+ */ | |
static VALUE | |
ossl_x509store_set_flags(VALUE self, VALUE flags) | |
{ | |
-#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) | |
X509_STORE *store; | |
long f = NUM2LONG(flags); | |
GetX509Store(self, store); | |
X509_STORE_set_flags(store, f); | |
-#else | |
- rb_iv_set(self, "@flags", flags); | |
-#endif | |
return flags; | |
} | |
+/* | |
+ * call-seq: | |
+ * store.purpose = purpose | |
+ * | |
+ * Sets the store's purpose to +purpose+. If specified, the verifications on | |
+ * the store will check every untrusted certificate's extensions are consistent | |
+ * with the purpose. The purpose is specified by constants: | |
+ * | |
+ * * X509::PURPOSE_SSL_CLIENT | |
+ * * X509::PURPOSE_SSL_SERVER | |
+ * * X509::PURPOSE_NS_SSL_SERVER | |
+ * * X509::PURPOSE_SMIME_SIGN | |
+ * * X509::PURPOSE_SMIME_ENCRYPT | |
+ * * X509::PURPOSE_CRL_SIGN | |
+ * * X509::PURPOSE_ANY | |
+ * * X509::PURPOSE_OCSP_HELPER | |
+ * * X509::PURPOSE_TIMESTAMP_SIGN | |
+ */ | |
static VALUE | |
ossl_x509store_set_purpose(VALUE self, VALUE purpose) | |
{ | |
-#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) | |
X509_STORE *store; | |
int p = NUM2INT(purpose); | |
GetX509Store(self, store); | |
X509_STORE_set_purpose(store, p); | |
-#else | |
- rb_iv_set(self, "@purpose", purpose); | |
-#endif | |
return purpose; | |
} | |
+/* | |
+ * call-seq: | |
+ * store.trust = trust | |
+ */ | |
static VALUE | |
ossl_x509store_set_trust(VALUE self, VALUE trust) | |
{ | |
-#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) | |
X509_STORE *store; | |
int t = NUM2INT(trust); | |
GetX509Store(self, store); | |
X509_STORE_set_trust(store, t); | |
-#else | |
- rb_iv_set(self, "@trust", trust); | |
-#endif | |
return trust; | |
} | |
+/* | |
+ * call-seq: | |
+ * store.time = time | |
+ * | |
+ * Sets the time to be used in verifications. | |
+ */ | |
static VALUE | |
ossl_x509store_set_time(VALUE self, VALUE time) | |
{ | |
@@ -225,13 +320,11 @@ ossl_x509store_set_time(VALUE self, VALUE time) | |
/* | |
* call-seq: | |
- * store.add_file(file) -> store | |
- * | |
+ * store.add_file(file) -> self | |
* | |
* Adds the certificates in +file+ to the certificate store. The +file+ can | |
* contain multiple PEM-encoded certificates. | |
*/ | |
- | |
static VALUE | |
ossl_x509store_add_file(VALUE self, VALUE file) | |
{ | |
@@ -240,8 +333,8 @@ ossl_x509store_add_file(VALUE self, VALUE file) | |
char *path = NULL; | |
if(file != Qnil){ | |
- SafeStringValue(file); | |
- path = RSTRING_PTR(file); | |
+ rb_check_safe_obj(file); | |
+ path = StringValueCStr(file); | |
} | |
GetX509Store(self, store); | |
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); | |
@@ -249,17 +342,16 @@ ossl_x509store_add_file(VALUE self, VALUE file) | |
if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){ | |
ossl_raise(eX509StoreError, NULL); | |
} | |
- /* | |
- * X509_load_cert_crl_file() which is called from X509_LOOKUP_load_file() | |
- * did not check the return value of X509_STORE_add_{cert,crl}(), leaking | |
- * "cert already in hash table" errors on the error queue, if duplicate | |
- * certificates are found. This will be fixed by OpenSSL 1.1.1. | |
- */ | |
- ERR_clear_error(); | |
return self; | |
} | |
+/* | |
+ * call-seq: | |
+ * store.add_path(path) -> self | |
+ * | |
+ * Adds +path+ as the hash dir to be looked up by the store. | |
+ */ | |
static VALUE | |
ossl_x509store_add_path(VALUE self, VALUE dir) | |
{ | |
@@ -268,8 +360,8 @@ ossl_x509store_add_path(VALUE self, VALUE dir) | |
char *path = NULL; | |
if(dir != Qnil){ | |
- SafeStringValue(dir); | |
- path = RSTRING_PTR(dir); | |
+ rb_check_safe_obj(dir); | |
+ path = StringValueCStr(dir); | |
} | |
GetX509Store(self, store); | |
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); | |
@@ -285,11 +377,12 @@ ossl_x509store_add_path(VALUE self, VALUE dir) | |
* call-seq: | |
* store.set_default_paths | |
* | |
- * Adds the default certificates to the certificate store. These certificates | |
- * are loaded from the default configuration directory which can usually be | |
+ * Configures +store+ to look up CA certificates from the system default | |
+ * certificate store as needed basis. The location of the store can usually be | |
* determined by: | |
* | |
- * File.dirname OpenSSL::Config::DEFAULT_CONFIG_FILE | |
+ * * OpenSSL::X509::DEFAULT_CERT_FILE | |
+ * * OpenSSL::X509::DEFAULT_CERT_DIR | |
*/ | |
static VALUE | |
ossl_x509store_set_default_paths(VALUE self) | |
@@ -310,7 +403,6 @@ ossl_x509store_set_default_paths(VALUE self) | |
* | |
* Adds the OpenSSL::X509::Certificate +cert+ to the certificate store. | |
*/ | |
- | |
static VALUE | |
ossl_x509store_add_cert(VALUE self, VALUE arg) | |
{ | |
@@ -326,6 +418,12 @@ ossl_x509store_add_cert(VALUE self, VALUE arg) | |
return self; | |
} | |
+/* | |
+ * call-seq: | |
+ * store.add_crl(crl) -> self | |
+ * | |
+ * Adds the OpenSSL::X509::CRL +crl+ to the store. | |
+ */ | |
static VALUE | |
ossl_x509store_add_crl(VALUE self, VALUE arg) | |
{ | |
@@ -345,6 +443,21 @@ static VALUE ossl_x509stctx_get_err(VALUE); | |
static VALUE ossl_x509stctx_get_err_string(VALUE); | |
static VALUE ossl_x509stctx_get_chain(VALUE); | |
+/* | |
+ * call-seq: | |
+ * store.verify(cert, chain = nil) -> true | false | |
+ * | |
+ * Performs a certificate verification on the OpenSSL::X509::Certificate +cert+. | |
+ * | |
+ * +chain+ can be an array of OpenSSL::X509::Certificate that is used to | |
+ * construct the certificate chain. | |
+ * | |
+ * If a block is given, it overrides the callback set by #verify_callback=. | |
+ * | |
+ * After finishing the verification, the error information can be retrieved by | |
+ * #error, #error_string, and the resuting complete certificate chain can be | |
+ * retrieved by #chain. | |
+ */ | |
static VALUE | |
ossl_x509store_verify(int argc, VALUE *argv, VALUE self) | |
{ | |
@@ -379,27 +492,6 @@ static const rb_data_type_t ossl_x509stctx_type = { | |
0, 0, RUBY_TYPED_FREE_IMMEDIATELY, | |
}; | |
- | |
-VALUE | |
-ossl_x509stctx_new(X509_STORE_CTX *ctx) | |
-{ | |
- VALUE obj; | |
- | |
- obj = NewX509StCtx(cX509StoreContext); | |
- SetX509StCtx(obj, ctx); | |
- | |
- return obj; | |
-} | |
- | |
-VALUE | |
-ossl_x509stctx_clear_ptr(VALUE obj) | |
-{ | |
- OSSL_Check_Kind(obj, cX509StoreContext); | |
- RDATA(obj)->data = NULL; | |
- | |
- return obj; | |
-} | |
- | |
/* | |
* Private functions | |
*/ | |
@@ -407,10 +499,10 @@ static void | |
ossl_x509stctx_free(void *ptr) | |
{ | |
X509_STORE_CTX *ctx = ptr; | |
- if(ctx->untrusted) | |
- sk_X509_pop_free(ctx->untrusted, X509_free); | |
- if(ctx->cert) | |
- X509_free(ctx->cert); | |
+ if (X509_STORE_CTX_get0_untrusted(ctx)) | |
+ sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free); | |
+ if (X509_STORE_CTX_get0_cert(ctx)) | |
+ X509_free(X509_STORE_CTX_get0_cert(ctx)); | |
X509_STORE_CTX_free(ctx); | |
} | |
@@ -429,11 +521,26 @@ ossl_x509stctx_alloc(VALUE klass) | |
return obj; | |
} | |
+static VALUE | |
+ossl_x509stctx_new(X509_STORE_CTX *ctx) | |
+{ | |
+ VALUE obj; | |
+ | |
+ obj = NewX509StCtx(cX509StoreContext); | |
+ SetX509StCtx(obj, ctx); | |
+ | |
+ return obj; | |
+} | |
+ | |
static VALUE ossl_x509stctx_set_flags(VALUE, VALUE); | |
static VALUE ossl_x509stctx_set_purpose(VALUE, VALUE); | |
static VALUE ossl_x509stctx_set_trust(VALUE, VALUE); | |
static VALUE ossl_x509stctx_set_time(VALUE, VALUE); | |
+/* | |
+ * call-seq: | |
+ * StoreContext.new(store, cert = nil, chain = nil) | |
+ */ | |
static VALUE | |
ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) | |
{ | |
@@ -448,17 +555,10 @@ ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) | |
SafeGetX509Store(store, x509st); | |
if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */ | |
if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain); | |
-#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) | |
if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ | |
sk_X509_pop_free(x509s, X509_free); | |
ossl_raise(eX509StoreError, NULL); | |
} | |
-#else | |
- X509_STORE_CTX_init(ctx, x509st, x509, x509s); | |
- ossl_x509stctx_set_flags(self, rb_iv_get(store, "@flags")); | |
- ossl_x509stctx_set_purpose(self, rb_iv_get(store, "@purpose")); | |
- ossl_x509stctx_set_trust(self, rb_iv_get(store, "@trust")); | |
-#endif | |
if (!NIL_P(t = rb_iv_get(store, "@time"))) | |
ossl_x509stctx_set_time(self, t); | |
rb_iv_set(self, "@verify_callback", rb_iv_get(store, "@verify_callback")); | |
@@ -467,20 +567,34 @@ ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) | |
return self; | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.verify -> true | false | |
+ */ | |
static VALUE | |
ossl_x509stctx_verify(VALUE self) | |
{ | |
X509_STORE_CTX *ctx; | |
- int result; | |
GetX509StCtx(self, ctx); | |
- X509_STORE_CTX_set_ex_data(ctx, ossl_store_ctx_ex_verify_cb_idx, | |
- (void*)rb_iv_get(self, "@verify_callback")); | |
- result = X509_verify_cert(ctx); | |
- | |
- return result ? Qtrue : Qfalse; | |
+ X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, | |
+ (void *)rb_iv_get(self, "@verify_callback")); | |
+ | |
+ switch (X509_verify_cert(ctx)) { | |
+ case 1: | |
+ return Qtrue; | |
+ case 0: | |
+ ossl_clear_error(); | |
+ return Qfalse; | |
+ default: | |
+ ossl_raise(eX509CertError, NULL); | |
+ } | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.chain -> Array of X509::Certificate | |
+ */ | |
static VALUE | |
ossl_x509stctx_get_chain(VALUE self) | |
{ | |
@@ -491,7 +605,7 @@ ossl_x509stctx_get_chain(VALUE self) | |
VALUE ary; | |
GetX509StCtx(self, ctx); | |
- if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){ | |
+ if((chain = X509_STORE_CTX_get0_chain(ctx)) == NULL){ | |
return Qnil; | |
} | |
if((num = sk_X509_num(chain)) < 0){ | |
@@ -507,6 +621,10 @@ ossl_x509stctx_get_chain(VALUE self) | |
return ary; | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.error -> Integer | |
+ */ | |
static VALUE | |
ossl_x509stctx_get_err(VALUE self) | |
{ | |
@@ -514,9 +632,13 @@ ossl_x509stctx_get_err(VALUE self) | |
GetX509StCtx(self, ctx); | |
- return INT2FIX(X509_STORE_CTX_get_error(ctx)); | |
+ return INT2NUM(X509_STORE_CTX_get_error(ctx)); | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.error = error_code | |
+ */ | |
static VALUE | |
ossl_x509stctx_set_error(VALUE self, VALUE err) | |
{ | |
@@ -528,6 +650,12 @@ ossl_x509stctx_set_error(VALUE self, VALUE err) | |
return err; | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.error_string -> String | |
+ * | |
+ * Returns the error string corresponding to the error code retrieved by #error. | |
+ */ | |
static VALUE | |
ossl_x509stctx_get_err_string(VALUE self) | |
{ | |
@@ -540,6 +668,10 @@ ossl_x509stctx_get_err_string(VALUE self) | |
return rb_str_new2(X509_verify_cert_error_string(err)); | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.error_depth -> Integer | |
+ */ | |
static VALUE | |
ossl_x509stctx_get_err_depth(VALUE self) | |
{ | |
@@ -547,9 +679,13 @@ ossl_x509stctx_get_err_depth(VALUE self) | |
GetX509StCtx(self, ctx); | |
- return INT2FIX(X509_STORE_CTX_get_error_depth(ctx)); | |
+ return INT2NUM(X509_STORE_CTX_get_error_depth(ctx)); | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.current_cert -> X509::Certificate | |
+ */ | |
static VALUE | |
ossl_x509stctx_get_curr_cert(VALUE self) | |
{ | |
@@ -560,21 +696,30 @@ ossl_x509stctx_get_curr_cert(VALUE self) | |
return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx)); | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.current_crl -> X509::CRL | |
+ */ | |
static VALUE | |
ossl_x509stctx_get_curr_crl(VALUE self) | |
{ | |
-#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) | |
X509_STORE_CTX *ctx; | |
+ X509_CRL *crl; | |
GetX509StCtx(self, ctx); | |
- if(!ctx->current_crl) return Qnil; | |
+ crl = X509_STORE_CTX_get0_current_crl(ctx); | |
+ if (!crl) | |
+ return Qnil; | |
- return ossl_x509crl_new(ctx->current_crl); | |
-#else | |
- return Qnil; | |
-#endif | |
+ return ossl_x509crl_new(crl); | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.flags = flags | |
+ * | |
+ * Sets the verification flags to the context. See Store#flags=. | |
+ */ | |
static VALUE | |
ossl_x509stctx_set_flags(VALUE self, VALUE flags) | |
{ | |
@@ -587,6 +732,12 @@ ossl_x509stctx_set_flags(VALUE self, VALUE flags) | |
return flags; | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.purpose = purpose | |
+ * | |
+ * Sets the purpose of the context. See Store#purpose=. | |
+ */ | |
static VALUE | |
ossl_x509stctx_set_purpose(VALUE self, VALUE purpose) | |
{ | |
@@ -599,6 +750,10 @@ ossl_x509stctx_set_purpose(VALUE self, VALUE purpose) | |
return purpose; | |
} | |
+/* | |
+ * call-seq: | |
+ * stctx.trust = trust | |
+ */ | |
static VALUE | |
ossl_x509stctx_set_trust(VALUE self, VALUE trust) | |
{ | |
@@ -613,7 +768,9 @@ ossl_x509stctx_set_trust(VALUE self, VALUE trust) | |
/* | |
* call-seq: | |
- * storectx.time = time => time | |
+ * stctx.time = time | |
+ * | |
+ * Sets the time used in the verification. If not set, the current time is used. | |
*/ | |
static VALUE | |
ossl_x509stctx_set_time(VALUE self, VALUE time) | |
@@ -634,13 +791,20 @@ ossl_x509stctx_set_time(VALUE self, VALUE time) | |
void | |
Init_ossl_x509store(void) | |
{ | |
- VALUE x509stctx; | |
- | |
#if 0 | |
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ | |
+ mOSSL = rb_define_module("OpenSSL"); | |
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); | |
mX509 = rb_define_module_under(mOSSL, "X509"); | |
#endif | |
+ /* Register ext_data slot for verify callback Proc */ | |
+ stctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"stctx_ex_verify_cb_idx", 0, 0, 0); | |
+ if (stctx_ex_verify_cb_idx < 0) | |
+ ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); | |
+ store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)"store_ex_verify_cb_idx", 0, 0, 0); | |
+ if (store_ex_verify_cb_idx < 0) | |
+ ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index"); | |
+ | |
eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError); | |
/* Document-class: OpenSSL::X509::Store | |
@@ -655,11 +819,11 @@ Init_ossl_x509store(void) | |
* | |
* This will use your system's built-in certificates. | |
* | |
- * If your system does not have a default set of certificates you can | |
- * obtain a set from Mozilla here: http://curl.haxx.se/docs/caextract.html | |
- * (Note that this set does not have an HTTPS download option so you may | |
- * wish to use the firefox-db2pem.sh script to extract the certificates | |
- * from a local install to avoid man-in-the-middle attacks.) | |
+ * If your system does not have a default set of certificates you can obtain | |
+ * a set extracted from Mozilla CA certificate store by cURL maintainers | |
+ * here: https://curl.haxx.se/docs/caextract.html (You may wish to use the | |
+ * firefox-db2pem.sh script to extract the certificates from a local install | |
+ * to avoid man-in-the-middle attacks.) | |
* | |
* After downloading or generating a cacert.pem from the above link you | |
* can create a certificate store from the pem file like this: | |
@@ -670,6 +834,7 @@ Init_ossl_x509store(void) | |
* The certificate store can be used with an SSLSocket like this: | |
* | |
* ssl_context = OpenSSL::SSL::SSLContext.new | |
+ * ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER | |
* ssl_context.cert_store = cert_store | |
* | |
* tcp_socket = TCPSocket.open 'example.com', 443 | |
@@ -678,12 +843,30 @@ Init_ossl_x509store(void) | |
*/ | |
cX509Store = rb_define_class_under(mX509, "Store", rb_cObject); | |
+ /* | |
+ * The callback for additional certificate verification. It is invoked for | |
+ * each untrusted certificate in the chain. | |
+ * | |
+ * The callback is invoked with two values, a boolean that indicates if the | |
+ * pre-verification by OpenSSL has succeeded or not, and the StoreContext in | |
+ * use. The callback must return either true or false. | |
+ */ | |
rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse); | |
+ /* | |
+ * The error code set by the last call of #verify. | |
+ */ | |
rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse); | |
+ /* | |
+ * The description for the error code set by the last call of #verify. | |
+ */ | |
rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse); | |
+ /* | |
+ * The certificate chain constructed by the last call of #verify. | |
+ */ | |
rb_attr(cX509Store, rb_intern("chain"), 1, 0, Qfalse); | |
rb_define_alloc_func(cX509Store, ossl_x509store_alloc); | |
rb_define_method(cX509Store, "initialize", ossl_x509store_initialize, -1); | |
+ rb_undef_method(cX509Store, "initialize_copy"); | |
rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_vfy_cb, 1); | |
rb_define_method(cX509Store, "flags=", ossl_x509store_set_flags, 1); | |
rb_define_method(cX509Store, "purpose=", ossl_x509store_set_purpose, 1); | |
@@ -696,21 +879,26 @@ Init_ossl_x509store(void) | |
rb_define_method(cX509Store, "add_crl", ossl_x509store_add_crl, 1); | |
rb_define_method(cX509Store, "verify", ossl_x509store_verify, -1); | |
- cX509StoreContext = rb_define_class_under(mX509,"StoreContext",rb_cObject); | |
- x509stctx = cX509StoreContext; | |
+ /* | |
+ * Document-class: OpenSSL::X509::StoreContext | |
+ * | |
+ * A StoreContext is used while validating a single certificate and holds | |
+ * the status involved. | |
+ */ | |
+ cX509StoreContext = rb_define_class_under(mX509,"StoreContext", rb_cObject); | |
rb_define_alloc_func(cX509StoreContext, ossl_x509stctx_alloc); | |
- rb_define_method(x509stctx,"initialize", ossl_x509stctx_initialize, -1); | |
- rb_define_method(x509stctx,"verify", ossl_x509stctx_verify, 0); | |
- rb_define_method(x509stctx,"chain", ossl_x509stctx_get_chain,0); | |
- rb_define_method(x509stctx,"error", ossl_x509stctx_get_err, 0); | |
- rb_define_method(x509stctx,"error=", ossl_x509stctx_set_error, 1); | |
- rb_define_method(x509stctx,"error_string",ossl_x509stctx_get_err_string,0); | |
- rb_define_method(x509stctx,"error_depth", ossl_x509stctx_get_err_depth, 0); | |
- rb_define_method(x509stctx,"current_cert",ossl_x509stctx_get_curr_cert, 0); | |
- rb_define_method(x509stctx,"current_crl", ossl_x509stctx_get_curr_crl, 0); | |
- rb_define_method(x509stctx,"flags=", ossl_x509stctx_set_flags, 1); | |
- rb_define_method(x509stctx,"purpose=", ossl_x509stctx_set_purpose, 1); | |
- rb_define_method(x509stctx,"trust=", ossl_x509stctx_set_trust, 1); | |
- rb_define_method(x509stctx,"time=", ossl_x509stctx_set_time, 1); | |
- | |
+ rb_define_method(cX509StoreContext, "initialize", ossl_x509stctx_initialize, -1); | |
+ rb_undef_method(cX509StoreContext, "initialize_copy"); | |
+ rb_define_method(cX509StoreContext, "verify", ossl_x509stctx_verify, 0); | |
+ rb_define_method(cX509StoreContext, "chain", ossl_x509stctx_get_chain,0); | |
+ rb_define_method(cX509StoreContext, "error", ossl_x509stctx_get_err, 0); | |
+ rb_define_method(cX509StoreContext, "error=", ossl_x509stctx_set_error, 1); | |
+ rb_define_method(cX509StoreContext, "error_string", ossl_x509stctx_get_err_string,0); | |
+ rb_define_method(cX509StoreContext, "error_depth", ossl_x509stctx_get_err_depth, 0); | |
+ rb_define_method(cX509StoreContext, "current_cert", ossl_x509stctx_get_curr_cert, 0); | |
+ rb_define_method(cX509StoreContext, "current_crl", ossl_x509stctx_get_curr_crl, 0); | |
+ rb_define_method(cX509StoreContext, "flags=", ossl_x509stctx_set_flags, 1); | |
+ rb_define_method(cX509StoreContext, "purpose=", ossl_x509stctx_set_purpose, 1); | |
+ rb_define_method(cX509StoreContext, "trust=", ossl_x509stctx_set_trust, 1); | |
+ rb_define_method(cX509StoreContext, "time=", ossl_x509stctx_set_time, 1); | |
} | |
diff --git a/ext/openssl/ruby_missing.h b/ext/openssl/ruby_missing.h | |
index d7384ec32c..8dacc8266e 100644 | |
--- a/ext/openssl/ruby_missing.h | |
+++ b/ext/openssl/ruby_missing.h | |
@@ -13,15 +13,11 @@ | |
#define rb_define_copy_func(klass, func) \ | |
rb_define_method((klass), "initialize_copy", (func), 1) | |
- | |
-#ifndef GetReadFile | |
#define FPTR_TO_FD(fptr) ((fptr)->fd) | |
-#else | |
-#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr))) | |
-#endif | |
-#ifndef HAVE_RB_IO_T | |
-#define rb_io_t OpenFile | |
+#ifndef RB_INTEGER_TYPE_P | |
+/* for Ruby 2.3 compatibility */ | |
+#define RB_INTEGER_TYPE_P(obj) (RB_FIXNUM_P(obj) || RB_TYPE_P(obj, T_BIGNUM)) | |
#endif | |
#endif /* _OSSL_RUBY_MISSING_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment