diff options
98 files changed, 3895 insertions, 3513 deletions
diff --git a/ext/openssl/History.md b/ext/openssl/History.md index 8baa0208ea..6e4baeb3be 100644 --- a/ext/openssl/History.md +++ b/ext/openssl/History.md @@ -1,3 +1,34 @@ +Version 2.1.0.beta1 +=================== + +Notable changes +--------------- + +* Support for OpenSSL versions before 1.0.1 is removed. + [[GitHub #86]](https://github.com/ruby/openssl/pull/86) +* OpenSSL::BN#negative?, #+@, and #-@ are added. +* OpenSSL::SSL::SSLSocket#connect raises a more informative exception when + certificate verification fails. + [[GitHub #99]](https://github.com/ruby/openssl/pull/99) +* OpenSSL::KDF module is newly added. Support for scrypt is added. + [[GitHub #109]](https://github.com/ruby/openssl/pull/109) +* OpenSSL.fips_mode is added. We have 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. + [[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) + + Version 2.0.5 ============= diff --git a/ext/openssl/depend b/ext/openssl/depend index 4e98617954..021c6d99a8 100644 --- a/ext/openssl/depend +++ b/ext/openssl/depend @@ -30,10 +30,10 @@ 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_pkcs5.h ossl.o: ossl_pkcs7.h ossl.o: ossl_pkey.h ossl.o: ossl_rand.h @@ -67,10 +67,10 @@ 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_pkcs5.h ossl_asn1.o: ossl_pkcs7.h ossl_asn1.o: ossl_pkey.h ossl_asn1.o: ossl_rand.h @@ -104,10 +104,10 @@ 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_pkcs5.h ossl_bio.o: ossl_pkcs7.h ossl_bio.o: ossl_pkey.h ossl_bio.o: ossl_rand.h @@ -141,10 +141,10 @@ 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_pkcs5.h ossl_bn.o: ossl_pkcs7.h ossl_bn.o: ossl_pkey.h ossl_bn.o: ossl_rand.h @@ -178,10 +178,10 @@ 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_pkcs5.h ossl_cipher.o: ossl_pkcs7.h ossl_cipher.o: ossl_pkey.h ossl_cipher.o: ossl_rand.h @@ -215,10 +215,10 @@ 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_pkcs5.h ossl_config.o: ossl_pkcs7.h ossl_config.o: ossl_pkey.h ossl_config.o: ossl_rand.h @@ -252,10 +252,10 @@ 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_pkcs5.h ossl_digest.o: ossl_pkcs7.h ossl_digest.o: ossl_pkey.h ossl_digest.o: ossl_rand.h @@ -289,10 +289,10 @@ 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_pkcs5.h ossl_engine.o: ossl_pkcs7.h ossl_engine.o: ossl_pkey.h ossl_engine.o: ossl_rand.h @@ -326,10 +326,10 @@ 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_pkcs5.h ossl_hmac.o: ossl_pkcs7.h ossl_hmac.o: ossl_pkey.h ossl_hmac.o: ossl_rand.h @@ -337,6 +337,43 @@ ossl_hmac.o: ossl_ssl.h ossl_hmac.o: ossl_version.h ossl_hmac.o: ossl_x509.h ossl_hmac.o: ruby_missing.h +ossl_kdf.o: $(RUBY_EXTCONF_H) +ossl_kdf.o: $(arch_hdrdir)/ruby/config.h +ossl_kdf.o: $(hdrdir)/ruby/backward.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/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/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: $(top_srcdir)/include/ruby.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_rand.h +ossl_kdf.o: ossl_ssl.h +ossl_kdf.o: ossl_version.h +ossl_kdf.o: ossl_x509.h +ossl_kdf.o: ruby_missing.h ossl_ns_spki.o: $(RUBY_EXTCONF_H) ossl_ns_spki.o: $(arch_hdrdir)/ruby/config.h ossl_ns_spki.o: $(hdrdir)/ruby/backward.h @@ -362,11 +399,11 @@ 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_pkcs5.h ossl_ns_spki.o: ossl_pkcs7.h ossl_ns_spki.o: ossl_pkey.h ossl_ns_spki.o: ossl_rand.h @@ -399,11 +436,11 @@ 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_pkcs5.h ossl_ocsp.o: ossl_pkcs7.h ossl_ocsp.o: ossl_pkey.h ossl_ocsp.o: ossl_rand.h @@ -436,11 +473,11 @@ 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_pkcs5.h ossl_pkcs12.o: ossl_pkcs7.h ossl_pkcs12.o: ossl_pkey.h ossl_pkcs12.o: ossl_rand.h @@ -448,43 +485,6 @@ ossl_pkcs12.o: ossl_ssl.h ossl_pkcs12.o: ossl_version.h ossl_pkcs12.o: ossl_x509.h ossl_pkcs12.o: ruby_missing.h -ossl_pkcs5.o: $(RUBY_EXTCONF_H) -ossl_pkcs5.o: $(arch_hdrdir)/ruby/config.h -ossl_pkcs5.o: $(hdrdir)/ruby/backward.h -ossl_pkcs5.o: $(hdrdir)/ruby/defines.h -ossl_pkcs5.o: $(hdrdir)/ruby/encoding.h -ossl_pkcs5.o: $(hdrdir)/ruby/intern.h -ossl_pkcs5.o: $(hdrdir)/ruby/io.h -ossl_pkcs5.o: $(hdrdir)/ruby/missing.h -ossl_pkcs5.o: $(hdrdir)/ruby/onigmo.h -ossl_pkcs5.o: $(hdrdir)/ruby/oniguruma.h -ossl_pkcs5.o: $(hdrdir)/ruby/ruby.h -ossl_pkcs5.o: $(hdrdir)/ruby/st.h -ossl_pkcs5.o: $(hdrdir)/ruby/subst.h -ossl_pkcs5.o: $(hdrdir)/ruby/thread.h -ossl_pkcs5.o: $(top_srcdir)/include/ruby.h -ossl_pkcs5.o: openssl_missing.h -ossl_pkcs5.o: ossl.h -ossl_pkcs5.o: ossl_asn1.h -ossl_pkcs5.o: ossl_bio.h -ossl_pkcs5.o: ossl_bn.h -ossl_pkcs5.o: ossl_cipher.h -ossl_pkcs5.o: ossl_config.h -ossl_pkcs5.o: ossl_digest.h -ossl_pkcs5.o: ossl_engine.h -ossl_pkcs5.o: ossl_hmac.h -ossl_pkcs5.o: ossl_ns_spki.h -ossl_pkcs5.o: ossl_ocsp.h -ossl_pkcs5.o: ossl_pkcs12.h -ossl_pkcs5.o: ossl_pkcs5.c -ossl_pkcs5.o: ossl_pkcs5.h -ossl_pkcs5.o: ossl_pkcs7.h -ossl_pkcs5.o: ossl_pkey.h -ossl_pkcs5.o: ossl_rand.h -ossl_pkcs5.o: ossl_ssl.h -ossl_pkcs5.o: ossl_version.h -ossl_pkcs5.o: ossl_x509.h -ossl_pkcs5.o: ruby_missing.h ossl_pkcs7.o: $(RUBY_EXTCONF_H) ossl_pkcs7.o: $(arch_hdrdir)/ruby/config.h ossl_pkcs7.o: $(hdrdir)/ruby/backward.h @@ -510,10 +510,10 @@ 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_pkcs5.h ossl_pkcs7.o: ossl_pkcs7.c ossl_pkcs7.o: ossl_pkcs7.h ossl_pkcs7.o: ossl_pkey.h @@ -547,10 +547,10 @@ 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_pkcs5.h ossl_pkey.o: ossl_pkcs7.h ossl_pkey.o: ossl_pkey.c ossl_pkey.o: ossl_pkey.h @@ -584,10 +584,10 @@ 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_pkcs5.h ossl_pkey_dh.o: ossl_pkcs7.h ossl_pkey_dh.o: ossl_pkey.h ossl_pkey_dh.o: ossl_pkey_dh.c @@ -621,10 +621,10 @@ 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_pkcs5.h ossl_pkey_dsa.o: ossl_pkcs7.h ossl_pkey_dsa.o: ossl_pkey.h ossl_pkey_dsa.o: ossl_pkey_dsa.c @@ -658,10 +658,10 @@ 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_pkcs5.h ossl_pkey_ec.o: ossl_pkcs7.h ossl_pkey_ec.o: ossl_pkey.h ossl_pkey_ec.o: ossl_pkey_ec.c @@ -695,10 +695,10 @@ 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_pkcs5.h ossl_pkey_rsa.o: ossl_pkcs7.h ossl_pkey_rsa.o: ossl_pkey.h ossl_pkey_rsa.o: ossl_pkey_rsa.c @@ -732,10 +732,10 @@ 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_pkcs5.h ossl_rand.o: ossl_pkcs7.h ossl_rand.o: ossl_pkey.h ossl_rand.o: ossl_rand.c @@ -769,10 +769,10 @@ 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_pkcs5.h ossl_ssl.o: ossl_pkcs7.h ossl_ssl.o: ossl_pkey.h ossl_ssl.o: ossl_rand.h @@ -806,10 +806,10 @@ 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_pkcs5.h ossl_ssl_session.o: ossl_pkcs7.h ossl_ssl_session.o: ossl_pkey.h ossl_ssl_session.o: ossl_rand.h @@ -843,10 +843,10 @@ 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_pkcs5.h ossl_x509.o: ossl_pkcs7.h ossl_x509.o: ossl_pkey.h ossl_x509.o: ossl_rand.h @@ -880,10 +880,10 @@ 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_pkcs5.h ossl_x509attr.o: ossl_pkcs7.h ossl_x509attr.o: ossl_pkey.h ossl_x509attr.o: ossl_rand.h @@ -917,10 +917,10 @@ 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_pkcs5.h ossl_x509cert.o: ossl_pkcs7.h ossl_x509cert.o: ossl_pkey.h ossl_x509cert.o: ossl_rand.h @@ -954,10 +954,10 @@ 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_pkcs5.h ossl_x509crl.o: ossl_pkcs7.h ossl_x509crl.o: ossl_pkey.h ossl_x509crl.o: ossl_rand.h @@ -991,10 +991,10 @@ 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_pkcs5.h ossl_x509ext.o: ossl_pkcs7.h ossl_x509ext.o: ossl_pkey.h ossl_x509ext.o: ossl_rand.h @@ -1028,10 +1028,10 @@ 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_pkcs5.h ossl_x509name.o: ossl_pkcs7.h ossl_x509name.o: ossl_pkey.h ossl_x509name.o: ossl_rand.h @@ -1065,10 +1065,10 @@ 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_pkcs5.h ossl_x509req.o: ossl_pkcs7.h ossl_x509req.o: ossl_pkey.h ossl_x509req.o: ossl_rand.h @@ -1102,10 +1102,10 @@ 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_pkcs5.h ossl_x509revoked.o: ossl_pkcs7.h ossl_x509revoked.o: ossl_pkey.h ossl_x509revoked.o: ossl_rand.h @@ -1139,10 +1139,10 @@ 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_pkcs5.h ossl_x509store.o: ossl_pkcs7.h ossl_x509store.o: ossl_pkey.h ossl_x509store.o: ossl_rand.h diff --git a/ext/openssl/deprecation.rb b/ext/openssl/deprecation.rb index 0c3ab6287e..1d51d065a9 100644 --- a/ext/openssl/deprecation.rb +++ b/ext/openssl/deprecation.rb @@ -3,9 +3,6 @@ module OpenSSL def self.deprecated_warning_flag unless flag = (@deprecated_warning_flag ||= nil) if try_compile("", flag = "-Werror=deprecated-declarations") - if /darwin/ =~ RUBY_PLATFORM and with_config("broken-apple-openssl") - flag = "-Wno-deprecated-declarations" - end $warnflags << " #{flag}" else flag = "" diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 75da65cde3..5212903b9a 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -91,30 +91,19 @@ unless result unless find_openssl_library Logging::message "=== Checking for required stuff failed. ===\n" Logging::message "Makefile wasn't created. Fix the errors above.\n" - exit 1 + 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 end -result = checking_for("OpenSSL version is 0.9.8 or later") { - try_static_assert("OPENSSL_VERSION_NUMBER >= 0x00908000L", "openssl/opensslv.h") -} -unless result - raise "OpenSSL 0.9.8 or later required." -end - -if /darwin/ =~ RUBY_PLATFORM and !OpenSSL.check_func("SSL_library_init()", "openssl/ssl.h") - raise "Ignore OpenSSL broken by Apple.\nPlease use another openssl. (e.g. using `configure --with-openssl-dir=/path/to/openssl')" +unless checking_for("OpenSSL version is 1.0.1 or later") { + try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10001000L", "openssl/opensslv.h") } + raise "OpenSSL >= 1.0.1 or LibreSSL is required" end Logging::message "=== Checking for OpenSSL features... ===\n" # compile options - -# SSLv2 and SSLv3 may be removed in future versions of OpenSSL, and even macros -# like OPENSSL_NO_SSL2 may not be defined. -have_func("SSLv2_method") -have_func("SSLv3_method") -have_func("TLSv1_1_method") -have_func("TLSv1_2_method") have_func("RAND_egd") engines = %w{builtin_engines openbsd_dev_crypto dynamic 4758cca aep atalla chil cswift nuron sureware ubsec padlock capi gmp gost cryptodev aesni} @@ -122,30 +111,6 @@ engines.each { |name| OpenSSL.check_func_or_macro("ENGINE_load_#{name}", "openssl/engine.h") } -# added in 0.9.8X -have_func("EVP_CIPHER_CTX_new") -have_func("EVP_CIPHER_CTX_free") -OpenSSL.check_func_or_macro("SSL_CTX_clear_options", "openssl/ssl.h") - -# added in 1.0.0 -have_func("ASN1_TIME_adj") -have_func("EVP_CIPHER_CTX_copy") -have_func("EVP_PKEY_base_id") -have_func("HMAC_CTX_copy") -have_func("PKCS5_PBKDF2_HMAC") -have_func("X509_NAME_hash_old") -have_func("X509_STORE_CTX_get0_current_crl") -have_func("X509_STORE_set_verify_cb") -have_func("i2d_ASN1_SET_ANY") -have_func("SSL_SESSION_cmp") # removed -OpenSSL.check_func_or_macro("SSL_set_tlsext_host_name", "openssl/ssl.h") -have_struct_member("CRYPTO_THREADID", "ptr", "openssl/crypto.h") -have_func("EVP_PKEY_get0") - -# added in 1.0.1 -have_func("SSL_CTX_set_next_proto_select_cb") -have_macro("EVP_CTRL_GCM_GET_TAG", ['openssl/evp.h']) && $defs.push("-DHAVE_AUTHENTICATED_ENCRYPTION") - # added in 1.0.2 have_func("EC_curve_nist2nid") have_func("X509_REVOKED_dup") @@ -189,6 +154,7 @@ OpenSSL.check_func_or_macro("SSL_CTX_set_min_proto_version", "openssl/ssl.h") have_func("SSL_CTX_get_security_level") have_func("X509_get0_notBefore") have_func("SSL_SESSION_get_protocol_version") +have_func("EVP_PBE_scrypt") Logging::message "=== Checking done. ===\n" diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb index 26d167a9b4..0914282920 100644 --- a/ext/openssl/lib/openssl.rb +++ b/ext/openssl/lib/openssl.rb @@ -19,3 +19,4 @@ require 'openssl/config' require 'openssl/digest' require 'openssl/x509' require 'openssl/ssl' +require 'openssl/pkcs5' diff --git a/ext/openssl/lib/openssl/bn.rb b/ext/openssl/lib/openssl/bn.rb index 6d6c96e42d..8d1ebefb6e 100644 --- a/ext/openssl/lib/openssl/bn.rb +++ b/ext/openssl/lib/openssl/bn.rb @@ -27,8 +27,9 @@ module OpenSSL end # OpenSSL ## +#-- # Add double dispatch to Integer -# +#++ class Integer # Casts an Integer as an OpenSSL::BN # diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb index d773637c0e..8b5dd9da57 100644 --- a/ext/openssl/lib/openssl/buffering.rb +++ b/ext/openssl/lib/openssl/buffering.rb @@ -63,7 +63,7 @@ module OpenSSL::Buffering end ## - # Consumes +size+ bytes from the buffer + # Consumes _size_ bytes from the buffer def consume_rbuff(size=nil) if @rbuffer.empty? @@ -79,7 +79,7 @@ module OpenSSL::Buffering public ## - # Reads +size+ bytes from the stream. If +buf+ is provided it must + # 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. @@ -106,7 +106,7 @@ module OpenSSL::Buffering end ## - # Reads at most +maxlen+ bytes from the stream. If +buf+ is provided it + # 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. @@ -136,7 +136,7 @@ module OpenSSL::Buffering end ## - # Reads at most +maxlen+ bytes in the non-blocking manner. + # 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. @@ -190,11 +190,11 @@ module OpenSSL::Buffering 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 + # 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. + # _eol_ may be a String or Regexp. # # Unlike IO#gets the line read will not be assigned to +$_+. # @@ -220,7 +220,7 @@ module OpenSSL::Buffering ## # Executes the block for every line in the stream where lines are separated - # by +eol+. + # by _eol_. # # See also #gets @@ -232,7 +232,7 @@ module OpenSSL::Buffering alias each_line each ## - # Reads lines from the stream which are separated by +eol+. + # Reads lines from the stream which are separated by _eol_. # # See also #gets @@ -245,7 +245,7 @@ module OpenSSL::Buffering end ## - # Reads a line from the stream which is separated by +eol+. + # Reads a line from the stream which is separated by _eol_. # # Raises EOFError if at end of file. @@ -281,7 +281,7 @@ module OpenSSL::Buffering end ## - # Pushes character +c+ back onto the stream such that a subsequent buffered + # 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. @@ -308,7 +308,7 @@ module OpenSSL::Buffering private ## - # Writes +s+ to the buffer. When the buffer is full or #sync is true the + # 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) @@ -336,8 +336,8 @@ module OpenSSL::Buffering public ## - # Writes +s+ to the stream. If the argument is not a string it will be - # converted using String#to_s. Returns the number of bytes written. + # 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) do_write(s) @@ -345,7 +345,7 @@ module OpenSSL::Buffering end ## - # Writes +s+ in the non-blocking manner. + # Writes _s_ in the non-blocking manner. # # If there is buffered data, it is flushed first. This may block. # @@ -387,8 +387,8 @@ module OpenSSL::Buffering end ## - # Writes +s+ to the stream. +s+ will be converted to a String using - # String#to_s. + # Writes _s_ to the stream. _s_ will be converted to a String using + # +.to_s+ method. def <<(s) do_write(s) @@ -396,7 +396,7 @@ module OpenSSL::Buffering end ## - # Writes +args+ to the stream along with a record separator. + # Writes _args_ to the stream along with a record separator. # # See IO#puts for full details. @@ -416,7 +416,7 @@ module OpenSSL::Buffering end ## - # Writes +args+ to the stream. + # Writes _args_ to the stream. # # See IO#print for full details. diff --git a/ext/openssl/lib/openssl/config.rb b/ext/openssl/lib/openssl/config.rb index 8822545192..48d8be0069 100644 --- a/ext/openssl/lib/openssl/config.rb +++ b/ext/openssl/lib/openssl/config.rb @@ -30,7 +30,8 @@ module OpenSSL class << self ## - # Parses a given +string+ as a blob that contains configuration for openssl. + # Parses a given _string_ as a blob that contains configuration for + # OpenSSL. # # If the source of the IO is a file, then consider using #parse_config. def parse(string) @@ -46,7 +47,7 @@ module OpenSSL alias load new ## - # Parses the configuration data read from +io+, see also #parse. + # Parses the configuration data read from _io_, see also #parse. # # Raises a ConfigError on invalid configuration data. def parse_config(io) @@ -236,7 +237,7 @@ module OpenSSL # # This can be used in contexts like OpenSSL::X509::ExtensionFactory.config= # - # If the optional +filename+ parameter is provided, then it is read in and + # If the optional _filename_ parameter is provided, then it is read in and # parsed via #parse_config. # # This can raise IO exceptions based on the access, or availability of the @@ -255,7 +256,7 @@ module OpenSSL end ## - # Gets the value of +key+ from the given +section+ + # Gets the value of _key_ from the given _section_ # # Given the following configurating file being loaded: # @@ -265,8 +266,8 @@ module OpenSSL # #=> [ default ] # # foo=bar # - # You can get a specific value from the config if you know the +section+ - # and +key+ like so: + # You can get a specific value from the config if you know the _section_ + # and _key_ like so: # # config.get_value('default','foo') # #=> "bar" @@ -297,7 +298,7 @@ module OpenSSL end ## - # Set the target +key+ with a given +value+ under a specific +section+. + # Set the target _key_ with a given _value_ under a specific _section_. # # Given the following configurating file being loaded: # @@ -307,7 +308,7 @@ module OpenSSL # #=> [ default ] # # foo=bar # - # You can set the value of +foo+ under the +default+ section to a new + # You can set the value of _foo_ under the _default_ section to a new # value: # # config.add_value('default', 'foo', 'buzz') @@ -322,7 +323,7 @@ module OpenSSL end ## - # Get a specific +section+ from the current configuration + # Get a specific _section_ from the current configuration # # Given the following configurating file being loaded: # @@ -351,7 +352,7 @@ module OpenSSL end ## - # Sets a specific +section+ name with a Hash +pairs+ + # Sets a specific _section_ name with a Hash _pairs_. # # Given the following configuration being created: # @@ -365,7 +366,7 @@ module OpenSSL # # baz=buz # # It's important to note that this will essentially merge any of the keys - # in +pairs+ with the existing +section+. For example: + # in _pairs_ with the existing _section_. For example: # # config['default'] # #=> {"foo"=>"bar", "baz"=>"buz"} diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb index 97ccbc9569..b6744de6bd 100644 --- a/ext/openssl/lib/openssl/digest.rb +++ b/ext/openssl/lib/openssl/digest.rb @@ -15,15 +15,12 @@ module OpenSSL class Digest - alg = %w(MD2 MD4 MD5 MDC2 RIPEMD160 SHA1) + alg = %w(MD2 MD4 MD5 MDC2 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512) if OPENSSL_VERSION_NUMBER < 0x10100000 alg += %w(DSS DSS1 SHA) end - if OPENSSL_VERSION_NUMBER > 0x00908000 - alg += %w(SHA224 SHA256 SHA384 SHA512) - end - # Return the +data+ hash computed with +name+ Digest. +name+ is either the + # Return the hash value computed with _name_ Digest. _name_ is either the # long name or short name of a supported digest algorithm. # # === Examples @@ -59,7 +56,7 @@ module OpenSSL end # Digest - # Returns a Digest subclass by +name+. + # Returns a Digest subclass by _name_ # # require 'openssl' # diff --git a/ext/openssl/lib/openssl/pkcs5.rb b/ext/openssl/lib/openssl/pkcs5.rb new file mode 100644 index 0000000000..959447df5e --- /dev/null +++ b/ext/openssl/lib/openssl/pkcs5.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: false +#-- +# 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 index 9af5f781f9..dcedd849a0 100644 --- a/ext/openssl/lib/openssl/pkey.rb +++ b/ext/openssl/lib/openssl/pkey.rb @@ -1,44 +1,3 @@ # frozen_string_literal: false module OpenSSL - module PKey - if defined?(OpenSSL::PKey::DH) - - class DH - # :nodoc: - DEFAULT_1024 = new <<-_end_of_pem_ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ -AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR -T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC ------END DH PARAMETERS----- - _end_of_pem_ - - # :nodoc: - DEFAULT_2048 = new <<-_end_of_pem_ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY -JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab -VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6 -YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3 -1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD -7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg== ------END DH PARAMETERS----- - _end_of_pem_ - end - - # :nodoc: - DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| - warn "using default DH parameters." if $VERBOSE - case keylen - when 1024 then OpenSSL::PKey::DH::DEFAULT_1024 - when 2048 then OpenSSL::PKey::DH::DEFAULT_2048 - else - nil - end - } - - else - DEFAULT_TMP_DH_CALLBACK = nil - end - end end diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index f40a451439..a628648e71 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -17,18 +17,36 @@ module OpenSSL module SSL class SSLContext DEFAULT_PARAMS = { # :nodoc: - :ssl_version => "SSLv23", + :min_version => OpenSSL::SSL::TLS1_VERSION, :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 if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) - opts |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 + opts |= OpenSSL::SSL::OP_NO_COMPRESSION opts }.call } + if defined?(OpenSSL::PKey::DH) + DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY +JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab +VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6 +YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3 +1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD +7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg== +-----END DH PARAMETERS----- + _end_of_pem_ + private_constant :DEFAULT_2048 + + DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc: + warn "using default DH parameters." if $VERBOSE + DEFAULT_2048 + } + end + if !(OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") && OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000) DEFAULT_PARAMS.merge!( @@ -87,14 +105,18 @@ module OpenSSL # # The callback is invoked with an SSLSocket and a server name. The # callback must return an SSLContext for the server name or nil. - attr_accessor :servername_cb if ExtConfig::HAVE_TLSEXT_HOST_NAME + attr_accessor :servername_cb # call-seq: - # SSLContext.new => ctx - # SSLContext.new(:TLSv1) => ctx - # SSLContext.new("SSLv23_client") => ctx + # SSLContext.new -> ctx + # SSLContext.new(:TLSv1) -> ctx + # SSLContext.new("SSLv23") -> ctx # - # You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS + # 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.options |= OpenSSL::SSL::OP_ALL self.ssl_version = version if version @@ -106,8 +128,8 @@ module OpenSSL # # 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 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 @@ -122,6 +144,88 @@ module OpenSSL end return params end + + # 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". + # + # Be careful that you don't overwrite OpenSSL::SSL::OP_NO_{SSL,TLS}v* + # options by #options= once you have called #min_version= or + # #max_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 + def min_version=(version) + set_minmax_proto_version(version, @max_proto_version ||= nil) + @min_proto_version = version + end + + # 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. + def max_version=(version) + set_minmax_proto_version(@min_proto_version ||= nil, version) + @max_proto_version = version + 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)[0]}: method type #{type.inspect} is ignored" + end + end + version = METHODS_MAP[meth.intern] or + raise ArgumentError, "unknown SSL method `%s'" % meth + set_minmax_proto_version(version, version) + @min_proto_version = @max_proto_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 @@ -242,9 +346,7 @@ module OpenSSL include Buffering include SocketForwarder - if ExtConfig::HAVE_TLSEXT_HOST_NAME - attr_reader :hostname - end + attr_reader :hostname # The underlying IO object. attr_reader :io @@ -317,7 +419,7 @@ module OpenSSL end def tmp_dh_callback - @context.tmp_dh_callback || OpenSSL::PKey::DEFAULT_TMP_DH_CALLBACK + @context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK end def tmp_ecdh_callback @@ -341,8 +443,8 @@ module OpenSSL attr_accessor :start_immediately # Creates a new instance of SSLServer. - # * +srv+ is an instance of TCPServer. - # * +ctx+ is an instance of OpenSSL::SSL::SSLContext. + # * _srv_ is an instance of TCPServer. + # * _ctx_ is an instance of OpenSSL::SSL::SSLContext. def initialize(svr, ctx) @svr = svr @ctx = ctx diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb index aef3456e0f..6d31b98c68 100644 --- a/ext/openssl/lib/openssl/x509.rb +++ b/ext/openssl/lib/openssl/x509.rb @@ -139,7 +139,13 @@ module OpenSSL end 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 diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec index 7cbbfeb513..2c2e300bb9 100644 --- a/ext/openssl/openssl.gemspec +++ b/ext/openssl/openssl.gemspec @@ -1,26 +1,26 @@ # -*- encoding: utf-8 -*- -# stub: openssl 2.0.5 ruby lib +# stub: openssl 2.1.0.beta1 ruby lib # stub: ext/openssl/extconf.rb Gem::Specification.new do |s| s.name = "openssl".freeze - s.version = "2.0.5" + s.version = "2.1.0.beta1" - s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new("> 1.3.1".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "msys2_mingw_dependencies" => "openssl" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Martin Bosslet".freeze, "SHIBATA Hiroshi".freeze, "Zachary Scott".freeze, "Kazuki Yamaguchi".freeze] - s.date = "2017-08-08" + s.date = "2017-09-03" s.description = "It wraps the OpenSSL library.".freeze s.email = ["[email protected]".freeze] s.extensions = ["ext/openssl/extconf.rb".freeze] s.extra_rdoc_files = ["CONTRIBUTING.md".freeze, "README.md".freeze, "History.md".freeze] - s.files = ["BSDL".freeze, "CONTRIBUTING.md".freeze, "History.md".freeze, "LICENSE.txt".freeze, "README.md".freeze, "ext/openssl/deprecation.rb".freeze, "ext/openssl/extconf.rb".freeze, "ext/openssl/openssl_missing.c".freeze, "ext/openssl/openssl_missing.h".freeze, "ext/openssl/ossl.c".freeze, "ext/openssl/ossl.h".freeze, "ext/openssl/ossl_asn1.c".freeze, "ext/openssl/ossl_asn1.h".freeze, "ext/openssl/ossl_bio.c".freeze, "ext/openssl/ossl_bio.h".freeze, "ext/openssl/ossl_bn.c".freeze, "ext/openssl/ossl_bn.h".freeze, "ext/openssl/ossl_cipher.c".freeze, "ext/openssl/ossl_cipher.h".freeze, "ext/openssl/ossl_config.c".freeze, "ext/openssl/ossl_config.h".freeze, "ext/openssl/ossl_digest.c".freeze, "ext/openssl/ossl_digest.h".freeze, "ext/openssl/ossl_engine.c".freeze, "ext/openssl/ossl_engine.h".freeze, "ext/openssl/ossl_hmac.c".freeze, "ext/openssl/ossl_hmac.h".freeze, "ext/openssl/ossl_ns_spki.c".freeze, "ext/openssl/ossl_ns_spki.h".freeze, "ext/openssl/ossl_ocsp.c".freeze, "ext/openssl/ossl_ocsp.h".freeze, "ext/openssl/ossl_pkcs12.c".freeze, "ext/openssl/ossl_pkcs12.h".freeze, "ext/openssl/ossl_pkcs5.c".freeze, "ext/openssl/ossl_pkcs5.h".freeze, "ext/openssl/ossl_pkcs7.c".freeze, "ext/openssl/ossl_pkcs7.h".freeze, "ext/openssl/ossl_pkey.c".freeze, "ext/openssl/ossl_pkey.h".freeze, "ext/openssl/ossl_pkey_dh.c".freeze, "ext/openssl/ossl_pkey_dsa.c".freeze, "ext/openssl/ossl_pkey_ec.c".freeze, "ext/openssl/ossl_pkey_rsa.c".freeze, "ext/openssl/ossl_rand.c".freeze, "ext/openssl/ossl_rand.h".freeze, "ext/openssl/ossl_ssl.c".freeze, "ext/openssl/ossl_ssl.h".freeze, "ext/openssl/ossl_ssl_session.c".freeze, "ext/openssl/ossl_version.h".freeze, "ext/openssl/ossl_x509.c".freeze, "ext/openssl/ossl_x509.h".freeze, "ext/openssl/ossl_x509attr.c".freeze, "ext/openssl/ossl_x509cert.c".freeze, "ext/openssl/ossl_x509crl.c".freeze, "ext/openssl/ossl_x509ext.c".freeze, "ext/openssl/ossl_x509name.c".freeze, "ext/openssl/ossl_x509req.c".freeze, "ext/openssl/ossl_x509revoked.c".freeze, "ext/openssl/ossl_x509store.c".freeze, "ext/openssl/ruby_missing.h".freeze, "lib/openssl.rb".freeze, "lib/openssl/bn.rb".freeze, "lib/openssl/buffering.rb".freeze, "lib/openssl/cipher.rb".freeze, "lib/openssl/config.rb".freeze, "lib/openssl/digest.rb".freeze, "lib/openssl/pkey.rb".freeze, "lib/openssl/ssl.rb".freeze, "lib/openssl/x509.rb".freeze] + s.files = ["BSDL".freeze, "CONTRIBUTING.md".freeze, "History.md".freeze, "LICENSE.txt".freeze, "README.md".freeze, "ext/openssl/deprecation.rb".freeze, "ext/openssl/extconf.rb".freeze, "ext/openssl/openssl_missing.c".freeze, "ext/openssl/openssl_missing.h".freeze, "ext/openssl/ossl.c".freeze, "ext/openssl/ossl.h".freeze, "ext/openssl/ossl_asn1.c".freeze, "ext/openssl/ossl_asn1.h".freeze, "ext/openssl/ossl_bio.c".freeze, "ext/openssl/ossl_bio.h".freeze, "ext/openssl/ossl_bn.c".freeze, "ext/openssl/ossl_bn.h".freeze, "ext/openssl/ossl_cipher.c".freeze, "ext/openssl/ossl_cipher.h".freeze, "ext/openssl/ossl_config.c".freeze, "ext/openssl/ossl_config.h".freeze, "ext/openssl/ossl_digest.c".freeze, "ext/openssl/ossl_digest.h".freeze, "ext/openssl/ossl_engine.c".freeze, "ext/openssl/ossl_engine.h".freeze, "ext/openssl/ossl_hmac.c".freeze, "ext/openssl/ossl_hmac.h".freeze, "ext/openssl/ossl_kdf.c".freeze, "ext/openssl/ossl_kdf.h".freeze, "ext/openssl/ossl_ns_spki.c".freeze, "ext/openssl/ossl_ns_spki.h".freeze, "ext/openssl/ossl_ocsp.c".freeze, "ext/openssl/ossl_ocsp.h".freeze, "ext/openssl/ossl_pkcs12.c".freeze, "ext/openssl/ossl_pkcs12.h".freeze, "ext/openssl/ossl_pkcs7.c".freeze, "ext/openssl/ossl_pkcs7.h".freeze, "ext/openssl/ossl_pkey.c".freeze, "ext/openssl/ossl_pkey.h".freeze, "ext/openssl/ossl_pkey_dh.c".freeze, "ext/openssl/ossl_pkey_dsa.c".freeze, "ext/openssl/ossl_pkey_ec.c".freeze, "ext/openssl/ossl_pkey_rsa.c".freeze, "ext/openssl/ossl_rand.c".freeze, "ext/openssl/ossl_rand.h".freeze, "ext/openssl/ossl_ssl.c".freeze, "ext/openssl/ossl_ssl.h".freeze, "ext/openssl/ossl_ssl_session.c".freeze, "ext/openssl/ossl_version.h".freeze, "ext/openssl/ossl_x509.c".freeze, "ext/openssl/ossl_x509.h".freeze, "ext/openssl/ossl_x509attr.c".freeze, "ext/openssl/ossl_x509cert.c".freeze, "ext/openssl/ossl_x509crl.c".freeze, "ext/openssl/ossl_x509ext.c".freeze, "ext/openssl/ossl_x509name.c".freeze, "ext/openssl/ossl_x509req.c".freeze, "ext/openssl/ossl_x509revoked.c".freeze, "ext/openssl/ossl_x509store.c".freeze, "ext/openssl/ruby_missing.h".freeze, "lib/openssl.rb".freeze, "lib/openssl/bn.rb".freeze, "lib/openssl/buffering.rb".freeze, "lib/openssl/cipher.rb".freeze, "lib/openssl/config.rb".freeze, "lib/openssl/digest.rb".freeze, "lib/openssl/pkcs5.rb".freeze, "lib/openssl/pkey.rb".freeze, "lib/openssl/ssl.rb".freeze, "lib/openssl/x509.rb".freeze] s.homepage = "https://www.ruby-lang.org/".freeze s.licenses = ["Ruby".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) - s.rubygems_version = "2.6.12".freeze + s.rubygems_version = "2.6.13".freeze s.summary = "OpenSSL provides SSL, TLS and general purpose cryptography.".freeze if s.respond_to? :specification_version then diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c index 94ce85aff4..b36ef0288e 100644 --- a/ext/openssl/openssl_missing.c +++ b/ext/openssl/openssl_missing.c @@ -20,73 +20,6 @@ #include "openssl_missing.h" -/* added in 0.9.8X */ -#if !defined(HAVE_EVP_CIPHER_CTX_NEW) -EVP_CIPHER_CTX * -ossl_EVP_CIPHER_CTX_new(void) -{ - EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX)); - if (!ctx) - return NULL; - EVP_CIPHER_CTX_init(ctx); - return ctx; -} -#endif - -#if !defined(HAVE_EVP_CIPHER_CTX_FREE) -void -ossl_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) -{ - if (ctx) { - EVP_CIPHER_CTX_cleanup(ctx); - OPENSSL_free(ctx); - } -} -#endif - -/* added in 1.0.0 */ -#if !defined(HAVE_EVP_CIPHER_CTX_COPY) -/* - * this function does not exist in OpenSSL yet... or ever?. - * a future version may break this function. - * tested on 0.9.7d. - */ -int -ossl_EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) -{ - memcpy(out, in, sizeof(EVP_CIPHER_CTX)); - -#if !defined(OPENSSL_NO_ENGINE) - if (in->engine) ENGINE_add(out->engine); - if (in->cipher_data) { - out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size); - memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); - } -#endif - - return 1; -} -#endif - -#if !defined(OPENSSL_NO_HMAC) -#if !defined(HAVE_HMAC_CTX_COPY) -int -ossl_HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in) -{ - if (!out || !in) - return 0; - - memcpy(out, in, sizeof(HMAC_CTX)); - - EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx); - EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx); - EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx); - - return 1; -} -#endif /* HAVE_HMAC_CTX_COPY */ -#endif /* NO_HMAC */ - /* added in 1.0.2 */ #if !defined(OPENSSL_NO_EC) #if !defined(HAVE_EC_CURVE_NIST2NID) diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h index 3d11aec2d2..cc31f6ace7 100644 --- a/ext/openssl/openssl_missing.h +++ b/ext/openssl/openssl_missing.h @@ -12,53 +12,6 @@ #include "ruby/config.h" -/* added in 0.9.8X */ -#if !defined(HAVE_EVP_CIPHER_CTX_NEW) -EVP_CIPHER_CTX *ossl_EVP_CIPHER_CTX_new(void); -# define EVP_CIPHER_CTX_new ossl_EVP_CIPHER_CTX_new -#endif - -#if !defined(HAVE_EVP_CIPHER_CTX_FREE) -void ossl_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); -# define EVP_CIPHER_CTX_free ossl_EVP_CIPHER_CTX_free -#endif - -#if !defined(HAVE_SSL_CTX_CLEAR_OPTIONS) -# define SSL_CTX_clear_options(ctx, op) ((ctx)->options &= ~(op)) -#endif - -/* added in 1.0.0 */ -#if !defined(HAVE_EVP_PKEY_BASE_ID) -# define EVP_PKEY_base_id(pkey) EVP_PKEY_type((pkey)->type) -#endif - -#if !defined(HAVE_EVP_CIPHER_CTX_COPY) -int ossl_EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *, const EVP_CIPHER_CTX *); -# define EVP_CIPHER_CTX_copy ossl_EVP_CIPHER_CTX_copy -#endif - -#if !defined(HAVE_HMAC_CTX_COPY) -int ossl_HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in); -# define HMAC_CTX_copy ossl_HMAC_CTX_copy -#endif - -#if !defined(HAVE_X509_STORE_CTX_GET0_CURRENT_CRL) -# define X509_STORE_CTX_get0_current_crl(x) ((x)->current_crl) -#endif - -#if !defined(HAVE_X509_STORE_SET_VERIFY_CB) -# define X509_STORE_set_verify_cb X509_STORE_set_verify_cb_func -#endif - -#if !defined(HAVE_I2D_ASN1_SET_ANY) -# define i2d_ASN1_SET_ANY(sk, x) i2d_ASN1_SET_OF_ASN1_TYPE((sk), (x), \ - i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0) -#endif - -#if !defined(HAVE_EVP_PKEY_GET0) -# define EVP_PKEY_get0(pk) (pk->pkey.ptr) -#endif - /* added in 1.0.2 */ #if !defined(OPENSSL_NO_EC) #if !defined(HAVE_EC_CURVE_NIST2NID) @@ -245,7 +198,7 @@ IMPL_PKEY_GETTER(EC_KEY, ec) #undef IMPL_KEY_ACCESSOR3 #endif /* HAVE_OPAQUE_OPENSSL */ -#if defined(HAVE_AUTHENTICATED_ENCRYPTION) && !defined(EVP_CTRL_AEAD_GET_TAG) +#if !defined(EVP_CTRL_AEAD_GET_TAG) # define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG # define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG # define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index c22966df5a..6ec5e91c66 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -92,22 +92,40 @@ 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; } @@ -220,7 +238,7 @@ VALUE eOSSLError; /* * Convert to DER string */ -ID ossl_s_to_der; +static ID ossl_s_to_der; VALUE ossl_to_der(VALUE obj) @@ -248,18 +266,15 @@ static VALUE ossl_make_error(VALUE exc, const char *fmt, va_list args) { VALUE str = Qnil; - const char *msg; - long e; + unsigned long e; - e = ERR_peek_last_error(); if (fmt) { str = rb_vsprintf(fmt, args); } + e = ERR_peek_last_error(); if (e) { - if (dOSSL == Qtrue) /* FULL INFO */ - msg = ERR_error_string(e, NULL); - else - msg = ERR_reason_error_string(e); + const char *msg = ERR_reason_error_string(e); + if (NIL_P(str)) { if (msg) str = rb_str_new_cstr(msg); } @@ -267,8 +282,8 @@ ossl_make_error(VALUE exc, const char *fmt, va_list args) if (RSTRING_LEN(str)) rb_str_cat2(str, ": "); rb_str_cat2(str, msg ? msg : "(null)"); } + ossl_clear_error(); } - ossl_clear_error(); if (NIL_P(str)) str = rb_str_new(0, 0); return rb_exc_new3(exc, str); @@ -319,7 +334,8 @@ ossl_clear_error(void) * * See any remaining errors held in queue. * - * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation. + * Any errors you see here are probably due to a bug in Ruby's OpenSSL + * implementation. */ VALUE ossl_get_errors(void) @@ -382,6 +398,23 @@ ossl_debug_set(VALUE self, VALUE val) } /* + * call-seq + * OpenSSL.fips_mode -> true | false + */ +static VALUE +ossl_fips_mode_get(VALUE self) +{ + +#ifdef OPENSSL_FIPS + VALUE enabled; + enabled = FIPS_mode() ? Qtrue : Qfalse; + return enabled; +#else + return Qfalse; +#endif +} + +/* * call-seq: * OpenSSL.fips_mode = boolean -> boolean * @@ -414,6 +447,72 @@ ossl_fips_mode_set(VALUE self, VALUE enabled) #endif } +#if defined(OSSL_DEBUG) +#if !defined(LIBRESSL_VERSION_NUMBER) && \ + (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_NO_CRYPTO_MDEBUG) || \ + defined(CRYPTO_malloc_debug_init)) +/* + * call-seq: + * OpenSSL.mem_check_start -> nil + * + * Calls CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON). Starts tracking memory + * allocations. See also OpenSSL.print_mem_leaks. + * + * This is available only when built with a capable OpenSSL and --enable-debug + * configure option. + */ +static VALUE +mem_check_start(VALUE self) +{ + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + return Qnil; +} + +/* + * call-seq: + * OpenSSL.print_mem_leaks -> true | false + * + * For debugging the Ruby/OpenSSL library. Calls CRYPTO_mem_leaks_fp(stderr). + * Prints detected memory leaks to standard error. This cleans the global state + * up thus you cannot use any methods of the library after calling this. + * + * Returns +true+ if leaks detected, +false+ otherwise. + * + * This is available only when built with a capable OpenSSL and --enable-debug + * configure option. + * + * === Example + * OpenSSL.mem_check_start + * NOT_GCED = OpenSSL::PKey::RSA.new(256) + * + * END { + * GC.start + * OpenSSL.print_mem_leaks # will print the leakage + * } + */ +static VALUE +print_mem_leaks(VALUE self) +{ +#if OPENSSL_VERSION_NUMBER >= 0x10100000 + int ret; +#endif + + BN_CTX_free(ossl_bn_ctx); + ossl_bn_ctx = NULL; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000 + ret = CRYPTO_mem_leaks_fp(stderr); + if (ret < 0) + ossl_raise(eOSSLError, "CRYPTO_mem_leaks_fp"); + return ret ? Qfalse : Qtrue; +#else + CRYPTO_mem_leaks_fp(stderr); + return Qnil; +#endif +} +#endif +#endif + #if !defined(HAVE_OPENSSL_110_THREADING_API) /** * Stores locks needed for OpenSSL thread safety @@ -461,19 +560,11 @@ ossl_dyn_destroy_callback(struct CRYPTO_dynlock_value *l, const char *file, int OPENSSL_free(l); } -#ifdef HAVE_CRYPTO_THREADID_PTR static void ossl_threadid_func(CRYPTO_THREADID *id) { /* register native thread id */ CRYPTO_THREADID_set_pointer(id, (void *)rb_nativethread_self()); } -#else -static unsigned long ossl_thread_id(void) -{ - /* before OpenSSL 1.0, this is 'unsigned long' */ - return (unsigned long)rb_nativethread_self(); -} -#endif static void Init_ossl_locks(void) { @@ -491,11 +582,7 @@ static void Init_ossl_locks(void) rb_nativethread_lock_initialize(&ossl_locks[i]); } -#ifdef HAVE_CRYPTO_THREADID_PTR CRYPTO_THREADID_set_callback(ossl_threadid_func); -#else - CRYPTO_set_id_callback(ossl_thread_id); -#endif CRYPTO_set_locking_callback(ossl_lock_callback); CRYPTO_set_dynlock_create_callback(ossl_dyn_create_callback); CRYPTO_set_dynlock_lock_callback(ossl_dyn_lock_callback); @@ -505,7 +592,7 @@ static void Init_ossl_locks(void) /* * OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the - * OpenSSL[http://www.openssl.org/] library. + * OpenSSL[https://www.openssl.org/] library. * * = Examples * @@ -1057,7 +1144,7 @@ Init_openssl(void) rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER)); /* - * Boolean indicating whether OpenSSL is FIPS-enabled or not + * Boolean indicating whether OpenSSL is FIPS-capable or not */ rb_define_const(mOSSL, "OPENSSL_FIPS", #ifdef OPENSSL_FIPS @@ -1067,6 +1154,7 @@ Init_openssl(void) #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); /* @@ -1106,7 +1194,6 @@ Init_openssl(void) Init_ossl_ns_spki(); Init_ossl_pkcs12(); Init_ossl_pkcs7(); - Init_ossl_pkcs5(); Init_ossl_pkey(); Init_ossl_rand(); Init_ossl_ssl(); @@ -1114,15 +1201,41 @@ Init_openssl(void) Init_ossl_ocsp(); Init_ossl_engine(); Init_ossl_asn1(); -} + Init_ossl_kdf(); #if defined(OSSL_DEBUG) -/* - * Check if all symbols are OK with 'make LDSHARED=gcc all' - */ -int -main(int argc, char *argv[]) -{ - return 0; + /* + * For debugging Ruby/OpenSSL. Enable only when built with --enable-debug + */ +#if !defined(LIBRESSL_VERSION_NUMBER) && \ + (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_NO_CRYPTO_MDEBUG) || \ + defined(CRYPTO_malloc_debug_init)) + rb_define_module_function(mOSSL, "mem_check_start", mem_check_start, 0); + rb_define_module_function(mOSSL, "print_mem_leaks", print_mem_leaks, 0); + +#if defined(CRYPTO_malloc_debug_init) /* <= 1.0.2 */ + CRYPTO_malloc_debug_init(); +#endif + +#if defined(V_CRYPTO_MDEBUG_ALL) /* <= 1.0.2 */ + CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000 /* <= 1.0.2 */ + { + int i; + /* + * See crypto/ex_data.c; call def_get_class() immediately to avoid + * allocations. 15 is the maximum number that is used as the class index + * in OpenSSL 1.0.2. + */ + for (i = 0; i <= 15; i++) { + if (CRYPTO_get_ex_new_index(i, 0, (void *)"ossl-mdebug-dummy", 0, 0, 0) < 0) + rb_raise(rb_eRuntimeError, "CRYPTO_get_ex_new_index for " + "class index %d failed", i); + } + } +#endif +#endif +#endif } -#endif /* OSSL_DEBUG */ diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index 78eddd09b4..f08889b22e 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -56,29 +56,29 @@ extern VALUE eOSSLError; }\ } while (0) -#define OSSL_Check_Instance(obj, klass) do {\ - if (!rb_obj_is_instance_of((obj), (klass))) {\ - ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected instance of %"PRIsVALUE")",\ - rb_obj_class(obj), (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");\ - }\ -} while (0) +/* + * Type conversions + */ +#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(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{\ long len = RSTRING_LEN(str);\ @@ -115,7 +115,6 @@ int ossl_pem_passwd_cb(char *, int, int, void *); /* * ERRor messages */ -#define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error()) NORETURN(void ossl_raise(VALUE, const char *, ...)); /* Clear OpenSSL error queue. If dOSSL is set, rb_warn() them. */ void ossl_clear_error(void); @@ -123,7 +122,6 @@ 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); @@ -141,20 +139,9 @@ extern VALUE dOSSL; } \ } while (0) -#define OSSL_Warning(fmt, ...) do { \ - OSSL_Debug((fmt), ##__VA_ARGS__); \ - rb_warning((fmt), ##__VA_ARGS__); \ -} 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 /* @@ -173,13 +160,13 @@ void ossl_debug(const char *, ...); #include "ossl_ocsp.h" #include "ossl_pkcs12.h" #include "ossl_pkcs7.h" -#include "ossl_pkcs5.h" #include "ossl_pkey.h" #include "ossl_rand.h" #include "ossl_ssl.h" #include "ossl_version.h" #include "ossl_x509.h" #include "ossl_engine.h" +#include "ossl_kdf.h" void Init_openssl(void); diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index 1d3ee4ac18..efa6b78742 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -9,11 +9,9 @@ */ #include "ossl.h" -static VALUE join_der(VALUE enumerable); static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, int yield, long *num_read); static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self); -static VALUE ossl_asn1eoc_initialize(VALUE self); /* * DATE conversion @@ -25,7 +23,6 @@ asn1time_to_time(const ASN1_TIME *time) VALUE argv[6]; int count; - if (!time || !time->data) return Qnil; memset(&tm, 0, sizeof(struct tm)); switch (time->type) { @@ -72,7 +69,6 @@ asn1time_to_time(const ASN1_TIME *time) return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv); } -#if defined(HAVE_ASN1_TIME_ADJ) void ossl_time_split(VALUE time, time_t *sec, int *days) { @@ -88,13 +84,6 @@ ossl_time_split(VALUE time, time_t *sec, int *days) *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400))); } } -#else -time_t -time_to_time_t(VALUE time) -{ - return (time_t)NUM2TIMET(rb_Integer(time)); -} -#endif /* * STRING conversion @@ -155,13 +144,13 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) #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_infinite_length(o) rb_attr_get((o),sivINFINITE_LENGTH) +#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_infinite_length(o,v) rb_ivar_set((o),sivINFINITE_LENGTH,(v)) +#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v)) VALUE mASN1; VALUE eASN1Error; @@ -187,7 +176,7 @@ 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, sivINFINITE_LENGTH, sivUNUSED_BITS; +static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS; static ID id_each; /* @@ -213,13 +202,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, (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; } @@ -269,15 +260,10 @@ obj_to_asn1utime(VALUE time) time_t sec; ASN1_UTCTIME *t; -#if defined(HAVE_ASN1_TIME_ADJ) int off_days; ossl_time_split(time, &sec, &off_days); if (!(t = ASN1_UTCTIME_adj(NULL, sec, off_days, 0))) -#else - sec = time_to_time_t(time); - if (!(t = ASN1_UTCTIME_set(NULL, sec))) -#endif ossl_raise(eASN1Error, NULL); return t; @@ -289,15 +275,10 @@ obj_to_asn1gtime(VALUE time) time_t sec; ASN1_GENERALIZEDTIME *t; -#if defined(HAVE_ASN1_TIME_ADJ) int off_days; ossl_time_split(time, &sec, &off_days); if (!(t = ASN1_GENERALIZEDTIME_adj(NULL, sec, off_days, 0))) -#else - sec = time_to_time_t(time); - if (!(t = ASN1_GENERALIZEDTIME_set(NULL, sec))) -#endif ossl_raise(eASN1Error, NULL); return t; @@ -517,7 +498,7 @@ ossl_asn1_get_asn1type(VALUE obj) VALUE value, rflag; void *ptr; void (*free_func)(); - int tag, flag; + int tag; tag = ossl_asn1_default_tag(obj); value = ossl_asn1_get_value(obj); @@ -533,8 +514,7 @@ ossl_asn1_get_asn1type(VALUE obj) break; case V_ASN1_BIT_STRING: rflag = rb_attr_get(obj, sivUNUSED_BITS); - flag = NIL_P(rflag) ? -1 : NUM2INT(rflag); - ptr = obj_to_asn1bstr(value, flag); + ptr = obj_to_asn1bstr(value, NUM2INT(rflag)); free_func = ASN1_BIT_STRING_free; break; case V_ASN1_NULL: @@ -598,8 +578,8 @@ ossl_asn1_default_tag(VALUE obj) return NUM2INT(tag); tmp_class = rb_class_superclass(tmp_class); } - ossl_raise(eASN1Error, "universal tag for %"PRIsVALUE" not found", - rb_obj_class(obj)); + + return -1; } static int @@ -615,20 +595,6 @@ ossl_asn1_tag(VALUE obj) } static int -ossl_asn1_is_explicit(VALUE obj) -{ - VALUE s; - - s = ossl_asn1_get_tagging(obj); - if (NIL_P(s) || s == sym_IMPLICIT) - return 0; - else if (s == sym_EXPLICIT) - return 1; - else - ossl_raise(eASN1Error, "invalid tag default"); -} - -static int ossl_asn1_tag_class(VALUE obj) { VALUE s; @@ -663,12 +629,12 @@ ossl_asn1_class2sym(int tc) * call-seq: * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data * - * +value+: Please have a look at Constructive and Primitive to see how Ruby + * _value_: Please have a look at Constructive and Primitive to see how Ruby * types are mapped to ASN.1 types and vice versa. * - * +tag+: A +Number+ indicating the tag number. + * _tag_: An Integer indicating the tag number. * - * +tag_class+: A +Symbol+ indicating the tag class. Please cf. ASN1 for + * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for * possible values. * * == Example @@ -680,73 +646,85 @@ ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class) { if(!SYMBOL_P(tag_class)) ossl_raise(eASN1Error, "invalid tag class"); - if (tag_class == sym_UNIVERSAL && NUM2INT(tag) > 31) - ossl_raise(eASN1Error, "tag number for Universal too large"); ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); ossl_asn1_set_tag_class(self, tag_class); - ossl_asn1_set_infinite_length(self, Qfalse); + ossl_asn1_set_indefinite_length(self, Qfalse); return self; } static VALUE -join_der_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, str)) +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; -static VALUE -join_der(VALUE enumerable) -{ - VALUE str = rb_str_new(0, 0); - rb_block_call(enumerable, id_each, 0, 0, join_der_i, str); + 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 infinite length encodings. - * Infinite length encodings are not allowed in strict DER, so strictly - * speaking the result of such an encoding would be a BER-encoding. + * 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 ossl_asn1data_to_der(VALUE self) { - VALUE value, der, inf_length; - int tag, tag_class, is_cons = 0; - long length; - unsigned char *p; - - value = ossl_asn1_get_value(self); - if(rb_obj_is_kind_of(value, rb_cArray)){ - is_cons = 1; - value = join_der(value); - } - StringValue(value); + VALUE value = ossl_asn1_get_value(self); - tag = ossl_asn1_tag(self); - tag_class = ossl_asn1_tag_class(self); - inf_length = ossl_asn1_get_infinite_length(self); - if (inf_length == Qtrue) { - is_cons = 2; + 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); } - if((length = ASN1_object_size(is_cons, RSTRING_LENINT(value), tag)) <= 0) - ossl_raise(eASN1Error, NULL); - der = rb_str_new(0, length); - p = (unsigned char *)RSTRING_PTR(der); - ASN1_put_object(&p, is_cons, RSTRING_LENINT(value), tag, tag_class); - memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); - p += RSTRING_LEN(value); - ossl_str_adjust(der, p); - - return der; } static VALUE @@ -829,46 +807,33 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, int tag, VALUE tc, long *num_read) { VALUE value, asn1data, ary; - int infinite; + int indefinite; long available_len, off = *offset; - infinite = (j == 0x21); + indefinite = (j == 0x21); ary = rb_ary_new(); - available_len = infinite ? max_len : length; + 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; - rb_ary_push(ary, value); - if (infinite && - NUM2INT(ossl_asn1_get_tag(value)) == V_ASN1_EOC && + if (indefinite && + ossl_asn1_tag(value) == V_ASN1_EOC && ossl_asn1_get_tag_class(value) == sym_UNIVERSAL) { break; } + rb_ary_push(ary, value); } if (tc == sym_UNIVERSAL) { VALUE args[4]; - int not_sequence_or_set; - - not_sequence_or_set = tag != V_ASN1_SEQUENCE && tag != V_ASN1_SET; - - if (not_sequence_or_set) { - if (infinite) { - asn1data = rb_obj_alloc(cASN1Constructive); - } - else { - ossl_raise(eASN1Error, "invalid non-infinite tag"); - return Qnil; - } - } - else { - VALUE klass = *ossl_asn1_info[tag].klass; - asn1data = rb_obj_alloc(klass); - } + 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; @@ -880,10 +845,10 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc); } - if (infinite) - ossl_asn1_set_infinite_length(asn1data, Qtrue); + if (indefinite) + ossl_asn1_set_indefinite_length(asn1data, Qtrue); else - ossl_asn1_set_infinite_length(asn1data, Qfalse); + ossl_asn1_set_indefinite_length(asn1data, Qfalse); *offset = off; return asn1data; @@ -936,7 +901,8 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, inner_read += hlen; } else { - if ((j & 0x01) && (len == 0)) ossl_raise(eASN1Error, "Infinite length for primitive value"); + 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; } @@ -968,13 +934,13 @@ int_ossl_decode_sanity_check(long len, long read, long offset) * * 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 (Number) - * * offset: Current byte offset (Number) - * * header length: Combined length in bytes of the Tag and Length headers. (Number) - * * length: The overall remaining length of the entire data (Number) + * * 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) + * * tag: The current tag number (Integer) * * == Example * der = File.binread('asn1data.der') @@ -1004,9 +970,9 @@ ossl_asn1_traverse(VALUE self, VALUE obj) * 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+. + * 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') @@ -1034,9 +1000,9 @@ ossl_asn1_decode(VALUE self, VALUE obj) * 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+ + * 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 @@ -1071,19 +1037,19 @@ ossl_asn1_decode_all(VALUE self, VALUE obj) /* * call-seq: - * OpenSSL::ASN1::Primitive.new( value [, tag, tagging, tag_class ]) => Primitive + * OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive * - * +value+: is mandatory. + * _value_: is mandatory. * - * +tag+: optional, may be specified for tagged values. If no +tag+ is + * _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 + * _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 + * _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. * @@ -1096,9 +1062,12 @@ 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){ + 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)) @@ -1111,11 +1080,9 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) } if(!SYMBOL_P(tag_class)) ossl_raise(eASN1Error, "invalid tag class"); - if (tagging == sym_IMPLICIT && NUM2INT(tag) > 31) - ossl_raise(eASN1Error, "tag number for Universal too large"); } else{ - tag = INT2NUM(ossl_asn1_default_tag(self)); + tag = INT2NUM(default_tag); tagging = Qnil; tag_class = sym_UNIVERSAL; } @@ -1123,7 +1090,9 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) ossl_asn1_set_value(self, value); ossl_asn1_set_tagging(self, tagging); ossl_asn1_set_tag_class(self, tag_class); - ossl_asn1_set_infinite_length(self, Qfalse); + ossl_asn1_set_indefinite_length(self, Qfalse); + if (default_tag == V_ASN1_BIT_STRING) + rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0)); return self; } @@ -1131,7 +1100,7 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) static VALUE ossl_asn1eoc_initialize(VALUE self) { VALUE tag, tagging, tag_class, value; - tag = INT2NUM(ossl_asn1_default_tag(self)); + tag = INT2FIX(0); tagging = Qnil; tag_class = sym_UNIVERSAL; value = rb_str_new("", 0); @@ -1139,51 +1108,58 @@ ossl_asn1eoc_initialize(VALUE self) { ossl_asn1_set_value(self, value); ossl_asn1_set_tagging(self, tagging); ossl_asn1_set_tag_class(self, tag_class); - ossl_asn1_set_infinite_length(self, Qfalse); + ossl_asn1_set_indefinite_length(self, Qfalse); return self; } +static VALUE +ossl_asn1eoc_to_der(VALUE self) +{ + return rb_str_new("\0\0", 2); +} + /* * call-seq: * asn1.to_der => DER-encoded String * - * See ASN1Data#to_der for details. * + * See ASN1Data#to_der for details. */ static VALUE ossl_asn1prim_to_der(VALUE self) { ASN1_TYPE *asn1; - int tn, tc, explicit; - long len, 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)); + } - len = ASN1_object_size(1, i2d_ASN1_TYPE(asn1, NULL), tn); - if(!(buf = OPENSSL_malloc(len))){ + asn1 = ossl_asn1_get_asn1type(self); + alllen = i2d_ASN1_TYPE(asn1, NULL); + if (alllen < 0) { ASN1_TYPE_free(asn1); - ossl_raise(eASN1Error, "cannot alloc buffer"); + ossl_raise(eASN1Error, "i2d_ASN1_TYPE"); } - p = buf; - if (tc == V_ASN1_UNIVERSAL) { - i2d_ASN1_TYPE(asn1, &p); - } else if (explicit) { - ASN1_put_object(&p, 1, i2d_ASN1_TYPE(asn1, NULL), tn, tc); - i2d_ASN1_TYPE(asn1, &p); - } else { - 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); + i2d_ASN1_TYPE(asn1, &p0); ASN1_TYPE_free(asn1); - reallen = p - buf; - assert(reallen <= len); - str = ossl_buf2str((char *)buf, rb_long2int(reallen)); /* buf will be free in ossl_buf2str */ + assert(p0 - p1 == alllen); - 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)); } /* @@ -1195,92 +1171,41 @@ ossl_asn1prim_to_der(VALUE self) static VALUE ossl_asn1cons_to_der(VALUE self) { - int tag, tn, tc, explicit, constructed = 1; - int found_prim = 0, seq_len; - long length; - unsigned char *p; - VALUE value, str, inf_length; - - tn = NUM2INT(ossl_asn1_get_tag(self)); - tc = ossl_asn1_tag_class(self); - inf_length = ossl_asn1_get_infinite_length(self); - if (inf_length == Qtrue) { - VALUE ary, example; - constructed = 2; - if (rb_obj_class(self) == cASN1Sequence || - rb_obj_class(self) == cASN1Set) { - tag = ossl_asn1_default_tag(self); - } - else { /* must be a constructive encoding of a primitive value */ - ary = ossl_asn1_get_value(self); - if (!rb_obj_is_kind_of(ary, rb_cArray)) - ossl_raise(eASN1Error, "Constructive value must be an Array"); - /* Recursively descend until a primitive value is found. - The overall value of the entire constructed encoding - is of the type of the first primitive encoding to be - found. */ - while (!found_prim){ - example = rb_ary_entry(ary, 0); - if (rb_obj_is_kind_of(example, cASN1Primitive)){ - found_prim = 1; - } - else { - /* example is another ASN1Constructive */ - if (!rb_obj_is_kind_of(example, cASN1Constructive)){ - ossl_raise(eASN1Error, "invalid constructed encoding"); - return Qnil; /* dummy */ - } - ary = ossl_asn1_get_value(example); - } - } - tag = ossl_asn1_default_tag(example); - } - } - else { - if (rb_obj_class(self) == cASN1Constructive) - ossl_raise(eASN1Error, "Constructive shall only be used with infinite length"); - tag = ossl_asn1_default_tag(self); - } - explicit = ossl_asn1_is_explicit(self); - value = join_der(ossl_asn1_get_value(self)); - - seq_len = ASN1_object_size(constructed, RSTRING_LENINT(value), tag); - length = ASN1_object_size(constructed, seq_len, tn); - str = rb_str_new(0, length); - p = (unsigned char *)RSTRING_PTR(str); - if(tc == V_ASN1_UNIVERSAL) - ASN1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc); - else{ - if(explicit){ - ASN1_put_object(&p, constructed, seq_len, tn, tc); - ASN1_put_object(&p, constructed, RSTRING_LENINT(value), tag, V_ASN1_UNIVERSAL); - } - else{ - ASN1_put_object(&p, constructed, RSTRING_LENINT(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; } - } - memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); - p += RSTRING_LEN(value); - /* In this case we need an additional EOC (one for the explicit part and - * one for the Constructive itself. The EOC for the Constructive is - * supplied by the user, but that for the "explicit wrapper" must be - * added here. - */ - if (explicit && inf_length == Qtrue) { - ASN1_put_eoc(&p); + item = ossl_to_der_if_possible(item); + StringValue(item); + rb_str_append(str, item); } - 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 <i>block</i> once for each element in +self+, passing that element - * as parameter +asn1+. If no block is given, an enumerator is returned + * 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 @@ -1300,8 +1225,8 @@ ossl_asn1cons_each(VALUE 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 + * 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. @@ -1320,14 +1245,13 @@ ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln) return Qtrue; } -/* Document-method: OpenSSL::ASN1::ObjectId#sn +/* + * call-seq: + * oid.sn -> string + * oid.short_name -> string * * The short name of the ObjectId, as defined in <openssl/objects.h>. */ -/* Document-method: OpenSSL::ASN1::ObjectId#short_name - * - * +short_name+ is an alias to +sn+ - */ static VALUE ossl_asn1obj_get_sn(VALUE self) { @@ -1341,14 +1265,13 @@ ossl_asn1obj_get_sn(VALUE self) return ret; } -/* Document-method: OpenSSL::ASN1::ObjectId#ln +/* + * call-seq: + * oid.ln -> string + * oid.long_name -> string * * The long name of the ObjectId, as defined in <openssl/objects.h>. */ -/* Document-method: OpenSSL::ASN1::ObjectId#long_name - * - * +long_name+ is an alias to +ln+ - */ static VALUE ossl_asn1obj_get_ln(VALUE self) { @@ -1362,23 +1285,48 @@ ossl_asn1obj_get_ln(VALUE self) return ret; } -/* Document-method: OpenSSL::ASN1::ObjectId#oid +static VALUE +asn1obj_get_oid_i(VALUE vobj) +{ + ASN1_OBJECT *a1obj = (void *)vobj; + 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(eASN1Error, "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(eASN1Error, "OBJ_obj2txt"); + } + rb_str_set_len(str, len); + return str; +} + +/* + * call-seq: + * oid.oid -> string * - * The object identifier as a +String+, e.g. "1.2.3.4.5" + * 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 = obj_to_asn1obj(ossl_asn1_get_value(self)); + str = rb_protect(asn1obj_get_oid_i, (VALUE)a1obj, &state); ASN1_OBJECT_free(a1obj); - - return rb_str_new2(buf); + if (state) + rb_jump_tag(state); + return str; } #define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \ @@ -1431,7 +1379,7 @@ Init_ossl_asn1(void) sivTAG = rb_intern("@tag"); sivTAGGING = rb_intern("@tagging"); sivTAG_CLASS = rb_intern("@tag_class"); - sivINFINITE_LENGTH = rb_intern("@infinite_length"); + sivINDEFINITE_LENGTH = rb_intern("@indefinite_length"); sivUNUSED_BITS = rb_intern("@unused_bits"); /* @@ -1457,24 +1405,21 @@ Init_ossl_asn1(void) * == 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 + * 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 + * 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. - * Primitive values that are encoded with "infinite length" are typically - * constructed (their values come in multiple chunks) and are therefore - * represented by instances of Constructive. The value of an Constructive - * is always an Array. + * opposed to "primitive" encodings with just one single value. The value of + * an Constructive is always an Array. * * ==== ASN1::Set and ASN1::Sequence * @@ -1491,18 +1436,18 @@ Init_ossl_asn1(void) * 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+ + * == 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 + * 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+ + * == 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+ + * 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) @@ -1604,9 +1549,9 @@ Init_ossl_asn1(void) * * 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 + * * _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. @@ -1615,9 +1560,9 @@ Init_ossl_asn1(void) * * 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 + * * _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 @@ -1628,13 +1573,13 @@ Init_ossl_asn1(void) * der = seq.to_der * asn1 = OpenSSL::ASN1.decode(der) * # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0 - * # @infinite_length=false, + * # @indefinite_length=false, * # @tag=16, * # @tag_class=:UNIVERSAL, * # @tagging=nil, * # @value= * # [#<OpenSSL::ASN1::ASN1Data:0x87326f4 - * # @infinite_length=false, + * # @indefinite_length=false, * # @tag=0, * # @tag_class=:CONTEXT_SPECIFIC, * # @value="\x01">]> @@ -1651,18 +1596,18 @@ Init_ossl_asn1(void) * der = seq.to_der * asn1 = OpenSSL::ASN1.decode(der) * # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0 - * # @infinite_length=false, + * # @indefinite_length=false, * # @tag=16, * # @tag_class=:UNIVERSAL, * # @tagging=nil, * # @value= * # [#<OpenSSL::ASN1::ASN1Data:0x87326f4 - * # @infinite_length=false, + * # @indefinite_length=false, * # @tag=0, * # @tag_class=:CONTEXT_SPECIFIC, * # @value= * # [#<OpenSSL::ASN1::Integer:0x85bf308 - * # @infinite_length=false, + * # @indefinite_length=false, * # @tag=2, * # @tag_class=:UNIVERSAL * # @tagging=nil, @@ -1678,73 +1623,75 @@ Init_ossl_asn1(void) */ rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0); /* - * A +Number+ representing the tag number of this ASN1Data. Never +nil+. + * 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+. + * 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+ indicating whether the encoding was infinite - * length (in the case of parsing) or whether an infinite length encoding - * shall be used (in the encoding case). - * In DER, every value has a finite length associated with it. But in - * scenarios where large amounts of data need to be transferred it - * might be desirable to have some kind of streaming support available. + * 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. Infinite length encodings are always constructed. + * 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 infinite length + * (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("infinite_length"), 1, 1, 0); + 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 infinite length encodings, thus it is not - * possible to set the +infinite_length+ attribute for Primitive and its - * sub-classes. + * 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 a +Boolean+ - * * OpenSSL::ASN1::Integer <=> +value+ is a +Number+ - * * 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 a +Number+ - * * 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::EndOfContent <=> _value_ is always +nil+ + * * OpenSSL::ASN1::Boolean <=> _value_ is +true+ or +false+ + * * OpenSSL::ASN1::Integer <=> _value_ is an Integer + * * 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 Integer + * * 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+. + * _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 * @@ -1753,15 +1700,15 @@ Init_ossl_asn1(void) * 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+. + * * _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+. + * constructor takes at least one parameter, the _value_. * * === Creating EndOfContent * eoc = OpenSSL::ASN1::EndOfContent.new @@ -1775,19 +1722,20 @@ Init_ossl_asn1(void) /* * 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 + * _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+. + * 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 * @@ -1809,48 +1757,13 @@ Init_ossl_asn1(void) * int = OpenSSL::ASN1::Integer.new(1) * str = OpenSSL::ASN1::PrintableString.new('abc') * set = OpenSSL::ASN1::Set.new( [ int, str ] ) - * - * == Infinite length primitive values - * - * The only case where Constructive is used directly is for infinite - * length encodings of primitive values. These encodings are always - * constructed, with the contents of the +value+ +Array+ being either - * UNIVERSAL non-infinite length partial encodings of the actual value - * or again constructive encodings with infinite length (i.e. infinite - * length primitive encodings may be constructed recursively with another - * infinite length value within an already infinite length value). Each - * partial encoding must be of the same UNIVERSAL type as the overall - * encoding. The value of the overall encoding consists of the - * concatenation of each partial encoding taken in sequence. The +value+ - * array of the outer infinite length value must end with a - * OpenSSL::ASN1::EndOfContent instance. - * - * Please note that it is not possible to encode Constructive without - * the +infinite_length+ attribute being set to +true+, use - * OpenSSL::ASN1::Sequence or OpenSSL::ASN1::Set in these cases instead. - * - * === Example - Infinite length OCTET STRING - * partial1 = OpenSSL::ASN1::OctetString.new("\x01") - * partial2 = OpenSSL::ASN1::OctetString.new("\x02") - * inf_octets = OpenSSL::ASN1::Constructive.new( [ partial1, - * partial2, - * OpenSSL::ASN1::EndOfContent.new ], - * OpenSSL::ASN1::OCTET_STRING, - * nil, - * :UNIVERSAL ) - * # The real value of inf_octets is "\x01\x02", i.e. the concatenation - * # of partial1 and partial2 - * inf_octets.infinite_length = true - * der = inf_octets.to_der - * asn1 = OpenSSL::ASN1.decode(der) - * puts asn1.infinite_length # => true */ 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 + * _tagging_ is not set when a ASN.1 structure is parsed using * OpenSSL::ASN1.decode. */ rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue); @@ -1907,6 +1820,7 @@ do{\ 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_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC)); diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h index d6a170c86c..939a96ce74 100644 --- a/ext/openssl/ossl_asn1.h +++ b/ext/openssl/ossl_asn1.h @@ -14,15 +14,11 @@ * ASN1_DATE conversions */ VALUE asn1time_to_time(const ASN1_TIME *); -#if defined(HAVE_ASN1_TIME_ADJ) /* Splits VALUE to seconds and offset days. VALUE is typically a Time or an * Integer. This is used when updating ASN1_*TIME with ASN1_TIME_adj() or * X509_time_adj_ex(). We can't use ASN1_TIME_set() and X509_time_adj() because * they have the Year 2038 issue on sizeof(time_t) == 4 environment */ void ossl_time_split(VALUE, time_t *, int *); -#else -time_t time_to_time_t(VALUE); -#endif /* * ASN1_STRING conversions diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c index 8fa0b6966d..42833d901a 100644 --- a/ext/openssl/ossl_bio.c +++ b/ext/openssl/ossl_bio.c @@ -26,32 +26,17 @@ ossl_obj2bio(volatile VALUE *pobj) } 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 2c3d952b38..da68c5e5a2 100644 --- a/ext/openssl/ossl_bio.h +++ b/ext/openssl/ossl_bio.h @@ -11,8 +11,6 @@ #define _OSSL_BIO_H_ BIO *ossl_obj2bio(volatile VALUE *); -VALUE ossl_membio2str0(BIO*); 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 aa0f2c605f..94ef6fd6f7 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -26,11 +26,6 @@ } \ } while (0) -#define SafeGetBN(obj, bn) do { \ - OSSL_Check_Kind((obj), cBN); \ - GetBN((obj), (bn)); \ -} while (0) - static void ossl_bn_free(void *ptr) { @@ -176,8 +171,7 @@ ossl_bn_alloc(VALUE klass) return obj; } -/* Document-method: OpenSSL::BN.new - * +/* * call-seq: * OpenSSL::BN.new => aBN * OpenSSL::BN.new(bn) => aBN @@ -185,7 +179,7 @@ ossl_bn_alloc(VALUE klass) * OpenSSL::BN.new(string) => aBN * OpenSSL::BN.new(string, 0 | 2 | 10 | 16) => aBN * - * Construct a new OpenSSL BigNum object. + * Construct a new OpenSSL BIGNUM object. */ static VALUE ossl_bn_initialize(int argc, VALUE *argv, VALUE self) @@ -250,7 +244,7 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) * bn.to_s(base) => string * * === Parameters - * * +base+ - integer + * * _base_ - Integer * Valid values: * * 0 - MPI * * 2 - binary @@ -377,6 +371,21 @@ BIGNUM_BOOL1(is_one) */ 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) \ @@ -498,7 +507,6 @@ BIGNUM_2c(mod_sqr) BIGNUM_2c(mod_inverse) /* - * Document-method: OpenSSL::BN#/ * call-seq: * bn1 / bn2 => [result, remainder] * @@ -614,12 +622,11 @@ BIGNUM_BIT(clear_bit) */ BIGNUM_BIT(mask_bits) -/* Document-method: OpenSSL::BN#bit_set? +/* * call-seq: * bn.bit_set?(bit) => true | false * - * Returns boolean of whether +bit+ is set. - * Bitwise operations for openssl BIGNUMs. + * 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) @@ -774,15 +781,15 @@ BIGNUM_RAND_RANGE(pseudo_rand) * call-seq: * BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn * - * Generates a random prime number of bit length +bits+. If +safe+ is true, - * generates a safe prime. If +add+ is specified, generates a prime that + * 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) @@ -856,6 +863,37 @@ ossl_bn_copy(VALUE self, VALUE other) return self; } +/* + * call-seq: + * +bn -> aBN + */ +static VALUE +ossl_bn_uplus(VALUE self) +{ + return self; +} + +/* + * 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; +} + #define BIGNUM_CMP(func) \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other) \ @@ -888,7 +926,7 @@ BIGNUM_CMP(ucmp) * call-seq: * bn == obj => true or false * - * Returns +true+ only if +obj+ has the same value as +bn+. Contrast this + * 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 @@ -913,7 +951,7 @@ ossl_bn_eq(VALUE self, VALUE other) * 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>big</i>. Contrast this + * <code>OpenSSL::BN</code> with the same value as <i>bn</i>. Contrast this * with OpenSSL::BN#==, which performs type conversions. */ static VALUE @@ -964,12 +1002,12 @@ ossl_bn_hash(VALUE self) * bn.prime? => true | false * bn.prime?(checks) => true | false * - * Performs a Miller-Rabin probabilistic primality test with +checks+ - * iterations. If +nchecks+ is not specified, a number of iterations is used + * Performs a Miller-Rabin probabilistic primality test with _checks_ + * iterations. If _checks_ is not specified, a number of iterations is used * that yields a false positive rate of at most 2^-80 for random input. * * === Parameters - * * +checks+ - integer + * * _checks_ - integer */ static VALUE ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) @@ -1004,8 +1042,8 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) * first attempts trial divisions with some small primes. * * === Parameters - * * +checks+ - integer - * * +trial_div+ - boolean + * * _checks_ - integer + * * _trial_div_ - boolean */ static VALUE ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self) @@ -1059,7 +1097,7 @@ Init_ossl_bn(void) 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?) */ @@ -1068,6 +1106,9 @@ Init_ossl_bn(void) 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, "+", ossl_bn_add, 1); rb_define_method(cBN, "-", ossl_bn_sub, 1); rb_define_method(cBN, "*", ossl_bn_mul, 1); @@ -1101,6 +1142,7 @@ Init_ossl_bn(void) 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 diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index c2f0927a75..bfa76c1aab 100644 --- a/ext/openssl/ossl_cipher.c +++ b/ext/openssl/ossl_cipher.c @@ -26,10 +26,6 @@ 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 @@ -53,7 +49,7 @@ static const rb_data_type_t ossl_cipher_type = { * PUBLIC */ const EVP_CIPHER * -GetCipherPtr(VALUE obj) +ossl_evp_get_cipherbyname(VALUE obj) { if (rb_obj_is_kind_of(obj, cCipher)) { EVP_CIPHER_CTX *ctx; @@ -108,7 +104,7 @@ ossl_cipher_alloc(VALUE klass) * call-seq: * Cipher.new(string) -> cipher * - * The string must contain a valid cipher name like "AES-128-CBC" or "3DES". + * The string must be a valid cipher name like "AES-128-CBC" or "3DES". * * A list of cipher names is available by calling OpenSSL::Cipher.ciphers. */ @@ -146,7 +142,7 @@ ossl_cipher_copy(VALUE self, VALUE other) if (!ctx1) { AllocCipher(self, ctx1); } - SafeGetCipher(other, ctx2); + GetCipher(other, ctx2); if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1) ossl_raise(eCipherError, NULL); @@ -296,9 +292,9 @@ ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self) * OpenSSL::PKCS5 instead. * * === Parameters - * * +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' + * * _salt_ must be an 8 byte string if provided. + * * _iterations_ is an integer with a default of 2048. + * * _digest_ is a Digest object that defaults to 'MD5' * * A minimum of 1000 iterations is recommended. * @@ -321,7 +317,7 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) salt = (unsigned char *)RSTRING_PTR(vsalt); } iter = NIL_P(viter) ? 2048 : NUM2INT(viter); - digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest); + digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_get_digestbyname(vdigest); GetCipher(self, ctx); EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt, (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv); @@ -365,12 +361,12 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p * cipher.update(data [, buffer]) -> string or buffer * * Encrypts data in a streaming fashion. Hand consecutive blocks of data - * to the +update+ method in order to encrypt it. Returns the encrypted + * 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. + * If _buffer_ is given, the encryption/decryption result will be written to + * it. _buffer_ will be resized automatically. */ static VALUE ossl_cipher_update(int argc, VALUE *argv, VALUE self) @@ -512,10 +508,8 @@ ossl_cipher_set_iv(VALUE self, VALUE iv) StringValue(iv); GetCipher(self, ctx); -#if defined(HAVE_AUTHENTICATED_ENCRYPTION) if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); -#endif if (!iv_len) iv_len = EVP_CIPHER_CTX_iv_length(ctx); if (RSTRING_LEN(iv) != iv_len) @@ -541,14 +535,9 @@ ossl_cipher_is_authenticated(VALUE self) GetCipher(self, ctx); -#if defined(HAVE_AUTHENTICATED_ENCRYPTION) return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse; -#else - return Qfalse; -#endif } -#ifdef HAVE_AUTHENTICATED_ENCRYPTION /* * call-seq: * cipher.auth_data = string -> string @@ -594,8 +583,8 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data) * Gets the authentication tag generated by Authenticated Encryption Cipher * modes (GCM for example). This tag may be stored along with the ciphertext, * then set on the decryption cipher to authenticate the contents of the - * ciphertext against changes. If the optional integer parameter +tag_len+ is - * given, the returned tag will be +tag_len+ bytes long. If the parameter is + * ciphertext against changes. If the optional integer parameter _tag_len_ is + * given, the returned tag will be _tag_len_ bytes long. If the parameter is * omitted, the default length of 16 bytes or the length previously set by * #auth_tag_len= will be used. For maximum security, the longest possible * should be chosen. @@ -631,13 +620,11 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self) * call-seq: * cipher.auth_tag = string -> string * - * Sets the authentication tag to verify the contents of the - * ciphertext. The tag must be set after calling Cipher#decrypt, - * Cipher#key= and Cipher#iv=, but before assigning the associated - * authenticated data using Cipher#auth_data= and of course, before - * decrypting any of the ciphertext. After all decryption is - * performed, the tag is verified automatically in the call to - * Cipher#final. + * Sets the authentication tag to verify the integrity of the ciphertext. + * This can be called only when the cipher supports AE. The tag must be set + * after calling Cipher#decrypt, Cipher#key= and Cipher#iv=, but before + * calling Cipher#final. After all decryption is performed, the tag is + * verified automatically in the call to Cipher#final. * * For OCB mode, the tag length must be supplied with #auth_tag_len= * beforehand. @@ -722,13 +709,6 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length) return iv_length; } -#else -#define ossl_cipher_set_auth_data rb_f_notimplement -#define ossl_cipher_get_auth_tag rb_f_notimplement -#define ossl_cipher_set_auth_tag rb_f_notimplement -#define ossl_cipher_set_auth_tag_len rb_f_notimplement -#define ossl_cipher_set_iv_length rb_f_notimplement -#endif /* * call-seq: @@ -806,10 +786,8 @@ ossl_cipher_iv_length(VALUE self) int len = 0; GetCipher(self, ctx); -#if defined(HAVE_AUTHENTICATED_ENCRYPTION) if (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx); -#endif if (!len) len = EVP_CIPHER_CTX_iv_length(ctx); @@ -1020,9 +998,9 @@ Init_ossl_cipher(void) * encryption and later decryption, the OpenSSL library still requires a * value to be set - "" may be used in case none is available. * - * An example using the GCM (Galois/Counter Mode). 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 + * 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. * * cipher = OpenSSL::Cipher::AES.new(128, :GCM).encrypt @@ -1033,8 +1011,8 @@ Init_ossl_cipher(void) * encrypted = cipher.update(data) + cipher.final * tag = cipher.auth_tag # produces 16 bytes tag by default * - * Now you are the receiver. You know the +key+ and have received +nonce+, - * +auth_data+, +encrypted+ and +tag+ through an untrusted network. Note + * 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 @@ -1055,7 +1033,7 @@ Init_ossl_cipher(void) eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError); 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); diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h index c444089fc2..2392d41c6a 100644 --- a/ext/openssl/ossl_cipher.h +++ b/ext/openssl/ossl_cipher.h @@ -13,7 +13,7 @@ extern VALUE cCipher; extern VALUE eCipherError; -const EVP_CIPHER *GetCipherPtr(VALUE); +const EVP_CIPHER *ossl_evp_get_cipherbyname(VALUE); VALUE ossl_cipher_new(const EVP_CIPHER *); void Init_ossl_cipher(void); diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c index fdafda0074..112ce33647 100644 --- a/ext/openssl/ossl_digest.c +++ b/ext/openssl/ossl_digest.c @@ -15,10 +15,6 @@ 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 @@ -46,7 +42,7 @@ static const rb_data_type_t ossl_digest_type = { * Public */ const EVP_MD * -GetDigestPtr(VALUE obj) +ossl_evp_get_digestbyname(VALUE obj) { const EVP_MD *md; ASN1_OBJECT *oid = NULL; @@ -65,7 +61,7 @@ GetDigestPtr(VALUE obj) } else { EVP_MD_CTX *ctx; - SafeGetDigest(obj, ctx); + GetDigest(obj, ctx); md = EVP_MD_CTX_md(ctx); } @@ -106,15 +102,15 @@ VALUE ossl_digest_update(VALUE, VALUE); * call-seq: * Digest.new(string [, data]) -> Digest * - * Creates a Digest instance based on +string+, which is either the ln + * Creates a Digest instance based on _string_, which is either the ln * (long name) or sn (short name) of a supported digest algorithm. * - * If +data+ (a +String+) is given, it is used as the initial input to the + * If _data_ (a String) is given, it is used as the initial input to the * Digest instance, i.e. * * digest = OpenSSL::Digest.new('sha256', 'digestdata') * - * is equal to + * is equivalent to * * digest = OpenSSL::Digest.new('sha256') * digest.update('digestdata') @@ -127,7 +123,7 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self) VALUE type, data; rb_scan_args(argc, argv, "11", &type, &data); - md = GetDigestPtr(type); + md = ossl_evp_get_digestbyname(type); if (!NIL_P(data)) StringValue(data); TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx); @@ -158,7 +154,7 @@ ossl_digest_copy(VALUE self, VALUE other) if (!ctx1) ossl_raise(eDigestError, "EVP_MD_CTX_new"); } - SafeGetDigest(other, ctx2); + GetDigest(other, ctx2); if (!EVP_MD_CTX_copy(ctx1, ctx2)) { ossl_raise(eDigestError, NULL); @@ -448,7 +444,7 @@ Init_ossl_digest(void) rb_define_alloc_func(cDigest, ossl_digest_alloc); rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1); - rb_define_copy_func(cDigest, ossl_digest_copy); + rb_define_method(cDigest, "initialize_copy", ossl_digest_copy, 1); rb_define_method(cDigest, "reset", ossl_digest_reset, 0); rb_define_method(cDigest, "update", ossl_digest_update, 1); rb_define_alias(cDigest, "<<", "update"); diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h index 512f7d3a39..50bf5666a3 100644 --- a/ext/openssl/ossl_digest.h +++ b/ext/openssl/ossl_digest.h @@ -13,7 +13,7 @@ extern VALUE cDigest; extern VALUE eDigestError; -const EVP_MD *GetDigestPtr(VALUE); +const EVP_MD *ossl_evp_get_digestbyname(VALUE); VALUE ossl_digest_new(const EVP_MD *); void Init_ossl_digest(void); diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c index e840bfd92c..d69b5dcac5 100644 --- a/ext/openssl/ossl_engine.c +++ b/ext/openssl/ossl_engine.c @@ -25,10 +25,6 @@ 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 @@ -72,14 +68,13 @@ static const rb_data_type_t ossl_engine_type = { 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; -/* Document-method: OpenSSL::Engine.load - * +/* * call-seq: - * load(enginename = nil) + * 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 + * 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. * */ @@ -153,9 +148,9 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ } -/* Document-method: OpenSSL::Engine.cleanup +/* * call-seq: - * OpenSSL::Engine.cleanup + * 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. @@ -169,7 +164,9 @@ ossl_engine_s_cleanup(VALUE self) return Qnil; } -/* Document-method: OpenSSL::Engine.engines +/* + * call-seq: + * OpenSSL::Engine.engines -> [engine, ...] * * Returns an array of currently loaded engines. */ @@ -193,17 +190,16 @@ ossl_engine_s_engines(VALUE klass) return ary; } -/* Document-method: OpenSSL::Engine.by_id - * +/* * call-seq: - * by_id(name) -> engine + * OpenSSL::Engine.by_id(name) -> engine * - * Fetch the engine as specified by the +id+ String + * 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 + * See OpenSSL::Engine.engines for the currently loaded engines. */ static VALUE ossl_engine_s_by_id(VALUE klass, VALUE id) @@ -227,9 +223,11 @@ ossl_engine_s_by_id(VALUE klass, VALUE id) return obj; } -/* Document-method: OpenSSL::Engine#id +/* + * call-seq: + * engine.id -> string * - * Get the id for this engine + * Gets the id for this engine. * * OpenSSL::Engine.load * OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...] @@ -244,9 +242,11 @@ ossl_engine_get_id(VALUE self) return rb_str_new2(ENGINE_get_id(e)); } -/* Document-method: OpenSSL::Engine#name +/* + * call-seq: + * engine.name -> string * - * Get the descriptive name for this engine + * Get the descriptive name for this engine. * * OpenSSL::Engine.load * OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...] @@ -262,7 +262,9 @@ ossl_engine_get_name(VALUE self) return rb_str_new2(ENGINE_get_name(e)); } -/* Document-method: OpenSSL::Engine#finish +/* + * call-seq: + * engine.finish -> nil * * Releases all internal structural references for this engine. * @@ -279,13 +281,12 @@ ossl_engine_finish(VALUE self) return Qnil; } -/* Document-method: OpenSSL::Engine#cipher - * +/* * call-seq: * engine.cipher(name) -> OpenSSL::Cipher * - * This returns an OpenSSL::Cipher by +name+, if it is available in this - * engine. + * 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. * @@ -312,12 +313,11 @@ ossl_engine_get_cipher(VALUE self, VALUE name) return ossl_cipher_new(ciph); } -/* Document-method: OpenSSL::Engine#digest - * +/* * call-seq: * engine.digest(name) -> OpenSSL::Digest * - * This returns an OpenSSL::Digest by +name+. + * Returns a new instance of OpenSSL::Digest by _name_. * * Will raise an EngineError if the digest is unavailable. * @@ -345,12 +345,11 @@ ossl_engine_get_digest(VALUE self, VALUE name) return ossl_digest_new(md); } -/* Document-method: OpenSSL::Engine#load_private_key - * +/* * call-seq: * engine.load_private_key(id = nil, data = nil) -> OpenSSL::PKey * - * Loads the given private key by +id+ and +data+. + * Loads the given private key identified by _id_ and _data_. * * An EngineError is raised of the OpenSSL::PKey is unavailable. * @@ -375,12 +374,11 @@ ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self) return obj; } -/* Document-method: OpenSSL::Engine#load_public_key - * +/* * call-seq: * engine.load_public_key(id = nil, data = nil) -> OpenSSL::PKey * - * Loads the given private key by +id+ and +data+. + * Loads the given public key identified by _id_ and _data_. * * An EngineError is raised of the OpenSSL::PKey is unavailable. * @@ -403,16 +401,15 @@ ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self) return ossl_pkey_new(pkey); } -/* Document-method: OpenSSL::Engine#set_default - * +/* * call-seq: * engine.set_default(flag) * - * Set the defaults for this engine with the given +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 + * _flag_ can be one of the following, other flags are available depending on * your OS. * * [All flags] 0xFFFF @@ -432,14 +429,13 @@ ossl_engine_set_default(VALUE self, VALUE flag) return Qtrue; } -/* Document-method: OpenSSL::Engine#ctrl_cmd - * +/* * call-seq: * engine.ctrl_cmd(command, value = nil) -> engine * - * Send the given +command+ to this engine. + * Sends the given _command_ to this engine. * - * Raises an EngineError if the +command+ fails. + * Raises an EngineError if the command fails. */ static VALUE ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self) @@ -469,7 +465,9 @@ ossl_engine_cmd_flag_to_name(int flag) } } -/* Document-method: OpenSSL::Engine#cmds +/* + * call-seq: + * engine.cmds -> [["name", "description", "flags"], ...] * * Returns an array of command definitions for the current engine */ @@ -495,9 +493,11 @@ ossl_engine_get_cmds(VALUE self) return ary; } -/* Document-method: OpenSSL::Engine#inspect +/* + * call-seq: + * engine.inspect -> string * - * Pretty print this engine + * Pretty prints this engine. */ static VALUE ossl_engine_inspect(VALUE self) diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c index 270979ed92..564dcab522 100644 --- a/ext/openssl/ossl_hmac.c +++ b/ext/openssl/ossl_hmac.c @@ -19,10 +19,6 @@ 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 @@ -110,7 +106,7 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) StringValue(key); GetHMAC(self, ctx); HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key), - GetDigestPtr(digest), NULL); + ossl_evp_get_digestbyname(digest), NULL); return self; } @@ -124,7 +120,7 @@ ossl_hmac_copy(VALUE self, VALUE other) if (self == other) return self; GetHMAC(self, ctx1); - SafeGetHMAC(other, ctx2); + GetHMAC(other, ctx2); if (!HMAC_CTX_copy(ctx1, ctx2)) ossl_raise(eHMACError, "HMAC_CTX_copy"); @@ -135,7 +131,7 @@ ossl_hmac_copy(VALUE self, VALUE other) * call-seq: * hmac.update(string) -> self * - * Returns +self+ updated with the message to be authenticated. + * Returns _hmac_ updated with the message to be authenticated. * Can be called repeatedly with chunks of the message. * * === Example @@ -234,7 +230,7 @@ ossl_hmac_hexdigest(VALUE self) * call-seq: * hmac.reset -> self * - * Returns +self+ as it was when it was first initialized, with all processed + * Returns _hmac_ as it was when it was first initialized, with all processed * data cleared from it. * * === Example @@ -264,16 +260,16 @@ ossl_hmac_reset(VALUE self) * call-seq: * HMAC.digest(digest, key, data) -> aString * - * Returns the authentication code as a binary string. The +digest+ parameter - * must be an instance of OpenSSL::Digest. + * 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' - * digest = OpenSSL::Digest.new('sha1') * - * hmac = OpenSSL::HMAC.digest(digest, key, data) + * hmac = OpenSSL::HMAC.digest('sha1', key, data) * #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9" * */ @@ -285,8 +281,9 @@ ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) StringValue(key); StringValue(data); - buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), - (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); + buf = HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key), + RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data), NULL, &buf_len); return rb_str_new((const char *)buf, buf_len); } @@ -295,16 +292,16 @@ ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) * call-seq: * HMAC.hexdigest(digest, key, data) -> aString * - * Returns the authentication code as a hex-encoded string. The +digest+ - * parameter must be an instance of OpenSSL::Digest. + * 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' - * digest = OpenSSL::Digest.new('sha1') * - * hmac = OpenSSL::HMAC.hexdigest(digest, key, data) + * hmac = OpenSSL::HMAC.hexdigest('sha1', key, data) * #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" * */ @@ -318,9 +315,9 @@ ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) StringValue(key); StringValue(data); - if (!HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), - (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), - buf, &buf_len)) + if (!HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key), + RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data), buf, &buf_len)) ossl_raise(eHMACError, "HMAC"); ret = rb_str_new(NULL, buf_len * 2); @@ -377,7 +374,7 @@ Init_ossl_hmac(void) 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); diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c new file mode 100644 index 0000000000..9fa42e174a --- /dev/null +++ b/ext/openssl/ossl_kdf.c @@ -0,0 +1,221 @@ +/* + * Ruby/OpenSSL Project + * Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors + */ +#include "ossl.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://tools.ietf.org/html/rfc2898#section-5.2). + * + * === Parameters + * pass :: The passphrase. + * 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; + 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_get_digestbyname(kwargs[3]); + + 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://tools.ietf.org/html/rfc7914#section-2) states + * that using values r=8 and p=1 appears to yield good results. + * + * See RFC 7914 (https://tools.ietf.org/html/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 + +void +Init_ossl_kdf(void) +{ +#if 0 + mOSSL = rb_define_module("OpenSSL"); + eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); +#endif + + /* + * 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 + * + * == 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::SHA256.new + * 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 compare two + * values, the following could be used: + * + * def eql_time_cmp(a, b) + * unless a.length == b.length + * return false + * end + * cmp = b.bytes + * result = 0 + * a.bytes.each_with_index {|c,i| + * result |= c ^ cmp[i] + * } + * result == 0 + * end + * + * Please note that the premature return in case of differing lengths + * typically does not leak valuable information - when using PBKDF2, the + * length of the values to be compared is of fixed size. + */ + 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 +} 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 4d978bd009..f17b9509c6 100644 --- a/ext/openssl/ossl_ns_spki.c +++ b/ext/openssl/ossl_ns_spki.c @@ -73,7 +73,7 @@ ossl_spki_alloc(VALUE klass) * SPKI.new([request]) => spki * * === Parameters - * * +request+ - optional raw request, either in PEM or DER format. + * * _request_ - optional raw request, either in PEM or DER format. */ static VALUE ossl_spki_initialize(int argc, VALUE *argv, VALUE self) @@ -198,7 +198,7 @@ ossl_spki_get_public_key(VALUE self) * spki.public_key = pub => pkey * * === Parameters - * * +pub+ - the public key to be set for this instance + * * _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 @@ -243,7 +243,7 @@ ossl_spki_get_challenge(VALUE self) * spki.challenge = str => string * * === Parameters - * * +str+ - the challenge string to be set for this instance + * * _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. @@ -268,8 +268,8 @@ ossl_spki_set_challenge(VALUE self, VALUE str) * 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 + * * _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 @@ -284,7 +284,7 @@ ossl_spki_sign(VALUE self, VALUE key, VALUE digest) const EVP_MD *md; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); GetSPKI(self, spki); if (!NETSCAPE_SPKI_sign(spki, pkey, md)) { ossl_raise(eSPKIError, NULL); @@ -298,7 +298,7 @@ ossl_spki_sign(VALUE self, VALUE key, VALUE digest) * spki.verify(key) => boolean * * === Parameters - * * +key+ - the public key to be used for verifying the SPKI signature + * * _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. diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c index a8b3503d2a..c0237791da 100644 --- a/ext/openssl/ossl_ocsp.c +++ b/ext/openssl/ossl_ocsp.c @@ -22,10 +22,6 @@ TypedData_Get_Struct((obj), OCSP_REQUEST, &ossl_ocsp_request_type, (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)); \ -} while (0) #define NewOCSPRes(klass) \ TypedData_Wrap_Struct((klass), &ossl_ocsp_response_type, 0) @@ -37,10 +33,6 @@ TypedData_Get_Struct((obj), OCSP_RESPONSE, &ossl_ocsp_response_type, (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)); \ -} while (0) #define NewOCSPBasicRes(klass) \ TypedData_Wrap_Struct((klass), &ossl_ocsp_basicresp_type, 0) @@ -52,10 +44,6 @@ TypedData_Get_Struct((obj), OCSP_BASICRESP, &ossl_ocsp_basicresp_type, (res)); \ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \ } while (0) -#define SafeGetOCSPBasicRes(obj, res) do { \ - OSSL_Check_Kind((obj), cOCSPBasicRes); \ - GetOCSPBasicRes((obj), (res)); \ -} while (0) #define NewOCSPSingleRes(klass) \ TypedData_Wrap_Struct((klass), &ossl_ocsp_singleresp_type, 0) @@ -67,10 +55,6 @@ TypedData_Get_Struct((obj), OCSP_SINGLERESP, &ossl_ocsp_singleresp_type, (res)); \ if(!(res)) ossl_raise(rb_eRuntimeError, "SingleResponse wasn't initialized!"); \ } while (0) -#define SafeGetOCSPSingleRes(obj, res) do { \ - OSSL_Check_Kind((obj), cOCSPSingleRes); \ - GetOCSPSingleRes((obj), (res)); \ -} while (0) #define NewOCSPCertId(klass) \ TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, 0) @@ -82,10 +66,6 @@ TypedData_Get_Struct((obj), OCSP_CERTID, &ossl_ocsp_certid_type, (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)); \ -} while (0) VALUE mOCSP; VALUE eOCSPError; @@ -200,7 +180,7 @@ ossl_ocspreq_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetOCSPReq(self, req_old); - SafeGetOCSPReq(other, req); + GetOCSPReq(other, req); req_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_REQUEST), req); if (!req_new) @@ -218,7 +198,7 @@ ossl_ocspreq_initialize_copy(VALUE self, VALUE other) * 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. + * from a _request_der_ string. */ static VALUE @@ -248,7 +228,7 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE 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 + * 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 @@ -281,7 +261,7 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self) * call-seq: * request.check_nonce(response) -> result * - * Checks the nonce validity for this request and +response+. + * Checks the nonce validity for this request and _response_. * * The return value is one of the following: * @@ -291,7 +271,7 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self) * 2 :: nonces both absent. * 3 :: nonce present in response only. * - * For most responses, clients can check +result+ > 0. If a responder doesn't + * 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. */ @@ -304,7 +284,7 @@ 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); @@ -314,7 +294,7 @@ ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp) * call-seq: * request.add_certid(certificate_id) -> request * - * Adds +certificate_id+ to the request. + * Adds _certificate_id_ to the request. */ static VALUE @@ -371,17 +351,17 @@ ossl_ocspreq_get_certid(VALUE self) * 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 + * 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 + * the signer certificate. Note that if _certs_ is +nil+ or not given, flag * OpenSSL::OCSP::NOCERTS is enabled. Pass an empty array to include only the * signer certificate. * - * +flags+ can be a bitwise OR of the following constants: + * _flags_ is a bitwise OR of the following constants: * * OpenSSL::OCSP::NOCERTS:: - * Don't include any certificates in the request. +certs+ will be ignored. + * Don't include any certificates in the request. _certs_ will be ignored. */ static VALUE ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self) @@ -404,7 +384,7 @@ ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self) if (NIL_P(digest)) md = EVP_sha1(); else - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); if (NIL_P(certs)) flg |= OCSP_NOCERTS; else @@ -421,9 +401,12 @@ ossl_ocspreq_sign(int argc, VALUE *argv, VALUE 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 + * 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 @@ -473,13 +456,29 @@ ossl_ocspreq_to_der(VALUE self) } /* + * 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+. + * Creates an OpenSSL::OCSP::Response from _status_ and _basic_response_. */ static VALUE @@ -521,7 +520,7 @@ ossl_ocspres_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetOCSPRes(self, res_old); - SafeGetOCSPRes(other, res); + GetOCSPRes(other, res); res_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_RESPONSE), res); if (!res_new) @@ -539,7 +538,7 @@ ossl_ocspres_initialize_copy(VALUE self, VALUE other) * 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. + * from a _response_der_ string. */ static VALUE @@ -677,7 +676,7 @@ ossl_ocspbres_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetOCSPBasicRes(self, bs_old); - SafeGetOCSPBasicRes(other, bs); + GetOCSPBasicRes(other, bs); bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs); if (!bs_new) @@ -693,7 +692,7 @@ ossl_ocspbres_initialize_copy(VALUE self, VALUE other) * call-seq: * OpenSSL::OCSP::BasicResponse.new(der_string = nil) -> basic_response * - * Creates a new BasicResponse. If +der_string+ is given, decodes +der_string+ + * Creates a new BasicResponse. If _der_string_ is given, decodes _der_string_ * as DER. */ @@ -724,7 +723,7 @@ ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self) * call-seq: * basic_response.copy_nonce(request) -> Integer * - * Copies the nonce from +request+ into this response. Returns 1 on success + * Copies the nonce from _request_ into this response. Returns 1 on success * and 0 on failure. */ @@ -736,7 +735,7 @@ 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); @@ -746,7 +745,7 @@ ossl_ocspbres_copy_nonce(VALUE self, VALUE request) * call-seq: * basic_response.add_nonce(nonce = nil) * - * Adds +nonce+ to this response. If no nonce was provided a random nonce + * Adds _nonce_ to this response. If no nonce was provided a random nonce * will be added. */ @@ -792,26 +791,26 @@ add_status_convert_time(VALUE obj) * 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 + * 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 + * _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. + * _revocation_time_ is the time when the certificate is revoked. * - * +this_update+ and +next_update+ indicate the time at which ths status is + * _this_update_ and _next_update_ indicate the time at which ths status is * verified to be correct and the time at or before which newer information - * will be available, respectively. +next_update+ is optional. + * will be available, respectively. _next_update_ is optional. * - * +extensions+ is an Array of OpenSSL::X509::Extension to be included in the + * _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+ + * 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. */ @@ -829,7 +828,7 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, VALUE tmp; GetOCSPBasicRes(self, bs); - SafeGetOCSPCertId(cid, id); + GetOCSPCertId(cid, id); st = NUM2INT(status); if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */ ext = rb_check_array_type(ext); @@ -888,7 +887,7 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, * Returns an Array of statuses for this response. Each status contains a * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the * reason for the status, the revocation time, the time of this update, the time - * for the next update and a list of OpenSSL::X509::Extensions. + * for the next update and a list of OpenSSL::X509::Extension. * * This should be superseded by BasicResponse#responses and #find_response that * return SingleResponse. @@ -977,7 +976,7 @@ ossl_ocspbres_get_responses(VALUE self) * call-seq: * basic_response.find_response(certificate_id) -> SingleResponse | nil * - * Returns a SingleResponse whose CertId matches with +certificate_id+, or nil + * Returns a SingleResponse whose CertId matches with _certificate_id_, or +nil+ * if this BasicResponse does not contain it. */ static VALUE @@ -988,7 +987,7 @@ ossl_ocspbres_find_response(VALUE self, VALUE target) OCSP_CERTID *id; int n; - SafeGetOCSPCertId(target, id); + GetOCSPCertId(target, id); GetOCSPBasicRes(self, bs); if ((n = OCSP_resp_find(bs, id, -1)) == -1) @@ -1006,10 +1005,10 @@ ossl_ocspbres_find_response(VALUE self, VALUE target) * 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 + * 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: + * _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 @@ -1036,7 +1035,7 @@ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self) if (NIL_P(digest)) md = EVP_sha1(); else - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); if (NIL_P(certs)) flg |= OCSP_NOCERTS; else @@ -1053,8 +1052,8 @@ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE 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. + * 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) @@ -1184,7 +1183,7 @@ ossl_ocspsres_alloc(VALUE klass) * call-seq: * OpenSSL::OCSP::SingleResponse.new(der_string) -> SingleResponse * - * Creates a new SingleResponse from +der_string+. + * Creates a new SingleResponse from _der_string_. */ static VALUE ossl_ocspsres_initialize(VALUE self, VALUE arg) @@ -1213,7 +1212,7 @@ ossl_ocspsres_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetOCSPSingleRes(self, sres_old); - SafeGetOCSPSingleRes(other, sres); + GetOCSPSingleRes(other, sres); sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres); if (!sres_new) @@ -1235,10 +1234,10 @@ ossl_ocspsres_initialize_copy(VALUE self, VALUE other) * * It is possible that the OCSP request takes a few seconds or the time is not * accurate. To avoid rejecting a valid response, this method allows the times - * to be within +nsec+ of the current time. + * 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 + * response to be considered valid. The _maxsec_ parameter can be used to limit * the age of responses. */ static VALUE @@ -1329,8 +1328,10 @@ ossl_ocspsres_get_this_update(VALUE self) 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); /* will handle NULL */ + return asn1time_to_time(time); } /* @@ -1348,6 +1349,8 @@ ossl_ocspsres_get_next_update(VALUE self) 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); } @@ -1369,6 +1372,8 @@ ossl_ocspsres_get_revocation_time(VALUE self) 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); } @@ -1468,7 +1473,7 @@ ossl_ocspcid_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetOCSPCertId(self, cid_old); - SafeGetOCSPCertId(other, cid); + GetOCSPCertId(other, cid); cid_new = OCSP_CERTID_dup(cid); if (!cid_new) @@ -1485,14 +1490,13 @@ ossl_ocspcid_initialize_copy(VALUE self, VALUE other) * OpenSSL::OCSP::CertificateId.new(subject, issuer, digest = nil) -> certificate_id * OpenSSL::OCSP::CertificateId.new(der_string) -> certificate_id * - * Creates a new OpenSSL::OCSP::CertificateId for the given +subject+ and - * +issuer+ X509 certificates. The +digest+ is used to compute the - * certificate ID and must be an OpenSSL::Digest instance. + * 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. */ - static VALUE ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self) { @@ -1517,7 +1521,7 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self) x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */ x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */ - md = !NIL_P(digest) ? GetDigestPtr(digest) : NULL; + md = !NIL_P(digest) ? ossl_evp_get_digestbyname(digest) : NULL; newid = OCSP_cert_to_id(md, x509s, x509i); if (!newid) @@ -1534,7 +1538,7 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self) * call-seq: * certificate_id.cmp(other) -> true or false * - * Compares this certificate id with +other+ and returns true if they are the + * Compares this certificate id with _other_ and returns +true+ if they are the * same. */ static VALUE @@ -1544,7 +1548,7 @@ 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; @@ -1554,7 +1558,7 @@ ossl_ocspcid_cmp(VALUE self, VALUE other) * call-seq: * certificate_id.cmp_issuer(other) -> true or false * - * Compares this certificate id's issuer with +other+ and returns true if + * Compares this certificate id's issuer with _other_ and returns +true+ if * they are the same. */ @@ -1565,7 +1569,7 @@ 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; @@ -1824,12 +1828,13 @@ Init_ossl_ocsp(void) cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject); rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc); - rb_define_copy_func(cOCSPReq, ossl_ocspreq_initialize_copy); + rb_define_method(cOCSPReq, "initialize_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); @@ -1842,7 +1847,7 @@ Init_ossl_ocsp(void) cOCSPRes = rb_define_class_under(mOCSP, "Response", rb_cObject); rb_define_singleton_method(cOCSPRes, "create", ossl_ocspres_s_create, 2); rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc); - rb_define_copy_func(cOCSPRes, ossl_ocspres_initialize_copy); + rb_define_method(cOCSPRes, "initialize_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); @@ -1857,7 +1862,7 @@ Init_ossl_ocsp(void) cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject); rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc); - rb_define_copy_func(cOCSPBasicRes, ossl_ocspbres_initialize_copy); + rb_define_method(cOCSPBasicRes, "initialize_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); @@ -1876,7 +1881,7 @@ Init_ossl_ocsp(void) */ cOCSPSingleRes = rb_define_class_under(mOCSP, "SingleResponse", rb_cObject); rb_define_alloc_func(cOCSPSingleRes, ossl_ocspsres_alloc); - rb_define_copy_func(cOCSPSingleRes, ossl_ocspsres_initialize_copy); + rb_define_method(cOCSPSingleRes, "initialize_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); @@ -1895,7 +1900,7 @@ Init_ossl_ocsp(void) cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject); rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc); - rb_define_copy_func(cOCSPCertId, ossl_ocspcid_initialize_copy); + rb_define_method(cOCSPCertId, "initialize_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); diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c index 8502a6de0d..ddb7d939cf 100644 --- a/ext/openssl/ossl_pkcs12.c +++ b/ext/openssl/ossl_pkcs12.c @@ -17,11 +17,6 @@ if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ } while (0) -#define SafeGetPKCS12(obj, p12) do { \ - OSSL_Check_Kind((obj), cPKCS12); \ - GetPKCS12((obj), (p12)); \ -} while (0) - #define ossl_pkcs12_set_key(o,v) rb_iv_set((o), "@key", (v)) #define ossl_pkcs12_set_cert(o,v) rb_iv_set((o), "@certificate", (v)) #define ossl_pkcs12_set_ca_certs(o,v) rb_iv_set((o), "@ca_certs", (v)) @@ -72,7 +67,7 @@ ossl_pkcs12_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetPKCS12(self, p12_old); - SafeGetPKCS12(other, p12); + GetPKCS12(other, p12); p12_new = ASN1_dup((i2d_of_void *)i2d_PKCS12, (d2i_of_void *)d2i_PKCS12, (char *)p12); if (!p12_new) @@ -89,20 +84,20 @@ ossl_pkcs12_initialize_copy(VALUE self, VALUE other) * 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. + * * _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. + * * _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(). */ @@ -161,8 +156,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) @@ -252,7 +247,7 @@ Init_ossl_pkcs12(void) rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1); rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate); - rb_define_copy_func(cPKCS12, ossl_pkcs12_initialize_copy); + rb_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); diff --git a/ext/openssl/ossl_pkcs5.c b/ext/openssl/ossl_pkcs5.c deleted file mode 100644 index 47c5bfa3b8..0000000000 --- a/ext/openssl/ossl_pkcs5.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2007 Technorama Ltd. <[email protected]> - */ -#include "ossl.h" - -VALUE mPKCS5; -VALUE ePKCS5; - -#ifdef HAVE_PKCS5_PBKDF2_HMAC -/* - * call-seq: - * PKCS5.pbkdf2_hmac(pass, salt, iter, keylen, digest) => string - * - * === Parameters - * * +pass+ - string - * * +salt+ - string - should be at least 8 bytes long. - * * +iter+ - integer - should be greater than 1000. 20000 is better. - * * +keylen+ - integer - * * +digest+ - a string or OpenSSL::Digest object. - * - * Available in OpenSSL >= 1.0.0. - * - * 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) -{ - 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_LENINT(pass), - (unsigned char *)RSTRING_PTR(salt), RSTRING_LENINT(salt), - NUM2INT(iter), md, len, - (unsigned char *)RSTRING_PTR(str)) != 1) - ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC"); - - return str; -} -#else -#define ossl_pkcs5_pbkdf2_hmac rb_f_notimplement -#endif - - -/* - * call-seq: - * PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, keylen) => string - * - * === Parameters - * * +pass+ - string - * * +salt+ - string - should be at least 8 bytes long. - * * +iter+ - integer - should be greater than 1000. 20000 is better. - * * +keylen+ - integer - * - * This method is available in almost any version of OpenSSL. - * - * Conforms to RFC 2898. - */ -static VALUE -ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen) -{ - 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_LENINT(pass), - (const unsigned char *)RSTRING_PTR(salt), RSTRING_LENINT(salt), NUM2INT(iter), - len, (unsigned char *)RSTRING_PTR(str)) != 1) - ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC_SHA1"); - - return str; -} - -void -Init_ossl_pkcs5(void) -{ -#if 0 - mOSSL = rb_define_module("OpenSSL"); - eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); -#endif - - /* Document-class: OpenSSL::PKCS5 - * - * Provides password-based encryption functionality based on PKCS#5. - * 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. - * - * PKCS5 offers support for PBKDF2 with an OpenSSL::Digest::SHA1-based - * HMAC, or an arbitrary Digest if the underlying version of OpenSSL - * already supports it (>= 1.0.0). - * - * === Parameters - * ==== Password - * Typically an arbitrary String that represents the password to be used - * for deriving a key. - * ==== Salt - * Prevents attacks based on dictionaries of common passwords. It is a - * public value that can be safely stored along with the password (e.g. - * if PBKDF2 is used for password storage). For maximum security, a fresh, - * random salt should be generated for each stored password. According - * to PKCS#5, a salt should be at least 8 bytes long. - * ==== Iteration Count - * Allows to tweak the length that the actual computation will take. The - * larger the iteration count, the longer it will take. - * ==== Key Length - * Specifies the length in bytes of the output that will be generated. - * Typically, the key length should be larger than or equal to the output - * length of the underlying digest function, otherwise an attacker could - * simply try to brute-force the key. According to PKCS#5, security is - * limited by the output length of the underlying digest function, i.e. - * security is not improved if a key length strictly larger than the - * digest output length is chosen. Therefore, when using PKCS5 for - * password storage, it suffices to store values equal to the digest - * output length, nothing is gained by storing larger values. - * - * == Examples - * === Generating a 128 bit key for a Cipher (e.g. AES) - * pass = "secret" - * salt = OpenSSL::Random.random_bytes(16) - * iter = 20000 - * key_len = 16 - * key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, key_len) - * - * === Storing Passwords - * pass = "secret" - * salt = OpenSSL::Random.random_bytes(16) #store this with the generated value - * iter = 20000 - * digest = OpenSSL::Digest::SHA256.new - * len = digest.digest_length - * #the final value to be stored - * value = OpenSSL::PKCS5.pbkdf2_hmac(pass, salt, iter, len, digest) - * - * === 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 compare two - * values, the following could be used: - * def eql_time_cmp(a, b) - * unless a.length == b.length - * return false - * end - * cmp = b.bytes.to_a - * result = 0 - * a.bytes.each_with_index {|c,i| - * result |= c ^ cmp[i] - * } - * result == 0 - * end - * Please note that the premature return in case of differing lengths - * typically does not leak valuable information - when using PKCS#5, the - * length of the values to be compared is of fixed size. - */ - - mPKCS5 = rb_define_module_under(mOSSL, "PKCS5"); - /* Document-class: OpenSSL::PKCS5::PKCS5Error - * - * Generic Exception class that is raised if an error occurs during a - * computation. - */ - 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 40cc5f230e..6395fa6f5c 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -23,10 +23,6 @@ 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 NewPKCS7si(klass) \ TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, 0) @@ -42,10 +38,6 @@ 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 NewPKCS7ri(klass) \ TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, 0) @@ -61,10 +53,6 @@ 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) (int)(sizeof(ary)/sizeof((ary)[0])) @@ -162,7 +150,7 @@ DupPKCS7SignerPtr(VALUE obj) { PKCS7_SIGNER_INFO *p7si, *pkcs7; - SafeGetPKCS7si(obj, p7si); + GetPKCS7si(obj, p7si); if (!(pkcs7 = ossl_PKCS7_SIGNER_INFO_dup(p7si))) { ossl_raise(ePKCS7Error, NULL); } @@ -189,7 +177,7 @@ DupPKCS7RecipientPtr(VALUE obj) { PKCS7_RECIP_INFO *p7ri, *pkcs7; - SafeGetPKCS7ri(obj, p7ri); + GetPKCS7ri(obj, p7ri); if (!(pkcs7 = ossl_PKCS7_RECIP_INFO_dup(p7ri))) { ossl_raise(ePKCS7Error, NULL); } @@ -238,7 +226,7 @@ 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); @@ -331,7 +319,7 @@ ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass) #endif } - else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */ + else ciph = ossl_evp_get_cipherbyname(cipher); flg = NIL_P(flags) ? 0 : NUM2INT(flags); ret = NewPKCS7(cPKCS7); in = ossl_obj2bio(&data); @@ -414,7 +402,7 @@ 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) { @@ -537,7 +525,7 @@ ossl_pkcs7_set_cipher(VALUE self, VALUE cipher) PKCS7 *pkcs7; GetPKCS7(self, pkcs7); - if (!PKCS7_set_cipher(pkcs7, GetCipherPtr(cipher))) { + if (!PKCS7_set_cipher(pkcs7, ossl_evp_get_cipherbyname(cipher))) { ossl_raise(ePKCS7Error, NULL); } @@ -933,7 +921,7 @@ ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest) pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); GetPKCS7si(self, p7si); if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, (EVP_MD*)md))) { ossl_raise(ePKCS7Error, NULL); @@ -1068,7 +1056,7 @@ Init_ossl_pkcs7(void) 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); diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 314d1d94af..23e2115409 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -92,7 +92,7 @@ pkey_new0(EVP_PKEY *pkey) case EVP_PKEY_DH: return ossl_dh_new(pkey); #endif -#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) +#if !defined(OPENSSL_NO_EC) case EVP_PKEY_EC: return ossl_ec_new(pkey); #endif @@ -123,15 +123,15 @@ ossl_pkey_new(EVP_PKEY *pkey) * OpenSSL::PKey.read(string [, pwd ]) -> PKey * OpenSSL::PKey.read(io [, pwd ]) -> PKey * - * Reads a DER or PEM encoded string from +string+ or +io+ and returns an + * 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 + * * _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 + * * _io_ is an instance of IO containing a DER- or PEM-encoded * arbitrary private or public key. - * * +pwd+ is an optional password in case +string+ or +file+ is an encrypted + * * _pwd_ is an optional password in case _string_ or _io_ is an encrypted * PEM resource. */ static VALUE @@ -207,7 +207,7 @@ GetPKeyPtr(VALUE obj) { EVP_PKEY *pkey; - SafeGetPKey(obj, pkey); + GetPKey(obj, pkey); return pkey; } @@ -220,7 +220,7 @@ GetPrivPKeyPtr(VALUE obj) if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) { ossl_raise(rb_eArgError, "Private key is needed."); } - SafeGetPKey(obj, pkey); + GetPKey(obj, pkey); return pkey; } @@ -230,7 +230,7 @@ DupPKeyPtr(VALUE obj) { EVP_PKEY *pkey; - SafeGetPKey(obj, pkey); + GetPKey(obj, pkey); EVP_PKEY_up_ref(pkey); return pkey; @@ -259,7 +259,7 @@ ossl_pkey_alloc(VALUE klass) * PKeyClass.new -> self * * Because PKey is an abstract class, actually calling this method explicitly - * will raise a +NotImplementedError+. + * will raise a NotImplementedError. */ static VALUE ossl_pkey_initialize(VALUE self) @@ -274,10 +274,10 @@ ossl_pkey_initialize(VALUE self) * call-seq: * pkey.sign(digest, data) -> String * - * To sign the +String+ +data+, +digest+, an instance of OpenSSL::Digest, must - * be provided. The return value is again a +String+ containing the signature. + * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must + * be provided. The return value is again a String containing the signature. * A PKeyError is raised should errors occur. - * Any previous state of the +Digest+ instance is irrelevant to the signature + * Any previous state of the Digest instance is irrelevant to the signature * outcome, the digest instance is reset to its initial state during the * operation. * @@ -298,7 +298,7 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) int result; pkey = GetPrivPKeyPtr(self); - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); StringValue(data); str = rb_str_new(0, EVP_PKEY_size(pkey)); @@ -326,12 +326,12 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) * call-seq: * pkey.verify(digest, signature, data) -> String * - * To verify the +String+ +signature+, +digest+, an instance of + * To verify the String _signature_, _digest_, an instance of * OpenSSL::Digest, must be provided to re-compute the message digest of the - * original +data+, also a +String+. The return value is +true+ if the + * original _data_, also a String. The return value is +true+ if the * signature is valid, +false+ otherwise. A PKeyError is raised should errors * occur. - * Any previous state of the +Digest+ instance is irrelevant to the validation + * Any previous state of the Digest instance is irrelevant to the validation * outcome, the digest instance is reset to its initial state during the * operation. * @@ -353,7 +353,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) GetPKey(self, pkey); pkey_check_public_key(pkey); - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); StringValue(sig); siglen = RSTRING_LENINT(sig); StringValue(data); diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index e3b723cd68..a87472ad09 100644 --- a/ext/openssl/ossl_pkey.h +++ b/ext/openssl/ossl_pkey.h @@ -34,10 +34,6 @@ extern const rb_data_type_t ossl_evp_pkey_type; 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) struct ossl_generate_cb_arg { int yield; diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index 9283271093..31f3b8e726 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -150,8 +150,8 @@ dh_generate(int size, int gen) * components alike. * * === Parameters - * * +size+ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. - * * +generator+ is a small number > 1, typically 2 or 5. + * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. + * * _generator_ is a small number > 1, typically 2 or 5. * */ static VALUE @@ -181,15 +181,15 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) * DH.new(size [, generator]) -> dh * * Either generates a DH instance from scratch or by reading already existing - * DH parameters from +string+. Note that when reading a DH instance from + * DH parameters from _string_. Note that when reading a DH instance from * data that was encoded from a DH instance by using DH#to_pem or DH#to_der * the result will *not* contain a public/private key pair yet. This needs to * be generated using DH#generate_key! first. * * === Parameters - * * +size+ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. - * * +generator+ is a small number > 1, typically 2 or 5. - * * +string+ contains the DER or PEM encoded key. + * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. + * * _generator_ is a small number > 1, typically 2 or 5. + * * _string_ contains the DER or PEM encoded key. * * === Examples * DH.new # -> dh @@ -436,7 +436,7 @@ ossl_dh_to_text(VALUE self) * dh.public_key -> aDH * * Returns a new DH instance that carries just the public information, i.e. - * the prime +p+ and the generator +g+, but no public/private key yet. Such + * the prime _p_ and the generator _g_, but no public/private key yet. Such * a pair may be generated using DH#generate_key!. The "public key" needed * for a key exchange with DH#compute_key is considered as per-session * information and may be retrieved with DH#pub_key once a key pair has @@ -526,7 +526,7 @@ ossl_dh_generate_key(VALUE self) * See DH_compute_key() for further information. * * === Parameters - * * +pub_bn+ is a OpenSSL::BN, *not* the DH instance returned by + * * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by * DH#public_key as that contains the DH parameters only. */ static VALUE @@ -557,7 +557,7 @@ ossl_dh_compute_key(VALUE self, VALUE pub) * call-seq: * dh.set_pqg(p, q, g) -> self * - * Sets +p+, +q+, +g+ for the DH instance. + * Sets _p_, _q_, _g_ to the DH instance. */ OSSL_PKEY_BN_DEF3(dh, DH, pqg, p, q, g) /* @@ -565,7 +565,7 @@ OSSL_PKEY_BN_DEF3(dh, DH, pqg, p, q, g) * call-seq: * dh.set_key(pub_key, priv_key) -> self * - * Sets +pub_key+ and +priv_key+ for the DH instance. +priv_key+ may be nil. + * Sets _pub_key_ and _priv_key_ for the DH instance. _priv_key_ may be +nil+. */ OSSL_PKEY_BN_DEF2(dh, DH, key, pub_key, priv_key) @@ -618,7 +618,7 @@ Init_ossl_dh(void) cDH = rb_define_class_under(mPKey, "DH", cPKey); rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1); rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); - rb_define_copy_func(cDH, ossl_dh_initialize_copy); + rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1); 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); diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index cd4313b1ff..56cc9dd4f1 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -172,7 +172,7 @@ dsa_generate(int size) * from scratch. * * === Parameters - * * +size+ is an integer representing the desired key size. + * * _size_ is an integer representing the desired key size. * */ static VALUE @@ -195,12 +195,12 @@ ossl_dsa_s_generate(VALUE klass, VALUE size) * DSA.new(size) -> dsa * DSA.new(string [, pass]) -> dsa * - * Creates a new DSA instance by reading an existing key from +string+. + * Creates a new DSA instance by reading an existing key from _string_. * * === Parameters - * * +size+ is an integer representing the desired key size. - * * +string+ contains a DER or PEM encoded key. - * * +pass+ is a string that contains an optional password. + * * _size_ is an integer representing the desired key size. + * * _string_ contains a DER or PEM encoded key. + * * _pass_ is a string that contains an optional password. * * === Examples * DSA.new -> dsa @@ -329,8 +329,8 @@ ossl_dsa_is_private(VALUE self) * Encodes this DSA to its PEM encoding. * * === Parameters - * * +cipher+ is an OpenSSL::Cipher. - * * +password+ is a string containing your password. + * * _cipher_ is an OpenSSL::Cipher. + * * _password_ is a string containing your password. * * === Examples * DSA.to_pem -> aString @@ -348,7 +348,7 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self) GetDSA(self, dsa); rb_scan_args(argc, argv, "02", &cipher, &pass); if (!NIL_P(cipher)) { - ciph = GetCipherPtr(cipher); + ciph = ossl_evp_get_cipherbyname(cipher); pass = ossl_pem_passwd_value(pass); } if (!(out = BIO_new(BIO_s_mem()))) { @@ -503,12 +503,12 @@ ossl_dsa_to_public_key(VALUE self) * call-seq: * dsa.syssign(string) -> aString * - * Computes and returns the DSA signature of +string+, where +string+ is + * 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. * * === Parameters - * * +string+ is a message digest of the original input data to be signed + * * _string_ is a message digest of the original input data to be signed. * * === Example * dsa = OpenSSL::PKey::DSA.new(2048) @@ -549,11 +549,11 @@ ossl_dsa_sign(VALUE self, VALUE data) * 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. + * does so by validating _sig_ using the public key of this DSA instance. * * === Parameters - * * +digest+ is a message digest of the original input data to be signed - * * +sig+ is a DSA signature value + * * _digest_ is a message digest of the original input data to be signed + * * _sig_ is a DSA signature value * * === Example * dsa = OpenSSL::PKey::DSA.new(2048) @@ -590,7 +590,7 @@ ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) * call-seq: * dsa.set_pqg(p, q, g) -> self * - * Sets +p+, +q+, +g+ for the DSA instance. + * Sets _p_, _q_, _g_ to the DSA instance. */ OSSL_PKEY_BN_DEF3(dsa, DSA, pqg, p, q, g) /* @@ -598,7 +598,7 @@ OSSL_PKEY_BN_DEF3(dsa, DSA, pqg, p, q, g) * 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. + * Sets _pub_key_ and _priv_key_ for the DSA instance. _priv_key_ may be +nil+. */ OSSL_PKEY_BN_DEF2(dsa, DSA, key, pub_key, priv_key) @@ -627,18 +627,12 @@ Init_ossl_dsa(void) * 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. - * Please note that for OpenSSL versions prior to 1.0.0 the digest - * algorithms OpenSSL::Digest::DSS (equivalent to SHA) or - * OpenSSL::Digest::DSS1 (equivalent to SHA-1) must be used for issuing - * signatures with a DSA key using OpenSSL::PKey#sign. - * Starting with OpenSSL 1.0.0, digest algorithms are no longer restricted, - * any Digest may be used for signing. */ 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); - rb_define_copy_func(cDSA, ossl_dsa_initialize_copy); + rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1); rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index 5262d3b206..9c406931a9 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -4,7 +4,7 @@ #include "ossl.h" -#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) +#if !defined(OPENSSL_NO_EC) #define EXPORT_PEM 0 #define EXPORT_DER 1 @@ -23,33 +23,21 @@ static const rb_data_type_t ossl_ec_point_type; GetPKeyEC(obj, _pkey); \ (key) = EVP_PKEY_get0_EC_KEY(_pkey); \ } while (0) -#define SafeGetEC(obj, key) do { \ - OSSL_Check_Kind(obj, cEC); \ - GetEC(obj, key); \ -} while (0) #define 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 SafeGetECGroup(obj, group) do { \ - OSSL_Check_Kind((obj), cEC_GROUP); \ - GetECGroup(obj, group); \ -} 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 SafeGetECPoint(obj, point) do { \ - OSSL_Check_Kind((obj), cEC_POINT); \ - GetECPoint(obj, point); \ -} while(0) #define GetECPointGroup(obj, group) do { \ VALUE _group = rb_attr_get(obj, id_i_group); \ - SafeGetECGroup(_group, group); \ + GetECGroup(_group, group); \ } while (0) VALUE cEC; @@ -128,7 +116,7 @@ ec_key_new_from_group(VALUE arg) if (rb_obj_is_kind_of(arg, cEC_GROUP)) { EC_GROUP *group; - SafeGetECGroup(arg, group); + GetECGroup(arg, group); if (!(ec = EC_KEY_new())) ossl_raise(eECError, NULL); @@ -208,7 +196,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) } else if (rb_obj_is_kind_of(arg, cEC)) { EC_KEY *other_ec = NULL; - SafeGetEC(arg, other_ec); + GetEC(arg, other_ec); if (!(ec = EC_KEY_dup(other_ec))) ossl_raise(eECError, NULL); } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { @@ -257,7 +245,7 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other) GetPKey(self, pkey); if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) ossl_raise(eECError, "EC already initialized"); - SafeGetEC(other, ec); + GetEC(other, ec); ec_new = EC_KEY_dup(ec); if (!ec_new) @@ -275,7 +263,7 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other) * key.group => group * * Returns the EC::Group that the key is associated with. Modifying the returned - * group does not affect +key+. + * group does not affect _key_. */ static VALUE ossl_ec_key_get_group(VALUE self) @@ -296,7 +284,7 @@ ossl_ec_key_get_group(VALUE self) * key.group = group * * 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. + * 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) @@ -305,7 +293,7 @@ ossl_ec_key_set_group(VALUE self, VALUE group_v) EC_GROUP *group; GetEC(self, ec); - SafeGetECGroup(group_v, group); + GetECGroup(group_v, group); if (EC_KEY_set_group(ec, group) != 1) ossl_raise(eECError, "EC_KEY_set_group"); @@ -390,7 +378,7 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) GetEC(self, ec); if (!NIL_P(public_key)) - SafeGetECPoint(public_key, point); + GetECPoint(public_key, point); switch (EC_KEY_set_public_key(ec, point)) { case 1: @@ -458,7 +446,7 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma private = 1; if (!NIL_P(ciph)) { - cipher = GetCipherPtr(ciph); + cipher = ossl_evp_get_cipherbyname(ciph); pass = ossl_pem_passwd_value(pass); } @@ -502,8 +490,8 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma * key.export([cipher, pass_phrase]) => String * key.to_pem([cipher, pass_phrase]) => String * - * Outputs the EC key in PEM encoding. If +cipher+ and +pass_phrase+ are given - * they will be used to encrypt the key. +cipher+ must be an OpenSSL::Cipher + * Outputs the EC key in PEM encoding. If _cipher_ and _pass_phrase_ are given + * they will be used to encrypt the key. _cipher_ must be an OpenSSL::Cipher * instance. Note that encryption will only be effective for a private key, * public keys will always be encoded in plain text. */ @@ -608,7 +596,7 @@ static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) VALUE str; GetEC(self, ec); - SafeGetECPoint(pubkey, point); + GetECPoint(pubkey, point); /* BUG: need a way to figure out the maximum string size */ buf_len = 1024; @@ -724,7 +712,7 @@ ec_group_new(const EC_GROUP *group) * * Creates a new EC::Group object. * - * +ec_method+ is a symbol that represents an EC_METHOD. Currently the following + * _ec_method_ is a symbol that represents an EC_METHOD. Currently the following * are supported: * * * :GFp_simple @@ -771,7 +759,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { const EC_GROUP *arg1_group; - SafeGetECGroup(arg1, arg1_group); + GetECGroup(arg1, arg1_group); if ((group = EC_GROUP_dup(arg1_group)) == NULL) ossl_raise(eEC_GROUP, "EC_GROUP_dup"); } else { @@ -847,7 +835,7 @@ ossl_ec_group_initialize_copy(VALUE self, VALUE other) TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group_new); if (group_new) ossl_raise(eEC_GROUP, "EC::Group already initialized"); - SafeGetECGroup(other, group); + GetECGroup(other, group); group_new = EC_GROUP_dup(group); if (!group_new) @@ -862,15 +850,15 @@ ossl_ec_group_initialize_copy(VALUE self, VALUE other) * 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. + * 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; GetECGroup(a, group1); - SafeGetECGroup(b, group2); + GetECGroup(b, group2); if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1) return Qfalse; @@ -903,8 +891,8 @@ static VALUE ossl_ec_group_get_generator(VALUE self) * call-seq: * group.set_generator(generator, order, cofactor) => self * - * Sets the curve parameters. +generator+ must be an instance of EC::Point that - * is on the curve. +order+ and +cofactor+ are integers. + * 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() */ @@ -915,7 +903,7 @@ static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE orde const BIGNUM *o, *co; GetECGroup(self, group); - SafeGetECPoint(generator, point); + GetECPoint(generator, point); o = GetBNPtr(order); co = GetBNPtr(cofactor); @@ -1127,14 +1115,14 @@ parse_point_conversion_form_symbol(VALUE sym) * * Sets the form how EC::Point data is encoded as ASN.1 as defined in X9.62. * - * +format+ can be one of these: + * _format_ can be one of these: * - * :compressed:: + * +: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:: + * +:uncompressed+:: * Encoded as z||x||y, where z is an octet 0x04. - * :hybrid:: + * +: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. * @@ -1356,13 +1344,13 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) const EC_POINT *arg_point; group_v = rb_attr_get(arg1, id_i_group); - SafeGetECGroup(group_v, group); - SafeGetECPoint(arg1, arg_point); + GetECGroup(group_v, group); + GetECPoint(arg1, arg_point); point = EC_POINT_dup(arg_point, group); } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { group_v = arg1; - SafeGetECGroup(group_v, group); + GetECGroup(group_v, group); point = EC_POINT_new(group); } else { @@ -1374,7 +1362,7 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) if (!rb_obj_is_kind_of(arg1, cEC_GROUP)) ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group"); group_v = arg1; - SafeGetECGroup(group_v, group); + GetECGroup(group_v, group); if (rb_obj_is_kind_of(arg2, cBN)) { const BIGNUM *bn = GetBNPtr(arg2); @@ -1418,10 +1406,10 @@ ossl_ec_point_initialize_copy(VALUE self, VALUE other) TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point_new); if (point_new) ossl_raise(eEC_POINT, "EC::Point already initialized"); - SafeGetECPoint(other, point); + GetECPoint(other, point); group_v = rb_obj_dup(rb_attr_get(other, id_i_group)); - SafeGetECGroup(group_v, group); + GetECGroup(group_v, group); point_new = EC_POINT_dup(point, group); if (!point_new) @@ -1448,8 +1436,8 @@ static VALUE ossl_ec_point_eql(VALUE a, VALUE b) return Qfalse; GetECPoint(a, point1); - SafeGetECPoint(b, point2); - SafeGetECGroup(group_v1, group); + GetECPoint(b, point2); + GetECGroup(group_v1, group); if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1) return Qfalse; @@ -1558,7 +1546,7 @@ static VALUE ossl_ec_point_set_to_infinity(VALUE self) * point.to_bn(conversion_form = nil) => OpenSSL::BN * * Convert the EC point into an octet string and store in an OpenSSL::BN. If - * +conversion_form+ is given, the point data is converted using the specified + * _conversion_form_ is given, the point data is converted using the specified * form. If not given, the default form set in the EC::Group object is used. * * See also EC::Point#point_conversion_form=. @@ -1597,12 +1585,12 @@ ossl_ec_point_to_bn(int argc, VALUE *argv, VALUE self) * 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, + * generator of the group of _point_. _bn2_ may be omitted, and in that case, * the result is just <tt>bn1 * point</tt>. * * The second form calculates <tt>bns[0] * point + bns[1] * points[0] + ... - * + bns[-1] * points[-1] + bn2 * G</tt>. +bn2+ may be omitted. +bns+ must be - * an array of OpenSSL::BN. +points+ must be an array of + * + bns[-1] * points[-1] + bn2 * G</tt>. _bn2_ may be omitted. _bns_ must be + * an array of OpenSSL::BN. _points_ must be an array of * OpenSSL::PKey::EC::Point. Please note that <tt>points[0]</tt> is not * multiplied by <tt>bns[0]</tt>, but <tt>bns[1]</tt>. */ @@ -1615,7 +1603,7 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self) const BIGNUM *bn_g = NULL; GetECPoint(self, point_self); - SafeGetECGroup(group_v, group); + GetECGroup(group_v, group); result = rb_obj_alloc(cEC_POINT); ossl_ec_point_initialize(1, &group_v, result); @@ -1656,7 +1644,7 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self) points = ALLOCV_N(const EC_POINT *, tmp_p, num); points[0] = point_self; /* self */ for (i = 0; i < num - 1; i++) - SafeGetECPoint(RARRAY_AREF(arg2, i), points[i + 1]); + GetECPoint(RARRAY_AREF(arg2, i), points[i + 1]); if (!NIL_P(arg3)) bn_g = GetBNPtr(arg3); @@ -1726,7 +1714,7 @@ void Init_ossl_ec(void) rb_define_singleton_method(cEC, "generate", ossl_ec_key_s_generate, 1); rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1); - rb_define_copy_func(cEC, ossl_ec_key_initialize_copy); + rb_define_method(cEC, "initialize_copy", ossl_ec_key_initialize_copy, 1); /* copy/dup/cmp */ rb_define_method(cEC, "group", ossl_ec_key_get_group, 0); @@ -1763,7 +1751,7 @@ void Init_ossl_ec(void) rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1); - rb_define_copy_func(cEC_GROUP, ossl_ec_group_initialize_copy); + rb_define_method(cEC_GROUP, "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 */ @@ -1799,7 +1787,7 @@ void Init_ossl_ec(void) rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc); rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1); - rb_define_copy_func(cEC_POINT, ossl_ec_point_initialize_copy); + rb_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?"); diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 1fcdd52cf4..26397bd021 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -172,8 +172,8 @@ rsa_generate(int size, unsigned long exp) * RSA.generate(size) => RSA instance * RSA.generate(size, exponent) => RSA instance * - * Generates an RSA keypair. +size+ is an integer representing the desired key - * size. Keys smaller than 1024 should be considered insecure. +exponent+ is + * Generates an RSA keypair. _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. */ static VALUE @@ -203,12 +203,12 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) * RSA.new(encoded_key) => RSA instance * RSA.new(encoded_key, pass_phrase) => RSA instance * - * Generates or loads an RSA keypair. If an integer +key_size+ is given it + * Generates or loads an RSA keypair. If an integer _key_size_ is given it * represents the desired key size. Keys less than 1024 bits should be * considered insecure. * - * A key can instead be loaded from an +encoded_key+ which must be PEM or DER - * encoded. A +pass_phrase+ can be used to decrypt the key. If none is given + * A key can instead be loaded from an _encoded_key_ which must be PEM or DER + * encoded. A _pass_phrase_ can be used to decrypt the key. If none is given * OpenSSL will prompt for the pass phrase. * * = Examples @@ -295,7 +295,7 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other) * call-seq: * rsa.public? => true * - * The return value is always true since every private key is also a public + * The return value is always +true+ since every private key is also a public * key. */ static VALUE @@ -333,8 +333,8 @@ ossl_rsa_is_private(VALUE self) * rsa.to_pem([cipher, pass_phrase]) => PEM-format String * rsa.to_s([cipher, pass_phrase]) => PEM-format String * - * Outputs this keypair in PEM encoding. If +cipher+ and +pass_phrase+ are - * given they will be used to encrypt the key. +cipher+ must be an + * Outputs this keypair in PEM encoding. If _cipher_ and _pass_phrase_ are + * given they will be used to encrypt the key. _cipher_ must be an * OpenSSL::Cipher instance. */ static VALUE @@ -350,7 +350,7 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "02", &cipher, &pass); if (!NIL_P(cipher)) { - ciph = GetCipherPtr(cipher); + ciph = ossl_evp_get_cipherbyname(cipher); pass = ossl_pem_passwd_value(pass); } if (!(out = BIO_new(BIO_s_mem()))) { @@ -409,7 +409,7 @@ ossl_rsa_to_der(VALUE self) * rsa.public_encrypt(string) => String * rsa.public_encrypt(string, padding) => String * - * Encrypt +string+ with the public key. +padding+ defaults to PKCS1_PADDING. + * Encrypt _string_ with the public key. _padding_ defaults to PKCS1_PADDING. * The encrypted string output can be decrypted using #private_decrypt. */ static VALUE @@ -441,8 +441,8 @@ ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) * 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. + * Decrypt _string_, which has been encrypted with the private key, with the + * public key. _padding_ defaults to PKCS1_PADDING. */ static VALUE ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) @@ -473,7 +473,7 @@ ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) * rsa.private_encrypt(string) => String * rsa.private_encrypt(string, padding) => String * - * Encrypt +string+ with the private key. +padding+ defaults to PKCS1_PADDING. + * Encrypt _string_ with the private key. _padding_ defaults to PKCS1_PADDING. * The encrypted string output can be decrypted using #public_decrypt. */ static VALUE @@ -507,8 +507,8 @@ ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) * 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. + * Decrypt _string_, which has been encrypted with the public key, with the + * private key. _padding_ defaults to PKCS1_PADDING. */ static VALUE ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) @@ -659,7 +659,7 @@ ossl_rsa_blinding_off(VALUE self) * call-seq: * rsa.set_key(n, e, d) -> self * - * Sets +n+, +e+, +d+ for the RSA instance. + * Sets _n_, _e_, _d_ for the RSA instance. */ OSSL_PKEY_BN_DEF3(rsa, RSA, key, n, e, d) /* @@ -667,7 +667,7 @@ OSSL_PKEY_BN_DEF3(rsa, RSA, key, n, e, d) * call-seq: * rsa.set_factors(p, q) -> self * - * Sets +p+, +q+ for the RSA instance. + * Sets _p_, _q_ for the RSA instance. */ OSSL_PKEY_BN_DEF2(rsa, RSA, factors, p, q) /* @@ -675,7 +675,7 @@ OSSL_PKEY_BN_DEF2(rsa, RSA, factors, p, q) * call-seq: * rsa.set_crt_params(dmp1, dmq1, iqmp) -> self * - * Sets +dmp1+, +dmq1+, +iqmp+ for the RSA instance. They are calculated by + * 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. */ @@ -717,7 +717,7 @@ Init_ossl_rsa(void) rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1); rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); - rb_define_copy_func(cRSA, ossl_rsa_initialize_copy); + rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1); rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0); rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0); diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c index 688c525afa..c95857060a 100644 --- a/ext/openssl/ossl_rand.c +++ b/ext/openssl/ossl_rand.c @@ -16,7 +16,7 @@ VALUE eRandomError; * call-seq: * seed(str) -> str * - * ::seed is equivalent to ::add where +entropy+ is length of +str+. + * ::seed is equivalent to ::add where _entropy_ is length of _str_. */ static VALUE ossl_rand_seed(VALUE self, VALUE str) @@ -31,15 +31,15 @@ ossl_rand_seed(VALUE self, VALUE str) * call-seq: * add(str, entropy) -> self * - * Mixes the bytes from +str+ into the Pseudo Random Number Generator(PRNG) + * 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 + * 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. + * The _entropy_ argument is (the lower bound of) an estimate of how much + * randomness is contained in _str_, measured in bytes. * * === Example * @@ -62,7 +62,7 @@ ossl_rand_add(VALUE self, VALUE str, VALUE entropy) * call-seq: * load_random_file(filename) -> true * - * Reads bytes from +filename+ and adds them to the PRNG. + * Reads bytes from _filename_ and adds them to the PRNG. */ static VALUE ossl_rand_load_file(VALUE self, VALUE filename) @@ -79,7 +79,7 @@ ossl_rand_load_file(VALUE self, VALUE filename) * call-seq: * write_random_file(filename) -> true * - * Writes a number of random generated bytes (currently 1024) to +filename+ + * 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. */ @@ -98,7 +98,7 @@ ossl_rand_write_file(VALUE self, VALUE filename) * call-seq: * random_bytes(length) -> string * - * Generates +string+ with +length+ number of cryptographically strong + * Generates a String with _length_ number of cryptographically strong * pseudo-random bytes. * * === Example @@ -129,7 +129,7 @@ ossl_rand_bytes(VALUE self, VALUE len) * call-seq: * pseudo_bytes(length) -> string * - * Generates +string+ with +length+ number of pseudo-random bytes. + * Generates a String with _length_ number of pseudo-random bytes. * * Pseudo-random byte sequences generated by ::pseudo_bytes will be unique if * they are of sufficient length, but are not necessarily unpredictable. @@ -176,9 +176,9 @@ 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+. + * 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 + * Fetches _length_ number of bytes and uses ::add to seed the OpenSSL built-in * PRNG. */ static VALUE @@ -199,7 +199,7 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len) * 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) diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index f9c9d76fc2..18d5f5e9ec 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -46,54 +46,19 @@ static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode, id_i_verify_hostname; static ID id_i_io, id_i_context, id_i_hostname; -/* - * SSLContext class - */ -static const struct { - const char *name; - SSL_METHOD *(*func)(void); /* FIXME: constify when dropping 0.9.8 */ - int version; -} ossl_ssl_method_tab[] = { -#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) -#define OSSL_SSL_METHOD_ENTRY(name, version) \ - { #name, (SSL_METHOD *(*)(void))TLS_method, version }, \ - { #name"_server", (SSL_METHOD *(*)(void))TLS_server_method, version }, \ - { #name"_client", (SSL_METHOD *(*)(void))TLS_client_method, version } -#else -#define OSSL_SSL_METHOD_ENTRY(name, version) \ - { #name, (SSL_METHOD *(*)(void))name##_method, version }, \ - { #name"_server", (SSL_METHOD *(*)(void))name##_server_method, version }, \ - { #name"_client", (SSL_METHOD *(*)(void))name##_client_method, version } -#endif -#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL2_METHOD) && defined(HAVE_SSLV2_METHOD) - OSSL_SSL_METHOD_ENTRY(SSLv2, SSL2_VERSION), -#endif -#if !defined(OPENSSL_NO_SSL3) && !defined(OPENSSL_NO_SSL3_METHOD) && defined(HAVE_SSLV3_METHOD) - OSSL_SSL_METHOD_ENTRY(SSLv3, SSL3_VERSION), -#endif -#if !defined(OPENSSL_NO_TLS1) && !defined(OPENSSL_NO_TLS1_METHOD) - OSSL_SSL_METHOD_ENTRY(TLSv1, TLS1_VERSION), -#endif -#if !defined(OPENSSL_NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_1_METHOD) && defined(HAVE_TLSV1_1_METHOD) - OSSL_SSL_METHOD_ENTRY(TLSv1_1, TLS1_1_VERSION), -#endif -#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_2_METHOD) && defined(HAVE_TLSV1_2_METHOD) - OSSL_SSL_METHOD_ENTRY(TLSv1_2, TLS1_2_VERSION), -#endif - OSSL_SSL_METHOD_ENTRY(SSLv23, 0), -#undef OSSL_SSL_METHOD_ENTRY -}; - static int ossl_ssl_ex_vcb_idx; -static int ossl_ssl_ex_store_p; static int ossl_ssl_ex_ptr_idx; +static int ossl_sslctx_ex_ptr_idx; +#if !defined(HAVE_X509_STORE_UP_REF) +static int ossl_sslctx_ex_store_p; +#endif static void ossl_sslctx_free(void *ptr) { SSL_CTX *ctx = ptr; #if !defined(HAVE_X509_STORE_UP_REF) - if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1) + if (ctx && SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_store_p)) ctx->cert_store = NULL; #endif SSL_CTX_free(ctx); @@ -111,22 +76,24 @@ static VALUE ossl_sslctx_s_alloc(VALUE klass) { SSL_CTX *ctx; - long mode = SSL_MODE_ENABLE_PARTIAL_WRITE | - SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; + long mode = 0 | + SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | + SSL_MODE_RELEASE_BUFFERS; VALUE obj; -#ifdef SSL_MODE_RELEASE_BUFFERS - mode |= SSL_MODE_RELEASE_BUFFERS; -#endif - obj = TypedData_Wrap_Struct(klass, &ossl_sslctx_type, 0); +#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) + ctx = SSL_CTX_new(TLS_method()); +#else ctx = SSL_CTX_new(SSLv23_method()); +#endif if (!ctx) { ossl_raise(eSSLError, "SSL_CTX_new"); } SSL_CTX_set_mode(ctx, mode); RTYPEDDATA_DATA(obj) = ctx; - SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)obj); + SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj); #if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_ECDH_AUTO) /* We use SSL_CTX_set1_curves_list() to specify the curve used in ECDH. It @@ -143,49 +110,89 @@ ossl_sslctx_s_alloc(VALUE klass) return obj; } +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 }, +#ifdef TLS1_3_VERSION + { "TLS1_3", TLS1_3_VERSION }, +#endif + }; + + 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.ssl_version = :TLSv1 - * ctx.ssl_version = "SSLv23_client" + * ctx.set_minmax_proto_version(min, max) -> nil * - * Sets the SSL/TLS protocol version for the context. This forces connections to - * use only the specified protocol version. - * - * You can get a list of valid versions with OpenSSL::SSL::SSLContext::METHODS + * Sets the minimum and maximum supported protocol versions. See #min_version= + * and #max_version=. */ static VALUE -ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method) +ossl_sslctx_set_minmax_proto_version(VALUE self, VALUE min_v, VALUE max_v) { SSL_CTX *ctx; - const char *s; - VALUE m = ssl_method; - int i; + int min, max; GetSSLCTX(self, ctx); - if (RB_TYPE_P(ssl_method, T_SYMBOL)) - m = rb_sym2str(ssl_method); - s = StringValueCStr(m); - for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { - if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) { -#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) - int version = ossl_ssl_method_tab[i].version; -#endif - SSL_METHOD *method = ossl_ssl_method_tab[i].func(); - - if (SSL_CTX_set_ssl_version(ctx, method) != 1) - ossl_raise(eSSLError, "SSL_CTX_set_ssl_version"); + min = parse_proto_version(min_v); + max = parse_proto_version(max_v); + +#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION + if (!SSL_CTX_set_min_proto_version(ctx, min)) + ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version"); + if (!SSL_CTX_set_max_proto_version(ctx, max)) + ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version"); +#else + { + unsigned long sum = 0, opts = 0; + int i; + static const struct { + int ver; + unsigned long opts; + } options_map[] = { + { SSL2_VERSION, SSL_OP_NO_SSLv2 }, + { SSL3_VERSION, SSL_OP_NO_SSLv3 }, + { TLS1_VERSION, SSL_OP_NO_TLSv1 }, + { TLS1_1_VERSION, SSL_OP_NO_TLSv1_1 }, + { TLS1_2_VERSION, SSL_OP_NO_TLSv1_2 }, +# if defined(TLS1_3_VERSION) + { TLS1_3_VERSION, SSL_OP_NO_TLSv1_3 }, +# endif + }; -#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) - if (!SSL_CTX_set_min_proto_version(ctx, version)) - ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version"); - if (!SSL_CTX_set_max_proto_version(ctx, version)) - ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version"); -#endif - return ssl_method; - } + for (i = 0; i < numberof(options_map); i++) { + sum |= options_map[i].opts; + if (min && min > options_map[i].ver || max && max < options_map[i].ver) + opts |= options_map[i].opts; + } + SSL_CTX_clear_options(ctx, sum); + SSL_CTX_set_options(ctx, opts); } +#endif - ossl_raise(rb_eArgError, "unknown SSL method `%"PRIsVALUE"'.", m); + return Qnil; } static VALUE @@ -380,13 +387,10 @@ ossl_sslctx_session_get_cb(SSL *ssl, 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((const char *)buf, len)); @@ -399,7 +403,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; @@ -424,14 +428,11 @@ static int ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess) { VALUE ary, ssl_obj, sess_obj; - void *ptr; 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); SSL_SESSION_up_ref(sess); DATA_PTR(sess_obj) = sess; @@ -473,14 +474,18 @@ static void ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) { VALUE ary, sslctx_obj, sess_obj; - void *ptr; int state = 0; + /* + * This callback is also called for all sessions in the internal store + * when SSL_CTX_free() is called. + */ + if (rb_during_gc()) + return; + OSSL_Debug("SSL SESSION remove callback entered"); - if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL) - return; - sslctx_obj = (VALUE)ptr; + sslctx_obj = (VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx); sess_obj = rb_obj_alloc(cSSLSession); SSL_SESSION_up_ref(sess); DATA_PTR(sess_obj) = sess; @@ -516,7 +521,6 @@ ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg)) static VALUE ossl_sslctx_setup(VALUE self); -#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME static VALUE ossl_call_servername_cb(VALUE ary) { @@ -551,16 +555,13 @@ static int ssl_servername_cb(SSL *ssl, int *ad, void *arg) { VALUE ary, ssl_obj; - void *ptr; int state = 0; const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername) return SSL_TLSEXT_ERR_OK; - if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) - return SSL_TLSEXT_ERR_ALERT_FATAL; - 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_new2(servername)); @@ -573,18 +574,13 @@ ssl_servername_cb(SSL *ssl, int *ad, void *arg) return SSL_TLSEXT_ERR_OK; } -#endif static void ssl_renegotiation_cb(const SSL *ssl) { VALUE ssl_obj, sslctx_obj, cb; - void *ptr; - - if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) - ossl_raise(eSSLError, "SSL object could not be retrieved"); - ssl_obj = (VALUE)ptr; + 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; @@ -592,7 +588,7 @@ ssl_renegotiation_cb(const SSL *ssl) (void) rb_funcall(cb, rb_intern("call"), 1, ssl_obj); } -#if defined(HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB) || \ +#if !defined(OPENSSL_NO_NEXTPROTONEG) || \ defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) static VALUE ssl_npn_encode_protocol_i(VALUE cur, VALUE encoded) @@ -677,7 +673,7 @@ ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out, } #endif -#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB +#ifndef OPENSSL_NO_NEXTPROTONEG static int ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) @@ -737,7 +733,11 @@ ossl_sslctx_get_options(VALUE self) { SSL_CTX *ctx; GetSSLCTX(self, ctx); - return LONG2NUM(SSL_CTX_get_options(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)); } /* @@ -756,7 +756,7 @@ ossl_sslctx_set_options(VALUE self, VALUE options) if (NIL_P(options)) { SSL_CTX_set_options(ctx, SSL_OP_ALL); } else { - SSL_CTX_set_options(ctx, NUM2LONG(options)); + SSL_CTX_set_options(ctx, NUM2ULONG(options)); } return self; @@ -820,7 +820,7 @@ ossl_sslctx_setup(VALUE self) * X509_STORE_free() doesn't care it. * So we won't increment it but mark it by ex_data. */ - SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void *)1); + SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_store_p, ctx); #else /* Fixed in OpenSSL 1.0.2; bff9ce4db38b (master), 5b4b9ce976fc (1.0.2) */ X509_STORE_up_ref(store); #endif @@ -891,7 +891,7 @@ ossl_sslctx_setup(VALUE self) val = rb_attr_get(self, id_i_verify_depth); if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val)); -#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB +#ifndef OPENSSL_NO_NEXTPROTONEG val = rb_attr_get(self, id_i_npn_protocols); if (!NIL_P(val)) { VALUE encoded = ssl_encode_npn_protocols(val); @@ -946,13 +946,11 @@ ossl_sslctx_setup(VALUE self) OSSL_Debug("SSL SESSION remove callback added"); } -#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME 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"); } -#endif return Qtrue; } @@ -989,12 +987,7 @@ ossl_sslctx_get_ciphers(VALUE self) int i, num; GetSSLCTX(self, ctx); - if(!ctx){ - rb_warning("SSL_CTX is not initialized."); - return Qnil; - } ciphers = SSL_CTX_get_ciphers(ctx); - if (!ciphers) return rb_ary_new(); @@ -1204,7 +1197,7 @@ ossl_sslctx_set_security_level(VALUE self, VALUE value) * call-seq: * ctx.session_add(session) -> true | false * - * Adds +session+ to the session cache. + * Adds _session_ to the session cache. */ static VALUE ossl_sslctx_session_add(VALUE self, VALUE arg) @@ -1213,7 +1206,7 @@ ossl_sslctx_session_add(VALUE self, VALUE arg) SSL_SESSION *sess; GetSSLCTX(self, ctx); - SafeGetSSLSession(arg, sess); + GetSSLSession(arg, sess); return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse; } @@ -1222,7 +1215,7 @@ ossl_sslctx_session_add(VALUE self, VALUE arg) * call-seq: * ctx.session_remove(session) -> true | false * - * Removes +session+ from the session cache. + * Removes _session_ from the session cache. */ static VALUE ossl_sslctx_session_remove(VALUE self, VALUE arg) @@ -1231,7 +1224,7 @@ ossl_sslctx_session_remove(VALUE self, VALUE arg) SSL_SESSION *sess; GetSSLCTX(self, ctx); - SafeGetSSLSession(arg, sess); + GetSSLSession(arg, sess); return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse; } @@ -1358,9 +1351,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+. + * Removes sessions in the internal cache that have expired at _time_. */ static VALUE ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) @@ -1422,10 +1415,10 @@ ossl_ssl_s_alloc(VALUE klass) * SSLSocket.new(io) => aSSLSocket * SSLSocket.new(io, ctx) => aSSLSocket * - * Creates a new SSL socket from +io+ which must be a real IO object (not an + * 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 + * If _ctx_ is provided the SSL Sockets initial params will be taken from * the context. * * The OpenSSL::Buffering module provides additional IO methods. @@ -1485,7 +1478,7 @@ ossl_ssl_setup(VALUE self) GetOpenFile(io, fptr); rb_io_check_readable(fptr); rb_io_check_writable(fptr); - if (!SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr)))) + if (!SSL_set_fd(ssl, TO_SOCKET(fptr->fd))) ossl_raise(eSSLError, "SSL_set_fd"); return Qtrue; @@ -1528,6 +1521,9 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) int ret, ret2; VALUE cb_state; int nonblock = opts != Qfalse; +#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED) + unsigned long err; +#endif rb_ivar_set(self, ID_callback_state, Qnil); @@ -1551,16 +1547,33 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) case SSL_ERROR_WANT_WRITE: if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); - rb_io_wait_writable(FPTR_TO_FD(fptr)); + rb_io_wait_writable(fptr->fd); continue; case SSL_ERROR_WANT_READ: if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); - rb_io_wait_readable(FPTR_TO_FD(fptr)); + rb_io_wait_readable(fptr->fd); 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)); +#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED) + case SSL_ERROR_SSL: + 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 */ + ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s: %s (%s)", + funcname, ret2, errno, SSL_state_string_long(ssl), + err_msg, verify_msg); + } +#endif default: ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); } @@ -1693,8 +1706,6 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) io = rb_attr_get(self, id_i_io); GetOpenFile(io, fptr); if (ssl_started(ssl)) { - if(!nonblock && SSL_pending(ssl) <= 0) - rb_thread_wait_fd(FPTR_TO_FD(fptr)); for (;;){ nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LENINT(str)); switch(ssl_get_error(ssl, nread)){ @@ -1706,12 +1717,12 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) case SSL_ERROR_WANT_WRITE: if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); - rb_io_wait_writable(FPTR_TO_FD(fptr)); + rb_io_wait_writable(fptr->fd); continue; case SSL_ERROR_WANT_READ: if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); - rb_io_wait_readable(FPTR_TO_FD(fptr)); + rb_io_wait_readable(fptr->fd); continue; case SSL_ERROR_SYSCALL: if (!ERR_peek_error()) { @@ -1756,7 +1767,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) * ssl.sysread(length) => string * ssl.sysread(length, buffer) => buffer * - * Reads +length+ bytes from the SSL connection. If a pre-allocated +buffer+ + * Reads _length_ bytes from the SSL connection. If a pre-allocated _buffer_ * is provided the data will be written into it. */ static VALUE @@ -1775,7 +1786,7 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self) * 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+ + * Reads _length_ bytes from the SSL connection. If a pre-allocated _buffer_ * is provided the data will be written into it. */ static VALUE @@ -1812,12 +1823,12 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) case SSL_ERROR_WANT_WRITE: if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); - rb_io_wait_writable(FPTR_TO_FD(fptr)); + rb_io_wait_writable(fptr->fd); continue; case SSL_ERROR_WANT_READ: if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); - rb_io_wait_readable(FPTR_TO_FD(fptr)); + rb_io_wait_readable(fptr->fd); continue; case SSL_ERROR_SYSCALL: if (errno) rb_sys_fail(0); @@ -1845,7 +1856,7 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) * call-seq: * ssl.syswrite(string) => Integer * - * Writes +string+ to the SSL connection. + * Writes _string_ to the SSL connection. */ static VALUE ossl_ssl_write(VALUE self, VALUE str) @@ -1857,7 +1868,7 @@ ossl_ssl_write(VALUE self, VALUE str) * call-seq: * ssl.syswrite_nonblock(string) => Integer * - * Writes +string+ to the SSL connection in a non-blocking manner. Raises an + * Writes _string_ to the SSL connection in a non-blocking manner. Raises an * SSLError if writing would block. */ static VALUE @@ -2001,22 +2012,21 @@ ossl_ssl_get_version(VALUE self) } /* -* call-seq: -* ssl.cipher => [name, version, bits, alg_bits] -* -* The cipher being used for the current connection -*/ + * 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; GetSSL(self, ssl); - - cipher = (SSL_CIPHER *)SSL_get_current_cipher(ssl); - - return ossl_ssl_cipher_to_ary(cipher); + cipher = SSL_get_current_cipher(ssl); + return cipher ? ossl_ssl_cipher_to_ary(cipher) : Qnil; } /* @@ -2062,7 +2072,7 @@ ossl_ssl_pending(VALUE self) * call-seq: * ssl.session_reused? -> true | false * - * Returns true if a reused session was negotiated during the handshake. + * Returns +true+ if a reused session was negotiated during the handshake. */ static VALUE ossl_ssl_session_reused(VALUE self) @@ -2087,7 +2097,7 @@ ossl_ssl_set_session(VALUE self, VALUE arg1) SSL_SESSION *sess; GetSSL(self, ssl); - SafeGetSSLSession(arg1, sess); + GetSSLSession(arg1, sess); if (SSL_set_session(ssl, sess) != 1) ossl_raise(eSSLError, "SSL_set_session"); @@ -2095,7 +2105,6 @@ ossl_ssl_set_session(VALUE self, VALUE arg1) return arg1; } -#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME /* * call-seq: * ssl.hostname = hostname -> hostname @@ -2122,7 +2131,6 @@ ossl_ssl_set_hostname(VALUE self, VALUE arg) return arg; } -#endif /* * call-seq: @@ -2166,7 +2174,7 @@ ossl_ssl_get_client_ca_list(VALUE self) return ossl_x509name_sk2ary(ca); } -# ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB +# ifndef OPENSSL_NO_NEXTPROTONEG /* * call-seq: * ssl.npn_protocol => String | nil @@ -2242,9 +2250,6 @@ ossl_ssl_tmp_key(VALUE self) void Init_ossl_ssl(void) { - int i; - VALUE ary; - #if 0 mOSSL = rb_define_module("OpenSSL"); eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); @@ -2254,9 +2259,20 @@ Init_ossl_ssl(void) ID_callback_state = rb_intern("callback_state"); - ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_vcb_idx",0,0,0); - ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_store_p",0,0,0); - ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_ptr_idx",0,0,0); + ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_vcb_idx", 0, 0, 0); + if (ossl_ssl_ex_vcb_idx < 0) + ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index"); + 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"); +#if !defined(HAVE_X509_STORE_UP_REF) + ossl_sslctx_ex_store_p = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_store_p", 0, 0, 0); + if (ossl_sslctx_ex_store_p < 0) + ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index"); +#endif /* Document-module: OpenSSL::SSL * @@ -2272,7 +2288,7 @@ Init_ossl_ssl(void) * This module contains configuration information about the SSL extension, * for example if socket support is enabled, or the host name TLS extension * is enabled. Constants in this module will always be defined, but contain - * `true` or `false` values depending on the configuration of your OpenSSL + * +true+ or +false+ values depending on the configuration of your OpenSSL * installation. */ mSSLExtConfig = rb_define_module_under(mOSSL, "ExtConfig"); @@ -2356,12 +2372,12 @@ Init_ossl_ssl(void) * 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 + * 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 + * If the callback returns +false+, the chain verification is immediately * stopped and a bad_certificate alert is then sent. */ rb_attr(cSSLContext, rb_intern("verify_callback"), 1, 1, Qfalse); @@ -2428,7 +2444,7 @@ Init_ossl_ssl(void) /* * A callback invoked when a new session was negotiated. * - * The callback is invoked with an SSLSocket. If false is returned the + * 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("session_new_cb"), 1, 1, Qfalse); @@ -2440,17 +2456,7 @@ Init_ossl_ssl(void) */ rb_attr(cSSLContext, rb_intern("session_remove_cb"), 1, 1, Qfalse); -#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME rb_define_const(mSSLExtConfig, "HAVE_TLSEXT_HOST_NAME", Qtrue); -#else - rb_define_const(mSSLExtConfig, "HAVE_TLSEXT_HOST_NAME", Qfalse); -#endif - -#ifdef TLS_DH_anon_WITH_AES_256_GCM_SHA384 - rb_define_const(mSSLExtConfig, "TLS_DH_anon_WITH_AES_256_GCM_SHA384", Qtrue); -#else - rb_define_const(mSSLExtConfig, "TLS_DH_anon_WITH_AES_256_GCM_SHA384", Qfalse); -#endif /* * A callback invoked whenever a new handshake is initiated. May be used @@ -2474,7 +2480,7 @@ Init_ossl_ssl(void) * end */ rb_attr(cSSLContext, rb_intern("renegotiation_cb"), 1, 1, Qfalse); -#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB +#ifndef OPENSSL_NO_NEXTPROTONEG /* * An Enumerable of Strings. Each String represents a protocol to be * advertised as the list of supported protocols for Next Protocol @@ -2540,7 +2546,8 @@ Init_ossl_ssl(void) rb_define_alias(cSSLContext, "ssl_timeout", "timeout"); rb_define_alias(cSSLContext, "ssl_timeout=", "timeout="); - rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1); + rb_define_private_method(cSSLContext, "set_minmax_proto_version", + ossl_sslctx_set_minmax_proto_version, 2); rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0); rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1); rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1); @@ -2608,14 +2615,6 @@ Init_ossl_ssl(void) 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); - /* The list of available SSL/TLS methods */ - rb_define_const(cSSLContext, "METHODS", ary); - /* * Document-class: OpenSSL::SSL::SSLSocket */ @@ -2649,67 +2648,120 @@ Init_ossl_ssl(void) rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1); rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0); rb_define_method(cSSLSocket, "client_ca", ossl_ssl_get_client_ca_list, 0); -#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME /* #hostname is defined in lib/openssl/ssl.rb */ rb_define_method(cSSLSocket, "hostname=", ossl_ssl_set_hostname, 1); -#endif # ifdef HAVE_SSL_GET_SERVER_TMP_KEY rb_define_method(cSSLSocket, "tmp_key", ossl_ssl_tmp_key, 0); # endif # ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB rb_define_method(cSSLSocket, "alpn_protocol", ossl_ssl_alpn_protocol, 0); # endif -# ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB +# ifndef OPENSSL_NO_NEXTPROTONEG rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0); # endif #endif -#define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, LONG2NUM(SSL_##x)) + 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)); - 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); - /* Introduce constants included in OP_ALL. These constants are mostly for - * unset some bits in OP_ALL such as; - * ctx.options = OP_ALL & ~OP_DONT_INSERT_EMPTY_FRAGMENTS - */ - 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); - ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - ossl_ssl_def_const(OP_SINGLE_ECDH_USE); - ossl_ssl_def_const(OP_SINGLE_DH_USE); - ossl_ssl_def_const(OP_EPHEMERAL_RSA); - ossl_ssl_def_const(OP_CIPHER_SERVER_PREFERENCE); - 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); -#if defined(SSL_OP_NO_TLSv1_1) - ossl_ssl_def_const(OP_NO_TLSv1_1); + rb_define_const(mSSL, "OP_ALL", ULONG2NUM(SSL_OP_ALL)); + rb_define_const(mSSL, "OP_LEGACY_SERVER_CONNECT", ULONG2NUM(SSL_OP_LEGACY_SERVER_CONNECT)); +#ifdef SSL_OP_TLSEXT_PADDING /* OpenSSL 1.0.1h and OpenSSL 1.0.2 */ + rb_define_const(mSSL, "OP_TLSEXT_PADDING", ULONG2NUM(SSL_OP_TLSEXT_PADDING)); +#endif +#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG /* OpenSSL 1.0.1f and OpenSSL 1.0.2 */ + rb_define_const(mSSL, "OP_SAFARI_ECDHE_ECDSA_BUG", ULONG2NUM(SSL_OP_SAFARI_ECDHE_ECDSA_BUG)); #endif -#if defined(SSL_OP_NO_TLSv1_2) - ossl_ssl_def_const(OP_NO_TLSv1_2); +#ifdef SSL_OP_ALLOW_NO_DHE_KEX /* OpenSSL 1.1.1 */ + rb_define_const(mSSL, "OP_ALLOW_NO_DHE_KEX", ULONG2NUM(SSL_OP_ALLOW_NO_DHE_KEX)); #endif -#if defined(SSL_OP_NO_TICKET) - ossl_ssl_def_const(OP_NO_TICKET); + 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 */ + rb_define_const(mSSL, "OP_NO_ENCRYPT_THEN_MAC", ULONG2NUM(SSL_OP_NO_ENCRYPT_THEN_MAC)); #endif -#if defined(SSL_OP_NO_COMPRESSION) - ossl_ssl_def_const(OP_NO_COMPRESSION); + 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 */ + rb_define_const(mSSL, "OP_NO_RENEGOTIATION", ULONG2NUM(SSL_OP_NO_RENEGOTIATION)); #endif - 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_CRYPTOPRO_TLSEXT_BUG", ULONG2NUM(SSL_OP_CRYPTOPRO_TLSEXT_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)); +#ifdef SSL_OP_NO_TLSv1_3 /* OpenSSL 1.1.1 */ + rb_define_const(mSSL, "OP_NO_TLSv1_3", ULONG2NUM(SSL_OP_NO_TLSv1_3)); +#endif + + /* 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)); +#ifdef TLS1_3_VERSION /* OpenSSL 1.1.1 */ + /* TLS 1.3 */ + rb_define_const(mSSL, "TLS1_3_VERSION", INT2NUM(TLS1_3_VERSION)); +#endif + sym_exception = ID2SYM(rb_intern("exception")); sym_wait_readable = ID2SYM(rb_intern("wait_readable")); diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h index c1a3cd6c1d..535c56097c 100644 --- a/ext/openssl/ossl_ssl.h +++ b/ext/openssl/ossl_ssl.h @@ -24,11 +24,6 @@ } \ } while (0) -#define SafeGetSSLSession(obj, sess) do { \ - OSSL_Check_Kind((obj), cSSLSession); \ - GetSSLSession((obj), (sess)); \ -} while (0) - extern const rb_data_type_t ossl_ssl_type; extern const rb_data_type_t ossl_ssl_session_type; extern VALUE mSSL; diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c index 661f53eefb..5514087387 100644 --- a/ext/openssl/ossl_ssl_session.c +++ b/ext/openssl/ossl_ssl_session.c @@ -80,7 +80,7 @@ ossl_ssl_session_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); sess = RTYPEDDATA_DATA(self); /* XXX */ - SafeGetSSLSession(other, sess_other); + GetSSLSession(other, sess_other); sess_new = ASN1_dup((i2d_of_void *)i2d_SSL_SESSION, (d2i_of_void *)d2i_SSL_SESSION, (char *)sess_other); @@ -93,8 +93,8 @@ ossl_ssl_session_initialize_copy(VALUE self, VALUE other) return self; } -#if !defined(HAVE_SSL_SESSION_CMP) -int ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b) +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); @@ -108,23 +108,21 @@ int ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b) return CRYPTO_memcmp(a_sid, b_sid, a_len); } -#define SSL_SESSION_cmp(a, b) ossl_SSL_SESSION_cmp(a, b) -#endif /* * call-seq: * session1 == session2 -> boolean * - * Returns true if the two Session is the same, false if not. + * 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; GetSSLSession(val1, ctx1); - SafeGetSSLSession(val2, ctx2); + GetSSLSession(val2, ctx2); - switch (SSL_SESSION_cmp(ctx1, ctx2)) { + switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) { case 0: return Qtrue; default: return Qfalse; } @@ -319,7 +317,7 @@ void Init_ossl_ssl_session(void) rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc); rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1); - rb_define_copy_func(cSSLSession, ossl_ssl_session_initialize_copy); + rb_define_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1); rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1); diff --git a/ext/openssl/ossl_version.h b/ext/openssl/ossl_version.h index be3eebe1f2..4167c9c83d 100644 --- a/ext/openssl/ossl_version.h +++ b/ext/openssl/ossl_version.h @@ -10,6 +10,6 @@ #if !defined(_OSSL_VERSION_H_) #define _OSSL_VERSION_H_ -#define OSSL_VERSION "2.0.5" +#define OSSL_VERSION "2.1.0" #endif /* _OSSL_VERSION_H_ */ diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c index 19ec274ae1..8a061b0687 100644 --- a/ext/openssl/ossl_x509.c +++ b/ext/openssl/ossl_x509.c @@ -20,15 +20,10 @@ ossl_x509_time_adjust(ASN1_TIME *s, VALUE time) { time_t sec; -#if defined(HAVE_ASN1_TIME_ADJ) int off_days; ossl_time_split(time, &sec, &off_days); return X509_time_adj_ex(s, off_days, 0, &sec); -#else - sec = time_to_time_t(time); - return X509_time_adj(s, 0, &sec); -#endif } void @@ -112,21 +107,15 @@ Init_ossl_x509(void) DefX509Const(V_FLAG_INHIBIT_MAP); /* Set by Store#flags= and StoreContext#flags=. */ DefX509Const(V_FLAG_NOTIFY_POLICY); -#if defined(X509_V_FLAG_EXTENDED_CRL_SUPPORT) /* Set by Store#flags= and StoreContext#flags=. Enables some additional * features including support for indirect signed CRLs. */ DefX509Const(V_FLAG_EXTENDED_CRL_SUPPORT); -#endif -#if defined(X509_V_FLAG_USE_DELTAS) /* Set by Store#flags= and StoreContext#flags=. Uses delta CRLs. If not * specified, deltas are ignored. */ DefX509Const(V_FLAG_USE_DELTAS); -#endif -#if defined(X509_V_FLAG_CHECK_SS_SIGNATURE) /* Set by Store#flags= and StoreContext#flags=. Enables checking of the * signature of the root self-signed CA. */ DefX509Const(V_FLAG_CHECK_SS_SIGNATURE); -#endif #if defined(X509_V_FLAG_TRUSTED_FIRST) /* Set by Store#flags= and StoreContext#flags=. When constructing a * certificate chain, search the Store first for the issuer certificate. @@ -161,10 +150,8 @@ Init_ossl_x509(void) DefX509Const(PURPOSE_ANY); /* Set by Store#purpose=. OCSP helper. */ DefX509Const(PURPOSE_OCSP_HELPER); -#if defined(X509_PURPOSE_TIMESTAMP_SIGN) /* Set by Store#purpose=. Time stamps signer. */ DefX509Const(PURPOSE_TIMESTAMP_SIGN); -#endif DefX509Const(TRUST_COMPAT); DefX509Const(TRUST_SSL_CLIENT); @@ -173,9 +160,7 @@ Init_ossl_x509(void) DefX509Const(TRUST_OBJECT_SIGN); DefX509Const(TRUST_OCSP_SIGN); DefX509Const(TRUST_OCSP_REQUEST); -#if defined(X509_TRUST_TSA) DefX509Const(TRUST_TSA); -#endif DefX509Default(CERT_AREA, cert_area); DefX509Default(CERT_DIR, cert_dir); diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h index a60f7c3da3..4fadfa6b82 100644 --- a/ext/openssl/ossl_x509.h +++ b/ext/openssl/ossl_x509.h @@ -41,7 +41,6 @@ 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); @@ -54,7 +53,6 @@ extern VALUE eX509CRLError; VALUE ossl_x509crl_new(X509_CRL *); X509_CRL *GetX509CRLPtr(VALUE); -X509_CRL *DupX509CRLPtr(VALUE); void Init_ossl_x509crl(void); /* @@ -84,9 +82,7 @@ void Init_ossl_x509name(void); 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); /* @@ -106,11 +102,8 @@ extern VALUE cX509Store; extern VALUE cX509StoreContext; extern VALUE eX509StoreError; -VALUE ossl_x509store_new(X509_STORE *); X509_STORE *GetX509StorePtr(VALUE); -X509_STORE *DupX509StorePtr(VALUE); -X509_STORE_CTX *GetX509StCtxtPtr(VALUE); void Init_ossl_x509store(void); /* diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c index ae0b347b5f..60846cfe9d 100644 --- a/ext/openssl/ossl_x509attr.c +++ b/ext/openssl/ossl_x509attr.c @@ -23,10 +23,6 @@ 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 @@ -76,7 +72,7 @@ GetX509AttrPtr(VALUE obj) { X509_ATTRIBUTE *attr; - SafeGetX509Attr(obj, attr); + GetX509Attr(obj, attr); return attr; } @@ -134,7 +130,7 @@ ossl_x509attr_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetX509Attr(self, attr); - SafeGetX509Attr(other, attr_other); + GetX509Attr(other, attr_other); attr_new = X509_ATTRIBUTE_dup(attr_other); if (!attr_new) @@ -319,7 +315,7 @@ Init_ossl_x509attr(void) cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject); rb_define_alloc_func(cX509Attr, ossl_x509attr_alloc); rb_define_method(cX509Attr, "initialize", ossl_x509attr_initialize, -1); - rb_define_copy_func(cX509Attr, ossl_x509attr_initialize_copy); + rb_define_method(cX509Attr, "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 87086a7c59..003a9c1949 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -23,10 +23,6 @@ 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 @@ -71,46 +67,12 @@ ossl_x509_new(X509 *x509) return obj; } -VALUE -ossl_x509_new_from_file(VALUE filename) -{ - X509 *x509; - FILE *fp; - VALUE obj; - - rb_check_safe_obj(filename); - obj = NewX509(cX509Cert); - if (!(fp = fopen(StringValueCStr(filename), "r"))) { - ossl_raise(eX509CertError, "%s", strerror(errno)); - } - rb_fd_fix_cloexec(fileno(fp)); - x509 = PEM_read_X509(fp, NULL, NULL, NULL); - /* - * prepare for DER... -#if !defined(OPENSSL_NO_FP_API) - if (!x509) { - (void)ERR_get_error(); - rewind(fp); - - x509 = d2i_X509_fp(fp, NULL); - } -#endif - */ - fclose(fp); - if (!x509) { - ossl_raise(eX509CertError, NULL); - } - SetX509(obj, x509); - - return obj; -} - X509 * GetX509CertPtr(VALUE obj) { X509 *x509; - SafeGetX509(obj, x509); + GetX509(obj, x509); return x509; } @@ -120,7 +82,7 @@ DupX509CertPtr(VALUE obj) { X509 *x509; - SafeGetX509(obj, x509); + GetX509(obj, x509); X509_up_ref(x509); @@ -184,7 +146,7 @@ ossl_x509_copy(VALUE self, VALUE other) if (self == other) return self; GetX509(self, a); - SafeGetX509(other, b); + GetX509(other, b); x509 = X509_dup(b); if (!x509) ossl_raise(eX509CertError, NULL); @@ -573,7 +535,7 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest) const EVP_MD *md; pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); GetX509(self, x509); if (!X509_sign(x509, pkey, md)) { ossl_raise(eX509CertError, NULL); @@ -586,7 +548,8 @@ 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 ossl_x509_verify(VALUE self, VALUE key) @@ -610,9 +573,10 @@ ossl_x509_verify(VALUE self, VALUE key) /* * 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 ossl_x509_check_private_key(VALUE self, VALUE key) @@ -829,7 +793,7 @@ Init_ossl_x509cert(void) 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); diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index 035025ab69..5ecd7ea0b2 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -23,10 +23,6 @@ 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 @@ -56,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); - X509_CRL_up_ref(crl); + GetX509CRL(obj, crl); return crl; } @@ -137,7 +122,7 @@ ossl_x509crl_copy(VALUE self, VALUE other) 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); } @@ -223,10 +208,14 @@ 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_get0_lastUpdate(crl)); + return asn1time_to_time(time); } static VALUE @@ -250,10 +239,14 @@ 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_get0_nextUpdate(crl)); + return asn1time_to_time(time); } static VALUE @@ -354,7 +347,7 @@ ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest) GetX509CRL(self, crl); pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); if (!X509_CRL_sign(crl, pkey, md)) { ossl_raise(eX509CRLError, NULL); } @@ -520,7 +513,7 @@ Init_ossl_x509crl(void) 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); diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c index b92b0786b2..2d9a7a31e8 100644 --- a/ext/openssl/ossl_x509ext.c +++ b/ext/openssl/ossl_x509ext.c @@ -23,10 +23,6 @@ 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 { \ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509extfactory_type, 0); \ if (!((ctx) = OPENSSL_malloc(sizeof(X509V3_CTX)))) \ @@ -90,7 +86,7 @@ GetX509ExtPtr(VALUE obj) { X509_EXTENSION *ext; - SafeGetX509Ext(obj, ext); + GetX509Ext(obj, ext); return ext; } @@ -263,15 +259,15 @@ ossl_x509ext_alloc(VALUE klass) /* * call-seq: - * OpenSSL::X509::Extension.new asn1 - * OpenSSL::X509::Extension.new name, value - * OpenSSL::X509::Extension.new name, value, critical + * 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 +asn1+ data or from an extension +name+ - * and +value+. The +name+ may be either an OID or an extension name. If - * +critical+ is true the extension is marked critical. + * 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) @@ -305,7 +301,7 @@ ossl_x509ext_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetX509Ext(self, ext); - SafeGetX509Ext(other, ext_other); + GetX509Ext(other, ext_other); ext_new = X509_EXTENSION_dup(ext_other); if (!ext_new) @@ -469,7 +465,7 @@ Init_ossl_x509ext(void) cX509Ext = rb_define_class_under(mX509, "Extension", rb_cObject); rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc); rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1); - rb_define_copy_func(cX509Ext, ossl_x509ext_initialize_copy); + rb_define_method(cX509Ext, "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); diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index ac98c1b94c..b2063954d1 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -23,10 +23,6 @@ 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")) @@ -81,7 +77,7 @@ GetX509NamePtr(VALUE obj) { X509_NAME *name; - SafeGetX509Name(obj, name); + GetX509Name(obj, name); return name; } @@ -135,15 +131,15 @@ ossl_x509name_init_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args)) * * 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+. + * 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 + * See add_entry for a description of the _distinguished_name_ Array's * contents */ static VALUE @@ -188,7 +184,7 @@ ossl_x509name_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetX509Name(self, name); - SafeGetX509Name(other, name_other); + GetX509Name(other, name_other); name_new = X509_NAME_dup(name_other); if (!name_new) @@ -202,9 +198,9 @@ ossl_x509name_initialize_copy(VALUE self, VALUE other) /* * 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+ + * 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 @@ -213,24 +209,39 @@ ossl_x509name_initialize_copy(VALUE self, VALUE other) * 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; + VALUE oid, value, type, opts, kwargs[2]; + static ID kwargs_ids[2]; const char *oid_name; + int loc = -1, set = 0; - rb_scan_args(argc, argv, "21", &oid, &value, &type); + 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, oid_name, NUM2INT(type), - (const unsigned char *)RSTRING_PTR(value), RSTRING_LENINT(value), -1, 0)) { - ossl_raise(eX509NameError, NULL); - } - + (unsigned char *)RSTRING_PTR(value), + RSTRING_LENINT(value), loc, set)) + ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt"); return self; } @@ -249,42 +260,73 @@ ossl_x509name_to_s_old(VALUE self) return str; } +static VALUE +x509name_print(VALUE self, unsigned long iflag) +{ + X509_NAME *name; + BIO *out; + + GetX509Name(self, name); + out = BIO_new(BIO_s_mem()); + if (!out) + ossl_raise(eX509NameError, NULL); + if (!X509_NAME_print_ex(out, name, 0, iflag)) { + BIO_free(out); + ossl_raise(eX509NameError, "X509_NAME_print_ex"); + } + return ossl_membio2str(out); +} + /* * call-seq: - * name.to_s => string - * name.to_s(flags) => string + * name.to_s -> string + * name.to_s(format) -> string * - * Returns this name as a Distinguished Name string. +flags+ may be one of: + * 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 + * is used. */ 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)) + 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 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); + 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], ...] @@ -338,18 +380,18 @@ 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 => integer - * name.<=> other => integer + * name.cmp(other) -> -1 | 0 | 1 + * name <=> other -> -1 | 0 | 1 * - * 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. + * 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. */ static VALUE ossl_x509name_cmp(VALUE self, VALUE other) @@ -365,9 +407,9 @@ ossl_x509name_cmp(VALUE self, VALUE other) /* * call-seq: - * name.eql? other => boolean + * name.eql?(other) -> true | false * - * Returns true if +name+ and +other+ refer to the same hash key. + * Returns true if _name_ and _other_ refer to the same hash key. */ static VALUE ossl_x509name_eql(VALUE self, VALUE other) @@ -398,7 +440,6 @@ ossl_x509name_hash(VALUE self) return ULONG2NUM(hash); } -#ifdef HAVE_X509_NAME_HASH_OLD /* * call-seq: * name.hash_old => integer @@ -417,7 +458,6 @@ ossl_x509name_hash_old(VALUE self) return ULONG2NUM(hash); } -#endif /* * call-seq: @@ -478,17 +518,17 @@ Init_ossl_x509name(void) rb_define_alloc_func(cX509Name, ossl_x509name_alloc); rb_define_method(cX509Name, "initialize", ossl_x509name_initialize, -1); - rb_define_copy_func(cX509Name, ossl_x509name_initialize_copy); + rb_define_method(cX509Name, "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); -#ifdef HAVE_X509_NAME_HASH_OLD rb_define_method(cX509Name, "hash_old", ossl_x509name_hash_old, 0); -#endif rb_define_method(cX509Name, "to_der", ossl_x509name_to_der, 0); utf8str = INT2NUM(V_ASN1_UTF8STRING); diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c index 15bc7052d3..9f20dba311 100644 --- a/ext/openssl/ossl_x509req.c +++ b/ext/openssl/ossl_x509req.c @@ -23,10 +23,6 @@ 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 @@ -51,49 +47,16 @@ static const rb_data_type_t ossl_x509req_type = { /* * Public functions */ -VALUE -ossl_x509req_new(X509_REQ *req) -{ - X509_REQ *new; - VALUE obj; - - obj = NewX509Req(cX509Req); - if (!req) { - new = X509_REQ_new(); - } else { - new = X509_REQ_dup(req); - } - if (!new) { - ossl_raise(eX509ReqError, NULL); - } - SetX509Req(obj, new); - - return obj; -} - 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 */ @@ -145,7 +108,7 @@ ossl_x509req_copy(VALUE self, VALUE other) 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); } @@ -347,7 +310,7 @@ ossl_x509req_sign(VALUE self, VALUE key, VALUE digest) GetX509Req(self, req); pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = GetDigestPtr(digest); + md = ossl_evp_get_digestbyname(digest); if (!X509_REQ_sign(req, pkey, md)) { ossl_raise(eX509ReqError, NULL); } @@ -457,7 +420,7 @@ Init_ossl_x509req(void) 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); diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c index 7960ea349e..85489efdb2 100644 --- a/ext/openssl/ossl_x509revoked.c +++ b/ext/openssl/ossl_x509revoked.c @@ -23,10 +23,6 @@ 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 @@ -76,7 +72,7 @@ DupX509RevokedPtr(VALUE obj) { X509_REVOKED *rev, *new; - SafeGetX509Rev(obj, rev); + GetX509Rev(obj, rev); if (!(new = X509_REVOKED_dup(rev))) { ossl_raise(eX509RevError, NULL); } @@ -116,7 +112,7 @@ ossl_x509revoked_initialize_copy(VALUE self, VALUE other) rb_check_frozen(self); GetX509Rev(self, rev); - SafeGetX509Rev(other, rev_other); + GetX509Rev(other, rev_other); rev_new = X509_REVOKED_dup(rev_other); if (!rev_new) @@ -159,10 +155,14 @@ 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(X509_REVOKED_get0_revocationDate(rev)); + return asn1time_to_time(time); } static VALUE @@ -267,7 +267,7 @@ Init_ossl_x509revoked(void) rb_define_alloc_func(cX509Rev, ossl_x509revoked_alloc); rb_define_method(cX509Rev, "initialize", ossl_x509revoked_initialize, -1); - rb_define_copy_func(cX509Rev, ossl_x509revoked_initialize_copy); + rb_define_method(cX509Rev, "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); diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 4becc8e3cd..c6cf67ad5d 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -23,10 +23,6 @@ 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 NewX509StCtx(klass) \ TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, 0) @@ -42,10 +38,6 @@ 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) /* * Verify callback stuff @@ -130,34 +122,12 @@ static const rb_data_type_t ossl_x509store_type = { /* * Public functions */ -VALUE -ossl_x509store_new(X509_STORE *store) -{ - VALUE obj; - - obj = NewX509Store(cX509Store); - SetX509Store(obj, store); - - return obj; -} - X509_STORE * GetX509StorePtr(VALUE obj) { X509_STORE *store; - SafeGetX509Store(obj, store); - - return store; -} - -X509_STORE * -DupX509StorePtr(VALUE obj) -{ - X509_STORE *store; - - SafeGetX509Store(obj, store); - X509_STORE_up_ref(store); + GetX509Store(obj, store); return store; } @@ -242,9 +212,9 @@ ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) /* * call-seq: - * store.flags = flag + * store.flags = flags * - * Sets +flag+ to the Store. +flag+ consists of zero or more of the constants + * Sets _flags_ to the Store. _flags_ consists of zero or more of the constants * defined in with name V_FLAG_* or'ed together. */ static VALUE @@ -263,7 +233,7 @@ ossl_x509store_set_flags(VALUE self, VALUE flags) * call-seq: * store.purpose = purpose * - * Sets the store's purpose to +purpose+. If specified, the verifications on + * Sets the store's purpose to _purpose_. If specified, the verifications on * the store will check every untrusted certificate's extensions are consistent * with the purpose. The purpose is specified by constants: * @@ -322,8 +292,9 @@ ossl_x509store_set_time(VALUE self, VALUE time) * call-seq: * store.add_file(file) -> self * - * Adds the certificates in +file+ to the certificate store. The +file+ can - * contain multiple PEM-encoded certificates. + * 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. */ static VALUE ossl_x509store_add_file(VALUE self, VALUE file) @@ -359,7 +330,7 @@ ossl_x509store_add_file(VALUE self, VALUE file) * call-seq: * store.add_path(path) -> self * - * Adds +path+ as the hash dir to be looked up by the store. + * Adds _path_ as the hash dir to be looked up by the store. */ static VALUE ossl_x509store_add_path(VALUE self, VALUE dir) @@ -386,7 +357,7 @@ ossl_x509store_add_path(VALUE self, VALUE dir) * call-seq: * store.set_default_paths * - * Configures +store+ to look up CA certificates from the system default + * 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: * @@ -410,7 +381,7 @@ ossl_x509store_set_default_paths(VALUE self) * call-seq: * store.add_cert(cert) * - * Adds the OpenSSL::X509::Certificate +cert+ to the certificate store. + * Adds the OpenSSL::X509::Certificate _cert_ to the certificate store. */ static VALUE ossl_x509store_add_cert(VALUE self, VALUE arg) @@ -431,7 +402,7 @@ ossl_x509store_add_cert(VALUE self, VALUE arg) * call-seq: * store.add_crl(crl) -> self * - * Adds the OpenSSL::X509::CRL +crl+ to the store. + * Adds the OpenSSL::X509::CRL _crl_ to the store. */ static VALUE ossl_x509store_add_crl(VALUE self, VALUE arg) @@ -456,15 +427,15 @@ static VALUE ossl_x509stctx_get_chain(VALUE); * call-seq: * store.verify(cert, chain = nil) -> true | false * - * Performs a certificate verification on the OpenSSL::X509::Certificate +cert+. + * Performs a certificate verification on the OpenSSL::X509::Certificate _cert_. * - * +chain+ can be an array of OpenSSL::X509::Certificate that is used to + * _chain_ can be an array of OpenSSL::X509::Certificate that is used to * construct the certificate chain. * * If a block is given, it overrides the callback set by #verify_callback=. * * After finishing the verification, the error information can be retrieved by - * #error, #error_string, and the resuting complete certificate chain can be + * #error, #error_string, and the resulting complete certificate chain can be * retrieved by #chain. */ static VALUE @@ -561,7 +532,7 @@ ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "12", &store, &cert, &chain); GetX509StCtx(self, ctx); - SafeGetX509Store(store, x509st); + GetX509Store(store, x509st); if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */ if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain); if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ diff --git a/ext/openssl/ruby_missing.h b/ext/openssl/ruby_missing.h index 8dacc8266e..b8a0a0c180 100644 --- a/ext/openssl/ruby_missing.h +++ b/ext/openssl/ruby_missing.h @@ -10,11 +10,6 @@ #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) - -#define FPTR_TO_FD(fptr) ((fptr)->fd) - #ifndef RB_INTEGER_TYPE_P /* for Ruby 2.3 compatibility */ #define RB_INTEGER_TYPE_P(obj) (RB_FIXNUM_P(obj) || RB_TYPE_P(obj, T_BIGNUM)) diff --git a/test/openssl/fixtures/pkey/dh1024.pem b/test/openssl/fixtures/pkey/dh1024.pem new file mode 100644 index 0000000000..f99c757f21 --- /dev/null +++ b/test/openssl/fixtures/pkey/dh1024.pem @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAKnKQ8MNK6nYZzLrrcuTsLxuiJGXoOO5gT+tljOTbHBuiktdMTITzIY0 +pFxIvjG05D7HoBZQfrR0c92NGWPkAiCkhQKB8JCbPVzwNLDy6DZ0pmofDKrEsYHG +AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC +-----END DH PARAMETERS----- diff --git a/test/openssl/fixtures/pkey/dsa1024.pem b/test/openssl/fixtures/pkey/dsa1024.pem new file mode 100644 index 0000000000..1bf498895e --- /dev/null +++ b/test/openssl/fixtures/pkey/dsa1024.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBugIBAAKBgQCH9aAoXvWWThIjkA6D+nI1F9ksF9iDq594rkiGNOT9sPDOdB+n +D+qeeeeloRlj19ymCSADPI0ZLRgkchkAEnY2RnqnhHOjVf/roGgRbW+iQDMbQ9wa +/pvc6/fAbsu1goE1hBYjm98/sZEeXavj8tR56IXnjF1b6Nx0+sgeUKFKEQIVAMiz +4BJUFeTtddyM4uadBM7HKLPRAoGAZdLBSYNGiij7vAjesF5mGUKTIgPd+JKuBEDx +OaBclsgfdoyoF/TMOkIty+PVlYD+//Vl2xnoUEIRaMXHwHfm0r2xUX++oeRaSScg +YizJdUxe5jvBuBszGPRc/mGpb9YvP0sB+FL1KmuxYmdODfCe51zl8uM/CVhouJ3w +DjmRGscCgYAuFlfC7p+e8huCKydfcv/beftqjewiOPpQ3u5uI6KPCtCJPpDhs3+4 +IihH2cPsAlqwGF4tlibW1+/z/OZ1AZinPK3y7b2jSJASEaPeEltVzB92hcd1khk2 +jTYcmSsV4VddplOPK9czytR/GbbibxsrhhgZUbd8LPbvIgaiadJ1PgIUBnJ/5vN2 +CVArsEzlPUCbohPvZnE= +-----END DSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/dsa256.pem b/test/openssl/fixtures/pkey/dsa256.pem new file mode 100644 index 0000000000..d9a407f736 --- /dev/null +++ b/test/openssl/fixtures/pkey/dsa256.pem @@ -0,0 +1,8 @@ +-----BEGIN DSA PRIVATE KEY----- +MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE +9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed +AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM +3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT +b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn +ISNX5cMzFHRW3Q== +-----END DSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/dsa512.pem b/test/openssl/fixtures/pkey/dsa512.pem new file mode 100644 index 0000000000..962c41cc67 --- /dev/null +++ b/test/openssl/fixtures/pkey/dsa512.pem @@ -0,0 +1,8 @@ +-----BEGIN DSA PRIVATE KEY----- +MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok +RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D +AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR +S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++ +Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S +55jreJD3Se3slps= +-----END DSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/p256.pem b/test/openssl/fixtures/pkey/p256.pem new file mode 100644 index 0000000000..97c97d9f9d --- /dev/null +++ b/test/openssl/fixtures/pkey/p256.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 +AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt +CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== +-----END EC PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/rsa1024.pem b/test/openssl/fixtures/pkey/rsa1024.pem new file mode 100644 index 0000000000..464de074be --- /dev/null +++ b/test/openssl/fixtures/pkey/rsa1024.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx +aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/ +Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB +AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0 +maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T +gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572 +74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE +JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX +sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII +8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA +wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi +qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD +dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA== +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/rsa2048.pem b/test/openssl/fixtures/pkey/rsa2048.pem new file mode 100644 index 0000000000..ac89cd88ed --- /dev/null +++ b/test/openssl/fixtures/pkey/rsa2048.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN +s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign +4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D +kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl +NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J +DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb +I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq +PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V +seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0 +Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc +VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW +wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G +0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj +XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb +aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n +h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw +Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k +IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb +v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId +U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr +vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS +Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC +9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41 +gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG +4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw== +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb index 91ae2cfd0c..3e7f8c13ce 100644 --- a/test/openssl/test_asn1.rb +++ b/test/openssl/test_asn1.rb @@ -1,10 +1,12 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestASN1 < OpenSSL::TestCase - def test_decode + def test_decode_x509_certificate subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") - key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + key = Fixtures.pkey("rsa1024") now = Time.at(Time.now.to_i) # suppress usec s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf exts = [ @@ -128,9 +130,9 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase assert_equal(OpenSSL::ASN1::Sequence, spkey.class) assert_equal(2, spkey.value.size) assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class) - assert_equal(143085709396403084580358323862163416700436550432664688288860593156058579474547937626086626045206357324274536445865308750491138538454154232826011964045825759324933943290377903384882276841880081931690695505836279972214003660451338124170055999155993192881685495391496854691199517389593073052473319331505702779271, spkey.value[0].value) + assert_equal(cert.public_key.n, spkey.value[0].value) assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class) - assert_equal(65537, spkey.value[1].value) + assert_equal(cert.public_key.e, spkey.value[1].value) extensions = tbs_cert.value[7] assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class) @@ -191,66 +193,8 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase assert_equal(cululated_sig, sig_val.value) end - def test_encode_boolean - encode_decode_test(OpenSSL::ASN1::Boolean, [true, false]) - end - - def test_encode_integer - encode_decode_test(OpenSSL::ASN1::Integer, [72, -127, -128, 128, -1, 0, 1, -(2**12345), 2**12345]) - end - - def test_encode_nil - m = OpenSSL::ASN1 - [ - m::Boolean, m::Integer, m::BitString, m::OctetString, - m::ObjectId, m::Enumerated, m::UTF8String, m::UTCTime, - m::GeneralizedTime, m::Sequence, m::Set - ].each do |klass| - #Primitives raise TypeError, Constructives NoMethodError - assert_raise(TypeError, NoMethodError) { klass.send(:new, nil).to_der } - end - end - - def encode_decode_test(type, values) - values.each do |v| - assert_equal(v, OpenSSL::ASN1.decode(type.new(v).to_der).value) - end - end - - def test_decode_pem #should fail gracefully (cf. [ruby-dev:44542]) - pem = <<-_EOS_ ------BEGIN CERTIFICATE----- -MIIC8zCCAdugAwIBAgIBATANBgkqhkiG9w0BAQUFADA9MRMwEQYKCZImiZPyLGQB -GRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMQswCQYDVQQDDAJDQTAe -Fw0xMTA5MjUxMzQ4MjZaFw0xMTA5MjUxNDQ4MjZaMD0xEzARBgoJkiaJk/IsZAEZ -FgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5LWxhbmcxCzAJBgNVBAMMAkNBMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuV9ht9J7k4NBs38jOXvvTKY9 -gW8nLICSno5EETR1cuF7i4pNs9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enen -fzq/t/e/1IRW0wkJUJUFQign4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWm -qbjs07JbuS4QQGGXLc+Su96DkYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v6 -8JkRFIhdGlb6JL8fllf/A/blNwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX -9KZYcU00mOX+fdxOSnGqS/8JDRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wID -AQABMA0GCSqGSIb3DQEBBQUAA4IBAQAiAtrIr1pLX4GYN5klviWKb8HC9ICYuAFI -NfE3FwqzErEVXotuMe3yPVyB3Bv6rjYY/x5EtS5+WPTbHlvHZTkfcsnTpizcn4mW -dJ6dDRaFCHt1YKKjUxqBt9lvvrc3nReYZN/P+s1mrDhWzGf8iPZgf8sFUHgnaK7W -CXRVXmPFgCDRNpDDVQ0MQkr509yYfTH+dujNzqTCwSvkyZFyQ7Oe8Yj0VR6kquG3 -rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm -/93PnPG1IvPjYNd5VlV+sXSnaxQn974HRCsMv7jA8BD6IgSaX6WK ------END CERTIFICATE----- - _EOS_ - assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1.decode(pem) } - assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1.decode_all(pem) } - end - - def test_primitive_cannot_set_infinite_length - prim = OpenSSL::ASN1::Integer.new(50) - assert_equal false, prim.infinite_length - assert_not_respond_to prim, :infinite_length= - end - def test_decode_all - expected = %w{ 02 01 01 02 01 02 02 01 03 } - raw = [expected.join('')].pack('H*') + raw = B(%w{ 02 01 01 02 01 02 02 01 03 }) ary = OpenSSL::ASN1.decode_all(raw) assert_equal(3, ary.size) ary.each_with_index do |asn1, i| @@ -259,288 +203,401 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm end end - def test_decode_utctime - expected = Time.at 1374535380 - assert_equal expected, OpenSSL::ASN1.decode("\x17\v1307222323Z").value - - expected += 17 - assert_equal expected, OpenSSL::ASN1.decode("\x17\r130722232317Z").value - end - - def test_encode_utctime_2k38 - encoded = OpenSSL::ASN1::UTCTime(2 ** 31 - 1).to_der - assert_equal 2 ** 31 - 1, OpenSSL::ASN1.decode(encoded).value.to_i - - encoded = OpenSSL::ASN1::UTCTime(2 ** 31).to_der - assert_equal 2 ** 31, OpenSSL::ASN1.decode(encoded).value.to_i + def test_object_id_register + oid = "1.2.34.56789" + pend "OID 1.2.34.56789 is already registered" if OpenSSL::ASN1::ObjectId(oid).sn + assert_equal true, OpenSSL::ASN1::ObjectId.register(oid, "ossl-test-sn", "ossl-test-ln") + obj = OpenSSL::ASN1::ObjectId(oid) + assert_equal oid, obj.oid + assert_equal "ossl-test-sn", obj.sn + assert_equal "ossl-test-ln", obj.ln + obj = encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId("ossl-test-ln") + assert_equal "ossl-test-sn", obj.value end - def test_decode_generalisedtime - expected = Time.at 1481225640 - assert_equal expected, OpenSSL::ASN1.decode("\x18\x0D201612081934Z").value - - expected += 29 - assert_equal expected, OpenSSL::ASN1.decode("\x18\x0F20161208193429Z").value + def test_end_of_content + encode_decode_test B(%w{ 00 00 }), OpenSSL::ASN1::EndOfContent.new + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 00 01 00 })) + } end - def test_decode_enumerated - encoded = OpenSSL::ASN1.Enumerated(0).to_der - assert_equal "\x0a\x01\x00".b, encoded - assert_equal encoded, OpenSSL::ASN1.decode(encoded).to_der + def test_boolean + encode_decode_test B(%w{ 01 01 00 }), OpenSSL::ASN1::Boolean.new(false) + encode_decode_test B(%w{ 01 01 FF }), OpenSSL::ASN1::Boolean.new(true) + decode_test B(%w{ 01 01 01 }), OpenSSL::ASN1::Boolean.new(true) + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 01 02 00 00 })) + } end - def test_create_inf_length_primitive - expected = %w{ 24 80 04 01 61 00 00 } - raw = [expected.join('')].pack('H*') - content = [OpenSSL::ASN1::OctetString.new("a"), OpenSSL::ASN1::EndOfContent.new] - cons = OpenSSL::ASN1::Constructive.new(content, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - cons.infinite_length = true - assert_equal(nil, cons.tagging) - assert_equal(raw, cons.to_der) - asn1 = OpenSSL::ASN1.decode(raw) - assert(asn1.infinite_length) - assert_equal(raw, asn1.to_der) + def test_integer + encode_decode_test B(%w{ 02 01 00 }), OpenSSL::ASN1::Integer.new(0) + encode_decode_test B(%w{ 02 01 48 }), OpenSSL::ASN1::Integer.new(72) + encode_decode_test B(%w{ 02 02 00 80 }), OpenSSL::ASN1::Integer.new(128) + encode_decode_test B(%w{ 02 01 81 }), OpenSSL::ASN1::Integer.new(-127) + encode_decode_test B(%w{ 02 01 80 }), OpenSSL::ASN1::Integer.new(-128) + encode_decode_test B(%w{ 02 01 FF }), OpenSSL::ASN1::Integer.new(-1) + encode_decode_test B(%w{ 02 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(2 ** 64) + encode_decode_test B(%w{ 02 09 FF 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(-(2 ** 64)) + # FIXME: OpenSSL < 1.1.0 does not fail + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 02 02 00 7F })) + # } + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 02 02 FF 80 })) + # } + end + + def test_enumerated + encode_decode_test B(%w{ 0A 01 00 }), OpenSSL::ASN1::Enumerated.new(0) + encode_decode_test B(%w{ 0A 01 48 }), OpenSSL::ASN1::Enumerated.new(72) + encode_decode_test B(%w{ 0A 02 00 80 }), OpenSSL::ASN1::Enumerated.new(128) + encode_decode_test B(%w{ 0A 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Enumerated.new(2 ** 64) + end + + def test_bitstring + encode_decode_test B(%w{ 03 01 00 }), OpenSSL::ASN1::BitString.new(B(%w{})) + encode_decode_test B(%w{ 03 02 00 01 }), OpenSSL::ASN1::BitString.new(B(%w{ 01 })) + obj = OpenSSL::ASN1::BitString.new(B(%w{ F0 })) + obj.unused_bits = 4 + encode_decode_test B(%w{ 03 02 04 F0 }), obj + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 03 00 })) + } + # OpenSSL < OpenSSL_1_0_1k and LibreSSL ignore the error + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 03 03 08 FF 00 })) + # } + # OpenSSL does not seem to prohibit this, though X.690 8.6.2.3 (15/08) does + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 03 01 04 })) + # } + assert_raise(OpenSSL::ASN1::ASN1Error) { + obj = OpenSSL::ASN1::BitString.new(B(%w{ FF FF })) + obj.unused_bits = 8 + obj.to_der + } end - def test_cons_without_inf_length_forbidden - assert_raise(OpenSSL::ASN1::ASN1Error) do - val = OpenSSL::ASN1::OctetString.new('a') - cons = OpenSSL::ASN1::Constructive.new([val], OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - cons.to_der - end + def test_string_basic + test = -> (tag, klass) { + encode_decode_test tag.chr + B(%w{ 00 }), klass.new(B(%w{})) + encode_decode_test tag.chr + B(%w{ 02 00 01 }), klass.new(B(%w{ 00 01 })) + } + test.(4, OpenSSL::ASN1::OctetString) + test.(12, OpenSSL::ASN1::UTF8String) + test.(18, OpenSSL::ASN1::NumericString) + test.(19, OpenSSL::ASN1::PrintableString) + test.(20, OpenSSL::ASN1::T61String) + test.(21, OpenSSL::ASN1::VideotexString) + test.(22, OpenSSL::ASN1::IA5String) + test.(25, OpenSSL::ASN1::GraphicString) + test.(26, OpenSSL::ASN1::ISO64String) + test.(27, OpenSSL::ASN1::GeneralString) + test.(28, OpenSSL::ASN1::UniversalString) + test.(30, OpenSSL::ASN1::BMPString) + end + + def test_null + encode_decode_test B(%w{ 05 00 }), OpenSSL::ASN1::Null.new(nil) + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 05 01 00 })) + } end - def test_cons_without_array_forbidden - assert_raise(OpenSSL::ASN1::ASN1Error) do - val = OpenSSL::ASN1::OctetString.new('a') - cons = OpenSSL::ASN1::Constructive.new(val, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - cons.infinite_length = true - cons.to_der + def test_object_identifier + encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new("0.0".b) + encode_decode_test B(%w{ 06 01 28 }), OpenSSL::ASN1::ObjectId.new("1.0".b) + encode_decode_test B(%w{ 06 03 88 37 03 }), OpenSSL::ASN1::ObjectId.new("2.999.3".b) + encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId.new("1.2.34.56789".b) + obj = encode_decode_test B(%w{ 06 09 60 86 48 01 65 03 04 02 01 }), OpenSSL::ASN1::ObjectId.new("sha256") + assert_equal "2.16.840.1.101.3.4.2.1", obj.oid + assert_equal "SHA256", obj.sn + assert_equal "sha256", obj.ln + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 06 00 })) + } + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 06 01 80 })) + } + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("3.0".b).to_der } + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("0.40".b).to_der } + + begin + oid = (0...100).to_a.join(".").b + obj = OpenSSL::ASN1::ObjectId.new(oid) + assert_equal oid, obj.oid + rescue OpenSSL::ASN1::ASN1Error + pend "OBJ_obj2txt() not working (LibreSSL?)" if $!.message =~ /OBJ_obj2txt/ + raise end end - def test_parse_empty_sequence - expected = %w{ A0 07 30 02 30 00 02 01 00 } - raw = [expected.join('')].pack('H*') - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(raw, asn1.to_der) - assert_equal(2, asn1.value.size) - seq = asn1.value[0] - assert_equal(1, seq.value.size) - inner_seq = seq.value[0] - assert_equal(0, inner_seq.value.size) - end + def test_sequence + encode_decode_test B(%w{ 30 00 }), OpenSSL::ASN1::Sequence.new([]) + encode_decode_test B(%w{ 30 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::Sequence.new([]), + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) + ]) + + expected = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) + expected.indefinite_length = true + encode_decode_test B(%w{ 30 80 04 01 00 00 00 }), expected + + # OpenSSL::ASN1::EndOfContent can only be at the end + obj = OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::EndOfContent.new, + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), + OpenSSL::ASN1::EndOfContent.new, + ]) + obj.indefinite_length = true + assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } + + # The last EOC in value is ignored if indefinite length form is used + expected = OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), + OpenSSL::ASN1::EndOfContent.new + ]) + expected.indefinite_length = true + encode_test B(%w{ 30 80 04 01 00 00 00 }), expected + end + + def test_set + encode_decode_test B(%w{ 31 00 }), OpenSSL::ASN1::Set.new([]) + encode_decode_test B(%w{ 31 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Set.new([ + OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::Sequence.new([]), + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) + ]) + expected = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) + expected.indefinite_length = true + encode_decode_test B(%w{ 31 80 04 01 00 00 00 }), expected + end + + def test_utctime + encode_decode_test B(%w{ 17 0D }) + "160908234339Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39)) + # possible range of UTCTime is 1969-2068 currently + encode_decode_test B(%w{ 17 0D }) + "690908234339Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(1969, 9, 8, 23, 43, 39)) + decode_test B(%w{ 17 0B }) + "6909082343Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(1969, 9, 8, 23, 43, 0)) + # not implemented + # decode_test B(%w{ 17 11 }) + "500908234339+0930".b, + # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 39, "+09:30")) + # decode_test B(%w{ 17 0F }) + "5009082343-0930".b, + # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 0, "-09:30")) + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b) + # } + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b) + # } + end + + def test_generalizedtime + encode_decode_test B(%w{ 18 0F }) + "20161208193429Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29)) + encode_decode_test B(%w{ 18 0F }) + "99990908234339Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39)) + decode_test B(%w{ 18 0D }) + "201612081934Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0)) + # not implemented + # decode_test B(%w{ 18 13 }) + "20161208193439+0930".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, "+09:30")) + # decode_test B(%w{ 18 11 }) + "201612081934-0930".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:30")) + # decode_test B(%w{ 18 11 }) + "201612081934-09".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:00")) + # decode_test B(%w{ 18 0D }) + "2016120819.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) + # decode_test B(%w{ 18 0D }) + "2016120819,5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) + # decode_test B(%w{ 18 0F }) + "201612081934.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 30)) + # decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5)) + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 18 0D }) + "201612081934Y".b) + # } + end + + def test_basic_asn1data + encode_test B(%w{ 00 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 0, :UNIVERSAL) + encode_test B(%w{ 01 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :UNIVERSAL) + encode_decode_test B(%w{ 41 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :APPLICATION) + encode_decode_test B(%w{ 81 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :CONTEXT_SPECIFIC) + encode_decode_test B(%w{ C1 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :PRIVATE) + encode_decode_test B(%w{ 1F 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 32, :UNIVERSAL) + encode_decode_test B(%w{ 1F C0 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 8224, :UNIVERSAL) + encode_decode_test B(%w{ 41 02 AB CD }), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :APPLICATION) + encode_decode_test B(%w{ 41 81 80 } + %w{ AB CD } * 64), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 64), 1, :APPLICATION) + encode_decode_test B(%w{ 41 82 01 00 } + %w{ AB CD } * 128), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 128), 1, :APPLICATION) + encode_decode_test B(%w{ 61 00 }), OpenSSL::ASN1::ASN1Data.new([], 1, :APPLICATION) + obj = OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE)], 1, :APPLICATION) + obj.indefinite_length = true + encode_decode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::ASN1Data.new([ + OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE), + OpenSSL::ASN1::EndOfContent.new + ], 1, :APPLICATION) + obj.indefinite_length = true + encode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :UNIVERSAL) + obj.indefinite_length = true + assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } + end + + def test_basic_primitive + encode_test B(%w{ 00 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 0) + encode_test B(%w{ 01 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :UNIVERSAL) + encode_test B(%w{ 81 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 01 02 AB CD }), OpenSSL::ASN1::Primitive.new(B(%w{ AB CD }), 1) + assert_raise(TypeError) { OpenSSL::ASN1::Primitive.new([], 1).to_der } - def test_parse_tagged_0_infinite - expected = %w{ 30 80 02 01 01 80 01 02 00 00 } - raw = [expected.join('')].pack('H*') - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(3, asn1.value.size) - int = asn1.value[0] - assert_universal(OpenSSL::ASN1::INTEGER, int) - tagged = asn1.value[1] - assert_equal(0, tagged.tag) - assert_universal(OpenSSL::ASN1::EOC, asn1.value[2]) - assert_equal(raw, asn1.to_der) - end - - def test_seq_infinite_length - content = [ OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::EndOfContent.new ] - cons = OpenSSL::ASN1::Sequence.new(content) - cons.infinite_length = true - expected = %w{ 30 80 05 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - - def test_set_infinite_length - content = [ OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Set.new(content) - cons.infinite_length = true - expected = %w{ 31 80 05 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + prim = OpenSSL::ASN1::Integer.new(50) + assert_equal false, prim.indefinite_length + assert_not_respond_to prim, :indefinite_length= end - def test_octet_string_infinite_length - octets = [ OpenSSL::ASN1::OctetString.new('aaa'), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new(octets, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - cons.infinite_length = true - expected = %w{ 24 80 04 03 61 61 61 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + def test_basic_constructed + octet_string = OpenSSL::ASN1::OctetString.new(B(%w{ AB CD })) + encode_test B(%w{ 20 00 }), OpenSSL::ASN1::Constructive.new([], 0) + encode_test B(%w{ 21 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :UNIVERSAL) + encode_test B(%w{ A1 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 21 04 04 02 AB CD }), OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj = OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj.indefinite_length = true + encode_decode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::Constructive.new([octet_string, OpenSSL::ASN1::EndOfContent.new], 1) + obj.indefinite_length = true + encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj end def test_prim_explicit_tagging oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) - expected = %w{ A0 03 04 01 61 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, oct_str.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end + encode_test B(%w{ A0 03 04 01 61 }), oct_str + oct_str2 = OpenSSL::ASN1::OctetString.new("a", 1, :EXPLICIT, :APPLICATION) + encode_test B(%w{ 61 03 04 01 61 }), oct_str2 - def test_prim_explicit_tagging_tag_class - oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) - oct_str2 = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT, :CONTEXT_SPECIFIC) - assert_equal(oct_str.to_der, oct_str2.to_der) + decoded = OpenSSL::ASN1.decode(oct_str2.to_der) + assert_equal :APPLICATION, decoded.tag_class + assert_equal 1, decoded.tag + assert_equal 1, decoded.value.size + inner = decoded.value[0] + assert_equal OpenSSL::ASN1::OctetString, inner.class + assert_equal B(%w{ 61 }), inner.value end def test_prim_implicit_tagging int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) - expected = %w{ 80 01 01 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, int.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end + encode_test B(%w{ 80 01 01 }), int + int2 = OpenSSL::ASN1::Integer.new(1, 1, :IMPLICIT, :APPLICATION) + encode_test B(%w{ 41 01 01 }), int2 + decoded = OpenSSL::ASN1.decode(int2.to_der) + assert_equal :APPLICATION, decoded.tag_class + assert_equal 1, decoded.tag + assert_equal B(%w{ 01 }), decoded.value - def test_prim_implicit_tagging_tag_class - int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) - int2 = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT, :CONTEXT_SPECIFIC); - assert_equal(int.to_der, int2.to_der) + # Special behavior: Encoding universal types with non-default 'tag' + # attribute and nil tagging method. + int3 = OpenSSL::ASN1::Integer.new(1, 1) + encode_test B(%w{ 01 01 01 }), int3 end def test_cons_explicit_tagging content = [ OpenSSL::ASN1::PrintableString.new('abc') ] seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) - expected = %w{ A2 07 30 05 13 03 61 62 63 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end + encode_test B(%w{ A2 07 30 05 13 03 61 62 63 }), seq + seq2 = OpenSSL::ASN1::Sequence.new(content, 3, :EXPLICIT, :APPLICATION) + encode_test B(%w{ 63 07 30 05 13 03 61 62 63 }), seq2 - def test_cons_explicit_tagging_inf_length - content = [ OpenSSL::ASN1::PrintableString.new('abc') , - OpenSSL::ASN1::EndOfContent.new() ] - seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) - seq.infinite_length = true - expected = %w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + content3 = [ OpenSSL::ASN1::PrintableString.new('abc'), + OpenSSL::ASN1::EndOfContent.new() ] + seq3 = OpenSSL::ASN1::Sequence.new(content3, 2, :EXPLICIT) + seq3.indefinite_length = true + encode_test B(%w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 }), seq3 end def test_cons_implicit_tagging content = [ OpenSSL::ASN1::Null.new(nil) ] seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) - expected = %w{ A1 02 05 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end + encode_test B(%w{ A1 02 05 00 }), seq + seq2 = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT, :APPLICATION) + encode_test B(%w{ 61 02 05 00 }), seq2 - def test_cons_implicit_tagging_inf_length - content = [ OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::EndOfContent.new() ] - seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) - seq.infinite_length = true - expected = %w{ A1 80 05 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end + content3 = [ OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::EndOfContent.new() ] + seq3 = OpenSSL::ASN1::Sequence.new(content3, 1, :IMPLICIT) + seq3.indefinite_length = true + encode_test B(%w{ A1 80 05 00 00 00 }), seq3 - def test_octet_string_infinite_length_explicit_tagging - octets = [ OpenSSL::ASN1::OctetString.new('aaa'), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new(octets, 1, :EXPLICIT) - cons.infinite_length = true - expected = %w{ A1 80 24 80 04 03 61 61 61 00 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + # Special behavior: Encoding universal types with non-default 'tag' + # attribute and nil tagging method. + seq4 = OpenSSL::ASN1::Sequence.new([], 1) + encode_test B(%w{ 21 00 }), seq4 end - def test_octet_string_infinite_length_implicit_tagging + def test_octet_string_constructed_tagging + octets = [ OpenSSL::ASN1::OctetString.new('aaa') ] + cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT) + encode_test B(%w{ A0 05 04 03 61 61 61 }), cons + octets = [ OpenSSL::ASN1::OctetString.new('aaa'), OpenSSL::ASN1::EndOfContent.new() ] cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT) - cons.infinite_length = true - expected = %w{ A0 80 04 03 61 61 61 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + cons.indefinite_length = true + encode_test B(%w{ A0 80 04 03 61 61 61 00 00 }), cons end - def test_recursive_octet_string_infinite_length + def test_recursive_octet_string_indefinite_length octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"), OpenSSL::ASN1::EndOfContent.new() ] octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"), OpenSSL::ASN1::EndOfContent.new() ] container1 = OpenSSL::ASN1::Constructive.new(octets_sub1, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - container1.infinite_length = true + container1.indefinite_length = true container2 = OpenSSL::ASN1::Constructive.new(octets_sub2, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - container2.infinite_length = true + container2.indefinite_length = true octets3 = OpenSSL::ASN1::OctetString.new("\x03") octets = [ container1, container2, octets3, OpenSSL::ASN1::EndOfContent.new() ] cons = OpenSSL::ASN1::Constructive.new(octets, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - cons.infinite_length = true - expected = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 } - raw = [expected.join('')].pack('H*') + cons.indefinite_length = true + raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) assert_equal(raw, cons.to_der) assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) end - def test_bit_string_infinite_length - content = [ OpenSSL::ASN1::BitString.new("\x01"), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new(content, OpenSSL::ASN1::BIT_STRING, nil, :UNIVERSAL) - cons.infinite_length = true - expected = %w{ 23 80 03 02 00 01 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - - def test_primitive_inf_length - assert_raise(OpenSSL::ASN1::ASN1Error) do - spec = %w{ 02 80 02 01 01 00 00 } - raw = [spec.join('')].pack('H*') - OpenSSL::ASN1.decode(raw) - OpenSSL::ASN1.decode_all(raw) - end - end - def test_recursive_octet_string_parse - test = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 } - raw = [test.join('')].pack('H*') + raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) asn1 = OpenSSL::ASN1.decode(raw) assert_equal(OpenSSL::ASN1::Constructive, asn1.class) assert_universal(OpenSSL::ASN1::OCTET_STRING, asn1) - assert_equal(true, asn1.infinite_length) - assert_equal(4, asn1.value.size) + assert_equal(true, asn1.indefinite_length) + assert_equal(3, asn1.value.size) nested1 = asn1.value[0] assert_equal(OpenSSL::ASN1::Constructive, nested1.class) assert_universal(OpenSSL::ASN1::OCTET_STRING, nested1) - assert_equal(true, nested1.infinite_length) - assert_equal(2, nested1.value.size) + assert_equal(true, nested1.indefinite_length) + assert_equal(1, nested1.value.size) oct1 = nested1.value[0] assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1) - assert_equal(false, oct1.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, nested1.value[1]) - assert_equal(false, nested1.value[1].infinite_length) + assert_equal(false, oct1.indefinite_length) nested2 = asn1.value[1] assert_equal(OpenSSL::ASN1::Constructive, nested2.class) assert_universal(OpenSSL::ASN1::OCTET_STRING, nested2) - assert_equal(true, nested2.infinite_length) - assert_equal(2, nested2.value.size) + assert_equal(true, nested2.indefinite_length) + assert_equal(1, nested2.value.size) oct2 = nested2.value[0] assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2) - assert_equal(false, oct2.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, nested2.value[1]) - assert_equal(false, nested2.value[1].infinite_length) + assert_equal(false, oct2.indefinite_length) oct3 = asn1.value[2] assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3) - assert_equal(false, oct3.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, asn1.value[3]) - assert_equal(false, asn1.value[3].infinite_length) + assert_equal(false, oct3.indefinite_length) end def test_decode_constructed_overread @@ -575,6 +632,46 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm private + def B(ary) + [ary.join].pack("H*") + end + + def assert_asn1_equal(a, b) + assert_equal a.class, b.class + assert_equal a.tag, b.tag + assert_equal a.tag_class, b.tag_class + assert_equal a.indefinite_length, b.indefinite_length + assert_equal a.unused_bits, b.unused_bits if a.respond_to?(:unused_bits) + case a.value + when Array + a.value.each_with_index { |ai, i| + assert_asn1_equal ai, b.value[i] + } + else + if OpenSSL::ASN1::ObjectId === a + assert_equal a.oid, b.oid + else + assert_equal a.value, b.value + end + end + assert_equal a.to_der, b.to_der + end + + def encode_test(der, obj) + assert_equal der, obj.to_der + end + + def decode_test(der, obj) + decoded = OpenSSL::ASN1.decode(der) + assert_asn1_equal obj, decoded + decoded + end + + def encode_decode_test(der, obj) + encode_test(der, obj) + decode_test(der, obj) + end + def assert_universal(tag, asn1) assert_equal(tag, asn1.tag) if asn1.respond_to?(:tagging) @@ -582,5 +679,6 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm end assert_equal(:UNIVERSAL, asn1.tag_class) end +end -end if defined?(OpenSSL::TestUtils) +end diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb index 37ba5e5595..7739028611 100644 --- a/test/openssl/test_bn.rb +++ b/test/openssl/test_bn.rb @@ -1,60 +1,275 @@ +# coding: us-ascii # frozen_string_literal: false require_relative 'utils' +require "prime" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestBN < OpenSSL::TestCase - def test_new_str - e1 = OpenSSL::BN.new(999.to_s(16), 16) # OpenSSL::BN.new(str, 16) must be most stable - e2 = OpenSSL::BN.new((2**107-1).to_s(16), 16) - assert_equal(e1, OpenSSL::BN.new("999")) - assert_equal(e2, OpenSSL::BN.new((2**107-1).to_s)) - assert_equal(e1, OpenSSL::BN.new("999", 10)) - assert_equal(e2, OpenSSL::BN.new((2**107-1).to_s, 10)) - assert_equal(e1, OpenSSL::BN.new("\x03\xE7", 2)) - assert_equal(e2, OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2)) - assert_equal(e1, OpenSSL::BN.new("\x00\x00\x00\x02\x03\xE7", 0)) - assert_equal(e2, OpenSSL::BN.new("\x00\x00\x00\x0E\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) - end - - def test_new_bn - e1 = OpenSSL::BN.new(999.to_s(16), 16) - e2 = OpenSSL::BN.new((2**107-1).to_s(16), 16) - assert_equal(e1, OpenSSL::BN.new(e1)) - assert_equal(e2, OpenSSL::BN.new(e2)) - end - - def test_new_integer - assert_equal(999.to_bn, OpenSSL::BN.new(999)) - assert_equal((2 ** 107 - 1).to_bn, OpenSSL::BN.new(2 ** 107 - 1)) - assert_equal(-999.to_bn, OpenSSL::BN.new(-999)) - assert_equal((-(2 ** 107 - 1)).to_bn, OpenSSL::BN.new(-(2 ** 107 - 1))) - end - - def test_to_bn - e1 = OpenSSL::BN.new(999.to_s(16), 16) - e2 = OpenSSL::BN.new((2**107-1).to_s(16), 16) - assert_equal(e1, 999.to_bn) - assert_equal(e2, (2**107-1).to_bn) - end - - def test_prime_p - assert_equal(true, OpenSSL::BN.new((2 ** 107 - 1).to_s(16), 16).prime?) - assert_equal(true, OpenSSL::BN.new((2 ** 127 - 1).to_s(16), 16).prime?(1)) - end - - def test_cmp - bn1 = OpenSSL::BN.new('1') - bn2 = OpenSSL::BN.new('1') - bn3 = OpenSSL::BN.new('2') - assert_equal(false, bn1 == nil) - assert_equal(true, bn1 != nil) - assert_equal(true, bn1 == bn2) - assert_equal(false, bn1 == bn3) - assert_equal(true, bn1.eql?(bn2)) - assert_equal(false, bn1.eql?(bn3)) - assert_equal(bn1.hash, bn2.hash) - assert_not_equal(bn3.hash, bn1.hash) + def setup + super + @e1 = OpenSSL::BN.new(999.to_s(16), 16) # OpenSSL::BN.new(str, 16) must be most stable + @e2 = OpenSSL::BN.new("-" + 999.to_s(16), 16) + @e3 = OpenSSL::BN.new((2**107-1).to_s(16), 16) + @e4 = OpenSSL::BN.new("-" + (2**107-1).to_s(16), 16) + end + + def test_new + assert_equal(@e1, OpenSSL::BN.new("999")) + assert_equal(@e1, OpenSSL::BN.new("999", 10)) + assert_equal(@e1, OpenSSL::BN.new("\x03\xE7", 2)) + assert_equal(@e1, OpenSSL::BN.new("\x00\x00\x00\x02\x03\xE7", 0)) + assert_equal(@e2, OpenSSL::BN.new("-999")) + assert_equal(@e2, OpenSSL::BN.new("-999", 10)) + assert_equal(@e2, OpenSSL::BN.new("\x00\x00\x00\x02\x83\xE7", 0)) + assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s)) + assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s, 10)) + assert_equal(@e3, OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2)) + assert_equal(@e3, OpenSSL::BN.new("\x00\x00\x00\x0E\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) + assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s)) + assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s, 10)) + assert_equal(@e4, OpenSSL::BN.new("\x00\x00\x00\x0E\x87\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) + + e1copy = OpenSSL::BN.new(@e1) + assert_equal(@e1, e1copy) + e1copy.clear_bit!(0) #=> 998 + assert_not_equal(@e1, e1copy) + + assert_equal(@e1, OpenSSL::BN.new(999)) + assert_equal(@e2, OpenSSL::BN.new(-999)) + assert_equal(@e3, OpenSSL::BN.new(2**107-1)) + assert_equal(@e4, OpenSSL::BN.new(-(2**107-1))) + + assert_equal(@e1, 999.to_bn) + assert_equal(@e2, -999.to_bn) + assert_equal(@e3, (2**107-1).to_bn) + assert_equal(@e4, (-(2**107-1)).to_bn) + end + + def test_to_str + assert_equal("999", @e1.to_s(10)) + assert_equal("-999", @e2.to_s(10)) + assert_equal((2**107-1).to_s, @e3.to_s(10)) + assert_equal((-(2**107-1)).to_s, @e4.to_s(10)) + assert_equal("999", @e1.to_s) + + assert_equal("03E7", @e1.to_s(16)) + assert_equal("-03E7", @e2.to_s(16)) + assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e3.to_s(16)) + assert_equal("-07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e4.to_s(16)) + + assert_equal("\x03\xe7", @e1.to_s(2)) + assert_equal("\x03\xe7", @e2.to_s(2)) + assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(2)) + assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(2)) + + assert_equal("\x00\x00\x00\x02\x03\xe7", @e1.to_s(0)) + assert_equal("\x00\x00\x00\x02\x83\xe7", @e2.to_s(0)) + assert_equal("\x00\x00\x00\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(0)) + assert_equal("\x00\x00\x00\x0e\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(0)) + end + + def test_to_int + assert_equal(999, @e1.to_i) + assert_equal(-999, @e2.to_i) + assert_equal(2**107-1, @e3.to_i) + assert_equal(-(2**107-1), @e4.to_i) + + assert_equal(999, @e1.to_int) + end + + def test_coerce + assert_equal(["", "-999"], @e2.coerce("")) + assert_equal([1000, -999], @e2.coerce(1000)) + assert_raise(TypeError) { @e2.coerce(Class.new.new) } + end + + def test_zero_p + assert_equal(true, 0.to_bn.zero?) + assert_equal(false, 1.to_bn.zero?) + end + + def test_one_p + assert_equal(true, 1.to_bn.one?) + assert_equal(false, 2.to_bn.one?) + end + + def test_odd_p + assert_equal(true, 1.to_bn.odd?) + assert_equal(false, 2.to_bn.odd?) + end + + def test_negative_p + assert_equal(false, 0.to_bn.negative?) + assert_equal(false, @e1.negative?) + assert_equal(true, @e2.negative?) + end + + def test_sqr + assert_equal(1, 1.to_bn.sqr) + assert_equal(100, 10.to_bn.sqr) + end + + def test_four_ops + assert_equal(3, 1.to_bn + 2) + assert_equal(-1, 1.to_bn + -2) + assert_equal(-1, 1.to_bn - 2) + assert_equal(3, 1.to_bn - -2) + assert_equal(2, 1.to_bn * 2) + assert_equal(-2, 1.to_bn * -2) + assert_equal([0, 1], 1.to_bn / 2) + assert_equal([2, 0], 2.to_bn / 1) + assert_raise(OpenSSL::BNError) { 1.to_bn / 0 } + end + + def test_unary_plus_minus + assert_equal(999, +@e1) + assert_equal(-999, +@e2) + assert_equal(-999, -@e1) + assert_equal(+999, -@e2) + end + + def test_mod + assert_equal(1, 1.to_bn % 2) + assert_equal(0, 2.to_bn % 1) + assert_equal(-2, -2.to_bn % 7) + end + + def test_exp + assert_equal(1, 1.to_bn ** 5) + assert_equal(32, 2.to_bn ** 5) + end + + def test_gcd + assert_equal(1, 7.to_bn.gcd(5)) + assert_equal(8, 24.to_bn.gcd(16)) + end + + def test_mod_sqr + assert_equal(4, 3.to_bn.mod_sqr(5)) + assert_equal(0, 59.to_bn.mod_sqr(59)) + end + + def test_mod_inverse + assert_equal(2, 3.to_bn.mod_inverse(5)) + assert_raise(OpenSSL::BNError) { 3.to_bn.mod_inverse(6) } + end + + def test_mod_add + assert_equal(1, 3.to_bn.mod_add(5, 7)) + assert_equal(2, 3.to_bn.mod_add(5, 3)) + assert_equal(5, 3.to_bn.mod_add(-5, 7)) + end + + def test_mod_sub + assert_equal(1, 11.to_bn.mod_sub(3, 7)) + assert_equal(2, 11.to_bn.mod_sub(3, 3)) + assert_equal(5, 3.to_bn.mod_sub(5, 7)) + end + + def test_mod_mul + assert_equal(1, 2.to_bn.mod_mul(4, 7)) + assert_equal(5, 2.to_bn.mod_mul(-1, 7)) + end + + def test_mod_exp + assert_equal(1, 3.to_bn.mod_exp(2, 8)) + assert_equal(4, 2.to_bn.mod_exp(5, 7)) + end + + def test_bit_operations + e = 0b10010010.to_bn + assert_equal(0b10010011, e.set_bit!(0)) + assert_equal(0b10010011, e.set_bit!(1)) + assert_equal(0b1010010011, e.set_bit!(9)) + + e = 0b10010010.to_bn + assert_equal(0b10010010, e.clear_bit!(0)) + assert_equal(0b10010000, e.clear_bit!(1)) + + e = 0b10010010.to_bn + assert_equal(0b10010010, e.mask_bits!(8)) + assert_equal(0b10, e.mask_bits!(3)) + + e = 0b10010010.to_bn + assert_equal(false, e.bit_set?(0)) + assert_equal(true, e.bit_set?(1)) + assert_equal(false, e.bit_set?(1000)) + + e = 0b10010010.to_bn + assert_equal(0b1001001000, e << 2) + assert_equal(0b10010010, e) + assert_equal(0b1001001000, e.lshift!(2)) + assert_equal(0b1001001000, e) + + e = 0b10010010.to_bn + assert_equal(0b100100, e >> 2) + assert_equal(0b10010010, e) + assert_equal(0b100100, e.rshift!(2)) + assert_equal(0b100100, e) + end + + def test_random + 10.times { + r1 = OpenSSL::BN.rand(8) + assert_include(128..255, r1) + r2 = OpenSSL::BN.rand(8, -1) + assert_include(0..255, r2) + r3 = OpenSSL::BN.rand(8, 1) + assert_include(192..255, r3) + r4 = OpenSSL::BN.rand(8, 1, true) + assert_include(192..255, r4) + assert_equal(true, r4.odd?) + + r5 = OpenSSL::BN.rand_range(256) + assert_include(0..255, r5) + } + end + + def test_prime + p1 = OpenSSL::BN.generate_prime(32) + assert_include(0...2**32, p1) + assert_equal(true, Prime.prime?(p1.to_i)) + p2 = OpenSSL::BN.generate_prime(32, true) + assert_equal(true, Prime.prime?((p2.to_i - 1) / 2)) + p3 = OpenSSL::BN.generate_prime(32, false, 4) + assert_equal(1, p3 % 4) + p4 = OpenSSL::BN.generate_prime(32, false, 4, 3) + assert_equal(3, p4 % 4) + + assert_equal(true, p1.prime?) + assert_equal(true, p2.prime?) + assert_equal(true, p3.prime?) + assert_equal(true, p4.prime?) + assert_equal(true, @e3.prime?) + assert_equal(true, @e3.prime_fasttest?) + end + + def test_num_bits_bytes + assert_equal(10, @e1.num_bits) + assert_equal(2, @e1.num_bytes) + assert_equal(107, @e3.num_bits) + assert_equal(14, @e3.num_bytes) + assert_equal(0, 0.to_bn.num_bits) + assert_equal(0, 0.to_bn.num_bytes) + assert_equal(9, -256.to_bn.num_bits) + assert_equal(2, -256.to_bn.num_bytes) + end + + def test_comparison + assert_equal(false, @e1 == nil) + assert_equal(false, @e1 == -999) + assert_equal(true, @e1 == 999) + assert_equal(true, @e1 == 999.to_bn) + assert_equal(false, @e1.eql?(nil)) + assert_equal(false, @e1.eql?(999)) + assert_equal(true, @e1.eql?(999.to_bn)) + assert_equal(@e1.hash, 999.to_bn.hash) + assert_not_equal(@e1.hash, @e3.hash) + assert_equal(0, @e1.cmp(999)) + assert_equal(1, @e1.cmp(-999)) + assert_equal(0, @e1.ucmp(999)) + assert_equal(0, @e1.ucmp(-999)) end end diff --git a/test/openssl/test_buffering.rb b/test/openssl/test_buffering.rb index f85353fc67..c85a6f020b 100644 --- a/test/openssl/test_buffering.rb +++ b/test/openssl/test_buffering.rb @@ -1,9 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -require 'stringio' -class OpenSSL::TestBuffering < OpenSSL::TestCase +if defined?(OpenSSL) +class OpenSSL::TestBuffering < OpenSSL::TestCase class IO include OpenSSL::Buffering @@ -85,5 +85,6 @@ class OpenSSL::TestBuffering < OpenSSL::TestCase end assert_equal([97, 98, 99], res) end +end -end if defined?(OpenSSL::TestUtils) +end diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb index ad0e87b441..d87dedf73c 100644 --- a/test/openssl/test_cipher.rb +++ b/test/openssl/test_cipher.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestCipher < OpenSSL::TestCase module Helper @@ -129,7 +129,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal ct, cipher.update(pt) << cipher.final cipher = new_decryptor("aes-128-ctr", key: key, iv: iv, padding: 0) assert_equal pt, cipher.update(ct) << cipher.final - end if has_cipher?('aes-128-ctr') + end def test_ciphers OpenSSL::Cipher.ciphers.each{|name| @@ -165,10 +165,8 @@ class OpenSSL::TestCipher < OpenSSL::TestCase end def test_authenticated - if has_cipher?('aes-128-gcm') - cipher = OpenSSL::Cipher.new('aes-128-gcm') - assert_predicate(cipher, :authenticated?) - end + cipher = OpenSSL::Cipher.new('aes-128-gcm') + assert_predicate(cipher, :authenticated?) cipher = OpenSSL::Cipher.new('aes-128-cbc') assert_not_predicate(cipher, :authenticated?) end @@ -220,7 +218,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad) cipher.update(ct2) assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } - end if has_cipher?("aes-128-gcm") + end def test_aes_gcm_variable_iv_len # GCM spec Appendix B Test Case 5 @@ -243,7 +241,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal tag, cipher.auth_tag cipher = new_decryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_tag: tag, auth_data: aad) assert_equal pt, cipher.update(ct) << cipher.final - end if has_cipher?("aes-128-gcm") + end def test_aes_ocb_tag_len # RFC 7253 Appendix A; the second sample @@ -295,7 +293,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal ct1, ct2 assert_equal tag1, tag2 - end if has_cipher?("aes-128-gcm") + end private @@ -312,7 +310,6 @@ class OpenSSL::TestCipher < OpenSSL::TestCase kwargs.each {|k, v| cipher.send(:"#{k}=", v) } end end - end end diff --git a/test/openssl/test_config.rb b/test/openssl/test_config.rb index 786bce9d2f..8096375c07 100644 --- a/test/openssl/test_config.rb +++ b/test/openssl/test_config.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestConfig < OpenSSL::TestCase def setup super @@ -171,7 +173,7 @@ __EOC__ def test_value # suppress deprecation warnings - OpenSSL::TestUtils.silent do + EnvUtil.suppress_warning do assert_equal('CA_default', @it.value('ca', 'default_ca')) assert_equal(nil, @it.value('ca', 'no such key')) assert_equal(nil, @it.value('no such section', 'no such key')) @@ -184,7 +186,7 @@ __EOC__ end def test_value_ENV - OpenSSL::TestUtils.silent do + EnvUtil.suppress_warning do key = ENV.keys.first assert_not_nil(key) # make sure we have at least one ENV var. assert_equal(ENV[key], @it.value('ENV', key)) @@ -199,7 +201,7 @@ __EOC__ end def test_section - OpenSSL::TestUtils.silent do + EnvUtil.suppress_warning do assert_equal({'HOME' => '.'}, @it.section('default')) assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default')) assert_equal({}, @it.section('no_such_section')) @@ -297,4 +299,6 @@ __EOC__ @it['newsection'] = {'a' => 'b'} assert_not_equal(@it.sections.sort, c.sections.sort) end -end if defined?(OpenSSL::TestUtils) +end + +end diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb index 9891d99ae3..2cb878b6fa 100644 --- a/test/openssl/test_digest.rb +++ b/test/openssl/test_digest.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestDigest < OpenSSL::TestCase def setup @@ -54,13 +54,10 @@ class OpenSSL::TestDigest < OpenSSL::TestCase end def test_digest_constants - algs = %w(MD4 MD5 RIPEMD160 SHA1) - if OpenSSL::OPENSSL_VERSION_NUMBER < 0x10100000 + algs = %w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512) + if !libressl? && !openssl?(1, 1, 0) algs += %w(DSS1 SHA) end - if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 - algs += %w(SHA224 SHA256 SHA384 SHA512) - end algs.each do |alg| assert_not_nil(OpenSSL::Digest.new(alg)) klass = OpenSSL::Digest.const_get(alg) @@ -73,34 +70,32 @@ class OpenSSL::TestDigest < OpenSSL::TestCase check_digest(OpenSSL::ASN1::ObjectId.new("SHA1")) end - if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 - def encode16(str) - str.unpack("H*").first - end + def encode16(str) + str.unpack("H*").first + end - def test_098_features - sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" - sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" - sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" - sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" - - assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) - assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) - assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) - assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) - - assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) - assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) - assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) - assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) - end + def test_sha2 + sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" + sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" + sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" + sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" + + assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) + assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) + assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) + assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) + + assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) + assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) + assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) + assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) + end - def test_digest_by_oid_and_name_sha2 - check_digest(OpenSSL::ASN1::ObjectId.new("SHA224")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA256")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA384")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA512")) - end + def test_digest_by_oid_and_name_sha2 + check_digest(OpenSSL::ASN1::ObjectId.new("SHA224")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA256")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA384")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA512")) end def test_openssl_digest @@ -121,14 +116,6 @@ class OpenSSL::TestDigest < OpenSSL::TestCase d = OpenSSL::Digest.new(oid.oid) assert_not_nil(d) end - - def libressl? - OpenSSL::OPENSSL_VERSION.include?('LibreSSL') - end - - def version_since(verary) - (OpenSSL::OPENSSL_LIBRARY_VERSION.scan(/\d+/).map(&:to_i) <=> verary) != -1 - end end end diff --git a/test/openssl/test_engine.rb b/test/openssl/test_engine.rb index 75e45eb7f0..4f3973a7c6 100644 --- a/test/openssl/test_engine.rb +++ b/test/openssl/test_engine.rb @@ -1,8 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -class OpenSSL::TestEngine < OpenSSL::TestCase +if defined?(OpenSSL) && defined?(OpenSSL::Engine) +class OpenSSL::TestEngine < OpenSSL::TestCase def test_engines_free # [ruby-dev:44173] with_openssl <<-'end;' OpenSSL::Engine.load("openssl") @@ -95,5 +96,6 @@ class OpenSSL::TestEngine < OpenSSL::TestCase cipher.update(data) + cipher.final end end +end -end if defined?(OpenSSL::TestUtils) && defined?(OpenSSL::Engine) +end diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb index 534dade02b..a4ab87f384 100644 --- a/test/openssl/test_fips.rb +++ b/test/openssl/test_fips.rb @@ -1,15 +1,23 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestFIPS < OpenSSL::TestCase - def test_fips_mode_is_reentrant OpenSSL.fips_mode = false OpenSSL.fips_mode = false end + def test_fips_mode_get + if OpenSSL::OPENSSL_FIPS + OpenSSL.fips_mode = true + assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true" + + OpenSSL.fips_mode = false + assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false" + end + end end end diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb index dbde97d9c9..831a5b6b37 100644 --- a/test/openssl/test_hmac.rb +++ b/test/openssl/test_hmac.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative 'utils' +if defined?(OpenSSL) + class OpenSSL::TestHMAC < OpenSSL::TestCase def test_hmac # RFC 2202 2. Test Cases for HMAC-MD5 @@ -37,4 +39,6 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase second = h1.update("test").hexdigest assert_equal first, second end -end if defined?(OpenSSL::TestUtils) +end + +end diff --git a/test/openssl/test_kdf.rb b/test/openssl/test_kdf.rb new file mode 100644 index 0000000000..d91fa3cf5d --- /dev/null +++ b/test/openssl/test_kdf.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: false +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestKDF < OpenSSL::TestCase + def test_pkcs5_pbkdf2_hmac_compatibility + expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt", iterations: 1, length: 20, hash: "sha1") + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt", 1, 20, "sha1")) + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", 1, 20)) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 + p ="password" + s = "salt" + c = 1 + dk_len = 20 + raw = %w{ 0c 60 c8 0f 96 1f 0e 71 + f3 a9 b5 24 af 60 12 06 + 2f e0 37 a6 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 + p ="password" + s = "salt" + c = 2 + dk_len = 20 + raw = %w{ ea 6c 01 4d c7 2d 6f 8c + cd 1e d9 2a ce 1d 41 f0 + d8 de 89 57 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 + p ="password" + s = "salt" + c = 4096 + dk_len = 20 + raw = %w{ 4b 00 79 01 b7 65 48 9a + be ad 49 d9 26 f7 21 d0 + 65 a4 29 c1 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + +# takes too long! +# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20 +# p ="password" +# s = "salt" +# c = 16777216 +# dk_len = 20 +# raw = %w{ ee fe 3d 61 cd 4d a4 e4 +# e9 94 5b 3d 6b a2 15 8c +# 26 34 e9 84 } +# expected = [raw.join('')].pack('H*') +# value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") +# assert_equal(expected, value) +# end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 + p ="passwordPASSWORDpassword" + s = "saltSALTsaltSALTsaltSALTsaltSALTsalt" + c = 4096 + dk_len = 25 + + raw = %w{ 3d 2e ec 4f e4 1c 84 9b + 80 c8 d8 36 62 c0 e4 4a + 8b 29 1a 96 4c f2 f0 70 + 38 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 + p ="pass\0word" + s = "sa\0lt" + c = 4096 + dk_len = 16 + raw = %w{ 56 fa 6a a7 55 48 09 9d + cc 37 d7 f0 34 25 e0 c3 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha256_c_20000_len_32 + #unfortunately no official test vectors available yet for SHA-2 + p ="password" + s = OpenSSL::Random.random_bytes(16) + c = 20000 + dk_len = 32 + value1 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") + value2 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") + assert_equal(value1, value2) + end + + def test_scrypt_rfc7914_first + pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + pass = "" + salt = "" + n = 16 + r = 1 + p = 1 + dklen = 64 + expected = B(%w{ 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 + f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 + fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 + e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 }) + assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) + end + + def test_scrypt_rfc7914_second + pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + pass = "password" + salt = "NaCl" + n = 1024 + r = 8 + p = 16 + dklen = 64 + expected = B(%w{ fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe + 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 + 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da + c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 }) + assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) + end + + private + + def B(ary) + [Array(ary).join].pack("H*") + end +end + +end diff --git a/test/openssl/test_ns_spki.rb b/test/openssl/test_ns_spki.rb index ac34613fc2..aa1e61824f 100644 --- a/test/openssl/test_ns_spki.rb +++ b/test/openssl/test_ns_spki.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestNSSPI < OpenSSL::TestCase def setup @@ -17,8 +17,8 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase end def test_build_data - key1 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + key1 = Fixtures.pkey("rsa1024") + key2 = Fixtures.pkey("rsa2048") spki = OpenSSL::Netscape::SPKI.new spki.challenge = "RandomString" spki.public_key = key1.public_key diff --git a/test/openssl/test_ocsp.rb b/test/openssl/test_ocsp.rb index 8881f25dd9..9d48496de5 100644 --- a/test/openssl/test_ocsp.rb +++ b/test/openssl/test_ocsp.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestOCSP < OpenSSL::TestCase def setup @@ -13,7 +13,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase # @cert2 @ocsp_cert ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") - @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @ca_key = Fixtures.pkey("rsa1024") ca_exts = [ ["basicConstraints", "CA:TRUE", true], ["keyUsage", "cRLSign,keyCertSign", true], @@ -22,7 +22,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase ca_subj, @ca_key, 1, ca_exts, nil, nil) cert_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA2") - @cert_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @cert_key = Fixtures.pkey("rsa1024") cert_exts = [ ["basicConstraints", "CA:TRUE", true], ["keyUsage", "cRLSign,keyCertSign", true], @@ -31,14 +31,14 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase cert_subj, @cert_key, 5, cert_exts, @ca_cert, @ca_key) cert2_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert") - @cert2_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @cert2_key = Fixtures.pkey("rsa1024") cert2_exts = [ ] @cert2 = OpenSSL::TestUtils.issue_cert( cert2_subj, @cert2_key, 10, cert2_exts, @cert, @cert_key) ocsp_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCAOCSP") - @ocsp_key = OpenSSL::TestUtils::TEST_KEY_RSA2048 + @ocsp_key = Fixtures.pkey("rsa2048") ocsp_exts = [ ["extendedKeyUsage", "OCSPSigning", true], ] @@ -122,7 +122,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) ret = req.verify([@cert], store) - if ret || OpenSSL::OPENSSL_VERSION =~ /OpenSSL/ && OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 + if ret || openssl?(1, 0, 2) || libressl?(2, 4, 2) assert_equal true, ret else # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when @@ -130,6 +130,21 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase # fixed by OpenSSL 1.0.1j, 1.0.2 and LibreSSL 2.4.2 pend "RT2560: ocsp_req_find_signer" end + + # not signed + req = OpenSSL::OCSP::Request.new.add_certid(cid) + assert_equal false, req.verify([], store) + end + + def test_request_is_signed + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + req = OpenSSL::OCSP::Request.new + req.add_certid(cid) + assert_equal false, req.signed? + assert_equal false, OpenSSL::OCSP::Request.new(req.to_der).signed? + req.sign(@cert, @cert_key, []) + assert_equal true, req.signed? + assert_equal true, OpenSSL::OCSP::Request.new(req.to_der).signed? end def test_request_nonce diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb index 9a5205f81c..89cf41a86b 100644 --- a/test/openssl/test_pair.rb +++ b/test/openssl/test_pair.rb @@ -1,61 +1,45 @@ # frozen_string_literal: false require_relative 'utils' - -if defined?(OpenSSL::TestUtils) - -require 'socket' require_relative 'ut_eof' +if defined?(OpenSSL) + module OpenSSL::SSLPairM - def server - host = "127.0.0.1" - port = 0 - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } - tcps = create_tcp_server(host, port) - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - return ssls + def setup + svr_dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + ee_exts = [ + ["keyUsage", "keyEncipherment,digitalSignature", true], + ] + @svr_key = OpenSSL::TestUtils::Fixtures.pkey("rsa1024") + @svr_cert = issue_cert(svr_dn, @svr_key, 1, ee_exts, nil, nil) end - def client(port) + def ssl_pair host = "127.0.0.1" - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 - s = create_tcp_client(host, port) - ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) - ssl.connect - ssl.sync_close = true - ssl - end + tcps = create_tcp_server(host, 0) + port = tcps.connect_address.ip_port - def ssl_pair - ssls = server th = Thread.new { + sctx = OpenSSL::SSL::SSLContext.new + sctx.cert = @svr_cert + sctx.key = @svr_key + sctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } + ssls = OpenSSL::SSL::SSLServer.new(tcps, sctx) ns = ssls.accept ssls.close ns } - port = ssls.to_io.local_address.ip_port - c = client(port) + + tcpc = create_tcp_client(host, port) + c = OpenSSL::SSL::SSLSocket.new(tcpc) + c.connect s = th.value - if block_given? - begin - yield c, s - ensure - c.close unless c.closed? - s.close unless s.closed? - end - else - return c, s - end + + yield c, s ensure - if th&.alive? - th.kill - th.join - end + tcpc&.close + tcps&.close + s&.close end end @@ -85,23 +69,27 @@ end module OpenSSL::TestEOF1M def open_file(content) - s1, s2 = ssl_pair - th = Thread.new { s2 << content; s2.close } - yield s1 - ensure - th.join if th - s1.close + ssl_pair { |s1, s2| + begin + th = Thread.new { s2 << content; s2.close } + yield s1 + ensure + th&.join + end + } end end module OpenSSL::TestEOF2M def open_file(content) - s1, s2 = ssl_pair - th = Thread.new { s1 << content; s1.close } - yield s2 - ensure - th.join if th - s2.close + ssl_pair { |s1, s2| + begin + th = Thread.new { s1 << content; s1.close } + yield s2 + ensure + th&.join + end + } end end @@ -189,6 +177,27 @@ module OpenSSL::TestPairM } end + def test_multibyte_read_write + # German a umlaut + auml = [%w{ C3 A4 }.join('')].pack('H*') + auml.force_encoding(Encoding::UTF_8) + bsize = auml.bytesize + + ssl_pair { |s1, s2| + assert_equal bsize, s1.write(auml) + read = s2.read(bsize) + assert_equal Encoding::ASCII_8BIT, read.encoding + assert_equal bsize, read.bytesize + assert_equal auml, read.force_encoding(Encoding::UTF_8) + + s1.puts(auml) + read = s2.gets + assert_equal Encoding::ASCII_8BIT, read.encoding + assert_equal bsize + 1, read.bytesize + assert_equal auml + "\n", read.force_encoding(Encoding::UTF_8) + } + end + def test_read_nonblock ssl_pair {|s1, s2| err = nil @@ -354,9 +363,9 @@ module OpenSSL::TestPairM def test_connect_accept_nonblock_no_exception ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "ADH" - ctx2.security_level = 0 - ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } + ctx2.cert = @svr_cert + ctx2.key = @svr_key + ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } sock1, sock2 = tcp_pair @@ -365,8 +374,6 @@ module OpenSSL::TestPairM assert_equal :wait_readable, accepted ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "ADH" - ctx1.security_level = 0 s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) th = Thread.new do rets = [] @@ -404,9 +411,9 @@ module OpenSSL::TestPairM def test_connect_accept_nonblock ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } + ctx.cert = @svr_cert + ctx.key = @svr_key + ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") } sock1, sock2 = tcp_pair @@ -428,8 +435,6 @@ module OpenSSL::TestPairM sleep 0.1 ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.security_level = 0 s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx) begin sleep 0.2 diff --git a/test/openssl/test_pkcs12.rb b/test/openssl/test_pkcs12.rb index 403718b94f..de8e35ed79 100644 --- a/test/openssl/test_pkcs12.rb +++ b/test/openssl/test_pkcs12.rb @@ -1,12 +1,10 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) module OpenSSL class TestPKCS12 < OpenSSL::TestCase - include OpenSSL::TestUtils - def setup super ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") @@ -16,7 +14,7 @@ module OpenSSL ["subjectKeyIdentifier","hash",false], ["authorityKeyIdentifier","keyid:always",false], ] - @cacert = issue_cert(ca, TEST_KEY_RSA2048, 1, ca_exts, nil, nil) + @cacert = issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA") inter_ca_key = OpenSSL::PKey.read <<-_EOS_ @@ -36,25 +34,26 @@ FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3 Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= -----END RSA PRIVATE KEY----- _EOS_ - @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, TEST_KEY_RSA2048) + @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, Fixtures.pkey("rsa2048")) exts = [ ["keyUsage","digitalSignature",true], ["subjectKeyIdentifier","hash",false], ] ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate") - @mycert = issue_cert(ee, TEST_KEY_RSA1024, 3, exts, @inter_cacert, inter_ca_key) + @mykey = Fixtures.pkey("rsa1024") + @mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key) end def test_create pkcs12 = OpenSSL::PKCS12.create( "omg", "hello", - TEST_KEY_RSA1024, + @mykey, @mycert ) - assert_equal @mycert, pkcs12.certificate - assert_equal TEST_KEY_RSA1024, pkcs12.key + assert_equal @mycert.to_der, pkcs12.certificate.to_der + assert_equal @mykey.to_der, pkcs12.key.to_der assert_nil pkcs12.ca_certs end @@ -62,11 +61,11 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= pkcs12 = OpenSSL::PKCS12.create( nil, "hello", - TEST_KEY_RSA1024, + @mykey, @mycert ) - assert_equal @mycert, pkcs12.certificate - assert_equal TEST_KEY_RSA1024, pkcs12.key + assert_equal @mycert.to_der, pkcs12.certificate.to_der + assert_equal @mykey.to_der, pkcs12.key.to_der assert_nil pkcs12.ca_certs decoded = OpenSSL::PKCS12.new(pkcs12.to_der) @@ -79,7 +78,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= pkcs12 = OpenSSL::PKCS12.create( "omg", "hello", - TEST_KEY_RSA1024, + @mykey, @mycert, chain ) @@ -94,7 +93,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= pkcs12 = OpenSSL::PKCS12.create( passwd, "hello", - TEST_KEY_RSA1024, + @mykey, @mycert, chain ) @@ -104,7 +103,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= assert_include_cert @cacert, decoded.ca_certs assert_include_cert @inter_cacert, decoded.ca_certs assert_cert @mycert, decoded.certificate - assert_equal TEST_KEY_RSA1024.to_der, decoded.key.to_der + assert_equal @mykey.to_der, decoded.key.to_der end def test_create_with_bad_nid @@ -112,7 +111,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= OpenSSL::PKCS12.create( "omg", "hello", - TEST_KEY_RSA1024, + @mykey, @mycert, [], "foo" @@ -124,7 +123,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= OpenSSL::PKCS12.create( "omg", "hello", - TEST_KEY_RSA1024, + @mykey, @mycert, [], nil, @@ -136,7 +135,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= OpenSSL::PKCS12.create( "omg", "hello", - TEST_KEY_RSA1024, + @mykey, @mycert, [], nil, @@ -150,7 +149,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= OpenSSL::PKCS12.create( "omg", "hello", - TEST_KEY_RSA1024, + @mykey, @mycert, [], nil, @@ -163,7 +162,7 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= OpenSSL::PKCS12.create( "omg", "hello", - TEST_KEY_RSA1024, + @mykey, @mycert, [], nil, @@ -216,7 +215,7 @@ vyl2WuMdEwQIMWFFphPkIUICAggA EOF p12 = OpenSSL::PKCS12.new(str, "abc123") - assert_equal TEST_KEY_RSA1024.to_der, p12.key.to_der + assert_equal @mykey.to_der, p12.key.to_der assert_equal @mycert.subject.to_der, p12.certificate.subject.to_der assert_equal [], Array(p12.ca_certs) end @@ -275,13 +274,13 @@ Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== EOF p12 = OpenSSL::PKCS12.new(str, "abc123") - assert_equal TEST_KEY_RSA1024.to_der, p12.key.to_der + assert_equal @mykey.to_der, p12.key.to_der assert_equal nil, p12.certificate assert_equal [], Array(p12.ca_certs) end def test_dup - p12 = OpenSSL::PKCS12.create("pass", "name", TEST_KEY_RSA1024, @mycert) + p12 = OpenSSL::PKCS12.create("pass", "name", @mykey, @mycert) assert_equal p12.to_der, p12.dup.to_der end @@ -308,7 +307,6 @@ Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== end false end - end end diff --git a/test/openssl/test_pkcs5.rb b/test/openssl/test_pkcs5.rb deleted file mode 100644 index ad8132c263..0000000000 --- a/test/openssl/test_pkcs5.rb +++ /dev/null @@ -1,98 +0,0 @@ -# frozen_string_literal: false -require_relative 'utils' - -class OpenSSL::TestPKCS5 < OpenSSL::TestCase - - def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 - p ="password" - s = "salt" - c = 1 - dk_len = 20 - raw = %w{ 0c 60 c8 0f 96 1f 0e 71 - f3 a9 b5 24 af 60 12 06 - 2f e0 37 a6 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 - p ="password" - s = "salt" - c = 2 - dk_len = 20 - raw = %w{ ea 6c 01 4d c7 2d 6f 8c - cd 1e d9 2a ce 1d 41 f0 - d8 de 89 57 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 - p ="password" - s = "salt" - c = 4096 - dk_len = 20 - raw = %w{ 4b 00 79 01 b7 65 48 9a - be ad 49 d9 26 f7 21 d0 - 65 a4 29 c1 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - -# takes too long! -# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20 -# p ="password" -# s = "salt" -# c = 16777216 -# dk_len = 20 -# raw = %w{ ee fe 3d 61 cd 4d a4 e4 -# e9 94 5b 3d 6b a2 15 8c -# 26 34 e9 84 } -# expected = [raw.join('')].pack('H*') -# value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) -# assert_equal(expected, value) -# end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 - p ="passwordPASSWORDpassword" - s = "saltSALTsaltSALTsaltSALTsaltSALTsalt" - c = 4096 - dk_len = 25 - - raw = %w{ 3d 2e ec 4f e4 1c 84 9b - 80 c8 d8 36 62 c0 e4 4a - 8b 29 1a 96 4c f2 f0 70 - 38 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 - p ="pass\0word" - s = "sa\0lt" - c = 4096 - dk_len = 16 - raw = %w{ 56 fa 6a a7 55 48 09 9d - cc 37 d7 f0 34 25 e0 c3 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha256_c_20000_len_32 - #unfortunately no official test vectors available yet for SHA-2 - p ="password" - s = OpenSSL::Random.random_bytes(16) - c = 20000 - dk_len = 32 - digest = OpenSSL::Digest::SHA256.new - value1 = OpenSSL::PKCS5.pbkdf2_hmac(p, s, c, dk_len, digest) - value2 = OpenSSL::PKCS5.pbkdf2_hmac(p, s, c, dk_len, digest) - assert_equal(value1, value2) - end if OpenSSL::PKCS5.respond_to?(:pbkdf2_hmac) - -end if defined?(OpenSSL::TestUtils) diff --git a/test/openssl/test_pkcs7.rb b/test/openssl/test_pkcs7.rb index 3219155462..149d3b9b5d 100644 --- a/test/openssl/test_pkcs7.rb +++ b/test/openssl/test_pkcs7.rb @@ -1,13 +1,13 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestPKCS7 < OpenSSL::TestCase def setup super - @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") @@ -28,10 +28,6 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase @ee2_cert = issue_cert(ee2, @rsa1024, 3, ee_exts, @ca_cert, @rsa2048) end - def issue_cert(*args) - OpenSSL::TestUtils.issue_cert(*args) - end - def test_signed store = OpenSSL::X509::Store.new store.add_cert(@ca_cert) diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb index 470c952e21..77cdb0ab84 100644 --- a/test/openssl/test_pkey_dh.rb +++ b/test/openssl/test_pkey_dh.rb @@ -1,29 +1,11 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH) class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase - DH1024 = OpenSSL::TestUtils::TEST_KEY_DH1024 - NEW_KEYLEN = 256 - def test_DEFAULT_parameters - list = { - 1024 => OpenSSL::PKey::DH::DEFAULT_1024, - 2048 => OpenSSL::PKey::DH::DEFAULT_2048, - } - - list.each do |expected_size, dh| - assert_equal expected_size, dh.p.num_bits - assert_predicate dh.p, :prime? - result, remainder = (dh.p - 1) / 2 - assert_predicate result, :prime? - assert_equal 0, remainder - assert_no_key dh - end - end - def test_new dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) assert_key(dh) @@ -37,12 +19,13 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase end def test_DHparams + dh1024 = Fixtures.pkey_dh("dh1024") asn1 = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Integer(DH1024.p), - OpenSSL::ASN1::Integer(DH1024.g) + OpenSSL::ASN1::Integer(dh1024.p), + OpenSSL::ASN1::Integer(dh1024.g) ]) key = OpenSSL::PKey::DH.new(asn1.to_der) - assert_same_dh dup_public(DH1024), key + assert_same_dh dup_public(dh1024), key pem = <<~EOF -----BEGIN DH PARAMETERS----- @@ -52,14 +35,14 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase -----END DH PARAMETERS----- EOF key = OpenSSL::PKey::DH.new(pem) - assert_same_dh dup_public(DH1024), key + assert_same_dh dup_public(dh1024), key - assert_equal asn1.to_der, DH1024.to_der - assert_equal pem, DH1024.export + assert_equal asn1.to_der, dh1024.to_der + assert_equal pem, dh1024.export end def test_public_key - dh = OpenSSL::TestUtils::TEST_KEY_DH1024 + dh = Fixtures.pkey_dh("dh1024") public_key = dh.public_key assert_no_key(public_key) #implies public_key.public? is false! assert_equal(dh.to_der, public_key.to_der) @@ -67,14 +50,14 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase end def test_generate_key - dh = OpenSSL::TestUtils::TEST_KEY_DH1024.public_key # creates a copy + dh = Fixtures.pkey_dh("dh1024").public_key # creates a copy assert_no_key(dh) dh.generate_key! assert_key(dh) end def test_key_exchange - dh = OpenSSL::TestUtils::TEST_KEY_DH1024 + dh = Fixtures.pkey_dh("dh1024") dh2 = dh.public_key dh.generate_key! dh2.generate_key! diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb index a4ccd1d8f9..d651949842 100644 --- a/test/openssl/test_pkey_dsa.rb +++ b/test/openssl/test_pkey_dsa.rb @@ -1,12 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -require 'base64' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) && defined?(OpenSSL::PKey::DSA) class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase - DSA512 = OpenSSL::TestUtils::TEST_KEY_DSA512 - def test_private key = OpenSSL::PKey::DSA.new(256) assert(key.private?) @@ -37,27 +34,27 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase end def test_sign_verify + dsa512 = Fixtures.pkey("dsa512") data = "Sign me!" if defined?(OpenSSL::Digest::DSS1) - signature = DSA512.sign(OpenSSL::Digest::DSS1.new, data) - assert_equal true, DSA512.verify(OpenSSL::Digest::DSS1.new, signature, data) + signature = dsa512.sign(OpenSSL::Digest::DSS1.new, data) + assert_equal true, dsa512.verify(OpenSSL::Digest::DSS1.new, signature, data) end - return if OpenSSL::OPENSSL_VERSION_NUMBER <= 0x010000000 - signature = DSA512.sign("SHA1", data) - assert_equal true, DSA512.verify("SHA1", signature, data) + signature = dsa512.sign("SHA1", data) + assert_equal true, dsa512.verify("SHA1", signature, data) signature0 = (<<~'end;').unpack("m")[0] MCwCFH5h40plgU5Fh0Z4wvEEpz0eE9SnAhRPbkRB8ggsN/vsSEYMXvJwjGg/ 6g== end; - assert_equal true, DSA512.verify("SHA256", signature0, data) + assert_equal true, dsa512.verify("SHA256", signature0, data) signature1 = signature0.succ - assert_equal false, DSA512.verify("SHA256", signature1, data) + assert_equal false, dsa512.verify("SHA256", signature1, data) end def test_sys_sign_verify - key = OpenSSL::TestUtils::TEST_KEY_DSA256 + key = Fixtures.pkey("dsa256") data = 'Sign me!' digest = OpenSSL::Digest::SHA1.digest(data) sig = key.syssign(digest) @@ -66,17 +63,18 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase def test_DSAPrivateKey # OpenSSL DSAPrivateKey format; similar to RSAPrivateKey + dsa512 = Fixtures.pkey("dsa512") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(0), - OpenSSL::ASN1::Integer(DSA512.p), - OpenSSL::ASN1::Integer(DSA512.q), - OpenSSL::ASN1::Integer(DSA512.g), - OpenSSL::ASN1::Integer(DSA512.pub_key), - OpenSSL::ASN1::Integer(DSA512.priv_key) + OpenSSL::ASN1::Integer(dsa512.p), + OpenSSL::ASN1::Integer(dsa512.q), + OpenSSL::ASN1::Integer(dsa512.g), + OpenSSL::ASN1::Integer(dsa512.pub_key), + OpenSSL::ASN1::Integer(dsa512.priv_key) ]) key = OpenSSL::PKey::DSA.new(asn1.to_der) assert_predicate key, :private? - assert_same_dsa DSA512, key + assert_same_dsa dsa512, key pem = <<~EOF -----BEGIN DSA PRIVATE KEY----- @@ -89,14 +87,15 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase -----END DSA PRIVATE KEY----- EOF key = OpenSSL::PKey::DSA.new(pem) - assert_same_dsa DSA512, key + assert_same_dsa dsa512, key - assert_equal asn1.to_der, DSA512.to_der - assert_equal pem, DSA512.export + assert_equal asn1.to_der, dsa512.to_der + assert_equal pem, dsa512.export end def test_DSAPrivateKey_encrypted # key = abcdef + dsa512 = Fixtures.pkey("dsa512") pem = <<~EOF -----BEGIN DSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED @@ -111,35 +110,36 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase -----END DSA PRIVATE KEY----- EOF key = OpenSSL::PKey::DSA.new(pem, "abcdef") - assert_same_dsa DSA512, key + assert_same_dsa dsa512, key key = OpenSSL::PKey::DSA.new(pem) { "abcdef" } - assert_same_dsa DSA512, key + assert_same_dsa dsa512, key cipher = OpenSSL::Cipher.new("aes-128-cbc") - exported = DSA512.to_pem(cipher, "abcdef\0\1") - assert_same_dsa DSA512, OpenSSL::PKey::DSA.new(exported, "abcdef\0\1") + exported = dsa512.to_pem(cipher, "abcdef\0\1") + assert_same_dsa dsa512, OpenSSL::PKey::DSA.new(exported, "abcdef\0\1") assert_raise(OpenSSL::PKey::DSAError) { OpenSSL::PKey::DSA.new(exported, "abcdef") } end def test_PUBKEY + dsa512 = Fixtures.pkey("dsa512") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("DSA"), OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Integer(DSA512.p), - OpenSSL::ASN1::Integer(DSA512.q), - OpenSSL::ASN1::Integer(DSA512.g) + OpenSSL::ASN1::Integer(dsa512.p), + OpenSSL::ASN1::Integer(dsa512.q), + OpenSSL::ASN1::Integer(dsa512.g) ]) ]), OpenSSL::ASN1::BitString( - OpenSSL::ASN1::Integer(DSA512.pub_key).to_der + OpenSSL::ASN1::Integer(dsa512.pub_key).to_der ) ]) key = OpenSSL::PKey::DSA.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_dsa dup_public(DSA512), key + assert_same_dsa dup_public(dsa512), key pem = <<~EOF -----BEGIN PUBLIC KEY----- @@ -152,10 +152,10 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase -----END PUBLIC KEY----- EOF key = OpenSSL::PKey::DSA.new(pem) - assert_same_dsa dup_public(DSA512), key + assert_same_dsa dup_public(dsa512), key - assert_equal asn1.to_der, dup_public(DSA512).to_der - assert_equal pem, dup_public(DSA512).export + assert_equal asn1.to_der, dup_public(dsa512).to_der + assert_equal pem, dup_public(dsa512).export end def test_read_DSAPublicKey_pem diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index c549d9c674..713c649a1e 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -1,11 +1,9 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) && defined?(OpenSSL::PKey::EC) +if defined?(OpenSSL) && defined?(OpenSSL::PKey::EC) class OpenSSL::TestEC < OpenSSL::PKeyTestCase - P256 = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 - def test_ec_key builtin_curves = OpenSSL::PKey::EC.builtin_curves assert_not_empty builtin_curves @@ -74,17 +72,18 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_sign_verify + p256 = Fixtures.pkey("p256") data = "Sign me!" - signature = P256.sign("SHA1", data) - assert_equal true, P256.verify("SHA1", signature, data) + signature = p256.sign("SHA1", data) + assert_equal true, p256.verify("SHA1", signature, data) signature0 = (<<~'end;').unpack("m")[0] MEQCIEOTY/hD7eI8a0qlzxkIt8LLZ8uwiaSfVbjX2dPAvN11AiAQdCYx56Fq QdBp1B4sxJoA8jvODMMklMyBKVmudboA6A== end; - assert_equal true, P256.verify("SHA256", signature0, data) + assert_equal true, p256.verify("SHA256", signature0, data) signature1 = signature0.succ - assert_equal false, P256.verify("SHA256", signature1, data) + assert_equal false, p256.verify("SHA256", signature1, data) end def test_dsa_sign_verify @@ -100,16 +99,9 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase key = OpenSSL::PKey::EC.new("prime256v1").generate_key! size = key.group.order.num_bits / 8 + 1 dgst = (1..size).to_a.pack('C*') - begin - sig = key.dsa_sign_asn1(dgst) - # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m - assert(key.dsa_verify_asn1(dgst + "garbage", sig)) - rescue OpenSSL::PKey::ECError => e - # just an exception for longer dgst before openssl-0.9.8m - assert_equal('ECDSA_sign: data too large for key size', e.message) - # no need to do following tests - return - end + sig = key.dsa_sign_asn1(dgst) + # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m + assert(key.dsa_verify_asn1(dgst + "garbage", sig)) end def test_dh_compute_key @@ -124,21 +116,22 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_ECPrivateKey + p256 = Fixtures.pkey("p256") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(1), - OpenSSL::ASN1::OctetString(P256.private_key.to_s(2)), + OpenSSL::ASN1::OctetString(p256.private_key.to_s(2)), OpenSSL::ASN1::ASN1Data.new( [OpenSSL::ASN1::ObjectId("prime256v1")], 0, :CONTEXT_SPECIFIC ), OpenSSL::ASN1::ASN1Data.new( - [OpenSSL::ASN1::BitString(P256.public_key.to_bn.to_s(2))], + [OpenSSL::ASN1::BitString(p256.public_key.to_bn.to_s(2))], 1, :CONTEXT_SPECIFIC ) ]) key = OpenSSL::PKey::EC.new(asn1.to_der) assert_predicate key, :private? - assert_same_ec P256, key + assert_same_ec p256, key pem = <<~EOF -----BEGIN EC PRIVATE KEY----- @@ -148,13 +141,14 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase -----END EC PRIVATE KEY----- EOF key = OpenSSL::PKey::EC.new(pem) - assert_same_ec P256, key + assert_same_ec p256, key - assert_equal asn1.to_der, P256.to_der - assert_equal pem, P256.export + assert_equal asn1.to_der, p256.to_der + assert_equal pem, p256.export end def test_ECPrivateKey_encrypted + p256 = Fixtures.pkey("p256") # key = abcdef pem = <<~EOF -----BEGIN EC PRIVATE KEY----- @@ -167,31 +161,32 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase -----END EC PRIVATE KEY----- EOF key = OpenSSL::PKey::EC.new(pem, "abcdef") - assert_same_ec P256, key + assert_same_ec p256, key key = OpenSSL::PKey::EC.new(pem) { "abcdef" } - assert_same_ec P256, key + assert_same_ec p256, key cipher = OpenSSL::Cipher.new("aes-128-cbc") - exported = P256.to_pem(cipher, "abcdef\0\1") - assert_same_ec P256, OpenSSL::PKey::EC.new(exported, "abcdef\0\1") + exported = p256.to_pem(cipher, "abcdef\0\1") + assert_same_ec p256, OpenSSL::PKey::EC.new(exported, "abcdef\0\1") assert_raise(OpenSSL::PKey::ECError) { OpenSSL::PKey::EC.new(exported, "abcdef") } end def test_PUBKEY + p256 = Fixtures.pkey("p256") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("id-ecPublicKey"), OpenSSL::ASN1::ObjectId("prime256v1") ]), OpenSSL::ASN1::BitString( - P256.public_key.to_bn.to_s(2) + p256.public_key.to_bn.to_s(2) ) ]) key = OpenSSL::PKey::EC.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_ec dup_public(P256), key + assert_same_ec dup_public(p256), key pem = <<~EOF -----BEGIN PUBLIC KEY----- @@ -200,10 +195,10 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase -----END PUBLIC KEY----- EOF key = OpenSSL::PKey::EC.new(pem) - assert_same_ec dup_public(P256), key + assert_same_ec dup_public(p256), key - assert_equal asn1.to_der, dup_public(P256).to_der - assert_equal pem, dup_public(P256).export + assert_equal asn1.to_der, dup_public(p256).to_der + assert_equal pem, dup_public(p256).export end def test_ec_group @@ -305,7 +300,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase raise if $!.message !~ /unsupported field/ end - p256_key = P256 + p256_key = Fixtures.pkey("p256") p256_g = p256_key.group assert_equal(p256_key.public_key, p256_g.generator.mul(p256_key.private_key)) diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb index 93760f747e..49ab379251 100644 --- a/test/openssl/test_pkey_rsa.rb +++ b/test/openssl/test_pkey_rsa.rb @@ -1,12 +1,9 @@ # frozen_string_literal: false -require_relative 'utils' -require 'base64' +require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase - RSA1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - def test_padding key = OpenSSL::PKey::RSA.new(512, 3) @@ -71,22 +68,23 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase end def test_sign_verify + rsa1024 = Fixtures.pkey("rsa1024") data = "Sign me!" - signature = RSA1024.sign("SHA1", data) - assert_equal true, RSA1024.verify("SHA1", signature, data) + signature = rsa1024.sign("SHA1", data) + assert_equal true, rsa1024.verify("SHA1", signature, data) signature0 = (<<~'end;').unpack("m")[0] oLCgbprPvfhM4pjFQiDTFeWI9Sk+Og7Nh9TmIZ/xSxf2CGXQrptlwo7NQ28+ WA6YQo8jPH4hSuyWIM4Gz4qRYiYRkl5TDMUYob94zm8Si1HxEiS9354tzvqS zS8MLW2BtNPuTubMxTItHGTnOzo9sUg0LAHVFt8kHG2NfKAw/gQ= end; - assert_equal true, RSA1024.verify("SHA256", signature0, data) + assert_equal true, rsa1024.verify("SHA256", signature0, data) signature1 = signature0.succ - assert_equal false, RSA1024.verify("SHA256", signature1, data) + assert_equal false, rsa1024.verify("SHA256", signature1, data) end def test_digest_state_irrelevant_sign - key = RSA1024 + key = Fixtures.pkey("rsa1024") digest1 = OpenSSL::Digest::SHA1.new digest2 = OpenSSL::Digest::SHA1.new data = 'Sign me!' @@ -97,7 +95,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase end def test_digest_state_irrelevant_verify - key = RSA1024 + key = Fixtures.pkey("rsa1024") digest1 = OpenSSL::Digest::SHA1.new digest2 = OpenSSL::Digest::SHA1.new data = 'Sign me!' @@ -116,20 +114,21 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase end def test_RSAPrivateKey + rsa1024 = Fixtures.pkey("rsa1024") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(0), - OpenSSL::ASN1::Integer(RSA1024.n), - OpenSSL::ASN1::Integer(RSA1024.e), - OpenSSL::ASN1::Integer(RSA1024.d), - OpenSSL::ASN1::Integer(RSA1024.p), - OpenSSL::ASN1::Integer(RSA1024.q), - OpenSSL::ASN1::Integer(RSA1024.dmp1), - OpenSSL::ASN1::Integer(RSA1024.dmq1), - OpenSSL::ASN1::Integer(RSA1024.iqmp) + OpenSSL::ASN1::Integer(rsa1024.n), + OpenSSL::ASN1::Integer(rsa1024.e), + OpenSSL::ASN1::Integer(rsa1024.d), + OpenSSL::ASN1::Integer(rsa1024.p), + OpenSSL::ASN1::Integer(rsa1024.q), + OpenSSL::ASN1::Integer(rsa1024.dmp1), + OpenSSL::ASN1::Integer(rsa1024.dmq1), + OpenSSL::ASN1::Integer(rsa1024.iqmp) ]) key = OpenSSL::PKey::RSA.new(asn1.to_der) assert_predicate key, :private? - assert_same_rsa RSA1024, key + assert_same_rsa rsa1024, key pem = <<~EOF -----BEGIN RSA PRIVATE KEY----- @@ -149,13 +148,14 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase -----END RSA PRIVATE KEY----- EOF key = OpenSSL::PKey::RSA.new(pem) - assert_same_rsa RSA1024, key + assert_same_rsa rsa1024, key - assert_equal asn1.to_der, RSA1024.to_der - assert_equal pem, RSA1024.export + assert_equal asn1.to_der, rsa1024.to_der + assert_equal pem, rsa1024.export end def test_RSAPrivateKey_encrypted + rsa1024 = Fixtures.pkey("rsa1024") # key = abcdef pem = <<~EOF -----BEGIN RSA PRIVATE KEY----- @@ -178,26 +178,27 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase -----END RSA PRIVATE KEY----- EOF key = OpenSSL::PKey::RSA.new(pem, "abcdef") - assert_same_rsa RSA1024, key + assert_same_rsa rsa1024, key key = OpenSSL::PKey::RSA.new(pem) { "abcdef" } - assert_same_rsa RSA1024, key + assert_same_rsa rsa1024, key cipher = OpenSSL::Cipher.new("aes-128-cbc") - exported = RSA1024.to_pem(cipher, "abcdef\0\1") - assert_same_rsa RSA1024, OpenSSL::PKey::RSA.new(exported, "abcdef\0\1") + exported = rsa1024.to_pem(cipher, "abcdef\0\1") + assert_same_rsa rsa1024, OpenSSL::PKey::RSA.new(exported, "abcdef\0\1") assert_raise(OpenSSL::PKey::RSAError) { OpenSSL::PKey::RSA.new(exported, "abcdef") } end def test_RSAPublicKey + rsa1024 = Fixtures.pkey("rsa1024") asn1 = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Integer(RSA1024.n), - OpenSSL::ASN1::Integer(RSA1024.e) + OpenSSL::ASN1::Integer(rsa1024.n), + OpenSSL::ASN1::Integer(rsa1024.e) ]) key = OpenSSL::PKey::RSA.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_rsa dup_public(RSA1024), key + assert_same_rsa dup_public(rsa1024), key pem = <<~EOF -----BEGIN RSA PUBLIC KEY----- @@ -207,10 +208,11 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase -----END RSA PUBLIC KEY----- EOF key = OpenSSL::PKey::RSA.new(pem) - assert_same_rsa dup_public(RSA1024), key + assert_same_rsa dup_public(rsa1024), key end def test_PUBKEY + rsa1024 = Fixtures.pkey("rsa1024") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("rsaEncryption"), @@ -218,14 +220,14 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase ]), OpenSSL::ASN1::BitString( OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Integer(RSA1024.n), - OpenSSL::ASN1::Integer(RSA1024.e) + OpenSSL::ASN1::Integer(rsa1024.n), + OpenSSL::ASN1::Integer(rsa1024.e) ]).to_der ) ]) key = OpenSSL::PKey::RSA.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_rsa dup_public(RSA1024), key + assert_same_rsa dup_public(rsa1024), key pem = <<~EOF -----BEGIN PUBLIC KEY----- @@ -236,14 +238,14 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase -----END PUBLIC KEY----- EOF key = OpenSSL::PKey::RSA.new(pem) - assert_same_rsa dup_public(RSA1024), key + assert_same_rsa dup_public(rsa1024), key - assert_equal asn1.to_der, dup_public(RSA1024).to_der - assert_equal pem, dup_public(RSA1024).export + assert_equal asn1.to_der, dup_public(rsa1024).to_der + assert_equal pem, dup_public(rsa1024).export end def test_pem_passwd - key = RSA1024 + key = Fixtures.pkey("rsa1024") pem3c = key.to_pem("aes-128-cbc", "key") assert_match (/ENCRYPTED/), pem3c assert_equal key.to_der, OpenSSL::PKey.read(pem3c, "key").to_der diff --git a/test/openssl/test_random.rb b/test/openssl/test_random.rb index 6079461920..d5a374540d 100644 --- a/test/openssl/test_random.rb +++ b/test/openssl/test_random.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require_relative "utils" +if defined?(OpenSSL) + class OpenSSL::TestRandom < OpenSSL::TestCase def test_random_bytes assert_equal("", OpenSSL::Random.random_bytes(0)) @@ -12,4 +14,6 @@ class OpenSSL::TestRandom < OpenSSL::TestCase assert_equal("", OpenSSL::Random.pseudo_bytes(0)) assert_equal(12, OpenSSL::Random.pseudo_bytes(12).bytesize) end if OpenSSL::Random.methods.include?(:pseudo_bytes) -end if defined?(OpenSSL::TestCase) +end + +end diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 8c65df953d..3f17ab0d38 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -1,10 +1,9 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestSSL < OpenSSL::SSLTestCase - def test_ctx_options ctx = OpenSSL::SSL::SSLContext.new @@ -35,7 +34,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase readwrite_loop(ctx, ssl) } - start_server(ctx_proc: ctx_proc, server_proc: server_proc) { |server, port| + start_server(ctx_proc: ctx_proc, server_proc: server_proc) { |port| begin sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new @@ -56,7 +55,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_sysread_and_syswrite - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| str = "x" * 100 + "\n" ssl.syswrite(str) @@ -72,7 +71,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_sync_close - start_server { |server, port| + start_server { |port| begin sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) @@ -97,7 +96,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_copy_stream - start_server do |server, port| + start_server do |port| server_connect(port) do |ssl| IO.pipe do |r, w| str = "hello world\n" @@ -112,21 +111,16 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_client_auth_failure vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag, ignore_listener_error: true) { |server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - begin - assert_handshake_error { ssl.connect } - ensure - ssl.close - end + start_server(verify_mode: vflag, ignore_listener_error: true) { |port| + assert_handshake_error { + server_connect(port) { |ssl| ssl.puts("abc"); ssl.gets } + } } end def test_client_auth_success vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag) { |server, port| + start_server(verify_mode: vflag) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.key = @cli_key ctx.cert = @cli_cert @@ -153,19 +147,21 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_client_auth_public_key vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag, ignore_listener_error: true) do |server, port| + start_server(verify_mode: vflag, ignore_listener_error: true) do |port| assert_raise(ArgumentError) { ctx = OpenSSL::SSL::SSLContext.new ctx.key = @cli_key.public_key ctx.cert = @cli_cert - server_connect(port, ctx) { } + server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } } ctx = OpenSSL::SSL::SSLContext.new ctx.client_cert_cb = Proc.new{ |ssl| [@cli_cert, @cli_key.public_key] } - assert_handshake_error { server_connect(port, ctx) } + assert_handshake_error { + server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } + } end end @@ -175,7 +171,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(verify_mode: vflag, ctx_proc: ctx_proc) { |server, port| + start_server(verify_mode: vflag, ctx_proc: ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new client_ca_from_server = nil ctx.client_cert_cb = Proc.new do |sslconn| @@ -187,8 +183,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_read_nonblock_without_session - OpenSSL::TestUtils.silent do - start_server(start_immediately: false) { |server, port| + EnvUtil.suppress_warning do + start_server(start_immediately: false) { |port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true @@ -206,26 +202,21 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_starttls server_proc = -> (ctx, ssl) { - begin - while line = ssl.gets - if line =~ /^STARTTLS$/ - ssl.write("x") - ssl.flush - ssl.accept - next - end - ssl.write(line) + while line = ssl.gets + if line =~ /^STARTTLS$/ + ssl.write("x") + ssl.flush + ssl.accept + break end - rescue OpenSSL::SSL::SSLError - rescue IOError - ensure - ssl.close rescue nil + ssl.write(line) end + readwrite_loop(ctx, ssl) } EnvUtil.suppress_warning do # read/write on not started session start_server(start_immediately: false, - server_proc: server_proc) { |server, port| + server_proc: server_proc) { |port| begin sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) @@ -248,7 +239,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_parallel - start_server { |server, port| + start_server { |port| ssls = [] 10.times{ sock = TCPSocket.new("127.0.0.1", port) @@ -269,7 +260,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_verify_result - start_server(ignore_listener_error: true) { |server, port| + start_server(ignore_listener_error: true) { |port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER @@ -283,7 +274,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end } - start_server { |server, port| + start_server { |port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER @@ -301,7 +292,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end } - start_server(ignore_listener_error: true) { |server, port| + start_server(ignore_listener_error: true) { |port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER @@ -321,7 +312,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_exception_in_verify_callback_is_ignored - start_server(ignore_listener_error: true) { |server, port| + start_server(ignore_listener_error: true) { |port| sock = TCPSocket.new("127.0.0.1", port) ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER @@ -332,7 +323,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) ssl.sync_close = true begin - OpenSSL::TestUtils.silent do + EnvUtil.suppress_warning do # SSLError, not RuntimeError assert_raise(OpenSSL::SSL::SSLError) { ssl.connect } end @@ -352,20 +343,22 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase assert ciphers_names.all?{|v| /A(EC)?DH/ !~ v }, "anon ciphers are disabled" assert ciphers_names.all?{|v| /(RC4|MD5|EXP|DES(?!-EDE|-CBC3))/ !~ v }, "weak ciphers are disabled" assert_equal 0, ctx.options & OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS - if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) # >= 1.0.0 - assert_equal OpenSSL::SSL::OP_NO_COMPRESSION, - ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION - end + assert_equal OpenSSL::SSL::OP_NO_COMPRESSION, + ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION end def test_post_connect_check_with_anon_ciphers + pend "TLS 1.2 is not supported" unless tls12_supported? + ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 ctx.ciphers = "aNULL" ctx.security_level = 0 } - start_server(ctx_proc: ctx_proc) { |server, port| + start_server(ctx_proc: ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 ctx.ciphers = "aNULL" ctx.security_level = 0 server_connect(port, ctx) { |ssl| @@ -379,7 +372,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase def test_post_connection_check sslerr = OpenSSL::SSL::SSLError - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} @@ -400,7 +393,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ["subjectAltName","IP:127.0.0.1",false], ] @svr_cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| assert(ssl.post_connection_check("localhost.localdomain")) assert(ssl.post_connection_check("127.0.0.1")) @@ -420,7 +413,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ["subjectAltName","DNS:*.localdomain",false], ] @svr_cert = issue_cert(@svr, @svr_key, 5, exts, @ca_cert, @ca_key) - start_server { |server, port| + start_server { |port| server_connect(port) { |ssl| assert(ssl.post_connection_check("localhost.localdomain")) assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} @@ -623,48 +616,44 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_tlsext_hostname - ctx3 = OpenSSL::SSL::SSLContext.new - ctx3.ciphers = "ADH" - ctx3.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } - ctx3.security_level = 0 - assert_not_predicate ctx3, :frozen? + fooctx = OpenSSL::SSL::SSLContext.new + fooctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } + fooctx.cert = @cli_cert + fooctx.key = @cli_key - ctx_proc = -> ctx { - ctx.ciphers = "ALL:!aNULL" + ctx_proc = proc { |ctx| ctx.servername_cb = proc { |ssl, servername| case servername when "foo.example.com" - ctx3 + fooctx when "bar.example.com" nil else - raise "unknown hostname" + raise "unreachable" end } } - start_server(ctx_proc: ctx_proc) do |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ciphers = "ALL" - ctx.security_level = 0 - + start_server(ctx_proc: ctx_proc) do |port| sock = TCPSocket.new("127.0.0.1", port) begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.hostname = "foo.example.com" ssl.connect - assert_match (/^ADH-/), ssl.cipher[0], "the context returned by servername_cb is used" - assert_predicate ctx3, :frozen? + assert_equal @cli_cert.serial, ssl.peer_cert.serial + assert_predicate fooctx, :frozen? ensure + ssl&.close sock.close end sock = TCPSocket.new("127.0.0.1", port) begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.hostname = "bar.example.com" ssl.connect - assert_not_match (/^A(EC)?DH-/), ssl.cipher[0], "the original context is used" + assert_equal @svr_cert.serial, ssl.peer_cert.serial ensure + ssl&.close sock.close end end @@ -674,9 +663,9 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase hostname = 'example.org' ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "aNULL" - ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } - ctx2.security_level = 0 + ctx2.cert = @svr_cert + ctx2.key = @svr_key + ctx2.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } ctx2.servername_cb = lambda { |args| Object.new } sock1, sock2 = socketpair @@ -684,8 +673,6 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "aNULL" - ctx1.security_level = 0 s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) s1.hostname = hostname @@ -716,7 +703,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ctx.key = @svr_key } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |server, port| + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| ctx = OpenSSL::SSL::SSLContext.new ctx.verify_hostname = true ctx.cert_store = OpenSSL::X509::Store.new @@ -749,27 +736,26 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end - def test_multibyte_read_write - #German a umlaut - auml = [%w{ C3 A4 }.join('')].pack('H*') - auml.force_encoding(Encoding::UTF_8) - - [10, 1000, 100000].each {|i| - str = nil - num_written = nil - server_proc = Proc.new {|ctx, ssl| - cmp = ssl.read - raw_size = cmp.size - cmp.force_encoding(Encoding::UTF_8) - assert_equal(str, cmp) - assert_equal(num_written, raw_size) - ssl.close + def test_connect_certificate_verify_failed_exception_message + start_server(ignore_listener_error: true) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params + assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { + server_connect(port, ctx) } - start_server(server_proc: server_proc) { |server, port| - server_connect(port) { |ssl| - str = auml * i - num_written = ssl.write(str) - } + } + + ctx_proc = proc { |ctx| + ctx.cert = issue_cert(@svr, @svr_key, 30, [], @ca_cert, @ca_key, + not_before: Time.now-100, not_after: Time.now-10) + } + start_server(ignore_listener_error: true, ctx_proc: ctx_proc) { |port| + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params(cert_store: store) + assert_raise_with_message(OpenSSL::SSL::SSLError, /expired/) { + server_connect(port, ctx) } } end @@ -781,7 +767,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase # But it also degrades gracefully, so keep it ctx.options = OpenSSL::SSL::OP_ALL } - start_server(ctx_proc: ctx_proc) { |server, port| + start_server(ctx_proc: ctx_proc) { |port| server_connect(port) { |ssl| ssl.puts('hello') assert_equal("hello\n", ssl.gets) @@ -789,112 +775,223 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end -if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) && OpenSSL::SSL::SSLContext::METHODS.include?(:SSLv3) + def check_supported_protocol_versions + possible_versions = [ + OpenSSL::SSL::SSL3_VERSION, + OpenSSL::SSL::TLS1_VERSION, + OpenSSL::SSL::TLS1_1_VERSION, + OpenSSL::SSL::TLS1_2_VERSION, + # OpenSSL 1.1.1 + defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION, + ].compact + + # Prepare for testing & do sanity check + supported = [] + possible_versions.each do |ver| + catch(:unsupported) { + ctx_proc = proc { |ctx| + begin + ctx.min_version = ctx.max_version = ver + rescue ArgumentError, OpenSSL::SSL::SSLError + throw :unsupported + end + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| + begin + server_connect(port) { } + rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET + else + supported << ver + end + end + } + end + assert_not_empty supported - def test_forbid_ssl_v3_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3 } - start_server_version(:SSLv23, ctx_proc) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :SSLv3 - assert_handshake_error { server_connect(port, ctx) } - } + supported end - def test_forbid_ssl_v3_from_server - start_server_version(:SSLv3) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3 - assert_handshake_error { server_connect(port, ctx) } + def test_minmax_version + supported = check_supported_protocol_versions + + # name: The string that would be returned by SSL_get_version() + # method: The version-specific method name (if any) + vmap = { + OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, + OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, + OpenSSL::SSL::TLS1_VERSION => { name: "TLSv1", method: "TLSv1" }, + OpenSSL::SSL::TLS1_1_VERSION => { name: "TLSv1.1", method: "TLSv1_1" }, + OpenSSL::SSL::TLS1_2_VERSION => { name: "TLSv1.2", method: "TLSv1_2" }, + # OpenSSL 1.1.1 + defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION => + { name: "TLSv1.3", method: nil }, } - end -end + # Server enables a single version + supported.each do |ver| + ctx_proc = proc { |ctx| ctx.min_version = ctx.max_version = ver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client enables a single version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = cver + if ver == cver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + } + else + assert_handshake_error { server_connect(port, ctx1) { } } + end -if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) + # There is no version-specific SSL methods for TLS 1.3 + if cver <= OpenSSL::SSL::TLS1_2_VERSION + # Client enables a single version using #ssl_version= + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.ssl_version = vmap[cver][:method] + if ver == cver + server_connect(port, ctx2) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + } + else + assert_handshake_error { server_connect(port, ctx2) { } } + end + end + end - def test_tls_v1_1 - start_server_version(:TLSv1_1) { |server, port| - server_connect(port) { |ssl| assert_equal("TLSv1.1", ssl.ssl_version) } - } - end + # Client enables all supported versions + ctx3 = OpenSSL::SSL::SSLContext.new + ctx3.min_version = ctx3.max_version = nil + server_connect(port, ctx3) { |ssl| + assert_equal vmap[ver][:name], ssl.ssl_version + } + } + end - def test_forbid_tls_v1_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1 } - start_server_version(:SSLv23, ctx_proc) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1 - assert_handshake_error { server_connect(port, ctx) } + if supported.size == 1 + pend "More than one protocol version must be supported" + end + + # Server sets min_version (earliest is disabled) + sver = supported[1] + ctx_proc = proc { |ctx| ctx.min_version = sver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client sets min_version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = cver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[supported.last][:name], ssl.ssl_version + } + + # Client sets max_version + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.max_version = cver + if cver >= sver + server_connect(port, ctx2) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + } + else + assert_handshake_error { server_connect(port, ctx2) { } } + end + end } - end - def test_forbid_tls_v1_from_server - start_server_version(:TLSv1) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1 - assert_handshake_error { server_connect(port, ctx) } + # Server sets max_version (latest is disabled) + sver = supported[-2] + ctx_proc = proc { |ctx| ctx.max_version = sver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client sets min_version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = cver + if cver <= sver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[sver][:name], ssl.ssl_version + } + else + assert_handshake_error { server_connect(port, ctx1) { } } + end + + # Client sets max_version + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.max_version = cver + server_connect(port, ctx2) { |ssl| + if cver >= sver + assert_equal vmap[sver][:name], ssl.ssl_version + else + assert_equal vmap[cver][:name], ssl.ssl_version + end + } + end } end -end - -if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) + def test_options_disable_versions + # Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0. + supported = check_supported_protocol_versions - def test_tls_v1_2 - start_server_version(:TLSv1_2) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2_client - server_connect(port, ctx) { |ssl| assert_equal("TLSv1.2", ssl.ssl_version) } - } - end if OpenSSL::OPENSSL_VERSION_NUMBER > 0x10001000 + if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) && + supported.include?(OpenSSL::SSL::TLS1_2_VERSION) + # Server disables ~ TLS 1.1 + ctx_proc = proc { |ctx| + ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | + OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client only supports TLS 1.1 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION + assert_handshake_error { server_connect(port, ctx1) { } } - def test_forbid_tls_v1_1_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_1 } - start_server_version(:SSLv23, ctx_proc) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_1 - assert_handshake_error { server_connect(port, ctx) } - } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) + # Client only supports TLS 1.2 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION + assert_nothing_raised { server_connect(port, ctx2) { } } + } - def test_forbid_tls_v1_1_from_server - start_server_version(:TLSv1_1) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_1 - assert_handshake_error { server_connect(port, ctx) } - } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) + # Server only supports TLS 1.1 + ctx_proc = proc { |ctx| + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client disables TLS 1.1 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1 + assert_handshake_error { server_connect(port, ctx1) { } } - def test_forbid_tls_v1_2_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_2 } - start_server_version(:SSLv23, ctx_proc) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2 - assert_handshake_error { server_connect(port, ctx) } - } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) + # Client disables TLS 1.2 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2 + assert_nothing_raised { server_connect(port, ctx2) { } } + } + else + pend "TLS 1.1 and TLS 1.2 must be supported; skipping" + end + end - def test_forbid_tls_v1_2_from_server - start_server_version(:TLSv1_2) { |server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_2 - assert_handshake_error { server_connect(port, ctx) } + def test_ssl_methods_constant + EnvUtil.suppress_warning { # Deprecated in v2.1.0 + base = [:TLSv1_2, :TLSv1_1, :TLSv1, :SSLv3, :SSLv2, :SSLv23] + base.each do |name| + assert_include OpenSSL::SSL::SSLContext::METHODS, name + assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_client" + assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_server" + end } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) - -end + end def test_renegotiation_cb num_handshakes = 0 renegotiation_cb = Proc.new { |ssl| num_handshakes += 1 } ctx_proc = Proc.new { |ctx| ctx.renegotiation_cb = renegotiation_cb } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| server_connect(port) { |ssl| assert_equal(1, num_handshakes) } } end -if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 +if openssl?(1, 0, 2) || libressl? def test_alpn_protocol_selection_ary advertised = ["http/1.1", "spdy/2"] ctx_proc = Proc.new { |ctx| @@ -903,7 +1000,7 @@ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 } ctx.alpn_protocols = advertised } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:SSLv23, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.alpn_protocols = advertised server_connect(port, ctx) { |ssl| @@ -916,14 +1013,12 @@ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 sock1, sock2 = socketpair ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "aNULL" - ctx1.security_level = 0 + ctx1.cert = @svr_cert + ctx1.key = @svr_key ctx1.alpn_select_cb = -> (protocols) { nil } ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "aNULL" - ctx2.security_level = 0 ctx2.alpn_protocols = ["http/1.1"] ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) @@ -942,14 +1037,14 @@ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 end end -if OpenSSL::OPENSSL_VERSION_NUMBER > 0x10001000 && - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - # NPN may be disabled by OpenSSL configure option - def test_npn_protocol_selection_ary + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + advertised = ["http/1.1", "spdy/2"] - ctx_proc = Proc.new { |ctx| ctx.npn_protocols = advertised } - start_server_version(:SSLv23, ctx_proc) { |server, port| + ctx_proc = proc { |ctx| ctx.npn_protocols = advertised } + start_server_version(:TLSv1_2, ctx_proc) { |port| selector = lambda { |which| ctx = OpenSSL::SSL::SSLContext.new ctx.npn_select_cb = -> (protocols) { protocols.send(which) } @@ -963,13 +1058,17 @@ if OpenSSL::OPENSSL_VERSION_NUMBER > 0x10001000 && end def test_npn_protocol_selection_enum + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + advertised = Object.new def advertised.each yield "http/1.1" yield "spdy/2" end ctx_proc = Proc.new { |ctx| ctx.npn_protocols = advertised } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:TLSv1_2, ctx_proc) { |port| selector = lambda { |selected, which| ctx = OpenSSL::SSL::SSLContext.new ctx.npn_select_cb = -> (protocols) { protocols.to_a.send(which) } @@ -983,8 +1082,12 @@ if OpenSSL::OPENSSL_VERSION_NUMBER > 0x10001000 && end def test_npn_protocol_selection_cancel + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:TLSv1_2, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.npn_select_cb = -> (protocols) { raise RuntimeError.new } assert_raise(RuntimeError) { server_connect(port, ctx) } @@ -992,8 +1095,12 @@ if OpenSSL::OPENSSL_VERSION_NUMBER > 0x10001000 && end def test_npn_advertised_protocol_too_long + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["a" * 256] } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:TLSv1_2, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.npn_select_cb = -> (protocols) { protocols.first } assert_handshake_error { server_connect(port, ctx) } @@ -1001,32 +1108,23 @@ if OpenSSL::OPENSSL_VERSION_NUMBER > 0x10001000 && end def test_npn_selected_protocol_too_long + pend "TLS 1.2 is not supported" unless tls12_supported? + pend "NPN is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) + ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } - start_server_version(:SSLv23, ctx_proc) { |server, port| + start_server_version(:TLSv1_2, ctx_proc) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.npn_select_cb = -> (protocols) { "a" * 256 } assert_handshake_error { server_connect(port, ctx) } } end -end - - def test_invalid_shutdown_by_gc - assert_nothing_raised { - start_server { |server, port| - 10.times { - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - GC.start - ssl.connect - sock.close - } - } - } - end - def test_close_after_socket_close - start_server { |server, port| + server_proc = proc { |ctx, ssl| + # Do nothing + } + start_server(server_proc: server_proc) { |port| sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true @@ -1047,84 +1145,90 @@ end } end - def test_close_and_socket_close_while_connecting - # test it doesn't cause a segmentation fault - ctx = OpenSSL::SSL::SSLContext.new - ctx.ciphers = "aNULL" - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } - ctx.security_level = 0 - - sock1, sock2 = socketpair - ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx) - ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx) + def test_get_ephemeral_key + # OpenSSL >= 1.0.2 + unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key) + pend "SSL_get_server_tmp_key() is not supported" + end - t = Thread.new { ssl1.connect } - ssl2.accept + if tls12_supported? + # kRSA + ctx_proc1 = proc { |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "kRSA" + } + start_server(ctx_proc: ctx_proc1) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "kRSA" + server_connect(port, ctx) { |ssl| assert_nil ssl.tmp_key } + end + end - ssl1.close - sock1.close - t.value rescue nil - ensure - ssl1.close if ssl1 - ssl2.close if ssl2 - sock1.close if sock1 - sock2.close if sock2 - end + if defined?(OpenSSL::PKey::DH) && tls12_supported? + # DHE + # TODO: How to test this with TLS 1.3? + ctx_proc2 = proc { |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "EDH" + } + start_server(ctx_proc: ctx_proc2) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "EDH" + server_connect(port, ctx) { |ssl| + assert_instance_of OpenSSL::PKey::DH, ssl.tmp_key + } + end + end - def test_get_ephemeral_key - return unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key) - pkey = OpenSSL::PKey - ciphers = { - 'ECDHE-RSA-AES128-SHA' => (pkey::EC if defined?(pkey::EC)), - 'DHE-RSA-AES128-SHA' => (pkey::DH if defined?(pkey::DH)), - 'AES128-SHA' => nil - } - conf_proc = Proc.new { |ctx| ctx.ciphers = 'ALL' } - start_server(ctx_proc: conf_proc) do |server, port| - ciphers.each do |cipher, ephemeral| + if defined?(OpenSSL::PKey::EC) + # ECDHE + ctx_proc3 = proc { |ctx| + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + ctx.ecdh_curves = "P-256" + } + start_server(ctx_proc: ctx_proc3) do |port| ctx = OpenSSL::SSL::SSLContext.new - begin - ctx.ciphers = cipher - rescue OpenSSL::SSL::SSLError => e - next if /no cipher match/ =~ e.message - raise - end - server_connect(port, ctx) do |ssl| - if ephemeral - assert_instance_of(ephemeral, ssl.tmp_key) - else - assert_nil(ssl.tmp_key) - end - end + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + server_connect(port, ctx) { |ssl| + assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key + } end end end def test_dh_callback + pend "TLS 1.2 is not supported" unless tls12_supported? + called = false ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 ctx.ciphers = "DH:!NULL" ctx.tmp_dh_callback = ->(*args) { called = true - OpenSSL::TestUtils::TEST_KEY_DH1024 + Fixtures.pkey_dh("dh1024") } } - start_server(ctx_proc: ctx_proc) do |server, port| + start_server(ctx_proc: ctx_proc) do |port| server_connect(port) { |ssl| assert called, "dh callback should be called" if ssl.respond_to?(:tmp_key) - assert_equal OpenSSL::TestUtils::TEST_KEY_DH1024.to_der, ssl.tmp_key.to_der + assert_equal Fixtures.pkey_dh("dh1024").to_der, ssl.tmp_key.to_der end } end end def test_connect_works_when_setting_dh_callback_to_nil + pend "TLS 1.2 is not supported" unless tls12_supported? + ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 ctx.ciphers = "DH:!NULL" # use DH ctx.tmp_dh_callback = nil } - start_server(ctx_proc: ctx_proc) do |server, port| + start_server(ctx_proc: ctx_proc) do |port| EnvUtil.suppress_warning { # uses default callback assert_nothing_raised { server_connect(port) { } @@ -1133,73 +1237,53 @@ end end end - def test_ecdh_callback - return unless OpenSSL::SSL::SSLContext.instance_methods.include?(:tmp_ecdh_callback) + def test_tmp_ecdh_callback + pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) + pend "tmp_ecdh_callback is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:tmp_ecdh_callback) + EnvUtil.suppress_warning do # tmp_ecdh_callback is deprecated (2016-05) - begin - called = false - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.ciphers = "ECDH" - # OpenSSL 1.1.0 doesn't have tmp_ecdh_callback so this shouldn't be required - ctx2.security_level = 0 - ctx2.tmp_ecdh_callback = ->(*args) { + called = false + ctx_proc = -> ctx { + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + ctx.tmp_ecdh_callback = -> (*args) { called = true OpenSSL::PKey::EC.new "prime256v1" } - - sock1, sock2 = socketpair - - s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.ciphers = "ECDH" - ctx1.security_level = 0 - - s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) - th = Thread.new do - s1.connect - end - - s2.accept - assert called, 'ecdh callback should be called' - rescue OpenSSL::SSL::SSLError => e - if e.message =~ /no cipher match/ - pend "ECDH cipher not supported." - else - raise e - end - ensure - th.join if th - s1.close if s1 - s2.close if s2 - sock1.close if sock1 - sock2.close if sock2 + } + start_server(ctx_proc: ctx_proc) do |port| + server_connect(port) { |s| + assert called, "tmp_ecdh_callback should be called" + } end end end def test_ecdh_curves + pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) + ctx_proc = -> ctx { - begin - ctx.ciphers = "ECDH:!NULL" - rescue OpenSSL::SSL::SSLError - pend "ECDH is not enabled in this OpenSSL" if $!.message =~ /no cipher match/ - raise - end + # Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3 + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" ctx.ecdh_curves = "P-384:P-521" } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |server, port| + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| ctx = OpenSSL::SSL::SSLContext.new ctx.ecdh_curves = "P-256:P-384" # disable P-521 for OpenSSL >= 1.0.2 server_connect(port, ctx) { |ssl| - assert ssl.cipher[0].start_with?("ECDH"), "ECDH should be used" - if ssl.respond_to?(:tmp_key) + cs = ssl.cipher[0] + if /\ATLS/ =~ cs # Is TLS 1.3 is used? assert_equal "secp384r1", ssl.tmp_key.group.curve_name + else + assert_match (/\AECDH/), cs + if ssl.respond_to?(:tmp_key) + assert_equal "secp384r1", ssl.tmp_key.group.curve_name + end end } - if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 && - !OpenSSL::OPENSSL_VERSION.include?("LibreSSL") + if openssl?(1, 0, 2) || libressl?(2, 5, 1) ctx = OpenSSL::SSL::SSLContext.new ctx.ecdh_curves = "P-256" @@ -1226,10 +1310,10 @@ end return end assert_equal(1, ctx.security_level) - # assert_raise(OpenSSL::SSL::SSLError) { ctx.key = OpenSSL::TestUtils::TEST_KEY_DSA512 } - # ctx.key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + # assert_raise(OpenSSL::SSL::SSLError) { ctx.key = Fixtures.pkey("dsa512") } + # ctx.key = Fixtures.pkey("rsa1024") # ctx.security_level = 2 - # assert_raise(OpenSSL::SSL::SSLError) { ctx.key = OpenSSL::TestUtils::TEST_KEY_RSA1024 } + # assert_raise(OpenSSL::SSL::SSLError) { ctx.key = Fixtures.pkey("rsa1024") } pend "FIXME: SSLContext#key= currently does not raise because SSL_CTX_use_certificate() is delayed" end @@ -1248,7 +1332,7 @@ end def test_freeze_calls_setup bug = "[ruby/openssl#85]" - start_server(ignore_listener_error: true) { |server, port| + start_server(ignore_listener_error: true) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER ctx.freeze @@ -1274,7 +1358,7 @@ end ) end - def server_connect(port, ctx=nil) + def server_connect(port, ctx = nil) sock = TCPSocket.new("127.0.0.1", port) ssl = ctx ? OpenSSL::SSL::SSLSocket.new(sock, ctx) : OpenSSL::SSL::SSLSocket.new(sock) ssl.sync_close = true diff --git a/test/openssl/test_ssl_session.rb b/test/openssl/test_ssl_session.rb index 7a99dca5ed..199f722e8d 100644 --- a/test/openssl/test_ssl_session.rb +++ b/test/openssl/test_ssl_session.rb @@ -1,57 +1,15 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase - def test_session_equals - session = OpenSSL::SSL::Session.new <<-SESSION ------BEGIN SSL SESSION PARAMETERS----- -MIIDFgIBAQICAwEEAgA5BCCY3pW6iTkPoD5SENuztz/gZjhvey6XnHbsxd22k0Ol -dgQw8uaN3hCRnlhoIKPWInCFzrp/tQsDRFs9jDjc9pwpy/oKHmJdQQMQA1g8FYnO -gpdVoQYCBE52ikKiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B -AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi -eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA5MTkwMDE4MTBaFw0xMTA5MTkwMDQ4 -MTBaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 -LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB -7JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ -GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw -DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQARC7GP7InX1t7VEXz2 -I8RI57S0/HSJL4fDIYP3zFpitHX1PZeo+7XuzMilvPjjBo/ky9Jzo8TYiY+N+JEz -mY/A/zPA4ZsJ7KYj6/FEdIc/vRlS0CvsbClbNjw1jl/PoB2FLr2b3uuBcZEsyZeP -yq154ijq37Ajf8K5Mi5FgshoP41BPtRPj+VVf61rv1IcEnNWdDCS6DR4XsaNC+zt -G6AqCqkytIXWRuDw6n6vYLF3A/tn2sldLo7/scY0PMDNbo63O/LTxkDHmPhSkD68 -8m9SsMeTR+RCiDEZWFPVcAH/8mDfi+5k8uN3qS+gOU/PPrmHGgl5ykiSFgqs4v61 -tddwpBAEDjcwMzA5NTYzMTU1MzAwpQMCARM= ------END SSL SESSION PARAMETERS----- - SESSION - - start_server(ignore_listener_error: true) { |_, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT - ctx.session_id_context = self.object_id.to_s - - sock = TCPSocket.new '127.0.0.1', port - begin - ssl = OpenSSL::SSL::SSLSocket.new sock, ctx - ssl.session = session - - assert_equal session, ssl.session - ensure - sock.close - end - } - end - def test_session - Timeout.timeout(5) do - start_server do |server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect + pend "TLS 1.2 is not supported" unless tls12_supported? + + ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } + start_server(ctx_proc: ctx_proc) do |port| + server_connect_with_session(port, nil, nil) { |ssl| session = ssl.session assert(session == OpenSSL::SSL::Session.new(session.to_pem)) assert(session == OpenSSL::SSL::Session.new(ssl)) @@ -68,8 +26,7 @@ tddwpBAEDjcwMzA5NTYzMTU1MzAwpQMCARM= pem.gsub!(/-----(BEGIN|END) SSL SESSION PARAMETERS-----/, '').gsub!(/[\r\n]+/m, '') assert_equal(session.to_der, pem.unpack('m*')[0]) assert_not_nil(session.to_text) - ssl.close - end + } end end @@ -150,222 +107,245 @@ __EOS__ def test_session_exts_read assert(OpenSSL::SSL::Session.new(DUMMY_SESSION)) - end if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x009080bf - - def test_client_session - last_session = nil - start_server do |server, port| - 2.times do - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = last_session if last_session - ssl.connect + end - session = ssl.session - if last_session - assert(ssl.session_reused?) - assert_equal(session.id, last_session.id) - assert_equal(session.to_pem, last_session.to_pem) - assert_equal(session.to_der, last_session.to_der) - # Older version of OpenSSL may not be consistent. Look up which versions later. - assert_equal(session.to_text, last_session.to_text) - else - assert(!ssl.session_reused?) - end - last_session = session + def test_resumption + non_resumable = nil + start_server { |port| + server_connect_with_session(port, nil, nil) { |ssl| + non_resumable = ssl.session + } + } - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) + ctx_proc = proc { |ctx| + ctx.options &= ~OpenSSL::SSL::OP_NO_TICKET + # Disable server-side session cache which is enabled by default + ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF + } + start_server(ctx_proc: ctx_proc) do |port| + sess1 = server_connect_with_session(port, nil, nil) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + ssl.session + } - ssl.close - end + server_connect_with_session(port, nil, non_resumable) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + } + + server_connect_with_session(port, nil, sess1) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal true, ssl.session_reused? + } end end - def test_server_session - connections = 0 - saved_session = nil + def test_server_session_cache + pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = Proc.new do |ctx, ssl| -# add test for session callbacks here + ctx_proc = Proc.new do |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.options |= OpenSSL::SSL::OP_NO_TICKET end + connections = nil + saved_session = nil server_proc = Proc.new do |ctx, ssl| - session = ssl.session stats = ctx.session_cache_stats case connections when 0 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 0) - assert_equal(stats[:cache_misses], 0) - assert(!ssl.session_reused?) + assert_equal false, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 0, stats[:cache_hits] + assert_equal 0, stats[:cache_misses] when 1 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 0) - assert(ssl.session_reused?) - ctx.session_remove(session) - saved_session = session.to_der + assert_equal true, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 1, stats[:cache_hits] + assert_equal 0, stats[:cache_misses] + + saved_session = ssl.session + assert_equal true, ctx.session_remove(ssl.session) when 2 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 1) - assert(!ssl.session_reused?) - ctx.session_add(OpenSSL::SSL::Session.new(saved_session)) + assert_equal false, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 1, stats[:cache_hits] + assert_equal 1, stats[:cache_misses] + + assert_equal true, ctx.session_add(saved_session.dup) when 3 - assert_equal(stats[:cache_num], 2) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 1) - assert(ssl.session_reused?) + assert_equal true, ssl.session_reused? + assert_equal 2, stats[:cache_num] + assert_equal 2, stats[:cache_hits] + assert_equal 1, stats[:cache_misses] + ctx.flush_sessions(Time.now + 10000) when 4 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 2) - assert(!ssl.session_reused?) - ctx.session_add(OpenSSL::SSL::Session.new(saved_session)) + assert_equal false, ssl.session_reused? + assert_equal 1, stats[:cache_num] + assert_equal 2, stats[:cache_hits] + assert_equal 2, stats[:cache_misses] + + assert_equal true, ctx.session_add(saved_session.dup) end - connections += 1 readwrite_loop(ctx, ssl) end - first_session = nil - start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |server, port| + start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port| + first_session = nil 10.times do |i| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - # disable RFC4507 support - ctx.options = OpenSSL::SSL::OP_NO_TICKET - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = first_session if first_session - ssl.connect - - session = ssl.session - if first_session - case i - when 1; assert(ssl.session_reused?) - when 2; assert(!ssl.session_reused?) - when 3; assert(ssl.session_reused?) - when 4; assert(!ssl.session_reused?) - when 5..10; assert(ssl.session_reused?) + connections = i + server_connect_with_session(port, nil, first_session) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + first_session ||= ssl.session + + case connections + when 0; + when 1; assert_equal true, ssl.session_reused? + when 2; assert_equal false, ssl.session_reused? + when 3; assert_equal true, ssl.session_reused? + when 4; assert_equal false, ssl.session_reused? + when 5..9; assert_equal true, ssl.session_reused? end - end - first_session ||= session - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close + } end end end def test_ctx_client_session_cb - called = {} - ctx = OpenSSL::SSL::SSLContext.new - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT - - ctx.session_new_cb = lambda { |ary| - sock, sess = ary - called[:new] = [sock, sess] - } + pend "TLS 1.2 is not supported" unless tls12_supported? - ctx.session_remove_cb = lambda { |ary| - ctx, sess = ary - called[:remove] = [ctx, sess] - # any resulting value is OK (ignored) - } + ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } + start_server(ctx_proc: ctx_proc) do |port| + called = {} + ctx = OpenSSL::SSL::SSLContext.new + ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT + ctx.session_new_cb = lambda { |ary| + sock, sess = ary + called[:new] = [sock, sess] + } + ctx.session_remove_cb = lambda { |ary| + ctx, sess = ary + called[:remove] = [ctx, sess] + # any resulting value is OK (ignored) + } - start_server do |server, port| - sock = TCPSocket.new("127.0.0.1", port) - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect + server_connect_with_session(port, ctx, nil) { |ssl| assert_equal(1, ctx.session_cache_stats[:cache_num]) assert_equal(1, ctx.session_cache_stats[:connect_good]) assert_equal([ssl, ssl.session], called[:new]) assert(ctx.session_remove(ssl.session)) assert(!ctx.session_remove(ssl.session)) assert_equal([ctx, ssl.session], called[:remove]) - ssl.close - ensure - sock.close if !sock.closed? - end + } end end def test_ctx_server_session_cb - called = {} + pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = Proc.new { |ctx, ssl| - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER - ctx.options = OpenSSL::SSL::OP_NO_TICKET - last_server_session = nil + connections = nil + called = {} + sctx = nil + ctx_proc = Proc.new { |ctx| + sctx = ctx + ctx.ssl_version = :TLSv1_2 + ctx.options |= OpenSSL::SSL::OP_NO_TICKET # get_cb is called whenever a client proposed to resume a session but # the session could not be found in the internal session cache. + last_server_session = nil ctx.session_get_cb = lambda { |ary| - sess, data = ary - if last_server_session - called[:get2] = [sess, data] - last_server_session + _sess, data = ary + called[:get] = data + + if connections == 2 + last_server_session.dup else - called[:get1] = [sess, data] - last_server_session = sess nil end } ctx.session_new_cb = lambda { |ary| - sock, sess = ary - called[:new] = [sock, sess] - # SSL server doesn't cache sessions so get_cb is called next time. - ctx.session_remove(sess) + _sock, sess = ary + called[:new] = sess + last_server_session = sess } ctx.session_remove_cb = lambda { |ary| - ctx, sess = ary - called[:remove] = [ctx, sess] + _ctx, sess = ary + called[:remove] = sess } } - - server_proc = Proc.new { |c, ssl| - ssl.session - c.session_cache_stats - readwrite_loop(c, ssl) - } - start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |server, port| - last_client_session = nil - 3.times do - sock = TCPSocket.new("127.0.0.1", port) - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, OpenSSL::SSL::SSLContext.new()) - ssl.sync_close = true - ssl.session = last_client_session if last_client_session - ssl.connect - last_client_session = ssl.session - ssl.close - Timeout.timeout(5) do - Thread.pass until called.key?(:new) - assert(called.delete(:new)) - Thread.pass until called.key?(:remove) - assert(called.delete(:remove)) - end - ensure - sock.close if !sock.closed? + start_server(ctx_proc: ctx_proc) do |port| + connections = 0 + sess0 = server_connect_with_session(port, nil, nil) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + ssl.session + } + assert_nil called[:get] + assert_not_nil called[:new] + assert_equal sess0.id, called[:new].id + assert_nil called[:remove] + called.clear + + # Internal cache hit + connections = 1 + server_connect_with_session(port, nil, sess0.dup) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal true, ssl.session_reused? + ssl.session + } + assert_nil called[:get] + assert_nil called[:new] + assert_nil called[:remove] + called.clear + + sctx.flush_sessions(Time.now + 10000) + assert_not_nil called[:remove] + assert_equal sess0.id, called[:remove].id + called.clear + + # External cache hit + connections = 2 + sess2 = server_connect_with_session(port, nil, sess0.dup) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + if !ssl.session_reused? && openssl?(1, 1, 0) && !openssl?(1, 1, 0, 7) + # OpenSSL >= 1.1.0, < 1.1.0g + pend "External session cache is not working; " \ + "see https://github.com/openssl/openssl/pull/4014" end - end + assert_equal true, ssl.session_reused? + ssl.session + } + assert_equal sess0.id, sess2.id + assert_equal sess0.id, called[:get] + assert_nil called[:new] + assert_nil called[:remove] + called.clear + + sctx.flush_sessions(Time.now + 10000) + assert_not_nil called[:remove] + assert_equal sess0.id, called[:remove].id + called.clear + + # Cache miss + connections = 3 + sess3 = server_connect_with_session(port, nil, sess0.dup) { |ssl| + ssl.puts("abc"); assert_equal "abc\n", ssl.gets + assert_equal false, ssl.session_reused? + ssl.session + } + assert_not_equal sess0.id, sess3.id + assert_equal sess0.id, called[:get] + assert_not_nil called[:new] + assert_equal sess3.id, called[:new].id + assert_nil called[:remove] end - assert(called[:get1]) - assert(called[:get2]) end def test_dup @@ -373,6 +353,21 @@ __EOS__ sess_dup = sess_orig.dup assert_equal(sess_orig.to_der, sess_dup.to_der) end + + private + + def server_connect_with_session(port, ctx = nil, sess = nil) + sock = TCPSocket.new("127.0.0.1", port) + ctx ||= OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.session = sess if sess + ssl.sync_close = true + ssl.connect + yield ssl if block_given? + ensure + ssl&.close + sock&.close + end end end diff --git a/test/openssl/test_x509attr.rb b/test/openssl/test_x509attr.rb index d7473f1a29..108162f407 100644 --- a/test/openssl/test_x509attr.rb +++ b/test/openssl/test_x509attr.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Attribute < OpenSSL::TestCase def test_new diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb index 5b2e712d2a..289994d17b 100644 --- a/test/openssl/test_x509cert.rb +++ b/test/openssl/test_x509cert.rb @@ -1,23 +1,19 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Certificate < OpenSSL::TestCase def setup super - @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 - @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") end - def issue_cert(*args) - OpenSSL::TestUtils.issue_cert(*args) - end - def test_serial [1, 2**32, 2**100].each{|s| cert = issue_cert(@ca, @rsa2048, s, [], nil, nil) @@ -34,13 +30,10 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase ["authorityKeyIdentifier","keyid:always",false], ] - sha1 = OpenSSL::Digest::SHA1.new - dsa_digest = OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new - [ - [@rsa1024, sha1], [@rsa2048, sha1], [@dsa256, dsa_digest], [@dsa512, dsa_digest] - ].each{|pk, digest| - cert = issue_cert(@ca, pk, 1, exts, nil, nil, digest: digest) + @rsa1024, @rsa2048, @dsa256, @dsa512, + ].each{|pk| + cert = issue_cert(@ca, pk, 1, exts, nil, nil) assert_equal(cert.extensions.sort_by(&:to_s)[2].value, OpenSSL::TestUtils.get_subject_key_id(cert)) cert = OpenSSL::X509::Certificate.new(cert.to_der) @@ -152,26 +145,15 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase } end - def test_dsig_algorithm_mismatch - assert_raise(OpenSSL::X509::CertificateError) do - issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: OpenSSL::Digest::DSS1.new) - end if OpenSSL::OPENSSL_VERSION_NUMBER < 0x10001000 # [ruby-core:42949] - end - def test_dsa_with_sha2 - begin - cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha256") - assert_equal("dsa_with_SHA256", cert.signature_algorithm) - rescue OpenSSL::X509::CertificateError - # dsa_with_sha2 not supported. skip following test. - return - end + cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha256") + assert_equal("dsa_with_SHA256", cert.signature_algorithm) # TODO: need more tests for dsa + sha2 # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1") assert_equal("dsaWithSHA1", cert.signature_algorithm) - end if defined?(OpenSSL::Digest::SHA256) + end def test_check_private_key cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb index 44dfffc952..1914a651cf 100644 --- a/test/openssl/test_x509crl.rb +++ b/test/openssl/test_x509crl.rb @@ -1,28 +1,20 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509CRL < OpenSSL::TestCase def setup super - @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 - @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") end - def issue_crl(*args) - OpenSSL::TestUtils.issue_crl(*args) - end - - def issue_cert(*args) - OpenSSL::TestUtils.issue_cert(*args) - end - def test_basic now = Time.at(Time.now.to_i) @@ -196,7 +188,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @dsa512, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) + cert, @dsa512, OpenSSL::Digest::SHA1.new) assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) }) assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) }) assert_equal(false, crl.verify(@dsa256)) diff --git a/test/openssl/test_x509ext.rb b/test/openssl/test_x509ext.rb index 58f03168bc..f384a25e8c 100644 --- a/test/openssl/test_x509ext.rb +++ b/test/openssl/test_x509ext.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Extension < OpenSSL::TestCase def setup diff --git a/test/openssl/test_x509name.rb b/test/openssl/test_x509name.rb index 60e8ddb8ac..2d92e645be 100644 --- a/test/openssl/test_x509name.rb +++ b/test/openssl/test_x509name.rb @@ -1,8 +1,8 @@ -# coding: US-ASCII +# coding: ASCII-8BIT # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Name < OpenSSL::TestCase def setup @@ -148,33 +148,28 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase end def test_s_parse - dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" + dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org/1.2.3.4.5.6=A=BCD" name = OpenSSL::X509::Name.parse(dn) assert_equal(dn, name.to_s) ary = name.to_a - assert_equal("DC", ary[0][0]) - assert_equal("DC", ary[1][0]) - assert_equal("CN", ary[2][0]) - assert_equal("org", ary[0][1]) - assert_equal("ruby-lang", ary[1][1]) - assert_equal("www.ruby-lang.org", ary[2][1]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) - - dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org" + assert_equal [ + ["DC", "org", OpenSSL::ASN1::IA5STRING], + ["DC", "ruby-lang", OpenSSL::ASN1::IA5STRING], + ["CN", "www.ruby-lang.org", OpenSSL::ASN1::UTF8STRING], + ["1.2.3.4.5.6", "A=BCD", OpenSSL::ASN1::UTF8STRING], + ], ary + + dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org, 1.2.3.4.5.6=A=BCD" name = OpenSSL::X509::Name.parse(dn2) - ary = name.to_a assert_equal(dn, name.to_s) - assert_equal("org", ary[0][1]) - assert_equal("ruby-lang", ary[1][1]) - assert_equal("www.ruby-lang.org", ary[2][1]) + assert_equal ary, name.to_a name = OpenSSL::X509::Name.parse(dn2, @obj_type_tmpl) ary = name.to_a assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[3][2]) end def test_s_parse_rfc2253 @@ -306,7 +301,6 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase end def test_add_entry_street - return if OpenSSL::OPENSSL_VERSION_NUMBER < 0x009080df # 0.9.8m # openssl/crypto/objects/obj_mac.h 1.83 dn = [ ["DC", "org"], @@ -323,16 +317,87 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase assert_equal("Namiki", ary[5][1]) end + def test_add_entry_placing + der = %w{ 30 2A + 31 12 + 30 10 06 03 55 04 0A 0C 09 72 75 62 79 2D 6C 61 6E 67 + 31 14 + 30 08 06 03 55 04 0B 0C 01 61 + 30 08 06 03 55 04 0B 0C 01 62 } + orig = OpenSSL::X509::Name.new([der.join].pack("H*")) + assert_equal("OU=b+OU=a,O=ruby-lang", orig.to_s(OpenSSL::X509::Name::RFC2253)) + # Skip for now; they do not work + # + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 0, set: 0) + # assert_equal("OU=b+OU=a,O=ruby-lang,CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 0, set: 1) + # assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: 1, set: -1) + assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 1, set: 0) + # assert_equal("OU=b+OU=a,CN=unya,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: 1, set: 1) + assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: -1, set: -1) + assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: -1, set: 0) + assert_equal("CN=unya,OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + end + + def test_to_s + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "フー, バー"], + ] + name = OpenSSL::X509::Name.new + dn.each { |x| name.add_entry(*x) } + + assert_equal "/DC=org/DC=ruby-lang/" \ + "CN=\\xE3\\x83\\x95\\xE3\\x83\\xBC, \\xE3\\x83\\x90\\xE3\\x83\\xBC", + name.to_s + # OpenSSL escapes characters with MSB by default + assert_equal \ + "CN=\\E3\\83\\95\\E3\\83\\BC\\, \\E3\\83\\90\\E3\\83\\BC," \ + "DC=ruby-lang,DC=org", + name.to_s(OpenSSL::X509::Name::RFC2253) + assert_equal "DC = org, DC = ruby-lang, " \ + "CN = \"\\E3\\83\\95\\E3\\83\\BC, \\E3\\83\\90\\E3\\83\\BC\"", + name.to_s(OpenSSL::X509::Name::ONELINE) + end + + def test_to_utf8 + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "フー, バー"], + ] + name = OpenSSL::X509::Name.new + dn.each { |x| name.add_entry(*x) } + + str = name.to_utf8 + expected = "CN=フー\\, バー,DC=ruby-lang,DC=org".force_encoding("UTF-8") + assert_equal expected, str + assert_equal Encoding.find("UTF-8"), str.encoding + end + def test_equals2 - n1 = OpenSSL::X509::Name.parse 'CN=a' - n2 = OpenSSL::X509::Name.parse 'CN=a' + n1 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' + n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' assert_equal n1, n2 end def test_spaceship - n1 = OpenSSL::X509::Name.parse 'CN=a' - n2 = OpenSSL::X509::Name.parse 'CN=b' + n1 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' + n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=b' assert_equal(-1, n1 <=> n2) end diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb index 585dda1bc6..a21d45da19 100644 --- a/test/openssl/test_x509req.rb +++ b/test/openssl/test_x509req.rb @@ -1,15 +1,15 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Request < OpenSSL::TestCase def setup super - @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 - @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") @dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou") end @@ -28,7 +28,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase req = OpenSSL::X509::Request.new(req.to_der) assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) - req = issue_csr(0, @dn, @dsa512, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) @@ -122,7 +122,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase end def test_sign_and_verify_dsa - req = issue_csr(0, @dn, @dsa512, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) assert_equal(false, req.verify(@dsa256)) @@ -131,18 +131,6 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase assert_equal(false, req.verify(@dsa512)) end - def test_sign_and_verify_rsa_dss1 - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) - assert_equal(true, req.verify(@rsa1024)) - assert_equal(false, req.verify(@rsa2048)) - assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) - req.version = 1 - assert_equal(false, req.verify(@rsa1024)) - rescue OpenSSL::X509::RequestError - pend - end if defined?(OpenSSL::Digest::DSS1) - def test_sign_and_verify_dsa_md5 assert_raise(OpenSSL::X509::RequestError){ issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } diff --git a/test/openssl/test_x509store.rb b/test/openssl/test_x509store.rb index c45233aaec..6412249b93 100644 --- a/test/openssl/test_x509store.rb +++ b/test/openssl/test_x509store.rb @@ -1,15 +1,15 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Store < OpenSSL::TestCase def setup super - @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 - @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 + @rsa1024 = Fixtures.pkey("rsa1024") + @rsa2048 = Fixtures.pkey("rsa2048") + @dsa256 = Fixtures.pkey("dsa256") + @dsa512 = Fixtures.pkey("dsa512") @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1") @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2") @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") @@ -26,14 +26,6 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase ctx.verify end - def issue_cert(*args) - OpenSSL::TestUtils.issue_cert(*args) - end - - def issue_crl(*args) - OpenSSL::TestUtils.issue_crl(*args) - end - def test_add_file ca_exts = [ ["basicConstraints", "CA:TRUE", true], @@ -217,7 +209,7 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase end def test_set_errors - return if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000 + return if openssl?(1, 1, 0) || libressl? now = Time.now ca1_cert = issue_cert(@ca1, @rsa2048, 1, [], nil, nil) store = OpenSSL::X509::Store.new @@ -233,17 +225,9 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [], ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) store.add_crl(crl1) - if /0\.9\.8.*-rhel/ =~ OpenSSL::OPENSSL_VERSION - # RedHat is distributing a patched version of OpenSSL that allows - # multiple CRL for a key (multi-crl.patch) - assert_nothing_raised do - store.add_crl(crl2) # add CRL issued by same CA twice. - end - else - assert_raise(OpenSSL::X509::StoreError){ - store.add_crl(crl2) # add CRL issued by same CA twice. - } - end + assert_raise(OpenSSL::X509::StoreError){ + store.add_crl(crl2) # add CRL issued by same CA twice. + } end def test_dup diff --git a/test/openssl/ut_eof.rb b/test/openssl/ut_eof.rb index 6de41c4a70..bd62fd50f9 100644 --- a/test/openssl/ut_eof.rb +++ b/test/openssl/ut_eof.rb @@ -1,6 +1,8 @@ # frozen_string_literal: false require 'test/unit' +if defined?(OpenSSL) + module OpenSSL::TestEOF def test_eof_0 open_file("") {|f| @@ -127,3 +129,5 @@ module OpenSSL::TestEOF end end end + +end diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb index bbc9c7efc2..f59d53b0d1 100644 --- a/test/openssl/utils.rb +++ b/test/openssl/utils.rb @@ -9,129 +9,57 @@ begin rescue LoadError end +# Compile OpenSSL with crypto-mdebug and run this test suite with OSSL_MDEBUG=1 +# environment variable to enable memory leak check. +if ENV["OSSL_MDEBUG"] == "1" + if OpenSSL.respond_to?(:print_mem_leaks) + OpenSSL.mem_check_start + + END { + GC.start + case OpenSSL.print_mem_leaks + when nil + warn "mdebug: check what is printed" + when true + raise "mdebug: memory leaks detected" + end + } + else + warn "OSSL_MDEBUG=1 is specified but OpenSSL is not built with crypto-mdebug" + end +end + require "test/unit" -require 'tempfile' -require "rbconfig" +require "tempfile" require "socket" require "envutil" -module OpenSSL::TestUtils - TEST_KEY_RSA1024 = OpenSSL::PKey::RSA.new <<-_end_of_pem_ ------BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx -aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/ -Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB -AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0 -maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T -gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572 -74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE -JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX -sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII -8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA -wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi -qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD -dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA== ------END RSA PRIVATE KEY----- - _end_of_pem_ - - TEST_KEY_RSA2048 = OpenSSL::PKey::RSA.new <<-_end_of_pem_ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN -s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign -4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D -kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl -NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J -DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb -I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq -PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V -seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0 -Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc -VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW -wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G -0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj -XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb -aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n -h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw -Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k -IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb -v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId -U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr -vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS -Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC -9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41 -gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG -4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw== ------END RSA PRIVATE KEY----- - _end_of_pem_ - - TEST_KEY_DSA256 = OpenSSL::PKey::DSA.new <<-_end_of_pem_ ------BEGIN DSA PRIVATE KEY----- -MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE -9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed -AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM -3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT -b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn -ISNX5cMzFHRW3Q== ------END DSA PRIVATE KEY----- - _end_of_pem_ +if defined?(OpenSSL) - TEST_KEY_DSA512 = OpenSSL::PKey::DSA.new <<-_end_of_pem_ ------BEGIN DSA PRIVATE KEY----- -MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok -RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D -AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR -S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++ -Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S -55jreJD3Se3slps= ------END DSA PRIVATE KEY----- - _end_of_pem_ - - TEST_KEY_DSA1024 = OpenSSL::PKey::DSA.new <<-_end_of_pem_ ------BEGIN DSA PRIVATE KEY----- -MIIBugIBAAKBgQCH9aAoXvWWThIjkA6D+nI1F9ksF9iDq594rkiGNOT9sPDOdB+n -D+qeeeeloRlj19ymCSADPI0ZLRgkchkAEnY2RnqnhHOjVf/roGgRbW+iQDMbQ9wa -/pvc6/fAbsu1goE1hBYjm98/sZEeXavj8tR56IXnjF1b6Nx0+sgeUKFKEQIVAMiz -4BJUFeTtddyM4uadBM7HKLPRAoGAZdLBSYNGiij7vAjesF5mGUKTIgPd+JKuBEDx -OaBclsgfdoyoF/TMOkIty+PVlYD+//Vl2xnoUEIRaMXHwHfm0r2xUX++oeRaSScg -YizJdUxe5jvBuBszGPRc/mGpb9YvP0sB+FL1KmuxYmdODfCe51zl8uM/CVhouJ3w -DjmRGscCgYAuFlfC7p+e8huCKydfcv/beftqjewiOPpQ3u5uI6KPCtCJPpDhs3+4 -IihH2cPsAlqwGF4tlibW1+/z/OZ1AZinPK3y7b2jSJASEaPeEltVzB92hcd1khk2 -jTYcmSsV4VddplOPK9czytR/GbbibxsrhhgZUbd8LPbvIgaiadJ1PgIUBnJ/5vN2 -CVArsEzlPUCbohPvZnE= ------END DSA PRIVATE KEY----- - _end_of_pem_ - -if defined?(OpenSSL::PKey::EC) - - TEST_KEY_EC_P256V1 = OpenSSL::PKey::EC.new <<-_end_of_pem_ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 -AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt -CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== ------END EC PRIVATE KEY----- - _end_of_pem_ - -end +module OpenSSL::TestUtils + module Fixtures + module_function - TEST_KEY_DH1024 = OpenSSL::PKey::DH.new <<-_end_of_pem_ ------BEGIN DH PARAMETERS----- -MIGHAoGBAKnKQ8MNK6nYZzLrrcuTsLxuiJGXoOO5gT+tljOTbHBuiktdMTITzIY0 -pFxIvjG05D7HoBZQfrR0c92NGWPkAiCkhQKB8JCbPVzwNLDy6DZ0pmofDKrEsYHG -AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC ------END DH PARAMETERS----- - _end_of_pem_ + def pkey(name) + OpenSSL::PKey.read(read_file("pkey", name)) + end - TEST_KEY_DH1024.set_key(OpenSSL::BN.new("556AF1598AE69899867CEBA9F29CE4862B884C2B43C9019EA0231908F6EFA785E3C462A6ECB16DF676866E997FFB72B487DC7967C58C3CA38CE974473BF19B2AA5DCBF102735572EBA6F353F6F0BBE7FF1DE1B07FE1381A355C275C33405004317F9491B5955F191F6615A63B30E55A027FB88A1A4B25608E09EEE68A7DF32D", 16), - OpenSSL::BN.new("48561834C67E65FFD2A9B47F41E5E78FDC95C387428FDB1E4B0188B64D1643C3A8D3455B945B7E8C4D166010C7C2CE23BFB9BEF43D0348FE7FA5284B0225E7FE1537546D114E3D8A4411B9B9351AB451E1A358F50ED61B1F00DA29336EEBBD649980AC86D76AF8BBB065298C2052672EEF3EF13AB47A15275FC2836F3AC74CEA", 16)) + def pkey_dh(name) + # DH parameters can be read by OpenSSL::PKey.read atm + OpenSSL::PKey::DH.new(read_file("pkey", name)) + end - DSA_SIGNATURE_DIGEST = OpenSSL::OPENSSL_VERSION_NUMBER > 0x10000000 ? - OpenSSL::Digest::SHA1 : - OpenSSL::Digest::DSS1 + def read_file(category, name) + @file_cache ||= {} + @file_cache[[category, name]] ||= + File.read(File.join(__dir__, "fixtures", category, name + ".pem")) + end + end module_function def issue_cert(dn, key, serial, extensions, issuer, issuer_key, - not_before: nil, not_after: nil, digest: nil) + not_before: nil, not_after: nil, digest: "sha256") cert = OpenSSL::X509::Certificate.new issuer = cert unless issuer issuer_key = key unless issuer_key @@ -149,7 +77,6 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC extensions.each{|oid, value, critical| cert.add_extension(ef.create_extension(oid, value, critical)) } - digest ||= OpenSSL::PKey::DSA === issuer_key ? DSA_SIGNATURE_DIGEST.new : "sha256" cert.sign(issuer_key, digest) cert end @@ -191,190 +118,191 @@ AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC OpenSSL::Digest::SHA1.hexdigest(pkvalue).scan(/../).join(":").upcase end - def silent - begin - back, $VERBOSE = $VERBOSE, nil - yield - ensure - $VERBOSE = back - end + def openssl?(major = nil, minor = nil, fix = nil, patch = 0) + return false if OpenSSL::OPENSSL_VERSION.include?("LibreSSL") + return true unless major + OpenSSL::OPENSSL_VERSION_NUMBER >= + major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10 end - class OpenSSL::TestCase < Test::Unit::TestCase - def setup - if ENV["OSSL_GC_STRESS"] == "1" - GC.stress = true - end - end - - def teardown - if ENV["OSSL_GC_STRESS"] == "1" - GC.stress = false - end - # OpenSSL error stack must be empty - assert_equal([], OpenSSL.errors) - end + def libressl?(major = nil, minor = nil, fix = nil) + version = OpenSSL::OPENSSL_VERSION.scan(/LibreSSL (\d+)\.(\d+)\.(\d+).*/)[0] + return false unless version + !major || (version.map(&:to_i) <=> [major, minor, fix]) >= 0 end +end - class OpenSSL::SSLTestCase < OpenSSL::TestCase - RUBY = EnvUtil.rubybin - ITERATIONS = ($0 == __FILE__) ? 100 : 10 - - def setup - super - @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA2048 - @svr_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @cli_key = OpenSSL::TestUtils::TEST_KEY_DSA1024 - @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") - @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","cRLSign,keyCertSign",true], - ] - ee_exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ] - @ca_cert = issue_cert(@ca, @ca_key, 1, ca_exts, nil, nil) - @svr_cert = issue_cert(@svr, @svr_key, 2, ee_exts, @ca_cert, @ca_key) - @cli_cert = issue_cert(@cli, @cli_key, 3, ee_exts, @ca_cert, @ca_key) - @server = nil - end +class OpenSSL::TestCase < Test::Unit::TestCase + include OpenSSL::TestUtils + extend OpenSSL::TestUtils - def issue_cert(*arg) - OpenSSL::TestUtils.issue_cert(*arg) + def setup + if ENV["OSSL_GC_STRESS"] == "1" + GC.stress = true end + end - def issue_crl(*arg) - OpenSSL::TestUtils.issue_crl(*arg) + def teardown + if ENV["OSSL_GC_STRESS"] == "1" + GC.stress = false end + # OpenSSL error stack must be empty + assert_equal([], OpenSSL.errors) + end +end - def readwrite_loop(ctx, ssl) - while line = ssl.gets - ssl.write(line) - end - rescue OpenSSL::SSL::SSLError - rescue IOError - ensure - ssl.close rescue nil - end +class OpenSSL::SSLTestCase < OpenSSL::TestCase + RUBY = EnvUtil.rubybin + ITERATIONS = ($0 == __FILE__) ? 100 : 10 + + def setup + super + @ca_key = Fixtures.pkey("rsa2048") + @svr_key = Fixtures.pkey("rsa1024") + @cli_key = Fixtures.pkey("rsa2048") + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","cRLSign,keyCertSign",true], + ] + ee_exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ] + @ca_cert = issue_cert(@ca, @ca_key, 1, ca_exts, nil, nil) + @svr_cert = issue_cert(@svr, @svr_key, 2, ee_exts, @ca_cert, @ca_key) + @cli_cert = issue_cert(@cli, @cli_key, 3, ee_exts, @ca_cert, @ca_key) + @server = nil + end - def server_loop(ctx, ssls, stop_pipe_r, ignore_listener_error, server_proc, threads) - loop do - ssl = nil - begin - readable, = IO.select([ssls, stop_pipe_r]) - if readable.include? stop_pipe_r - return - end - ssl = ssls.accept - rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET - if ignore_listener_error - retry - else - raise - end - end + def tls12_supported? + ctx = OpenSSL::SSL::SSLContext.new + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + true + rescue + end - th = Thread.start do - server_proc.call(ctx, ssl) - end - threads << th - end - rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET - if !ignore_listener_error - raise - end + def readwrite_loop(ctx, ssl) + while line = ssl.gets + ssl.write(line) end + end - def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true, - ctx_proc: nil, server_proc: method(:readwrite_loop), - ignore_listener_error: false, &block) - IO.pipe {|stop_pipe_r, stop_pipe_w| - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - ctx = OpenSSL::SSL::SSLContext.new - ctx.cert_store = store - ctx.cert = @svr_cert - ctx.key = @svr_key - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } - begin - ctx.ecdh_curves = "P-256" - rescue NotImplementedError - end - ctx.verify_mode = verify_mode - ctx_proc.call(ctx) if ctx_proc - - Socket.do_not_reverse_lookup = true - tcps = nil - tcps = TCPServer.new("127.0.0.1", 0) - port = tcps.connect_address.ip_port - - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - ssls.start_immediately = start_immediately - - threads = [] - begin - server = Thread.new do - begin - server_loop(ctx, ssls, stop_pipe_r, ignore_listener_error, server_proc, threads) - ensure - tcps.close + def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true, + ctx_proc: nil, server_proc: method(:readwrite_loop), + ignore_listener_error: false, &block) + IO.pipe {|stop_pipe_r, stop_pipe_w| + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + ctx = OpenSSL::SSL::SSLContext.new + ctx.cert_store = store + ctx.cert = @svr_cert + ctx.key = @svr_key + ctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") } + ctx.verify_mode = verify_mode + ctx_proc.call(ctx) if ctx_proc + + Socket.do_not_reverse_lookup = true + tcps = TCPServer.new("127.0.0.1", 0) + port = tcps.connect_address.ip_port + + ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) + ssls.start_immediately = start_immediately + + threads = [] + begin + server_thread = Thread.new do + begin + loop do + begin + readable, = IO.select([ssls, stop_pipe_r]) + break if readable.include? stop_pipe_r + ssl = ssls.accept + rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL, + Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET + retry if ignore_listener_error + raise + end + + th = Thread.new do + begin + server_proc.call(ctx, ssl) + ensure + ssl.close + end + true + end + threads << th end + ensure + tcps.close end - threads.unshift server - - $stderr.printf("SSL server started: pid=%d port=%d\n", $$, port) if $DEBUG + end - client = Thread.new do - begin - block.call(server, port.to_i) - ensure - stop_pipe_w.close - end + client_thread = Thread.new do + begin + block.call(port) + ensure + # Stop accepting new connection + stop_pipe_w.close + server_thread.join end - threads.unshift client - ensure - assert_join_threads(threads) end - } - end + threads.unshift client_thread + ensure + # Terminate existing connections. If a thread did 'pend', re-raise it. + pend = nil + threads.each { |th| + begin + th.join(10) or + th.raise(RuntimeError, "[start_server] thread did not exit in 10 secs") + rescue (defined?(MiniTest::Skip) ? MiniTest::Skip : Test::Unit::PendedError) + # MiniTest::Skip is for the Ruby tree + pend = $! + rescue Exception + end + } + raise pend if pend + assert_join_threads(threads) + end + } end +end - class OpenSSL::PKeyTestCase < OpenSSL::TestCase - def check_component(base, test, keys) - keys.each { |comp| - assert_equal base.send(comp), test.send(comp) - } - end +class OpenSSL::PKeyTestCase < OpenSSL::TestCase + def check_component(base, test, keys) + keys.each { |comp| + assert_equal base.send(comp), test.send(comp) + } + end - def dup_public(key) - case key - when OpenSSL::PKey::RSA - rsa = OpenSSL::PKey::RSA.new - rsa.set_key(key.n, key.e, nil) - rsa - when OpenSSL::PKey::DSA - dsa = OpenSSL::PKey::DSA.new - dsa.set_pqg(key.p, key.q, key.g) - dsa.set_key(key.pub_key, nil) - dsa - when OpenSSL::PKey::DH - dh = OpenSSL::PKey::DH.new - dh.set_pqg(key.p, nil, key.g) - dh + def dup_public(key) + case key + when OpenSSL::PKey::RSA + rsa = OpenSSL::PKey::RSA.new + rsa.set_key(key.n, key.e, nil) + rsa + when OpenSSL::PKey::DSA + dsa = OpenSSL::PKey::DSA.new + dsa.set_pqg(key.p, key.q, key.g) + dsa.set_key(key.pub_key, nil) + dsa + when OpenSSL::PKey::DH + dh = OpenSSL::PKey::DH.new + dh.set_pqg(key.p, nil, key.g) + dh + else + if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key + ec = OpenSSL::PKey::EC.new(key.group) + ec.public_key = key.public_key + ec else - if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key - ec = OpenSSL::PKey::EC.new(key.group) - ec.public_key = key.public_key - ec - else - raise "unknown key type" - end + raise "unknown key type" end end end +end -end if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) and - /\AOpenSSL +0\./ !~ OpenSSL::OPENSSL_LIBRARY_VERSION +end |