diff options
Diffstat (limited to 'ext/openssl')
78 files changed, 28026 insertions, 9206 deletions
diff --git a/ext/openssl/.cvsignore b/ext/openssl/.cvsignore deleted file mode 100644 index 3a9a9f341f..0000000000 --- a/ext/openssl/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -GNUmakefile -Makefile -mkmf.log -dep -extconf.h diff --git a/ext/openssl/History.md b/ext/openssl/History.md new file mode 100644 index 0000000000..419237ff16 --- /dev/null +++ b/ext/openssl/History.md @@ -0,0 +1,965 @@ +Version 4.0.0 +============= + +Compatibility +------------- + +* Ruby >= 2.7 +* OpenSSL >= 1.1.1, LibreSSL >= 3.9, and AWS-LC 1.66.0 + - Removed support for OpenSSL 1.0.2-1.1.0 and LibreSSL 3.1-3.8. + [[GitHub #835]](https://github.com/ruby/openssl/issues/835) + - Added support for AWS-LC. + [[GitHub #833]](https://github.com/ruby/openssl/issues/833) + + +Notable changes +--------------- + +* `OpenSSL::SSL` + - Reduce overhead when writing to `OpenSSL::SSL::SSLSocket`. `#syswrite` no + longer creates a temporary String object. + [[GitHub #831]](https://github.com/ruby/openssl/pull/831) + - Make `OpenSSL::SSL::SSLContext#min_version=` and `#max_version=` wrap the + corresponding OpenSSL APIs directly, and remove the fallback to SSL options. + [[GitHub #849]](https://github.com/ruby/openssl/pull/849) + - Add `OpenSSL::SSL::SSLContext#sigalgs=` and `#client_sigalgs=` for + specifying signature algorithms to use for connections. + [[GitHub #895]](https://github.com/ruby/openssl/pull/895) + - Rename `OpenSSL::SSL::SSLContext#ecdh_curves=` to `#groups=` following + the underlying OpenSSL API rename. This method is no longer specific to + ECDHE. The old method remains as an alias. + [[GitHub #900]](https://github.com/ruby/openssl/pull/900) + - Add `OpenSSL::SSL::SSLSocket#sigalg`, `#peer_sigalg`, and `#group` for + getting the signature algorithm and the key agreement group used in the + current connection. + [[GitHub #908]](https://github.com/ruby/openssl/pull/908) + - Enable `SSL_CTX_set_dh_auto()` for servers by default. + [[GitHub #924]](https://github.com/ruby/openssl/pull/924) + - Improve Ractor compatibility. Note that the internal-use constant + `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS` is now frozen. + [[GitHub #925]](https://github.com/ruby/openssl/pull/925) +* `OpenSSL::PKey` + - Remove `OpenSSL::PKey::EC::Point#mul` support with array arguments. The + underlying OpenSSL API has been removed, and the method has been deprecated + since ruby/openssl v3.0.0. + [[GitHub #843]](https://github.com/ruby/openssl/pull/843) + - `OpenSSL::PKey::{RSA,DSA,DH}#params` uses `nil` to indicate missing fields + instead of the number `0`. + [[GitHub #774]](https://github.com/ruby/openssl/pull/774) + - Unify `OpenSSL::PKey::PKeyError` classes. The former subclasses + `OpenSSL::PKey::DHError`, `OpenSSL::PKey::DSAError`, + `OpenSSL::PKey::ECError`, and `OpenSSL::PKey::RSAError` have been merged + into a single class. + [[GitHub #929]](https://github.com/ruby/openssl/pull/929) +* `OpenSSL::Cipher` + - `OpenSSL::Cipher#encrypt` and `#decrypt` no longer accept arguments. + Passing passwords has been deprecated since Ruby 1.8.2 (released in 2004). + [[GitHub #887]](https://github.com/ruby/openssl/pull/887) + - `OpenSSL::Cipher#final` raises `OpenSSL::Cipher::AuthTagError` when the + integrity check fails for AEAD ciphers. `OpenSSL::Cipher::AuthTagError` is a + new subclass of `OpenSSL::Cipher::CipherError`, which was previously raised. + [[GitHub #939]](https://github.com/ruby/openssl/pull/939) + - `OpenSSL::Cipher.new` now raises `OpenSSL::Cipher::CipherError` instead of + `RuntimeError` when OpenSSL does not recognize the algorithm. + [[GitHub #958]](https://github.com/ruby/openssl/pull/958) + - Add support for "fetched" cipher algorithms with OpenSSL 3.0 or later. + [[GitHub #958]](https://github.com/ruby/openssl/pull/958) +* `OpenSSL::Digest` + - `OpenSSL::Digest.new` now raises `OpenSSL::Digest::DigestError` instead of + `RuntimeError` when OpenSSL does not recognize the algorithm. + [[GitHub #958]](https://github.com/ruby/openssl/pull/958) + - Add support for "fetched" digest algorithms with OpenSSL 3.0 or later. + [[GitHub #958]](https://github.com/ruby/openssl/pull/958) +* `OpenSSL::ASN1.decode` now assumes a 1950-2049 year range for `UTCTime` + according to RFC 5280. It previously used a 1969-2068 range. The encoder + has always used the 1950-2049 range. + [[GitHub #909]](https://github.com/ruby/openssl/pull/909) +* `OpenSSL::OpenSSLError`, the base class for all ruby/openssl errors, carry + an additional attribute `#errors` to keep the content of OpenSSL's error + queue. Also, add `#detailed_message` for Ruby 3.2 or later. + [[GitHub #976]](https://github.com/ruby/openssl/pull/976) +* `OpenSSL::PKCS7.new` raises `OpenSSL::PKCS7::PKCS7Error` instead of + `ArgumentError` on error to be consistent with other constructors. + [[GitHub #983]](https://github.com/ruby/openssl/pull/983) + + +Version 3.3.2 +============= + +Merged changes in 3.1.3 and 3.2.3. + + +Version 3.3.1 +============= + +Merged changes in 3.1.2 and 3.2.2. + + +Version 3.3.0 +============= + +Compatibility +------------- + +* Ruby version: 2.7 or later +* OpenSSL version: OpenSSL 1.0.2 or later, and LibreSSL 3.1 or later + +Notable changes +--------------- + +* `OpenSSL::SSL` + - `OpenSSL::SSL::SSLSocket#set_params` no longer sets `#min_version=` to TLS + 1.0 except when OpenSSL 1.0.2 is used. This has been done to disable + SSL 3.0, which is not supported by default in OpenSSL 1.1.0 or later, or in + LibreSSL. This lets it respect the system default if the system-wide + configuration file specifies a higher minimum protocol version. + [[GitHub #710]](https://github.com/ruby/openssl/pull/710) + - `OpenSSL::SSL::SSLSocket.new` no longer enables the `OpenSSL::SSL::OP_ALL` + SSL options by default and follows the system default. + [[GitHub #767]](https://github.com/ruby/openssl/pull/767) + - Add the following IO methods to `OpenSSL::SSL::SSLSocket`, which will pass + along to the underlying socket: `#local_address`, `#remote_address`, + `#close_on_exec=`, `#close_on_exec?`, `#wait`, `#wait_readable`, and + `#wait_writable`. + [[GitHub #708]](https://github.com/ruby/openssl/pull/708) + - Update `OpenSSL::SSL::SSLSocket#gets` to take the `chomp` keyword argument. + [[GitHub #708]](https://github.com/ruby/openssl/pull/708) + - Make `OpenSSL::SSL::SSLSocket` respect the `IO#timeout` value of the + underlying socket on Ruby 3.2 or later. `#timeout` and `#timeout=` methods + are also added. + [[GitHub #714]](https://github.com/ruby/openssl/pull/714) + - Add `OpenSSL::SSL::SSLSocket#close_read` and `#close_write`. + [[GitHub #743]](https://github.com/ruby/openssl/pull/743) + - Add `OpenSSL::Digest.digests` to get a list of all available digest + algorithms. + [[GitHub #726]](https://github.com/ruby/openssl/pull/726) + - Fix `OpenSSL::SSL::SSLSocket#read_nonblock` clearing the passed String + buffer when nothing can be read from the connection. + [[GitHub #739]](https://github.com/ruby/openssl/pull/739) +* Add `#to_text` methods to `OpenSSL::Timestamp::Response`, + `OpenSSL::Timestamp::Request`, `OpenSSL::Timestamp::TokenInfo`, and + `OpenSSL::PKCS7` to get a human-readable representation of the object. + [[GitHub #756]](https://github.com/ruby/openssl/pull/756) +* Add `OpenSSL::X509::Certificate#tbs_bytes` to get the DER encoding of the + TBSCertificate. + [[GitHub #753]](https://github.com/ruby/openssl/pull/753) +* Allow passing `nil` as the digest algorithm to `#sign` methods on + `OpenSSL::X509::Certificate`, `OpenSSL::X509::Request`, and + `OpenSSL::X509::CRL`. This adds supports for signing with EdDSA keys. + [[GitHub #761]](https://github.com/ruby/openssl/pull/761) + [[GitHub #804]](https://github.com/ruby/openssl/pull/804) +* Add `OpenSSL::SSL::SSLSocket#readbyte`. + [[GitHub #771]](https://github.com/ruby/openssl/pull/771) +* Change `OpenSSL::X509::Store#time=` to set the time to the `X509_VERIFY_PARAM` + in the `X509_STORE`. This allows `OpenSSL::Timestamp::Response#verify` to + verify a signature with the specified timestamp. + [[GitHub #770]](https://github.com/ruby/openssl/pull/770) +* Make `OpenSSL::PKCS7.encrypt`'s third parameter `cipher` mandatory. It had + an undocumented default value "RC2-40-CBC", which is not only insecure, but + also not supported in OpenSSL 3.0 or later. + [[GitHub #796]](https://github.com/ruby/openssl/pull/796) +* Make `OpenSSL::BN` shareable between ractors when frozen. + [[GitHub #808]](https://github.com/ruby/openssl/pull/808) +* Make `OpenSSL::Config` instances frozen by default, and make it shareable + between ractors. `OpenSSL::Config::DEFAULT_CONFIG_FILE` is also frozen. + [[GitHub #809]](https://github.com/ruby/openssl/pull/809) +* Add `OpenSSL::PKCS12#set_mac` to configure the MAC parameters and recalculate + a MAC for the content. + [[GitHub #788]](https://github.com/ruby/openssl/pull/788) + +And various non-user-visible changes and bug fixes. Please see the commit +history for more details. + + +Version 3.2.3 +============= + +Merged changes in 3.1.3. + + +Version 3.2.2 +============= + +Merged changes in 3.1.2. + + +Version 3.2.1 +============= + +Merged changes in 3.0.3. + + +Version 3.2.0 +============= + +Compatibility +------------- + +* Ruby >= 2.7 + - Support for Ruby 2.6 has been removed. Note that Ruby 2.6 reached the + end-of-life in 2022-04. + [[GitHub #639]](https://github.com/ruby/openssl/pull/639) +* OpenSSL >= 1.0.2 or LibreSSL >= 3.1 + +Notable changes +--------------- + +* Add a stub gemspec for JRuby, which depends on the `jruby-openssl` gem. + [[GitHub #598]](https://github.com/ruby/openssl/pull/598) +* Add support for the FIPS module in OpenSSL 3.0/3.1. + [[GitHub #608]](https://github.com/ruby/openssl/pull/608) +* Rework `OpenSSL::PKey` routines for loading DER or PEM encoded keys for better + compatibility with OpenSSL 3.0/3.1 with the FIPS module. + [[GitHub #615]](https://github.com/ruby/openssl/pull/615) + [[GitHub #669]](https://github.com/ruby/openssl/pull/669) +* Add `OpenSSL::Provider` module for loading and unloading OpenSSL 3 providers. + [[GitHub #635]](https://github.com/ruby/openssl/pull/635) +* Add `OpenSSL::PKey.new_raw_private_key`, `.new_raw_public_key`, + `OpenSSL::PKey::PKey#raw_private_key`, and `#raw_public_key` for public key + algorithms that use "raw private/public key", such as X25519 and Ed25519. + [[GitHub #646]](https://github.com/ruby/openssl/pull/646) +* Improve OpenSSL error messages to include additional information when + it is available in OpenSSL's error queue. + [[GitHub #648]](https://github.com/ruby/openssl/pull/648) +* Change `OpenSSL::SSL::SSLContext#ca_file=` and `#ca_path=` to raise + `OpenSSL::SSL::SSLError` instead of printing a warning message. + [[GitHub #659]](https://github.com/ruby/openssl/pull/659) +* Allow `OpenSSL::X509::ExtensionFactory#create_extension` to take OIDs in the + dotted-decimal notation. + [[GitHub #141]](https://github.com/ruby/openssl/pull/141) + + +Version 3.1.3 +============= + +Bug fixes +--------- + +* Fix missing NULL check for `EVP_PKEY_get0()` functions with OpenSSL 3.x. + [[GitHub #957]](https://github.com/ruby/openssl/pull/957) + + +Version 3.1.2 +============= + +Bug fixes +--------- + +* Fix crash when attempting to export an incomplete `OpenSSL::PKey::DSA` key. + [[GitHub #845]](https://github.com/ruby/openssl/issues/845) + [[GitHub #847]](https://github.com/ruby/openssl/pull/847) +* Remove the `OpenSSL::X509::V_FLAG_CRL_CHECK_ALL` flag from the default store + used by `OpenSSL::SSL::SSLContext#set_params`. It causes certificate + verification to fail with OpenSSL 3.6.0. It has no effect with any other + OpenSSL versions. + [[GitHub #949]](https://github.com/ruby/openssl/issues/949) + [[GitHub #950]](https://github.com/ruby/openssl/pull/950) + + +Version 3.1.1 +============= + +Merged changes in 3.0.3. + + +Version 3.1.0 +============= + +Ruby/OpenSSL 3.1 will be maintained for the lifetime of Ruby 3.2. + +Merged bug fixes in 2.2.3 and 3.0.2. Among the new features and changes are: + +Notable changes +--------------- + +* Add `OpenSSL::SSL::SSLContext#ciphersuites=` to allow setting TLS 1.3 cipher + suites. + [[GitHub #493]](https://github.com/ruby/openssl/pull/493) +* Add `OpenSSL::SSL::SSLSocket#export_keying_material` for exporting keying + material of the session, as defined in RFC 5705. + [[GitHub #530]](https://github.com/ruby/openssl/pull/530) +* Add `OpenSSL::SSL::SSLContext#keylog_cb=` for setting the TLS key logging + callback, which is useful for supporting NSS's SSLKEYLOGFILE debugging output. + [[GitHub #536]](https://github.com/ruby/openssl/pull/536) +* Remove the default digest algorithm from `OpenSSL::OCSP::BasicResponse#sign` + and `OpenSSL::OCSP::Request#sign`. Omitting the 5th parameter of these + methods used to be equivalent of specifying SHA-1. This default value is now + removed and we will let the underlying OpenSSL library decide instead. + [[GitHub #507]](https://github.com/ruby/openssl/pull/507) +* Add `OpenSSL::BN#mod_sqrt`. + [[GitHub #553]](https://github.com/ruby/openssl/pull/553) +* Allow calling `OpenSSL::Cipher#update` with an empty string. This was + prohibited to workaround an ancient bug in OpenSSL. + [[GitHub #568]](https://github.com/ruby/openssl/pull/568) +* Fix build on platforms without socket support, such as WASI. `OpenSSL::SSL` + will not be defined if OpenSSL is compiled with `OPENSSL_NO_SOCK`. + [[GitHub #558]](https://github.com/ruby/openssl/pull/558) +* Improve support for recent LibreSSL versions. This includes HKDF support in + LibreSSL 3.6 and Ed25519 support in LibreSSL 3.7. + + +Version 3.0.3 +============= + +Bug fixes +--------- + +* Fix a performance regression introduced in v2.1.3 on a buffered write to + `SSLSocket`. + [[GitHub #706]](https://github.com/ruby/openssl/pull/706) +* Fix `OpenSSL::PKCS7` to handle PKCS#7 structures without content. + [[GitHub #690]](https://github.com/ruby/openssl/pull/690) + [[GitHub #752]](https://github.com/ruby/openssl/pull/752) +* Fix `OpenSSL::ASN1::ObjectId#==` with OIDs without a known name. + [[GitHub #791]](https://github.com/ruby/openssl/issues/791) + [[GitHub #792]](https://github.com/ruby/openssl/pull/792) +* Fix `OpenSSL::X509::Certificate#crl_uris` to handle CDP with multiple CRL + URIs. + [[GitHub #775]](https://github.com/ruby/openssl/issues/775) + [[GitHub #776]](https://github.com/ruby/openssl/pull/776) +* Fix `OpenSSL::Cipher#update` to always make the output buffer `String` + independent. + [[Bug #20937]](https://bugs.ruby-lang.org/issues/20937) + [[GitHub #824]](https://github.com/ruby/openssl/pull/824) + + +Version 3.0.2 +============= + +Merged changes in 2.2.3. Additionally, the following issues are fixed by this +release. + +Bug fixes +--------- + +* Fix OpenSSL::PKey::EC#check_key not working correctly on OpenSSL 3.0. + [[GitHub #563]](https://github.com/ruby/openssl/issues/563) + [[GitHub #580]](https://github.com/ruby/openssl/pull/580) + + +Version 3.0.1 +============= + +Merged changes in 2.1.4 and 2.2.2. Additionally, the following issues are fixed +by this release. + +Bug fixes +--------- + +* Add missing type check in OpenSSL::PKey::PKey#sign's optional parameters. + [[GitHub #531]](https://github.com/ruby/openssl/pull/531) +* Work around OpenSSL 3.0's HMAC issues with a zero-length key. + [[GitHub #538]](https://github.com/ruby/openssl/pull/538) +* Fix a regression in OpenSSL::PKey::DSA.generate's default of 'q' size. + [[GitHub #483]](https://github.com/ruby/openssl/issues/483) + [[GitHub #539]](https://github.com/ruby/openssl/pull/539) +* Restore OpenSSL::PKey.read's ability to decode "openssl ecparam -genkey" + output when linked against OpenSSL 3.0. + [[GitHub #535]](https://github.com/ruby/openssl/pull/535) + [[GitHub #540]](https://github.com/ruby/openssl/pull/540) +* Restore error checks in OpenSSL::PKey::EC#{to_der,to_pem}. + [[GitHub #541]](https://github.com/ruby/openssl/pull/541) + + +Version 3.0.0 +============= + +Compatibility notes +------------------- + +* OpenSSL 1.0.1 and Ruby 2.3-2.5 are no longer supported. + [[GitHub #396]](https://github.com/ruby/openssl/pull/396) + [[GitHub #466]](https://github.com/ruby/openssl/pull/466) + +* OpenSSL 3.0 support is added. It is the first major version bump from OpenSSL + 1.1 and contains incompatible changes that affect Ruby/OpenSSL. + Note that OpenSSL 3.0 support is preliminary and not all features are + currently available: + [[GitHub #369]](https://github.com/ruby/openssl/issues/369) + + - Deprecate the ability to modify `OpenSSL::PKey::PKey` instances. OpenSSL 3.0 + made EVP_PKEY structure immutable, and hence the following methods are not + available when Ruby/OpenSSL is linked against OpenSSL 3.0. + [[GitHub #480]](https://github.com/ruby/openssl/pull/480) + + - `OpenSSL::PKey::RSA#set_key`, `#set_factors`, `#set_crt_params` + - `OpenSSL::PKey::DSA#set_pqg`, `#set_key` + - `OpenSSL::PKey::DH#set_pqg`, `#set_key`, `#generate_key!` + - `OpenSSL::PKey::EC#private_key=`, `#public_key=`, `#group=`, `#generate_key!` + + - Deprecate `OpenSSL::Engine`. The ENGINE API has been deprecated in OpenSSL 3.0 + in favor of the new "provider" concept and will be removed in a future + version. + [[GitHub #481]](https://github.com/ruby/openssl/pull/481) + +* `OpenSSL::SSL::SSLContext#tmp_ecdh_callback` has been removed. It has been + deprecated since v2.0.0 because it is incompatible with modern OpenSSL + versions. + [[GitHub #394]](https://github.com/ruby/openssl/pull/394) + +* `OpenSSL::SSL::SSLSocket#read` and `#write` now raise `OpenSSL::SSL::SSLError` + if called before a TLS connection is established. Historically, they + read/wrote unencrypted data to the underlying socket directly in that case. + [[GitHub #9]](https://github.com/ruby/openssl/issues/9) + [[GitHub #469]](https://github.com/ruby/openssl/pull/469) + + +Notable changes +--------------- + +* Enhance OpenSSL::PKey's common interface. + [[GitHub #370]](https://github.com/ruby/openssl/issues/370) + + - Key deserialization: Enhance `OpenSSL::PKey.read` to handle PEM encoding of + DH parameters, which used to be only deserialized by `OpenSSL::PKey::DH.new`. + [[GitHub #328]](https://github.com/ruby/openssl/issues/328) + - Key generation: Add `OpenSSL::PKey.generate_parameters` and + `OpenSSL::PKey.generate_key`. + [[GitHub #329]](https://github.com/ruby/openssl/issues/329) + - Public key signing: Enhance `OpenSSL::PKey::PKey#sign` and `#verify` to use + the new EVP_DigestSign() family to enable PureEdDSA support on OpenSSL 1.1.1 + or later. They also now take optional algorithm-specific parameters for more + control. + [[GitHub #329]](https://github.com/ruby/openssl/issues/329) + - Low-level public key signing and verification: Add + `OpenSSL::PKey::PKey#sign_raw`, `#verify_raw`, and `#verify_recover`. + [[GitHub #382]](https://github.com/ruby/openssl/issues/382) + - Public key encryption: Add `OpenSSL::PKey::PKey#encrypt` and `#decrypt`. + [[GitHub #382]](https://github.com/ruby/openssl/issues/382) + - Key agreement: Add `OpenSSL::PKey::PKey#derive`. + [[GitHub #329]](https://github.com/ruby/openssl/issues/329) + - Key comparison: Add `OpenSSL::PKey::PKey#compare?` to conveniently check + that two keys have common parameters and a public key. + [[GitHub #383]](https://github.com/ruby/openssl/issues/383) + +* Add `OpenSSL::BN#set_flags` and `#get_flags`. This can be used in combination + with `OpenSSL::BN::CONSTTIME` to force constant-time computation. + [[GitHub #417]](https://github.com/ruby/openssl/issues/417) + +* Add `OpenSSL::BN#abs` to get the absolute value of the BIGNUM. + [[GitHub #430]](https://github.com/ruby/openssl/issues/430) + +* Add `OpenSSL::SSL::SSLSocket#getbyte`. + [[GitHub #438]](https://github.com/ruby/openssl/issues/438) + +* Add `OpenSSL::SSL::SSLContext#tmp_dh=`. + [[GitHub #459]](https://github.com/ruby/openssl/pull/459) + +* Add `OpenSSL::X509::Certificate.load` to load a PEM-encoded and concatenated + list of X.509 certificates at once. + [[GitHub #441]](https://github.com/ruby/openssl/pull/441) + +* Change `OpenSSL::X509::Certificate.new` to attempt to deserialize the given + string first as DER encoding first and then as PEM encoding to ensure the + round-trip consistency. + [[GitHub #442]](https://github.com/ruby/openssl/pull/442) + +* Update various part of the code base to use the modern API. No breaking + changes are intended with this. This includes: + + - `OpenSSL::HMAC` uses the EVP API. + [[GitHub #371]](https://github.com/ruby/openssl/issues/371) + - `OpenSSL::Config` uses native OpenSSL API to parse config files. + [[GitHub #342]](https://github.com/ruby/openssl/issues/342) + + +Version 2.2.3 +============= + +Bug fixes +--------- + +* Fix serveral methods in OpenSSL::PKey::EC::Point attempting to raise an error + with an incorrect class, which would end up with a TypeError. + [[GitHub #570]](https://github.com/ruby/openssl/pull/570) +* Fix OpenSSL::PKey::EC::Point#eql? and OpenSSL::PKey::EC::Group#eql? + incorrectly treated OpenSSL's internal errors as "not equal". + [[GitHub #564]](https://github.com/ruby/openssl/pull/564) +* Fix build with LibreSSL 3.5 or later. + + +Version 2.2.2 +============= + +Merged changes in 2.1.4. + + +Version 2.2.1 +============= + +Merged changes in 2.1.3. Additionally, the following issues are fixed by this +release. + +Bug fixes +--------- + +* Fix crash in `OpenSSL::Timestamp::{Request,Response,TokenInfo}.new` when + invalid arguments are given. + [[GitHub #407]](https://github.com/ruby/openssl/pull/407) +* Fix `OpenSSL::Timestamp::Factory#create_timestamp` with LibreSSL on platforms + where `time_t` has a different size from `long`. + [[GitHub #454]](https://github.com/ruby/openssl/pull/454) + + +Version 2.2.0 +============= + +Compatibility notes +------------------- + +* Remove unsupported MDC2, DSS, DSS1, and SHA algorithms. +* Remove `OpenSSL::PKCS7::SignerInfo#name` alias for `#issuer`. + [[GitHub #266]](https://github.com/ruby/openssl/pull/266) +* Deprecate `OpenSSL::Config#add_value` and `#[]=` for future removal. + [[GitHub #322]](https://github.com/ruby/openssl/pull/322) + + +Notable changes +--------------- + +* Change default `OpenSSL::SSL::SSLServer#listen` backlog argument from + 5 to `Socket::SOMAXCONN`. + [[GitHub #286]](https://github.com/ruby/openssl/issues/286) +* Make `OpenSSL::HMAC#==` use a timing safe string comparison. + [[GitHub #284]](https://github.com/ruby/openssl/pull/284) +* Add support for SHA3 and BLAKE digests. + [[GitHub #282]](https://github.com/ruby/openssl/pull/282) +* Add `OpenSSL::SSL::SSLSocket.open` for opening a `TCPSocket` and + returning an `OpenSSL::SSL::SSLSocket` for it. + [[GitHub #225]](https://github.com/ruby/openssl/issues/225) +* Support marshalling of `OpenSSL::X509` and `OpenSSL::PKey` objects. + [[GitHub #281]](https://github.com/ruby/openssl/pull/281) + [[GitHub #363]](https://github.com/ruby/openssl/pull/363) +* Add `OpenSSL.secure_compare` for timing safe string comparison for + strings of possibly unequal length. + [[GitHub #280]](https://github.com/ruby/openssl/pull/280) +* Add `OpenSSL.fixed_length_secure_compare` for timing safe string + comparison for strings of equal length. + [[GitHub #269]](https://github.com/ruby/openssl/pull/269) +* Add `OpenSSL::SSL::SSLSocket#{finished_message,peer_finished_message}` + for last finished message sent and received. + [[GitHub #250]](https://github.com/ruby/openssl/pull/250) +* Add `OpenSSL::Timestamp` module for handing timestamp requests and + responses. + [[GitHub #204]](https://github.com/ruby/openssl/pull/204) +* Add helper methods for `OpenSSL::X509::Certificate`: + `find_extension`, `subject_key_identifier`, + `authority_key_identifier`, `crl_uris`, `ca_issuer_uris` and + `ocsp_uris`, and for `OpenSSL::X509::CRL`: + `find_extension` and `subject_key_identifier`. + [[GitHub #260]](https://github.com/ruby/openssl/pull/260) + [[GitHub #275]](https://github.com/ruby/openssl/pull/275) + [[GitHub #293]](https://github.com/ruby/openssl/pull/293) +* Add `OpenSSL::ECPoint#add` for performing elliptic curve point addition. + [[GitHub #261]](https://github.com/ruby/openssl/pull/261) +* Make `OpenSSL::PKey::RSA#{export,to_der}` check `key`, `factors`, and + `crt_params` to do proper private key serialization. + [[GitHub #258]](https://github.com/ruby/openssl/pull/258) +* Add `OpenSSL::SSL::{SSLSocket,SSLServer}#fileno`, returning the + underlying socket file descriptor number. + [[GitHub #247]](https://github.com/ruby/openssl/pull/247) +* Support client certificates with TLS 1.3, and support post-handshake + authentication with OpenSSL 1.1.1+. + [[GitHub #239]](https://github.com/ruby/openssl/pull/239) +* Add `OpenSSL::ASN1::ObjectId#==` for equality testing. +* Add `OpenSSL::X509::Extension#value_der` for the raw value of + the extension. + [[GitHub #234]](https://github.com/ruby/openssl/pull/234) +* Significantly reduce allocated memory in `OpenSSL::Buffering#do_write`. + [[GitHub #212]](https://github.com/ruby/openssl/pull/212) +* Ensure all valid IPv6 addresses are considered valid as elements + of subjectAlternativeName in certificates. + [[GitHub #185]](https://github.com/ruby/openssl/pull/185) +* Allow recipient's certificate to be omitted in PCKS7#decrypt. + [[GitHub #183]](https://github.com/ruby/openssl/pull/183) +* Add support for reading keys in PKCS #8 format and export via instance methods + added to `OpenSSL::PKey` classes: `private_to_der`, `private_to_pem`, + `public_to_der` and `public_to_pem`. + [[GitHub #297]](https://github.com/ruby/openssl/pull/297) + + +Version 2.1.4 +============= + +Bug fixes +--------- + +* Do not use pkg-config if --with-openssl-dir option is specified. + [[GitHub #486]](https://github.com/ruby/openssl/pull/486) + + +Version 2.1.3 +============= + +Bug fixes +--------- + +* Fix deprecation warnings on Ruby 3.0. +* Add ".include" directive support in `OpenSSL::Config`. + [[GitHub #216]](https://github.com/ruby/openssl/pull/216) +* Fix handling of IPv6 address SANs. + [[GitHub #185]](https://github.com/ruby/openssl/pull/185) +* Hostname verification failure with `OpenSSL::SSL::SSLContext#verify_hostname=` + sets a proper error code. + [[GitHub #350]](https://github.com/ruby/openssl/pull/350) +* Fix crash with `OpenSSL::BN.new(nil, 2)`. + [[Bug #15760]](https://bugs.ruby-lang.org/issues/15760) +* `OpenSSL::SSL::SSLSocket#sys{read,write}` prevent internal string buffers from + being modified by another thread. + [[GitHub #453]](https://github.com/ruby/openssl/pull/453) +* Fix misuse of input record separator in `OpenSSL::Buffering` where it was + for output. +* Fix wrong integer casting in `OpenSSL::PKey::EC#dsa_verify_asn1`. + [[GitHub #460]](https://github.com/ruby/openssl/pull/460) +* `extconf.rb` explicitly checks that OpenSSL's version number is 1.0.1 or + newer but also less than 3.0. Ruby/OpenSSL v2.1.x and v2.2.x will not support + OpenSSL 3.0 API. + [[GitHub #458]](https://github.com/ruby/openssl/pull/458) +* Activate `digest` gem correctly. `digest` library could go into an + inconsistent state if there are multiple versions of `digest` is installed + and `openssl` is `require`d before `digest`. + [[GitHub #463]](https://github.com/ruby/openssl/pull/463) +* Fix GC.compact compatibility. + [[GitHub #464]](https://github.com/ruby/openssl/issues/464) + [[GitHub #465]](https://github.com/ruby/openssl/pull/465) + + +Version 2.1.2 +============= + +Merged changes in 2.0.9. + + +Version 2.1.1 +============= + +Merged changes in 2.0.8. + + +Version 2.1.0 +============= + +Notable changes +--------------- + +* Support for OpenSSL versions before 1.0.1 and LibreSSL versions before 2.5 + is removed. + [[GitHub #86]](https://github.com/ruby/openssl/pull/86) +* OpenSSL::BN#negative?, #+@, and #-@ are added. +* OpenSSL::SSL::SSLSocket#connect raises a more informative exception when + certificate verification fails. + [[GitHub #99]](https://github.com/ruby/openssl/pull/99) +* OpenSSL::KDF module is newly added. In addition to PBKDF2-HMAC that has moved + from OpenSSL::PKCS5, scrypt and HKDF are supported. + [[GitHub #109]](https://github.com/ruby/openssl/pull/109) + [[GitHub #173]](https://github.com/ruby/openssl/pull/173) +* OpenSSL.fips_mode is added. We had the setter, but not the getter. + [[GitHub #125]](https://github.com/ruby/openssl/pull/125) +* OpenSSL::OCSP::Request#signed? is added. +* OpenSSL::ASN1 handles the indefinite length form better. OpenSSL::ASN1.decode + no longer wrongly treats the end-of-contents octets as part of the content. + OpenSSL::ASN1::ASN1Data#infinite_length is renamed to #indefinite_length. + [[GitHub #98]](https://github.com/ruby/openssl/pull/98) +* OpenSSL::X509::Name#add_entry now accepts two additional keyword arguments + 'loc' and 'set'. + [[GitHub #94]](https://github.com/ruby/openssl/issues/94) +* OpenSSL::SSL::SSLContext#min_version= and #max_version= are added to replace + #ssl_version= that was built on top of the deprecated OpenSSL C API. Use of + that method and the constant OpenSSL::SSL::SSLContext::METHODS is now + deprecated. + [[GitHub #142]](https://github.com/ruby/openssl/pull/142) +* OpenSSL::X509::Name#to_utf8 is added. + [[GitHub #26]](https://github.com/ruby/openssl/issues/26) + [[GitHub #143]](https://github.com/ruby/openssl/pull/143) +* OpenSSL::X509::{Extension,Attribute,Certificate,CRL,Revoked,Request} can be + compared with == operator. + [[GitHub #161]](https://github.com/ruby/openssl/pull/161) +* TLS Fallback Signaling Cipher Suite Value (SCSV) support is added. + [[GitHub #165]](https://github.com/ruby/openssl/pull/165) +* Build failure with OpenSSL 1.1 built with no-deprecated is fixed. + [[GitHub #160]](https://github.com/ruby/openssl/pull/160) +* OpenSSL::Buffering#write accepts an arbitrary number of arguments. + [[Feature #9323]](https://bugs.ruby-lang.org/issues/9323) + [[GitHub #162]](https://github.com/ruby/openssl/pull/162) +* OpenSSL::PKey::RSA#sign_pss and #verify_pss are added. They perform RSA-PSS + signature and verification. + [[GitHub #75]](https://github.com/ruby/openssl/issues/75) + [[GitHub #76]](https://github.com/ruby/openssl/pull/76) + [[GitHub #169]](https://github.com/ruby/openssl/pull/169) +* OpenSSL::SSL::SSLContext#add_certificate is added. + [[GitHub #167]](https://github.com/ruby/openssl/pull/167) +* OpenSSL::PKey::EC::Point#to_octet_string is added. + OpenSSL::PKey::EC::Point.new can now take String as the second argument. + [[GitHub #177]](https://github.com/ruby/openssl/pull/177) + + +Version 2.0.9 +============= + +Security fixes +-------------- + +* OpenSSL::X509::Name#<=> could incorrectly return 0 (= equal) for non-equal + objects. CVE-2018-16395 is assigned for this issue. + https://hackerone.com/reports/387250 + +Bug fixes +--------- + +* Fixed OpenSSL::PKey::\*.{new,generate} immediately aborting if the thread is + interrupted. + [[Bug #14882]](https://bugs.ruby-lang.org/issues/14882) + [[GitHub #205]](https://github.com/ruby/openssl/pull/205) +* Fixed OpenSSL::X509::Name#to_s failing with OpenSSL::X509::NameError if + called against an empty instance. + [[GitHub #200]](https://github.com/ruby/openssl/issues/200) + [[GitHub #211]](https://github.com/ruby/openssl/pull/211) + + +Version 2.0.8 +============= + +Bug fixes +--------- + +* OpenSSL::Cipher#pkcs5_keyivgen raises an error when a negative iteration + count is given. + [[GitHub #184]](https://github.com/ruby/openssl/pull/184) +* Fixed build with LibreSSL 2.7. + [[GitHub #192]](https://github.com/ruby/openssl/issues/192) + [[GitHub #193]](https://github.com/ruby/openssl/pull/193) + + +Version 2.0.7 +============= + +Bug fixes +--------- + +* OpenSSL::Cipher#auth_data= could segfault if called against a non-AEAD cipher. + [[Bug #14024]](https://bugs.ruby-lang.org/issues/14024) +* OpenSSL::X509::Certificate#public_key= (and similar methods) could segfault + when an instance of OpenSSL::PKey::PKey with no public key components is + passed. + [[Bug #14087]](https://bugs.ruby-lang.org/issues/14087) + [[GitHub #168]](https://github.com/ruby/openssl/pull/168) + + +Version 2.0.6 +============= + +Bug fixes +--------- + +* The session_remove_cb set to an OpenSSL::SSL::SSLContext is no longer called + during GC. +* A possible deadlock in OpenSSL::SSL::SSLSocket#sysread is fixed. + [[GitHub #139]](https://github.com/ruby/openssl/pull/139) +* OpenSSL::BN#hash could return an unnormalized fixnum value on Windows. + [[Bug #13877]](https://bugs.ruby-lang.org/issues/13877) +* OpenSSL::SSL::SSLSocket#sysread and #sysread_nonblock set the length of the + destination buffer String to 0 on error. + [[GitHub #153]](https://github.com/ruby/openssl/pull/153) +* Possible deadlock is fixed. This happened only when built with older versions + of OpenSSL (before 1.1.0) or LibreSSL. + [[GitHub #155]](https://github.com/ruby/openssl/pull/155) + + +Version 2.0.5 +============= + +Bug fixes +--------- + +* Reading a PEM/DER-encoded private key or certificate from an IO object did + not work properly on mswin platforms. + [[ruby/openssl#128]](https://github.com/ruby/openssl/issues/128) +* Broken length check in the PEM passphrase callback is fixed. +* It failed to compile when OpenSSL is configured without TLS 1.0 support. + + +Version 2.0.4 +============= + +Bug fixes +--------- + +* It now compiles with LibreSSL without renaming on Windows (mswin). +* A workaround for the error queue leak of X509_load_cert_crl_file() that + causes random errors is added. + [[Bug #11033]](https://bugs.ruby-lang.org/issues/11033) + + +Version 2.0.3 +============= + +Bug fixes +--------- + +* OpenSSL::ASN1::Constructive#each which was broken by 2.0.0 is fixed. + [[ruby/openssl#96]](https://github.com/ruby/openssl/pull/96) +* Fixed build with static OpenSSL libraries on Windows. + [[Bug #13080]](https://bugs.ruby-lang.org/issues/13080) +* OpenSSL::X509::Name#eql? which was broken by 2.0.0 is fixed. + + +Version 2.0.2 +============= + +Bug fixes +--------- + +* Fix build with early 0.9.8 series which did not have SSL_CTX_clear_options(). + [ruby-core:78693] + + +Version 2.0.1 +============= + +Bug fixes +--------- + +* A GC issue around OpenSSL::BN is fixed. + [[ruby/openssl#87]](https://github.com/ruby/openssl/issues/87) +* OpenSSL::ASN1 now parses BER encoding of GeneralizedTime without seconds. + [[ruby/openssl#88]](https://github.com/ruby/openssl/pull/88) + + +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::SSLContext#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/depend b/ext/openssl/depend new file mode 100644 index 0000000000..435f4a1c68 --- /dev/null +++ b/ext/openssl/depend @@ -0,0 +1,6507 @@ +# AUTOGENERATED DEPENDENCIES START +openssl_missing.o: $(RUBY_EXTCONF_H) +openssl_missing.o: $(arch_hdrdir)/ruby/config.h +openssl_missing.o: openssl_missing.c +openssl_missing.o: openssl_missing.h +ossl.o: $(RUBY_EXTCONF_H) +ossl.o: $(arch_hdrdir)/ruby/config.h +ossl.o: $(hdrdir)/ruby.h +ossl.o: $(hdrdir)/ruby/assert.h +ossl.o: $(hdrdir)/ruby/backward.h +ossl.o: $(hdrdir)/ruby/backward/2/assume.h +ossl.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl.o: $(hdrdir)/ruby/backward/2/bool.h +ossl.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl.o: $(hdrdir)/ruby/backward/2/limits.h +ossl.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl.o: $(hdrdir)/ruby/defines.h +ossl.o: $(hdrdir)/ruby/encoding.h +ossl.o: $(hdrdir)/ruby/intern.h +ossl.o: $(hdrdir)/ruby/internal/abi.h +ossl.o: $(hdrdir)/ruby/internal/anyargs.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl.o: $(hdrdir)/ruby/internal/assume.h +ossl.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl.o: $(hdrdir)/ruby/internal/attr/const.h +ossl.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl.o: $(hdrdir)/ruby/internal/attr/error.h +ossl.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl.o: $(hdrdir)/ruby/internal/attr/format.h +ossl.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl.o: $(hdrdir)/ruby/internal/cast.h +ossl.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl.o: $(hdrdir)/ruby/internal/config.h +ossl.o: $(hdrdir)/ruby/internal/constant_p.h +ossl.o: $(hdrdir)/ruby/internal/core.h +ossl.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl.o: $(hdrdir)/ruby/internal/core/robject.h +ossl.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl.o: $(hdrdir)/ruby/internal/ctype.h +ossl.o: $(hdrdir)/ruby/internal/dllexport.h +ossl.o: $(hdrdir)/ruby/internal/dosish.h +ossl.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl.o: $(hdrdir)/ruby/internal/error.h +ossl.o: $(hdrdir)/ruby/internal/eval.h +ossl.o: $(hdrdir)/ruby/internal/event.h +ossl.o: $(hdrdir)/ruby/internal/fl_type.h +ossl.o: $(hdrdir)/ruby/internal/gc.h +ossl.o: $(hdrdir)/ruby/internal/glob.h +ossl.o: $(hdrdir)/ruby/internal/globals.h +ossl.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl.o: $(hdrdir)/ruby/internal/has/extension.h +ossl.o: $(hdrdir)/ruby/internal/has/feature.h +ossl.o: $(hdrdir)/ruby/internal/has/warning.h +ossl.o: $(hdrdir)/ruby/internal/intern/array.h +ossl.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl.o: $(hdrdir)/ruby/internal/intern/class.h +ossl.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl.o: $(hdrdir)/ruby/internal/intern/error.h +ossl.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl.o: $(hdrdir)/ruby/internal/intern/file.h +ossl.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl.o: $(hdrdir)/ruby/internal/intern/io.h +ossl.o: $(hdrdir)/ruby/internal/intern/load.h +ossl.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl.o: $(hdrdir)/ruby/internal/intern/object.h +ossl.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl.o: $(hdrdir)/ruby/internal/intern/process.h +ossl.o: $(hdrdir)/ruby/internal/intern/random.h +ossl.o: $(hdrdir)/ruby/internal/intern/range.h +ossl.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl.o: $(hdrdir)/ruby/internal/intern/re.h +ossl.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl.o: $(hdrdir)/ruby/internal/intern/select.h +ossl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl.o: $(hdrdir)/ruby/internal/intern/set.h +ossl.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl.o: $(hdrdir)/ruby/internal/intern/string.h +ossl.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl.o: $(hdrdir)/ruby/internal/intern/time.h +ossl.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl.o: $(hdrdir)/ruby/internal/interpreter.h +ossl.o: $(hdrdir)/ruby/internal/iterator.h +ossl.o: $(hdrdir)/ruby/internal/memory.h +ossl.o: $(hdrdir)/ruby/internal/method.h +ossl.o: $(hdrdir)/ruby/internal/module.h +ossl.o: $(hdrdir)/ruby/internal/newobj.h +ossl.o: $(hdrdir)/ruby/internal/scan_args.h +ossl.o: $(hdrdir)/ruby/internal/special_consts.h +ossl.o: $(hdrdir)/ruby/internal/static_assert.h +ossl.o: $(hdrdir)/ruby/internal/stdalign.h +ossl.o: $(hdrdir)/ruby/internal/stdbool.h +ossl.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl.o: $(hdrdir)/ruby/internal/symbol.h +ossl.o: $(hdrdir)/ruby/internal/value.h +ossl.o: $(hdrdir)/ruby/internal/value_type.h +ossl.o: $(hdrdir)/ruby/internal/variable.h +ossl.o: $(hdrdir)/ruby/internal/warning_push.h +ossl.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl.o: $(hdrdir)/ruby/io.h +ossl.o: $(hdrdir)/ruby/missing.h +ossl.o: $(hdrdir)/ruby/onigmo.h +ossl.o: $(hdrdir)/ruby/oniguruma.h +ossl.o: $(hdrdir)/ruby/ractor.h +ossl.o: $(hdrdir)/ruby/ruby.h +ossl.o: $(hdrdir)/ruby/st.h +ossl.o: $(hdrdir)/ruby/subst.h +ossl.o: $(hdrdir)/ruby/thread.h +ossl.o: openssl_missing.h +ossl.o: ossl.c +ossl.o: ossl.h +ossl.o: ossl_asn1.h +ossl.o: ossl_bio.h +ossl.o: ossl_bn.h +ossl.o: ossl_cipher.h +ossl.o: ossl_config.h +ossl.o: ossl_digest.h +ossl.o: ossl_engine.h +ossl.o: ossl_hmac.h +ossl.o: ossl_kdf.h +ossl.o: ossl_ns_spki.h +ossl.o: ossl_ocsp.h +ossl.o: ossl_pkcs12.h +ossl.o: ossl_pkcs7.h +ossl.o: ossl_pkey.h +ossl.o: ossl_provider.h +ossl.o: ossl_rand.h +ossl.o: ossl_ssl.h +ossl.o: ossl_ts.h +ossl.o: ossl_x509.h +ossl_asn1.o: $(RUBY_EXTCONF_H) +ossl_asn1.o: $(arch_hdrdir)/ruby/config.h +ossl_asn1.o: $(hdrdir)/ruby.h +ossl_asn1.o: $(hdrdir)/ruby/assert.h +ossl_asn1.o: $(hdrdir)/ruby/backward.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_asn1.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_asn1.o: $(hdrdir)/ruby/defines.h +ossl_asn1.o: $(hdrdir)/ruby/encoding.h +ossl_asn1.o: $(hdrdir)/ruby/intern.h +ossl_asn1.o: $(hdrdir)/ruby/internal/abi.h +ossl_asn1.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_asn1.o: $(hdrdir)/ruby/internal/assume.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_asn1.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_asn1.o: $(hdrdir)/ruby/internal/cast.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_asn1.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_asn1.o: $(hdrdir)/ruby/internal/config.h +ossl_asn1.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_asn1.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_asn1.o: $(hdrdir)/ruby/internal/ctype.h +ossl_asn1.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_asn1.o: $(hdrdir)/ruby/internal/dosish.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_asn1.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_asn1.o: $(hdrdir)/ruby/internal/error.h +ossl_asn1.o: $(hdrdir)/ruby/internal/eval.h +ossl_asn1.o: $(hdrdir)/ruby/internal/event.h +ossl_asn1.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_asn1.o: $(hdrdir)/ruby/internal/gc.h +ossl_asn1.o: $(hdrdir)/ruby/internal/glob.h +ossl_asn1.o: $(hdrdir)/ruby/internal/globals.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_asn1.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_asn1.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_asn1.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_asn1.o: $(hdrdir)/ruby/internal/iterator.h +ossl_asn1.o: $(hdrdir)/ruby/internal/memory.h +ossl_asn1.o: $(hdrdir)/ruby/internal/method.h +ossl_asn1.o: $(hdrdir)/ruby/internal/module.h +ossl_asn1.o: $(hdrdir)/ruby/internal/newobj.h +ossl_asn1.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_asn1.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_asn1.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_asn1.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_asn1.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_asn1.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_asn1.o: $(hdrdir)/ruby/internal/symbol.h +ossl_asn1.o: $(hdrdir)/ruby/internal/value.h +ossl_asn1.o: $(hdrdir)/ruby/internal/value_type.h +ossl_asn1.o: $(hdrdir)/ruby/internal/variable.h +ossl_asn1.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_asn1.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_asn1.o: $(hdrdir)/ruby/io.h +ossl_asn1.o: $(hdrdir)/ruby/missing.h +ossl_asn1.o: $(hdrdir)/ruby/onigmo.h +ossl_asn1.o: $(hdrdir)/ruby/oniguruma.h +ossl_asn1.o: $(hdrdir)/ruby/ractor.h +ossl_asn1.o: $(hdrdir)/ruby/ruby.h +ossl_asn1.o: $(hdrdir)/ruby/st.h +ossl_asn1.o: $(hdrdir)/ruby/subst.h +ossl_asn1.o: $(hdrdir)/ruby/thread.h +ossl_asn1.o: openssl_missing.h +ossl_asn1.o: ossl.h +ossl_asn1.o: ossl_asn1.c +ossl_asn1.o: ossl_asn1.h +ossl_asn1.o: ossl_bio.h +ossl_asn1.o: ossl_bn.h +ossl_asn1.o: ossl_cipher.h +ossl_asn1.o: ossl_config.h +ossl_asn1.o: ossl_digest.h +ossl_asn1.o: ossl_engine.h +ossl_asn1.o: ossl_hmac.h +ossl_asn1.o: ossl_kdf.h +ossl_asn1.o: ossl_ns_spki.h +ossl_asn1.o: ossl_ocsp.h +ossl_asn1.o: ossl_pkcs12.h +ossl_asn1.o: ossl_pkcs7.h +ossl_asn1.o: ossl_pkey.h +ossl_asn1.o: ossl_provider.h +ossl_asn1.o: ossl_rand.h +ossl_asn1.o: ossl_ssl.h +ossl_asn1.o: ossl_ts.h +ossl_asn1.o: ossl_x509.h +ossl_bio.o: $(RUBY_EXTCONF_H) +ossl_bio.o: $(arch_hdrdir)/ruby/config.h +ossl_bio.o: $(hdrdir)/ruby.h +ossl_bio.o: $(hdrdir)/ruby/assert.h +ossl_bio.o: $(hdrdir)/ruby/backward.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_bio.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_bio.o: $(hdrdir)/ruby/defines.h +ossl_bio.o: $(hdrdir)/ruby/encoding.h +ossl_bio.o: $(hdrdir)/ruby/intern.h +ossl_bio.o: $(hdrdir)/ruby/internal/abi.h +ossl_bio.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_bio.o: $(hdrdir)/ruby/internal/assume.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_bio.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_bio.o: $(hdrdir)/ruby/internal/cast.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_bio.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_bio.o: $(hdrdir)/ruby/internal/config.h +ossl_bio.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_bio.o: $(hdrdir)/ruby/internal/core.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_bio.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_bio.o: $(hdrdir)/ruby/internal/ctype.h +ossl_bio.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_bio.o: $(hdrdir)/ruby/internal/dosish.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_bio.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_bio.o: $(hdrdir)/ruby/internal/error.h +ossl_bio.o: $(hdrdir)/ruby/internal/eval.h +ossl_bio.o: $(hdrdir)/ruby/internal/event.h +ossl_bio.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_bio.o: $(hdrdir)/ruby/internal/gc.h +ossl_bio.o: $(hdrdir)/ruby/internal/glob.h +ossl_bio.o: $(hdrdir)/ruby/internal/globals.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_bio.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_bio.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_bio.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_bio.o: $(hdrdir)/ruby/internal/iterator.h +ossl_bio.o: $(hdrdir)/ruby/internal/memory.h +ossl_bio.o: $(hdrdir)/ruby/internal/method.h +ossl_bio.o: $(hdrdir)/ruby/internal/module.h +ossl_bio.o: $(hdrdir)/ruby/internal/newobj.h +ossl_bio.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_bio.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_bio.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_bio.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_bio.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_bio.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_bio.o: $(hdrdir)/ruby/internal/symbol.h +ossl_bio.o: $(hdrdir)/ruby/internal/value.h +ossl_bio.o: $(hdrdir)/ruby/internal/value_type.h +ossl_bio.o: $(hdrdir)/ruby/internal/variable.h +ossl_bio.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_bio.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_bio.o: $(hdrdir)/ruby/io.h +ossl_bio.o: $(hdrdir)/ruby/missing.h +ossl_bio.o: $(hdrdir)/ruby/onigmo.h +ossl_bio.o: $(hdrdir)/ruby/oniguruma.h +ossl_bio.o: $(hdrdir)/ruby/ractor.h +ossl_bio.o: $(hdrdir)/ruby/ruby.h +ossl_bio.o: $(hdrdir)/ruby/st.h +ossl_bio.o: $(hdrdir)/ruby/subst.h +ossl_bio.o: $(hdrdir)/ruby/thread.h +ossl_bio.o: openssl_missing.h +ossl_bio.o: ossl.h +ossl_bio.o: ossl_asn1.h +ossl_bio.o: ossl_bio.c +ossl_bio.o: ossl_bio.h +ossl_bio.o: ossl_bn.h +ossl_bio.o: ossl_cipher.h +ossl_bio.o: ossl_config.h +ossl_bio.o: ossl_digest.h +ossl_bio.o: ossl_engine.h +ossl_bio.o: ossl_hmac.h +ossl_bio.o: ossl_kdf.h +ossl_bio.o: ossl_ns_spki.h +ossl_bio.o: ossl_ocsp.h +ossl_bio.o: ossl_pkcs12.h +ossl_bio.o: ossl_pkcs7.h +ossl_bio.o: ossl_pkey.h +ossl_bio.o: ossl_provider.h +ossl_bio.o: ossl_rand.h +ossl_bio.o: ossl_ssl.h +ossl_bio.o: ossl_ts.h +ossl_bio.o: ossl_x509.h +ossl_bn.o: $(RUBY_EXTCONF_H) +ossl_bn.o: $(arch_hdrdir)/ruby/config.h +ossl_bn.o: $(hdrdir)/ruby.h +ossl_bn.o: $(hdrdir)/ruby/assert.h +ossl_bn.o: $(hdrdir)/ruby/backward.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_bn.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_bn.o: $(hdrdir)/ruby/defines.h +ossl_bn.o: $(hdrdir)/ruby/encoding.h +ossl_bn.o: $(hdrdir)/ruby/intern.h +ossl_bn.o: $(hdrdir)/ruby/internal/abi.h +ossl_bn.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_bn.o: $(hdrdir)/ruby/internal/assume.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_bn.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_bn.o: $(hdrdir)/ruby/internal/cast.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_bn.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_bn.o: $(hdrdir)/ruby/internal/config.h +ossl_bn.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_bn.o: $(hdrdir)/ruby/internal/core.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_bn.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_bn.o: $(hdrdir)/ruby/internal/ctype.h +ossl_bn.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_bn.o: $(hdrdir)/ruby/internal/dosish.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_bn.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_bn.o: $(hdrdir)/ruby/internal/error.h +ossl_bn.o: $(hdrdir)/ruby/internal/eval.h +ossl_bn.o: $(hdrdir)/ruby/internal/event.h +ossl_bn.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_bn.o: $(hdrdir)/ruby/internal/gc.h +ossl_bn.o: $(hdrdir)/ruby/internal/glob.h +ossl_bn.o: $(hdrdir)/ruby/internal/globals.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_bn.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_bn.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_bn.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_bn.o: $(hdrdir)/ruby/internal/iterator.h +ossl_bn.o: $(hdrdir)/ruby/internal/memory.h +ossl_bn.o: $(hdrdir)/ruby/internal/method.h +ossl_bn.o: $(hdrdir)/ruby/internal/module.h +ossl_bn.o: $(hdrdir)/ruby/internal/newobj.h +ossl_bn.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_bn.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_bn.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_bn.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_bn.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_bn.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_bn.o: $(hdrdir)/ruby/internal/symbol.h +ossl_bn.o: $(hdrdir)/ruby/internal/value.h +ossl_bn.o: $(hdrdir)/ruby/internal/value_type.h +ossl_bn.o: $(hdrdir)/ruby/internal/variable.h +ossl_bn.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_bn.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_bn.o: $(hdrdir)/ruby/io.h +ossl_bn.o: $(hdrdir)/ruby/missing.h +ossl_bn.o: $(hdrdir)/ruby/onigmo.h +ossl_bn.o: $(hdrdir)/ruby/oniguruma.h +ossl_bn.o: $(hdrdir)/ruby/ractor.h +ossl_bn.o: $(hdrdir)/ruby/ruby.h +ossl_bn.o: $(hdrdir)/ruby/st.h +ossl_bn.o: $(hdrdir)/ruby/subst.h +ossl_bn.o: $(hdrdir)/ruby/thread.h +ossl_bn.o: openssl_missing.h +ossl_bn.o: ossl.h +ossl_bn.o: ossl_asn1.h +ossl_bn.o: ossl_bio.h +ossl_bn.o: ossl_bn.c +ossl_bn.o: ossl_bn.h +ossl_bn.o: ossl_cipher.h +ossl_bn.o: ossl_config.h +ossl_bn.o: ossl_digest.h +ossl_bn.o: ossl_engine.h +ossl_bn.o: ossl_hmac.h +ossl_bn.o: ossl_kdf.h +ossl_bn.o: ossl_ns_spki.h +ossl_bn.o: ossl_ocsp.h +ossl_bn.o: ossl_pkcs12.h +ossl_bn.o: ossl_pkcs7.h +ossl_bn.o: ossl_pkey.h +ossl_bn.o: ossl_provider.h +ossl_bn.o: ossl_rand.h +ossl_bn.o: ossl_ssl.h +ossl_bn.o: ossl_ts.h +ossl_bn.o: ossl_x509.h +ossl_cipher.o: $(RUBY_EXTCONF_H) +ossl_cipher.o: $(arch_hdrdir)/ruby/config.h +ossl_cipher.o: $(hdrdir)/ruby.h +ossl_cipher.o: $(hdrdir)/ruby/assert.h +ossl_cipher.o: $(hdrdir)/ruby/backward.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_cipher.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_cipher.o: $(hdrdir)/ruby/defines.h +ossl_cipher.o: $(hdrdir)/ruby/encoding.h +ossl_cipher.o: $(hdrdir)/ruby/intern.h +ossl_cipher.o: $(hdrdir)/ruby/internal/abi.h +ossl_cipher.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_cipher.o: $(hdrdir)/ruby/internal/assume.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_cipher.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_cipher.o: $(hdrdir)/ruby/internal/cast.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_cipher.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_cipher.o: $(hdrdir)/ruby/internal/config.h +ossl_cipher.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_cipher.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_cipher.o: $(hdrdir)/ruby/internal/ctype.h +ossl_cipher.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_cipher.o: $(hdrdir)/ruby/internal/dosish.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_cipher.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_cipher.o: $(hdrdir)/ruby/internal/error.h +ossl_cipher.o: $(hdrdir)/ruby/internal/eval.h +ossl_cipher.o: $(hdrdir)/ruby/internal/event.h +ossl_cipher.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_cipher.o: $(hdrdir)/ruby/internal/gc.h +ossl_cipher.o: $(hdrdir)/ruby/internal/glob.h +ossl_cipher.o: $(hdrdir)/ruby/internal/globals.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_cipher.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_cipher.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_cipher.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_cipher.o: $(hdrdir)/ruby/internal/iterator.h +ossl_cipher.o: $(hdrdir)/ruby/internal/memory.h +ossl_cipher.o: $(hdrdir)/ruby/internal/method.h +ossl_cipher.o: $(hdrdir)/ruby/internal/module.h +ossl_cipher.o: $(hdrdir)/ruby/internal/newobj.h +ossl_cipher.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_cipher.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_cipher.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_cipher.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_cipher.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_cipher.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_cipher.o: $(hdrdir)/ruby/internal/symbol.h +ossl_cipher.o: $(hdrdir)/ruby/internal/value.h +ossl_cipher.o: $(hdrdir)/ruby/internal/value_type.h +ossl_cipher.o: $(hdrdir)/ruby/internal/variable.h +ossl_cipher.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_cipher.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_cipher.o: $(hdrdir)/ruby/io.h +ossl_cipher.o: $(hdrdir)/ruby/missing.h +ossl_cipher.o: $(hdrdir)/ruby/onigmo.h +ossl_cipher.o: $(hdrdir)/ruby/oniguruma.h +ossl_cipher.o: $(hdrdir)/ruby/ractor.h +ossl_cipher.o: $(hdrdir)/ruby/ruby.h +ossl_cipher.o: $(hdrdir)/ruby/st.h +ossl_cipher.o: $(hdrdir)/ruby/subst.h +ossl_cipher.o: $(hdrdir)/ruby/thread.h +ossl_cipher.o: openssl_missing.h +ossl_cipher.o: ossl.h +ossl_cipher.o: ossl_asn1.h +ossl_cipher.o: ossl_bio.h +ossl_cipher.o: ossl_bn.h +ossl_cipher.o: ossl_cipher.c +ossl_cipher.o: ossl_cipher.h +ossl_cipher.o: ossl_config.h +ossl_cipher.o: ossl_digest.h +ossl_cipher.o: ossl_engine.h +ossl_cipher.o: ossl_hmac.h +ossl_cipher.o: ossl_kdf.h +ossl_cipher.o: ossl_ns_spki.h +ossl_cipher.o: ossl_ocsp.h +ossl_cipher.o: ossl_pkcs12.h +ossl_cipher.o: ossl_pkcs7.h +ossl_cipher.o: ossl_pkey.h +ossl_cipher.o: ossl_provider.h +ossl_cipher.o: ossl_rand.h +ossl_cipher.o: ossl_ssl.h +ossl_cipher.o: ossl_ts.h +ossl_cipher.o: ossl_x509.h +ossl_config.o: $(RUBY_EXTCONF_H) +ossl_config.o: $(arch_hdrdir)/ruby/config.h +ossl_config.o: $(hdrdir)/ruby.h +ossl_config.o: $(hdrdir)/ruby/assert.h +ossl_config.o: $(hdrdir)/ruby/backward.h +ossl_config.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_config.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_config.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_config.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_config.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_config.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_config.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_config.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_config.o: $(hdrdir)/ruby/defines.h +ossl_config.o: $(hdrdir)/ruby/encoding.h +ossl_config.o: $(hdrdir)/ruby/intern.h +ossl_config.o: $(hdrdir)/ruby/internal/abi.h +ossl_config.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_config.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_config.o: $(hdrdir)/ruby/internal/assume.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_config.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_config.o: $(hdrdir)/ruby/internal/cast.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_config.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_config.o: $(hdrdir)/ruby/internal/config.h +ossl_config.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_config.o: $(hdrdir)/ruby/internal/core.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_config.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_config.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_config.o: $(hdrdir)/ruby/internal/ctype.h +ossl_config.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_config.o: $(hdrdir)/ruby/internal/dosish.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_config.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_config.o: $(hdrdir)/ruby/internal/error.h +ossl_config.o: $(hdrdir)/ruby/internal/eval.h +ossl_config.o: $(hdrdir)/ruby/internal/event.h +ossl_config.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_config.o: $(hdrdir)/ruby/internal/gc.h +ossl_config.o: $(hdrdir)/ruby/internal/glob.h +ossl_config.o: $(hdrdir)/ruby/internal/globals.h +ossl_config.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_config.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_config.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_config.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_config.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_config.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_config.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_config.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_config.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_config.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_config.o: $(hdrdir)/ruby/internal/iterator.h +ossl_config.o: $(hdrdir)/ruby/internal/memory.h +ossl_config.o: $(hdrdir)/ruby/internal/method.h +ossl_config.o: $(hdrdir)/ruby/internal/module.h +ossl_config.o: $(hdrdir)/ruby/internal/newobj.h +ossl_config.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_config.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_config.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_config.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_config.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_config.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_config.o: $(hdrdir)/ruby/internal/symbol.h +ossl_config.o: $(hdrdir)/ruby/internal/value.h +ossl_config.o: $(hdrdir)/ruby/internal/value_type.h +ossl_config.o: $(hdrdir)/ruby/internal/variable.h +ossl_config.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_config.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_config.o: $(hdrdir)/ruby/io.h +ossl_config.o: $(hdrdir)/ruby/missing.h +ossl_config.o: $(hdrdir)/ruby/onigmo.h +ossl_config.o: $(hdrdir)/ruby/oniguruma.h +ossl_config.o: $(hdrdir)/ruby/ractor.h +ossl_config.o: $(hdrdir)/ruby/ruby.h +ossl_config.o: $(hdrdir)/ruby/st.h +ossl_config.o: $(hdrdir)/ruby/subst.h +ossl_config.o: $(hdrdir)/ruby/thread.h +ossl_config.o: openssl_missing.h +ossl_config.o: ossl.h +ossl_config.o: ossl_asn1.h +ossl_config.o: ossl_bio.h +ossl_config.o: ossl_bn.h +ossl_config.o: ossl_cipher.h +ossl_config.o: ossl_config.c +ossl_config.o: ossl_config.h +ossl_config.o: ossl_digest.h +ossl_config.o: ossl_engine.h +ossl_config.o: ossl_hmac.h +ossl_config.o: ossl_kdf.h +ossl_config.o: ossl_ns_spki.h +ossl_config.o: ossl_ocsp.h +ossl_config.o: ossl_pkcs12.h +ossl_config.o: ossl_pkcs7.h +ossl_config.o: ossl_pkey.h +ossl_config.o: ossl_provider.h +ossl_config.o: ossl_rand.h +ossl_config.o: ossl_ssl.h +ossl_config.o: ossl_ts.h +ossl_config.o: ossl_x509.h +ossl_digest.o: $(RUBY_EXTCONF_H) +ossl_digest.o: $(arch_hdrdir)/ruby/config.h +ossl_digest.o: $(hdrdir)/ruby.h +ossl_digest.o: $(hdrdir)/ruby/assert.h +ossl_digest.o: $(hdrdir)/ruby/backward.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_digest.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_digest.o: $(hdrdir)/ruby/defines.h +ossl_digest.o: $(hdrdir)/ruby/encoding.h +ossl_digest.o: $(hdrdir)/ruby/intern.h +ossl_digest.o: $(hdrdir)/ruby/internal/abi.h +ossl_digest.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_digest.o: $(hdrdir)/ruby/internal/assume.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_digest.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_digest.o: $(hdrdir)/ruby/internal/cast.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_digest.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_digest.o: $(hdrdir)/ruby/internal/config.h +ossl_digest.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_digest.o: $(hdrdir)/ruby/internal/core.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_digest.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_digest.o: $(hdrdir)/ruby/internal/ctype.h +ossl_digest.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_digest.o: $(hdrdir)/ruby/internal/dosish.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_digest.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_digest.o: $(hdrdir)/ruby/internal/error.h +ossl_digest.o: $(hdrdir)/ruby/internal/eval.h +ossl_digest.o: $(hdrdir)/ruby/internal/event.h +ossl_digest.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_digest.o: $(hdrdir)/ruby/internal/gc.h +ossl_digest.o: $(hdrdir)/ruby/internal/glob.h +ossl_digest.o: $(hdrdir)/ruby/internal/globals.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_digest.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_digest.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_digest.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_digest.o: $(hdrdir)/ruby/internal/iterator.h +ossl_digest.o: $(hdrdir)/ruby/internal/memory.h +ossl_digest.o: $(hdrdir)/ruby/internal/method.h +ossl_digest.o: $(hdrdir)/ruby/internal/module.h +ossl_digest.o: $(hdrdir)/ruby/internal/newobj.h +ossl_digest.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_digest.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_digest.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_digest.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_digest.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_digest.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_digest.o: $(hdrdir)/ruby/internal/symbol.h +ossl_digest.o: $(hdrdir)/ruby/internal/value.h +ossl_digest.o: $(hdrdir)/ruby/internal/value_type.h +ossl_digest.o: $(hdrdir)/ruby/internal/variable.h +ossl_digest.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_digest.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_digest.o: $(hdrdir)/ruby/io.h +ossl_digest.o: $(hdrdir)/ruby/missing.h +ossl_digest.o: $(hdrdir)/ruby/onigmo.h +ossl_digest.o: $(hdrdir)/ruby/oniguruma.h +ossl_digest.o: $(hdrdir)/ruby/ractor.h +ossl_digest.o: $(hdrdir)/ruby/ruby.h +ossl_digest.o: $(hdrdir)/ruby/st.h +ossl_digest.o: $(hdrdir)/ruby/subst.h +ossl_digest.o: $(hdrdir)/ruby/thread.h +ossl_digest.o: openssl_missing.h +ossl_digest.o: ossl.h +ossl_digest.o: ossl_asn1.h +ossl_digest.o: ossl_bio.h +ossl_digest.o: ossl_bn.h +ossl_digest.o: ossl_cipher.h +ossl_digest.o: ossl_config.h +ossl_digest.o: ossl_digest.c +ossl_digest.o: ossl_digest.h +ossl_digest.o: ossl_engine.h +ossl_digest.o: ossl_hmac.h +ossl_digest.o: ossl_kdf.h +ossl_digest.o: ossl_ns_spki.h +ossl_digest.o: ossl_ocsp.h +ossl_digest.o: ossl_pkcs12.h +ossl_digest.o: ossl_pkcs7.h +ossl_digest.o: ossl_pkey.h +ossl_digest.o: ossl_provider.h +ossl_digest.o: ossl_rand.h +ossl_digest.o: ossl_ssl.h +ossl_digest.o: ossl_ts.h +ossl_digest.o: ossl_x509.h +ossl_engine.o: $(RUBY_EXTCONF_H) +ossl_engine.o: $(arch_hdrdir)/ruby/config.h +ossl_engine.o: $(hdrdir)/ruby.h +ossl_engine.o: $(hdrdir)/ruby/assert.h +ossl_engine.o: $(hdrdir)/ruby/backward.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_engine.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_engine.o: $(hdrdir)/ruby/defines.h +ossl_engine.o: $(hdrdir)/ruby/encoding.h +ossl_engine.o: $(hdrdir)/ruby/intern.h +ossl_engine.o: $(hdrdir)/ruby/internal/abi.h +ossl_engine.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_engine.o: $(hdrdir)/ruby/internal/assume.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_engine.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_engine.o: $(hdrdir)/ruby/internal/cast.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_engine.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_engine.o: $(hdrdir)/ruby/internal/config.h +ossl_engine.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_engine.o: $(hdrdir)/ruby/internal/core.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_engine.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_engine.o: $(hdrdir)/ruby/internal/ctype.h +ossl_engine.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_engine.o: $(hdrdir)/ruby/internal/dosish.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_engine.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_engine.o: $(hdrdir)/ruby/internal/error.h +ossl_engine.o: $(hdrdir)/ruby/internal/eval.h +ossl_engine.o: $(hdrdir)/ruby/internal/event.h +ossl_engine.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_engine.o: $(hdrdir)/ruby/internal/gc.h +ossl_engine.o: $(hdrdir)/ruby/internal/glob.h +ossl_engine.o: $(hdrdir)/ruby/internal/globals.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_engine.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_engine.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_engine.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_engine.o: $(hdrdir)/ruby/internal/iterator.h +ossl_engine.o: $(hdrdir)/ruby/internal/memory.h +ossl_engine.o: $(hdrdir)/ruby/internal/method.h +ossl_engine.o: $(hdrdir)/ruby/internal/module.h +ossl_engine.o: $(hdrdir)/ruby/internal/newobj.h +ossl_engine.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_engine.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_engine.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_engine.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_engine.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_engine.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_engine.o: $(hdrdir)/ruby/internal/symbol.h +ossl_engine.o: $(hdrdir)/ruby/internal/value.h +ossl_engine.o: $(hdrdir)/ruby/internal/value_type.h +ossl_engine.o: $(hdrdir)/ruby/internal/variable.h +ossl_engine.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_engine.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_engine.o: $(hdrdir)/ruby/io.h +ossl_engine.o: $(hdrdir)/ruby/missing.h +ossl_engine.o: $(hdrdir)/ruby/onigmo.h +ossl_engine.o: $(hdrdir)/ruby/oniguruma.h +ossl_engine.o: $(hdrdir)/ruby/ractor.h +ossl_engine.o: $(hdrdir)/ruby/ruby.h +ossl_engine.o: $(hdrdir)/ruby/st.h +ossl_engine.o: $(hdrdir)/ruby/subst.h +ossl_engine.o: $(hdrdir)/ruby/thread.h +ossl_engine.o: openssl_missing.h +ossl_engine.o: ossl.h +ossl_engine.o: ossl_asn1.h +ossl_engine.o: ossl_bio.h +ossl_engine.o: ossl_bn.h +ossl_engine.o: ossl_cipher.h +ossl_engine.o: ossl_config.h +ossl_engine.o: ossl_digest.h +ossl_engine.o: ossl_engine.c +ossl_engine.o: ossl_engine.h +ossl_engine.o: ossl_hmac.h +ossl_engine.o: ossl_kdf.h +ossl_engine.o: ossl_ns_spki.h +ossl_engine.o: ossl_ocsp.h +ossl_engine.o: ossl_pkcs12.h +ossl_engine.o: ossl_pkcs7.h +ossl_engine.o: ossl_pkey.h +ossl_engine.o: ossl_provider.h +ossl_engine.o: ossl_rand.h +ossl_engine.o: ossl_ssl.h +ossl_engine.o: ossl_ts.h +ossl_engine.o: ossl_x509.h +ossl_hmac.o: $(RUBY_EXTCONF_H) +ossl_hmac.o: $(arch_hdrdir)/ruby/config.h +ossl_hmac.o: $(hdrdir)/ruby.h +ossl_hmac.o: $(hdrdir)/ruby/assert.h +ossl_hmac.o: $(hdrdir)/ruby/backward.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_hmac.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_hmac.o: $(hdrdir)/ruby/defines.h +ossl_hmac.o: $(hdrdir)/ruby/encoding.h +ossl_hmac.o: $(hdrdir)/ruby/intern.h +ossl_hmac.o: $(hdrdir)/ruby/internal/abi.h +ossl_hmac.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_hmac.o: $(hdrdir)/ruby/internal/assume.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_hmac.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_hmac.o: $(hdrdir)/ruby/internal/cast.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_hmac.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_hmac.o: $(hdrdir)/ruby/internal/config.h +ossl_hmac.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_hmac.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_hmac.o: $(hdrdir)/ruby/internal/ctype.h +ossl_hmac.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_hmac.o: $(hdrdir)/ruby/internal/dosish.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_hmac.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_hmac.o: $(hdrdir)/ruby/internal/error.h +ossl_hmac.o: $(hdrdir)/ruby/internal/eval.h +ossl_hmac.o: $(hdrdir)/ruby/internal/event.h +ossl_hmac.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_hmac.o: $(hdrdir)/ruby/internal/gc.h +ossl_hmac.o: $(hdrdir)/ruby/internal/glob.h +ossl_hmac.o: $(hdrdir)/ruby/internal/globals.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_hmac.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_hmac.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_hmac.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_hmac.o: $(hdrdir)/ruby/internal/iterator.h +ossl_hmac.o: $(hdrdir)/ruby/internal/memory.h +ossl_hmac.o: $(hdrdir)/ruby/internal/method.h +ossl_hmac.o: $(hdrdir)/ruby/internal/module.h +ossl_hmac.o: $(hdrdir)/ruby/internal/newobj.h +ossl_hmac.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_hmac.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_hmac.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_hmac.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_hmac.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_hmac.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_hmac.o: $(hdrdir)/ruby/internal/symbol.h +ossl_hmac.o: $(hdrdir)/ruby/internal/value.h +ossl_hmac.o: $(hdrdir)/ruby/internal/value_type.h +ossl_hmac.o: $(hdrdir)/ruby/internal/variable.h +ossl_hmac.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_hmac.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_hmac.o: $(hdrdir)/ruby/io.h +ossl_hmac.o: $(hdrdir)/ruby/missing.h +ossl_hmac.o: $(hdrdir)/ruby/onigmo.h +ossl_hmac.o: $(hdrdir)/ruby/oniguruma.h +ossl_hmac.o: $(hdrdir)/ruby/ractor.h +ossl_hmac.o: $(hdrdir)/ruby/ruby.h +ossl_hmac.o: $(hdrdir)/ruby/st.h +ossl_hmac.o: $(hdrdir)/ruby/subst.h +ossl_hmac.o: $(hdrdir)/ruby/thread.h +ossl_hmac.o: openssl_missing.h +ossl_hmac.o: ossl.h +ossl_hmac.o: ossl_asn1.h +ossl_hmac.o: ossl_bio.h +ossl_hmac.o: ossl_bn.h +ossl_hmac.o: ossl_cipher.h +ossl_hmac.o: ossl_config.h +ossl_hmac.o: ossl_digest.h +ossl_hmac.o: ossl_engine.h +ossl_hmac.o: ossl_hmac.c +ossl_hmac.o: ossl_hmac.h +ossl_hmac.o: ossl_kdf.h +ossl_hmac.o: ossl_ns_spki.h +ossl_hmac.o: ossl_ocsp.h +ossl_hmac.o: ossl_pkcs12.h +ossl_hmac.o: ossl_pkcs7.h +ossl_hmac.o: ossl_pkey.h +ossl_hmac.o: ossl_provider.h +ossl_hmac.o: ossl_rand.h +ossl_hmac.o: ossl_ssl.h +ossl_hmac.o: ossl_ts.h +ossl_hmac.o: ossl_x509.h +ossl_kdf.o: $(RUBY_EXTCONF_H) +ossl_kdf.o: $(arch_hdrdir)/ruby/config.h +ossl_kdf.o: $(hdrdir)/ruby.h +ossl_kdf.o: $(hdrdir)/ruby/assert.h +ossl_kdf.o: $(hdrdir)/ruby/backward.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_kdf.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_kdf.o: $(hdrdir)/ruby/defines.h +ossl_kdf.o: $(hdrdir)/ruby/encoding.h +ossl_kdf.o: $(hdrdir)/ruby/intern.h +ossl_kdf.o: $(hdrdir)/ruby/internal/abi.h +ossl_kdf.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_kdf.o: $(hdrdir)/ruby/internal/assume.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_kdf.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_kdf.o: $(hdrdir)/ruby/internal/cast.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_kdf.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_kdf.o: $(hdrdir)/ruby/internal/config.h +ossl_kdf.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_kdf.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_kdf.o: $(hdrdir)/ruby/internal/ctype.h +ossl_kdf.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_kdf.o: $(hdrdir)/ruby/internal/dosish.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_kdf.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_kdf.o: $(hdrdir)/ruby/internal/error.h +ossl_kdf.o: $(hdrdir)/ruby/internal/eval.h +ossl_kdf.o: $(hdrdir)/ruby/internal/event.h +ossl_kdf.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_kdf.o: $(hdrdir)/ruby/internal/gc.h +ossl_kdf.o: $(hdrdir)/ruby/internal/glob.h +ossl_kdf.o: $(hdrdir)/ruby/internal/globals.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_kdf.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_kdf.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_kdf.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_kdf.o: $(hdrdir)/ruby/internal/iterator.h +ossl_kdf.o: $(hdrdir)/ruby/internal/memory.h +ossl_kdf.o: $(hdrdir)/ruby/internal/method.h +ossl_kdf.o: $(hdrdir)/ruby/internal/module.h +ossl_kdf.o: $(hdrdir)/ruby/internal/newobj.h +ossl_kdf.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_kdf.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_kdf.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_kdf.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_kdf.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_kdf.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_kdf.o: $(hdrdir)/ruby/internal/symbol.h +ossl_kdf.o: $(hdrdir)/ruby/internal/value.h +ossl_kdf.o: $(hdrdir)/ruby/internal/value_type.h +ossl_kdf.o: $(hdrdir)/ruby/internal/variable.h +ossl_kdf.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_kdf.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_kdf.o: $(hdrdir)/ruby/io.h +ossl_kdf.o: $(hdrdir)/ruby/missing.h +ossl_kdf.o: $(hdrdir)/ruby/onigmo.h +ossl_kdf.o: $(hdrdir)/ruby/oniguruma.h +ossl_kdf.o: $(hdrdir)/ruby/ractor.h +ossl_kdf.o: $(hdrdir)/ruby/ruby.h +ossl_kdf.o: $(hdrdir)/ruby/st.h +ossl_kdf.o: $(hdrdir)/ruby/subst.h +ossl_kdf.o: $(hdrdir)/ruby/thread.h +ossl_kdf.o: openssl_missing.h +ossl_kdf.o: ossl.h +ossl_kdf.o: ossl_asn1.h +ossl_kdf.o: ossl_bio.h +ossl_kdf.o: ossl_bn.h +ossl_kdf.o: ossl_cipher.h +ossl_kdf.o: ossl_config.h +ossl_kdf.o: ossl_digest.h +ossl_kdf.o: ossl_engine.h +ossl_kdf.o: ossl_hmac.h +ossl_kdf.o: ossl_kdf.c +ossl_kdf.o: ossl_kdf.h +ossl_kdf.o: ossl_ns_spki.h +ossl_kdf.o: ossl_ocsp.h +ossl_kdf.o: ossl_pkcs12.h +ossl_kdf.o: ossl_pkcs7.h +ossl_kdf.o: ossl_pkey.h +ossl_kdf.o: ossl_provider.h +ossl_kdf.o: ossl_rand.h +ossl_kdf.o: ossl_ssl.h +ossl_kdf.o: ossl_ts.h +ossl_kdf.o: ossl_x509.h +ossl_ns_spki.o: $(RUBY_EXTCONF_H) +ossl_ns_spki.o: $(arch_hdrdir)/ruby/config.h +ossl_ns_spki.o: $(hdrdir)/ruby.h +ossl_ns_spki.o: $(hdrdir)/ruby/assert.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_ns_spki.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_ns_spki.o: $(hdrdir)/ruby/defines.h +ossl_ns_spki.o: $(hdrdir)/ruby/encoding.h +ossl_ns_spki.o: $(hdrdir)/ruby/intern.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/abi.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/assume.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/cast.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/config.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/ctype.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/dosish.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/error.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/eval.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/event.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/gc.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/glob.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/globals.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/iterator.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/memory.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/method.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/module.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/newobj.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/symbol.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/value.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/value_type.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/variable.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_ns_spki.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_ns_spki.o: $(hdrdir)/ruby/io.h +ossl_ns_spki.o: $(hdrdir)/ruby/missing.h +ossl_ns_spki.o: $(hdrdir)/ruby/onigmo.h +ossl_ns_spki.o: $(hdrdir)/ruby/oniguruma.h +ossl_ns_spki.o: $(hdrdir)/ruby/ractor.h +ossl_ns_spki.o: $(hdrdir)/ruby/ruby.h +ossl_ns_spki.o: $(hdrdir)/ruby/st.h +ossl_ns_spki.o: $(hdrdir)/ruby/subst.h +ossl_ns_spki.o: $(hdrdir)/ruby/thread.h +ossl_ns_spki.o: openssl_missing.h +ossl_ns_spki.o: ossl.h +ossl_ns_spki.o: ossl_asn1.h +ossl_ns_spki.o: ossl_bio.h +ossl_ns_spki.o: ossl_bn.h +ossl_ns_spki.o: ossl_cipher.h +ossl_ns_spki.o: ossl_config.h +ossl_ns_spki.o: ossl_digest.h +ossl_ns_spki.o: ossl_engine.h +ossl_ns_spki.o: ossl_hmac.h +ossl_ns_spki.o: ossl_kdf.h +ossl_ns_spki.o: ossl_ns_spki.c +ossl_ns_spki.o: ossl_ns_spki.h +ossl_ns_spki.o: ossl_ocsp.h +ossl_ns_spki.o: ossl_pkcs12.h +ossl_ns_spki.o: ossl_pkcs7.h +ossl_ns_spki.o: ossl_pkey.h +ossl_ns_spki.o: ossl_provider.h +ossl_ns_spki.o: ossl_rand.h +ossl_ns_spki.o: ossl_ssl.h +ossl_ns_spki.o: ossl_ts.h +ossl_ns_spki.o: ossl_x509.h +ossl_ocsp.o: $(RUBY_EXTCONF_H) +ossl_ocsp.o: $(arch_hdrdir)/ruby/config.h +ossl_ocsp.o: $(hdrdir)/ruby.h +ossl_ocsp.o: $(hdrdir)/ruby/assert.h +ossl_ocsp.o: $(hdrdir)/ruby/backward.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_ocsp.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_ocsp.o: $(hdrdir)/ruby/defines.h +ossl_ocsp.o: $(hdrdir)/ruby/encoding.h +ossl_ocsp.o: $(hdrdir)/ruby/intern.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/abi.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/assume.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/cast.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/config.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/ctype.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/dosish.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/error.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/eval.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/event.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/gc.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/glob.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/globals.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/iterator.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/memory.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/method.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/module.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/newobj.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/symbol.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/value.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/value_type.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/variable.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_ocsp.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_ocsp.o: $(hdrdir)/ruby/io.h +ossl_ocsp.o: $(hdrdir)/ruby/missing.h +ossl_ocsp.o: $(hdrdir)/ruby/onigmo.h +ossl_ocsp.o: $(hdrdir)/ruby/oniguruma.h +ossl_ocsp.o: $(hdrdir)/ruby/ractor.h +ossl_ocsp.o: $(hdrdir)/ruby/ruby.h +ossl_ocsp.o: $(hdrdir)/ruby/st.h +ossl_ocsp.o: $(hdrdir)/ruby/subst.h +ossl_ocsp.o: $(hdrdir)/ruby/thread.h +ossl_ocsp.o: openssl_missing.h +ossl_ocsp.o: ossl.h +ossl_ocsp.o: ossl_asn1.h +ossl_ocsp.o: ossl_bio.h +ossl_ocsp.o: ossl_bn.h +ossl_ocsp.o: ossl_cipher.h +ossl_ocsp.o: ossl_config.h +ossl_ocsp.o: ossl_digest.h +ossl_ocsp.o: ossl_engine.h +ossl_ocsp.o: ossl_hmac.h +ossl_ocsp.o: ossl_kdf.h +ossl_ocsp.o: ossl_ns_spki.h +ossl_ocsp.o: ossl_ocsp.c +ossl_ocsp.o: ossl_ocsp.h +ossl_ocsp.o: ossl_pkcs12.h +ossl_ocsp.o: ossl_pkcs7.h +ossl_ocsp.o: ossl_pkey.h +ossl_ocsp.o: ossl_provider.h +ossl_ocsp.o: ossl_rand.h +ossl_ocsp.o: ossl_ssl.h +ossl_ocsp.o: ossl_ts.h +ossl_ocsp.o: ossl_x509.h +ossl_pkcs12.o: $(RUBY_EXTCONF_H) +ossl_pkcs12.o: $(arch_hdrdir)/ruby/config.h +ossl_pkcs12.o: $(hdrdir)/ruby.h +ossl_pkcs12.o: $(hdrdir)/ruby/assert.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_pkcs12.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_pkcs12.o: $(hdrdir)/ruby/defines.h +ossl_pkcs12.o: $(hdrdir)/ruby/encoding.h +ossl_pkcs12.o: $(hdrdir)/ruby/intern.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/abi.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/assume.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/cast.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/config.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/ctype.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/dosish.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/error.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/eval.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/event.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/gc.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/glob.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/globals.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/iterator.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/memory.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/method.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/module.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/newobj.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/symbol.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/value.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/value_type.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/variable.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_pkcs12.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_pkcs12.o: $(hdrdir)/ruby/io.h +ossl_pkcs12.o: $(hdrdir)/ruby/missing.h +ossl_pkcs12.o: $(hdrdir)/ruby/onigmo.h +ossl_pkcs12.o: $(hdrdir)/ruby/oniguruma.h +ossl_pkcs12.o: $(hdrdir)/ruby/ractor.h +ossl_pkcs12.o: $(hdrdir)/ruby/ruby.h +ossl_pkcs12.o: $(hdrdir)/ruby/st.h +ossl_pkcs12.o: $(hdrdir)/ruby/subst.h +ossl_pkcs12.o: $(hdrdir)/ruby/thread.h +ossl_pkcs12.o: openssl_missing.h +ossl_pkcs12.o: ossl.h +ossl_pkcs12.o: ossl_asn1.h +ossl_pkcs12.o: ossl_bio.h +ossl_pkcs12.o: ossl_bn.h +ossl_pkcs12.o: ossl_cipher.h +ossl_pkcs12.o: ossl_config.h +ossl_pkcs12.o: ossl_digest.h +ossl_pkcs12.o: ossl_engine.h +ossl_pkcs12.o: ossl_hmac.h +ossl_pkcs12.o: ossl_kdf.h +ossl_pkcs12.o: ossl_ns_spki.h +ossl_pkcs12.o: ossl_ocsp.h +ossl_pkcs12.o: ossl_pkcs12.c +ossl_pkcs12.o: ossl_pkcs12.h +ossl_pkcs12.o: ossl_pkcs7.h +ossl_pkcs12.o: ossl_pkey.h +ossl_pkcs12.o: ossl_provider.h +ossl_pkcs12.o: ossl_rand.h +ossl_pkcs12.o: ossl_ssl.h +ossl_pkcs12.o: ossl_ts.h +ossl_pkcs12.o: ossl_x509.h +ossl_pkcs7.o: $(RUBY_EXTCONF_H) +ossl_pkcs7.o: $(arch_hdrdir)/ruby/config.h +ossl_pkcs7.o: $(hdrdir)/ruby.h +ossl_pkcs7.o: $(hdrdir)/ruby/assert.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_pkcs7.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_pkcs7.o: $(hdrdir)/ruby/defines.h +ossl_pkcs7.o: $(hdrdir)/ruby/encoding.h +ossl_pkcs7.o: $(hdrdir)/ruby/intern.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/abi.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/assume.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/cast.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/config.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/ctype.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/dosish.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/error.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/eval.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/event.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/gc.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/glob.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/globals.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/iterator.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/memory.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/method.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/module.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/newobj.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/symbol.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/value.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/value_type.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/variable.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_pkcs7.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_pkcs7.o: $(hdrdir)/ruby/io.h +ossl_pkcs7.o: $(hdrdir)/ruby/missing.h +ossl_pkcs7.o: $(hdrdir)/ruby/onigmo.h +ossl_pkcs7.o: $(hdrdir)/ruby/oniguruma.h +ossl_pkcs7.o: $(hdrdir)/ruby/ractor.h +ossl_pkcs7.o: $(hdrdir)/ruby/ruby.h +ossl_pkcs7.o: $(hdrdir)/ruby/st.h +ossl_pkcs7.o: $(hdrdir)/ruby/subst.h +ossl_pkcs7.o: $(hdrdir)/ruby/thread.h +ossl_pkcs7.o: openssl_missing.h +ossl_pkcs7.o: ossl.h +ossl_pkcs7.o: ossl_asn1.h +ossl_pkcs7.o: ossl_bio.h +ossl_pkcs7.o: ossl_bn.h +ossl_pkcs7.o: ossl_cipher.h +ossl_pkcs7.o: ossl_config.h +ossl_pkcs7.o: ossl_digest.h +ossl_pkcs7.o: ossl_engine.h +ossl_pkcs7.o: ossl_hmac.h +ossl_pkcs7.o: ossl_kdf.h +ossl_pkcs7.o: ossl_ns_spki.h +ossl_pkcs7.o: ossl_ocsp.h +ossl_pkcs7.o: ossl_pkcs12.h +ossl_pkcs7.o: ossl_pkcs7.c +ossl_pkcs7.o: ossl_pkcs7.h +ossl_pkcs7.o: ossl_pkey.h +ossl_pkcs7.o: ossl_provider.h +ossl_pkcs7.o: ossl_rand.h +ossl_pkcs7.o: ossl_ssl.h +ossl_pkcs7.o: ossl_ts.h +ossl_pkcs7.o: ossl_x509.h +ossl_pkey.o: $(RUBY_EXTCONF_H) +ossl_pkey.o: $(arch_hdrdir)/ruby/config.h +ossl_pkey.o: $(hdrdir)/ruby.h +ossl_pkey.o: $(hdrdir)/ruby/assert.h +ossl_pkey.o: $(hdrdir)/ruby/backward.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_pkey.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_pkey.o: $(hdrdir)/ruby/defines.h +ossl_pkey.o: $(hdrdir)/ruby/encoding.h +ossl_pkey.o: $(hdrdir)/ruby/intern.h +ossl_pkey.o: $(hdrdir)/ruby/internal/abi.h +ossl_pkey.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_pkey.o: $(hdrdir)/ruby/internal/assume.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_pkey.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_pkey.o: $(hdrdir)/ruby/internal/cast.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_pkey.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_pkey.o: $(hdrdir)/ruby/internal/config.h +ossl_pkey.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_pkey.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_pkey.o: $(hdrdir)/ruby/internal/ctype.h +ossl_pkey.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_pkey.o: $(hdrdir)/ruby/internal/dosish.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_pkey.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_pkey.o: $(hdrdir)/ruby/internal/error.h +ossl_pkey.o: $(hdrdir)/ruby/internal/eval.h +ossl_pkey.o: $(hdrdir)/ruby/internal/event.h +ossl_pkey.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_pkey.o: $(hdrdir)/ruby/internal/gc.h +ossl_pkey.o: $(hdrdir)/ruby/internal/glob.h +ossl_pkey.o: $(hdrdir)/ruby/internal/globals.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_pkey.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_pkey.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_pkey.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_pkey.o: $(hdrdir)/ruby/internal/iterator.h +ossl_pkey.o: $(hdrdir)/ruby/internal/memory.h +ossl_pkey.o: $(hdrdir)/ruby/internal/method.h +ossl_pkey.o: $(hdrdir)/ruby/internal/module.h +ossl_pkey.o: $(hdrdir)/ruby/internal/newobj.h +ossl_pkey.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_pkey.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_pkey.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_pkey.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_pkey.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_pkey.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_pkey.o: $(hdrdir)/ruby/internal/symbol.h +ossl_pkey.o: $(hdrdir)/ruby/internal/value.h +ossl_pkey.o: $(hdrdir)/ruby/internal/value_type.h +ossl_pkey.o: $(hdrdir)/ruby/internal/variable.h +ossl_pkey.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_pkey.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_pkey.o: $(hdrdir)/ruby/io.h +ossl_pkey.o: $(hdrdir)/ruby/missing.h +ossl_pkey.o: $(hdrdir)/ruby/onigmo.h +ossl_pkey.o: $(hdrdir)/ruby/oniguruma.h +ossl_pkey.o: $(hdrdir)/ruby/ractor.h +ossl_pkey.o: $(hdrdir)/ruby/ruby.h +ossl_pkey.o: $(hdrdir)/ruby/st.h +ossl_pkey.o: $(hdrdir)/ruby/subst.h +ossl_pkey.o: $(hdrdir)/ruby/thread.h +ossl_pkey.o: openssl_missing.h +ossl_pkey.o: ossl.h +ossl_pkey.o: ossl_asn1.h +ossl_pkey.o: ossl_bio.h +ossl_pkey.o: ossl_bn.h +ossl_pkey.o: ossl_cipher.h +ossl_pkey.o: ossl_config.h +ossl_pkey.o: ossl_digest.h +ossl_pkey.o: ossl_engine.h +ossl_pkey.o: ossl_hmac.h +ossl_pkey.o: ossl_kdf.h +ossl_pkey.o: ossl_ns_spki.h +ossl_pkey.o: ossl_ocsp.h +ossl_pkey.o: ossl_pkcs12.h +ossl_pkey.o: ossl_pkcs7.h +ossl_pkey.o: ossl_pkey.c +ossl_pkey.o: ossl_pkey.h +ossl_pkey.o: ossl_provider.h +ossl_pkey.o: ossl_rand.h +ossl_pkey.o: ossl_ssl.h +ossl_pkey.o: ossl_ts.h +ossl_pkey.o: ossl_x509.h +ossl_pkey_dh.o: $(RUBY_EXTCONF_H) +ossl_pkey_dh.o: $(arch_hdrdir)/ruby/config.h +ossl_pkey_dh.o: $(hdrdir)/ruby.h +ossl_pkey_dh.o: $(hdrdir)/ruby/assert.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_pkey_dh.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_pkey_dh.o: $(hdrdir)/ruby/defines.h +ossl_pkey_dh.o: $(hdrdir)/ruby/encoding.h +ossl_pkey_dh.o: $(hdrdir)/ruby/intern.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/abi.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/assume.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/cast.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/config.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/ctype.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/dosish.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/error.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/eval.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/event.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/gc.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/glob.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/globals.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/iterator.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/memory.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/method.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/module.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/newobj.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/symbol.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/value.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/value_type.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/variable.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_pkey_dh.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_pkey_dh.o: $(hdrdir)/ruby/io.h +ossl_pkey_dh.o: $(hdrdir)/ruby/missing.h +ossl_pkey_dh.o: $(hdrdir)/ruby/onigmo.h +ossl_pkey_dh.o: $(hdrdir)/ruby/oniguruma.h +ossl_pkey_dh.o: $(hdrdir)/ruby/ractor.h +ossl_pkey_dh.o: $(hdrdir)/ruby/ruby.h +ossl_pkey_dh.o: $(hdrdir)/ruby/st.h +ossl_pkey_dh.o: $(hdrdir)/ruby/subst.h +ossl_pkey_dh.o: $(hdrdir)/ruby/thread.h +ossl_pkey_dh.o: openssl_missing.h +ossl_pkey_dh.o: ossl.h +ossl_pkey_dh.o: ossl_asn1.h +ossl_pkey_dh.o: ossl_bio.h +ossl_pkey_dh.o: ossl_bn.h +ossl_pkey_dh.o: ossl_cipher.h +ossl_pkey_dh.o: ossl_config.h +ossl_pkey_dh.o: ossl_digest.h +ossl_pkey_dh.o: ossl_engine.h +ossl_pkey_dh.o: ossl_hmac.h +ossl_pkey_dh.o: ossl_kdf.h +ossl_pkey_dh.o: ossl_ns_spki.h +ossl_pkey_dh.o: ossl_ocsp.h +ossl_pkey_dh.o: ossl_pkcs12.h +ossl_pkey_dh.o: ossl_pkcs7.h +ossl_pkey_dh.o: ossl_pkey.h +ossl_pkey_dh.o: ossl_pkey_dh.c +ossl_pkey_dh.o: ossl_provider.h +ossl_pkey_dh.o: ossl_rand.h +ossl_pkey_dh.o: ossl_ssl.h +ossl_pkey_dh.o: ossl_ts.h +ossl_pkey_dh.o: ossl_x509.h +ossl_pkey_dsa.o: $(RUBY_EXTCONF_H) +ossl_pkey_dsa.o: $(arch_hdrdir)/ruby/config.h +ossl_pkey_dsa.o: $(hdrdir)/ruby.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/assert.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/defines.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/encoding.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/intern.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/abi.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/assume.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/cast.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/config.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/ctype.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/dosish.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/error.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/eval.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/event.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/gc.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/glob.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/globals.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/iterator.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/memory.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/method.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/module.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/newobj.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/symbol.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/value.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/value_type.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/variable.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/io.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/missing.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/onigmo.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/oniguruma.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/ractor.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/ruby.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/st.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/subst.h +ossl_pkey_dsa.o: $(hdrdir)/ruby/thread.h +ossl_pkey_dsa.o: openssl_missing.h +ossl_pkey_dsa.o: ossl.h +ossl_pkey_dsa.o: ossl_asn1.h +ossl_pkey_dsa.o: ossl_bio.h +ossl_pkey_dsa.o: ossl_bn.h +ossl_pkey_dsa.o: ossl_cipher.h +ossl_pkey_dsa.o: ossl_config.h +ossl_pkey_dsa.o: ossl_digest.h +ossl_pkey_dsa.o: ossl_engine.h +ossl_pkey_dsa.o: ossl_hmac.h +ossl_pkey_dsa.o: ossl_kdf.h +ossl_pkey_dsa.o: ossl_ns_spki.h +ossl_pkey_dsa.o: ossl_ocsp.h +ossl_pkey_dsa.o: ossl_pkcs12.h +ossl_pkey_dsa.o: ossl_pkcs7.h +ossl_pkey_dsa.o: ossl_pkey.h +ossl_pkey_dsa.o: ossl_pkey_dsa.c +ossl_pkey_dsa.o: ossl_provider.h +ossl_pkey_dsa.o: ossl_rand.h +ossl_pkey_dsa.o: ossl_ssl.h +ossl_pkey_dsa.o: ossl_ts.h +ossl_pkey_dsa.o: ossl_x509.h +ossl_pkey_ec.o: $(RUBY_EXTCONF_H) +ossl_pkey_ec.o: $(arch_hdrdir)/ruby/config.h +ossl_pkey_ec.o: $(hdrdir)/ruby.h +ossl_pkey_ec.o: $(hdrdir)/ruby/assert.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_pkey_ec.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_pkey_ec.o: $(hdrdir)/ruby/defines.h +ossl_pkey_ec.o: $(hdrdir)/ruby/encoding.h +ossl_pkey_ec.o: $(hdrdir)/ruby/intern.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/abi.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/assume.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/cast.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/config.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/ctype.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/dosish.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/error.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/eval.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/event.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/gc.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/glob.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/globals.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/iterator.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/memory.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/method.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/module.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/newobj.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/symbol.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/value.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/value_type.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/variable.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_pkey_ec.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_pkey_ec.o: $(hdrdir)/ruby/io.h +ossl_pkey_ec.o: $(hdrdir)/ruby/missing.h +ossl_pkey_ec.o: $(hdrdir)/ruby/onigmo.h +ossl_pkey_ec.o: $(hdrdir)/ruby/oniguruma.h +ossl_pkey_ec.o: $(hdrdir)/ruby/ractor.h +ossl_pkey_ec.o: $(hdrdir)/ruby/ruby.h +ossl_pkey_ec.o: $(hdrdir)/ruby/st.h +ossl_pkey_ec.o: $(hdrdir)/ruby/subst.h +ossl_pkey_ec.o: $(hdrdir)/ruby/thread.h +ossl_pkey_ec.o: openssl_missing.h +ossl_pkey_ec.o: ossl.h +ossl_pkey_ec.o: ossl_asn1.h +ossl_pkey_ec.o: ossl_bio.h +ossl_pkey_ec.o: ossl_bn.h +ossl_pkey_ec.o: ossl_cipher.h +ossl_pkey_ec.o: ossl_config.h +ossl_pkey_ec.o: ossl_digest.h +ossl_pkey_ec.o: ossl_engine.h +ossl_pkey_ec.o: ossl_hmac.h +ossl_pkey_ec.o: ossl_kdf.h +ossl_pkey_ec.o: ossl_ns_spki.h +ossl_pkey_ec.o: ossl_ocsp.h +ossl_pkey_ec.o: ossl_pkcs12.h +ossl_pkey_ec.o: ossl_pkcs7.h +ossl_pkey_ec.o: ossl_pkey.h +ossl_pkey_ec.o: ossl_pkey_ec.c +ossl_pkey_ec.o: ossl_provider.h +ossl_pkey_ec.o: ossl_rand.h +ossl_pkey_ec.o: ossl_ssl.h +ossl_pkey_ec.o: ossl_ts.h +ossl_pkey_ec.o: ossl_x509.h +ossl_pkey_rsa.o: $(RUBY_EXTCONF_H) +ossl_pkey_rsa.o: $(arch_hdrdir)/ruby/config.h +ossl_pkey_rsa.o: $(hdrdir)/ruby.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/assert.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/defines.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/encoding.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/intern.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/abi.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/assume.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/cast.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/config.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/ctype.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/dosish.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/error.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/eval.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/event.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/gc.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/glob.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/globals.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/iterator.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/memory.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/method.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/module.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/newobj.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/symbol.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/value.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/value_type.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/variable.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/io.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/missing.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/onigmo.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/oniguruma.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/ractor.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/ruby.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/st.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/subst.h +ossl_pkey_rsa.o: $(hdrdir)/ruby/thread.h +ossl_pkey_rsa.o: openssl_missing.h +ossl_pkey_rsa.o: ossl.h +ossl_pkey_rsa.o: ossl_asn1.h +ossl_pkey_rsa.o: ossl_bio.h +ossl_pkey_rsa.o: ossl_bn.h +ossl_pkey_rsa.o: ossl_cipher.h +ossl_pkey_rsa.o: ossl_config.h +ossl_pkey_rsa.o: ossl_digest.h +ossl_pkey_rsa.o: ossl_engine.h +ossl_pkey_rsa.o: ossl_hmac.h +ossl_pkey_rsa.o: ossl_kdf.h +ossl_pkey_rsa.o: ossl_ns_spki.h +ossl_pkey_rsa.o: ossl_ocsp.h +ossl_pkey_rsa.o: ossl_pkcs12.h +ossl_pkey_rsa.o: ossl_pkcs7.h +ossl_pkey_rsa.o: ossl_pkey.h +ossl_pkey_rsa.o: ossl_pkey_rsa.c +ossl_pkey_rsa.o: ossl_provider.h +ossl_pkey_rsa.o: ossl_rand.h +ossl_pkey_rsa.o: ossl_ssl.h +ossl_pkey_rsa.o: ossl_ts.h +ossl_pkey_rsa.o: ossl_x509.h +ossl_provider.o: $(RUBY_EXTCONF_H) +ossl_provider.o: $(arch_hdrdir)/ruby/config.h +ossl_provider.o: $(hdrdir)/ruby.h +ossl_provider.o: $(hdrdir)/ruby/assert.h +ossl_provider.o: $(hdrdir)/ruby/backward.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_provider.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_provider.o: $(hdrdir)/ruby/defines.h +ossl_provider.o: $(hdrdir)/ruby/encoding.h +ossl_provider.o: $(hdrdir)/ruby/intern.h +ossl_provider.o: $(hdrdir)/ruby/internal/abi.h +ossl_provider.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_provider.o: $(hdrdir)/ruby/internal/assume.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_provider.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_provider.o: $(hdrdir)/ruby/internal/cast.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_provider.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_provider.o: $(hdrdir)/ruby/internal/config.h +ossl_provider.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_provider.o: $(hdrdir)/ruby/internal/core.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_provider.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_provider.o: $(hdrdir)/ruby/internal/ctype.h +ossl_provider.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_provider.o: $(hdrdir)/ruby/internal/dosish.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_provider.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_provider.o: $(hdrdir)/ruby/internal/error.h +ossl_provider.o: $(hdrdir)/ruby/internal/eval.h +ossl_provider.o: $(hdrdir)/ruby/internal/event.h +ossl_provider.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_provider.o: $(hdrdir)/ruby/internal/gc.h +ossl_provider.o: $(hdrdir)/ruby/internal/glob.h +ossl_provider.o: $(hdrdir)/ruby/internal/globals.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_provider.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_provider.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_provider.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_provider.o: $(hdrdir)/ruby/internal/iterator.h +ossl_provider.o: $(hdrdir)/ruby/internal/memory.h +ossl_provider.o: $(hdrdir)/ruby/internal/method.h +ossl_provider.o: $(hdrdir)/ruby/internal/module.h +ossl_provider.o: $(hdrdir)/ruby/internal/newobj.h +ossl_provider.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_provider.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_provider.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_provider.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_provider.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_provider.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_provider.o: $(hdrdir)/ruby/internal/symbol.h +ossl_provider.o: $(hdrdir)/ruby/internal/value.h +ossl_provider.o: $(hdrdir)/ruby/internal/value_type.h +ossl_provider.o: $(hdrdir)/ruby/internal/variable.h +ossl_provider.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_provider.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_provider.o: $(hdrdir)/ruby/io.h +ossl_provider.o: $(hdrdir)/ruby/missing.h +ossl_provider.o: $(hdrdir)/ruby/onigmo.h +ossl_provider.o: $(hdrdir)/ruby/oniguruma.h +ossl_provider.o: $(hdrdir)/ruby/ractor.h +ossl_provider.o: $(hdrdir)/ruby/ruby.h +ossl_provider.o: $(hdrdir)/ruby/st.h +ossl_provider.o: $(hdrdir)/ruby/subst.h +ossl_provider.o: $(hdrdir)/ruby/thread.h +ossl_provider.o: openssl_missing.h +ossl_provider.o: ossl.h +ossl_provider.o: ossl_asn1.h +ossl_provider.o: ossl_bio.h +ossl_provider.o: ossl_bn.h +ossl_provider.o: ossl_cipher.h +ossl_provider.o: ossl_config.h +ossl_provider.o: ossl_digest.h +ossl_provider.o: ossl_engine.h +ossl_provider.o: ossl_hmac.h +ossl_provider.o: ossl_kdf.h +ossl_provider.o: ossl_ns_spki.h +ossl_provider.o: ossl_ocsp.h +ossl_provider.o: ossl_pkcs12.h +ossl_provider.o: ossl_pkcs7.h +ossl_provider.o: ossl_pkey.h +ossl_provider.o: ossl_provider.c +ossl_provider.o: ossl_provider.h +ossl_provider.o: ossl_rand.h +ossl_provider.o: ossl_ssl.h +ossl_provider.o: ossl_ts.h +ossl_provider.o: ossl_x509.h +ossl_rand.o: $(RUBY_EXTCONF_H) +ossl_rand.o: $(arch_hdrdir)/ruby/config.h +ossl_rand.o: $(hdrdir)/ruby.h +ossl_rand.o: $(hdrdir)/ruby/assert.h +ossl_rand.o: $(hdrdir)/ruby/backward.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_rand.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_rand.o: $(hdrdir)/ruby/defines.h +ossl_rand.o: $(hdrdir)/ruby/encoding.h +ossl_rand.o: $(hdrdir)/ruby/intern.h +ossl_rand.o: $(hdrdir)/ruby/internal/abi.h +ossl_rand.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_rand.o: $(hdrdir)/ruby/internal/assume.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_rand.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_rand.o: $(hdrdir)/ruby/internal/cast.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_rand.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_rand.o: $(hdrdir)/ruby/internal/config.h +ossl_rand.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_rand.o: $(hdrdir)/ruby/internal/core.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_rand.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_rand.o: $(hdrdir)/ruby/internal/ctype.h +ossl_rand.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_rand.o: $(hdrdir)/ruby/internal/dosish.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_rand.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_rand.o: $(hdrdir)/ruby/internal/error.h +ossl_rand.o: $(hdrdir)/ruby/internal/eval.h +ossl_rand.o: $(hdrdir)/ruby/internal/event.h +ossl_rand.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_rand.o: $(hdrdir)/ruby/internal/gc.h +ossl_rand.o: $(hdrdir)/ruby/internal/glob.h +ossl_rand.o: $(hdrdir)/ruby/internal/globals.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_rand.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_rand.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_rand.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_rand.o: $(hdrdir)/ruby/internal/iterator.h +ossl_rand.o: $(hdrdir)/ruby/internal/memory.h +ossl_rand.o: $(hdrdir)/ruby/internal/method.h +ossl_rand.o: $(hdrdir)/ruby/internal/module.h +ossl_rand.o: $(hdrdir)/ruby/internal/newobj.h +ossl_rand.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_rand.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_rand.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_rand.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_rand.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_rand.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_rand.o: $(hdrdir)/ruby/internal/symbol.h +ossl_rand.o: $(hdrdir)/ruby/internal/value.h +ossl_rand.o: $(hdrdir)/ruby/internal/value_type.h +ossl_rand.o: $(hdrdir)/ruby/internal/variable.h +ossl_rand.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_rand.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_rand.o: $(hdrdir)/ruby/io.h +ossl_rand.o: $(hdrdir)/ruby/missing.h +ossl_rand.o: $(hdrdir)/ruby/onigmo.h +ossl_rand.o: $(hdrdir)/ruby/oniguruma.h +ossl_rand.o: $(hdrdir)/ruby/ractor.h +ossl_rand.o: $(hdrdir)/ruby/ruby.h +ossl_rand.o: $(hdrdir)/ruby/st.h +ossl_rand.o: $(hdrdir)/ruby/subst.h +ossl_rand.o: $(hdrdir)/ruby/thread.h +ossl_rand.o: openssl_missing.h +ossl_rand.o: ossl.h +ossl_rand.o: ossl_asn1.h +ossl_rand.o: ossl_bio.h +ossl_rand.o: ossl_bn.h +ossl_rand.o: ossl_cipher.h +ossl_rand.o: ossl_config.h +ossl_rand.o: ossl_digest.h +ossl_rand.o: ossl_engine.h +ossl_rand.o: ossl_hmac.h +ossl_rand.o: ossl_kdf.h +ossl_rand.o: ossl_ns_spki.h +ossl_rand.o: ossl_ocsp.h +ossl_rand.o: ossl_pkcs12.h +ossl_rand.o: ossl_pkcs7.h +ossl_rand.o: ossl_pkey.h +ossl_rand.o: ossl_provider.h +ossl_rand.o: ossl_rand.c +ossl_rand.o: ossl_rand.h +ossl_rand.o: ossl_ssl.h +ossl_rand.o: ossl_ts.h +ossl_rand.o: ossl_x509.h +ossl_ssl.o: $(RUBY_EXTCONF_H) +ossl_ssl.o: $(arch_hdrdir)/ruby/config.h +ossl_ssl.o: $(hdrdir)/ruby.h +ossl_ssl.o: $(hdrdir)/ruby/assert.h +ossl_ssl.o: $(hdrdir)/ruby/backward.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_ssl.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_ssl.o: $(hdrdir)/ruby/defines.h +ossl_ssl.o: $(hdrdir)/ruby/encoding.h +ossl_ssl.o: $(hdrdir)/ruby/intern.h +ossl_ssl.o: $(hdrdir)/ruby/internal/abi.h +ossl_ssl.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_ssl.o: $(hdrdir)/ruby/internal/assume.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_ssl.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_ssl.o: $(hdrdir)/ruby/internal/cast.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_ssl.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_ssl.o: $(hdrdir)/ruby/internal/config.h +ossl_ssl.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_ssl.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_ssl.o: $(hdrdir)/ruby/internal/ctype.h +ossl_ssl.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_ssl.o: $(hdrdir)/ruby/internal/dosish.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_ssl.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_ssl.o: $(hdrdir)/ruby/internal/error.h +ossl_ssl.o: $(hdrdir)/ruby/internal/eval.h +ossl_ssl.o: $(hdrdir)/ruby/internal/event.h +ossl_ssl.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_ssl.o: $(hdrdir)/ruby/internal/gc.h +ossl_ssl.o: $(hdrdir)/ruby/internal/glob.h +ossl_ssl.o: $(hdrdir)/ruby/internal/globals.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_ssl.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_ssl.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_ssl.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_ssl.o: $(hdrdir)/ruby/internal/iterator.h +ossl_ssl.o: $(hdrdir)/ruby/internal/memory.h +ossl_ssl.o: $(hdrdir)/ruby/internal/method.h +ossl_ssl.o: $(hdrdir)/ruby/internal/module.h +ossl_ssl.o: $(hdrdir)/ruby/internal/newobj.h +ossl_ssl.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_ssl.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_ssl.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_ssl.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_ssl.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_ssl.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_ssl.o: $(hdrdir)/ruby/internal/symbol.h +ossl_ssl.o: $(hdrdir)/ruby/internal/value.h +ossl_ssl.o: $(hdrdir)/ruby/internal/value_type.h +ossl_ssl.o: $(hdrdir)/ruby/internal/variable.h +ossl_ssl.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_ssl.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_ssl.o: $(hdrdir)/ruby/io.h +ossl_ssl.o: $(hdrdir)/ruby/missing.h +ossl_ssl.o: $(hdrdir)/ruby/onigmo.h +ossl_ssl.o: $(hdrdir)/ruby/oniguruma.h +ossl_ssl.o: $(hdrdir)/ruby/ractor.h +ossl_ssl.o: $(hdrdir)/ruby/ruby.h +ossl_ssl.o: $(hdrdir)/ruby/st.h +ossl_ssl.o: $(hdrdir)/ruby/subst.h +ossl_ssl.o: $(hdrdir)/ruby/thread.h +ossl_ssl.o: openssl_missing.h +ossl_ssl.o: ossl.h +ossl_ssl.o: ossl_asn1.h +ossl_ssl.o: ossl_bio.h +ossl_ssl.o: ossl_bn.h +ossl_ssl.o: ossl_cipher.h +ossl_ssl.o: ossl_config.h +ossl_ssl.o: ossl_digest.h +ossl_ssl.o: ossl_engine.h +ossl_ssl.o: ossl_hmac.h +ossl_ssl.o: ossl_kdf.h +ossl_ssl.o: ossl_ns_spki.h +ossl_ssl.o: ossl_ocsp.h +ossl_ssl.o: ossl_pkcs12.h +ossl_ssl.o: ossl_pkcs7.h +ossl_ssl.o: ossl_pkey.h +ossl_ssl.o: ossl_provider.h +ossl_ssl.o: ossl_rand.h +ossl_ssl.o: ossl_ssl.c +ossl_ssl.o: ossl_ssl.h +ossl_ssl.o: ossl_ts.h +ossl_ssl.o: ossl_x509.h +ossl_ssl_session.o: $(RUBY_EXTCONF_H) +ossl_ssl_session.o: $(arch_hdrdir)/ruby/config.h +ossl_ssl_session.o: $(hdrdir)/ruby.h +ossl_ssl_session.o: $(hdrdir)/ruby/assert.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_ssl_session.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_ssl_session.o: $(hdrdir)/ruby/defines.h +ossl_ssl_session.o: $(hdrdir)/ruby/encoding.h +ossl_ssl_session.o: $(hdrdir)/ruby/intern.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/abi.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/assume.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/cast.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/config.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/ctype.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/dosish.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/error.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/eval.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/event.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/gc.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/glob.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/globals.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/iterator.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/memory.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/method.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/module.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/newobj.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/symbol.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/value.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/value_type.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/variable.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_ssl_session.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_ssl_session.o: $(hdrdir)/ruby/io.h +ossl_ssl_session.o: $(hdrdir)/ruby/missing.h +ossl_ssl_session.o: $(hdrdir)/ruby/onigmo.h +ossl_ssl_session.o: $(hdrdir)/ruby/oniguruma.h +ossl_ssl_session.o: $(hdrdir)/ruby/ractor.h +ossl_ssl_session.o: $(hdrdir)/ruby/ruby.h +ossl_ssl_session.o: $(hdrdir)/ruby/st.h +ossl_ssl_session.o: $(hdrdir)/ruby/subst.h +ossl_ssl_session.o: $(hdrdir)/ruby/thread.h +ossl_ssl_session.o: openssl_missing.h +ossl_ssl_session.o: ossl.h +ossl_ssl_session.o: ossl_asn1.h +ossl_ssl_session.o: ossl_bio.h +ossl_ssl_session.o: ossl_bn.h +ossl_ssl_session.o: ossl_cipher.h +ossl_ssl_session.o: ossl_config.h +ossl_ssl_session.o: ossl_digest.h +ossl_ssl_session.o: ossl_engine.h +ossl_ssl_session.o: ossl_hmac.h +ossl_ssl_session.o: ossl_kdf.h +ossl_ssl_session.o: ossl_ns_spki.h +ossl_ssl_session.o: ossl_ocsp.h +ossl_ssl_session.o: ossl_pkcs12.h +ossl_ssl_session.o: ossl_pkcs7.h +ossl_ssl_session.o: ossl_pkey.h +ossl_ssl_session.o: ossl_provider.h +ossl_ssl_session.o: ossl_rand.h +ossl_ssl_session.o: ossl_ssl.h +ossl_ssl_session.o: ossl_ssl_session.c +ossl_ssl_session.o: ossl_ts.h +ossl_ssl_session.o: ossl_x509.h +ossl_ts.o: $(RUBY_EXTCONF_H) +ossl_ts.o: $(arch_hdrdir)/ruby/config.h +ossl_ts.o: $(hdrdir)/ruby.h +ossl_ts.o: $(hdrdir)/ruby/assert.h +ossl_ts.o: $(hdrdir)/ruby/backward.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_ts.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_ts.o: $(hdrdir)/ruby/defines.h +ossl_ts.o: $(hdrdir)/ruby/encoding.h +ossl_ts.o: $(hdrdir)/ruby/intern.h +ossl_ts.o: $(hdrdir)/ruby/internal/abi.h +ossl_ts.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_ts.o: $(hdrdir)/ruby/internal/assume.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_ts.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_ts.o: $(hdrdir)/ruby/internal/cast.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_ts.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_ts.o: $(hdrdir)/ruby/internal/config.h +ossl_ts.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_ts.o: $(hdrdir)/ruby/internal/core.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_ts.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_ts.o: $(hdrdir)/ruby/internal/ctype.h +ossl_ts.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_ts.o: $(hdrdir)/ruby/internal/dosish.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_ts.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_ts.o: $(hdrdir)/ruby/internal/error.h +ossl_ts.o: $(hdrdir)/ruby/internal/eval.h +ossl_ts.o: $(hdrdir)/ruby/internal/event.h +ossl_ts.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_ts.o: $(hdrdir)/ruby/internal/gc.h +ossl_ts.o: $(hdrdir)/ruby/internal/glob.h +ossl_ts.o: $(hdrdir)/ruby/internal/globals.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_ts.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_ts.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_ts.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_ts.o: $(hdrdir)/ruby/internal/iterator.h +ossl_ts.o: $(hdrdir)/ruby/internal/memory.h +ossl_ts.o: $(hdrdir)/ruby/internal/method.h +ossl_ts.o: $(hdrdir)/ruby/internal/module.h +ossl_ts.o: $(hdrdir)/ruby/internal/newobj.h +ossl_ts.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_ts.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_ts.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_ts.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_ts.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_ts.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_ts.o: $(hdrdir)/ruby/internal/symbol.h +ossl_ts.o: $(hdrdir)/ruby/internal/value.h +ossl_ts.o: $(hdrdir)/ruby/internal/value_type.h +ossl_ts.o: $(hdrdir)/ruby/internal/variable.h +ossl_ts.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_ts.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_ts.o: $(hdrdir)/ruby/io.h +ossl_ts.o: $(hdrdir)/ruby/missing.h +ossl_ts.o: $(hdrdir)/ruby/onigmo.h +ossl_ts.o: $(hdrdir)/ruby/oniguruma.h +ossl_ts.o: $(hdrdir)/ruby/ractor.h +ossl_ts.o: $(hdrdir)/ruby/ruby.h +ossl_ts.o: $(hdrdir)/ruby/st.h +ossl_ts.o: $(hdrdir)/ruby/subst.h +ossl_ts.o: $(hdrdir)/ruby/thread.h +ossl_ts.o: openssl_missing.h +ossl_ts.o: ossl.h +ossl_ts.o: ossl_asn1.h +ossl_ts.o: ossl_bio.h +ossl_ts.o: ossl_bn.h +ossl_ts.o: ossl_cipher.h +ossl_ts.o: ossl_config.h +ossl_ts.o: ossl_digest.h +ossl_ts.o: ossl_engine.h +ossl_ts.o: ossl_hmac.h +ossl_ts.o: ossl_kdf.h +ossl_ts.o: ossl_ns_spki.h +ossl_ts.o: ossl_ocsp.h +ossl_ts.o: ossl_pkcs12.h +ossl_ts.o: ossl_pkcs7.h +ossl_ts.o: ossl_pkey.h +ossl_ts.o: ossl_provider.h +ossl_ts.o: ossl_rand.h +ossl_ts.o: ossl_ssl.h +ossl_ts.o: ossl_ts.c +ossl_ts.o: ossl_ts.h +ossl_ts.o: ossl_x509.h +ossl_x509.o: $(RUBY_EXTCONF_H) +ossl_x509.o: $(arch_hdrdir)/ruby/config.h +ossl_x509.o: $(hdrdir)/ruby.h +ossl_x509.o: $(hdrdir)/ruby/assert.h +ossl_x509.o: $(hdrdir)/ruby/backward.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509.o: $(hdrdir)/ruby/defines.h +ossl_x509.o: $(hdrdir)/ruby/encoding.h +ossl_x509.o: $(hdrdir)/ruby/intern.h +ossl_x509.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509.o: $(hdrdir)/ruby/internal/config.h +ossl_x509.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509.o: $(hdrdir)/ruby/internal/core.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509.o: $(hdrdir)/ruby/internal/error.h +ossl_x509.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509.o: $(hdrdir)/ruby/internal/event.h +ossl_x509.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509.o: $(hdrdir)/ruby/internal/method.h +ossl_x509.o: $(hdrdir)/ruby/internal/module.h +ossl_x509.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509.o: $(hdrdir)/ruby/internal/value.h +ossl_x509.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509.o: $(hdrdir)/ruby/io.h +ossl_x509.o: $(hdrdir)/ruby/missing.h +ossl_x509.o: $(hdrdir)/ruby/onigmo.h +ossl_x509.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509.o: $(hdrdir)/ruby/ractor.h +ossl_x509.o: $(hdrdir)/ruby/ruby.h +ossl_x509.o: $(hdrdir)/ruby/st.h +ossl_x509.o: $(hdrdir)/ruby/subst.h +ossl_x509.o: $(hdrdir)/ruby/thread.h +ossl_x509.o: openssl_missing.h +ossl_x509.o: ossl.h +ossl_x509.o: ossl_asn1.h +ossl_x509.o: ossl_bio.h +ossl_x509.o: ossl_bn.h +ossl_x509.o: ossl_cipher.h +ossl_x509.o: ossl_config.h +ossl_x509.o: ossl_digest.h +ossl_x509.o: ossl_engine.h +ossl_x509.o: ossl_hmac.h +ossl_x509.o: ossl_kdf.h +ossl_x509.o: ossl_ns_spki.h +ossl_x509.o: ossl_ocsp.h +ossl_x509.o: ossl_pkcs12.h +ossl_x509.o: ossl_pkcs7.h +ossl_x509.o: ossl_pkey.h +ossl_x509.o: ossl_provider.h +ossl_x509.o: ossl_rand.h +ossl_x509.o: ossl_ssl.h +ossl_x509.o: ossl_ts.h +ossl_x509.o: ossl_x509.c +ossl_x509.o: ossl_x509.h +ossl_x509attr.o: $(RUBY_EXTCONF_H) +ossl_x509attr.o: $(arch_hdrdir)/ruby/config.h +ossl_x509attr.o: $(hdrdir)/ruby.h +ossl_x509attr.o: $(hdrdir)/ruby/assert.h +ossl_x509attr.o: $(hdrdir)/ruby/backward.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509attr.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509attr.o: $(hdrdir)/ruby/defines.h +ossl_x509attr.o: $(hdrdir)/ruby/encoding.h +ossl_x509attr.o: $(hdrdir)/ruby/intern.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/config.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/error.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/event.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/method.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/module.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/value.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509attr.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509attr.o: $(hdrdir)/ruby/io.h +ossl_x509attr.o: $(hdrdir)/ruby/missing.h +ossl_x509attr.o: $(hdrdir)/ruby/onigmo.h +ossl_x509attr.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509attr.o: $(hdrdir)/ruby/ractor.h +ossl_x509attr.o: $(hdrdir)/ruby/ruby.h +ossl_x509attr.o: $(hdrdir)/ruby/st.h +ossl_x509attr.o: $(hdrdir)/ruby/subst.h +ossl_x509attr.o: $(hdrdir)/ruby/thread.h +ossl_x509attr.o: openssl_missing.h +ossl_x509attr.o: ossl.h +ossl_x509attr.o: ossl_asn1.h +ossl_x509attr.o: ossl_bio.h +ossl_x509attr.o: ossl_bn.h +ossl_x509attr.o: ossl_cipher.h +ossl_x509attr.o: ossl_config.h +ossl_x509attr.o: ossl_digest.h +ossl_x509attr.o: ossl_engine.h +ossl_x509attr.o: ossl_hmac.h +ossl_x509attr.o: ossl_kdf.h +ossl_x509attr.o: ossl_ns_spki.h +ossl_x509attr.o: ossl_ocsp.h +ossl_x509attr.o: ossl_pkcs12.h +ossl_x509attr.o: ossl_pkcs7.h +ossl_x509attr.o: ossl_pkey.h +ossl_x509attr.o: ossl_provider.h +ossl_x509attr.o: ossl_rand.h +ossl_x509attr.o: ossl_ssl.h +ossl_x509attr.o: ossl_ts.h +ossl_x509attr.o: ossl_x509.h +ossl_x509attr.o: ossl_x509attr.c +ossl_x509cert.o: $(RUBY_EXTCONF_H) +ossl_x509cert.o: $(arch_hdrdir)/ruby/config.h +ossl_x509cert.o: $(hdrdir)/ruby.h +ossl_x509cert.o: $(hdrdir)/ruby/assert.h +ossl_x509cert.o: $(hdrdir)/ruby/backward.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509cert.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509cert.o: $(hdrdir)/ruby/defines.h +ossl_x509cert.o: $(hdrdir)/ruby/encoding.h +ossl_x509cert.o: $(hdrdir)/ruby/intern.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/config.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/error.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/event.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/method.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/module.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/value.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509cert.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509cert.o: $(hdrdir)/ruby/io.h +ossl_x509cert.o: $(hdrdir)/ruby/missing.h +ossl_x509cert.o: $(hdrdir)/ruby/onigmo.h +ossl_x509cert.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509cert.o: $(hdrdir)/ruby/ractor.h +ossl_x509cert.o: $(hdrdir)/ruby/ruby.h +ossl_x509cert.o: $(hdrdir)/ruby/st.h +ossl_x509cert.o: $(hdrdir)/ruby/subst.h +ossl_x509cert.o: $(hdrdir)/ruby/thread.h +ossl_x509cert.o: openssl_missing.h +ossl_x509cert.o: ossl.h +ossl_x509cert.o: ossl_asn1.h +ossl_x509cert.o: ossl_bio.h +ossl_x509cert.o: ossl_bn.h +ossl_x509cert.o: ossl_cipher.h +ossl_x509cert.o: ossl_config.h +ossl_x509cert.o: ossl_digest.h +ossl_x509cert.o: ossl_engine.h +ossl_x509cert.o: ossl_hmac.h +ossl_x509cert.o: ossl_kdf.h +ossl_x509cert.o: ossl_ns_spki.h +ossl_x509cert.o: ossl_ocsp.h +ossl_x509cert.o: ossl_pkcs12.h +ossl_x509cert.o: ossl_pkcs7.h +ossl_x509cert.o: ossl_pkey.h +ossl_x509cert.o: ossl_provider.h +ossl_x509cert.o: ossl_rand.h +ossl_x509cert.o: ossl_ssl.h +ossl_x509cert.o: ossl_ts.h +ossl_x509cert.o: ossl_x509.h +ossl_x509cert.o: ossl_x509cert.c +ossl_x509crl.o: $(RUBY_EXTCONF_H) +ossl_x509crl.o: $(arch_hdrdir)/ruby/config.h +ossl_x509crl.o: $(hdrdir)/ruby.h +ossl_x509crl.o: $(hdrdir)/ruby/assert.h +ossl_x509crl.o: $(hdrdir)/ruby/backward.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509crl.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509crl.o: $(hdrdir)/ruby/defines.h +ossl_x509crl.o: $(hdrdir)/ruby/encoding.h +ossl_x509crl.o: $(hdrdir)/ruby/intern.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/config.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/error.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/event.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/method.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/module.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/value.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509crl.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509crl.o: $(hdrdir)/ruby/io.h +ossl_x509crl.o: $(hdrdir)/ruby/missing.h +ossl_x509crl.o: $(hdrdir)/ruby/onigmo.h +ossl_x509crl.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509crl.o: $(hdrdir)/ruby/ractor.h +ossl_x509crl.o: $(hdrdir)/ruby/ruby.h +ossl_x509crl.o: $(hdrdir)/ruby/st.h +ossl_x509crl.o: $(hdrdir)/ruby/subst.h +ossl_x509crl.o: $(hdrdir)/ruby/thread.h +ossl_x509crl.o: openssl_missing.h +ossl_x509crl.o: ossl.h +ossl_x509crl.o: ossl_asn1.h +ossl_x509crl.o: ossl_bio.h +ossl_x509crl.o: ossl_bn.h +ossl_x509crl.o: ossl_cipher.h +ossl_x509crl.o: ossl_config.h +ossl_x509crl.o: ossl_digest.h +ossl_x509crl.o: ossl_engine.h +ossl_x509crl.o: ossl_hmac.h +ossl_x509crl.o: ossl_kdf.h +ossl_x509crl.o: ossl_ns_spki.h +ossl_x509crl.o: ossl_ocsp.h +ossl_x509crl.o: ossl_pkcs12.h +ossl_x509crl.o: ossl_pkcs7.h +ossl_x509crl.o: ossl_pkey.h +ossl_x509crl.o: ossl_provider.h +ossl_x509crl.o: ossl_rand.h +ossl_x509crl.o: ossl_ssl.h +ossl_x509crl.o: ossl_ts.h +ossl_x509crl.o: ossl_x509.h +ossl_x509crl.o: ossl_x509crl.c +ossl_x509ext.o: $(RUBY_EXTCONF_H) +ossl_x509ext.o: $(arch_hdrdir)/ruby/config.h +ossl_x509ext.o: $(hdrdir)/ruby.h +ossl_x509ext.o: $(hdrdir)/ruby/assert.h +ossl_x509ext.o: $(hdrdir)/ruby/backward.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509ext.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509ext.o: $(hdrdir)/ruby/defines.h +ossl_x509ext.o: $(hdrdir)/ruby/encoding.h +ossl_x509ext.o: $(hdrdir)/ruby/intern.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/config.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/error.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/event.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/method.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/module.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/value.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509ext.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509ext.o: $(hdrdir)/ruby/io.h +ossl_x509ext.o: $(hdrdir)/ruby/missing.h +ossl_x509ext.o: $(hdrdir)/ruby/onigmo.h +ossl_x509ext.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509ext.o: $(hdrdir)/ruby/ractor.h +ossl_x509ext.o: $(hdrdir)/ruby/ruby.h +ossl_x509ext.o: $(hdrdir)/ruby/st.h +ossl_x509ext.o: $(hdrdir)/ruby/subst.h +ossl_x509ext.o: $(hdrdir)/ruby/thread.h +ossl_x509ext.o: openssl_missing.h +ossl_x509ext.o: ossl.h +ossl_x509ext.o: ossl_asn1.h +ossl_x509ext.o: ossl_bio.h +ossl_x509ext.o: ossl_bn.h +ossl_x509ext.o: ossl_cipher.h +ossl_x509ext.o: ossl_config.h +ossl_x509ext.o: ossl_digest.h +ossl_x509ext.o: ossl_engine.h +ossl_x509ext.o: ossl_hmac.h +ossl_x509ext.o: ossl_kdf.h +ossl_x509ext.o: ossl_ns_spki.h +ossl_x509ext.o: ossl_ocsp.h +ossl_x509ext.o: ossl_pkcs12.h +ossl_x509ext.o: ossl_pkcs7.h +ossl_x509ext.o: ossl_pkey.h +ossl_x509ext.o: ossl_provider.h +ossl_x509ext.o: ossl_rand.h +ossl_x509ext.o: ossl_ssl.h +ossl_x509ext.o: ossl_ts.h +ossl_x509ext.o: ossl_x509.h +ossl_x509ext.o: ossl_x509ext.c +ossl_x509name.o: $(RUBY_EXTCONF_H) +ossl_x509name.o: $(arch_hdrdir)/ruby/config.h +ossl_x509name.o: $(hdrdir)/ruby.h +ossl_x509name.o: $(hdrdir)/ruby/assert.h +ossl_x509name.o: $(hdrdir)/ruby/backward.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509name.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509name.o: $(hdrdir)/ruby/defines.h +ossl_x509name.o: $(hdrdir)/ruby/encoding.h +ossl_x509name.o: $(hdrdir)/ruby/intern.h +ossl_x509name.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509name.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509name.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509name.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509name.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509name.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509name.o: $(hdrdir)/ruby/internal/config.h +ossl_x509name.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509name.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509name.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509name.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509name.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509name.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509name.o: $(hdrdir)/ruby/internal/error.h +ossl_x509name.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509name.o: $(hdrdir)/ruby/internal/event.h +ossl_x509name.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509name.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509name.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509name.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509name.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509name.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509name.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509name.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509name.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509name.o: $(hdrdir)/ruby/internal/method.h +ossl_x509name.o: $(hdrdir)/ruby/internal/module.h +ossl_x509name.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509name.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509name.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509name.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509name.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509name.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509name.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509name.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509name.o: $(hdrdir)/ruby/internal/value.h +ossl_x509name.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509name.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509name.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509name.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509name.o: $(hdrdir)/ruby/io.h +ossl_x509name.o: $(hdrdir)/ruby/missing.h +ossl_x509name.o: $(hdrdir)/ruby/onigmo.h +ossl_x509name.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509name.o: $(hdrdir)/ruby/ractor.h +ossl_x509name.o: $(hdrdir)/ruby/ruby.h +ossl_x509name.o: $(hdrdir)/ruby/st.h +ossl_x509name.o: $(hdrdir)/ruby/subst.h +ossl_x509name.o: $(hdrdir)/ruby/thread.h +ossl_x509name.o: openssl_missing.h +ossl_x509name.o: ossl.h +ossl_x509name.o: ossl_asn1.h +ossl_x509name.o: ossl_bio.h +ossl_x509name.o: ossl_bn.h +ossl_x509name.o: ossl_cipher.h +ossl_x509name.o: ossl_config.h +ossl_x509name.o: ossl_digest.h +ossl_x509name.o: ossl_engine.h +ossl_x509name.o: ossl_hmac.h +ossl_x509name.o: ossl_kdf.h +ossl_x509name.o: ossl_ns_spki.h +ossl_x509name.o: ossl_ocsp.h +ossl_x509name.o: ossl_pkcs12.h +ossl_x509name.o: ossl_pkcs7.h +ossl_x509name.o: ossl_pkey.h +ossl_x509name.o: ossl_provider.h +ossl_x509name.o: ossl_rand.h +ossl_x509name.o: ossl_ssl.h +ossl_x509name.o: ossl_ts.h +ossl_x509name.o: ossl_x509.h +ossl_x509name.o: ossl_x509name.c +ossl_x509req.o: $(RUBY_EXTCONF_H) +ossl_x509req.o: $(arch_hdrdir)/ruby/config.h +ossl_x509req.o: $(hdrdir)/ruby.h +ossl_x509req.o: $(hdrdir)/ruby/assert.h +ossl_x509req.o: $(hdrdir)/ruby/backward.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509req.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509req.o: $(hdrdir)/ruby/defines.h +ossl_x509req.o: $(hdrdir)/ruby/encoding.h +ossl_x509req.o: $(hdrdir)/ruby/intern.h +ossl_x509req.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509req.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509req.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509req.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509req.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509req.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509req.o: $(hdrdir)/ruby/internal/config.h +ossl_x509req.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509req.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509req.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509req.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509req.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509req.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509req.o: $(hdrdir)/ruby/internal/error.h +ossl_x509req.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509req.o: $(hdrdir)/ruby/internal/event.h +ossl_x509req.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509req.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509req.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509req.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509req.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509req.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509req.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509req.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509req.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509req.o: $(hdrdir)/ruby/internal/method.h +ossl_x509req.o: $(hdrdir)/ruby/internal/module.h +ossl_x509req.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509req.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509req.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509req.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509req.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509req.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509req.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509req.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509req.o: $(hdrdir)/ruby/internal/value.h +ossl_x509req.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509req.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509req.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509req.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509req.o: $(hdrdir)/ruby/io.h +ossl_x509req.o: $(hdrdir)/ruby/missing.h +ossl_x509req.o: $(hdrdir)/ruby/onigmo.h +ossl_x509req.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509req.o: $(hdrdir)/ruby/ractor.h +ossl_x509req.o: $(hdrdir)/ruby/ruby.h +ossl_x509req.o: $(hdrdir)/ruby/st.h +ossl_x509req.o: $(hdrdir)/ruby/subst.h +ossl_x509req.o: $(hdrdir)/ruby/thread.h +ossl_x509req.o: openssl_missing.h +ossl_x509req.o: ossl.h +ossl_x509req.o: ossl_asn1.h +ossl_x509req.o: ossl_bio.h +ossl_x509req.o: ossl_bn.h +ossl_x509req.o: ossl_cipher.h +ossl_x509req.o: ossl_config.h +ossl_x509req.o: ossl_digest.h +ossl_x509req.o: ossl_engine.h +ossl_x509req.o: ossl_hmac.h +ossl_x509req.o: ossl_kdf.h +ossl_x509req.o: ossl_ns_spki.h +ossl_x509req.o: ossl_ocsp.h +ossl_x509req.o: ossl_pkcs12.h +ossl_x509req.o: ossl_pkcs7.h +ossl_x509req.o: ossl_pkey.h +ossl_x509req.o: ossl_provider.h +ossl_x509req.o: ossl_rand.h +ossl_x509req.o: ossl_ssl.h +ossl_x509req.o: ossl_ts.h +ossl_x509req.o: ossl_x509.h +ossl_x509req.o: ossl_x509req.c +ossl_x509revoked.o: $(RUBY_EXTCONF_H) +ossl_x509revoked.o: $(arch_hdrdir)/ruby/config.h +ossl_x509revoked.o: $(hdrdir)/ruby.h +ossl_x509revoked.o: $(hdrdir)/ruby/assert.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509revoked.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509revoked.o: $(hdrdir)/ruby/defines.h +ossl_x509revoked.o: $(hdrdir)/ruby/encoding.h +ossl_x509revoked.o: $(hdrdir)/ruby/intern.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/config.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/error.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/event.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/method.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/module.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/value.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509revoked.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509revoked.o: $(hdrdir)/ruby/io.h +ossl_x509revoked.o: $(hdrdir)/ruby/missing.h +ossl_x509revoked.o: $(hdrdir)/ruby/onigmo.h +ossl_x509revoked.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509revoked.o: $(hdrdir)/ruby/ractor.h +ossl_x509revoked.o: $(hdrdir)/ruby/ruby.h +ossl_x509revoked.o: $(hdrdir)/ruby/st.h +ossl_x509revoked.o: $(hdrdir)/ruby/subst.h +ossl_x509revoked.o: $(hdrdir)/ruby/thread.h +ossl_x509revoked.o: openssl_missing.h +ossl_x509revoked.o: ossl.h +ossl_x509revoked.o: ossl_asn1.h +ossl_x509revoked.o: ossl_bio.h +ossl_x509revoked.o: ossl_bn.h +ossl_x509revoked.o: ossl_cipher.h +ossl_x509revoked.o: ossl_config.h +ossl_x509revoked.o: ossl_digest.h +ossl_x509revoked.o: ossl_engine.h +ossl_x509revoked.o: ossl_hmac.h +ossl_x509revoked.o: ossl_kdf.h +ossl_x509revoked.o: ossl_ns_spki.h +ossl_x509revoked.o: ossl_ocsp.h +ossl_x509revoked.o: ossl_pkcs12.h +ossl_x509revoked.o: ossl_pkcs7.h +ossl_x509revoked.o: ossl_pkey.h +ossl_x509revoked.o: ossl_provider.h +ossl_x509revoked.o: ossl_rand.h +ossl_x509revoked.o: ossl_ssl.h +ossl_x509revoked.o: ossl_ts.h +ossl_x509revoked.o: ossl_x509.h +ossl_x509revoked.o: ossl_x509revoked.c +ossl_x509store.o: $(RUBY_EXTCONF_H) +ossl_x509store.o: $(arch_hdrdir)/ruby/config.h +ossl_x509store.o: $(hdrdir)/ruby.h +ossl_x509store.o: $(hdrdir)/ruby/assert.h +ossl_x509store.o: $(hdrdir)/ruby/backward.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/assume.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/attributes.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/bool.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/inttypes.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/limits.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/long_long.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/stdalign.h +ossl_x509store.o: $(hdrdir)/ruby/backward/2/stdarg.h +ossl_x509store.o: $(hdrdir)/ruby/defines.h +ossl_x509store.o: $(hdrdir)/ruby/encoding.h +ossl_x509store.o: $(hdrdir)/ruby/intern.h +ossl_x509store.o: $(hdrdir)/ruby/internal/abi.h +ossl_x509store.o: $(hdrdir)/ruby/internal/anyargs.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/char.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/double.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/int.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/long.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/short.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +ossl_x509store.o: $(hdrdir)/ruby/internal/assume.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/artificial.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/cold.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/const.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/constexpr.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/deprecated.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/error.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/forceinline.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/format.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noalias.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noexcept.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noinline.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/nonnull.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noreturn.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/pure.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/restrict.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/warning.h +ossl_x509store.o: $(hdrdir)/ruby/internal/attr/weakref.h +ossl_x509store.o: $(hdrdir)/ruby/internal/cast.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_is.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +ossl_x509store.o: $(hdrdir)/ruby/internal/compiler_since.h +ossl_x509store.o: $(hdrdir)/ruby/internal/config.h +ossl_x509store.o: $(hdrdir)/ruby/internal/constant_p.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rarray.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rbasic.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rbignum.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rclass.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rdata.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rfile.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rhash.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/robject.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rregexp.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rstring.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rstruct.h +ossl_x509store.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +ossl_x509store.o: $(hdrdir)/ruby/internal/ctype.h +ossl_x509store.o: $(hdrdir)/ruby/internal/dllexport.h +ossl_x509store.o: $(hdrdir)/ruby/internal/dosish.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/coderange.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/ctype.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/encoding.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/pathname.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/re.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/string.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/symbol.h +ossl_x509store.o: $(hdrdir)/ruby/internal/encoding/transcode.h +ossl_x509store.o: $(hdrdir)/ruby/internal/error.h +ossl_x509store.o: $(hdrdir)/ruby/internal/eval.h +ossl_x509store.o: $(hdrdir)/ruby/internal/event.h +ossl_x509store.o: $(hdrdir)/ruby/internal/fl_type.h +ossl_x509store.o: $(hdrdir)/ruby/internal/gc.h +ossl_x509store.o: $(hdrdir)/ruby/internal/glob.h +ossl_x509store.o: $(hdrdir)/ruby/internal/globals.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/attribute.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/builtin.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/c_attribute.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/extension.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/feature.h +ossl_x509store.o: $(hdrdir)/ruby/internal/has/warning.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/array.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/bignum.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/class.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/compar.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/complex.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/cont.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/dir.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/enum.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/enumerator.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/error.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/eval.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/file.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/hash.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/io.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/load.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/marshal.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/numeric.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/object.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/parse.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/proc.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/process.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/random.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/range.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/rational.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/re.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/ruby.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/select.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/set.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/signal.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/sprintf.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/string.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/struct.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/thread.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/time.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/variable.h +ossl_x509store.o: $(hdrdir)/ruby/internal/intern/vm.h +ossl_x509store.o: $(hdrdir)/ruby/internal/interpreter.h +ossl_x509store.o: $(hdrdir)/ruby/internal/iterator.h +ossl_x509store.o: $(hdrdir)/ruby/internal/memory.h +ossl_x509store.o: $(hdrdir)/ruby/internal/method.h +ossl_x509store.o: $(hdrdir)/ruby/internal/module.h +ossl_x509store.o: $(hdrdir)/ruby/internal/newobj.h +ossl_x509store.o: $(hdrdir)/ruby/internal/scan_args.h +ossl_x509store.o: $(hdrdir)/ruby/internal/special_consts.h +ossl_x509store.o: $(hdrdir)/ruby/internal/static_assert.h +ossl_x509store.o: $(hdrdir)/ruby/internal/stdalign.h +ossl_x509store.o: $(hdrdir)/ruby/internal/stdbool.h +ossl_x509store.o: $(hdrdir)/ruby/internal/stdckdint.h +ossl_x509store.o: $(hdrdir)/ruby/internal/symbol.h +ossl_x509store.o: $(hdrdir)/ruby/internal/value.h +ossl_x509store.o: $(hdrdir)/ruby/internal/value_type.h +ossl_x509store.o: $(hdrdir)/ruby/internal/variable.h +ossl_x509store.o: $(hdrdir)/ruby/internal/warning_push.h +ossl_x509store.o: $(hdrdir)/ruby/internal/xmalloc.h +ossl_x509store.o: $(hdrdir)/ruby/io.h +ossl_x509store.o: $(hdrdir)/ruby/missing.h +ossl_x509store.o: $(hdrdir)/ruby/onigmo.h +ossl_x509store.o: $(hdrdir)/ruby/oniguruma.h +ossl_x509store.o: $(hdrdir)/ruby/ractor.h +ossl_x509store.o: $(hdrdir)/ruby/ruby.h +ossl_x509store.o: $(hdrdir)/ruby/st.h +ossl_x509store.o: $(hdrdir)/ruby/subst.h +ossl_x509store.o: $(hdrdir)/ruby/thread.h +ossl_x509store.o: openssl_missing.h +ossl_x509store.o: ossl.h +ossl_x509store.o: ossl_asn1.h +ossl_x509store.o: ossl_bio.h +ossl_x509store.o: ossl_bn.h +ossl_x509store.o: ossl_cipher.h +ossl_x509store.o: ossl_config.h +ossl_x509store.o: ossl_digest.h +ossl_x509store.o: ossl_engine.h +ossl_x509store.o: ossl_hmac.h +ossl_x509store.o: ossl_kdf.h +ossl_x509store.o: ossl_ns_spki.h +ossl_x509store.o: ossl_ocsp.h +ossl_x509store.o: ossl_pkcs12.h +ossl_x509store.o: ossl_pkcs7.h +ossl_x509store.o: ossl_pkey.h +ossl_x509store.o: ossl_provider.h +ossl_x509store.o: ossl_rand.h +ossl_x509store.o: ossl_ssl.h +ossl_x509store.o: ossl_ts.h +ossl_x509store.o: ossl_x509.h +ossl_x509store.o: ossl_x509store.c +# AUTOGENERATED DEPENDENCIES END diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 37053848ef..a897c86b65 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -1,128 +1,182 @@ +# -*- coding: us-ascii -*- +# frozen_string_literal: true =begin -= $RCSfile$ -- Generator for Makefile - = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> All rights reserved. = Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ + This program is licensed under the same licence as Ruby. + (See the file 'COPYING'.) =end require "mkmf" -dir_config("openssl") -dir_config("kerberos") - -$defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}" +ssl_dirs = dir_config("openssl") +dir_config_given = ssl_dirs.any? + +_, ssl_ldir = ssl_dirs +if ssl_ldir&.split(File::PATH_SEPARATOR)&.none? { |dir| File.directory?(dir) } + # According to the `mkmf.rb#dir_config`, the `--with-openssl-dir=<dir>` uses + # the value of the `File.basename(RbConfig::MAKEFILE_CONFIG["libdir"])` as a + # loaded library directory name. + ruby_ldir_name = File.basename(RbConfig::MAKEFILE_CONFIG["libdir"]) + + raise "OpenSSL library directory could not be found in '#{ssl_ldir}'. " \ + "You might want to fix this error in one of the following ways.\n" \ + " * Recompile OpenSSL by configuring it with --libdir=#{ruby_ldir_name} " \ + " to specify the OpenSSL library directory.\n" \ + " * Recompile Ruby by configuring it with --libdir=<dir> to specify the " \ + "Ruby library directory.\n" \ + " * Compile this openssl gem with --with-openssl-include=<dir> and " \ + "--with-openssl-lib=<dir> options to specify the OpenSSL include and " \ + "library directories." +end -message "=== OpenSSL for Ruby configurator ===\n" +Logging::message "=== OpenSSL for Ruby configurator ===\n" -## -# Adds -Wall -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("-D""OPENSSL_SUPPRESS_DEPRECATED") - if /gcc/ =~ CONFIG["CC"] - $CPPFLAGS += " -Wall" unless $CPPFLAGS.split.include? "-Wall" - end -end +# Missing in TruffleRuby +have_func("rb_call_super_kw(0, NULL, 0)", "ruby.h") +# Ruby 3.1 +have_func("rb_io_descriptor", "ruby/io.h") +have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") +# Ruby 3.2 +have_func("rb_io_timeout", "ruby/io.h") -message "=== Checking for system dependent stuff... ===\n" +Logging::message "=== Checking for system dependent stuff... ===\n" have_library("nsl", "t_open") have_library("socket", "socket") -have_header("assert.h") +if $mswin || $mingw + have_library("ws2_32") +end -message "=== Checking for required stuff... ===\n" if $mingw - have_library("wsock32") - have_library("gdi32") + append_cflags '-D_FORTIFY_SOURCE=2' + append_ldflags '-fstack-protector' + have_library 'ssp' end -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")} -if !result - unless pkg_config("openssl") and have_header("openssl/ssl.h") - message "=== Checking for required stuff failed. ===\n" - message "Makefile wasn't created. Fix the errors above.\n" - exit 1 + +def find_openssl_library + if $mswin || $mingw + # required for static OpenSSL libraries + have_library("crypt32") end + + return false unless have_header("openssl/ssl.h") + + ret = have_library("crypto", "CRYPTO_malloc") && + have_library("ssl", "SSL_new") + return ret if ret + + if $mswin + # OpenSSL >= 1.1.0: libcrypto.lib and libssl.lib. + if have_library("libcrypto", "CRYPTO_malloc") && + have_library("libssl", "SSL_new") + return true + end + + # LibreSSL: libcrypto-##.lib and libssl-##.lib, where ## is the ABI version + # number. We have to find the version number out by scanning libpath. + libpath = $LIBPATH.dup + libpath |= ENV["LIB"].split(File::PATH_SEPARATOR) + libpath.map! { |d| d.tr(File::ALT_SEPARATOR, File::SEPARATOR) } + + ret = [ + ["crypto", "CRYPTO_malloc"], + ["ssl", "SSL_new"] + ].all? do |base, func| + result = false + libs = ["lib#{base}-[0-9][0-9]", "lib#{base}-[0-9][0-9][0-9]"] + libs = Dir.glob(libs.map{|l| libpath.map{|d| File.join(d, l + ".*")}}.flatten).map{|path| File.basename(path, ".*")}.uniq + libs.each do |lib| + result = have_library(lib, func) + break if result + end + result + end + return ret if ret + end + return false end -unless have_header("openssl/conf_api.h") - message "OpenSSL 0.9.6 or later required.\n" - exit 1 +Logging::message "=== Checking for required stuff... ===\n" +pkg_config_found = !dir_config_given && pkg_config("openssl") && have_header("openssl/ssl.h") + +if !pkg_config_found && !find_openssl_library + Logging::message "=== Checking for required stuff failed. ===\n" + Logging::message "Makefile wasn't created. Fix the errors above.\n" + raise "OpenSSL library could not be found. You might want to use " \ + "--with-openssl-dir=<dir> option to specify the prefix where OpenSSL " \ + "is installed." end -%w"rb_str_set_len rb_block_call".each {|func| have_func(func, "ruby.h")} - -message "=== Checking for OpenSSL features... ===\n" -have_func("ERR_peek_last_error") -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") -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("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("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_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("OPENSSL_cleanse") -if try_compile("#define FOO(a, ...) foo(a, ##__VA_ARGS__)\n int x(){FOO(1);FOO(1,2);FOO(1,2,3);}\n") - $defs.push("-DHAVE_VA_ARGS_MACRO") +version_ok = if have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h") + is_libressl = true + checking_for("LibreSSL version >= 3.9.0") { + try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x30900000L", "openssl/opensslv.h") } +else + is_openssl = true + checking_for("OpenSSL version >= 1.1.1") { + try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10101000L", "openssl/opensslv.h") } 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") +unless version_ok + raise "OpenSSL >= 1.1.1 or LibreSSL >= 3.9.0 is required" end -if try_compile(<<SRC) -#include <openssl/opensslv.h> -#if OPENSSL_VERSION_NUMBER < 0x00907000L -# error "OpenSSL version is less than 0.9.7." -#endif -SRC - have_header("openssl/ocsp.h") + +# Prevent wincrypt.h from being included, which defines conflicting macro with openssl/x509.h +if is_libressl && ($mswin || $mingw) + $defs.push("-DNOCRYPT") end -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") -message "=== Checking done. ===\n" +Logging::message "=== Checking for OpenSSL features... ===\n" +evp_h = "openssl/evp.h".freeze +ts_h = "openssl/ts.h".freeze +ssl_h = "openssl/ssl.h".freeze + +# compile options +have_func("RAND_egd()", "openssl/rand.h") + +# added in OpenSSL 1.0.2, not in LibreSSL yet +have_func("SSL_CTX_set1_sigalgs_list(NULL, NULL)", ssl_h) +# added in OpenSSL 1.0.2, not in LibreSSL or AWS-LC yet +have_func("SSL_CTX_set1_client_sigalgs_list(NULL, NULL)", ssl_h) + +# added in 1.1.0, currently not in LibreSSL +have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0)", evp_h) + +# added in OpenSSL 1.1.1 and LibreSSL 3.5.0, then removed in LibreSSL 4.0.0 +have_func("EVP_PKEY_check(NULL)", evp_h) + +# added in 3.0.0 +have_func("SSL_CTX_set0_tmp_dh_pkey(NULL, NULL)", ssl_h) +have_func("ERR_get_error_all(NULL, NULL, NULL, NULL, NULL)", "openssl/err.h") +have_func("SSL_CTX_load_verify_file(NULL, \"\")", ssl_h) +have_func("BN_check_prime(NULL, NULL, NULL)", "openssl/bn.h") +have_func("EVP_MD_CTX_get0_md(NULL)", evp_h) +have_func("EVP_MD_CTX_get_pkey_ctx(NULL)", evp_h) +have_func("EVP_PKEY_eq(NULL, NULL)", evp_h) +have_func("EVP_PKEY_dup(NULL)", evp_h) + +# added in 3.2.0 +have_func("SSL_get0_group_name(NULL)", ssl_h) + +# added in 3.4.0 +have_func("TS_VERIFY_CTX_set0_certs(NULL, NULL)", ts_h) + +# added in 3.5.0 +have_func("SSL_get0_peer_signature_name(NULL, NULL)", ssl_h) + +Logging::message "=== Checking done. ===\n" + +# Append flags from environment variables. +extcflags = ENV["RUBY_OPENSSL_EXTCFLAGS"] +append_cflags(extcflags.split) if extcflags +extldflags = ENV["RUBY_OPENSSL_EXTLDFLAGS"] +append_ldflags(extldflags.split) if extldflags create_header create_makefile("openssl") -message "Done.\n" +Logging::message "Done.\n" diff --git a/ext/openssl/lib/net/ftptls.rb b/ext/openssl/lib/net/ftptls.rb deleted file mode 100644 index a21c1f6c3c..0000000000 --- a/ext/openssl/lib/net/ftptls.rb +++ /dev/null @@ -1,53 +0,0 @@ -=begin -= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP. - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2003 Blaz Grilc <farmer@gmx.co.uk> - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Requirements - -= Version - $Id$ - -= Notes - Tested on FreeBSD 5-CURRENT and 4-STABLE - - ruby 1.6.8 (2003-01-17) [i386-freebsd5] - - OpenSSL 0.9.7a Feb 19 2003 - - ruby-openssl-0.2.0.p0 - tested on ftp server: glftpd 1.30 -=end - -require 'socket' -require 'openssl' -require 'net/ftp' - -module Net - class FTPTLS < FTP - def connect(host, port=FTP_PORT) - @hostname = host - super - end - - def login(user = "anonymous", passwd = nil, acct = nil) - store = OpenSSL::X509::Store.new - store.set_default_paths - ctx = OpenSSL::SSL::SSLContext.new('SSLv23') - ctx.cert_store = store - ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER - ctx.key = nil - ctx.cert = nil - voidcmd("AUTH TLS") - @sock = OpenSSL::SSL::SSLSocket.new(@sock, ctx) - @sock.connect - @sock.post_connection_check(@hostname) - super(user, passwd, acct) - voidcmd("PBSZ 0") - end - end -end diff --git a/ext/openssl/lib/net/telnets.rb b/ext/openssl/lib/net/telnets.rb deleted file mode 100644 index 2b69280432..0000000000 --- a/ext/openssl/lib/net/telnets.rb +++ /dev/null @@ -1,251 +0,0 @@ -=begin -= $RCSfile$ -- SSL/TLS enhancement for Net::Telnet. - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org> - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ - - 2001/11/06: Contiributed to Ruby/OpenSSL project. - -== class Net::Telnet - -This class will initiate SSL/TLS session automaticaly if the server -sent OPT_STARTTLS. Some options are added for SSL/TLS. - - host = Net::Telnet::new({ - "Host" => "localhost", - "Port" => "telnets", - ## follows are new options. - 'CertFile' => "user.crt", - 'KeyFile' => "user.key", - 'CAFile' => "/some/where/certs/casert.pem", - 'CAPath' => "/some/where/caserts", - 'VerifyMode' => SSL::VERIFY_PEER, - 'VerifyCallback' => verify_proc - }) - -Or, the new options ('Cert', 'Key' and 'CACert') are available from -Michal Rokos's OpenSSL module. - - cert_data = File.open("user.crt"){|io| io.read } - pkey_data = File.open("user.key"){|io| io.read } - cacert_data = File.open("your_ca.pem"){|io| io.read } - host = Net::Telnet::new({ - "Host" => "localhost", - "Port" => "telnets", - 'Cert' => OpenSSL::X509::Certificate.new(cert_data) - 'Key' => OpenSSL::PKey::RSA.new(pkey_data) - 'CACert' => OpenSSL::X509::Certificate.new(cacert_data) - 'CAFile' => "/some/where/certs/casert.pem", - 'CAPath' => "/some/where/caserts", - 'VerifyMode' => SSL::VERIFY_PEER, - 'VerifyCallback' => verify_proc - }) - -This class is expected to be a superset of usual Net::Telnet. -=end - -require "net/telnet" -require "openssl" - -module Net - class Telnet - attr_reader :ssl - - OPT_STARTTLS = 46.chr # "\056" # "\x2e" # Start TLS - TLS_FOLLOWS = 1.chr # "\001" # "\x01" # FOLLOWS (for STARTTLS) - - alias preprocess_orig preprocess - - def ssl?; @ssl; end - - def preprocess(string) - # combine CR+NULL into CR - string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"] - - # combine EOL into "\n" - string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"] - - string.gsub(/#{IAC}( - [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]| - [#{DO}#{DONT}#{WILL}#{WONT}][#{OPT_BINARY}-#{OPT_EXOPL}]| - #{SB}[#{OPT_BINARY}-#{OPT_EXOPL}] - (#{IAC}#{IAC}|[^#{IAC}])+#{IAC}#{SE} - )/xno) do - if IAC == $1 # handle escaped IAC characters - IAC - elsif AYT == $1 # respond to "IAC AYT" (are you there) - self.write("nobody here but us pigeons" + EOL) - '' - elsif DO[0] == $1[0] # respond to "IAC DO x" - if OPT_BINARY[0] == $1[1] - @telnet_option["BINARY"] = true - self.write(IAC + WILL + OPT_BINARY) - elsif OPT_STARTTLS[0] == $1[1] - self.write(IAC + WILL + OPT_STARTTLS) - self.write(IAC + SB + OPT_STARTTLS + TLS_FOLLOWS + IAC + SE) - else - self.write(IAC + WONT + $1[1..1]) - end - '' - elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x" - self.write(IAC + WONT + $1[1..1]) - '' - elsif WILL[0] == $1[0] # respond to "IAC WILL x" - if OPT_BINARY[0] == $1[1] - self.write(IAC + DO + OPT_BINARY) - elsif OPT_ECHO[0] == $1[1] - self.write(IAC + DO + OPT_ECHO) - elsif OPT_SGA[0] == $1[1] - @telnet_option["SGA"] = true - self.write(IAC + DO + OPT_SGA) - else - self.write(IAC + DONT + $1[1..1]) - end - '' - elsif WONT[0] == $1[0] # respond to "IAC WON'T x" - if OPT_ECHO[0] == $1[1] - self.write(IAC + DONT + OPT_ECHO) - elsif OPT_SGA[0] == $1[1] - @telnet_option["SGA"] = false - self.write(IAC + DONT + OPT_SGA) - else - self.write(IAC + DONT + $1[1..1]) - end - '' - elsif SB[0] == $1[0] # respond to "IAC SB xxx IAC SE" - if OPT_STARTTLS[0] == $1[1] && TLS_FOLLOWS[0] == $2[0] - @sock = OpenSSL::SSL::SSLSocket.new(@sock) - @sock.cert = @options['Cert'] unless @sock.cert - @sock.key = @options['Key'] unless @sock.key - @sock.ca_cert = @options['CACert'] - @sock.ca_file = @options['CAFile'] - @sock.ca_path = @options['CAPath'] - @sock.timeout = @options['Timeout'] - @sock.verify_mode = @options['VerifyMode'] - @sock.verify_callback = @options['VerifyCallback'] - @sock.verify_depth = @options['VerifyDepth'] - @sock.connect - if @options['VerifyMode'] != OpenSSL::SSL::VERIFY_NONE - @sock.post_connection_check(@options['Host']) - end - @ssl = true - end - '' - else - '' - end - end - end # preprocess - - alias waitfor_org waitfor - - def waitfor(options) - time_out = @options["Timeout"] - waittime = @options["Waittime"] - - if options.kind_of?(Hash) - prompt = if options.has_key?("Match") - options["Match"] - elsif options.has_key?("Prompt") - options["Prompt"] - elsif options.has_key?("String") - Regexp.new( Regexp.quote(options["String"]) ) - end - time_out = options["Timeout"] if options.has_key?("Timeout") - waittime = options["Waittime"] if options.has_key?("Waittime") - else - prompt = options - end - - if time_out == false - time_out = nil - end - - line = '' - buf = '' - @rest = '' unless @rest - - until(prompt === line and not IO::select([@sock], nil, nil, waittime)) - unless IO::select([@sock], nil, nil, time_out) - raise TimeoutError, "timed-out; wait for the next data" - end - begin - c = @rest + @sock.sysread(1024 * 1024) - @dumplog.log_dump('<', c) if @options.has_key?("Dump_log") - if @options["Telnetmode"] - pos = 0 - catch(:next){ - while true - case c[pos] - when IAC[0] - case c[pos+1] - when DO[0], DONT[0], WILL[0], WONT[0] - throw :next unless c[pos+2] - pos += 3 - when SB[0] - ret = detect_sub_negotiation(c, pos) - throw :next unless ret - pos = ret - when nil - throw :next - else - pos += 2 - end - when nil - throw :next - else - pos += 1 - end - end - } - - buf = preprocess(c[0...pos]) - @rest = c[pos..-1] - end - @log.print(buf) if @options.has_key?("Output_log") - line.concat(buf) - yield buf if block_given? - rescue EOFError # End of file reached - if line == '' - line = nil - yield nil if block_given? - end - break - end - end - line - end - - private - - def detect_sub_negotiation(data, pos) - return nil if data.length < pos+6 # IAC SB x param IAC SE - pos += 3 - while true - case data[pos] - when IAC[0] - if data[pos+1] == SE[0] - pos += 2 - return pos - else - pos += 2 - end - when nil - return nil - else - pos += 1 - end - end - end - - end -end diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb index 24a9eed136..98fa8d39f2 100644 --- a/ext/openssl/lib/openssl.rb +++ b/ext/openssl/lib/openssl.rb @@ -1,24 +1,41 @@ +# frozen_string_literal: true =begin -= $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions - = Info 'OpenSSL for Ruby 2' project Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> All rights reserved. = Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ + This program is licensed under the same licence as Ruby. + (See the file 'COPYING'.) =end require 'openssl.so' -require 'openssl/bn' -require 'openssl/cipher' -require 'openssl/digest' -require 'openssl/ssl' -require 'openssl/x509' +require_relative 'openssl/bn' +require_relative 'openssl/cipher' +require_relative 'openssl/digest' +require_relative 'openssl/hmac' +require_relative 'openssl/pkcs5' +require_relative 'openssl/pkey' +require_relative 'openssl/ssl' +require_relative 'openssl/version' +require_relative 'openssl/x509' +module OpenSSL + # :call-seq: + # OpenSSL.secure_compare(string, string) -> true or false + # + # Constant time memory comparison. Inputs are hashed using SHA-256 to mask + # the length of the secret. Returns +true+ if the strings are identical, + # +false+ otherwise. + # + # This method is expensive due to the SHA-256 hashing. In most cases, where + # the input lengths are known to be equal or are not sensitive, + # OpenSSL.fixed_length_secure_compare should be used instead. + def self.secure_compare(a, b) + hashed_a = OpenSSL::Digest.digest('SHA256', a) + hashed_b = OpenSSL::Digest.digest('SHA256', b) + OpenSSL.fixed_length_secure_compare(hashed_a, hashed_b) && a == b + end +end diff --git a/ext/openssl/lib/openssl/bn.rb b/ext/openssl/lib/openssl/bn.rb index e7cbf2cfaf..e4889a140c 100644 --- a/ext/openssl/lib/openssl/bn.rb +++ b/ext/openssl/lib/openssl/bn.rb @@ -1,35 +1,40 @@ -=begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for BN - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -## -# Should we care what if somebody require this file directly? -#require 'openssl' +# frozen_string_literal: true +#-- +# +# = Ruby-space definitions that completes C-space funcs for BN +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> +# All rights reserved. +# +# = Licence +# This program is licensed under the same licence as Ruby. +# (See the file 'COPYING'.) +#++ module OpenSSL class BN include Comparable + + def pretty_print(q) + q.object_group(self) { + q.text ' ' + q.text to_i.to_s + } + end end # BN end # OpenSSL ## +#-- # Add double dispatch to Integer -# +#++ class Integer + # Casts an Integer as an OpenSSL::BN + # + # See `man bn` for more info. def to_bn OpenSSL::BN::new(self) end end # Integer - diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb index 8800aa53cc..1464a4292d 100644 --- a/ext/openssl/lib/openssl/buffering.rb +++ b/ext/openssl/lib/openssl/buffering.rb @@ -1,27 +1,65 @@ -=begin -= $RCSfile$ -- Buffering mix-in module. +# coding: binary +# frozen_string_literal: true +#-- +#= Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org> +# All rights reserved. +# +#= Licence +# This program is licensed under the same licence as Ruby. +# (See the file 'COPYING'.) +#++ -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org> - All rights reserved. +## +# OpenSSL IO buffering mix-in module. +# +# This module allows an OpenSSL::SSL::SSLSocket to behave like an IO. +# +# You typically won't use this module directly, you can see it implemented in +# OpenSSL::SSL::SSLSocket. -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) +module OpenSSL::Buffering + include Enumerable -= Version - $Id$ -=end + # A buffer which will retain binary encoding. + class Buffer < String + unless String.method_defined?(:append_as_bytes) + alias_method :_append, :<< + def append_as_bytes(string) + if string.encoding == Encoding::BINARY + _append(string) + else + _append(string.b) + end + + self + end + end + + undef_method :concat + undef_method :<< + end + + ## + # The "sync mode" of the SSLSocket. + # + # See IO#sync for full details. -module Buffering - include Enumerable attr_accessor :sync + + ## + # Default size to read from or write to the SSLSocket for buffer operations. + BLOCK_SIZE = 1024*16 - def initialize(*args) + ## + # Creates an instance of OpenSSL's buffering IO module. + + def initialize(*) + super @eof = false - @rbuffer = "" + @rbuffer = Buffer.new @sync = @io.sync end @@ -30,9 +68,12 @@ module Buffering # private + ## + # Fills the buffer from the underlying SSLSocket + def fill_rbuff begin - @rbuffer << self.sysread(BLOCK_SIZE) + @rbuffer.append_as_bytes(self.sysread(BLOCK_SIZE)) rescue Errno::EAGAIN retry rescue EOFError @@ -40,19 +81,40 @@ module Buffering end end + ## + # Consumes _size_ bytes from the buffer + def consume_rbuff(size=nil) if @rbuffer.empty? nil else size = @rbuffer.size unless size - ret = @rbuffer[0, size] - @rbuffer[0, size] = "" - ret + @rbuffer.slice!(0, size) end end public + # call-seq: + # ssl.getbyte => 81 + # + # Get the next 8bit byte from `ssl`. Returns `nil` on EOF + def getbyte + read(1)&.ord + end + + # Get the next 8bit byte. Raises EOFError on EOF + def readbyte + raise EOFError if eof? + getbyte + end + + ## + # Reads _size_ bytes from the stream. If _buf_ is provided it must + # reference a string which will receive the data. + # + # See IO#read for full details. + def read(size=nil, buf=nil) if size == 0 if buf @@ -74,6 +136,12 @@ module Buffering (size && ret.empty?) ? nil : ret end + ## + # Reads at most _maxlen_ bytes from the stream. If _buf_ is provided it + # must reference a string which will receive the data. + # + # See IO#readpartial for full details. + def readpartial(maxlen, buf=nil) if maxlen == 0 if buf @@ -95,11 +163,75 @@ module Buffering buf.replace(ret) ret = buf end - raise EOFError if ret.empty? ret end - def gets(eol=$/) + ## + # Reads at most _maxlen_ bytes in the non-blocking manner. + # + # When no data can be read without blocking it raises + # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. + # + # IO::WaitReadable means SSL needs to read internally so read_nonblock + # should be called again when the underlying IO is readable. + # + # IO::WaitWritable means SSL needs to write internally so read_nonblock + # should be called again after the underlying IO is writable. + # + # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows: + # + # # emulates blocking read (readpartial). + # begin + # result = ssl.read_nonblock(maxlen) + # rescue IO::WaitReadable + # IO.select([io]) + # retry + # rescue IO::WaitWritable + # IO.select(nil, [io]) + # retry + # end + # + # 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 a keyword argument _exception_ to +false+, you can indicate + # that read_nonblock should not raise an IO::Wait*able exception, but + # return the symbol +:wait_writable+ or +:wait_readable+ instead. At EOF, + # it will return +nil+ instead of raising EOFError. + + def read_nonblock(maxlen, buf=nil, exception: true) + if maxlen == 0 + if buf + buf.clear + return buf + else + return "" + end + end + if @rbuffer.empty? + return sysread_nonblock(maxlen, buf, exception: exception) + end + ret = consume_rbuff(maxlen) + if buf + buf.replace(ret) + ret = buf + end + ret + end + + ## + # Reads the next "line" from the stream. Lines are separated by _eol_. If + # _limit_ is provided the result will not be longer than the given number of + # bytes. + # + # _eol_ may be a String or Regexp. + # + # Unlike IO#gets the line read will not be assigned to +$_+. + # + # Unlike IO#gets the separator must be provided if a limit is provided. + + def gets(eol=$/, limit=nil, chomp: false) idx = @rbuffer.index(eol) until @eof break if idx @@ -111,9 +243,22 @@ module Buffering else size = idx ? idx+eol.size : nil end - consume_rbuff(size) + if size && limit && limit >= 0 + size = [size, limit].min + end + line = consume_rbuff(size) + if chomp && line + line.chomp!(eol) + end + line end + ## + # Executes the block for every line in the stream where lines are separated + # by _eol_. + # + # See also #gets + def each(eol=$/) while line = self.gets(eol) yield line @@ -121,6 +266,11 @@ module Buffering end alias each_line each + ## + # Reads lines from the stream which are separated by _eol_. + # + # See also #gets + def readlines(eol=$/) ary = [] while line = self.gets(eol) @@ -129,31 +279,58 @@ module Buffering ary end + ## + # Reads a line from the stream which is separated by _eol_. + # + # Raises EOFError if at end of file. + def readline(eol=$/) raise EOFError if eof? gets(eol) end + ## + # Reads one character from the stream. Returns nil if called at end of + # file. + def getc - c = read(1) - c ? c[0] : nil + read(1) end - def each_byte + ## + # Calls the given block once for each byte in the stream. + + def each_byte # :yields: byte while c = getc - yield(c) + yield(c.ord) end end + ## + # Reads a one-character string from the stream. Raises an EOFError at end + # of file. + def readchar raise EOFError if eof? getc end + ## + # Pushes character _c_ back onto the stream such that a subsequent buffered + # character read will return it. + # + # Unlike IO#getc multiple bytes may be pushed back onto the stream. + # + # Has no effect on unbuffered reads (such as #sysread). + def ungetc(c) @rbuffer[0,0] = c.chr end + ## + # Returns true if the stream is at file which means there is no more data to + # be read. + def eof? fill_rbuff if !@eof && @rbuffer.empty? @eof && @rbuffer.empty? @@ -165,73 +342,162 @@ module Buffering # private + ## + # Writes _s_ to the buffer. When the buffer is full or #sync is true the + # buffer is flushed to the underlying socket. + def do_write(s) - @wbuffer = "" unless defined? @wbuffer - @wbuffer << s + @wbuffer = Buffer.new unless defined? @wbuffer + @wbuffer.append_as_bytes(s) + @sync ||= false - if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/) - remain = idx ? idx + $/.size : @wbuffer.length - nwritten = 0 - while remain > 0 - str = @wbuffer[nwritten,remain] - begin - nwrote = syswrite(str) - rescue Errno::EAGAIN - retry + buffer_size = @wbuffer.bytesize + if @sync or buffer_size > BLOCK_SIZE + nwrote = 0 + begin + while nwrote < buffer_size do + begin + chunk = if nwrote > 0 + @wbuffer.byteslice(nwrote, @wbuffer.bytesize) + else + @wbuffer + end + + nwrote += syswrite(chunk) + rescue Errno::EAGAIN + retry + end + end + ensure + if nwrote < @wbuffer.bytesize + @wbuffer[0, nwrote] = "" + else + @wbuffer.clear end - remain -= nwrote - nwritten += nwrote end - @wbuffer[0,nwritten] = "" end end public - def write(s) - do_write(s) - s.length + ## + # Writes _s_ to the stream. If the argument is not a String it will be + # converted using +.to_s+ method. Returns the number of bytes written. + + def write(*s) + s.inject(0) do |written, str| + do_write(str) + written + str.bytesize + end end - def << (s) + ## + # Writes _s_ in the non-blocking manner. + # + # If there is buffered data, it is flushed first. This may block. + # + # write_nonblock returns number of bytes written to the SSL connection. + # + # When no data can be written without blocking it raises + # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. + # + # IO::WaitReadable means SSL needs to read internally so write_nonblock + # should be called again after the underlying IO is readable. + # + # IO::WaitWritable means SSL needs to write internally so write_nonblock + # should be called again after underlying IO is writable. + # + # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows. + # + # # emulates blocking write. + # begin + # result = ssl.write_nonblock(str) + # rescue IO::WaitReadable + # IO.select([io]) + # retry + # rescue IO::WaitWritable + # IO.select(nil, [io]) + # retry + # end + # + # 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 a keyword argument _exception_ to +false+, you can 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 + syswrite_nonblock(s, exception: exception) + end + + ## + # Writes _s_ to the stream. _s_ will be converted to a String using + # +.to_s+ method. + + def <<(s) do_write(s) self end + ## + # Writes _args_ to the stream along with a record separator. + # + # See IO#puts for full details. + def puts(*args) - s = "" + s = Buffer.new if args.empty? - s << "\n" + s.append_as_bytes("\n") end args.each{|arg| - s << arg.to_s - if $/ && /\n\z/ !~ s - s << "\n" - end + s.append_as_bytes(arg.to_s) + s.sub!(/(?<!\n)\z/, "\n") } do_write(s) nil end + ## + # Writes _args_ to the stream. + # + # See IO#print for full details. + def print(*args) - s = "" - args.each{ |arg| s << arg.to_s } + s = Buffer.new + args.each{ |arg| s.append_as_bytes(arg.to_s) } do_write(s) nil end + ## + # Formats and writes to the stream converting parameters under control of + # the format string. + # + # See Kernel#sprintf for format string details. + def printf(s, *args) do_write(s % args) nil end + ## + # Flushes buffered data to the SSLSocket. + def flush osync = @sync @sync = true do_write "" + return self + ensure @sync = osync end + ## + # Closes the SSLSocket and flushes any unwritten data. + def close flush rescue nil sysclose diff --git a/ext/openssl/lib/openssl/cipher.rb b/ext/openssl/lib/openssl/cipher.rb index 290e9c1d2d..ab75ac8e1a 100644 --- a/ext/openssl/lib/openssl/cipher.rb +++ b/ext/openssl/lib/openssl/cipher.rb @@ -1,22 +1,16 @@ -=begin -= $RCSfile$ -- Ruby-space predefined Cipher subclasses - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -## -# Should we care what if somebody require this file directly? -#require 'openssl' +# frozen_string_literal: true +#-- +# = Ruby-space predefined Cipher subclasses +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> +# All rights reserved. +# +# = Licence +# This program is licensed under the same licence as Ruby. +# (See the file 'COPYING'.) +#++ module OpenSSL class Cipher @@ -24,7 +18,7 @@ module OpenSSL 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) @@ -32,34 +26,42 @@ module OpenSSL %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::Digest 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 8d7df73b54..46ddfd6021 100644 --- a/ext/openssl/lib/openssl/digest.rb +++ b/ext/openssl/lib/openssl/digest.rb @@ -1,54 +1,69 @@ -=begin -= $RCSfile$ -- Ruby-space predefined Digest subclasses - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -## -# Should we care what if somebody require this file directly? -#require 'openssl' +# frozen_string_literal: true +#-- +# = Ruby-space predefined Digest subclasses +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> +# All rights reserved. +# +# = Licence +# This program is licensed under the same licence as Ruby. +# (See the file 'COPYING'.) +#++ module OpenSSL class Digest - alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) - if OPENSSL_VERSION_NUMBER > 0x00908000 - alg += %w(SHA224 SHA256 SHA384 SHA512) + # Return the hash value computed with _name_ Digest. _name_ is either the + # long name or short name of a supported digest algorithm. + # + # === Example + # + # OpenSSL::Digest.digest("SHA256", "abc") + + def self.digest(name, data) + super(data, name) end - alg.each{|name| - klass = Class.new(Digest){ - define_method(:initialize){|*data| - if data.length > 1 - raise ArgumentError, - "wrong number of arguments (#{data.length} for 1)" - end - super(name, data.first) - } + %w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512).each do |name| + klass = Class.new(self) { + define_method(:initialize, ->(data = nil) {super(name, data)}) } - singleton = (class <<klass; self; end) + + singleton = (class << klass; self; end) + singleton.class_eval{ - define_method(:digest){|data| Digest.digest(name, data) } - define_method(:hexdigest){|data| Digest.hexdigest(name, data) } + define_method(:digest) {|data| new.digest(data)} + define_method(:hexdigest) {|data| new.hexdigest(data)} } - const_set(name, klass) - } - # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. - class Digest < Digest - # add warning + const_set(name.tr('-', '_'), klass) end + # Deprecated. + # + # This class is only provided for backwards compatibility. + # Use OpenSSL::Digest instead. + class Digest < Digest; end # :nodoc: + deprecate_constant :Digest + end # Digest -end # OpenSSL + # Returns a Digest subclass by _name_ + # + # require 'openssl' + # + # OpenSSL::Digest("MD5") + # # => OpenSSL::Digest::MD5 + # + # OpenSSL::Digest("Foo") + # # => NameError: wrong constant name Foo + + def Digest(name) + OpenSSL::Digest.const_get(name) + end + + module_function :Digest + +end # OpenSSL diff --git a/ext/openssl/lib/openssl/hmac.rb b/ext/openssl/lib/openssl/hmac.rb new file mode 100644 index 0000000000..c8c844d8d7 --- /dev/null +++ b/ext/openssl/lib/openssl/hmac.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +module OpenSSL + class HMAC + # Securely compare with another HMAC instance in constant time. + def ==(other) + return false unless HMAC === other + return false unless self.digest.bytesize == other.digest.bytesize + + OpenSSL.fixed_length_secure_compare(self.digest, other.digest) + end + + # :call-seq: + # hmac.base64digest -> string + # + # Returns the authentication code an a Base64-encoded string. + def base64digest + [digest].pack("m0") + end + + class << self + # :call-seq: + # HMAC.digest(digest, key, data) -> aString + # + # Returns the authentication code as a binary string. The _digest_ parameter + # specifies the digest algorithm to use. This may be a String representing + # the algorithm name or an instance of OpenSSL::Digest. + # + # === Example + # key = 'key' + # data = 'The quick brown fox jumps over the lazy dog' + # + # hmac = OpenSSL::HMAC.digest('SHA1', key, data) + # #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9" + def digest(digest, key, data) + hmac = new(key, digest) + hmac << data + hmac.digest + end + + # :call-seq: + # HMAC.hexdigest(digest, key, data) -> aString + # + # Returns the authentication code as a hex-encoded string. The _digest_ + # parameter specifies the digest algorithm to use. This may be a String + # representing the algorithm name or an instance of OpenSSL::Digest. + # + # === Example + # key = 'key' + # data = 'The quick brown fox jumps over the lazy dog' + # + # hmac = OpenSSL::HMAC.hexdigest('SHA1', key, data) + # #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" + def hexdigest(digest, key, data) + hmac = new(key, digest) + hmac << data + hmac.hexdigest + end + + # :call-seq: + # HMAC.base64digest(digest, key, data) -> aString + # + # Returns the authentication code as a Base64-encoded string. The _digest_ + # parameter specifies the digest algorithm to use. This may be a String + # representing the algorithm name or an instance of OpenSSL::Digest. + # + # === Example + # key = 'key' + # data = 'The quick brown fox jumps over the lazy dog' + # + # hmac = OpenSSL::HMAC.base64digest('SHA1', key, data) + # #=> "3nybhbi3iqa8ino29wqQcBydtNk=" + def base64digest(digest, key, data) + [digest(digest, key, data)].pack("m0") + end + end + end +end diff --git a/ext/openssl/lib/openssl/marshal.rb b/ext/openssl/lib/openssl/marshal.rb new file mode 100644 index 0000000000..eb8eda4748 --- /dev/null +++ b/ext/openssl/lib/openssl/marshal.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +#-- +# = Ruby-space definitions to add DER (de)serialization to classes +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> +# All rights reserved. +# +# = Licence +# This program is licensed under the same licence as Ruby. +# (See the file 'COPYING'.) +#++ +module OpenSSL + module Marshal + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def _load(string) + new(string) + end + end + + def _dump(_level) + to_der + end + end +end diff --git a/ext/openssl/lib/openssl/pkcs5.rb b/ext/openssl/lib/openssl/pkcs5.rb new file mode 100644 index 0000000000..8dedc4beef --- /dev/null +++ b/ext/openssl/lib/openssl/pkcs5.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +#-- +# Ruby/OpenSSL Project +# Copyright (C) 2017 Ruby/OpenSSL Project Authors +#++ + +module OpenSSL + module PKCS5 + module_function + + # OpenSSL::PKCS5.pbkdf2_hmac has been renamed to OpenSSL::KDF.pbkdf2_hmac. + # This method is provided for backwards compatibility. + def pbkdf2_hmac(pass, salt, iter, keylen, digest) + OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter, + length: keylen, hash: digest) + end + + def pbkdf2_hmac_sha1(pass, salt, iter, keylen) + pbkdf2_hmac(pass, salt, iter, keylen, "sha1") + end + end +end diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb new file mode 100644 index 0000000000..39871e15dd --- /dev/null +++ b/ext/openssl/lib/openssl/pkey.rb @@ -0,0 +1,493 @@ +# frozen_string_literal: true +#-- +# Ruby/OpenSSL Project +# Copyright (C) 2017 Ruby/OpenSSL Project Authors +#++ + +require_relative 'marshal' + +module OpenSSL::PKey + # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError. + DHError = PKeyError + + class DH + include OpenSSL::Marshal + + # :call-seq: + # dh.public_key -> dhnew + # + # Returns a new DH instance that carries just the \DH parameters. + # + # Contrary to the method name, the returned DH object contains only + # parameters and not the public key. + # + # This method is provided for backwards compatibility. In most cases, there + # is no need to call this method. + # + # For the purpose of re-generating the key pair while keeping the + # parameters, check OpenSSL::PKey.generate_key. + # + # Example: + # # OpenSSL::PKey::DH.generate by default generates a random key pair + # dh1 = OpenSSL::PKey::DH.generate(2048) + # p dh1.priv_key #=> #<OpenSSL::BN 1288347...> + # dhcopy = dh1.public_key + # p dhcopy.priv_key #=> nil + def public_key + DH.new(to_der) + end + + # :call-seq: + # dh.params -> hash + # + # Stores all parameters of key to a Hash. + # + # The hash has keys 'p', 'q', 'g', 'pub_key', and 'priv_key'. + def params + %w{p q g pub_key priv_key}.map { |name| + [name, send(name)] + }.to_h + end + + # :call-seq: + # dh.compute_key(pub_bn) -> string + # + # Returns a String containing a shared secret computed from the other + # party's public value. + # + # This method is provided for backwards compatibility, and calls #derive + # internally. + # + # === Parameters + # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by + # DH#public_key as that contains the DH parameters only. + def compute_key(pub_bn) + # FIXME: This is constructing an X.509 SubjectPublicKeyInfo and is very + # inefficient + obj = OpenSSL::ASN1.Sequence([ + OpenSSL::ASN1.Sequence([ + OpenSSL::ASN1.ObjectId("dhKeyAgreement"), + OpenSSL::ASN1.Sequence([ + OpenSSL::ASN1.Integer(p), + OpenSSL::ASN1.Integer(g), + ]), + ]), + OpenSSL::ASN1.BitString(OpenSSL::ASN1.Integer(pub_bn).to_der), + ]) + derive(OpenSSL::PKey.read(obj.to_der)) + end + + # :call-seq: + # dh.generate_key! -> self + # + # Generates a private and public key unless a private key already exists. + # If this DH instance was generated from public \DH parameters (e.g. by + # encoding the result of DH#public_key), then this method needs to be + # called first in order to generate the per-session keys before performing + # the actual key exchange. + # + # <b>Deprecated in version 3.0</b>. This method is incompatible with + # OpenSSL 3.0.0 or later. + # + # See also OpenSSL::PKey.generate_key. + # + # Example: + # # DEPRECATED USAGE: This will not work on OpenSSL 3.0 or later + # dh0 = OpenSSL::PKey::DH.new(2048) + # dh = dh0.public_key # #public_key only copies the DH parameters (contrary to the name) + # dh.generate_key! + # puts dh.private? # => true + # puts dh0.pub_key == dh.pub_key #=> false + # + # # With OpenSSL::PKey.generate_key + # dh0 = OpenSSL::PKey::DH.new(2048) + # dh = OpenSSL::PKey.generate_key(dh0) + # puts dh0.pub_key == dh.pub_key #=> false + def generate_key! + if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 + raise PKeyError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \ + "use OpenSSL::PKey.generate_key instead" + end + + unless priv_key + tmp = OpenSSL::PKey.generate_key(self) + set_key(tmp.pub_key, tmp.priv_key) + end + self + end + + class << self + # :call-seq: + # DH.generate(size, generator = 2) -> dh + # + # Creates a new DH instance from scratch by generating random parameters + # and a key pair. + # + # See also OpenSSL::PKey.generate_parameters and + # OpenSSL::PKey.generate_key. + # + # +size+:: + # The desired key size in bits. + # +generator+:: + # The generator. + def generate(size, generator = 2, &blk) + dhparams = OpenSSL::PKey.generate_parameters("DH", { + "dh_paramgen_prime_len" => size, + "dh_paramgen_generator" => generator, + }, &blk) + OpenSSL::PKey.generate_key(dhparams) + end + + # Handle DH.new(size, generator) form here; new(str) and new() forms + # are handled by #initialize + def new(*args, &blk) # :nodoc: + if args[0].is_a?(Integer) + generate(*args, &blk) + else + super + end + end + end + end + + # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError. + DSAError = PKeyError + + class DSA + include OpenSSL::Marshal + + # :call-seq: + # dsa.public_key -> dsanew + # + # Returns a new DSA instance that carries just the \DSA parameters and the + # public key. + # + # This method is provided for backwards compatibility. In most cases, there + # is no need to call this method. + # + # For the purpose of serializing the public key, to PEM or DER encoding of + # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and + # PKey#public_to_der. + def public_key + OpenSSL::PKey.read(public_to_der) + end + + # :call-seq: + # dsa.params -> hash + # + # Stores all parameters of key to a Hash. + # + # The hash has keys 'p', 'q', 'g', 'pub_key', and 'priv_key'. + def params + %w{p q g pub_key priv_key}.map { |name| + [name, send(name)] + }.to_h + end + + class << self + # :call-seq: + # DSA.generate(size) -> dsa + # + # Creates a new DSA instance by generating a private/public key pair + # from scratch. + # + # See also OpenSSL::PKey.generate_parameters and + # OpenSSL::PKey.generate_key. + # + # +size+:: + # The desired key size in bits. + def generate(size, &blk) + # FIPS 186-4 specifies four (L,N) pairs: (1024,160), (2048,224), + # (2048,256), and (3072,256). + # + # q size is derived here with compatibility with + # DSA_generator_parameters_ex() which previous versions of ruby/openssl + # used to call. + qsize = size >= 2048 ? 256 : 160 + dsaparams = OpenSSL::PKey.generate_parameters("DSA", { + "dsa_paramgen_bits" => size, + "dsa_paramgen_q_bits" => qsize, + }, &blk) + OpenSSL::PKey.generate_key(dsaparams) + end + + # Handle DSA.new(size) form here; new(str) and new() forms + # are handled by #initialize + def new(*args, &blk) # :nodoc: + if args[0].is_a?(Integer) + generate(*args, &blk) + else + super + end + end + end + + # :call-seq: + # dsa.syssign(string) -> string + # + # Computes and returns the \DSA signature of +string+, where +string+ is + # expected to be an already-computed message digest of the original input + # data. The signature is issued using the private key of this DSA instance. + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. + # + # +string+:: + # A message digest of the original input data to be signed. + # + # Example: + # dsa = OpenSSL::PKey::DSA.new(2048) + # doc = "Sign me" + # digest = OpenSSL::Digest.digest('SHA1', doc) + # + # # With legacy #syssign and #sysverify: + # sig = dsa.syssign(digest) + # p dsa.sysverify(digest, sig) #=> true + # + # # With #sign_raw and #verify_raw: + # sig = dsa.sign_raw(nil, digest) + # p dsa.verify_raw(nil, sig, digest) #=> true + def syssign(string) + q or raise PKeyError, "incomplete DSA" + private? or raise PKeyError, "Private DSA key needed!" + sign_raw(nil, string) + end + + # :call-seq: + # dsa.sysverify(digest, sig) -> true | false + # + # Verifies whether the signature is valid given the message digest input. + # It does so by validating +sig+ using the public key of this DSA instance. + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. + # + # +digest+:: + # A message digest of the original input data to be signed. + # +sig+:: + # A \DSA signature value. + def sysverify(digest, sig) + verify_raw(nil, sig, digest) + end + end + + if defined?(EC) + # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError. + ECError = PKeyError + + class EC + include OpenSSL::Marshal + + # :call-seq: + # key.dsa_sign_asn1(data) -> String + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. + def dsa_sign_asn1(data) + sign_raw(nil, data) + end + + # :call-seq: + # key.dsa_verify_asn1(data, sig) -> true | false + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. + def dsa_verify_asn1(data, sig) + verify_raw(nil, sig, data) + end + + # :call-seq: + # ec.dh_compute_key(pubkey) -> string + # + # Derives a shared secret by ECDH. _pubkey_ must be an instance of + # OpenSSL::PKey::EC::Point and must belong to the same group. + # + # This method is provided for backwards compatibility, and calls #derive + # internally. + def dh_compute_key(pubkey) + obj = OpenSSL::ASN1.Sequence([ + OpenSSL::ASN1.Sequence([ + OpenSSL::ASN1.ObjectId("id-ecPublicKey"), + group.to_der, + ]), + OpenSSL::ASN1.BitString(pubkey.to_octet_string(:uncompressed)), + ]) + derive(OpenSSL::PKey.read(obj.to_der)) + end + end + + class EC::Point + # :call-seq: + # point.to_bn([conversion_form]) -> OpenSSL::BN + # + # Returns the octet string representation of the EC point as an instance of + # OpenSSL::BN. + # + # If _conversion_form_ is not given, the _point_conversion_form_ attribute + # set to the group is used. + # + # See #to_octet_string for more information. + def to_bn(conversion_form = group.point_conversion_form) + OpenSSL::BN.new(to_octet_string(conversion_form), 2) + end + end + end + + # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError. + RSAError = PKeyError + + class RSA + include OpenSSL::Marshal + + # :call-seq: + # rsa.public_key -> rsanew + # + # Returns a new RSA instance that carries just the public key components. + # + # This method is provided for backwards compatibility. In most cases, there + # is no need to call this method. + # + # For the purpose of serializing the public key, to PEM or DER encoding of + # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and + # PKey#public_to_der. + def public_key + OpenSSL::PKey.read(public_to_der) + end + + # :call-seq: + # rsa.params -> hash + # + # Stores all parameters of key to a Hash. + # + # The hash has keys 'n', 'e', 'd', 'p', 'q', 'dmp1', 'dmq1', and 'iqmp'. + def params + %w{n e d p q dmp1 dmq1 iqmp}.map { |name| + [name, send(name)] + }.to_h + end + + class << self + # :call-seq: + # RSA.generate(size, exponent = 65537) -> RSA + # + # Generates an \RSA keypair. + # + # See also OpenSSL::PKey.generate_key. + # + # +size+:: + # The desired key size in bits. + # +exponent+:: + # An odd Integer, normally 3, 17, or 65537. + def generate(size, exp = 0x10001, &blk) + OpenSSL::PKey.generate_key("RSA", { + "rsa_keygen_bits" => size, + "rsa_keygen_pubexp" => exp, + }, &blk) + end + + # Handle RSA.new(size, exponent) form here; new(str) and new() forms + # are handled by #initialize + def new(*args, &blk) # :nodoc: + if args[0].is_a?(Integer) + generate(*args, &blk) + else + super + end + end + end + + # :call-seq: + # rsa.private_encrypt(string) -> String + # rsa.private_encrypt(string, padding) -> String + # + # Encrypt +string+ with the private key. +padding+ defaults to + # PKCS1_PADDING, which is known to be insecure but is kept for backwards + # compatibility. The encrypted string output can be decrypted using + # #public_decrypt. + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and + # PKey::PKey#verify_recover instead. + def private_encrypt(string, padding = PKCS1_PADDING) + n or raise PKeyError, "incomplete RSA" + private? or raise PKeyError, "private key needed." + sign_raw(nil, string, { + "rsa_padding_mode" => translate_padding_mode(padding), + }) + end + + # :call-seq: + # rsa.public_decrypt(string) -> String + # rsa.public_decrypt(string, padding) -> String + # + # Decrypt +string+, which has been encrypted with the private key, with the + # public key. +padding+ defaults to PKCS1_PADDING which is known to be + # insecure but is kept for backwards compatibility. + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and + # PKey::PKey#verify_recover instead. + def public_decrypt(string, padding = PKCS1_PADDING) + n or raise PKeyError, "incomplete RSA" + verify_recover(nil, string, { + "rsa_padding_mode" => translate_padding_mode(padding), + }) + end + + # :call-seq: + # rsa.public_encrypt(string) -> String + # rsa.public_encrypt(string, padding) -> String + # + # Encrypt +string+ with the public key. +padding+ defaults to + # PKCS1_PADDING, which is known to be insecure but is kept for backwards + # compatibility. The encrypted string output can be decrypted using + # #private_decrypt. + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. + def public_encrypt(data, padding = PKCS1_PADDING) + n or raise PKeyError, "incomplete RSA" + encrypt(data, { + "rsa_padding_mode" => translate_padding_mode(padding), + }) + end + + # :call-seq: + # rsa.private_decrypt(string) -> String + # rsa.private_decrypt(string, padding) -> String + # + # Decrypt +string+, which has been encrypted with the public key, with the + # private key. +padding+ defaults to PKCS1_PADDING, which is known to be + # insecure but is kept for backwards compatibility. + # + # <b>Deprecated in version 3.0</b>. + # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. + def private_decrypt(data, padding = PKCS1_PADDING) + n or raise PKeyError, "incomplete RSA" + private? or raise PKeyError, "private key needed." + decrypt(data, { + "rsa_padding_mode" => translate_padding_mode(padding), + }) + end + + PKCS1_PADDING = 1 + SSLV23_PADDING = 2 + NO_PADDING = 3 + PKCS1_OAEP_PADDING = 4 + + private def translate_padding_mode(num) + case num + when PKCS1_PADDING + "pkcs1" + when SSLV23_PADDING + "sslv23" + when NO_PADDING + "none" + when PKCS1_OAEP_PADDING + "oaep" + else + raise PKeyError, "unsupported padding mode" + end + end + end +end diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index ad9559f6b6..3268c126b9 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -1,26 +1,184 @@ +# frozen_string_literal: true =begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL - = Info 'OpenSSL for Ruby 2' project Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org> All rights reserved. = Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ + This program is licensed under the same licence as Ruby. + (See the file 'COPYING'.) =end -require "openssl" require "openssl/buffering" -require "fcntl" + +if defined?(OpenSSL::SSL) + +require "io/nonblock" +require "ipaddr" +require "socket" module OpenSSL module SSL + class SSLContext + DEFAULT_PARAMS = { # :nodoc: + :verify_mode => OpenSSL::SSL::VERIFY_PEER, + :verify_hostname => true, + :options => -> { + opts = OpenSSL::SSL::OP_ALL + opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS + opts |= OpenSSL::SSL::OP_NO_COMPRESSION + opts + }.call + } + + if !OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") + DEFAULT_PARAMS.merge!( + min_version: OpenSSL::SSL::TLS1_VERSION, + 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(":").freeze, + ) + end + DEFAULT_PARAMS.freeze + + DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc: + DEFAULT_CERT_STORE.set_default_paths + + # 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 + + # call-seq: + # SSLContext.new -> ctx + # SSLContext.new(:TLSv1) -> ctx + # SSLContext.new("SSLv23") -> ctx + # + # Creates a new SSL context. + # + # If an argument is given, #ssl_version= is called with the value. Note + # that this form is deprecated. New applications should use #min_version= + # and #max_version= as necessary. + def initialize(version = nil) + self.ssl_version = version if version + self.verify_mode = OpenSSL::SSL::VERIFY_NONE + self.verify_hostname = false + end + + ## + # 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) + self.options |= params.delete(:options) # set before min_version/max_version + params.each{|name, value| self.__send__("#{name}=", value) } + if self.verify_mode != OpenSSL::SSL::VERIFY_NONE + unless self.ca_file or self.ca_path or self.cert_store + if not defined?(Ractor) or Ractor.current == Ractor.main + self.cert_store = DEFAULT_CERT_STORE + else + self.cert_store = Ractor.current[:__openssl_default_store__] ||= + OpenSSL::X509::Store.new.tap { |store| + store.set_default_paths + } + end + end + end + return params + end + + # call-seq: + # ctx.ssl_version = :TLSv1 + # ctx.ssl_version = "SSLv23" + # + # Sets the SSL/TLS protocol version for the context. This forces + # connections to use only the specified protocol version. This is + # deprecated and only provided for backwards compatibility. Use + # #min_version= and #max_version= instead. + # + # === History + # As the name hints, this used to call the SSL_CTX_set_ssl_version() + # function which sets the SSL method used for connections created from + # the context. As of Ruby/OpenSSL 2.1, this accessor method is + # implemented to call #min_version= and #max_version= instead. + def ssl_version=(meth) + meth = meth.to_s if meth.is_a?(Symbol) + if /(?<type>_client|_server)\z/ =~ meth + meth = $` + if $VERBOSE + warn "#{caller(1, 1)[0]}: method type #{type.inspect} is ignored" + end + end + version = METHODS_MAP[meth.intern] or + raise ArgumentError, "unknown SSL method `%s'" % meth + self.min_version = self.max_version = version + end + + METHODS_MAP = { + SSLv23: 0, + SSLv2: OpenSSL::SSL::SSL2_VERSION, + SSLv3: OpenSSL::SSL::SSL3_VERSION, + TLSv1: OpenSSL::SSL::TLS1_VERSION, + TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION, + TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION, + }.freeze + private_constant :METHODS_MAP + + # The list of available SSL/TLS methods. This constant is only provided + # for backwards compatibility. + METHODS = METHODS_MAP.flat_map { |name,| + [name, :"#{name}_client", :"#{name}_server"] + }.freeze + deprecate_constant :METHODS + end + module SocketForwarder + # The file descriptor for the socket. + def fileno + to_io.fileno + end + def addr to_io.addr end @@ -29,6 +187,14 @@ module OpenSSL to_io.peeraddr end + def local_address + to_io.local_address + end + + def remote_address + to_io.remote_address + end + def setsockopt(level, optname, optval) to_io.setsockopt(level, optname, optval) end @@ -48,94 +214,329 @@ module OpenSSL def do_not_reverse_lookup=(flag) to_io.do_not_reverse_lookup = flag end + + def close_on_exec=(value) + to_io.close_on_exec = value + end + + def close_on_exec? + to_io.close_on_exec? + end + + def wait(*args) + to_io.wait(*args) + end + + def wait_readable(*args) + to_io.wait_readable(*args) + end + + def wait_writable(*args) + to_io.wait_writable(*args) + end + + if IO.method_defined?(:timeout) + def timeout + to_io.timeout + end + + def timeout=(value) + to_io.timeout=(value) + end + end end - module Nonblock - def initialize(*args) - flag = File::NONBLOCK - flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL) - @io.fcntl(Fcntl::F_SETFL, flag) - super + def verify_certificate_identity(cert, hostname) + should_verify_common_name = true + cert.extensions.each{|ext| + next if ext.oid != "subjectAltName" + ostr = OpenSSL::ASN1.decode(ext.to_der).value.last + sequence = OpenSSL::ASN1.decode(ostr.value) + sequence.value.each{|san| + case san.tag + when 2 # dNSName in GeneralName (RFC5280) + should_verify_common_name = false + return true if verify_hostname(hostname, san.value) + when 7 # iPAddress in GeneralName (RFC5280) + should_verify_common_name = false + if san.value.size == 4 || san.value.size == 16 + begin + return true if san.value == IPAddr.new(hostname).hton + rescue IPAddr::InvalidAddressError + end + end + end + } + } + if should_verify_common_name + cert.subject.to_a.each{|oid, value| + if oid == "CN" + return true if verify_hostname(hostname, value) + end + } end + return false end + module_function :verify_certificate_identity + + def verify_hostname(hostname, san) # :nodoc: + # RFC 5280, IA5String is limited to the set of ASCII characters + return false unless san.ascii_only? + return false unless hostname.ascii_only? + + # See RFC 6125, section 6.4.1 + # Matching is case-insensitive. + san_parts = san.downcase.split(".") + + # TODO: this behavior should probably be more strict + return san == hostname if san_parts.size < 2 + + # Matching is case-insensitive. + host_parts = hostname.downcase.split(".") + + # RFC 6125, section 6.4.3, subitem 2. + # If the wildcard character is the only character of the left-most + # label in the presented identifier, the client SHOULD NOT compare + # against anything but the left-most label of the reference + # identifier (e.g., *.example.com would match foo.example.com but + # not bar.foo.example.com or example.com). + return false unless san_parts.size == host_parts.size + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in + # which the wildcard character comprises a label other than the + # left-most label (e.g., do not match bar.*.example.net). + return false unless verify_wildcard(host_parts.shift, san_parts.shift) + + san_parts.join(".") == host_parts.join(".") + end + module_function :verify_hostname + + def verify_wildcard(domain_component, san_component) # :nodoc: + parts = san_component.split("*", -1) + + return false if parts.size > 2 + return san_component == domain_component if parts.size == 1 + + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + return false if domain_component.start_with?("xn--") && san_component != "*" + + parts[0].length + parts[1].length < domain_component.length && + domain_component.start_with?(parts[0]) && + domain_component.end_with?(parts[1]) + end + module_function :verify_wildcard class SSLSocket include Buffering include SocketForwarder - include Nonblock + attr_reader :hostname + + # 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 + # + # Sends "close notify" to the peer and tries to shut down the SSL + # connection gracefully. + # + # If sync_close is set to +true+, the underlying IO is also closed. + def sysclose + return if closed? + stop + io.close if sync_close + end + + # 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. def post_connection_check(hostname) - check_common_name = true - cert = peer_cert - cert.extensions.each{|ext| - next if ext.oid != "subjectAltName" - ext.value.split(/,\s+/).each{|general_name| - if /\ADNS:(.*)/ =~ general_name - check_common_name = false - reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") - return true if /\A#{reg}\z/i =~ hostname - elsif /\AIP Address:(.*)/ =~ general_name - check_common_name = false - return true if $1 == hostname - end - } - } - if check_common_name - cert.subject.to_a.each{|oid, value| - if oid == "CN" - reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") - return true if /\A#{reg}\z/i =~ hostname - end - } + 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." + end + raise SSLError, msg end - raise SSLError, "hostname was not match with the server certificate" + + unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) + raise SSLError, "hostname \"#{hostname}\" does not match the server certificate" + end + 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 nil end + + # Close the stream for reading. + # This method is ignored by OpenSSL as there is no reasonable way to + # implement it, but exists for compatibility with IO. + def close_read + # Unsupported and ignored. + # Just don't read any more. + end + + # Closes the stream for writing. The behavior of this method depends on + # the version of OpenSSL and the TLS protocol in use. + # + # - Sends a 'close_notify' alert to the peer. + # - Does not wait for the peer's 'close_notify' alert in response. + # + # In TLS 1.2 and earlier: + # - On receipt of a 'close_notify' alert, responds with a 'close_notify' + # alert of its own and close down the connection immediately, + # discarding any pending writes. + # + # Therefore, on TLS 1.2, this method will cause the connection to be + # completely shut down. On TLS 1.3, the connection will remain open for + # reading only. + def close_write + stop + end + + private + + def using_anon_cipher? + ctx = OpenSSL::SSL::SSLContext.new + ctx.ciphers = "aNULL" + ctx.ciphers.include?(cipher) + end + + def client_cert_cb + @context.client_cert_cb + end + + def session_new_cb + @context.session_new_cb + end + + def session_get_cb + @context.session_get_cb + end + + class << self + + # call-seq: + # open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil) + # + # Creates a new instance of SSLSocket. + # _remote\_host_ and _remote\_port_ are used to open TCPSocket. + # If _local\_host_ and _local\_port_ are specified, + # then those parameters are used on the local end to establish the connection. + # If _context_ is provided, + # the SSL Sockets initial params will be taken from the context. + # + # === Examples + # + # sock = OpenSSL::SSL::SSLSocket.open('localhost', 443) + # sock.connect # Initiates a connection to localhost:443 + # + # with SSLContext: + # + # ctx = OpenSSL::SSL::SSLContext.new + # sock = OpenSSL::SSL::SSLSocket.open('localhost', 443, context: ctx) + # sock.connect # Initiates a connection to localhost:443 with SSLContext + def open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil) + sock = ::TCPSocket.open(remote_host, remote_port, local_host, local_port) + if context.nil? + return OpenSSL::SSL::SSLSocket.new(sock) + else + return OpenSSL::SSL::SSLSocket.new(sock, context) + end + end + end end + ## + # SSLServer represents a TCP/IP server socket with Secure Sockets Layer. class SSLServer include SocketForwarder + # When true then #accept works exactly the same as TCPServer#accept attr_accessor :start_immediately + # Creates a new instance of SSLServer. + # * _srv_ is an instance of TCPServer. + # * _ctx_ is an instance of OpenSSL::SSL::SSLContext. def initialize(svr, ctx) @svr = svr @ctx = ctx unless ctx.session_id_context - session_id = OpenSSL::Digest::MD5.hexdigest($0) + # see #6137 - session id may not exceed 32 bytes + prng = ::Random.new($0.hash) + session_id = prng.bytes(16).unpack1('H*') @ctx.session_id_context = session_id end @start_immediately = true end + # Returns the TCPServer passed to the SSLServer when initialized. def to_io @svr end - def listen(backlog=5) + # See TCPServer#listen for details. + def listen(backlog=Socket::SOMAXCONN) @svr.listen(backlog) end + # See BasicSocket#shutdown for details. + def shutdown(how=Socket::SHUT_RDWR) + @svr.shutdown(how) + end + + # Works similar to TCPServer#accept. def accept - sock = @svr.accept + # Socket#accept returns [socket, addrinfo]. + # TCPServer#accept returns a socket. + # The following comma strips addrinfo. + sock, = @svr.accept begin ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) ssl.sync_close = true ssl.accept if @start_immediately ssl - rescue SSLError => ex - sock.close + rescue Exception => ex + if ssl + ssl.close + else + sock.close + end raise ex end end + # See IO#close for details. def close @svr.close end end end end + +end diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb new file mode 100644 index 0000000000..88570562e2 --- /dev/null +++ b/ext/openssl/lib/openssl/version.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module OpenSSL + # The version string of Ruby/OpenSSL. + VERSION = "4.0.0" +end diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb index e711bda39c..66765ffeab 100644 --- a/ext/openssl/lib/openssl/x509.rb +++ b/ext/openssl/lib/openssl/x509.rb @@ -1,20 +1,18 @@ -=begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses +# frozen_string_literal: true +#-- +# = Ruby-space definitions that completes C-space funcs for X509 and subclasses +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> +# All rights reserved. +# +# = Licence +# This program is licensed under the same licence as Ruby. +# (See the file 'COPYING'.) +#++ -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz> - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -require "openssl" +require_relative 'marshal' module OpenSSL module X509 @@ -28,7 +26,7 @@ module OpenSSL end def create_ext_from_array(ary) - raise ExtensionError, "unexpected array form" if ary.size > 3 + raise ExtensionError, "unexpected array form" if ary.size > 3 create_ext(ary[0], ary[1], ary[2]) end @@ -38,20 +36,27 @@ module OpenSSL value.strip! create_ext(oid, value) end - + def create_ext_from_hash(hash) create_ext(hash["oid"], hash["value"], hash["critical"]) end end - + class Extension + include OpenSSL::Marshal + + def ==(other) + return false unless Extension === other + to_der == other.to_der + end + def to_s # "oid = critical, value" str = self.oid str << " = " str << "critical, " if self.critical? str << self.value.gsub(/\n/, ", ") end - + def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} end @@ -59,16 +64,153 @@ module OpenSSL def to_a [ self.oid, self.value, self.critical? ] end + + module Helpers + def find_extension(oid) + extensions.find { |e| e.oid == oid } + end + end + + module SubjectKeyIdentifier + include Helpers + + # Get the subject's key identifier from the subjectKeyIdentifier + # exteension, as described in RFC5280 Section 4.2.1.2. + # + # Returns the binary String key identifier or nil or raises + # ASN1::ASN1Error. + def subject_key_identifier + ext = find_extension("subjectKeyIdentifier") + return nil if ext.nil? + + ski_asn1 = ASN1.decode(ext.value_der) + if ext.critical? || ski_asn1.tag_class != :UNIVERSAL || ski_asn1.tag != ASN1::OCTET_STRING + raise ASN1::ASN1Error, "invalid extension" + end + + ski_asn1.value + end + end + + module AuthorityKeyIdentifier + include Helpers + + # Get the issuing certificate's key identifier from the + # authorityKeyIdentifier extension, as described in RFC5280 + # Section 4.2.1.1 + # + # Returns the binary String keyIdentifier or nil or raises + # ASN1::ASN1Error. + def authority_key_identifier + ext = find_extension("authorityKeyIdentifier") + return nil if ext.nil? + + aki_asn1 = ASN1.decode(ext.value_der) + if ext.critical? || aki_asn1.tag_class != :UNIVERSAL || aki_asn1.tag != ASN1::SEQUENCE + raise ASN1::ASN1Error, "invalid extension" + end + + key_id = aki_asn1.value.find do |v| + v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0 + end + + key_id.nil? ? nil : key_id.value + end + end + + module CRLDistributionPoints + include Helpers + + # Get the distributionPoint fullName URI from the certificate's CRL + # distribution points extension, as described in RFC 5280 Section + # 4.2.1.13. + # + # Returns an array of strings or nil or raises ASN1::ASN1Error. + def crl_uris + ext = find_extension("crlDistributionPoints") + return nil if ext.nil? + + cdp_asn1 = ASN1.decode(ext.value_der) + if cdp_asn1.tag_class != :UNIVERSAL || cdp_asn1.tag != ASN1::SEQUENCE + raise ASN1::ASN1Error, "invalid extension" + end + + crl_uris = cdp_asn1.flat_map do |crl_distribution_point| + distribution_point = crl_distribution_point.value.find do |v| + v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0 + end + full_name = distribution_point&.value&.find do |v| + v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0 + end + full_name&.value&.select do |v| + v.tag_class == :CONTEXT_SPECIFIC && v.tag == 6 # uniformResourceIdentifier + end + end + + crl_uris.empty? ? nil : crl_uris.map(&:value) + end + end + + module AuthorityInfoAccess + include Helpers + + # Get the information and services for the issuer from the certificate's + # authority information access extension exteension, as described in RFC5280 + # Section 4.2.2.1. + # + # Returns an array of strings or nil or raises ASN1::ASN1Error. + def ca_issuer_uris + aia_asn1 = parse_aia_asn1 + return nil if aia_asn1.nil? + + ca_issuer = aia_asn1.value.select do |authority_info_access| + authority_info_access.value.first.value == "caIssuers" + end + + ca_issuer&.map(&:value)&.map(&:last)&.map(&:value) + end + + # Get the URIs for OCSP from the certificate's authority information access + # extension exteension, as described in RFC5280 Section 4.2.2.1. + # + # Returns an array of strings or nil or raises ASN1::ASN1Error. + def ocsp_uris + aia_asn1 = parse_aia_asn1 + return nil if aia_asn1.nil? + + ocsp = aia_asn1.value.select do |authority_info_access| + authority_info_access.value.first.value == "OCSP" + end + + ocsp&.map(&:value)&.map(&:last)&.map(&:value) + end + + private + + def parse_aia_asn1 + ext = find_extension("authorityInfoAccess") + return nil if ext.nil? + + aia_asn1 = ASN1.decode(ext.value_der) + if ext.critical? || aia_asn1.tag_class != :UNIVERSAL || aia_asn1.tag != ASN1::SEQUENCE + raise ASN1::ASN1Error, "invalid extension" + end + + aia_asn1 + end + end end class Name + include OpenSSL::Marshal + module RFC2253DN Special = ',=+<>#;' HexChar = /[0-9a-fA-F]/ HexPair = /#{HexChar}#{HexChar}/ HexString = /#{HexPair}+/ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ - StringChar = /[^#{Special}\\"]/ + StringChar = /[^\\"#{Special}]/ QuoteChar = /[^\\"]/ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ AttributeValue = / @@ -82,7 +224,8 @@ module OpenSSL def expand_pair(str) return nil unless str - return str.gsub(Pair){|pair| + return str.gsub(Pair){ + pair = $& case pair.size when 2 then pair[1,1] when 3 then Integer("0x#{pair[1,2]}").chr @@ -93,7 +236,7 @@ module OpenSSL def expand_hexstring(str) return nil unless str - der = str.gsub(HexPair){|hex| Integer("0x#{hex}").chr } + der = str.gsub(HexPair){$&.to_i(16).chr } a1 = OpenSSL::ASN1.decode(der) return a1.value, a1.tag end @@ -110,7 +253,6 @@ module OpenSSL ary = [] while true if md = TypeAndValue.match(str) - matched = md.to_s remain = md.post_match type = md[1] value, tag = expand_value(md[2], md[3], md[4]) rescue nil @@ -136,19 +278,123 @@ module OpenSSL end end - class <<self + class << self + # Parses the UTF-8 string representation of a distinguished name, + # according to RFC 2253. + # + # See also #to_utf8 for the opposite operation. def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE) ary = OpenSSL::X509::Name::RFC2253DN.scan(str) self.new(ary, template) end + # Parses the string representation of a distinguished name. Two + # different forms are supported: + # + # - \OpenSSL format (<tt>X509_NAME_oneline()</tt>) used by + # <tt>#to_s</tt>. For example: <tt>/DC=com/DC=example/CN=nobody</tt> + # - \OpenSSL format (<tt>X509_NAME_print()</tt>) + # used by <tt>#to_s(OpenSSL::X509::Name::COMPAT)</tt>. For example: + # <tt>DC=com, DC=example, CN=nobody</tt> + # + # Neither of them is standardized and has quirks and inconsistencies + # in handling of escaped characters or multi-valued RDNs. + # + # Use of this method is discouraged in new applications. See + # Name.parse_rfc2253 and #to_utf8 for the alternative. def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE) - ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) } + if str.start_with?("/") + # /A=B/C=D format + ary = str[1..-1].split("/").map { |i| i.split("=", 2) } + else + # Comma-separated + ary = str.split(",").map { |i| i.strip.split("=", 2) } + end self.new(ary, template) end alias parse parse_openssl end + + def pretty_print(q) + q.object_group(self) { + q.text ' ' + q.text to_s(OpenSSL::X509::Name::RFC2253) + } + end + end + + class Attribute + include OpenSSL::Marshal + + def ==(other) + return false unless Attribute === other + to_der == other.to_der + end + end + + class StoreContext + def cleanup + warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE + end + end + + class Certificate + include OpenSSL::Marshal + include Extension::SubjectKeyIdentifier + include Extension::AuthorityKeyIdentifier + include Extension::CRLDistributionPoints + include Extension::AuthorityInfoAccess + + def inspect + "#<#{self.class}: " \ + "subject=#{subject.inspect}, " \ + "issuer=#{issuer.inspect}, " \ + "serial=#{serial.inspect}, " \ + "not_before=#{not_before.inspect rescue "(error)"}, " \ + "not_after=#{not_after.inspect rescue "(error)"}>" + end + + def pretty_print(q) + q.object_group(self) { + q.breakable + q.text 'subject='; q.pp self.subject; q.text ','; q.breakable + q.text 'issuer='; q.pp self.issuer; q.text ','; q.breakable + q.text 'serial='; q.pp self.serial; q.text ','; q.breakable + q.text 'not_before='; q.pp self.not_before; q.text ','; q.breakable + q.text 'not_after='; q.pp self.not_after + } + end + + def self.load_file(path) + load(File.binread(path)) + end + end + + class CRL + include OpenSSL::Marshal + include Extension::AuthorityKeyIdentifier + + def ==(other) + return false unless CRL === other + to_der == other.to_der + end + end + + class Revoked + def ==(other) + return false unless Revoked === other + to_der == other.to_der + end + end + + class Request + include OpenSSL::Marshal + + def ==(other) + return false unless Request === other + to_der == other.to_der + end end end end diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec new file mode 100644 index 0000000000..7072d599d8 --- /dev/null +++ b/ext/openssl/openssl.gemspec @@ -0,0 +1,28 @@ +Gem::Specification.new do |spec| + spec.name = "openssl" + spec.version = "4.0.0" + spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"] + spec.email = ["ruby-core@ruby-lang.org"] + spec.summary = %q{SSL/TLS and general-purpose cryptography for Ruby} + spec.description = %q{OpenSSL for Ruby provides access to SSL/TLS and general-purpose cryptography based on the OpenSSL library.} + spec.homepage = "https://github.com/ruby/openssl" + spec.licenses = ["Ruby", "BSD-2-Clause"] + + if Gem::Platform === spec.platform and spec.platform =~ 'java' or RUBY_ENGINE == 'jruby' + spec.platform = "java" + spec.files = [] + spec.add_runtime_dependency('jruby-openssl', '~> 0.14') + else + spec.files = Dir.glob(["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md"], base: File.expand_path("..", __FILE__)) + + ["BSDL", "COPYING"] + spec.require_paths = ["lib"] + spec.extensions = ["ext/openssl/extconf.rb"] + end + + spec.extra_rdoc_files = Dir["*.md"] + spec.rdoc_options = ["--main", "README.md"] + + spec.required_ruby_version = ">= 2.7.0" + + spec.metadata["msys2_mingw_dependencies"] = "openssl" +end diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c deleted file mode 100644 index f77731ed65..0000000000 --- a/ext/openssl/openssl_missing.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * $Id$ - * 'OpenSSL for Ruby' project - * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> - * All rights reserved. - */ -/* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) - */ -#include RUBY_EXTCONF_H - -#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ST_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_missing.h" - -#if !defined(HAVE_HMAC_CTX_COPY) -int -HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in) -{ - if (!out || !in) return 0; - memcpy(out, in, sizeof(HMAC_CTX)); - - if (!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)) - return 0; - return 1; -} -#endif /* HAVE_HMAC_CTX_COPY */ -#endif /* NO_HMAC */ - -#if !defined(HAVE_X509_STORE_SET_EX_DATA) - -int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data) -{ - return CRYPTO_set_ex_data(&str->ex_data, idx, data); -} - -void *X509_STORE_get_ex_data(X509_STORE *str, int idx) -{ - return CRYPTO_get_ex_data(&str->ex_data, idx); -} -#endif - -#if !defined(HAVE_EVP_MD_CTX_CREATE) -EVP_MD_CTX * -EVP_MD_CTX_create(void) -{ - EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX)); - if (!ctx) return NULL; - - memset(ctx, 0, sizeof(EVP_MD_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) -void -EVP_MD_CTX_destroy(EVP_MD_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)); -} -#endif - -#if !defined(HAVE_EVP_CIPHER_CTX_COPY) -/* - * this function does not exist in OpenSSL yet... or ever?. - * a future version may break this function. - * tested on 0.9.7d. - */ -int -EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in) -{ - memcpy(out, in, sizeof(EVP_CIPHER_CTX)); - -#if defined(HAVE_ENGINE_ADD) && defined(HAVE_ST_ENGINE) - if (in->engine) ENGINE_add(out->engine); - if (in->cipher_data) { - out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size); - memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); - } -#endif - - return 1; -} -#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) -int -X509_CRL_sort(X509_CRL *c) -{ - 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 !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)); -} - -int -X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev) -{ - X509_CRL_INFO *inf; - - 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 - -#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 - -#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 (!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); - } - - return 1; -} -#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) -{ - return bn_rand_range(1, r, range); -} -#endif - -#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE) -#define OPENSSL_CONF "openssl.cnf" -char * -CONF_get1_default_config_file(void) -{ - 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; -} -#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) -{ - 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; -} -#endif - diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h index e8c75ca42c..6592f9ccea 100644 --- a/ext/openssl/openssl_missing.h +++ b/ext/openssl/openssl_missing.h @@ -1,130 +1,32 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_OPENSSL_MISSING_H_) #define _OSSL_OPENSSL_MISSING_H_ -#if defined(__cplusplus) -extern "C" { +#include "ruby/config.h" + +/* added in 3.0.0 */ +#ifndef HAVE_EVP_MD_CTX_GET0_MD +# define EVP_MD_CTX_get0_md(ctx) EVP_MD_CTX_md(ctx) #endif /* - * These functions are not included in headers of OPENSSL <= 0.9.6b + * OpenSSL 1.1.0 added EVP_MD_CTX_pkey_ctx(), and then it was renamed to + * EVP_MD_CTX_get_pkey_ctx(x) in OpenSSL 3.0. */ - -#if !defined(PEM_read_bio_DSAPublicKey) -# define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ - (char *(*)())d2i_DSAPublicKey,PEM_STRING_DSA_PUBLIC,bp,(char **)x,cb,u) -#endif - -#if !defined(PEM_write_bio_DSAPublicKey) -# define PEM_write_bio_DSAPublicKey(bp,x) \ - PEM_ASN1_write_bio((int (*)())i2d_DSAPublicKey,\ - PEM_STRING_DSA_PUBLIC,\ - bp,(char *)x, NULL, NULL, 0, NULL, NULL) -#endif - -#if !defined(DSAPrivateKey_dup) -# define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPrivateKey, \ - (char *(*)())d2i_DSAPrivateKey,(char *)dsa) -#endif - -#if !defined(DSAPublicKey_dup) -# define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPublicKey, \ - (char *(*)())d2i_DSAPublicKey,(char *)dsa) -#endif - -#if !defined(X509_REVOKED_dup) -# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((int (*)())i2d_X509_REVOKED, \ - (char *(*)())d2i_X509_REVOKED, (char *)rev) +#ifndef HAVE_EVP_MD_CTX_GET_PKEY_CTX +# define EVP_MD_CTX_get_pkey_ctx(x) EVP_MD_CTX_pkey_ctx(x) #endif -#if !defined(PKCS7_SIGNER_INFO_dup) -# define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((int (*)())i2d_PKCS7_SIGNER_INFO, \ - (char *(*)())d2i_PKCS7_SIGNER_INFO, (char *)si) +#ifndef HAVE_EVP_PKEY_EQ +# define EVP_PKEY_eq(a, b) EVP_PKEY_cmp(a, b) #endif -#if !defined(PKCS7_RECIP_INFO_dup) -# define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((int (*)())i2d_PKCS7_RECIP_INFO, \ - (char *(*)())d2i_PKCS7_RECIP_INFO, (char *)ri) -#endif - -void HMAC_CTX_init(HMAC_CTX *ctx); -int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in); -void HMAC_CTX_cleanup(HMAC_CTX *ctx); - -EVP_MD_CTX *EVP_MD_CTX_create(void); -void EVP_MD_CTX_init(EVP_MD_CTX *ctx); -int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); -void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); - -#if !defined(HAVE_EVP_CIPHER_CTX_COPY) -int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in); -#endif - -#if !defined(HAVE_EVP_DIGESTINIT_EX) -# define EVP_DigestInit_ex(ctx, md, engine) EVP_DigestInit(ctx, md) -#endif -#if !defined(HAVE_EVP_DIGESTFINAL_EX) -# define EVP_DigestFinal_ex(ctx, buf, len) EVP_DigestFinal(ctx, buf, len) -#endif - -#if !defined(HAVE_EVP_CIPHERINIT_EX) -# define EVP_CipherInit_ex(ctx, type, impl, key, iv, enc) EVP_CipherInit(ctx, type, key, iv, enc) -#endif -#if !defined(HAVE_EVP_CIPHERFINAL_EX) -# define EVP_CipherFinal_ex(ctx, outm, outl) EVP_CipherFinal(ctx, outm, outl) -#endif - -#if !defined(EVP_CIPHER_name) -# define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e)) -#endif - -#if !defined(EVP_MD_name) -# define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e)) -#endif - -#if !defined(HAVE_EVP_HMAC_INIT_EX) -# define HMAC_Init_ex(ctx, key, len, digest, engine) HMAC_Init(ctx, key, len, digest) -#endif - -#if !defined(PKCS7_is_detached) -# define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7)) -#endif - -#if !defined(PKCS7_type_is_encrypted) -# define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted) -#endif - -#if !defined(HAVE_OPENSSL_CLEANSE) -#define OPENSSL_cleanse(p, l) memset(p, 0, l) -#endif - -void *X509_STORE_get_ex_data(X509_STORE *str, int idx); -int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data); -int X509_CRL_set_version(X509_CRL *x, long version); -int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); -int X509_CRL_sort(X509_CRL *c); -int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); -int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); -int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); -int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); -int BN_rand_range(BIGNUM *r, BIGNUM *range); -int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range); -char *CONF_get1_default_config_file(void); -int PEM_def_callback(char *buf, int num, int w, void *key); - -#if defined(__cplusplus) -} -#endif - - #endif /* _OSSL_OPENSSL_MISSING_H_ */ - diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 53f476fd65..98127fcba0 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -1,238 +1,220 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" #include <stdarg.h> /* for ossl_raise */ /* - * String to HEXString conversion - */ -int -string2hex(char *buf, int buf_len, char **hexbuf, int *hexbuf_len) -{ - static const char hex[]="0123456789abcdef"; - int i, len = 2 * buf_len; - - if (buf_len < 0 || len < buf_len) { /* PARANOIA? */ - return -1; - } - 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; -} - -/* * Data Conversion */ -STACK_OF(X509) * -ossl_x509_ary2sk0(VALUE ary) -{ - STACK_OF(X509) *sk; - VALUE val; - X509 *x509; - int i; - - Check_Type(ary, T_ARRAY); - sk = sk_X509_new_null(); - if (!sk) ossl_raise(eOSSLError, NULL); - - for (i = 0; i < RARRAY_LEN(ary); i++) { - val = rb_ary_entry(ary, i); - if (!rb_obj_is_kind_of(val, cX509Cert)) { - sk_X509_pop_free(sk, X509_free); - ossl_raise(eOSSLError, "object not X509 cert in array"); - } - x509 = DupX509CertPtr(val); /* NEED TO DUP */ - sk_X509_push(sk, x509); - } - return sk; +#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \ +VALUE \ +ossl_##name##_ary2sk0(VALUE ary) \ +{ \ + STACK_OF(type) *sk; \ + VALUE val; \ + type *x; \ + int i; \ + \ + Check_Type(ary, T_ARRAY); \ + sk = sk_##type##_new_null(); \ + if (!sk) ossl_raise(eOSSLError, NULL); \ + \ + for (i = 0; i < RARRAY_LEN(ary); i++) { \ + val = rb_ary_entry(ary, i); \ + if (!rb_obj_is_kind_of(val, expected_class)) { \ + sk_##type##_pop_free(sk, type##_free); \ + ossl_raise(eOSSLError, "object in array not" \ + " of class ##type##"); \ + } \ + x = dup(val); /* NEED TO DUP */ \ + sk_##type##_push(sk, x); \ + } \ + return (VALUE)sk; \ +} \ + \ +STACK_OF(type) * \ +ossl_protect_##name##_ary2sk(VALUE ary, int *status) \ +{ \ + return (STACK_OF(type)*)rb_protect( \ + (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \ + ary, \ + status); \ +} \ + \ +STACK_OF(type) * \ +ossl_##name##_ary2sk(VALUE ary) \ +{ \ + STACK_OF(type) *sk; \ + int status = 0; \ + \ + sk = ossl_protect_##name##_ary2sk(ary, &status); \ + if (status) rb_jump_tag(status); \ + \ + return sk; \ } +OSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr) -STACK_OF(X509) * -ossl_protect_x509_ary2sk(VALUE ary, int *status) -{ - return (STACK_OF(X509)*)rb_protect((VALUE(*)_((VALUE)))ossl_x509_ary2sk0, - ary, status); -} - -STACK_OF(X509) * -ossl_x509_ary2sk(VALUE ary) -{ - STACK_OF(X509) *sk; - int status = 0; - - sk = ossl_protect_x509_ary2sk(ary, &status); - if(status) rb_jump_tag(status); - - return sk; -} - -#define OSSL_IMPL_SK2ARY(name, type) \ -VALUE \ -ossl_##name##_sk2ary(STACK *sk) \ -{ \ - type *t; \ - int i, num; \ - VALUE ary; \ - \ - if (!sk) { \ - OSSL_Debug("empty sk!"); \ - return Qnil; \ - } \ - num = sk_num(sk); \ - if (num < 0) { \ - OSSL_Debug("items in sk < -1???"); \ - return rb_ary_new(); \ - } \ - ary = rb_ary_new2(num); \ - \ - for (i=0; i<num; i++) { \ - t = (type *)sk_value(sk, i); \ - rb_ary_push(ary, ossl_##name##_new(t)); \ - } \ - return ary; \ +#define OSSL_IMPL_SK2ARY(name, type) \ +VALUE \ +ossl_##name##_sk2ary(const STACK_OF(type) *sk) \ +{ \ + type *t; \ + int i, num; \ + VALUE ary; \ + \ + RUBY_ASSERT(sk != NULL); \ + num = sk_##type##_num(sk); \ + ary = rb_ary_new_capa(num); \ + \ + for (i=0; i<num; i++) { \ + t = sk_##type##_value(sk, i); \ + rb_ary_push(ary, ossl_##name##_new(t)); \ + } \ + return ary; \ } OSSL_IMPL_SK2ARY(x509, X509) OSSL_IMPL_SK2ARY(x509crl, X509_CRL) +OSSL_IMPL_SK2ARY(x509name, X509_NAME) static VALUE -ossl_str_new(int size) +ossl_str_new_i(VALUE size) { - return rb_str_new(0, size); + return rb_str_new(NULL, (long)size); +} + +VALUE +ossl_str_new(const char *ptr, long len, int *pstate) +{ + VALUE str; + int state; + + str = rb_protect(ossl_str_new_i, len, &state); + if (pstate) + *pstate = state; + if (state) { + if (!pstate) + rb_set_errinfo(Qnil); + return Qnil; + } + if (ptr) + memcpy(RSTRING_PTR(str), ptr, len); + return str; } VALUE ossl_buf2str(char *buf, int len) { VALUE str; - int status = 0; + int state; - str = rb_protect((VALUE(*)_((VALUE)))ossl_str_new, len, &status); - if(!NIL_P(str)) memcpy(RSTRING_PTR(str), buf, len); + str = ossl_str_new(buf, len, &state); OPENSSL_free(buf); - if(status) rb_jump_tag(status); - + if (state) + rb_jump_tag(state); return str; } +void +ossl_bin2hex(const 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 */ -static VALUE -ossl_pem_passwd_cb0(VALUE flag) -{ - VALUE pass; +VALUE +ossl_pem_passwd_value(VALUE pass) +{ + if (NIL_P(pass)) + return Qnil; + + StringValue(pass); - pass = rb_yield(flag); - SafeStringValue(pass); + /* 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) +{ + VALUE pass = rb_yield(flag); + if (NIL_P(pass)) + return Qnil; + StringValue(pass); + return pass; +} + 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; - - if (pwd || !rb_block_given_p()) - return PEM_def_callback(buf, max_len, flag, pwd); + long len; + int status; + VALUE rflag, pass = (VALUE)pwd_; - while (1) { - /* - * when the flag is nonzero, this passphrase - * will be used to perform encryption; otherwise it will - * be used to perform decryption. - */ - rflag = flag ? Qtrue : Qfalse; - pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status); - if (status) return -1; /* exception was raised. */ - len = RSTRING_LEN(pass); - if (len < 4) { /* 4 is OpenSSL hardcoded limit */ - rb_warning("password must be longer than 4 bytes"); - continue; - } - if (len > max_len) { - rb_warning("password must be shorter then %d bytes", max_len-1); - continue; - } - memcpy(buf, RSTRING_PTR(pass), len); - break; + 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 <= max_len) { + memcpy(buf, RSTRING_PTR(pass), len); + return (int)len; + } + } + OSSL_Debug("passed data is not valid String???"); + return -1; } - return len; -} -/* - * Verify callback - */ -int ossl_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_verify_cb_idx); - if ((void*)proc == 0) - proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx); - if ((void*)proc == 0) - return ok; - if (!NIL_P(proc)) { - rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new, - (VALUE)ctx, &state); - ret = Qfalse; - if (!state) { - args.proc = proc; - args.preverify_ok = ok ? Qtrue : Qfalse; - args.store_ctx = rctx; - ret = rb_ensure(ossl_call_verify_cb_proc, (VALUE)&args, - 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; - } + if (!rb_block_given_p()) { + return PEM_def_callback(buf, max_len, flag, NULL); } - return ok; + while (1) { + /* + * when the flag is nonzero, this password + * will be used to perform encryption; otherwise it will + * be used to perform decryption. + */ + rflag = flag ? Qtrue : Qfalse; + pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status); + if (status) { + /* ignore an exception raised. */ + rb_set_errinfo(Qnil); + return -1; + } + if (NIL_P(pass)) + return -1; + len = RSTRING_LEN(pass); + if (len > max_len) { + rb_warning("password must not be longer than %d bytes", max_len); + continue; + } + memcpy(buf, RSTRING_PTR(pass), len); + break; + } + return (int)len; } /* @@ -248,7 +230,7 @@ VALUE eOSSLError; /* * Convert to DER string */ -ID ossl_s_to_der; +static ID ossl_s_to_der; VALUE ossl_to_der(VALUE obj) @@ -265,61 +247,158 @@ VALUE ossl_to_der_if_possible(VALUE obj) { if(rb_respond_to(obj, ossl_s_to_der)) - return ossl_to_der(obj); + return ossl_to_der(obj); return obj; } /* * Errors */ +static ID id_i_errors; + +static void collect_errors_into(VALUE ary); + +VALUE +ossl_make_error(VALUE exc, VALUE str) +{ + unsigned long e; + const char *data; + int flags; + VALUE errors = rb_ary_new(); + + if (NIL_P(str)) + str = rb_str_new(NULL, 0); + +#ifdef HAVE_ERR_GET_ERROR_ALL + e = ERR_peek_last_error_all(NULL, NULL, NULL, &data, &flags); +#else + e = ERR_peek_last_error_line_data(NULL, NULL, &data, &flags); +#endif + if (e) { + const char *msg = ERR_reason_error_string(e); + + if (RSTRING_LEN(str)) rb_str_cat_cstr(str, ": "); + rb_str_cat_cstr(str, msg ? msg : "(null)"); + if (flags & ERR_TXT_STRING && data) + rb_str_catf(str, " (%s)", data); + collect_errors_into(errors); + } + + VALUE obj = rb_exc_new_str(exc, str); + rb_ivar_set(obj, id_i_errors, errors); + return obj; +} + void ossl_raise(VALUE exc, const char *fmt, ...) { va_list args; - char buf[BUFSIZ]; - const char *msg; - long e; - int len = 0; + VALUE err; -#ifdef HAVE_ERR_PEEK_LAST_ERROR - e = ERR_peek_last_error(); -#else - e = ERR_peek_error(); -#endif if (fmt) { - va_start(args, fmt); - len = vsnprintf(buf, BUFSIZ, fmt, args); - va_end(args); + va_start(args, fmt); + err = rb_vsprintf(fmt, args); + va_end(args); } - if (len < BUFSIZ && e) { - if (dOSSL == Qtrue) /* FULL INFO */ - msg = ERR_error_string(e, NULL); - else - msg = ERR_reason_error_string(e); - fmt = len ? ": %s" : "%s"; - len += snprintf(buf+len, BUFSIZ-len, fmt, msg); + else { + err = Qnil; } - 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)); - } + + rb_exc_raise(ossl_make_error(exc, err)); +} + +static void +collect_errors_into(VALUE ary) +{ + if (dOSSL == Qtrue || !NIL_P(ary)) { + unsigned long e; + const char *file, *data, *func, *lib, *reason; + int line, flags; + +#ifdef HAVE_ERR_GET_ERROR_ALL + while ((e = ERR_get_error_all(&file, &line, &func, &data, &flags))) { +#else + while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) { + func = ERR_func_error_string(e); +#endif + lib = ERR_lib_error_string(e); + reason = ERR_reason_error_string(e); + + VALUE str = rb_sprintf("error:%08lX:%s:%s:%s", e, lib ? lib : "", + func ? func : "", reason ? reason : ""); + if (flags & ERR_TXT_STRING) { + if (!data) + data = "(null)"; + rb_str_catf(str, " (%s)", data); + } + + if (dOSSL == Qtrue) + rb_warn("error on stack: %"PRIsVALUE, str); + if (!NIL_P(ary)) + rb_ary_push(ary, str); + } + } + else { + ERR_clear_error(); } - ERR_clear_error(); +} - if(len > BUFSIZ) len = strlen(buf); - rb_exc_raise(rb_exc_new(exc, buf, len)); +void +ossl_clear_error(void) +{ + collect_errors_into(Qnil); +} + +/* + * call-seq: + * ossl_error.detailed_message(**) -> string + * + * Returns the exception message decorated with the captured \OpenSSL error + * queue entries. + */ +static VALUE +osslerror_detailed_message(int argc, VALUE *argv, VALUE self) +{ + VALUE str; +#ifdef HAVE_RB_CALL_SUPER_KW + // Ruby >= 3.2 + if (RTEST(rb_funcall(rb_eException, rb_intern("method_defined?"), 1, + ID2SYM(rb_intern("detailed_message"))))) + str = rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS); + else +#endif + str = rb_funcall(self, rb_intern("message"), 0); + VALUE errors = rb_attr_get(self, id_i_errors); + + // OpenSSLError was not created by ossl_make_error() + if (!RB_TYPE_P(errors, T_ARRAY)) + return str; + + str = rb_str_resurrect(str); + rb_str_catf(str, "\nOpenSSL error queue reported %ld errors:", + RARRAY_LEN(errors)); + for (long i = 0; i < RARRAY_LEN(errors); i++) { + VALUE err = RARRAY_AREF(errors, i); + rb_str_catf(str, "\n%"PRIsVALUE, err); + } + return str; } /* * call-seq: * OpenSSL.errors -> [String...] * - * See any remaining errors held in queue. + * Returns any remaining errors held in the \OpenSSL thread-local error queue + * and clears the queue. This should normally return an empty array. + * + * This is intended for debugging Ruby/OpenSSL. If you see any errors here, + * it likely indicates a bug in the extension. Please file an issue at + * https://github.com/ruby/openssl. * - * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation. + * For debugging your program, OpenSSL.debug= may be useful. */ -VALUE -ossl_get_errors() +static VALUE +ossl_get_errors(VALUE _) { VALUE ary; long e; @@ -337,25 +416,11 @@ ossl_get_errors() */ VALUE dOSSL; -#if !defined(HAVE_VA_ARGS_MACRO) -void -ossl_debug(const char *fmt, ...) -{ - va_list args; - - if (dOSSL == Qtrue) { - fprintf(stderr, "OSSL_DEBUG: "); - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, " [CONTEXT N/A]\n"); - } -} -#endif - /* * call-seq: * OpenSSL.debug -> true | false + * + * Returns whether Ruby/OpenSSL's debug mode is currently enabled. */ static VALUE ossl_debug_get(VALUE self) @@ -365,35 +430,572 @@ ossl_debug_get(VALUE self) /* * call-seq: - * OpenSSL.debug = boolean -> boolean + * OpenSSL.debug = 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 errors 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; } /* - * OSSL library init + * call-seq: + * OpenSSL.fips_mode -> true | false + * + * Returns whether the FIPS mode is currently enabled. + */ +static VALUE +ossl_fips_mode_get(VALUE self) +{ + +#if OSSL_OPENSSL_PREREQ(3, 0, 0) + VALUE enabled; + enabled = EVP_default_properties_is_fips_enabled(NULL) ? Qtrue : Qfalse; + return enabled; +#elif defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC) + VALUE enabled; + enabled = FIPS_mode() ? Qtrue : Qfalse; + return enabled; +#else + return Qfalse; +#endif +} + +/* + * call-seq: + * OpenSSL.fips_mode = boolean + * + * Turns FIPS mode on or off. Turning on FIPS mode will obviously only have an + * effect for FIPS-capable installations of the \OpenSSL library. Trying to do + * so otherwise will result in an error. + * + * === Examples + * 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) +{ +#if OSSL_OPENSSL_PREREQ(3, 0, 0) + if (RTEST(enabled)) { + if (!EVP_default_properties_enable_fips(NULL, 1)) { + ossl_raise(eOSSLError, "Turning on FIPS mode failed"); + } + } else { + if (!EVP_default_properties_enable_fips(NULL, 0)) { + ossl_raise(eOSSLError, "Turning off FIPS mode failed"); + } + } + return enabled; +#elif defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC) + if (RTEST(enabled)) { + int mode = FIPS_mode(); + if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */ + ossl_raise(eOSSLError, "Turning on FIPS mode failed"); + } else { + if(!FIPS_mode_set(0)) /* turning off twice is OK */ + ossl_raise(eOSSLError, "Turning off FIPS mode failed"); + } + return enabled; +#else + if (RTEST(enabled)) + ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode"); + return enabled; +#endif +} + +/* + * call-seq: + * OpenSSL.fixed_length_secure_compare(string, string) -> true or false + * + * Constant time memory comparison for fixed length strings, such as results + * of \HMAC calculations. + * + * Returns +true+ if the strings are identical, +false+ if they are of the same + * length but not identical. If the length is different, ArgumentError is + * raised. + */ +static VALUE +ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2) +{ + const unsigned char *p1 = (const unsigned char *)StringValuePtr(str1); + const unsigned char *p2 = (const unsigned char *)StringValuePtr(str2); + long len1 = RSTRING_LEN(str1); + long len2 = RSTRING_LEN(str2); + + if (len1 != len2) { + ossl_raise(rb_eArgError, "inputs must be of equal length"); + } + + switch (CRYPTO_memcmp(p1, p2, len1)) { + case 0: return Qtrue; + default: return Qfalse; + } +} + +/* + * OpenSSL provides \SSL, TLS and general purpose cryptography. It wraps the + * OpenSSL[https://www.openssl.org/] library. + * + * = Examples + * + * All examples assume you have loaded OpenSSL with: + * + * require 'openssl' + * + * These examples build atop each other. For example the key created in the + * next is used in throughout these examples. + * + * == Keys + * + * === Creating a Key + * + * This example creates a 2048 bit RSA keypair and writes it to the current + * directory. + * + * key = OpenSSL::PKey::RSA.new 2048 + * + * File.write 'private_key.pem', key.private_to_pem + * File.write 'public_key.pem', key.public_to_pem + * + * === Exporting a Key + * + * Keys saved to disk without encryption are not secure as anyone who gets + * ahold of the key may use it unless it is encrypted. In order to securely + * export a key you may export it with a password. + * + * cipher = OpenSSL::Cipher.new 'aes-256-cbc' + * password = 'my secure password goes here' + * + * key_secure = key.private_to_pem cipher, password + * + * File.write 'private.secure.pem', key_secure + * + * OpenSSL::Cipher.ciphers returns a list of available ciphers. + * + * === Loading a Key + * + * A key can also be loaded from a file. + * + * key2 = OpenSSL::PKey.read File.read 'private_key.pem' + * key2.public? # => true + * key2.private? # => true + * + * or + * + * key3 = OpenSSL::PKey.read File.read 'public_key.pem' + * key3.public? # => true + * key3.private? # => false + * + * === Loading an Encrypted Key + * + * \OpenSSL will prompt you for your password when loading an encrypted key. + * If you will not be able to type in the password you may provide it when + * loading the key: + * + * key4_pem = File.read 'private.secure.pem' + * password = 'my secure password goes here' + * key4 = OpenSSL::PKey.read key4_pem, password + * + * == RSA Encryption + * + * RSA provides encryption and decryption using the public and private keys. + * You can use a variety of padding methods depending upon the intended use of + * encrypted data. + * + * === Encryption & Decryption + * + * Asymmetric public/private key encryption is slow and victim to attack in + * cases where it is used without padding or directly to encrypt larger chunks + * of data. Typical use cases for RSA encryption involve "wrapping" a symmetric + * key with the public key of the recipient who would "unwrap" that symmetric + * key again using their private key. + * The following illustrates a simplified example of such a key transport + * scheme. It shouldn't be used in practice, though, standardized protocols + * should always be preferred. + * + * wrapped_key = key.public_encrypt key + * + * A symmetric key encrypted with the public key can only be decrypted with + * the corresponding private key of the recipient. + * + * original_key = key.private_decrypt wrapped_key + * + * By default PKCS#1 padding will be used, but it is also possible to use + * other forms of padding, see PKey::RSA for further details. + * + * === Signatures + * + * Using "private_encrypt" to encrypt some data with the private key is + * equivalent to applying a digital signature to the data. A verifying + * party may validate the signature by comparing the result of decrypting + * the signature with "public_decrypt" to the original data. However, + * OpenSSL::PKey already has methods "sign" and "verify" that handle + * digital signatures in a standardized way - "private_encrypt" and + * "public_decrypt" shouldn't be used in practice. + * + * To sign a document, a cryptographically secure hash of the document is + * computed first, which is then signed using the private key. + * + * signature = key.sign 'SHA256', document + * + * To validate the signature, again a hash of the document is computed and + * the signature is decrypted using the public key. The result is then + * compared to the hash just computed, if they are equal the signature was + * valid. + * + * if key.verify 'SHA256', signature, document + * puts 'Valid' + * else + * puts 'Invalid' + * end + * + * == PBKDF2 Password-based Encryption + * + * If supported by the underlying \OpenSSL version used, Password-based + * Encryption should use the features of PKCS5. If not supported or if + * required by legacy applications, the older, less secure methods specified + * in RFC 2898 are also supported (see below). + * + * PKCS5 supports PBKDF2 as it was specified in PKCS#5 + * v2.0[http://www.rsa.com/rsalabs/node.asp?id=2127]. It still uses a + * password, a salt, and additionally a number of iterations that will + * slow the key derivation process down. The slower this is, the more work + * it requires being able to brute-force the resulting key. + * + * === Encryption + * + * The strategy is to first instantiate a Cipher for encryption, and + * then to generate a random IV plus a key derived from the password + * using PBKDF2. PKCS #5 v2.0 recommends at least 8 bytes for the salt, + * the number of iterations largely depends on the hardware being used. + * + * cipher = OpenSSL::Cipher.new 'aes-256-cbc' + * cipher.encrypt + * iv = cipher.random_iv + * + * pwd = 'some hopefully not to easily guessable password' + * salt = OpenSSL::Random.random_bytes 16 + * iter = 20000 + * key_len = cipher.key_len + * digest = OpenSSL::Digest.new('SHA256') + * + * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest) + * cipher.key = key + * + * Now encrypt the data: + * + * encrypted = cipher.update document + * encrypted << cipher.final + * + * === Decryption + * + * Use the same steps as before to derive the symmetric AES key, this time + * setting the Cipher up for decryption. + * + * cipher = OpenSSL::Cipher.new 'aes-256-cbc' + * cipher.decrypt + * cipher.iv = iv # the one generated with #random_iv + * + * pwd = 'some hopefully not to easily guessable password' + * salt = ... # the one generated above + * iter = 20000 + * key_len = cipher.key_len + * digest = OpenSSL::Digest.new('SHA256') + * + * key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest) + * cipher.key = key + * + * Now decrypt the data: + * + * decrypted = cipher.update encrypted + * decrypted << cipher.final + * + * == \X509 Certificates + * + * === Creating a Certificate + * + * 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 + * cert.version = 2 + * cert.serial = 0 + * cert.not_before = Time.now + * cert.not_after = Time.now + 3600 + * + * cert.public_key = key.public_key + * cert.subject = name + * + * === Certificate Extensions + * + * You can add extensions to the certificate with + * OpenSSL::SSL::ExtensionFactory to indicate the purpose of the certificate. + * + * extension_factory = OpenSSL::X509::ExtensionFactory.new nil, cert + * + * cert.add_extension \ + * extension_factory.create_extension('basicConstraints', 'CA:FALSE', true) + * + * cert.add_extension \ + * extension_factory.create_extension( + * 'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature') + * + * cert.add_extension \ + * extension_factory.create_extension('subjectKeyIdentifier', 'hash') + * + * The list of supported extensions (and in some cases their possible values) + * can be derived from the "objects.h" file in the \OpenSSL source code. + * + * === Signing a Certificate + * + * To sign a certificate set the issuer and use OpenSSL::X509::Certificate#sign + * with a digest algorithm. This creates a self-signed cert because we're using + * the same name and key to sign the certificate as was used to create the + * certificate. + * + * cert.issuer = name + * cert.sign key, OpenSSL::Digest.new('SHA1') + * + * open 'certificate.pem', 'w' do |io| io.write cert.to_pem end + * + * === Loading a Certificate + * + * Like a key, a cert can also be loaded from a file. + * + * cert2 = OpenSSL::X509::Certificate.new File.read 'certificate.pem' + * + * === Verifying a Certificate + * + * Certificate#verify will return true when a certificate was signed with the + * given public key. + * + * raise 'certificate can not be verified' unless cert2.verify key + * + * == Certificate Authority + * + * A certificate authority (CA) is a trusted third party that allows you to + * verify the ownership of unknown certificates. The CA issues key signatures + * that indicate it trusts the user of that key. A user encountering the key + * can verify the signature by using the CA's public key. + * + * === CA Key + * + * CA keys are valuable, so we encrypt and save it to disk and make sure it is + * not readable by other users. + * + * ca_key = OpenSSL::PKey::RSA.new 2048 + * password = 'my secure password goes here' + * + * cipher = 'aes-256-cbc' + * + * open 'ca_key.pem', 'w', 0400 do |io| + * io.write ca_key.private_to_pem(cipher, password) + * end + * + * === CA Certificate + * + * A CA certificate is created the same way we created a certificate above, but + * with different extensions. + * + * ca_name = OpenSSL::X509::Name.parse '/CN=ca/DC=example' + * + * ca_cert = OpenSSL::X509::Certificate.new + * ca_cert.serial = 0 + * ca_cert.version = 2 + * ca_cert.not_before = Time.now + * ca_cert.not_after = Time.now + 86400 + * + * ca_cert.public_key = ca_key.public_key + * ca_cert.subject = ca_name + * ca_cert.issuer = ca_name + * + * extension_factory = OpenSSL::X509::ExtensionFactory.new + * extension_factory.subject_certificate = ca_cert + * extension_factory.issuer_certificate = ca_cert + * + * ca_cert.add_extension \ + * extension_factory.create_extension('subjectKeyIdentifier', 'hash') + * + * This extension indicates the CA's key may be used as a CA. + * + * ca_cert.add_extension \ + * extension_factory.create_extension('basicConstraints', 'CA:TRUE', true) + * + * This extension indicates the CA's key may be used to verify signatures on + * both certificates and certificate revocations. + * + * ca_cert.add_extension \ + * extension_factory.create_extension( + * 'keyUsage', 'cRLSign,keyCertSign', true) + * + * Root CA certificates are self-signed. + * + * ca_cert.sign ca_key, OpenSSL::Digest.new('SHA1') + * + * The CA certificate is saved to disk so it may be distributed to all the + * users of the keys this CA will sign. + * + * open 'ca_cert.pem', 'w' do |io| + * io.write ca_cert.to_pem + * end + * + * === Certificate Signing Request + * + * The CA signs keys through a Certificate Signing Request (CSR). The CSR + * contains the information necessary to identify the key. + * + * csr = OpenSSL::X509::Request.new + * csr.version = 0 + * csr.subject = name + * csr.public_key = key.public_key + * csr.sign key, OpenSSL::Digest.new('SHA1') + * + * A CSR is saved to disk and sent to the CA for signing. + * + * open 'csr.pem', 'w' do |io| + * io.write csr.to_pem + * end + * + * === Creating a Certificate from a CSR + * + * Upon receiving a CSR the CA will verify it before signing it. A minimal + * verification would be to check the CSR's signature. + * + * csr = OpenSSL::X509::Request.new File.read 'csr.pem' + * + * raise 'CSR can not be verified' unless csr.verify csr.public_key + * + * After verification a certificate is created, marked for various usages, + * signed with the CA key and returned to the requester. + * + * csr_cert = OpenSSL::X509::Certificate.new + * csr_cert.serial = 0 + * csr_cert.version = 2 + * csr_cert.not_before = Time.now + * csr_cert.not_after = Time.now + 600 + * + * csr_cert.subject = csr.subject + * csr_cert.public_key = csr.public_key + * csr_cert.issuer = ca_cert.subject + * + * extension_factory = OpenSSL::X509::ExtensionFactory.new + * extension_factory.subject_certificate = csr_cert + * extension_factory.issuer_certificate = ca_cert + * + * csr_cert.add_extension \ + * extension_factory.create_extension('basicConstraints', 'CA:FALSE') + * + * csr_cert.add_extension \ + * extension_factory.create_extension( + * 'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature') + * + * csr_cert.add_extension \ + * extension_factory.create_extension('subjectKeyIdentifier', 'hash') + * + * csr_cert.sign ca_key, OpenSSL::Digest.new('SHA1') + * + * open 'csr_cert.pem', 'w' do |io| + * io.write csr_cert.to_pem + * end + * + * == \SSL and TLS Connections + * + * Using our created key and certificate we can create an \SSL or TLS + * connection. An OpenSSL::SSL::SSLContext is used to set up an \SSL session. + * + * context = OpenSSL::SSL::SSLContext.new + * + * === \SSL Server + * + * An \SSL server requires the certificate and private key to communicate + * securely with its clients: + * + * context.cert = cert + * context.key = key + * + * Then create an OpenSSL::SSL::SSLServer with a TCP server socket and the + * context. Use the SSLServer like an ordinary TCP server. + * + * require 'socket' + * + * tcp_server = TCPServer.new 5000 + * ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context + * + * loop do + * ssl_connection = ssl_server.accept + * + * data = ssl_connection.gets + * + * response = "I got #{data.dump}" + * puts response + * + * ssl_connection.puts "I got #{data.dump}" + * ssl_connection.close + * end + * + * === \SSL client + * + * An \SSL client is created with a TCP socket and the context. + * OpenSSL::SSL::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 OpenSSL::SSL::SSLSocket#close doesn't close the underlying socket + * by default. Set OpenSSL::SSL::SSLSocket#sync_close to true if you want. + * + * require 'socket' + * + * 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 + * security the client or server can verify the certificate of its peer. + * + * The client can be modified to verify the server's certificate against the + * certificate authority's certificate: + * + * context.ca_file = 'ca_cert.pem' + * context.verify_mode = OpenSSL::SSL::VERIFY_PEER + * + * require 'socket' + * + * tcp_socket = TCPSocket.new 'localhost', 5000 + * ssl_client = OpenSSL::SSL::SSLSocket.new tcp_socket, context + * ssl_client.connect + * + * ssl_client.puts "hello server!" + * puts ssl_client.gets + * + * If the server certificate is invalid or <tt>context.ca_file</tt> is not set + * when verifying peers an OpenSSL::SSL::SSLError will be raised. + * */ void -Init_openssl() +Init_openssl(void) { +#ifdef HAVE_RB_EXT_RACTOR_SAFE + rb_ext_ractor_safe(true); +#endif + +#undef rb_intern /* * Init timezone info */ @@ -404,55 +1006,116 @@ Init_openssl() /* * Init all digests, ciphers */ - /* CRYPTO_malloc_init(); */ - /* ENGINE_load_builtin_engines(); */ - OpenSSL_add_ssl_algorithms(); - OpenSSL_add_all_algorithms(); - ERR_load_crypto_strings(); - SSL_load_error_strings(); + if (!OPENSSL_init_ssl(0, NULL)) + rb_raise(rb_eRuntimeError, "OPENSSL_init_ssl"); /* - * FIXME: - * On unload do: + * Init main module */ -#if 0 - CONF_modules_unload(1); - destroy_ui_method(); - EVP_cleanup(); - ENGINE_cleanup(); - CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); - ERR_free_strings(); -#endif + rb_global_variable(&mOSSL); + mOSSL = rb_define_module("OpenSSL"); + rb_define_singleton_method(mOSSL, "fixed_length_secure_compare", ossl_crypto_fixed_length_secure_compare, 2); /* - * Init main module + * \OpenSSL library version string used to compile the Ruby/OpenSSL + * extension. This may differ from the version used at runtime. */ - mOSSL = rb_define_module("OpenSSL"); + rb_define_const(mOSSL, "OPENSSL_VERSION", + rb_obj_freeze(rb_str_new_cstr(OPENSSL_VERSION_TEXT))); /* - * Constants + * \OpenSSL library version string currently used at runtime. + */ + rb_define_const( + mOSSL, + "OPENSSL_LIBRARY_VERSION", + rb_obj_freeze(rb_str_new_cstr(OpenSSL_version(OPENSSL_VERSION))) + ); + + /* + * \OpenSSL library version number used to compile the Ruby/OpenSSL + * extension. This may differ from the version used at runtime. + * + * The version number is encoded into a single integer value. The number + * follows the format: + * + * [\OpenSSL 3.0.0 or later] + * <tt>0xMNN00PP0</tt> (major minor 00 patch 0) + * [\OpenSSL 1.1.1 or earlier] + * <tt>0xMNNFFPPS</tt> (major minor fix patch status) + * [LibreSSL] + * <tt>0x20000000</tt> (a fixed value) + * + * See also the man page OPENSSL_VERSION_NUMBER(3). */ - rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION)); - rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT)); rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER)); +#if defined(LIBRESSL_VERSION_NUMBER) + /* + * LibreSSL library version number used to compile the Ruby/OpenSSL + * extension. This may differ from the version used at runtime. + * + * This constant is only defined if the extension was compiled against + * LibreSSL. The number follows the format: + * <tt>0xMNNFF00f</tt> (major minor fix 00 status). + * + * See also the man page LIBRESSL_VERSION_NUMBER(3). + */ + rb_define_const(mOSSL, "LIBRESSL_VERSION_NUMBER", INT2NUM(LIBRESSL_VERSION_NUMBER)); +#endif + /* - * Generic error, - * common for all classes under OpenSSL module + * Boolean indicating whether the \OpenSSL library is FIPS-capable or not. + * Always <tt>true</tt> for \OpenSSL 3.0 and later. + * + * This is obsolete and will be removed in the future. + * See also OpenSSL.fips_mode. */ - eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError); + rb_define_const(mOSSL, "OPENSSL_FIPS", +/* OpenSSL 3 is FIPS-capable even when it is installed without fips option */ +#if OSSL_OPENSSL_PREREQ(3, 0, 0) + Qtrue +#elif defined(OPENSSL_FIPS) + Qtrue +#elif defined(OPENSSL_IS_AWSLC) // AWS-LC FIPS can only be enabled during compile time. + FIPS_mode() ? Qtrue : Qfalse +#else + Qfalse +#endif + ); + + rb_define_module_function(mOSSL, "fips_mode", ossl_fips_mode_get, 0); + rb_define_module_function(mOSSL, "fips_mode=", ossl_fips_mode_set, 1); + rb_global_variable(&eOSSLError); /* - * Verify callback Proc index for ext-data + * Generic error class for OpenSSL. All error classes in this library + * inherit from this class. + * + * This class indicates that an error was reported by the underlying + * \OpenSSL library. */ - if ((ossl_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0)) < 0) - ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); + eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); + /* + * \OpenSSL error queue entries captured at the time the exception was + * raised. The same information is printed to stderr if OpenSSL.debug is + * set to +true+. + * + * This is an array of zero or more strings, ordered from the oldest to the + * newest. The format of the strings is not stable and may vary across + * versions of \OpenSSL or versions of this Ruby extension. + * + * See also the man page ERR_get_error(3). + */ + rb_attr(eOSSLError, rb_intern_const("errors"), 1, 0, 0); + rb_define_method(eOSSLError, "detailed_message", osslerror_detailed_message, -1); /* * Init debug core */ dOSSL = Qfalse; + rb_global_variable(&dOSSL); + rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0); rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1); rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0); @@ -461,36 +1124,27 @@ Init_openssl() * Get ID of to_der */ ossl_s_to_der = rb_intern("to_der"); + id_i_errors = rb_intern("@errors"); /* * Init components */ + Init_ossl_asn1(); Init_ossl_bn(); Init_ossl_cipher(); Init_ossl_config(); Init_ossl_digest(); + Init_ossl_engine(); Init_ossl_hmac(); + Init_ossl_kdf(); Init_ossl_ns_spki(); + Init_ossl_ocsp(); Init_ossl_pkcs12(); Init_ossl_pkcs7(); - Init_ossl_pkcs5(); Init_ossl_pkey(); + Init_ossl_provider(); Init_ossl_rand(); Init_ossl_ssl(); + Init_ossl_ts(); Init_ossl_x509(); - Init_ossl_ocsp(); - Init_ossl_engine(); - Init_ossl_asn1(); -} - -#if defined(OSSL_DEBUG) -/* - * Check if all symbols are OK with 'make LDSHARED=gcc all' - */ -int -main(int argc, char *argv[], char *env[]) -{ - return 0; } -#endif /* OSSL_DEBUG */ - diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index a4bc661eb1..0b479a7200 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -1,74 +1,82 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_H_) #define _OSSL_H_ #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 <ruby.h> -#include <rubyio.h> - -/* - * Check the OpenSSL version - * The only supported are: - * OpenSSL >= 0.9.7 - */ -#include <openssl/opensslv.h> - -#ifdef HAVE_ASSERT_H -# include <assert.h> +#include <errno.h> +#include <ruby/io.h> +#include <ruby/thread.h> +#ifdef HAVE_RUBY_RACTOR_H +#include <ruby/ractor.h> #else -# define assert(condition) +#define RUBY_TYPED_FROZEN_SHAREABLE 0 #endif -#if defined(_WIN32) -# define OSSL_NO_CONF_API 1 -# include <winsock2.h> -#endif -#include <errno.h> +#include <openssl/opensslv.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> #include <openssl/pkcs7.h> -#include <openssl/hmac.h> #include <openssl/rand.h> #include <openssl/conf.h> -#include <openssl/conf_api.h> -#undef X509_NAME -#undef PKCS7_SIGNER_INFO -#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ST_ENGINE) -# define OSSL_ENGINE_ENABLED -# include <openssl/engine.h> +#ifndef OPENSSL_NO_TS + #include <openssl/ts.h> #endif -#if defined(HAVE_OPENSSL_OCSP_H) -# define OSSL_OCSP_ENABLED +#include <openssl/crypto.h> +#if !defined(OPENSSL_NO_OCSP) # include <openssl/ocsp.h> #endif +#include <openssl/bn.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#include <openssl/evp.h> +#include <openssl/dh.h> +#include "openssl_missing.h" + +#ifndef LIBRESSL_VERSION_NUMBER +# define OSSL_IS_LIBRESSL 0 +# define OSSL_OPENSSL_PREREQ(maj, min, pat) \ + (OPENSSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12))) +# define OSSL_LIBRESSL_PREREQ(maj, min, pat) 0 +#else +# define OSSL_IS_LIBRESSL 1 +# define OSSL_OPENSSL_PREREQ(maj, min, pat) 0 +# define OSSL_LIBRESSL_PREREQ(maj, min, pat) \ + (LIBRESSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12))) +#endif + +#if OSSL_OPENSSL_PREREQ(3, 0, 0) +# define OSSL_3_const const +#else +# define OSSL_3_const /* const */ +#endif + +#if !defined(OPENSSL_NO_ENGINE) && !OSSL_OPENSSL_PREREQ(3, 0, 0) +# define OSSL_USE_ENGINE +#endif + +#if OSSL_OPENSSL_PREREQ(3, 0, 0) +# define OSSL_USE_PROVIDER +# include <openssl/provider.h> +#endif + +#if OSSL_OPENSSL_PREREQ(3, 0, 0) +# define OSSL_HAVE_IMMUTABLE_PKEY +#endif /* * Common Module @@ -84,76 +92,79 @@ extern VALUE eOSSLError; * CheckTypes */ #define OSSL_Check_Kind(obj, klass) do {\ - if (!rb_obj_is_kind_of(obj, klass)) {\ - ossl_raise(rb_eTypeError, "wrong argument (%s)! (Expected kind of %s)",\ - rb_obj_classname(obj), rb_class2name(klass));\ - }\ -} while (0) - -#define OSSL_Check_Instance(obj, klass) do {\ - if (!rb_obj_is_instance_of(obj, klass)) {\ - ossl_raise(rb_eTypeError, "wrong argument (%s)! (Expected instance of %s)",\ - rb_obj_classname(obj), rb_class2name(klass));\ - }\ -} while (0) - -#define OSSL_Check_Same_Class(obj1, obj2) do {\ - if (!rb_obj_is_instance_of(obj1, rb_obj_class(obj2))) {\ - ossl_raise(rb_eTypeError, "wrong argument type");\ - }\ + if (!rb_obj_is_kind_of((obj), (klass))) {\ + ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %"PRIsVALUE")",\ + rb_obj_class(obj), (klass));\ + }\ } while (0) /* - * String to HEXString conversion + * Type conversions */ -int string2hex(char *, int, char **, int *); +#if !defined(NUM2UINT64T) /* in case Ruby starts to provide */ +# if SIZEOF_LONG == 8 +# define NUM2UINT64T(x) ((uint64_t)NUM2ULONG(x)) +# elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 +# define NUM2UINT64T(x) ((uint64_t)NUM2ULL(x)) +# else +# error "unknown platform; no 64-bit width integer" +# endif +#endif /* * 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_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); +VALUE ossl_str_new(const char *, long, int *); #define ossl_str_adjust(str, p) \ do{\ - int len = RSTRING_LEN(str);\ - int newlen = (p) - (unsigned char*)RSTRING_PTR(str);\ - assert(newlen <= len);\ - rb_str_set_len(str, newlen);\ + long newlen = (long)((p) - (unsigned char*)RSTRING_PTR(str));\ + assert(newlen <= RSTRING_LEN(str));\ + 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(const 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 *); /* - * ERRor messages + * Clear BIO* with this in PEM/DER fallback scenarios to avoid decoding + * errors piling up in OpenSSL::Errors */ -#define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error()) -NORETURN(void ossl_raise(VALUE, const char *, ...)); +#define OSSL_BIO_reset(bio) do { \ + (void)BIO_reset((bio)); \ + ossl_clear_error(); \ +} while (0) /* - * Verify callback + * ERRor messages */ -extern int ossl_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 *); +PRINTF_ARGS(NORETURN(void ossl_raise(VALUE, const char *, ...)), 2, 3); +/* Make exception instance from str and OpenSSL error reason string. */ +VALUE ossl_make_error(VALUE exc, VALUE str); +/* Clear OpenSSL error queue. If dOSSL is set, rb_warn() them. */ +void ossl_clear_error(void); /* * String to DER String */ -extern ID ossl_s_to_der; VALUE ossl_to_der(VALUE); VALUE ossl_to_der_if_possible(VALUE); @@ -162,60 +173,37 @@ VALUE ossl_to_der_if_possible(VALUE); */ extern VALUE dOSSL; -#if defined(HAVE_VA_ARGS_MACRO) -#define OSSL_Debug(fmt, ...) do { \ - if (dOSSL == Qtrue) { \ - fprintf(stderr, "OSSL_DEBUG: "); \ - fprintf(stderr, fmt, ##__VA_ARGS__); \ - fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \ - } \ -} while (0) - -#define OSSL_Warning(fmt, ...) do { \ - OSSL_Debug(fmt, ##__VA_ARGS__); \ - rb_warning(fmt, ##__VA_ARGS__); \ +#define OSSL_Debug(...) do { \ + if (dOSSL == Qtrue) { \ + fprintf(stderr, "OSSL_DEBUG: "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \ + } \ } while (0) -#define OSSL_Warn(fmt, ...) do { \ - OSSL_Debug(fmt, ##__VA_ARGS__); \ - rb_warn(fmt, ##__VA_ARGS__); \ -} while (0) -#else -void ossl_debug(const char *, ...); -#define OSSL_Debug ossl_debug -#define OSSL_Warning rb_warning -#define OSSL_Warn rb_warn -#endif - /* * Include all parts */ -#include "openssl_missing.h" -#include "ruby_missing.h" #include "ossl_asn1.h" #include "ossl_bio.h" #include "ossl_bn.h" #include "ossl_cipher.h" #include "ossl_config.h" #include "ossl_digest.h" +#include "ossl_engine.h" #include "ossl_hmac.h" +#include "ossl_kdf.h" #include "ossl_ns_spki.h" #include "ossl_ocsp.h" #include "ossl_pkcs12.h" #include "ossl_pkcs7.h" -#include "ossl_pkcs5.h" #include "ossl_pkey.h" +#include "ossl_provider.h" #include "ossl_rand.h" #include "ossl_ssl.h" -#include "ossl_version.h" +#include "ossl_ts.h" #include "ossl_x509.h" -#include "ossl_engine.h" 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 8ceea95021..71a87f0463 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -1,194 +1,211 @@ /* - * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #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 +/********/ +/* + * ASN1 module + */ +#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE) +#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG) +#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING) +#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS) +#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH) + +#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v)) +#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v)) +#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v)) +#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v)) +#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v)) + +VALUE mASN1; +static VALUE eASN1Error; + +VALUE cASN1Data; +static VALUE cASN1Primitive; +static VALUE cASN1Constructive; + +static VALUE cASN1EndOfContent; +static VALUE cASN1Boolean; /* BOOLEAN */ +static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */ +static VALUE cASN1BitString; /* BIT STRING */ +static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */ +static VALUE cASN1NumericString, cASN1PrintableString; +static VALUE cASN1T61String, cASN1VideotexString; +static VALUE cASN1IA5String, cASN1GraphicString; +static VALUE cASN1ISO64String, cASN1GeneralString; +static VALUE cASN1UniversalString, cASN1BMPString; +static VALUE cASN1Null; /* NULL */ +static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */ +static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */ +static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */ + +static VALUE sym_IMPLICIT, sym_EXPLICIT; +static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE; +static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS; +static ID id_each; /* * DATE conversion */ +static VALUE +time_utc_new(VALUE args) +{ + return rb_funcallv(rb_cTime, rb_intern("utc"), 6, (VALUE *)args); +} + +static VALUE +time_utc_new_rescue(VALUE args, VALUE exc) +{ + rb_raise(eASN1Error, "invalid time"); +} + VALUE -asn1time_to_time(ASN1_TIME *time) +asn1time_to_time(const ASN1_TIME *time) { struct tm tm; - VALUE argv[6]; - - if (!time || !time->data) return Qnil; - memset(&tm, 0, sizeof(struct tm)); - - switch (time->type) { - case V_ASN1_UTCTIME: - if (sscanf(time->data, "%2d%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 UTCTIME format"); - } - if (tm.tm_year < 69) { - tm.tm_year += 2000; - } else { - tm.tm_year += 1900; - } - break; - case V_ASN1_GENERALIZEDTIME: - if (sscanf(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" ); - } - break; - default: - rb_warning("unknown time format"); - return Qnil; - } - argv[0] = INT2NUM(tm.tm_year); - argv[1] = INT2NUM(tm.tm_mon); - argv[2] = INT2NUM(tm.tm_mday); - argv[3] = INT2NUM(tm.tm_hour); - argv[4] = INT2NUM(tm.tm_min); - argv[5] = INT2NUM(tm.tm_sec); - - return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv); + if (!ASN1_TIME_to_tm(time, &tm)) + ossl_raise(eASN1Error, "ASN1_TIME_to_tm"); + + VALUE args[] = { + INT2NUM(tm.tm_year + 1900), + INT2NUM(tm.tm_mon + 1), + INT2NUM(tm.tm_mday), + INT2NUM(tm.tm_hour), + INT2NUM(tm.tm_min), + INT2NUM(tm.tm_sec), + }; + return rb_rescue2(time_utc_new, (VALUE)args, time_utc_new_rescue, Qnil, + rb_eArgError, 0); } -/* - * This function is not exported in Ruby's *.h - */ -extern struct timeval rb_time_timeval(VALUE); +static VALUE +asn1time_to_time_i(VALUE arg) +{ + return asn1time_to_time((ASN1_TIME *)arg); +} -time_t -time_to_time_t(VALUE time) +void +ossl_time_split(VALUE time, time_t *sec, int *days) { - return (time_t)NUM2LONG(rb_Integer(time)); + 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))); + } } /* * STRING conversion */ VALUE -asn1str_to_str(ASN1_STRING *str) +asn1str_to_str(const ASN1_STRING *str) { - return rb_str_new(str->data, str->length); + return rb_str_new((const char *)ASN1_STRING_get0_data(str), + ASN1_STRING_length(str)); } /* * 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!"); + 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); - ossl_raise(eOSSLError, NULL); - } - num = rb_cstr_to_inum(txt, 10, Qtrue); - OPENSSL_free(txt); -#else + if (ASN1_STRING_type(ai) == V_ASN1_ENUMERATED) + bn = ASN1_ENUMERATED_to_BN(ai, NULL); + else + bn = ASN1_INTEGER_to_BN(ai, NULL); + + if (!bn) + ossl_raise(eOSSLError, NULL); 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); + BIGNUM *bn; + + if (NIL_P(obj)) + ossl_raise(rb_eTypeError, "Can't convert nil into Integer"); + + bn = GetBNPtr(obj); + + if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) + ossl_raise(eOSSLError, NULL); + return ai; } -#else -ASN1_INTEGER * -num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) + +static VALUE +asn1integer_to_num_i(VALUE arg) { - BIGNUM *bn = GetBNPtr(obj); - - if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) { - ossl_raise(eOSSLError, NULL); - } - return ai; + return asn1integer_to_num((ASN1_INTEGER *)arg); } -#endif -/********/ /* - * ASN1 module + * ASN1_OBJECT conversions */ -#define ossl_asn1_get_value(o) rb_attr_get((o),rb_intern("@value")) -#define ossl_asn1_get_tag(o) rb_attr_get((o),rb_intern("@tag")) -#define ossl_asn1_get_tagging(o) rb_attr_get((o),rb_intern("@tagging")) -#define ossl_asn1_get_tag_class(o) rb_attr_get((o),rb_intern("@tag_class")) - -#define ossl_asn1_set_value(o,v) rb_iv_set((o),"@value",(v)) -#define ossl_asn1_set_tag(o,v) rb_iv_set((o),"@tag",(v)) -#define ossl_asn1_set_tagging(o,v) rb_iv_set((o),"@tagging",(v)) -#define ossl_asn1_set_tag_class(o,v) rb_iv_set((o),"@tag_class",(v)) +VALUE +ossl_asn1obj_to_string_oid(const ASN1_OBJECT *a1obj) +{ + VALUE str; + int len; + + str = rb_usascii_str_new(NULL, 127); + len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1); + if (len <= 0 || len == INT_MAX) + ossl_raise(eOSSLError, "OBJ_obj2txt"); + if (len > RSTRING_LEN(str)) { + /* +1 is for the \0 terminator added by OBJ_obj2txt() */ + rb_str_resize(str, len + 1); + len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1); + if (len <= 0) + ossl_raise(eOSSLError, "OBJ_obj2txt"); + } + rb_str_set_len(str, len); + return str; +} -VALUE mASN1; -VALUE eASN1Error; +VALUE +ossl_asn1obj_to_string(const ASN1_OBJECT *obj) +{ + int nid = OBJ_obj2nid(obj); + if (nid != NID_undef) + return rb_str_new_cstr(OBJ_nid2sn(nid)); + return ossl_asn1obj_to_string_oid(obj); +} -VALUE cASN1Data; -VALUE cASN1Primitive; -VALUE cASN1Constructive; - -VALUE cASN1Boolean; /* BOOLEAN */ -VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */ -VALUE cASN1BitString; /* BIT STRING */ -VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */ -VALUE cASN1NumericString, cASN1PrintableString; -VALUE cASN1T61String, cASN1VideotexString; -VALUE cASN1IA5String, cASN1GraphicString; -VALUE cASN1ISO64String, cASN1GeneralString; -VALUE cASN1UniversalString, cASN1BMPString; -VALUE cASN1Null; /* NULL */ -VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */ -VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */ -VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */ - -static ID sIMPLICIT, sEXPLICIT; -static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE; +VALUE +ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj) +{ + int nid = OBJ_obj2nid(obj); + if (nid != NID_undef) + return rb_str_new_cstr(OBJ_nid2ln(nid)); + return ossl_asn1obj_to_string_oid(obj); +} /* * Ruby to ASN1 converters @@ -196,7 +213,10 @@ static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE; static ASN1_BOOLEAN obj_to_asn1bool(VALUE obj) { - return RTEST(obj) ? 0xff : 0x100; + if (NIL_P(obj)) + ossl_raise(rb_eTypeError, "Can't convert nil into Boolean"); + + return RTEST(obj) ? 0xff : 0x0; } static ASN1_INTEGER* @@ -210,13 +230,15 @@ obj_to_asn1bstr(VALUE obj, long unused_bits) { ASN1_BIT_STRING *bstr; - if(unused_bits < 0) unused_bits = 0; + if (unused_bits < 0 || unused_bits > 7) + ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\ + "the range 0 to 7"); StringValue(obj); if(!(bstr = ASN1_BIT_STRING_new())) - ossl_raise(eASN1Error, NULL); - ASN1_BIT_STRING_set(bstr, RSTRING_PTR(obj), RSTRING_LEN(obj)); + ossl_raise(eASN1Error, NULL); + ASN1_BIT_STRING_set(bstr, (unsigned char *)RSTRING_PTR(obj), RSTRING_LENINT(obj)); bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */ - bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT|(unused_bits&0x07); + bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits; return bstr; } @@ -228,8 +250,8 @@ obj_to_asn1str(VALUE obj) StringValue(obj); if(!(str = ASN1_STRING_new())) - ossl_raise(eASN1Error, NULL); - ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LEN(obj)); + ossl_raise(eASN1Error, NULL); + ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj)); return str; } @@ -240,47 +262,51 @@ obj_to_asn1null(VALUE obj) ASN1_NULL *null; if(!NIL_P(obj)) - ossl_raise(eASN1Error, "nil expected"); + ossl_raise(eASN1Error, "nil expected"); if(!(null = ASN1_NULL_new())) - ossl_raise(eASN1Error, NULL); + ossl_raise(eASN1Error, NULL); return null; } -static ASN1_OBJECT* -obj_to_asn1obj(VALUE obj) +ASN1_OBJECT * +ossl_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; - sec = time_to_time_t(time); - if(!(t = ASN1_UTCTIME_set(NULL, sec))) + int off_days; + + ossl_time_split(time, &sec, &off_days); + if (!(t = ASN1_UTCTIME_adj(NULL, sec, off_days, 0))) ossl_raise(eASN1Error, NULL); return t; } -static ASN1_GENERALIZEDTIME* +static ASN1_GENERALIZEDTIME * obj_to_asn1gtime(VALUE time) { time_t sec; ASN1_GENERALIZEDTIME *t; - sec = time_to_time_t(time); - if(!(t =ASN1_GENERALIZEDTIME_set(NULL, sec))) + int off_days; + + ossl_time_split(time, &sec, &off_days); + if (!(t = ASN1_GENERALIZEDTIME_adj(NULL, sec, off_days, 0))) ossl_raise(eASN1Error, NULL); return t; @@ -294,8 +320,8 @@ obj_to_asn1derstr(VALUE obj) str = ossl_to_der(obj); if(!(a1str = ASN1_STRING_new())) - ossl_raise(eASN1Error, NULL); - ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LEN(str)); + ossl_raise(eASN1Error, NULL); + ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str)); return a1str; } @@ -304,31 +330,31 @@ obj_to_asn1derstr(VALUE obj) * DER to Ruby converters */ static VALUE -decode_bool(unsigned char* der, int length) +decode_bool(unsigned char* der, long length) { - int bool; - unsigned char *p; + const unsigned char *p = der; - p = der; - if((bool = 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 bool ? Qtrue : Qfalse; + return p[2] ? Qtrue : Qfalse; } static VALUE -decode_int(unsigned char* der, int length) +decode_int(unsigned char* der, long length) { ASN1_INTEGER *ai; - unsigned char *p; - VALUE ret; + const unsigned char *p; + VALUE ret; int status = 0; p = der; if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length))) - ossl_raise(eASN1Error, NULL); - ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num, - (VALUE)ai, &status); + ossl_raise(eASN1Error, NULL); + ret = rb_protect(asn1integer_to_num_i, + (VALUE)ai, &status); ASN1_INTEGER_free(ai); if(status) rb_jump_tag(status); @@ -336,44 +362,39 @@ decode_int(unsigned char* der, int length) } static VALUE -decode_bstr(unsigned char* der, int length, long *unused_bits) +decode_bstr(unsigned char* der, long length, long *unused_bits) { ASN1_BIT_STRING *bstr; - unsigned char *p, *buf; + const unsigned char *p; long len; VALUE ret; p = der; if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length))) - ossl_raise(eASN1Error, NULL); + ossl_raise(eASN1Error, NULL); len = bstr->length; - if(!(buf = OPENSSL_malloc(len))){ - ASN1_BIT_STRING_free(bstr); - ossl_raise(eASN1Error, NULL); - } *unused_bits = 0; if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT) - *unused_bits = bstr->flags & 0x07; - memcpy(buf, bstr->data, len); + *unused_bits = bstr->flags & 0x07; + ret = rb_str_new((const char *)bstr->data, len); ASN1_BIT_STRING_free(bstr); - ret = ossl_buf2str(buf, len); return ret; } static VALUE -decode_enum(unsigned char* der, int length) +decode_enum(unsigned char* der, long length) { ASN1_ENUMERATED *ai; - unsigned char *p; - VALUE ret; + const unsigned char *p; + VALUE ret; int status = 0; p = der; if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length))) - ossl_raise(eASN1Error, NULL); - ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num, - (VALUE)ai, &status); + ossl_raise(eASN1Error, NULL); + ret = rb_protect(asn1integer_to_num_i, + (VALUE)ai, &status); ASN1_ENUMERATED_free(ai); if(status) rb_jump_tag(status); @@ -381,67 +402,71 @@ decode_enum(unsigned char* der, int length) } static VALUE -decode_null(unsigned char* der, int length) +decode_null(unsigned char* der, long length) { ASN1_NULL *null; - unsigned char *p; + const unsigned char *p; p = der; if(!(null = d2i_ASN1_NULL(NULL, &p, length))) - ossl_raise(eASN1Error, NULL); + ossl_raise(eASN1Error, NULL); ASN1_NULL_free(null); return Qnil; } +VALUE +asn1obj_to_string_i(VALUE arg) +{ + return ossl_asn1obj_to_string((const ASN1_OBJECT *)arg); +} + static VALUE -decode_obj(unsigned char* der, int length) +decode_obj(unsigned char* der, long length) { ASN1_OBJECT *obj; - unsigned char *p; + const unsigned char *p; VALUE ret; - int nid; - BIO *bio; + int state; p = der; - if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length))) - ossl_raise(eASN1Error, NULL); - if((nid = OBJ_obj2nid(obj)) != NID_undef){ - ASN1_OBJECT_free(obj); - ret = rb_str_new2(OBJ_nid2sn(nid)); - } - else{ - if(!(bio = BIO_new(BIO_s_mem()))){ - ASN1_OBJECT_free(obj); - ossl_raise(eASN1Error, NULL); - } - i2a_ASN1_OBJECT(bio, obj); - ASN1_OBJECT_free(obj); - ret = ossl_membio2str(bio); - } - + if (!(obj = d2i_ASN1_OBJECT(NULL, &p, length))) + ossl_raise(eASN1Error, "d2i_ASN1_OBJECT"); + ret = rb_protect(asn1obj_to_string_i, (VALUE)obj, &state); + ASN1_OBJECT_free(obj); + if (state) + rb_jump_tag(state); return ret; } static VALUE -decode_time(unsigned char* der, int length) +decode_time(unsigned char* der, long length) { ASN1_TIME *time; - unsigned char *p; + const unsigned char *p; VALUE ret; int status = 0; p = der; if(!(time = d2i_ASN1_TIME(NULL, &p, length))) - ossl_raise(eASN1Error, NULL); - ret = rb_protect((VALUE(*)_((VALUE)))asn1time_to_time, - (VALUE)time, &status); + ossl_raise(eASN1Error, NULL); + ret = rb_protect(asn1time_to_time_i, + (VALUE)time, &status); ASN1_TIME_free(time); if(status) rb_jump_tag(status); return ret; } +static VALUE +decode_eoc(unsigned char *der, long length) +{ + if (length != 2 || !(der[0] == 0x00 && der[1] == 0x00)) + ossl_raise(eASN1Error, NULL); + + return rb_str_new("", 0); +} + /********/ typedef struct { @@ -449,8 +474,8 @@ typedef struct { VALUE *klass; } ossl_asn1_info_t; -static ossl_asn1_info_t ossl_asn1_info[] = { - { "EOC", NULL, }, /* 0 */ +static const ossl_asn1_info_t ossl_asn1_info[] = { + { "EOC", &cASN1EndOfContent, }, /* 0 */ { "BOOLEAN", &cASN1Boolean, }, /* 1 */ { "INTEGER", &cASN1Integer, }, /* 2 */ { "BIT_STRING", &cASN1BitString, }, /* 3 */ @@ -483,79 +508,81 @@ static ossl_asn1_info_t ossl_asn1_info[] = { { "BMPSTRING", &cASN1BMPString, }, /* 30 */ }; -int ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0])); +enum {ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0]))}; + +static VALUE class_tag_map; static int ossl_asn1_default_tag(VALUE obj); -ASN1_TYPE* +static ASN1_TYPE * ossl_asn1_get_asn1type(VALUE obj) { ASN1_TYPE *ret; VALUE value, rflag; void *ptr; - void (*free_func)(); - long tag, flag; + typedef void free_func_type(void *); + free_func_type *free_func; + int tag; tag = ossl_asn1_default_tag(obj); value = ossl_asn1_get_value(obj); switch(tag){ - case V_ASN1_BOOLEAN: - ptr = (void*)obj_to_asn1bool(value); - free_func = NULL; - break; - case V_ASN1_INTEGER: /* FALLTHROUGH */ - case V_ASN1_ENUMERATED: - ptr = obj_to_asn1int(value); - free_func = ASN1_INTEGER_free; - break; - case V_ASN1_BIT_STRING: - rflag = rb_attr_get(obj, rb_intern("@unused_bits")); - flag = NIL_P(rflag) ? -1 : NUM2INT(rflag); - ptr = obj_to_asn1bstr(value, flag); - free_func = ASN1_BIT_STRING_free; - break; - case V_ASN1_NULL: - ptr = obj_to_asn1null(value); - free_func = ASN1_NULL_free; - break; - case V_ASN1_OCTET_STRING: /* FALLTHROUGH */ - case V_ASN1_UTF8STRING: /* FALLTHROUGH */ - case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */ - case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */ - case V_ASN1_T61STRING: /* FALLTHROUGH */ - case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */ - case V_ASN1_IA5STRING: /* FALLTHROUGH */ - case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */ - case V_ASN1_ISO64STRING: /* FALLTHROUGH */ - case V_ASN1_GENERALSTRING: /* FALLTHROUGH */ - case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */ - case V_ASN1_BMPSTRING: - ptr = obj_to_asn1str(value); - free_func = ASN1_STRING_free; - break; - case V_ASN1_OBJECT: - ptr = obj_to_asn1obj(value); - free_func = ASN1_OBJECT_free; - break; - case V_ASN1_UTCTIME: - ptr = obj_to_asn1utime(value); - free_func = ASN1_TIME_free; - break; - case V_ASN1_GENERALIZEDTIME: - ptr = obj_to_asn1gtime(value); - free_func = ASN1_TIME_free; - break; - case V_ASN1_SET: /* FALLTHROUGH */ - case V_ASN1_SEQUENCE: - ptr = obj_to_asn1derstr(obj); - free_func = ASN1_STRING_free; - break; - default: - ossl_raise(eASN1Error, "unsupported ASN.1 type"); + case V_ASN1_BOOLEAN: + ptr = (void*)(VALUE)obj_to_asn1bool(value); + free_func = NULL; + break; + case V_ASN1_INTEGER: /* FALLTHROUGH */ + case V_ASN1_ENUMERATED: + ptr = obj_to_asn1int(value); + free_func = (free_func_type *)ASN1_INTEGER_free; + break; + case V_ASN1_BIT_STRING: + rflag = rb_attr_get(obj, sivUNUSED_BITS); + ptr = obj_to_asn1bstr(value, NUM2INT(rflag)); + free_func = (free_func_type *)ASN1_BIT_STRING_free; + break; + case V_ASN1_NULL: + ptr = obj_to_asn1null(value); + free_func = (free_func_type *)ASN1_NULL_free; + break; + case V_ASN1_OCTET_STRING: /* FALLTHROUGH */ + case V_ASN1_UTF8STRING: /* FALLTHROUGH */ + case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */ + case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */ + case V_ASN1_T61STRING: /* FALLTHROUGH */ + case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */ + case V_ASN1_IA5STRING: /* FALLTHROUGH */ + case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */ + case V_ASN1_ISO64STRING: /* FALLTHROUGH */ + case V_ASN1_GENERALSTRING: /* FALLTHROUGH */ + case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */ + case V_ASN1_BMPSTRING: + ptr = obj_to_asn1str(value); + free_func = (free_func_type *)ASN1_STRING_free; + break; + case V_ASN1_OBJECT: + ptr = ossl_to_asn1obj(value); + free_func = (free_func_type *)ASN1_OBJECT_free; + break; + case V_ASN1_UTCTIME: + ptr = obj_to_asn1utime(value); + free_func = (free_func_type *)ASN1_TIME_free; + break; + case V_ASN1_GENERALIZEDTIME: + ptr = obj_to_asn1gtime(value); + free_func = (free_func_type *)ASN1_TIME_free; + break; + case V_ASN1_SET: /* FALLTHROUGH */ + case V_ASN1_SEQUENCE: + ptr = obj_to_asn1derstr(obj); + free_func = (free_func_type *)ASN1_STRING_free; + break; + default: + ossl_raise(eASN1Error, "unsupported ASN.1 type"); } if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){ - if(free_func) free_func(ptr); - ossl_raise(eASN1Error, "ASN1_TYPE alloc failure"); + if(free_func) free_func(ptr); + ossl_raise(eASN1Error, "ASN1_TYPE alloc failure"); } memset(ret, 0, sizeof(ASN1_TYPE)); ASN1_TYPE_set(ret, tag, ptr); @@ -566,18 +593,17 @@ ossl_asn1_get_asn1type(VALUE obj) static int ossl_asn1_default_tag(VALUE obj) { - int i; - - for(i = 0; i < ossl_asn1_info_size; i++){ - if(ossl_asn1_info[i].klass && - rb_obj_is_kind_of(obj, *ossl_asn1_info[i].klass)){ - return i; - } + VALUE tmp_class, tag; + + tmp_class = CLASS_OF(obj); + 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); } - ossl_raise(eASN1Error, "universal tag for %s not found", - rb_class2name(CLASS_OF(obj))); - return -1; /* dummy */ + return -1; } static int @@ -587,432 +613,678 @@ ossl_asn1_tag(VALUE obj) tag = ossl_asn1_get_tag(obj); if(NIL_P(tag)) - ossl_raise(eASN1Error, "tag number not specified"); + ossl_raise(eASN1Error, "tag number not specified"); return NUM2INT(tag); } 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){ - 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){ - ossl_raise(eASN1Error, "invalid tag class"); - } - - return ret; + 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"); } 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; } +/* + * call-seq: + * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data + * + * _value_: Please have a look at Constructive and Primitive to see how Ruby + * types are mapped to ASN.1 types and vice versa. + * + * _tag_: An Integer indicating the tag number. + * + * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for + * possible values. + * + * == Example + * asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42) + * tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER + */ static VALUE 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) - ossl_raise(eASN1Error, "tag number for Universal too large"); + ossl_raise(eASN1Error, "invalid tag class"); ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); ossl_asn1_set_tag_class(self, tag_class); + ossl_asn1_set_indefinite_length(self, Qfalse); return self; } -static VALUE -join_der_i(VALUE i, VALUE str) +static VALUE +to_der_internal(VALUE self, int constructed, int indef_len, VALUE body) { - i = ossl_to_der_if_possible(i); - StringValue(i); - rb_str_append(str, i); - return Qnil; + int encoding = constructed ? indef_len ? 2 : 1 : 0; + int tag_class = ossl_asn1_tag_class(self); + int tag_number = ossl_asn1_tag(self); + int default_tag_number = ossl_asn1_default_tag(self); + int body_length, total_length; + VALUE str; + unsigned char *p; + + body_length = RSTRING_LENINT(body); + if (ossl_asn1_get_tagging(self) == sym_EXPLICIT) { + int inner_length, e_encoding = indef_len ? 2 : 1; + + if (default_tag_number == -1) + ossl_raise(eASN1Error, "explicit tagging of unknown tag"); + + inner_length = ASN1_object_size(encoding, body_length, default_tag_number); + total_length = ASN1_object_size(e_encoding, inner_length, tag_number); + str = rb_str_new(NULL, total_length); + p = (unsigned char *)RSTRING_PTR(str); + /* Put explicit tag */ + ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class); + /* Append inner object */ + ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL); + memcpy(p, RSTRING_PTR(body), body_length); + p += body_length; + if (indef_len) { + ASN1_put_eoc(&p); /* For inner object */ + ASN1_put_eoc(&p); /* For wrapper object */ + } + } + else { + total_length = ASN1_object_size(encoding, body_length, tag_number); + str = rb_str_new(NULL, total_length); + p = (unsigned char *)RSTRING_PTR(str); + ASN1_put_object(&p, encoding, body_length, tag_number, tag_class); + memcpy(p, RSTRING_PTR(body), body_length); + p += body_length; + if (indef_len) + ASN1_put_eoc(&p); + } + assert(p - (unsigned char *)RSTRING_PTR(str) == total_length); + return str; } +static VALUE ossl_asn1prim_to_der(VALUE); +static VALUE ossl_asn1cons_to_der(VALUE); +/* + * call-seq: + * asn1.to_der => DER-encoded String + * + * Encodes this ASN1Data into a DER-encoded String value. The result is + * DER-encoded except for the possibility of indefinite length forms. + * Indefinite length forms are not allowed in strict DER, so strictly speaking + * the result of such an encoding would be a BER-encoding. + */ static VALUE -join_der(VALUE enumerable) +ossl_asn1data_to_der(VALUE self) { - VALUE str = rb_str_new(0, 0); - rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str); - return str; + VALUE value = ossl_asn1_get_value(self); + + if (rb_obj_is_kind_of(value, rb_cArray)) + return ossl_asn1cons_to_der(self); + else { + if (RTEST(ossl_asn1_get_indefinite_length(self))) + ossl_raise(eASN1Error, "indefinite length form cannot be used " \ + "with primitive encoding"); + return ossl_asn1prim_to_der(self); + } } +static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self); +static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset, + int depth, int yield, long *num_read); + static VALUE -ossl_asn1data_to_der(VALUE self) +int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, + VALUE tc, long *num_read) { - VALUE value, der; - int tag, tag_class, is_cons = 0; - long length; + VALUE value, asn1data; unsigned char *p; + long flag = 0; - value = ossl_asn1_get_value(self); - if(rb_obj_is_kind_of(value, rb_cArray)){ - is_cons = 1; - value = join_der(value); + p = *pp; + + if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) { + switch(tag){ + case V_ASN1_EOC: + value = decode_eoc(p, hlen+length); + break; + case V_ASN1_BOOLEAN: + value = decode_bool(p, hlen+length); + break; + case V_ASN1_INTEGER: + value = decode_int(p, hlen+length); + break; + case V_ASN1_BIT_STRING: + value = decode_bstr(p, hlen+length, &flag); + break; + case V_ASN1_NULL: + value = decode_null(p, hlen+length); + break; + case V_ASN1_ENUMERATED: + value = decode_enum(p, hlen+length); + break; + case V_ASN1_OBJECT: + value = decode_obj(p, hlen+length); + break; + case V_ASN1_UTCTIME: /* FALLTHROUGH */ + case V_ASN1_GENERALIZEDTIME: + value = decode_time(p, hlen+length); + break; + default: + /* use original value */ + p += hlen; + value = rb_str_new((const char *)p, length); + break; + } + } + else { + p += hlen; + value = rb_str_new((const char *)p, length); + } + + *pp += hlen + length; + *num_read = hlen + length; + + 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] = tc; + asn1data = rb_obj_alloc(klass); + ossl_asn1_initialize(4, args, asn1data); + if(tag == V_ASN1_BIT_STRING){ + rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag)); + } + } + else { + asn1data = rb_obj_alloc(cASN1Data); + ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc); } - StringValue(value); - - tag = ossl_asn1_tag(self); - tag_class = ossl_asn1_tag_class(self); - if((length = ASN1_object_size(1, RSTRING_LEN(value), tag)) <= 0) - ossl_raise(eASN1Error, NULL); - der = rb_str_new(0, length); - p = RSTRING_PTR(der); - ASN1_put_object(&p, is_cons, RSTRING_LEN(value), tag, tag_class); - memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); - p += RSTRING_LEN(value); - ossl_str_adjust(der, p); - - return der; + + return asn1data; } static VALUE -ossl_asn1_decode0(unsigned char **pp, long length, long *offset, long depth, - int once, int yield) +int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, + long *offset, int depth, int yield, int j, + int tag, VALUE tc, long *num_read) { - unsigned char *start, *p; - long len, off = *offset; - int hlen, tag, tc, j; - VALUE ary, asn1data, value, tag_class; + VALUE value, asn1data, ary; + int indefinite; + long available_len, off = *offset; + indefinite = (j == 0x21); ary = rb_ary_new(); + + available_len = indefinite ? max_len : length; + while (available_len > 0) { + long inner_read = 0; + value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read); + *num_read += inner_read; + available_len -= inner_read; + + if (indefinite) { + if (ossl_asn1_tag(value) == V_ASN1_EOC && + ossl_asn1_get_tag_class(value) == sym_UNIVERSAL) + break; + if (available_len == 0) + ossl_raise(eASN1Error, "EOC missing in indefinite length encoding"); + } + rb_ary_push(ary, value); + } + + if (tc == sym_UNIVERSAL) { + VALUE args[4]; + if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET) + asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass); + else + asn1data = rb_obj_alloc(cASN1Constructive); + args[0] = ary; + args[1] = INT2NUM(tag); + args[2] = Qnil; + args[3] = tc; + ossl_asn1_initialize(4, args, asn1data); + } + else { + asn1data = rb_obj_alloc(cASN1Data); + ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc); + } + + if (indefinite) + ossl_asn1_set_indefinite_length(asn1data, Qtrue); + else + ossl_asn1_set_indefinite_length(asn1data, Qfalse); + + *offset = off; + return asn1data; +} + +static VALUE +ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, + int yield, long *num_read) +{ + unsigned char *start, *p; + const unsigned char *p0; + long len = 0, inner_read = 0, off = *offset, hlen; + int tag, tc, j; + VALUE asn1data, tag_class; + p = *pp; - while(length > 0){ - start = p; - j = ASN1_get_object(&p, &len, &tag, &tc, length); - if(j & 0x80) ossl_raise(eASN1Error, NULL); - hlen = p - start; - if(yield){ - VALUE arg = rb_ary_new(); - rb_ary_push(arg, LONG2NUM(depth)); - rb_ary_push(arg, LONG2NUM(off)); - rb_ary_push(arg, LONG2NUM(hlen)); - rb_ary_push(arg, LONG2NUM(len)); - rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse); - rb_ary_push(arg, ossl_asn1_class2sym(tc)); - rb_ary_push(arg, INT2NUM(tag)); - rb_yield(arg); - } - length -= hlen; - off += hlen; - if(len > length) ossl_raise(eASN1Error, "value is too short"); - if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) - tag_class = sPRIVATE; - else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) - tag_class = sCONTEXT_SPECIFIC; - else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) - tag_class = sAPPLICATION; - else - tag_class = sUNIVERSAL; - if(j & V_ASN1_CONSTRUCTED){ - /* TODO: if j == 0x21 it is indefinite length object. */ - if((j == 0x21) && (len == 0)){ - long lastoff = off; - value = ossl_asn1_decode0(&p, length, &off, depth+1, 0, yield); - len = off - lastoff; - } - else value = ossl_asn1_decode0(&p, len, &off, depth+1, 0, yield); - } - else{ - value = rb_str_new(p, len); - p += len; - off += len; - } - if(tag_class == sUNIVERSAL && - tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass){ - VALUE klass = *ossl_asn1_info[tag].klass; - long flag = 0; - if(!rb_obj_is_kind_of(value, rb_cArray)){ - switch(tag){ - case V_ASN1_BOOLEAN: - value = decode_bool(start, hlen+len); - break; - case V_ASN1_INTEGER: - value = decode_int(start, hlen+len); - break; - case V_ASN1_BIT_STRING: - value = decode_bstr(start, hlen+len, &flag); - break; - case V_ASN1_NULL: - value = decode_null(start, hlen+len); - break; - case V_ASN1_ENUMERATED: - value = decode_enum(start, hlen+len); - break; - case V_ASN1_OBJECT: - value = decode_obj(start, hlen+len); - break; - case V_ASN1_UTCTIME: /* FALLTHROUGH */ - case V_ASN1_GENERALIZEDTIME: - value = decode_time(start, hlen+len); - break; - default: - /* use original value */ - break; - } - } - asn1data = rb_funcall(klass, rb_intern("new"), 1, value); - if(tag == V_ASN1_BIT_STRING){ - rb_iv_set(asn1data, "@unused_bits", LONG2NUM(flag)); - } - } - else{ - asn1data = rb_funcall(cASN1Data, rb_intern("new"), 3, - value, INT2NUM(tag), ID2SYM(tag_class)); - } - rb_ary_push(ary, asn1data); - length -= len; - if(once) break; + start = p; + p0 = p; + j = ASN1_get_object(&p0, &len, &tag, &tc, length); + p = (unsigned char *)p0; + 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 = sym_PRIVATE; + else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) + tag_class = sym_CONTEXT_SPECIFIC; + else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) + tag_class = sym_APPLICATION; + else + tag_class = sym_UNIVERSAL; + + hlen = p - start; + + if(yield) { + VALUE arg = rb_ary_new(); + rb_ary_push(arg, LONG2NUM(depth)); + rb_ary_push(arg, LONG2NUM(*offset)); + rb_ary_push(arg, LONG2NUM(hlen)); + rb_ary_push(arg, LONG2NUM(len)); + rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse); + rb_ary_push(arg, ossl_asn1_class2sym(tc)); + rb_ary_push(arg, INT2NUM(tag)); + rb_yield(arg); + } + + if(j & V_ASN1_CONSTRUCTED) { + *pp += hlen; + off += hlen; + asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read); + inner_read += hlen; + } + else { + if ((j & 0x01) && (len == 0)) + ossl_raise(eASN1Error, "indefinite length for primitive value"); + asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read); + off += hlen + len; } - *pp = p; + if (num_read) + *num_read = inner_read; + if (len != 0 && inner_read != hlen + len) { + ossl_raise(eASN1Error, + "Type mismatch. Bytes read: %ld Bytes available: %ld", + inner_read, hlen + len); + } + *offset = off; + return asn1data; +} - return ary; +static void +int_ossl_decode_sanity_check(long len, long read, long offset) +{ + if (len != 0 && (read != len || offset != len)) { + ossl_raise(eASN1Error, + "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld", + read, len, offset); + } } +/* + * call-seq: + * OpenSSL::ASN1.traverse(asn1) -> nil + * + * If a block is given, it prints out each of the elements encountered. + * Block parameters are (in that order): + * * depth: The recursion depth, plus one with each constructed value being encountered (Integer) + * * offset: Current byte offset (Integer) + * * header length: Combined length in bytes of the Tag and Length headers. (Integer) + * * length: The overall remaining length of the entire data (Integer) + * * constructed: Whether this value is constructed or not (Boolean) + * * tag_class: Current tag class (Symbol) + * * tag: The current tag number (Integer) + * + * == Example + * der = File.binread('asn1data.der') + * OpenSSL::ASN1.traverse(der) do | depth, offset, header_len, length, constructed, tag_class, tag| + * puts "Depth: #{depth} Offset: #{offset} Length: #{length}" + * puts "Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}" + * end + */ static VALUE ossl_asn1_traverse(VALUE self, VALUE obj) { unsigned char *p; - long offset = 0; - volatile VALUE tmp; + VALUE tmp; + long len, read = 0, offset = 0; obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); - p = RSTRING_PTR(tmp); - ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 1); - + p = (unsigned char *)RSTRING_PTR(tmp); + len = RSTRING_LEN(tmp); + ossl_asn1_decode0(&p, len, &offset, 0, 1, &read); + RB_GC_GUARD(tmp); + int_ossl_decode_sanity_check(len, read, offset); return Qnil; } +/* + * call-seq: + * OpenSSL::ASN1.decode(der) -> ASN1Data + * + * Decodes a BER- or DER-encoded value and creates an ASN1Data instance. _der_ + * may be a String or any object that features a +.to_der+ method transforming + * it into a BER-/DER-encoded String+ + * + * == Example + * der = File.binread('asn1data') + * asn1 = OpenSSL::ASN1.decode(der) + */ static VALUE ossl_asn1_decode(VALUE self, VALUE obj) { - VALUE ret, ary; + VALUE ret; unsigned char *p; - long offset = 0; - volatile VALUE tmp; + VALUE tmp; + long len, read = 0, offset = 0; obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); - p = RSTRING_PTR(tmp); - ary = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 1, 0); - ret = rb_ary_entry(ary, 0); - + p = (unsigned char *)RSTRING_PTR(tmp); + len = RSTRING_LEN(tmp); + ret = ossl_asn1_decode0(&p, len, &offset, 0, 0, &read); + RB_GC_GUARD(tmp); + int_ossl_decode_sanity_check(len, read, offset); return ret; } +/* + * call-seq: + * OpenSSL::ASN1.decode_all(der) -> Array of ASN1Data + * + * Similar to #decode with the difference that #decode expects one + * distinct value represented in _der_. #decode_all on the contrary + * decodes a sequence of sequential BER/DER values lined up in _der_ + * and returns them as an array. + * + * == Example + * ders = File.binread('asn1data_seq') + * asn1_ary = OpenSSL::ASN1.decode_all(ders) + */ static VALUE ossl_asn1_decode_all(VALUE self, VALUE obj) { - VALUE ret; + VALUE ary, val; unsigned char *p; - long offset = 0; - volatile VALUE tmp; + long len, tmp_len = 0, read = 0, offset = 0; + VALUE tmp; obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); - p = RSTRING_PTR(tmp); - ret = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 0); - - return ret; + p = (unsigned char *)RSTRING_PTR(tmp); + len = RSTRING_LEN(tmp); + tmp_len = len; + ary = rb_ary_new(); + while (tmp_len > 0) { + long tmp_read = 0; + val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read); + rb_ary_push(ary, val); + read += tmp_read; + tmp_len -= tmp_read; + } + RB_GC_GUARD(tmp); + int_ossl_decode_sanity_check(len, read, offset); + return ary; } +/* + * call-seq: + * OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive + * + * _value_: is mandatory. + * + * _tag_: optional, may be specified for tagged values. If no _tag_ is + * specified, the UNIVERSAL tag corresponding to the Primitive sub-class + * is used by default. + * + * _tagging_: may be used as an encoding hint to encode a value either + * explicitly or implicitly, see ASN1 for possible values. + * + * _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to + * +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then + * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please + * cf. ASN1. + * + * == Example + * int = OpenSSL::ASN1::Integer.new(42) + * zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT) + * private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE) + */ static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) { VALUE value, tag, tagging, tag_class; + int default_tag; rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class); - if(argc > 1){ - if(NIL_P(tag)) - ossl_raise(eASN1Error, "must specify tag number"); - if(NIL_P(tagging)) - tagging = ID2SYM(sEXPLICIT); - if(!SYMBOL_P(tagging)) - ossl_raise(eASN1Error, "invalid tag default"); - if(NIL_P(tag_class)) - tag_class = ID2SYM(sCONTEXT_SPECIFIC); - if(!SYMBOL_P(tag_class)) - ossl_raise(eASN1Error, "invalid tag class"); - if(SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31) - ossl_raise(eASN1Error, "tag number for Universal too large"); + default_tag = ossl_asn1_default_tag(self); + + if (default_tag == -1 || argc > 1) { + if(NIL_P(tag)) + ossl_raise(eASN1Error, "must specify tag number"); + if(!NIL_P(tagging) && !SYMBOL_P(tagging)) + ossl_raise(eASN1Error, "invalid tagging method"); + if(NIL_P(tag_class)) { + if (NIL_P(tagging)) + tag_class = sym_UNIVERSAL; + else + tag_class = sym_CONTEXT_SPECIFIC; + } + if(!SYMBOL_P(tag_class)) + ossl_raise(eASN1Error, "invalid tag class"); } else{ - tag = INT2NUM(ossl_asn1_default_tag(self)); + tag = INT2NUM(default_tag); tagging = Qnil; - tag_class = ID2SYM(sUNIVERSAL); + tag_class = sym_UNIVERSAL; } ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); ossl_asn1_set_tagging(self, tagging); ossl_asn1_set_tag_class(self, tag_class); + ossl_asn1_set_indefinite_length(self, Qfalse); + if (default_tag == V_ASN1_BIT_STRING) + rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0)); 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 VALUE +ossl_asn1eoc_initialize(VALUE self) { + VALUE tag, tagging, tag_class, value; + tag = INT2FIX(0); + tagging = Qnil; + tag_class = sym_UNIVERSAL; + value = rb_str_new("", 0); + ossl_asn1_set_tag(self, tag); + ossl_asn1_set_value(self, value); + ossl_asn1_set_tagging(self, tagging); + ossl_asn1_set_tag_class(self, tag_class); + ossl_asn1_set_indefinite_length(self, Qfalse); + return self; } -static void -ossl_ASN1_TYPE_free(ASN1_TYPE *a) +static VALUE +ossl_asn1eoc_to_der(VALUE self) { -#if OPENSSL_VERSION_NUMBER < 0x00907000L - if(!a) return; - if(a->type == V_ASN1_BOOLEAN){ - OPENSSL_free(a); - return; - } -#endif - ASN1_TYPE_free(a); + return rb_str_new("\0\0", 2); } +/* + * call-seq: + * asn1.to_der => DER-encoded String + * + * See ASN1Data#to_der for details. + */ static VALUE ossl_asn1prim_to_der(VALUE self) { ASN1_TYPE *asn1; - int tn, tc, explicit; - long length, reallen; - unsigned char *buf, *p; + long alllen, bodylen; + unsigned char *p0, *p1; + int j, tag, tc, state; VALUE str; - tn = NUM2INT(ossl_asn1_get_tag(self)); - tc = ossl_asn1_tag_class(self); - explicit = ossl_asn1_is_explicit(self); - asn1 = ossl_asn1_get_asn1type(self); + if (ossl_asn1_default_tag(self) == -1) { + str = ossl_asn1_get_value(self); + return to_der_internal(self, 0, 0, StringValue(str)); + } - length = ASN1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn); - if(!(buf = OPENSSL_malloc(length))){ - ossl_ASN1_TYPE_free(asn1); - ossl_raise(eASN1Error, "cannot alloc buffer"); + asn1 = ossl_asn1_get_asn1type(self); + alllen = i2d_ASN1_TYPE(asn1, NULL); + if (alllen < 0) { + ASN1_TYPE_free(asn1); + ossl_raise(eASN1Error, "i2d_ASN1_TYPE"); } - p = buf; - if(tc == V_ASN1_UNIVERSAL) ossl_i2d_ASN1_TYPE(asn1, &p); - else{ - if(explicit){ - ASN1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc); - ossl_i2d_ASN1_TYPE(asn1, &p); - } - else{ - ossl_i2d_ASN1_TYPE(asn1, &p); - *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED); - } + str = ossl_str_new(NULL, alllen, &state); + if (state) { + ASN1_TYPE_free(asn1); + rb_jump_tag(state); + } + p0 = p1 = (unsigned char *)RSTRING_PTR(str); + if (i2d_ASN1_TYPE(asn1, &p0) < 0) { + ASN1_TYPE_free(asn1); + ossl_raise(eASN1Error, "i2d_ASN1_TYPE"); } - ossl_ASN1_TYPE_free(asn1); - reallen = p - buf; - assert(reallen <= length); - str = ossl_buf2str(buf, reallen); /* buf will be free in ossl_buf2str */ + ASN1_TYPE_free(asn1); + ossl_str_adjust(str, p0); - return str; + /* Strip header since to_der_internal() wants only the payload */ + j = ASN1_get_object((const unsigned char **)&p1, &bodylen, &tag, &tc, alllen); + if (j & 0x80) + ossl_raise(eASN1Error, "ASN1_get_object"); /* should not happen */ + + return to_der_internal(self, 0, 0, rb_str_drop_bytes(str, alllen - bodylen)); } +/* + * call-seq: + * asn1.to_der => DER-encoded String + * + * See ASN1Data#to_der for details. + */ static VALUE ossl_asn1cons_to_der(VALUE self) { - int tag, tn, tc, explicit; - long seq_len, length; - unsigned char *p; - VALUE value, str; - - tag = ossl_asn1_default_tag(self); - tn = NUM2INT(ossl_asn1_get_tag(self)); - tc = ossl_asn1_tag_class(self); - explicit = ossl_asn1_is_explicit(self); - value = join_der(ossl_asn1_get_value(self)); - - seq_len = ASN1_object_size(1, RSTRING_LEN(value), tag); - length = ASN1_object_size(1, seq_len, tn); - str = rb_str_new(0, length); - p = RSTRING_PTR(str); - if(tc == V_ASN1_UNIVERSAL) - ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc); - else{ - if(explicit){ - ASN1_put_object(&p, 1, seq_len, tn, tc); - ASN1_put_object(&p, 1, RSTRING_LEN(value), tag, V_ASN1_UNIVERSAL); - } - else ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc); + VALUE ary, str; + long i; + int indef_len; + + indef_len = RTEST(ossl_asn1_get_indefinite_length(self)); + ary = rb_convert_type(ossl_asn1_get_value(self), T_ARRAY, "Array", "to_a"); + str = rb_str_new(NULL, 0); + for (i = 0; i < RARRAY_LEN(ary); i++) { + VALUE item = RARRAY_AREF(ary, i); + + if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) { + if (i != RARRAY_LEN(ary) - 1) + ossl_raise(eASN1Error, "illegal EOC octets in value"); + + /* + * EOC is not really part of the content, but we required to add one + * at the end in the past. + */ + break; + } + + item = ossl_to_der_if_possible(item); + StringValue(item); + rb_str_append(str, item); } - memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); - p += RSTRING_LEN(value); - ossl_str_adjust(str, p); - return str; + return to_der_internal(self, 1, indef_len, str); } +/* + * call-seq: + * asn1_ary.each { |asn1| block } => asn1_ary + * + * Calls the given block once for each element in self, passing that element + * as parameter _asn1_. If no block is given, an enumerator is returned + * instead. + * + * == Example + * asn1_ary.each do |asn1| + * puts asn1 + * end + */ static VALUE ossl_asn1cons_each(VALUE self) { - rb_ary_each(ossl_asn1_get_value(self)); + rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0); + return self; } +/* + * call-seq: + * OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name) + * + * This adds a new ObjectId to the internal tables. Where _object_id_ is the + * numerical form, _short_name_ is the short name, and _long_name_ is the long + * name. + * + * Returns +true+ if successful. Raises an OpenSSL::ASN1::ASN1Error if it fails. + * + */ 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); + ossl_raise(eASN1Error, NULL); return Qtrue; } +/* + * call-seq: + * oid.sn -> string + * oid.short_name -> string + * + * The short name of the ObjectId, as defined in <openssl/objects.h>. + */ static VALUE ossl_asn1obj_get_sn(VALUE self) { @@ -1020,12 +1292,19 @@ ossl_asn1obj_get_sn(VALUE self) int nid; val = ossl_asn1_get_value(self); - if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef) - ret = rb_str_new2(OBJ_nid2sn(nid)); + if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef) + ret = rb_str_new2(OBJ_nid2sn(nid)); return ret; } +/* + * call-seq: + * oid.ln -> string + * oid.long_name -> string + * + * The long name of the ObjectId, as defined in <openssl/objects.h>. + */ static VALUE ossl_asn1obj_get_ln(VALUE self) { @@ -1033,25 +1312,57 @@ ossl_asn1obj_get_ln(VALUE self) int nid; val = ossl_asn1_get_value(self); - if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef) - ret = rb_str_new2(OBJ_nid2ln(nid)); + if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef) + ret = rb_str_new2(OBJ_nid2ln(nid)); return ret; } static VALUE +asn1obj_get_oid_i(VALUE vobj) +{ + return ossl_asn1obj_to_string_oid((const ASN1_OBJECT *)vobj); +} + +/* + * call-seq: + * oid.oid -> string + * + * Returns a String representing the Object Identifier in the dot notation, + * e.g. "1.2.3.4.5" + */ +static VALUE ossl_asn1obj_get_oid(VALUE self) { - VALUE val; + VALUE str; ASN1_OBJECT *a1obj; - char buf[128]; + int state; - val = ossl_asn1_get_value(self); - a1obj = obj_to_asn1obj(val); - OBJ_obj2txt(buf, sizeof(buf), a1obj, 1); + a1obj = ossl_to_asn1obj(ossl_asn1_get_value(self)); + str = rb_protect(asn1obj_get_oid_i, (VALUE)a1obj, &state); ASN1_OBJECT_free(a1obj); + if (state) + rb_jump_tag(state); + return str; +} + +/* + * call-seq: + * oid == other_oid => true or false + * + * Returns +true+ if _other_oid_ is the same as _oid_. + */ +static VALUE +ossl_asn1obj_eq(VALUE self, VALUE other) +{ + VALUE oid1, oid2; - return rb_str_new2(buf); + if (!rb_obj_is_kind_of(other, cASN1ObjectId)) + return Qfalse; + + oid1 = ossl_asn1obj_get_oid(self); + oid2 = ossl_asn1obj_get_oid(other); + return rb_str_equal(oid1, oid2); } #define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \ @@ -1080,51 +1391,414 @@ OSSL_ASN1_IMPL_FACTORY_METHOD(UTCTime) OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralizedTime) OSSL_ASN1_IMPL_FACTORY_METHOD(Sequence) OSSL_ASN1_IMPL_FACTORY_METHOD(Set) +OSSL_ASN1_IMPL_FACTORY_METHOD(EndOfContent) void -Init_ossl_asn1() +Init_ossl_asn1(void) { - VALUE ary; - int i; - -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); -#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"); - +#undef rb_intern + + 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"); + sivTAGGING = rb_intern("@tagging"); + sivTAG_CLASS = rb_intern("@tag_class"); + sivINDEFINITE_LENGTH = rb_intern("@indefinite_length"); + sivUNUSED_BITS = rb_intern("@unused_bits"); + + /* + * Document-module: OpenSSL::ASN1 + * + * Abstract Syntax Notation One (or ASN.1) is a notation syntax to + * describe data structures and is defined in ITU-T X.680. ASN.1 itself + * does not mandate any encoding or parsing rules, but usually ASN.1 data + * structures are encoded using the Distinguished Encoding Rules (DER) or + * less often the Basic Encoding Rules (BER) described in ITU-T X.690. DER + * and BER encodings are binary Tag-Length-Value (TLV) encodings that are + * quite concise compared to other popular data description formats such + * as XML, JSON etc. + * ASN.1 data structures are very common in cryptographic applications, + * e.g. X.509 public key certificates or certificate revocation lists + * (CRLs) are all defined in ASN.1 and DER-encoded. ASN.1, DER and BER are + * the building blocks of applied cryptography. + * The ASN1 module provides the necessary classes that allow generation + * of ASN.1 data structures and the methods to encode them using a DER + * encoding. The decode method allows parsing arbitrary BER-/DER-encoded + * data to a Ruby object that can then be modified and re-encoded at will. + * + * == ASN.1 class hierarchy + * + * The base class representing ASN.1 structures is ASN1Data. ASN1Data offers + * attributes to read and set the _tag_, the _tag_class_ and finally the + * _value_ of a particular ASN.1 item. Upon parsing, any tagged values + * (implicit or explicit) will be represented by ASN1Data instances because + * their "real type" can only be determined using out-of-band information + * from the ASN.1 type declaration. Since this information is normally + * known when encoding a type, all sub-classes of ASN1Data offer an + * additional attribute _tagging_ that allows to encode a value implicitly + * (+:IMPLICIT+) or explicitly (+:EXPLICIT+). + * + * === Constructive + * + * Constructive is, as its name implies, the base class for all + * constructed encodings, i.e. those that consist of several values, + * opposed to "primitive" encodings with just one single value. The value of + * an Constructive is always an Array. + * + * ==== ASN1::Set and ASN1::Sequence + * + * The most common constructive encodings are SETs and SEQUENCEs, which is + * why there are two sub-classes of Constructive representing each of + * them. + * + * === Primitive + * + * This is the super class of all primitive values. Primitive + * itself is not used when parsing ASN.1 data, all values are either + * instances of a corresponding sub-class of Primitive or they are + * instances of ASN1Data if the value was tagged implicitly or explicitly. + * Please cf. Primitive documentation for details on sub-classes and + * their respective mappings of ASN.1 data types to Ruby objects. + * + * == Possible values for _tagging_ + * + * When constructing an ASN1Data object the ASN.1 type definition may + * require certain elements to be either implicitly or explicitly tagged. + * This can be achieved by setting the _tagging_ attribute manually for + * sub-classes of ASN1Data. Use the symbol +:IMPLICIT+ for implicit + * tagging and +:EXPLICIT+ if the element requires explicit tagging. + * + * == Possible values for _tag_class_ + * + * It is possible to create arbitrary ASN1Data objects that also support + * a PRIVATE or APPLICATION tag class. Possible values for the _tag_class_ + * attribute are: + * * +:UNIVERSAL+ (the default for untagged values) + * * +:CONTEXT_SPECIFIC+ (the default for tagged values) + * * +:APPLICATION+ + * * +:PRIVATE+ + * + * == Tag constants + * + * There is a constant defined for each universal tag: + * * OpenSSL::ASN1::EOC (0) + * * OpenSSL::ASN1::BOOLEAN (1) + * * OpenSSL::ASN1::INTEGER (2) + * * OpenSSL::ASN1::BIT_STRING (3) + * * OpenSSL::ASN1::OCTET_STRING (4) + * * OpenSSL::ASN1::NULL (5) + * * OpenSSL::ASN1::OBJECT (6) + * * OpenSSL::ASN1::ENUMERATED (10) + * * OpenSSL::ASN1::UTF8STRING (12) + * * OpenSSL::ASN1::SEQUENCE (16) + * * OpenSSL::ASN1::SET (17) + * * OpenSSL::ASN1::NUMERICSTRING (18) + * * OpenSSL::ASN1::PRINTABLESTRING (19) + * * OpenSSL::ASN1::T61STRING (20) + * * OpenSSL::ASN1::VIDEOTEXSTRING (21) + * * OpenSSL::ASN1::IA5STRING (22) + * * OpenSSL::ASN1::UTCTIME (23) + * * OpenSSL::ASN1::GENERALIZEDTIME (24) + * * OpenSSL::ASN1::GRAPHICSTRING (25) + * * OpenSSL::ASN1::ISO64STRING (26) + * * OpenSSL::ASN1::GENERALSTRING (27) + * * OpenSSL::ASN1::UNIVERSALSTRING (28) + * * OpenSSL::ASN1::BMPSTRING (30) + * + * == UNIVERSAL_TAG_NAME constant + * + * An Array that stores the name of a given tag number. These names are + * the same as the name of the tag constant that is additionally defined, + * e.g. <tt>UNIVERSAL_TAG_NAME[2] = "INTEGER"</tt> and <tt>OpenSSL::ASN1::INTEGER = 2</tt>. + * + * == Example usage + * + * === Decoding and viewing a DER-encoded file + * require 'openssl' + * require 'pp' + * der = File.binread('data.der') + * asn1 = OpenSSL::ASN1.decode(der) + * pp der + * + * === Creating an ASN.1 structure and DER-encoding it + * require 'openssl' + * version = OpenSSL::ASN1::Integer.new(1) + * # Explicitly 0-tagged implies context-specific tag class + * serial = OpenSSL::ASN1::Integer.new(12345, 0, :EXPLICIT, :CONTEXT_SPECIFIC) + * name = OpenSSL::ASN1::PrintableString.new('Data 1') + * sequence = OpenSSL::ASN1::Sequence.new( [ version, serial, name ] ) + * der = sequence.to_der + */ mASN1 = rb_define_module_under(mOSSL, "ASN1"); + + /* Document-class: OpenSSL::ASN1::ASN1Error + * + * Generic error class for all errors raised in ASN1 and any of the + * classes defined in it. + */ eASN1Error = rb_define_class_under(mASN1, "ASN1Error", eOSSLError); rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1); rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1); rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1); - ary = rb_ary_new(); - rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary); - for(i = 0; i < ossl_asn1_info_size; i++){ - if(ossl_asn1_info[i].name[0] == '[') continue; - rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i)); - rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name)); + + VALUE ary = rb_ary_new_capa(ossl_asn1_info_size); + for (int i = 0; i < ossl_asn1_info_size; i++) { + const char *name = ossl_asn1_info[i].name; + if (name[0] == '[') + continue; + rb_define_const(mASN1, name, INT2NUM(i)); + rb_ary_store(ary, i, rb_obj_freeze(rb_str_new_cstr(name))); } + rb_obj_freeze(ary); + /* + * Array storing tag names at the tag's index. + */ + rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary); + /* Document-class: OpenSSL::ASN1::ASN1Data + * + * The top-level class representing any ASN.1 object. When parsed by + * ASN1.decode, tagged values are always represented by an instance + * of ASN1Data. + * + * == The role of ASN1Data for parsing tagged values + * + * When encoding an ASN.1 type it is inherently clear what original + * type (e.g. INTEGER, OCTET STRING etc.) this value has, regardless + * of its tagging. + * But opposed to the time an ASN.1 type is to be encoded, when parsing + * them it is not possible to deduce the "real type" of tagged + * values. This is why tagged values are generally parsed into ASN1Data + * instances, but with a different outcome for implicit and explicit + * tagging. + * + * === Example of a parsed implicitly tagged value + * + * An implicitly 1-tagged INTEGER value will be parsed as an + * ASN1Data with + * * _tag_ equal to 1 + * * _tag_class_ equal to +:CONTEXT_SPECIFIC+ + * * _value_ equal to a String that carries the raw encoding + * of the INTEGER. + * This implies that a subsequent decoding step is required to + * completely decode implicitly tagged values. + * + * === Example of a parsed explicitly tagged value + * + * An explicitly 1-tagged INTEGER value will be parsed as an + * ASN1Data with + * * _tag_ equal to 1 + * * _tag_class_ equal to +:CONTEXT_SPECIFIC+ + * * _value_ equal to an Array with one single element, an + * instance of OpenSSL::ASN1::Integer, i.e. the inner element + * is the non-tagged primitive value, and the tagging is represented + * in the outer ASN1Data + * + * == Example - Decoding an implicitly tagged INTEGER + * int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) # implicit 0-tagged + * seq = OpenSSL::ASN1::Sequence.new( [int] ) + * der = seq.to_der + * asn1 = OpenSSL::ASN1.decode(der) + * # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0 + * # @indefinite_length=false, + * # @tag=16, + * # @tag_class=:UNIVERSAL, + * # @tagging=nil, + * # @value= + * # [#<OpenSSL::ASN1::ASN1Data:0x87326f4 + * # @indefinite_length=false, + * # @tag=0, + * # @tag_class=:CONTEXT_SPECIFIC, + * # @value="\x01">]> + * raw_int = asn1.value[0] + * # manually rewrite tag and tag class to make it an UNIVERSAL value + * raw_int.tag = OpenSSL::ASN1::INTEGER + * raw_int.tag_class = :UNIVERSAL + * int2 = OpenSSL::ASN1.decode(raw_int) + * puts int2.value # => 1 + * + * == Example - Decoding an explicitly tagged INTEGER + * int = OpenSSL::ASN1::Integer.new(1, 0, :EXPLICIT) # explicit 0-tagged + * seq = OpenSSL::ASN1::Sequence.new( [int] ) + * der = seq.to_der + * asn1 = OpenSSL::ASN1.decode(der) + * # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0 + * # @indefinite_length=false, + * # @tag=16, + * # @tag_class=:UNIVERSAL, + * # @tagging=nil, + * # @value= + * # [#<OpenSSL::ASN1::ASN1Data:0x87326f4 + * # @indefinite_length=false, + * # @tag=0, + * # @tag_class=:CONTEXT_SPECIFIC, + * # @value= + * # [#<OpenSSL::ASN1::Integer:0x85bf308 + * # @indefinite_length=false, + * # @tag=2, + * # @tag_class=:UNIVERSAL + * # @tagging=nil, + * # @value=1>]>]> + * int2 = asn1.value[0].value[0] + * puts int2.value # => 1 + */ cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject); + /* + * Carries the value of a ASN.1 type. + * Please confer Constructive and Primitive for the mappings between + * ASN.1 data types and Ruby classes. + */ rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0); + /* + * An Integer representing the tag number of this ASN1Data. Never +nil+. + */ rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0); + /* + * A Symbol representing the tag class of this ASN1Data. Never +nil+. + * See ASN1Data for possible values. + */ rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0); + /* + * Never +nil+. A boolean value indicating whether the encoding uses + * indefinite length (in the case of parsing) or whether an indefinite + * length form shall be used (in the encoding case). + * In DER, every value uses definite length form. But in scenarios where + * large amounts of data need to be transferred it might be desirable to + * have some kind of streaming support available. + * For example, huge OCTET STRINGs are preferably sent in smaller-sized + * chunks, each at a time. + * This is possible in BER by setting the length bytes of an encoding + * to zero and by this indicating that the following value will be + * sent in chunks. Indefinite length encodings are always constructed. + * The end of such a stream of chunks is indicated by sending a EOC + * (End of Content) tag. SETs and SEQUENCEs may use an indefinite length + * encoding, but also primitive types such as e.g. OCTET STRINGS or + * BIT STRINGS may leverage this functionality (cf. ITU-T X.690). + */ + rb_attr(cASN1Data, rb_intern("indefinite_length"), 1, 1, 0); + rb_define_alias(cASN1Data, "infinite_length", "indefinite_length"); + rb_define_alias(cASN1Data, "infinite_length=", "indefinite_length="); rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3); rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0); + /* Document-class: OpenSSL::ASN1::Primitive + * + * The parent class for all primitive encodings. Attributes are the same as + * for ASN1Data, with the addition of _tagging_. + * Primitive values can never be encoded with indefinite length form, thus + * it is not possible to set the _indefinite_length_ attribute for Primitive + * and its sub-classes. + * + * == Primitive sub-classes and their mapping to Ruby classes + * * OpenSSL::ASN1::EndOfContent <=> _value_ is always +nil+ + * * OpenSSL::ASN1::Boolean <=> _value_ is +true+ or +false+ + * * OpenSSL::ASN1::Integer <=> _value_ is an OpenSSL::BN + * * OpenSSL::ASN1::BitString <=> _value_ is a String + * * OpenSSL::ASN1::OctetString <=> _value_ is a String + * * OpenSSL::ASN1::Null <=> _value_ is always +nil+ + * * OpenSSL::ASN1::Object <=> _value_ is a String + * * OpenSSL::ASN1::Enumerated <=> _value_ is an OpenSSL::BN + * * OpenSSL::ASN1::UTF8String <=> _value_ is a String + * * OpenSSL::ASN1::NumericString <=> _value_ is a String + * * OpenSSL::ASN1::PrintableString <=> _value_ is a String + * * OpenSSL::ASN1::T61String <=> _value_ is a String + * * OpenSSL::ASN1::VideotexString <=> _value_ is a String + * * OpenSSL::ASN1::IA5String <=> _value_ is a String + * * OpenSSL::ASN1::UTCTime <=> _value_ is a Time + * * OpenSSL::ASN1::GeneralizedTime <=> _value_ is a Time + * * OpenSSL::ASN1::GraphicString <=> _value_ is a String + * * OpenSSL::ASN1::ISO64String <=> _value_ is a String + * * OpenSSL::ASN1::GeneralString <=> _value_ is a String + * * OpenSSL::ASN1::UniversalString <=> _value_ is a String + * * OpenSSL::ASN1::BMPString <=> _value_ is a String + * + * == OpenSSL::ASN1::BitString + * + * === Additional attributes + * _unused_bits_: if the underlying BIT STRING's + * length is a multiple of 8 then _unused_bits_ is 0. Otherwise + * _unused_bits_ indicates the number of bits that are to be ignored in + * the final octet of the BitString's _value_. + * + * == OpenSSL::ASN1::ObjectId + * + * NOTE: 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>. + * * _oid_: the object identifier as a String, e.g. "1.2.3.4.5" + * * _short_name_: alias for _sn_. + * * _long_name_: alias for _ln_. + * + * == Examples + * With the Exception of OpenSSL::ASN1::EndOfContent, each Primitive class + * constructor takes at least one parameter, the _value_. + * + * === Creating EndOfContent + * eoc = OpenSSL::ASN1::EndOfContent.new + * + * === Creating any other Primitive + * prim = <class>.new(value) # <class> being one of the sub-classes except EndOfContent + * prim_zero_tagged_implicit = <class>.new(value, 0, :IMPLICIT) + * prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT) + */ cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data); + /* + * May be used as a hint for encoding a value either implicitly or + * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+. + * _tagging_ is not set when a ASN.1 structure is parsed using + * OpenSSL::ASN1.decode. + */ rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue); + rb_undef_method(cASN1Primitive, "indefinite_length="); + rb_undef_method(cASN1Primitive, "infinite_length="); rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1); rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0); + /* Document-class: OpenSSL::ASN1::Constructive + * + * The parent class for all constructed encodings. The _value_ attribute + * of a Constructive is always an Array. Attributes are the same as + * for ASN1Data, with the addition of _tagging_. + * + * == SET and SEQUENCE + * + * Most constructed encodings come in the form of a SET or a SEQUENCE. + * These encodings are represented by one of the two sub-classes of + * Constructive: + * * OpenSSL::ASN1::Set + * * OpenSSL::ASN1::Sequence + * Please note that tagged sequences and sets are still parsed as + * instances of ASN1Data. Find further details on tagged values + * there. + * + * === Example - constructing a SEQUENCE + * int = OpenSSL::ASN1::Integer.new(1) + * str = OpenSSL::ASN1::PrintableString.new('abc') + * sequence = OpenSSL::ASN1::Sequence.new( [ int, str ] ) + * + * === Example - constructing a SET + * int = OpenSSL::ASN1::Integer.new(1) + * str = OpenSSL::ASN1::PrintableString.new('abc') + * set = OpenSSL::ASN1::Set.new( [ int, str ] ) + */ cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data); rb_include_module(cASN1Constructive, rb_mEnumerable); + /* + * May be used as a hint for encoding a value either implicitly or + * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+. + * _tagging_ is not set when a ASN.1 structure is parsed using + * OpenSSL::ASN1.decode. + */ rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue); rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1); rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0); @@ -1160,11 +1834,54 @@ do{\ OSSL_ASN1_DEFINE_CLASS(Sequence, Constructive); OSSL_ASN1_DEFINE_CLASS(Set, Constructive); + OSSL_ASN1_DEFINE_CLASS(EndOfContent, Data); + + + /* Document-class: OpenSSL::ASN1::ObjectId + * + * Represents the primitive object id for OpenSSL::ASN1 + */ +#if 0 + cASN1ObjectId = rb_define_class_under(mASN1, "ObjectId", cASN1Primitive); /* let rdoc know */ +#endif rb_define_singleton_method(cASN1ObjectId, "register", ossl_asn1obj_s_register, 3); rb_define_method(cASN1ObjectId, "sn", ossl_asn1obj_get_sn, 0); rb_define_method(cASN1ObjectId, "ln", ossl_asn1obj_get_ln, 0); rb_define_method(cASN1ObjectId, "oid", ossl_asn1obj_get_oid, 0); rb_define_alias(cASN1ObjectId, "short_name", "sn"); rb_define_alias(cASN1ObjectId, "long_name", "ln"); + rb_define_method(cASN1ObjectId, "==", ossl_asn1obj_eq, 1); rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0); + + rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0); + rb_define_method(cASN1EndOfContent, "to_der", ossl_asn1eoc_to_der, 0); + + class_tag_map = rb_hash_new(); + rb_gc_register_mark_object(class_tag_map); + rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC)); + rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN)); + rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER)); + rb_hash_aset(class_tag_map, cASN1BitString, INT2NUM(V_ASN1_BIT_STRING)); + rb_hash_aset(class_tag_map, cASN1OctetString, INT2NUM(V_ASN1_OCTET_STRING)); + rb_hash_aset(class_tag_map, cASN1Null, INT2NUM(V_ASN1_NULL)); + rb_hash_aset(class_tag_map, cASN1ObjectId, INT2NUM(V_ASN1_OBJECT)); + rb_hash_aset(class_tag_map, cASN1Enumerated, INT2NUM(V_ASN1_ENUMERATED)); + rb_hash_aset(class_tag_map, cASN1UTF8String, INT2NUM(V_ASN1_UTF8STRING)); + rb_hash_aset(class_tag_map, cASN1Sequence, INT2NUM(V_ASN1_SEQUENCE)); + rb_hash_aset(class_tag_map, cASN1Set, INT2NUM(V_ASN1_SET)); + rb_hash_aset(class_tag_map, cASN1NumericString, INT2NUM(V_ASN1_NUMERICSTRING)); + rb_hash_aset(class_tag_map, cASN1PrintableString, INT2NUM(V_ASN1_PRINTABLESTRING)); + rb_hash_aset(class_tag_map, cASN1T61String, INT2NUM(V_ASN1_T61STRING)); + rb_hash_aset(class_tag_map, cASN1VideotexString, INT2NUM(V_ASN1_VIDEOTEXSTRING)); + rb_hash_aset(class_tag_map, cASN1IA5String, INT2NUM(V_ASN1_IA5STRING)); + rb_hash_aset(class_tag_map, cASN1UTCTime, INT2NUM(V_ASN1_UTCTIME)); + rb_hash_aset(class_tag_map, cASN1GeneralizedTime, INT2NUM(V_ASN1_GENERALIZEDTIME)); + rb_hash_aset(class_tag_map, cASN1GraphicString, INT2NUM(V_ASN1_GRAPHICSTRING)); + rb_hash_aset(class_tag_map, cASN1ISO64String, INT2NUM(V_ASN1_ISO64STRING)); + rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING)); + rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING)); + rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING)); + rb_obj_freeze(class_tag_map); + + id_each = rb_intern_const("each"); } diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h index 8aad9f970d..b605df8f3f 100644 --- a/ext/openssl/ossl_asn1.h +++ b/ext/openssl/ossl_asn1.h @@ -1,12 +1,11 @@ /* - * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_ASN1_H_) #define _OSSL_ASN1_H_ @@ -14,45 +13,45 @@ /* * ASN1_DATE conversions */ -VALUE asn1time_to_time(ASN1_TIME *); -time_t time_to_time_t(VALUE); +VALUE asn1time_to_time(const ASN1_TIME *); +/* 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 *); /* * 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 *); /* + * ASN1_OBJECT conversions + */ +ASN1_OBJECT *ossl_to_asn1obj(VALUE obj); +/* + * Returns the short name if available, the dotted decimal notation otherwise. + * This is the most common way to return ASN1_OBJECT to Ruby. + */ +VALUE ossl_asn1obj_to_string(const ASN1_OBJECT *a1obj); +/* + * However, some places use long names instead. This is likely unintentional, + * but we keep the current behavior in existing methods. + */ +VALUE ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *a1obj); + +/* * ASN1 module */ extern VALUE mASN1; -extern VALUE eASN1Error; extern VALUE cASN1Data; -extern VALUE cASN1Primitive; -extern VALUE cASN1Constructive; - -extern VALUE cASN1Boolean; /* BOOLEAN */ -extern VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */ -extern VALUE cASN1BitString; /* BIT STRING */ -extern VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */ -extern VALUE cASN1NumericString, cASN1PrintableString; -extern VALUE cASN1T61String, cASN1VideotexString; -extern VALUE cASN1IA5String, cASN1GraphicString; -extern VALUE cASN1ISO64String, cASN1GeneralString; -extern VALUE cASN1UniversalString, cASN1BMPString; -extern VALUE cASN1Null; /* NULL */ -extern VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */ -extern VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */ -extern VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */ - -ASN1_TYPE *ossl_asn1_get_asn1type(VALUE); void Init_ossl_asn1(void); diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c index 6db1fb9a62..4edde5091d 100644 --- a/ext/openssl/ossl_bio.c +++ b/ext/openssl/ossl_bio.c @@ -1,86 +1,42 @@ /* - * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif BIO * -ossl_obj2bio(VALUE obj) +ossl_obj2bio(volatile VALUE *pobj) { + VALUE obj = *pobj; BIO *bio; - if (TYPE(obj) == T_FILE) { - rb_io_t *fptr; - FILE *fp; - int fd; - - GetOpenFile(obj, fptr); - rb_io_check_readable(fptr); - if ((fd = dup(FPTR_TO_FD(fptr))) < 0){ - rb_sys_fail(0); - } - if (!(fp = fdopen(fd, "r"))){ - close(fd); - rb_sys_fail(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_LEN(obj)); - if (!bio) ossl_raise(eOSSLError, NULL); - } - + if (RB_TYPE_P(obj, T_FILE)) + obj = rb_funcallv(obj, rb_intern("read"), 0, NULL); + StringValue(obj); + bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj)); + if (!bio) + ossl_raise(eOSSLError, "BIO_new_mem_buf"); + *pobj = obj; return bio; } -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) +ossl_membio2str(BIO *bio) { VALUE ret; + int state; BUF_MEM *buf; BIO_get_mem_ptr(bio, &buf); - ret = rb_str_new(buf->data, buf->length); - - return ret; -} - -VALUE -ossl_protect_membio2str(BIO *bio, int *status) -{ - return rb_protect((VALUE(*)_((VALUE)))ossl_membio2str0, (VALUE)bio, status); -} - -VALUE -ossl_membio2str(BIO *bio) -{ - VALUE ret; - int status = 0; - - ret = ossl_protect_membio2str(bio, &status); + ret = ossl_str_new(buf->data, buf->length, &state); BIO_free(bio); - if(status) rb_jump_tag(status); + if (state) + rb_jump_tag(state); return ret; } diff --git a/ext/openssl/ossl_bio.h b/ext/openssl/ossl_bio.h index 2d8f675c5b..1b871f1cd7 100644 --- a/ext/openssl/ossl_bio.h +++ b/ext/openssl/ossl_bio.h @@ -1,21 +1,16 @@ /* - * $Id$ * 'OpenSSL for Ruby' team members * Copyright (C) 2003 * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_BIO_H_) #define _OSSL_BIO_H_ -BIO *ossl_obj2bio(VALUE); -BIO *ossl_protect_obj2bio(VALUE,int*); -VALUE ossl_membio2str0(BIO*); +BIO *ossl_obj2bio(volatile VALUE *); VALUE ossl_membio2str(BIO*); -VALUE ossl_protect_membio2str(BIO*,int*); #endif - diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index 60d9e552a4..9014f2df2b 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -1,40 +1,55 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Technorama team <oss-ruby@technorama.net> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ /* modified by Michal Rokos <m.rokos@sh.cvut.cz> */ #include "ossl.h" -#define WrapBN(klass, obj, bn) do { \ - if (!bn) { \ - ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \ - } \ - obj = Data_Wrap_Struct(klass, 0, BN_clear_free, bn); \ +#define NewBN(klass) \ + TypedData_Wrap_Struct((klass), &ossl_bn_type, 0) +#define SetBN(obj, bn) do { \ + if (!(bn)) { \ + ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \ + } \ + RTYPEDDATA_DATA(obj) = (bn); \ } while (0) #define GetBN(obj, bn) do { \ - Data_Get_Struct(obj, BIGNUM, bn); \ - if (!bn) { \ - ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \ - } \ + TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \ + if (!(bn)) { \ + ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \ + } \ } while (0) -#define SafeGetBN(obj, bn) do { \ - OSSL_Check_Kind(obj, cBN); \ - GetBN(obj, bn); \ -} while (0) +static void +ossl_bn_free(void *ptr) +{ + BN_clear_free(ptr); +} + +static const rb_data_type_t ossl_bn_type = { + "OpenSSL/BN", + { + 0, ossl_bn_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE, +}; /* * Classes */ VALUE cBN; -VALUE eBNError; + +/* Document-class: OpenSSL::BNError + * + * Generic Error for all of OpenSSL::BN (big num) + */ +static VALUE eBNError; /* * Public @@ -45,67 +60,187 @@ ossl_bn_new(const BIGNUM *bn) BIGNUM *newbn; VALUE obj; - newbn = bn ? BN_dup(bn) : BN_new(); - if (!newbn) { - ossl_raise(eBNError, NULL); - } - WrapBN(cBN, obj, newbn); + obj = NewBN(cBN); + newbn = BN_dup(bn); + if (!newbn) + ossl_raise(eBNError, "BN_dup"); + SetBN(obj, newbn); return obj; } -BIGNUM * -GetBNPtr(VALUE obj) -{ - BIGNUM *bn = NULL; - - 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); - if (!BN_dec2bn(&bn, StringValuePtr(obj))) { - ossl_raise(eBNError, NULL); - } - WrapBN(cBN, obj, bn); /* Handle potencial mem leaks */ - break; - default: - ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN"); +static BIGNUM * +integer_to_bnptr(VALUE obj, BIGNUM *orig) +{ + BIGNUM *bn; + + 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; + } + + 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 potential mem leaks */ + bn = integer_to_bnptr(obj, NULL); + SetBN(newobj, bn); + } + + return newobj; +} + +BIGNUM * +ossl_bn_value_ptr(volatile VALUE *ptr) +{ + 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; } /* * Private */ -/* - * BN_CTX - is used in more difficult math. ops - * (Why just 1? Because Ruby itself isn't thread safe, - * we don't need to care about threads) - */ -BN_CTX *ossl_bn_ctx; + +#ifdef HAVE_RB_EXT_RACTOR_SAFE +static void +ossl_bn_ctx_free(void *ptr) +{ + BN_CTX *ctx = (BN_CTX *)ptr; + BN_CTX_free(ctx); +} + +static struct rb_ractor_local_storage_type ossl_bn_ctx_key_type = { + NULL, // mark + ossl_bn_ctx_free, +}; + +static rb_ractor_local_key_t ossl_bn_ctx_key; + +BN_CTX * +ossl_bn_ctx_get(void) +{ + // stored in ractor local storage + + BN_CTX *ctx = rb_ractor_local_storage_ptr(ossl_bn_ctx_key); + if (!ctx) { + if (!(ctx = BN_CTX_new())) { + ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX"); + } + rb_ractor_local_storage_ptr_set(ossl_bn_ctx_key, ctx); + } + return ctx; +} +#else +// for ruby 2.x +static BN_CTX *gv_ossl_bn_ctx; + +BN_CTX * +ossl_bn_ctx_get(void) +{ + if (gv_ossl_bn_ctx == NULL) { + if (!(gv_ossl_bn_ctx = BN_CTX_new())) { + ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX"); + } + } + return gv_ossl_bn_ctx; +} + +void +ossl_bn_ctx_free(void) +{ + BN_CTX_free(gv_ossl_bn_ctx); + gv_ossl_bn_ctx = NULL; +} +#endif static VALUE ossl_bn_alloc(VALUE klass) { BIGNUM *bn; - VALUE obj; - + VALUE obj = NewBN(klass); + if (!(bn = BN_new())) { - ossl_raise(eBNError, NULL); + ossl_raise(eBNError, NULL); } - WrapBN(klass, obj, bn); + SetBN(obj, bn); return obj; } /* * call-seq: - * BN.new => aBN - * BN.new(bn) => aBN - * BN.new(string) => aBN - * BN.new(string, 0 | 2 | 10 | 16) => aBN + * OpenSSL::BN.new(bn) -> aBN + * OpenSSL::BN.new(integer) -> aBN + * OpenSSL::BN.new(string, base = 10) -> aBN + * + * Construct a new \OpenSSL BIGNUM object. + * + * If +bn+ is an Integer or OpenSSL::BN, a new instance of OpenSSL::BN + * representing the same value is returned. See also Integer#to_bn for the + * short-hand. + * + * If a String is given, the content will be parsed according to +base+. + * + * +string+:: + * The string to be parsed. + * +base+:: + * The format. Must be one of the following: + * - +0+ - MPI format. See the man page BN_mpi2bn(3) for details. + * - +2+ - Variable-length and big-endian binary encoding of a positive + * number. + * - +10+ - Decimal number representation, with a leading '-' for a negative + * number. + * - +16+ - Hexadecimal number representation, with a leading '-' for a + * negative number. */ static VALUE ossl_bn_initialize(int argc, VALUE *argv, VALUE self) @@ -113,61 +248,82 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) BIGNUM *bn; VALUE str, bs; int base = 10; + char *ptr; if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) { - base = NUM2INT(bs); + base = NUM2INT(bs); } - StringValue(str); - GetBN(self, bn); - if (RTEST(rb_obj_is_kind_of(str, cBN))) { - BIGNUM *other; - GetBN(str, other); /* Safe - we checked kind_of? above */ - if (!BN_copy(bn, other)) { - ossl_raise(eBNError, NULL); - } - return self; + if (NIL_P(str)) { + ossl_raise(rb_eArgError, "invalid argument"); } + rb_check_frozen(self); + if (RB_INTEGER_TYPE_P(str)) { + GetBN(self, bn); + integer_to_bnptr(str, bn); + + return self; + } + + if (RTEST(rb_obj_is_kind_of(str, cBN))) { + BIGNUM *other; + + GetBN(self, bn); + GetBN(str, other); /* Safe - we checked kind_of? above */ + if (!BN_copy(bn, other)) { + ossl_raise(eBNError, NULL); + } + return self; + } + + GetBN(self, bn); switch (base) { - case 0: - if (!BN_mpi2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) { - ossl_raise(eBNError, NULL); - } - break; - case 2: - if (!BN_bin2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) { - ossl_raise(eBNError, NULL); - } - break; - case 10: - if (!BN_dec2bn(&bn, RSTRING_PTR(str))) { - ossl_raise(eBNError, NULL); - } - break; - case 16: - if (!BN_hex2bn(&bn, RSTRING_PTR(str))) { - ossl_raise(eBNError, NULL); - } - break; - default: - ossl_raise(rb_eArgError, "illegal radix %d", base); + case 0: + ptr = StringValuePtr(str); + if (!BN_mpi2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) { + ossl_raise(eBNError, NULL); + } + break; + case 2: + ptr = StringValuePtr(str); + if (!BN_bin2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) { + ossl_raise(eBNError, NULL); + } + break; + case 10: + if (!BN_dec2bn(&bn, StringValueCStr(str))) { + ossl_raise(eBNError, NULL); + } + break; + case 16: + if (!BN_hex2bn(&bn, StringValueCStr(str))) { + ossl_raise(eBNError, NULL); + } + break; + default: + ossl_raise(rb_eArgError, "invalid radix %d", base); } return self; } /* * call-seq: - * bn.to_s => string - * bn.to_s(base) => string + * bn.to_s(base = 10) -> string * - * === Parameters - * * +base+ - integer - * * * Valid values: - * * * * 0 - MPI - * * * * 2 - binary - * * * * 10 - the default - * * * * 16 - hex + * Returns the string representation of the bignum. + * + * BN.new can parse the encoded string to convert back into an OpenSSL::BN. + * + * +base+:: + * The format. Must be one of the following: + * - +0+ - MPI format. See the man page BN_bn2mpi(3) for details. + * - +2+ - Variable-length and big-endian binary encoding. The sign of + * the bignum is ignored. + * - +10+ - Decimal number representation, with a leading '-' for a negative + * bignum. + * - +16+ - Hexadecimal number representation, with a leading '-' for a + * negative bignum. */ static VALUE ossl_bn_to_s(int argc, VALUE *argv, VALUE self) @@ -178,32 +334,32 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self) char *buf; if (rb_scan_args(argc, argv, "01", &bs) == 1) { - base = NUM2INT(bs); + base = NUM2INT(bs); } GetBN(self, bn); switch (base) { - case 0: - len = BN_bn2mpi(bn, NULL); + case 0: + len = BN_bn2mpi(bn, NULL); str = rb_str_new(0, len); - if (BN_bn2mpi(bn, RSTRING_PTR(str)) != len) - ossl_raise(eBNError, NULL); - break; - case 2: - len = BN_num_bytes(bn); + if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len) + ossl_raise(eBNError, NULL); + break; + case 2: + len = BN_num_bytes(bn); str = rb_str_new(0, len); - if (BN_bn2bin(bn, RSTRING_PTR(str)) != len) - ossl_raise(eBNError, NULL); - break; - case 10: - if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL); - str = ossl_buf2str(buf, strlen(buf)); - break; - case 16: - if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL); - str = ossl_buf2str(buf, strlen(buf)); - break; - default: - ossl_raise(rb_eArgError, "illegal radix %d", base); + if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len) + ossl_raise(eBNError, NULL); + break; + case 10: + if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL); + str = ossl_buf2str(buf, rb_long2int(strlen(buf))); + break; + case 16: + if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL); + str = ossl_buf2str(buf, rb_long2int(strlen(buf))); + break; + default: + ossl_raise(rb_eArgError, "invalid radix %d", base); } return str; @@ -222,10 +378,10 @@ ossl_bn_to_i(VALUE self) GetBN(self, bn); - if (!(txt = BN_bn2dec(bn))) { - ossl_raise(eBNError, NULL); + if (!(txt = BN_bn2hex(bn))) { + ossl_raise(eBNError, NULL); } - num = rb_cstr_to_inum(txt, 10, Qtrue); + num = rb_cstr_to_inum(txt, 16, Qtrue); OPENSSL_free(txt); return num; @@ -241,200 +397,332 @@ static VALUE ossl_bn_coerce(VALUE self, VALUE other) { switch(TYPE(other)) { - case T_STRING: - self = ossl_bn_to_s(0, NULL, self); - break; - case T_FIXNUM: - case T_BIGNUM: - self = ossl_bn_to_i(self); - break; - default: - if (!RTEST(rb_obj_is_kind_of(other, cBN))) { - ossl_raise(rb_eTypeError, "Don't know how to coerce"); - } + case T_STRING: + self = ossl_bn_to_s(0, NULL, self); + break; + case T_FIXNUM: + case T_BIGNUM: + self = ossl_bn_to_i(self); + break; + default: + if (!RTEST(rb_obj_is_kind_of(other, cBN))) { + ossl_raise(rb_eTypeError, "Don't know how to coerce"); + } } return rb_assoc_new(other, self); } -#define BIGNUM_BOOL1(func) \ - /* \ - * call-seq: \ - * bn.##func -> true | false \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self) \ - { \ - BIGNUM *bn; \ - GetBN(self, bn); \ - if (BN_##func(bn)) { \ - return Qtrue; \ - } \ - return Qfalse; \ - } -BIGNUM_BOOL1(is_zero); -BIGNUM_BOOL1(is_one); -BIGNUM_BOOL1(is_odd); - -#define BIGNUM_1c(func) \ - /* \ - * call-seq: \ - * bn.##func -> aBN \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self) \ - { \ - BIGNUM *bn, *result; \ - VALUE obj; \ - GetBN(self, bn); \ - if (!(result = BN_new())) { \ - ossl_raise(eBNError, NULL); \ - } \ - if (!BN_##func(result, bn, ossl_bn_ctx)) { \ - BN_free(result); \ - ossl_raise(eBNError, NULL); \ - } \ - WrapBN(CLASS_OF(self), obj, result); \ - return obj; \ - } -BIGNUM_1c(sqr); - -#define BIGNUM_2(func) \ - /* \ - * call-seq: \ - * bn.##func(bn2) -> aBN \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self, VALUE other) \ - { \ - BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ - VALUE obj; \ - GetBN(self, bn1); \ - if (!(result = BN_new())) { \ - ossl_raise(eBNError, NULL); \ - } \ - if (!BN_##func(result, bn1, bn2)) { \ - BN_free(result); \ - ossl_raise(eBNError, NULL); \ - } \ - WrapBN(CLASS_OF(self), obj, result); \ - return obj; \ - } -BIGNUM_2(add); -BIGNUM_2(sub); - -#define BIGNUM_2c(func) \ - /* \ - * call-seq: \ - * bn.##func(bn2) -> aBN \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self, VALUE other) \ - { \ - BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ - VALUE obj; \ - GetBN(self, bn1); \ - if (!(result = BN_new())) { \ - ossl_raise(eBNError, NULL); \ - } \ - if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \ - BN_free(result); \ - ossl_raise(eBNError, NULL); \ - } \ - WrapBN(CLASS_OF(self), obj, result); \ - return obj; \ - } -BIGNUM_2c(mul); -BIGNUM_2c(mod); -BIGNUM_2c(exp); -BIGNUM_2c(gcd); -BIGNUM_2c(mod_sqr); -BIGNUM_2c(mod_inverse); +#define BIGNUM_BOOL1(func) \ + static VALUE \ + ossl_bn_##func(VALUE self) \ + { \ + BIGNUM *bn; \ + GetBN(self, bn); \ + if (BN_##func(bn)) { \ + return Qtrue; \ + } \ + return Qfalse; \ + } + +/* + * 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) + +/* + * call-seq: + * bn.negative? => true | false + */ +static VALUE +ossl_bn_is_negative(VALUE self) +{ + BIGNUM *bn; + + GetBN(self, bn); + if (BN_is_zero(bn)) + return Qfalse; + return BN_is_negative(bn) ? Qtrue : Qfalse; +} + +#define BIGNUM_1c(func) \ + static VALUE \ + ossl_bn_##func(VALUE self) \ + { \ + BIGNUM *bn, *result; \ + VALUE obj; \ + GetBN(self, bn); \ + obj = NewBN(rb_obj_class(self)); \ + if (!(result = BN_new())) { \ + ossl_raise(eBNError, NULL); \ + } \ + if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \ + BN_free(result); \ + ossl_raise(eBNError, NULL); \ + } \ + SetBN(obj, result); \ + return obj; \ + } + +/* + * Document-method: OpenSSL::BN#sqr + * call-seq: + * bn.sqr => aBN + */ +BIGNUM_1c(sqr) + +#define BIGNUM_2(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE other) \ + { \ + BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ + VALUE obj; \ + GetBN(self, bn1); \ + obj = NewBN(rb_obj_class(self)); \ + if (!(result = BN_new())) { \ + ossl_raise(eBNError, NULL); \ + } \ + if (BN_##func(result, bn1, bn2) <= 0) { \ + BN_free(result); \ + ossl_raise(eBNError, NULL); \ + } \ + SetBN(obj, result); \ + return obj; \ + } + +/* + * Document-method: OpenSSL::BN#+ + * call-seq: + * bn + bn2 => aBN + */ +BIGNUM_2(add) + +/* + * Document-method: OpenSSL::BN#- + * call-seq: + * bn - bn2 => aBN + */ +BIGNUM_2(sub) + +#define BIGNUM_2c(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE other) \ + { \ + BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ + VALUE obj; \ + GetBN(self, bn1); \ + obj = NewBN(rb_obj_class(self)); \ + if (!(result = BN_new())) { \ + ossl_raise(eBNError, NULL); \ + } \ + if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \ + BN_free(result); \ + ossl_raise(eBNError, NULL); \ + } \ + SetBN(obj, result); \ + return obj; \ + } + +/* + * 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) + +#define BIGNUM_2cr(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE other) \ + { \ + BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ + VALUE obj; \ + GetBN(self, bn1); \ + obj = NewBN(rb_obj_class(self)); \ + if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \ + ossl_raise(eBNError, NULL); \ + SetBN(obj, result); \ + return obj; \ + } + +/* + * Document-method: OpenSSL::BN#mod_sqrt + * call-seq: + * bn.mod_sqrt(bn2) => aBN + */ +BIGNUM_2cr(mod_sqrt) + +/* + * Document-method: OpenSSL::BN#mod_inverse + * call-seq: + * bn.mod_inverse(bn2) => aBN + */ +BIGNUM_2cr(mod_inverse) /* * call-seq: * bn1 / bn2 => [result, remainder] + * + * Division of OpenSSL::BN instances */ 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); + klass = rb_obj_class(self); + obj1 = NewBN(klass); + obj2 = NewBN(klass); if (!(r1 = BN_new())) { - ossl_raise(eBNError, NULL); + ossl_raise(eBNError, NULL); } if (!(r2 = BN_new())) { - BN_free(r1); - ossl_raise(eBNError, NULL); + BN_free(r1); + ossl_raise(eBNError, NULL); } if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) { - BN_free(r1); - BN_free(r2); - ossl_raise(eBNError, NULL); + BN_free(r1); + BN_free(r2); + ossl_raise(eBNError, NULL); } - WrapBN(CLASS_OF(self), obj1, r1); - WrapBN(CLASS_OF(self), obj2, r2); - + SetBN(obj1, r1); + SetBN(obj2, r2); + return rb_ary_new3(2, obj1, obj2); } -#define BIGNUM_3c(func) \ - /* \ - * call-seq: \ - * bn.##func(bn1, bn2) -> aBN \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \ - { \ - BIGNUM *bn1, *bn2 = GetBNPtr(other1); \ - BIGNUM *bn3 = GetBNPtr(other2), *result; \ - VALUE obj; \ - GetBN(self, bn1); \ - if (!(result = BN_new())) { \ - ossl_raise(eBNError, NULL); \ - } \ - if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \ - BN_free(result); \ - ossl_raise(eBNError, NULL); \ - } \ - WrapBN(CLASS_OF(self), obj, result); \ - return obj; \ - } -BIGNUM_3c(mod_add); -BIGNUM_3c(mod_sub); -BIGNUM_3c(mod_mul); -BIGNUM_3c(mod_exp); - -#define BIGNUM_BIT(func) \ - /* \ - * call-seq: \ - * bn.##func(bit) -> self \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self, VALUE bit) \ - { \ - BIGNUM *bn; \ - GetBN(self, bn); \ - if (!BN_##func(bn, NUM2INT(bit))) { \ - ossl_raise(eBNError, NULL); \ - } \ - return self; \ - } -BIGNUM_BIT(set_bit); -BIGNUM_BIT(clear_bit); -BIGNUM_BIT(mask_bits); - -/* - * call-seq: - * bn.bit_set?(bit) => true | false +#define BIGNUM_3c(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \ + { \ + BIGNUM *bn1, *bn2 = GetBNPtr(other1); \ + BIGNUM *bn3 = GetBNPtr(other2), *result; \ + VALUE obj; \ + GetBN(self, bn1); \ + obj = NewBN(rb_obj_class(self)); \ + if (!(result = BN_new())) { \ + ossl_raise(eBNError, NULL); \ + } \ + if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \ + BN_free(result); \ + ossl_raise(eBNError, NULL); \ + } \ + SetBN(obj, result); \ + return obj; \ + } + +/* + * 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) + +#define BIGNUM_BIT(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE bit) \ + { \ + BIGNUM *bn; \ + rb_check_frozen(self); \ + GetBN(self, bn); \ + if (BN_##func(bn, NUM2INT(bit)) <= 0) { \ + ossl_raise(eBNError, NULL); \ + } \ + return self; \ + } + +/* + * 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) + +/* + * call-seq: + * bn.bit_set?(bit) => true | false + * + * Tests bit _bit_ in _bn_ and returns +true+ if set, +false+ if not set. */ static VALUE ossl_bn_is_bit_set(VALUE self, VALUE bit) @@ -445,125 +733,146 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit) b = NUM2INT(bit); GetBN(self, bn); if (BN_is_bit_set(bn, b)) { - return Qtrue; + return Qtrue; } return Qfalse; } -#define BIGNUM_SHIFT(func) \ - /* \ - * call-seq: \ - * bn.##func(bits) -> aBN \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self, VALUE bits) \ - { \ - BIGNUM *bn, *result; \ - int b; \ - VALUE obj; \ - b = NUM2INT(bits); \ - GetBN(self, bn); \ - if (!(result = BN_new())) { \ - ossl_raise(eBNError, NULL); \ - } \ - if (!BN_##func(result, bn, b)) { \ - BN_free(result); \ - ossl_raise(eBNError, NULL); \ - } \ - WrapBN(CLASS_OF(self), obj, result); \ - return obj; \ - } -BIGNUM_SHIFT(lshift); -BIGNUM_SHIFT(rshift); - -#define BIGNUM_SELF_SHIFT(func) \ - /* \ - * call-seq: \ - * bn.##func!(bits) -> self \ - * \ - */ \ - static VALUE \ - ossl_bn_self_##func(VALUE self, VALUE bits) \ - { \ - BIGNUM *bn; \ - int b; \ - b = NUM2INT(bits); \ - GetBN(self, bn); \ - if (!BN_##func(bn, bn, b)) \ - ossl_raise(eBNError, NULL); \ - return self; \ - } -BIGNUM_SELF_SHIFT(lshift); -BIGNUM_SELF_SHIFT(rshift); - -#define BIGNUM_RAND(func) \ - /* \ - * call-seq: \ - * BN.##func(bits [, fill [, odd]]) -> aBN \ - * \ - */ \ - static VALUE \ - ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \ - { \ - BIGNUM *result; \ - int bottom = 0, top = 0, b; \ - VALUE bits, fill, odd, obj; \ - \ - switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { \ - case 3: \ - bottom = (odd == Qtrue) ? 1 : 0; \ - /* FALLTHROUGH */ \ - case 2: \ - top = FIX2INT(fill); \ - } \ - b = NUM2INT(bits); \ - if (!(result = BN_new())) { \ - ossl_raise(eBNError, NULL); \ - } \ - if (!BN_##func(result, b, top, bottom)) { \ - BN_free(result); \ - ossl_raise(eBNError, NULL); \ - } \ - WrapBN(klass, obj, result); \ - return obj; \ - } -BIGNUM_RAND(rand); -BIGNUM_RAND(pseudo_rand); - -#define BIGNUM_RAND_RANGE(func) \ - /* \ - * call-seq: \ - * BN.##func(range) -> aBN \ - * \ - */ \ - static VALUE \ - ossl_bn_s_##func##_range(VALUE klass, VALUE range) \ - { \ - BIGNUM *bn = GetBNPtr(range), *result; \ - VALUE obj; \ - if (!(result = BN_new())) { \ - ossl_raise(eBNError, NULL); \ - } \ - if (!BN_##func##_range(result, bn)) { \ - BN_free(result); \ - ossl_raise(eBNError, NULL); \ - } \ - WrapBN(klass, obj, result); \ - return obj; \ - } -BIGNUM_RAND_RANGE(rand); -BIGNUM_RAND_RANGE(pseudo_rand); +#define BIGNUM_SHIFT(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE bits) \ + { \ + BIGNUM *bn, *result; \ + int b; \ + VALUE obj; \ + b = NUM2INT(bits); \ + GetBN(self, bn); \ + obj = NewBN(rb_obj_class(self)); \ + if (!(result = BN_new())) { \ + ossl_raise(eBNError, NULL); \ + } \ + if (BN_##func(result, bn, b) <= 0) { \ + BN_free(result); \ + ossl_raise(eBNError, NULL); \ + } \ + SetBN(obj, result); \ + return obj; \ + } + +/* + * Document-method: OpenSSL::BN#<< + * call-seq: + * bn << bits -> aBN + */ +BIGNUM_SHIFT(lshift) + +/* + * Document-method: OpenSSL::BN#>> + * call-seq: + * bn >> bits -> aBN + */ +BIGNUM_SHIFT(rshift) + +#define BIGNUM_SELF_SHIFT(func) \ + static VALUE \ + ossl_bn_self_##func(VALUE self, VALUE bits) \ + { \ + BIGNUM *bn; \ + int b; \ + rb_check_frozen(self); \ + b = NUM2INT(bits); \ + GetBN(self, bn); \ + if (BN_##func(bn, bn, b) <= 0) \ + ossl_raise(eBNError, NULL); \ + return self; \ + } + +/* + * 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) + +/* + * call-seq: + * BN.rand(bits [, fill [, odd]]) -> aBN + * + * Generates a cryptographically strong pseudo-random number of +bits+. + * + * See also the man page BN_rand(3). + */ +static VALUE +ossl_bn_s_rand(int argc, VALUE *argv, VALUE klass) +{ + BIGNUM *result; + int bottom = 0, top = 0, b; + VALUE bits, fill, odd, obj; + + switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { + case 3: + bottom = (odd == Qtrue) ? 1 : 0; + /* FALLTHROUGH */ + case 2: + top = NUM2INT(fill); + } + b = NUM2INT(bits); + obj = NewBN(klass); + if (!(result = BN_new())) { + ossl_raise(eBNError, "BN_new"); + } + if (BN_rand(result, b, top, bottom) <= 0) { + BN_free(result); + ossl_raise(eBNError, "BN_rand"); + } + SetBN(obj, result); + return obj; +} + +/* + * call-seq: + * BN.rand_range(range) -> aBN + * + * Generates a cryptographically strong pseudo-random number in the range + * 0...+range+. + * + * See also the man page BN_rand_range(3). + */ +static VALUE +ossl_bn_s_rand_range(VALUE klass, VALUE range) +{ + BIGNUM *bn = GetBNPtr(range), *result; + VALUE obj = NewBN(klass); + if (!(result = BN_new())) + ossl_raise(eBNError, "BN_new"); + if (BN_rand_range(result, bn) <= 0) { + BN_free(result); + ossl_raise(eBNError, "BN_rand_range"); + } + SetBN(obj, result); + return obj; +} /* * call-seq: * BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn * + * Generates a random prime number of bit length _bits_. If _safe_ is set to + * +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 - * * +add+ - BN - * * +rem+ - BN + * * _bits_ - integer + * * _safe_ - boolean + * * _add_ - BN + * * _rem_ - BN */ static VALUE ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) @@ -573,85 +882,231 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) VALUE vnum, vsafe, vadd, vrem, obj; rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem); - + num = NUM2INT(vnum); if (vsafe == Qfalse) { - safe = 0; + safe = 0; } if (!NIL_P(vadd)) { - add = GetBNPtr(vadd); - rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem); + add = GetBNPtr(vadd); + rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem); } + obj = NewBN(klass); if (!(result = BN_new())) { - ossl_raise(eBNError, NULL); + ossl_raise(eBNError, NULL); } - if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) { - BN_free(result); - ossl_raise(eBNError, NULL); + if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) { + BN_free(result); + ossl_raise(eBNError, NULL); } - WrapBN(klass, obj, result); - + SetBN(obj, result); + return obj; } -#define BIGNUM_NUM(func) \ - /* \ - * call-seq: \ - * bn.##func -> integer \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self) \ - { \ - BIGNUM *bn; \ - GetBN(self, bn); \ - return INT2FIX(BN_##func(bn)); \ +#define BIGNUM_NUM(func) \ + static VALUE \ + ossl_bn_##func(VALUE self) \ + { \ + BIGNUM *bn; \ + GetBN(self, bn); \ + return INT2NUM(BN_##func(bn)); \ } -BIGNUM_NUM(num_bytes); -BIGNUM_NUM(num_bits); +/* + * 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) + +/* :nodoc: */ static VALUE ossl_bn_copy(VALUE self, VALUE other) { BIGNUM *bn1, *bn2; - + rb_check_frozen(self); - + if (self == other) return self; - + GetBN(self, bn1); bn2 = GetBNPtr(other); - + if (!BN_copy(bn1, bn2)) { - ossl_raise(eBNError, NULL); + ossl_raise(eBNError, NULL); } return self; } -#define BIGNUM_CMP(func) \ - /* \ - * call-seq: \ - * bn.##func(bn2) -> integer \ - * \ - */ \ - static VALUE \ - ossl_bn_##func(VALUE self, VALUE other) \ - { \ - BIGNUM *bn1, *bn2 = GetBNPtr(other); \ - GetBN(self, bn1); \ - return INT2FIX(BN_##func(bn1, bn2)); \ +/* + * call-seq: + * +bn -> aBN + */ +static VALUE +ossl_bn_uplus(VALUE self) +{ + VALUE obj; + BIGNUM *bn1, *bn2; + + GetBN(self, bn1); + obj = NewBN(cBN); + bn2 = BN_dup(bn1); + if (!bn2) + ossl_raise(eBNError, "BN_dup"); + SetBN(obj, bn2); + + return obj; +} + +/* + * call-seq: + * -bn -> aBN + */ +static VALUE +ossl_bn_uminus(VALUE self) +{ + VALUE obj; + BIGNUM *bn1, *bn2; + + GetBN(self, bn1); + obj = NewBN(cBN); + bn2 = BN_dup(bn1); + if (!bn2) + ossl_raise(eBNError, "BN_dup"); + SetBN(obj, bn2); + BN_set_negative(bn2, !BN_is_negative(bn2)); + + return obj; +} + +/* + * call-seq: + * bn.abs -> aBN + */ +static VALUE +ossl_bn_abs(VALUE self) +{ + BIGNUM *bn1; + + GetBN(self, bn1); + if (BN_is_negative(bn1)) { + return ossl_bn_uminus(self); + } + else { + return ossl_bn_uplus(self); + } +} + +#define BIGNUM_CMP(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE other) \ + { \ + BIGNUM *bn1, *bn2 = GetBNPtr(other); \ + GetBN(self, bn1); \ + 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) + +/* + * call-seq: + * bn == obj => true or false + * + * Returns +true+ only if _obj_ has the same value as _bn_. Contrast this + * with OpenSSL::BN#eql?, which requires obj to be OpenSSL::BN. + */ +static VALUE +ossl_bn_eq(VALUE self, VALUE other) +{ + BIGNUM *bn1, *bn2; + + GetBN(self, bn1); + other = try_convert_to_bn(other); + if (NIL_P(other)) + return Qfalse; + GetBN(other, bn2); + + if (!BN_cmp(bn1, bn2)) { + return Qtrue; } -BIGNUM_CMP(cmp); -BIGNUM_CMP(ucmp); + return Qfalse; +} +/* + * call-seq: + * bn.eql?(obj) => true or false + * + * Returns <code>true</code> only if <i>obj</i> is a + * <code>OpenSSL::BN</code> with the same value as <i>bn</i>. Contrast this + * with OpenSSL::BN#==, which performs type conversions. + */ static VALUE ossl_bn_eql(VALUE self, VALUE other) { - if (ossl_bn_cmp(self, other) == INT2FIX(0)) { - return Qtrue; + BIGNUM *bn1, *bn2; + + if (!rb_obj_is_kind_of(other, cBN)) + return Qfalse; + GetBN(self, bn1); + GetBN(other, bn2); + + return BN_cmp(bn1, bn2) ? Qfalse : Qtrue; +} + +/* + * call-seq: + * bn.hash => Integer + * + * Returns a hash code for this object. + * + * See also Object#hash. + */ +static VALUE +ossl_bn_hash(VALUE self) +{ + BIGNUM *bn; + VALUE tmp, hash; + unsigned char *buf; + int len; + + GetBN(self, bn); + len = BN_num_bytes(bn); + buf = ALLOCV(tmp, len); + if (BN_bn2bin(bn, buf) != len) { + ALLOCV_END(tmp); + ossl_raise(eBNError, "BN_bn2bin"); } - return Qfalse; + + hash = ST2FIX(rb_memhash(buf, len)); + ALLOCV_END(tmp); + + return hash; } /* @@ -659,30 +1114,29 @@ ossl_bn_eql(VALUE self, VALUE other) * bn.prime? => true | false * bn.prime?(checks) => true | false * - * === Parameters - * * +checks+ - integer + * Performs a Miller-Rabin probabilistic primality test for +bn+. + * + * <b>+checks+ parameter is deprecated in version 3.0.</b> It has no effect. */ static VALUE ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) { BIGNUM *bn; - VALUE vchecks; - int checks = BN_prime_checks; + int ret; - if (rb_scan_args(argc, argv, "01", &vchecks) == 0) { - checks = NUM2INT(vchecks); - } + rb_check_arity(argc, 0, 1); GetBN(self, bn); - switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) { - case 1: - return Qtrue; - case 0: - return Qfalse; - default: - ossl_raise(eBNError, NULL); - } - /* not reachable */ - return Qnil; + +#ifdef HAVE_BN_CHECK_PRIME + ret = BN_check_prime(bn, ossl_bn_ctx, NULL); + if (ret < 0) + ossl_raise(eBNError, "BN_check_prime"); +#else + ret = BN_is_prime_fasttest_ex(bn, BN_prime_checks, ossl_bn_ctx, 1, NULL); + if (ret < 0) + ossl_raise(eBNError, "BN_is_prime_fasttest_ex"); +#endif + return ret ? Qtrue : Qfalse; } /* @@ -691,36 +1145,53 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) * bn.prime_fasttest?(checks) => true | false * bn.prime_fasttest?(checks, trial_div) => true | false * - * === Parameters - * * +checks+ - integer - * * +trial_div+ - boolean + * Performs a Miller-Rabin probabilistic primality test for +bn+. + * + * <b>Deprecated in version 3.0.</b> Use #prime? instead. + * + * +checks+ and +trial_div+ parameters no longer have any effect. */ static VALUE ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self) { + rb_check_arity(argc, 0, 2); + return ossl_bn_is_prime(0, argv, self); +} + +/* + * call-seq: + * bn.get_flags(flags) => flags + * + * Returns the flags on the BN object. + * The argument is used as a bit mask. + * + * === Parameters + * * _flags_ - integer + */ +static VALUE +ossl_bn_get_flags(VALUE self, VALUE arg) +{ BIGNUM *bn; - VALUE vchecks, vtrivdiv; - int checks = BN_prime_checks, do_trial_division = 1; + GetBN(self, bn); - rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv); + return INT2NUM(BN_get_flags(bn, NUM2INT(arg))); +} - if (!NIL_P(vchecks)) { - checks = NUM2INT(vchecks); - } +/* + * call-seq: + * bn.set_flags(flags) => nil + * + * Enables the flags on the BN object. + * Currently, the flags argument can contain zero of OpenSSL::BN::CONSTTIME. + */ +static VALUE +ossl_bn_set_flags(VALUE self, VALUE arg) +{ + BIGNUM *bn; GetBN(self, bn); - /* handle true/false */ - if (vtrivdiv == Qfalse) { - do_trial_division = 0; - } - switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) { - case 1: - return Qtrue; - case 0: - return Qfalse; - default: - ossl_raise(eBNError, NULL); - } - /* not reachable */ + + rb_check_frozen(self); + BN_set_flags(bn, NUM2INT(arg)); return Qnil; } @@ -729,24 +1200,22 @@ ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self) * (NOTE: ordering of methods is the same as in 'man bn') */ void -Init_ossl_bn() +Init_ossl_bn(void) { -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); +#ifdef HAVE_RB_EXT_RACTOR_SAFE + ossl_bn_ctx_key = rb_ractor_local_storage_ptr_newkey(&ossl_bn_ctx_key_type); +#else + ossl_bn_ctx_get(); #endif - if (!(ossl_bn_ctx = BN_CTX_new())) { - ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX"); - } - eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError); cBN = rb_define_class_under(mOSSL, "BN", rb_cObject); rb_define_alloc_func(cBN, ossl_bn_alloc); rb_define_method(cBN, "initialize", ossl_bn_initialize, -1); - - rb_define_copy_func(cBN, ossl_bn_copy); + + rb_define_method(cBN, "initialize_copy", ossl_bn_copy, 1); rb_define_method(cBN, "copy", ossl_bn_copy, 1); /* swap (=coerce?) */ @@ -755,6 +1224,10 @@ Init_ossl_bn() rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0); /* num_bits_word */ + rb_define_method(cBN, "+@", ossl_bn_uplus, 0); + rb_define_method(cBN, "-@", ossl_bn_uminus, 0); + rb_define_method(cBN, "abs", ossl_bn_abs, 0); + rb_define_method(cBN, "+", ossl_bn_add, 1); rb_define_method(cBN, "-", ossl_bn_sub, 1); rb_define_method(cBN, "*", ossl_bn_mul, 1); @@ -767,6 +1240,7 @@ Init_ossl_bn() rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2); rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2); rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1); + rb_define_method(cBN, "mod_sqrt", ossl_bn_mod_sqrt, 1); rb_define_method(cBN, "**", ossl_bn_exp, 1); rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2); rb_define_method(cBN, "gcd", ossl_bn_gcd, 1); @@ -781,26 +1255,29 @@ Init_ossl_bn() rb_define_alias(cBN, "<=>", "cmp"); rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1); rb_define_method(cBN, "eql?", ossl_bn_eql, 1); - rb_define_alias(cBN, "==", "eql?"); - rb_define_alias(cBN, "===", "eql?"); + rb_define_method(cBN, "hash", ossl_bn_hash, 0); + rb_define_method(cBN, "==", ossl_bn_eq, 1); + rb_define_alias(cBN, "===", "=="); rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0); rb_define_method(cBN, "one?", ossl_bn_is_one, 0); /* is_word */ rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0); + rb_define_method(cBN, "negative?", ossl_bn_is_negative, 0); /* zero * one * value_one - DON'T IMPL. * set_word * get_word */ - + rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1); - rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1); rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1); - rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1); + rb_define_alias(rb_singleton_class(cBN), "pseudo_rand", "rand"); + rb_define_alias(rb_singleton_class(cBN), "pseudo_rand_range", "rand_range"); 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); @@ -813,6 +1290,23 @@ Init_ossl_bn() /* lshift1 - DON'T IMPL. */ /* rshift1 - DON'T IMPL. */ + rb_define_method(cBN, "get_flags", ossl_bn_get_flags, 1); + rb_define_method(cBN, "set_flags", ossl_bn_set_flags, 1); + +#ifdef BN_FLG_CONSTTIME + rb_define_const(cBN, "CONSTTIME", INT2NUM(BN_FLG_CONSTTIME)); +#endif + /* BN_FLG_MALLOCED and BN_FLG_STATIC_DATA seems for C programming. + * Allowing them leads to memory leak. + * So, for now, they are not exported +#ifdef BN_FLG_MALLOCED + rb_define_const(cBN, "MALLOCED", INT2NUM(BN_FLG_MALLOCED)); +#endif +#ifdef BN_FLG_STATIC_DATA + rb_define_const(cBN, "STATIC_DATA", INT2NUM(BN_FLG_STATIC_DATA)); +#endif + */ + /* * bn2bin * bin2bn @@ -830,7 +1324,7 @@ Init_ossl_bn() rb_define_alias(cBN, "to_int", "to_i"); rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0); rb_define_method(cBN, "coerce", ossl_bn_coerce, 1); - + /* * TODO: * But how to: from_bin, from_mpi? PACK? @@ -842,11 +1336,4 @@ Init_ossl_bn() /* 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 d6c396227b..0c186bd1c5 100644 --- a/ext/openssl/ossl_bn.h +++ b/ext/openssl/ossl_bn.h @@ -1,25 +1,25 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_BN_H_) #define _OSSL_BN_H_ extern VALUE cBN; -extern VALUE eBNError; -extern BN_CTX *ossl_bn_ctx; +BN_CTX *ossl_bn_ctx_get(void); +#define ossl_bn_ctx ossl_bn_ctx_get() + +#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); #endif /* _OSS_BN_H_ */ - diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index b680dc6e64..f3cd247c8f 100644 --- a/ext/openssl/ossl_cipher.c +++ b/ext/openssl/ossl_cipher.c @@ -1,47 +1,103 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define MakeCipher(obj, klass, ctx) \ - obj = Data_Make_Struct(klass, EVP_CIPHER_CTX, 0, ossl_cipher_free, ctx) +#define NewCipher(klass) \ + TypedData_Wrap_Struct((klass), &ossl_cipher_type, 0) +#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) #define GetCipher(obj, ctx) do { \ - Data_Get_Struct(obj, EVP_CIPHER_CTX, ctx); \ - if (!ctx) { \ - ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \ + GetCipherInit((obj), (ctx)); \ + if (!(ctx)) { \ + ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \ } \ } while (0) -#define SafeGetCipher(obj, ctx) do { \ - OSSL_Check_Kind(obj, cCipher); \ - GetCipher(obj, ctx); \ -} while (0) /* * Classes */ -VALUE cCipher; -VALUE eCipherError; +static VALUE cCipher; +static VALUE eCipherError; +static VALUE eAuthTagError; +static ID id_auth_tag_len, id_key_set, id_cipher_holder; static VALUE ossl_cipher_alloc(VALUE klass); +static void ossl_cipher_free(void *ptr); + +static const rb_data_type_t ossl_cipher_type = { + "OpenSSL/Cipher", + { + 0, ossl_cipher_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +#ifdef OSSL_USE_PROVIDER +static void +ossl_evp_cipher_free(void *ptr) +{ + // This is safe to call against const EVP_CIPHER * returned by + // EVP_get_cipherbyname() + EVP_CIPHER_free(ptr); +} + +static const rb_data_type_t ossl_evp_cipher_holder_type = { + "OpenSSL/EVP_CIPHER", + { + .dfree = ossl_evp_cipher_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; +#endif /* * PUBLIC */ const EVP_CIPHER * -GetCipherPtr(VALUE obj) +ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder) { - EVP_CIPHER_CTX *ctx; - - SafeGetCipher(obj, ctx); + *holder = Qnil; + if (rb_obj_is_kind_of(obj, cCipher)) { + EVP_CIPHER_CTX *ctx; + GetCipher(obj, ctx); + EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_CIPHER_CTX_cipher(ctx); +#ifdef OSSL_USE_PROVIDER + *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL); + if (!EVP_CIPHER_up_ref(cipher)) + ossl_raise(eCipherError, "EVP_CIPHER_up_ref"); + RTYPEDDATA_DATA(*holder) = cipher; +#endif + return cipher; + } - return EVP_CIPHER_CTX_cipher(ctx); + const char *name = StringValueCStr(obj); + EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name); +#ifdef OSSL_USE_PROVIDER + if (!cipher) { + ossl_clear_error(); + *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL); + cipher = EVP_CIPHER_fetch(NULL, name, NULL); + RTYPEDDATA_DATA(*holder) = cipher; + } +#endif + if (!cipher) + ossl_raise(eCipherError, "unsupported cipher algorithm: %"PRIsVALUE, + obj); + return cipher; } VALUE @@ -50,11 +106,13 @@ ossl_cipher_new(const EVP_CIPHER *cipher) VALUE ret; EVP_CIPHER_CTX *ctx; + // NOTE: This does not set id_cipher_holder because this function should + // only be called from ossl_engine.c, which will not use any + // reference-counted ciphers. ret = ossl_cipher_alloc(cCipher); - GetCipher(ret, ctx); - EVP_CIPHER_CTX_init(ctx); + AllocCipher(ret, ctx); if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) - ossl_raise(eCipherError, NULL); + ossl_raise(eCipherError, NULL); return ret; } @@ -63,31 +121,22 @@ ossl_cipher_new(const EVP_CIPHER *cipher) * PRIVATE */ static void -ossl_cipher_free(EVP_CIPHER_CTX *ctx) +ossl_cipher_free(void *ptr) { - if (ctx) { - EVP_CIPHER_CTX_cleanup(ctx); - free(ctx); - } + EVP_CIPHER_CTX_free(ptr); } static VALUE ossl_cipher_alloc(VALUE klass) { - EVP_CIPHER_CTX *ctx; - VALUE obj; - - MakeCipher(obj, klass, ctx); - EVP_CIPHER_CTX_init(ctx); - - return obj; + return NewCipher(klass); } /* * call-seq: * Cipher.new(string) -> cipher * - * The string must contain a valid cipher name like "AES-128-CBC" or "3DES". + * The string must contain a valid cipher name like "aes-256-cbc". * * A list of cipher names is available by calling OpenSSL::Cipher.ciphers. */ @@ -96,68 +145,74 @@ ossl_cipher_initialize(VALUE self, VALUE str) { EVP_CIPHER_CTX *ctx; const EVP_CIPHER *cipher; - char *name; + VALUE cipher_holder; - name = StringValuePtr(str); - GetCipher(self, ctx); - if (!(cipher = EVP_get_cipherbyname(name))) { - ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name); + GetCipherInit(self, ctx); + if (ctx) { + ossl_raise(rb_eRuntimeError, "Cipher already initialized!"); } + cipher = ossl_evp_cipher_fetch(str, &cipher_holder); + AllocCipher(self, ctx); if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) - ossl_raise(eCipherError, NULL); + ossl_raise(eCipherError, "EVP_CipherInit_ex"); + rb_ivar_set(self, id_cipher_holder, cipher_holder); return self; } + +/* :nodoc: */ static VALUE ossl_cipher_copy(VALUE self, VALUE other) { EVP_CIPHER_CTX *ctx1, *ctx2; - + rb_check_frozen(self); if (self == other) return self; - GetCipher(self, ctx1); - SafeGetCipher(other, ctx2); + GetCipherInit(self, ctx1); + if (!ctx1) { + AllocCipher(self, ctx1); + } + GetCipher(other, ctx2); if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1) - ossl_raise(eCipherError, NULL); + ossl_raise(eCipherError, NULL); return self; } -static void* -add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary) +static void +add_cipher_name_to_ary(const OBJ_NAME *name, void *arg) { + VALUE ary = (VALUE)arg; rb_ary_push(ary, rb_str_new2(name->name)); - return NULL; } /* * call-seq: - * Cipher.ciphers -> array[string...] + * OpenSSL::Cipher.ciphers -> array[string...] * * Returns the names of all available ciphers in an array. */ static VALUE ossl_s_ciphers(VALUE self) { -#ifdef HAVE_OBJ_NAME_DO_ALL_SORTED VALUE ary; ary = rb_ary_new(); OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, - (void(*)(const OBJ_NAME*,void*))add_cipher_name_to_ary, - (void*)ary); + add_cipher_name_to_ary, + (void*)ary); return ary; -#else - rb_notimplement(); -#endif } /* * call-seq: * cipher.reset -> self * + * Fully resets the internal state of the Cipher. By using this, the same + * Cipher instance may be used several times for encryption or decryption tasks. + * * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1). */ static VALUE @@ -167,52 +222,23 @@ ossl_cipher_reset(VALUE self) GetCipher(self, ctx); if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1) - ossl_raise(eCipherError, NULL); - + ossl_raise(eCipherError, NULL); + return self; } static VALUE -ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) +ossl_cipher_init(VALUE self, int enc) { EVP_CIPHER_CTX *ctx; - unsigned char key[EVP_MAX_KEY_LENGTH], *p_key = NULL; - unsigned char iv[EVP_MAX_IV_LENGTH], *p_iv = NULL; - VALUE pass, init_v; - - if(rb_scan_args(argc, argv, "02", &pass, &init_v) > 0){ - /* - * oops. this code mistakes salt for IV. - * We deprecated the arguments for this method, but we decided - * keeping this behaviour for backward compatibility. - */ - char *cname = rb_class2name(rb_obj_class(self)); - rb_warn("argumtents for %s#encrypt and %s#decrypt were deprecated; " - "use %s#pkcs5_keyivgen to derive key and IV", - cname, cname, cname); - StringValue(pass); - GetCipher(self, ctx); - if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv)); - else{ - StringValue(init_v); - if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) { - memset(iv, 0, EVP_MAX_IV_LENGTH); - memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v)); - } - else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv)); - } - EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv, - RSTRING_PTR(pass), RSTRING_LEN(pass), 1, key, NULL); - p_key = key; - p_iv = iv; - } - else { - GetCipher(self, ctx); - } - if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) { - ossl_raise(eCipherError, NULL); + + GetCipher(self, ctx); + if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, enc) != 1) { + ossl_raise(eCipherError, "EVP_CipherInit_ex"); } + rb_ivar_set(self, id_key_set, Qfalse); + return self; } @@ -220,136 +246,174 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) * call-seq: * cipher.encrypt -> self * - * Make sure to call .encrypt or .decrypt before using any of the following methods: - * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] + * Initializes the Cipher for encryption. + * + * Make sure to call either #encrypt or #decrypt before using the Cipher for + * any operation or setting any parameters. * * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1). */ static VALUE -ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self) +ossl_cipher_encrypt(VALUE self) { - return ossl_cipher_init(argc, argv, self, 1); + return ossl_cipher_init(self, 1); } /* * call-seq: * cipher.decrypt -> self * - * Make sure to call .encrypt or .decrypt before using any of the following methods: - * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] + * Initializes the Cipher for decryption. + * + * Make sure to call either #encrypt or #decrypt before using the Cipher for + * any operation or setting any parameters. * * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0). */ static VALUE -ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self) +ossl_cipher_decrypt(VALUE self) { - return ossl_cipher_init(argc, argv, self, 0); + return ossl_cipher_init(self, 0); } /* * 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. + * Generates and sets the key/IV based on a password. * - * 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. Use a PKCS5 v2 key generation method instead. + * *WARNING*: This method is deprecated and should not be used. This method + * corresponds to EVP_BytesToKey(), a non-standard OpenSSL extension of the + * legacy PKCS #5 v1.5 key derivation function. See OpenSSL::KDF for other + * options to derive keys from passwords. * * === 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' - * - * A minimum of 1000 iterations is recommended. - * + * * _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' */ static VALUE ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; const EVP_MD *digest; - VALUE vpass, vsalt, viter, vdigest; + VALUE vpass, vsalt, viter, vdigest, md_holder; unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL; int iter; rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest); StringValue(vpass); if(!NIL_P(vsalt)){ - StringValue(vsalt); - if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN) - rb_raise(eCipherError, "salt must be an 8-octet string"); - salt = RSTRING_PTR(vsalt); + StringValue(vsalt); + if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN) + ossl_raise(eCipherError, "salt must be an 8-octet string"); + salt = (unsigned char *)RSTRING_PTR(vsalt); } iter = NIL_P(viter) ? 2048 : NUM2INT(viter); - digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest); + if (iter <= 0) + rb_raise(rb_eArgError, "iterations must be a positive integer"); + digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_md_fetch(vdigest, &md_holder); GetCipher(self, ctx); EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt, - RSTRING_PTR(vpass), RSTRING_LEN(vpass), iter, key, iv); + (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv); if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1) - ossl_raise(eCipherError, NULL); + ossl_raise(eCipherError, NULL); OPENSSL_cleanse(key, sizeof key); OPENSSL_cleanse(iv, sizeof iv); + rb_ivar_set(self, id_key_set, Qtrue); + return Qnil; } - -/* - * call-seq: - * cipher << data -> string - * - * === Parameters - * +data+ is a nonempty string. - * - * This method is deprecated and not available in 1.9.x or later. - */ -static VALUE -ossl_cipher_update_deprecated(VALUE self, VALUE data) +static int +ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr, + const unsigned char *in, long in_len) { - char *cname; + int out_part_len; + int limit = INT_MAX / 2 + 1; + long out_len = 0; - cname = rb_class2name(rb_obj_class(self)); - rb_warning("%s#<< is deprecated; use %s#update instead", cname, cname); - return rb_funcall(self, rb_intern("update"), 1, data); -} + 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; +} /* * call-seq: * cipher.update(data [, buffer]) -> string or buffer * - * === Parameters - * +data+ is a nonempty string. - * +buffer+ is an optional string to store the result. + * Encrypts data in a streaming fashion. Hand consecutive blocks of data + * to the #update method in order to encrypt it. Returns the encrypted + * data chunk. When done, the output of Cipher#final should be additionally + * added to the result. + * + * If _buffer_ is given, the encryption/decryption result will be written to + * it. _buffer_ will be resized automatically. + * + * *NOTE*: When decrypting using an AEAD cipher, the integrity of the output + * is not verified until #final has been called. */ -static VALUE +static VALUE ossl_cipher_update(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; - char *in; - int in_len, out_len; + unsigned char *in; + long in_len, out_len; VALUE data, str; rb_scan_args(argc, argv, "11", &data, &str); + if (!RTEST(rb_attr_get(self, id_key_set))) + ossl_raise(eCipherError, "key not set"); + StringValue(data); - in = RSTRING_PTR(data); - if ((in_len = RSTRING_LEN(data)) == 0) - rb_raise(rb_eArgError, "data must not be empty"); + in = (unsigned char *)RSTRING_PTR(data); + in_len = RSTRING_LEN(data); GetCipher(self, ctx); - out_len = in_len+EVP_CIPHER_CTX_block_size(ctx); - if (NIL_P(str)) { - str = rb_str_new(0, out_len); - } else { + /* + * As of OpenSSL 3.2, there is no reliable way to determine the required + * output buffer size for arbitrary cipher modes. + * https://github.com/openssl/openssl/issues/22628 + * + * in_len+block_size is usually sufficient, but AES key wrap with padding + * ciphers require in_len+15 even though they have a block size of 8 bytes. + * + * Using EVP_MAX_BLOCK_LENGTH (32) as a safe upper bound for ciphers + * currently implemented in OpenSSL, but this can change in the future. + */ + if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) { + ossl_raise(rb_eRangeError, + "data too big to make output buffer: %ld bytes", in_len); + } + out_len = in_len + EVP_MAX_BLOCK_LENGTH; + + if (NIL_P(str)) + str = rb_str_buf_new(out_len); + else { StringValue(str); - rb_str_resize(str, out_len); + if ((long)rb_str_capacity(str) >= out_len) + rb_str_modify(str); + else + rb_str_modify_expand(str, out_len - RSTRING_LEN(str)); } - if (!EVP_CipherUpdate(ctx, RSTRING_PTR(str), &out_len, in, in_len)) - ossl_raise(eCipherError, NULL); - assert(out_len < RSTRING_LEN(str)); + if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), + &out_len, in, in_len)) + ossl_raise(eCipherError, "EVP_CipherUpdate"); rb_str_set_len(str, out_len); return str; @@ -357,13 +421,22 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) /* * call-seq: - * cipher.final -> aString + * cipher.final -> string + * + * Returns the remaining data held in the cipher object. Further calls to + * Cipher#update or Cipher#final are invalid. This call should always + * be made as the last call of an encryption or decryption operation, after + * having fed the entire plaintext or ciphertext to the Cipher instance. * - * Returns the remaining data held in the cipher object. Further calls to update() or final() will return garbage. + * When encrypting using an AEAD cipher, the authentication tag can be + * retrieved by #auth_tag after #final has been called. * - * See EVP_CipherFinal_ex for further information. + * When decrypting using an AEAD cipher, this method will verify the integrity + * of the ciphertext and the associated data with the authentication tag, + * which must be set by #auth_tag= prior to calling this method. + * If the verification fails, CipherError will be raised. */ -static VALUE +static VALUE ossl_cipher_final(VALUE self) { EVP_CIPHER_CTX *ctx; @@ -372,9 +445,17 @@ ossl_cipher_final(VALUE self) GetCipher(self, ctx); str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx)); - if (!EVP_CipherFinal_ex(ctx, RSTRING_PTR(str), &out_len)) - ossl_raise(eCipherError, NULL); - assert(out_len <= RSTRING_LEN(str)); + if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len)) { + /* For AEAD ciphers, this is likely an authentication failure */ + if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) { + /* For AEAD ciphers, EVP_CipherFinal_ex failures are authentication tag verification failures */ + ossl_raise(eAuthTagError, "AEAD authentication tag verification failed"); + } + else { + /* For non-AEAD ciphers */ + ossl_raise(eCipherError, "cipher final failed"); + } + } rb_str_set_len(str, out_len); return str; @@ -384,7 +465,8 @@ ossl_cipher_final(VALUE self) * call-seq: * cipher.name -> string * - * Returns the name of the cipher which may differ slightly from the original name provided. + * Returns the short name of the cipher which may differ slightly from the + * original name provided. */ static VALUE ossl_cipher_name(VALUE self) @@ -398,63 +480,297 @@ ossl_cipher_name(VALUE self) /* * call-seq: - * cipher.key = string -> string + * cipher.key = string + * + * Sets the cipher key. To generate a key, you should either use a secure + * random byte string or, if the key is to be derived from a password, you + * should rely on PBKDF2 functionality provided by OpenSSL::PKCS5. To + * generate a secure random-based key, Cipher#random_key may be used. * - * Sets the cipher key. + * Only call this method after calling Cipher#encrypt or Cipher#decrypt. * - * Only call this method after calling cipher.encrypt or cipher.decrypt. + * See also the man page EVP_CipherInit_ex(3). */ 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, RSTRING_PTR(key), NULL, -1) != 1) + if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1) ossl_raise(eCipherError, NULL); + rb_ivar_set(self, id_key_set, Qtrue); + return key; } /* * call-seq: - * cipher.iv = string -> string + * cipher.iv = string + * + * Sets the cipher IV. Please note that since you should never be using ECB + * mode, an IV is always explicitly required and should be set prior to + * encryption. The IV itself can be safely transmitted in public. * - * Sets the cipher iv. + * This method expects the String to have the length equal to #iv_len. To use + * a different IV length with an AEAD cipher, #iv_len= must be set prior to + * calling this method. * - * Only call this method after calling cipher.encrypt or cipher.decrypt. + * *NOTE*: In OpenSSL API conventions, the IV value may correspond to the + * "nonce" instead in some cipher modes. Refer to the OpenSSL man pages for + * details. + * + * See also the man page EVP_CipherInit_ex(3). */ 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 (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) + iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); + if (!iv_len) + iv_len = EVP_CIPHER_CTX_iv_length(ctx); + 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, RSTRING_PTR(iv), -1) != 1) - ossl_raise(eCipherError, NULL); + if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1) + ossl_raise(eCipherError, NULL); return iv; } +/* + * call-seq: + * cipher.authenticated? -> true | false + * + * Indicates whether this Cipher instance uses an AEAD mode. + */ +static VALUE +ossl_cipher_is_authenticated(VALUE self) +{ + EVP_CIPHER_CTX *ctx; + + GetCipher(self, ctx); + + return (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse; +} /* * call-seq: - * cipher.key_length = integer -> integer + * cipher.auth_data = string + * + * Sets additional authenticated data (AAD), also called associated data, for + * this Cipher. This method is available for AEAD ciphers. * - * Sets the key length of the cipher. If the cipher is a fixed length cipher then attempting to set the key - * length to any value other than the fixed value is an error. + * The contents of this field should be non-sensitive data which will be + * added to the ciphertext to generate the authentication tag which validates + * the contents of the ciphertext. * - * Under normal circumstances you do not need to call this method (and probably shouldn't). + * This method must be called after #key= and #iv= have been set, but before + * starting actual encryption or decryption with #update. In some cipher modes, + * #auth_tag_len= and #ccm_data_len= may also need to be called before this + * method. + * + * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3). + * This method internally calls EVP_CipherUpdate() with the output buffer + * set to NULL. + */ +static VALUE +ossl_cipher_set_auth_data(VALUE self, VALUE data) +{ + EVP_CIPHER_CTX *ctx; + unsigned char *in; + long in_len, out_len; + + StringValue(data); + + in = (unsigned char *) RSTRING_PTR(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"); + + return data; +} + +/* + * call-seq: + * cipher.auth_tag(tag_len = 16) -> String + * + * Gets the generated authentication tag. This method is available for AEAD + * ciphers, and should be called after encryption has been finalized by calling + * #final. + * + * The returned tag will be _tag_len_ bytes long. Some cipher modes require + * the desired length in advance using a separate call to #auth_tag_len=, + * before starting encryption. + * + * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3). + * This method internally calls EVP_CIPHER_CTX_ctrl() with + * EVP_CTRL_AEAD_GET_TAG. + */ +static VALUE +ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self) +{ + VALUE vtag_len, ret; + EVP_CIPHER_CTX *ctx; + int tag_len = 16; + + 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); + + if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)) + ossl_raise(eCipherError, "authentication tag not supported by this cipher"); + + ret = rb_str_new(NULL, tag_len); + 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; +} + +/* + * call-seq: + * cipher.auth_tag = string + * + * Sets the authentication tag to verify the integrity of the ciphertext. + * + * The authentication tag must be set before #final is called. The tag is + * verified during the #final call. + * + * Note that, for CCM mode and OCB mode, the expected length of the tag must + * be set before starting decryption by a separate call to #auth_tag_len=. + * The content of the tag can be provided at any time before #final is called. + * + * *NOTE*: The caller must ensure that the String passed to this method has + * the desired length. Some cipher modes support variable tag lengths, and + * this method may accept a truncated tag without raising an exception. + * + * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3). + * This method internally calls EVP_CIPHER_CTX_ctrl() with + * EVP_CTRL_AEAD_SET_TAG. + */ +static VALUE +ossl_cipher_set_auth_tag(VALUE self, VALUE vtag) +{ + EVP_CIPHER_CTX *ctx; + unsigned char *tag; + int tag_len; + + StringValue(vtag); + tag = (unsigned char *) RSTRING_PTR(vtag); + tag_len = RSTRING_LENINT(vtag); + + GetCipher(self, ctx); + if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)) + ossl_raise(eCipherError, "authentication tag not supported by this cipher"); + + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag)) + ossl_raise(eCipherError, "unable to set AEAD tag"); + + return vtag; +} + +/* + * call-seq: + * cipher.auth_tag_len = integer + * + * Sets the length of the expected authentication tag for this Cipher. This + * method is available for some of AEAD ciphers that require the length to be + * set before starting encryption or decryption, such as CCM mode or OCB mode. + * + * For CCM mode and OCB mode, the tag length must be set before #iv= is set. + * + * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3). + * This method internally calls EVP_CIPHER_CTX_ctrl() with + * EVP_CTRL_AEAD_SET_TAG and a NULL buffer. + */ +static VALUE +ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen) +{ + int tag_len = NUM2INT(vlen); + EVP_CIPHER_CTX *ctx; + + GetCipher(self, ctx); + if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)) + ossl_raise(eCipherError, "AEAD not supported by this cipher"); + + if (!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 + * + * Sets the IV/nonce length for this Cipher. This method is available for AEAD + * ciphers that support variable IV lengths. This method can be called if a + * different IV length than OpenSSL's default is desired, prior to calling + * #iv=. + * + * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3). + * This method internally calls EVP_CIPHER_CTX_ctrl() with + * EVP_CTRL_AEAD_SET_IVLEN. + */ +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_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)) + ossl_raise(eCipherError, "cipher does not support AEAD"); + + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL)) + 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; +} + +/* + * call-seq: + * cipher.key_len = integer + * + * Sets the key length of the cipher. If the cipher is a fixed length cipher + * then attempting to set the key length to any value other than the fixed + * value is an error. + * + * Under normal circumstances you do not need to call this method (and + * probably shouldn't). * * See EVP_CIPHER_CTX_set_key_length for further information. */ @@ -463,7 +779,7 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length) { int len = NUM2INT(key_length); EVP_CIPHER_CTX *ctx; - + GetCipher(self, ctx); if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1) ossl_raise(eCipherError, NULL); @@ -471,97 +787,351 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length) return key_length; } +// TODO: Should #padding= take a boolean value instead? /* * call-seq: - * cipher.padding = integer -> integer + * cipher.padding = 1 or 0 * - * Enables or disables padding. By default encryption operations are padded using standard block padding and the - * padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the - * total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur. + * Enables or disables padding. By default encryption operations are padded + * using standard block padding and the padding is checked and removed when + * decrypting. If the pad parameter is zero then no padding is performed, the + * total amount of data encrypted or decrypted must then be a multiple of the + * block size or an error will occur. * * See EVP_CIPHER_CTX_set_padding for further information. */ static VALUE ossl_cipher_set_padding(VALUE self, VALUE padding) { -#if defined(HAVE_EVP_CIPHER_CTX_SET_PADDING) EVP_CIPHER_CTX *ctx; int pad = NUM2INT(padding); GetCipher(self, ctx); if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1) - ossl_raise(eCipherError, NULL); -#else - rb_notimplement(); -#endif + ossl_raise(eCipherError, NULL); return padding; } -#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))); \ - } -CIPHER_0ARG_INT(key_length) -CIPHER_0ARG_INT(iv_length) -CIPHER_0ARG_INT(block_size) - -#if 0 /* * call-seq: - * cipher.key_length -> integer + * cipher.key_len -> integer * + * Returns the key length in bytes of the Cipher. */ -static VALUE ossl_cipher_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_length -> integer + * cipher.iv_len -> integer * + * Returns the expected length in bytes for an IV for this Cipher. */ -static VALUE ossl_cipher_iv_length() { } +static VALUE +ossl_cipher_iv_length(VALUE self) +{ + EVP_CIPHER_CTX *ctx; + int len = 0; + + GetCipher(self, ctx); + if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) + len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); + if (!len) + len = EVP_CIPHER_CTX_iv_length(ctx); + + return INT2NUM(len); +} + /* * call-seq: * cipher.block_size -> integer * + * Returns the size in bytes of the blocks on which this Cipher operates on. */ -static VALUE ossl_cipher_block_size() { } -#endif +static VALUE +ossl_cipher_block_size(VALUE self) +{ + EVP_CIPHER_CTX *ctx; + + GetCipher(self, ctx); + + return INT2NUM(EVP_CIPHER_CTX_block_size(ctx)); +} + +/* + * call-seq: + * cipher.ccm_data_len = integer + * + * Sets the total length of the plaintext / ciphertext message that will be + * processed by #update in CCM mode. + * + * Make sure to call this method after #key= and #iv= have been set, and + * before #auth_data= or #update are called. + * + * This method is only available for CCM mode ciphers. + * + * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3). + */ +static VALUE +ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len) +{ + int in_len, out_len; + EVP_CIPHER_CTX *ctx; + + in_len = NUM2INT(data_len); + + GetCipher(self, ctx); + if (EVP_CipherUpdate(ctx, NULL, &out_len, NULL, in_len) != 1) + ossl_raise(eCipherError, NULL); + + return data_len; +} /* * INIT */ -void +void Init_ossl_cipher(void) { -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); -#endif + /* Document-class: OpenSSL::Cipher + * + * Provides symmetric algorithms for encryption and decryption. The + * algorithms that are available depend on the particular version + * of OpenSSL that is installed. + * + * === Listing all supported algorithms + * + * A list of supported algorithms can be obtained by + * + * puts OpenSSL::Cipher.ciphers + * + * === Instantiating a Cipher + * + * There are several ways to create a Cipher instance. Generally, a + * Cipher algorithm is categorized by its name, the key length in bits + * and the cipher mode to be used. The most generic way to create a + * Cipher is the following + * + * cipher = OpenSSL::Cipher.new('<name>-<key length>-<mode>') + * + * That is, a string consisting of the hyphenated concatenation of the + * individual components name, key length and mode. Either all uppercase + * or all lowercase strings may be used, for example: + * + * cipher = OpenSSL::Cipher.new('aes-128-cbc') + * + * === Choosing either encryption or decryption mode + * + * Encryption and decryption are often very similar operations for + * symmetric algorithms, this is reflected by not having to choose + * different classes for either operation, both can be done using the + * same class. Still, after obtaining a Cipher instance, we need to + * tell the instance what it is that we intend to do with it, so we + * need to call either + * + * cipher.encrypt + * + * or + * + * cipher.decrypt + * + * on the Cipher instance. This should be the first call after creating + * the instance, otherwise configuration that has already been set could + * get lost in the process. + * + * === Choosing a key + * + * Symmetric encryption requires a key that is the same for the encrypting + * and for the decrypting party and after initial key establishment should + * be kept as private information. There are a lot of ways to create + * insecure keys, the most notable is to simply take a password as the key + * without processing the password further. A simple and secure way to + * create a key for a particular Cipher is + * + * cipher = OpenSSL::Cipher.new('aes-256-cfb') + * cipher.encrypt + * key = cipher.random_key # also sets the generated key on the Cipher + * + * If you absolutely need to use passwords as encryption keys, you + * should use Password-Based Key Derivation Function 2 (PBKDF2) by + * generating the key with the help of the functionality provided by + * OpenSSL::PKCS5.pbkdf2_hmac_sha1 or OpenSSL::PKCS5.pbkdf2_hmac. + * + * Although there is Cipher#pkcs5_keyivgen, its use is deprecated and + * it should only be used in legacy applications because it does not use + * the newer PKCS#5 v2 algorithms. + * + * === Choosing an IV + * + * The cipher modes CBC, CFB, OFB and CTR all need an "initialization + * vector", or short, IV. ECB mode is the only mode that does not require + * an IV, but there is almost no legitimate use case for this mode + * because of the fact that it does not sufficiently hide plaintext + * patterns. Therefore + * + * <b>You should never use ECB mode unless you are absolutely sure that + * you absolutely need it</b> + * + * Because of this, you will end up with a mode that explicitly requires + * 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> + * + * A new, random IV should be created for every encryption of data. Think + * 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 + * + * 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 + * + * ECB (which should not be used) and CBC are both block-based modes. + * This means that unlike for the other streaming-based modes, they + * operate on fixed-size blocks of data, and therefore they require a + * "finalization" step to produce or correctly decrypt the last block of + * data by appropriately handling some form of padding. Therefore it is + * essential to add the output of OpenSSL::Cipher#final to your + * encryption/decryption buffer or you will end up with decryption errors + * or truncated data. + * + * Although this is not really necessary for streaming-mode ciphers, it is + * still recommended to apply the same pattern of adding the output of + * Cipher#final there as well - it also enables you to switch between + * modes more easily in the future. + * + * === Encrypting and decrypting some data + * + * data = "Very, very confidential data" + * + * cipher = OpenSSL::Cipher.new('aes-128-cbc') + * cipher.encrypt + * key = cipher.random_key + * iv = cipher.random_iv + * + * encrypted = cipher.update(data) + cipher.final + * ... + * decipher = OpenSSL::Cipher.new('aes-128-cbc') + * decipher.decrypt + * decipher.key = key + * decipher.iv = iv + * + * plain = decipher.update(encrypted) + decipher.final + * + * puts data == plain #=> true + * + * === Authenticated Encryption and Associated Data (AEAD) + * + * If the OpenSSL version used supports it, an Authenticated Encryption + * mode (such as GCM or CCM) should always be preferred over any + * unauthenticated mode. Currently, OpenSSL supports AE only in combination + * with Associated Data (AEAD) where additional associated data is included + * in the encryption process to compute a tag at the end of the encryption. + * This tag will also be used in the decryption process and by verifying + * its validity, the authenticity of a given ciphertext is established. + * + * This is superior to unauthenticated modes in that it allows to detect + * if somebody effectively changed the ciphertext after it had been + * encrypted. This prevents malicious modifications of the ciphertext that + * could otherwise be exploited to modify ciphertexts in ways beneficial to + * potential attackers. + * + * Associated data, also called additional authenticated data (AAD), is + * optionally used where there is additional information, such as + * headers or some metadata, that must be also authenticated but not + * necessarily need to be encrypted. + * + * 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 guarantees of GCM mode. + * + * key = OpenSSL::Random.random_bytes(16) + * nonce = OpenSSL::Random.random_bytes(12) + * auth_data = "authenticated but unencrypted data" + * data = "encrypted data" + * + * cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt + * cipher.key = key + * cipher.iv = nonce + * cipher.auth_data = auth_data + * + * encrypted = cipher.update(data) + cipher.final + * tag = cipher.auth_tag(16) + * + * 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.new('aes-128-gcm').decrypt + * decipher.key = key + * decipher.iv = nonce + * decipher.auth_tag = tag # could be called at any time before #final + * decipher.auth_data = auth_data + * + * decrypted = decipher.update(encrypted) + decipher.final + * + * puts data == decrypted #=> true + * + * Note that other AEAD ciphers may require additional steps, such as + * setting the expected tag length (#auth_tag_len=) or the total data + * length (#ccm_data_len=) in advance. Make sure to read the relevant man + * page for details. + */ cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject); eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError); + eAuthTagError = rb_define_class_under(cCipher, "AuthTagError", eCipherError); rb_define_alloc_func(cCipher, ossl_cipher_alloc); - rb_define_copy_func(cCipher, ossl_cipher_copy); + rb_define_method(cCipher, "initialize_copy", ossl_cipher_copy, 1); rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0); rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1); rb_define_method(cCipher, "reset", ossl_cipher_reset, 0); - rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1); - rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1); + rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, 0); + rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, 0); rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1); rb_define_method(cCipher, "update", ossl_cipher_update, -1); -#if RUBY_VERSION_CODE < 190 - rb_define_method(cCipher, "<<", ossl_cipher_update_deprecated, 1); -#endif rb_define_method(cCipher, "final", ossl_cipher_final, 0); rb_define_method(cCipher, "name", ossl_cipher_name, 0); rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1); + 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); -} + rb_define_method(cCipher, "ccm_data_len=", ossl_cipher_set_ccm_data_len, 1); + id_auth_tag_len = rb_intern_const("auth_tag_len"); + id_key_set = rb_intern_const("key_set"); + id_cipher_holder = rb_intern_const("EVP_CIPHER_holder"); +} diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h index bed4fa853b..fba63a140f 100644 --- a/ext/openssl/ossl_cipher.h +++ b/ext/openssl/ossl_cipher.h @@ -1,22 +1,26 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_CIPHER_H_) #define _OSSL_CIPHER_H_ -extern VALUE cCipher; -extern VALUE eCipherError; - -const EVP_CIPHER *GetCipherPtr(VALUE); +/* + * Gets EVP_CIPHER from a String or an OpenSSL::Digest instance (discouraged, + * but still supported for compatibility). A holder object is created if the + * EVP_CIPHER is a "fetched" algorithm. + */ +const EVP_CIPHER *ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder); +/* + * This is meant for OpenSSL::Engine#cipher. EVP_CIPHER must not be a fetched + * one. + */ VALUE ossl_cipher_new(const EVP_CIPHER *); void Init_ossl_cipher(void); #endif /* _OSSL_CIPHER_H_ */ - diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c index cc8e324029..274875a978 100644 --- a/ext/openssl/ossl_config.c +++ b/ext/openssl/ossl_config.c @@ -1,462 +1,456 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapConfig(klass, obj, conf) do { \ - if (!conf) { \ - ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \ - } \ - obj = Data_Wrap_Struct(klass, 0, NCONF_free, conf); \ -} while (0) -#define GetConfig(obj, conf) do { \ - Data_Get_Struct(obj, CONF, conf); \ - if (!conf) { \ - ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \ - } \ -} while (0) -#define SafeGetConfig(obj, conf) do { \ - OSSL_Check_Kind(obj, cConfig); \ - GetConfig(obj, conf); \ -} while(0); +static VALUE cConfig, eConfigError; -/* - * Classes - */ -VALUE cConfig; -VALUE eConfigError; - -/* - * Public - */ +static void +nconf_free(void *conf) +{ + NCONF_free(conf); +} -static CONF *parse_config(VALUE, CONF*); +static const rb_data_type_t ossl_config_type = { + "OpenSSL/CONF", + { + 0, nconf_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE, +}; CONF * -GetConfigPtr(VALUE obj) +GetConfig(VALUE obj) { CONF *conf; - SafeGetConfig(obj, conf); - + TypedData_Get_Struct(obj, CONF, &ossl_config_type, conf); + if (!conf) + rb_raise(rb_eRuntimeError, "CONF is not initialized"); return conf; } -CONF * -DupConfigPtr(VALUE obj) +static VALUE +config_s_alloc(VALUE klass) { - VALUE str; - - OSSL_Check_Kind(obj, cConfig); - str = rb_funcall(obj, rb_intern("to_s"), 0); + VALUE obj; + CONF *conf; - return parse_config(str, NULL); + obj = TypedData_Wrap_Struct(klass, &ossl_config_type, 0); + conf = NCONF_new(NULL); + if (!conf) + ossl_raise(eConfigError, "NCONF_new"); + RTYPEDDATA_DATA(obj) = conf; + return obj; } -/* - * Private - */ -static CONF * -parse_config(VALUE str, CONF *dst) +static void +config_load_bio(CONF *conf, BIO *bio) { - CONF *conf; - BIO *bio; long eline = -1; - bio = ossl_obj2bio(str); - conf = dst ? dst : NCONF_new(NULL); - if(!conf){ - BIO_free(bio); - ossl_raise(eConfigError, NULL); - } - if(!NCONF_load_bio(conf, bio, &eline)){ - BIO_free(bio); - if(!dst) NCONF_free(conf); - if (eline <= 0) ossl_raise(eConfigError, "wrong config format"); - else ossl_raise(eConfigError, "error in line %d", eline); - ossl_raise(eConfigError, NULL); + if (!NCONF_load_bio(conf, bio, &eline)) { + BIO_free(bio); + if (eline <= 0) + ossl_raise(eConfigError, "wrong config format"); + else + ossl_raise(eConfigError, "error in line %ld", eline); } BIO_free(bio); - return conf; -} - -static VALUE -ossl_config_s_parse(VALUE klass, VALUE str) -{ - CONF *conf; - VALUE obj; - - conf = parse_config(str, NULL); - WrapConfig(klass, obj, conf); - - return obj; + /* + * Clear the error queue even if it is parsed successfully. + * Particularly, when the .include directive refers to a non-existent file, + * it is only reported in the error queue. + */ + ossl_clear_error(); } +/* + * call-seq: + * Config.parse(string) -> OpenSSL::Config + * + * Parses a given _string_ as a blob that contains configuration for OpenSSL. + */ static VALUE -ossl_config_s_alloc(VALUE klass) +config_s_parse(VALUE klass, VALUE str) { - CONF *conf; - VALUE obj; - - if(!(conf = NCONF_new(NULL))) - ossl_raise(eConfigError, NULL); - WrapConfig(klass, obj, conf); + VALUE obj = config_s_alloc(klass); + CONF *conf = GetConfig(obj); + BIO *bio; + bio = ossl_obj2bio(&str); + config_load_bio(conf, bio); /* Consumes BIO */ + rb_obj_freeze(obj); return obj; } -static VALUE -ossl_config_copy(VALUE self, VALUE other) -{ - VALUE str; - CONF *conf; - - str = rb_funcall(self, rb_intern("to_s"), 0); - GetConfig(other, conf); - parse_config(str, conf); - - return self; -} +static VALUE config_get_sections(VALUE self); +static VALUE config_get_section(VALUE self, VALUE section); +/* + * call-seq: + * Config.parse_config(io) -> hash + * + * Parses the configuration data read from _io_ and returns the whole content + * as a Hash. + */ static VALUE -ossl_config_initialize(int argc, VALUE *argv, VALUE self) +config_s_parse_config(VALUE klass, VALUE io) { - CONF *conf; - long eline = -1; - char *filename; - VALUE path; - - rb_scan_args(argc, argv, "01", &path); - if(!NIL_P(path)){ - SafeStringValue(path); - filename = StringValuePtr(path); - GetConfig(self, conf); - if (!NCONF_load(conf, filename, &eline)){ - if (eline <= 0) - ossl_raise(eConfigError, "wrong config file %s", filename); - else - ossl_raise(eConfigError, "error in %s:%d", filename, eline); - } + VALUE obj, sections, ret; + long i; + + obj = config_s_parse(klass, io); + sections = config_get_sections(obj); + ret = rb_hash_new(); + for (i = 0; i < RARRAY_LEN(sections); i++) { + VALUE section = rb_ary_entry(sections, i); + rb_hash_aset(ret, section, config_get_section(obj, section)); } -#ifdef OSSL_NO_CONF_API - else rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)"); -#else - else { - GetConfig(self, conf); - _CONF_new_data(conf); - } -#endif - - return self; + return ret; } +/* + * call-seq: + * Config.new(filename) -> OpenSSL::Config + * + * Creates an instance of OpenSSL::Config from the content of the file + * specified by _filename_. + * + * This can be used in contexts like OpenSSL::X509::ExtensionFactory.config= + * + * This can raise IO exceptions based on the access, or availability of the + * file. A ConfigError exception may be raised depending on the validity of + * the data being configured. + */ static VALUE -ossl_config_add_value(VALUE self, VALUE section, VALUE name, VALUE value) +config_initialize(int argc, VALUE *argv, VALUE self) { -#ifdef OSSL_NO_CONF_API - rb_notimplement(); -#else - CONF *conf; - CONF_VALUE *sv, *cv; - - StringValue(section); - StringValue(name); - StringValue(value); - GetConfig(self, conf); - if(!(sv = _CONF_get_section(conf, RSTRING_PTR(section)))){ - if(!(sv = _CONF_new_section(conf, RSTRING_PTR(section)))){ - ossl_raise(eConfigError, NULL); - } - } - if(!(cv = OPENSSL_malloc(sizeof(CONF_VALUE)))){ - ossl_raise(eConfigError, NULL); + CONF *conf = GetConfig(self); + VALUE filename; + + /* 0-arguments call has no use-case, but is kept for compatibility */ + rb_scan_args(argc, argv, "01", &filename); + rb_check_frozen(self); + if (!NIL_P(filename)) { + BIO *bio = BIO_new_file(StringValueCStr(filename), "rb"); + if (!bio) + ossl_raise(eConfigError, "BIO_new_file"); + config_load_bio(conf, bio); /* Consumes BIO */ } - cv->name = BUF_strdup(RSTRING_PTR(name)); - cv->value = BUF_strdup(RSTRING_PTR(value)); - if(!cv->name || !cv->value || !_CONF_add_string(conf, sv, cv)){ - OPENSSL_free(cv->name); - OPENSSL_free(cv->value); - OPENSSL_free(cv); - ossl_raise(eConfigError, "_CONF_add_string failure"); - } - - return value; -#endif + rb_obj_freeze(self); + return self; } static VALUE -ossl_config_get_value(VALUE self, VALUE section, VALUE name) +config_initialize_copy(VALUE self, VALUE other) { - CONF *conf; - char *str; - - StringValue(section); - StringValue(name); - GetConfig(self, conf); - str = NCONF_get_string(conf, RSTRING_PTR(section), RSTRING_PTR(name)); - if(!str){ - ERR_clear_error(); - return Qnil; - } + CONF *conf = GetConfig(self); + VALUE str; + BIO *bio; - return rb_str_new2(str); + str = rb_funcall(other, rb_intern("to_s"), 0); + rb_check_frozen(self); + bio = ossl_obj2bio(&str); + config_load_bio(conf, bio); /* Consumes BIO */ + rb_obj_freeze(self); + return self; } +/* + * call-seq: + * config.get_value(section, key) -> string + * + * Gets the value of _key_ from the given _section_. + * + * Given the following configurating file being loaded: + * + * config = OpenSSL::Config.load('foo.cnf') + * #=> #<OpenSSL::Config sections=["default"]> + * puts config.to_s + * #=> [ default ] + * # foo=bar + * + * You can get a specific value from the config if you know the _section_ + * and _key_ like so: + * + * config.get_value('default','foo') + * #=> "bar" + */ static VALUE -ossl_config_get_value_old(int argc, VALUE *argv, VALUE self) +config_get_value(VALUE self, VALUE section, VALUE key) { - VALUE section, name; - - rb_scan_args(argc, argv, "11", §ion, &name); - - /* support conf.value(nil, "HOME") -> conf.get_value("", "HOME") */ - if (NIL_P(section)) section = rb_str_new2(""); - /* support conf.value("HOME") -> conf.get_value("", "HOME") */ - if (NIL_P(name)) { - name = section; - section = rb_str_new2(""); + CONF *conf = GetConfig(self); + const char *str, *sectionp; + + StringValueCStr(section); + StringValueCStr(key); + /* For compatibility; NULL means "default". */ + sectionp = RSTRING_LEN(section) ? RSTRING_PTR(section) : NULL; + str = NCONF_get_string(conf, sectionp, RSTRING_PTR(key)); + if (!str) { + ossl_clear_error(); + return Qnil; } - /* NOTE: Don't care about conf.get_value(nil, nil) */ - rb_warn("Config#value is deprecated; use Config#get_value"); - return ossl_config_get_value(self, section, name); -} - -static VALUE -set_conf_section_i(VALUE i, VALUE *arg) -{ - VALUE name, value; - - Check_Type(i, T_ARRAY); - name = rb_ary_entry(i, 0); - value = rb_ary_entry(i, 1); - ossl_config_add_value(arg[0], arg[1], name, value); - - return Qnil; -} - -static VALUE -ossl_config_set_section(VALUE self, VALUE section, VALUE hash) -{ - VALUE arg[2]; - - arg[0] = self; - arg[1] = section; - rb_block_call(hash, rb_intern("each"), 0, 0, set_conf_section_i, (VALUE)arg); - return hash; + return rb_str_new_cstr(str); } /* - * Get all numbers as strings - use str.to_i to convert - * long number = CONF_get_number(confp->config, sect, StringValuePtr(item)); + * call-seq: + * config[section] -> hash + * + * Gets all key-value pairs in a specific _section_ from the current + * configuration. + * + * Given the following configurating file being loaded: + * + * config = OpenSSL::Config.load('foo.cnf') + * #=> #<OpenSSL::Config sections=["default"]> + * puts config.to_s + * #=> [ default ] + * # foo=bar + * + * You can get a hash of the specific section like so: + * + * config['default'] + * #=> {"foo"=>"bar"} + * */ static VALUE -ossl_config_get_section(VALUE self, VALUE section) +config_get_section(VALUE self, VALUE section) { - CONF *conf; + CONF *conf = GetConfig(self); STACK_OF(CONF_VALUE) *sk; - CONF_VALUE *entry; int i, entries; VALUE hash; hash = rb_hash_new(); - StringValue(section); - GetConfig(self, conf); - if (!(sk = NCONF_get_section(conf, StringValuePtr(section)))) { - ERR_clear_error(); - return hash; + StringValueCStr(section); + if (!(sk = NCONF_get_section(conf, RSTRING_PTR(section)))) { + ossl_clear_error(); + return hash; } - if ((entries = sk_CONF_VALUE_num(sk)) < 0) { - OSSL_Debug("# of items in section is < 0?!?"); - return hash; + entries = sk_CONF_VALUE_num(sk); + for (i = 0; i < entries; i++) { + CONF_VALUE *entry = sk_CONF_VALUE_value(sk, i); + rb_hash_aset(hash, rb_str_new_cstr(entry->name), + rb_str_new_cstr(entry->value)); } - for (i=0; i<entries; i++) { - entry = sk_CONF_VALUE_value(sk, i); - rb_hash_aset(hash, rb_str_new2(entry->name), rb_str_new2(entry->value)); - } - return hash; } -static VALUE -ossl_config_get_section_old(VALUE self, VALUE section) -{ - rb_warn("Config#section is deprecated; use Config#[]"); - return ossl_config_get_section(self, section); -} - -#ifdef IMPLEMENT_LHASH_DOALL_ARG_FN static void -get_conf_section(CONF_VALUE *cv, VALUE ary) +get_conf_section_doall_arg(CONF_VALUE *cv, VALUE *aryp) { - if(cv->name) return; - rb_ary_push(ary, rb_str_new2(cv->section)); + if (cv->name) + return; + rb_ary_push(*aryp, rb_str_new_cstr(cv->section)); } -static IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE*, VALUE); +/* IMPLEMENT_LHASH_DOALL_ARG_CONST() requires >= OpenSSL 1.1.0 */ +static IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE, VALUE) +/* + * call-seq: + * config.sections -> array of string + * + * Get the names of all sections in the current configuration. + */ static VALUE -ossl_config_get_sections(VALUE self) +config_get_sections(VALUE self) { - CONF *conf; + CONF *conf = GetConfig(self); VALUE ary; - GetConfig(self, conf); ary = rb_ary_new(); - lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(get_conf_section), (void*)ary); - + lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(get_conf_section), + &ary); return ary; } static void -dump_conf_value(CONF_VALUE *cv, VALUE str) +dump_conf_value_doall_arg(CONF_VALUE *cv, VALUE *strp) { + VALUE str = *strp; STACK_OF(CONF_VALUE) *sk; - CONF_VALUE *v; int i, num; - if (cv->name) return; - sk = (STACK_OF(CONF_VALUE)*)cv->value; + if (cv->name) + return; + sk = (STACK_OF(CONF_VALUE) *)cv->value; num = sk_CONF_VALUE_num(sk); - rb_str_cat2(str, "[ "); - rb_str_cat2(str, cv->section); - rb_str_cat2(str, " ]\n"); - for(i = 0; i < num; i++){ - v = sk_CONF_VALUE_value(sk, i); - rb_str_cat2(str, v->name ? v->name : "None"); - rb_str_cat2(str, "="); - rb_str_cat2(str, v->value ? v->value : "None"); - rb_str_cat2(str, "\n"); + rb_str_cat_cstr(str, "[ "); + rb_str_cat_cstr(str, cv->section); + rb_str_cat_cstr(str, " ]\n"); + for (i = 0; i < num; i++){ + CONF_VALUE *v = sk_CONF_VALUE_value(sk, i); + rb_str_cat_cstr(str, v->name ? v->name : "None"); + rb_str_cat_cstr(str, "="); + rb_str_cat_cstr(str, v->value ? v->value : "None"); + rb_str_cat_cstr(str, "\n"); } - rb_str_cat2(str, "\n"); + rb_str_cat_cstr(str, "\n"); } -static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE*, VALUE); +static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE, VALUE) +/* + * call-seq: + * config.to_s -> string + * + * + * Gets the parsable form of the current configuration. + * + * Given the following configuration file being loaded: + * + * config = OpenSSL::Config.load('baz.cnf') + * #=> #<OpenSSL::Config sections=["default"]> + * puts config.to_s + * #=> [ default ] + * # foo=bar + * # baz=buz + * + * You can get the serialized configuration using #to_s and then parse + * it later: + * + * serialized_config = config.to_s + * # much later... + * new_config = OpenSSL::Config.parse(serialized_config) + * #=> #<OpenSSL::Config sections=["default"]> + * puts new_config + * #=> [ default ] + * foo=bar + * baz=buz + */ static VALUE -dump_conf(CONF *conf) +config_to_s(VALUE self) { + CONF *conf = GetConfig(self); VALUE str; - str = rb_str_new(0, 0); - lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_conf_value), (void*)str); - + str = rb_str_new(NULL, 0); + lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(dump_conf_value), + &str); return str; } -static VALUE -ossl_config_to_s(VALUE self) -{ - CONF *conf; - - GetConfig(self, conf); - - return dump_conf(conf); -} - static void -each_conf_value(CONF_VALUE *cv, void* dummy) +each_conf_value_doall_arg(CONF_VALUE *cv, void *unused) { STACK_OF(CONF_VALUE) *sk; - CONF_VALUE *v; - VALUE section, name, value, args; + VALUE section; int i, num; - if (cv->name) return; - sk = (STACK_OF(CONF_VALUE)*)cv->value; + if (cv->name) + return; + sk = (STACK_OF(CONF_VALUE) *)cv->value; num = sk_CONF_VALUE_num(sk); - section = rb_str_new2(cv->section); - for(i = 0; i < num; i++){ - v = sk_CONF_VALUE_value(sk, i); - name = v->name ? rb_str_new2(v->name) : Qnil; - value = v->value ? rb_str_new2(v->value) : Qnil; - args = rb_ary_new3(3, section, name, value); - rb_yield(args); + section = rb_str_new_cstr(cv->section); + for (i = 0; i < num; i++){ + CONF_VALUE *v = sk_CONF_VALUE_value(sk, i); + VALUE name = v->name ? rb_str_new_cstr(v->name) : Qnil; + VALUE value = v->value ? rb_str_new_cstr(v->value) : Qnil; + rb_yield(rb_ary_new3(3, section, name, value)); } } -static IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE*, void*); +static IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE, void) +/* + * call-seq: + * config.each { |section, key, value| } + * + * Retrieves the section and its pairs for the current configuration. + * + * config.each do |section, key, value| + * # ... + * end + */ static VALUE -ossl_config_each(VALUE self) -{ - CONF *conf; - - GetConfig(self, conf); - lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(each_conf_value), (void*)NULL); - - return self; -} -#else -static VALUE -ossl_config_get_sections(VALUE self) +config_each(VALUE self) { - rb_warn("#sections don't work with %s", OPENSSL_VERSION_TEXT); - return rb_ary_new(); -} + CONF *conf = GetConfig(self); -static VALUE -ossl_config_to_s(VALUE self) -{ - rb_warn("#to_s don't work with %s", OPENSSL_VERSION_TEXT); - return rb_str_new(0, 0); -} + RETURN_ENUMERATOR(self, 0, 0); -static VALUE -ossl_config_each(VALUE self) -{ - rb_warn("#each don't work with %s", OPENSSL_VERSION_TEXT); + lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(each_conf_value), + NULL); return self; } -#endif +/* + * call-seq: + * config.inspect -> string + * + * String representation of this configuration object, including the class + * name and its sections. + */ static VALUE -ossl_config_inspect(VALUE self) +config_inspect(VALUE self) { - VALUE str, ary = ossl_config_get_sections(self); - char *cname = rb_class2name(rb_obj_class(self)); + VALUE str, ary = config_get_sections(self); + const char *cname = rb_class2name(rb_obj_class(self)); - str = rb_str_new2("#<"); - rb_str_cat2(str, cname); - rb_str_cat2(str, " sections="); + str = rb_str_new_cstr("#<"); + rb_str_cat_cstr(str, cname); + rb_str_cat_cstr(str, " sections="); rb_str_append(str, rb_inspect(ary)); - rb_str_cat2(str, ">"); + rb_str_cat_cstr(str, ">"); return str; } -/* - * INIT - */ void -Init_ossl_config() +Init_ossl_config(void) { - eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); + char *path; + VALUE path_str; + + /* Document-class: OpenSSL::Config + * + * Configuration for the openssl library. + * + * Many system's installation of openssl library will depend on your system + * configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for + * the location of the file for your host. + * + * See also https://docs.openssl.org/master/man5/config/ + */ cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject); - rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", - rb_str_new2(CONF_get1_default_config_file())); + /* Document-class: OpenSSL::ConfigError + * + * General error for openssl library configuration files. Including formatting, + * parsing errors, etc. + */ + eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); + rb_include_module(cConfig, rb_mEnumerable); - rb_define_singleton_method(cConfig, "parse", ossl_config_s_parse, 1); + rb_define_singleton_method(cConfig, "parse", config_s_parse, 1); + rb_define_singleton_method(cConfig, "parse_config", config_s_parse_config, 1); rb_define_alias(CLASS_OF(cConfig), "load", "new"); - rb_define_alloc_func(cConfig, ossl_config_s_alloc); - rb_define_copy_func(cConfig, ossl_config_copy); - rb_define_method(cConfig, "initialize", ossl_config_initialize, -1); - rb_define_method(cConfig, "get_value", ossl_config_get_value, 2); - rb_define_method(cConfig, "value", ossl_config_get_value_old, -1); - rb_define_method(cConfig, "add_value", ossl_config_add_value, 3); - rb_define_method(cConfig, "[]", ossl_config_get_section, 1); - rb_define_method(cConfig, "section", ossl_config_get_section_old, 1); - rb_define_method(cConfig, "[]=", ossl_config_set_section, 2); - rb_define_method(cConfig, "sections", ossl_config_get_sections, 0); - rb_define_method(cConfig, "to_s", ossl_config_to_s, 0); - rb_define_method(cConfig, "each", ossl_config_each, 0); - rb_define_method(cConfig, "inspect", ossl_config_inspect, 0); + rb_define_alloc_func(cConfig, config_s_alloc); + rb_define_method(cConfig, "initialize", config_initialize, -1); + rb_define_method(cConfig, "initialize_copy", config_initialize_copy, 1); + rb_define_method(cConfig, "get_value", config_get_value, 2); + rb_define_method(cConfig, "[]", config_get_section, 1); + rb_define_method(cConfig, "sections", config_get_sections, 0); + rb_define_method(cConfig, "to_s", config_to_s, 0); + rb_define_method(cConfig, "each", config_each, 0); + rb_define_method(cConfig, "inspect", config_inspect, 0); + + /* Document-const: DEFAULT_CONFIG_FILE + * + * The default system configuration file for OpenSSL. + */ + path = CONF_get1_default_config_file(); + path_str = rb_obj_freeze(ossl_buf2str(path, rb_long2int(strlen(path)))); + rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", path_str); } diff --git a/ext/openssl/ossl_config.h b/ext/openssl/ossl_config.h index cb226b27e5..a254360c2c 100644 --- a/ext/openssl/ossl_config.h +++ b/ext/openssl/ossl_config.h @@ -1,22 +1,16 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ -#if !defined(_OSSL_CONFIG_H_) -#define _OSSL_CONFIG_H_ +#ifndef OSSL_CONFIG_H +#define OSSL_CONFIG_H -extern VALUE cConfig; -extern VALUE eConfigError; - -CONF* GetConfigPtr(VALUE obj); -CONF* DupConfigPtr(VALUE obj); +CONF *GetConfig(VALUE obj); void Init_ossl_config(void); -#endif /* _OSSL_CONFIG_H_ */ - +#endif /* OSSL_CONFIG_H */ diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c index 118626fd71..e23968b1e3 100644 --- a/ext/openssl/ossl_digest.c +++ b/ext/openssl/ossl_digest.c @@ -1,70 +1,121 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" #define GetDigest(obj, ctx) do { \ - Data_Get_Struct(obj, EVP_MD_CTX, ctx); \ - if (!ctx) { \ - ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \ + TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \ + if (!(ctx)) { \ + ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \ } \ } while (0) -#define SafeGetDigest(obj, ctx) do { \ - OSSL_Check_Kind(obj, cDigest); \ - GetDigest(obj, ctx); \ -} while (0) /* * Classes */ -VALUE cDigest; -VALUE eDigestError; +static VALUE cDigest; +static VALUE eDigestError; +static ID id_md_holder; static VALUE ossl_digest_alloc(VALUE klass); +static void +ossl_digest_free(void *ctx) +{ + EVP_MD_CTX_destroy(ctx); +} + +static const rb_data_type_t ossl_digest_type = { + "OpenSSL/Digest", + { + 0, ossl_digest_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +#ifdef OSSL_USE_PROVIDER +static void +ossl_evp_md_free(void *ptr) +{ + // This is safe to call against const EVP_MD * returned by + // EVP_get_digestbyname() + EVP_MD_free(ptr); +} + +static const rb_data_type_t ossl_evp_md_holder_type = { + "OpenSSL/EVP_MD", + { + .dfree = ossl_evp_md_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; +#endif + /* * Public */ const EVP_MD * -GetDigestPtr(VALUE obj) +ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder) { - const EVP_MD *md; - - if (TYPE(obj) == T_STRING) { - const char *name = STR2CSTR(obj); - - md = EVP_get_digestbyname(name); - if (!md) - ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name); - } else { + *holder = Qnil; + if (rb_obj_is_kind_of(obj, cDigest)) { EVP_MD_CTX *ctx; - - SafeGetDigest(obj, ctx); - - md = EVP_MD_CTX_md(ctx); /*== ctx->digest*/ + GetDigest(obj, ctx); + EVP_MD *md = (EVP_MD *)EVP_MD_CTX_get0_md(ctx); +#ifdef OSSL_USE_PROVIDER + *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL); + if (!EVP_MD_up_ref(md)) + ossl_raise(eDigestError, "EVP_MD_up_ref"); + RTYPEDDATA_DATA(*holder) = md; +#endif + return md; } + const char *name = StringValueCStr(obj); + EVP_MD *md = (EVP_MD *)EVP_get_digestbyname(name); + if (!md) { + ASN1_OBJECT *oid = OBJ_txt2obj(name, 0); + md = (EVP_MD *)EVP_get_digestbyobj(oid); + ASN1_OBJECT_free(oid); + } +#ifdef OSSL_USE_PROVIDER + if (!md) { + ossl_clear_error(); + *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL); + md = EVP_MD_fetch(NULL, name, NULL); + RTYPEDDATA_DATA(*holder) = md; + } +#endif + if (!md) + ossl_raise(eDigestError, "unsupported digest algorithm: %"PRIsVALUE, + obj); return md; } VALUE ossl_digest_new(const EVP_MD *md) -{ +{ VALUE ret; EVP_MD_CTX *ctx; + // NOTE: This does not set id_md_holder because this function should + // only be called from ossl_engine.c, which will not use any + // reference-counted digests. ret = ossl_digest_alloc(cDigest); - GetDigest(ret, ctx); - EVP_MD_CTX_init(ctx); - EVP_DigestInit_ex(ctx, md, NULL); - + 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; } @@ -74,274 +125,351 @@ ossl_digest_new(const EVP_MD *md) static VALUE ossl_digest_alloc(VALUE klass) { - EVP_MD_CTX *ctx; - VALUE obj; - - ctx = EVP_MD_CTX_create(); - if (ctx == NULL) - ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed"); - EVP_MD_CTX_init(ctx); - obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx); - - return obj; + return TypedData_Wrap_Struct(klass, &ossl_digest_type, 0); } -VALUE ossl_digest_update(VALUE, VALUE); +static VALUE ossl_digest_update(VALUE, VALUE); /* * call-seq: - * Digest.new(string) -> digest + * Digest.new(string [, data]) -> Digest * + * Creates a Digest instance based on _string_, which is either the ln + * (long name) or sn (short name) of a supported digest algorithm. A list of + * supported algorithms can be obtained by calling OpenSSL::Digest.digests. + * + * 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 equivalent to + * + * digest = OpenSSL::Digest.new('sha256') + * digest.update('digestdata') */ static VALUE ossl_digest_initialize(int argc, VALUE *argv, VALUE self) { EVP_MD_CTX *ctx; const EVP_MD *md; - char *name; - VALUE type, data; + VALUE type, data, md_holder; rb_scan_args(argc, argv, "11", &type, &data); - StringValue(type); + md = ossl_evp_md_fetch(type, &md_holder); if (!NIL_P(data)) StringValue(data); - name = StringValuePtr(type); - - md = EVP_get_digestbyname(name); - if (!md) { - ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name); + + 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"); } - GetDigest(self, ctx); - EVP_DigestInit_ex(ctx, md, NULL); - + + if (!EVP_DigestInit_ex(ctx, md, NULL)) + ossl_raise(eDigestError, "Digest initialization failed"); + rb_ivar_set(self, id_md_holder, md_holder); + if (!NIL_P(data)) return ossl_digest_update(self, data); return self; } +/* :nodoc: */ static VALUE ossl_digest_copy(VALUE self, VALUE other) { EVP_MD_CTX *ctx1, *ctx2; - + rb_check_frozen(self); if (self == other) return self; - GetDigest(self, ctx1); - SafeGetDigest(other, ctx2); + 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"); + } + GetDigest(other, ctx2); if (!EVP_MD_CTX_copy(ctx1, ctx2)) { - ossl_raise(eDigestError, NULL); + ossl_raise(eDigestError, NULL); } return self; } +static void +add_digest_name_to_ary(const OBJ_NAME *name, void *arg) +{ + VALUE ary = (VALUE)arg; + rb_ary_push(ary, rb_str_new2(name->name)); +} + /* * call-seq: - * digest.reset -> self + * OpenSSL::Digest.digests -> array[string...] * + * Returns the names of all available digests in an array. */ static VALUE -ossl_digest_reset(VALUE self) +ossl_s_digests(VALUE self) { - EVP_MD_CTX *ctx; + VALUE ary; - GetDigest(self, ctx); - EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL); + ary = rb_ary_new(); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, + add_digest_name_to_ary, + (void*)ary); - return self; + return ary; } /* * call-seq: - * digest.update(string) -> aString + * digest.reset -> self + * + * Resets the Digest in the sense that any Digest#update that has been + * performed is abandoned and the Digest is set to its initial state again. * */ -VALUE -ossl_digest_update(VALUE self, VALUE data) +static VALUE +ossl_digest_reset(VALUE self) { EVP_MD_CTX *ctx; - StringValue(data); GetDigest(self, ctx); - EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); + if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) { + ossl_raise(eDigestError, "Digest initialization failed."); + } return self; } -static void -digest_final(EVP_MD_CTX *ctx, char **buf, int *buf_len) -{ - EVP_MD_CTX final; - - if (!EVP_MD_CTX_copy(&final, ctx)) { - ossl_raise(eDigestError, NULL); - } - if (!(*buf = OPENSSL_malloc(EVP_MD_CTX_size(&final)))) { - EVP_MD_CTX_cleanup(&final); - ossl_raise(eDigestError, "Cannot allocate mem for digest"); - } - EVP_DigestFinal_ex(&final, *buf, buf_len); - EVP_MD_CTX_cleanup(&final); -} - /* * call-seq: - * digest.final -> aString + * digest.update(string) -> aString + * + * Not every message digest can be computed in one single pass. If a message + * digest is to be computed from several subsequent sources, then each may + * be passed individually to the Digest instance. + * + * === Example + * digest = OpenSSL::Digest.new('SHA256') + * digest.update('First input') + * digest << 'Second input' # equivalent to digest.update('Second input') + * result = digest.digest * */ static VALUE -ossl_digest_digest(VALUE self) +ossl_digest_update(VALUE self, VALUE data) { EVP_MD_CTX *ctx; - char *buf; - int buf_len; - VALUE digest; - + + StringValue(data); GetDigest(self, ctx); - digest_final(ctx, &buf, &buf_len); - digest = ossl_buf2str(buf, buf_len); - - return digest; + + if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) + ossl_raise(eDigestError, "EVP_DigestUpdate"); + + return self; } /* * call-seq: - * digest.hexdigest -> aString + * digest.finish -> aString * */ static VALUE -ossl_digest_hexdigest(VALUE self) +ossl_digest_finish(VALUE self) { EVP_MD_CTX *ctx; - char *buf, *hexbuf; - int buf_len; - VALUE hexdigest; + VALUE str; GetDigest(self, ctx); - digest_final(ctx, &buf, &buf_len); - if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) { - OPENSSL_free(buf); - ossl_raise(eDigestError, "Memory alloc error"); - } - OPENSSL_free(buf); - hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); + str = rb_str_new(NULL, EVP_MD_CTX_size(ctx)); + if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL)) + ossl_raise(eDigestError, "EVP_DigestFinal_ex"); - return hexdigest; -} - -static VALUE -ossl_digest_s_digest(VALUE klass, VALUE str, VALUE data) -{ - VALUE obj = rb_class_new_instance(1, &str, klass); - - ossl_digest_update(obj, data); - - return ossl_digest_digest(obj); -} - -static VALUE -ossl_digest_s_hexdigest(VALUE klass, VALUE str, VALUE data) -{ - VALUE obj = rb_class_new_instance(1, &str, klass); - - ossl_digest_update(obj, data); - - return ossl_digest_hexdigest(obj); + return str; } /* * call-seq: - * digest1 == digest2 -> true | false + * digest.name -> string + * + * Returns the short name of this Digest algorithm which may differ slightly + * from the original name provided. + * + * === Example + * digest = OpenSSL::Digest.new('SHA512') + * puts digest.name # => SHA512 * */ static VALUE -ossl_digest_equal(VALUE self, VALUE other) +ossl_digest_name(VALUE self) { EVP_MD_CTX *ctx; - VALUE str1, str2; - if (rb_obj_is_kind_of(other, cDigest) == Qtrue) { - str2 = ossl_digest_digest(other); - } else { - StringValue(other); - str2 = other; - } GetDigest(self, ctx); - if (RSTRING_LEN(str2) == EVP_MD_CTX_size(ctx)) { - str1 = ossl_digest_digest(self); - } else { - str1 = ossl_digest_hexdigest(self); - } - if (RSTRING_LEN(str1) == RSTRING_LEN(str2) - && rb_str_cmp(str1, str2) == 0) { - return Qtrue; - } - return Qfalse; + return rb_str_new_cstr(EVP_MD_name(EVP_MD_CTX_get0_md(ctx))); } /* * call-seq: - * digest.name -> string + * digest.digest_length -> integer + * + * Returns the output size of the digest, i.e. the length in bytes of the + * final message digest result. + * + * === Example + * digest = OpenSSL::Digest.new('SHA1') + * puts digest.digest_length # => 20 * */ static VALUE -ossl_digest_name(VALUE self) +ossl_digest_size(VALUE self) { EVP_MD_CTX *ctx; GetDigest(self, ctx); - return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx))); + return INT2NUM(EVP_MD_CTX_size(ctx)); } /* * call-seq: - * digest.size -> integer + * digest.block_length -> integer * - * Returns the output size of the digest. + * Returns the block length of the digest algorithm, i.e. the length in bytes + * of an individual block. Most modern algorithms partition a message to be + * digested into a sequence of fix-sized blocks that are processed + * consecutively. + * + * === Example + * digest = OpenSSL::Digest.new('SHA1') + * puts digest.block_length # => 64 */ static VALUE -ossl_digest_size(VALUE self) +ossl_digest_block_length(VALUE self) { EVP_MD_CTX *ctx; GetDigest(self, ctx); - return INT2NUM(EVP_MD_CTX_size(ctx)); + return INT2NUM(EVP_MD_CTX_block_size(ctx)); } /* * INIT */ void -Init_ossl_digest() +Init_ossl_digest(void) { -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); -#endif - - cDigest = rb_define_class_under(mOSSL, "Digest", rb_cObject); + /* Document-class: OpenSSL::Digest + * + * OpenSSL::Digest allows you to compute message digests (sometimes + * interchangeably called "hashes") of arbitrary data that are + * cryptographically secure, i.e. a Digest implements a secure one-way + * function. + * + * One-way functions offer some useful properties. E.g. given two + * distinct inputs the probability that both yield the same output + * is highly unlikely. Combined with the fact that every message digest + * algorithm has a fixed-length output of just a few bytes, digests are + * often used to create unique identifiers for arbitrary data. A common + * example is the creation of a unique id for binary documents that are + * stored in a database. + * + * Another useful characteristic of one-way functions (and thus the name) + * is that given a digest there is no indication about the original + * data that produced it, i.e. the only way to identify the original input + * is to "brute-force" through every possible combination of inputs. + * + * These characteristics make one-way functions also ideal companions + * for public key signature algorithms: instead of signing an entire + * document, first a hash of the document is produced with a considerably + * faster message digest algorithm and only the few bytes of its output + * need to be signed using the slower public key algorithm. To validate + * the integrity of a signed document, it suffices to re-compute the hash + * and verify that it is equal to that in the signature. + * + * You can get a list of all digest algorithms supported on your system by + * running this command in your terminal: + * + * openssl list -digest-algorithms + * + * Among the OpenSSL 1.1.1 supported message digest algorithms are: + * * SHA224, SHA256, SHA384, SHA512, SHA512-224 and SHA512-256 + * * SHA3-224, SHA3-256, SHA3-384 and SHA3-512 + * * BLAKE2s256 and BLAKE2b512 + * + * Each of these algorithms can be instantiated using the name: + * + * digest = OpenSSL::Digest.new('SHA256') + * + * "Breaking" a message digest algorithm means defying its one-way + * function characteristics, i.e. producing a collision or finding a way + * to get to the original data by means that are more efficient than + * brute-forcing etc. Most of the supported digest algorithms can be + * considered broken in this sense, even the very popular MD5 and SHA1 + * algorithms. Should security be your highest concern, then you should + * probably rely on SHA224, SHA256, SHA384 or SHA512. + * + * === Hashing a file + * + * data = File.binread('document') + * sha256 = OpenSSL::Digest.new('SHA256') + * digest = sha256.digest(data) + * + * === Hashing several pieces of data at once + * + * data1 = File.binread('file1') + * data2 = File.binread('file2') + * data3 = File.binread('file3') + * sha256 = OpenSSL::Digest.new('SHA256') + * sha256 << data1 + * sha256 << data2 + * sha256 << data3 + * digest = sha256.digest + * + * === Reuse a Digest instance + * + * data1 = File.binread('file1') + * sha256 = OpenSSL::Digest.new('SHA256') + * digest1 = sha256.digest(data1) + * + * data2 = File.binread('file2') + * sha256.reset + * digest2 = sha256.digest(data2) + * + */ + + /* + * Digest::Class is defined by the digest library. rb_require() cannot be + * used here because it bypasses RubyGems. + */ + rb_funcall(Qnil, rb_intern_const("require"), 1, rb_str_new_cstr("digest")); + cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class")); + /* Document-class: OpenSSL::Digest::DigestError + * + * Generic Exception class that is raised if an error occurs during a + * Digest operation. + */ eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError); - + rb_define_alloc_func(cDigest, ossl_digest_alloc); - rb_define_singleton_method(cDigest, "digest", ossl_digest_s_digest, 2); - rb_define_singleton_method(cDigest, "hexdigest", ossl_digest_s_hexdigest, 2); - + + rb_define_module_function(cDigest, "digests", ossl_s_digests, 0); rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1); + rb_define_method(cDigest, "initialize_copy", ossl_digest_copy, 1); rb_define_method(cDigest, "reset", ossl_digest_reset, 0); - - rb_define_copy_func(cDigest, ossl_digest_copy); - - rb_define_method(cDigest, "digest", ossl_digest_digest, 0); - rb_define_method(cDigest, "hexdigest", ossl_digest_hexdigest, 0); - rb_define_alias(cDigest, "inspect", "hexdigest"); - rb_define_alias(cDigest, "to_s", "hexdigest"); - rb_define_method(cDigest, "update", ossl_digest_update, 1); rb_define_alias(cDigest, "<<", "update"); - - rb_define_method(cDigest, "==", ossl_digest_equal, 1); - + rb_define_private_method(cDigest, "finish", ossl_digest_finish, 0); + rb_define_method(cDigest, "digest_length", ossl_digest_size, 0); + rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0); + rb_define_method(cDigest, "name", ossl_digest_name, 0); - rb_define_method(cDigest, "size", ossl_digest_size, 0); + + id_md_holder = rb_intern_const("EVP_MD_holder"); } diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h index 8cc5b1bc56..9c3bb2b149 100644 --- a/ext/openssl/ossl_digest.h +++ b/ext/openssl/ossl_digest.h @@ -1,22 +1,25 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_DIGEST_H_) #define _OSSL_DIGEST_H_ -extern VALUE cDigest; -extern VALUE eDigestError; - -const EVP_MD *GetDigestPtr(VALUE); +/* + * Gets EVP_MD from a String or an OpenSSL::Digest instance (discouraged, but + * still supported for compatibility). A holder object is created if the EVP_MD + * is a "fetched" algorithm. + */ +const EVP_MD *ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder); +/* + * This is meant for OpenSSL::Engine#digest. EVP_MD must not be a fetched one. + */ VALUE ossl_digest_new(const EVP_MD *); void Init_ossl_digest(void); #endif /* _OSSL_DIGEST_H_ */ - diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c index cd835d1237..a2bcb07ea4 100644 --- a/ext/openssl/ossl_engine.c +++ b/ext/openssl/ossl_engine.c @@ -1,57 +1,89 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#if defined(OSSL_ENGINE_ENABLED) +#ifdef OSSL_USE_ENGINE +# include <openssl/engine.h> -#define WrapEngine(klass, obj, engine) do { \ - if (!engine) { \ - ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ +#define NewEngine(klass) \ + TypedData_Wrap_Struct((klass), &ossl_engine_type, 0) +#define SetEngine(obj, engine) do { \ + if (!(engine)) { \ + ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ } \ - obj = Data_Wrap_Struct(klass, 0, ENGINE_free, engine); \ + RTYPEDDATA_DATA(obj) = (engine); \ } while(0) #define GetEngine(obj, engine) do { \ - Data_Get_Struct(obj, ENGINE, engine); \ - if (!engine) { \ + TypedData_Get_Struct((obj), ENGINE, &ossl_engine_type, (engine)); \ + if (!(engine)) { \ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ } \ } while (0) -#define SafeGetEngine(obj, engine) do { \ - OSSL_Check_Kind(obj, cEngine); \ - GetPKCS7(obj, engine); \ -} while (0) -/* +/* * Classes */ -VALUE cEngine; -VALUE eEngineError; +/* Document-class: OpenSSL::Engine + * + * This class is the access to openssl's ENGINE cryptographic module + * implementation. + * + * See also, https://www.openssl.org/docs/crypto/engine.html + */ +static VALUE cEngine; +/* Document-class: OpenSSL::Engine::EngineError + * + * This is the generic exception for OpenSSL::Engine related errors + */ +static VALUE eEngineError; /* * Private */ -#define OSSL_ENGINE_LOAD_IF_MATCH(x) \ +#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \ do{\ - if(!strcmp(#x, RSTRING_PTR(name))){\ - ENGINE_load_##x();\ - return Qtrue;\ - }\ + if(!strcmp(#engine_name, RSTRING_PTR(name))){\ + if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\ + return Qtrue;\ + else\ + ossl_raise(eEngineError, "OPENSSL_init_crypto"); \ + }\ }while(0) +static void +ossl_engine_free(void *engine) +{ + ENGINE_free(engine); +} + +static const rb_data_type_t ossl_engine_type = { + "OpenSSL/Engine", + { + 0, ossl_engine_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* + * call-seq: + * OpenSSL::Engine.load(name = nil) + * + * This method loads engines. If _name_ is nil, then all builtin engines are + * loaded. Otherwise, the given _name_, as a String, is loaded if available to + * your runtime, and returns true. If _name_ is not found, then nil is + * returned. + * + */ static VALUE ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) { -#if !defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES) - return Qnil; -#else VALUE name; rb_scan_args(argc, argv, "01", &name); @@ -59,36 +91,37 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) ENGINE_load_builtin_engines(); return Qtrue; } - StringValue(name); -#ifndef OPENSSL_NO_STATIC_ENGINE - OSSL_ENGINE_LOAD_IF_MATCH(dynamic); - OSSL_ENGINE_LOAD_IF_MATCH(cswift); - OSSL_ENGINE_LOAD_IF_MATCH(chil); - OSSL_ENGINE_LOAD_IF_MATCH(atalla); - OSSL_ENGINE_LOAD_IF_MATCH(nuron); - OSSL_ENGINE_LOAD_IF_MATCH(ubsec); - OSSL_ENGINE_LOAD_IF_MATCH(aep); - OSSL_ENGINE_LOAD_IF_MATCH(sureware); - OSSL_ENGINE_LOAD_IF_MATCH(4758cca); -#endif -#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO - 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)); + StringValueCStr(name); + OSSL_ENGINE_LOAD_IF_MATCH(dynamic, DYNAMIC); + OSSL_ENGINE_LOAD_IF_MATCH(padlock, PADLOCK); + OSSL_ENGINE_LOAD_IF_MATCH(capi, CAPI); + OSSL_ENGINE_LOAD_IF_MATCH(cryptodev, CRYPTODEV); + OSSL_ENGINE_LOAD_IF_MATCH(openssl, OPENSSL); + rb_warning("no such builtin loader for `%"PRIsVALUE"'", name); return Qnil; -#endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ } +/* + * call-seq: + * OpenSSL::Engine.cleanup + * + * It is only necessary to run cleanup when engines are loaded via + * OpenSSL::Engine.load. However, running cleanup before exit is recommended. + * + * 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; } +/* + * call-seq: + * OpenSSL::Engine.engines -> [engine, ...] + * + * Returns an array of currently loaded engines. + */ static VALUE ossl_engine_s_engines(VALUE klass) { @@ -97,48 +130,62 @@ ossl_engine_s_engines(VALUE klass) ary = rb_ary_new(); for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){ - WrapEngine(klass, obj, e); + obj = NewEngine(klass); + /* Need a ref count of two here because of ENGINE_free being + * called internally by OpenSSL when moving to the next ENGINE + * and by us when releasing the ENGINE reference */ + ENGINE_up_ref(e); + SetEngine(obj, e); rb_ary_push(ary, obj); } return ary; } +/* + * call-seq: + * OpenSSL::Engine.by_id(name) -> engine + * + * Fetches the engine as specified by the _id_ String. + * + * OpenSSL::Engine.by_id("openssl") + * => #<OpenSSL::Engine id="openssl" name="Software engine support"> + * + * See OpenSSL::Engine.engines for the currently loaded engines. + */ static VALUE 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)))) - ossl_raise(eEngineError, NULL); - WrapEngine(klass, obj, e); + ossl_raise(eEngineError, NULL); + SetEngine(obj, e); if(rb_block_given_p()) rb_yield(obj); if(!ENGINE_init(e)) - ossl_raise(eEngineError, NULL); + ossl_raise(eEngineError, NULL); ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK, - 0, NULL, (void(*)())ossl_pem_passwd_cb); - ERR_clear_error(); - - return obj; -} - -static VALUE -ossl_engine_s_alloc(VALUE klass) -{ - ENGINE *e; - VALUE obj; - - if (!(e = ENGINE_new())) { - ossl_raise(eEngineError, NULL); - } - WrapEngine(klass, obj, e); + 0, NULL, (void(*)(void))ossl_pem_passwd_cb); + ossl_clear_error(); return obj; } +/* + * call-seq: + * engine.id -> string + * + * Gets the id for this engine. + * + * OpenSSL::Engine.load + * OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...] + * OpenSSL::Engine.engines.first.id + * #=> "rsax" + */ static VALUE ossl_engine_get_id(VALUE self) { @@ -147,6 +194,18 @@ ossl_engine_get_id(VALUE self) return rb_str_new2(ENGINE_get_id(e)); } +/* + * call-seq: + * engine.name -> string + * + * Get the descriptive name for this engine. + * + * OpenSSL::Engine.load + * OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...] + * OpenSSL::Engine.engines.first.name + * #=> "RSAX engine support" + * + */ static VALUE ossl_engine_get_name(VALUE self) { @@ -155,6 +214,14 @@ ossl_engine_get_name(VALUE self) return rb_str_new2(ENGINE_get_name(e)); } +/* + * call-seq: + * engine.finish -> nil + * + * Releases all internal structural references for this engine. + * + * May raise an EngineError if the engine is unavailable + */ static VALUE ossl_engine_finish(VALUE self) { @@ -166,52 +233,79 @@ ossl_engine_finish(VALUE self) return Qnil; } +/* + * call-seq: + * engine.cipher(name) -> OpenSSL::Cipher + * + * Returns a new instance of OpenSSL::Cipher by _name_, if it is available in + * this engine. + * + * An EngineError will be raised if the cipher is unavailable. + * + * e = OpenSSL::Engine.by_id("openssl") + * => #<OpenSSL::Engine id="openssl" name="Software engine support"> + * e.cipher("RC4") + * => #<OpenSSL::Cipher:0x007fc5cacc3048> + * + */ static VALUE ossl_engine_get_cipher(VALUE self, VALUE name) { -#if defined(HAVE_ENGINE_GET_CIPHER) 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); if(!ciph) ossl_raise(eEngineError, NULL); return ossl_cipher_new(ciph); -#else - rb_notimplement(); -#endif } +/* + * call-seq: + * engine.digest(name) -> OpenSSL::Digest + * + * Returns a new instance of OpenSSL::Digest by _name_. + * + * Will raise an EngineError if the digest is unavailable. + * + * e = OpenSSL::Engine.by_id("openssl") + * #=> #<OpenSSL::Engine id="openssl" name="Software engine support"> + * e.digest("SHA1") + * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709> + * e.digest("zomg") + * #=> OpenSSL::Engine::EngineError: no such digest `zomg' + */ static VALUE ossl_engine_get_digest(VALUE self, VALUE name) { -#if defined(HAVE_ENGINE_GET_DIGEST) 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); if(!md) ossl_raise(eEngineError, NULL); return ossl_digest_new(md); -#else - rb_notimplement(); -#endif } +/* + * call-seq: + * engine.load_private_key(id = nil, data = nil) -> OpenSSL::PKey + * + * Loads the given private key identified by _id_ and _data_. + * + * An EngineError is raised of the OpenSSL::PKey is unavailable. + * + */ static VALUE ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self) { @@ -221,21 +315,26 @@ 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); + obj = ossl_pkey_wrap(pkey); OSSL_PKEY_SET_PRIVATE(obj); return obj; } +/* + * call-seq: + * engine.load_public_key(id = nil, data = nil) -> OpenSSL::PKey + * + * Loads the given public key identified by _id_ and _data_. + * + * An EngineError is raised of the OpenSSL::PKey is unavailable. + * + */ static VALUE ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self) { @@ -245,19 +344,31 @@ 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); + return ossl_pkey_wrap(pkey); } +/* + * call-seq: + * engine.set_default(flag) + * + * Set the defaults for this engine with the given _flag_. + * + * These flags are used to control combinations of algorithm methods. + * + * _flag_ can be one of the following, other flags are available depending on + * your OS. + * + * [All flags] 0xFFFF + * [No flags] 0x0000 + * + * See also <openssl/engine.h> + */ static VALUE ossl_engine_set_default(VALUE self, VALUE flag) { @@ -270,6 +381,14 @@ ossl_engine_set_default(VALUE self, VALUE flag) return Qtrue; } +/* + * call-seq: + * engine.ctrl_cmd(command, value = nil) -> engine + * + * Sends the given _command_ to this engine. + * + * Raises an EngineError if the command fails. + */ static VALUE ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self) { @@ -279,10 +398,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; @@ -292,14 +409,20 @@ static VALUE ossl_engine_cmd_flag_to_name(int flag) { switch(flag){ - case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC"); - case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING"); - case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT"); - case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL"); - default: return rb_str_new2("UNKNOWN"); + case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC"); + case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING"); + case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT"); + case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL"); + default: return rb_str_new2("UNKNOWN"); } } +/* + * call-seq: + * engine.cmds -> [["name", "description", "flags"], ...] + * + * Returns an array of command definitions for the current engine + */ static VALUE ossl_engine_get_cmds(VALUE self) { @@ -310,49 +433,47 @@ ossl_engine_get_cmds(VALUE self) GetEngine(self, e); ary = rb_ary_new(); if ((defn = ENGINE_get_cmd_defns(e)) != NULL){ - for (p = defn; p->cmd_num > 0; p++){ - tmp = rb_ary_new(); - rb_ary_push(tmp, rb_str_new2(p->cmd_name)); - rb_ary_push(tmp, rb_str_new2(p->cmd_desc)); - rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags)); - rb_ary_push(ary, tmp); - } + for (p = defn; p->cmd_num > 0; p++){ + tmp = rb_ary_new(); + rb_ary_push(tmp, rb_str_new2(p->cmd_name)); + rb_ary_push(tmp, rb_str_new2(p->cmd_desc)); + rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags)); + rb_ary_push(ary, tmp); + } } return ary; } +/* + * call-seq: + * engine.inspect -> string + * + * Pretty prints this engine. + */ static VALUE ossl_engine_inspect(VALUE self) { - VALUE str; - char *cname = rb_class2name(rb_obj_class(self)); - - str = rb_str_new2("#<"); - rb_str_cat2(str, cname); - rb_str_cat2(str, " id=\""); - rb_str_append(str, ossl_engine_get_id(self)); - rb_str_cat2(str, "\" name=\""); - rb_str_append(str, ossl_engine_get_name(self)); - rb_str_cat2(str, "\">"); - - return str; + ENGINE *e; + + GetEngine(self, e); + return rb_sprintf("#<%"PRIsVALUE" id=\"%s\" name=\"%s\">", + rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e)); } #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x)) void -Init_ossl_engine() +Init_ossl_engine(void) { 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); @@ -370,24 +491,14 @@ Init_ossl_engine() DefEngineConst(METHOD_DSA); DefEngineConst(METHOD_DH); DefEngineConst(METHOD_RAND); -#ifdef ENGINE_METHOD_BN_MOD_EXP - DefEngineConst(METHOD_BN_MOD_EXP); -#endif -#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); } #else void -Init_ossl_engine() +Init_ossl_engine(void) { } #endif diff --git a/ext/openssl/ossl_engine.h b/ext/openssl/ossl_engine.h index ea2f256912..cedcebb772 100644 --- a/ext/openssl/ossl_engine.h +++ b/ext/openssl/ossl_engine.h @@ -1,20 +1,16 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz> * Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(OSSL_ENGINE_H) #define OSSL_ENGINE_H -extern VALUE cEngine; -extern VALUE eEngineError; - void Init_ossl_engine(void); #endif /* OSSL_ENGINE_H */ diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c index ba85f521f7..ddcc6a5f8d 100644 --- a/ext/openssl/ossl_hmac.c +++ b/ext/openssl/ossl_hmac.c @@ -1,35 +1,29 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ -#if !defined(OPENSSL_NO_HMAC) - #include "ossl.h" -#define MakeHMAC(obj, klass, ctx) \ - obj = Data_Make_Struct(klass, HMAC_CTX, 0, ossl_hmac_free, ctx) +#define NewHMAC(klass) \ + TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0) #define GetHMAC(obj, ctx) do { \ - Data_Get_Struct(obj, HMAC_CTX, ctx); \ - if (!ctx) { \ - ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \ + TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \ + if (!(ctx)) { \ + ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \ } \ } while (0) -#define SafeGetHMAC(obj, ctx) do { \ - OSSL_Check_Kind(obj, cHMAC); \ - GetHMAC(obj, ctx); \ -} while (0) /* * Classes */ -VALUE cHMAC; -VALUE eHMACError; +static VALUE cHMAC; +static VALUE eHMACError; +static ID id_md_holder; /* * Public @@ -39,21 +33,31 @@ VALUE eHMACError; * Private */ static void -ossl_hmac_free(HMAC_CTX *ctx) +ossl_hmac_free(void *ctx) { - HMAC_CTX_cleanup(ctx); - free(ctx); + EVP_MD_CTX_free(ctx); } +static const rb_data_type_t ossl_hmac_type = { + "OpenSSL/HMAC", + { + 0, ossl_hmac_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + static VALUE ossl_hmac_alloc(VALUE klass) { - HMAC_CTX *ctx; VALUE obj; + EVP_MD_CTX *ctx; + + obj = NewHMAC(klass); + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(eHMACError, "EVP_MD_CTX"); + RTYPEDDATA_DATA(obj) = ctx; - MakeHMAC(obj, klass, ctx); - HMAC_CTX_init(ctx); - return obj; } @@ -62,34 +66,70 @@ ossl_hmac_alloc(VALUE klass) * call-seq: * HMAC.new(key, digest) -> hmac * + * Returns an instance of OpenSSL::HMAC set with the key and digest + * algorithm to be used. The instance represents the initial state of + * the message authentication code before any data has been processed. + * To process data with it, use the instance method #update with your + * data as an argument. + * + * === Example + * + * key = 'key' + * instance = OpenSSL::HMAC.new(key, 'SHA1') + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * instance.class + * #=> OpenSSL::HMAC + * + * === A note about comparisons + * + * Two instances can be securely compared with #== in constant time: + * + * other_instance = OpenSSL::HMAC.new('key', 'SHA1') + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * instance == other_instance + * #=> true + * */ static VALUE ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) { - HMAC_CTX *ctx; + EVP_MD_CTX *ctx; + EVP_PKEY *pkey; + const EVP_MD *md; + VALUE md_holder; - StringValue(key); GetHMAC(self, ctx); - HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LEN(key), - GetDigestPtr(digest), NULL); + StringValue(key); + md = ossl_evp_md_fetch(digest, &md_holder); + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, + (unsigned char *)RSTRING_PTR(key), + RSTRING_LENINT(key)); + if (!pkey) + ossl_raise(eHMACError, "EVP_PKEY_new_raw_private_key"); + if (EVP_DigestSignInit(ctx, NULL, md, NULL, pkey) != 1) { + EVP_PKEY_free(pkey); + ossl_raise(eHMACError, "EVP_DigestSignInit"); + } + rb_ivar_set(self, id_md_holder, md_holder); + /* Decrement reference counter; EVP_MD_CTX still keeps it */ + EVP_PKEY_free(pkey); return self; } +/* :nodoc: */ static VALUE ossl_hmac_copy(VALUE self, VALUE other) { - HMAC_CTX *ctx1, *ctx2; - + EVP_MD_CTX *ctx1, *ctx2; + rb_check_frozen(self); if (self == other) return self; GetHMAC(self, ctx1); - SafeGetHMAC(other, ctx2); - - if (!HMAC_CTX_copy(ctx1, ctx2)) { - ossl_raise(eHMACError, NULL); - } + GetHMAC(other, ctx2); + if (EVP_MD_CTX_copy(ctx1, ctx2) != 1) + ossl_raise(eHMACError, "EVP_MD_CTX_copy"); return self; } @@ -97,161 +137,160 @@ ossl_hmac_copy(VALUE self, VALUE other) * call-seq: * hmac.update(string) -> self * + * Returns _hmac_ updated with the message to be authenticated. + * Can be called repeatedly with chunks of the message. + * + * === Example + * + * first_chunk = 'The quick brown fox jumps ' + * second_chunk = 'over the lazy dog' + * + * instance.update(first_chunk) + * #=> 5b9a8038a65d571076d97fe783989e52278a492a + * instance.update(second_chunk) + * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9 + * */ static VALUE ossl_hmac_update(VALUE self, VALUE data) { - HMAC_CTX *ctx; + EVP_MD_CTX *ctx; StringValue(data); GetHMAC(self, ctx); - HMAC_Update(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); + if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1) + ossl_raise(eHMACError, "EVP_DigestSignUpdate"); return self; } -static void -hmac_final(HMAC_CTX *ctx, char **buf, int *buf_len) -{ - HMAC_CTX final; - - if (!HMAC_CTX_copy(&final, ctx)) { - ossl_raise(eHMACError, NULL); - } - 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"); - } - HMAC_Final(&final, *buf, buf_len); - HMAC_CTX_cleanup(&final); -} - /* * call-seq: - * hmac.digest -> aString + * hmac.digest -> string * + * Returns the authentication code an instance represents as a binary string. + * + * === Example + * instance = OpenSSL::HMAC.new('key', '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; - char *buf; - int buf_len; - VALUE digest; - + EVP_MD_CTX *ctx; + size_t buf_len = EVP_MAX_MD_SIZE; + VALUE ret; + GetHMAC(self, ctx); - hmac_final(ctx, &buf, &buf_len); - digest = ossl_buf2str(buf, buf_len); - - return digest; + ret = rb_str_new(NULL, EVP_MAX_MD_SIZE); + if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(ret), + &buf_len) != 1) + ossl_raise(eHMACError, "EVP_DigestSignFinal"); + rb_str_set_len(ret, (long)buf_len); + + return ret; } /* * call-seq: - * hmac.hexdigest -> aString + * hmac.hexdigest -> string * + * Returns the authentication code an instance represents as a hex-encoded + * string. */ static VALUE ossl_hmac_hexdigest(VALUE self) { - HMAC_CTX *ctx; - char *buf, *hexbuf; - int buf_len; - VALUE hexdigest; - + EVP_MD_CTX *ctx; + unsigned char buf[EVP_MAX_MD_SIZE]; + size_t buf_len = EVP_MAX_MD_SIZE; + VALUE ret; + GetHMAC(self, ctx); - hmac_final(ctx, &buf, &buf_len); - if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) { - OPENSSL_free(buf); - ossl_raise(eHMACError, "Memory alloc error"); - } - OPENSSL_free(buf); - hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); + if (EVP_DigestSignFinal(ctx, buf, &buf_len) != 1) + ossl_raise(eHMACError, "EVP_DigestSignFinal"); + ret = rb_str_new(NULL, buf_len * 2); + ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len); - return hexdigest; + return ret; } /* * call-seq: * hmac.reset -> self * + * Returns _hmac_ as it was when it was first initialized, with all processed + * data cleared from it. + * + * === Example + * + * data = "The quick brown fox jumps over the lazy dog" + * instance = OpenSSL::HMAC.new('key', 'SHA1') + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * + * instance.update(data) + * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9 + * instance.reset + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * */ static VALUE ossl_hmac_reset(VALUE self) { - HMAC_CTX *ctx; + EVP_MD_CTX *ctx; + EVP_PKEY *pkey; GetHMAC(self, ctx); - HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); + pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx)); + if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1) + ossl_raise(eHMACError, "EVP_DigestSignInit"); return self; } /* - * call-seq: - * HMAC.digest(digest, key, data) -> aString - * - */ -static VALUE -ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) -{ - char *buf; - int buf_len; - - StringValue(key); - StringValue(data); - buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), - RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); - - return rb_str_new(buf, buf_len); -} - -/* - * call-seq: - * HMAC.digest(digest, key, data) -> aString - * - */ -static VALUE -ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) -{ - char *buf, *hexbuf; - int buf_len; - VALUE hexdigest; - - StringValue(key); - StringValue(data); - - buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), - RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); - if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) { - ossl_raise(eHMACError, "Cannot convert buf to hexbuf"); - } - hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); - - return hexdigest; -} - -/* * INIT */ void -Init_ossl_hmac() +Init_ossl_hmac(void) { -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); -#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.binread("file1") + * data2 = File.binread("file2") + * key = "key" + * hmac = OpenSSL::HMAC.new(key, 'SHA256') + * hmac << data1 + * hmac << data2 + * mac = hmac.digest + */ eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError); - + cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject); rb_define_alloc_func(cHMAC, ossl_hmac_alloc); - rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3); - rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3); - + rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2); - rb_define_copy_func(cHMAC, ossl_hmac_copy); + rb_define_method(cHMAC, "initialize_copy", ossl_hmac_copy, 1); rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0); rb_define_method(cHMAC, "update", ossl_hmac_update, 1); @@ -260,13 +299,6 @@ Init_ossl_hmac() rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0); rb_define_alias(cHMAC, "inspect", "hexdigest"); rb_define_alias(cHMAC, "to_s", "hexdigest"); -} -#else /* NO_HMAC */ -# warning >>> OpenSSL is compiled without HMAC support <<< -void -Init_ossl_hmac() -{ - rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC."); + id_md_holder = rb_intern_const("EVP_MD_holder"); } -#endif /* NO_HMAC */ diff --git a/ext/openssl/ossl_hmac.h b/ext/openssl/ossl_hmac.h index 1a2978b39a..e5bed37c9f 100644 --- a/ext/openssl/ossl_hmac.h +++ b/ext/openssl/ossl_hmac.h @@ -1,19 +1,15 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_HMAC_H_) #define _OSSL_HMAC_H_ -extern VALUE cHMAC; -extern VALUE eHMACError; - void Init_ossl_hmac(void); #endif /* _OSSL_HMAC_H_ */ diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c new file mode 100644 index 0000000000..1f28016440 --- /dev/null +++ b/ext/openssl/ossl_kdf.c @@ -0,0 +1,300 @@ +/* + * Ruby/OpenSSL Project + * Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors + */ +#include "ossl.h" +#include <openssl/kdf.h> + +static VALUE mKDF, eKDF; + +/* + * call-seq: + * KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString + * + * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in combination + * with HMAC. Takes _pass_, _salt_ and _iterations_, and then derives a key + * of _length_ bytes. + * + * For more information about PBKDF2, see RFC 2898 Section 5.2 + * (https://www.rfc-editor.org/rfc/rfc2898#section-5.2). + * + * === Parameters + * pass :: The password. + * salt :: The salt. Salts prevent attacks based on dictionaries of common + * passwords and attacks based on rainbow tables. It is a public + * value that can be safely stored along with the password (e.g. + * if the derived value is used for password storage). + * iterations :: The iteration count. This provides the ability to tune the + * algorithm. It is better to use the highest count possible for + * the maximum resistance to brute-force attacks. + * length :: The desired length of the derived key in octets. + * hash :: The hash algorithm used with HMAC for the PRF. May be a String + * representing the algorithm name, or an instance of + * OpenSSL::Digest. + */ +static VALUE +kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self) +{ + VALUE pass, salt, opts, kwargs[4], str, md_holder; + static ID kwargs_ids[4]; + int iters, len; + const EVP_MD *md; + + if (!kwargs_ids[0]) { + kwargs_ids[0] = rb_intern_const("salt"); + kwargs_ids[1] = rb_intern_const("iterations"); + kwargs_ids[2] = rb_intern_const("length"); + kwargs_ids[3] = rb_intern_const("hash"); + } + rb_scan_args(argc, argv, "1:", &pass, &opts); + rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs); + + StringValue(pass); + salt = StringValue(kwargs[0]); + iters = NUM2INT(kwargs[1]); + len = NUM2INT(kwargs[2]); + md = ossl_evp_md_fetch(kwargs[3], &md_holder); + + str = rb_str_new(0, len); + if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass), + (unsigned char *)RSTRING_PTR(salt), + RSTRING_LENINT(salt), iters, md, len, + (unsigned char *)RSTRING_PTR(str))) + ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC"); + + return str; +} + +#if defined(HAVE_EVP_PBE_SCRYPT) +/* + * call-seq: + * KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString + * + * Derives a key from _pass_ using given parameters with the scrypt + * password-based key derivation function. The result can be used for password + * storage. + * + * scrypt is designed to be memory-hard and more secure against brute-force + * attacks using custom hardwares than alternative KDFs such as PBKDF2 or + * bcrypt. + * + * The keyword arguments _N_, _r_ and _p_ can be used to tune scrypt. RFC 7914 + * (published on 2016-08, https://www.rfc-editor.org/rfc/rfc7914#section-2) states + * that using values r=8 and p=1 appears to yield good results. + * + * See RFC 7914 (https://www.rfc-editor.org/rfc/rfc7914) for more information. + * + * === Parameters + * pass :: Passphrase. + * salt :: Salt. + * N :: CPU/memory cost parameter. This must be a power of 2. + * r :: Block size parameter. + * p :: Parallelization parameter. + * length :: Length in octets of the derived key. + * + * === Example + * pass = "password" + * salt = SecureRandom.random_bytes(16) + * dk = OpenSSL::KDF.scrypt(pass, salt: salt, N: 2**14, r: 8, p: 1, length: 32) + * p dk #=> "\xDA\xE4\xE2...\x7F\xA1\x01T" + */ +static VALUE +kdf_scrypt(int argc, VALUE *argv, VALUE self) +{ + VALUE pass, salt, opts, kwargs[5], str; + static ID kwargs_ids[5]; + size_t len; + uint64_t N, r, p, maxmem; + + if (!kwargs_ids[0]) { + kwargs_ids[0] = rb_intern_const("salt"); + kwargs_ids[1] = rb_intern_const("N"); + kwargs_ids[2] = rb_intern_const("r"); + kwargs_ids[3] = rb_intern_const("p"); + kwargs_ids[4] = rb_intern_const("length"); + } + rb_scan_args(argc, argv, "1:", &pass, &opts); + rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs); + + StringValue(pass); + salt = StringValue(kwargs[0]); + N = NUM2UINT64T(kwargs[1]); + r = NUM2UINT64T(kwargs[2]); + p = NUM2UINT64T(kwargs[3]); + len = NUM2LONG(kwargs[4]); + /* + * OpenSSL uses 32MB by default (if zero is specified), which is too small. + * Let's not limit memory consumption but just let malloc() fail inside + * OpenSSL. The amount is controllable by other parameters. + */ + maxmem = SIZE_MAX; + + str = rb_str_new(0, len); + if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass), + (unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt), + N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len)) + ossl_raise(eKDF, "EVP_PBE_scrypt"); + + return str; +} +#endif + +/* + * call-seq: + * KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String + * + * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in + * {RFC 5869}[https://www.rfc-editor.org/rfc/rfc5869]. + * + * New in OpenSSL 1.1.0. + * + * === Parameters + * _ikm_:: + * The input keying material. + * _salt_:: + * The salt. + * _info_:: + * The context and application specific information. + * _length_:: + * The output length in octets. Must be <= <tt>255 * HashLen</tt>, where + * HashLen is the length of the hash function output in octets. + * _hash_:: + * The hash function. + * + * === Example + * # The values from https://www.rfc-editor.org/rfc/rfc5869#appendix-A.1 + * ikm = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*") + * salt = ["000102030405060708090a0b0c"].pack("H*") + * info = ["f0f1f2f3f4f5f6f7f8f9"].pack("H*") + * p OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: 42, hash: "SHA256").unpack1("H*") + * # => "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865" + */ +static VALUE +kdf_hkdf(int argc, VALUE *argv, VALUE self) +{ + VALUE ikm, salt, info, opts, kwargs[4], str, md_holder; + static ID kwargs_ids[4]; + int saltlen, ikmlen, infolen; + size_t len; + const EVP_MD *md; + EVP_PKEY_CTX *pctx; + + if (!kwargs_ids[0]) { + kwargs_ids[0] = rb_intern_const("salt"); + kwargs_ids[1] = rb_intern_const("info"); + kwargs_ids[2] = rb_intern_const("length"); + kwargs_ids[3] = rb_intern_const("hash"); + } + rb_scan_args(argc, argv, "1:", &ikm, &opts); + rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs); + + StringValue(ikm); + ikmlen = RSTRING_LENINT(ikm); + salt = StringValue(kwargs[0]); + saltlen = RSTRING_LENINT(salt); + info = StringValue(kwargs[1]); + infolen = RSTRING_LENINT(info); + len = (size_t)NUM2LONG(kwargs[2]); + if (len > LONG_MAX) + rb_raise(rb_eArgError, "length must be non-negative"); + md = ossl_evp_md_fetch(kwargs[3], &md_holder); + + str = rb_str_new(NULL, (long)len); + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + if (!pctx) + ossl_raise(eKDF, "EVP_PKEY_CTX_new_id"); + if (EVP_PKEY_derive_init(pctx) <= 0) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(eKDF, "EVP_PKEY_derive_init"); + } + if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md"); + } + if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt), + saltlen) <= 0) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt"); + } + if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm), + ikmlen) <= 0) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key"); + } + if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info), + infolen) <= 0) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info"); + } + if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(eKDF, "EVP_PKEY_derive"); + } + rb_str_set_len(str, (long)len); + EVP_PKEY_CTX_free(pctx); + + return str; +} + +void +Init_ossl_kdf(void) +{ + /* + * Document-module: OpenSSL::KDF + * + * Provides functionality of various KDFs (key derivation function). + * + * KDF is typically used for securely deriving arbitrary length symmetric + * keys to be used with an OpenSSL::Cipher from passwords. Another use case + * is for storing passwords: Due to the ability to tweak the effort of + * computation by increasing the iteration count, computation can be slowed + * down artificially in order to render possible attacks infeasible. + * + * Currently, OpenSSL::KDF provides implementations for the following KDF: + * + * * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in + * combination with HMAC + * * scrypt + * * HKDF + * + * == Examples + * === Generating a 128 bit key for a Cipher (e.g. AES) + * pass = "secret" + * salt = OpenSSL::Random.random_bytes(16) + * iter = 20_000 + * key_len = 16 + * key = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter, + * length: key_len, hash: "sha1") + * + * === Storing Passwords + * pass = "secret" + * # store this with the generated value + * salt = OpenSSL::Random.random_bytes(16) + * iter = 20_000 + * hash = OpenSSL::Digest.new('SHA256') + * len = hash.digest_length + * # the final value to be stored + * value = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter, + * length: len, hash: hash) + * + * == Important Note on Checking Passwords + * When comparing passwords provided by the user with previously stored + * values, a common mistake made is comparing the two values using "==". + * Typically, "==" short-circuits on evaluation, and is therefore + * vulnerable to timing attacks. The proper way is to use a method that + * always takes the same amount of time when comparing two values, thus + * not leaking any information to potential attackers. To do this, use + * +OpenSSL.fixed_length_secure_compare+. + */ + mKDF = rb_define_module_under(mOSSL, "KDF"); + /* + * Generic exception class raised if an error occurs in OpenSSL::KDF module. + */ + eKDF = rb_define_class_under(mKDF, "KDFError", eOSSLError); + + rb_define_module_function(mKDF, "pbkdf2_hmac", kdf_pbkdf2_hmac, -1); +#if defined(HAVE_EVP_PBE_SCRYPT) + rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1); +#endif + rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1); +} diff --git a/ext/openssl/ossl_kdf.h b/ext/openssl/ossl_kdf.h new file mode 100644 index 0000000000..b6503f8d9d --- /dev/null +++ b/ext/openssl/ossl_kdf.h @@ -0,0 +1,6 @@ +#if !defined(OSSL_KDF_H) +#define OSSL_KDF_H + +void Init_ossl_kdf(void); + +#endif diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c index 738a203d93..8440c2ee82 100644 --- a/ext/openssl/ossl_ns_spki.c +++ b/ext/openssl/ossl_ns_spki.c @@ -1,34 +1,35 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapSPKI(klass, obj, spki) do { \ - if (!spki) { \ - ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ +#define NewSPKI(klass) \ + TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, 0) +#define SetSPKI(obj, spki) do { \ + if (!(spki)) { \ + ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, NETSCAPE_SPKI_free, spki); \ + RTYPEDDATA_DATA(obj) = (spki); \ } while (0) #define GetSPKI(obj, spki) do { \ - Data_Get_Struct(obj, NETSCAPE_SPKI, spki); \ - if (!spki) { \ - ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ + TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \ + if (!(spki)) { \ + ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ } \ } while (0) /* * Classes */ -VALUE mNetscape; -VALUE cSPKI; -VALUE eSPKIError; +static VALUE mNetscape; +static VALUE cSPKI; +static VALUE eSPKIError; /* * Public functions @@ -37,44 +38,73 @@ VALUE eSPKIError; /* * Private functions */ + +static void +ossl_netscape_spki_free(void *spki) +{ + NETSCAPE_SPKI_free(spki); +} + +static const rb_data_type_t ossl_netscape_spki_type = { + "OpenSSL/NETSCAPE_SPKI", + { + 0, ossl_netscape_spki_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + static VALUE ossl_spki_alloc(VALUE klass) { NETSCAPE_SPKI *spki; VALUE obj; - + + obj = NewSPKI(klass); if (!(spki = NETSCAPE_SPKI_new())) { - ossl_raise(eSPKIError, NULL); - } - WrapSPKI(klass, obj, spki); - + ossl_raise(eSPKIError, NULL); + } + SetSPKI(obj, spki); + return obj; } +/* + * call-seq: + * SPKI.new([request]) => spki + * + * === Parameters + * * _request_ - optional raw request, either in PEM or DER format. + */ static VALUE ossl_spki_initialize(int argc, VALUE *argv, VALUE self) { NETSCAPE_SPKI *spki; VALUE buffer; - unsigned char *p; - + const unsigned char *p; + if (rb_scan_args(argc, argv, "01", &buffer) == 0) { - return self; + return self; } StringValue(buffer); - if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), -1))) { - p = RSTRING_PTR(buffer); - if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) { - ossl_raise(eSPKIError, NULL); - } + 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; } +/* + * call-seq: + * spki.to_der => DER-encoded string + * + * Returns the DER encoding of this SPKI. + */ static VALUE ossl_spki_to_der(VALUE self) { @@ -85,55 +115,70 @@ ossl_spki_to_der(VALUE self) GetSPKI(self, spki); if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0) - ossl_raise(eX509CertError, NULL); + ossl_raise(eSPKIError, "i2d_NETSCAPE_SPKI"); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if (i2d_NETSCAPE_SPKI(spki, &p) <= 0) - ossl_raise(eX509CertError, NULL); + ossl_raise(eSPKIError, "i2d_NETSCAPE_SPKI"); ossl_str_adjust(str, p); - + return str; } +/* + * call-seq: + * spki.to_pem => PEM-encoded string + * + * Returns the PEM encoding of this SPKI. + */ static VALUE ossl_spki_to_pem(VALUE self) { NETSCAPE_SPKI *spki; char *data; VALUE str; - + GetSPKI(self, spki); if (!(data = NETSCAPE_SPKI_b64_encode(spki))) { - ossl_raise(eSPKIError, NULL); + ossl_raise(eSPKIError, NULL); } - str = ossl_buf2str(data, strlen(data)); + str = ossl_buf2str(data, rb_long2int(strlen(data))); return str; } +/* + * call-seq: + * spki.to_text => string + * + * Returns a textual representation of this SPKI, useful for debugging + * purposes. + */ static VALUE 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()))) { - ossl_raise(eSPKIError, NULL); + ossl_raise(eSPKIError, NULL); } if (!NETSCAPE_SPKI_print(out, spki)) { - BIO_free(out); - ossl_raise(eSPKIError, NULL); + 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); } +/* + * call-seq: + * spki.public_key => pkey + * + * Returns the public key associated with the SPKI, an instance of + * OpenSSL::PKey. + */ static VALUE ossl_spki_get_public_key(VALUE self) { @@ -142,40 +187,67 @@ ossl_spki_get_public_key(VALUE self) GetSPKI(self, spki); if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */ - ossl_raise(eSPKIError, NULL); + ossl_raise(eSPKIError, NULL); } - return ossl_pkey_new(pkey); /* NO DUP - OK */ + return ossl_pkey_wrap(pkey); } +/* + * call-seq: + * spki.public_key = pub => pkey + * + * === Parameters + * * _pub_ - the public key to be set for this instance + * + * Sets the public key to be associated with the SPKI, an instance of + * OpenSSL::PKey. This should be the public key corresponding to the + * private key used for signing the SPKI. + */ static VALUE ossl_spki_set_public_key(VALUE self, VALUE key) { NETSCAPE_SPKI *spki; + EVP_PKEY *pkey; GetSPKI(self, spki); - if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ - ossl_raise(eSPKIError, NULL); - } - + pkey = GetPKeyPtr(key); + ossl_pkey_check_public_key(pkey); + if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) + ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey"); return key; } +/* + * call-seq: + * spki.challenge => string + * + * Returns the challenge string associated with this SPKI. + */ static VALUE ossl_spki_get_challenge(VALUE self) { NETSCAPE_SPKI *spki; GetSPKI(self, spki); - if (spki->spkac->challenge->length <= 0) { - OSSL_Debug("Challenge.length <= 0?"); - return rb_str_new(0, 0); + if (ASN1_STRING_length(spki->spkac->challenge) <= 0) { + OSSL_Debug("Challenge.length <= 0?"); + return rb_str_new(0, 0); } - return rb_str_new(spki->spkac->challenge->data, - spki->spkac->challenge->length); + return asn1str_to_str(spki->spkac->challenge); } +/* + * call-seq: + * spki.challenge = str => string + * + * === Parameters + * * _str_ - the challenge string to be set for this instance + * + * Sets the challenge to be associated with the SPKI. May be used by the + * server, e.g. to prevent replay. + */ static VALUE ossl_spki_set_challenge(VALUE self, VALUE str) { @@ -184,65 +256,136 @@ ossl_spki_set_challenge(VALUE self, VALUE str) StringValue(str); GetSPKI(self, spki); if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str), - RSTRING_LEN(str))) { - ossl_raise(eSPKIError, NULL); + RSTRING_LENINT(str))) { + ossl_raise(eSPKIError, NULL); } - + return str; } +/* + * call-seq: + * spki.sign(key, digest) => spki + * + * === Parameters + * * _key_ - the private key to be used for signing this instance + * * _digest_ - the digest to be used for signing this instance + * + * To sign an SPKI, the private key corresponding to the public key set + * for this instance should be used, in addition to a digest algorithm in + * the form of an OpenSSL::Digest. The private key should be an instance of + * OpenSSL::PKey. + */ static VALUE ossl_spki_sign(VALUE self, VALUE key, VALUE digest) { NETSCAPE_SPKI *spki; EVP_PKEY *pkey; const EVP_MD *md; + VALUE md_holder; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + md = ossl_evp_md_fetch(digest, &md_holder); GetSPKI(self, spki); - if (!NETSCAPE_SPKI_sign(spki, pkey, md)) { - ossl_raise(eSPKIError, NULL); - } + if (!NETSCAPE_SPKI_sign(spki, pkey, md)) + ossl_raise(eSPKIError, "NETSCAPE_SPKI_sign"); return self; } /* - * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' + * call-seq: + * spki.verify(key) => boolean + * + * === Parameters + * * _key_ - the public key to be used for verifying the SPKI signature + * + * Returns +true+ if the signature is valid, +false+ otherwise. To verify an + * SPKI, the public key contained within the SPKI should be used. */ static VALUE ossl_spki_verify(VALUE self, VALUE key) { NETSCAPE_SPKI *spki; + EVP_PKEY *pkey; GetSPKI(self, spki); - switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ - case 0: - return Qfalse; - case 1: - return Qtrue; - default: - ossl_raise(eSPKIError, NULL); + pkey = GetPKeyPtr(key); + ossl_pkey_check_public_key(pkey); + switch (NETSCAPE_SPKI_verify(spki, pkey)) { + case 0: + ossl_clear_error(); + return Qfalse; + case 1: + return Qtrue; + default: + ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify"); } - return Qnil; /* dummy */ } -/* - * NETSCAPE_SPKI init +/* Document-class: OpenSSL::Netscape::SPKI + * + * A Simple Public Key Infrastructure implementation (pronounced "spooky"). + * The structure is defined as + * PublicKeyAndChallenge ::= SEQUENCE { + * spki SubjectPublicKeyInfo, + * challenge IA5STRING + * } + * + * SignedPublicKeyAndChallenge ::= SEQUENCE { + * publicKeyAndChallenge PublicKeyAndChallenge, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + * where the definitions of SubjectPublicKeyInfo and AlgorithmIdentifier can + * be found in RFC5280. SPKI is typically used in browsers for generating + * a public/private key pair and a subsequent certificate request, using + * the HTML <keygen> element. + * + * == Examples + * + * === Creating an SPKI + * key = OpenSSL::PKey::RSA.new 2048 + * spki = OpenSSL::Netscape::SPKI.new + * spki.challenge = "RandomChallenge" + * spki.public_key = key.public_key + * spki.sign(key, OpenSSL::Digest.new('SHA256')) + * #send a request containing this to a server generating a certificate + * === Verifying an SPKI request + * request = #... + * spki = OpenSSL::Netscape::SPKI.new request + * unless spki.verify(spki.public_key) + * # signature is invalid + * end + * #proceed + */ + +/* Document-module: OpenSSL::Netscape + * + * OpenSSL::Netscape is a namespace for SPKI (Simple Public Key + * Infrastructure) which implements Signed Public Key and Challenge. + * See {RFC 2692}[https://www.rfc-editor.org/rfc/rfc2692] and {RFC + * 2693}[https://www.rfc-editor.org/rfc/rfc2692] for details. + */ + +/* Document-class: OpenSSL::Netscape::SPKIError + * + * Generic Exception class that is raised if an error occurs during an + * operation on an instance of OpenSSL::Netscape::SPKI. */ + void -Init_ossl_ns_spki() +Init_ossl_ns_spki(void) { mNetscape = rb_define_module_under(mOSSL, "Netscape"); - + eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError); - + cSPKI = rb_define_class_under(mNetscape, "SPKI", rb_cObject); - + rb_define_alloc_func(cSPKI, ossl_spki_alloc); rb_define_method(cSPKI, "initialize", ossl_spki_initialize, -1); - + rb_define_method(cSPKI, "to_der", ossl_spki_to_der, 0); rb_define_method(cSPKI, "to_pem", ossl_spki_to_pem, 0); rb_define_alias(cSPKI, "to_s", "to_pem"); @@ -254,4 +397,3 @@ Init_ossl_ns_spki() rb_define_method(cSPKI, "challenge", ossl_spki_get_challenge, 0); rb_define_method(cSPKI, "challenge=", ossl_spki_set_challenge, 1); } - diff --git a/ext/openssl/ossl_ns_spki.h b/ext/openssl/ossl_ns_spki.h index 9977035a9c..043b6cdb66 100644 --- a/ext/openssl/ossl_ns_spki.h +++ b/ext/openssl/ossl_ns_spki.h @@ -1,21 +1,15 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_NS_SPKI_H_) #define _OSSL_NS_SPKI_H_ -extern VALUE mNetscape; -extern VALUE cSPKI; -extern VALUE eSPKIError; - void Init_ossl_ns_spki(void); #endif /* _OSSL_NS_SPKI_H_ */ - diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c index 1e8e5903bd..93d8bc8567 100644 --- a/ext/openssl/ossl_ocsp.c +++ b/ext/openssl/ossl_ocsp.c @@ -1,90 +1,167 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz> * Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#if defined(OSSL_OCSP_ENABLED) +#if !defined(OPENSSL_NO_OCSP) -#define WrapOCSPReq(klass, obj, req) do { \ - if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ - obj = Data_Wrap_Struct(klass, 0, OCSP_REQUEST_free, req); \ +#define NewOCSPReq(klass) \ + TypedData_Wrap_Struct((klass), &ossl_ocsp_request_type, 0) +#define SetOCSPReq(obj, req) do { \ + if(!(req)) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ + RTYPEDDATA_DATA(obj) = (req); \ } while (0) #define GetOCSPReq(obj, req) do { \ - Data_Get_Struct(obj, OCSP_REQUEST, req); \ - if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ -} while (0) -#define SafeGetOCSPReq(obj, req) do { \ - OSSL_Check_Kind(obj, cOCSPReq); \ - GetOCSPReq(obj, req); \ + TypedData_Get_Struct((obj), OCSP_REQUEST, &ossl_ocsp_request_type, (req)); \ + if(!(req)) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \ } while (0) -#define WrapOCSPRes(klass, obj, res) do { \ - if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ - obj = Data_Wrap_Struct(klass, 0, OCSP_RESPONSE_free, res); \ +#define NewOCSPRes(klass) \ + TypedData_Wrap_Struct((klass), &ossl_ocsp_response_type, 0) +#define SetOCSPRes(obj, res) do { \ + if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ + RTYPEDDATA_DATA(obj) = (res); \ } while (0) #define GetOCSPRes(obj, res) do { \ - Data_Get_Struct(obj, OCSP_RESPONSE, res); \ - if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ -} while (0) -#define SafeGetOCSPRes(obj, res) do { \ - OSSL_Check_Kind(obj, cOCSPRes); \ - GetOCSPRes(obj, res); \ + TypedData_Get_Struct((obj), OCSP_RESPONSE, &ossl_ocsp_response_type, (res)); \ + if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ } while (0) -#define WrapOCSPBasicRes(klass, obj, res) do { \ - if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ - obj = Data_Wrap_Struct(klass, 0, OCSP_BASICRESP_free, res); \ +#define NewOCSPBasicRes(klass) \ + TypedData_Wrap_Struct((klass), &ossl_ocsp_basicresp_type, 0) +#define SetOCSPBasicRes(obj, res) do { \ + if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ + RTYPEDDATA_DATA(obj) = (res); \ } while (0) #define GetOCSPBasicRes(obj, res) do { \ - Data_Get_Struct(obj, OCSP_BASICRESP, res); \ - if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ + TypedData_Get_Struct((obj), OCSP_BASICRESP, &ossl_ocsp_basicresp_type, (res)); \ + if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ +} 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 SafeGetOCSPBasicRes(obj, res) do { \ - OSSL_Check_Kind(obj, cOCSPBasicRes); \ - GetOCSPBasicRes(obj, res); \ +#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 WrapOCSPCertId(klass, obj, cid) do { \ - if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ - obj = Data_Wrap_Struct(klass, 0, OCSP_CERTID_free, cid); \ +#define NewOCSPCertId(klass) \ + TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, 0) +#define SetOCSPCertId(obj, cid) do { \ + if(!(cid)) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ + RTYPEDDATA_DATA(obj) = (cid); \ } while (0) #define GetOCSPCertId(obj, cid) do { \ - Data_Get_Struct(obj, OCSP_CERTID, cid); \ - if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ -} while (0) -#define SafeGetOCSPCertId(obj, cid) do { \ - OSSL_Check_Kind(obj, cOCSPCertId); \ - GetOCSPCertId(obj, cid); \ + TypedData_Get_Struct((obj), OCSP_CERTID, &ossl_ocsp_certid_type, (cid)); \ + if(!(cid)) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \ } while (0) -VALUE mOCSP; -VALUE eOCSPError; -VALUE cOCSPReq; -VALUE cOCSPRes; -VALUE cOCSPBasicRes; -VALUE cOCSPCertId; +static VALUE mOCSP; +static VALUE eOCSPError; +static VALUE cOCSPReq; +static VALUE cOCSPRes; +static VALUE cOCSPBasicRes; +static VALUE cOCSPSingleRes; +static VALUE cOCSPCertId; + +static void +ossl_ocsp_request_free(void *ptr) +{ + OCSP_REQUEST_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_request_type = { + "OpenSSL/OCSP/REQUEST", + { + 0, ossl_ocsp_request_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static void +ossl_ocsp_response_free(void *ptr) +{ + OCSP_RESPONSE_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_response_type = { + "OpenSSL/OCSP/RESPONSE", + { + 0, ossl_ocsp_response_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static void +ossl_ocsp_basicresp_free(void *ptr) +{ + OCSP_BASICRESP_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_basicresp_type = { + "OpenSSL/OCSP/BASICRESP", + { + 0, ossl_ocsp_basicresp_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +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 | RUBY_TYPED_WB_PROTECTED, +}; + +static void +ossl_ocsp_certid_free(void *ptr) +{ + OCSP_CERTID_free(ptr); +} + +static const rb_data_type_t ossl_ocsp_certid_type = { + "OpenSSL/OCSP/CERTID", + { + 0, ossl_ocsp_certid_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; /* * Public */ static VALUE -ossl_ocspcertid_new(OCSP_CERTID *cid) +ossl_ocspcid_new(const OCSP_CERTID *cid) { - VALUE obj; - WrapOCSPCertId(cOCSPCertId, obj, cid); + VALUE obj = NewOCSPCertId(cOCSPCertId); + /* OpenSSL 1.1.1 takes a non-const pointer */ + OCSP_CERTID *cid_new = OCSP_CERTID_dup((OCSP_CERTID *)cid); + if (!cid_new) + ossl_raise(eOCSPError, "OCSP_CERTID_dup"); + SetOCSPCertId(obj, cid_new); return obj; } /* - * OCSP::Resquest + * OCSP::Request */ static VALUE ossl_ocspreq_alloc(VALUE klass) @@ -92,33 +169,77 @@ ossl_ocspreq_alloc(VALUE klass) OCSP_REQUEST *req; VALUE obj; + obj = NewOCSPReq(klass); if (!(req = OCSP_REQUEST_new())) - ossl_raise(eOCSPError, NULL); - WrapOCSPReq(klass, obj, req); + ossl_raise(eOCSPError, NULL); + SetOCSPReq(obj, req); return obj; } +/* :nodoc: */ +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); + GetOCSPReq(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 + * OpenSSL::OCSP::Request.new(request_der) -> request + * + * Creates a new OpenSSL::OCSP::Request. The request may be created empty or + * from a _request_der_ string. + */ + static VALUE ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self) { VALUE arg; - unsigned char *p; + OCSP_REQUEST *req, *req_new; + const unsigned char *p; rb_scan_args(argc, argv, "01", &arg); if(!NIL_P(arg)){ - arg = ossl_to_der_if_possible(arg); - StringValue(arg); - p = (unsigned char*)RSTRING_PTR(arg); - if(!d2i_OCSP_REQUEST((OCSP_REQUEST**)&DATA_PTR(self), &p, - RSTRING_LEN(arg))){ - ossl_raise(eOCSPError, "cannot load DER encoded request"); - } + GetOCSPReq(self, req); + arg = ossl_to_der_if_possible(arg); + StringValue(arg); + 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; } +/* + * call-seq: + * request.add_nonce(nonce = nil) -> request + * + * Adds a _nonce_ to the OCSP request. If no nonce is given a random one will + * be generated. + * + * The nonce is used to prevent replay attacks but some servers do not support + * it. + */ + static VALUE ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self) { @@ -128,31 +249,38 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "01", &val); if(NIL_P(val)) { - GetOCSPReq(self, req); - ret = OCSP_request_add1_nonce(req, NULL, -1); + GetOCSPReq(self, req); + ret = OCSP_request_add1_nonce(req, NULL, -1); } else{ - StringValue(val); - GetOCSPReq(self, req); - ret = OCSP_request_add1_nonce(req, RSTRING_PTR(val), RSTRING_LEN(val)); + StringValue(val); + GetOCSPReq(self, req); + ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val)); } if(!ret) ossl_raise(eOCSPError, NULL); return self; } -/* Check nonce validity in a request and response. - * Return value reflects result: - * 1: nonces present and equal. - * 2: nonces both absent. - * 3: nonce present in response only. - * 0: nonces both present and not equal. - * -1: nonce in request only. +/* + * call-seq: + * request.check_nonce(response) -> result * - * For most responders clients can check return > 0. - * If responder doesn't handle nonces return != 0 may be - * necessary. return == 0 is always an error. + * Checks the nonce validity for this request and _response_. + * + * The return value is one of the following: + * + * -1 :: nonce in request only. + * 0 :: nonces both present and not equal. + * 1 :: nonces present and equal. + * 2 :: nonces both absent. + * 3 :: nonce present in response only. + * + * For most responses, clients can check _result_ > 0. If a responder doesn't + * handle nonces <code>result.nonzero?</code> may be necessary. A result of + * <code>0</code> is always an error. */ + static VALUE ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp) { @@ -161,77 +289,127 @@ ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp) int res; GetOCSPReq(self, req); - SafeGetOCSPBasicRes(basic_resp, bs); + GetOCSPBasicRes(basic_resp, bs); res = OCSP_check_nonce(req, bs); return INT2NUM(res); } +/* + * call-seq: + * request.add_certid(certificate_id) -> request + * + * Adds _certificate_id_ to the request. + */ + static VALUE ossl_ocspreq_add_certid(VALUE self, VALUE certid) { OCSP_REQUEST *req; - OCSP_CERTID *id; + OCSP_CERTID *id, *id_new; GetOCSPReq(self, req); GetOCSPCertId(certid, id); - if(!OCSP_request_add0_id(req, OCSP_CERTID_dup(id))) - ossl_raise(eOCSPError, NULL); + + if (!(id_new = OCSP_CERTID_dup(id))) + ossl_raise(eOCSPError, "OCSP_CERTID_dup"); + if (!OCSP_request_add0_id(req, id_new)) { + OCSP_CERTID_free(id_new); + ossl_raise(eOCSPError, "OCSP_request_add0_id"); + } return self; } +/* + * call-seq: + * request.certid -> [certificate_id, ...] + * + * Returns all certificate IDs in this request. + */ + static VALUE ossl_ocspreq_get_certid(VALUE self) { OCSP_REQUEST *req; - OCSP_ONEREQ *one; - OCSP_CERTID *id; - VALUE ary, tmp; - int i, count; GetOCSPReq(self, req); - count = OCSP_request_onereq_count(req); - ary = (count > 0) ? rb_ary_new() : Qnil; - for(i = 0; i < count; i++){ - one = OCSP_request_onereq_get0(req, i); - if(!(id = OCSP_CERTID_dup(OCSP_onereq_get0_id(one)))) - ossl_raise(eOCSPError, NULL); - WrapOCSPCertId(cOCSPCertId, tmp, id); - rb_ary_push(ary, tmp); + int count = OCSP_request_onereq_count(req); + if (count < 0) + ossl_raise(eOCSPError, "OCSP_request_onereq_count"); + if (count == 0) + return Qnil; + + VALUE ary = rb_ary_new_capa(count); + for (int i = 0; i < count; i++) { + OCSP_ONEREQ *one = OCSP_request_onereq_get0(req, i); + OCSP_CERTID *cid = OCSP_onereq_get0_id(one); + rb_ary_push(ary, ossl_ocspcid_new(cid)); } return ary; } +/* + * call-seq: + * request.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self + * + * 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_ is 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, md_holder; 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); + md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder); + 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, "OCSP_request_sign"); return self; } +/* + * call-seq: + * request.verify(certificates, store, flags = 0) -> true or false + * + * Verifies this request using the given _certificates_ and _store_. + * _certificates_ is an array of OpenSSL::X509::Certificate, _store_ is an + * OpenSSL::X509::Store. + * + * Note that +false+ is returned if the request does not have a signature. + * Use #signed? to check whether the request is signed or not. + */ + static VALUE ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self) { @@ -242,17 +420,22 @@ 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 : INT2NUM(flags); + 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; } +/* + * Returns this request as a DER-encoded string + */ + static VALUE ossl_ocspreq_to_der(VALUE self) { @@ -263,19 +446,42 @@ ossl_ocspreq_to_der(VALUE self) GetOCSPReq(self, req); if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0) - ossl_raise(eOCSPError, NULL); + ossl_raise(eOCSPError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if(i2d_OCSP_REQUEST(req, &p) <= 0) - ossl_raise(eOCSPError, NULL); + ossl_raise(eOCSPError, NULL); ossl_str_adjust(str, p); return str; } /* + * call-seq: + * request.signed? -> true or false + * + * Returns +true+ if the request is signed, +false+ otherwise. Note that the + * validity of the signature is *not* checked. Use #verify to verify that. + */ +static VALUE +ossl_ocspreq_signed_p(VALUE self) +{ + OCSP_REQUEST *req; + + GetOCSPReq(self, req); + return OCSP_request_is_signed(req) ? Qtrue : Qfalse; +} + +/* * OCSP::Response */ + +/* call-seq: + * OpenSSL::OCSP::Response.create(status, basic_response = nil) -> response + * + * Creates an OpenSSL::OCSP::Response from _status_ and _basic_response_. + */ + static VALUE ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp) { @@ -286,9 +492,10 @@ ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp) if(NIL_P(basic_resp)) bs = NULL; else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */ + obj = NewOCSPRes(klass); if(!(res = OCSP_response_create(st, bs))) - ossl_raise(eOCSPError, NULL); - WrapOCSPRes(klass, obj, res); + ossl_raise(eOCSPError, NULL); + SetOCSPRes(obj, res); return obj; } @@ -299,33 +506,73 @@ ossl_ocspres_alloc(VALUE klass) OCSP_RESPONSE *res; VALUE obj; + obj = NewOCSPRes(klass); if(!(res = OCSP_RESPONSE_new())) - ossl_raise(eOCSPError, NULL); - WrapOCSPRes(klass, obj, res); + ossl_raise(eOCSPError, NULL); + SetOCSPRes(obj, res); return obj; } +/* :nodoc: */ +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); + GetOCSPRes(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 + * OpenSSL::OCSP::Response.new(response_der) -> response + * + * Creates a new OpenSSL::OCSP::Response. The response may be created empty or + * from a _response_der_ string. + */ + static VALUE ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self) { VALUE arg; - unsigned char *p; + OCSP_RESPONSE *res, *res_new; + const unsigned char *p; rb_scan_args(argc, argv, "01", &arg); if(!NIL_P(arg)){ - arg = ossl_to_der_if_possible(arg); - StringValue(arg); - p = RSTRING_PTR(arg); - if(!d2i_OCSP_RESPONSE((OCSP_RESPONSE**)&DATA_PTR(self), &p, - RSTRING_LEN(arg))){ - ossl_raise(eOCSPError, "cannot load DER encoded response"); - } + GetOCSPRes(self, res); + arg = ossl_to_der_if_possible(arg); + StringValue(arg); + p = (unsigned char *)RSTRING_PTR(arg); + 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; } +/* + * call-seq: + * response.status -> Integer + * + * Returns the status of the response. + */ + static VALUE ossl_ocspres_status(VALUE self) { @@ -338,6 +585,13 @@ ossl_ocspres_status(VALUE self) return INT2NUM(st); } +/* + * call-seq: + * response.status_string -> String + * + * Returns a status string for the response. + */ + static VALUE ossl_ocspres_status_string(VALUE self) { @@ -350,6 +604,13 @@ ossl_ocspres_status_string(VALUE self) return rb_str_new2(OCSP_response_status_str(st)); } +/* + * call-seq: + * response.basic + * + * Returns a BasicResponse for this response + */ + static VALUE ossl_ocspres_get_basic(VALUE self) { @@ -358,13 +619,21 @@ ossl_ocspres_get_basic(VALUE self) VALUE ret; GetOCSPRes(self, res); + ret = NewOCSPBasicRes(cOCSPBasicRes); if(!(bs = OCSP_response_get1_basic(res))) - return Qnil; - WrapOCSPBasicRes(cOCSPBasicRes, ret, bs); + return Qnil; + SetOCSPBasicRes(ret, bs); return ret; } +/* + * call-seq: + * response.to_der -> String + * + * Returns this response as a DER-encoded string. + */ + static VALUE ossl_ocspres_to_der(VALUE self) { @@ -375,11 +644,11 @@ ossl_ocspres_to_der(VALUE self) GetOCSPRes(self, res); if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0) - ossl_raise(eOCSPError, NULL); + ossl_raise(eOCSPError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); - if(i2d_OCSP_RESPONSE(res, NULL) <= 0) - ossl_raise(eOCSPError, NULL); + p = (unsigned char *)RSTRING_PTR(str); + if(i2d_OCSP_RESPONSE(res, &p) <= 0) + ossl_raise(eOCSPError, NULL); ossl_str_adjust(str, p); return str; @@ -394,19 +663,73 @@ ossl_ocspbres_alloc(VALUE klass) OCSP_BASICRESP *bs; VALUE obj; + obj = NewOCSPBasicRes(klass); if(!(bs = OCSP_BASICRESP_new())) - ossl_raise(eOCSPError, NULL); - WrapOCSPBasicRes(klass, obj, bs); + ossl_raise(eOCSPError, NULL); + SetOCSPBasicRes(obj, bs); return obj; } +/* :nodoc: */ +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); + GetOCSPBasicRes(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(der_string = nil) -> basic_response + * + * 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; } +/* + * call-seq: + * basic_response.copy_nonce(request) -> Integer + * + * Copies the nonce from _request_ into this response. Returns 1 on success + * and 0 on failure. + */ + static VALUE ossl_ocspbres_copy_nonce(VALUE self, VALUE request) { @@ -415,12 +738,20 @@ ossl_ocspbres_copy_nonce(VALUE self, VALUE request) int ret; GetOCSPBasicRes(self, bs); - SafeGetOCSPReq(request, req); + GetOCSPReq(request, req); ret = OCSP_copy_nonce(bs, req); return INT2NUM(ret); } +/* + * call-seq: + * basic_response.add_nonce(nonce = nil) + * + * Adds _nonce_ to this response. If no nonce was provided a random nonce + * will be added. + */ + static VALUE ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self) { @@ -430,13 +761,13 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "01", &val); if(NIL_P(val)) { - GetOCSPBasicRes(self, bs); - ret = OCSP_basic_add1_nonce(bs, NULL, -1); + GetOCSPBasicRes(self, bs); + ret = OCSP_basic_add1_nonce(bs, NULL, -1); } else{ - StringValue(val); - GetOCSPBasicRes(self, bs); - ret = OCSP_basic_add1_nonce(bs, RSTRING_PTR(val), RSTRING_LEN(val)); + StringValue(val); + GetOCSPBasicRes(self, bs); + ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val)); } if(!ret) ossl_raise(eOCSPError, NULL); @@ -444,64 +775,105 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE 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 certificate status for _certificate_id_. _status_ is the status, and + * must be one of these: + * + * - OpenSSL::OCSP::V_CERTSTATUS_GOOD + * - OpenSSL::OCSP::V_CERTSTATUS_REVOKED + * - OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN + * + * _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 the 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, - VALUE thisupd, VALUE nextupd, VALUE ext) + VALUE reason, VALUE revtime, + VALUE thisupd, VALUE nextupd, VALUE ext) { OCSP_BASICRESP *bs; OCSP_SINGLERESP *single; OCSP_CERTID *id; - int st, rsn; - ASN1_TIME *ths, *nxt, *rev; - int error, i, 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); + GetOCSPCertId(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); - for (i = 0; i < RARRAY_LEN(ext); i++) - OSSL_Check_Kind(RARRAY_PTR(ext)[i], cX509Ext); + 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; + error = 1; + goto err; } 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_PTR(ext)[i]); - if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){ - X509_EXTENSION_free(x509ext); - error = 1; - goto err; - } - X509_EXTENSION_free(x509ext); - } + X509_EXTENSION *x509ext; + + for(i = 0; i < RARRAY_LEN(ext); i++){ + x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i)); + if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){ + error = 1; + goto err; + } + } } - err: + err: ASN1_TIME_free(ths); ASN1_TIME_free(nxt); ASN1_TIME_free(rev); @@ -511,81 +883,157 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, return self; } +/* + * call-seq: + * 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::Extension. + * + * This should be superseded by BasicResponse#responses and #find_response that + * return SingleResponse. + */ static VALUE ossl_ocspbres_get_status(VALUE self) { OCSP_BASICRESP *bs; - OCSP_SINGLERESP *single; - OCSP_CERTID *cid; - ASN1_TIME *revtime, *thisupd, *nextupd; - int status, reason; - X509_EXTENSION *x509ext; - VALUE ret, ary, ext; - int count, ext_count, i, j; GetOCSPBasicRes(self, bs); - ret = rb_ary_new(); + VALUE ret = rb_ary_new(); + int count = OCSP_resp_count(bs); + for (int i = 0; i < count; i++) { + OCSP_SINGLERESP *single = OCSP_resp_get0(bs, i); + ASN1_TIME *revtime, *thisupd, *nextupd; + int reason; + + int status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd); + if (status < 0) + ossl_raise(eOCSPError, "OCSP_single_get0_status"); + + VALUE ary = rb_ary_new(); + rb_ary_push(ary, ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(single))); + rb_ary_push(ary, INT2NUM(status)); + rb_ary_push(ary, INT2NUM(reason)); + rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil); + rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil); + rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil); + VALUE ext = rb_ary_new(); + int ext_count = OCSP_SINGLERESP_get_ext_count(single); + for (int j = 0; j < ext_count; j++) { + X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j); + rb_ary_push(ext, ossl_x509ext_new(x509ext)); + } + rb_ary_push(ary, ext); + rb_ary_push(ret, ary); + } + + return ret; +} + +static VALUE ossl_ocspsres_new(const OCSP_SINGLERESP *); + +/* + * call-seq: + * basic_response.responses -> Array of SingleResponse + * + * 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); - for(i = 0; i < count; i++){ - single = OCSP_resp_get0(bs, i); - if(!single) continue; - - revtime = thisupd = nextupd = NULL; - status = OCSP_single_get0_status(single, &reason, &revtime, - &thisupd, &nextupd); - if(status < 0) continue; - if(!(cid = OCSP_CERTID_dup(single->certId))) - ossl_raise(eOCSPError, NULL); - ary = rb_ary_new(); - rb_ary_push(ary, ossl_ocspcertid_new(cid)); - rb_ary_push(ary, INT2NUM(status)); - rb_ary_push(ary, INT2NUM(reason)); - rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil); - rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil); - rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil); - ext = rb_ary_new(); - ext_count = OCSP_SINGLERESP_get_ext_count(single); - for(j = 0; j < ext_count; j++){ - x509ext = OCSP_SINGLERESP_get_ext(single, j); - rb_ary_push(ext, ossl_x509ext_new(x509ext)); - } - rb_ary_push(ary, ext); - rb_ary_push(ret, ary); + ret = rb_ary_new_capa(count); + + for (i = 0; i < count; i++) { + rb_ary_push(ret, ossl_ocspsres_new(OCSP_resp_get0(bs, i))); } 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_CERTID *id; + int n; + + GetOCSPCertId(target, id); + GetOCSPBasicRes(self, bs); + + if ((n = OCSP_resp_find(bs, id, -1)) == -1) + return Qnil; + return ossl_ocspsres_new(OCSP_resp_get0(bs, n)); +} + +/* + * 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, md_holder; 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(); - flg |= OCSP_NOCERTS; - } - else{ - x509s = ossl_x509_ary2sk(certs); - } - GetOCSPBasicRes(self, bs); - ret = OCSP_basic_sign(bs, signer, key, EVP_sha1(), x509s, flg); + if (!NIL_P(flags)) + flg = NUM2INT(flags); + md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder); + if (NIL_P(certs)) + flg |= OCSP_NOCERTS; + else + x509s = ossl_x509_ary2sk(certs); + + 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, "OCSP_basic_sign"); return self; } +/* + * call-seq: + * basic_response.verify(certificates, store, flags = 0) -> true or false + * + * 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) { @@ -596,18 +1044,347 @@ ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self) int flg, result; rb_scan_args(argc, argv, "21", &certs, &store, &flags); + GetOCSPBasicRes(self, bs); x509st = GetX509StorePtr(store); - flg = NIL_P(flags) ? 0 : INT2NUM(flags); + flg = NIL_P(flags) ? 0 : NUM2INT(flags); x509s = ossl_x509_ary2sk(certs); - GetOCSPBasicRes(self, bs); result = OCSP_basic_verify(bs, 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 > 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; + + 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(const OCSP_SINGLERESP *sres) +{ + VALUE obj; + OCSP_SINGLERESP *sres_new; + + obj = NewOCSPSingleRes(cOCSPSingleRes); + /* OpenSSL 1.1.1 takes a non-const pointer */ + sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), + (OCSP_SINGLERESP *)sres); + if (!sres_new) + ossl_raise(eOCSPError, "ASN1_item_dup"); + SetOCSPSingleRes(obj, sres_new); + + 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; +} + +/* :nodoc: */ +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); + GetOCSPSingleRes(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_ seconds 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; - return result ? Qtrue : Qfalse; + GetOCSPSingleRes(self, sres); + return ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(sres)); } /* + * 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"); + if (!time) + return Qnil; + + return asn1time_to_time(time); +} + +/* + * 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"); + if (!time) + return Qnil; + + 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"); + if (!time) + return Qnil; + + 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 */ static VALUE @@ -616,30 +1393,93 @@ ossl_ocspcid_alloc(VALUE klass) OCSP_CERTID *id; VALUE obj; + obj = NewOCSPCertId(klass); if(!(id = OCSP_CERTID_new())) - ossl_raise(eOCSPError, NULL); - WrapOCSPCertId(klass, obj, id); + ossl_raise(eOCSPError, NULL); + SetOCSPCertId(obj, id); return obj; } +/* :nodoc: */ +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); + GetOCSPCertId(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 + * OpenSSL::OCSP::CertificateId.new(obj) -> certificate_id + * + * Creates a new OpenSSL::OCSP::CertificateId for the given _subject_ and + * _issuer_ X509 certificates. The _digest_ is a digest algorithm that is used + * to compute the hash values. This defaults to SHA-1. + * + * If only one argument is given, decodes it as DER representation of a + * certificate ID or generates certificate ID from the object that responds to + * the to_der method. + */ static VALUE -ossl_ocspcid_initialize(VALUE self, VALUE subject, VALUE issuer) +ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self) { OCSP_CERTID *id, *newid; - X509 *x509s, *x509i; + VALUE subject, issuer, digest; - x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */ - x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */ - if(!(newid = OCSP_cert_to_id(NULL, x509s, x509i))) - ossl_raise(eOCSPError, NULL); 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; + VALUE md_holder; + + x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */ + x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */ + md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder); + + newid = OCSP_cert_to_id(md, x509s, x509i); + if (!newid) + ossl_raise(eOCSPError, "OCSP_cert_to_id"); + } + + SetOCSPCertId(self, newid); OCSP_CERTID_free(id); - RDATA(self)->data = newid; return self; } +/* + * call-seq: + * certificate_id.cmp(other) -> true or false + * + * Compares this certificate id with _other_ and returns +true+ if they are the + * same. + */ static VALUE ossl_ocspcid_cmp(VALUE self, VALUE other) { @@ -647,12 +1487,20 @@ ossl_ocspcid_cmp(VALUE self, VALUE other) int result; GetOCSPCertId(self, id); - SafeGetOCSPCertId(other, id2); + GetOCSPCertId(other, id2); result = OCSP_id_cmp(id, id2); return (result == 0) ? Qtrue : Qfalse; } +/* + * call-seq: + * certificate_id.cmp_issuer(other) -> true or false + * + * Compares this certificate id's issuer with _other_ and returns +true+ if + * they are the same. + */ + static VALUE ossl_ocspcid_cmp_issuer(VALUE self, VALUE other) { @@ -660,110 +1508,431 @@ ossl_ocspcid_cmp_issuer(VALUE self, VALUE other) int result; GetOCSPCertId(self, id); - SafeGetOCSPCertId(other, id2); + GetOCSPCertId(other, id2); result = OCSP_id_issuer_cmp(id, id2); return (result == 0) ? Qtrue : Qfalse; } +/* + * call-seq: + * certificate_id.serial -> Integer + * + * 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, ASN1_STRING_length(name_hash) * 2); + ossl_bin2hex(ASN1_STRING_get0_data(name_hash), RSTRING_PTR(ret), + ASN1_STRING_length(name_hash)); + + 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, ASN1_STRING_length(key_hash) * 2); + ossl_bin2hex(ASN1_STRING_get0_data(key_hash), RSTRING_PTR(ret), + ASN1_STRING_length(key_hash)); + + 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; + + GetOCSPCertId(self, id); + OCSP_id_get0_info(NULL, &oid, NULL, NULL, id); + return ossl_asn1obj_to_string_long_name(oid); +} + +/* + * 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 asn1integer_to_num(id->serialNumber); + return str; } void -Init_ossl_ocsp() +Init_ossl_ocsp(void) { + /* + * OpenSSL::OCSP implements Online Certificate Status Protocol requests + * and responses. + * + * Creating and sending an OCSP request requires a subject certificate + * that contains an OCSP URL in an authorityInfoAccess extension and the + * issuer certificate for the subject certificate. First, load the issuer + * and subject certificates: + * + * subject = OpenSSL::X509::Certificate.new subject_pem + * issuer = OpenSSL::X509::Certificate.new issuer_pem + * + * To create the request we need to create a certificate ID for the + * subject certificate so the CA knows which certificate we are asking + * about: + * + * digest = OpenSSL::Digest.new('SHA1') + * certificate_id = + * OpenSSL::OCSP::CertificateId.new subject, issuer, digest + * + * Then create a request and add the certificate ID to it: + * + * request = OpenSSL::OCSP::Request.new + * request.add_certid certificate_id + * + * Adding a nonce to the request protects against replay attacks but not + * all CA process the nonce. + * + * request.add_nonce + * + * To submit the request to the CA for verification we need to extract the + * OCSP URI from the subject certificate: + * + * ocsp_uris = subject.ocsp_uris + * + * require 'uri' + * + * ocsp_uri = URI ocsp_uris[0] + * + * To submit the request we'll POST the request to the OCSP URI (per RFC + * 2560). Note that we only handle HTTP requests and don't handle any + * redirects in this example, so this is insufficient for serious use. + * + * require 'net/http' + * + * http_response = + * Net::HTTP.start ocsp_uri.hostname, ocsp_uri.port do |http| + * http.post ocsp_uri.path, request.to_der, + * 'content-type' => 'application/ocsp-request' + * end + * + * response = OpenSSL::OCSP::Response.new http_response.body + * response_basic = response.basic + * + * First we check if the response has a valid signature. Without a valid + * signature we cannot trust it. If you get a failure here you may be + * missing a system certificate store or may be missing the intermediate + * certificates. + * + * store = OpenSSL::X509::Store.new + * store.set_default_paths + * + * unless response_basic.verify [], store then + * raise 'response is not signed by a trusted certificate' + * end + * + * The response contains the status information (success/fail). We can + * display the status as a string: + * + * puts response.status_string #=> successful + * + * Next we need to know the response details to determine if the response + * matches our request. First we check the nonce. Again, not all CAs + * support a nonce. See Request#check_nonce for the meanings of the + * return values. + * + * p request.check_nonce basic_response #=> value from -1 to 3 + * + * Then extract the status information for the certificate from the basic + * response. + * + * single_response = basic_response.find_response(certificate_id) + * + * unless single_response + * raise 'basic_response does not have the status for the certificate' + * end + * + * Then check the validity. A status issued in the future must be rejected. + * + * unless single_response.check_validity + * raise 'this_update is in the future or next_update time has passed' + * end + * + * 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 + */ + mOCSP = rb_define_module_under(mOSSL, "OCSP"); + /* + * OCSP error class. + */ + eOCSPError = rb_define_class_under(mOCSP, "OCSPError", eOSSLError); + /* + * An OpenSSL::OCSP::Request contains the certificate information for + * determining if a certificate has been revoked or not. A Request can be + * created for a certificate or from a DER-encoded request created + * elsewhere. + */ + cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject); rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc); + rb_define_method(cOCSPReq, "initialize_copy", ossl_ocspreq_initialize_copy, 1); 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); rb_define_method(cOCSPReq, "add_certid", ossl_ocspreq_add_certid, 1); rb_define_method(cOCSPReq, "certid", ossl_ocspreq_get_certid, 0); + rb_define_method(cOCSPReq, "signed?", ossl_ocspreq_signed_p, 0); rb_define_method(cOCSPReq, "sign", ossl_ocspreq_sign, -1); rb_define_method(cOCSPReq, "verify", ossl_ocspreq_verify, -1); rb_define_method(cOCSPReq, "to_der", ossl_ocspreq_to_der, 0); + /* + * An OpenSSL::OCSP::Response contains the status of a certificate check + * which is created from an OpenSSL::OCSP::Request. + */ + 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_method(cOCSPRes, "initialize_copy", ossl_ocspres_initialize_copy, 1); 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); rb_define_method(cOCSPRes, "basic", ossl_ocspres_get_basic, 0); rb_define_method(cOCSPRes, "to_der", ossl_ocspres_to_der, 0); + /* + * An OpenSSL::OCSP::BasicResponse contains the status of a certificate + * check which is created from an OpenSSL::OCSP::Request. A + * BasicResponse is more detailed than a Response. + */ + cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject); rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc); + rb_define_method(cOCSPBasicRes, "initialize_copy", ossl_ocspbres_initialize_copy, 1); 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_method(cOCSPSingleRes, "initialize_copy", ossl_ocspsres_initialize_copy, 1); + 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 + * that a status check can be performed. + */ cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject); rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc); - rb_define_method(cOCSPCertId, "initialize", ossl_ocspcid_initialize, 2); + rb_define_method(cOCSPCertId, "initialize_copy", ossl_ocspcid_initialize_copy, 1); + 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)); -#define DefOCSPConst(x) rb_define_const(mOCSP, #x, INT2NUM(OCSP_##x)) - - DefOCSPConst(RESPONSE_STATUS_SUCCESSFUL); - DefOCSPConst(RESPONSE_STATUS_MALFORMEDREQUEST); - DefOCSPConst(RESPONSE_STATUS_INTERNALERROR); - DefOCSPConst(RESPONSE_STATUS_TRYLATER); - DefOCSPConst(RESPONSE_STATUS_SIGREQUIRED); - DefOCSPConst(RESPONSE_STATUS_UNAUTHORIZED); - - DefOCSPConst(REVOKED_STATUS_NOSTATUS); - DefOCSPConst(REVOKED_STATUS_UNSPECIFIED); - DefOCSPConst(REVOKED_STATUS_KEYCOMPROMISE); - DefOCSPConst(REVOKED_STATUS_CACOMPROMISE); - DefOCSPConst(REVOKED_STATUS_AFFILIATIONCHANGED); - DefOCSPConst(REVOKED_STATUS_SUPERSEDED); - DefOCSPConst(REVOKED_STATUS_CESSATIONOFOPERATION); - DefOCSPConst(REVOKED_STATUS_CERTIFICATEHOLD); - DefOCSPConst(REVOKED_STATUS_REMOVEFROMCRL); - - DefOCSPConst(NOCERTS); - DefOCSPConst(NOINTERN); - DefOCSPConst(NOSIGS); - DefOCSPConst(NOCHAIN); - DefOCSPConst(NOVERIFY); - DefOCSPConst(NOEXPLICIT); - DefOCSPConst(NOCASIGN); - DefOCSPConst(NODELEGATED); - DefOCSPConst(NOCHECKS); - DefOCSPConst(TRUSTOTHER); - DefOCSPConst(RESPID_KEY); - DefOCSPConst(NOTIME); - -#define DefOCSPVConst(x) rb_define_const(mOCSP, "V_" #x, INT2NUM(V_OCSP_##x)) - - DefOCSPVConst(CERTSTATUS_GOOD); - DefOCSPVConst(CERTSTATUS_REVOKED); - DefOCSPVConst(CERTSTATUS_UNKNOWN); - DefOCSPVConst(RESPID_NAME); - DefOCSPVConst(RESPID_KEY); -} - -#else /* ! OSSL_OCSP_ENABLED */ + /* Illegal confirmation request */ + rb_define_const(mOCSP, "RESPONSE_STATUS_MALFORMEDREQUEST", INT2NUM(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST)); + + /* The certificate was revoked for an unknown reason */ + rb_define_const(mOCSP, "REVOKED_STATUS_NOSTATUS", INT2NUM(OCSP_REVOKED_STATUS_NOSTATUS)); + + /* You must sign the request and resubmit */ + rb_define_const(mOCSP, "RESPONSE_STATUS_SIGREQUIRED", INT2NUM(OCSP_RESPONSE_STATUS_SIGREQUIRED)); + + /* Response has valid confirmations */ + rb_define_const(mOCSP, "RESPONSE_STATUS_SUCCESSFUL", INT2NUM(OCSP_RESPONSE_STATUS_SUCCESSFUL)); + + /* Try again later */ + rb_define_const(mOCSP, "RESPONSE_STATUS_TRYLATER", INT2NUM(OCSP_RESPONSE_STATUS_TRYLATER)); + + /* The certificate subject's name or other information changed */ + rb_define_const(mOCSP, "REVOKED_STATUS_AFFILIATIONCHANGED", INT2NUM(OCSP_REVOKED_STATUS_AFFILIATIONCHANGED)); + + /* This CA certificate was revoked due to a key compromise */ + rb_define_const(mOCSP, "REVOKED_STATUS_CACOMPROMISE", INT2NUM(OCSP_REVOKED_STATUS_CACOMPROMISE)); + + /* The certificate is on hold */ + rb_define_const(mOCSP, "REVOKED_STATUS_CERTIFICATEHOLD", INT2NUM(OCSP_REVOKED_STATUS_CERTIFICATEHOLD)); + + /* The certificate is no longer needed */ + rb_define_const(mOCSP, "REVOKED_STATUS_CESSATIONOFOPERATION", INT2NUM(OCSP_REVOKED_STATUS_CESSATIONOFOPERATION)); + + /* The certificate was revoked due to a key compromise */ + rb_define_const(mOCSP, "REVOKED_STATUS_KEYCOMPROMISE", INT2NUM(OCSP_REVOKED_STATUS_KEYCOMPROMISE)); + + /* The certificate was previously on hold and should now be removed from + * the CRL */ + rb_define_const(mOCSP, "REVOKED_STATUS_REMOVEFROMCRL", INT2NUM(OCSP_REVOKED_STATUS_REMOVEFROMCRL)); + + /* The certificate was superseded by a new certificate */ + rb_define_const(mOCSP, "REVOKED_STATUS_SUPERSEDED", INT2NUM(OCSP_REVOKED_STATUS_SUPERSEDED)); + + /* Your request is unauthorized. */ + rb_define_const(mOCSP, "RESPONSE_STATUS_UNAUTHORIZED", INT2NUM(OCSP_RESPONSE_STATUS_UNAUTHORIZED)); + + /* The certificate was revoked for an unspecified reason */ + rb_define_const(mOCSP, "REVOKED_STATUS_UNSPECIFIED", INT2NUM(OCSP_REVOKED_STATUS_UNSPECIFIED)); + + /* Do not include certificates in the response */ + rb_define_const(mOCSP, "NOCERTS", INT2NUM(OCSP_NOCERTS)); + + /* Do not search certificates contained in the response for a signer */ + rb_define_const(mOCSP, "NOINTERN", INT2NUM(OCSP_NOINTERN)); + + /* Do not check the signature on the response */ + rb_define_const(mOCSP, "NOSIGS", INT2NUM(OCSP_NOSIGS)); + + /* Do not verify the certificate chain on the response */ + rb_define_const(mOCSP, "NOCHAIN", INT2NUM(OCSP_NOCHAIN)); + + /* Do not verify the response at all */ + rb_define_const(mOCSP, "NOVERIFY", INT2NUM(OCSP_NOVERIFY)); + + /* Do not check trust */ + rb_define_const(mOCSP, "NOEXPLICIT", INT2NUM(OCSP_NOEXPLICIT)); + + /* (This flag is not used by OpenSSL 1.0.1g) */ + rb_define_const(mOCSP, "NOCASIGN", INT2NUM(OCSP_NOCASIGN)); + + /* (This flag is not used by OpenSSL 1.0.1g) */ + rb_define_const(mOCSP, "NODELEGATED", INT2NUM(OCSP_NODELEGATED)); + + /* Do not make additional signing certificate checks */ + rb_define_const(mOCSP, "NOCHECKS", INT2NUM(OCSP_NOCHECKS)); + + /* Do not verify additional certificates */ + rb_define_const(mOCSP, "TRUSTOTHER", INT2NUM(OCSP_TRUSTOTHER)); + + /* Identify the response by signing the certificate key ID */ + rb_define_const(mOCSP, "RESPID_KEY", INT2NUM(OCSP_RESPID_KEY)); + + /* Do not include producedAt time in response */ + rb_define_const(mOCSP, "NOTIME", INT2NUM(OCSP_NOTIME)); + + /* Indicates the certificate is not revoked but does not necessarily mean + * the certificate was issued or that this response is within the + * certificate's validity interval */ + rb_define_const(mOCSP, "V_CERTSTATUS_GOOD", INT2NUM(V_OCSP_CERTSTATUS_GOOD)); + /* Indicates the certificate has been revoked either permanently or + * temporarily (on hold). */ + rb_define_const(mOCSP, "V_CERTSTATUS_REVOKED", INT2NUM(V_OCSP_CERTSTATUS_REVOKED)); + + /* Indicates the responder does not know about the certificate being + * requested. */ + rb_define_const(mOCSP, "V_CERTSTATUS_UNKNOWN", INT2NUM(V_OCSP_CERTSTATUS_UNKNOWN)); + + /* The responder ID is based on the key name. */ + rb_define_const(mOCSP, "V_RESPID_NAME", INT2NUM(V_OCSP_RESPID_NAME)); + + /* The responder ID is based on the public key. */ + rb_define_const(mOCSP, "V_RESPID_KEY", INT2NUM(V_OCSP_RESPID_KEY)); +} +#else void -Init_ossl_ocsp() +Init_ossl_ocsp(void) { } #endif diff --git a/ext/openssl/ossl_ocsp.h b/ext/openssl/ossl_ocsp.h index 65b4f2e23f..becd70ffed 100644 --- a/ext/openssl/ossl_ocsp.h +++ b/ext/openssl/ossl_ocsp.h @@ -1,24 +1,16 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz> * Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_OCSP_H_) #define _OSSL_OCSP_H_ -#if defined(OSSL_OCSP_ENABLED) -extern VALUE mOCSP; -extern VALUE cOPCSReq; -extern VALUE cOPCSRes; -extern VALUE cOPCSBasicRes; -#endif - void Init_ossl_ocsp(void); #endif /* _OSSL_OCSP_H_ */ diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c index 2ec69ba8db..32b82a881c 100644 --- a/ext/openssl/ossl_pkcs12.c +++ b/ext/openssl/ossl_pkcs12.c @@ -1,23 +1,20 @@ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) - * $Id$ + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapPKCS12(klass, obj, p12) do { \ - if(!p12) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ - obj = Data_Wrap_Struct(klass, 0, PKCS12_free, p12); \ -} while (0) +#define NewPKCS12(klass) \ + TypedData_Wrap_Struct((klass), &ossl_pkcs12_type, 0) -#define GetPKCS12(obj, p12) do { \ - Data_Get_Struct(obj, PKCS12, p12); \ - if(!p12) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ +#define SetPKCS12(obj, p12) do { \ + if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ + RTYPEDDATA_DATA(obj) = (p12); \ } while (0) -#define SafeGetPKCS12(obj, p12) do { \ - OSSL_Check_Kind(obj, cPKCS12); \ - GetPKCS12(obj, p12); \ +#define GetPKCS12(obj, p12) do { \ + TypedData_Get_Struct((obj), PKCS12, &ossl_pkcs12_type, (p12)); \ + if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ } while (0) #define ossl_pkcs12_set_key(o,v) rb_iv_set((o), "@key", (v)) @@ -30,43 +27,78 @@ /* * Classes */ -VALUE cPKCS12; -VALUE ePKCS12Error; +static VALUE cPKCS12; +static VALUE ePKCS12Error; /* * Private */ +static void +ossl_pkcs12_free(void *ptr) +{ + PKCS12_free(ptr); +} + +static const rb_data_type_t ossl_pkcs12_type = { + "OpenSSL/PKCS12", + { + 0, ossl_pkcs12_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + static VALUE ossl_pkcs12_s_allocate(VALUE klass) { PKCS12 *p12; VALUE obj; + obj = NewPKCS12(klass); if(!(p12 = PKCS12_new())) ossl_raise(ePKCS12Error, NULL); - WrapPKCS12(klass, obj, p12); + SetPKCS12(obj, p12); return obj; } +/* :nodoc: */ +static VALUE +ossl_pkcs12_initialize_copy(VALUE self, VALUE other) +{ + PKCS12 *p12, *p12_old, *p12_new; + + rb_check_frozen(self); + GetPKCS12(self, p12_old); + GetPKCS12(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]]]]]]) * * === Parameters - * * +pass+ - string - * * +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. - * * +ca+ - An optional array of X509::Certificate's. - * * +key_pbe+ - string - * * +cert_pbe+ - string - * * +key_iter+ - integer - * * +mac_iter+ - integer - * * +keytype+ - An integer representing an MSIE specific extension. + * * _pass_ - string + * * _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. + * * _ca_ - An optional array of X509::Certificate's. + * * _key_pbe_ - string + * * _cert_pbe_ - string + * * _key_iter_ - integer + * * _mac_iter_ - integer + * * _keytype_ - An integer representing an MSIE specific extension. * - * Any optional arguments may be supplied as nil to preserve the OpenSSL defaults. + * Any optional arguments may be supplied as +nil+ to preserve the OpenSSL defaults. * * See the OpenSSL documentation for PKCS12_create(). */ @@ -81,21 +113,20 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) STACK_OF(X509) *x509s; int nkey = 0, ncert = 0, kiter = 0, miter = 0, ktype = 0; 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); - x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca); /* TODO: make a VALUE to nid function */ if (!NIL_P(key_nid)) { - if ((nkey = OBJ_txt2nid(StringValuePtr(key_nid))) == NID_undef) - rb_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) - rb_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); @@ -104,11 +135,23 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) if (!NIL_P(keytype)) ktype = NUM2INT(keytype); +#if defined(OPENSSL_IS_AWSLC) + if (ktype != 0) { + ossl_raise(rb_eArgError, "Unknown key usage type %"PRIsVALUE, INT2NUM(ktype)); + } +#else + if (ktype != 0 && ktype != KEY_SIG && ktype != KEY_EX) { + ossl_raise(rb_eArgError, "Unknown key usage type %"PRIsVALUE, INT2NUM(ktype)); + } +#endif + + obj = NewPKCS12(cPKCS12); + x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca); p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s, nkey, ncert, kiter, miter, ktype); sk_X509_pop_free(x509s, X509_free); if(!p12) ossl_raise(ePKCS12Error, NULL); - WrapPKCS12(cPKCS12, obj, p12); + SetPKCS12(obj, p12); ossl_pkcs12_set_key(obj, pkey); ossl_pkcs12_set_cert(obj, cert); @@ -117,6 +160,24 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) return obj; } +static VALUE +ossl_pkey_wrap_i(VALUE arg) +{ + return ossl_pkey_wrap((EVP_PKEY *)arg); +} + +static VALUE +ossl_x509_new_i(VALUE arg) +{ + return ossl_x509_new((X509 *)arg); +} + +static VALUE +ossl_x509_sk2ary_i(VALUE arg) +{ + return ossl_x509_sk2ary((STACK_OF(X509) *)arg); +} + /* * call-seq: * PKCS12.new -> pkcs12 @@ -124,8 +185,8 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) * PKCS12.new(str, pass) -> pkcs12 * * === Parameters - * * +str+ - Must be a DER encoded PKCS12 string. - * * +pass+ - string + * * _str_ - Must be a DER encoded PKCS12 string. + * * _pass_ - string */ static VALUE ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) @@ -137,25 +198,29 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) X509 *x509; STACK_OF(X509) *x509s = NULL; int st = 0; + 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); - d2i_PKCS12_bio(in, (PKCS12 **)&DATA_PTR(self)); + passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass); + in = ossl_obj2bio(&arg); + d2i_PKCS12_bio(in, &pkcs); + DATA_PTR(self) = pkcs; BIO_free(in); pkey = cert = ca = Qnil; - if(!PKCS12_parse((PKCS12*)DATA_PTR(self), passphrase, &key, &x509, &x509s)) - ossl_raise(ePKCS12Error, "PKCS12_parse"); - 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(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s)) + ossl_raise(ePKCS12Error, "PKCS12_parse"); + if (key) { + pkey = rb_protect(ossl_pkey_wrap_i, (VALUE)key, &st); + if (st) goto err; + } + if (x509) { + cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st); + if (st) goto err; + } + if (x509s) { + ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st); + if (st) goto err; } err: @@ -179,19 +244,62 @@ ossl_pkcs12_to_der(VALUE self) GetPKCS12(self, p12); if((len = i2d_PKCS12(p12, NULL)) <= 0) - ossl_raise(ePKCS12Error, NULL); + ossl_raise(ePKCS12Error, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if(i2d_PKCS12(p12, &p) <= 0) - ossl_raise(ePKCS12Error, NULL); + ossl_raise(ePKCS12Error, NULL); ossl_str_adjust(str, p); return str; } +/* + * call-seq: + * pkcs12.set_mac(pass, salt = nil, iter = nil, md_type = nil) + * + * Sets MAC parameters and generates MAC over the PKCS #12 structure. + * + * This method uses HMAC and the PKCS #12 specific password-based KDF as + * specified in the original PKCS #12. + * + * See also the man page PKCS12_set_mac(3). + * + * Added in version 3.3.0. + */ +static VALUE +pkcs12_set_mac(int argc, VALUE *argv, VALUE self) +{ + PKCS12 *p12; + VALUE pass, salt, iter, md_name, md_holder = Qnil; + int iter_i = 0; + const EVP_MD *md_type = NULL; + + rb_scan_args(argc, argv, "13", &pass, &salt, &iter, &md_name); + rb_check_frozen(self); + GetPKCS12(self, p12); + + StringValue(pass); + if (!NIL_P(salt)) + StringValue(salt); + if (!NIL_P(iter)) + iter_i = NUM2INT(iter); + if (!NIL_P(md_name)) + md_type = ossl_evp_md_fetch(md_name, &md_holder); + + if (!PKCS12_set_mac(p12, RSTRING_PTR(pass), RSTRING_LENINT(pass), + !NIL_P(salt) ? (unsigned char *)RSTRING_PTR(salt) : NULL, + !NIL_P(salt) ? RSTRING_LENINT(salt) : 0, + iter_i, md_type)) + ossl_raise(ePKCS12Error, "PKCS12_set_mac"); + + return Qnil; +} + void -Init_ossl_pkcs12() +Init_ossl_pkcs12(void) { +#undef rb_intern /* * Defines a file format commonly used to store private keys with * accompanying public key certificates, protected with a password-based @@ -202,9 +310,17 @@ Init_ossl_pkcs12() rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1); rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate); + rb_define_method(cPKCS12, "initialize_copy", ossl_pkcs12_initialize_copy, 1); 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); rb_define_method(cPKCS12, "initialize", ossl_pkcs12_initialize, -1); rb_define_method(cPKCS12, "to_der", ossl_pkcs12_to_der, 0); + rb_define_method(cPKCS12, "set_mac", pkcs12_set_mac, -1); + +#if !defined(OPENSSL_IS_AWSLC) + /* MSIE specific PKCS12 key usage extensions */ + rb_define_const(cPKCS12, "KEY_EX", INT2NUM(KEY_EX)); + rb_define_const(cPKCS12, "KEY_SIG", INT2NUM(KEY_SIG)); +#endif } diff --git a/ext/openssl/ossl_pkcs12.h b/ext/openssl/ossl_pkcs12.h index 24d25d00bb..6d2cd901cb 100644 --- a/ext/openssl/ossl_pkcs12.h +++ b/ext/openssl/ossl_pkcs12.h @@ -1,15 +1,10 @@ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) - * $Id$ + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_PKCS12_H_) #define _OSSL_PKCS12_H_ -extern VALUE cPKCS12; -extern VALUE ePKCS12Error; - void Init_ossl_pkcs12(void); #endif /* _OSSL_PKCS12_H_ */ - diff --git a/ext/openssl/ossl_pkcs5.c b/ext/openssl/ossl_pkcs5.c deleted file mode 100644 index ca02a18c67..0000000000 --- a/ext/openssl/ossl_pkcs5.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * $Id$ - * Copyright (C) 2007 Technorama Ltd. <oss-ruby@technorama.net> - */ -#include "ossl.h" - -VALUE mPKCS5; -VALUE ePKCS5; - -/* - * call-seq: - * PKCS5.pbkdf2_hmac(pass, salt, iter, keylen, digest) => string - * - * === Parameters - * * +pass+ - string - * * +salt+ - string - * * +iter+ - integer - should be greater than 1000. 2000 is better. - * * +keylen+ - integer - * * +digest+ - a string or OpenSSL::Digest object. - * - * Available in OpenSSL 0.9.9?. - * - * Digests other than SHA1 may not be supported by other cryptography libraries. - */ -static VALUE -ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen, VALUE digest) -{ -#ifdef HAVE_PKCS5_PBKDF2_HMAC - VALUE str; - const EVP_MD md; - int len = NUM2INT(keylen); - - StringValue(pass); - StringValue(salt); - md = GetDigestPtr(digest); - - str = rb_str_new(0, len); - - if (PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LEN(pass), RSTRING_PTR(salt), RSTRING_LEN(salt), NUM2INT(iter), md, len, RSTRING_PTR(str)) != 1) - ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC"); - - return str; -#else - rb_notimplement(); -#endif -} - - -/* - * call-seq: - * PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, keylen) => string - * - * === Parameters - * * +pass+ - string - * * +salt+ - string - * * +iter+ - integer - should be greater than 1000. 2000 is better. - * * +keylen+ - integer - * - * This method is available almost any version OpenSSL. - * - * Conforms to rfc2898. - */ -static VALUE -ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen) -{ -#ifdef HAVE_PKCS5_PBKDF2_HMAC_SHA1 - VALUE str; - int len = NUM2INT(keylen); - - StringValue(pass); - StringValue(salt); - - str = rb_str_new(0, len); - - if (PKCS5_PBKDF2_HMAC_SHA1(RSTRING_PTR(pass), RSTRING_LEN(pass), RSTRING_PTR(salt), RSTRING_LEN(salt), NUM2INT(iter), len, RSTRING_PTR(str)) != 1) - ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC_SHA1"); - - return str; -#else - rb_notimplement(); -#endif -} - -void -Init_ossl_pkcs5() -{ - /* - * Password-based Encryption - * - */ - mPKCS5 = rb_define_module_under(mOSSL, "PKCS5"); - ePKCS5 = rb_define_class_under(mPKCS5, "PKCS5Error", eOSSLError); - - rb_define_module_function(mPKCS5, "pbkdf2_hmac", ossl_pkcs5_pbkdf2_hmac, 5); - rb_define_module_function(mPKCS5, "pbkdf2_hmac_sha1", ossl_pkcs5_pbkdf2_hmac_sha1, 4); -} diff --git a/ext/openssl/ossl_pkcs5.h b/ext/openssl/ossl_pkcs5.h deleted file mode 100644 index a3b132bc50..0000000000 --- a/ext/openssl/ossl_pkcs5.h +++ /dev/null @@ -1,6 +0,0 @@ -#if !defined(_OSSL_PKCS5_H_) -#define _OSSL_PKCS5_H_ - -void Init_ossl_pkcs5(void); - -#endif /* _OSSL_PKCS5_H_ */ diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index 6918844779..6e51fd42b9 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -1,135 +1,192 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapPKCS7(klass, obj, pkcs7) do { \ - if (!pkcs7) { \ - ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ +#define NewPKCS7(klass) \ + TypedData_Wrap_Struct((klass), &ossl_pkcs7_type, 0) +#define SetPKCS7(obj, pkcs7) do { \ + if (!(pkcs7)) { \ + ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ } \ - obj = Data_Wrap_Struct(klass, 0, PKCS7_free, pkcs7); \ + RTYPEDDATA_DATA(obj) = (pkcs7); \ } while (0) #define GetPKCS7(obj, pkcs7) do { \ - Data_Get_Struct(obj, PKCS7, pkcs7); \ - if (!pkcs7) { \ - ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ + TypedData_Get_Struct((obj), PKCS7, &ossl_pkcs7_type, (pkcs7)); \ + if (!(pkcs7)) { \ + ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \ } \ } while (0) -#define SafeGetPKCS7(obj, pkcs7) do { \ - OSSL_Check_Kind(obj, cPKCS7); \ - GetPKCS7(obj, pkcs7); \ -} while (0) -#define WrapPKCS7si(klass, obj, p7si) do { \ - if (!p7si) { \ - ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ +#define NewPKCS7si(klass) \ + TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, 0) +#define SetPKCS7si(obj, p7si) do { \ + if (!(p7si)) { \ + ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ } \ - obj = Data_Wrap_Struct(klass, 0, PKCS7_SIGNER_INFO_free, p7si); \ + RTYPEDDATA_DATA(obj) = (p7si); \ } while (0) #define GetPKCS7si(obj, p7si) do { \ - Data_Get_Struct(obj, PKCS7_SIGNER_INFO, p7si); \ - if (!p7si) { \ - ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ + TypedData_Get_Struct((obj), PKCS7_SIGNER_INFO, &ossl_pkcs7_signer_info_type, (p7si)); \ + if (!(p7si)) { \ + ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \ } \ } while (0) -#define SafeGetPKCS7si(obj, p7si) do { \ - OSSL_Check_Kind(obj, cPKCS7Signer); \ - GetPKCS7si(obj, p7si); \ -} while (0) -#define WrapPKCS7ri(klass, obj, p7ri) do { \ - if (!p7ri) { \ - ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ +#define NewPKCS7ri(klass) \ + TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, 0) +#define SetPKCS7ri(obj, p7ri) do { \ + if (!(p7ri)) { \ + ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ } \ - obj = Data_Wrap_Struct(klass, 0, PKCS7_RECIP_INFO_free, p7ri); \ + RTYPEDDATA_DATA(obj) = (p7ri); \ } while (0) #define GetPKCS7ri(obj, p7ri) do { \ - Data_Get_Struct(obj, PKCS7_RECIP_INFO, p7ri); \ - if (!p7ri) { \ - ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ + TypedData_Get_Struct((obj), PKCS7_RECIP_INFO, &ossl_pkcs7_recip_info_type, (p7ri)); \ + if (!(p7ri)) { \ + ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \ } \ } while (0) -#define SafeGetPKCS7ri(obj, p7ri) do { \ - OSSL_Check_Kind(obj, cPKCS7Recipient); \ - GetPKCS7ri(obj, p7ri); \ -} while (0) -#define numberof(ary) (sizeof(ary)/sizeof(ary[0])) +#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0])) #define ossl_pkcs7_set_data(o,v) rb_iv_set((o), "@data", (v)) #define ossl_pkcs7_get_data(o) rb_iv_get((o), "@data") #define ossl_pkcs7_set_err_string(o,v) rb_iv_set((o), "@error_string", (v)) #define ossl_pkcs7_get_err_string(o) rb_iv_get((o), "@error_string") -/* +/* * Classes */ -VALUE cPKCS7; -VALUE cPKCS7Signer; -VALUE cPKCS7Recipient; -VALUE ePKCS7Error; +static VALUE cPKCS7; +static VALUE cPKCS7Signer; +static VALUE cPKCS7Recipient; +static VALUE ePKCS7Error; +static ID id_md_holder, id_cipher_holder; + +static void +ossl_pkcs7_free(void *ptr) +{ + PKCS7_free(ptr); +} -/* - * Public - * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM) - */ -static VALUE -ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si) +static const rb_data_type_t ossl_pkcs7_type = { + "OpenSSL/PKCS7", + { + 0, ossl_pkcs7_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +VALUE +ossl_pkcs7_new(PKCS7 *p7) { - PKCS7_SIGNER_INFO *pkcs7; - VALUE obj; + PKCS7 *new; + VALUE obj = NewPKCS7(cPKCS7); - pkcs7 = p7si ? PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new(); - if (!pkcs7) ossl_raise(ePKCS7Error, NULL); - WrapPKCS7si(cPKCS7Signer, obj, pkcs7); + new = PKCS7_dup(p7); + if (!new) + ossl_raise(ePKCS7Error, "PKCS7_dup"); + SetPKCS7(obj, new); return obj; } +static void +ossl_pkcs7_signer_info_free(void *ptr) +{ + PKCS7_SIGNER_INFO_free(ptr); +} + +static const rb_data_type_t ossl_pkcs7_signer_info_type = { + "OpenSSL/PKCS7/SIGNER_INFO", + { + 0, ossl_pkcs7_signer_info_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static void +ossl_pkcs7_recip_info_free(void *ptr) +{ + PKCS7_RECIP_INFO_free(ptr); +} + +static const rb_data_type_t ossl_pkcs7_recip_info_type = { + "OpenSSL/PKCS7/RECIP_INFO", + { + 0, ossl_pkcs7_recip_info_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* + * Public + * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM) + */ static PKCS7_SIGNER_INFO * -DupPKCS7SignerPtr(VALUE obj) +ossl_PKCS7_SIGNER_INFO_dup(PKCS7_SIGNER_INFO *si) { - PKCS7_SIGNER_INFO *p7si, *pkcs7; - - SafeGetPKCS7si(obj, p7si); - if (!(pkcs7 = PKCS7_SIGNER_INFO_dup(p7si))) { - ossl_raise(ePKCS7Error, NULL); + PKCS7_SIGNER_INFO *si_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO, + (d2i_of_void *)d2i_PKCS7_SIGNER_INFO, + si); + if (si_new && si->pkey) { + EVP_PKEY_up_ref(si->pkey); + si_new->pkey = si->pkey; } + return si_new; +} - return pkcs7; +static PKCS7_RECIP_INFO * +ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *ri) +{ + PKCS7_RECIP_INFO *ri_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO, + (d2i_of_void *)d2i_PKCS7_RECIP_INFO, + ri); + if (ri_new && ri->cert) { + if (!X509_up_ref(ri->cert)) { + PKCS7_RECIP_INFO_free(ri_new); + return NULL; + } + ri_new->cert = ri->cert; + } + return ri_new; } static VALUE -ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri) +ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si) { - PKCS7_RECIP_INFO *pkcs7; + PKCS7_SIGNER_INFO *p7si_new; VALUE obj; - pkcs7 = p7ri ? PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new(); - if (!pkcs7) ossl_raise(ePKCS7Error, NULL); - WrapPKCS7ri(cPKCS7Recipient, obj, pkcs7); + obj = NewPKCS7si(cPKCS7Signer); + p7si_new = ossl_PKCS7_SIGNER_INFO_dup(p7si); + if (!p7si_new) + ossl_raise(ePKCS7Error, "ASN1_dup"); + SetPKCS7si(obj, p7si_new); return obj; } -static PKCS7_RECIP_INFO * -DupPKCS7RecipientPtr(VALUE obj) +static VALUE +ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri) { - PKCS7_RECIP_INFO *p7ri, *pkcs7; - - SafeGetPKCS7ri(obj, p7ri); - if (!(pkcs7 = PKCS7_RECIP_INFO_dup(p7ri))) { - ossl_raise(ePKCS7Error, NULL); - } + PKCS7_RECIP_INFO *p7ri_new; + VALUE obj; - return pkcs7; + obj = NewPKCS7ri(cPKCS7Recipient); + p7ri_new = ossl_PKCS7_RECIP_INFO_dup(p7ri); + if (!p7ri_new) + ossl_raise(ePKCS7Error,"ASN1_dup"); + SetPKCS7ri(obj, p7ri_new); + + return obj; } /* @@ -143,13 +200,20 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg) PKCS7 *pkcs7; VALUE ret, data; - in = ossl_obj2bio(arg); + ret = NewPKCS7(cPKCS7); + in = ossl_obj2bio(&arg); out = NULL; pkcs7 = SMIME_read_PKCS7(in, &out); BIO_free(in); - if(!pkcs7) ossl_raise(ePKCS7Error, NULL); + if (!pkcs7) + ossl_raise(ePKCS7Error, "Could not parse the PKCS7"); + if (!pkcs7->d.ptr) { + PKCS7_free(pkcs7); + ossl_raise(ePKCS7Error, "No content in PKCS7"); + } + data = out ? ossl_membio2str(out) : Qnil; - WrapPKCS7(cPKCS7, ret, pkcs7); + SetPKCS7(ret, pkcs7); ossl_pkcs7_set_data(ret, data); ossl_pkcs7_set_err_string(ret, Qnil); @@ -172,10 +236,10 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass) rb_scan_args(argc, argv, "12", &pkcs7, &data, &flags); flg = NIL_P(flags) ? 0 : NUM2INT(flags); if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7); - SafeGetPKCS7(pkcs7, p7); + GetPKCS7(pkcs7, p7); if(!NIL_P(data) && PKCS7_is_detached(p7)) - flg |= PKCS7_DETACHED; - in = NIL_P(data) ? NULL : ossl_obj2bio(data); + flg |= PKCS7_DETACHED; + in = NIL_P(data) ? NULL : ossl_obj2bio(&data); if(!(out = BIO_new(BIO_s_mem()))){ BIO_free(in); ossl_raise(ePKCS7Error, NULL); @@ -211,21 +275,22 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass) x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); - in = ossl_obj2bio(data); + ret = NewPKCS7(cPKCS7); + in = ossl_obj2bio(&data); if(NIL_P(certs)) x509s = NULL; else{ - x509s = ossl_protect_x509_ary2sk(certs, &status); - if(status){ - BIO_free(in); - rb_jump_tag(status); - } + x509s = ossl_protect_x509_ary2sk(certs, &status); + if(status){ + BIO_free(in); + rb_jump_tag(status); + } } if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){ - BIO_free(in); - sk_X509_pop_free(x509s, X509_free); - ossl_raise(ePKCS7Error, NULL); + BIO_free(in); + sk_X509_pop_free(x509s, X509_free); + ossl_raise(ePKCS7Error, NULL); } - WrapPKCS7(cPKCS7, ret, pkcs7); + SetPKCS7(ret, pkcs7); ossl_pkcs7_set_data(ret, data); ossl_pkcs7_set_err_string(ret, Qnil); BIO_free(in); @@ -236,12 +301,19 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * PKCS7.encrypt(certs, data, [, cipher [, flags]]) => pkcs7 + * PKCS7.encrypt(certs, data, cipher, flags = 0) => pkcs7 + * + * Creates a PKCS #7 enveloped-data structure. + * + * Before version 3.3.0, +cipher+ was optional and defaulted to + * <tt>"RC2-40-CBC"</tt>. + * + * See also the man page PKCS7_encrypt(3). */ static VALUE ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass) { - VALUE certs, data, cipher, flags; + VALUE certs, data, cipher, flags, cipher_holder; STACK_OF(X509) *x509s; BIO *in; const EVP_CIPHER *ciph; @@ -250,36 +322,29 @@ ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass) PKCS7 *p7; rb_scan_args(argc, argv, "22", &certs, &data, &cipher, &flags); - if(NIL_P(cipher)){ -#if !defined(OPENSSL_NO_RC2) - ciph = EVP_rc2_40_cbc(); -#elif !defined(OPENSSL_NO_DES) - ciph = EVP_des_ede3_cbc(); -#elif !defined(OPENSSL_NO_RC2) - ciph = EVP_rc2_40_cbc(); -#elif !defined(OPENSSL_NO_AES) - ciph = EVP_EVP_aes_128_cbc(); -#else - ossl_raise(ePKCS7Error, "Must specify cipher"); -#endif - - } - else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */ + if (NIL_P(cipher)) { + rb_raise(rb_eArgError, + "cipher must be specified. Before version 3.3, " \ + "the default cipher was RC2-40-CBC."); + } + ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder); flg = NIL_P(flags) ? 0 : NUM2INT(flags); - in = ossl_obj2bio(data); + ret = NewPKCS7(cPKCS7); + in = ossl_obj2bio(&data); x509s = ossl_protect_x509_ary2sk(certs, &status); if(status){ - BIO_free(in); - rb_jump_tag(status); + BIO_free(in); + rb_jump_tag(status); } - if(!(p7 = PKCS7_encrypt(x509s, in, (EVP_CIPHER*)ciph, flg))){ - BIO_free(in); - sk_X509_pop_free(x509s, X509_free); - ossl_raise(ePKCS7Error, NULL); + if (!(p7 = PKCS7_encrypt(x509s, in, ciph, flg))) { + BIO_free(in); + sk_X509_pop_free(x509s, X509_free); + ossl_raise(ePKCS7Error, NULL); } BIO_free(in); - WrapPKCS7(cPKCS7, ret, p7); + SetPKCS7(ret, p7); ossl_pkcs7_set_data(ret, data); + rb_ivar_set(ret, id_cipher_holder, cipher_holder); sk_X509_pop_free(x509s, X509_free); return ret; @@ -291,11 +356,12 @@ ossl_pkcs7_alloc(VALUE klass) PKCS7 *pkcs7; VALUE obj; + obj = NewPKCS7(klass); if (!(pkcs7 = PKCS7_new())) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } - WrapPKCS7(klass, obj, pkcs7); - + SetPKCS7(obj, pkcs7); + return obj; } @@ -309,26 +375,36 @@ ossl_pkcs7_alloc(VALUE klass) static VALUE ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self) { - PKCS7 *p7; + PKCS7 *p7, *p7_orig = RTYPEDDATA_DATA(self); BIO *in; VALUE arg; if(rb_scan_args(argc, argv, "01", &arg) == 0) - return self; + return self; arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - p7 = PEM_read_bio_PKCS7(in, (PKCS7 **)&DATA_PTR(self), NULL, NULL); + in = ossl_obj2bio(&arg); + p7 = d2i_PKCS7_bio(in, NULL); if (!p7) { - BIO_reset(in); - p7 = d2i_PKCS7_bio(in, (PKCS7 **)&DATA_PTR(self)); + OSSL_BIO_reset(in); + p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); } BIO_free(in); + if (!p7) + ossl_raise(ePKCS7Error, "Could not parse the PKCS7"); + if (!p7->d.ptr) { + PKCS7_free(p7); + ossl_raise(ePKCS7Error, "No content in PKCS7"); + } + + RTYPEDDATA_DATA(self) = p7; + PKCS7_free(p7_orig); ossl_pkcs7_set_data(self, Qnil); ossl_pkcs7_set_err_string(self, Qnil); return self; } +/* :nodoc: */ static VALUE ossl_pkcs7_copy(VALUE self, VALUE other) { @@ -338,11 +414,11 @@ ossl_pkcs7_copy(VALUE self, VALUE other) if (self == other) return self; GetPKCS7(self, a); - SafeGetPKCS7(other, b); + GetPKCS7(other, b); pkcs7 = PKCS7_dup(b); if (!pkcs7) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } DATA_PTR(self) = pkcs7; PKCS7_free(a); @@ -355,9 +431,10 @@ ossl_pkcs7_sym2typeid(VALUE sym) { int i, ret = Qnil; const char *s; + size_t l; - static struct { - const char *name; + static const struct { + char name[20]; int nid; } p7_type_tab[] = { { "signed", NID_pkcs7_signed }, @@ -366,18 +443,20 @@ ossl_pkcs7_sym2typeid(VALUE sym) { "enveloped", NID_pkcs7_enveloped }, { "encrypted", NID_pkcs7_encrypted }, { "digest", NID_pkcs7_digest }, - { NULL, 0 }, }; - if(TYPE(sym) == T_SYMBOL) s = rb_id2name(SYM2ID(sym)); - else s = StringValuePtr(sym); - for(i = 0; i < numberof(p7_type_tab); i++){ - if(p7_type_tab[i].name == NULL) - ossl_raise(ePKCS7Error, "unknown type \"%s\"", s); - if(strcmp(p7_type_tab[i].name, s) == 0){ - ret = p7_type_tab[i].nid; - break; - } + 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 \"%"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; + break; + } } return ret; @@ -394,7 +473,7 @@ ossl_pkcs7_set_type(VALUE self, VALUE type) GetPKCS7(self, p7); if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type))) - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); return type; } @@ -410,15 +489,15 @@ ossl_pkcs7_get_type(VALUE self) GetPKCS7(self, p7); if(PKCS7_type_is_signed(p7)) - return ID2SYM(rb_intern("signed")); + return ID2SYM(rb_intern("signed")); if(PKCS7_type_is_encrypted(p7)) - return ID2SYM(rb_intern("encrypted")); + return ID2SYM(rb_intern("encrypted")); if(PKCS7_type_is_enveloped(p7)) - return ID2SYM(rb_intern("enveloped")); + return ID2SYM(rb_intern("enveloped")); if(PKCS7_type_is_signedAndEnveloped(p7)) - return ID2SYM(rb_intern("signedAndEnveloped")); + return ID2SYM(rb_intern("signedAndEnveloped")); if(PKCS7_type_is_data(p7)) - return ID2SYM(rb_intern("data")); + return ID2SYM(rb_intern("data")); return Qnil; } @@ -429,9 +508,9 @@ ossl_pkcs7_set_detached(VALUE self, VALUE flag) GetPKCS7(self, p7); if(flag != Qtrue && flag != Qfalse) - ossl_raise(ePKCS7Error, "must specify a boolean"); + ossl_raise(ePKCS7Error, "must specify a boolean"); if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0)) - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); return flag; } @@ -441,6 +520,8 @@ ossl_pkcs7_get_detached(VALUE self) { PKCS7 *p7; GetPKCS7(self, p7); + if (!PKCS7_type_is_signed(p7)) + return Qfalse; return PKCS7_get_detached(p7) ? Qtrue : Qfalse; } @@ -456,11 +537,14 @@ static VALUE ossl_pkcs7_set_cipher(VALUE self, VALUE cipher) { PKCS7 *pkcs7; + const EVP_CIPHER *ciph; + VALUE cipher_holder; GetPKCS7(self, pkcs7); - if (!PKCS7_set_cipher(pkcs7, GetCipherPtr(cipher))) { - ossl_raise(ePKCS7Error, NULL); - } + ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder); + if (!PKCS7_set_cipher(pkcs7, ciph)) + ossl_raise(ePKCS7Error, "PKCS7_set_cipher"); + rb_ivar_set(self, id_cipher_holder, cipher_holder); return cipher; } @@ -469,17 +553,18 @@ static VALUE ossl_pkcs7_add_signer(VALUE self, VALUE signer) { PKCS7 *pkcs7; - PKCS7_SIGNER_INFO *p7si; + PKCS7_SIGNER_INFO *si, *si_new; - p7si = DupPKCS7SignerPtr(signer); /* NEED TO DUP */ GetPKCS7(self, pkcs7); - if (!PKCS7_add_signer(pkcs7, p7si)) { - PKCS7_SIGNER_INFO_free(p7si); - ossl_raise(ePKCS7Error, "Could not add signer."); - } - if (PKCS7_type_is_signed(pkcs7)){ - PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType, - V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data)); + GetPKCS7si(signer, si); + + si_new = ossl_PKCS7_SIGNER_INFO_dup(si); + if (!si_new) + ossl_raise(ePKCS7Error, "PKCS7_SIGNER_INFO_dup"); + + if (PKCS7_add_signer(pkcs7, si_new) != 1) { + PKCS7_SIGNER_INFO_free(si_new); + ossl_raise(ePKCS7Error, "PKCS7_add_signer"); } return self; @@ -490,22 +575,17 @@ ossl_pkcs7_get_signer(VALUE self) { PKCS7 *pkcs7; STACK_OF(PKCS7_SIGNER_INFO) *sk; - PKCS7_SIGNER_INFO *si; int num, i; VALUE ary; - + GetPKCS7(self, pkcs7); - if (!(sk = PKCS7_get_signer_info(pkcs7))) { - OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!"); - return rb_ary_new(); - } - if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) { - ossl_raise(ePKCS7Error, "Negative number of signers!"); - } - ary = rb_ary_new2(num); + if (!(sk = PKCS7_get_signer_info(pkcs7))) + return rb_ary_new(); + num = sk_PKCS7_SIGNER_INFO_num(sk); + ary = rb_ary_new_capa(num); for (i=0; i<num; i++) { - si = sk_PKCS7_SIGNER_INFO_value(sk, i); - rb_ary_push(ary, ossl_pkcs7si_new(si)); + PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i); + rb_ary_push(ary, ossl_pkcs7si_new(si)); } return ary; @@ -515,13 +595,18 @@ static VALUE ossl_pkcs7_add_recipient(VALUE self, VALUE recip) { PKCS7 *pkcs7; - PKCS7_RECIP_INFO *ri; + PKCS7_RECIP_INFO *ri, *ri_new; - ri = DupPKCS7RecipientPtr(recip); /* NEED TO DUP */ GetPKCS7(self, pkcs7); - if (!PKCS7_add_recipient_info(pkcs7, ri)) { - PKCS7_RECIP_INFO_free(ri); - ossl_raise(ePKCS7Error, "Could not add recipient."); + GetPKCS7ri(recip, ri); + + ri_new = ossl_PKCS7_RECIP_INFO_dup(ri); + if (!ri_new) + ossl_raise(ePKCS7Error, "PKCS7_RECIP_INFO_dup"); + + if (PKCS7_add_recipient_info(pkcs7, ri_new) != 1) { + PKCS7_RECIP_INFO_free(ri_new); + ossl_raise(ePKCS7Error, "PKCS7_add_recipient_info"); } return self; @@ -532,24 +617,21 @@ ossl_pkcs7_get_recipient(VALUE self) { PKCS7 *pkcs7; STACK_OF(PKCS7_RECIP_INFO) *sk; - PKCS7_RECIP_INFO *si; int num, i; VALUE ary; - + GetPKCS7(self, pkcs7); if (PKCS7_type_is_enveloped(pkcs7)) - sk = pkcs7->d.enveloped->recipientinfo; + sk = pkcs7->d.enveloped->recipientinfo; else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) - sk = pkcs7->d.signed_and_enveloped->recipientinfo; + sk = pkcs7->d.signed_and_enveloped->recipientinfo; else sk = NULL; if (!sk) return rb_ary_new(); - if ((num = sk_PKCS7_RECIP_INFO_num(sk)) < 0) { - ossl_raise(ePKCS7Error, "Negative number of recipient!"); - } - ary = rb_ary_new2(num); + num = sk_PKCS7_RECIP_INFO_num(sk); + ary = rb_ary_new_capa(num); for (i=0; i<num; i++) { - si = sk_PKCS7_RECIP_INFO_value(sk, i); - rb_ary_push(ary, ossl_pkcs7ri_new(si)); + PKCS7_RECIP_INFO *ri = sk_PKCS7_RECIP_INFO_value(sk, i); + rb_ary_push(ary, ossl_pkcs7ri_new(ri)); } return ary; @@ -564,40 +646,60 @@ ossl_pkcs7_add_certificate(VALUE self, VALUE cert) GetPKCS7(self, pkcs7); x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ if (!PKCS7_add_certificate(pkcs7, x509)){ - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } return self; } -static STACK * -pkcs7_get_certs_or_crls(VALUE self, int want_certs) +static STACK_OF(X509) * +pkcs7_get_certs(VALUE self) { PKCS7 *pkcs7; STACK_OF(X509) *certs; - STACK_OF(X509_CRL) *crls; int i; GetPKCS7(self, pkcs7); i = OBJ_obj2nid(pkcs7->type); switch(i){ - case NID_pkcs7_signed: + case NID_pkcs7_signed: certs = pkcs7->d.sign->cert; - crls = pkcs7->d.sign->crl; break; - case NID_pkcs7_signedAndEnveloped: + case NID_pkcs7_signedAndEnveloped: certs = pkcs7->d.signed_and_enveloped->cert; + break; + default: + certs = NULL; + } + + return certs; +} + +static STACK_OF(X509_CRL) * +pkcs7_get_crls(VALUE self) +{ + PKCS7 *pkcs7; + STACK_OF(X509_CRL) *crls; + int i; + + GetPKCS7(self, pkcs7); + i = OBJ_obj2nid(pkcs7->type); + switch(i){ + case NID_pkcs7_signed: + crls = pkcs7->d.sign->crl; + break; + case NID_pkcs7_signedAndEnveloped: crls = pkcs7->d.signed_and_enveloped->crl; break; - default: - certs = crls = NULL; + default: + crls = NULL; } - return want_certs ? certs : crls; + return crls; } static VALUE -ossl_pkcs7_set_certs_i(VALUE i, VALUE arg) +ossl_pkcs7_set_certs_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg)) { return ossl_pkcs7_add_certificate(arg, i); } @@ -608,8 +710,11 @@ ossl_pkcs7_set_certificates(VALUE self, VALUE ary) STACK_OF(X509) *certs; X509 *cert; - certs = pkcs7_get_certs_or_crls(self, 1); - while((cert = sk_X509_pop(certs))) X509_free(cert); + certs = pkcs7_get_certs(self); + if (certs) { + while ((cert = sk_X509_pop(certs))) + X509_free(cert); + } rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self); return ary; @@ -618,7 +723,10 @@ ossl_pkcs7_set_certificates(VALUE self, VALUE ary) static VALUE ossl_pkcs7_get_certificates(VALUE self) { - return ossl_x509_sk2ary(pkcs7_get_certs_or_crls(self, 1)); + STACK_OF(X509) *certs = pkcs7_get_certs(self); + if (!certs) + return Qnil; + return ossl_x509_sk2ary(certs); } static VALUE @@ -630,14 +738,14 @@ ossl_pkcs7_add_crl(VALUE self, VALUE crl) GetPKCS7(self, pkcs7); /* NO DUP needed! */ x509crl = GetX509CRLPtr(crl); if (!PKCS7_add_crl(pkcs7, x509crl)) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } return self; } static VALUE -ossl_pkcs7_set_crls_i(VALUE i, VALUE arg) +ossl_pkcs7_set_crls_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg)) { return ossl_pkcs7_add_crl(arg, i); } @@ -648,8 +756,11 @@ ossl_pkcs7_set_crls(VALUE self, VALUE ary) STACK_OF(X509_CRL) *crls; X509_CRL *crl; - crls = pkcs7_get_certs_or_crls(self, 0); - while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl); + crls = pkcs7_get_crls(self); + if (crls) { + while ((crl = sk_X509_CRL_pop(crls))) + X509_CRL_free(crl); + } rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self); return ary; @@ -658,7 +769,10 @@ ossl_pkcs7_set_crls(VALUE self, VALUE ary) static VALUE ossl_pkcs7_get_crls(VALUE self) { - return ossl_x509crl_sk2ary(pkcs7_get_certs_or_crls(self, 0)); + STACK_OF(X509_CRL) *crls = pkcs7_get_crls(self); + if (!crls) + return Qnil; + return ossl_x509crl_sk2ary(crls); } static VALUE @@ -671,38 +785,39 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self) BIO *in, *out; PKCS7 *p7; VALUE data; - const char *msg; + GetPKCS7(self, p7); rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags); + 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); - if(status){ - BIO_free(in); - rb_jump_tag(status); - } + x509s = ossl_protect_x509_ary2sk(certs, &status); + if(status){ + BIO_free(in); + rb_jump_tag(status); + } } - x509st = GetX509StorePtr(store); - GetPKCS7(self, p7); if(!(out = BIO_new(BIO_s_mem()))){ - BIO_free(in); - sk_X509_pop_free(x509s, X509_free); - ossl_raise(ePKCS7Error, NULL); + BIO_free(in); + sk_X509_pop_free(x509s, X509_free); + ossl_raise(ePKCS7Error, NULL); } ok = PKCS7_verify(p7, x509s, x509st, in, out, flg); BIO_free(in); - if (ok < 0) ossl_raise(ePKCS7Error, NULL); - msg = ERR_reason_error_string(ERR_get_error()); - ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil); - ERR_clear_error(); + sk_X509_pop_free(x509s, X509_free); data = ossl_membio2str(out); ossl_pkcs7_set_data(self, data); - sk_X509_pop_free(x509s, X509_free); - - return (ok == 1) ? Qtrue : Qfalse; + if (ok != 1) { + const char *msg = ERR_reason_error_string(ERR_peek_error()); + ossl_pkcs7_set_err_string(self, msg ? rb_str_new_cstr(msg) : Qnil); + ossl_clear_error(); + return Qfalse; + } + ossl_pkcs7_set_err_string(self, Qnil); + return Qtrue; } static VALUE @@ -716,16 +831,16 @@ ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self) BIO *out; VALUE str; - rb_scan_args(argc, argv, "21", &pkey, &cert, &flags); + rb_scan_args(argc, argv, "12", &pkey, &cert, &flags); key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */ - x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ + x509 = NIL_P(cert) ? NULL : GetX509CertPtr(cert); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); GetPKCS7(self, p7); if(!(out = BIO_new(BIO_s_mem()))) - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); if(!PKCS7_decrypt(p7, key, x509, out, flg)){ - BIO_free(out); - ossl_raise(ePKCS7Error, NULL); + BIO_free(out); + ossl_raise(ePKCS7Error, NULL); } str = ossl_membio2str(out); /* out will be free */ @@ -738,30 +853,38 @@ ossl_pkcs7_add_data(VALUE self, VALUE data) PKCS7 *pkcs7; BIO *out, *in; char buf[4096]; - int len; + int len, ret; - in = ossl_obj2bio(data); GetPKCS7(self, pkcs7); - if(PKCS7_type_is_signed(pkcs7)){ - if(!PKCS7_content_new(pkcs7, NID_pkcs7_data)) - ossl_raise(ePKCS7Error, NULL); - } - if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err; - for(;;){ - if((len = BIO_read(in, buf, sizeof(buf))) <= 0) - break; - if(BIO_write(out, buf, len) != len) - goto err; - } - if(!PKCS7_dataFinal(pkcs7, out)) goto err; - ossl_pkcs7_set_data(self, Qnil); - - err: - BIO_free(out); - BIO_free(in); - if(ERR_peek_error()){ - ossl_raise(ePKCS7Error, NULL); + if (PKCS7_type_is_signed(pkcs7)) { + if (!PKCS7_content_new(pkcs7, NID_pkcs7_data)) + ossl_raise(ePKCS7Error, "PKCS7_content_new"); + } + in = ossl_obj2bio(&data); + if (!(out = PKCS7_dataInit(pkcs7, NULL))) { + BIO_free(in); + ossl_raise(ePKCS7Error, "PKCS7_dataInit"); } + for (;;) { + if ((len = BIO_read(in, buf, sizeof(buf))) <= 0) + break; + if (BIO_write(out, buf, len) != len) { + BIO_free_all(out); + BIO_free(in); + ossl_raise(ePKCS7Error, "BIO_write"); + } + } + if (BIO_flush(out) <= 0) { + BIO_free_all(out); + BIO_free(in); + ossl_raise(ePKCS7Error, "BIO_flush"); + } + ret = PKCS7_dataFinal(pkcs7, out); + BIO_free_all(out); + BIO_free(in); + if (!ret) + ossl_raise(ePKCS7Error, "PKCS7_dataFinal"); + ossl_pkcs7_set_data(self, Qnil); return data; } @@ -776,30 +899,49 @@ ossl_pkcs7_to_der(VALUE self) GetPKCS7(self, pkcs7); if((len = i2d_PKCS7(pkcs7, NULL)) <= 0) - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if(i2d_PKCS7(pkcs7, &p) <= 0) - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); ossl_str_adjust(str, p); return str; } static VALUE +ossl_pkcs7_to_text(VALUE self) +{ + PKCS7 *pkcs7; + BIO *out; + VALUE str; + + GetPKCS7(self, pkcs7); + if(!(out = BIO_new(BIO_s_mem()))) + ossl_raise(ePKCS7Error, NULL); + if(!PKCS7_print_ctx(out, pkcs7, 0, NULL)) { + BIO_free(out); + ossl_raise(ePKCS7Error, NULL); + } + str = ossl_membio2str(out); + + return str; +} + +static VALUE ossl_pkcs7_to_pem(VALUE self) { PKCS7 *pkcs7; BIO *out; VALUE str; - + GetPKCS7(self, pkcs7); if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } if (!PEM_write_bio_PKCS7(out, pkcs7)) { - BIO_free(out); - ossl_raise(ePKCS7Error, NULL); + BIO_free(out); + ossl_raise(ePKCS7Error, NULL); } str = ossl_membio2str(out); @@ -815,10 +957,11 @@ ossl_pkcs7si_alloc(VALUE klass) PKCS7_SIGNER_INFO *p7si; VALUE obj; + obj = NewPKCS7si(klass); if (!(p7si = PKCS7_SIGNER_INFO_new())) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } - WrapPKCS7si(klass, obj, p7si); + SetPKCS7si(obj, p7si); return obj; } @@ -830,14 +973,15 @@ ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest) EVP_PKEY *pkey; X509 *x509; const EVP_MD *md; + VALUE md_holder; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + md = ossl_evp_md_fetch(digest, &md_holder); GetPKCS7si(self, p7si); - if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, (EVP_MD*)md))) { - ossl_raise(ePKCS7Error, NULL); - } + if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md))) + ossl_raise(ePKCS7Error, "PKCS7_SIGNER_INFO_set"); + rb_ivar_set(self, id_md_holder, md_holder); return self; } @@ -867,14 +1011,14 @@ ossl_pkcs7si_get_signed_time(VALUE self) { PKCS7_SIGNER_INFO *p7si; ASN1_TYPE *asn1obj; - + GetPKCS7si(self, p7si); - + if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } if (asn1obj->type == V_ASN1_UTCTIME) { - return asn1time_to_time(asn1obj->value.utctime); + return asn1time_to_time(asn1obj->value.utctime); } /* * OR @@ -894,10 +1038,11 @@ ossl_pkcs7ri_alloc(VALUE klass) PKCS7_RECIP_INFO *p7ri; VALUE obj; + obj = NewPKCS7ri(klass); if (!(p7ri = PKCS7_RECIP_INFO_new())) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } - WrapPKCS7ri(klass, obj, p7ri); + SetPKCS7ri(obj, p7ri); return obj; } @@ -911,7 +1056,7 @@ ossl_pkcs7ri_initialize(VALUE self, VALUE cert) x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ GetPKCS7ri(self, p7ri); if (!PKCS7_RECIP_INFO_set(p7ri, x509)) { - ossl_raise(ePKCS7Error, NULL); + ossl_raise(ePKCS7Error, NULL); } return self; @@ -951,8 +1096,9 @@ ossl_pkcs7ri_get_enc_key(VALUE self) * INIT */ void -Init_ossl_pkcs7() +Init_ossl_pkcs7(void) { +#undef rb_intern 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); @@ -962,7 +1108,7 @@ Init_ossl_pkcs7() rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse); rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse); rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc); - rb_define_copy_func(cPKCS7, ossl_pkcs7_copy); + rb_define_method(cPKCS7, "initialize_copy", ossl_pkcs7_copy, 1); rb_define_method(cPKCS7, "initialize", ossl_pkcs7_initialize, -1); rb_define_method(cPKCS7, "type=", ossl_pkcs7_set_type, 1); rb_define_method(cPKCS7, "type", ossl_pkcs7_get_type, 0); @@ -987,22 +1133,22 @@ Init_ossl_pkcs7() rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0); rb_define_alias(cPKCS7, "to_s", "to_pem"); rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0); + rb_define_method(cPKCS7, "to_text", ossl_pkcs7_to_text, 0); cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject); rb_define_const(cPKCS7, "Signer", cPKCS7Signer); rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc); rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3); rb_define_method(cPKCS7Signer, "issuer", ossl_pkcs7si_get_issuer, 0); - rb_define_alias(cPKCS7Signer, "name", "issuer"); rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0); rb_define_method(cPKCS7Signer,"signed_time",ossl_pkcs7si_get_signed_time,0); cPKCS7Recipient = rb_define_class_under(cPKCS7,"RecipientInfo",rb_cObject); rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc); - rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1); + rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1); rb_define_method(cPKCS7Recipient, "issuer", ossl_pkcs7ri_get_issuer,0); rb_define_method(cPKCS7Recipient, "serial", ossl_pkcs7ri_get_serial,0); - rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0); + rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0); #define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x)) @@ -1016,4 +1162,7 @@ Init_ossl_pkcs7() DefPKCS7Const(BINARY); DefPKCS7Const(NOATTR); DefPKCS7Const(NOSMIMECAP); + + id_md_holder = rb_intern_const("EVP_MD_holder"); + id_cipher_holder = rb_intern_const("EVP_CIPHER_holder"); } diff --git a/ext/openssl/ossl_pkcs7.h b/ext/openssl/ossl_pkcs7.h index 371c421103..140fda1835 100644 --- a/ext/openssl/ossl_pkcs7.h +++ b/ext/openssl/ossl_pkcs7.h @@ -1,22 +1,16 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_PKCS7_H_) #define _OSSL_PKCS7_H_ -extern VALUE cPKCS7; -extern VALUE cPKCS7Signer; -extern VALUE cPKCS7Recipient; -extern VALUE ePKCS7Error; - +VALUE ossl_pkcs7_new(PKCS7 *p7); void Init_ossl_pkcs7(void); #endif /* _OSSL_PKCS7_H_ */ - diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index b295cfc25e..d2fd5b29c3 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -1,88 +1,552 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" +#ifdef OSSL_USE_ENGINE +# include <openssl/engine.h> +#endif + /* * Classes */ 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) +static void +ossl_evp_pkey_free(void *ptr) { - VALUE ary; - - ary = rb_ary_new2(2); - rb_ary_store(ary, 0, INT2NUM(p)); - rb_ary_store(ary, 1, INT2NUM(n)); - - rb_yield(ary); + EVP_PKEY_free(ptr); } /* * Public */ -VALUE -ossl_pkey_new(EVP_PKEY *pkey) +const rb_data_type_t ossl_evp_pkey_type = { + "OpenSSL/EVP_PKEY", + { + 0, ossl_evp_pkey_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE +pkey_wrap0(VALUE arg) { - if (!pkey) { - ossl_raise(ePKeyError, "Cannot make new key from NULL."); - } - switch (EVP_PKEY_type(pkey->type)) { + EVP_PKEY *pkey = (EVP_PKEY *)arg; + VALUE klass, obj; + + switch (EVP_PKEY_base_id(pkey)) { #if !defined(OPENSSL_NO_RSA) - case EVP_PKEY_RSA: - return ossl_rsa_new(pkey); + case EVP_PKEY_RSA: klass = cRSA; break; #endif #if !defined(OPENSSL_NO_DSA) - case EVP_PKEY_DSA: - return ossl_dsa_new(pkey); + case EVP_PKEY_DSA: klass = cDSA; break; #endif #if !defined(OPENSSL_NO_DH) - case EVP_PKEY_DH: - return ossl_dh_new(pkey); + case EVP_PKEY_DH: klass = cDH; break; #endif -#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) - case EVP_PKEY_EC: - return ossl_ec_new(pkey); +#if !defined(OPENSSL_NO_EC) + case EVP_PKEY_EC: klass = cEC; break; #endif - default: - ossl_raise(ePKeyError, "unsupported key type"); + default: klass = cPKey; break; } - return Qnil; /* not reached */ + obj = rb_obj_alloc(klass); + RTYPEDDATA_DATA(obj) = pkey; + return obj; } VALUE -ossl_pkey_new_from_file(VALUE filename) +ossl_pkey_wrap(EVP_PKEY *pkey) +{ + VALUE obj; + int status; + + obj = rb_protect(pkey_wrap0, (VALUE)pkey, &status); + if (status) { + EVP_PKEY_free(pkey); + rb_jump_tag(status); + } + + return obj; +} + +#if OSSL_OPENSSL_PREREQ(3, 0, 0) +# include <openssl/decoder.h> + +static EVP_PKEY * +ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass) +{ + void *ppass = (void *)pass; + OSSL_DECODER_CTX *dctx; + EVP_PKEY *pkey = NULL; + int pos = 0, pos2; + + dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL, + selection, NULL, NULL); + if (!dctx) + goto out; + if (selection == EVP_PKEY_KEYPAIR && + OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, + ppass) != 1) + goto out; + while (1) { + if (OSSL_DECODER_from_bio(dctx, bio) == 1) + goto out; + if (BIO_eof(bio)) + break; + pos2 = BIO_tell(bio); + if (pos2 < 0 || pos2 <= pos) + break; + ossl_clear_error(); + pos = pos2; + } + out: + OSSL_BIO_reset(bio); + OSSL_DECODER_CTX_free(dctx); + return pkey; +} + +EVP_PKEY * +ossl_pkey_read_generic(BIO *bio, VALUE pass) +{ + EVP_PKEY *pkey = NULL; + /* First check DER, then check PEM. */ + const char *input_types[] = {"DER", "PEM"}; + int input_type_num = (int)(sizeof(input_types) / sizeof(char *)); + /* + * Non-zero selections to try to decode. + * + * See EVP_PKEY_fromdata(3) - Selections to see all the selections. + * + * This is a workaround for the decoder failing to decode or returning + * bogus keys with selection 0, if a key management provider is different + * from a decoder provider. The workaround is to avoid using selection 0. + * + * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10 + * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z + * + * See https://github.com/openssl/openssl/pull/21519 for details. + * + * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep + * compatibility with ruby/openssl < 3.0 which decoded the following as a + * private key. + * + * $ openssl ecparam -name prime256v1 -genkey -outform PEM + * -----BEGIN EC PARAMETERS----- + * BggqhkjOPQMBBw== + * -----END EC PARAMETERS----- + * -----BEGIN EC PRIVATE KEY----- + * MHcCAQEEIAG8ugBbA5MHkqnZ9ujQF93OyUfL9tk8sxqM5Wv5tKg5oAoGCCqGSM49 + * AwEHoUQDQgAEVcjhJfkwqh5C7kGuhAf8XaAjVuG5ADwb5ayg/cJijCgs+GcXeedj + * 86avKpGH84DXUlB23C/kPt+6fXYlitUmXQ== + * -----END EC PRIVATE KEY----- + * + * While the first PEM block is a proper encoding of ECParameters, thus + * OSSL_DECODER_from_bio() would pick it up, ruby/openssl used to return + * the latter instead. Existing applications expect this behavior. + * + * Note that normally, the input is supposed to contain a single decodable + * PEM block only, so this special handling should not create a new problem. + * + * Note that we need to create the OSSL_DECODER_CTX variable each time when + * we use the different selection as a workaround. + * See https://github.com/openssl/openssl/issues/20657 for details. + */ + int selections[] = { + EVP_PKEY_KEYPAIR, + EVP_PKEY_KEY_PARAMETERS, + EVP_PKEY_PUBLIC_KEY + }; + int selection_num = (int)(sizeof(selections) / sizeof(int)); + int i, j; + + for (i = 0; i < input_type_num; i++) { + for (j = 0; j < selection_num; j++) { + pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass); + if (pkey) { + goto out; + } + } + } + out: + return pkey; +} +#else +EVP_PKEY * +ossl_pkey_read_generic(BIO *bio, VALUE pass) +{ + void *ppass = (void *)pass; + EVP_PKEY *pkey; + + if ((pkey = d2i_PrivateKey_bio(bio, NULL))) + goto out; + OSSL_BIO_reset(bio); + if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass))) + goto out; + OSSL_BIO_reset(bio); + if ((pkey = d2i_PUBKEY_bio(bio, NULL))) + goto out; + OSSL_BIO_reset(bio); + /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */ + if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass))) + goto out; + OSSL_BIO_reset(bio); + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) + goto out; + OSSL_BIO_reset(bio); + if ((pkey = PEM_read_bio_Parameters(bio, NULL))) + goto out; + + out: + return pkey; +} +#endif + +/* + * call-seq: + * 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. + * * _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 _io_ is an encrypted + * PEM resource. + */ +static VALUE +ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + BIO *bio; + VALUE data, pass; + + rb_scan_args(argc, argv, "11", &data, &pass); + bio = ossl_obj2bio(&data); + pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass)); + BIO_free(bio); + if (!pkey) + ossl_raise(ePKeyError, "Could not parse PKey"); + return ossl_pkey_wrap(pkey); +} + +static VALUE +pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) +{ + VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1); + EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v; + + if (SYMBOL_P(key)) + key = rb_sym2str(key); + value = rb_String(value); + + if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")", + key, value); + return Qnil; +} + +static VALUE +pkey_ctx_apply_options0(VALUE args_v) +{ + VALUE *args = (VALUE *)args_v; + Check_Type(args[1], T_HASH); + + rb_block_call(args[1], rb_intern("each"), 0, NULL, + pkey_ctx_apply_options_i, args[0]); + return Qnil; +} + +static void +pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state) { - FILE *fp; + VALUE args[2]; + args[0] = (VALUE)ctx; + args[1] = options; + + rb_protect(pkey_ctx_apply_options0, (VALUE)args, state); +} + +struct pkey_blocking_generate_arg { + EVP_PKEY_CTX *ctx; EVP_PKEY *pkey; + int state; + unsigned int yield: 1; + unsigned int genparam: 1; + unsigned int interrupted: 1; +}; + +static VALUE +pkey_gen_cb_yield(VALUE ctx_v) +{ + EVP_PKEY_CTX *ctx = (void *)ctx_v; + int i, info_num; + VALUE *argv; + + info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1); + argv = ALLOCA_N(VALUE, info_num); + for (i = 0; i < info_num; i++) + argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i)); + + return rb_yield_values2(info_num, argv); +} + +static VALUE +call_check_ints0(VALUE arg) +{ + rb_thread_check_ints(); + return Qnil; +} + +static void * +call_check_ints(void *arg) +{ + int state; + rb_protect(call_check_ints0, Qnil, &state); + return (void *)(VALUE)state; +} - SafeStringValue(filename); - if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { - ossl_raise(ePKeyError, "%s", strerror(errno)); +static int +pkey_gen_cb(EVP_PKEY_CTX *ctx) +{ + struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); + int state; + + if (arg->yield) { + rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state); + if (state) { + arg->state = state; + return 0; + } + } + if (arg->interrupted) { + arg->interrupted = 0; + state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL); + if (state) { + arg->state = state; + return 0; + } } + return 1; +} + +static void +pkey_blocking_gen_stop(void *ptr) +{ + struct pkey_blocking_generate_arg *arg = ptr; + arg->interrupted = 1; +} + +static void * +pkey_blocking_gen(void *ptr) +{ + struct pkey_blocking_generate_arg *arg = ptr; + + if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0) + return NULL; + if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0) + return NULL; + return arg->pkey; +} + +static VALUE +pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) +{ + EVP_PKEY_CTX *ctx; + VALUE alg, options; + struct pkey_blocking_generate_arg gen_arg = { 0 }; + int state; - pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL); - fclose(fp); - if (!pkey) { - ossl_raise(ePKeyError, NULL); + rb_scan_args(argc, argv, "11", &alg, &options); + if (rb_obj_is_kind_of(alg, cPKey)) { + EVP_PKEY *base_pkey; + + GetPKey(alg, base_pkey); + ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); } + else { +#if OSSL_OPENSSL_PREREQ(3, 0, 0) + ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name"); +#else + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng; + int pkey_id; + + StringValue(alg); + ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg), + RSTRING_LENINT(alg)); + if (!ameth) + ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg); + EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); +#if !defined(OPENSSL_NO_ENGINE) + if (tmpeng) + ENGINE_finish(tmpeng); +#endif - return ossl_pkey_new(pkey); + ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id"); +#endif + } + + if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init"); + } + if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_keygen_init"); + } + + if (!NIL_P(options)) { + pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + } + + gen_arg.genparam = genparam; + gen_arg.ctx = ctx; + gen_arg.yield = rb_block_given_p(); + EVP_PKEY_CTX_set_app_data(ctx, &gen_arg); + EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb); + if (gen_arg.yield) + pkey_blocking_gen(&gen_arg); + else + rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg, + pkey_blocking_gen_stop, &gen_arg); + EVP_PKEY_CTX_free(ctx); + if (!gen_arg.pkey) { + if (gen_arg.state) { + ossl_clear_error(); + rb_jump_tag(gen_arg.state); + } + else { + ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen"); + } + } + + return ossl_pkey_wrap(gen_arg.pkey); +} + +/* + * call-seq: + * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey + * + * Generates new parameters for the algorithm. _algo_name_ is a String that + * represents the algorithm. The optional argument _options_ is a Hash that + * specifies the options specific to the algorithm. The order of the options + * can be important. + * + * A block can be passed optionally. The meaning of the arguments passed to + * the block varies depending on the implementation of the algorithm. The block + * may be called once or multiple times, or may not even be called. + * + * For the supported options, see the documentation for the 'openssl genpkey' + * utility command. + * + * == Example + * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) + * p pkey.p.num_bits #=> 2048 + */ +static VALUE +ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self) +{ + return pkey_generate(argc, argv, self, 1); +} + +/* + * call-seq: + * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey + * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey + * + * Generates a new key (pair). + * + * If a String is given as the first argument, it generates a new random key + * for the algorithm specified by the name just as ::generate_parameters does. + * If an OpenSSL::PKey::PKey is given instead, it generates a new random key + * for the same algorithm as the key, using the parameters the key contains. + * + * See ::generate_parameters for the details of _options_ and the given block. + * + * == Example + * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) + * pkey_params.priv_key #=> nil + * pkey = OpenSSL::PKey.generate_key(pkey_params) + * pkey.priv_key #=> #<OpenSSL::BN 6277... + */ +static VALUE +ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self) +{ + return pkey_generate(argc, argv, self, 0); +} + +/* + * TODO: There is no convenient way to check the presence of public key + * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without + * these should only be created by OpenSSL::PKey.generate_parameters or by + * parsing DER-/PEM-encoded string. We would need another flag for that. + */ +void +ossl_pkey_check_public_key(const EVP_PKEY *pkey) +{ +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + if (EVP_PKEY_missing_parameters(pkey)) + ossl_raise(ePKeyError, "parameters missing"); +#else + 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"); +#endif } EVP_PKEY * @@ -90,7 +554,7 @@ GetPKeyPtr(VALUE obj) { EVP_PKEY *pkey; - SafeGetPKey(obj, pkey); + GetPKey(obj, pkey); return pkey; } @@ -99,136 +563,1215 @@ EVP_PKEY * GetPrivPKeyPtr(VALUE obj) { EVP_PKEY *pkey; - - if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { - ossl_raise(rb_eArgError, "Private key is needed."); - } - SafeGetPKey(obj, pkey); - return pkey; + GetPKey(obj, pkey); + if (OSSL_PKEY_IS_PRIVATE(obj)) + return pkey; + /* + * The EVP API does not provide a way to check if the EVP_PKEY has private + * components. Assuming it does... + */ + if (!rb_respond_to(obj, id_private_q)) + return pkey; + if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL))) + return pkey; + + rb_raise(rb_eArgError, "private key is needed"); } EVP_PKEY * DupPKeyPtr(VALUE obj) { EVP_PKEY *pkey; - - SafeGetPKey(obj, pkey); - CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); + + GetPKey(obj, pkey); + EVP_PKEY_up_ref(pkey); return pkey; } -EVP_PKEY * -DupPrivPKeyPtr(VALUE obj) +/* + * Private + */ +static VALUE +ossl_pkey_alloc(VALUE klass) { - EVP_PKEY *pkey; - - if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { - ossl_raise(rb_eArgError, "Private key is needed."); + return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL); +} + +/* + * call-seq: + * PKeyClass.new -> self + * + * Because PKey is an abstract class, actually calling this method explicitly + * will raise a NotImplementedError. + */ +static VALUE +ossl_pkey_initialize(VALUE self) +{ + if (rb_obj_is_instance_of(self, cPKey)) { + ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly"); } - SafeGetPKey(obj, pkey); - CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); + return self; +} - return pkey; +#ifdef HAVE_EVP_PKEY_DUP +/* :nodoc: */ +static VALUE +ossl_pkey_initialize_copy(VALUE self, VALUE other) +{ + EVP_PKEY *pkey, *pkey_other; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + if (pkey_other) { + pkey = EVP_PKEY_dup(pkey_other); + if (!pkey) + ossl_raise(ePKeyError, "EVP_PKEY_dup"); + RTYPEDDATA_DATA(self) = pkey; + } + return self; } +#endif + +#ifndef OSSL_USE_PROVIDER +static int +lookup_pkey_type(VALUE type) +{ + const EVP_PKEY_ASN1_METHOD *ameth; + int pkey_id; + + StringValue(type); + /* + * XXX: EVP_PKEY_asn1_find_str() looks up a PEM type string. Should we use + * OBJ_txt2nid() instead (and then somehow check if the NID is an acceptable + * EVP_PKEY type)? + * It is probably fine, though, since it can handle all algorithms that + * support raw keys in 1.1.1: { X25519, X448, ED25519, ED448, HMAC }. + */ + ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type)); + if (!ameth) + ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type); + EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); + return pkey_id; +} +#endif /* - * Private + * call-seq: + * OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey + * + * See the OpenSSL documentation for EVP_PKEY_new_raw_private_key() */ + static VALUE -ossl_pkey_alloc(VALUE klass) +ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key) { EVP_PKEY *pkey; - VALUE obj; + size_t keylen; + + StringValue(key); + keylen = RSTRING_LEN(key); + +#ifdef OSSL_USE_PROVIDER + pkey = EVP_PKEY_new_raw_private_key_ex(NULL, StringValueCStr(type), NULL, + (unsigned char *)RSTRING_PTR(key), + keylen); + if (!pkey) + ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key_ex"); +#else + int pkey_id = lookup_pkey_type(type); + pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen); + if (!pkey) + ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key"); +#endif + + return ossl_pkey_wrap(pkey); +} + +/* + * call-seq: + * OpenSSL::PKey.new_raw_public_key(algo, string) -> PKey + * + * See the OpenSSL documentation for EVP_PKEY_new_raw_public_key() + */ + +static VALUE +ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key) +{ + EVP_PKEY *pkey; + size_t keylen; + + StringValue(key); + keylen = RSTRING_LEN(key); + +#ifdef OSSL_USE_PROVIDER + pkey = EVP_PKEY_new_raw_public_key_ex(NULL, StringValueCStr(type), NULL, + (unsigned char *)RSTRING_PTR(key), + keylen); + if (!pkey) + ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key_ex"); +#else + int pkey_id = lookup_pkey_type(type); + pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen); + if (!pkey) + ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key"); +#endif + + return ossl_pkey_wrap(pkey); +} + +/* + * call-seq: + * pkey.oid -> string + * + * Returns the short name of the OID associated with _pkey_. + */ +static VALUE +ossl_pkey_oid(VALUE self) +{ + EVP_PKEY *pkey; + int nid; + + GetPKey(self, pkey); + nid = EVP_PKEY_id(pkey); +#ifdef OSSL_USE_PROVIDER + if (nid == EVP_PKEY_KEYMGMT) + ossl_raise(ePKeyError, "EVP_PKEY_id"); +#endif + return rb_str_new_cstr(OBJ_nid2sn(nid)); +} + +/* + * call-seq: + * pkey.inspect -> string + * + * Returns a string describing the PKey object. + */ +static VALUE +ossl_pkey_inspect(VALUE self) +{ + EVP_PKEY *pkey; + + GetPKey(self, pkey); + VALUE str = rb_sprintf("#<%"PRIsVALUE":%p", + rb_obj_class(self), (void *)self); + int nid = EVP_PKEY_id(pkey); +#ifdef OSSL_USE_PROVIDER + if (nid != EVP_PKEY_KEYMGMT) +#endif + rb_str_catf(str, " oid=%s", OBJ_nid2sn(nid)); +#ifdef OSSL_USE_PROVIDER + rb_str_catf(str, " type_name=%s", EVP_PKEY_get0_type_name(pkey)); + const OSSL_PROVIDER *prov = EVP_PKEY_get0_provider(pkey); + if (prov) + rb_str_catf(str, " provider=%s", OSSL_PROVIDER_get0_name(prov)); +#endif + rb_str_catf(str, ">"); + return str; +} + +/* + * call-seq: + * pkey.to_text -> string + * + * Dumps key parameters, public key, and private key components contained in + * the key into a human-readable text. + * + * This is intended for debugging purpose. + * + * See also the man page EVP_PKEY_print_private(3). + */ +static VALUE +ossl_pkey_to_text(VALUE self) +{ + EVP_PKEY *pkey; + BIO *bio; + + GetPKey(self, pkey); + if (!(bio = BIO_new(BIO_s_mem()))) + ossl_raise(ePKeyError, "BIO_new"); + + if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1) + goto out; + OSSL_BIO_reset(bio); + if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1) + goto out; + OSSL_BIO_reset(bio); + if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1) + goto out; - if (!(pkey = EVP_PKEY_new())) { - ossl_raise(ePKeyError, NULL); + BIO_free(bio); + ossl_raise(ePKeyError, "EVP_PKEY_print_params"); + + out: + return ossl_membio2str(bio); +} + +VALUE +ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der) +{ + EVP_PKEY *pkey; + VALUE cipher, pass, cipher_holder; + const EVP_CIPHER *enc = NULL; + BIO *bio; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "02", &cipher, &pass); + if (!NIL_P(cipher)) { + enc = ossl_evp_cipher_fetch(cipher, &cipher_holder); + pass = ossl_pem_passwd_value(pass); } - WrapPKey(klass, obj, pkey); - return obj; + bio = BIO_new(BIO_s_mem()); + if (!bio) + ossl_raise(ePKeyError, "BIO_new"); + if (to_der) { + if (!i2d_PrivateKey_bio(bio, pkey)) { + BIO_free(bio); + ossl_raise(ePKeyError, "i2d_PrivateKey_bio"); + } + } + else { + if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0, + ossl_pem_passwd_cb, + (void *)pass)) { + BIO_free(bio); + ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional"); + } + } + return ossl_membio2str(bio); } static VALUE -ossl_pkey_initialize(VALUE self) +do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der) { - if (rb_obj_is_instance_of(self, cPKey)) { - ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class."); + EVP_PKEY *pkey; + VALUE cipher, pass, cipher_holder; + const EVP_CIPHER *enc = NULL; + BIO *bio; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "02", &cipher, &pass); + if (argc > 0) { + /* + * TODO: EncryptedPrivateKeyInfo actually has more options. + * Should they be exposed? + */ + enc = ossl_evp_cipher_fetch(cipher, &cipher_holder); + pass = ossl_pem_passwd_value(pass); } - return self; + + bio = BIO_new(BIO_s_mem()); + if (!bio) + ossl_raise(ePKeyError, "BIO_new"); + if (to_der) { + if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0, + ossl_pem_passwd_cb, (void *)pass)) { + BIO_free(bio); + ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio"); + } + } + else { + if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0, + ossl_pem_passwd_cb, (void *)pass)) { + BIO_free(bio); + ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey"); + } + } + return ossl_membio2str(bio); +} + +/* + * call-seq: + * pkey.private_to_der -> string + * pkey.private_to_der(cipher, password) -> string + * + * Serializes the private key to DER-encoded PKCS #8 format. If called without + * arguments, unencrypted PKCS #8 PrivateKeyInfo format is used. If called with + * a cipher name and a password, PKCS #8 EncryptedPrivateKeyInfo format with + * PBES2 encryption scheme is used. + */ +static VALUE +ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self) +{ + return do_pkcs8_export(argc, argv, self, 1); } +/* + * call-seq: + * pkey.private_to_pem -> string + * pkey.private_to_pem(cipher, password) -> string + * + * Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der + * for more details. + * + * An unencrypted PEM-encoded key will look like: + * + * -----BEGIN PRIVATE KEY----- + * [...] + * -----END PRIVATE KEY----- + * + * An encrypted PEM-encoded key will look like: + * + * -----BEGIN ENCRYPTED PRIVATE KEY----- + * [...] + * -----END ENCRYPTED PRIVATE KEY----- + */ static VALUE -ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) +ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self) +{ + return do_pkcs8_export(argc, argv, self, 0); +} + +/* + * call-seq: + * pkey.raw_private_key => string + * + * See the OpenSSL documentation for EVP_PKEY_get_raw_private_key() + */ + +static VALUE +ossl_pkey_raw_private_key(VALUE self) { EVP_PKEY *pkey; - EVP_MD_CTX ctx; - int buf_len; VALUE str; + size_t len; + + GetPKey(self, pkey); + if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key"); + str = rb_str_new(NULL, len); + + if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key"); + + rb_str_set_len(str, len); + + return str; +} - if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) { - ossl_raise(rb_eArgError, "Private key is needed."); +VALUE +ossl_pkey_export_spki(VALUE self, int to_der) +{ + EVP_PKEY *pkey; + BIO *bio; + + GetPKey(self, pkey); + ossl_pkey_check_public_key(pkey); + bio = BIO_new(BIO_s_mem()); + if (!bio) + ossl_raise(ePKeyError, "BIO_new"); + if (to_der) { + if (!i2d_PUBKEY_bio(bio, pkey)) { + BIO_free(bio); + ossl_raise(ePKeyError, "i2d_PUBKEY_bio"); + } + } + else { + if (!PEM_write_bio_PUBKEY(bio, pkey)) { + BIO_free(bio); + ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY"); + } } + return ossl_membio2str(bio); +} + +/* + * call-seq: + * pkey.public_to_der -> string + * + * Serializes the public key to DER-encoded X.509 SubjectPublicKeyInfo format. + */ +static VALUE +ossl_pkey_public_to_der(VALUE self) +{ + return ossl_pkey_export_spki(self, 1); +} + +/* + * call-seq: + * pkey.public_to_pem -> string + * + * Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format. + * + * A PEM-encoded key will look like: + * + * -----BEGIN PUBLIC KEY----- + * [...] + * -----END PUBLIC KEY----- + */ +static VALUE +ossl_pkey_public_to_pem(VALUE self) +{ + return ossl_pkey_export_spki(self, 0); +} + +/* + * call-seq: + * pkey.raw_public_key => string + * + * See the OpenSSL documentation for EVP_PKEY_get_raw_public_key() + */ + +static VALUE +ossl_pkey_raw_public_key(VALUE self) +{ + EVP_PKEY *pkey; + VALUE str; + size_t len; + GetPKey(self, pkey); - EVP_SignInit(&ctx, GetDigestPtr(digest)); - StringValue(data); - EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); - str = rb_str_new(0, EVP_PKEY_size(pkey)+16); - if (!EVP_SignFinal(&ctx, RSTRING_PTR(str), &buf_len, pkey)) - ossl_raise(ePKeyError, NULL); - assert(buf_len <= RSTRING_LEN(str)); - rb_str_set_len(str, buf_len); + if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key"); + str = rb_str_new(NULL, len); + + if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key"); + + rb_str_set_len(str, len); return str; } +/* + * call-seq: + * pkey.compare?(another_pkey) -> true | false + * + * Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key. + * + * == Example + * x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate) + * rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key) + * + * rsa_key.compare?(x509.public_key) => true | false + */ static VALUE -ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) +ossl_pkey_compare(VALUE self, VALUE other) +{ + int ret; + EVP_PKEY *selfPKey; + EVP_PKEY *otherPKey; + + GetPKey(self, selfPKey); + GetPKey(other, otherPKey); + + /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3) + * docs param_cmp could return any negative number. + */ + if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey)) + ossl_raise(rb_eTypeError, "cannot match different PKey types"); + + ret = EVP_PKEY_eq(selfPKey, otherPKey); + + if (ret == 0) + return Qfalse; + else if (ret == 1) + return Qtrue; + else + ossl_raise(ePKeyError, "EVP_PKEY_eq"); +} + +/* + * call-seq: + * pkey.sign(digest, data [, options]) -> string + * + * Hashes and signs the +data+ using a message digest algorithm +digest+ and + * a private key +pkey+. + * + * See #verify for the verification operation. + * + * See also the man page EVP_DigestSign(3). + * + * +digest+:: + * A String that represents the message digest algorithm name, or +nil+ + * if the PKey type requires no digest algorithm. + * For backwards compatibility, this can be an instance of OpenSSL::Digest. + * Its state will not affect the signature. + * +data+:: + * A String. The data to be hashed and signed. + * +options+:: + * A Hash that contains algorithm specific control operations to \OpenSSL. + * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. + * +options+ parameter was added in version 3.0. + * + * Example: + * data = "Sign me!" + * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) + * signopts = { rsa_padding_mode: "pss" } + * signature = pkey.sign("SHA256", data, signopts) + * + * # Creates a copy of the RSA key pkey, but without the private components + * pub_key = pkey.public_key + * puts pub_key.verify("SHA256", signature, data, signopts) # => true + */ +static VALUE +ossl_pkey_sign(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; - EVP_MD_CTX ctx; + VALUE digest, data, options, sig, md_holder; + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; + EVP_PKEY_CTX *pctx; + size_t siglen; + int state; + + pkey = GetPrivPKeyPtr(self); + rb_scan_args(argc, argv, "21", &digest, &data, &options); + if (!NIL_P(digest)) + md = ossl_evp_md_fetch(digest, &md_holder); + StringValue(data); + + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(ePKeyError, "EVP_MD_CTX_new"); + if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignInit"); + } + if (!NIL_P(options)) { + pkey_ctx_apply_options(pctx, options, &state); + if (state) { + EVP_MD_CTX_free(ctx); + rb_jump_tag(state); + } + } + if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSign"); + } + if (siglen > LONG_MAX) { + EVP_MD_CTX_free(ctx); + rb_raise(ePKeyError, "signature would be too large"); + } + sig = ossl_str_new(NULL, (long)siglen, &state); + if (state) { + EVP_MD_CTX_free(ctx); + rb_jump_tag(state); + } + if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen, + (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSign"); + } + EVP_MD_CTX_free(ctx); + rb_str_set_len(sig, siglen); + return sig; +} + +/* + * call-seq: + * pkey.verify(digest, signature, data [, options]) -> true or false + * + * Verifies the +signature+ for the +data+ using a message digest algorithm + * +digest+ and a public key +pkey+. + * + * Returns +true+ if the signature is successfully verified, +false+ otherwise. + * The caller must check the return value. + * + * See #sign for the signing operation and an example. + * + * See also the man page EVP_DigestVerify(3). + * + * +digest+:: + * See #sign. + * +signature+:: + * A String containing the signature to be verified. + * +data+:: + * See #sign. + * +options+:: + * See #sign. +options+ parameter was added in version 3.0. + */ +static VALUE +ossl_pkey_verify(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + VALUE digest, sig, data, options, md_holder; + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; + EVP_PKEY_CTX *pctx; + int state, ret; GetPKey(self, pkey); - EVP_VerifyInit(&ctx, GetDigestPtr(digest)); + rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); + ossl_pkey_check_public_key(pkey); + if (!NIL_P(digest)) + md = ossl_evp_md_fetch(digest, &md_holder); StringValue(sig); StringValue(data); - EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); - switch (EVP_VerifyFinal(&ctx, RSTRING_PTR(sig), RSTRING_LEN(sig), pkey)) { - case 0: - return Qfalse; - case 1: - return Qtrue; - default: - ossl_raise(ePKeyError, NULL); + + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(ePKeyError, "EVP_MD_CTX_new"); + if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } + if (!NIL_P(options)) { + pkey_ctx_apply_options(pctx, options, &state); + if (state) { + EVP_MD_CTX_free(ctx); + rb_jump_tag(state); + } + } + ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig), + RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)); + EVP_MD_CTX_free(ctx); + if (ret < 0) + ossl_raise(ePKeyError, "EVP_DigestVerify"); + if (ret) + return Qtrue; + else { + ossl_clear_error(); + return Qfalse; } - return Qnil; /* dummy */ +} + +/* + * call-seq: + * pkey.sign_raw(digest, data [, options]) -> string + * + * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be + * hashed by +digest+ automatically. + * + * See #verify_raw for the verification operation. + * + * Added in version 3.0. See also the man page EVP_PKEY_sign(3). + * + * +digest+:: + * A String that represents the message digest algorithm name, or +nil+ + * if the PKey type requires no digest algorithm. + * Although this method will not hash +data+ with it, this parameter may still + * be required depending on the signature algorithm. + * +data+:: + * A String. The data to be signed. + * +options+:: + * A Hash that contains algorithm specific control operations to \OpenSSL. + * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. + * + * Example: + * data = "Sign me!" + * hash = OpenSSL::Digest.digest("SHA256", data) + * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) + * signopts = { rsa_padding_mode: "pss" } + * signature = pkey.sign_raw("SHA256", hash, signopts) + * + * # Creates a copy of the RSA key pkey, but without the private components + * pub_key = pkey.public_key + * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true + */ +static VALUE +ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + VALUE digest, data, options, sig, md_holder; + const EVP_MD *md = NULL; + EVP_PKEY_CTX *ctx; + size_t outlen; + int state; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "21", &digest, &data, &options); + if (!NIL_P(digest)) + md = ossl_evp_md_fetch(digest, &md_holder); + StringValue(data); + + ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + if (EVP_PKEY_sign_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_sign_init"); + } + if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); + } + if (!NIL_P(options)) { + pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + } + if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_sign"); + } + if (outlen > LONG_MAX) { + EVP_PKEY_CTX_free(ctx); + rb_raise(ePKeyError, "signature would be too large"); + } + sig = ossl_str_new(NULL, (long)outlen, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen, + (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_sign"); + } + EVP_PKEY_CTX_free(ctx); + rb_str_set_len(sig, outlen); + return sig; +} + +/* + * call-seq: + * pkey.verify_raw(digest, signature, data [, options]) -> true or false + * + * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike + * #verify, this method will not hash +data+ with +digest+ automatically. + * + * Returns +true+ if the signature is successfully verified, +false+ otherwise. + * The caller must check the return value. + * + * See #sign_raw for the signing operation and an example code. + * + * Added in version 3.0. See also the man page EVP_PKEY_verify(3). + * + * +signature+:: + * A String containing the signature to be verified. + */ +static VALUE +ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + VALUE digest, sig, data, options, md_holder; + const EVP_MD *md = NULL; + EVP_PKEY_CTX *ctx; + int state, ret; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); + ossl_pkey_check_public_key(pkey); + if (!NIL_P(digest)) + md = ossl_evp_md_fetch(digest, &md_holder); + StringValue(sig); + StringValue(data); + + ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + if (EVP_PKEY_verify_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_verify_init"); + } + if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); + } + if (!NIL_P(options)) { + pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + } + ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig), + RSTRING_LEN(sig), + (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)); + EVP_PKEY_CTX_free(ctx); + if (ret < 0) + ossl_raise(ePKeyError, "EVP_PKEY_verify"); + + if (ret) + return Qtrue; + else { + ossl_clear_error(); + return Qfalse; + } +} + +/* + * call-seq: + * pkey.verify_recover(digest, signature [, options]) -> string + * + * Recovers the signed data from +signature+ using a public key +pkey+. Not all + * signature algorithms support this operation. + * + * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3). + * + * +signature+:: + * A String containing the signature to be verified. + */ +static VALUE +ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + VALUE digest, sig, options, out, md_holder; + const EVP_MD *md = NULL; + EVP_PKEY_CTX *ctx; + int state; + size_t outlen; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "21", &digest, &sig, &options); + ossl_pkey_check_public_key(pkey); + if (!NIL_P(digest)) + md = ossl_evp_md_fetch(digest, &md_holder); + StringValue(sig); + + ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + if (EVP_PKEY_verify_recover_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init"); + } + if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); + } + if (!NIL_P(options)) { + pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + } + if (EVP_PKEY_verify_recover(ctx, NULL, &outlen, + (unsigned char *)RSTRING_PTR(sig), + RSTRING_LEN(sig)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); + } + out = ossl_str_new(NULL, (long)outlen, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen, + (unsigned char *)RSTRING_PTR(sig), + RSTRING_LEN(sig)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); + } + EVP_PKEY_CTX_free(ctx); + rb_str_set_len(out, outlen); + return out; +} + +/* + * call-seq: + * pkey.derive(peer_pkey) -> string + * + * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain + * the private components, _peer_pkey_ must contain the public components. + */ +static VALUE +ossl_pkey_derive(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey, *peer_pkey; + EVP_PKEY_CTX *ctx; + VALUE peer_pkey_obj, str; + size_t keylen; + int state; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "1", &peer_pkey_obj); + GetPKey(peer_pkey_obj, peer_pkey); + + ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + if (EVP_PKEY_derive_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive_init"); + } + if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer"); + } + if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive"); + } + if (keylen > LONG_MAX) + rb_raise(ePKeyError, "derived key would be too large"); + str = ossl_str_new(NULL, (long)keylen, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_derive"); + } + EVP_PKEY_CTX_free(ctx); + rb_str_set_len(str, keylen); + return str; +} + +/* + * call-seq: + * pkey.encrypt(data [, options]) -> string + * + * Performs a public key encryption operation using +pkey+. + * + * See #decrypt for the reverse operation. + * + * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3). + * + * +data+:: + * A String to be encrypted. + * +options+:: + * A Hash that contains algorithm specific control operations to \OpenSSL. + * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. + * + * Example: + * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) + * data = "secret data" + * encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep") + * decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep") + * p decrypted #=> "secret data" + */ +static VALUE +ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + EVP_PKEY_CTX *ctx; + VALUE data, options, str; + size_t outlen; + int state; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "11", &data, &options); + StringValue(data); + + ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + if (EVP_PKEY_encrypt_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init"); + } + if (!NIL_P(options)) { + pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + } + if (EVP_PKEY_encrypt(ctx, NULL, &outlen, + (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); + } + if (outlen > LONG_MAX) { + EVP_PKEY_CTX_free(ctx); + rb_raise(ePKeyError, "encrypted data would be too large"); + } + str = ossl_str_new(NULL, (long)outlen, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, + (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); + } + EVP_PKEY_CTX_free(ctx); + rb_str_set_len(str, outlen); + return str; +} + +/* + * call-seq: + * pkey.decrypt(data [, options]) -> string + * + * Performs a public key decryption operation using +pkey+. + * + * See #encrypt for a description of the parameters and an example. + * + * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3). + */ +static VALUE +ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + EVP_PKEY_CTX *ctx; + VALUE data, options, str; + size_t outlen; + int state; + + GetPKey(self, pkey); + rb_scan_args(argc, argv, "11", &data, &options); + StringValue(data); + + ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + if (EVP_PKEY_decrypt_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init"); + } + if (!NIL_P(options)) { + pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + } + if (EVP_PKEY_decrypt(ctx, NULL, &outlen, + (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); + } + if (outlen > LONG_MAX) { + EVP_PKEY_CTX_free(ctx); + rb_raise(ePKeyError, "decrypted data would be too large"); + } + str = ossl_str_new(NULL, (long)outlen, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); + } + if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, + (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) <= 0) { + EVP_PKEY_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); + } + EVP_PKEY_CTX_free(ctx); + rb_str_set_len(str, outlen); + return str; } /* * INIT */ void -Init_ossl_pkey() +Init_ossl_pkey(void) { -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); -#endif - +#undef rb_intern + /* Document-module: OpenSSL::PKey + * + * == Asymmetric Public Key Algorithms + * + * Asymmetric public key algorithms solve the problem of establishing and + * sharing secret keys to en-/decrypt messages. The key in such an + * 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 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 + * a symmetric key shared between two parties that are in possession of + * each other's public key. + * + * Asymmetric algorithms offer a lot of nice features that are used in a + * lot of different areas. A very common application is the creation and + * validation of digital signatures. To sign a document, the signatory + * generally uses a message digest algorithm (cf. OpenSSL::Digest) to + * compute a digest of the document that is then encrypted (i.e. signed) + * using the private key. Anyone in possession of the public key may then + * verify the signature by computing the message digest of the original + * document on their own, decrypting the signature using the signatory's + * public key and comparing the result to the message digest they + * previously computed. The signature is valid if and only if the + * decrypted signature is equal to this message digest. + * + * The PKey module offers support for three popular public/private key + * algorithms: + * * RSA (OpenSSL::PKey::RSA) + * * DSA (OpenSSL::PKey::DSA) + * * Elliptic Curve Cryptography (OpenSSL::PKey::EC) + * Each of these implementations is in fact a sub-class of the abstract + * PKey class which offers the interface for supporting digital signatures + * in the form of PKey#sign and PKey#verify. + * + * == Diffie-Hellman Key Exchange + * + * Finally PKey also features OpenSSL::PKey::DH, an implementation of + * the Diffie-Hellman key exchange protocol based on discrete logarithms + * in finite fields, the same basis that DSA is built on. + * The Diffie-Hellman protocol can be used to exchange (symmetric) keys + * over insecure channels without needing any prior joint knowledge + * between the participating parties. As the security of DH demands + * relatively long "public keys" (i.e. the part that is overtly + * transmitted between participants) DH tends to be quite slow. If + * security or speed is your primary concern, OpenSSL::PKey::EC offers + * another implementation of the Diffie-Hellman protocol. + * + */ mPKey = rb_define_module_under(mOSSL, "PKey"); - + + /* Document-class: OpenSSL::PKey::PKeyError + * + * Raised when errors occur during PKey#sign or PKey#verify. + * + * Before version 4.0.0, OpenSSL::PKey::PKeyError had the following + * subclasses. These subclasses have been removed and the constants are + * now defined as aliases of OpenSSL::PKey::PKeyError. + * + * * OpenSSL::PKey::DHError + * * OpenSSL::PKey::DSAError + * * OpenSSL::PKey::ECError + * * OpenSSL::PKey::RSAError + */ ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); + /* Document-class: OpenSSL::PKey::PKey + * + * An abstract class that bundles signature creation (PKey#sign) and + * validation (PKey#verify) that is common to all implementations except + * OpenSSL::PKey::DH + * * OpenSSL::PKey::RSA + * * OpenSSL::PKey::DSA + * * OpenSSL::PKey::EC + */ cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); - + + rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1); + rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1); + rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1); + rb_define_module_function(mPKey, "new_raw_private_key", ossl_pkey_new_raw_private_key, 2); + rb_define_module_function(mPKey, "new_raw_public_key", ossl_pkey_new_raw_public_key, 2); + rb_define_alloc_func(cPKey, ossl_pkey_alloc); rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); +#ifdef HAVE_EVP_PKEY_DUP + rb_define_method(cPKey, "initialize_copy", ossl_pkey_initialize_copy, 1); +#else + rb_undef_method(cPKey, "initialize_copy"); +#endif + rb_define_method(cPKey, "oid", ossl_pkey_oid, 0); + rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0); + rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0); + rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1); + rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1); + rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0); + rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0); + rb_define_method(cPKey, "raw_private_key", ossl_pkey_raw_private_key, 0); + rb_define_method(cPKey, "raw_public_key", ossl_pkey_raw_public_key, 0); + rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1); + + rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); + rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); + rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1); + rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1); + rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1); + rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); + rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); - rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); - rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); - id_private_q = rb_intern("private?"); - + /* * INIT rsa, dsa, dh, ec */ @@ -237,4 +1780,3 @@ Init_ossl_pkey() Init_ossl_dh(); Init_ossl_ec(); } - diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index 67ff1fddd0..023361b90f 100644 --- a/ext/openssl/ossl_pkey.h +++ b/ext/openssl/ossl_pkey.h @@ -1,141 +1,193 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ -#if !defined(_OSSL_PKEY_H_) -#define _OSSL_PKEY_H_ +#if !defined(OSSL_PKEY_H) +#define OSSL_PKEY_H 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) -#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse) -#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue) +/* For ENGINE */ +#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern("private"), Qtrue) +#define OSSL_PKEY_IS_PRIVATE(obj) (rb_attr_get((obj), rb_intern("private")) == Qtrue) -#define WrapPKey(klass, obj, pkey) do { \ - if (!pkey) { \ - rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \ - } \ - obj = Data_Wrap_Struct(klass, 0, EVP_PKEY_free, pkey); \ - OSSL_PKEY_SET_PUBLIC(obj); \ -} while (0) #define GetPKey(obj, pkey) do {\ - Data_Get_Struct(obj, EVP_PKEY, pkey);\ - if (!pkey) { \ - rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ + TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \ + if (!(pkey)) { \ + rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ } \ } while (0) -#define SafeGetPKey(obj, pkey) do { \ - OSSL_Check_Kind(obj, cPKey); \ - GetPKey(obj, pkey); \ -} while (0) -void ossl_generate_cb(int, int, void *); - -VALUE ossl_pkey_new(EVP_PKEY *); -VALUE ossl_pkey_new_from_file(VALUE); +/* Takes ownership of the EVP_PKEY */ +VALUE ossl_pkey_wrap(EVP_PKEY *); +void ossl_pkey_check_public_key(const EVP_PKEY *); +EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); EVP_PKEY *GetPKeyPtr(VALUE); EVP_PKEY *DupPKeyPtr(VALUE); EVP_PKEY *GetPrivPKeyPtr(VALUE); -EVP_PKEY *DupPrivPKeyPtr(VALUE); + +/* + * Serializes _self_ in X.509 SubjectPublicKeyInfo format and returns the + * resulting String. Sub-classes use this when overriding #to_der. + */ +VALUE ossl_pkey_export_spki(VALUE self, int to_der); +/* + * Serializes the private key _self_ in the traditional private key format + * and returns the resulting String. Sub-classes use this when overriding + * #to_der. + */ +VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, + int to_der); + void Init_ossl_pkey(void); /* * RSA */ extern VALUE cRSA; -extern VALUE eRSAError; - -VALUE ossl_rsa_new(EVP_PKEY *); void Init_ossl_rsa(void); /* * DSA */ extern VALUE cDSA; -extern VALUE eDSAError; - -VALUE ossl_dsa_new(EVP_PKEY *); void Init_ossl_dsa(void); /* * DH */ extern VALUE cDH; -extern VALUE eDHError; -extern DH *OSSL_DEFAULT_DH_512; -extern DH *OSSL_DEFAULT_DH_1024; - -VALUE ossl_dh_new(EVP_PKEY *); void Init_ossl_dh(void); /* * EC */ extern VALUE cEC; -extern VALUE eECError; -extern VALUE cEC_GROUP; -extern VALUE eEC_GROUP; -extern VALUE cEC_POINT; -extern VALUE eEC_POINT; VALUE ossl_ec_new(EVP_PKEY *); void Init_ossl_ec(void); +#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \ +/* \ + * call-seq: \ + * _keytype##.##_name -> aBN \ + */ \ +static VALUE ossl_##_keytype##_get_##_name(VALUE self) \ +{ \ + const _type *obj; \ + const BIGNUM *bn; \ + \ + Get##_type(self, obj); \ + _get; \ + if (bn == NULL) \ + return Qnil; \ + return ossl_bn_new(bn); \ +} -#define OSSL_PKEY_BN(keytype, name) \ -/* \ - * call-seq: \ - * key.##name -> aBN \ - */ \ -static VALUE ossl_##keytype##_get_##name(VALUE self) \ -{ \ - EVP_PKEY *pkey; \ - BIGNUM *bn; \ - \ - GetPKey(self, pkey); \ - bn = pkey->pkey.keytype->name; \ - if (bn == NULL) \ - return Qnil; \ - return ossl_bn_new(bn); \ -} \ -/* \ - * call-seq: \ - * key.##name = bn -> bn \ - */ \ -static VALUE ossl_##keytype##_set_##name(VALUE self, VALUE bignum) \ -{ \ - EVP_PKEY *pkey; \ - BIGNUM *bn; \ - \ - GetPKey(self, pkey); \ - if (NIL_P(bignum)) { \ - BN_clear_free(pkey->pkey.keytype->name); \ - pkey->pkey.keytype->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) \ - ossl_raise(eBNError, NULL); \ - if (BN_copy(pkey->pkey.keytype->name, bn) == NULL) \ - ossl_raise(eBNError, NULL); \ - return bignum; \ +#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)) + +#ifndef OSSL_HAVE_IMMUTABLE_PKEY +#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(ePKeyError, "BN_dup"); \ + } \ + \ + 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 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) +#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(ePKeyError, "BN_dup"); \ + } \ + \ + if (!_type##_set0_##_group(obj, bn1, bn2)) { \ + BN_clear_free(bn1); \ + BN_clear_free(bn2); \ + ossl_raise(ePKeyError, #_type"_set0_"#_group); \ + } \ + return self; \ +} +#else +#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \ +static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \ +{ \ + rb_raise(ePKeyError, \ + #_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \ +} + +#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \ +static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \ +{ \ + rb_raise(ePKeyError, \ + #_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \ +} +#endif + +#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) \ + rb_define_method((class), #name, ossl_##keytype##_get_##name, 0) -#endif /* _OSSL_PKEY_H_ */ +#endif /* OSSL_PKEY_H */ diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index a6924a6bb8..3f2975c5a3 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -1,236 +1,259 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ -#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? */ \ - ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \ + GetPKey((obj), (pkey)); \ + 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); \ + if ((dh) == NULL) \ + ossl_raise(ePKeyError, "failed to get DH from EVP_PKEY"); \ +} while (0) /* * Classes */ VALUE cDH; -VALUE eDHError; - -/* - * Public - */ -static VALUE -dh_instance(VALUE klass, DH *dh) -{ - EVP_PKEY *pkey; - VALUE obj; - - if (!dh) { - return Qfalse; - } - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_DH(pkey, dh)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - WrapPKey(klass, obj, pkey); - - return obj; -} - -VALUE -ossl_dh_new(EVP_PKEY *pkey) -{ - VALUE obj; - - if (!pkey) { - obj = dh_instance(cDH, DH_new()); - } else { - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) { - ossl_raise(rb_eTypeError, "Not a DH key!"); - } - WrapPKey(cDH, obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eDHError, NULL); - } - - return obj; -} /* * Private */ -static DH * -dh_generate(int size, int gen) -{ - DH *dh; - - dh = DH_generate_parameters(size, gen, - rb_block_given_p() ? ossl_generate_cb : NULL, - NULL); - if (!dh) return 0; - - if (!DH_generate_key(dh)) { - DH_free(dh); - return 0; - } - - return dh; -} - /* - * call-seq: - * DH.generate(size [, generator]) -> dh + * call-seq: + * DH.new -> dh + * DH.new(string) -> dh + * DH.new(size [, generator]) -> dh * - * === Parameters - * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. - * * +generator+ is a small number > 1, typically 2 or 5. + * Creates a new instance of OpenSSL::PKey::DH. * - */ -static VALUE -ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) -{ - DH *dh ; - int g = 2; - VALUE size, gen, obj; - - if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { - g = FIX2INT(gen); - } - dh = dh_generate(FIX2INT(size), g); - obj = dh_instance(klass, dh); - if (obj == Qfalse) { - DH_free(dh); - ossl_raise(eDHError, NULL); - } - - return obj; -} - -/* - * call-seq: - * DH.new([size [, generator] | string]) -> dh + * If called without arguments, an empty instance without any parameter or key + * components is created. Use #set_pqg to manually set the parameters afterwards + * (and optionally #set_key to set private and public key components). + * This form is not compatible with OpenSSL 3.0 or later. + * + * If a String is given, tries to parse it as a DER- or PEM- encoded parameters. + * See also OpenSSL::PKey.read which can parse keys of any kinds. + * + * The DH.new(size [, generator]) form is an alias of DH.generate. * - * === Parameters - * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. - * * +generator+ is a small number > 1, typically 2 or 5. - * * +string+ contains the DER or PEM encoded key. + * +string+:: + * A String that contains the DER or PEM encoded key. + * +size+:: + * See DH.generate. + * +generator+:: + * See DH.generate. * - * === Examples - * * DH.new -> dh - * * DH.new(1024) -> dh - * * DH.new(1024, 5) -> dh - * * DH.new(File.read('key.pem')) -> dh + * Examples: + * # Creating an instance from scratch + * # Note that this is deprecated and will result in ArgumentError when + * # using OpenSSL 3.0 or later. + * dh = OpenSSL::PKey::DH.new + * dh.set_pqg(bn_p, nil, bn_g) + * + * # Generating a parameters and a key pair + * dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048) + * + * # Reading DH parameters from a PEM-encoded string + * dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only + * dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair */ static VALUE ossl_dh_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; + int type; DH *dh; - int g = 2; - BIO *in; - VALUE arg, gen; + BIO *in = NULL; + VALUE arg; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + + /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */ + if (rb_scan_args(argc, argv, "01", &arg) == 0) { +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(rb_eArgError, "OpenSSL::PKey::DH.new cannot be called " \ + "without arguments; pkeys are immutable with OpenSSL 3.0"); +#else + dh = DH_new(); + if (!dh) + ossl_raise(ePKeyError, "DH_new"); + goto legacy; +#endif + } - GetPKey(self, pkey); - if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) { - dh = DH_new(); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); + + /* + * On OpenSSL <= 1.1.1 and current versions of LibreSSL, the generic + * routine does not support DER-encoded parameters + */ + dh = d2i_DHparams_bio(in, NULL); + if (dh) + goto legacy; + OSSL_BIO_reset(in); + + pkey = ossl_pkey_read_generic(in, Qnil); + BIO_free(in); + if (!pkey) + ossl_raise(ePKeyError, "could not parse pkey"); + + type = EVP_PKEY_base_id(pkey); + if (type != EVP_PKEY_DH) { + EVP_PKEY_free(pkey); + rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type)); } - else if (FIXNUM_P(arg)) { - if (!NIL_P(gen)) { - g = FIX2INT(gen); - } - if (!(dh = dh_generate(FIX2INT(arg), g))) { - ossl_raise(eDHError, NULL); - } + RTYPEDDATA_DATA(self) = pkey; + return self; + + legacy: + BIO_free(in); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { + EVP_PKEY_free(pkey); + DH_free(dh); + ossl_raise(ePKeyError, "EVP_PKEY_assign_DH"); } - else { - arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); - if (!dh){ - BIO_reset(in); - dh = d2i_DHparams_bio(in, NULL); - } - BIO_free(in); - if (!dh) ossl_raise(eDHError, NULL); + RTYPEDDATA_DATA(self) = pkey; + return self; +} + +#ifndef HAVE_EVP_PKEY_DUP +/* :nodoc: */ +static VALUE +ossl_dh_initialize_copy(VALUE self, VALUE other) +{ + EVP_PKEY *pkey; + DH *dh, *dh_other; + const BIGNUM *pub, *priv; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + GetDH(other, dh_other); + + dh = DHparams_dup(dh_other); + if (!dh) + ossl_raise(ePKeyError, "DHparams_dup"); + + 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(ePKeyError, "BN_dup"); + } + DH_set0_key(dh, pub2, priv2); } - if (!EVP_PKEY_assign_DH(pkey, dh)) { - DH_free(dh); - ossl_raise(eDHError, NULL); + + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { + EVP_PKEY_free(pkey); + DH_free(dh); + ossl_raise(ePKeyError, "EVP_PKEY_assign_DH"); } + RTYPEDDATA_DATA(self) = pkey; return self; } +#endif /* * call-seq: * dh.public? -> true | false * + * Indicates whether this DH instance has a public key associated with it or + * not. The public key may be retrieved with DH#pub_key. */ static VALUE ossl_dh_is_public(VALUE self) { - EVP_PKEY *pkey; + OSSL_3_const 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; } /* * call-seq: * dh.private? -> true | false * + * Indicates whether this DH instance has a private key associated with it or + * not. The private key may be retrieved with DH#priv_key. */ static VALUE ossl_dh_is_private(VALUE self) { - EVP_PKEY *pkey; + OSSL_3_const DH *dh; + const BIGNUM *bn; - GetPKeyDH(self, pkey); - - return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse; + GetDH(self, dh); + DH_get0_key(dh, NULL, &bn); + +#if !defined(OPENSSL_NO_ENGINE) + return (bn || DH_get0_engine((DH *)dh)) ? Qtrue : Qfalse; +#else + return bn ? Qtrue : Qfalse; +#endif } /* * call-seq: + * dh.export -> aString * dh.to_pem -> aString + * dh.to_s -> aString * + * Serializes the DH parameters to a PEM-encoding. + * + * Note that any existing per-session public/private keys will *not* get + * encoded, just the Diffie-Hellman parameters will be encoded. + * + * PEM-encoded parameters will look like: + * + * -----BEGIN DH PARAMETERS----- + * [...] + * -----END DH PARAMETERS----- + * + * See also #public_to_pem (X.509 SubjectPublicKeyInfo) and + * #private_to_pem (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for + * serialization with the private or public key components. */ static VALUE ossl_dh_export(VALUE self) { - EVP_PKEY *pkey; + OSSL_3_const DH *dh; BIO *out; VALUE str; - GetPKeyDH(self, pkey); + GetDH(self, dh); if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eDHError, NULL); + ossl_raise(ePKeyError, NULL); } - if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) { - BIO_free(out); - ossl_raise(eDHError, NULL); + if (!PEM_write_bio_DHparams(out, dh)) { + BIO_free(out); + ossl_raise(ePKeyError, NULL); } str = ossl_membio2str(out); @@ -241,22 +264,30 @@ ossl_dh_export(VALUE self) * call-seq: * dh.to_der -> aString * + * Serializes the DH parameters to a DER-encoding + * + * Note that any existing per-session public/private keys will *not* get + * encoded, just the Diffie-Hellman parameters will be encoded. + * + * See also #public_to_der (X.509 SubjectPublicKeyInfo) and + * #private_to_der (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for + * serialization with the private or public key components. */ static VALUE ossl_dh_to_der(VALUE self) -{ - EVP_PKEY *pkey; +{ + OSSL_3_const DH *dh; unsigned char *p; long len; VALUE str; - GetPKeyDH(self, pkey); - if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0) - ossl_raise(eDHError, NULL); + GetDH(self, dh); + if((len = i2d_DHparams(dh, NULL)) <= 0) + ossl_raise(ePKeyError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); - if(i2d_DHparams(pkey->pkey.dh, &p) < 0) - ossl_raise(eDHError, NULL); + p = (unsigned char *)RSTRING_PTR(str); + if(i2d_DHparams(dh, &p) < 0) + ossl_raise(ePKeyError, NULL); ossl_str_adjust(str, p); return str; @@ -264,271 +295,126 @@ ossl_dh_to_der(VALUE self) /* * call-seq: - * dh.params -> hash + * dh.params_ok? -> true | false * - * Stores all parameters of key to the hash - * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! - * Don't use :-)) (I's up to you) - */ -static VALUE -ossl_dh_get_params(VALUE self) -{ - EVP_PKEY *pkey; - VALUE hash; - - GetPKeyDH(self, pkey); - - 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)); - - return hash; -} - -/* - * call-seq: - * dh.to_text -> aString - * - * Prints all parameters of key to buffer - * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! - * Don't use :-)) (I's up to you) - */ -static VALUE -ossl_dh_to_text(VALUE self) -{ - EVP_PKEY *pkey; - BIO *out; - VALUE str; - - GetPKeyDH(self, pkey); - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eDHError, NULL); - } - if (!DHparams_print(out, pkey->pkey.dh)) { - BIO_free(out); - ossl_raise(eDHError, NULL); - } - str = ossl_membio2str(out); - - return str; -} - -/* - * call-seq: - * dh.public_key -> aDH + * Validates the Diffie-Hellman parameters associated with this instance. + * It checks whether a safe prime and a suitable generator are used. If this + * is not the case, +false+ is returned. * - * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY + * See also the man page EVP_PKEY_param_check(3). */ static VALUE -ossl_dh_to_public_key(VALUE self) +ossl_dh_check_params(VALUE self) { + int ret; +#ifdef HAVE_EVP_PKEY_CHECK EVP_PKEY *pkey; - 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); - if (obj == Qfalse) { - DH_free(dh); - ossl_raise(eDHError, NULL); - } + EVP_PKEY_CTX *pctx; - return obj; -} - -/* - * call-seq: - * dh.check_params -> true | false - * - */ -static VALUE -ossl_dh_check_params(VALUE self) -{ + GetPKey(self, pkey); + pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!pctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + ret = EVP_PKEY_param_check(pctx); + EVP_PKEY_CTX_free(pctx); +#else DH *dh; - EVP_PKEY *pkey; int codes; - - GetPKeyDH(self, pkey); - dh = pkey->pkey.dh; - if (!DH_check(dh, &codes)) { - return Qfalse; - } + GetDH(self, dh); + ret = DH_check(dh, &codes) == 1 && codes == 0; +#endif - return codes == 0 ? Qtrue : Qfalse; + if (ret == 1) + return Qtrue; + else { + /* DH_check_ex() will put error entry on failure */ + ossl_clear_error(); + return Qfalse; + } } /* - * call-seq: - * dh.generate_key -> self + * Document-method: OpenSSL::PKey::DH#set_pqg + * call-seq: + * dh.set_pqg(p, q, g) -> self * + * Sets _p_, _q_, _g_ to the DH instance. */ -static VALUE -ossl_dh_generate_key(VALUE self) -{ - DH *dh; - EVP_PKEY *pkey; - - GetPKeyDH(self, pkey); - dh = pkey->pkey.dh; - - if (!DH_generate_key(dh)) - ossl_raise(eDHError, "Failed to generate key"); - return self; -} - +OSSL_PKEY_BN_DEF3(dh, DH, pqg, p, q, g) /* - * call-seq: - * dh.compute_key(pub_bn) -> aString + * Document-method: OpenSSL::PKey::DH#set_key + * call-seq: + * dh.set_key(pub_key, priv_key) -> self * - * === Parameters - * * +pub_bn+ is a OpenSSL::BN. - * - * Returns aString containing a shared secret computed from the other parties public value. - * - * See DH_compute_key() for further information. - * - */ -static VALUE -ossl_dh_compute_key(VALUE self, VALUE pub) -{ - DH *dh; - EVP_PKEY *pkey; - BIGNUM *pub_key; - VALUE str; - int len; - - GetPKeyDH(self, pkey); - dh = pkey->pkey.dh; - pub_key = GetBNPtr(pub); - len = DH_size(dh); - str = rb_str_new(0, len); - if ((len = DH_compute_key(RSTRING_PTR(str), pub_key, dh)) < 0) { - ossl_raise(eDHError, NULL); - } - rb_str_set_len(str, len); - - return str; -} - -OSSL_PKEY_BN(dh, p); -OSSL_PKEY_BN(dh, g); -OSSL_PKEY_BN(dh, pub_key); -OSSL_PKEY_BN(dh, priv_key); - -/* - * -----BEGIN DH PARAMETERS----- - * MEYCQQD0zXHljRg/mJ9PYLACLv58Cd8VxBxxY7oEuCeURMiTqEhMym16rhhKgZG2 - * zk2O9uUIBIxSj+NKMURHGaFKyIvLAgEC - * -----END DH PARAMETERS----- - */ -static unsigned char DEFAULT_DH_512_PRIM[] = { - 0xf4, 0xcd, 0x71, 0xe5, 0x8d, 0x18, 0x3f, 0x98, - 0x9f, 0x4f, 0x60, 0xb0, 0x02, 0x2e, 0xfe, 0x7c, - 0x09, 0xdf, 0x15, 0xc4, 0x1c, 0x71, 0x63, 0xba, - 0x04, 0xb8, 0x27, 0x94, 0x44, 0xc8, 0x93, 0xa8, - 0x48, 0x4c, 0xca, 0x6d, 0x7a, 0xae, 0x18, 0x4a, - 0x81, 0x91, 0xb6, 0xce, 0x4d, 0x8e, 0xf6, 0xe5, - 0x08, 0x04, 0x8c, 0x52, 0x8f, 0xe3, 0x4a, 0x31, - 0x44, 0x47, 0x19, 0xa1, 0x4a, 0xc8, 0x8b, 0xcb, -}; -static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 }; -DH *OSSL_DEFAULT_DH_512 = NULL; - -/* - * -----BEGIN DH PARAMETERS----- - * MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ - * AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR - * T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC - * -----END DH PARAMETERS----- + * Sets _pub_key_ and _priv_key_ for the DH instance. _priv_key_ may be +nil+. */ -static unsigned char DEFAULT_DH_1024_PRIM[] = { - 0x9d, 0x25, 0x39, 0x5c, 0xb4, 0x54, 0x8a, 0xff, - 0x25, 0xe6, 0xd6, 0x9f, 0x4c, 0xc3, 0xc1, 0x8d, - 0xa1, 0xfa, 0xba, 0x88, 0x4c, 0x53, 0xa9, 0x74, - 0xda, 0xfa, 0xba, 0x0b, 0x20, 0xbe, 0x40, 0xd7, - 0xba, 0xe7, 0x1d, 0x70, 0x28, 0x61, 0x60, 0x4c, - 0x49, 0x01, 0x5f, 0xd9, 0x0f, 0x60, 0x16, 0x3d, - 0xba, 0xd3, 0xa9, 0x5e, 0xfa, 0x98, 0x64, 0x60, - 0x26, 0x0e, 0x04, 0x75, 0xd8, 0x13, 0xd7, 0x31, - 0xb4, 0x8e, 0xad, 0xeb, 0x9c, 0x57, 0x4c, 0x8f, - 0x65, 0xf3, 0x90, 0x16, 0x31, 0xdc, 0x15, 0x6f, - 0x7d, 0x1d, 0x00, 0xae, 0x76, 0xf2, 0xd1, 0x11, - 0xd1, 0x4f, 0x88, 0x7b, 0x29, 0x9f, 0xf6, 0xce, - 0x68, 0xef, 0x57, 0xe7, 0x85, 0xf2, 0x40, 0x54, - 0x1c, 0x12, 0x40, 0xa2, 0x35, 0x25, 0xcf, 0x12, - 0xa3, 0xe1, 0x07, 0x8e, 0xdb, 0x1d, 0xb4, 0x14, - 0xff, 0x57, 0xe7, 0x19, 0x8d, 0x51, 0x77, 0x83 -}; -static unsigned char DEFAULT_DH_1024_GEN[] = { 0x02 }; -DH *OSSL_DEFAULT_DH_1024 = NULL; - -static DH* -ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen) -{ - DH *dh; - - if ((dh = DH_new()) == NULL) ossl_raise(eDHError, NULL); - dh->p = BN_bin2bn(p, plen, NULL); - dh->g = BN_bin2bn(g, glen, NULL); - if (dh->p == NULL || dh->g == NULL){ - DH_free(dh); - ossl_raise(eDHError, NULL); - } - - return dh; -} +OSSL_PKEY_BN_DEF2(dh, DH, key, pub_key, priv_key) /* * INIT */ void -Init_ossl_dh() +Init_ossl_dh(void) { -#if 0 /* let rdoc know about mOSSL and mPKey */ - mOSSL = rb_define_module("OpenSSL"); - mPKey = rb_define_module_under(mOSSL, "PKey"); -#endif - - eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError); + /* Document-class: OpenSSL::PKey::DH + * + * An implementation of the Diffie-Hellman key exchange protocol based on + * discrete logarithms in finite fields, the same basis that DSA is built + * 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. + * + * === Example of a key exchange + * # you may send the parameters (der) and own public key (pub1) publicly + * # to the participating party + * dh1 = OpenSSL::PKey::DH.new(2048) + * der = dh1.to_der + * pub1 = dh1.pub_key + * + * # the other party generates its per-session key pair + * dhparams = OpenSSL::PKey::DH.new(der) + * dh2 = OpenSSL::PKey.generate_key(dhparams) + * pub2 = dh2.pub_key + * + * symm_key1 = dh1.compute_key(pub2) + * symm_key2 = dh2.compute_key(pub1) + * puts symm_key1 == symm_key2 # => true + */ 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); +#ifndef HAVE_EVP_PKEY_DUP + rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1); +#endif 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); rb_define_method(cDH, "export", ossl_dh_export, 0); rb_define_alias(cDH, "to_pem", "export"); rb_define_alias(cDH, "to_s", "export"); rb_define_method(cDH, "to_der", ossl_dh_to_der, 0); - rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); - rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); - 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, "params", ossl_dh_get_params, 0); - - OSSL_DEFAULT_DH_512 = ossl_create_dh( - DEFAULT_DH_512_PRIM, sizeof(DEFAULT_DH_512_PRIM), - DEFAULT_DH_512_GEN, sizeof(DEFAULT_DH_512_GEN)); - OSSL_DEFAULT_DH_1024 = ossl_create_dh( - DEFAULT_DH_1024_PRIM, sizeof(DEFAULT_DH_1024_PRIM), - DEFAULT_DH_1024_GEN, sizeof(DEFAULT_DH_1024_GEN)); + rb_define_method(cDH, "set_pqg", ossl_dh_set_pqg, 3); + rb_define_method(cDH, "set_key", ossl_dh_set_key, 2); } #else /* defined NO_DH */ -# warning >>> OpenSSL is compiled without DH support <<< void -Init_ossl_dh() +Init_ossl_dh(void) { - rb_warning("OpenSSL is compiled without DH support"); } #endif /* NO_DH */ - diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index 95dc426366..041646a058 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -1,488 +1,371 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ -#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? */ \ - ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \ + GetPKey((obj), (pkey)); \ + 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); \ + if ((dsa) == NULL) \ + ossl_raise(ePKeyError, "failed to get DSA from EVP_PKEY"); \ +} while (0) -#define DSA_HAS_PRIVATE(dsa) ((dsa)->priv_key) -#define DSA_PRIVATE(obj,dsa) (DSA_HAS_PRIVATE(dsa)||OSSL_PKEY_IS_PRIVATE(obj)) - -/* - * Classes - */ -VALUE cDSA; -VALUE eDSAError; - -/* - * Public - */ -static VALUE -dsa_instance(VALUE klass, DSA *dsa) +static inline int +DSA_HAS_PRIVATE(OSSL_3_const DSA *dsa) { - EVP_PKEY *pkey; - VALUE obj; - - if (!dsa) { - return Qfalse; - } - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_DSA(pkey, dsa)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - WrapPKey(klass, obj, pkey); - - return obj; + const BIGNUM *bn; + DSA_get0_key(dsa, NULL, &bn); + return !!bn; } -VALUE -ossl_dsa_new(EVP_PKEY *pkey) +static inline int +DSA_PRIVATE(VALUE obj, OSSL_3_const DSA *dsa) { - VALUE obj; - - if (!pkey) { - obj = dsa_instance(cDSA, DSA_new()); - } else { - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { - ossl_raise(rb_eTypeError, "Not a DSA key!"); - } - WrapPKey(cDSA, obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eDSAError, NULL); - } - - return obj; + return DSA_HAS_PRIVATE(dsa) || OSSL_PKEY_IS_PRIVATE(obj); } /* - * Private + * Classes */ -static DSA * -dsa_generate(int size) -{ - DSA *dsa; - unsigned char seed[20]; - int seed_len = 20, counter; - unsigned long h; - - if (!RAND_bytes(seed, seed_len)) { - return 0; - } - dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h, - rb_block_given_p() ? ossl_generate_cb : NULL, - NULL); - if(!dsa) return 0; - - if (!DSA_generate_key(dsa)) { - DSA_free(dsa); - return 0; - } - - return dsa; -} +VALUE cDSA; /* - * call-seq: - * DSA.generate(size) -> dsa - * - * === Parameters - * * +size+ is an integer representing the desired key size. - * + * Private */ -static VALUE -ossl_dsa_s_generate(VALUE klass, VALUE size) -{ - DSA *dsa = dsa_generate(FIX2INT(size)); /* err handled by dsa_instance */ - VALUE obj = dsa_instance(klass, dsa); - - if (obj == Qfalse) { - DSA_free(dsa); - ossl_raise(eDSAError, NULL); - } - - return obj; -} - /* * call-seq: - * DSA.new([size | string [, pass]) -> dsa + * DSA.new -> dsa + * DSA.new(string [, pass]) -> dsa + * DSA.new(size) -> dsa + * + * Creates a new DSA instance by reading an existing key from _string_. + * + * If called without arguments, creates a new instance with no key components + * set. They can be set individually by #set_pqg and #set_key. + * This form is not compatible with OpenSSL 3.0 or later. + * + * If called with a String, tries to parse as DER or PEM encoding of a \DSA key. + * See also OpenSSL::PKey.read which can parse keys of any kinds. + * + * If called with a number, generates random parameters and a key pair. This + * form works as an alias of DSA.generate. + * + * +string+:: + * A String that contains a DER or PEM encoded key. + * +pass+:: + * A String that contains an optional password. + * +size+:: + * See DSA.generate. * - * === Parameters - * * +size+ is an integer representing the desired key size. - * * +string+ contains a DER or PEM encoded key. - * * +pass+ is a string that contains a optional password. + * Examples: + * p OpenSSL::PKey::DSA.new(1024) + * #=> #<OpenSSL::PKey::DSA:0x000055a8d6025bf0 oid=DSA> * - * === Examples - * * DSA.new -> dsa - * * DSA.new(1024) -> dsa - * * DSA.new(File.read('dsa.pem')) -> dsa - * * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa + * p OpenSSL::PKey::DSA.new(File.read('dsa.pem')) + * #=> #<OpenSSL::PKey::DSA:0x000055555d6b8110 oid=DSA> * + * p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword') + * #=> #<OpenSSL::PKey::DSA:0x0000556f973c40b8 oid=DSA> */ static VALUE ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; DSA *dsa; - BIO *in; - char *passwd = NULL; + BIO *in = NULL; VALUE arg, pass; - - GetPKey(self, pkey); - if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { + int type; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + + /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(rb_eArgError, "OpenSSL::PKey::DSA.new cannot be called " \ + "without arguments; pkeys are immutable with OpenSSL 3.0"); +#else dsa = DSA_new(); + if (!dsa) + ossl_raise(ePKeyError, "DSA_new"); + goto legacy; +#endif } - else if (FIXNUM_P(arg)) { - if (!(dsa = dsa_generate(FIX2INT(arg)))) { - ossl_raise(eDSAError, NULL); - } + + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); + + /* DER-encoded DSAPublicKey format isn't supported by the generic routine */ + dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey, + PEM_STRING_DSA_PUBLIC, + in, NULL, NULL, NULL); + if (dsa) + goto legacy; + OSSL_BIO_reset(in); + + pkey = ossl_pkey_read_generic(in, pass); + BIO_free(in); + if (!pkey) + ossl_raise(ePKeyError, "Neither PUB key nor PRIV key"); + + type = EVP_PKEY_base_id(pkey); + if (type != EVP_PKEY_DSA) { + EVP_PKEY_free(pkey); + rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type)); } - else { - if (!NIL_P(pass)) passwd = StringValuePtr(pass); - arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); - if (!dsa) { - BIO_reset(in); - dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); - } - if (!dsa) { - BIO_reset(in); - dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); - } - if (!dsa) { - BIO_reset(in); - dsa = d2i_DSAPrivateKey_bio(in, NULL); - } - if (!dsa) { - BIO_reset(in); - dsa = d2i_DSA_PUBKEY_bio(in, NULL); - } - BIO_free(in); - if (!dsa) ossl_raise(eDSAError, "Neither PUB key nor PRIV key:"); + RTYPEDDATA_DATA(self) = pkey; + return self; + + legacy: + BIO_free(in); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) { + EVP_PKEY_free(pkey); + DSA_free(dsa); + ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA"); } - if (!EVP_PKEY_assign_DSA(pkey, dsa)) { - DSA_free(dsa); - ossl_raise(eDSAError, NULL); + RTYPEDDATA_DATA(self) = pkey; + return self; +} + +#ifndef HAVE_EVP_PKEY_DUP +/* :nodoc: */ +static VALUE +ossl_dsa_initialize_copy(VALUE self, VALUE other) +{ + EVP_PKEY *pkey; + DSA *dsa, *dsa_new; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + GetDSA(other, dsa); + + dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, + (d2i_of_void *)d2i_DSAPrivateKey, + (char *)dsa); + if (!dsa_new) + ossl_raise(ePKeyError, "ASN1_dup"); + + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) { + EVP_PKEY_free(pkey); + DSA_free(dsa_new); + ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA"); } + RTYPEDDATA_DATA(self) = pkey; return self; } +#endif /* * call-seq: * dsa.public? -> true | false * + * Indicates whether this DSA instance has a public key associated with it or + * not. The public key may be retrieved with DSA#public_key. */ static VALUE ossl_dsa_is_public(VALUE self) { - EVP_PKEY *pkey; + const 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; } /* * call-seq: * dsa.private? -> true | false * + * Indicates whether this DSA instance has a private key associated with it or + * not. The private key may be retrieved with DSA#private_key. */ static VALUE ossl_dsa_is_private(VALUE self) { - EVP_PKEY *pkey; - - GetPKeyDSA(self, pkey); - - return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse; + OSSL_3_const DSA *dsa; + + GetDSA(self, dsa); + + return DSA_PRIVATE(self, dsa) ? Qtrue : Qfalse; } /* * call-seq: + * dsa.export([cipher, password]) -> aString * dsa.to_pem([cipher, password]) -> aString + * dsa.to_s([cipher, password]) -> aString + * + * Serializes a private or public key to a PEM-encoding. + * + * [When the key contains public components only] + * + * Serializes it into an X.509 SubjectPublicKeyInfo. + * The parameters _cipher_ and _password_ are ignored. + * + * A PEM-encoded key will look like: + * + * -----BEGIN PUBLIC KEY----- + * [...] + * -----END PUBLIC KEY----- + * + * Consider using #public_to_pem instead. This serializes the key into an + * X.509 SubjectPublicKeyInfo regardless of whether it is a public key + * or a private key. + * + * [When the key contains private components, and no parameters are given] + * + * Serializes it into a traditional \OpenSSL DSAPrivateKey. + * + * A PEM-encoded key will look like: + * + * -----BEGIN DSA PRIVATE KEY----- + * [...] + * -----END DSA PRIVATE KEY----- + * + * [When the key contains private components, and _cipher_ and _password_ are given] + * + * Serializes it into a traditional \OpenSSL DSAPrivateKey and encrypts it in + * OpenSSL's traditional PEM encryption format. + * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an + * instance of OpenSSL::Cipher. * - * === Parameters - * +cipher+ is an OpenSSL::Cipher. - * +password+ is a string containing your password. + * An encrypted PEM-encoded key will look like: * - * === Examples - * * DSA.to_pem -> aString - * * DSA.to_pem(cipher, 'mypassword') -> aString + * -----BEGIN DSA PRIVATE KEY----- + * Proc-Type: 4,ENCRYPTED + * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0 * + * [...] + * -----END DSA PRIVATE KEY----- + * + * Note that this format uses MD5 to derive the encryption key, and hence + * will not be available on FIPS-compliant systems. + * + * <b>This method is kept for compatibility.</b> + * This should only be used when the traditional, non-standard \OpenSSL format + * is required. + * + * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem + * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead. */ static VALUE ossl_dsa_export(int argc, VALUE *argv, VALUE self) { - EVP_PKEY *pkey; - BIO *out; - const EVP_CIPHER *ciph = NULL; - char *passwd = NULL; - VALUE cipher, pass, str; - - GetPKeyDSA(self, pkey); - rb_scan_args(argc, argv, "02", &cipher, &pass); - if (!NIL_P(cipher)) { - ciph = GetCipherPtr(cipher); - if (!NIL_P(pass)) { - passwd = StringValuePtr(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)){ - BIO_free(out); - ossl_raise(eDSAError, NULL); - } - } else { - if (!PEM_write_bio_DSAPublicKey(out, pkey->pkey.dsa)) { - BIO_free(out); - ossl_raise(eDSAError, NULL); - } - } - str = ossl_membio2str(out); + OSSL_3_const DSA *dsa; - return str; + GetDSA(self, dsa); + if (DSA_HAS_PRIVATE(dsa)) + return ossl_pkey_export_traditional(argc, argv, self, 0); + else + return ossl_pkey_export_spki(self, 0); } /* * call-seq: * dsa.to_der -> aString * - */ -static VALUE -ossl_dsa_to_der(VALUE self) -{ - EVP_PKEY *pkey; - 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; - else - i2d_func = i2d_DSA_PUBKEY; - if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0) - ossl_raise(eDSAError, NULL); - str = rb_str_new(0, len); - p = RSTRING_PTR(str); - if(i2d_func(pkey->pkey.dsa, &p) < 0) - ossl_raise(eDSAError, NULL); - ossl_str_adjust(str, p); - - return str; -} - -/* - * call-seq: - * dsa.params -> hash + * Serializes a private or public key to a DER-encoding. * - * Stores all parameters of key to the hash - * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! - * Don't use :-)) (I's up to you) - */ -static VALUE -ossl_dsa_get_params(VALUE self) -{ - EVP_PKEY *pkey; - VALUE hash; - - GetPKeyDSA(self, pkey); - - 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)); - - return hash; -} - -/* - * call-seq: - * dsa.to_text -> aString + * See #to_pem for details. * - * Prints all parameters of key to buffer - * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! - * Don't use :-)) (I's up to you) - */ -static VALUE -ossl_dsa_to_text(VALUE self) -{ - EVP_PKEY *pkey; - BIO *out; - VALUE str; - - GetPKeyDSA(self, pkey); - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eDSAError, NULL); - } - if (!DSA_print(out, pkey->pkey.dsa, 0)) { /* offset = 0 */ - BIO_free(out); - ossl_raise(eDSAError, NULL); - } - str = ossl_membio2str(out); - - return str; -} - -/* - * call-seq: - * dsa.public_key -> aDSA + * <b>This method is kept for compatibility.</b> + * This should only be used when the traditional, non-standard \OpenSSL format + * is required. * - * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY + * Consider using #public_to_der or #private_to_der instead. */ static VALUE -ossl_dsa_to_public_key(VALUE self) +ossl_dsa_to_der(VALUE self) { - EVP_PKEY *pkey; - DSA *dsa; - VALUE obj; - - GetPKeyDSA(self, pkey); - /* err check performed by dsa_instance */ - dsa = DSAPublicKey_dup(pkey->pkey.dsa); - obj = dsa_instance(CLASS_OF(self), dsa); - if (obj == Qfalse) { - DSA_free(dsa); - ossl_raise(eDSAError, NULL); - } - return obj; + OSSL_3_const DSA *dsa; + + GetDSA(self, dsa); + if (DSA_HAS_PRIVATE(dsa)) + return ossl_pkey_export_traditional(0, NULL, self, 1); + else + return ossl_pkey_export_spki(self, 1); } -#define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16) /* - * call-seq: - * dsa.syssign(string) -> aString + * Document-method: OpenSSL::PKey::DSA#set_pqg + * call-seq: + * dsa.set_pqg(p, q, g) -> self * + * Sets _p_, _q_, _g_ to the DSA instance. */ -static VALUE -ossl_dsa_sign(VALUE self, VALUE data) -{ - EVP_PKEY *pkey; - int buf_len; - VALUE str; - - GetPKeyDSA(self, pkey); - StringValue(data); - if (!DSA_PRIVATE(self, pkey->pkey.dsa)) { - ossl_raise(eDSAError, "Private DSA key needed!"); - } - str = rb_str_new(0, ossl_dsa_buf_size(pkey)); - if (!DSA_sign(0, RSTRING_PTR(data), RSTRING_LEN(data), RSTRING_PTR(str), - &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */ - ossl_raise(eDSAError, NULL); - } - rb_str_set_len(str, buf_len); - - return str; -} - +OSSL_PKEY_BN_DEF3(dsa, DSA, pqg, p, q, g) /* - * call-seq: - * dsa.sysverify(digest, sig) -> true | false + * 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+. */ -static VALUE -ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) -{ - EVP_PKEY *pkey; - int ret; - - GetPKeyDSA(self, pkey); - StringValue(digest); - StringValue(sig); - /* type is ignored (0) */ - ret = DSA_verify(0, RSTRING_PTR(digest), RSTRING_LEN(digest), - RSTRING_PTR(sig), RSTRING_LEN(sig), pkey->pkey.dsa); - if (ret < 0) { - ossl_raise(eDSAError, NULL); - } - else if (ret == 1) { - return Qtrue; - } - - 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); +OSSL_PKEY_BN_DEF2(dsa, DSA, key, pub_key, priv_key) /* * INIT */ void -Init_ossl_dsa() +Init_ossl_dsa(void) { -#if 0 /* let rdoc know about mOSSL and mPKey */ - mOSSL = rb_define_module("OpenSSL"); - mPKey = rb_define_module_under(mOSSL, "PKey"); -#endif - - eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError); - + /* Document-class: OpenSSL::PKey::DSA + * + * DSA, the Digital Signature Algorithm, is specified in NIST's + * FIPS 186-3. It is an asymmetric public key algorithm that may be used + * similar to e.g. RSA. + */ cDSA = rb_define_class_under(mPKey, "DSA", cPKey); - - rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); + rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); +#ifndef HAVE_EVP_PKEY_DUP + rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1); +#endif rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); - rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0); rb_define_method(cDSA, "export", ossl_dsa_export, -1); rb_define_alias(cDSA, "to_pem", "export"); rb_define_alias(cDSA, "to_s", "export"); rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0); - rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0); - rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1); - rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); DEF_OSSL_PKEY_BN(cDSA, dsa, p); DEF_OSSL_PKEY_BN(cDSA, dsa, q); 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, "params", ossl_dsa_get_params, 0); + rb_define_method(cDSA, "set_pqg", ossl_dsa_set_pqg, 3); + rb_define_method(cDSA, "set_key", ossl_dsa_set_key, 2); } #else /* defined NO_DSA */ -# warning >>> OpenSSL is compiled without DSA support <<< - void -Init_ossl_dsa() +Init_ossl_dsa(void) { - rb_warning("OpenSSL is compiled without DSA support"); } - #endif /* NO_DSA */ diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index c3a15e722b..35f031819d 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -4,308 +4,268 @@ #include "ossl.h" -#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; - +#if !defined(OPENSSL_NO_EC) #define EXPORT_PEM 0 #define EXPORT_DER 1 +static const rb_data_type_t ossl_ec_group_type; +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) { \ - ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \ + GetPKey((obj), (pkey)); \ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { \ + ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \ } \ } while (0) +#define GetEC(obj, key) do { \ + EVP_PKEY *_pkey; \ + GetPKeyEC(obj, _pkey); \ + (key) = EVP_PKEY_get0_EC_KEY(_pkey); \ + if ((key) == NULL) \ + ossl_raise(ePKeyError, "failed to get EC_KEY from EVP_PKEY"); \ +} while (0) -#define SafeGet_ec_group(obj, group) do { \ - OSSL_Check_Kind(obj, cEC_GROUP); \ - Data_Get_Struct(obj, ossl_ec_group, 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) \ - rb_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 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 Get_EC_GROUP(obj, g) do { \ - ossl_ec_group *ec_group; \ - Data_Get_Struct(obj, ossl_ec_group, ec_group); \ - if (ec_group == NULL) \ - rb_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); \ - if (group == NULL) \ - rb_raise(eEC_GROUP, "EC_GROUP is not initialized"); \ -} while(0) - -#define SafeRequire_EC_GROUP(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; \ - Data_Get_Struct(obj, ossl_ec_point, ec_point); \ - if (ec_point == NULL) \ - rb_raise(eEC_POINT, "missing ossl_ec_point structure"); \ - p = ec_point->point; \ -} while(0) - -#define Require_EC_POINT(obj, point) do { \ - Get_EC_POINT(obj, point); \ - if (point == NULL) \ - rb_raise(eEC_POINT, "EC_POINT is not initialized"); \ -} while(0) - -#define SafeRequire_EC_POINT(obj, point) do { \ - OSSL_Check_Kind(obj, cEC_POINT); \ - Require_EC_POINT(obj, point); \ -} while(0) +#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 GetECPointGroup(obj, group) do { \ + VALUE _group = rb_attr_get(obj, id_i_group); \ + GetECGroup(_group, group); \ +} while (0) VALUE cEC; -VALUE eECError; -VALUE cEC_GROUP; -VALUE eEC_GROUP; -VALUE cEC_POINT; -VALUE eEC_POINT; - -static ID s_GFp; -static ID s_GFp_simple; -static ID s_GFp_mont; -static ID s_GFp_nist; -static ID s_GF2m; -static ID s_GF2m_simple; - -static ID ID_uncompressed; -static ID ID_compressed; -static ID ID_hybrid; - -static VALUE ec_instance(VALUE klass, EC_KEY *ec) +static VALUE cEC_GROUP; +static VALUE eEC_GROUP; +static VALUE cEC_POINT; +static VALUE eEC_POINT; + +static VALUE sym_GFp, sym_GF2m; +static VALUE sym_uncompressed, sym_compressed, sym_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); + +/* + * 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) { - EVP_PKEY *pkey; - VALUE obj; - - if (!ec) { - return Qfalse; - } - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { - EVP_PKEY_free(pkey); - return Qfalse; + EC_KEY *ec; + + if (rb_obj_is_kind_of(arg, cEC_GROUP)) { + EC_GROUP *group; + + GetECGroup(arg, group); + if (!(ec = EC_KEY_new())) + ossl_raise(ePKeyError, NULL); + + if (!EC_KEY_set_group(ec, group)) { + EC_KEY_free(ec); + ossl_raise(ePKeyError, NULL); + } + } else { + int nid = OBJ_sn2nid(StringValueCStr(arg)); + + if (nid == NID_undef) + ossl_raise(ePKeyError, "invalid curve name"); + + if (!(ec = EC_KEY_new_by_curve_name(nid))) + ossl_raise(ePKeyError, NULL); + + EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); } - WrapPKey(klass, obj, pkey); - return obj; + return ec; } -VALUE ossl_ec_new(EVP_PKEY *pkey) +/* + * call-seq: + * EC.generate(ec_group) -> ec + * EC.generate(string) -> ec + * + * Creates a new EC instance with a new random private and public key. + */ +static VALUE +ossl_ec_key_s_generate(VALUE klass, VALUE arg) { + EVP_PKEY *pkey; + EC_KEY *ec; VALUE obj; - if (!pkey) { - obj = ec_instance(cEC, EC_KEY_new()); - } else { - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { - ossl_raise(rb_eTypeError, "Not a EC key!"); - } - WrapPKey(cEC, obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eECError, NULL); + obj = rb_obj_alloc(klass); + + ec = ec_key_new_from_group(arg); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { + EVP_PKEY_free(pkey); + EC_KEY_free(ec); + ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY"); } + RTYPEDDATA_DATA(obj) = pkey; + + if (!EC_KEY_generate_key(ec)) + ossl_raise(ePKeyError, "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) - * OpenSSL::PKey::EC.new(der_string) +/* + * 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) * - * See the OpenSSL documentation for: - * EC_KEY_* + * 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; + BIO *in; VALUE arg, pass; - VALUE group = Qnil; - - GetPKey(self, pkey); - if (pkey->pkey.ec) - rb_raise(eECError, "EC_KEY already initialized"); + int type; - rb_scan_args(argc, argv, "02", &arg, &pass); + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + rb_scan_args(argc, argv, "02", &arg, &pass); if (NIL_P(arg)) { - ec = EC_KEY_new(); - } 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); - - ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL); - if (!ec) { - BIO_reset(in); - ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL); - } - if (!ec) { - BIO_reset(in); - ec = d2i_ECPrivateKey_bio(in, NULL); - } - if (!ec) { - BIO_reset(in); - ec = d2i_EC_PUBKEY_bio(in, NULL); - } - - BIO_free(in); +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(rb_eArgError, "OpenSSL::PKey::EC.new cannot be called " \ + "without arguments; pkeys are immutable with OpenSSL 3.0"); +#else + if (!(ec = EC_KEY_new())) + ossl_raise(ePKeyError, "EC_KEY_new"); + goto legacy; +#endif + } + else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { + ec = ec_key_new_from_group(arg); + goto legacy; + } - if (ec == NULL) { - const char *name = STR2CSTR(arg); - int nid = OBJ_sn2nid(name); + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); - if (nid == NID_undef) - ossl_raise(eECError, "unknown curve name (%s)\n", name); + pkey = ossl_pkey_read_generic(in, pass); + BIO_free(in); + if (!pkey) { + ossl_clear_error(); + ec = ec_key_new_from_group(arg); + goto legacy; + } - if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL) - ossl_raise(eECError, "unable to create curve (%s)\n", name); + type = EVP_PKEY_base_id(pkey); + if (type != EVP_PKEY_EC) { + EVP_PKEY_free(pkey); + rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type)); + } + RTYPEDDATA_DATA(self) = pkey; + return self; - EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); - EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); - } - } + legacy: + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { + EVP_PKEY_free(pkey); + EC_KEY_free(ec); + ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY"); } + RTYPEDDATA_DATA(self) = pkey; + return self; +} - if (ec == NULL) - ossl_raise(eECError, NULL); +#ifndef HAVE_EVP_PKEY_DUP +/* :nodoc: */ +static VALUE +ossl_ec_key_initialize_copy(VALUE self, VALUE other) +{ + EVP_PKEY *pkey; + EC_KEY *ec, *ec_new; - if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { - EC_KEY_free(ec); - ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); - } + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + GetEC(other, ec); - rb_iv_set(self, "@group", Qnil); + ec_new = EC_KEY_dup(ec); + if (!ec_new) + ossl_raise(ePKeyError, "EC_KEY_dup"); - if (!NIL_P(group)) - rb_funcall(self, rb_intern("group="), 1, arg); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) { + EC_KEY_free(ec_new); + ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY"); + } + RTYPEDDATA_DATA(self) = pkey; return self; } +#endif /* - * 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; + OSSL_3_const EC_KEY *ec; + 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 + * modification 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; +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); +#else 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); + GetECGroup(group_v, group); if (EC_KEY_set_group(ec, group) != 1) - ossl_raise(eECError, "EC_KEY_set_group"); + ossl_raise(ePKeyError, "EC_KEY_set_group"); return group_v; +#endif } /* @@ -316,11 +276,10 @@ static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v) */ static VALUE ossl_ec_key_get_private_key(VALUE self) { - EC_KEY *ec; + OSSL_3_const 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; @@ -335,44 +294,29 @@ static VALUE ossl_ec_key_get_private_key(VALUE self) */ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) { +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); +#else EC_KEY *ec; BIGNUM *bn = NULL; - Require_EC_KEY(self, ec); + GetEC(self, ec); if (!NIL_P(private_key)) bn = GetBNPtr(private_key); switch (EC_KEY_set_private_key(ec, bn)) { - case 1: + case 1: break; - case 0: + case 0: if (bn == NULL) break; - default: - ossl_raise(eECError, "EC_KEY_set_private_key"); + /* fallthrough */ + default: + ossl_raise(ePKeyError, "EC_KEY_set_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); - Data_Get_Struct(obj, ossl_ec_point, 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; +#endif } /* @@ -383,20 +327,14 @@ static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v) */ static VALUE ossl_ec_key_get_public_key(VALUE self) { - EC_KEY *ec; + OSSL_3_const 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)); } /* @@ -407,382 +345,329 @@ static VALUE ossl_ec_key_get_public_key(VALUE self) */ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) { +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); +#else 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); + GetECPoint(public_key, point); switch (EC_KEY_set_public_key(ec, point)) { - case 1: + case 1: break; - case 0: + case 0: if (point == NULL) break; - default: - ossl_raise(eECError, "EC_KEY_set_public_key"); + /* fallthrough */ + default: + ossl_raise(ePKeyError, "EC_KEY_set_public_key"); } return public_key; +#endif } /* * 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; + OSSL_3_const 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); - - return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse); -} - -static VALUE ossl_ec_key_to_string(VALUE self, int format) -{ - EC_KEY *ec; - BIO *out; - int i = -1; - int private = 0; - EVP_CIPHER *cipher = NULL; - char *password = NULL; - VALUE str; - - Require_EC_KEY(self, ec); - - if (EC_KEY_get0_public_key(ec) == NULL) - rb_raise(eECError, "can't export - no public key set"); - - if (EC_KEY_check_key(ec) != 1) - ossl_raise(eECError, "can't export - EC_KEY_check_key failed"); - - if (EC_KEY_get0_private_key(ec)) - private = 1; - - if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eECError, "BIO_new(BIO_s_mem())"); - - switch(format) { - case EXPORT_PEM: - if (private) { - if (cipher || password) -/* BUG: finish cipher/password key export */ - rb_notimplement(); - i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password); - } else { - if (cipher || password) - rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); - - i = PEM_write_bio_EC_PUBKEY(out, ec); - } - - break; - case EXPORT_DER: - if (private) { - if (cipher || password) - rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); + OSSL_3_const EC_KEY *ec; - i = i2d_ECPrivateKey_bio(out, ec); - } else { - if (cipher || password) - rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); - - i = i2d_EC_PUBKEY_bio(out, ec); - } + GetEC(self, ec); - break; - default: - BIO_free(out); - rb_raise(rb_eRuntimeError, "unknown format (internal error)"); - } - - if (i != 1) { - BIO_free(out); - ossl_raise(eECError, "outlen=%d", i); - } - - str = ossl_membio2str(out); - - return str; + return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse; } /* * call-seq: - * key.to_pem => String + * key.export([cipher, password]) => String + * key.to_pem([cipher, password]) => String + * + * Serializes a private or public key to a PEM-encoding. + * + * [When the key contains public components only] + * + * Serializes it into an X.509 SubjectPublicKeyInfo. + * The parameters _cipher_ and _password_ are ignored. + * + * A PEM-encoded key will look like: + * + * -----BEGIN PUBLIC KEY----- + * [...] + * -----END PUBLIC KEY----- + * + * Consider using #public_to_pem instead. This serializes the key into an + * X.509 SubjectPublicKeyInfo regardless of whether it is a public key + * or a private key. + * + * [When the key contains private components, and no parameters are given] + * + * Serializes it into a SEC 1/RFC 5915 ECPrivateKey. + * + * A PEM-encoded key will look like: + * + * -----BEGIN EC PRIVATE KEY----- + * [...] + * -----END EC PRIVATE KEY----- + * + * [When the key contains private components, and _cipher_ and _password_ are given] + * + * Serializes it into a SEC 1/RFC 5915 ECPrivateKey + * and encrypts it in OpenSSL's traditional PEM encryption format. + * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an + * instance of OpenSSL::Cipher. + * + * An encrypted PEM-encoded key will look like: * - * See the OpenSSL documentation for PEM_write_bio_ECPrivateKey() + * -----BEGIN EC PRIVATE KEY----- + * Proc-Type: 4,ENCRYPTED + * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0 + * + * [...] + * -----END EC PRIVATE KEY----- + * + * Note that this format uses MD5 to derive the encryption key, and hence + * will not be available on FIPS-compliant systems. + * + * <b>This method is kept for compatibility.</b> + * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is + * required. + * + * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem + * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead. */ -static VALUE ossl_ec_key_to_pem(VALUE self) +static VALUE +ossl_ec_key_export(int argc, VALUE *argv, VALUE self) { - return ossl_ec_key_to_string(self, EXPORT_PEM); + OSSL_3_const EC_KEY *ec; + + GetEC(self, ec); + if (EC_KEY_get0_public_key(ec) == NULL) + ossl_raise(ePKeyError, "can't export - no public key set"); + if (EC_KEY_get0_private_key(ec)) + return ossl_pkey_export_traditional(argc, argv, self, 0); + else + return ossl_pkey_export_spki(self, 0); } /* * call-seq: * key.to_der => String * - * See the OpenSSL documentation for i2d_ECPrivateKey_bio() - */ -static VALUE ossl_ec_key_to_der(VALUE self) -{ - return ossl_ec_key_to_string(self, EXPORT_DER); -} - -/* - * call-seq: - * key.to_text => String + * Serializes a private or public key to a DER-encoding. * - * See the OpenSSL documentation for EC_KEY_print() + * See #to_pem for details. + * + * <b>This method is kept for compatibility.</b> + * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is + * required. + * + * Consider using #public_to_der or #private_to_der instead. */ -static VALUE ossl_ec_key_to_text(VALUE self) +static VALUE +ossl_ec_key_to_der(VALUE self) { - EC_KEY *ec; - BIO *out; - VALUE str; + OSSL_3_const EC_KEY *ec; - Require_EC_KEY(self, ec); - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eECError, "BIO_new(BIO_s_mem())"); - } - if (!EC_KEY_print(out, ec, 0)) { - BIO_free(out); - ossl_raise(eECError, "EC_KEY_print"); - } - str = ossl_membio2str(out); - - return str; + GetEC(self, ec); + if (EC_KEY_get0_public_key(ec) == NULL) + ossl_raise(ePKeyError, "can't export - no public key set"); + if (EC_KEY_get0_private_key(ec)) + return ossl_pkey_export_traditional(0, NULL, self, 1); + else + return ossl_pkey_export_spki(self, 1); } - /* * 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) { +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); +#else 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"); + ossl_raise(ePKeyError, "EC_KEY_generate_key"); return self; +#endif } /* - * call-seq: - * key.check_key => true + * call-seq: + * key.check_key => true * - * Raises an exception if the key is invalid. + * Raises an exception if the key is invalid. * - * See the OpenSSL documentation for EC_KEY_check_key() + * See also the man page EVP_PKEY_public_check(3). */ static VALUE ossl_ec_key_check_key(VALUE self) { - EC_KEY *ec; - - Require_EC_KEY(self, ec); - - if (EC_KEY_check_key(ec) != 1) - ossl_raise(eECError, "EC_KEY_check_key"); +#ifdef HAVE_EVP_PKEY_CHECK + EVP_PKEY *pkey; + EVP_PKEY_CTX *pctx; + const EC_KEY *ec; - return Qtrue; -} + GetPKey(self, pkey); + GetEC(self, ec); + pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); + if (!pctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + + if (EC_KEY_get0_private_key(ec) != NULL) { + if (EVP_PKEY_check(pctx) != 1) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(ePKeyError, "EVP_PKEY_check"); + } + } + else { + if (EVP_PKEY_public_check(pctx) != 1) { + EVP_PKEY_CTX_free(pctx); + ossl_raise(ePKeyError, "EVP_PKEY_public_check"); + } + } -/* - * call-seq: - * key.dh_compute_key(pubkey) => String - * - * See the OpenSSL documentation for ECDH_compute_key() - */ -static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) -{ + EVP_PKEY_CTX_free(pctx); +#else EC_KEY *ec; - EC_POINT *point; - int buf_len; - VALUE str; - Require_EC_KEY(self, ec); - SafeRequire_EC_POINT(pubkey, point); - -/* BUG: need a way to figure out the maximum string size */ - buf_len = 1024; - str = rb_str_new(0, buf_len); -/* BUG: take KDF as a block */ - buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); - if (buf_len < 0) - ossl_raise(eECError, "ECDH_compute_key"); - - rb_str_resize(str, buf_len); + GetEC(self, ec); + if (EC_KEY_check_key(ec) != 1) + ossl_raise(ePKeyError, "EC_KEY_check_key"); +#endif - return str; + return Qtrue; } -/* sign_setup */ - /* - * call-seq: - * key.dsa_sign_asn1(data) => String - * - * See the OpenSSL documentation for ECDSA_sign() + * OpenSSL::PKey::EC::Group */ -static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) +static void +ossl_ec_group_free(void *ptr) { - EC_KEY *ec; - unsigned int buf_len; - VALUE str; - - Require_EC_KEY(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); - if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) - ossl_raise(eECError, "ECDSA_sign"); - - rb_str_resize(str, buf_len); - - return str; + EC_GROUP_free(ptr); } -/* - * call-seq: - * key.dsa_verify(data, sig) => true or false - * - * See the OpenSSL documentation for ECDSA_verify() - */ -static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) -{ - EC_KEY *ec; - - Require_EC_KEY(self, ec); - StringValue(data); - StringValue(sig); - - switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(sig), RSTRING_LEN(sig), ec)) { - case 1: return Qtrue; - case 0: return Qfalse; - default: break; - } - - ossl_raise(eECError, "ECDSA_verify"); -} +static const rb_data_type_t ossl_ec_group_type = { + "OpenSSL/ec_group", + { + 0, ossl_ec_group_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; -static void ossl_ec_group_free(ossl_ec_group *ec_group) +static VALUE +ossl_ec_group_alloc(VALUE klass) { - if (!ec_group->dont_free && ec_group->group) - EC_GROUP_clear_free(ec_group->group); - free(ec_group); + return TypedData_Wrap_Struct(klass, &ossl_ec_group_type, NULL); } -static VALUE ossl_ec_group_alloc(VALUE klass) +static VALUE +ec_group_new(const EC_GROUP *group) { - ossl_ec_group *ec_group; VALUE obj; + EC_GROUP *group_new; - obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, 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) - * - * See the OpenSSL documentation for EC_GROUP_* +/* + * call-seq: + * OpenSSL::PKey::EC::Group.new(ec_group) + * OpenSSL::PKey::EC::Group.new(pem_or_der_encoded) + * 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. + * + * 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; - Data_Get_Struct(self, ossl_ec_group, ec_group); - if (ec_group->group != NULL) - rb_raise(rb_eRuntimeError, "EC_GROUP is already initialized"); + 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)) { - case 1: - if (SYMBOL_P(arg1)) { - const EC_METHOD *method = NULL; - ID id = SYM2ID(arg1); - - if (id == s_GFp_simple) { - method = EC_GFp_simple_method(); - } else if (id == s_GFp_mont) { - method = EC_GFp_mont_method(); - } else if (id == s_GFp_nist) { - method = EC_GFp_nist_method(); - } else if (id == s_GF2m_simple) { - method = EC_GF2m_simple_method(); - } - - if (method) { - if ((group = EC_GROUP_new(method)) == NULL) - ossl_raise(eEC_GROUP, "EC_GROUP_new"); - } else { - rb_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple"); - } - } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { + case 1: + if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { const EC_GROUP *arg1_group; - SafeRequire_EC_GROUP(arg1, arg1_group); + GetECGroup(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) { - BIO_reset(in); + OSSL_BIO_reset(in); group = d2i_ECPKParameters_bio(in, NULL); } BIO_free(in); if (!group) { - const char *name = STR2CSTR(arg1); + const char *name = StringValueCStr(arg1); int nid = OBJ_sn2nid(name); + 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); +#if !defined(OPENSSL_IS_AWSLC) group = EC_GROUP_new_by_curve_name(nid); +#else /* EC_GROUPs are static and immutable by default in AWS-LC. */ + group = EC_GROUP_new_by_curve_name_mutable(nid); +#endif 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); @@ -790,79 +675,112 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) } break; - case 4: + case 4: if (SYMBOL_P(arg1)) { - ID id = SYM2ID(arg1); EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL; const BIGNUM *p = GetBNPtr(arg2); const BIGNUM *a = GetBNPtr(arg3); const BIGNUM *b = GetBNPtr(arg4); - if (id == s_GFp) { + if (arg1 == sym_GFp) { new_curve = EC_GROUP_new_curve_GFp; - } else if (id == s_GF2m) { + } +#if !defined(OPENSSL_NO_EC2M) + else if (arg1 == sym_GF2m) { new_curve = EC_GROUP_new_curve_GF2m; - } else { - rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m"); + } +#endif + else { + ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m"); } if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL) ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*"); } else { - rb_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m"); + ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m"); } break; - default: - rb_raise(rb_eArgError, "wrong number of arguments"); + default: + ossl_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1 or 4)", argc); } - if (group == NULL) - ossl_raise(eEC_GROUP, ""); + ASSUME(group); + RTYPEDDATA_DATA(self) = group; - ec_group->group = group; + return self; +} + +/* :nodoc: */ +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"); + GetECGroup(other, 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 == 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); + GetECGroup(b, group2); - if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1) - return Qfalse; - - return Qtrue; + switch (EC_GROUP_cmp(group1, group2, ossl_bn_ctx)) { + case 0: return Qtrue; + case 1: return Qfalse; + default: ossl_raise(eEC_GROUP, "EC_GROUP_cmp"); + } } -/* call-seq: - * group.generator => ec_point +/* + * call-seq: + * group.generator => ec_point + * + * Returns the generator of the group. * - * See the OpenSSL documentation for EC_GROUP_get0_generator() + * 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) { @@ -870,8 +788,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); + GetECPoint(generator, point); o = GetBNPtr(order); co = GetBNPtr(cofactor); @@ -881,20 +799,22 @@ 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 + * + * Returns the order of the group. * - * See the OpenSSL documentation for EC_GROUP_get_order() + * See the OpenSSL documentation for EC_GROUP_get_order() */ static VALUE ossl_ec_group_get_order(VALUE self) { VALUE bn_obj; BIGNUM *bn; - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); + EC_GROUP *group; - bn_obj = ossl_bn_new(NULL); + GetECGroup(self, group); + bn_obj = ossl_bn_new(BN_value_one()); bn = GetBNPtr(bn_obj); if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1) @@ -903,20 +823,22 @@ 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 + * + * Returns the cofactor of the group. * - * See the OpenSSL documentation for EC_GROUP_get_cofactor() + * See the OpenSSL documentation for EC_GROUP_get_cofactor() */ static VALUE ossl_ec_group_get_cofactor(VALUE self) { VALUE bn_obj; BIGNUM *bn; - EC_GROUP *group = NULL; - - Require_EC_GROUP(self, group); + EC_GROUP *group; - bn_obj = ossl_bn_new(NULL); + GetECGroup(self, group); + bn_obj = ossl_bn_new(BN_value_one()); bn = GetBNPtr(bn_obj); if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1) @@ -925,36 +847,41 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self) return bn_obj; } -/* call-seq: - * group.curve_name => String +/* + * call-seq: + * group.curve_name -> string or nil + * + * Returns the curve name (short name) corresponding to this group, or +nil+ + * if \OpenSSL does not have an OID associated with the group. * - * See the OpenSSL documentation for EC_GROUP_get_curve_name() + * See the OpenSSL documentation for EC_GROUP_get_curve_name() */ static VALUE ossl_ec_group_get_curve_name(VALUE self) { - EC_GROUP *group = NULL; + EC_GROUP *group; int nid; - Get_EC_GROUP(self, group); - if (group == NULL) - return Qnil; - + GetECGroup(self, group); nid = EC_GROUP_get_curve_name(group); - -/* BUG: an nid or asn1 object should be returned, maybe. */ - return rb_str_new2(OBJ_nid2sn(nid)); + if (nid == NID_undef) + return Qnil; + return rb_str_new_cstr(OBJ_nid2sn(nid)); } -/* call-seq: - * EC.builtin_curves => [[name, comment], ...] +/* + * call-seq: + * EC.builtin_curves => [[sn, comment], ...] + * + * Obtains a list of all predefined curves by the OpenSSL. Curve names are + * returned as sn. * - * See the OpenSSL documentation for EC_builtin_curves() + * See the OpenSSL documentation for EC_get_builtin_curves(). */ static VALUE ossl_s_builtin_curves(VALUE self) { EC_builtin_curve *curves = NULL; int n; - int crv_len = EC_get_builtin_curves(NULL, 0); + int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0)); VALUE ary, ret; curves = ALLOCA_N(EC_builtin_curve, crv_len); @@ -978,125 +905,158 @@ static VALUE ossl_s_builtin_curves(VALUE self) return ret; } -/* call-seq: - * group.asn1_flag => Fixnum +/* + * call-seq: + * group.asn1_flag -> Integer + * + * Returns the flags set on the group. * - * See the OpenSSL documentation for EC_GROUP_get_asn1_flag() + * 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. * - * See the OpenSSL documentation for EC_GROUP_set_asn1_flag() + * The flag value can be either of: + * + * * 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) { - EC_GROUP *group = NULL; + EC_GROUP *group; 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) { - case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break; - case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break; - case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break; - default: rb_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form); + case POINT_CONVERSION_UNCOMPRESSED: + return sym_uncompressed; + case POINT_CONVERSION_COMPRESSED: + return sym_compressed; + case POINT_CONVERSION_HYBRID: + return sym_hybrid; + default: + ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, " \ + "this module should be updated", form); } - - return ID2SYM(ret); } -/* call-seq: - * group.point_conversion_form = form => form +static point_conversion_form_t +parse_point_conversion_form_symbol(VALUE sym) +{ + if (sym == sym_uncompressed) + return POINT_CONVERSION_UNCOMPRESSED; + if (sym == sym_compressed) + return POINT_CONVERSION_COMPRESSED; + if (sym == sym_hybrid) + return POINT_CONVERSION_HYBRID; + ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE + " (expected :compressed, :uncompressed, or :hybrid)", sym); +} + +/* + * call-seq: + * group.point_conversion_form = form * - * See the OpenSSL documentation for EC_GROUP_set_point_conversion_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() */ -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 { - rb_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) return Qnil; - return rb_str_new(EC_GROUP_get0_seed(group), seed_len); + 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, RSTRING_PTR(seed), RSTRING_LEN(seed)) != RSTRING_LEN(seed)) + if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed)) ossl_raise(eEC_GROUP, "EC_GROUP_set_seed"); return seed; @@ -1104,16 +1064,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)); } @@ -1125,26 +1086,26 @@ 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())"); switch(format) { - case EXPORT_PEM: + case EXPORT_PEM: i = PEM_write_bio_ECPKParameters(out, group); - break; - case EXPORT_DER: + break; + case EXPORT_DER: i = i2d_ECPKParameters_bio(out, group); - break; - default: + break; + default: BIO_free(out); - rb_raise(rb_eRuntimeError, "unknown format (internal error)"); + ossl_raise(rb_eRuntimeError, "unknown format (internal error)"); } if (i != 1) { BIO_free(out); - ossl_raise(eECError, NULL); + ossl_raise(ePKeyError, NULL); } str = ossl_membio2str(out); @@ -1152,8 +1113,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() */ @@ -1162,20 +1124,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) { @@ -1183,13 +1147,13 @@ 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())"); + ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); } if (!ECPKParameters_print(out, group, 0)) { - BIO_free(out); - ossl_raise(eEC_GROUP, NULL); + BIO_free(out); + ossl_raise(eEC_GROUP, NULL); } str = ossl_membio2str(out); @@ -1197,300 +1161,409 @@ static VALUE ossl_ec_group_to_text(VALUE self) } -static void ossl_ec_point_free(ossl_ec_point *ec_point) +/* + * OpenSSL::PKey::EC::Point + */ +static void +ossl_ec_point_free(void *ptr) { - if (!ec_point->dont_free && ec_point->point) - EC_POINT_clear_free(ec_point->point); - free(ec_point); + EC_POINT_clear_free(ptr); } -static VALUE ossl_ec_point_alloc(VALUE klass) +static const rb_data_type_t ossl_ec_point_type = { + "OpenSSL/EC_POINT", + { + 0, ossl_ec_point_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE +ossl_ec_point_alloc(VALUE klass) { - ossl_ec_point *ec_point; + return TypedData_Wrap_Struct(klass, &ossl_ec_point_type, NULL); +} + +static VALUE +ec_point_new(const EC_POINT *point, const EC_GROUP *group) +{ + EC_POINT *point_new; VALUE obj; - obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, 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; } +static VALUE ossl_ec_point_initialize_copy(VALUE, VALUE); /* - * 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 [, encoded_point]) + * + * Creates a new instance of OpenSSL::PKey::EC::Point. If the only argument is + * an instance of EC::Point, a copy is returned. Otherwise, creates a point + * that belongs to _group_. * - * See the OpenSSL documentation for EC_POINT_* + * _encoded_point_ is the octet string representation of the point. This + * must be either a String or an OpenSSL::BN. */ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) { - ossl_ec_point *ec_point; - EC_POINT *point = NULL; - VALUE arg1, arg2; - VALUE group_v = Qnil; - const EC_GROUP *group = NULL; + EC_POINT *point; + VALUE group_v, arg2; + const EC_GROUP *group; - Data_Get_Struct(self, ossl_ec_point, ec_point); - if (ec_point->point) + TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point); + if (point) rb_raise(eEC_POINT, "EC_POINT already initialized"); - switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) { - case 1: - 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); - - 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); - - point = EC_POINT_new(group); - } else { - rb_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group"); - } + rb_scan_args(argc, argv, "11", &group_v, &arg2); + if (rb_obj_is_kind_of(group_v, cEC_POINT)) { + if (argc != 1) + rb_raise(rb_eArgError, "invalid second argument"); + return ossl_ec_point_initialize_copy(self, group_v); + } - break; - case 2: - if (!rb_obj_is_kind_of(arg1, cEC_GROUP)) - rb_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group"); - group_v = arg1; - SafeRequire_EC_GROUP(group_v, group); - + GetECGroup(group_v, group); + if (argc == 1) { + point = EC_POINT_new(group); + if (!point) + ossl_raise(eEC_POINT, "EC_POINT_new"); + } + else { 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); - -/* BUG: finish me */ - - BIO_free(in); - - if (point == NULL) { - ossl_raise(eEC_POINT, "unknown type for 2nd arg"); + point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx); + if (!point) + ossl_raise(eEC_POINT, "EC_POINT_bn2point"); + } + else { + StringValue(arg2); + point = EC_POINT_new(group); + if (!point) + ossl_raise(eEC_POINT, "EC_POINT_new"); + if (!EC_POINT_oct2point(group, point, + (unsigned char *)RSTRING_PTR(arg2), + RSTRING_LEN(arg2), ossl_bn_ctx)) { + EC_POINT_free(point); + ossl_raise(eEC_POINT, "EC_POINT_oct2point"); } } - break; - default: - rb_raise(rb_eArgError, "wrong number of arguments"); } - if (point == NULL) - ossl_raise(eEC_POINT, NULL); + RTYPEDDATA_DATA(self) = point; + rb_ivar_set(self, id_i_group, group_v); - if (NIL_P(group_v)) - rb_raise(rb_eRuntimeError, "missing group (internal error)"); + return self; +} - ec_point->point = point; +/* :nodoc: */ +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"); + GetECPoint(other, point); + + group_v = rb_obj_dup(rb_attr_get(other, id_i_group)); + GetECGroup(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 == 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); + GetECPoint(b, point2); + GetECGroup(group_v1, group); - if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1) - return Qfalse; + switch (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx)) { + case 0: return Qtrue; + case 1: return Qfalse; + default: ossl_raise(eEC_POINT, "EC_POINT_cmp"); + } - return Qtrue; + UNREACHABLE; } /* - * 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; - case 0: return Qfalse; - default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity"); + case 1: return Qtrue; + case 0: return Qfalse; + default: ossl_raise(eEC_POINT, "EC_POINT_is_at_infinity"); } + + UNREACHABLE; } /* - * 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; - case 0: return Qfalse; - default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve"); + case 1: return Qtrue; + case 0: return Qfalse; + default: ossl_raise(eEC_POINT, "EC_POINT_is_on_curve"); } + + UNREACHABLE; } /* - * call-seq: - * point.make_affine! => self + * call-seq: + * point.make_affine! => self * + * This method is deprecated and should not be used. This is a no-op. */ 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); + rb_warn("OpenSSL::PKey::EC::Point#make_affine! is deprecated"); +#if !defined(OSSL_HAVE_IMMUTABLE_PKEY) && !defined(OPENSSL_IS_AWSLC) if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1) - ossl_raise(cEC_POINT, "EC_POINT_make_affine"); + ossl_raise(eEC_POINT, "EC_POINT_make_affine"); +#endif return 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"); + ossl_raise(eEC_POINT, "EC_POINT_invert"); return 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"); + ossl_raise(eEC_POINT, "EC_POINT_set_to_infinity"); return self; } /* - * call-seq: - * point.to_bn => OpenSSL::BN + * call-seq: + * point.to_octet_string(conversion_form) -> String + * + * Returns the octet string representation of the elliptic curve point. + * + * _conversion_form_ specifies how the point is converted. Possible values are: * - * See the OpenSSL documentation for EC_POINT_point2bn() + * - +:compressed+ + * - +:uncompressed+ + * - +:hybrid+ */ -static VALUE ossl_ec_point_to_bn(VALUE self) +static VALUE +ossl_ec_point_to_octet_string(VALUE self, VALUE conversion_form) { EC_POINT *point; - VALUE bn_obj; - VALUE group_v = rb_iv_get(self, "@group"); const EC_GROUP *group; point_conversion_form_t form; - BIGNUM *bn; + VALUE str; + size_t len; + + GetECPoint(self, point); + GetECPointGroup(self, group); + form = parse_point_conversion_form_symbol(conversion_form); + + len = EC_POINT_point2oct(group, point, form, NULL, 0, ossl_bn_ctx); + if (!len) + ossl_raise(eEC_POINT, "EC_POINT_point2oct"); + str = rb_str_new(NULL, (long)len); + if (!EC_POINT_point2oct(group, point, form, + (unsigned char *)RSTRING_PTR(str), len, + ossl_bn_ctx)) + ossl_raise(eEC_POINT, "EC_POINT_point2oct"); + return str; +} - Require_EC_POINT(self, point); - SafeRequire_EC_GROUP(group_v, group); +/* + * call-seq: + * point.add(point) => point + * + * Performs elliptic curve point addition. + */ +static VALUE ossl_ec_point_add(VALUE self, VALUE other) +{ + EC_POINT *point_self, *point_other, *point_result; + const EC_GROUP *group; + VALUE group_v = rb_attr_get(self, id_i_group); + VALUE result; - form = EC_GROUP_get_point_conversion_form(group); + GetECPoint(self, point_self); + GetECPoint(other, point_other); + GetECGroup(group_v, group); - bn_obj = rb_obj_alloc(cBN); - bn = GetBNPtr(bn_obj); + result = rb_obj_alloc(cEC_POINT); + ossl_ec_point_initialize(1, &group_v, result); + GetECPoint(result, point_result); - if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL) - ossl_raise(eEC_POINT, "EC_POINT_point2bn"); + if (EC_POINT_add(group, point_result, point_self, point_other, ossl_bn_ctx) != 1) { + ossl_raise(eEC_POINT, "EC_POINT_add"); + } - return bn_obj; + return result; } -static void no_copy(VALUE klass) +/* + * call-seq: + * point.mul(bn1 [, 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 omitted, and in that case, + * the result is just <tt>bn1 * point</tt>. + * + * Before version 4.0.0, and when compiled with OpenSSL 1.1.1 or older, this + * method allowed another form: + * point.mul(bns, points [, bn2]) => point + */ +static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self) { - rb_undef_method(klass, "copy"); - rb_undef_method(klass, "clone"); - rb_undef_method(klass, "dup"); - rb_undef_method(klass, "initialize_copy"); + EC_POINT *point_self, *point_result; + const EC_GROUP *group; + VALUE group_v = rb_attr_get(self, id_i_group); + VALUE arg1, arg2, arg3, result; + const BIGNUM *bn_g = NULL; + + GetECPoint(self, point_self); + GetECGroup(group_v, group); + + result = rb_obj_alloc(cEC_POINT); + ossl_ec_point_initialize(1, &group_v, result); + GetECPoint(result, point_result); + + rb_scan_args(argc, argv, "12", &arg1, &arg2, &arg3); + if (RB_TYPE_P(arg1, T_ARRAY) || argc > 2) + rb_raise(rb_eNotImpError, "OpenSSL::PKey::EC::Point#mul with arrays " \ + "is no longer supported"); + + BIGNUM *bn = GetBNPtr(arg1); + 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); + + return result; } -void Init_ossl_ec() +void Init_ossl_ec(void) { -#ifdef DONT_NEED_RDOC_WORKAROUND - mOSSL = rb_define_module("OpenSSL"); - mPKey = rb_define_module_under(mOSSL, "PKey"); -#endif - - eECError = rb_define_class_under(mPKey, "ECError", ePKeyError); - +#undef rb_intern + /* + * 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); eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError); eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError); - s_GFp = rb_intern("GFp"); - s_GF2m = rb_intern("GF2m"); - s_GFp_simple = rb_intern("GFp_simple"); - s_GFp_mont = rb_intern("GFp_mont"); - s_GFp_nist = rb_intern("GFp_nist"); - s_GF2m_simple = rb_intern("GF2m_simple"); + sym_GFp = ID2SYM(rb_intern_const("GFp")); + sym_GF2m = ID2SYM(rb_intern_const("GF2m")); - ID_uncompressed = rb_intern("uncompressed"); - ID_compressed = rb_intern("compressed"); - ID_hybrid = rb_intern("hybrid"); + sym_uncompressed = ID2SYM(rb_intern_const("uncompressed")); + sym_compressed = ID2SYM(rb_intern_const("compressed")); + sym_hybrid = ID2SYM(rb_intern_const("hybrid")); -#ifdef OPENSSL_EC_NAMED_CURVE - rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE)); -#endif + rb_define_const(cEC, "NAMED_CURVE", INT2NUM(OPENSSL_EC_NAMED_CURVE)); + rb_define_const(cEC, "EXPLICIT_CURVE", INT2NUM(OPENSSL_EC_EXPLICIT_CURVE)); 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); -/* copy/dup/cmp */ +#ifndef HAVE_EVP_PKEY_DUP + rb_define_method(cEC, "initialize_copy", ossl_ec_key_initialize_copy, 1); +#endif rb_define_method(cEC, "group", ossl_ec_key_get_group, 0); rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1); @@ -1498,8 +1571,10 @@ void Init_ossl_ec() 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 @@ -1507,21 +1582,18 @@ void Init_ossl_ec() 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); - rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); - rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); -/* do_sign/do_verify */ - - rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, 0); + rb_define_method(cEC, "export", ossl_ec_key_export, -1); + rb_define_alias(cEC, "to_pem", "export"); rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0); - rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0); rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1); + rb_define_method(cEC_GROUP, "initialize_copy", ossl_ec_group_initialize_copy, 1); rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1); rb_define_alias(cEC_GROUP, "==", "eql?"); /* copy/dup/cmp */ @@ -1557,6 +1629,7 @@ void Init_ossl_ec() rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc); rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1); + rb_define_method(cEC_POINT, "initialize_copy", ossl_ec_point_initialize_copy, 1); 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?"); @@ -1568,18 +1641,15 @@ void Init_ossl_ec() 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_octet_string", ossl_ec_point_to_octet_string, 1); + rb_define_method(cEC_POINT, "add", ossl_ec_point_add, 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 */ -# warning >>> OpenSSL is compiled without EC support <<< - -void Init_ossl_ec() +void Init_ossl_ec(void) { } - #endif /* NO_EC */ diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 4a690a7cb5..039b2c6a34 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -1,565 +1,566 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ -#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? */ \ - ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \ + GetPKey((obj), (pkey)); \ + 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); \ + if ((rsa) == NULL) \ + ossl_raise(ePKeyError, "failed to get RSA from EVP_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)) - -/* - * Classes - */ -VALUE cRSA; -VALUE eRSAError; - -/* - * Public - */ -static VALUE -rsa_instance(VALUE klass, RSA *rsa) +static inline int +RSA_HAS_PRIVATE(OSSL_3_const RSA *rsa) { - EVP_PKEY *pkey; - VALUE obj; - - if (!rsa) { - return Qfalse; - } - if (!(pkey = EVP_PKEY_new())) { - return Qfalse; - } - if (!EVP_PKEY_assign_RSA(pkey, rsa)) { - EVP_PKEY_free(pkey); - return Qfalse; - } - WrapPKey(klass, obj, pkey); - - return obj; + const BIGNUM *e, *d; + + RSA_get0_key(rsa, NULL, &e, &d); + return e && d; } -VALUE -ossl_rsa_new(EVP_PKEY *pkey) +static inline int +RSA_PRIVATE(VALUE obj, OSSL_3_const RSA *rsa) { - VALUE obj; - - if (!pkey) { - obj = rsa_instance(cRSA, RSA_new()); - } - else { - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { - ossl_raise(rb_eTypeError, "Not a RSA key!"); - } - WrapPKey(cRSA, obj, pkey); - } - if (obj == Qfalse) { - ossl_raise(eRSAError, NULL); - } - - return obj; + return RSA_HAS_PRIVATE(rsa) || OSSL_PKEY_IS_PRIVATE(obj); } /* - * Private + * Classes */ -static RSA * -rsa_generate(int size, int exp) -{ - return RSA_generate_key(size, exp, - rb_block_given_p() ? ossl_generate_cb : NULL, - NULL); -} +VALUE cRSA; /* - * call-seq: - * RSA.generate(size [, exponent]) -> rsa + * Private + */ +/* + * call-seq: + * RSA.new -> rsa + * RSA.new(encoded_key [, password ]) -> rsa + * RSA.new(encoded_key) { password } -> rsa + * RSA.new(size [, exponent]) -> rsa + * + * Generates or loads an \RSA keypair. * - * === Parameters - * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. - * * +exponent+ is an odd number normally 3, 17, or 65537. + * If called without arguments, creates a new instance with no key components + * set. They can be set individually by #set_key, #set_factors, and + * #set_crt_params. + * This form is not compatible with OpenSSL 3.0 or later. * + * If called with a String, tries to parse as DER or PEM encoding of an \RSA key. + * Note that if _password_ is not specified, but the key is encrypted with a + * password, \OpenSSL will prompt for it. + * See also OpenSSL::PKey.read which can parse keys of any kind. + * + * If called with a number, generates a new key pair. This form works as an + * alias of RSA.generate. + * + * Examples: + * OpenSSL::PKey::RSA.new 2048 + * OpenSSL::PKey::RSA.new File.read 'rsa.pem' + * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my password' */ static VALUE -ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) +ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) { -/* why does this method exist? why can't initialize take an optional exponent? */ + EVP_PKEY *pkey; RSA *rsa; - VALUE size, exp; - VALUE obj; - - rb_scan_args(argc, argv, "11", &size, &exp); - - rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2INT(exp)); /* err handled by rsa_instance */ - obj = rsa_instance(klass, rsa); + BIO *in = NULL; + VALUE arg, pass; + int type; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + + /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { +#ifdef OSSL_HAVE_IMMUTABLE_PKEY + rb_raise(rb_eArgError, "OpenSSL::PKey::RSA.new cannot be called " \ + "without arguments; pkeys are immutable with OpenSSL 3.0"); +#else + rsa = RSA_new(); + if (!rsa) + ossl_raise(ePKeyError, "RSA_new"); + goto legacy; +#endif + } - if (obj == Qfalse) { - RSA_free(rsa); - ossl_raise(eRSAError, NULL); + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); + + /* First try RSAPublicKey format */ + rsa = d2i_RSAPublicKey_bio(in, NULL); + if (rsa) + goto legacy; + OSSL_BIO_reset(in); + rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); + if (rsa) + goto legacy; + OSSL_BIO_reset(in); + + /* Use the generic routine */ + pkey = ossl_pkey_read_generic(in, pass); + BIO_free(in); + if (!pkey) + ossl_raise(ePKeyError, "Neither PUB key nor PRIV key"); + + type = EVP_PKEY_base_id(pkey); + if (type != EVP_PKEY_RSA) { + EVP_PKEY_free(pkey); + rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type)); } + RTYPEDDATA_DATA(self) = pkey; + return self; - return obj; + legacy: + BIO_free(in); + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) { + EVP_PKEY_free(pkey); + RSA_free(rsa); + ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA"); + } + RTYPEDDATA_DATA(self) = pkey; + return self; } -/* - * call-seq: - * RSA.new([size | encoded_key] [, pass]) -> rsa - * - * === Parameters - * * +size+ is an integer representing the desired key size. - * * +encoded_key+ is a string containing PEM or DER encoded key. - * * +pass+ is an optional string with the password to decrypt the encoded key. - * - * === Examples - * * RSA.new(2048) -> rsa - * * RSA.new(File.read("rsa.pem")) -> rsa - * * RSA.new(File.read("rsa.pem"), "mypassword") -> rsa - */ +#ifndef HAVE_EVP_PKEY_DUP +/* :nodoc: */ static VALUE -ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) +ossl_rsa_initialize_copy(VALUE self, VALUE other) { 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 : NUM2INT(pass)); - if (!rsa) ossl_raise(eRSAError, NULL); - } - else { - if (!NIL_P(pass)) passwd = StringValuePtr(pass); - arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); - if (!rsa) { - BIO_reset(in); - rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); - } - if (!rsa) { - BIO_reset(in); - rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL); - } - if (!rsa) { - BIO_reset(in); - rsa = d2i_RSAPrivateKey_bio(in, NULL); - } - if (!rsa) { - BIO_reset(in); - rsa = d2i_RSAPublicKey_bio(in, NULL); - } - if (!rsa) { - BIO_reset(in); - rsa = d2i_RSA_PUBKEY_bio(in, NULL); - } - BIO_free(in); - if (!rsa) ossl_raise(eRSAError, "Neither PUB key nor PRIV key:"); - } - if (!EVP_PKEY_assign_RSA(pkey, rsa)) { - RSA_free(rsa); - ossl_raise(eRSAError, NULL); + RSA *rsa, *rsa_new; + + TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); + if (pkey) + rb_raise(rb_eTypeError, "pkey already initialized"); + GetRSA(other, rsa); + + rsa_new = (RSA *)ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, + (d2i_of_void *)d2i_RSAPrivateKey, + (char *)rsa); + if (!rsa_new) + ossl_raise(ePKeyError, "ASN1_dup"); + + pkey = EVP_PKEY_new(); + if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) { + RSA_free(rsa_new); + ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA"); } + RTYPEDDATA_DATA(self) = pkey; return self; } +#endif /* - * call-seq: - * rsa.public? -> true - * - * The return value is always true since every private key is also a public key. + * call-seq: + * rsa.public? => true * + * The return value is always +true+ since every private key is also a public + * key. */ static VALUE ossl_rsa_is_public(VALUE self) { - EVP_PKEY *pkey; + OSSL_3_const RSA *rsa; - GetPKeyRSA(self, pkey); + GetRSA(self, rsa); /* * This method should check for n and e. BUG. */ + (void)rsa; return Qtrue; } /* - * call-seq: - * rsa.private? -> true | false + * call-seq: + * rsa.private? => true | false * + * Does this keypair contain a private key? */ static VALUE ossl_rsa_is_private(VALUE self) { - EVP_PKEY *pkey; - - GetPKeyRSA(self, pkey); - - return (RSA_PRIVATE(self, pkey->pkey.rsa)) ? Qtrue : Qfalse; + OSSL_3_const RSA *rsa; + + GetRSA(self, rsa); + + return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse; } -/* - * call-seq: - * rsa.to_pem([cipher, pass]) -> aString - * - * === Parameters - * * +cipher+ is a Cipher object. - * * +pass+ is a string. - * - * === Examples - * * rsa.to_pem -> aString - * * rsa.to_pem(cipher, pass) -> aString - */ -static VALUE -ossl_rsa_export(int argc, VALUE *argv, VALUE self) +static int +can_export_rsaprivatekey(VALUE self) { - EVP_PKEY *pkey; - BIO *out; - const EVP_CIPHER *ciph = NULL; - char *passwd = NULL; - VALUE cipher, pass, str; + OSSL_3_const RSA *rsa; + const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; - GetPKeyRSA(self, pkey); + GetRSA(self, rsa); - rb_scan_args(argc, argv, "02", &cipher, &pass); + RSA_get0_key(rsa, &n, &e, &d); + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); - if (!NIL_P(cipher)) { - ciph = GetCipherPtr(cipher); - if (!NIL_P(pass)) { - passwd = StringValuePtr(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)) { - BIO_free(out); - ossl_raise(eRSAError, NULL); - } - } else { - if (!PEM_write_bio_RSAPublicKey(out, pkey->pkey.rsa)) { - BIO_free(out); - ossl_raise(eRSAError, NULL); - } - } - str = ossl_membio2str(out); - - return str; + return n && e && d && p && q && dmp1 && dmq1 && iqmp; } /* - * call-seq: - * rsa.to_der -> aString + * call-seq: + * rsa.export([cipher, password]) => PEM-format String + * rsa.to_pem([cipher, password]) => PEM-format String + * rsa.to_s([cipher, password]) => PEM-format String + * + * Serializes a private or public key to a PEM-encoding. + * + * [When the key contains public components only] + * + * Serializes it into an X.509 SubjectPublicKeyInfo. + * The parameters _cipher_ and _password_ are ignored. + * + * A PEM-encoded key will look like: + * + * -----BEGIN PUBLIC KEY----- + * [...] + * -----END PUBLIC KEY----- + * + * Consider using #public_to_pem instead. This serializes the key into an + * X.509 SubjectPublicKeyInfo regardless of whether the key is a public key + * or a private key. + * + * [When the key contains private components, and no parameters are given] + * + * Serializes it into a PKCS #1 RSAPrivateKey. + * + * A PEM-encoded key will look like: + * + * -----BEGIN RSA PRIVATE KEY----- + * [...] + * -----END RSA PRIVATE KEY----- + * + * [When the key contains private components, and _cipher_ and _password_ are given] + * + * Serializes it into a PKCS #1 RSAPrivateKey + * and encrypts it in OpenSSL's traditional PEM encryption format. + * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an + * instance of OpenSSL::Cipher. + * + * An encrypted PEM-encoded key will look like: + * + * -----BEGIN RSA PRIVATE KEY----- + * Proc-Type: 4,ENCRYPTED + * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0 + * + * [...] + * -----END RSA PRIVATE KEY----- + * + * Note that this format uses MD5 to derive the encryption key, and hence + * will not be available on FIPS-compliant systems. + * + * <b>This method is kept for compatibility.</b> + * This should only be used when the PKCS #1 RSAPrivateKey format is required. * + * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem + * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead. */ static VALUE -ossl_rsa_to_der(VALUE self) +ossl_rsa_export(int argc, VALUE *argv, VALUE self) { - EVP_PKEY *pkey; - int (*i2d_func)_((const RSA*, unsigned char**)); - unsigned char *p; - long len; - VALUE str; - - GetPKeyRSA(self, pkey); - if(RSA_HAS_PRIVATE(pkey->pkey.rsa)) - i2d_func = i2d_RSAPrivateKey; + if (can_export_rsaprivatekey(self)) + return ossl_pkey_export_traditional(argc, argv, self, 0); else - i2d_func = i2d_RSAPublicKey; - if((len = i2d_func(pkey->pkey.rsa, NULL)) <= 0) - ossl_raise(eRSAError, NULL); - str = rb_str_new(0, len); - p = RSTRING_PTR(str); - if(i2d_func(pkey->pkey.rsa, &p) < 0) - ossl_raise(eRSAError, NULL); - ossl_str_adjust(str, p); - - return str; + return ossl_pkey_export_spki(self, 0); } -#define ossl_rsa_buf_size(pkey) (RSA_size((pkey)->pkey.rsa)+16) - /* - * call-seq: - * rsa.public_encrypt(string [, padding]) -> aString + * call-seq: + * rsa.to_der => DER-format String * - */ -static VALUE -ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) -{ - EVP_PKEY *pkey; - int buf_len, pad; - VALUE str, buffer, padding; - - GetPKeyRSA(self, pkey); - 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)); - buf_len = RSA_public_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), - RSTRING_PTR(str), pkey->pkey.rsa, - pad); - if (buf_len < 0) ossl_raise(eRSAError, NULL); - rb_str_set_len(str, buf_len); - - return str; -} - -/* - * call-seq: - * rsa.public_decrypt(string [, padding]) -> aString + * Serializes a private or public key to a DER-encoding. * + * See #to_pem for details. + * + * <b>This method is kept for compatibility.</b> + * This should only be used when the PKCS #1 RSAPrivateKey format is required. + * + * Consider using #public_to_der or #private_to_der instead. */ static VALUE -ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) +ossl_rsa_to_der(VALUE self) { - EVP_PKEY *pkey; - int buf_len, pad; - VALUE str, buffer, padding; - - GetPKeyRSA(self, pkey); - 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)); - buf_len = RSA_public_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), - RSTRING_PTR(str), pkey->pkey.rsa, - pad); - if (buf_len < 0) ossl_raise(eRSAError, NULL); - rb_str_set_len(str, buf_len); - - return str; + if (can_export_rsaprivatekey(self)) + return ossl_pkey_export_traditional(0, NULL, self, 1); + else + return ossl_pkey_export_spki(self, 1); } /* - * call-seq: - * rsa.private_encrypt(string [, padding]) -> aString + * call-seq: + * rsa.sign_pss(digest, data, salt_length:, mgf1_hash:) -> String + * + * Signs _data_ using the Probabilistic Signature Scheme (RSA-PSS) and returns + * the calculated signature. * + * PKeyError will be raised if an error occurs. + * + * See #verify_pss for the verification operation. + * + * === Parameters + * _digest_:: + * A String containing the message digest algorithm name. + * _data_:: + * A String. The data to be signed. + * _salt_length_:: + * The length in octets of the salt. Two special values are reserved: + * +:digest+ means the digest length, and +:max+ means the maximum possible + * length for the combination of the private key and the selected message + * digest algorithm. + * _mgf1_hash_:: + * The hash algorithm used in MGF1 (the currently supported mask generation + * function (MGF)). + * + * === Example + * data = "Sign me!" + * pkey = OpenSSL::PKey::RSA.new(2048) + * signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256") + * pub_key = OpenSSL::PKey.read(pkey.public_to_der) + * puts pub_key.verify_pss("SHA256", signature, data, + * salt_length: :auto, mgf1_hash: "SHA256") # => true */ static VALUE -ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) +ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self) { + VALUE digest, data, options, kwargs[2], signature, mgf1md_holder, md_holder; + static ID kwargs_ids[2]; EVP_PKEY *pkey; - int buf_len, pad; - VALUE str, buffer, padding; - - GetPKeyRSA(self, pkey); - if (!RSA_PRIVATE(self, pkey->pkey.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)); - buf_len = RSA_private_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), - RSTRING_PTR(str), pkey->pkey.rsa, - pad); - if (buf_len < 0) ossl_raise(eRSAError, NULL); - rb_str_set_len(str, buf_len); - - return str; -} + EVP_PKEY_CTX *pkey_ctx; + const EVP_MD *md, *mgf1md; + EVP_MD_CTX *md_ctx; + size_t buf_len; + int salt_len; + + if (!kwargs_ids[0]) { + kwargs_ids[0] = rb_intern_const("salt_length"); + kwargs_ids[1] = rb_intern_const("mgf1_hash"); + } + rb_scan_args(argc, argv, "2:", &digest, &data, &options); + rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs); + if (kwargs[0] == ID2SYM(rb_intern("max"))) + salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */ + else if (kwargs[0] == ID2SYM(rb_intern("digest"))) + salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */ + else + salt_len = NUM2INT(kwargs[0]); + mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder); + pkey = GetPrivPKeyPtr(self); + buf_len = EVP_PKEY_size(pkey); + md = ossl_evp_md_fetch(digest, &md_holder); + StringValue(data); + signature = rb_str_new(NULL, (long)buf_len); -/* - * call-seq: - * rsa.private_decrypt(string [, padding]) -> aString - * - */ -static VALUE -ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) -{ - EVP_PKEY *pkey; - int buf_len, pad; - VALUE str, buffer, padding; + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) + goto err; - GetPKeyRSA(self, pkey); - if (!RSA_PRIVATE(self, pkey->pkey.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)); - buf_len = RSA_private_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), - RSTRING_PTR(str), pkey->pkey.rsa, - pad); - if (buf_len < 0) ossl_raise(eRSAError, NULL); - rb_str_set_len(str, buf_len); - - return str; -} + if (EVP_DigestSignInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1) + goto err; -/* - * call-seq: - * rsa.params -> hash - * - * Stores all parameters of key to the hash - * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! - * Don't use :-)) (I's up to you) - */ -static VALUE -ossl_rsa_get_params(VALUE self) -{ - EVP_PKEY *pkey; - VALUE hash; - - GetPKeyRSA(self, pkey); - - 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)); - - return hash; + if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) + goto err; + + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1) + goto err; + + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1) + goto err; + + if (EVP_DigestSignUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1) + goto err; + + if (EVP_DigestSignFinal(md_ctx, (unsigned char *)RSTRING_PTR(signature), &buf_len) != 1) + goto err; + + rb_str_set_len(signature, (long)buf_len); + + EVP_MD_CTX_free(md_ctx); + return signature; + + err: + EVP_MD_CTX_free(md_ctx); + ossl_raise(ePKeyError, NULL); } /* - * call-seq: - * rsa.to_text -> aString + * call-seq: + * rsa.verify_pss(digest, signature, data, salt_length:, mgf1_hash:) -> true | false * - * Prints all parameters of key to buffer - * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! - * Don't use :-)) (It's up to you) + * Verifies _data_ using the Probabilistic Signature Scheme (RSA-PSS). + * + * The return value is +true+ if the signature is valid, +false+ otherwise. + * PKeyError will be raised if an error occurs. + * + * See #sign_pss for the signing operation and an example code. + * + * === Parameters + * _digest_:: + * A String containing the message digest algorithm name. + * _data_:: + * A String. The data to be signed. + * _salt_length_:: + * The length in octets of the salt. Two special values are reserved: + * +:digest+ means the digest length, and +:auto+ means automatically + * determining the length based on the signature. + * _mgf1_hash_:: + * The hash algorithm used in MGF1. */ static VALUE -ossl_rsa_to_text(VALUE self) +ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self) { + VALUE digest, signature, data, options, kwargs[2], mgf1md_holder, md_holder; + static ID kwargs_ids[2]; EVP_PKEY *pkey; - BIO *out; - VALUE str; - - GetPKeyRSA(self, pkey); - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eRSAError, NULL); + EVP_PKEY_CTX *pkey_ctx; + const EVP_MD *md, *mgf1md; + EVP_MD_CTX *md_ctx; + int result, salt_len; + + if (!kwargs_ids[0]) { + kwargs_ids[0] = rb_intern_const("salt_length"); + kwargs_ids[1] = rb_intern_const("mgf1_hash"); } - if (!RSA_print(out, pkey->pkey.rsa, 0)) { /* offset = 0 */ - BIO_free(out); - ossl_raise(eRSAError, NULL); + rb_scan_args(argc, argv, "3:", &digest, &signature, &data, &options); + rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs); + if (kwargs[0] == ID2SYM(rb_intern("auto"))) + salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */ + else if (kwargs[0] == ID2SYM(rb_intern("digest"))) + salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */ + else + salt_len = NUM2INT(kwargs[0]); + mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder); + + GetPKey(self, pkey); + md = ossl_evp_md_fetch(digest, &md_holder); + StringValue(signature); + StringValue(data); + + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) + goto err; + + if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1) + goto err; + + if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) + goto err; + + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1) + goto err; + + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1) + goto err; + + if (EVP_DigestVerifyUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1) + goto err; + + result = EVP_DigestVerifyFinal(md_ctx, + (unsigned char *)RSTRING_PTR(signature), + RSTRING_LEN(signature)); + EVP_MD_CTX_free(md_ctx); + + switch (result) { + case 0: + ossl_clear_error(); + return Qfalse; + case 1: + return Qtrue; + default: + ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); } - str = ossl_membio2str(out); - return str; + err: + EVP_MD_CTX_free(md_ctx); + ossl_raise(ePKeyError, NULL); } /* - * call-seq: - * rsa.public_key -> aRSA + * Document-method: OpenSSL::PKey::RSA#set_key + * call-seq: + * rsa.set_key(n, e, d) -> self * - * Makes new instance RSA PUBLIC_KEY from PRIVATE_KEY + * Sets _n_, _e_, _d_ for the RSA instance. */ -static VALUE -ossl_rsa_to_public_key(VALUE self) -{ - EVP_PKEY *pkey; - RSA *rsa; - VALUE obj; - - GetPKeyRSA(self, pkey); - /* err check performed by rsa_instance */ - rsa = RSAPublicKey_dup(pkey->pkey.rsa); - obj = rsa_instance(CLASS_OF(self), rsa); - if (obj == Qfalse) { - RSA_free(rsa); - ossl_raise(eRSAError, NULL); - } - return obj; -} - +OSSL_PKEY_BN_DEF3(rsa, RSA, key, n, e, d) /* - * TODO: Test me - -static VALUE -ossl_rsa_blinding_on(VALUE self) -{ - EVP_PKEY *pkey; - - GetPKeyRSA(self, pkey); - - if (RSA_blinding_on(pkey->pkey.rsa, ossl_bn_ctx) != 1) { - ossl_raise(eRSAError, NULL); - } - return self; -} - -static VALUE -ossl_rsa_blinding_off(VALUE self) -{ - EVP_PKEY *pkey; - - GetPKeyRSA(self, pkey); - RSA_blinding_off(pkey->pkey.rsa); - - return self; -} + * 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(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); +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() +Init_ossl_rsa(void) { -#if 0 /* let rdoc know about mOSSL and mPKey */ - mOSSL = rb_define_module("OpenSSL"); - mPKey = rb_define_module_under(mOSSL, "PKey"); -#endif - - eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError); - + /* Document-class: OpenSSL::PKey::RSA + * + * RSA is an asymmetric public key algorithm that has been formalized in + * RFC 3447. It is in widespread use in public key infrastructures (PKI) + * where certificates (cf. OpenSSL::X509::Certificate) often are issued + * on the basis of a public/private RSA key pair. RSA is used in a wide + * field of applications such as secure (symmetric) key exchange, e.g. + * when establishing a secure TLS/SSL connection. It is also used in + * various digital signature schemes. + */ cRSA = rb_define_class_under(mPKey, "RSA", cPKey); - rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1); rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); - +#ifndef HAVE_EVP_PKEY_DUP + rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1); +#endif + rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0); rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0); - rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0); rb_define_method(cRSA, "export", ossl_rsa_export, -1); rb_define_alias(cRSA, "to_pem", "export"); rb_define_alias(cRSA, "to_s", "export"); rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0); - rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0); - rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1); - rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1); - rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1); - rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1); + rb_define_method(cRSA, "sign_pss", ossl_rsa_sign_pss, -1); + rb_define_method(cRSA, "verify_pss", ossl_rsa_verify_pss, -1); DEF_OSSL_PKEY_BN(cRSA, rsa, n); DEF_OSSL_PKEY_BN(cRSA, rsa, e); @@ -569,13 +570,9 @@ Init_ossl_rsa() 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, "params", ossl_rsa_get_params, 0); - - DefRSAConst(PKCS1_PADDING); - DefRSAConst(SSLV23_PADDING); - DefRSAConst(NO_PADDING); - DefRSAConst(PKCS1_OAEP_PADDING); + 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); /* * TODO: Test it @@ -585,11 +582,8 @@ Init_ossl_rsa() } #else /* defined NO_RSA */ -# warning >>> OpenSSL is compiled without RSA support <<< void -Init_ossl_rsa() +Init_ossl_rsa(void) { - rb_warning("OpenSSL is compiled without RSA support"); } #endif /* NO_RSA */ - diff --git a/ext/openssl/ossl_provider.c b/ext/openssl/ossl_provider.c new file mode 100644 index 0000000000..ea5abb8e48 --- /dev/null +++ b/ext/openssl/ossl_provider.c @@ -0,0 +1,204 @@ +/* + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) + */ +#include "ossl.h" + +#ifdef OSSL_USE_PROVIDER +#define NewProvider(klass) \ + TypedData_Wrap_Struct((klass), &ossl_provider_type, 0) +#define SetProvider(obj, provider) do { \ + if (!(provider)) { \ + ossl_raise(rb_eRuntimeError, "Provider wasn't initialized."); \ + } \ + RTYPEDDATA_DATA(obj) = (provider); \ +} while(0) +#define GetProvider(obj, provider) do { \ + TypedData_Get_Struct((obj), OSSL_PROVIDER, &ossl_provider_type, (provider)); \ + if (!(provider)) { \ + ossl_raise(rb_eRuntimeError, "PROVIDER wasn't initialized."); \ + } \ +} while (0) + +static const rb_data_type_t ossl_provider_type = { + "OpenSSL/Provider", + { + 0, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* + * Classes + */ +/* Document-class: OpenSSL::Provider + * + * This class is the access to openssl's Provider + * See also, https://www.openssl.org/docs/manmaster/man7/provider.html + */ +static VALUE cProvider; +/* Document-class: OpenSSL::Provider::ProviderError + * + * This is the generic exception for OpenSSL::Provider related errors + */ +static VALUE eProviderError; + +/* + * call-seq: + * OpenSSL::Provider.load(name) -> provider + * + * This method loads and initializes a provider + */ +static VALUE +ossl_provider_s_load(VALUE klass, VALUE name) +{ + OSSL_PROVIDER *provider = NULL; + VALUE obj; + + const char *provider_name_ptr = StringValueCStr(name); + + provider = OSSL_PROVIDER_load(NULL, provider_name_ptr); + if (provider == NULL) { + ossl_raise(eProviderError, "Failed to load %s provider", provider_name_ptr); + } + obj = NewProvider(klass); + SetProvider(obj, provider); + + return obj; +} + +struct ary_with_state { VALUE ary; int state; }; +struct rb_push_provider_name_args { OSSL_PROVIDER *prov; VALUE ary; }; + +static VALUE +rb_push_provider_name(VALUE rb_push_provider_name_args) +{ + struct rb_push_provider_name_args *args = (struct rb_push_provider_name_args *)rb_push_provider_name_args; + + VALUE name = rb_str_new2(OSSL_PROVIDER_get0_name(args->prov)); + return rb_ary_push(args->ary, name); +} + +static int +push_provider(OSSL_PROVIDER *prov, void *cbdata) +{ + struct ary_with_state *ary_with_state = (struct ary_with_state *)cbdata; + struct rb_push_provider_name_args args = { prov, ary_with_state->ary }; + + rb_protect(rb_push_provider_name, (VALUE)&args, &ary_with_state->state); + if (ary_with_state->state) { + return 0; + } else { + return 1; + } +} + +/* + * call-seq: + * OpenSSL::Provider.provider_names -> [provider_name, ...] + * + * Returns an array of currently loaded provider names. + */ +static VALUE +ossl_provider_s_provider_names(VALUE klass) +{ + VALUE ary = rb_ary_new(); + struct ary_with_state cbdata = { ary, 0 }; + + int result = OSSL_PROVIDER_do_all(NULL, &push_provider, (void*)&cbdata); + if (result != 1 ) { + if (cbdata.state) { + rb_jump_tag(cbdata.state); + } else { + ossl_raise(eProviderError, "Failed to load provider names"); + } + } + + return ary; +} + +/* + * call-seq: + * provider.unload -> true + * + * This method unloads this provider. + * + * if provider unload fails or already unloaded, it raises OpenSSL::Provider::ProviderError + */ +static VALUE +ossl_provider_unload(VALUE self) +{ + OSSL_PROVIDER *prov; + if (RTYPEDDATA_DATA(self) == NULL) { + ossl_raise(eProviderError, "Provider already unloaded."); + } + GetProvider(self, prov); + + int result = OSSL_PROVIDER_unload(prov); + + if (result != 1) { + ossl_raise(eProviderError, "Failed to unload provider"); + } + RTYPEDDATA_DATA(self) = NULL; + return Qtrue; +} + +/* + * call-seq: + * provider.name -> string + * + * Get the name of this provider. + * + * if this provider is already unloaded, it raises OpenSSL::Provider::ProviderError + */ +static VALUE +ossl_provider_get_name(VALUE self) +{ + OSSL_PROVIDER *prov; + if (RTYPEDDATA_DATA(self) == NULL) { + ossl_raise(eProviderError, "Provider already unloaded."); + } + GetProvider(self, prov); + + return rb_str_new2(OSSL_PROVIDER_get0_name(prov)); +} + +/* + * call-seq: + * provider.inspect -> string + * + * Pretty prints this provider. + */ +static VALUE +ossl_provider_inspect(VALUE self) +{ + OSSL_PROVIDER *prov; + if (RTYPEDDATA_DATA(self) == NULL ) { + return rb_sprintf("#<%"PRIsVALUE" unloaded provider>", rb_obj_class(self)); + } + GetProvider(self, prov); + + return rb_sprintf("#<%"PRIsVALUE" name=\"%s\">", + rb_obj_class(self), OSSL_PROVIDER_get0_name(prov)); +} + +void +Init_ossl_provider(void) +{ + cProvider = rb_define_class_under(mOSSL, "Provider", rb_cObject); + eProviderError = rb_define_class_under(cProvider, "ProviderError", eOSSLError); + + rb_undef_alloc_func(cProvider); + rb_define_singleton_method(cProvider, "load", ossl_provider_s_load, 1); + rb_define_singleton_method(cProvider, "provider_names", ossl_provider_s_provider_names, 0); + + rb_define_method(cProvider, "unload", ossl_provider_unload, 0); + rb_define_method(cProvider, "name", ossl_provider_get_name, 0); + rb_define_method(cProvider, "inspect", ossl_provider_inspect, 0); +} +#else +void +Init_ossl_provider(void) +{ +} +#endif diff --git a/ext/openssl/ossl_provider.h b/ext/openssl/ossl_provider.h new file mode 100644 index 0000000000..1d69cb1e44 --- /dev/null +++ b/ext/openssl/ossl_provider.h @@ -0,0 +1,5 @@ +#if !defined(OSSL_PROVIDER_H) +#define OSSL_PROVIDER_H + +void Init_ossl_provider(void); +#endif diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c index 3b6eaf3f47..753f8b25f7 100644 --- a/ext/openssl/ossl_rand.c +++ b/ext/openssl/ossl_rand.c @@ -1,120 +1,137 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> + * * All rights reserved. - */ -/* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -/* - * Classes - */ -VALUE mRandom; -VALUE eRandomError; - -/* - * Struct - */ - -/* - * Public - */ +static VALUE mRandom; +static VALUE eRandomError; /* - * Private + * call-seq: + * seed(str) -> str + * + * ::seed is equivalent to ::add where _entropy_ is length of _str_. */ static VALUE ossl_rand_seed(VALUE self, VALUE str) { StringValue(str); - RAND_seed(RSTRING_PTR(str), RSTRING_LEN(str)); + RAND_seed(RSTRING_PTR(str), RSTRING_LENINT(str)); return str; } /* * call-seq: - * load_random_file(filename) -> true + * add(str, entropy) -> self + * + * Mixes the bytes from _str_ into the Pseudo Random Number Generator(PRNG) + * state. + * + * Thus, if the data from _str_ are unpredictable to an adversary, this + * increases the uncertainty about the state and makes the PRNG output less + * predictable. + * + * The _entropy_ argument is (the lower bound of) an estimate of how much + * randomness is contained in _str_, measured in bytes. * + * === Example + * + * pid = $$ + * now = Time.now + * ary = [now.to_i, now.nsec, 1000, pid] + * OpenSSL::Random.add(ary.join, 0.0) + * OpenSSL::Random.seed(ary.join) */ static VALUE -ossl_rand_load_file(VALUE self, VALUE filename) +ossl_rand_add(VALUE self, VALUE str, VALUE entropy) { - SafeStringValue(filename); - - if(!RAND_load_file(RSTRING_PTR(filename), -1)) { - ossl_raise(eRandomError, NULL); - } - return Qtrue; + StringValue(str); + RAND_add(RSTRING_PTR(str), RSTRING_LENINT(str), NUM2DBL(entropy)); + + return self; } /* * call-seq: - * write_random_file(filename) -> true + * load_random_file(filename) -> true * + * Reads bytes from _filename_ and adds them to the PRNG. */ static VALUE -ossl_rand_write_file(VALUE self, VALUE filename) +ossl_rand_load_file(VALUE self, VALUE filename) { - SafeStringValue(filename); - if (RAND_write_file(RSTRING_PTR(filename)) == -1) { - ossl_raise(eRandomError, NULL); + if(!RAND_load_file(StringValueCStr(filename), -1)) { + ossl_raise(eRandomError, NULL); } return Qtrue; } /* * call-seq: - * random_bytes(length) -> aString + * write_random_file(filename) -> true * + * Writes a number of random generated bytes (currently 1024) to _filename_ + * which can be used to initialize the PRNG by calling ::load_random_file in a + * later session. */ static VALUE -ossl_rand_bytes(VALUE self, VALUE len) +ossl_rand_write_file(VALUE self, VALUE filename) { - VALUE str; - - str = rb_str_new(0, FIX2INT(len)); - if (!RAND_bytes(RSTRING_PTR(str), FIX2INT(len))) { - ossl_raise(eRandomError, NULL); + if (RAND_write_file(StringValueCStr(filename)) == -1) { + ossl_raise(eRandomError, NULL); } - - return str; + return Qtrue; } /* * call-seq: - * pseudo_bytes(length) -> aString + * random_bytes(length) -> string + * + * Generates a String with _length_ number of cryptographically strong + * pseudo-random bytes. + * + * === Example * + * OpenSSL::Random.random_bytes(12) + * #=> "..." */ static VALUE -ossl_rand_pseudo_bytes(VALUE self, VALUE len) +ossl_rand_bytes(VALUE self, VALUE len) { VALUE str; - - str = rb_str_new(0, FIX2INT(len)); - if (!RAND_pseudo_bytes(RSTRING_PTR(str), FIX2INT(len))) { - ossl_raise(eRandomError, NULL); + int n = NUM2INT(len); + int ret; + + str = rb_str_new(0, n); + ret = RAND_bytes((unsigned char *)RSTRING_PTR(str), n); + if (ret == 0) { + ossl_raise(eRandomError, "RAND_bytes"); + } else if (ret == -1) { + ossl_raise(eRandomError, "RAND_bytes is not supported"); } return str; } +#ifdef HAVE_RAND_EGD /* * call-seq: * egd(filename) -> true * + * Same as ::egd_bytes but queries 255 bytes by default. */ static VALUE ossl_rand_egd(VALUE self, VALUE filename) { - SafeStringValue(filename); - - if(!RAND_egd(RSTRING_PTR(filename))) { - ossl_raise(eRandomError, NULL); + if (RAND_egd(StringValueCStr(filename)) == -1) { + ossl_raise(eRandomError, NULL); } return Qtrue; } @@ -123,23 +140,28 @@ ossl_rand_egd(VALUE self, VALUE filename) * call-seq: * egd_bytes(filename, length) -> true * + * Queries the entropy gathering daemon EGD on socket path given by _filename_. + * + * Fetches _length_ number of bytes and uses ::add to seed the OpenSSL built-in + * PRNG. */ static VALUE ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len) { - SafeStringValue(filename); + int n = NUM2INT(len); - if (!RAND_egd_bytes(RSTRING_PTR(filename), FIX2INT(len))) { - ossl_raise(eRandomError, NULL); + if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) { + ossl_raise(eRandomError, NULL); } return Qtrue; } +#endif /* HAVE_RAND_EGD */ /* * call-seq: * status? => true | false * - * Return true if the PRNG has been seeded with enough data, false otherwise. + * Return +true+ if the PRNG has been seeded with enough data, +false+ otherwise. */ static VALUE ossl_rand_status(VALUE self) @@ -147,31 +169,25 @@ ossl_rand_status(VALUE self) return RAND_status() ? Qtrue : Qfalse; } -#define DEFMETH(class, name, func, argc) \ - rb_define_method(class, name, func, argc); \ - rb_define_singleton_method(class, name, func, argc); - /* * INIT */ void -Init_ossl_rand() +Init_ossl_rand(void) { -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); -#endif - mRandom = rb_define_module_under(mOSSL, "Random"); - + eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError); - - DEFMETH(mRandom, "seed", ossl_rand_seed, 1); - DEFMETH(mRandom, "load_random_file", ossl_rand_load_file, 1); - DEFMETH(mRandom, "write_random_file", ossl_rand_write_file, 1); - DEFMETH(mRandom, "random_bytes", ossl_rand_bytes, 1); - DEFMETH(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1); - DEFMETH(mRandom, "egd", ossl_rand_egd, 1); - DEFMETH(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2); - DEFMETH(mRandom, "status?", ossl_rand_status, 0) -} + rb_define_module_function(mRandom, "seed", ossl_rand_seed, 1); + rb_define_module_function(mRandom, "random_add", ossl_rand_add, 2); + 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); + rb_define_alias(rb_singleton_class(mRandom), "pseudo_bytes", "random_bytes"); +#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); +#endif /* HAVE_RAND_EGD */ + rb_define_module_function(mRandom, "status?", ossl_rand_status, 0); +} diff --git a/ext/openssl/ossl_rand.h b/ext/openssl/ossl_rand.h index ce2ae0d129..294986d017 100644 --- a/ext/openssl/ossl_rand.h +++ b/ext/openssl/ossl_rand.h @@ -1,20 +1,15 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_RAND_H_) #define _OSSL_RAND_H_ -extern VALUE mRandom; -extern VALUE eRandomError; - void Init_ossl_rand(void); #endif /* _OSSL_RAND_H_ */ - diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 76423b773b..630d46e43f 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1,5 +1,4 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2000-2002 GOTOU Yuuzou <gotoyuzo@notwork.org> * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> @@ -7,315 +6,252 @@ * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#include <rubysig.h> -#include <rubyio.h> -#if defined(HAVE_UNISTD_H) -# include <unistd.h> /* for read(), and write() */ -#endif +#ifndef OPENSSL_NO_SOCK +#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0])) -#define numberof(ary) (sizeof(ary)/sizeof(ary[0])) +#if !defined(OPENSSL_NO_NEXTPROTONEG) && !OSSL_IS_LIBRESSL +# define OSSL_USE_NEXTPROTONEG +#endif #ifdef _WIN32 # define TO_SOCKET(s) _get_osfhandle(s) #else -# define TO_SOCKET(s) s +# define TO_SOCKET(s) (s) #endif +#define GetSSLCTX(obj, ctx) do { \ + TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \ +} while (0) + VALUE mSSL; -VALUE eSSLError; -VALUE cSSLContext; +static VALUE eSSLError; +static VALUE cSSLContext; VALUE cSSLSocket; -#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_options(o,v) rb_iv_set((o),"@options",(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_tmp_dh_cb(o,v) rb_iv_set((o),"@tmp_dh_callback",(v)) -#define ossl_sslctx_set_sess_id_ctx(o, v) rb_iv_get((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_options(o) rb_iv_get((o),"@options") -#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_dh_cb(o) rb_iv_get((o),"@tmp_dh_callback") -#define ossl_sslctx_get_sess_id_ctx(o) rb_iv_get((o),"@session_id_context") - -static const char *ossl_sslctx_attrs[] = { - "cert", "key", "client_ca", "ca_file", "ca_path", - "timeout", "verify_mode", "verify_depth", - "verify_callback", "options", "cert_store", "extra_chain_cert", - "client_cert_cb", "tmp_dh_callback", "session_id_context", - "session_get_cb", "session_new_cb", "session_remove_cb", -}; - -#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_sync_close(o) rb_iv_get((o),"@sync_close") -#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_get_tmp_dh(o) rb_iv_get((o),"@tmp_dh") +static VALUE eSSLErrorWaitReadable; +static VALUE eSSLErrorWaitWritable; -#define ossl_ssl_set_io(o,v) rb_iv_set((o),"@io",(v)) -#define ossl_ssl_set_ctx(o,v) rb_iv_set((o),"@context",(v)) -#define ossl_ssl_set_sync_close(o,v) rb_iv_set((o),"@sync_close",(v)) -#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)) +static ID id_call, ID_callback_state, id_npn_protocols_encoded, id_each; +static VALUE sym_exception, sym_wait_readable, sym_wait_writable; -static const char *ossl_ssl_attr_readers[] = { "io", "context", }; -static const char *ossl_ssl_attrs[] = { "sync_close", }; +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_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, id_i_keylog_cb, id_i_tmp_dh_callback; +static ID id_i_io, id_i_context, id_i_hostname; -ID ID_callback_state; - -/* - * SSLContext class - */ -struct { - const char *name; - SSL_METHOD *(*func)(void); -} ossl_ssl_method_tab[] = { -#define OSSL_SSL_METHOD_ENTRY(name) { #name, name##_method } - OSSL_SSL_METHOD_ENTRY(TLSv1), - OSSL_SSL_METHOD_ENTRY(TLSv1_server), - OSSL_SSL_METHOD_ENTRY(TLSv1_client), - OSSL_SSL_METHOD_ENTRY(SSLv2), - OSSL_SSL_METHOD_ENTRY(SSLv2_server), - OSSL_SSL_METHOD_ENTRY(SSLv2_client), - OSSL_SSL_METHOD_ENTRY(SSLv3), - OSSL_SSL_METHOD_ENTRY(SSLv3_server), - OSSL_SSL_METHOD_ENTRY(SSLv3_client), - OSSL_SSL_METHOD_ENTRY(SSLv23), - OSSL_SSL_METHOD_ENTRY(SSLv23_server), - OSSL_SSL_METHOD_ENTRY(SSLv23_client), -#undef OSSL_SSL_METHOD_ENTRY -}; - -int ossl_ssl_ex_vcb_idx; -int ossl_ssl_ex_store_p; -int ossl_ssl_ex_ptr_idx; -int ossl_ssl_ex_client_cert_cb_idx; -int ossl_ssl_ex_tmp_dh_callback_idx; +static int ossl_ssl_ex_ptr_idx; +static int ossl_sslctx_ex_ptr_idx; static void -ossl_sslctx_free(SSL_CTX *ctx) +ossl_sslctx_mark(void *ptr) { - if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1) - ctx->cert_store = NULL; - SSL_CTX_free(ctx); + SSL_CTX *ctx = ptr; + rb_gc_mark((VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx)); } -static VALUE -ossl_sslctx_s_alloc(VALUE klass) +static void +ossl_sslctx_free(void *ptr) { - SSL_CTX *ctx; - - ctx = SSL_CTX_new(SSLv23_method()); - if (!ctx) { - ossl_raise(eSSLError, "SSL_CTX_new:"); - } - SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); - SSL_CTX_set_options(ctx, SSL_OP_ALL); - return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx); + SSL_CTX_free(ptr); } -/* - * call-seq: - * SSLContext.new => ctx - * SSLContext.new(:TLSv1) => ctx - * SSLContext.new("SSLv23_client") => ctx - * - * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS - */ +static const rb_data_type_t ossl_sslctx_type = { + "OpenSSL/SSL/CTX", + { + ossl_sslctx_mark, ossl_sslctx_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + static VALUE -ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self) +ossl_sslctx_s_alloc(VALUE klass) { - VALUE ssl_method; - SSL_METHOD *method = NULL; SSL_CTX *ctx; - int i; - const char *s; + long mode = 0 | + SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | + SSL_MODE_RELEASE_BUFFERS; + VALUE obj; - for(i = 0; i < numberof(ossl_sslctx_attrs); i++){ - char buf[32]; - snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]); - rb_iv_set(self, buf, Qnil); - } - if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){ - return self; - } - if(TYPE(ssl_method) == T_SYMBOL) - s = rb_id2name(SYM2ID(ssl_method)); - else - s = StringValuePtr(ssl_method); - 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 (!method) { - ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s); - } - Data_Get_Struct(self, SSL_CTX, ctx); - if (SSL_CTX_set_ssl_version(ctx, method) != 1) { - ossl_raise(eSSLError, "SSL_CTX_set_ssl_version:"); + obj = TypedData_Wrap_Struct(klass, &ossl_sslctx_type, 0); + ctx = SSL_CTX_new(TLS_method()); + if (!ctx) { + ossl_raise(eSSLError, "SSL_CTX_new"); } + SSL_CTX_set_mode(ctx, mode); + SSL_CTX_set_dh_auto(ctx, 1); + RTYPEDDATA_DATA(obj) = ctx; + SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj); - return self; + return obj; } static VALUE ossl_call_client_cert_cb(VALUE obj) { - VALUE cb, ary, cert, key; - SSL *ssl; + VALUE ctx_obj, cb, ary, cert, key; - Data_Get_Struct(obj, SSL, ssl); - cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx); - if (NIL_P(cb)) return Qfalse; - ary = rb_funcall(cb, rb_intern("call"), 1, obj); + 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; + + ary = rb_funcallv(cb, id_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; - int status, success; + VALUE obj, ret; obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); - success = rb_protect((VALUE(*)_((VALUE)))ossl_call_client_cert_cb, - obj, &status); - if (status || !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) +struct tmp_dh_callback_args { + VALUE ssl_obj; + int is_export; + int keylength; +}; + static VALUE -ossl_call_tmp_dh_callback(VALUE *args) +ossl_call_tmp_dh_callback(VALUE arg) { - SSL *ssl; - VALUE cb, dh; - EVP_PKEY *pkey; - - Data_Get_Struct(args[0], SSL, ssl); - cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx); - if (NIL_P(cb)) return Qfalse; - dh = rb_funcall(cb, rb_intern("call"), 3, args[0], args[1], args[2]); - pkey = GetPKeyPtr(dh); - if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) return Qfalse; - ossl_ssl_set_tmp_dh(args[0], dh); - - return Qtrue; + struct tmp_dh_callback_args *args = (struct tmp_dh_callback_args *)arg; + VALUE ctx_obj, cb, obj; + const DH *dh; + + ctx_obj = rb_attr_get(args->ssl_obj, id_i_context); + cb = rb_attr_get(ctx_obj, id_i_tmp_dh_callback); + if (NIL_P(cb)) + return (VALUE)NULL; + + obj = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export), + INT2NUM(args->keylength)); + // TODO: We should riase if obj is not DH + dh = EVP_PKEY_get0_DH(GetPKeyPtr(obj)); + if (!dh) + ossl_clear_error(); + + return (VALUE)dh; } -static DH* +static DH * ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength) { - VALUE args[3]; - int status, success; - - args[0] = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); - args[1] = INT2FIX(is_export); - args[2] = INT2FIX(keylength); - success = rb_protect((VALUE(*)_((VALUE)))ossl_call_tmp_dh_callback, - (VALUE)args, &status); - if (status || !success) return NULL; - - return GetPKeyPtr(ossl_ssl_get_tmp_dh(args[0]))->pkey.dh; + int state; + VALUE rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + struct tmp_dh_callback_args args = {rb_ssl, is_export, keylength}; + VALUE ret = rb_protect(ossl_call_tmp_dh_callback, (VALUE)&args, &state); + if (state) { + rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state)); + return NULL; + } + return (DH *)ret; } +#endif /* OPENSSL_NO_DH */ -static DH* -ossl_default_tmp_dh_callback(SSL *ssl, int is_export, int keylength) +static VALUE +call_verify_certificate_identity(VALUE ctx_v) { - switch(keylength){ - case 512: - return OSSL_DEFAULT_DH_512; - case 1024: - return OSSL_DEFAULT_DH_1024; + X509_STORE_CTX *ctx = (X509_STORE_CTX *)ctx_v; + SSL *ssl; + VALUE ssl_obj, hostname, cert_obj; + + 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); + + if (!RTEST(hostname)) { + rb_warning("verify_hostname requires hostname to be set"); + return Qtrue; } - return NULL; + + 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 /* OPENSSL_NO_DH */ 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_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); + cb = rb_attr_get(sslctx_obj, id_i_verify_callback); + 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; + } + if (ret != Qtrue) { + preverify_ok = 0; + X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH); + } + } + + return ossl_verify_cb_call(cb, preverify_ok, ctx); } static VALUE ossl_call_session_get_cb(VALUE ary) { - VALUE ssl_obj, sslctx_obj, cb, ret; - + VALUE ssl_obj, cb; + 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, "@session_get_cb"); + cb = rb_funcall(ssl_obj, rb_intern("session_get_cb"), 0); if (NIL_P(cb)) return Qnil; - return rb_funcall(cb, rb_intern("call"), 1, ary); + return rb_funcallv(cb, id_call, 1, &ary); } -/* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */ static SSL_SESSION * -ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy) +ossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy) { VALUE ary, ssl_obj, ret_obj; SSL_SESSION *sess; - void *ptr; int state = 0; OSSL_Debug("SSL SESSION get callback entered"); - if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) - return NULL; - ssl_obj = (VALUE)ptr; + ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); ary = rb_ary_new2(2); rb_ary_push(ary, ssl_obj); - rb_ary_push(ary, rb_str_new(buf, len)); + rb_ary_push(ary, rb_str_new((const char *)buf, len)); - ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state); + ret_obj = rb_protect(ossl_call_session_get_cb, ary, &state); if (state) { rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); return NULL; @@ -323,7 +259,7 @@ ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy) if (!rb_obj_is_instance_of(ret_obj, cSSLSession)) return NULL; - SafeGetSSLSession(ret_obj, sess); + GetSSLSession(ret_obj, sess); *copy = 1; return sess; @@ -332,84 +268,137 @@ ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy) static VALUE ossl_call_session_new_cb(VALUE ary) { - VALUE ssl_obj, sslctx_obj, cb, ret; - + VALUE ssl_obj, cb; + 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, "@session_new_cb"); + cb = rb_funcall(ssl_obj, rb_intern("session_new_cb"), 0); if (NIL_P(cb)) return Qnil; - return rb_funcall(cb, rb_intern("call"), 1, ary); + return rb_funcallv(cb, id_call, 1, &ary); } /* return 1 normal. return 0 removes the session */ static int ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess) { - VALUE ary, ssl_obj, sess_obj, ret_obj; - void *ptr; + VALUE ary, ssl_obj, sess_obj; int state = 0; OSSL_Debug("SSL SESSION new callback entered"); - if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) - return 1; - ssl_obj = (VALUE)ptr; + ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); 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, ssl_obj); rb_ary_push(ary, sess_obj); - ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); + rb_protect(ossl_call_session_new_cb, ary, &state); if (state) { rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); - return 0; /* what should be returned here??? */ } - return RTEST(ret_obj) ? 1 : 0; + /* + * return 0 which means to OpenSSL that the session is still + * valid (since we created Ruby Session object) and was not freed by us + * with SSL_SESSION_free(). Call SSLContext#remove_session(sess) in + * session_get_cb block if you don't want OpenSSL to cache the session + * internally. + */ + return 0; } +#if !OSSL_IS_LIBRESSL +/* + * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements + * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see + * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6). + */ + +struct ossl_call_keylog_cb_args { + VALUE ssl_obj; + const char * line; +}; + +static VALUE +ossl_call_keylog_cb(VALUE args_v) +{ + VALUE sslctx_obj, cb, line_v; + struct ossl_call_keylog_cb_args *args = (struct ossl_call_keylog_cb_args *) args_v; + + sslctx_obj = rb_attr_get(args->ssl_obj, id_i_context); + + cb = rb_attr_get(sslctx_obj, id_i_keylog_cb); + if (NIL_P(cb)) return Qnil; + + line_v = rb_str_new_cstr(args->line); + + return rb_funcall(cb, id_call, 2, args->ssl_obj, line_v); +} + +static void +ossl_sslctx_keylog_cb(const SSL *ssl, const char *line) +{ + VALUE ssl_obj; + struct ossl_call_keylog_cb_args args; + int state = 0; + + OSSL_Debug("SSL keylog callback entered"); + + ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + args.ssl_obj = ssl_obj; + args.line = line; + + rb_protect(ossl_call_keylog_cb, (VALUE)&args, &state); + if (state) { + rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); + } +} +#endif + static VALUE ossl_call_session_remove_cb(VALUE ary) { - VALUE sslctx_obj, cb, ret; - + VALUE sslctx_obj, cb; + 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); + return rb_funcallv(cb, id_call, 1, &ary); } static void ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) { - VALUE ary, sslctx_obj, sess_obj, ret_obj; - void *ptr; + VALUE ary, sslctx_obj, sess_obj; 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; + sslctx_obj = (VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx); 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); - ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); + rb_protect(ossl_call_session_remove_cb, ary, &state); if (state) { /* the SSL_CTX is frozen, nowhere to save state. @@ -420,153 +409,538 @@ ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) } static VALUE -ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg) +ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg)) { X509 *x509; SSL_CTX *ctx; - Data_Get_Struct(arg, SSL_CTX, ctx); + GetSSLCTX(arg, ctx); x509 = DupX509CertPtr(i); - if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){ - ossl_raise(eSSLError, NULL); + if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) { + X509_free(x509); + ossl_raise(eSSLError, "SSL_CTX_add_extra_chain_cert"); } return i; } +static VALUE ossl_sslctx_setup(VALUE self); + +static VALUE +ossl_call_servername_cb(VALUE arg) +{ + SSL *ssl = (void *)arg; + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if (!servername) + return Qnil; + + VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + VALUE sslctx_obj = rb_attr_get(ssl_obj, id_i_context); + VALUE cb = rb_attr_get(sslctx_obj, id_i_servername_cb); + VALUE ary = rb_assoc_new(ssl_obj, rb_str_new_cstr(servername)); + + VALUE ret_obj = rb_funcallv(cb, id_call, 1, &ary); + if (rb_obj_is_kind_of(ret_obj, cSSLContext)) { + SSL_CTX *ctx2; + ossl_sslctx_setup(ret_obj); + GetSSLCTX(ret_obj, ctx2); + if (!SSL_set_SSL_CTX(ssl, ctx2)) + ossl_raise(eSSLError, "SSL_set_SSL_CTX"); + 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"); + } + + return Qnil; +} + +static int +ssl_servername_cb(SSL *ssl, int *ad, void *arg) +{ + int state; + + rb_protect(ossl_call_servername_cb, (VALUE)ssl, &state); + if (state) { + VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + return SSL_TLSEXT_ERR_OK; +} + +static void +ssl_renegotiation_cb(const SSL *ssl) +{ + VALUE ssl_obj, sslctx_obj, cb; + + ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + 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; + + rb_funcallv(cb, id_call, 1, &ssl_obj); +} + +static VALUE +ssl_npn_encode_protocol_i(RB_BLOCK_CALL_FUNC_ARGLIST(cur, encoded)) +{ + int len = RSTRING_LENINT(cur); + char len_byte; + if (len < 1 || len > 255) + ossl_raise(eSSLError, "Advertised protocol must have length 1..255"); + /* Encode the length byte */ + len_byte = len; + rb_str_buf_cat(encoded, &len_byte, 1); + rb_str_buf_cat(encoded, RSTRING_PTR(cur), len); + return Qnil; +} + +static VALUE +ssl_encode_npn_protocols(VALUE protocols) +{ + VALUE encoded = rb_str_new(NULL, 0); + rb_block_call(protocols, id_each, 0, 0, ssl_npn_encode_protocol_i, encoded); + return encoded; +} + +struct npn_select_cb_common_args { + VALUE cb; + const unsigned char *in; + unsigned inlen; +}; + +static VALUE +npn_select_cb_common_i(VALUE tmp) +{ + struct npn_select_cb_common_args *args = (void *)tmp; + const unsigned char *in = args->in, *in_end = in + args->inlen; + unsigned char l; + long len; + VALUE selected, protocols = rb_ary_new(); + + /* assume OpenSSL verifies this format */ + /* The format is len_1|proto_1|...|len_n|proto_n */ + while (in < in_end) { + l = *in++; + rb_ary_push(protocols, rb_str_new((const char *)in, l)); + in += l; + } + + selected = rb_funcallv(args->cb, id_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)RSTRING_LEN(selected); + + return SSL_TLSEXT_ERR_OK; +} + +#ifdef OSSL_USE_NEXTPROTONEG +static int +ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen, + void *arg) +{ + VALUE protocols = rb_attr_get((VALUE)arg, id_npn_protocols_encoded); + + *out = (const unsigned char *) RSTRING_PTR(protocols); + *outlen = RSTRING_LENINT(protocols); + + return SSL_TLSEXT_ERR_OK; +} + +static int +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_attr_get(sslctx_obj, id_i_npn_select_cb); + + return ssl_npn_select_cb_common(ssl, cb, (const unsigned char **)out, + outlen, in, inlen); +} +#endif + +static int +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_attr_get(sslctx_obj, id_i_alpn_select_cb); + + return ssl_npn_select_cb_common(ssl, cb, out, outlen, in, inlen); +} + +/* 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 is_server = SSL_is_server((SSL *)ssl); + + if (is_server && where & SSL_CB_HANDSHAKE_START) { + ssl_renegotiation_cb(ssl); + } +} + +/* + * call-seq: + * ctx.options -> integer + * + * Gets various \OpenSSL options. + */ +static VALUE +ossl_sslctx_get_options(VALUE self) +{ + SSL_CTX *ctx; + GetSSLCTX(self, ctx); + /* + * Do explicit cast because SSL_CTX_get_options() returned (signed) long in + * OpenSSL before 1.1.0. + */ + return ULONG2NUM((unsigned long)SSL_CTX_get_options(ctx)); +} + +/* + * call-seq: + * ctx.options = integer + * + * Sets various \OpenSSL options. The options are a bit field and can be + * combined with the bitwise OR operator (<tt>|</tt>). Available options are + * defined as constants in OpenSSL::SSL that begin with +OP_+. + * + * For backwards compatibility, passing +nil+ has the same effect as passing + * OpenSSL::SSL::OP_ALL. + * + * See also man page SSL_CTX_set_options(3). + */ +static VALUE +ossl_sslctx_set_options(VALUE self, VALUE options) +{ + SSL_CTX *ctx; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + + SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx)); + + if (NIL_P(options)) { + SSL_CTX_set_options(ctx, SSL_OP_ALL); + } else { + SSL_CTX_set_options(ctx, NUM2ULONG(options)); + } + + return self; +} + +/* + * call-seq: + * ctx.setup => Qtrue # first time + * ctx.setup => nil # thereafter + * + * This method is called automatically when a new SSLSocket is created. + * However, it is not thread-safe and must be called before creating + * SSLSocket objects in a multi-threaded program. + */ static VALUE 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 i, verify_mode; + int verify_mode; + long i; VALUE val; if(OBJ_FROZEN(self)) return Qnil; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); #if !defined(OPENSSL_NO_DH) - if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ - SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); - } - else{ - rb_warning("using default DH parameters."); - SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback); + if (!NIL_P(rb_attr_get(self, id_i_tmp_dh_callback))) { + SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); + SSL_CTX_set_dh_auto(ctx, 0); } #endif - SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self); - val = ossl_sslctx_get_cert_store(self); - if(!NIL_P(val)){ - /* - * 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 */ +#if !defined(OPENSSL_IS_AWSLC) /* AWS-LC has no support for TLS 1.3 PHA. */ + SSL_CTX_set_post_handshake_auth(ctx, 1); +#endif + + 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); - SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); + X509_STORE_up_ref(store); } - 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); + 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 */ - ossl_raise(eSSLError, "SSL_CTX_use_certificate:"); + ossl_raise(eSSLError, "SSL_CTX_use_certificate"); } if (!SSL_CTX_use_PrivateKey(ctx, key)) { /* Adds a ref => Safe to FREE */ - ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:"); + ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey"); } if (!SSL_CTX_check_private_key(ctx)) { - ossl_raise(eSSLError, "SSL_CTX_check_private_key:"); + ossl_raise(eSSLError, "SSL_CTX_check_private_key"); } } - val = ossl_sslctx_get_client_ca(self); + val = rb_attr_get(self, id_i_client_ca); if(!NIL_P(val)){ - if(TYPE(val) == T_ARRAY){ - for(i = 0; i < RARRAY_LEN(val); i++){ - client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]); - if (!SSL_CTX_add_client_CA(ctx, client_ca)){ - /* Copies X509_NAME => FREE it. */ - ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); - } - } + if (RB_TYPE_P(val, T_ARRAY)) { + for(i = 0; i < RARRAY_LEN(val); i++){ + client_ca = GetX509CertPtr(RARRAY_AREF(val, i)); + if (!SSL_CTX_add_client_CA(ctx, client_ca)){ + /* Copies X509_NAME => FREE it. */ + ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); + } + } } - else{ - client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ + else{ + client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ if (!SSL_CTX_add_client_CA(ctx, client_ca)){ - /* Copies X509_NAME => FREE it. */ - ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); + /* Copies X509_NAME => FREE it. */ + ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } - } + } } - 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); - if(ca_file || ca_path){ - if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) - rb_warning("can't set verify locations"); + 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); +#ifdef HAVE_SSL_CTX_LOAD_VERIFY_FILE + if (ca_file && !SSL_CTX_load_verify_file(ctx, ca_file)) + ossl_raise(eSSLError, "SSL_CTX_load_verify_file"); + if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path)) + ossl_raise(eSSLError, "SSL_CTX_load_verify_dir"); +#else + if (ca_file || ca_path) { + if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) + ossl_raise(eSSLError, "SSL_CTX_load_verify_locations"); } +#endif - 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))) - SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); + 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); - if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); + val = rb_attr_get(self, id_i_verify_depth); + if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val)); + +#ifdef OSSL_USE_NEXTPROTONEG + val = rb_attr_get(self, id_i_npn_protocols); + if (!NIL_P(val)) { + 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 *)self); + OSSL_Debug("SSL NPN advertise callback added"); + } + 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 + + val = rb_attr_get(self, id_i_alpn_protocols); + if (!NIL_P(val)) { + VALUE rprotos = ssl_encode_npn_protocols(val); + + /* 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_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"); + } - val = ossl_sslctx_get_options(self); - if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val)); 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, RSTRING_PTR(val), - RSTRING_LEN(val))){ - ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); - } + StringValue(val); + if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val), + RSTRING_LENINT(val))){ + ossl_raise(eSSLError, "SSL_CTX_set_session_id_context"); + } } - if (RTEST(rb_iv_get(self, "@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_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"))) { - SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); - OSSL_Debug("SSL SESSION new callback added"); + 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"))) { - SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); - OSSL_Debug("SSL SESSION remove callback added"); + 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"); + } + + 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"); + } + +#if !OSSL_IS_LIBRESSL + /* + * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements + * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see + * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6). + */ + if (RTEST(rb_attr_get(self, id_i_keylog_cb))) { + SSL_CTX_set_keylog_callback(ctx, ossl_sslctx_keylog_cb); + OSSL_Debug("SSL keylog callback added"); } +#endif + return Qtrue; } +static int +parse_proto_version(VALUE str) +{ + int i; + static const struct { + const char *name; + int version; + } map[] = { + { "SSL2", SSL2_VERSION }, + { "SSL3", SSL3_VERSION }, + { "TLS1", TLS1_VERSION }, + { "TLS1_1", TLS1_1_VERSION }, + { "TLS1_2", TLS1_2_VERSION }, + { "TLS1_3", TLS1_3_VERSION }, + }; + + if (NIL_P(str)) + return 0; + if (RB_INTEGER_TYPE_P(str)) + return NUM2INT(str); + + if (SYMBOL_P(str)) + str = rb_sym2str(str); + StringValue(str); + for (i = 0; i < numberof(map); i++) + if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str))) + return map[i].version; + rb_raise(rb_eArgError, "unrecognized version %+"PRIsVALUE, str); +} + +/* + * call-seq: + * ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION + * ctx.min_version = :TLS1_2 + * ctx.min_version = nil + * + * Sets the lower bound on the supported SSL/TLS protocol version. The + * version may be specified by an integer constant named + * OpenSSL::SSL::*_VERSION, a Symbol, or +nil+ which means "any version". + * + * === Example + * ctx = OpenSSL::SSL::SSLContext.new + * ctx.min_version = OpenSSL::SSL::TLS1_1_VERSION + * ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + * + * sock = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx) + * sock.connect # Initiates a connection using either TLS 1.1 or TLS 1.2 + */ +static VALUE +ossl_sslctx_set_min_version(VALUE self, VALUE v) +{ + SSL_CTX *ctx; + int version; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + version = parse_proto_version(v); + + if (!SSL_CTX_set_min_proto_version(ctx, version)) + ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version"); + return v; +} + +/* + * call-seq: + * ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + * ctx.max_version = :TLS1_2 + * ctx.max_version = nil + * + * Sets the upper bound of the supported SSL/TLS protocol version. See + * #min_version= for the possible values. + */ static VALUE -ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) +ossl_sslctx_set_max_version(VALUE self, VALUE v) +{ + SSL_CTX *ctx; + int version; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + version = parse_proto_version(v); + + if (!SSL_CTX_set_max_proto_version(ctx, version)) + ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version"); + return v; +} + +static VALUE +ossl_ssl_cipher_to_ary(const SSL_CIPHER *cipher) { VALUE ary; int bits, alg_bits; @@ -575,8 +949,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; } @@ -584,56 +958,42 @@ ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) /* * call-seq: * ctx.ciphers => [[name, version, bits, alg_bits], ...] + * + * 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; - Data_Get_Struct(self, SSL_CTX, ctx); - if(!ctx){ - rb_warning("SSL_CTX is not initialized."); - return Qnil; - } - ciphers = ctx->cipher_list; - + GetSSLCTX(self, ctx); + ciphers = SSL_CTX_get_ciphers(ctx); if (!ciphers) return rb_ary_new(); - num = sk_num((STACK*)ciphers); + num = sk_SSL_CIPHER_num(ciphers); ary = rb_ary_new2(num); for(i = 0; i < num; i++){ - cipher = (SSL_CIPHER*)sk_value((STACK*)ciphers, i); + cipher = sk_SSL_CIPHER_value(ciphers, i); rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher)); } return ary; } -/* - * call-seq: - * ctx.ciphers = "cipher1:cipher2:..." - * ctx.ciphers = [name, ...] - * ctx.ciphers = [[name, version, bits, alg_bits], ...] - */ static VALUE -ossl_sslctx_set_ciphers(VALUE self, VALUE v) +build_cipher_string(VALUE v) { - SSL_CTX *ctx; VALUE str, elem; - int i; - rb_check_frozen(self); - if (NIL_P(v)) - return v; - else if (TYPE(v) == T_ARRAY) { + if (RB_TYPE_P(v, T_ARRAY)) { str = rb_str_new(0, 0); - for (i = 0; i < RARRAY_LEN(v); i++) { + for (long i = 0; i < RARRAY_LEN(v); i++) { elem = rb_ary_entry(v, i); - if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0); + if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0); elem = rb_String(elem); rb_str_append(str, elem); if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":"); @@ -643,23 +1003,374 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) StringValue(str); } - Data_Get_Struct(self, SSL_CTX, ctx); - if(!ctx){ - ossl_raise(eSSLError, "SSL_CTX is not initialized."); - return Qnil; - } - if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) { - ossl_raise(eSSLError, "SSL_CTX_set_cipher_list:"); - } + return str; +} + +/* + * call-seq: + * ctx.ciphers = "cipher1:cipher2:..." + * ctx.ciphers = [name, ...] + * ctx.ciphers = [[name, version, bits, alg_bits], ...] + * + * Sets the list of available cipher suites for TLS 1.2 and below for this + * context. + * + * Note in a server context some ciphers require the appropriate certificates. + * For example, an RSA cipher suite can only be chosen when an RSA certificate + * is available. + * + * This method does not affect TLS 1.3 connections. See also #ciphersuites=. + */ +static VALUE +ossl_sslctx_set_ciphers(VALUE self, VALUE v) +{ + SSL_CTX *ctx; + VALUE str; + + rb_check_frozen(self); + // Assigning nil is a no-op for compatibility + if (NIL_P(v)) + return v; + + str = build_cipher_string(v); + + GetSSLCTX(self, ctx); + if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) + ossl_raise(eSSLError, "SSL_CTX_set_cipher_list"); return v; } +/* + * call-seq: + * ctx.ciphersuites = "cipher1:cipher2:..." + * ctx.ciphersuites = [name, ...] + * + * Sets the list of available TLS 1.3 cipher suites for this context. + */ +static VALUE +ossl_sslctx_set_ciphersuites(VALUE self, VALUE v) +{ + SSL_CTX *ctx; + VALUE str; + + rb_check_frozen(self); + // Assigning nil is a no-op for compatibility + if (NIL_P(v)) + return v; + + str = build_cipher_string(v); + + GetSSLCTX(self, ctx); + if (!SSL_CTX_set_ciphersuites(ctx, StringValueCStr(str))) + ossl_raise(eSSLError, "SSL_CTX_set_ciphersuites"); + + return v; +} + +#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST +/* + * call-seq: + * ctx.sigalgs = "sigalg1:sigalg2:..." + * + * Sets the list of "supported signature algorithms" for this context. + * + * For a TLS client, the list is used in the "signature_algorithms" extension + * in the ClientHello message. For a server, the list is used by OpenSSL to + * determine the set of shared signature algorithms. OpenSSL will pick the most + * appropriate one from it. + * + * See also #client_sigalgs= for the client authentication equivalent. + */ +static VALUE +ossl_sslctx_set_sigalgs(VALUE self, VALUE v) +{ + SSL_CTX *ctx; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + + if (!SSL_CTX_set1_sigalgs_list(ctx, StringValueCStr(v))) + ossl_raise(eSSLError, "SSL_CTX_set1_sigalgs_list"); + + return v; +} +#endif + +#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST +/* + * call-seq: + * ctx.client_sigalgs = "sigalg1:sigalg2:..." + * + * Sets the list of "supported signature algorithms" for client authentication + * for this context. + * + * For a TLS server, the list is sent to the client as part of the + * CertificateRequest message. + * + * See also #sigalgs= for the server authentication equivalent. + */ +static VALUE +ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v) +{ + SSL_CTX *ctx; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + + if (!SSL_CTX_set1_client_sigalgs_list(ctx, StringValueCStr(v))) + ossl_raise(eSSLError, "SSL_CTX_set1_client_sigalgs_list"); + + return v; +} +#endif + +#ifndef OPENSSL_NO_DH +/* + * call-seq: + * ctx.tmp_dh = pkey + * + * Sets DH parameters used for ephemeral DH key exchange. This is relevant for + * servers only. + * + * +pkey+ is an instance of OpenSSL::PKey::DH. Note that key components + * contained in the key object, if any, are ignored. The server will always + * generate a new key pair for each handshake. + * + * Added in version 3.0. See also the man page SSL_CTX_set0_tmp_dh_pkey(3). + * + * Example: + * ctx = OpenSSL::SSL::SSLContext.new + * ctx.tmp_dh = OpenSSL::DH.generate(2048) + * svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx) + * Thread.new { svr.accept } + */ +static VALUE +ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg) +{ + SSL_CTX *ctx; + EVP_PKEY *pkey; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + pkey = GetPKeyPtr(arg); + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) + rb_raise(eSSLError, "invalid pkey type %s (expected DH)", + OBJ_nid2sn(EVP_PKEY_base_id(pkey))); +#ifdef HAVE_SSL_CTX_SET0_TMP_DH_PKEY + if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey)) + ossl_raise(eSSLError, "SSL_CTX_set0_tmp_dh_pkey"); + EVP_PKEY_up_ref(pkey); +#else + if (!SSL_CTX_set_tmp_dh(ctx, EVP_PKEY_get0_DH(pkey))) + ossl_raise(eSSLError, "SSL_CTX_set_tmp_dh"); +#endif + + // Turn off the "auto" DH parameters set by ossl_sslctx_s_alloc() + SSL_CTX_set_dh_auto(ctx, 0); + + return arg; +} +#endif + +/* + * call-seq: + * ctx.groups = groups_list + * ctx.ecdh_curves = groups_list + * + * Sets the list of supported groups for key agreement for this context. + * + * For a TLS client, the list is directly used in the "supported_groups" + * extension. For a server, the list is used by OpenSSL to determine the set of + * shared supported groups. OpenSSL will pick the most appropriate one from it. + * + * #ecdh_curves= is a deprecated alias for #groups=. + * + * See also the man page SSL_CTX_set1_groups_list(3). + * + * === Example + * ctx1 = OpenSSL::SSL::SSLContext.new + * ctx1.groups = "X25519:P-256:P-224" + * svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1) + * Thread.new { svr.accept } + * + * ctx2 = OpenSSL::SSL::SSLContext.new + * ctx2.groups = "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_groups(VALUE self, VALUE arg) +{ + SSL_CTX *ctx; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + StringValueCStr(arg); + + if (!SSL_CTX_set1_groups_list(ctx, RSTRING_PTR(arg))) + ossl_raise(eSSLError, "SSL_CTX_set1_groups_list"); + return arg; +} + +/* + * 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); + + return INT2NUM(SSL_CTX_get_security_level(ctx)); +} + +/* + * 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); + + SSL_CTX_set_security_level(ctx, NUM2INT(value)); + + return value; +} + +#ifdef SSL_MODE_SEND_FALLBACK_SCSV +/* + * call-seq: + * ctx.enable_fallback_scsv() => nil + * + * Activate TLS_FALLBACK_SCSV for this context. + * See RFC 7507. + */ +static VALUE +ossl_sslctx_enable_fallback_scsv(VALUE self) +{ + SSL_CTX *ctx; + + GetSSLCTX(self, ctx); + SSL_CTX_set_mode(ctx, SSL_MODE_SEND_FALLBACK_SCSV); + + return Qnil; +} +#endif + +/* + * call-seq: + * ctx.add_certificate(certificate, pkey [, extra_certs]) -> self + * + * Adds a certificate to the context. _pkey_ must be a corresponding private + * key with _certificate_. + * + * Multiple certificates with different public key type can be added by + * repeated calls of this method, and OpenSSL will choose the most appropriate + * certificate during the handshake. + * + * #cert=, #key=, and #extra_chain_cert= are old accessor methods for setting + * certificate and internally call this method. + * + * === Parameters + * _certificate_:: + * A certificate. An instance of OpenSSL::X509::Certificate. + * _pkey_:: + * The private key for _certificate_. An instance of OpenSSL::PKey::PKey. + * _extra_certs_:: + * Optional. An array of OpenSSL::X509::Certificate. When sending a + * certificate chain, the certificates specified by this are sent following + * _certificate_, in the order in the array. + * + * === Example + * rsa_cert = OpenSSL::X509::Certificate.new(...) + * rsa_pkey = OpenSSL::PKey.read(...) + * ca_intermediate_cert = OpenSSL::X509::Certificate.new(...) + * ctx.add_certificate(rsa_cert, rsa_pkey, [ca_intermediate_cert]) + * + * ecdsa_cert = ... + * ecdsa_pkey = ... + * another_ca_cert = ... + * ctx.add_certificate(ecdsa_cert, ecdsa_pkey, [another_ca_cert]) + */ +static VALUE +ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self) +{ + VALUE cert, key, extra_chain_ary; + SSL_CTX *ctx; + X509 *x509; + STACK_OF(X509) *extra_chain = NULL; + EVP_PKEY *pkey, *pub_pkey; + + GetSSLCTX(self, ctx); + rb_scan_args(argc, argv, "21", &cert, &key, &extra_chain_ary); + rb_check_frozen(self); + x509 = GetX509CertPtr(cert); + pkey = GetPrivPKeyPtr(key); + + /* + * The reference counter is bumped, and decremented immediately. + * X509_get0_pubkey() is only available in OpenSSL >= 1.1.0. + */ + pub_pkey = X509_get_pubkey(x509); + EVP_PKEY_free(pub_pkey); + if (!pub_pkey) + rb_raise(rb_eArgError, "certificate does not contain public key"); + if (EVP_PKEY_eq(pub_pkey, pkey) != 1) + rb_raise(rb_eArgError, "public key mismatch"); + + if (argc >= 3) + extra_chain = ossl_x509_ary2sk(extra_chain_ary); + + if (!SSL_CTX_use_certificate(ctx, x509)) { + sk_X509_pop_free(extra_chain, X509_free); + ossl_raise(eSSLError, "SSL_CTX_use_certificate"); + } + if (!SSL_CTX_use_PrivateKey(ctx, pkey)) { + sk_X509_pop_free(extra_chain, X509_free); + ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey"); + } + if (extra_chain && !SSL_CTX_set0_chain(ctx, extra_chain)) { + sk_X509_pop_free(extra_chain, X509_free); + ossl_raise(eSSLError, "SSL_CTX_set0_chain"); + } + return self; +} /* * call-seq: * ctx.session_add(session) -> true | false * + * Adds _session_ to the session cache. */ static VALUE ossl_sslctx_session_add(VALUE self, VALUE arg) @@ -667,8 +1378,8 @@ ossl_sslctx_session_add(VALUE self, VALUE arg) SSL_CTX *ctx; SSL_SESSION *sess; - Data_Get_Struct(self, SSL_CTX, ctx); - SafeGetSSLSession(arg, sess); + GetSSLCTX(self, ctx); + GetSSLSession(arg, sess); return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse; } @@ -677,6 +1388,7 @@ ossl_sslctx_session_add(VALUE self, VALUE arg) * call-seq: * ctx.session_remove(session) -> true | false * + * Removes _session_ from the session cache. */ static VALUE ossl_sslctx_session_remove(VALUE self, VALUE arg) @@ -684,38 +1396,42 @@ ossl_sslctx_session_remove(VALUE self, VALUE arg) SSL_CTX *ctx; SSL_SESSION *sess; - Data_Get_Struct(self, SSL_CTX, ctx); - SafeGetSSLSession(arg, sess); + GetSSLCTX(self, ctx); + GetSSLSession(arg, sess); return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse; } /* * call-seq: - * ctx.session_cache_mode -> integer + * ctx.session_cache_mode -> Integer * + * The current session cache mode. */ static VALUE ossl_sslctx_get_session_cache_mode(VALUE self) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx)); } /* * call-seq: - * ctx.session_cache_mode=(integer) -> integer + * ctx.session_cache_mode=(integer) -> Integer * + * Sets the SSL session cache mode. Bitwise-or together the desired + * SESSION_CACHE_* constants to set. See SSL_CTX_set_session_cache_mode(3) for + * details. */ static VALUE ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg)); @@ -724,30 +1440,34 @@ ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg) /* * call-seq: - * ctx.session_cache_size -> integer + * ctx.session_cache_size -> Integer * + * Returns the current session cache size. Zero is used to represent an + * unlimited cache size. */ static VALUE ossl_sslctx_get_session_cache_size(VALUE self) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx)); } /* * call-seq: - * ctx.session_cache_size=(integer) -> integer + * ctx.session_cache_size=(integer) -> Integer * + * Sets the session cache size. Returns the previously valid session cache + * size. Zero is used to represent an unlimited session cache size. */ static VALUE ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg) { SSL_CTX *ctx; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg)); @@ -758,6 +1478,23 @@ ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg) * call-seq: * ctx.session_cache_stats -> Hash * + * Returns a Hash containing the following keys: + * + * :accept:: Number of started SSL/TLS handshakes in server mode + * :accept_good:: Number of established SSL/TLS sessions in server mode + * :accept_renegotiate:: Number of start renegotiations in server mode + * :cache_full:: Number of sessions that were removed due to cache overflow + * :cache_hits:: Number of successfully reused connections + * :cache_misses:: Number of sessions proposed by clients that were not found + * in the cache + * :cache_num:: Number of sessions in the internal session cache + * :cb_hits:: Number of sessions retrieved from the external cache in server + * mode + * :connect:: Number of started SSL/TLS handshakes in client mode + * :connect_good:: Number of established SSL/TLS sessions in client mode + * :connect_renegotiate:: Number of start renegotiations in client mode + * :timeouts:: Number of sessions proposed by clients that were found in the + * cache but had expired due to timeouts */ static VALUE ossl_sslctx_get_session_cache_stats(VALUE self) @@ -765,21 +1502,21 @@ ossl_sslctx_get_session_cache_stats(VALUE self) SSL_CTX *ctx; VALUE hash; - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); hash = rb_hash_new(); - rb_hash_aset(hash, rb_str_new2("cache_num"), LONG2NUM(SSL_CTX_sess_number(ctx))); - rb_hash_aset(hash, rb_str_new2("connect"), LONG2NUM(SSL_CTX_sess_connect(ctx))); - rb_hash_aset(hash, rb_str_new2("connect_good"), LONG2NUM(SSL_CTX_sess_connect_good(ctx))); - rb_hash_aset(hash, rb_str_new2("connect_renegotiate"), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx))); - rb_hash_aset(hash, rb_str_new2("accept"), LONG2NUM(SSL_CTX_sess_accept(ctx))); - rb_hash_aset(hash, rb_str_new2("accept_good"), LONG2NUM(SSL_CTX_sess_accept_good(ctx))); - rb_hash_aset(hash, rb_str_new2("accept_renegotiate"), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx))); - rb_hash_aset(hash, rb_str_new2("cache_hits"), LONG2NUM(SSL_CTX_sess_hits(ctx))); - rb_hash_aset(hash, rb_str_new2("cb_hits"), LONG2NUM(SSL_CTX_sess_cb_hits(ctx))); - rb_hash_aset(hash, rb_str_new2("cache_misses"), LONG2NUM(SSL_CTX_sess_misses(ctx))); - rb_hash_aset(hash, rb_str_new2("cache_full"), LONG2NUM(SSL_CTX_sess_cache_full(ctx))); - rb_hash_aset(hash, rb_str_new2("timeouts"), LONG2NUM(SSL_CTX_sess_timeouts(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx))); + rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx))); return hash; } @@ -787,8 +1524,9 @@ ossl_sslctx_get_session_cache_stats(VALUE self) /* * call-seq: - * ctx.flush_sessions(time | nil) -> self + * ctx.flush_sessions(time) -> self * + * Removes sessions in the internal cache that have expired at _time_. */ static VALUE ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) @@ -796,21 +1534,20 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) VALUE arg1; SSL_CTX *ctx; time_t tm = 0; - int cb_state; rb_scan_args(argc, argv, "01", &arg1); - Data_Get_Struct(self, SSL_CTX, ctx); + GetSSLCTX(self, ctx); if (NIL_P(arg1)) { tm = time(0); } else if (rb_obj_is_instance_of(arg1, rb_cTime)) { tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0)); } else { - rb_raise(rb_eArgError, "arg must be Time or nil"); + ossl_raise(rb_eArgError, "arg must be Time or nil"); } - SSL_CTX_flush_sessions(ctx, tm); + SSL_CTX_flush_sessions(ctx, (long)tm); return self; } @@ -818,26 +1555,61 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) /* * SSLSocket class */ +static inline int +ssl_started(SSL *ssl) +{ + /* BIO is created through ossl_ssl_setup(), called by #connect or #accept */ + return SSL_get_rbio(ssl) != NULL; +} + static void -ossl_ssl_shutdown(SSL *ssl) +ossl_ssl_mark(void *ptr) { - if (ssl) { - SSL_shutdown(ssl); - SSL_clear(ssl); - } + SSL *ssl = ptr; + rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)); } static void -ossl_ssl_free(SSL *ssl) +ossl_ssl_free(void *ssl) { - ossl_ssl_shutdown(ssl); SSL_free(ssl); } +const rb_data_type_t ossl_ssl_type = { + "OpenSSL/SSL", + { + ossl_ssl_mark, ossl_ssl_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + static VALUE ossl_ssl_s_alloc(VALUE klass) { - return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL); + return TypedData_Wrap_Struct(klass, &ossl_ssl_type, NULL); +} + +static VALUE +peer_ip_address(VALUE self) +{ + VALUE remote_address = rb_funcall(rb_attr_get(self, id_i_io), rb_intern("remote_address"), 0); + + return rb_funcall(remote_address, rb_intern("inspect_sockaddr"), 0); +} + +static VALUE +fallback_peer_ip_address(VALUE self, VALUE args) +{ + return rb_str_new_cstr("(null)"); +} + +static VALUE +peeraddr_ip_str(VALUE self) +{ + VALUE rb_mErrno = rb_const_get(rb_cObject, rb_intern("Errno")); + VALUE rb_eSystemCallError = rb_const_get(rb_mErrno, rb_intern("SystemCallError")); + + return rb_rescue2(peer_ip_address, self, fallback_peer_ip_address, (VALUE)0, rb_eSystemCallError, NULL); } /* @@ -845,9 +1617,11 @@ ossl_ssl_s_alloc(VALUE klass) * SSLSocket.new(io) => aSSLSocket * SSLSocket.new(io, ctx) => aSSLSocket * - * === Parameters - * * +io+ is a real ruby IO object. Not an IO like object that responds to read/write. - * * +ctx+ is an OpenSSLSSL::SSLContext. + * 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. * @@ -857,252 +1631,595 @@ ossl_ssl_s_alloc(VALUE klass) static VALUE ossl_ssl_initialize(int argc, VALUE *argv, VALUE self) { - VALUE io, ctx; + VALUE io, v_ctx; + SSL *ssl; + SSL_CTX *ctx; - if (rb_scan_args(argc, argv, "11", &io, &ctx) == 1) { - ctx = rb_funcall(cSSLContext, rb_intern("new"), 0); - } - OSSL_Check_Kind(ctx, cSSLContext); + 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); Check_Type(io, T_FILE); - ossl_ssl_set_io(self, io); - ossl_ssl_set_ctx(self, ctx); - ossl_ssl_set_sync_close(self, Qfalse); - ossl_sslctx_setup(ctx); - rb_call_super(0, 0); + 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); + + rb_call_super(0, NULL); return self; } +#ifndef HAVE_RB_IO_DESCRIPTOR +static int +io_descriptor_fallback(VALUE io) +{ + rb_io_t *fptr; + GetOpenFile(io, fptr); + return fptr->fd; +} +#define rb_io_descriptor io_descriptor_fallback +#endif + static VALUE ossl_ssl_setup(VALUE self) { - VALUE io, v_ctx, cb; - SSL_CTX *ctx; + VALUE io; SSL *ssl; rb_io_t *fptr; - Data_Get_Struct(self, SSL, ssl); - if(!ssl){ - v_ctx = ossl_ssl_get_ctx(self); - Data_Get_Struct(v_ctx, SSL_CTX, ctx); + GetSSL(self, ssl); + if (ssl_started(ssl)) + return Qtrue; - ssl = SSL_new(ctx); - if (!ssl) { - ossl_raise(eSSLError, "SSL_new:"); - } - DATA_PTR(self) = ssl; - - 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); - cb = ossl_sslctx_get_client_cert_cb(v_ctx); - SSL_set_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx, (void*)cb); - cb = ossl_sslctx_get_tmp_dh_cb(v_ctx); - SSL_set_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx, (void*)cb); - } + io = rb_attr_get(self, id_i_io); + GetOpenFile(io, fptr); + rb_io_check_readable(fptr); + rb_io_check_writable(fptr); + if (!SSL_set_fd(ssl, TO_SOCKET(rb_io_descriptor(io)))) + ossl_raise(eSSLError, "SSL_set_fd"); return Qtrue; } #ifdef _WIN32 -#define ssl_get_error(ssl, ret) (errno = WSAGetLastError(), SSL_get_error(ssl, ret)) +#define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error((ssl), (ret))) #else -#define ssl_get_error(ssl, ret) SSL_get_error(ssl, ret) +#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret)) #endif +static void +write_would_block(int nonblock) +{ + if (nonblock) + ossl_raise(eSSLErrorWaitWritable, "write would block"); +} + +static void +read_would_block(int nonblock) +{ + if (nonblock) + ossl_raise(eSSLErrorWaitReadable, "read would block"); +} + +static int +no_exception_p(VALUE opts) +{ + if (RB_TYPE_P(opts, T_HASH) && + rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse) + return 1; + return 0; +} + +// Provided by Ruby 3.2.0 and later in order to support the default IO#timeout. +#ifndef RUBY_IO_TIMEOUT_DEFAULT +#define RUBY_IO_TIMEOUT_DEFAULT Qnil +#endif + +#ifdef HAVE_RB_IO_TIMEOUT +#define IO_TIMEOUT_ERROR rb_eIOTimeoutError +#else +#define IO_TIMEOUT_ERROR rb_eIOError +#endif + + +static void +io_wait_writable(VALUE io) +{ +#ifdef HAVE_RB_IO_MAYBE_WAIT + if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) { + rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!"); + } +#else + rb_io_t *fptr; + GetOpenFile(io, fptr); + rb_io_wait_writable(fptr->fd); +#endif +} + +static void +io_wait_readable(VALUE io) +{ +#ifdef HAVE_RB_IO_MAYBE_WAIT + if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) { + rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!"); + } +#else + rb_io_t *fptr; + GetOpenFile(io, fptr); + rb_io_wait_readable(fptr->fd); +#endif +} + static VALUE -ossl_start_ssl(VALUE self, int (*func)(), const char *funcname) +ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts) { SSL *ssl; - rb_io_t *fptr; int ret, ret2; VALUE cb_state; + int nonblock = opts != Qfalse; rb_ivar_set(self, ID_callback_state, Qnil); - Data_Get_Struct(self, SSL, ssl); - GetOpenFile(ossl_ssl_get_io(self), fptr); - for(;;){ - if((ret = func(ssl)) > 0) break; - switch((ret2 = ssl_get_error(ssl, ret))){ - case SSL_ERROR_WANT_WRITE: - rb_io_wait_writable(FPTR_TO_FD(fptr)); + GetSSL(self, ssl); + + VALUE io = rb_attr_get(self, id_i_io); + for (;;) { + ret = func(ssl); + + 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; + + switch ((ret2 = ssl_get_error(ssl, ret))) { + case SSL_ERROR_WANT_WRITE: + if (no_exception_p(opts)) { return sym_wait_writable; } + write_would_block(nonblock); + io_wait_writable(io); continue; - case SSL_ERROR_WANT_READ: - rb_io_wait_readable(FPTR_TO_FD(fptr)); + case SSL_ERROR_WANT_READ: + if (no_exception_p(opts)) { return sym_wait_readable; } + read_would_block(nonblock); + io_wait_readable(io); continue; - case SSL_ERROR_SYSCALL: - if (errno) rb_sys_fail(funcname); - ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); - default: - ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); - } + case SSL_ERROR_SYSCALL: +#ifdef __APPLE__ + /* See ossl_ssl_write_internal() */ + if (errno == EPROTOTYPE) + continue; +#endif + if (errno) rb_sys_fail(funcname); + /* fallthrough */ + default: { + VALUE error_append = Qnil; +#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED) + unsigned long err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_SSL && + ERR_GET_REASON(err) == SSL_R_CERTIFICATE_VERIFY_FAILED) { + const char *err_msg = ERR_reason_error_string(err), + *verify_msg = X509_verify_cert_error_string(SSL_get_verify_result(ssl)); + if (!err_msg) + err_msg = "(null)"; + if (!verify_msg) + verify_msg = "(null)"; + ossl_clear_error(); /* let ossl_raise() not append message */ + error_append = rb_sprintf(": %s (%s)", err_msg, verify_msg); + } +#endif + ossl_raise(eSSLError, + "%s%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s%"PRIsVALUE, + funcname, + ret2 == SSL_ERROR_SYSCALL ? " SYSCALL" : "", + ret2, + errno, + peeraddr_ip_str(self), + SSL_state_string_long(ssl), + error_append); + } + } } - cb_state = rb_ivar_get(self, ID_callback_state); - if (!NIL_P(cb_state)) - rb_jump_tag(NUM2INT(cb_state)); - return self; } /* * call-seq: * ssl.connect => self + * + * Initiates an SSL/TLS handshake with a server. */ static VALUE ossl_ssl_connect(VALUE self) { ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_connect, "SSL_connect"); + + return ossl_start_ssl(self, SSL_connect, "SSL_connect", Qfalse); +} + +/* + * call-seq: + * ssl.connect_nonblock([options]) => self + * + * Initiates the SSL/TLS handshake as a client in non-blocking manner. + * + * # emulates blocking connect + * begin + * ssl.connect_nonblock + * rescue IO::WaitReadable + * IO.select([s2]) + * retry + * rescue IO::WaitWritable + * IO.select(nil, [s2]) + * retry + * end + * + * By specifying a keyword argument _exception_ to +false+, you can indicate + * that connect_nonblock should not raise an IO::WaitReadable or + * IO::WaitWritable exception, but return the symbol +:wait_readable+ or + * +:wait_writable+ instead. + */ +static VALUE +ossl_ssl_connect_nonblock(int argc, VALUE *argv, VALUE self) +{ + VALUE opts; + rb_scan_args(argc, argv, "0:", &opts); + + ossl_ssl_setup(self); + + return ossl_start_ssl(self, SSL_connect, "SSL_connect", opts); } /* * call-seq: * ssl.accept => self + * + * Waits for a SSL/TLS client to initiate a handshake. */ static VALUE ossl_ssl_accept(VALUE self) { ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_accept, "SSL_accept"); + + return ossl_start_ssl(self, SSL_accept, "SSL_accept", Qfalse); } /* * call-seq: - * ssl.sysread(length) => string - * ssl.sysread(length, buffer) => buffer + * ssl.accept_nonblock([options]) => self * - * === Parameters - * * +length+ is a positive integer. - * * +buffer+ is a string used to store the result. + * Initiates the SSL/TLS handshake as a server in non-blocking manner. + * + * # emulates blocking accept + * begin + * ssl.accept_nonblock + * rescue IO::WaitReadable + * IO.select([s2]) + * retry + * rescue IO::WaitWritable + * IO.select(nil, [s2]) + * retry + * end + * + * By specifying a keyword argument _exception_ to +false+, you can indicate + * that accept_nonblock should not raise an IO::WaitReadable or + * IO::WaitWritable exception, but return the symbol +:wait_readable+ or + * +:wait_writable+ instead. */ static VALUE -ossl_ssl_read(int argc, VALUE *argv, VALUE self) +ossl_ssl_accept_nonblock(int argc, VALUE *argv, VALUE self) +{ + VALUE opts; + + rb_scan_args(argc, argv, "0:", &opts); + ossl_ssl_setup(self); + + return ossl_start_ssl(self, SSL_accept, "SSL_accept", opts); +} + +static VALUE +ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) { SSL *ssl; - int ilen, nread = 0; - VALUE len, str; - rb_io_t *fptr; + int ilen; + VALUE len, str, cb_state; + VALUE opts = Qnil; + + if (nonblock) { + rb_scan_args(argc, argv, "11:", &len, &str, &opts); + } else { + rb_scan_args(argc, argv, "11", &len, &str); + } + GetSSL(self, ssl); + if (!ssl_started(ssl)) + rb_raise(eSSLError, "SSL session is not started yet"); - rb_scan_args(argc, argv, "11", &len, &str); ilen = NUM2INT(len); - if(NIL_P(str)) str = rb_str_new(0, ilen); - else{ + if (NIL_P(str)) + str = rb_str_new(0, ilen); + else { StringValue(str); - rb_str_modify(str); - rb_str_resize(str, ilen); + if (RSTRING_LEN(str) >= ilen) + rb_str_modify(str); + else + rb_str_modify_expand(str, ilen - RSTRING_LEN(str)); } - if(ilen == 0) return str; - - Data_Get_Struct(self, SSL, ssl); - GetOpenFile(ossl_ssl_get_io(self), fptr); - if (ssl) { - if(SSL_pending(ssl) <= 0) - rb_thread_wait_fd(FPTR_TO_FD(fptr)); - for (;;){ - nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); - switch(ssl_get_error(ssl, nread)){ - case SSL_ERROR_NONE: - goto end; - case SSL_ERROR_ZERO_RETURN: - rb_eof_error(); - case SSL_ERROR_WANT_WRITE: - rb_io_wait_writable(FPTR_TO_FD(fptr)); - continue; - case SSL_ERROR_WANT_READ: - rb_io_wait_readable(FPTR_TO_FD(fptr)); - continue; - case SSL_ERROR_SYSCALL: - if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); - rb_sys_fail(0); - default: - ossl_raise(eSSLError, "SSL_read:"); - } - } - } - else { - ID id_sysread = rb_intern("sysread"); - rb_warning("SSL session is not started yet."); - return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str); + + if (ilen == 0) { + rb_str_set_len(str, 0); + return str; } - end: - rb_str_set_len(str, nread); - OBJ_TAINT(str); + VALUE io = rb_attr_get(self, id_i_io); - return str; + for (;;) { + rb_str_locktmp(str); + int nread = SSL_read(ssl, RSTRING_PTR(str), ilen); + rb_str_unlocktmp(str); + + cb_state = rb_attr_get(self, ID_callback_state); + if (!NIL_P(cb_state)) { + rb_ivar_set(self, ID_callback_state, Qnil); + ossl_clear_error(); + rb_jump_tag(NUM2INT(cb_state)); + } + + switch (ssl_get_error(ssl, nread)) { + case SSL_ERROR_NONE: + rb_str_set_len(str, nread); + return str; + case SSL_ERROR_ZERO_RETURN: + if (no_exception_p(opts)) { return Qnil; } + rb_eof_error(); + case SSL_ERROR_WANT_WRITE: + if (nonblock) { + if (no_exception_p(opts)) { return sym_wait_writable; } + write_would_block(nonblock); + } + io_wait_writable(io); + break; + case SSL_ERROR_WANT_READ: + if (nonblock) { + if (no_exception_p(opts)) { return sym_wait_readable; } + read_would_block(nonblock); + } + io_wait_readable(io); + break; + case SSL_ERROR_SYSCALL: + 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(); + } + } + /* fall through */ + default: + ossl_raise(eSSLError, "SSL_read"); + } + + // Ensure the buffer is not modified during io_wait_*able() + rb_str_modify(str); + if (rb_str_capacity(str) < (size_t)ilen) + rb_raise(eSSLError, "read buffer was modified"); + } } /* * call-seq: - * ssl.syswrite(string) => integer + * ssl.sysread(length) => string + * ssl.sysread(length, buffer) => buffer + * + * Reads _length_ bytes from the SSL connection. If a pre-allocated _buffer_ + * is provided the data will be written into it. */ static VALUE -ossl_ssl_write(VALUE self, VALUE str) +ossl_ssl_read(int argc, VALUE *argv, VALUE self) { + return ossl_ssl_read_internal(argc, argv, self, 0); +} + +/* + * call-seq: + * ssl.sysread_nonblock(length) => string + * ssl.sysread_nonblock(length, buffer) => buffer + * ssl.sysread_nonblock(length[, buffer [, opts]) => buffer + * + * A non-blocking version of #sysread. Raises an SSLError if reading would + * block. If "exception: false" is passed, this method returns a symbol of + * :wait_readable, :wait_writable, or nil, rather than raising an exception. + * + * Reads _length_ bytes from the SSL connection. If a pre-allocated _buffer_ + * is provided the data will be written into it. + */ +static VALUE +ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self) +{ + return ossl_ssl_read_internal(argc, argv, self, 1); +} + +static VALUE +ossl_ssl_write_internal_safe(VALUE _args) +{ + VALUE *args = (VALUE*)_args; + VALUE self = args[0]; + VALUE str = args[1]; + VALUE opts = args[2]; + SSL *ssl; - int nwrite = 0; rb_io_t *fptr; + int num, nonblock = opts != Qfalse; + VALUE cb_state; - StringValue(str); - Data_Get_Struct(self, SSL, ssl); - GetOpenFile(ossl_ssl_get_io(self), fptr); - - if (ssl) { - for (;;){ - nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); - switch(ssl_get_error(ssl, nwrite)){ - case SSL_ERROR_NONE: - goto end; - case SSL_ERROR_WANT_WRITE: - rb_io_wait_writable(FPTR_TO_FD(fptr)); - continue; - case SSL_ERROR_WANT_READ: - rb_io_wait_readable(FPTR_TO_FD(fptr)); + GetSSL(self, ssl); + if (!ssl_started(ssl)) + rb_raise(eSSLError, "SSL session is not started yet"); + + VALUE io = rb_attr_get(self, id_i_io); + GetOpenFile(io, fptr); + + /* SSL_write(3ssl) manpage states num == 0 is undefined */ + num = RSTRING_LENINT(str); + if (num == 0) + return INT2FIX(0); + + for (;;) { + int nwritten = SSL_write(ssl, RSTRING_PTR(str), num); + + cb_state = rb_attr_get(self, ID_callback_state); + if (!NIL_P(cb_state)) { + rb_ivar_set(self, ID_callback_state, Qnil); + ossl_clear_error(); + rb_jump_tag(NUM2INT(cb_state)); + } + + switch (ssl_get_error(ssl, nwritten)) { + case SSL_ERROR_NONE: + return INT2NUM(nwritten); + case SSL_ERROR_WANT_WRITE: + if (no_exception_p(opts)) { return sym_wait_writable; } + write_would_block(nonblock); + io_wait_writable(io); + continue; + case SSL_ERROR_WANT_READ: + if (no_exception_p(opts)) { return sym_wait_readable; } + read_would_block(nonblock); + io_wait_readable(io); + continue; + case SSL_ERROR_SYSCALL: +#ifdef __APPLE__ + /* + * It appears that send syscall can return EPROTOTYPE if the + * socket is being torn down. Retry to get a proper errno to + * make the error handling in line with the socket library. + * [Bug #14713] https://bugs.ruby-lang.org/issues/14713 + */ + if (errno == EPROTOTYPE) continue; - case SSL_ERROR_SYSCALL: - if (errno) rb_sys_fail(0); - default: - ossl_raise(eSSLError, "SSL_write:"); - } +#endif + if (errno) rb_sys_fail(0); + /* fallthrough */ + default: + ossl_raise(eSSLError, "SSL_write"); } } - 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); +} + + +static VALUE +ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) +{ + StringValue(str); + int frozen = RB_OBJ_FROZEN(str); + if (!frozen) { + rb_str_locktmp(str); + } + int state; + VALUE args[3] = {self, str, opts}; + VALUE result = rb_protect(ossl_ssl_write_internal_safe, (VALUE)args, &state); + if (!frozen) { + rb_str_unlocktmp(str); } - end: - return INT2NUM(nwrite); + if (state) { + rb_jump_tag(state); + } + return result; } /* * call-seq: - * ssl.sysclose => nil + * ssl.syswrite(string) => Integer + * + * Writes _string_ to the SSL connection. */ static VALUE -ossl_ssl_close(VALUE self) +ossl_ssl_write(VALUE self, VALUE str) +{ + return ossl_ssl_write_internal(self, str, Qfalse); +} + +/* + * call-seq: + * ssl.syswrite_nonblock(string) => Integer + * + * Writes _string_ to the SSL connection in a non-blocking manner. Raises an + * SSLError if writing would block. + */ +static VALUE +ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self) +{ + VALUE str, opts; + + rb_scan_args(argc, argv, "1:", &str, &opts); + + return ossl_ssl_write_internal(self, str, opts); +} + +/* + * call-seq: + * ssl.stop => nil + * + * Sends "close notify" to the peer and tries to shut down the SSL connection + * gracefully. + */ +static VALUE +ossl_ssl_stop(VALUE self) { SSL *ssl; + int ret; - Data_Get_Struct(self, SSL, ssl); - ossl_ssl_shutdown(ssl); - if (RTEST(ossl_ssl_get_sync_close(self))) - rb_funcall(ossl_ssl_get_io(self), rb_intern("close"), 0); + 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; } /* * call-seq: * ssl.cert => cert or nil + * + * The X509 certificate for this socket endpoint. */ static VALUE ossl_ssl_get_cert(VALUE self) @@ -1110,11 +2227,7 @@ ossl_ssl_get_cert(VALUE self) SSL *ssl; X509 *cert = NULL; - Data_Get_Struct(self, SSL, ssl); - if (ssl) { - rb_warning("SSL session is not started yet."); - return Qnil; - } + GetSSL(self, ssl); /* * Is this OpenSSL bug? Should add a ref? @@ -1131,6 +2244,8 @@ ossl_ssl_get_cert(VALUE self) /* * call-seq: * ssl.peer_cert => cert or nil + * + * The X509 certificate for this socket's peer. */ static VALUE ossl_ssl_get_peer_cert(VALUE self) @@ -1139,12 +2254,7 @@ ossl_ssl_get_peer_cert(VALUE self) X509 *cert = NULL; VALUE obj; - Data_Get_Struct(self, SSL, ssl); - - if (!ssl){ - rb_warning("SSL session is not started yet."); - return Qnil; - } + GetSSL(self, ssl); cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */ @@ -1160,6 +2270,8 @@ ossl_ssl_get_peer_cert(VALUE self) /* * call-seq: * ssl.peer_cert_chain => [cert, ...] or nil + * + * The X509 certificate chain for this socket's peer. */ static VALUE ossl_ssl_get_peer_cert_chain(VALUE self) @@ -1170,18 +2282,15 @@ ossl_ssl_get_peer_cert_chain(VALUE self) VALUE ary; int i, num; - Data_Get_Struct(self, SSL, ssl); - if(!ssl){ - rb_warning("SSL session is not started yet."); - return Qnil; - } + GetSSL(self, ssl); + chain = SSL_get_peer_cert_chain(ssl); if(!chain) return Qnil; - num = sk_num(chain); + num = sk_X509_num(chain); ary = rb_ary_new2(num); for (i = 0; i < num; i++){ - cert = (X509*)sk_value(chain, i); - rb_ary_push(ary, ossl_x509_new(cert)); + cert = sk_X509_value(chain, i); + rb_ary_push(ary, ossl_x509_new(cert)); } return ary; @@ -1189,27 +2298,45 @@ ossl_ssl_get_peer_cert_chain(VALUE self) /* * call-seq: - * ssl.cipher => [name, version, bits, alg_bits] + * ssl.ssl_version => String + * + * Returns a String representing the SSL/TLS version that was negotiated + * for the connection, for example "TLSv1.2". + */ +static VALUE +ossl_ssl_get_version(VALUE self) +{ + SSL *ssl; + + GetSSL(self, ssl); + + return rb_str_new2(SSL_get_version(ssl)); +} + +/* + * call-seq: + * ssl.cipher -> nil or [name, version, bits, alg_bits] + * + * Returns the cipher suite actually used in the current session, or nil if + * no session has been established. */ static VALUE ossl_ssl_get_cipher(VALUE self) { SSL *ssl; - SSL_CIPHER *cipher; + const SSL_CIPHER *cipher; - Data_Get_Struct(self, SSL, ssl); - if (!ssl) { - rb_warning("SSL session is not started yet."); - return Qnil; - } + GetSSL(self, ssl); cipher = SSL_get_current_cipher(ssl); - - return ossl_ssl_cipher_to_ary(cipher); + return cipher ? ossl_ssl_cipher_to_ary(cipher) : Qnil; } /* * call-seq: * ssl.state => string + * + * A description of the current connection state. This is for diagnostic + * purposes only. */ static VALUE ossl_ssl_get_state(VALUE self) @@ -1217,11 +2344,8 @@ ossl_ssl_get_state(VALUE self) SSL *ssl; VALUE ret; - Data_Get_Struct(self, SSL, ssl); - if (!ssl) { - rb_warning("SSL session is not started yet."); - return Qnil; - } + GetSSL(self, ssl); + ret = rb_str_new2(SSL_state_string(ssl)); if (ruby_verbose) { rb_str_cat2(ret, ": "); @@ -1232,49 +2356,41 @@ ossl_ssl_get_state(VALUE self) /* * call-seq: - * ssl.pending => integer + * ssl.pending => Integer + * + * The number of bytes that are immediately available for reading. */ static VALUE ossl_ssl_pending(VALUE self) { SSL *ssl; - Data_Get_Struct(self, SSL, ssl); - if (!ssl) { - rb_warning("SSL session is not started yet."); - return Qnil; - } + GetSSL(self, ssl); return INT2NUM(SSL_pending(ssl)); } /* - * call-seq: - * ssl.session_reused? -> true | false + * call-seq: + * ssl.session_reused? -> true | false * + * Returns +true+ if a reused session was negotiated during the handshake. */ static VALUE ossl_ssl_session_reused(VALUE self) { SSL *ssl; - Data_Get_Struct(self, SSL, ssl); - if (!ssl) { - rb_warning("SSL session is not started yet."); - return Qnil; - } + GetSSL(self, ssl); - switch(SSL_session_reused(ssl)) { - case 1: return Qtrue; - case 0: return Qfalse; - default: ossl_raise(eSSLError, "SSL_session_reused"); - } + return SSL_session_reused(ssl) ? Qtrue : Qfalse; } /* - * call-seq: - * ssl.session = session -> session + * call-seq: + * ssl.session = session -> session * + * Sets the Session to be used when the connection is established. */ static VALUE ossl_ssl_set_session(VALUE self, VALUE arg1) @@ -1282,72 +2398,695 @@ ossl_ssl_set_session(VALUE self, VALUE arg1) SSL *ssl; SSL_SESSION *sess; -/* why is ossl_ssl_setup delayed? */ - ossl_ssl_setup(self); + GetSSL(self, ssl); + GetSSLSession(arg1, sess); + + if (SSL_set_session(ssl, sess) != 1) + ossl_raise(eSSLError, "SSL_set_session"); - Data_Get_Struct(self, SSL, ssl); - if (!ssl) { - rb_warning("SSL session is not started yet."); + return arg1; +} + +/* + * 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; +} + +/* + * call-seq: + * ssl.verify_result => Integer + * + * Returns the result of the peer certificates verification. See verify(1) + * for error values and descriptions. + * + * If no peer certificate was presented X509_V_OK is returned. + */ +static VALUE +ossl_ssl_get_verify_result(VALUE self) +{ + SSL *ssl; + + GetSSL(self, ssl); + + return LONG2NUM(SSL_get_verify_result(ssl)); +} + +/* + * call-seq: + * ssl.finished_message => "finished message" + * + * Returns the last *Finished* message sent + * + */ +static VALUE +ossl_ssl_get_finished(VALUE self) +{ + SSL *ssl; + char sizer[1], *buf; + size_t len; + + GetSSL(self, ssl); + + len = SSL_get_finished(ssl, sizer, 0); + if (len == 0) + return Qnil; + + buf = ALLOCA_N(char, len); + SSL_get_finished(ssl, buf, len); + return rb_str_new(buf, len); +} + +/* + * call-seq: + * ssl.peer_finished_message => "peer finished message" + * + * Returns the last *Finished* message received + * + */ +static VALUE +ossl_ssl_get_peer_finished(VALUE self) +{ + SSL *ssl; + char sizer[1], *buf; + size_t len; + + GetSSL(self, ssl); + + len = SSL_get_peer_finished(ssl, sizer, 0); + if (len == 0) return Qnil; + + buf = ALLOCA_N(char, len); + SSL_get_peer_finished(ssl, buf, len); + return rb_str_new(buf, len); +} + +/* + * call-seq: + * ssl.client_ca => [x509name, ...] or nil + * + * Returns the list of client CAs. Please note that in contrast to + * SSLContext#client_ca= no array of X509::Certificate is returned but + * X509::Name instances of the CA's subject distinguished name. + * + * In server mode, returns the list set by SSLContext#client_ca=. + * In client mode, returns the list of client CAs sent from the server. + */ +static VALUE +ossl_ssl_get_client_ca_list(VALUE self) +{ + SSL *ssl; + STACK_OF(X509_NAME) *ca; + + GetSSL(self, ssl); + + ca = SSL_get_client_CA_list(ssl); + if (!ca) + return Qnil; + return ossl_x509name_sk2ary(ca); +} + +# ifdef OSSL_USE_NEXTPROTONEG +/* + * call-seq: + * ssl.npn_protocol => String | nil + * + * Returns the protocol string that was finally selected by the client + * during the handshake. + */ +static VALUE +ossl_ssl_npn_protocol(VALUE self) +{ + SSL *ssl; + const unsigned char *out; + unsigned int outlen; + + GetSSL(self, ssl); + + SSL_get0_next_proto_negotiated(ssl, &out, &outlen); + if (!outlen) + return Qnil; + else + return rb_str_new((const char *) out, outlen); +} +# endif + +/* + * call-seq: + * ssl.alpn_protocol => String | nil + * + * Returns the ALPN protocol string that was finally selected by the server + * during the handshake. + */ +static VALUE +ossl_ssl_alpn_protocol(VALUE self) +{ + SSL *ssl; + const unsigned char *out; + unsigned int outlen; + + GetSSL(self, ssl); + + SSL_get0_alpn_selected(ssl, &out, &outlen); + if (!outlen) + return Qnil; + else + return rb_str_new((const char *) out, outlen); +} + +/* + * call-seq: + * session.export_keying_material(label, length) -> String + * + * Enables use of shared session key material in accordance with RFC 5705. + */ +static VALUE +ossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self) +{ + SSL *ssl; + VALUE str; + VALUE label; + VALUE length; + VALUE context; + unsigned char *p; + size_t len; + int use_ctx = 0; + unsigned char *ctx = NULL; + size_t ctx_len = 0; + int ret; + + rb_scan_args(argc, argv, "21", &label, &length, &context); + StringValue(label); + + GetSSL(self, ssl); + + len = (size_t)NUM2LONG(length); + str = rb_str_new(0, len); + p = (unsigned char *)RSTRING_PTR(str); + if (!NIL_P(context)) { + use_ctx = 1; + StringValue(context); + ctx = (unsigned char *)RSTRING_PTR(context); + ctx_len = RSTRING_LEN(context); } + ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label), + RSTRING_LENINT(label), ctx, ctx_len, use_ctx); + if (ret == 0 || ret == -1) { + ossl_raise(eSSLError, "SSL_export_keying_material"); + } + return str; +} + +/* + * 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; - SafeGetSSLSession(arg1, sess); + GetSSL(self, ssl); + if (!SSL_get_server_tmp_key(ssl, &key)) + return Qnil; + return ossl_pkey_wrap(key); +} - if (SSL_set_session(ssl, sess) != 1) - ossl_raise(eSSLError, "SSL_set_session"); +#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME +/* + * call-seq: + * ssl.sigalg => String or nil + * + * Returns the signature algorithm name, the IANA name of the signature scheme + * used by the local to sign the TLS handshake. + */ +static VALUE +ossl_ssl_get_sigalg(VALUE self) +{ + SSL *ssl; + const char *name; - return arg1; + GetSSL(self, ssl); + if (!SSL_get0_signature_name(ssl, &name)) + return Qnil; + return rb_str_new_cstr(name); +} + +/* + * call-seq: + * ssl.peer_sigalg => String or nil + * + * Returns the signature algorithm name, the IANA name of the signature scheme + * used by the peer to sign the TLS handshake. + */ +static VALUE +ossl_ssl_get_peer_sigalg(VALUE self) +{ + SSL *ssl; + const char *name; + + GetSSL(self, ssl); + if (!SSL_get0_peer_signature_name(ssl, &name)) + return Qnil; + return rb_str_new_cstr(name); } +#endif +#ifdef HAVE_SSL_GET0_GROUP_NAME +/* + * call-seq: + * ssl.group => String or nil + * + * Returns the name of the group that was used for the key agreement of the + * current TLS session establishment. + */ +static VALUE +ossl_ssl_get_group(VALUE self) +{ + SSL *ssl; + const char *name; + + GetSSL(self, ssl); + if (!(name = SSL_get0_group_name(ssl))) + return Qnil; + return rb_str_new_cstr(name); +} +#endif + +#endif /* !defined(OPENSSL_NO_SOCK) */ void -Init_ossl_ssl() +Init_ossl_ssl(void) { - int i; - VALUE ary; - -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); +#if 0 + 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"); +#ifndef OPENSSL_NO_SOCK + id_call = rb_intern_const("call"); + ID_callback_state = rb_intern_const("callback_state"); - ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_vcb_idx",0,0,0); - ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,"ossl_ssl_ex_store_p",0,0,0); - ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_ptr_idx",0,0,0); - ossl_ssl_ex_client_cert_cb_idx = - SSL_get_ex_new_index(0,"ossl_ssl_ex_client_cert_cb_idx",0,0,0); - ossl_ssl_ex_tmp_dh_callback_idx = - SSL_get_ex_new_index(0,"ossl_ssl_ex_tmp_dh_callback_idx",0,0,0); + ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_ptr_idx", 0, 0, 0); + if (ossl_ssl_ex_ptr_idx < 0) + ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index"); + ossl_sslctx_ex_ptr_idx = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_ptr_idx", 0, 0, 0); + if (ossl_sslctx_ex_ptr_idx < 0) + ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index"); + /* Document-module: OpenSSL::SSL + * + * Use SSLContext to set up the parameters for a TLS (former SSL) + * connection. Both client and server TLS connections are supported, + * SSLSocket and SSLServer may be used in conjunction with an instance + * of SSLContext to set up connections. + */ mSSL = rb_define_module_under(mOSSL, "SSL"); + + /* Document-class: OpenSSL::SSL::SSLError + * + * Generic error class raised by SSLSocket and SSLContext. + */ eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError); + eSSLErrorWaitReadable = rb_define_class_under(mSSL, "SSLErrorWaitReadable", eSSLError); + rb_include_module(eSSLErrorWaitReadable, rb_mWaitReadable); + eSSLErrorWaitWritable = rb_define_class_under(mSSL, "SSLErrorWaitWritable", eSSLError); + rb_include_module(eSSLErrorWaitWritable, rb_mWaitWritable); - /* class SSLContext + Init_ossl_ssl_session(); + + /* Document-class: OpenSSL::SSL::SSLContext + * + * An SSLContext is used to set various options regarding certificates, + * algorithms, verification, session caching, etc. The SSLContext is + * used to create an SSLSocket. * - * The following attributes are available but don't show up in rdoc. - * All attributes must be set before calling SSLSocket.new(io, ctx). - * * 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 + * All attributes must be set before creating an SSLSocket as the + * SSLContext will be frozen afterward. */ cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject); rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc); - for(i = 0; i < numberof(ossl_sslctx_attrs); i++) - rb_attr(cSSLContext, rb_intern(ossl_sslctx_attrs[i]), 1, 1, Qfalse); - rb_define_method(cSSLContext, "initialize", ossl_sslctx_initialize, -1); + rb_undef_method(cSSLContext, "initialize_copy"); + + /* + * Context certificate + * + * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated. + * It is recommended to use #add_certificate instead. + */ + rb_attr(cSSLContext, rb_intern_const("cert"), 1, 1, Qfalse); + + /* + * Context private key + * + * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated. + * It is recommended to use #add_certificate instead. + */ + rb_attr(cSSLContext, rb_intern_const("key"), 1, 1, Qfalse); + + /* + * A certificate or Array of certificates that will be sent to the client. + */ + rb_attr(cSSLContext, rb_intern_const("client_ca"), 1, 1, Qfalse); + + /* + * The path to a file containing a PEM-format CA certificate + */ + rb_attr(cSSLContext, rb_intern_const("ca_file"), 1, 1, Qfalse); + + /* + * The path to a directory containing CA certificates in PEM format. + * + * Files are looked up by subject's X509 name's hash value. + */ + rb_attr(cSSLContext, rb_intern_const("ca_path"), 1, 1, Qfalse); + + /* + * Maximum session lifetime in seconds. + */ + rb_attr(cSSLContext, rb_intern_const("timeout"), 1, 1, Qfalse); + + /* + * Session verification mode. + * + * 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_const("verify_mode"), 1, 1, Qfalse); + + /* + * Number of CA certificates to walk when verifying a certificate chain. + */ + rb_attr(cSSLContext, rb_intern_const("verify_depth"), 1, 1, Qfalse); + + /* + * A callback for additional certificate verification. The callback is + * invoked for each certificate in the chain. + * + * The callback is invoked with two values. _preverify_ok_ indicates + * indicates if the verification was passed (+true+) or not (+false+). + * _store_context_ is an OpenSSL::X509::StoreContext containing the + * context used for certificate verification. + * + * If the callback returns +false+, the chain verification is immediately + * stopped and a bad_certificate alert is then sent. + */ + rb_attr(cSSLContext, rb_intern_const("verify_callback"), 1, 1, Qfalse); + + /* + * 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_const("verify_hostname"), 1, 1, Qfalse); + + /* + * An OpenSSL::X509::Store used for certificate verification. + */ + rb_attr(cSSLContext, rb_intern_const("cert_store"), 1, 1, Qfalse); + + /* + * An Array of extra X509 certificates to be added to the certificate + * chain. + * + * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated. + * It is recommended to use #add_certificate instead. + */ + rb_attr(cSSLContext, rb_intern_const("extra_chain_cert"), 1, 1, Qfalse); + + /* + * A callback invoked when a client certificate is requested by a server + * and no certificate has been set. + * + * The callback is invoked with a Session and must return an Array + * containing an OpenSSL::X509::Certificate and an OpenSSL::PKey. If any + * other value is returned the handshake is suspended. + */ + rb_attr(cSSLContext, rb_intern_const("client_cert_cb"), 1, 1, Qfalse); + +#ifndef OPENSSL_NO_DH + /* + * A callback invoked when DH parameters are required for ephemeral DH key + * exchange. + * + * The callback is invoked with the SSLSocket, a + * flag indicating the use of an export cipher and the keylength + * required. + * + * The callback must return an OpenSSL::PKey::DH instance of the correct + * key length. + * + * <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead. + */ + rb_attr(cSSLContext, rb_intern_const("tmp_dh_callback"), 1, 1, Qfalse); +#endif + + /* + * Sets the context in which a session can be reused. This allows + * sessions for multiple applications to be distinguished, for example, by + * name. + */ + rb_attr(cSSLContext, rb_intern_const("session_id_context"), 1, 1, Qfalse); + + /* + * A callback invoked on a server when a session is proposed by the client + * but the session could not be found in the server's internal cache. + * + * The callback is invoked with the SSLSocket and session id. The + * callback may return a Session from an external cache. + */ + rb_attr(cSSLContext, rb_intern_const("session_get_cb"), 1, 1, Qfalse); + + /* + * A callback invoked when a new session was negotiated. + * + * The callback is invoked with an SSLSocket. If +false+ is returned the + * session will be removed from the internal cache. + */ + rb_attr(cSSLContext, rb_intern_const("session_new_cb"), 1, 1, Qfalse); + + /* + * A callback invoked when a session is removed from the internal cache. + * + * The callback is invoked with an SSLContext and a Session. + * + * IMPORTANT NOTE: It is currently not possible to use this safely in a + * multi-threaded application. The callback is called inside a global lock + * and it can randomly cause deadlock on Ruby thread switching. + */ + rb_attr(cSSLContext, rb_intern_const("session_remove_cb"), 1, 1, Qfalse); + + /* + * A callback invoked whenever a new handshake is initiated on an + * established connection. May be used to disable renegotiation entirely. + * + * The callback is invoked with the active SSLSocket. The callback's + * return value is ignored. A normal return indicates "approval" of the + * renegotiation and will continue the process. To forbid renegotiation + * and to cancel the process, raise an exception within the callback. + * + * === Disable client renegotiation + * + * When running a server, it is often desirable to disable client + * renegotiation entirely. You may use a callback as follows to implement + * this feature: + * + * ctx.renegotiation_cb = lambda do |ssl| + * raise RuntimeError, "Client renegotiation disabled" + * end + */ + rb_attr(cSSLContext, rb_intern_const("renegotiation_cb"), 1, 1, Qfalse); +#ifdef OSSL_USE_NEXTPROTONEG + /* + * An Enumerable of Strings. Each String represents a protocol to be + * advertised as the list of supported protocols for Next 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. + * + * === Example + * + * ctx.npn_protocols = ["http/1.1", "spdy/2"] + */ + rb_attr(cSSLContext, rb_intern_const("npn_protocols"), 1, 1, Qfalse); + /* + * A callback invoked on the client side when the client needs to select + * a protocol from the list sent by the server. Supported in OpenSSL 1.0.1 + * and higher. The client MUST select a protocol of those advertised by + * the server. 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 NPN extension on the client - any protocols + * advertised by the server will be ignored. + * + * === Example + * + * ctx.npn_select_cb = lambda do |protocols| + * # inspect the protocols and select one + * protocols.first + * end + */ + rb_attr(cSSLContext, rb_intern_const("npn_select_cb"), 1, 1, Qfalse); +#endif + + /* + * 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.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 + * + * ctx.alpn_protocols = ["http/1.1", "spdy/2", "h2"] + */ + rb_attr(cSSLContext, rb_intern_const("alpn_protocols"), 1, 1, Qfalse); + /* + * 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 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 server - any protocols + * advertised by the client will be ignored. + * + * === Example + * + * ctx.alpn_select_cb = lambda do |protocols| + * # inspect the protocols and select one + * protocols.first + * end + */ + rb_attr(cSSLContext, rb_intern_const("alpn_select_cb"), 1, 1, Qfalse); + + /* + * A callback invoked when TLS key material is generated or received, in + * order to allow applications to store this keying material for debugging + * purposes. + * + * The callback is invoked with an SSLSocket and a string containing the + * key material in the format used by NSS for its SSLKEYLOGFILE debugging + * output. + * + * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements + * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see + * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6). + * + * === Example + * + * context.keylog_cb = proc do |_sock, line| + * File.open('ssl_keylog_file', "a") do |f| + * f.write("#{line}\n") + * end + * end + */ + rb_attr(cSSLContext, rb_intern_const("keylog_cb"), 1, 1, Qfalse); + + rb_define_alias(cSSLContext, "ssl_timeout", "timeout"); + rb_define_alias(cSSLContext, "ssl_timeout=", "timeout="); + rb_define_method(cSSLContext, "min_version=", ossl_sslctx_set_min_version, 1); + rb_define_method(cSSLContext, "max_version=", ossl_sslctx_set_max_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, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1); +#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST // Not in LibreSSL yet + rb_define_method(cSSLContext, "sigalgs=", ossl_sslctx_set_sigalgs, 1); +#endif +#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST // Not in LibreSSL or AWS-LC yet + rb_define_method(cSSLContext, "client_sigalgs=", ossl_sslctx_set_client_sigalgs, 1); +#endif +#ifndef OPENSSL_NO_DH + rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1); +#endif + rb_define_method(cSSLContext, "groups=", ossl_sslctx_set_groups, 1); + rb_define_alias(cSSLContext, "ecdh_curves=", "groups="); + rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0); + rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1); +#ifdef SSL_MODE_SEND_FALLBACK_SCSV + rb_define_method(cSSLContext, "enable_fallback_scsv", ossl_sslctx_enable_fallback_scsv, 0); +#endif + rb_define_method(cSSLContext, "add_certificate", ossl_sslctx_add_certificate, -1); + + rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0); + rb_define_alias(cSSLContext, "freeze", "setup"); + + /* + * No session caching for client or server + */ + 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", 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", LONG2NUM(SSL_SESS_CACHE_SERVER)); + + /* + * Both client and server sessions are added to the session cache + */ + 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 + * connections. Since this may lead to a delay that cannot be controlled, + * the automatic flushing may be disabled and #flush_sessions can be + * called explicitly. + */ + 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 + * internal cache. + * + * This flag has no effect on clients + */ + 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", 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", LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL)); - - rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF)); - 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_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER)); - 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_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR)); - rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)); - rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE)); - rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(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); rb_define_method(cSSLContext, "session_cache_mode", ossl_sslctx_get_session_cache_mode, 0); @@ -1356,79 +3095,210 @@ Init_ossl_ssl() rb_define_method(cSSLContext, "session_cache_size=", ossl_sslctx_set_session_cache_size, 1); rb_define_method(cSSLContext, "session_cache_stats", ossl_sslctx_get_session_cache_stats, 0); rb_define_method(cSSLContext, "flush_sessions", ossl_sslctx_flush_sessions, -1); + rb_define_method(cSSLContext, "options", ossl_sslctx_get_options, 0); + rb_define_method(cSSLContext, "options=", ossl_sslctx_set_options, 1); - ary = rb_ary_new2(numberof(ossl_ssl_method_tab)); - for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { - rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name))); - } - rb_obj_freeze(ary); - /* holds a list of available SSL/TLS methods */ - rb_define_const(cSSLContext, "METHODS", ary); - - /* class SSLSocket - * - * The following attributes are available but don't show up in rdoc. - * * io, context, sync_close - * + /* + * Document-class: OpenSSL::SSL::SSLSocket */ cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject); rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc); - for(i = 0; i < numberof(ossl_ssl_attr_readers); i++) - rb_attr(cSSLSocket, rb_intern(ossl_ssl_attr_readers[i]), 1, 0, Qfalse); - for(i = 0; i < numberof(ossl_ssl_attrs); i++) - rb_attr(cSSLSocket, rb_intern(ossl_ssl_attrs[i]), 1, 1, Qfalse); - rb_define_alias(cSSLSocket, "to_io", "io"); 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); + rb_define_method(cSSLSocket, "accept_nonblock", ossl_ssl_accept_nonblock, -1); rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1); + rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1); rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1); - rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0); + rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, -1); + rb_define_private_method(cSSLSocket, "stop", ossl_ssl_stop, 0); rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0); rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0); rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0); + rb_define_method(cSSLSocket, "ssl_version", ossl_ssl_get_version, 0); rb_define_method(cSSLSocket, "cipher", ossl_ssl_get_cipher, 0); rb_define_method(cSSLSocket, "state", ossl_ssl_get_state, 0); rb_define_method(cSSLSocket, "pending", ossl_ssl_pending, 0); rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0); + /* implementation of OpenSSL::SSL::SSLSocket#session is in lib/openssl/ssl.rb */ 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); + /* #hostname is defined in lib/openssl/ssl.rb */ + rb_define_method(cSSLSocket, "hostname=", ossl_ssl_set_hostname, 1); + rb_define_method(cSSLSocket, "finished_message", ossl_ssl_get_finished, 0); + rb_define_method(cSSLSocket, "peer_finished_message", ossl_ssl_get_peer_finished, 0); + rb_define_method(cSSLSocket, "tmp_key", ossl_ssl_tmp_key, 0); + rb_define_method(cSSLSocket, "alpn_protocol", ossl_ssl_alpn_protocol, 0); + rb_define_method(cSSLSocket, "export_keying_material", ossl_ssl_export_keying_material, -1); +# ifdef OSSL_USE_NEXTPROTONEG + rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0); +# endif +#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME + rb_define_method(cSSLSocket, "sigalg", ossl_ssl_get_sigalg, 0); + rb_define_method(cSSLSocket, "peer_sigalg", ossl_ssl_get_peer_sigalg, 0); +#endif +#ifdef HAVE_SSL_GET0_GROUP_NAME + rb_define_method(cSSLSocket, "group", ossl_ssl_get_group, 0); +#endif -#define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2FIX(SSL_##x)) - - ossl_ssl_def_const(VERIFY_NONE); - ossl_ssl_def_const(VERIFY_PEER); - ossl_ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT); - ossl_ssl_def_const(VERIFY_CLIENT_ONCE); - /* Not introduce constants included in OP_ALL such as... - * ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG); - * ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG); - * 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); - * ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING); - * 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); + rb_define_const(mSSL, "VERIFY_NONE", INT2NUM(SSL_VERIFY_NONE)); + rb_define_const(mSSL, "VERIFY_PEER", INT2NUM(SSL_VERIFY_PEER)); + rb_define_const(mSSL, "VERIFY_FAIL_IF_NO_PEER_CERT", INT2NUM(SSL_VERIFY_FAIL_IF_NO_PEER_CERT)); + rb_define_const(mSSL, "VERIFY_CLIENT_ONCE", INT2NUM(SSL_VERIFY_CLIENT_ONCE)); + + rb_define_const(mSSL, "OP_ALL", ULONG2NUM(SSL_OP_ALL)); +#ifdef SSL_OP_CLEANSE_PLAINTEXT /* OpenSSL 3.0 */ + rb_define_const(mSSL, "OP_CLEANSE_PLAINTEXT", ULONG2NUM(SSL_OP_CLEANSE_PLAINTEXT)); +#endif + rb_define_const(mSSL, "OP_LEGACY_SERVER_CONNECT", ULONG2NUM(SSL_OP_LEGACY_SERVER_CONNECT)); +#ifdef SSL_OP_ENABLE_KTLS /* OpenSSL 3.0 */ + rb_define_const(mSSL, "OP_ENABLE_KTLS", ULONG2NUM(SSL_OP_ENABLE_KTLS)); +#endif + rb_define_const(mSSL, "OP_TLSEXT_PADDING", ULONG2NUM(SSL_OP_TLSEXT_PADDING)); + rb_define_const(mSSL, "OP_SAFARI_ECDHE_ECDSA_BUG", ULONG2NUM(SSL_OP_SAFARI_ECDHE_ECDSA_BUG)); +#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF /* OpenSSL 3.0 */ + rb_define_const(mSSL, "OP_IGNORE_UNEXPECTED_EOF", ULONG2NUM(SSL_OP_IGNORE_UNEXPECTED_EOF)); +#endif +#ifdef SSL_OP_ALLOW_CLIENT_RENEGOTIATION /* OpenSSL 3.0 */ + rb_define_const(mSSL, "OP_ALLOW_CLIENT_RENEGOTIATION", ULONG2NUM(SSL_OP_ALLOW_CLIENT_RENEGOTIATION)); +#endif +#ifdef SSL_OP_DISABLE_TLSEXT_CA_NAMES /* OpenSSL 3.0 */ + rb_define_const(mSSL, "OP_DISABLE_TLSEXT_CA_NAMES", ULONG2NUM(SSL_OP_DISABLE_TLSEXT_CA_NAMES)); +#endif +#ifdef SSL_OP_ALLOW_NO_DHE_KEX /* OpenSSL 1.1.1, missing in LibreSSL */ + rb_define_const(mSSL, "OP_ALLOW_NO_DHE_KEX", ULONG2NUM(SSL_OP_ALLOW_NO_DHE_KEX)); +#endif + rb_define_const(mSSL, "OP_DONT_INSERT_EMPTY_FRAGMENTS", ULONG2NUM(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)); + rb_define_const(mSSL, "OP_NO_TICKET", ULONG2NUM(SSL_OP_NO_TICKET)); + rb_define_const(mSSL, "OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION", ULONG2NUM(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)); + rb_define_const(mSSL, "OP_NO_COMPRESSION", ULONG2NUM(SSL_OP_NO_COMPRESSION)); + rb_define_const(mSSL, "OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION", ULONG2NUM(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); +#ifdef SSL_OP_NO_ENCRYPT_THEN_MAC /* OpenSSL 1.1.1, missing in LibreSSL */ + rb_define_const(mSSL, "OP_NO_ENCRYPT_THEN_MAC", ULONG2NUM(SSL_OP_NO_ENCRYPT_THEN_MAC)); +#endif +#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT /* OpenSSL 1.1.1, missing in LibreSSL */ + rb_define_const(mSSL, "OP_ENABLE_MIDDLEBOX_COMPAT", ULONG2NUM(SSL_OP_ENABLE_MIDDLEBOX_COMPAT)); #endif -#if defined(SSL_OP_SINGLE_ECDH_USE) - ossl_ssl_def_const(OP_SINGLE_ECDH_USE); +#ifdef SSL_OP_PRIORITIZE_CHACHA /* OpenSSL 1.1.1, missing in LibreSSL */ + rb_define_const(mSSL, "OP_PRIORITIZE_CHACHA", ULONG2NUM(SSL_OP_PRIORITIZE_CHACHA)); #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); +#ifdef SSL_OP_NO_ANTI_REPLAY /* OpenSSL 1.1.1, missing in LibreSSL */ + rb_define_const(mSSL, "OP_NO_ANTI_REPLAY", ULONG2NUM(SSL_OP_NO_ANTI_REPLAY)); #endif - ossl_ssl_def_const(OP_TLS_ROLLBACK_BUG); - ossl_ssl_def_const(OP_NO_SSLv2); - ossl_ssl_def_const(OP_NO_SSLv3); - ossl_ssl_def_const(OP_NO_TLSv1); - ossl_ssl_def_const(OP_PKCS1_CHECK_1); - ossl_ssl_def_const(OP_PKCS1_CHECK_2); - ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG); - ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); + rb_define_const(mSSL, "OP_NO_SSLv3", ULONG2NUM(SSL_OP_NO_SSLv3)); + rb_define_const(mSSL, "OP_NO_TLSv1", ULONG2NUM(SSL_OP_NO_TLSv1)); + rb_define_const(mSSL, "OP_NO_TLSv1_1", ULONG2NUM(SSL_OP_NO_TLSv1_1)); + rb_define_const(mSSL, "OP_NO_TLSv1_2", ULONG2NUM(SSL_OP_NO_TLSv1_2)); + rb_define_const(mSSL, "OP_NO_TLSv1_3", ULONG2NUM(SSL_OP_NO_TLSv1_3)); + rb_define_const(mSSL, "OP_CIPHER_SERVER_PREFERENCE", ULONG2NUM(SSL_OP_CIPHER_SERVER_PREFERENCE)); + rb_define_const(mSSL, "OP_TLS_ROLLBACK_BUG", ULONG2NUM(SSL_OP_TLS_ROLLBACK_BUG)); +#ifdef SSL_OP_NO_RENEGOTIATION /* OpenSSL 1.1.1, missing in LibreSSL */ + rb_define_const(mSSL, "OP_NO_RENEGOTIATION", ULONG2NUM(SSL_OP_NO_RENEGOTIATION)); +#endif + rb_define_const(mSSL, "OP_CRYPTOPRO_TLSEXT_BUG", ULONG2NUM(SSL_OP_CRYPTOPRO_TLSEXT_BUG)); + + /* SSL_OP_* flags for DTLS */ +#if 0 + rb_define_const(mSSL, "OP_NO_QUERY_MTU", ULONG2NUM(SSL_OP_NO_QUERY_MTU)); + rb_define_const(mSSL, "OP_COOKIE_EXCHANGE", ULONG2NUM(SSL_OP_COOKIE_EXCHANGE)); + rb_define_const(mSSL, "OP_CISCO_ANYCONNECT", ULONG2NUM(SSL_OP_CISCO_ANYCONNECT)); +#endif + + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_MICROSOFT_SESS_ID_BUG", ULONG2NUM(SSL_OP_MICROSOFT_SESS_ID_BUG)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_NETSCAPE_CHALLENGE_BUG", ULONG2NUM(SSL_OP_NETSCAPE_CHALLENGE_BUG)); + /* Deprecated in OpenSSL 0.9.8q and 1.0.0c. */ + rb_define_const(mSSL, "OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", ULONG2NUM(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG)); + /* Deprecated in OpenSSL 1.0.1h and 1.0.2. */ + rb_define_const(mSSL, "OP_SSLREF2_REUSE_CERT_TYPE_BUG", ULONG2NUM(SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_MICROSOFT_BIG_SSLV3_BUFFER", ULONG2NUM(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)); + /* Deprecated in OpenSSL 0.9.7h and 0.9.8b. */ + rb_define_const(mSSL, "OP_MSIE_SSLV2_RSA_PADDING", ULONG2NUM(SSL_OP_MSIE_SSLV2_RSA_PADDING)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_SSLEAY_080_CLIENT_DH_BUG", ULONG2NUM(SSL_OP_SSLEAY_080_CLIENT_DH_BUG)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_TLS_D5_BUG", ULONG2NUM(SSL_OP_TLS_D5_BUG)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_TLS_BLOCK_PADDING_BUG", ULONG2NUM(SSL_OP_TLS_BLOCK_PADDING_BUG)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_SINGLE_ECDH_USE", ULONG2NUM(SSL_OP_SINGLE_ECDH_USE)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_SINGLE_DH_USE", ULONG2NUM(SSL_OP_SINGLE_DH_USE)); + /* Deprecated in OpenSSL 1.0.1k and 1.0.2. */ + rb_define_const(mSSL, "OP_EPHEMERAL_RSA", ULONG2NUM(SSL_OP_EPHEMERAL_RSA)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_NO_SSLv2", ULONG2NUM(SSL_OP_NO_SSLv2)); + /* Deprecated in OpenSSL 1.0.1. */ + rb_define_const(mSSL, "OP_PKCS1_CHECK_1", ULONG2NUM(SSL_OP_PKCS1_CHECK_1)); + /* Deprecated in OpenSSL 1.0.1. */ + rb_define_const(mSSL, "OP_PKCS1_CHECK_2", ULONG2NUM(SSL_OP_PKCS1_CHECK_2)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_NETSCAPE_CA_DN_BUG", ULONG2NUM(SSL_OP_NETSCAPE_CA_DN_BUG)); + /* Deprecated in OpenSSL 1.1.0. */ + rb_define_const(mSSL, "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", ULONG2NUM(SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG)); + + + /* + * SSL/TLS version constants. Used by SSLContext#min_version= and + * #max_version= + */ + /* SSL 2.0 */ + rb_define_const(mSSL, "SSL2_VERSION", INT2NUM(SSL2_VERSION)); + /* SSL 3.0 */ + rb_define_const(mSSL, "SSL3_VERSION", INT2NUM(SSL3_VERSION)); + /* TLS 1.0 */ + rb_define_const(mSSL, "TLS1_VERSION", INT2NUM(TLS1_VERSION)); + /* TLS 1.1 */ + rb_define_const(mSSL, "TLS1_1_VERSION", INT2NUM(TLS1_1_VERSION)); + /* TLS 1.2 */ + rb_define_const(mSSL, "TLS1_2_VERSION", INT2NUM(TLS1_2_VERSION)); + /* TLS 1.3 */ + rb_define_const(mSSL, "TLS1_3_VERSION", INT2NUM(TLS1_3_VERSION)); + + + sym_exception = ID2SYM(rb_intern_const("exception")); + sym_wait_readable = ID2SYM(rb_intern_const("wait_readable")); + sym_wait_writable = ID2SYM(rb_intern_const("wait_writable")); + + id_npn_protocols_encoded = rb_intern_const("npn_protocols_encoded"); + id_each = rb_intern_const("each"); + +#define DefIVarID(name) do \ + id_i_##name = rb_intern_const("@"#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(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(keylog_cb); + DefIVarID(tmp_dh_callback); + + DefIVarID(io); + DefIVarID(context); + DefIVarID(hostname); +#endif /* !defined(OPENSSL_NO_SOCK) */ } diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h index 487f41216c..a87e62d450 100644 --- a/ext/openssl/ossl_ssl.h +++ b/ext/openssl/ossl_ssl.h @@ -1,36 +1,36 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_SSL_H_) #define _OSSL_SSL_H_ -#define GetSSLSession(obj, sess) do { \ - Data_Get_Struct(obj, SSL_SESSION, sess); \ - if (!sess) { \ - ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ - } \ +#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 SafeGetSSLSession(obj, sess) do { \ - OSSL_Check_Kind(obj, cSSLSession); \ - GetSSLSession(obj, sess); \ +#define GetSSLSession(obj, sess) do { \ + TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \ + if (!(sess)) { \ + ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ + } \ } while (0) - + +extern const rb_data_type_t ossl_ssl_type; +extern const rb_data_type_t ossl_ssl_session_type; extern VALUE mSSL; -extern VALUE eSSLError; extern VALUE cSSLSocket; -extern VALUE cSSLContext; extern VALUE cSSLSession; void Init_ossl_ssl(void); void Init_ossl_ssl_session(void); #endif /* _OSSL_SSL_H_ */ - diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c index b347f2c1b2..8a2fbf4100 100644 --- a/ext/openssl/ossl_ssl_session.c +++ b/ext/openssl/ossl_ssl_session.c @@ -4,203 +4,249 @@ #include "ossl.h" -#define GetSSLSession(obj, sess) do { \ - Data_Get_Struct(obj, SSL_SESSION, sess); \ - if (!sess) { \ - ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ - } \ -} while (0) - -#define SafeGetSSLSession(obj, sess) do { \ - OSSL_Check_Kind(obj, cSSLSession); \ - GetSSLSession(obj, sess); \ -} while (0) - - +#ifndef OPENSSL_NO_SOCK VALUE cSSLSession; static VALUE eSSLSession; +static void +ossl_ssl_session_free(void *ptr) +{ + SSL_SESSION_free(ptr); +} + +const rb_data_type_t ossl_ssl_session_type = { + "OpenSSL/SSL/Session", + { + 0, ossl_ssl_session_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + static VALUE ossl_ssl_session_alloc(VALUE klass) { - return Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL); + return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL); } /* * 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. -*/ -static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) + * 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; - VALUE obj; - unsigned char *p; + SSL_SESSION *ctx; - if (RDATA(self)->data) - ossl_raise(eSSLSession, "SSL Session already initialized"); + if (RTYPEDDATA_DATA(self)) + ossl_raise(eSSLSession, "SSL Session already initialized"); - if (rb_obj_is_instance_of(arg1, cSSLSocket)) { - SSL *ssl; + if (rb_obj_is_instance_of(arg1, cSSLSocket)) { + SSL *ssl; - Data_Get_Struct(arg1, SSL, ssl); + GetSSL(arg1, ssl); - if ((ctx = SSL_get1_session(ssl)) == NULL) - ossl_raise(eSSLSession, "no session available"); - } else { - BIO *in = ossl_obj2bio(arg1); + if ((ctx = SSL_get1_session(ssl)) == NULL) + ossl_raise(eSSLSession, "no session available"); + } + else { + BIO *in = ossl_obj2bio(&arg1); - ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL); + ctx = d2i_SSL_SESSION_bio(in, NULL); + if (!ctx) { + OSSL_BIO_reset(in); + ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL); + } + BIO_free(in); + if (!ctx) + ossl_raise(rb_eArgError, "unknown type"); + } - if (!ctx) { - BIO_reset(in); - ctx = d2i_SSL_SESSION_bio(in, NULL); - } + RTYPEDDATA_DATA(self) = ctx; - BIO_free(in); + return self; +} - if (!ctx) - ossl_raise(rb_eArgError, "unknown type"); - } +/* :nodoc: */ +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 */ + GetSSLSession(other, sess_other); - /* should not happen */ - if (ctx == NULL) - ossl_raise(eSSLSession, "ctx not set - internal error"); + 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"); - RDATA(self)->data = ctx; + RTYPEDDATA_DATA(self) = sess_new; + SSL_SESSION_free(sess); - return self; + return self; +} + +static int +ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b) +{ + 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 (SSL_SESSION_get_protocol_version(a) != SSL_SESSION_get_protocol_version(b)) + return 1; + if (a_len != b_len) + return 1; + + return CRYPTO_memcmp(a_sid, b_sid, a_len); } /* * 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; + SSL_SESSION *ctx1, *ctx2; - GetSSLSession(val1, ctx1); - SafeGetSSLSession(val2, ctx2); + GetSSLSession(val1, ctx1); + GetSSLSession(val2, ctx2); - switch (SSL_SESSION_cmp(ctx1, ctx2)) { - case 0: return Qtrue; - default: return Qfalse; - } + switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) { + case 0: return Qtrue; + default: return Qfalse; + } } /* * call-seq: * session.time -> Time * -*/ -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); + GetSSLSession(self, ctx); + t = SSL_SESSION_get_time(ctx); + if (t == 0) + return Qnil; - t = SSL_SESSION_get_time(ctx); + return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t)); +} + +/* + * call-seq: + * session.timeout -> Integer + * + * Returns the timeout value set for the session, in seconds from the + * established time. + * + */ +static VALUE +ossl_ssl_session_get_timeout(VALUE self) +{ + SSL_SESSION *ctx; + long t; - if (t == 0) - return Qnil; + GetSSLSession(self, ctx); + t = SSL_SESSION_get_timeout(ctx); - return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t)); + return LONG2NUM(t); } /* * call-seq: - * session.timeout -> integer + * session.time = time + * session.time = integer * - * How long until the session expires in seconds. + * Sets start time of the session. Time resolution is in seconds. * -*/ -static VALUE ossl_ssl_session_get_timeout(VALUE self) + */ +static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v) { - SSL_SESSION *ctx; - time_t t; - - GetSSLSession(self, ctx); + SSL_SESSION *ctx; + long t; + + GetSSLSession(self, ctx); + if (rb_obj_is_instance_of(time_v, rb_cTime)) { + time_v = rb_funcall(time_v, rb_intern("to_i"), 0); + } + t = NUM2LONG(time_v); + SSL_SESSION_set_time(ctx, t); + return ossl_ssl_session_get_time(self); +} - t = SSL_SESSION_get_timeout(ctx); +/* + * call-seq: + * 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; + long t; - return ULONG2NUM(t); + GetSSLSession(self, ctx); + t = NUM2LONG(time_v); + SSL_SESSION_set_timeout(ctx, t); + return ossl_ssl_session_get_timeout(self); } -#define SSLSESSION_SET_TIME(func) \ - static VALUE ossl_ssl_session_set_##func(VALUE self, VALUE time_v) \ - { \ - SSL_SESSION *ctx; \ - time_t t; \ - \ - GetSSLSession(self, ctx); \ - \ - if (rb_obj_is_instance_of(time_v, rb_cTime)) { \ - time_v = rb_funcall(time_v, rb_intern("to_i"), 0); \ - } else if (FIXNUM_P(time_v)) { \ - ; \ - } else { \ - rb_raise(rb_eArgError, "unknown type"); \ - } \ - \ - t = NUM2ULONG(time_v); \ - \ - SSL_SESSION_set_##func(ctx, t); \ - \ - return ossl_ssl_session_get_##func(self); \ - } - -SSLSESSION_SET_TIME(time) -SSLSESSION_SET_TIME(timeout) - -#ifdef HAVE_SSL_SESSION_GET_ID /* * call-seq: - * session.id -> aString + * session.id -> String * * Returns the Session ID. -*/ + */ static VALUE ossl_ssl_session_get_id(VALUE self) { - SSL_SESSION *ctx; - const unsigned char *p = NULL; - unsigned int i = 0; + SSL_SESSION *ctx; + const unsigned char *p = NULL; + unsigned int i = 0; - GetSSLSession(self, ctx); + GetSSLSession(self, ctx); - p = SSL_SESSION_get_id(ctx, &i); + p = SSL_SESSION_get_id(ctx, &i); - return rb_str_new(p, i); + 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; - unsigned char buf[1024*10], *p; - int len; - - GetSSLSession(self, ctx); - - p = buf; - len = i2d_SSL_SESSION(ctx, &p); - - if (len <= 0) - ossl_raise(eSSLSession, "i2d_SSL_SESSION"); - else if (len >= sizeof(buf)) - ossl_raise(eSSLSession, "i2d_SSL_SESSION too large"); - - return rb_str_new(p, len); + SSL_SESSION *ctx; + unsigned char *p; + int len; + VALUE str; + + GetSSLSession(self, ctx); + len = i2d_SSL_SESSION(ctx, NULL); + if (len <= 0) { + ossl_raise(eSSLSession, "i2d_SSL_SESSION"); + } + + str = rb_str_new(0, len); + p = (unsigned char *)RSTRING_PTR(str); + i2d_SSL_SESSION(ctx, &p); + ossl_str_adjust(str, p); + return str; } /* @@ -208,31 +254,25 @@ 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); - - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eSSLSession, "BIO_s_mem()"); - } - - if (!(i=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; + SSL_SESSION *ctx; + BIO *out; + + GetSSLSession(self, ctx); + + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eSSLSession, "BIO_s_mem()"); + } + + if (!PEM_write_bio_SSL_SESSION(out, ctx)) { + BIO_free(out); + ossl_raise(eSSLSession, "SSL_SESSION_print()"); + } + + + return ossl_membio2str(out); } @@ -240,57 +280,48 @@ 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); - - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eSSLSession, "BIO_s_mem()"); - } - - if (!SSL_SESSION_print(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; + SSL_SESSION *ctx; + BIO *out; + + GetSSLSession(self, ctx); + + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eSSLSession, "BIO_s_mem()"); + } + + if (!SSL_SESSION_print(out, ctx)) { + BIO_free(out); + ossl_raise(eSSLSession, "SSL_SESSION_print()"); + } + + return ossl_membio2str(out); } - + +#endif /* !defined(OPENSSL_NO_SOCK) */ void Init_ossl_ssl_session(void) { -#if 0 /* let rdoc know about mOSSL */ - mOSSL = rb_define_module("OpenSSL"); - mSSL = rb_define_module_under(mOSSL, "SSL"); -#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_method(cSSLSession, "==", ossl_ssl_session_eq, 1); - - rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0); - 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); -#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); +#ifndef OPENSSL_NO_SOCK + 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_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1); + + rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1); + + rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0); + 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); + rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0); + 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); +#endif /* !defined(OPENSSL_NO_SOCK) */ } diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c new file mode 100644 index 0000000000..b31a854a63 --- /dev/null +++ b/ext/openssl/ossl_ts.c @@ -0,0 +1,1551 @@ +/* + * + * Copyright (C) 2010 Martin Bosslet <Martin.Bosslet@googlemail.com> + * All rights reserved. + */ +/* + * This program is licenced under the same licence as Ruby. + * (See the file 'COPYING'.) + */ +#include "ossl.h" + +#ifndef OPENSSL_NO_TS + +#define NewTSRequest(klass) \ + TypedData_Wrap_Struct((klass), &ossl_ts_req_type, 0) +#define SetTSRequest(obj, req) do { \ + if (!(req)) { \ + ossl_raise(rb_eRuntimeError, "TS_REQ wasn't initialized."); \ + } \ + RTYPEDDATA_DATA(obj) = (req); \ +} while (0) +#define GetTSRequest(obj, req) do { \ + TypedData_Get_Struct((obj), TS_REQ, &ossl_ts_req_type, (req)); \ + if (!(req)) { \ + ossl_raise(rb_eRuntimeError, "TS_REQ wasn't initialized."); \ + } \ +} while (0) + +#define NewTSResponse(klass) \ + TypedData_Wrap_Struct((klass), &ossl_ts_resp_type, 0) +#define SetTSResponse(obj, resp) do { \ + if (!(resp)) { \ + ossl_raise(rb_eRuntimeError, "TS_RESP wasn't initialized."); \ + } \ + RTYPEDDATA_DATA(obj) = (resp); \ +} while (0) +#define GetTSResponse(obj, resp) do { \ + TypedData_Get_Struct((obj), TS_RESP, &ossl_ts_resp_type, (resp)); \ + if (!(resp)) { \ + ossl_raise(rb_eRuntimeError, "TS_RESP wasn't initialized."); \ + } \ +} while (0) + +#define NewTSTokenInfo(klass) \ + TypedData_Wrap_Struct((klass), &ossl_ts_token_info_type, 0) +#define SetTSTokenInfo(obj, info) do { \ + if (!(info)) { \ + ossl_raise(rb_eRuntimeError, "TS_TST_INFO wasn't initialized."); \ + } \ + RTYPEDDATA_DATA(obj) = (info); \ +} while (0) +#define GetTSTokenInfo(obj, info) do { \ + TypedData_Get_Struct((obj), TS_TST_INFO, &ossl_ts_token_info_type, (info)); \ + if (!(info)) { \ + ossl_raise(rb_eRuntimeError, "TS_TST_INFO wasn't initialized."); \ + } \ +} while (0) + +#define ossl_tsfac_get_default_policy_id(o) rb_attr_get((o),rb_intern("@default_policy_id")) +#define ossl_tsfac_get_serial_number(o) rb_attr_get((o),rb_intern("@serial_number")) +#define ossl_tsfac_get_gen_time(o) rb_attr_get((o),rb_intern("@gen_time")) +#define ossl_tsfac_get_additional_certs(o) rb_attr_get((o),rb_intern("@additional_certs")) +#define ossl_tsfac_get_allowed_digests(o) rb_attr_get((o),rb_intern("@allowed_digests")) + +static VALUE mTimestamp; +static VALUE eTimestampError; +static VALUE cTimestampRequest; +static VALUE cTimestampResponse; +static VALUE cTimestampTokenInfo; +static VALUE cTimestampFactory; +static VALUE sBAD_ALG, sBAD_REQUEST, sBAD_DATA_FORMAT, sTIME_NOT_AVAILABLE; +static VALUE sUNACCEPTED_POLICY, sUNACCEPTED_EXTENSION, sADD_INFO_NOT_AVAILABLE; +static VALUE sSYSTEM_FAILURE; + +static void +ossl_ts_req_free(void *ptr) +{ + TS_REQ_free(ptr); +} + +static const rb_data_type_t ossl_ts_req_type = { + "OpenSSL/Timestamp/Request", + { + 0, ossl_ts_req_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static void +ossl_ts_resp_free(void *ptr) +{ + TS_RESP_free(ptr); +} + +static const rb_data_type_t ossl_ts_resp_type = { + "OpenSSL/Timestamp/Response", + { + 0, ossl_ts_resp_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static void +ossl_ts_token_info_free(void *ptr) +{ + TS_TST_INFO_free(ptr); +} + +static const rb_data_type_t ossl_ts_token_info_type = { + "OpenSSL/Timestamp/TokenInfo", + { + 0, ossl_ts_token_info_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE +asn1_to_der(void *template, int (*i2d)(void *template, unsigned char **pp)) +{ + VALUE str; + int len; + unsigned char *p; + + if((len = i2d(template, NULL)) <= 0) + ossl_raise(eTimestampError, "Error when encoding to DER"); + str = rb_str_new(0, len); + p = (unsigned char *)RSTRING_PTR(str); + if(i2d(template, &p) <= 0) + ossl_raise(eTimestampError, "Error when encoding to DER"); + rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str)); + + return str; +} + +static VALUE +obj_to_asn1obj_i(VALUE obj) +{ + return (VALUE)ossl_to_asn1obj(obj); +} + +static VALUE +ossl_ts_req_alloc(VALUE klass) +{ + TS_REQ *req; + VALUE obj; + + obj = NewTSRequest(klass); + if (!(req = TS_REQ_new())) + ossl_raise(eTimestampError, NULL); + SetTSRequest(obj, req); + + /* Defaults */ + TS_REQ_set_version(req, 1); + TS_REQ_set_cert_req(req, 1); + + return obj; +} + +/* + * When creating a Request with the +File+ or +string+ parameter, the + * corresponding +File+ or +string+ must be DER-encoded. + * + * call-seq: + * OpenSSL::Timestamp::Request.new(file) -> request + * OpenSSL::Timestamp::Request.new(string) -> request + * OpenSSL::Timestamp::Request.new -> empty request + */ +static VALUE +ossl_ts_req_initialize(int argc, VALUE *argv, VALUE self) +{ + TS_REQ *ts_req = DATA_PTR(self); + BIO *in; + VALUE arg; + + if(rb_scan_args(argc, argv, "01", &arg) == 0) { + return self; + } + + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); + ts_req = d2i_TS_REQ_bio(in, &ts_req); + BIO_free(in); + if (!ts_req) { + DATA_PTR(self) = NULL; + ossl_raise(eTimestampError, "Error when decoding the timestamp request"); + } + DATA_PTR(self) = ts_req; + + return self; +} + +/* + * Returns the 'short name' of the object identifier that represents the + * algorithm that was used to create the message imprint digest. + * + * call-seq: + * request.algorithm -> string + */ +static VALUE +ossl_ts_req_get_algorithm(VALUE self) +{ + TS_REQ *req; + TS_MSG_IMPRINT *mi; + X509_ALGOR *algor; + const ASN1_OBJECT *obj; + + GetTSRequest(self, req); + mi = TS_REQ_get_msg_imprint(req); + algor = TS_MSG_IMPRINT_get_algo(mi); + X509_ALGOR_get0(&obj, NULL, NULL, algor); + return ossl_asn1obj_to_string(obj); +} + +/* + * Allows to set the object identifier or the 'short name' of the + * algorithm that was used to create the message imprint digest. + * + * ===Example: + * request.algorithm = "SHA1" + * + * call-seq: + * request.algorithm = "string" -> string + */ +static VALUE +ossl_ts_req_set_algorithm(VALUE self, VALUE algo) +{ + TS_REQ *req; + TS_MSG_IMPRINT *mi; + ASN1_OBJECT *obj; + X509_ALGOR *algor; + + GetTSRequest(self, req); + obj = ossl_to_asn1obj(algo); + mi = TS_REQ_get_msg_imprint(req); + algor = TS_MSG_IMPRINT_get_algo(mi); + if (!X509_ALGOR_set0(algor, obj, V_ASN1_NULL, NULL)) { + ASN1_OBJECT_free(obj); + ossl_raise(eTimestampError, "X509_ALGOR_set0"); + } + + return algo; +} + +/* + * Returns the message imprint (digest) of the data to be timestamped. + * + * call-seq: + * request.message_imprint -> string or nil + */ +static VALUE +ossl_ts_req_get_msg_imprint(VALUE self) +{ + TS_REQ *req; + TS_MSG_IMPRINT *mi; + ASN1_OCTET_STRING *hashed_msg; + VALUE ret; + + GetTSRequest(self, req); + mi = TS_REQ_get_msg_imprint(req); + hashed_msg = TS_MSG_IMPRINT_get_msg(mi); + + ret = asn1str_to_str(hashed_msg); + + return ret; +} + +/* + * Set the message imprint digest. + * + * call-seq: + * request.message_imprint = "string" -> string + */ +static VALUE +ossl_ts_req_set_msg_imprint(VALUE self, VALUE hash) +{ + TS_REQ *req; + TS_MSG_IMPRINT *mi; + StringValue(hash); + + GetTSRequest(self, req); + mi = TS_REQ_get_msg_imprint(req); + if (!TS_MSG_IMPRINT_set_msg(mi, (unsigned char *)RSTRING_PTR(hash), RSTRING_LENINT(hash))) + ossl_raise(eTimestampError, "TS_MSG_IMPRINT_set_msg"); + + return hash; +} + +/* + * Returns the version of this request. +1+ is the default value. + * + * call-seq: + * request.version -> Integer + */ +static VALUE +ossl_ts_req_get_version(VALUE self) +{ + TS_REQ *req; + + GetTSRequest(self, req); + return LONG2NUM(TS_REQ_get_version(req)); +} + +/* + * Sets the version number for this Request. This should be +1+ for compliant + * servers. + * + * call-seq: + * request.version = number -> Integer + */ +static VALUE +ossl_ts_req_set_version(VALUE self, VALUE version) +{ + TS_REQ *req; + long ver; + + if ((ver = NUM2LONG(version)) < 0) + ossl_raise(eTimestampError, "version must be >= 0!"); + GetTSRequest(self, req); + if (!TS_REQ_set_version(req, ver)) + ossl_raise(eTimestampError, "TS_REQ_set_version"); + + return version; +} + +/* + * Returns the 'short name' of the object identifier that represents the + * timestamp policy under which the server shall create the timestamp. + * + * call-seq: + * request.policy_id -> string or nil + */ +static VALUE +ossl_ts_req_get_policy_id(VALUE self) +{ + TS_REQ *req; + + GetTSRequest(self, req); + if (!TS_REQ_get_policy_id(req)) + return Qnil; + return ossl_asn1obj_to_string(TS_REQ_get_policy_id(req)); +} + +/* + * Allows to set the object identifier that represents the + * timestamp policy under which the server shall create the timestamp. This + * may be left +nil+, implying that the timestamp server will issue the + * timestamp using some default policy. + * + * ===Example: + * request.policy_id = "1.2.3.4.5" + * + * call-seq: + * request.policy_id = "string" -> string + */ +static VALUE +ossl_ts_req_set_policy_id(VALUE self, VALUE oid) +{ + TS_REQ *req; + ASN1_OBJECT *obj; + int ok; + + GetTSRequest(self, req); + obj = ossl_to_asn1obj(oid); + ok = TS_REQ_set_policy_id(req, obj); + ASN1_OBJECT_free(obj); + if (!ok) + ossl_raise(eTimestampError, "TS_REQ_set_policy_id"); + + return oid; +} + +/* + * Returns the nonce (number used once) that the server shall include in its + * response. + * + * call-seq: + * request.nonce -> BN or nil + */ +static VALUE +ossl_ts_req_get_nonce(VALUE self) +{ + TS_REQ *req; + const ASN1_INTEGER * nonce; + + GetTSRequest(self, req); + if (!(nonce = TS_REQ_get_nonce(req))) + return Qnil; + return asn1integer_to_num(nonce); +} + +/* + * Sets the nonce (number used once) that the server shall include in its + * response. If the nonce is set, the server must return the same nonce value in + * a valid Response. + * + * call-seq: + * request.nonce = number -> BN + */ +static VALUE +ossl_ts_req_set_nonce(VALUE self, VALUE num) +{ + TS_REQ *req; + ASN1_INTEGER *nonce; + int ok; + + GetTSRequest(self, req); + nonce = num_to_asn1integer(num, NULL); + ok = TS_REQ_set_nonce(req, nonce); + ASN1_INTEGER_free(nonce); + if (!ok) + ossl_raise(eTimestampError, NULL); + return num; +} + +/* + * Indicates whether the response shall contain the timestamp authority's + * certificate or not. + * + * call-seq: + * request.cert_requested? -> true or false + */ +static VALUE +ossl_ts_req_get_cert_requested(VALUE self) +{ + TS_REQ *req; + + GetTSRequest(self, req); + return TS_REQ_get_cert_req(req) ? Qtrue: Qfalse; +} + +/* + * Specify whether the response shall contain the timestamp authority's + * certificate or not. The default value is +true+. + * + * call-seq: + * request.cert_requested = boolean -> true or false + */ +static VALUE +ossl_ts_req_set_cert_requested(VALUE self, VALUE requested) +{ + TS_REQ *req; + + GetTSRequest(self, req); + TS_REQ_set_cert_req(req, RTEST(requested)); + + return requested; +} + +/* + * DER-encodes this Request. + * + * call-seq: + * request.to_der -> DER-encoded string + */ +static VALUE +ossl_ts_req_to_der(VALUE self) +{ + TS_REQ *req; + TS_MSG_IMPRINT *mi; + X509_ALGOR *algo; + const ASN1_OBJECT *obj; + ASN1_OCTET_STRING *hashed_msg; + + GetTSRequest(self, req); + mi = TS_REQ_get_msg_imprint(req); + + algo = TS_MSG_IMPRINT_get_algo(mi); + X509_ALGOR_get0(&obj, NULL, NULL, algo); + if (OBJ_obj2nid(obj) == NID_undef) + ossl_raise(eTimestampError, "Message imprint missing algorithm"); + + hashed_msg = TS_MSG_IMPRINT_get_msg(mi); + if (!ASN1_STRING_length(hashed_msg)) + ossl_raise(eTimestampError, "Message imprint missing hashed message"); + + return asn1_to_der((void *)req, (int (*)(void *, unsigned char **))i2d_TS_REQ); +} + +static VALUE +ossl_ts_req_to_text(VALUE self) +{ + TS_REQ *req; + BIO *out; + + GetTSRequest(self, req); + + out = BIO_new(BIO_s_mem()); + if (!out) ossl_raise(eTimestampError, NULL); + + if (!TS_REQ_print_bio(out, req)) { + BIO_free(out); + ossl_raise(eTimestampError, NULL); + } + + return ossl_membio2str(out); +} + +static VALUE +ossl_ts_resp_alloc(VALUE klass) +{ + TS_RESP *resp; + VALUE obj; + + obj = NewTSResponse(klass); + if (!(resp = TS_RESP_new())) + ossl_raise(eTimestampError, NULL); + SetTSResponse(obj, resp); + + return obj; +} + +/* + * Creates a Response from a +File+ or +string+ parameter, the + * corresponding +File+ or +string+ must be DER-encoded. Please note + * that Response is an immutable read-only class. If you'd like to create + * timestamps please refer to Factory instead. + * + * call-seq: + * OpenSSL::Timestamp::Response.new(file) -> response + * OpenSSL::Timestamp::Response.new(string) -> response + */ +static VALUE +ossl_ts_resp_initialize(VALUE self, VALUE der) +{ + TS_RESP *ts_resp = DATA_PTR(self); + BIO *in; + + der = ossl_to_der_if_possible(der); + in = ossl_obj2bio(&der); + ts_resp = d2i_TS_RESP_bio(in, &ts_resp); + BIO_free(in); + if (!ts_resp) { + DATA_PTR(self) = NULL; + ossl_raise(eTimestampError, "Error when decoding the timestamp response"); + } + DATA_PTR(self) = ts_resp; + + return self; +} + +/* + * Returns one of GRANTED, GRANTED_WITH_MODS, REJECTION, WAITING, + * REVOCATION_WARNING or REVOCATION_NOTIFICATION. A timestamp token has + * been created only in case +status+ is equal to GRANTED or GRANTED_WITH_MODS. + * + * call-seq: + * response.status -> BN (never nil) + */ +static VALUE +ossl_ts_resp_get_status(VALUE self) +{ + TS_RESP *resp; + TS_STATUS_INFO *si; + const ASN1_INTEGER *st; + + GetTSResponse(self, resp); + si = TS_RESP_get_status_info(resp); + st = TS_STATUS_INFO_get0_status(si); + + return asn1integer_to_num(st); +} + +/* + * In cases no timestamp token has been created, this field contains further + * info about the reason why response creation failed. The method returns either + * nil (the request was successful and a timestamp token was created) or one of + * the following: + * * :BAD_ALG - Indicates that the timestamp server rejects the message + * imprint algorithm used in the Request + * * :BAD_REQUEST - Indicates that the timestamp server was not able to process + * the Request properly + * * :BAD_DATA_FORMAT - Indicates that the timestamp server was not able to + * parse certain data in the Request + * * :TIME_NOT_AVAILABLE - Indicates that the server could not access its time + * source + * * :UNACCEPTED_POLICY - Indicates that the requested policy identifier is not + * recognized or supported by the timestamp server + * * :UNACCEPTED_EXTENSIION - Indicates that an extension in the Request is + * not supported by the timestamp server + * * :ADD_INFO_NOT_AVAILABLE -Indicates that additional information requested + * is either not understood or currently not available + * * :SYSTEM_FAILURE - Timestamp creation failed due to an internal error that + * occurred on the timestamp server + * + * call-seq: + * response.failure_info -> nil or symbol + */ +static VALUE +ossl_ts_resp_get_failure_info(VALUE self) +{ + TS_RESP *resp; + TS_STATUS_INFO *si; + const ASN1_BIT_STRING *fi; + + GetTSResponse(self, resp); + si = TS_RESP_get_status_info(resp); + fi = TS_STATUS_INFO_get0_failure_info(si); + if (!fi) + return Qnil; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_ALG)) + return sBAD_ALG; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_REQUEST)) + return sBAD_REQUEST; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_DATA_FORMAT)) + return sBAD_DATA_FORMAT; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_TIME_NOT_AVAILABLE)) + return sTIME_NOT_AVAILABLE; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_POLICY)) + return sUNACCEPTED_POLICY; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_EXTENSION)) + return sUNACCEPTED_EXTENSION; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_ADD_INFO_NOT_AVAILABLE)) + return sADD_INFO_NOT_AVAILABLE; + if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_SYSTEM_FAILURE)) + return sSYSTEM_FAILURE; + + ossl_raise(eTimestampError, "Unrecognized failure info."); +} + +/* + * In cases of failure this field may contain an array of strings further + * describing the origin of the failure. + * + * call-seq: + * response.status_text -> Array of strings or nil + */ +static VALUE +ossl_ts_resp_get_status_text(VALUE self) +{ + TS_RESP *resp; + TS_STATUS_INFO *si; + const STACK_OF(ASN1_UTF8STRING) *text; + ASN1_UTF8STRING *current; + int i; + VALUE ret = rb_ary_new(); + + GetTSResponse(self, resp); + si = TS_RESP_get_status_info(resp); + if ((text = TS_STATUS_INFO_get0_text(si))) { + for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) { + current = sk_ASN1_UTF8STRING_value(text, i); + rb_ary_push(ret, asn1str_to_str(current)); + } + } + + return ret; +} + +/* + * If a timestamp token is present, this returns it in the form of a + * OpenSSL::PKCS7. + * + * call-seq: + * response.token -> nil or OpenSSL::PKCS7 + */ +static VALUE +ossl_ts_resp_get_token(VALUE self) +{ + TS_RESP *resp; + PKCS7 *p7; + + GetTSResponse(self, resp); + if (!(p7 = TS_RESP_get_token(resp))) + return Qnil; + return ossl_pkcs7_new(p7); +} + +/* + * Get the response's token info if present. + * + * call-seq: + * response.token_info -> nil or OpenSSL::Timestamp::TokenInfo + */ +static VALUE +ossl_ts_resp_get_token_info(VALUE self) +{ + TS_RESP *resp; + TS_TST_INFO *info, *copy; + VALUE obj; + + GetTSResponse(self, resp); + if (!(info = TS_RESP_get_tst_info(resp))) + return Qnil; + + obj = NewTSTokenInfo(cTimestampTokenInfo); + + if (!(copy = TS_TST_INFO_dup(info))) + ossl_raise(eTimestampError, NULL); + + SetTSTokenInfo(obj, copy); + + return obj; +} + +/* + * If the Request specified to request the TSA certificate + * (Request#cert_requested = true), then this field contains the + * certificate of the timestamp authority. + * + * call-seq: + * response.tsa_certificate -> OpenSSL::X509::Certificate or nil + */ +static VALUE +ossl_ts_resp_get_tsa_certificate(VALUE self) +{ + TS_RESP *resp; + PKCS7 *p7; + PKCS7_SIGNER_INFO *ts_info; + X509 *cert; + + GetTSResponse(self, resp); + if (!(p7 = TS_RESP_get_token(resp))) + return Qnil; + ts_info = sk_PKCS7_SIGNER_INFO_value(p7->d.sign->signer_info, 0); + cert = PKCS7_cert_from_signer_info(p7, ts_info); + if (!cert) + return Qnil; + return ossl_x509_new(cert); +} + +/* + * Returns the Response in DER-encoded form. + * + * call-seq: + * response.to_der -> string + */ +static VALUE +ossl_ts_resp_to_der(VALUE self) +{ + TS_RESP *resp; + + GetTSResponse(self, resp); + return asn1_to_der((void *)resp, (int (*)(void *, unsigned char **))i2d_TS_RESP); +} + +static VALUE +ossl_ts_resp_to_text(VALUE self) +{ + TS_RESP *resp; + BIO *out; + + GetTSResponse(self, resp); + + out = BIO_new(BIO_s_mem()); + if (!out) ossl_raise(eTimestampError, NULL); + + if (!TS_RESP_print_bio(out, resp)) { + BIO_free(out); + ossl_raise(eTimestampError, NULL); + } + + return ossl_membio2str(out); +} + +/* + * Verifies a timestamp token by checking the signature, validating the + * certificate chain implied by tsa_certificate and by checking conformance to + * a given Request. Mandatory parameters are the Request associated to this + * Response, and an OpenSSL::X509::Store of trusted roots. + * + * Intermediate certificates can optionally be supplied for creating the + * certificate chain. These intermediate certificates must all be + * instances of OpenSSL::X509::Certificate. + * + * If validation fails, several kinds of exceptions can be raised: + * * TypeError if types don't fit + * * TimestampError if something is wrong with the timestamp token itself, if + * it is not conformant to the Request, or if validation of the timestamp + * certificate chain fails. + * + * call-seq: + * response.verify(Request, root_store) -> Response + * response.verify(Request, root_store, [intermediate_cert]) -> Response + */ +static VALUE +ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self) +{ + VALUE ts_req, store, intermediates; + TS_RESP *resp; + TS_REQ *req; + X509_STORE *x509st; + TS_VERIFY_CTX *ctx; + STACK_OF(X509) *x509inter = NULL; + PKCS7* p7; + X509 *cert; + int status, i, ok; + + rb_scan_args(argc, argv, "21", &ts_req, &store, &intermediates); + + GetTSResponse(self, resp); + GetTSRequest(ts_req, req); + x509st = GetX509StorePtr(store); + + if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL))) { + ossl_raise(eTimestampError, "Error when creating the verification context."); + } + + if (!NIL_P(intermediates)) { + x509inter = ossl_protect_x509_ary2sk(intermediates, &status); + if (status) { + TS_VERIFY_CTX_free(ctx); + rb_jump_tag(status); + } + } else if (!(x509inter = sk_X509_new_null())) { + TS_VERIFY_CTX_free(ctx); + ossl_raise(eTimestampError, "sk_X509_new_null"); + } + + if (!(p7 = TS_RESP_get_token(resp))) { + TS_VERIFY_CTX_free(ctx); + sk_X509_pop_free(x509inter, X509_free); + ossl_raise(eTimestampError, "TS_RESP_get_token"); + } + for (i=0; i < sk_X509_num(p7->d.sign->cert); i++) { + cert = sk_X509_value(p7->d.sign->cert, i); + if (!sk_X509_push(x509inter, cert)) { + sk_X509_pop_free(x509inter, X509_free); + TS_VERIFY_CTX_free(ctx); + ossl_raise(eTimestampError, "sk_X509_push"); + } + X509_up_ref(cert); + } + + if (!X509_STORE_up_ref(x509st)) { + sk_X509_pop_free(x509inter, X509_free); + TS_VERIFY_CTX_free(ctx); + ossl_raise(eTimestampError, "X509_STORE_up_ref"); + } + +#ifdef HAVE_TS_VERIFY_CTX_SET0_CERTS + TS_VERIFY_CTX_set0_certs(ctx, x509inter); + TS_VERIFY_CTX_set0_store(ctx, x509st); +#else +# if OSSL_OPENSSL_PREREQ(3, 0, 0) || OSSL_IS_LIBRESSL + TS_VERIFY_CTX_set_certs(ctx, x509inter); +# else + TS_VERIFY_CTS_set_certs(ctx, x509inter); +# endif + TS_VERIFY_CTX_set_store(ctx, x509st); +#endif + TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE); + + ok = TS_RESP_verify_response(ctx, resp); + TS_VERIFY_CTX_free(ctx); + + if (!ok) + ossl_raise(eTimestampError, "TS_RESP_verify_response"); + + return self; +} + +static VALUE +ossl_ts_token_info_alloc(VALUE klass) +{ + TS_TST_INFO *info; + VALUE obj; + + obj = NewTSTokenInfo(klass); + if (!(info = TS_TST_INFO_new())) + ossl_raise(eTimestampError, NULL); + SetTSTokenInfo(obj, info); + + return obj; +} + +/* + * Creates a TokenInfo from a +File+ or +string+ parameter, the + * corresponding +File+ or +string+ must be DER-encoded. Please note + * that TokenInfo is an immutable read-only class. If you'd like to create + * timestamps please refer to Factory instead. + * + * call-seq: + * OpenSSL::Timestamp::TokenInfo.new(file) -> token-info + * OpenSSL::Timestamp::TokenInfo.new(string) -> token-info + */ +static VALUE +ossl_ts_token_info_initialize(VALUE self, VALUE der) +{ + TS_TST_INFO *info = DATA_PTR(self); + BIO *in; + + der = ossl_to_der_if_possible(der); + in = ossl_obj2bio(&der); + info = d2i_TS_TST_INFO_bio(in, &info); + BIO_free(in); + if (!info) { + DATA_PTR(self) = NULL; + ossl_raise(eTimestampError, "Error when decoding the timestamp token info"); + } + DATA_PTR(self) = info; + + return self; +} + +/* + * Returns the version number of the token info. With compliant servers, + * this value should be +1+ if present. If status is GRANTED or + * GRANTED_WITH_MODS. + * + * call-seq: + * token_info.version -> Integer or nil + */ +static VALUE +ossl_ts_token_info_get_version(VALUE self) +{ + TS_TST_INFO *info; + + GetTSTokenInfo(self, info); + return LONG2NUM(TS_TST_INFO_get_version(info)); +} + +/* + * Returns the timestamp policy object identifier of the policy this timestamp + * was created under. If status is GRANTED or GRANTED_WITH_MODS, this is never + * +nil+. + * + * ===Example: + * id = token_info.policy_id + * puts id -> "1.2.3.4.5" + * + * call-seq: + * token_info.policy_id -> string or nil + */ +static VALUE +ossl_ts_token_info_get_policy_id(VALUE self) +{ + TS_TST_INFO *info; + + GetTSTokenInfo(self, info); + return ossl_asn1obj_to_string(TS_TST_INFO_get_policy_id(info)); +} + +/* + * Returns the 'short name' of the object identifier representing the algorithm + * that was used to derive the message imprint digest. For valid timestamps, + * this is the same value that was already given in the Request. If status is + * GRANTED or GRANTED_WITH_MODS, this is never +nil+. + * + * ===Example: + * algo = token_info.algorithm + * puts algo -> "SHA1" + * + * call-seq: + * token_info.algorithm -> string or nil + */ +static VALUE +ossl_ts_token_info_get_algorithm(VALUE self) +{ + TS_TST_INFO *info; + TS_MSG_IMPRINT *mi; + X509_ALGOR *algo; + const ASN1_OBJECT *obj; + + GetTSTokenInfo(self, info); + mi = TS_TST_INFO_get_msg_imprint(info); + algo = TS_MSG_IMPRINT_get_algo(mi); + X509_ALGOR_get0(&obj, NULL, NULL, algo); + return ossl_asn1obj_to_string(obj); +} + +/* + * Returns the message imprint digest. For valid timestamps, + * this is the same value that was already given in the Request. + * If status is GRANTED or GRANTED_WITH_MODS, this is never +nil+. + * + * ===Example: + * mi = token_info.msg_imprint + * puts mi -> "DEADBEEF" + * + * call-seq: + * token_info.msg_imprint -> string. + */ +static VALUE +ossl_ts_token_info_get_msg_imprint(VALUE self) +{ + TS_TST_INFO *info; + TS_MSG_IMPRINT *mi; + ASN1_OCTET_STRING *hashed_msg; + VALUE ret; + + GetTSTokenInfo(self, info); + mi = TS_TST_INFO_get_msg_imprint(info); + hashed_msg = TS_MSG_IMPRINT_get_msg(mi); + ret = asn1str_to_str(hashed_msg); + + return ret; +} + +/* + * Returns serial number of the timestamp token. This value shall never be the + * same for two timestamp tokens issued by a dedicated timestamp authority. + * If status is GRANTED or GRANTED_WITH_MODS, this is never +nil+. + * + * call-seq: + * token_info.serial_number -> BN or nil + */ +static VALUE +ossl_ts_token_info_get_serial_number(VALUE self) +{ + TS_TST_INFO *info; + + GetTSTokenInfo(self, info); + return asn1integer_to_num(TS_TST_INFO_get_serial(info)); +} + +/* + * Returns time when this timestamp token was created. If status is GRANTED or + * GRANTED_WITH_MODS, this is never +nil+. + * + * call-seq: + * token_info.gen_time -> Time + */ +static VALUE +ossl_ts_token_info_get_gen_time(VALUE self) +{ + TS_TST_INFO *info; + + GetTSTokenInfo(self, info); + return asn1time_to_time(TS_TST_INFO_get_time(info)); +} + +/* + * If the ordering field is missing, or if the ordering field is present + * and set to false, then the genTime field only indicates the time at + * which the time-stamp token has been created by the TSA. In such a + * case, the ordering of time-stamp tokens issued by the same TSA or + * different TSAs is only possible when the difference between the + * genTime of the first time-stamp token and the genTime of the second + * time-stamp token is greater than the sum of the accuracies of the + * genTime for each time-stamp token. + * + * If the ordering field is present and set to true, every time-stamp + * token from the same TSA can always be ordered based on the genTime + * field, regardless of the genTime accuracy. + * + * call-seq: + * token_info.ordering -> true, falses or nil + */ +static VALUE +ossl_ts_token_info_get_ordering(VALUE self) +{ + TS_TST_INFO *info; + + GetTSTokenInfo(self, info); + return TS_TST_INFO_get_ordering(info) ? Qtrue : Qfalse; +} + +/* + * If the timestamp token is valid then this field contains the same nonce that + * was passed to the timestamp server in the initial Request. + * + * call-seq: + * token_info.nonce -> BN or nil + */ +static VALUE +ossl_ts_token_info_get_nonce(VALUE self) +{ + TS_TST_INFO *info; + const ASN1_INTEGER *nonce; + + GetTSTokenInfo(self, info); + if (!(nonce = TS_TST_INFO_get_nonce(info))) + return Qnil; + + return asn1integer_to_num(nonce); +} + +/* + * Returns the TokenInfo in DER-encoded form. + * + * call-seq: + * token_info.to_der -> string + */ +static VALUE +ossl_ts_token_info_to_der(VALUE self) +{ + TS_TST_INFO *info; + + GetTSTokenInfo(self, info); + return asn1_to_der((void *)info, (int (*)(void *, unsigned char **))i2d_TS_TST_INFO); +} + +static VALUE +ossl_ts_token_info_to_text(VALUE self) +{ + TS_TST_INFO *info; + BIO *out; + + GetTSTokenInfo(self, info); + + out = BIO_new(BIO_s_mem()); + if (!out) ossl_raise(eTimestampError, NULL); + + if (!TS_TST_INFO_print_bio(out, info)) { + BIO_free(out); + ossl_raise(eTimestampError, NULL); + } + + return ossl_membio2str(out); +} + +static ASN1_INTEGER * +ossl_tsfac_serial_cb(struct TS_resp_ctx *ctx, void *data) +{ + ASN1_INTEGER **snptr = (ASN1_INTEGER **)data; + ASN1_INTEGER *sn = *snptr; + *snptr = NULL; + return sn; +} + +static int +#if !defined(LIBRESSL_VERSION_NUMBER) +ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, long *sec, long *usec) +#else +ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, time_t *sec, long *usec) +#endif +{ + *sec = *((long *)data); + *usec = 0; + return 1; +} + +static VALUE +ossl_evp_md_fetch_i(VALUE args_) +{ + VALUE *args = (VALUE *)args_, md_holder; + const EVP_MD *md; + + md = ossl_evp_md_fetch(args[1], &md_holder); + rb_ary_push(args[0], md_holder); + return (VALUE)md; +} + +static VALUE +ossl_obj2bio_i(VALUE arg) +{ + return (VALUE)ossl_obj2bio((VALUE *)arg); +} + +/* + * Creates a Response with the help of an OpenSSL::PKey, an + * OpenSSL::X509::Certificate and a Request. + * + * Mandatory parameters for timestamp creation that need to be set in the + * Request: + * + * * Request#algorithm + * * Request#message_imprint + * + * Mandatory parameters that need to be set in the Factory: + * * Factory#serial_number + * * Factory#gen_time + * * Factory#allowed_digests + * + * In addition one of either Request#policy_id or Factory#default_policy_id + * must be set. + * + * Raises a TimestampError if creation fails, though successfully created error + * responses may be returned. + * + * call-seq: + * factory.create_timestamp(key, certificate, request) -> Response + */ +static VALUE +ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request) +{ + VALUE serial_number, def_policy_id, gen_time, additional_certs, + allowed_digests, allowed_digests_tmp = Qnil; + VALUE str; + STACK_OF(X509) *inter_certs; + VALUE tsresp, ret = Qnil; + EVP_PKEY *sign_key; + X509 *tsa_cert; + TS_REQ *req; + TS_RESP *response = NULL; + TS_RESP_CTX *ctx = NULL; + BIO *req_bio; + ASN1_INTEGER *asn1_serial = NULL; + ASN1_OBJECT *def_policy_id_obj = NULL; + long lgen_time; + const char * err_msg = NULL; + int status = 0; + + tsresp = NewTSResponse(cTimestampResponse); + tsa_cert = GetX509CertPtr(certificate); + sign_key = GetPrivPKeyPtr(key); + GetTSRequest(request, req); + + gen_time = ossl_tsfac_get_gen_time(self); + if (!rb_obj_is_instance_of(gen_time, rb_cTime)) { + err_msg = "@gen_time must be a Time."; + goto end; + } + lgen_time = NUM2LONG(rb_funcall(gen_time, rb_intern("to_i"), 0)); + + serial_number = ossl_tsfac_get_serial_number(self); + if (NIL_P(serial_number)) { + err_msg = "@serial_number must be set."; + goto end; + } + asn1_serial = num_to_asn1integer(serial_number, NULL); + + def_policy_id = ossl_tsfac_get_default_policy_id(self); + if (NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) { + err_msg = "No policy id in the request and no default policy set"; + goto end; + } + if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) { + def_policy_id_obj = (ASN1_OBJECT*)rb_protect(obj_to_asn1obj_i, (VALUE)def_policy_id, &status); + if (status) + goto end; + } + + if (!(ctx = TS_RESP_CTX_new())) { + err_msg = "Memory allocation failed."; + goto end; + } + + TS_RESP_CTX_set_serial_cb(ctx, ossl_tsfac_serial_cb, &asn1_serial); + if (!TS_RESP_CTX_set_signer_cert(ctx, tsa_cert)) { + err_msg = "Certificate does not contain the timestamping extension"; + goto end; + } + + additional_certs = ossl_tsfac_get_additional_certs(self); + if (rb_obj_is_kind_of(additional_certs, rb_cArray)) { + inter_certs = ossl_protect_x509_ary2sk(additional_certs, &status); + if (status) + goto end; + + /* this dups the sk_X509 and ups each cert's ref count */ + TS_RESP_CTX_set_certs(ctx, inter_certs); + sk_X509_pop_free(inter_certs, X509_free); + } + + TS_RESP_CTX_set_signer_key(ctx, sign_key); + if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) + TS_RESP_CTX_set_def_policy(ctx, def_policy_id_obj); + if (TS_REQ_get_policy_id(req)) + TS_RESP_CTX_set_def_policy(ctx, TS_REQ_get_policy_id(req)); + TS_RESP_CTX_set_time_cb(ctx, ossl_tsfac_time_cb, &lgen_time); + + allowed_digests = ossl_tsfac_get_allowed_digests(self); + if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) { + allowed_digests_tmp = rb_ary_new_capa(RARRAY_LEN(allowed_digests)); + for (long i = 0; i < RARRAY_LEN(allowed_digests); i++) { + VALUE args[] = { + allowed_digests_tmp, + rb_ary_entry(allowed_digests, i), + }; + const EVP_MD *md = (const EVP_MD *)rb_protect(ossl_evp_md_fetch_i, + (VALUE)args, &status); + if (status) + goto end; + if (!TS_RESP_CTX_add_md(ctx, md)) + goto end; + } + } + + str = rb_protect(ossl_to_der, request, &status); + if (status) + goto end; + + req_bio = (BIO*)rb_protect(ossl_obj2bio_i, (VALUE)&str, &status); + if (status) + goto end; + + response = TS_RESP_create_response(ctx, req_bio); + BIO_free(req_bio); + RB_GC_GUARD(allowed_digests_tmp); + + if (!response) { + err_msg = "Error during response generation"; + goto end; + } + + /* bad responses aren't exceptional, but openssl still sets error + * information. */ + ossl_clear_error(); + + SetTSResponse(tsresp, response); + ret = tsresp; + + end: + ASN1_INTEGER_free(asn1_serial); + ASN1_OBJECT_free(def_policy_id_obj); + TS_RESP_CTX_free(ctx); + if (err_msg) + rb_exc_raise(ossl_make_error(eTimestampError, rb_str_new_cstr(err_msg))); + if (status) + rb_jump_tag(status); + return ret; +} + +/* + * INIT + */ +void +Init_ossl_ts(void) +{ + /* + * Possible return value for +Response#failure_info+. Indicates that the + * timestamp server rejects the message imprint algorithm used in the + * +Request+ + */ + sBAD_ALG = ID2SYM(rb_intern_const("BAD_ALG")); + + /* + * Possible return value for +Response#failure_info+. Indicates that the + * timestamp server was not able to process the +Request+ properly. + */ + sBAD_REQUEST = ID2SYM(rb_intern_const("BAD_REQUEST")); + /* + * Possible return value for +Response#failure_info+. Indicates that the + * timestamp server was not able to parse certain data in the +Request+. + */ + sBAD_DATA_FORMAT = ID2SYM(rb_intern_const("BAD_DATA_FORMAT")); + + sTIME_NOT_AVAILABLE = ID2SYM(rb_intern_const("TIME_NOT_AVAILABLE")); + sUNACCEPTED_POLICY = ID2SYM(rb_intern_const("UNACCEPTED_POLICY")); + sUNACCEPTED_EXTENSION = ID2SYM(rb_intern_const("UNACCEPTED_EXTENSION")); + sADD_INFO_NOT_AVAILABLE = ID2SYM(rb_intern_const("ADD_INFO_NOT_AVAILABLE")); + sSYSTEM_FAILURE = ID2SYM(rb_intern_const("SYSTEM_FAILURE")); + + /* Document-class: OpenSSL::Timestamp + * Provides classes and methods to request, create and validate + * {RFC3161-compliant}[http://www.ietf.org/rfc/rfc3161.txt] timestamps. + * Request may be used to either create requests from scratch or to parse + * existing requests that again can be used to request timestamps from a + * timestamp server, e.g. via the net/http. The resulting timestamp + * response may be parsed using Response. + * + * Please note that Response is read-only and immutable. To create a + * Response, an instance of Factory as well as a valid Request are needed. + * + * ===Create a Response: + * #Assumes ts.p12 is a PKCS#12-compatible file with a private key + * #and a certificate that has an extended key usage of 'timeStamping' + * p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd') + * md = OpenSSL::Digest.new('SHA1') + * hash = md.digest(data) #some binary data to be timestamped + * req = OpenSSL::Timestamp::Request.new + * req.algorithm = 'SHA1' + * req.message_imprint = hash + * req.policy_id = "1.2.3.4.5" + * req.nonce = 42 + * fac = OpenSSL::Timestamp::Factory.new + * fac.gen_time = Time.now + * fac.serial_number = 1 + * timestamp = fac.create_timestamp(p12.key, p12.certificate, req) + * + * ===Verify a timestamp response: + * #Assume we have a timestamp token in a file called ts.der + * ts = OpenSSL::Timestamp::Response.new(File.binread('ts.der')) + * #Assume we have the Request for this token in a file called req.der + * req = OpenSSL::Timestamp::Request.new(File.binread('req.der')) + * # Assume the associated root CA certificate is contained in a + * # DER-encoded file named root.cer + * root = OpenSSL::X509::Certificate.new(File.binread('root.cer')) + * # get the necessary intermediate certificates, available in + * # DER-encoded form in inter1.cer and inter2.cer + * inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer')) + * inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer')) + * ts.verify(req, root, inter1, inter2) -> ts or raises an exception if validation fails + * + */ + mTimestamp = rb_define_module_under(mOSSL, "Timestamp"); + + /* Document-class: OpenSSL::Timestamp::TimestampError + * Generic exception class of the Timestamp module. + */ + eTimestampError = rb_define_class_under(mTimestamp, "TimestampError", eOSSLError); + + /* Document-class: OpenSSL::Timestamp::Response + * Immutable and read-only representation of a timestamp response returned + * from a timestamp server after receiving an associated Request. Allows + * access to specific information about the response but also allows to + * verify the Response. + */ + cTimestampResponse = rb_define_class_under(mTimestamp, "Response", rb_cObject); + rb_define_alloc_func(cTimestampResponse, ossl_ts_resp_alloc); + rb_define_method(cTimestampResponse, "initialize", ossl_ts_resp_initialize, 1); + rb_define_method(cTimestampResponse, "status", ossl_ts_resp_get_status, 0); + rb_define_method(cTimestampResponse, "failure_info", ossl_ts_resp_get_failure_info, 0); + rb_define_method(cTimestampResponse, "status_text", ossl_ts_resp_get_status_text, 0); + rb_define_method(cTimestampResponse, "token", ossl_ts_resp_get_token, 0); + rb_define_method(cTimestampResponse, "token_info", ossl_ts_resp_get_token_info, 0); + rb_define_method(cTimestampResponse, "tsa_certificate", ossl_ts_resp_get_tsa_certificate, 0); + rb_define_method(cTimestampResponse, "to_der", ossl_ts_resp_to_der, 0); + rb_define_method(cTimestampResponse, "to_text", ossl_ts_resp_to_text, 0); + rb_define_method(cTimestampResponse, "verify", ossl_ts_resp_verify, -1); + + /* Document-class: OpenSSL::Timestamp::TokenInfo + * Immutable and read-only representation of a timestamp token info from a + * Response. + */ + cTimestampTokenInfo = rb_define_class_under(mTimestamp, "TokenInfo", rb_cObject); + rb_define_alloc_func(cTimestampTokenInfo, ossl_ts_token_info_alloc); + rb_define_method(cTimestampTokenInfo, "initialize", ossl_ts_token_info_initialize, 1); + rb_define_method(cTimestampTokenInfo, "version", ossl_ts_token_info_get_version, 0); + rb_define_method(cTimestampTokenInfo, "policy_id", ossl_ts_token_info_get_policy_id, 0); + rb_define_method(cTimestampTokenInfo, "algorithm", ossl_ts_token_info_get_algorithm, 0); + rb_define_method(cTimestampTokenInfo, "message_imprint", ossl_ts_token_info_get_msg_imprint, 0); + rb_define_method(cTimestampTokenInfo, "serial_number", ossl_ts_token_info_get_serial_number, 0); + rb_define_method(cTimestampTokenInfo, "gen_time", ossl_ts_token_info_get_gen_time, 0); + rb_define_method(cTimestampTokenInfo, "ordering", ossl_ts_token_info_get_ordering, 0); + rb_define_method(cTimestampTokenInfo, "nonce", ossl_ts_token_info_get_nonce, 0); + rb_define_method(cTimestampTokenInfo, "to_der", ossl_ts_token_info_to_der, 0); + rb_define_method(cTimestampTokenInfo, "to_text", ossl_ts_token_info_to_text, 0); + + /* Document-class: OpenSSL::Timestamp::Request + * Allows to create timestamp requests or parse existing ones. A Request is + * also needed for creating timestamps from scratch with Factory. When + * created from scratch, some default values are set: + * * version is set to +1+ + * * cert_requested is set to +true+ + * * algorithm, message_imprint, policy_id, and nonce are set to +false+ + */ + cTimestampRequest = rb_define_class_under(mTimestamp, "Request", rb_cObject); + rb_define_alloc_func(cTimestampRequest, ossl_ts_req_alloc); + rb_define_method(cTimestampRequest, "initialize", ossl_ts_req_initialize, -1); + rb_define_method(cTimestampRequest, "version=", ossl_ts_req_set_version, 1); + rb_define_method(cTimestampRequest, "version", ossl_ts_req_get_version, 0); + rb_define_method(cTimestampRequest, "algorithm=", ossl_ts_req_set_algorithm, 1); + rb_define_method(cTimestampRequest, "algorithm", ossl_ts_req_get_algorithm, 0); + rb_define_method(cTimestampRequest, "message_imprint=", ossl_ts_req_set_msg_imprint, 1); + rb_define_method(cTimestampRequest, "message_imprint", ossl_ts_req_get_msg_imprint, 0); + rb_define_method(cTimestampRequest, "policy_id=", ossl_ts_req_set_policy_id, 1); + rb_define_method(cTimestampRequest, "policy_id", ossl_ts_req_get_policy_id, 0); + rb_define_method(cTimestampRequest, "nonce=", ossl_ts_req_set_nonce, 1); + rb_define_method(cTimestampRequest, "nonce", ossl_ts_req_get_nonce, 0); + rb_define_method(cTimestampRequest, "cert_requested=", ossl_ts_req_set_cert_requested, 1); + rb_define_method(cTimestampRequest, "cert_requested?", ossl_ts_req_get_cert_requested, 0); + rb_define_method(cTimestampRequest, "to_der", ossl_ts_req_to_der, 0); + rb_define_method(cTimestampRequest, "to_text", ossl_ts_req_to_text, 0); + + /* + * Indicates a successful response. Equal to +0+. + */ + rb_define_const(cTimestampResponse, "GRANTED", INT2NUM(TS_STATUS_GRANTED)); + /* + * Indicates a successful response that probably contains modifications + * from the initial request. Equal to +1+. + */ + rb_define_const(cTimestampResponse, "GRANTED_WITH_MODS", INT2NUM(TS_STATUS_GRANTED_WITH_MODS)); + /* + * Indicates a failure. No timestamp token was created. Equal to +2+. + */ + rb_define_const(cTimestampResponse, "REJECTION", INT2NUM(TS_STATUS_REJECTION)); + /* + * Indicates a failure. No timestamp token was created. Equal to +3+. + */ + rb_define_const(cTimestampResponse, "WAITING", INT2NUM(TS_STATUS_WAITING)); + /* + * Indicates a failure. No timestamp token was created. Revocation of a + * certificate is imminent. Equal to +4+. + */ + rb_define_const(cTimestampResponse, "REVOCATION_WARNING", INT2NUM(TS_STATUS_REVOCATION_WARNING)); + /* + * Indicates a failure. No timestamp token was created. A certificate + * has been revoked. Equal to +5+. + */ + rb_define_const(cTimestampResponse, "REVOCATION_NOTIFICATION", INT2NUM(TS_STATUS_REVOCATION_NOTIFICATION)); + + /* Document-class: OpenSSL::Timestamp::Factory + * + * Used to generate a Response from scratch. + * + * Please bear in mind that the implementation will always apply and prefer + * the policy object identifier given in the request over the default policy + * id specified in the Factory. As a consequence, +default_policy_id+ will + * only be applied if no Request#policy_id was given. But this also means + * that one needs to check the policy identifier in the request manually + * before creating the Response, e.g. to check whether it complies to a + * specific set of acceptable policies. + * + * There exists also the possibility to add certificates (instances of + * OpenSSL::X509::Certificate) besides the timestamping certificate + * that will be included in the resulting timestamp token if + * Request#cert_requested? is +true+. Ideally, one would also include any + * intermediate certificates (the root certificate can be left out - in + * order to trust it any verifying party will have to be in its possession + * anyway). This simplifies validation of the timestamp since these + * intermediate certificates are "already there" and need not be passed as + * external parameters to Response#verify anymore, thus minimizing external + * resources needed for verification. + * + * ===Example: Inclusion of (untrusted) intermediate certificates + * + * Assume we received a timestamp request that has set Request#policy_id to + * +nil+ and Request#cert_requested? to true. The raw request bytes are + * stored in a variable called +req_raw+. We'd still like to integrate + * the necessary intermediate certificates (in +inter1.cer+ and + * +inter2.cer+) to simplify validation of the resulting Response. +ts.p12+ + * is a PKCS#12-compatible file including the private key and the + * timestamping certificate. + * + * req = OpenSSL::Timestamp::Request.new(raw_bytes) + * p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd') + * inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer')) + * inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer')) + * fac = OpenSSL::Timestamp::Factory.new + * fac.gen_time = Time.now + * fac.serial_number = 1 + * fac.allowed_digests = ["sha256", "sha384", "sha512"] + * #needed because the Request contained no policy identifier + * fac.default_policy_id = '1.2.3.4.5' + * fac.additional_certificates = [ inter1, inter2 ] + * timestamp = fac.create_timestamp(p12.key, p12.certificate, req) + */ + cTimestampFactory = rb_define_class_under(mTimestamp, "Factory", rb_cObject); + /* + * The list of digest algorithms that the factory is allowed + * create timestamps for. Known vulnerable or weak algorithms should not be + * allowed where possible. Must be an Array of String or OpenSSL::Digest + * subclass instances. + */ + rb_attr(cTimestampFactory, rb_intern_const("allowed_digests"), 1, 1, 0); + /* + * A String representing the default policy object identifier, or +nil+. + * + * Request#policy_id will always be preferred over this if present in the + * Request, only if Request#policy_id is +nil+ default_policy will be used. + * If none of both is present, a TimestampError will be raised when trying + * to create a Response. + */ + rb_attr(cTimestampFactory, rb_intern_const("default_policy_id"), 1, 1, 0); + /* + * The serial number to be used for timestamp creation. Must be present for + * timestamp creation. Must be an instance of OpenSSL::BN or Integer. + */ + rb_attr(cTimestampFactory, rb_intern_const("serial_number"), 1, 1, 0); + /* + * The Time value to be used in the Response. Must be present for timestamp + * creation. + */ + rb_attr(cTimestampFactory, rb_intern_const("gen_time"), 1, 1, 0); + /* + * Additional certificates apart from the timestamp certificate (e.g. + * intermediate certificates) to be added to the Response. + * Must be an Array of OpenSSL::X509::Certificate, or +nil+. + */ + rb_attr(cTimestampFactory, rb_intern_const("additional_certs"), 1, 1, 0); + rb_define_method(cTimestampFactory, "create_timestamp", ossl_tsfac_create_ts, 3); +} +#else /* OPENSSL_NO_TS */ +void +Init_ossl_ts(void) +{ +} +#endif diff --git a/ext/openssl/ossl_ts.h b/ext/openssl/ossl_ts.h new file mode 100644 index 0000000000..eeca3046eb --- /dev/null +++ b/ext/openssl/ossl_ts.h @@ -0,0 +1,16 @@ +/* + * + * Copyright (C) 2010 Martin Bosslet <Martin.Bosslet@googlemail.com> + * All rights reserved. + */ +/* + * This program is licenced under the same licence as Ruby. + * (See the file 'COPYING'.) + */ + +#if !defined(_OSSL_TS_H_) +#define _OSSL_TS_H_ + +void Init_ossl_ts(void); + +#endif diff --git a/ext/openssl/ossl_version.h b/ext/openssl/ossl_version.h deleted file mode 100644 index 63878e0d8e..0000000000 --- a/ext/openssl/ossl_version.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * $Id$ - * 'OpenSSL for Ruby' project - * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> - * All rights reserved. - */ -/* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) - */ -#if !defined(_OSSL_VERSION_H_) -#define _OSSL_VERSION_H_ - -#define OSSL_VERSION "1.0.0" - -#endif /* _OSSL_VERSION_H_ */ diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c index fd1d9b6c7e..bc3914fda2 100644 --- a/ext/openssl/ossl_x509.c +++ b/ext/openssl/ossl_x509.c @@ -1,23 +1,34 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" 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())) + rb_define_const(mX509, "DEFAULT_" #x, \ + rb_obj_freeze(rb_str_new_cstr(X509_get_default_##i()))) + +ASN1_TIME * +ossl_x509_time_adjust(ASN1_TIME *s, VALUE time) +{ + time_t sec; + + int off_days; + + ossl_time_split(time, &sec, &off_days); + return X509_time_adj_ex(s, off_days, 0, &sec); +} void -Init_ossl_x509() +Init_ossl_x509(void) { mX509 = rb_define_module_under(mOSSL, "X509"); @@ -30,7 +41,11 @@ Init_ossl_x509() Init_ossl_x509revoked(); Init_ossl_x509store(); + /* Constants are up-to-date with 1.1.1. */ + + /* Certificate verification error code */ DefX509Const(V_OK); + DefX509Const(V_ERR_UNSPECIFIED); DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT); DefX509Const(V_ERR_UNABLE_TO_GET_CRL); DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); @@ -62,37 +77,156 @@ Init_ossl_x509() DefX509Const(V_ERR_AKID_SKID_MISMATCH); DefX509Const(V_ERR_AKID_ISSUER_SERIAL_MISMATCH); DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN); + DefX509Const(V_ERR_UNABLE_TO_GET_CRL_ISSUER); + DefX509Const(V_ERR_UNHANDLED_CRITICAL_EXTENSION); + DefX509Const(V_ERR_KEYUSAGE_NO_CRL_SIGN); + DefX509Const(V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); + DefX509Const(V_ERR_INVALID_NON_CA); + DefX509Const(V_ERR_PROXY_PATH_LENGTH_EXCEEDED); + DefX509Const(V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); + DefX509Const(V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); + DefX509Const(V_ERR_INVALID_EXTENSION); + DefX509Const(V_ERR_INVALID_POLICY_EXTENSION); + DefX509Const(V_ERR_NO_EXPLICIT_POLICY); + DefX509Const(V_ERR_DIFFERENT_CRL_SCOPE); + DefX509Const(V_ERR_UNSUPPORTED_EXTENSION_FEATURE); + DefX509Const(V_ERR_UNNESTED_RESOURCE); + DefX509Const(V_ERR_PERMITTED_VIOLATION); + DefX509Const(V_ERR_EXCLUDED_VIOLATION); + DefX509Const(V_ERR_SUBTREE_MINMAX); DefX509Const(V_ERR_APPLICATION_VERIFICATION); + DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); + DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); + DefX509Const(V_ERR_UNSUPPORTED_NAME_SYNTAX); + DefX509Const(V_ERR_CRL_PATH_VALIDATION_ERROR); +#if defined(X509_V_ERR_PATH_LOOP) /* OpenSSL 1.1.0, missing in LibreSSL */ + DefX509Const(V_ERR_PATH_LOOP); +#endif +#if defined(X509_V_ERR_SUITE_B_INVALID_VERSION) /* OpenSSL 1.1.0, missing in LibreSSL */ + DefX509Const(V_ERR_SUITE_B_INVALID_VERSION); + DefX509Const(V_ERR_SUITE_B_INVALID_ALGORITHM); + DefX509Const(V_ERR_SUITE_B_INVALID_CURVE); + DefX509Const(V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM); + DefX509Const(V_ERR_SUITE_B_LOS_NOT_ALLOWED); + DefX509Const(V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256); +#endif + DefX509Const(V_ERR_HOSTNAME_MISMATCH); + DefX509Const(V_ERR_EMAIL_MISMATCH); + DefX509Const(V_ERR_IP_ADDRESS_MISMATCH); +#if defined(X509_V_ERR_DANE_NO_MATCH) /* OpenSSL 1.1.0, missing in LibreSSL */ + DefX509Const(V_ERR_DANE_NO_MATCH); +#endif + DefX509Const(V_ERR_EE_KEY_TOO_SMALL); + DefX509Const(V_ERR_CA_KEY_TOO_SMALL); + DefX509Const(V_ERR_CA_MD_TOO_WEAK); + DefX509Const(V_ERR_INVALID_CALL); + DefX509Const(V_ERR_STORE_LOOKUP); +#if defined(X509_V_ERR_NO_VALID_SCTS) /* OpenSSL 1.1.0, missing in LibreSSL */ + DefX509Const(V_ERR_NO_VALID_SCTS); +#endif +#if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION) /* OpenSSL 1.1.0, missing in LibreSSL */ + DefX509Const(V_ERR_PROXY_SUBJECT_NAME_VIOLATION); +#endif +#if defined(X509_V_ERR_OCSP_VERIFY_NEEDED) /* OpenSSL 1.1.1, missing in LibreSSL */ + DefX509Const(V_ERR_OCSP_VERIFY_NEEDED); + DefX509Const(V_ERR_OCSP_VERIFY_FAILED); + DefX509Const(V_ERR_OCSP_CERT_UNKNOWN); +#endif -#if defined(X509_V_FLAG_CRL_CHECK) + /* Certificate verify flags */ + /* Set by Store#flags= and StoreContext#flags=. */ + DefX509Const(V_FLAG_USE_CHECK_TIME); + /* 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); + /* Set by Store#flags= and StoreContext#flags=. Enables some additional + * features including support for indirect signed CRLs. */ + DefX509Const(V_FLAG_EXTENDED_CRL_SUPPORT); + /* Set by Store#flags= and StoreContext#flags=. Uses delta CRLs. If not + * specified, deltas are ignored. */ + DefX509Const(V_FLAG_USE_DELTAS); + /* Set by Store#flags= and StoreContext#flags=. Enables checking of the + * signature of the root self-signed CA. */ + DefX509Const(V_FLAG_CHECK_SS_SIGNATURE); + /* 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); +#if defined(X509_V_FLAG_SUITEB_128_LOS_ONLY) /* OpenSSL 1.1.0, missing in LibreSSL */ + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 128 bit only mode. */ + DefX509Const(V_FLAG_SUITEB_128_LOS_ONLY); + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 192 bit only mode. */ + DefX509Const(V_FLAG_SUITEB_192_LOS); + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 128 bit mode allowing 192 bit algorithms. */ + DefX509Const(V_FLAG_SUITEB_128_LOS); #endif + /* Set by Store#flags= and StoreContext#flags=. + * Allows partial chains if at least one certificate is in trusted store. */ + DefX509Const(V_FLAG_PARTIAL_CHAIN); + /* 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); + /* 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); + /* 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); -#endif + /* Set by Store#purpose=. Time stamps signer. */ + DefX509Const(PURPOSE_TIMESTAMP_SIGN); DefX509Const(TRUST_COMPAT); DefX509Const(TRUST_SSL_CLIENT); 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); -#endif + DefX509Const(TRUST_TSA); DefX509Default(CERT_AREA, cert_area); DefX509Default(CERT_DIR, cert_dir); @@ -101,4 +235,3 @@ Init_ossl_x509() DefX509Default(CERT_FILE_ENV, cert_file_env); DefX509Default(PRIVATE_DIR, private_dir); } - diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h index 1a43569073..d25167ee7b 100644 --- a/ext/openssl/ossl_x509.h +++ b/ext/openssl/ossl_x509.h @@ -1,12 +1,11 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #if !defined(_OSSL_X509_H_) #define _OSSL_X509_H_ @@ -16,26 +15,30 @@ */ 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); /* * X509Attr */ extern VALUE cX509Attr; -extern VALUE eX509AttrError; VALUE ossl_x509attr_new(X509_ATTRIBUTE *); -X509_ATTRIBUTE *DupX509AttrPtr(VALUE); +X509_ATTRIBUTE *GetX509AttrPtr(VALUE); void Init_ossl_x509attr(void); /* * X509Cert */ extern VALUE cX509Cert; -extern VALUE eX509CertError; VALUE ossl_x509_new(X509 *); -VALUE ossl_x509_new_from_file(VALUE); X509 *GetX509CertPtr(VALUE); X509 *DupX509CertPtr(VALUE); void Init_ossl_x509cert(void); @@ -43,32 +46,22 @@ void Init_ossl_x509cert(void); /* * X509CRL */ -extern VALUE cX509CRL; -extern VALUE eX509CRLError; - VALUE ossl_x509crl_new(X509_CRL *); X509_CRL *GetX509CRLPtr(VALUE); -X509_CRL *DupX509CRLPtr(VALUE); void Init_ossl_x509crl(void); /* * X509Extension */ extern VALUE cX509Ext; -extern VALUE cX509ExtFactory; -extern VALUE eX509ExtError; VALUE ossl_x509ext_new(X509_EXTENSION *); X509_EXTENSION *GetX509ExtPtr(VALUE); -X509_EXTENSION *DupX509ExtPtr(VALUE); void Init_ossl_x509ext(void); /* * X509Name */ -extern VALUE cX509Name; -extern VALUE eX509NameError; - VALUE ossl_x509name_new(X509_NAME *); X509_NAME *GetX509NamePtr(VALUE); void Init_ossl_x509name(void); @@ -76,19 +69,13 @@ void Init_ossl_x509name(void); /* * X509Request */ -extern VALUE cX509Req; -extern VALUE eX509ReqError; - -VALUE ossl_x509req_new(X509_REQ *); X509_REQ *GetX509ReqPtr(VALUE); -X509_REQ *DupX509ReqPtr(VALUE); void Init_ossl_x509req(void); /* * X509Revoked */ extern VALUE cX509Rev; -extern VALUE eX509RevError; VALUE ossl_x509revoked_new(X509_REVOKED *); X509_REVOKED *DupX509RevokedPtr(VALUE); @@ -97,18 +84,13 @@ void Init_ossl_x509revoked(void); /* * X509Store and X509StoreContext */ -extern VALUE cX509Store; -extern VALUE cX509StoreContext; -extern VALUE eX509StoreError; - -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 ca1c59aba9..4769e56e1e 100644 --- a/ext/openssl/ossl_x509attr.c +++ b/ext/openssl/ossl_x509attr.c @@ -1,37 +1,48 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapX509Attr(klass, obj, attr) do { \ - if (!attr) { \ - ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ +#define NewX509Attr(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509attr_type, 0) +#define SetX509Attr(obj, attr) do { \ + if (!(attr)) { \ + ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_ATTRIBUTE_free, attr); \ + RTYPEDDATA_DATA(obj) = (attr); \ } while (0) #define GetX509Attr(obj, attr) do { \ - Data_Get_Struct(obj, X509_ATTRIBUTE, attr); \ - if (!attr) { \ - ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \ + if (!(attr)) { \ + ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \ } \ } while (0) -#define SafeGetX509Attr(obj, attr) do { \ - OSSL_Check_Kind(obj, cX509Attr); \ - GetX509Attr(obj, attr); \ -} while (0) /* * Classes */ VALUE cX509Attr; -VALUE eX509AttrError; +static VALUE eX509AttrError; + +static void +ossl_x509attr_free(void *ptr) +{ + X509_ATTRIBUTE_free(ptr); +} + +static const rb_data_type_t ossl_x509attr_type = { + "OpenSSL/X509/ATTRIBUTE", + { + 0, ossl_x509attr_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; /* * Public @@ -41,31 +52,24 @@ ossl_x509attr_new(X509_ATTRIBUTE *attr) { X509_ATTRIBUTE *new; VALUE obj; - - if (!attr) { - new = X509_ATTRIBUTE_new(); - } else { - new = X509_ATTRIBUTE_dup(attr); - } - if (!new) { - ossl_raise(eX509AttrError, NULL); - } - WrapX509Attr(cX509Attr, obj, new); + + obj = NewX509Attr(cX509Attr); + new = X509_ATTRIBUTE_dup(attr); + if (!new) + ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup"); + SetX509Attr(obj, new); return obj; } X509_ATTRIBUTE * -DupX509AttrPtr(VALUE obj) +GetX509AttrPtr(VALUE obj) { - X509_ATTRIBUTE *attr, *new; + X509_ATTRIBUTE *attr; - SafeGetX509Attr(obj, attr); - if (!(new = X509_ATTRIBUTE_dup(attr))) { - ossl_raise(eX509AttrError, NULL); - } + GetX509Attr(obj, attr); - return new; + return attr; } /* @@ -77,9 +81,10 @@ ossl_x509attr_alloc(VALUE klass) X509_ATTRIBUTE *attr; VALUE obj; - if (!(attr = X509_ATTRIBUTE_new())) - ossl_raise(eX509AttrError, NULL); - WrapX509Attr(klass, obj, attr); + obj = NewX509Attr(klass); + if (!(attr = X509_ATTRIBUTE_new())) + ossl_raise(eX509AttrError, NULL); + SetX509Attr(obj, attr); return obj; } @@ -92,19 +97,20 @@ static VALUE ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self) { VALUE oid, value; - X509_ATTRIBUTE *attr; - unsigned char *p; + X509_ATTRIBUTE *attr, *x; + const unsigned char *p; GetX509Attr(self, attr); if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){ - oid = ossl_to_der_if_possible(oid); - StringValue(oid); - p = RSTRING_PTR(oid); - if(!d2i_X509_ATTRIBUTE((X509_ATTRIBUTE**)&DATA_PTR(self), - &p, RSTRING_LEN(oid))){ - ossl_raise(eX509AttrError, NULL); - } - return self; + oid = ossl_to_der_if_possible(oid); + StringValue(oid); + p = (unsigned char *)RSTRING_PTR(oid); + x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid)); + DATA_PTR(self) = attr; + if(!x){ + ossl_raise(eX509AttrError, NULL); + } + return self; } rb_funcall(self, rb_intern("oid="), 1, oid); rb_funcall(self, rb_intern("value="), 1, value); @@ -112,6 +118,26 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* :nodoc: */ +static VALUE +ossl_x509attr_initialize_copy(VALUE self, VALUE other) +{ + X509_ATTRIBUTE *attr, *attr_other, *attr_new; + + rb_check_frozen(self); + GetX509Attr(self, attr); + GetX509Attr(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 @@ -122,52 +148,36 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid) X509_ATTRIBUTE *attr; ASN1_OBJECT *obj; char *s; - - s = StringValuePtr(oid); + + GetX509Attr(self, attr); + s = StringValueCStr(oid); obj = OBJ_txt2obj(s, 0); - if(!obj) obj = OBJ_txt2obj(s, 1); if(!obj) ossl_raise(eX509AttrError, NULL); - GetX509Attr(self, attr); - X509_ATTRIBUTE_set1_object(attr, obj); - + if (!X509_ATTRIBUTE_set1_object(attr, obj)) { + ASN1_OBJECT_free(obj); + ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object"); + } + ASN1_OBJECT_free(obj); + return oid; } /* * call-seq: - * attr.oid => string + * attr.oid -> string + * + * Returns the OID of the attribute. Returns the short name or the dotted + * decimal notation. */ static VALUE ossl_x509attr_get_oid(VALUE self) { X509_ATTRIBUTE *attr; - ASN1_OBJECT *oid; - BIO *out; - VALUE ret; - int nid; GetX509Attr(self, attr); - oid = X509_ATTRIBUTE_get0_object(attr); - if ((nid = OBJ_obj2nid(oid)) != NID_undef) - ret = rb_str_new2(OBJ_nid2sn(nid)); - else{ - if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eX509AttrError, NULL); - i2a_ASN1_OBJECT(out, oid); - ret = ossl_membio2str(out); - } - - return ret; + return ossl_asn1obj_to_string(X509_ATTRIBUTE_get0_object(attr)); } -#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)->set) -# define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->set = 0) -#endif - /* * call-seq: * attr.value = asn1 => asn1 @@ -176,21 +186,36 @@ static VALUE ossl_x509attr_set_value(VALUE self, VALUE value) { X509_ATTRIBUTE *attr; - ASN1_TYPE *a1type; + GetX509Attr(self, attr); + + OSSL_Check_Kind(value, cASN1Data); + VALUE der = ossl_to_der(value); + const unsigned char *p = (const unsigned char *)RSTRING_PTR(der); + STACK_OF(ASN1_TYPE) *sk = d2i_ASN1_SET_ANY(NULL, &p, RSTRING_LEN(der)); + if (!sk) + ossl_raise(eX509AttrError, "attribute value must be ASN1::Set"); - 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."); + 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) { + sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); + ossl_raise(eX509AttrError, "X509_ATTRIBUTE_create_by_OBJ"); + } + SetX509Attr(self, new_attr); + X509_ATTRIBUTE_free(attr); + attr = new_attr; } - 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); + + for (int i = 0; i < sk_ASN1_TYPE_num(sk); i++) { + ASN1_TYPE *a1type = sk_ASN1_TYPE_value(sk, i); + if (!X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type), + a1type->value.ptr, -1)) { + sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); + ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_data"); + } } - OSSL_X509ATTR_SET_SINGLE(attr); - attr->value.single = a1type; + sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); return value; } @@ -203,31 +228,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 = 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, NULL, - i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0); - str = rb_str_new(0, length); - p = 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); } /* @@ -244,12 +272,12 @@ ossl_x509attr_to_der(VALUE self) GetX509Attr(self, attr); if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0) - ossl_raise(eX509AttrError, NULL); + ossl_raise(eX509AttrError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + 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_raise(eX509AttrError, NULL); + ossl_str_adjust(str, p); return str; } @@ -258,13 +286,14 @@ ossl_x509attr_to_der(VALUE self) * X509_ATTRIBUTE init */ void -Init_ossl_x509attr() +Init_ossl_x509attr(void) { 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_method(cX509Attr, "initialize_copy", ossl_x509attr_initialize_copy, 1); 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 b97f27ffa9..95679c7d24 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -1,37 +1,48 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapX509(klass, obj, x509) do { \ - if (!x509) { \ - ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ +#define NewX509(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509_type, 0) +#define SetX509(obj, x509) do { \ + if (!(x509)) { \ + ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_free, x509); \ + RTYPEDDATA_DATA(obj) = (x509); \ } while (0) #define GetX509(obj, x509) do { \ - Data_Get_Struct(obj, X509, x509); \ - if (!x509) { \ - ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509, &ossl_x509_type, (x509)); \ + if (!(x509)) { \ + ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \ } \ } while (0) -#define SafeGetX509(obj, x509) do { \ - OSSL_Check_Kind(obj, cX509Cert); \ - GetX509(obj, x509); \ -} while (0) /* * Classes */ VALUE cX509Cert; -VALUE eX509CertError; +static VALUE eX509CertError; + +static void +ossl_x509_free(void *ptr) +{ + X509_free(ptr); +} + +static const rb_data_type_t ossl_x509_type = { + "OpenSSL/X509", + { + 0, ossl_x509_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; /* * Public @@ -42,46 +53,11 @@ ossl_x509_new(X509 *x509) X509 *new; VALUE obj; - if (!x509) { - new = X509_new(); - } else { - new = X509_dup(x509); - } - if (!new) { - ossl_raise(eX509CertError, NULL); - } - WrapX509(cX509Cert, obj, new); - - return obj; -} - -VALUE -ossl_x509_new_from_file(VALUE filename) -{ - X509 *x509; - FILE *fp; - VALUE obj; - - SafeStringValue(filename); - if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { - ossl_raise(eX509CertError, "%s", strerror(errno)); - } - x509 = PEM_read_X509(fp, NULL, NULL, NULL); - /* - * prepare for DER... -#if !defined(OPENSSL_NO_FP_API) - if (!x509) { - rewind(fp); - - x509 = d2i_X509_fp(fp, NULL); - } -#endif - */ - fclose(fp); - if (!x509) { - ossl_raise(eX509CertError, NULL); - } - WrapX509(cX509Cert, obj, x509); + obj = NewX509(cX509Cert); + new = X509_dup(x509); + if (!new) + ossl_raise(eX509CertError, "X509_dup"); + SetX509(obj, new); return obj; } @@ -90,9 +66,9 @@ X509 * GetX509CertPtr(VALUE obj) { X509 *x509; - - SafeGetX509(obj, x509); - + + GetX509(obj, x509); + return x509; } @@ -100,27 +76,27 @@ X509 * DupX509CertPtr(VALUE obj) { X509 *x509; - - SafeGetX509(obj, x509); - - CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); - + + GetX509(obj, x509); + + X509_up_ref(x509); + return x509; } /* * Private */ -static VALUE +static VALUE ossl_x509_alloc(VALUE klass) { X509 *x509; VALUE obj; + obj = NewX509(klass); x509 = X509_new(); if (!x509) ossl_raise(eX509CertError, NULL); - - WrapX509(klass, obj, x509); + SetX509(obj, x509); return obj; } @@ -130,44 +106,50 @@ ossl_x509_alloc(VALUE klass) * Certificate.new => cert * Certificate.new(string) => cert */ -static VALUE +static VALUE ossl_x509_initialize(int argc, VALUE *argv, VALUE self) { BIO *in; - X509 *x509; + X509 *x509, *x509_orig = RTYPEDDATA_DATA(self); VALUE arg; + rb_check_frozen(self); if (rb_scan_args(argc, argv, "01", &arg) == 0) { - /* create just empty X509Cert */ - return self; + /* create just empty X509Cert */ + return self; } arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - x509 = PEM_read_bio_X509(in, (X509 **)&DATA_PTR(self), NULL, NULL); + in = ossl_obj2bio(&arg); + x509 = d2i_X509_bio(in, NULL); if (!x509) { - BIO_reset(in); - x509 = d2i_X509_bio(in, (X509 **)&DATA_PTR(self)); + OSSL_BIO_reset(in); + x509 = PEM_read_bio_X509(in, NULL, NULL, NULL); } BIO_free(in); - if (!x509) ossl_raise(eX509CertError, NULL); - + if (!x509) + ossl_raise(eX509CertError, "PEM_read_bio_X509"); + + RTYPEDDATA_DATA(self) = x509; + X509_free(x509_orig); + return self; } +/* :nodoc: */ static VALUE ossl_x509_copy(VALUE self, VALUE other) { X509 *a, *b, *x509; - + rb_check_frozen(self); if (self == other) return self; GetX509(self, a); - SafeGetX509(other, b); + GetX509(other, b); x509 = X509_dup(b); if (!x509) ossl_raise(eX509CertError, NULL); - + DATA_PTR(self) = x509; X509_free(a); @@ -178,7 +160,7 @@ ossl_x509_copy(VALUE self, VALUE other) * call-seq: * cert.to_der => string */ -static VALUE +static VALUE ossl_x509_to_der(VALUE self) { X509 *x509; @@ -188,13 +170,13 @@ ossl_x509_to_der(VALUE self) GetX509(self, x509); if ((len = i2d_X509(x509, NULL)) <= 0) - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if (i2d_X509(x509, &p) <= 0) - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); ossl_str_adjust(str, p); - + return str; } @@ -202,20 +184,20 @@ ossl_x509_to_der(VALUE self) * call-seq: * cert.to_pem => string */ -static VALUE +static VALUE ossl_x509_to_pem(VALUE self) { X509 *x509; BIO *out; VALUE str; - + GetX509(self, x509); out = BIO_new(BIO_s_mem()); if (!out) ossl_raise(eX509CertError, NULL); if (!PEM_write_bio_X509(out, x509)) { - BIO_free(out); - ossl_raise(eX509CertError, NULL); + BIO_free(out); + ossl_raise(eX509CertError, NULL); } str = ossl_membio2str(out); @@ -232,15 +214,15 @@ ossl_x509_to_text(VALUE self) X509 *x509; BIO *out; VALUE str; - + GetX509(self, x509); out = BIO_new(BIO_s_mem()); if (!out) ossl_raise(eX509CertError, NULL); if (!X509_print(out, x509)) { - BIO_free(out); - ossl_raise(eX509CertError, NULL); + BIO_free(out); + ossl_raise(eX509CertError, NULL); } str = ossl_membio2str(out); @@ -251,7 +233,7 @@ ossl_x509_to_text(VALUE self) /* * Makes from X509 X509_REQuest */ -static VALUE +static VALUE ossl_x509_to_req(VALUE self) { X509 *x509; @@ -260,7 +242,7 @@ ossl_x509_to_req(VALUE self) GetX509(self, x509); if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) { - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); } obj = ossl_x509req_new(req); X509_REQ_free(req); @@ -273,13 +255,13 @@ ossl_x509_to_req(VALUE self) * call-seq: * cert.version => integer */ -static VALUE +static VALUE ossl_x509_get_version(VALUE self) { X509 *x509; GetX509(self, x509); - + return LONG2NUM(X509_get_version(x509)); } @@ -287,18 +269,18 @@ ossl_x509_get_version(VALUE self) * call-seq: * cert.version = integer => integer */ -static VALUE +static VALUE ossl_x509_set_version(VALUE self, VALUE version) { X509 *x509; long ver; if ((ver = NUM2LONG(version)) < 0) { - ossl_raise(eX509CertError, "version must be >= 0!"); + ossl_raise(eX509CertError, "version must be >= 0!"); } GetX509(self, x509); if (!X509_set_version(x509, ver)) { - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); } return version; @@ -308,13 +290,13 @@ ossl_x509_set_version(VALUE self, VALUE version) * call-seq: * cert.serial => integer */ -static VALUE +static VALUE ossl_x509_get_serial(VALUE self) { X509 *x509; GetX509(self, x509); - + return asn1integer_to_num(X509_get_serialNumber(x509)); } @@ -322,56 +304,52 @@ ossl_x509_get_serial(VALUE self) * call-seq: * cert.serial = integer => integer */ -static VALUE +static VALUE ossl_x509_set_serial(VALUE self, VALUE num) { X509 *x509; GetX509(self, x509); + X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509))); - x509->cert_info->serialNumber = - num_to_asn1integer(num, X509_get_serialNumber(x509)); - return num; } /* * call-seq: * cert.signature_algorithm => string + * + * Returns the signature algorithm used to sign this certificate. This returns + * the algorithm name found in the TBSCertificate structure, not the outer + * \Certificate structure. + * + * Returns the long name of the signature algorithm, or the dotted decimal + * notation if \OpenSSL does not define a long name for it. */ -static VALUE +static VALUE ossl_x509_get_signature_algorithm(VALUE self) { X509 *x509; - BIO *out; - VALUE str; + const ASN1_OBJECT *obj; GetX509(self, x509); - out = BIO_new(BIO_s_mem()); - if (!out) ossl_raise(eX509CertError, NULL); - - if (!i2a_ASN1_OBJECT(out, x509->cert_info->signature->algorithm)) { - BIO_free(out); - ossl_raise(eX509CertError, NULL); - } - str = ossl_membio2str(out); - - return str; + X509_ALGOR_get0(&obj, NULL, NULL, X509_get0_tbs_sigalg(x509)); + return ossl_asn1obj_to_string_long_name(obj); } /* * call-seq: * cert.subject => name */ -static VALUE +static VALUE ossl_x509_get_subject(VALUE self) { X509 *x509; X509_NAME *name; - + GetX509(self, x509); if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */ - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); } return ossl_x509name_new(name); @@ -381,14 +359,14 @@ ossl_x509_get_subject(VALUE self) * call-seq: * cert.subject = name => name */ -static VALUE +static VALUE ossl_x509_set_subject(VALUE self, VALUE subject) { X509 *x509; - + GetX509(self, x509); if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */ - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); } return subject; @@ -398,7 +376,7 @@ ossl_x509_set_subject(VALUE self, VALUE subject) * call-seq: * cert.issuer => name */ -static VALUE +static VALUE ossl_x509_get_issuer(VALUE self) { X509 *x509; @@ -406,7 +384,7 @@ ossl_x509_get_issuer(VALUE self) GetX509(self, x509); if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */ - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); } return ossl_x509name_new(name); @@ -416,14 +394,14 @@ ossl_x509_get_issuer(VALUE self) * call-seq: * cert.issuer = name => name */ -static VALUE +static VALUE ossl_x509_set_issuer(VALUE self, VALUE issuer) { X509 *x509; GetX509(self, x509); if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */ - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); } return issuer; @@ -433,15 +411,15 @@ ossl_x509_set_issuer(VALUE self, VALUE issuer) * call-seq: * cert.not_before => time */ -static VALUE +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! */ - ossl_raise(eX509CertError, NULL); + if (!(asn1time = X509_get0_notBefore(x509))) { + ossl_raise(eX509CertError, NULL); } return asn1time_to_time(asn1time); @@ -451,17 +429,19 @@ ossl_x509_get_not_before(VALUE self) * call-seq: * cert.not_before = time => time */ -static VALUE +static VALUE ossl_x509_set_not_before(VALUE self, VALUE time) { X509 *x509; - time_t sec; - - sec = time_to_time_t(time); + ASN1_TIME *asn1time; + 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_set1_notBefore(x509, asn1time)) { + ASN1_TIME_free(asn1time); + ossl_raise(eX509CertError, "X509_set_notBefore"); } + ASN1_TIME_free(asn1time); return time; } @@ -470,15 +450,15 @@ ossl_x509_set_not_before(VALUE self, VALUE time) * call-seq: * cert.not_after => time */ -static VALUE +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! */ - ossl_raise(eX509CertError, NULL); + if (!(asn1time = X509_get0_notAfter(x509))) { + ossl_raise(eX509CertError, NULL); } return asn1time_to_time(asn1time); @@ -486,19 +466,21 @@ ossl_x509_get_not_after(VALUE self) /* * call-seq: - * cert.not_before = time => time + * cert.not_after = time => time */ -static VALUE +static VALUE ossl_x509_set_not_after(VALUE self, VALUE time) { X509 *x509; - time_t sec; - - sec = time_to_time_t(time); + ASN1_TIME *asn1time; + 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_set1_notAfter(x509, asn1time)) { + ASN1_TIME_free(asn1time); + ossl_raise(eX509CertError, "X509_set_notAfter"); } + ASN1_TIME_free(asn1time); return time; } @@ -507,7 +489,7 @@ ossl_x509_set_not_after(VALUE self, VALUE time) * call-seq: * cert.public_key => key */ -static VALUE +static VALUE ossl_x509_get_public_key(VALUE self) { X509 *x509; @@ -515,26 +497,27 @@ ossl_x509_get_public_key(VALUE self) GetX509(self, x509); if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */ - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509CertError, NULL); } - return ossl_pkey_new(pkey); /* NO DUP - OK */ + return ossl_pkey_wrap(pkey); } /* * call-seq: - * cert.public_key = key => key + * cert.public_key = key */ -static VALUE +static VALUE ossl_x509_set_public_key(VALUE self, VALUE key) { X509 *x509; + EVP_PKEY *pkey; GetX509(self, x509); - if (!X509_set_pubkey(x509, GetPKeyPtr(key))) { /* DUPs pkey */ - ossl_raise(eX509CertError, NULL); - } - + pkey = GetPKeyPtr(key); + ossl_pkey_check_public_key(pkey); + if (!X509_set_pubkey(x509, pkey)) + ossl_raise(eX509CertError, "X509_set_pubkey"); return key; } @@ -542,19 +525,20 @@ ossl_x509_set_public_key(VALUE self, VALUE key) * call-seq: * cert.sign(key, digest) => self */ -static VALUE +static VALUE ossl_x509_sign(VALUE self, VALUE key, VALUE digest) { X509 *x509; EVP_PKEY *pkey; const EVP_MD *md; + VALUE md_holder; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + /* NULL needed for some key types, e.g. Ed25519 */ + md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder); GetX509(self, x509); - if (!X509_sign(x509, pkey, md)) { - ossl_raise(eX509CertError, NULL); - } + if (!X509_sign(x509, pkey, md)) + ossl_raise(eX509CertError, "X509_sign"); return self; } @@ -563,45 +547,48 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest) * call-seq: * cert.verify(key) => true | false * - * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' + * Verifies the signature of the certificate, with the public key _key_. _key_ + * must be an instance of OpenSSL::PKey. */ -static VALUE +static VALUE 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) { - return Qtrue; + pkey = GetPKeyPtr(key); + ossl_pkey_check_public_key(pkey); + switch (X509_verify(x509, pkey)) { + case 1: + return Qtrue; + case 0: + ossl_clear_error(); + return Qfalse; + default: + ossl_raise(eX509CertError, NULL); } - - return Qfalse; } /* * call-seq: - * cert.check_private_key(key) + * cert.check_private_key(key) -> true | false * - * Checks if 'key' is PRIV key for this cert + * Returns +true+ if _key_ is the corresponding private key to the Subject + * Public Key Information, +false+ otherwise. */ -static VALUE +static VALUE ossl_x509_check_private_key(VALUE self, VALUE key) { X509 *x509; EVP_PKEY *pkey; - + /* not needed private key, but should be */ 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()); - return Qfalse; + ossl_clear_error(); + return Qfalse; } return Qtrue; @@ -611,7 +598,7 @@ ossl_x509_check_private_key(VALUE self, VALUE key) * call-seq: * cert.extensions => [extension...] */ -static VALUE +static VALUE ossl_x509_get_extensions(VALUE self) { X509 *x509; @@ -621,13 +608,10 @@ ossl_x509_get_extensions(VALUE self) GetX509(self, x509); count = X509_get_ext_count(x509); - if (count < 0) { - return rb_ary_new(); - } - ary = rb_ary_new2(count); + ary = rb_ary_new_capa(count); for (i=0; i<count; i++) { - ext = X509_get_ext(x509, i); /* NO DUP - don't free! */ - rb_ary_push(ary, ossl_x509ext_new(ext)); + ext = X509_get_ext(x509, i); /* NO DUP - don't free! */ + rb_ary_push(ary, ossl_x509ext_new(ext)); } return ary; @@ -637,29 +621,26 @@ ossl_x509_get_extensions(VALUE self) * call-seq: * cert.extensions = [ext...] => [ext...] */ -static VALUE +static VALUE ossl_x509_set_extensions(VALUE self, VALUE ary) { X509 *x509; X509_EXTENSION *ext; - int i; - + long i; + Check_Type(ary, T_ARRAY); /* All ary's members should be X509Extension */ for (i=0; i<RARRAY_LEN(ary); i++) { - OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext); + 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; + for (i = X509_get_ext_count(x509); i > 0; i--) + X509_EXTENSION_free(X509_delete_ext(x509, 0)); for (i=0; i<RARRAY_LEN(ary); i++) { - ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]); - - if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */ - X509_EXTENSION_free(ext); - ossl_raise(eX509CertError, NULL); - } - X509_EXTENSION_free(ext); + ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); + if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */ + ossl_raise(eX509CertError, "X509_add_ext"); + } } return ary; @@ -669,71 +650,336 @@ ossl_x509_set_extensions(VALUE self, VALUE ary) * call-seq: * cert.add_extension(extension) => extension */ -static VALUE +static VALUE ossl_x509_add_extension(VALUE self, VALUE extension) { X509 *x509; 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); + ossl_raise(eX509CertError, NULL); } - X509_EXTENSION_free(ext); return extension; } +/* + * call-seq: + * cert1 == cert2 -> true | false + * + * Compares the two certificates. Note that this takes into account all fields, + * not just the issuer name and the serial number. + * + * This method uses X509_cmp() from OpenSSL, which compares certificates based + * on their cached DER encodings. The comparison can be unreliable if a + * certificate is incomplete. + * + * See also the man page X509_cmp(3). + */ static VALUE -ossl_x509_inspect(VALUE self) +ossl_x509_eq(VALUE self, VALUE other) { + X509 *a, *b; + + GetX509(self, a); + if (!rb_obj_is_kind_of(other, cX509Cert)) + return Qfalse; + GetX509(other, b); + + return !X509_cmp(a, b) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * cert.tbs_bytes => string + * + * Returns the DER-encoded bytes of the certificate's to be signed certificate. + * This is mainly useful for validating embedded certificate transparency signatures. + */ +static VALUE +ossl_x509_tbs_bytes(VALUE self) +{ + X509 *x509; + int len; + unsigned char *p0; VALUE str; - char *cname = rb_class2name(rb_obj_class(self)); - str = rb_str_new2("#<"); - rb_str_cat2(str, cname); - rb_str_cat2(str, " "); + GetX509(self, x509); + len = i2d_re_X509_tbs(x509, NULL); + if (len <= 0) { + ossl_raise(eX509CertError, "i2d_re_X509_tbs"); + } + str = rb_str_new(NULL, len); + p0 = (unsigned char *)RSTRING_PTR(str); + if (i2d_re_X509_tbs(x509, &p0) <= 0) { + ossl_raise(eX509CertError, "i2d_re_X509_tbs"); + } + ossl_str_adjust(str, p0); + + return str; +} + +struct load_chained_certificates_arguments { + VALUE certificates; + X509 *certificate; +}; - rb_str_cat2(str, "subject="); - rb_str_append(str, rb_inspect(ossl_x509_get_subject(self))); - rb_str_cat2(str, ", "); +static VALUE +load_chained_certificates_append_push(VALUE _arguments) { + struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments; - rb_str_cat2(str, "issuer="); - rb_str_append(str, rb_inspect(ossl_x509_get_issuer(self))); - rb_str_cat2(str, ", "); + if (arguments->certificates == Qnil) { + arguments->certificates = rb_ary_new(); + } - rb_str_cat2(str, "serial="); - rb_str_append(str, rb_inspect(ossl_x509_get_serial(self))); - rb_str_cat2(str, ", "); + rb_ary_push(arguments->certificates, ossl_x509_new(arguments->certificate)); - rb_str_cat2(str, "not_before="); - rb_str_append(str, rb_inspect(ossl_x509_get_not_before(self))); - rb_str_cat2(str, ", "); + return Qnil; +} - rb_str_cat2(str, "not_after="); - rb_str_append(str, rb_inspect(ossl_x509_get_not_after(self))); +static VALUE +load_chained_certificate_append_ensure(VALUE _arguments) { + struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments; - str = rb_str_cat2(str, ">"); + X509_free(arguments->certificate); - return str; + return Qnil; +} + +inline static VALUE +load_chained_certificates_append(VALUE certificates, X509 *certificate) { + struct load_chained_certificates_arguments arguments; + arguments.certificates = certificates; + arguments.certificate = certificate; + + rb_ensure(load_chained_certificates_append_push, (VALUE)&arguments, load_chained_certificate_append_ensure, (VALUE)&arguments); + + return arguments.certificates; +} + +static VALUE +load_chained_certificates_PEM(BIO *in) { + VALUE certificates = Qnil; + X509 *certificate = PEM_read_bio_X509(in, NULL, NULL, NULL); + + /* If we cannot read even one certificate: */ + if (certificate == NULL) { + /* If we cannot read one certificate because we could not read the PEM encoding: */ + if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) { + ossl_clear_error(); + } + + if (ERR_peek_last_error()) + ossl_raise(eX509CertError, NULL); + else + return Qnil; + } + + certificates = load_chained_certificates_append(Qnil, certificate); + + while ((certificate = PEM_read_bio_X509(in, NULL, NULL, NULL))) { + load_chained_certificates_append(certificates, certificate); + } + + /* We tried to read one more certificate but could not read start line: */ + if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) { + /* This is not an error, it means we are finished: */ + ossl_clear_error(); + + return certificates; + } + + /* Alternatively, if we reached the end of the file and there was no error: */ + if (BIO_eof(in) && !ERR_peek_last_error()) { + return certificates; + } else { + /* Otherwise, we tried to read a certificate but failed somewhere: */ + ossl_raise(eX509CertError, NULL); + } +} + +static VALUE +load_chained_certificates_DER(BIO *in) { + X509 *certificate = d2i_X509_bio(in, NULL); + + /* If we cannot read one certificate: */ + if (certificate == NULL) { + /* Ignore error. We could not load. */ + ossl_clear_error(); + + return Qnil; + } + + return load_chained_certificates_append(Qnil, certificate); +} + +static VALUE +load_chained_certificates(VALUE _io) { + BIO *in = (BIO*)_io; + VALUE certificates = Qnil; + + /* + DER is a binary format and it may contain octets within it that look like + PEM encoded certificates. So we need to check DER first. + */ + certificates = load_chained_certificates_DER(in); + + if (certificates != Qnil) + return certificates; + + OSSL_BIO_reset(in); + + certificates = load_chained_certificates_PEM(in); + + if (certificates != Qnil) + return certificates; + + /* Otherwise we couldn't read the output correctly so fail: */ + ossl_raise(eX509CertError, "Could not detect format of certificate data!"); +} + +static VALUE +load_chained_certificates_ensure(VALUE _io) { + BIO *in = (BIO*)_io; + + BIO_free(in); + + return Qnil; +} + +/* + * call-seq: + * OpenSSL::X509::Certificate.load(string) -> [certs...] + * OpenSSL::X509::Certificate.load(file) -> [certs...] + * + * Read the chained certificates from the given input. Supports both PEM + * and DER encoded certificates. + * + * PEM is a text format and supports more than one certificate. + * + * DER is a binary format and only supports one certificate. + * + * If the file is empty, or contains only unrelated data, an + * +OpenSSL::X509::CertificateError+ exception will be raised. + */ +static VALUE +ossl_x509_load(VALUE klass, VALUE buffer) +{ + BIO *in = ossl_obj2bio(&buffer); + + return rb_ensure(load_chained_certificates, (VALUE)in, load_chained_certificates_ensure, (VALUE)in); } /* * INIT */ -void -Init_ossl_x509cert() +void +Init_ossl_x509cert(void) { eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError); - + + /* Document-class: OpenSSL::X509::Certificate + * + * Implementation of an X.509 certificate as specified in RFC 5280. + * Provides access to a certificate's attributes and allows certificates + * to be read from a string, but also supports the creation of new + * certificates from scratch. + * + * === Reading a certificate from a file + * + * Certificate is capable of handling DER-encoded certificates and + * certificates encoded in OpenSSL's PEM format. + * + * raw = File.binread "cert.cer" # DER- or PEM-encoded + * certificate = OpenSSL::X509::Certificate.new raw + * + * === Saving a certificate to a file + * + * A certificate may be encoded in DER format + * + * cert = ... + * File.open("cert.cer", "wb") { |f| f.print cert.to_der } + * + * or in PEM format + * + * cert = ... + * File.open("cert.pem", "wb") { |f| f.print cert.to_pem } + * + * X.509 certificates are associated with a private/public key pair, + * typically a RSA, DSA or ECC key (see also OpenSSL::PKey::RSA, + * OpenSSL::PKey::DSA and OpenSSL::PKey::EC), the public key itself is + * stored within the certificate and can be accessed in form of an + * OpenSSL::PKey. Certificates are typically used to be able to associate + * some form of identity with a key pair, for example web servers serving + * pages over HTTPs use certificates to authenticate themselves to the user. + * + * The public key infrastructure (PKI) model relies on trusted certificate + * authorities ("root CAs") that issue these certificates, so that end + * users need to base their trust just on a selected few authorities + * that themselves again vouch for subordinate CAs issuing their + * certificates to end users. + * + * The OpenSSL::X509 module provides the tools to set up an independent + * PKI, similar to scenarios where the 'openssl' command line tool is + * used for issuing certificates in a private PKI. + * + * === Creating a root CA certificate and an end-entity certificate + * + * First, we need to create a "self-signed" root certificate. To do so, + * we need to generate a key first. Please note that the choice of "1" + * as a serial number is considered a security flaw for real certificates. + * Secure choices are integers in the two-digit byte range and ideally + * not sequential but secure random numbers, steps omitted here to keep + * the example concise. + * + * root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key + * root_ca = OpenSSL::X509::Certificate.new + * root_ca.version = 2 # cf. RFC 5280 - to make it a "v3" certificate + * root_ca.serial = 1 + * root_ca.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby CA" + * root_ca.issuer = root_ca.subject # root CA's are "self-signed" + * root_ca.public_key = root_key.public_key + * root_ca.not_before = Time.now + * root_ca.not_after = root_ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity + * ef = OpenSSL::X509::ExtensionFactory.new + * ef.subject_certificate = root_ca + * ef.issuer_certificate = root_ca + * root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true)) + * root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true)) + * root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) + * root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false)) + * root_ca.sign(root_key, OpenSSL::Digest.new('SHA256')) + * + * The next step is to create the end-entity certificate using the root CA + * certificate. + * + * key = OpenSSL::PKey::RSA.new 2048 + * cert = OpenSSL::X509::Certificate.new + * cert.version = 2 + * cert.serial = 2 + * cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby certificate" + * cert.issuer = root_ca.subject # root CA is the issuer + * cert.public_key = key.public_key + * cert.not_before = Time.now + * cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 # 1 years validity + * ef = OpenSSL::X509::ExtensionFactory.new + * ef.subject_certificate = cert + * ef.issuer_certificate = root_ca + * cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true)) + * cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) + * cert.sign(root_key, OpenSSL::Digest.new('SHA256')) + * + */ cX509Cert = rb_define_class_under(mX509, "Certificate", rb_cObject); - + + rb_define_singleton_method(cX509Cert, "load", ossl_x509_load, 1); + rb_define_alloc_func(cX509Cert, ossl_x509_alloc); rb_define_method(cX509Cert, "initialize", ossl_x509_initialize, -1); - rb_define_copy_func(cX509Cert, ossl_x509_copy); - + rb_define_method(cX509Cert, "initialize_copy", ossl_x509_copy, 1); + rb_define_method(cX509Cert, "to_der", ossl_x509_to_der, 0); rb_define_method(cX509Cert, "to_pem", ossl_x509_to_pem, 0); rb_define_alias(cX509Cert, "to_s", "to_pem"); @@ -759,6 +1005,6 @@ Init_ossl_x509cert() rb_define_method(cX509Cert, "extensions", ossl_x509_get_extensions, 0); rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1); rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1); - rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0); + rb_define_method(cX509Cert, "==", ossl_x509_eq, 1); + rb_define_method(cX509Cert, "tbs_bytes", ossl_x509_tbs_bytes, 0); } - diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index be9ddacf48..a221429c34 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -1,37 +1,48 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapX509CRL(klass, obj, crl) do { \ - if (!crl) { \ - ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ +#define NewX509CRL(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509crl_type, 0) +#define SetX509CRL(obj, crl) do { \ + if (!(crl)) { \ + ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_CRL_free, crl); \ + RTYPEDDATA_DATA(obj) = (crl); \ } while (0) #define GetX509CRL(obj, crl) do { \ - Data_Get_Struct(obj, X509_CRL, crl); \ - if (!crl) { \ - ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509_CRL, &ossl_x509crl_type, (crl)); \ + if (!(crl)) { \ + ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \ } \ } while (0) -#define SafeGetX509CRL(obj, crl) do { \ - OSSL_Check_Kind(obj, cX509CRL); \ - GetX509CRL(obj, crl); \ -} while (0) /* * Classes */ -VALUE cX509CRL; -VALUE eX509CRLError; +static VALUE cX509CRL; +static VALUE eX509CRLError; + +static void +ossl_x509crl_free(void *ptr) +{ + X509_CRL_free(ptr); +} + +static const rb_data_type_t ossl_x509crl_type = { + "OpenSSL/X509/CRL", + { + 0, ossl_x509crl_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; /* * PUBLIC @@ -41,18 +52,7 @@ GetX509CRLPtr(VALUE obj) { X509_CRL *crl; - SafeGetX509CRL(obj, crl); - - return crl; -} - -X509_CRL * -DupX509CRLPtr(VALUE obj) -{ - X509_CRL *crl; - - SafeGetX509CRL(obj, crl); - CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL); + GetX509CRL(obj, crl); return crl; } @@ -63,64 +63,73 @@ ossl_x509crl_new(X509_CRL *crl) X509_CRL *tmp; VALUE obj; - tmp = crl ? X509_CRL_dup(crl) : X509_CRL_new(); - if(!tmp) ossl_raise(eX509CRLError, NULL); - WrapX509CRL(cX509CRL, obj, tmp); - + obj = NewX509CRL(cX509CRL); + tmp = X509_CRL_dup(crl); + if (!tmp) + ossl_raise(eX509CRLError, "X509_CRL_dup"); + SetX509CRL(obj, tmp); + return obj; } /* * PRIVATE */ -static VALUE +static VALUE ossl_x509crl_alloc(VALUE klass) { X509_CRL *crl; VALUE obj; + obj = NewX509CRL(klass); if (!(crl = X509_CRL_new())) { - ossl_raise(eX509CRLError, NULL); + ossl_raise(eX509CRLError, NULL); } - WrapX509CRL(klass, obj, crl); + SetX509CRL(obj, crl); return obj; } -static VALUE +static VALUE ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self) { BIO *in; - X509_CRL *crl; + X509_CRL *crl, *crl_orig = RTYPEDDATA_DATA(self); VALUE arg; + rb_check_frozen(self); if (rb_scan_args(argc, argv, "01", &arg) == 0) { - return self; + return self; } arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - crl = PEM_read_bio_X509_CRL(in, (X509_CRL **)&DATA_PTR(self), NULL, NULL); + in = ossl_obj2bio(&arg); + crl = d2i_X509_CRL_bio(in, NULL); if (!crl) { - BIO_reset(in); - crl = d2i_X509_CRL_bio(in, (X509_CRL **)&DATA_PTR(self)); + OSSL_BIO_reset(in); + crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); } BIO_free(in); - if (!crl) ossl_raise(eX509CRLError, NULL); + if (!crl) + ossl_raise(eX509CRLError, "PEM_read_bio_X509_CRL"); + + RTYPEDDATA_DATA(self) = crl; + X509_CRL_free(crl_orig); return self; } +/* :nodoc: */ static VALUE ossl_x509crl_copy(VALUE self, VALUE other) { X509_CRL *a, *b, *crl; - + rb_check_frozen(self); if (self == other) return self; GetX509CRL(self, a); - SafeGetX509CRL(other, b); + GetX509CRL(other, b); if (!(crl = X509_CRL_dup(b))) { - ossl_raise(eX509CRLError, NULL); + ossl_raise(eX509CRLError, NULL); } X509_CRL_free(a); DATA_PTR(self) = crl; @@ -128,7 +137,7 @@ ossl_x509crl_copy(VALUE self, VALUE other) return self; } -static VALUE +static VALUE ossl_x509crl_get_version(VALUE self) { X509_CRL *crl; @@ -140,46 +149,46 @@ ossl_x509crl_get_version(VALUE self) return LONG2NUM(ver); } -static VALUE +static VALUE ossl_x509crl_set_version(VALUE self, VALUE version) { X509_CRL *crl; long ver; if ((ver = NUM2LONG(version)) < 0) { - ossl_raise(eX509CRLError, "version must be >= 0!"); + ossl_raise(eX509CRLError, "version must be >= 0!"); } GetX509CRL(self, crl); if (!X509_CRL_set_version(crl, ver)) { - ossl_raise(eX509CRLError, NULL); + ossl_raise(eX509CRLError, NULL); } return version; } -static VALUE +/* + * call-seq: + * crl.signature_algorithm -> string + * + * Returns the signature algorithm used to sign this CRL. + * + * Returns the long name of the signature algorithm, or the dotted decimal + * notation if \OpenSSL does not define a long name for it. + */ +static VALUE ossl_x509crl_get_signature_algorithm(VALUE self) { X509_CRL *crl; - BIO *out; - BUF_MEM *buf; - VALUE str; + const X509_ALGOR *alg; + const ASN1_OBJECT *obj; GetX509CRL(self, crl); - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eX509CRLError, NULL); - } - if (!i2a_ASN1_OBJECT(out, crl->sig_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; + X509_CRL_get0_signature(crl, NULL, &alg); + X509_ALGOR_get0(&obj, NULL, NULL, alg); + return ossl_asn1obj_to_string_long_name(obj); } -static VALUE +static VALUE ossl_x509crl_get_issuer(VALUE self) { X509_CRL *crl; @@ -189,7 +198,7 @@ ossl_x509crl_get_issuer(VALUE self) return ossl_x509name_new(X509_CRL_get_issuer(crl)); /* NO DUP - don't free */ } -static VALUE +static VALUE ossl_x509crl_set_issuer(VALUE self, VALUE issuer) { X509_CRL *crl; @@ -197,58 +206,69 @@ ossl_x509crl_set_issuer(VALUE self, VALUE issuer) GetX509CRL(self, crl); if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */ - ossl_raise(eX509CRLError, NULL); + ossl_raise(eX509CRLError, NULL); } return issuer; } -static VALUE +static VALUE ossl_x509crl_get_last_update(VALUE self) { X509_CRL *crl; + const ASN1_TIME *time; GetX509CRL(self, crl); + time = X509_CRL_get0_lastUpdate(crl); + if (!time) + return Qnil; - return asn1time_to_time(X509_CRL_get_lastUpdate(crl)); + return asn1time_to_time(time); } -static VALUE +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_set1_lastUpdate(crl, asn1time)) { + ASN1_TIME_free(asn1time); + ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate"); } + ASN1_TIME_free(asn1time); return time; } -static VALUE +static VALUE ossl_x509crl_get_next_update(VALUE self) { X509_CRL *crl; + const ASN1_TIME *time; GetX509CRL(self, crl); + time = X509_CRL_get0_nextUpdate(crl); + if (!time) + return Qnil; - return asn1time_to_time(X509_CRL_get_nextUpdate(crl)); + return asn1time_to_time(time); } -static VALUE +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_set1_nextUpdate(crl, asn1time)) { + ASN1_TIME_free(asn1time); + ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate"); } + ASN1_TIME_free(asn1time); return time; } @@ -258,53 +278,55 @@ ossl_x509crl_get_revoked(VALUE self) { X509_CRL *crl; int i, num; - X509_REVOKED *rev; - VALUE ary, revoked; + STACK_OF(X509_REVOKED) *sk; + VALUE ary; GetX509CRL(self, crl); - num = sk_X509_CRL_num(X509_CRL_get_REVOKED(crl)); - if (num < 0) { - OSSL_Debug("num < 0???"); - return rb_ary_new(); - } - ary = rb_ary_new2(num); + sk = X509_CRL_get_REVOKED(crl); + if (!sk) + return rb_ary_new(); + + num = sk_X509_REVOKED_num(sk); + ary = rb_ary_new_capa(num); for(i=0; i<num; i++) { - /* NO DUP - don't free! */ - rev = (X509_REVOKED *)sk_X509_CRL_value(X509_CRL_get_REVOKED(crl), i); - revoked = ossl_x509revoked_new(rev); - rb_ary_push(ary, revoked); + X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i); + rb_ary_push(ary, ossl_x509revoked_new(rev)); } return ary; } -static VALUE +static VALUE ossl_x509crl_set_revoked(VALUE self, VALUE ary) { X509_CRL *crl; X509_REVOKED *rev; - int i; + STACK_OF(X509_REVOKED) *sk; + long i; Check_Type(ary, T_ARRAY); /* All ary members should be X509 Revoked */ for (i=0; i<RARRAY_LEN(ary); i++) { - OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Rev); + 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_PTR(ary)[i]); - if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */ - ossl_raise(eX509CRLError, NULL); - } + rev = DupX509RevokedPtr(RARRAY_AREF(ary, i)); + if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */ + X509_REVOKED_free(rev); + ossl_raise(eX509CRLError, "X509_CRL_add0_revoked"); + } } X509_CRL_sort(crl); return ary; } -static VALUE +static VALUE ossl_x509crl_add_revoked(VALUE self, VALUE revoked) { X509_CRL *crl; @@ -313,120 +335,110 @@ ossl_x509crl_add_revoked(VALUE self, VALUE revoked) GetX509CRL(self, crl); rev = DupX509RevokedPtr(revoked); if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */ - ossl_raise(eX509CRLError, NULL); + X509_REVOKED_free(rev); + ossl_raise(eX509CRLError, "X509_CRL_add0_revoked"); } X509_CRL_sort(crl); return revoked; } -static VALUE +static VALUE ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest) { X509_CRL *crl; EVP_PKEY *pkey; const EVP_MD *md; + VALUE md_holder; GetX509CRL(self, crl); pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); - if (!X509_CRL_sign(crl, pkey, md)) { - ossl_raise(eX509CRLError, NULL); - } + /* NULL needed for some key types, e.g. Ed25519 */ + md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder); + if (!X509_CRL_sign(crl, pkey, md)) + ossl_raise(eX509CRLError, "X509_CRL_sign"); return self; } -static VALUE +static VALUE ossl_x509crl_verify(VALUE self, VALUE key) { X509_CRL *crl; - int ret; + EVP_PKEY *pkey; GetX509CRL(self, crl); - if ((ret = X509_CRL_verify(crl, GetPKeyPtr(key))) < 0) { - ossl_raise(eX509CRLError, NULL); - } - if (ret == 1) { - return Qtrue; + pkey = GetPKeyPtr(key); + ossl_pkey_check_public_key(pkey); + switch (X509_CRL_verify(crl, pkey)) { + case 1: + return Qtrue; + case 0: + ossl_clear_error(); + return Qfalse; + default: + ossl_raise(eX509CRLError, NULL); } - - return Qfalse; } -static VALUE +static VALUE 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()))) { - ossl_raise(eX509CRLError, NULL); + ossl_raise(eX509CRLError, NULL); } if (!i2d_X509_CRL_bio(out, crl)) { - BIO_free(out); - ossl_raise(eX509CRLError, NULL); + 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 +static VALUE 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()))) { - ossl_raise(eX509CRLError, NULL); + ossl_raise(eX509CRLError, NULL); } if (!PEM_write_bio_X509_CRL(out, crl)) { - BIO_free(out); - ossl_raise(eX509CRLError, NULL); + 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 +static VALUE 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()))) { - ossl_raise(eX509CRLError, NULL); + ossl_raise(eX509CRLError, NULL); } if (!X509_CRL_print(out, crl)) { - BIO_free(out); - ossl_raise(eX509CRLError, NULL); + 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); } /* * Gets X509v3 extensions as array of X509Ext objects */ -static VALUE +static VALUE ossl_x509crl_get_extensions(VALUE self) { X509_CRL *crl; @@ -436,14 +448,10 @@ ossl_x509crl_get_extensions(VALUE self) GetX509CRL(self, crl); count = X509_CRL_get_ext_count(crl); - if (count < 0) { - OSSL_Debug("count < 0???"); - return rb_ary_new(); - } - ary = rb_ary_new2(count); + ary = rb_ary_new_capa(count); for (i=0; i<count; i++) { - ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */ - rb_ary_push(ary, ossl_x509ext_new(ext)); + ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */ + rb_ary_push(ary, ossl_x509ext_new(ext)); } return ary; @@ -452,46 +460,42 @@ ossl_x509crl_get_extensions(VALUE self) /* * Sets X509_EXTENSIONs */ -static VALUE +static VALUE ossl_x509crl_set_extensions(VALUE self, VALUE ary) { X509_CRL *crl; X509_EXTENSION *ext; - int i; - + long i; + Check_Type(ary, T_ARRAY); /* All ary members should be X509 Extensions */ for (i=0; i<RARRAY_LEN(ary); i++) { - OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext); + 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; + for (i = X509_CRL_get_ext_count(crl); i > 0; i--) + X509_EXTENSION_free(X509_CRL_delete_ext(crl, 0)); for (i=0; i<RARRAY_LEN(ary); i++) { - ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]); - if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */ - X509_EXTENSION_free(ext); - ossl_raise(eX509CRLError, NULL); - } - 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, "X509_CRL_add_ext"); + } } return ary; } -static VALUE +static VALUE ossl_x509crl_add_extension(VALUE self, VALUE extension) { X509_CRL *crl; 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); - ossl_raise(eX509CRLError, NULL); + ext = GetX509ExtPtr(extension); + if (!X509_CRL_add_ext(crl, ext, -1)) { + ossl_raise(eX509CRLError, NULL); } - X509_EXTENSION_free(ext); return extension; } @@ -499,17 +503,17 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension) /* * INIT */ -void -Init_ossl_x509crl() +void +Init_ossl_x509crl(void) { eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError); cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject); - + rb_define_alloc_func(cX509CRL, ossl_x509crl_alloc); rb_define_method(cX509CRL, "initialize", ossl_x509crl_initialize, -1); - rb_define_copy_func(cX509CRL, ossl_x509crl_copy); - + rb_define_method(cX509CRL, "initialize_copy", ossl_x509crl_copy, 1); + rb_define_method(cX509CRL, "version", ossl_x509crl_get_version, 0); rb_define_method(cX509CRL, "version=", ossl_x509crl_set_version, 1); rb_define_method(cX509CRL, "signature_algorithm", ossl_x509crl_get_signature_algorithm, 0); @@ -532,4 +536,3 @@ Init_ossl_x509crl() rb_define_method(cX509CRL, "extensions=", ossl_x509crl_set_extensions, 1); rb_define_method(cX509CRL, "add_extension", ossl_x509crl_add_extension, 1); } - diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c index aa9366f901..ef66ecc3fe 100644 --- a/ext/openssl/ossl_x509ext.c +++ b/ext/openssl/ossl_x509ext.c @@ -1,41 +1,39 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapX509Ext(klass, obj, ext) do { \ - if (!ext) { \ - ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ +#define NewX509Ext(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509ext_type, 0) +#define SetX509Ext(obj, ext) do { \ + if (!(ext)) { \ + ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_EXTENSION_free, ext); \ + RTYPEDDATA_DATA(obj) = (ext); \ } while (0) #define GetX509Ext(obj, ext) do { \ - Data_Get_Struct(obj, X509_EXTENSION, ext); \ - if (!ext) { \ - ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \ + if (!(ext)) { \ + ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \ } \ } while (0) -#define SafeGetX509Ext(obj, ext) do { \ - OSSL_Check_Kind(obj, cX509Ext); \ - GetX509Ext(obj, ext); \ -} while (0) #define MakeX509ExtFactory(klass, obj, ctx) do { \ - if (!(ctx = OPENSSL_malloc(sizeof(X509V3_CTX)))) \ + (obj) = TypedData_Wrap_Struct((klass), &ossl_x509extfactory_type, 0); \ + if (!((ctx) = OPENSSL_malloc(sizeof(X509V3_CTX)))) \ ossl_raise(rb_eRuntimeError, "CTX wasn't allocated!"); \ - X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, 0); \ - obj = Data_Wrap_Struct(klass, 0, ossl_x509extfactory_free, ctx); \ + X509V3_set_ctx((ctx), NULL, NULL, NULL, NULL, 0); \ + RTYPEDDATA_DATA(obj) = (ctx); \ } while (0) #define GetX509ExtFactory(obj, ctx) do { \ - Data_Get_Struct(obj, X509V3_CTX, ctx); \ - if (!ctx) { \ - ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \ + if (!(ctx)) { \ + ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \ } \ } while (0) @@ -43,28 +41,38 @@ * Classes */ VALUE cX509Ext; -VALUE cX509ExtFactory; -VALUE eX509ExtError; +static VALUE cX509ExtFactory; +static VALUE eX509ExtError; + +static void +ossl_x509ext_free(void *ptr) +{ + X509_EXTENSION_free(ptr); +} + +static const rb_data_type_t ossl_x509ext_type = { + "OpenSSL/X509/EXTENSION", + { + 0, ossl_x509ext_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; /* * Public */ -VALUE +VALUE ossl_x509ext_new(X509_EXTENSION *ext) { X509_EXTENSION *new; VALUE obj; - if (!ext) { - new = X509_EXTENSION_new(); - } else { - new = X509_EXTENSION_dup(ext); - } - if (!new) { - ossl_raise(eX509ExtError, NULL); - } - WrapX509Ext(cX509Ext, obj, new); - + obj = NewX509Ext(cX509Ext); + new = X509_EXTENSION_dup(ext); + if (!new) + ossl_raise(eX509ExtError, "X509_EXTENSION_dup"); + SetX509Ext(obj, new); + return obj; } @@ -73,24 +81,11 @@ GetX509ExtPtr(VALUE obj) { X509_EXTENSION *ext; - SafeGetX509Ext(obj, ext); + GetX509Ext(obj, ext); 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 */ @@ -98,23 +93,32 @@ DupX509ExtPtr(VALUE obj) * Ext factory */ static void -ossl_x509extfactory_free(X509V3_CTX *ctx) +ossl_x509extfactory_free(void *ctx) { OPENSSL_free(ctx); } -static VALUE +static const rb_data_type_t ossl_x509extfactory_type = { + "OpenSSL/X509/EXTENSION/Factory", + { + 0, ossl_x509extfactory_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE ossl_x509extfactory_alloc(VALUE klass) { X509V3_CTX *ctx; VALUE obj; MakeX509ExtFactory(klass, obj, ctx); + rb_iv_set(obj, "@config", Qnil); return obj; } -static VALUE +static VALUE ossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert) { X509V3_CTX *ctx; @@ -126,7 +130,7 @@ ossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert) return cert; } -static VALUE +static VALUE ossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert) { X509V3_CTX *ctx; @@ -138,7 +142,7 @@ ossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert) return cert; } -static VALUE +static VALUE ossl_x509extfactory_set_subject_req(VALUE self, VALUE req) { X509V3_CTX *ctx; @@ -150,7 +154,7 @@ ossl_x509extfactory_set_subject_req(VALUE self, VALUE req) return req; } -static VALUE +static VALUE ossl_x509extfactory_set_crl(VALUE self, VALUE crl) { X509V3_CTX *ctx; @@ -163,91 +167,70 @@ ossl_x509extfactory_set_crl(VALUE self, VALUE crl) } static VALUE -ossl_x509extfactory_set_config(VALUE self, VALUE config) -{ -#ifdef HAVE_X509V3_SET_NCONF - X509V3_CTX *ctx; - CONF *conf; - - GetX509ExtFactory(self, ctx); - rb_iv_set(self, "@config", config); - conf = GetConfigPtr(config); /* NO DUP NEEDED */ - X509V3_set_nconf(ctx, conf); - - return config; -#else - rb_notimplement(); -#endif -} - -static VALUE ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self) { /*X509V3_CTX *ctx;*/ VALUE issuer_cert, subject_cert, subject_req, crl; - + /*GetX509ExtFactory(self, ctx);*/ rb_scan_args(argc, argv, "04", - &issuer_cert, &subject_cert, &subject_req, &crl); + &issuer_cert, &subject_cert, &subject_req, &crl); if (!NIL_P(issuer_cert)) - ossl_x509extfactory_set_issuer_cert(self, issuer_cert); + ossl_x509extfactory_set_issuer_cert(self, issuer_cert); if (!NIL_P(subject_cert)) - ossl_x509extfactory_set_subject_cert(self, subject_cert); + ossl_x509extfactory_set_subject_cert(self, subject_cert); if (!NIL_P(subject_req)) - ossl_x509extfactory_set_subject_req(self, subject_req); + ossl_x509extfactory_set_subject_req(self, subject_req); if (!NIL_P(crl)) - ossl_x509extfactory_set_crl(self, crl); + ossl_x509extfactory_set_crl(self, crl); return 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 +static VALUE ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self) { X509V3_CTX *ctx; 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 + const char *oid_cstr = NULL; rb_scan_args(argc, argv, "21", &oid, &value, &critical); - StringValue(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)); + oid_cstr = StringValueCStr(oid); + nid = OBJ_ln2nid(oid_cstr); + if (nid != NID_undef) + oid_cstr = OBJ_nid2sn(nid); + valstr = rb_str_new2(RTEST(critical) ? "critical," : ""); rb_str_append(valstr, value); + StringValueCStr(valstr); + GetX509ExtFactory(self, ctx); -#ifdef HAVE_X509V3_EXT_NCONF_NID + obj = NewX509Ext(cX509Ext); rconf = rb_iv_get(self, "@config"); - conf = NIL_P(rconf) ? NULL : GetConfigPtr(rconf); - ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr)); -#else - if (!empty_lhash) empty_lhash = lh_new(NULL, NULL); - ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING_PTR(valstr)); -#endif + conf = NIL_P(rconf) ? NULL : GetConfig(rconf); + X509V3_set_nconf(ctx, conf); + + ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr)); + X509V3_set_ctx_nodb(ctx); if (!ext){ - ossl_raise(eX509ExtError, "%s = %s", - RSTRING_PTR(oid), RSTRING_PTR(value)); + ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr); } - WrapX509Ext(cX509Ext, obj, ext); + SetX509Ext(obj, ext); return obj; } @@ -261,30 +244,44 @@ ossl_x509ext_alloc(VALUE klass) X509_EXTENSION *ext; VALUE obj; + obj = NewX509Ext(klass); if(!(ext = X509_EXTENSION_new())){ - ossl_raise(eX509ExtError, NULL); + ossl_raise(eX509ExtError, NULL); } - WrapX509Ext(klass, obj, ext); + SetX509Ext(obj, ext); return obj; } +/* + * call-seq: + * OpenSSL::X509::Extension.new(der) + * OpenSSL::X509::Extension.new(oid, value) + * OpenSSL::X509::Extension.new(oid, value, critical) + * + * Creates an X509 extension. + * + * The extension may be created from _der_ data or from an extension _oid_ + * and _value_. The _oid_ may be either an OID or an extension name. If + * _critical_ is +true+ the extension is marked critical. + */ static VALUE ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self) { VALUE oid, value, critical; - unsigned char *p; - X509_EXTENSION *ext; + const unsigned char *p; + X509_EXTENSION *ext, *x; GetX509Ext(self, ext); if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){ - oid = ossl_to_der_if_possible(oid); - StringValue(oid); - p = RSTRING_PTR(oid); - if(!d2i_X509_EXTENSION((X509_EXTENSION**)&DATA_PTR(self), - &p, RSTRING_LEN(oid))) - ossl_raise(eX509ExtError, NULL); - return self; + oid = ossl_to_der_if_possible(oid); + StringValue(oid); + p = (unsigned char *)RSTRING_PTR(oid); + x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid)); + DATA_PTR(self) = ext; + if(!x) + ossl_raise(eX509ExtError, NULL); + return self; } rb_funcall(self, rb_intern("oid="), 1, oid); rb_funcall(self, rb_intern("value="), 1, value); @@ -293,19 +290,41 @@ ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* :nodoc: */ +static VALUE +ossl_x509ext_initialize_copy(VALUE self, VALUE other) +{ + X509_EXTENSION *ext, *ext_other, *ext_new; + + rb_check_frozen(self); + GetX509Ext(self, ext); + GetX509Ext(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) { X509_EXTENSION *ext; ASN1_OBJECT *obj; - char *s; - s = StringValuePtr(oid); - obj = OBJ_txt2obj(s, 0); - if(!obj) obj = OBJ_txt2obj(s, 1); - if(!obj) ossl_raise(eX509ExtError, NULL); GetX509Ext(self, ext); - X509_EXTENSION_set_object(ext, obj); + obj = OBJ_txt2obj(StringValueCStr(oid), 0); + if (!obj) + ossl_raise(eX509ExtError, "OBJ_txt2obj"); + if (!X509_EXTENSION_set_object(ext, obj)) { + ASN1_OBJECT_free(obj); + ossl_raise(eX509ExtError, "X509_EXTENSION_set_object"); + } + ASN1_OBJECT_free(obj); return oid; } @@ -315,24 +334,16 @@ ossl_x509ext_set_value(VALUE self, VALUE data) { X509_EXTENSION *ext; ASN1_OCTET_STRING *asn1s; - char *s; + GetX509Ext(self, ext); data = ossl_to_der_if_possible(data); StringValue(data); - if(!(s = OPENSSL_malloc(RSTRING_LEN(data)))) - ossl_raise(eX509ExtError, "malloc error"); - memcpy(s, RSTRING_PTR(data), RSTRING_LEN(data)); - if(!(asn1s = ASN1_OCTET_STRING_new())){ - free(s); - ossl_raise(eX509ExtError, NULL); - } - if(!M_ASN1_OCTET_STRING_set(asn1s, s, RSTRING_LEN(data))){ - free(s); - ASN1_OCTET_STRING_free(asn1s); - ossl_raise(eX509ExtError, NULL); + asn1s = X509_EXTENSION_get_data(ext); + + if (!ASN1_OCTET_STRING_set(asn1s, (unsigned char *)RSTRING_PTR(data), + RSTRING_LENINT(data))) { + ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set"); } - GetX509Ext(self, ext); - X509_EXTENSION_set_data(ext, asn1s); return data; } @@ -348,27 +359,20 @@ ossl_x509ext_set_critical(VALUE self, VALUE flag) return flag; } -static VALUE +/* + * call-seq: + * ext.oid -> string + * + * Returns the OID of the extension. Returns the short name or the dotted + * decimal notation. + */ +static VALUE ossl_x509ext_get_oid(VALUE obj) { X509_EXTENSION *ext; - ASN1_OBJECT *extobj; - BIO *out; - VALUE ret; - int nid; GetX509Ext(obj, ext); - extobj = X509_EXTENSION_get_object(ext); - if ((nid = OBJ_obj2nid(extobj)) != NID_undef) - ret = rb_str_new2(OBJ_nid2sn(nid)); - else{ - if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eX509ExtError, NULL); - i2a_ASN1_OBJECT(out, extobj); - ret = ossl_membio2str(out); - } - - return ret; + return ossl_asn1obj_to_string(X509_EXTENSION_get_object(ext)); } static VALUE @@ -380,15 +384,28 @@ ossl_x509ext_get_value(VALUE obj) GetX509Ext(obj, ext); if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eX509ExtError, NULL); + 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; } static VALUE +ossl_x509ext_get_value_der(VALUE obj) +{ + X509_EXTENSION *ext; + ASN1_OCTET_STRING *value; + + GetX509Ext(obj, ext); + if ((value = X509_EXTENSION_get_data(ext)) == NULL) + ossl_raise(eX509ExtError, NULL); + + return asn1str_to_str(value); +} + +static VALUE ossl_x509ext_get_critical(VALUE obj) { X509_EXTENSION *ext; @@ -407,11 +424,11 @@ ossl_x509ext_to_der(VALUE obj) GetX509Ext(obj, ext); if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0) - ossl_raise(eX509ExtError, NULL); + ossl_raise(eX509ExtError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if(i2d_X509_EXTENSION(ext, &p) < 0) - ossl_raise(eX509ExtError, NULL); + ossl_raise(eX509ExtError, NULL); ossl_str_adjust(str, p); return str; @@ -421,36 +438,38 @@ ossl_x509ext_to_der(VALUE obj) * INIT */ void -Init_ossl_x509ext() +Init_ossl_x509ext(void) { +#undef rb_intern eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError); - + cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject); - + rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc); rb_define_method(cX509ExtFactory, "initialize", ossl_x509extfactory_initialize, -1); - + rb_attr(cX509ExtFactory, rb_intern("issuer_certificate"), 1, 0, Qfalse); rb_attr(cX509ExtFactory, rb_intern("subject_certificate"), 1, 0, Qfalse); rb_attr(cX509ExtFactory, rb_intern("subject_request"), 1, 0, Qfalse); rb_attr(cX509ExtFactory, rb_intern("crl"), 1, 0, Qfalse); - rb_attr(cX509ExtFactory, rb_intern("config"), 1, 0, Qfalse); + rb_attr(cX509ExtFactory, rb_intern("config"), 1, 1, Qfalse); rb_define_method(cX509ExtFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1); rb_define_method(cX509ExtFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1); rb_define_method(cX509ExtFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1); rb_define_method(cX509ExtFactory, "crl=", ossl_x509extfactory_set_crl, 1); - rb_define_method(cX509ExtFactory, "config=", ossl_x509extfactory_set_config, 1); rb_define_method(cX509ExtFactory, "create_ext", ossl_x509extfactory_create_ext, -1); - + 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_method(cX509Ext, "initialize_copy", ossl_x509ext_initialize_copy, 1); 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); rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0); rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0); + rb_define_method(cX509Ext, "value_der", ossl_x509ext_get_value_der, 0); rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0); rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0); } diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index b4434d2a34..5b3c3f7261 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -1,62 +1,69 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapX509Name(klass, obj, name) do { \ - if (!name) { \ - ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ +#define NewX509Name(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509name_type, 0) +#define SetX509Name(obj, name) do { \ + if (!(name)) { \ + ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_NAME_free, name); \ + RTYPEDDATA_DATA(obj) = (name); \ } while (0) #define GetX509Name(obj, name) do { \ - Data_Get_Struct(obj, X509_NAME, name); \ - if (!name) { \ - ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ + TypedData_Get_Struct((obj), X509_NAME, &ossl_x509name_type, (name)); \ + if (!(name)) { \ + ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \ } \ } while (0) -#define SafeGetX509Name(obj, name) do { \ - OSSL_Check_Kind(obj, cX509Name); \ - GetX509Name(obj, name); \ -} while (0) #define OBJECT_TYPE_TEMPLATE \ - rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE")) + rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE")) #define DEFAULT_OBJECT_TYPE \ - rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE")) + rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE")) /* * Classes */ -VALUE cX509Name; -VALUE eX509NameError; +static VALUE cX509Name; +static VALUE eX509NameError; + +static void +ossl_x509name_free(void *ptr) +{ + X509_NAME_free(ptr); +} + +static const rb_data_type_t ossl_x509name_type = { + "OpenSSL/X509/NAME", + { + 0, ossl_x509name_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; /* * Public */ -VALUE +VALUE ossl_x509name_new(X509_NAME *name) { X509_NAME *new; VALUE obj; - if (!name) { - new = X509_NAME_new(); - } else { - new = X509_NAME_dup(name); - } - if (!new) { - ossl_raise(eX509NameError, NULL); - } - WrapX509Name(cX509Name, obj, new); - + obj = NewX509Name(cX509Name); + new = X509_NAME_dup(name); + if (!new) + ossl_raise(eX509NameError, "X509_NAME_dup"); + SetX509Name(obj, new); + return obj; } @@ -65,7 +72,7 @@ GetX509NamePtr(VALUE obj) { X509_NAME *name; - SafeGetX509Name(obj, name); + GetX509Name(obj, name); return name; } @@ -78,21 +85,22 @@ ossl_x509name_alloc(VALUE klass) { X509_NAME *name; VALUE obj; - + + obj = NewX509Name(klass); if (!(name = X509_NAME_new())) { - ossl_raise(eX509NameError, NULL); + ossl_raise(eX509NameError, NULL); } - WrapX509Name(klass, obj, name); + SetX509Name(obj, name); return obj; } -static int id_aref; +static ID id_aref; static VALUE ossl_x509name_add_entry(int, VALUE*, VALUE); -#define rb_aref(obj, key) rb_funcall(obj, id_aref, 1, key) +#define rb_aref(obj, key) rb_funcall((obj), id_aref, 1, (key)) static VALUE -ossl_x509name_init_i(VALUE i, VALUE args) +ossl_x509name_init_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args)) { VALUE self = rb_ary_entry(args, 0); VALUE template = rb_ary_entry(args, 1); @@ -111,10 +119,23 @@ ossl_x509name_init_i(VALUE i, VALUE args) /* * call-seq: - * X509::Name.new => name - * X509::Name.new(string) => name - * X509::Name.new(dn) => name - * X509::Name.new(dn, template) => name + * X509::Name.new => name + * X509::Name.new(der) => name + * X509::Name.new(distinguished_name) => name + * X509::Name.new(distinguished_name, template) => name + * + * Creates a new Name. + * + * A name may be created from a DER encoded string _der_, an Array + * representing a _distinguished_name_ or a _distinguished_name_ along with a + * _template_. + * + * name = OpenSSL::X509::Name.new [['CN', 'nobody'], ['DC', 'example']] + * + * name = OpenSSL::X509::Name.new name.to_der + * + * See add_entry for a description of the _distinguished_name_ Array's + * contents */ static VALUE ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) @@ -124,50 +145,99 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) GetX509Name(self, name); if (rb_scan_args(argc, argv, "02", &arg, &template) == 0) { - return self; + return self; } else { - VALUE tmp = rb_check_array_type(arg); - if (!NIL_P(tmp)) { - VALUE args; - if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE; - args = rb_ary_new3(2, self, template); - rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args); - } - else{ - unsigned char *p; - VALUE str = ossl_to_der_if_possible(arg); - StringValue(str); - p = RSTRING_PTR(str); - if(!d2i_X509_NAME((X509_NAME**)&DATA_PTR(self), &p, RSTRING_LEN(str))){ - ossl_raise(eX509NameError, NULL); - } - } + VALUE tmp = rb_check_array_type(arg); + if (!NIL_P(tmp)) { + VALUE args; + if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE; + args = rb_ary_new3(2, self, template); + rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args); + } + else{ + const unsigned char *p; + VALUE str = ossl_to_der_if_possible(arg); + X509_NAME *x; + StringValue(str); + p = (unsigned char *)RSTRING_PTR(str); + x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str)); + DATA_PTR(self) = name; + if(!x){ + ossl_raise(eX509NameError, NULL); + } + } } return self; } +/* :nodoc: */ +static VALUE +ossl_x509name_initialize_copy(VALUE self, VALUE other) +{ + X509_NAME *name, *name_other, *name_new; + + rb_check_frozen(self); + GetX509Name(self, name); + GetX509Name(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 + * name.add_entry(oid, value [, type], loc: -1, set: 0) => self + * + * Adds a new entry with the given _oid_ and _value_ to this name. The _oid_ + * is an object identifier defined in ASN.1. Some common OIDs are: + * + * C:: Country Name + * CN:: Common Name + * DC:: Domain Component + * O:: Organization Name + * OU:: Organizational Unit Name + * ST:: State or Province Name + * + * The optional keyword parameters _loc_ and _set_ specify where to insert the + * new attribute. Refer to the manpage of X509_NAME_add_entry(3) for details. + * _loc_ defaults to -1 and _set_ defaults to 0. This appends a single-valued + * RDN to the end. */ static VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self) { X509_NAME *name; - VALUE oid, value, type; - - rb_scan_args(argc, argv, "21", &oid, &value, &type); - StringValue(oid); + VALUE oid, value, type, opts, kwargs[2]; + static ID kwargs_ids[2]; + const char *oid_name; + int loc = -1, set = 0; + + if (!kwargs_ids[0]) { + kwargs_ids[0] = rb_intern_const("loc"); + kwargs_ids[1] = rb_intern_const("set"); + } + rb_scan_args(argc, argv, "21:", &oid, &value, &type, &opts); + rb_get_kwargs(opts, kwargs_ids, 0, 2, kwargs); + oid_name = StringValueCStr(oid); StringValue(value); if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid); + if (kwargs[0] != Qundef) + loc = NUM2INT(kwargs[0]); + if (kwargs[1] != Qundef) + set = NUM2INT(kwargs[1]); GetX509Name(self, name); - if (!X509_NAME_add_entry_by_txt(name, RSTRING_PTR(oid), NUM2INT(type), - RSTRING_PTR(value), RSTRING_LEN(value), -1, 0)) { - ossl_raise(eX509NameError, NULL); - } - + if (!X509_NAME_add_entry_by_txt(name, oid_name, NUM2INT(type), + (unsigned char *)RSTRING_PTR(value), + RSTRING_LENINT(value), loc, set)) + ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt"); return self; } @@ -176,78 +246,117 @@ ossl_x509name_to_s_old(VALUE self) { X509_NAME *name; char *buf; - VALUE str; GetX509Name(self, name); buf = X509_NAME_oneline(name, NULL, 0); - str = rb_str_new2(buf); - OPENSSL_free(buf); + if (!buf) + ossl_raise(eX509NameError, "X509_NAME_oneline"); + return ossl_buf2str(buf, rb_long2int(strlen(buf))); +} - return str; +static VALUE +x509name_print(VALUE self, unsigned long iflag) +{ + X509_NAME *name; + BIO *out; + int ret; + + GetX509Name(self, name); + out = BIO_new(BIO_s_mem()); + if (!out) + ossl_raise(eX509NameError, NULL); + ret = X509_NAME_print_ex(out, name, 0, iflag); + if (ret < 0 || (iflag == XN_FLAG_COMPAT && ret == 0)) { + BIO_free(out); + ossl_raise(eX509NameError, "X509_NAME_print_ex"); + } + return ossl_membio2str(out); } /* * call-seq: - * name.to_s => string - * name.to_s(integer) => string + * name.to_s -> string + * name.to_s(format) -> string + * + * Returns a String representation of the Distinguished Name. _format_ is + * one of: + * + * * OpenSSL::X509::Name::COMPAT + * * OpenSSL::X509::Name::RFC2253 + * * OpenSSL::X509::Name::ONELINE + * * OpenSSL::X509::Name::MULTILINE + * + * If _format_ is omitted, the largely broken and traditional OpenSSL format + * (<tt>X509_NAME_oneline()</tt> format) is chosen. + * + * <b>Use of this method is discouraged.</b> None of the formats other than + * OpenSSL::X509::Name::RFC2253 is standardized and may show an inconsistent + * behavior through \OpenSSL versions. + * + * It is recommended to use #to_utf8 instead, which is equivalent to calling + * <tt>name.to_s(OpenSSL::X509::Name::RFC2253).force_encoding("UTF-8")</tt>. */ static VALUE ossl_x509name_to_s(int argc, VALUE *argv, VALUE self) { - X509_NAME *name; - VALUE flag, str; - BIO *out; - unsigned long iflag; - - rb_scan_args(argc, argv, "01", &flag); - if (NIL_P(flag)) - return ossl_x509name_to_s_old(self); - else iflag = NUM2ULONG(flag); - if (!(out = BIO_new(BIO_s_mem()))) - ossl_raise(eX509NameError, NULL); - GetX509Name(self, name); - if (!X509_NAME_print_ex(out, name, 0, iflag)){ - BIO_free(out); - ossl_raise(eX509NameError, NULL); - } - str = ossl_membio2str(out); + rb_check_arity(argc, 0, 1); + /* name.to_s(nil) was allowed */ + if (!argc || NIL_P(argv[0])) + return ossl_x509name_to_s_old(self); + else + return x509name_print(self, NUM2ULONG(argv[0])); +} +/* + * call-seq: + * name.to_utf8 -> string + * + * Returns an UTF-8 representation of the distinguished name, as specified + * in {RFC 2253}[https://www.ietf.org/rfc/rfc2253.txt]. + */ +static VALUE +ossl_x509name_to_utf8(VALUE self) +{ + VALUE str = x509name_print(self, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB); + rb_enc_associate_index(str, rb_utf8_encindex()); return str; } +/* :nodoc: */ +static VALUE +ossl_x509name_inspect(VALUE self) +{ + return rb_enc_sprintf(rb_utf8_encoding(), "#<%"PRIsVALUE" %"PRIsVALUE">", + rb_obj_class(self), ossl_x509name_to_utf8(self)); +} + /* * call-seq: * name.to_a => [[name, data, type], ...] + * + * Returns an Array representation of the distinguished name suitable for + * passing to ::new */ -static VALUE +static VALUE ossl_x509name_to_a(VALUE self) { X509_NAME *name; - X509_NAME_ENTRY *entry; - int i,entries; - char long_name[512]; - const char *short_name; - VALUE ary, ret; - + int entries; + VALUE ret; + GetX509Name(self, name); entries = X509_NAME_entry_count(name); - if (entries < 0) { - OSSL_Debug("name entries < 0!"); - return rb_ary_new(); - } - ret = rb_ary_new2(entries); - for (i=0; i<entries; i++) { - if (!(entry = X509_NAME_get_entry(name, i))) { - ossl_raise(eX509NameError, NULL); - } - if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name), entry->object)) { - ossl_raise(eX509NameError, NULL); - } - short_name = OBJ_nid2sn(OBJ_ln2nid(long_name)); - ary = rb_ary_new3(3, rb_str_new2(short_name), - rb_str_new(entry->value->data, entry->value->length), - INT2FIX(entry->value->type)); - rb_ary_push(ret, ary); + ret = rb_ary_new_capa(entries); + for (int i = 0; i < entries; i++) { + const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i); + if (!entry) + ossl_raise(eX509NameError, "X509_NAME_get_entry"); + const ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(entry); + VALUE vname = ossl_asn1obj_to_string(obj); + const ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry); + VALUE vdata = asn1str_to_str(data); + VALUE type = INT2NUM(ASN1_STRING_type(data)); + rb_ary_push(ret, rb_ary_new_from_args(3, vname, vdata, type)); } return ret; } @@ -258,37 +367,56 @@ ossl_x509name_cmp0(VALUE self, VALUE other) X509_NAME *name1, *name2; GetX509Name(self, name1); - SafeGetX509Name(other, name2); + GetX509Name(other, name2); return X509_NAME_cmp(name1, name2); } +/* + * call-seq: + * name.cmp(other) -> -1 | 0 | 1 | nil + * name <=> other -> -1 | 0 | 1 | nil + * + * Compares this Name with _other_ and returns +0+ if they are the same and +-1+ + * or ++1+ if they are greater or less than each other respectively. + * Returns +nil+ if they are not comparable (i.e. different types). + */ static VALUE ossl_x509name_cmp(VALUE self, VALUE other) { int result; + if (!rb_obj_is_kind_of(other, cX509Name)) + return Qnil; + result = ossl_x509name_cmp0(self, other); if (result < 0) return INT2FIX(-1); - if (result > 1) return INT2FIX(1); + if (result > 0) return INT2FIX(1); return INT2FIX(0); } +/* + * call-seq: + * name.eql?(other) -> true | false + * + * Returns true if _name_ and _other_ refer to the same hash key. + */ 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) == 0 ? Qtrue : Qfalse; } /* * call-seq: * name.hash => integer + * + * The hash value returned is suitable for use as a certificate's filename in + * a CA path. */ static VALUE ossl_x509name_hash(VALUE self) @@ -305,7 +433,28 @@ ossl_x509name_hash(VALUE self) /* * call-seq: + * name.hash_old => integer + * + * Returns an MD5 based hash used in OpenSSL 0.9.X. + */ +static VALUE +ossl_x509name_hash_old(VALUE self) +{ + X509_NAME *name; + unsigned long hash; + + GetX509Name(self, name); + + hash = X509_NAME_hash_old(name); + + return ULONG2NUM(hash); +} + +/* + * call-seq: * name.to_der => string + * + * Converts the name to DER encoding */ static VALUE ossl_x509name_to_der(VALUE self) @@ -317,45 +466,67 @@ ossl_x509name_to_der(VALUE self) GetX509Name(self, name); if((len = i2d_X509_NAME(name, NULL)) <= 0) - ossl_raise(eX509NameError, NULL); + ossl_raise(eX509NameError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if(i2d_X509_NAME(name, &p) <= 0) - ossl_raise(eX509NameError, NULL); + ossl_raise(eX509NameError, NULL); ossl_str_adjust(str, p); return str; } /* - * INIT + * Document-class: OpenSSL::X509::Name + * + * An X.509 name represents a hostname, email address or other entity + * associated with a public key. + * + * You can create a Name by parsing a distinguished name String or by + * supplying the distinguished name as an Array. + * + * name = OpenSSL::X509::Name.parse_rfc2253 'DC=example,CN=nobody' + * + * name = OpenSSL::X509::Name.new [['CN', 'nobody'], ['DC', 'example']] */ -void -Init_ossl_x509name() + +void +Init_ossl_x509name(void) { +#undef rb_intern VALUE utf8str, ptrstr, ia5str, hash; id_aref = rb_intern("[]"); eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError); cX509Name = rb_define_class_under(mX509, "Name", rb_cObject); + rb_include_module(cX509Name, rb_mComparable); + rb_define_alloc_func(cX509Name, ossl_x509name_alloc); rb_define_method(cX509Name, "initialize", ossl_x509name_initialize, -1); + rb_define_method(cX509Name, "initialize_copy", ossl_x509name_initialize_copy, 1); 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_utf8", ossl_x509name_to_utf8, 0); + rb_define_method(cX509Name, "inspect", ossl_x509name_inspect, 0); rb_define_method(cX509Name, "to_a", ossl_x509name_to_a, 0); rb_define_method(cX509Name, "cmp", ossl_x509name_cmp, 1); rb_define_alias(cX509Name, "<=>", "cmp"); rb_define_method(cX509Name, "eql?", ossl_x509name_eql, 1); rb_define_method(cX509Name, "hash", ossl_x509name_hash, 0); + rb_define_method(cX509Name, "hash_old", ossl_x509name_hash_old, 0); rb_define_method(cX509Name, "to_der", ossl_x509name_to_der, 0); utf8str = INT2NUM(V_ASN1_UTF8STRING); ptrstr = INT2NUM(V_ASN1_PRINTABLESTRING); ia5str = INT2NUM(V_ASN1_IA5STRING); + + /* + * The default object type for name entries. + */ rb_define_const(cX509Name, "DEFAULT_OBJECT_TYPE", utf8str); hash = rb_hash_new(); - RHASH(hash)->ifnone = utf8str; + RHASH_SET_IFNONE(hash, utf8str); rb_hash_aset(hash, rb_str_new2("C"), ptrstr); rb_hash_aset(hash, rb_str_new2("countryName"), ptrstr); rb_hash_aset(hash, rb_str_new2("serialNumber"), ptrstr); @@ -363,10 +534,39 @@ Init_ossl_x509name() rb_hash_aset(hash, rb_str_new2("DC"), ia5str); rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str); rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str); + rb_obj_freeze(hash); + + /* + * The default object type template for name entries. + */ rb_define_const(cX509Name, "OBJECT_TYPE_TEMPLATE", hash); + /* + * A flag for #to_s. + * + * Breaks the name returned into multiple lines if longer than 80 + * characters. + */ rb_define_const(cX509Name, "COMPAT", ULONG2NUM(XN_FLAG_COMPAT)); + + /* + * A flag for #to_s. + * + * Returns an RFC2253 format name. + */ rb_define_const(cX509Name, "RFC2253", ULONG2NUM(XN_FLAG_RFC2253)); + + /* + * A flag for #to_s. + * + * Returns a more readable format than RFC2253. + */ rb_define_const(cX509Name, "ONELINE", ULONG2NUM(XN_FLAG_ONELINE)); + + /* + * A flag for #to_s. + * + * Returns a multiline format. + */ rb_define_const(cX509Name, "MULTILINE", ULONG2NUM(XN_FLAG_MULTILINE)); } diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c index 13a42dddaf..433cc461a9 100644 --- a/ext/openssl/ossl_x509req.c +++ b/ext/openssl/ossl_x509req.c @@ -1,134 +1,120 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapX509Req(klass, obj, req) do { \ - if (!req) { \ - ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ +#define NewX509Req(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509req_type, 0) +#define SetX509Req(obj, req) do { \ + if (!(req)) { \ + ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_REQ_free, req); \ + RTYPEDDATA_DATA(obj) = (req); \ } while (0) #define GetX509Req(obj, req) do { \ - Data_Get_Struct(obj, X509_REQ, req); \ - if (!req) { \ - ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509_REQ, &ossl_x509req_type, (req)); \ + if (!(req)) { \ + ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ } \ } while (0) -#define SafeGetX509Req(obj, req) do { \ - OSSL_Check_Kind(obj, cX509Req); \ - GetX509Req(obj, req); \ -} while (0) /* * Classes */ -VALUE cX509Req; -VALUE eX509ReqError; +static VALUE cX509Req; +static VALUE eX509ReqError; -/* - * Public functions - */ -VALUE -ossl_x509req_new(X509_REQ *req) +static void +ossl_x509req_free(void *ptr) { - X509_REQ *new; - VALUE obj; - - if (!req) { - new = X509_REQ_new(); - } else { - new = X509_REQ_dup(req); - } - if (!new) { - ossl_raise(eX509ReqError, NULL); - } - WrapX509Req(cX509Req, obj, new); - - return obj; + X509_REQ_free(ptr); } +static const rb_data_type_t ossl_x509req_type = { + "OpenSSL/X509/REQ", + { + 0, ossl_x509req_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* + * Public functions + */ X509_REQ * GetX509ReqPtr(VALUE obj) { X509_REQ *req; - SafeGetX509Req(obj, req); + GetX509Req(obj, req); return req; } -X509_REQ * -DupX509ReqPtr(VALUE obj) -{ - X509_REQ *req, *new; - - SafeGetX509Req(obj, req); - if (!(new = X509_REQ_dup(req))) { - ossl_raise(eX509ReqError, NULL); - } - - return new; -} - /* * Private functions */ -static VALUE +static VALUE ossl_x509req_alloc(VALUE klass) { X509_REQ *req; VALUE obj; + obj = NewX509Req(klass); if (!(req = X509_REQ_new())) { - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } - WrapX509Req(klass, obj, req); + SetX509Req(obj, req); return obj; } -static VALUE +static VALUE ossl_x509req_initialize(int argc, VALUE *argv, VALUE self) { BIO *in; - X509_REQ *req; + X509_REQ *req, *req_orig = RTYPEDDATA_DATA(self); VALUE arg; + rb_check_frozen(self); if (rb_scan_args(argc, argv, "01", &arg) == 0) { - return self; + return self; } arg = ossl_to_der_if_possible(arg); - in = ossl_obj2bio(arg); - req = PEM_read_bio_X509_REQ(in, (X509_REQ **)&DATA_PTR(self), NULL, NULL); + in = ossl_obj2bio(&arg); + req = d2i_X509_REQ_bio(in, NULL); if (!req) { - BIO_reset(in); - req = d2i_X509_REQ_bio(in, (X509_REQ **)&DATA_PTR(self)); + OSSL_BIO_reset(in); + req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); } BIO_free(in); - if (!req) ossl_raise(eX509ReqError, NULL); + if (!req) + ossl_raise(eX509ReqError, "PEM_read_bio_X509_REQ"); + + RTYPEDDATA_DATA(self) = req; + X509_REQ_free(req_orig); return self; } +/* :nodoc: */ static VALUE ossl_x509req_copy(VALUE self, VALUE other) { X509_REQ *a, *b, *req; - + rb_check_frozen(self); if (self == other) return self; GetX509Req(self, a); - SafeGetX509Req(other, b); + GetX509Req(other, b); if (!(req = X509_REQ_dup(b))) { - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } X509_REQ_free(a); DATA_PTR(self) = req; @@ -136,27 +122,22 @@ ossl_x509req_copy(VALUE self, VALUE other) return self; } -static VALUE +static VALUE 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()))) { - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } if (!PEM_write_bio_X509_REQ(out, req)) { - BIO_free(out); - ossl_raise(eX509ReqError, NULL); + 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 @@ -169,60 +150,55 @@ ossl_x509req_to_der(VALUE self) GetX509Req(self, req); if ((len = i2d_X509_REQ(req, NULL)) <= 0) - ossl_raise(eX509CertError, NULL); + ossl_raise(eX509ReqError, NULL); str = rb_str_new(0, len); - p = RSTRING_PTR(str); + p = (unsigned char *)RSTRING_PTR(str); if (i2d_X509_REQ(req, &p) <= 0) - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); ossl_str_adjust(str, p); return str; } -static VALUE +static VALUE 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()))) { - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } if (!X509_REQ_print(out, req)) { - BIO_free(out); - ossl_raise(eX509ReqError, NULL); + 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 /* * Makes X509 from X509_REQuest */ -static VALUE +static VALUE ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key) { X509_REQ *req; X509 *x509; - + GetX509Req(self, req); ... if (!(x509 = X509_REQ_to_X509(req, d, pkey))) { - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } return ossl_x509_new(x509); } #endif -static VALUE +static VALUE ossl_x509req_get_version(VALUE self) { X509_REQ *req; @@ -231,27 +207,27 @@ ossl_x509req_get_version(VALUE self) GetX509Req(self, req); version = X509_REQ_get_version(req); - return LONG2FIX(version); + return LONG2NUM(version); } -static VALUE +static VALUE ossl_x509req_set_version(VALUE self, VALUE version) { X509_REQ *req; long ver; - if ((ver = FIX2LONG(version)) < 0) { - ossl_raise(eX509ReqError, "version must be >= 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; } -static VALUE +static VALUE ossl_x509req_get_subject(VALUE self) { X509_REQ *req; @@ -259,50 +235,49 @@ ossl_x509req_get_subject(VALUE self) GetX509Req(self, req); if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */ - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } return ossl_x509name_new(name); } -static VALUE +static VALUE ossl_x509req_set_subject(VALUE self, VALUE subject) { X509_REQ *req; - + GetX509Req(self, req); /* DUPs name */ if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) { - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } return subject; } -static VALUE +/* + * call-seq: + * req.signature_algorithm -> string + * + * Returns the signature algorithm used to sign this request. + * + * Returns the long name of the signature algorithm, or the dotted decimal + * notation if \OpenSSL does not define a long name for it. + */ +static VALUE ossl_x509req_get_signature_algorithm(VALUE self) { X509_REQ *req; - BIO *out; - BUF_MEM *buf; - VALUE str; + const X509_ALGOR *alg; + const ASN1_OBJECT *obj; GetX509Req(self, req); - - if (!(out = BIO_new(BIO_s_mem()))) { - ossl_raise(eX509ReqError, NULL); - } - if (!i2a_ASN1_OBJECT(out, req->sig_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; + X509_REQ_get0_signature(req, NULL, &alg); + X509_ALGOR_get0(&obj, NULL, NULL, alg); + return ossl_asn1obj_to_string_long_name(obj); } -static VALUE +static VALUE ossl_x509req_get_public_key(VALUE self) { X509_REQ *req; @@ -310,40 +285,40 @@ ossl_x509req_get_public_key(VALUE self) GetX509Req(self, req); if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */ - ossl_raise(eX509ReqError, NULL); + ossl_raise(eX509ReqError, NULL); } - return ossl_pkey_new(pkey); /* NO DUP - OK */ + return ossl_pkey_wrap(pkey); } -static VALUE +static VALUE ossl_x509req_set_public_key(VALUE self, VALUE key) { X509_REQ *req; EVP_PKEY *pkey; GetX509Req(self, req); - pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ - if (!X509_REQ_set_pubkey(req, pkey)) { - ossl_raise(eX509ReqError, NULL); - } - + pkey = GetPKeyPtr(key); + ossl_pkey_check_public_key(pkey); + if (!X509_REQ_set_pubkey(req, pkey)) + ossl_raise(eX509ReqError, "X509_REQ_set_pubkey"); return key; } -static VALUE +static VALUE ossl_x509req_sign(VALUE self, VALUE key, VALUE digest) { X509_REQ *req; EVP_PKEY *pkey; const EVP_MD *md; + VALUE md_holder; GetX509Req(self, req); pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); - if (!X509_REQ_sign(req, pkey, md)) { - ossl_raise(eX509ReqError, NULL); - } + /* NULL needed for some key types, e.g. Ed25519 */ + md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder); + if (!X509_REQ_sign(req, pkey, md)) + ossl_raise(eX509ReqError, "X509_REQ_sign"); return self; } @@ -351,82 +326,83 @@ ossl_x509req_sign(VALUE self, VALUE key, VALUE digest) /* * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' */ -static VALUE +static VALUE 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); + pkey = GetPKeyPtr(key); + ossl_pkey_check_public_key(pkey); + switch (X509_REQ_verify(req, pkey)) { + case 1: + return Qtrue; + case 0: + ossl_clear_error(); + return Qfalse; + default: + ossl_raise(eX509ReqError, NULL); } - if (i > 0) { - return Qtrue; - } - - return Qfalse; } -static VALUE +static VALUE ossl_x509req_get_attributes(VALUE self) { X509_REQ *req; int count, i; X509_ATTRIBUTE *attr; VALUE ary; - + GetX509Req(self, req); count = X509_REQ_get_attr_count(req); if (count < 0) { - OSSL_Debug("count < 0???"); - return rb_ary_new(); + OSSL_Debug("count < 0???"); + return rb_ary_new(); } ary = rb_ary_new2(count); for (i=0; i<count; i++) { - attr = X509_REQ_get_attr(req, i); - rb_ary_push(ary, ossl_x509attr_new(attr)); + attr = X509_REQ_get_attr(req, i); + rb_ary_push(ary, ossl_x509attr_new(attr)); } return ary; } -static VALUE +static VALUE ossl_x509req_set_attributes(VALUE self, VALUE ary) { X509_REQ *req; X509_ATTRIBUTE *attr; - int i; + long i; VALUE item; Check_Type(ary, T_ARRAY); for (i=0;i<RARRAY_LEN(ary); i++) { - OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Attr); + 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; + for (i = X509_REQ_get_attr_count(req); i > 0; i--) + X509_ATTRIBUTE_free(X509_REQ_delete_attr(req, 0)); for (i=0;i<RARRAY_LEN(ary); i++) { - item = RARRAY_PTR(ary)[i]; - attr = DupX509AttrPtr(item); - if (!X509_REQ_add1_attr(req, attr)) { - ossl_raise(eX509ReqError, NULL); - } + item = RARRAY_AREF(ary, i); + attr = GetX509AttrPtr(item); + if (!X509_REQ_add1_attr(req, attr)) { + ossl_raise(eX509ReqError, "X509_REQ_add1_attr"); + } } return ary; } -static VALUE +static VALUE ossl_x509req_add_attribute(VALUE self, VALUE attr) { X509_REQ *req; GetX509Req(self, req); - if (!X509_REQ_add1_attr(req, DupX509AttrPtr(attr))) { - ossl_raise(eX509ReqError, NULL); + if (!X509_REQ_add1_attr(req, GetX509AttrPtr(attr))) { + ossl_raise(eX509ReqError, NULL); } return attr; @@ -435,17 +411,17 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr) /* * X509_REQUEST init */ -void -Init_ossl_x509req() +void +Init_ossl_x509req(void) { eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError); - + cX509Req = rb_define_class_under(mX509, "Request", rb_cObject); - + rb_define_alloc_func(cX509Req, ossl_x509req_alloc); rb_define_method(cX509Req, "initialize", ossl_x509req_initialize, -1); - rb_define_copy_func(cX509Req, ossl_x509req_copy); - + rb_define_method(cX509Req, "initialize_copy", ossl_x509req_copy, 1); + rb_define_method(cX509Req, "to_pem", ossl_x509req_to_pem, 0); rb_define_method(cX509Req, "to_der", ossl_x509req_to_der, 0); rb_define_alias(cX509Req, "to_s", "to_pem"); @@ -463,4 +439,3 @@ Init_ossl_x509req() rb_define_method(cX509Req, "attributes=", ossl_x509req_set_attributes, 1); rb_define_method(cX509Req, "add_attribute", ossl_x509req_add_attribute, 1); } - diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c index d0f816bad4..b88c390c72 100644 --- a/ext/openssl/ossl_x509revoked.c +++ b/ext/openssl/ossl_x509revoked.c @@ -1,56 +1,63 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#define WrapX509Rev(klass, obj, rev) do { \ - if (!rev) { \ - ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ +#define NewX509Rev(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509rev_type, 0) +#define SetX509Rev(obj, rev) do { \ + if (!(rev)) { \ + ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_REVOKED_free, rev); \ + RTYPEDDATA_DATA(obj) = (rev); \ } while (0) #define GetX509Rev(obj, rev) do { \ - Data_Get_Struct(obj, X509_REVOKED, rev); \ - if (!rev) { \ - ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509_REVOKED, &ossl_x509rev_type, (rev)); \ + if (!(rev)) { \ + ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \ } \ } while (0) -#define SafeGetX509Rev(obj, rev) do { \ - OSSL_Check_Kind(obj, cX509Rev); \ - GetX509Rev(obj, rev); \ -} while (0) /* * Classes */ VALUE cX509Rev; -VALUE eX509RevError; +static VALUE eX509RevError; + +static void +ossl_x509rev_free(void *ptr) +{ + X509_REVOKED_free(ptr); +} + +static const rb_data_type_t ossl_x509rev_type = { + "OpenSSL/X509/REV", + { + 0, ossl_x509rev_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; /* * PUBLIC */ -VALUE +VALUE ossl_x509revoked_new(X509_REVOKED *rev) { X509_REVOKED *new; VALUE obj; - if (!rev) { - new = X509_REVOKED_new(); - } else { - new = X509_REVOKED_dup(rev); - } - if (!new) { - ossl_raise(eX509RevError, NULL); - } - WrapX509Rev(cX509Rev, obj, new); + obj = NewX509Rev(cX509Rev); + new = X509_REVOKED_dup(rev); + if (!new) + ossl_raise(eX509RevError, "X509_REVOKED_dup"); + SetX509Rev(obj, new); return obj; } @@ -60,9 +67,9 @@ DupX509RevokedPtr(VALUE obj) { X509_REVOKED *rev, *new; - SafeGetX509Rev(obj, rev); + GetX509Rev(obj, rev); if (!(new = X509_REVOKED_dup(rev))) { - ossl_raise(eX509RevError, NULL); + ossl_raise(eX509RevError, NULL); } return new; @@ -71,76 +78,109 @@ DupX509RevokedPtr(VALUE obj) /* * PRIVATE */ -static VALUE +static VALUE ossl_x509revoked_alloc(VALUE klass) { X509_REVOKED *rev; VALUE obj; + obj = NewX509Rev(klass); if (!(rev = X509_REVOKED_new())) { - ossl_raise(eX509RevError, NULL); + ossl_raise(eX509RevError, NULL); } - WrapX509Rev(klass, obj, rev); + SetX509Rev(obj, rev); return obj; } -static VALUE +static VALUE ossl_x509revoked_initialize(int argc, VALUE *argv, VALUE self) { /* EMPTY */ return self; } -static VALUE +/* :nodoc: */ +static VALUE +ossl_x509revoked_initialize_copy(VALUE self, VALUE other) +{ + X509_REVOKED *rev, *rev_other, *rev_new; + + rb_check_frozen(self); + GetX509Rev(self, rev); + GetX509Rev(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) { X509_REVOKED *rev; GetX509Rev(self, rev); - return asn1integer_to_num(rev->serialNumber); + return asn1integer_to_num(X509_REVOKED_get0_serialNumber(rev)); } -static VALUE +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; } -static VALUE +static VALUE ossl_x509revoked_get_time(VALUE self) { X509_REVOKED *rev; - + const ASN1_TIME *time; + GetX509Rev(self, rev); + time = X509_REVOKED_get0_revocationDate(rev); + if (!time) + return Qnil; - return asn1time_to_time(rev->revocationDate); + return asn1time_to_time(time); } -static VALUE +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; } /* * Gets X509v3 extensions as array of X509Ext objects */ -static VALUE +static VALUE ossl_x509revoked_get_extensions(VALUE self) { X509_REVOKED *rev; @@ -150,14 +190,10 @@ ossl_x509revoked_get_extensions(VALUE self) GetX509Rev(self, rev); count = X509_REVOKED_get_ext_count(rev); - if (count < 0) { - OSSL_Debug("count < 0???"); - return rb_ary_new(); - } - ary = rb_ary_new2(count); + ary = rb_ary_new_capa(count); for (i=0; i<count; i++) { - ext = X509_REVOKED_get_ext(rev, i); - rb_ary_push(ary, ossl_x509ext_new(ext)); + ext = X509_REVOKED_get_ext(rev, i); + rb_ary_push(ary, ossl_x509ext_new(ext)); } return ary; @@ -166,27 +202,27 @@ ossl_x509revoked_get_extensions(VALUE self) /* * Sets X509_EXTENSIONs */ -static VALUE +static VALUE ossl_x509revoked_set_extensions(VALUE self, VALUE ary) { X509_REVOKED *rev; X509_EXTENSION *ext; - int i; + long i; VALUE item; Check_Type(ary, T_ARRAY); for (i=0; i<RARRAY_LEN(ary); i++) { - OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext); + OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext); } GetX509Rev(self, rev); - sk_X509_EXTENSION_pop_free(rev->extensions, X509_EXTENSION_free); - rev->extensions = NULL; + for (i = X509_REVOKED_get_ext_count(rev); i > 0; i--) + X509_EXTENSION_free(X509_REVOKED_delete_ext(rev, 0)); for (i=0; i<RARRAY_LEN(ary); i++) { - item = RARRAY_PTR(ary)[i]; - ext = DupX509ExtPtr(item); - if(!X509_REVOKED_add_ext(rev, ext, -1)) { - ossl_raise(eX509RevError, NULL); - } + item = RARRAY_AREF(ary, i); + ext = GetX509ExtPtr(item); + if(!X509_REVOKED_add_ext(rev, ext, -1)) { + ossl_raise(eX509RevError, "X509_REVOKED_add_ext"); + } } return ary; @@ -196,28 +232,49 @@ static VALUE ossl_x509revoked_add_extension(VALUE self, VALUE ext) { X509_REVOKED *rev; - + GetX509Rev(self, rev); - if(!X509_REVOKED_add_ext(rev, DupX509ExtPtr(ext), -1)) { - ossl_raise(eX509RevError, NULL); + if (!X509_REVOKED_add_ext(rev, GetX509ExtPtr(ext), -1)) { + ossl_raise(eX509RevError, NULL); } return ext; } +static VALUE +ossl_x509revoked_to_der(VALUE self) +{ + X509_REVOKED *rev; + VALUE str; + int len; + unsigned char *p; + + GetX509Rev(self, rev); + len = i2d_X509_REVOKED(rev, NULL); + if (len <= 0) + ossl_raise(eX509RevError, "i2d_X509_REVOKED"); + str = rb_str_new(NULL, len); + p = (unsigned char *)RSTRING_PTR(str); + if (i2d_X509_REVOKED(rev, &p) <= 0) + ossl_raise(eX509RevError, "i2d_X509_REVOKED"); + ossl_str_adjust(str, p); + return str; +} + /* * INIT */ void -Init_ossl_x509revoked() +Init_ossl_x509revoked(void) { 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_method(cX509Rev, "initialize_copy", ossl_x509revoked_initialize_copy, 1); + rb_define_method(cX509Rev, "serial", ossl_x509revoked_get_serial, 0); rb_define_method(cX509Rev, "serial=", ossl_x509revoked_set_serial, 1); rb_define_method(cX509Rev, "time", ossl_x509revoked_get_time, 0); @@ -225,5 +282,5 @@ Init_ossl_x509revoked() rb_define_method(cX509Rev, "extensions", ossl_x509revoked_get_extensions, 0); rb_define_method(cX509Rev, "extensions=", ossl_x509revoked_set_extensions, 1); rb_define_method(cX509Rev, "add_extension", ossl_x509revoked_add_extension, 1); + rb_define_method(cX509Rev, "to_der", ossl_x509revoked_to_der, 0); } - diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 24a6625ee4..be1458cec5 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -1,104 +1,182 @@ /* - * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> * All rights reserved. */ /* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) + * This program is licensed under the same licence as Ruby. + * (See the file 'COPYING'.) */ #include "ossl.h" -#include <rubysig.h> -#define WrapX509Store(klass, obj, st) do { \ - if (!st) { \ - ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ +#define NewX509Store(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509store_type, 0) +#define SetX509Store(obj, st) do { \ + if (!(st)) { \ + ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, X509_STORE_free, st); \ + RTYPEDDATA_DATA(obj) = (st); \ } while (0) #define GetX509Store(obj, st) do { \ - Data_Get_Struct(obj, X509_STORE, st); \ - if (!st) { \ - ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ + TypedData_Get_Struct((obj), X509_STORE, &ossl_x509store_type, (st)); \ + if (!(st)) { \ + ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \ } \ } while (0) -#define SafeGetX509Store(obj, st) do { \ - OSSL_Check_Kind(obj, cX509Store); \ - GetX509Store(obj, st); \ -} while (0) -#define WrapX509StCtx(klass, obj, ctx) do { \ - if (!ctx) { \ - ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \ +#define NewX509StCtx(klass) \ + TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, 0) +#define SetX509StCtx(obj, ctx) do { \ + if (!(ctx)) { \ + ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \ } \ - obj = Data_Wrap_Struct(klass, 0, ossl_x509stctx_free, ctx); \ + RTYPEDDATA_DATA(obj) = (ctx); \ } while (0) #define GetX509StCtx(obj, ctx) do { \ - Data_Get_Struct(obj, X509_STORE_CTX, ctx); \ - if (!ctx) { \ - ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \ + TypedData_Get_Struct((obj), X509_STORE_CTX, &ossl_x509stctx_type, (ctx)); \ + if (!(ctx)) { \ + ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \ } \ } while (0) -#define SafeGetX509StCtx(obj, storep) do { \ - OSSL_Check_Kind(obj, cX509StoreContext); \ - GetX509Store(obj, ctx); \ -} while (0) /* - * Classes + * Verify callback stuff */ -VALUE cX509Store; -VALUE cX509StoreContext; -VALUE eX509StoreError; +static int stctx_ex_verify_cb_idx, store_ex_verify_cb_idx; +static VALUE ossl_x509stctx_new(X509_STORE_CTX *); -/* - * Public functions - */ -VALUE -ossl_x509store_new(X509_STORE *store) -{ - VALUE obj; +struct ossl_verify_cb_args { + VALUE proc; + VALUE preverify_ok; + VALUE store_ctx; +}; - WrapX509Store(cX509Store, obj, store); +static VALUE +ossl_x509stctx_new_i(VALUE arg) +{ + return ossl_x509stctx_new((X509_STORE_CTX *)arg); +} - return obj; +static VALUE +call_verify_cb_proc(VALUE arg) +{ + struct ossl_verify_cb_args *args = (struct ossl_verify_cb_args *)arg; + return rb_funcall(args->proc, rb_intern("call"), 2, + args->preverify_ok, args->store_ctx); } -X509_STORE * -GetX509StorePtr(VALUE obj) +int +ossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx) { - X509_STORE *store; + VALUE rctx, ret; + struct ossl_verify_cb_args args; + int state; - SafeGetX509Store(obj, store); + if (NIL_P(proc)) + return ok; - return store; + ret = Qfalse; + rctx = rb_protect(ossl_x509stctx_new_i, (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(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 + */ +static VALUE cX509Store; +static VALUE cX509StoreContext; +static VALUE eX509StoreError; + +static void +ossl_x509store_mark(void *ptr) +{ + X509_STORE *store = ptr; + // Note: this reference is stored as @verify_callback so we don't need to mark it. + // However we do need to ensure GC compaction won't move it, hence why + // we call rb_gc_mark here. + rb_gc_mark((VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx)); } +static void +ossl_x509store_free(void *ptr) +{ + X509_STORE_free(ptr); +} + +static const rb_data_type_t ossl_x509store_type = { + "OpenSSL/X509/STORE", + { + ossl_x509store_mark, ossl_x509store_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* + * Public functions + */ X509_STORE * -DupX509StorePtr(VALUE obj) -{ +GetX509StorePtr(VALUE obj) +{ X509_STORE *store; - SafeGetX509Store(obj, store); - CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); - + GetX509Store(obj, store); + return store; } /* * Private functions */ -static VALUE +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) { X509_STORE *store; VALUE obj; - if((store = X509_STORE_new()) == NULL){ - ossl_raise(eX509StoreError, NULL); - } - WrapX509Store(klass, obj, store); + obj = NewX509Store(klass); + if ((store = X509_STORE_new()) == NULL) + ossl_raise(eX509StoreError, "X509_STORE_new"); + SetX509Store(obj, store); return obj; } @@ -112,8 +190,9 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb) X509_STORE *store; GetX509Store(self, store); - X509_STORE_set_ex_data(store, ossl_verify_cb_idx, (void*)cb); rb_iv_set(self, "@verify_callback", cb); + X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb); + RB_OBJ_WRITTEN(self, Qundef, cb); return cb; } @@ -123,142 +202,224 @@ 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) { X509_STORE *store; -/* BUG: This method takes any number of arguments but appears to ignore them. */ GetX509Store(self, store); - X509_STORE_set_verify_cb_func(store, ossl_verify_cb); + if (argc != 0) + rb_warn("OpenSSL::X509::Store.new does not take any arguments"); + X509_STORE_set_verify_cb(store, x509store_verify_cb); ossl_x509store_set_vfy_cb(self, Qnil); -#if (OPENSSL_VERSION_NUMBER < 0x00907000L) - rb_iv_set(self, "@flags", INT2NUM(0)); - rb_iv_set(self, "@purpose", INT2NUM(0)); - rb_iv_set(self, "@trust", INT2NUM(0)); -#endif - /* last verification status */ rb_iv_set(self, "@error", Qnil); rb_iv_set(self, "@error_string", Qnil); rb_iv_set(self, "@chain", Qnil); - rb_iv_set(self, "@time", Qnil); return self; } +/* + * call-seq: + * store.flags = flags + * + * Sets the default flags used by certificate chain verification performed with + * the Store. + * + * _flags_ consists of zero or more of the constants defined in OpenSSL::X509 + * with name V_FLAG_* or'ed together. + * + * OpenSSL::X509::StoreContext#flags= can be used to change the flags for a + * single verification operation. + * + * See also the man page X509_VERIFY_PARAM_set_flags(3). + */ 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 default verification purpose. If specified, + * the verifications on the store will check every 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 + * + * OpenSSL::X509::StoreContext#purpose= can be used to change the value for a + * single verification operation. + * + * See also the man page X509_VERIFY_PARAM_set_purpose(3). + */ static VALUE ossl_x509store_set_purpose(VALUE self, VALUE purpose) { -#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) X509_STORE *store; - long p = NUM2LONG(purpose); - + 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 + * + * Sets the default trust settings used by the certificate verification with + * the store. + * + * OpenSSL::X509::StoreContext#trust= can be used to change the value for a + * single verification operation. + * + * See also the man page X509_VERIFY_PARAM_set_trust(3). + */ static VALUE ossl_x509store_set_trust(VALUE self, VALUE trust) { -#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) X509_STORE *store; - long t = NUM2LONG(trust); + int t = NUM2INT(trust); GetX509Store(self, store); X509_STORE_set_trust(store, t); -#else - rb_iv_set(self, "@trust", trust); -#endif return trust; } -static VALUE +/* + * call-seq: + * store.time = time + * + * Sets the time to be used in the certificate verifications with the store. + * By default, if not specified, the current system time is used. + * + * OpenSSL::X509::StoreContext#time= can be used to change the value for a + * single verification operation. + * + * See also the man page X509_VERIFY_PARAM_set_time(3). + */ +static VALUE ossl_x509store_set_time(VALUE self, VALUE time) { - rb_iv_set(self, "@time", time); + X509_STORE *store; + X509_VERIFY_PARAM *param; + + GetX509Store(self, store); + param = X509_STORE_get0_param(store); + X509_VERIFY_PARAM_set_time(param, NUM2LONG(rb_Integer(time))); return time; } -static VALUE +/* + * call-seq: + * store.add_file(file) -> self + * + * Adds the certificates in _file_ to the certificate store. _file_ is the path + * to the file, and the file contains one or more certificates in PEM format + * concatenated together. + * + * See also the man page X509_LOOKUP_file(3). + */ +static VALUE ossl_x509store_add_file(VALUE self, VALUE file) { X509_STORE *store; X509_LOOKUP *lookup; - char *path = NULL; + const char *path; - if(file != Qnil){ - Check_SafeStr(file); - path = RSTRING_PTR(file); - } GetX509Store(self, store); + path = StringValueCStr(file); lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); - if(lookup == NULL) ossl_raise(eX509StoreError, NULL); - if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){ - ossl_raise(eX509StoreError, NULL); - } + if (!lookup) + ossl_raise(eX509StoreError, "X509_STORE_add_lookup"); + if (X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1) + ossl_raise(eX509StoreError, "X509_LOOKUP_load_file"); return self; } -static VALUE +/* + * call-seq: + * store.add_path(path) -> self + * + * Adds _path_ as the hash dir to be looked up by the store. + * + * See also the man page X509_LOOKUP_hash_dir(3). + */ +static VALUE ossl_x509store_add_path(VALUE self, VALUE dir) { X509_STORE *store; X509_LOOKUP *lookup; - char *path = NULL; + const char *path; - if(dir != Qnil){ - Check_SafeStr(dir); - path = RSTRING_PTR(dir); - } GetX509Store(self, store); + path = StringValueCStr(dir); lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); - if(lookup == NULL) ossl_raise(eX509StoreError, NULL); - if(X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1){ - ossl_raise(eX509StoreError, NULL); - } + if (!lookup) + ossl_raise(eX509StoreError, "X509_STORE_add_lookup"); + if (X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1) + ossl_raise(eX509StoreError, "X509_LOOKUP_add_dir"); return self; } +/* + * call-seq: + * store.set_default_paths + * + * 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: + * + * * OpenSSL::X509::DEFAULT_CERT_FILE + * * OpenSSL::X509::DEFAULT_CERT_DIR + * + * See also the man page X509_STORE_set_default_paths(3). + */ static VALUE ossl_x509store_set_default_paths(VALUE self) { X509_STORE *store; GetX509Store(self, store); - if (X509_STORE_set_default_paths(store) != 1){ - ossl_raise(eX509StoreError, NULL); - } + if (X509_STORE_set_default_paths(store) != 1) + ossl_raise(eX509StoreError, "X509_STORE_set_default_paths"); return Qnil; } +/* + * call-seq: + * store.add_cert(cert) -> self + * + * Adds the OpenSSL::X509::Certificate _cert_ to the certificate store. + * + * See also the man page X509_STORE_add_cert(3). + */ static VALUE ossl_x509store_add_cert(VALUE self, VALUE arg) { @@ -267,13 +428,20 @@ ossl_x509store_add_cert(VALUE self, VALUE arg) cert = GetX509CertPtr(arg); /* NO NEED TO DUP */ GetX509Store(self, store); - if (X509_STORE_add_cert(store, cert) != 1){ - ossl_raise(eX509StoreError, NULL); - } + if (X509_STORE_add_cert(store, cert) != 1) + ossl_raise(eX509StoreError, "X509_STORE_add_cert"); return self; } +/* + * call-seq: + * store.add_crl(crl) -> self + * + * Adds the OpenSSL::X509::CRL _crl_ to the store. + * + * See also the man page X509_STORE_add_crl(3). + */ static VALUE ossl_x509store_add_crl(VALUE self, VALUE arg) { @@ -282,9 +450,8 @@ ossl_x509store_add_crl(VALUE self, VALUE arg) crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */ GetX509Store(self, store); - if (X509_STORE_add_crl(store, crl) != 1){ - ossl_raise(eX509StoreError, NULL); - } + if (X509_STORE_add_crl(store, crl) != 1) + ossl_raise(eX509StoreError, "X509_STORE_add_crl"); return self; } @@ -293,7 +460,22 @@ static VALUE ossl_x509stctx_get_err(VALUE); static VALUE ossl_x509stctx_get_err_string(VALUE); static VALUE ossl_x509stctx_get_chain(VALUE); -static 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 resulting complete certificate chain can be + * retrieved by #chain. + */ +static VALUE ossl_x509store_verify(int argc, VALUE *argv, VALUE self) { VALUE cert, chain; @@ -302,7 +484,7 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &cert, &chain); ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain); proc = rb_block_given_p() ? rb_block_proc() : - rb_iv_get(self, "@verify_callback"); + rb_iv_get(self, "@verify_callback"); rb_iv_set(ctx, "@verify_callback", proc); result = rb_funcall(ctx, rb_intern("verify"), 0); @@ -314,52 +496,58 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self) } /* - * Public Functions + * Private functions */ -static void ossl_x509stctx_free(X509_STORE_CTX*); - -VALUE -ossl_x509stctx_new(X509_STORE_CTX *ctx) -{ - VALUE obj; - - WrapX509StCtx(cX509StoreContext, obj, ctx); - - return obj; -} - -VALUE -ossl_x509stctx_clear_ptr(VALUE obj) +static void +ossl_x509stctx_mark(void *ptr) { - OSSL_Check_Kind(obj, cX509StoreContext); - RDATA(obj)->data = NULL; - - return obj; + X509_STORE_CTX *ctx = ptr; + // Note: this reference is stored as @verify_callback so we don't need to mark it. + // However we do need to ensure GC compaction won't move it, hence why + // we call rb_gc_mark here. + rb_gc_mark((VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx)); } -/* - * Private functions - */ static void -ossl_x509stctx_free(X509_STORE_CTX *ctx) +ossl_x509stctx_free(void *ptr) { - if(ctx->untrusted) - sk_X509_pop_free(ctx->untrusted, X509_free); - if(ctx->cert) - X509_free(ctx->cert); + X509_STORE_CTX *ctx = ptr; + 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); } -static VALUE +static const rb_data_type_t ossl_x509stctx_type = { + "OpenSSL/X509/STORE_CTX", + { + ossl_x509stctx_mark, ossl_x509stctx_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE ossl_x509stctx_alloc(VALUE klass) { X509_STORE_CTX *ctx; VALUE obj; - if((ctx = X509_STORE_CTX_new()) == NULL){ - ossl_raise(eX509StoreError, NULL); - } - WrapX509StCtx(klass, obj, ctx); + obj = NewX509StCtx(klass); + if ((ctx = X509_STORE_CTX_new()) == NULL) + ossl_raise(eX509StoreError, "X509_STORE_CTX_new"); + SetX509StCtx(obj, ctx); + + return obj; +} + +static VALUE +ossl_x509stctx_new(X509_STORE_CTX *ctx) +{ + VALUE obj; + + obj = NewX509StCtx(cX509StoreContext); + SetX509StCtx(obj, ctx); return obj; } @@ -367,103 +555,146 @@ ossl_x509stctx_alloc(VALUE klass) 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, untrusted = nil) + * + * Sets up a StoreContext for a verification of the X.509 certificate _cert_. + */ static VALUE ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) { - VALUE store, cert, chain, t; + VALUE store, cert, chain; X509_STORE_CTX *ctx; X509_STORE *x509st; X509 *x509 = NULL; STACK_OF(X509) *x509s = NULL; + int state; rb_scan_args(argc, argv, "12", &store, &cert, &chain); GetX509StCtx(self, ctx); - 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){ + GetX509Store(store, x509st); + if (!NIL_P(cert)) + x509 = DupX509CertPtr(cert); /* NEED TO DUP */ + if (!NIL_P(chain)) { + x509s = ossl_protect_x509_ary2sk(chain, &state); + if (state) { + X509_free(x509); + rb_jump_tag(state); + } + } + if (X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ + X509_free(x509); sk_X509_pop_free(x509s, X509_free); - ossl_raise(eX509StoreError, NULL); + ossl_raise(eX509StoreError, "X509_STORE_CTX_init"); } -#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")); rb_iv_set(self, "@cert", cert); return self; } +/* + * call-seq: + * stctx.verify -> true | false + * + * Performs the certificate verification using the parameters set to _stctx_. + * + * See also the man page X509_verify_cert(3). + */ static VALUE ossl_x509stctx_verify(VALUE self) { X509_STORE_CTX *ctx; - int result; GetX509StCtx(self, ctx); - X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx, - (void*)rb_iv_get(self, "@verify_callback")); - result = X509_verify_cert(ctx); - - return result ? Qtrue : Qfalse; + VALUE cb = rb_iv_get(self, "@verify_callback"); + X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb); + RB_OBJ_WRITTEN(self, Qundef, cb); + + switch (X509_verify_cert(ctx)) { + case 1: + return Qtrue; + case 0: + ossl_clear_error(); + return Qfalse; + default: + ossl_raise(eX509StoreError, "X509_verify_cert"); + } } +/* + * call-seq: + * stctx.chain -> nil | Array of X509::Certificate + * + * Returns the verified chain. + * + * See also the man page X509_STORE_CTX_set0_verified_chain(3). + */ static VALUE ossl_x509stctx_get_chain(VALUE self) { X509_STORE_CTX *ctx; - STACK_OF(X509) *chain; - X509 *x509; - int i, num; - VALUE ary; + const STACK_OF(X509) *chain; GetX509StCtx(self, ctx); - if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){ - return Qnil; - } - if((num = sk_X509_num(chain)) < 0){ - OSSL_Debug("certs in chain < 0???"); - return rb_ary_new(); - } - ary = rb_ary_new2(num); - for(i = 0; i < num; i++) { - x509 = sk_X509_value(chain, i); - rb_ary_push(ary, ossl_x509_new(x509)); - } - - return ary; + chain = X509_STORE_CTX_get0_chain(ctx); + if (!chain) + return Qnil; /* Could be an empty array instead? */ + return ossl_x509_sk2ary(chain); } -static VALUE +/* + * call-seq: + * stctx.error -> Integer + * + * Returns the error code of _stctx_. This is typically called after #verify + * is done, or from the verification callback set to + * OpenSSL::X509::Store#verify_callback=. + * + * See also the man page X509_STORE_CTX_get_error(3). + */ +static VALUE ossl_x509stctx_get_err(VALUE self) { X509_STORE_CTX *ctx; 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 + * + * Sets the error code of _stctx_. This is used by the verification callback + * set to OpenSSL::X509::Store#verify_callback=. + * + * See also the man page X509_STORE_CTX_set_error(3). + */ static VALUE ossl_x509stctx_set_error(VALUE self, VALUE err) { X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); - X509_STORE_CTX_set_error(ctx, FIX2INT(err)); + X509_STORE_CTX_set_error(ctx, NUM2INT(err)); return err; } -static VALUE +/* + * call-seq: + * stctx.error_string -> String + * + * Returns the human readable error string corresponding to the error code + * retrieved by #error. + * + * See also the man page X509_verify_cert_error_string(3). + */ +static VALUE ossl_x509stctx_get_err_string(VALUE self) { X509_STORE_CTX *ctx; @@ -475,52 +706,77 @@ ossl_x509stctx_get_err_string(VALUE self) return rb_str_new2(X509_verify_cert_error_string(err)); } -static VALUE +/* + * call-seq: + * stctx.error_depth -> Integer + * + * Returns the depth of the chain. This is used in combination with #error. + * + * See also the man page X509_STORE_CTX_get_error_depth(3). + */ +static VALUE ossl_x509stctx_get_err_depth(VALUE self) { X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); - return INT2FIX(X509_STORE_CTX_get_error_depth(ctx)); + return INT2NUM(X509_STORE_CTX_get_error_depth(ctx)); } -static VALUE +/* + * call-seq: + * stctx.current_cert -> X509::Certificate + * + * Returns the certificate which caused the error. + * + * See also the man page X509_STORE_CTX_get_current_cert(3). + */ +static VALUE ossl_x509stctx_get_curr_cert(VALUE self) { X509_STORE_CTX *ctx; + X509 *x509; GetX509StCtx(self, ctx); + x509 = X509_STORE_CTX_get_current_cert(ctx); + if (!x509) + return Qnil; - return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx)); + return ossl_x509_new(x509); } +/* + * call-seq: + * stctx.current_crl -> X509::CRL + * + * Returns the CRL which caused the error. + * + * See also the man page X509_STORE_CTX_get_current_crl(3). + */ static VALUE ossl_x509stctx_get_curr_crl(VALUE self) { -#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) - X509_STORE_CTX *ctx; - - GetX509StCtx(self, ctx); - if(!ctx->current_crl) return Qnil; - - return ossl_x509crl_new(ctx->current_crl); -#else - return Qnil; -#endif -} - -static VALUE -ossl_x509stctx_cleanup(VALUE self) -{ X509_STORE_CTX *ctx; + X509_CRL *crl; GetX509StCtx(self, ctx); - X509_STORE_CTX_cleanup(ctx); + crl = X509_STORE_CTX_get0_current_crl(ctx); + if (!crl) + return Qnil; - return self; + return ossl_x509crl_new(crl); } +/* + * call-seq: + * stctx.flags = flags + * + * Sets the verification flags to the context. This overrides the default value + * set by Store#flags=. + * + * See also the man page X509_VERIFY_PARAM_set_flags(3). + */ static VALUE ossl_x509stctx_set_flags(VALUE self, VALUE flags) { @@ -533,11 +789,20 @@ ossl_x509stctx_set_flags(VALUE self, VALUE flags) return flags; } +/* + * call-seq: + * stctx.purpose = purpose + * + * Sets the purpose of the context. This overrides the default value set by + * Store#purpose=. + * + * See also the man page X509_VERIFY_PARAM_set_purpose(3). + */ static VALUE ossl_x509stctx_set_purpose(VALUE self, VALUE purpose) { X509_STORE_CTX *store; - long p = NUM2LONG(purpose); + int p = NUM2INT(purpose); GetX509StCtx(self, store); X509_STORE_CTX_set_purpose(store, p); @@ -545,11 +810,20 @@ ossl_x509stctx_set_purpose(VALUE self, VALUE purpose) return purpose; } +/* + * call-seq: + * stctx.trust = trust + * + * Sets the trust settings of the context. This overrides the default value set + * by Store#trust=. + * + * See also the man page X509_VERIFY_PARAM_set_trust(3). + */ static VALUE ossl_x509stctx_set_trust(VALUE self, VALUE trust) { X509_STORE_CTX *store; - long t = NUM2LONG(trust); + int t = NUM2INT(trust); GetX509StCtx(self, store); X509_STORE_CTX_set_trust(store, t); @@ -559,7 +833,11 @@ 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. + * + * See also the man page X509_VERIFY_PARAM_set_time(3). */ static VALUE ossl_x509stctx_set_time(VALUE self, VALUE time) @@ -577,20 +855,94 @@ ossl_x509stctx_set_time(VALUE self, VALUE time) /* * INIT */ -void -Init_ossl_x509store() -{ - VALUE x509stctx; +void +Init_ossl_x509store(void) +{ +#undef rb_intern + /* 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 + * + * The X509 certificate store holds trusted CA certificates used to verify + * peer certificates. + * + * The easiest way to create a useful certificate store is: + * + * cert_store = OpenSSL::X509::Store.new + * cert_store.set_default_paths + * + * 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 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: + * + * cert_store = OpenSSL::X509::Store.new + * cert_store.add_file 'cacert.pem' + * + * 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 + * + * ssl_socket = OpenSSL::SSL::SSLSocket.new tcp_socket, ssl_context + */ + cX509Store = rb_define_class_under(mX509, "Store", rb_cObject); + /* + * The callback for additional certificate verification. It is invoked for + * each certificate in the chain and can be used to implement custom + * certificate verification conditions. + * + * 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 can use StoreContext#error= to change the error code as + * needed. The callback must return either true or false. + * + * NOTE: any exception raised within the callback will be ignored. + * + * See also the man page X509_STORE_CTX_set_verify_cb(3). + */ rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse); + /* + * The error code set by the last call of #verify. + * + * See also StoreContext#error. + */ rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse); + /* + * The description for the error code set by the last call of #verify. + * + * See also StoreContext#error_string. + */ rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse); + /* + * The certificate chain constructed by the last call of #verify. + * + * See also StoreContext#chain. + */ 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); @@ -603,22 +955,26 @@ Init_ossl_x509store() 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,"cleanup", ossl_x509stctx_cleanup, 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 deleted file mode 100644 index 64b76f26b4..0000000000 --- a/ext/openssl/ruby_missing.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * $Id$ - * 'OpenSSL for Ruby' project - * Copyright (C) 2001-2003 Michal Rokos <m.rokos@sh.cvut.cz> - * All rights reserved. - */ -/* - * This program is licenced under the same licence as Ruby. - * (See the file 'LICENCE'.) - */ -#if !defined(_OSSL_RUBY_MISSING_H_) -#define _OSSL_RUBY_MISSING_H_ - -#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 -#endif - -#ifndef HAVE_RB_STR_SET_LEN -/* these methods should probably be backported to 1.8 */ -#define rb_str_set_len(str, length) do { \ - RSTRING(str)->ptr[length] = 0; \ - RSTRING(str)->len = length; \ -} while(0) -#endif /* ! HAVE_RB_STR_SET_LEN */ - -#ifndef HAVE_RB_BLOCK_CALL -/* the openssl module doesn't use arg[3-4] and arg2 is always rb_each */ -#define rb_block_call(arg1, arg2, arg3, arg4, arg5, arg6) rb_iterate(rb_each, arg1, arg5, arg6) -#endif /* ! HAVE_RB_BLOCK_CALL */ - -#endif /* _OSSL_RUBY_MISSING_H_ */ |
