From a55320b0933cbcfd05d427fe3712bc519c713deb Mon Sep 17 00:00:00 2001 From: rhe Date: Sat, 25 Nov 2017 14:12:08 +0000 Subject: openssl: import v2.1.0.beta2 Import Ruby/OpenSSL 2.1.0.beta2. The full commit log since commit e72d960db262 which was imported by r60013 can be found at: https://github.com/ruby/openssl/compare/e72d960db262...v2.1.0.beta2 ---------------------------------------------------------------- Kazuki Yamaguchi (26): bn: use ALLOCV() macro instead of xmalloc() appveyor.yml: remove 'openssl version' line test/test_ssl_session: skip tests for session_remove_cb x509ext: implement X509::Extension#== x509attr: implement X509::Attribute#== x509cert: implement X509::Certificate#== x509revoked: add missing X509::Revoked#to_der x509crl, x509revoked: implement X509::{CRL,Revoked}#== x509req: implement X509::Request#== ssl: extract rb_intern("call") cipher: disallow setting AAD for non-AEAD ciphers test/test_cipher: fix test_non_aead_cipher_set_auth_data failure ssl: fix conflict of options in SSLContext#set_params buffering: let #write accept multiple arguments pkey: make pkey_check_public_key() non-static x509cert, x509crl, x509req, ns_spki: check sanity of public key test/envutil: port assert_warning from Ruby trunk test/utils: remove a pointless .public_key call in issue_cert ssl: add SSLContext#add_certificate test/test_ssl: fix test_security_level Drop support for LibreSSL 2.4 kdf: add HKDF support test/test_x509cert: fix flaky test test/test_x509crl: fix random failure History.md: fix a typo Ruby/OpenSSL 2.1.0.beta2 Mark Wright (1): Fix build failure against OpenSSL 1.1 built with no-deprecated Thanks rhenium for the code review and fixes. Peter Karman (1): Add RSA sign_pss() and verify_pss() methods aeris (1): TLS Fallback Signaling Cipher Suite Value kazu (1): Use caller with length to reduce unused strings git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60907 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- test/openssl/test_cipher.rb | 7 ++ test/openssl/test_kdf.rb | 42 +++++++++++ test/openssl/test_ocsp.rb | 11 ++- test/openssl/test_pair.rb | 9 +++ test/openssl/test_pkey_rsa.rb | 33 +++++++++ test/openssl/test_ssl.rb | 157 ++++++++++++++++++++++++++++++++++++++++-- test/openssl/test_x509attr.rb | 17 +++++ test/openssl/test_x509cert.rb | 20 ++++++ test/openssl/test_x509crl.rb | 52 ++++++++++++++ test/openssl/test_x509ext.rb | 11 +++ test/openssl/test_x509req.rb | 10 +++ test/openssl/utils.rb | 2 +- 12 files changed, 358 insertions(+), 13 deletions(-) (limited to 'test/openssl') diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb index d87dedf73c..56061741bc 100644 --- a/test/openssl/test_cipher.rb +++ b/test/openssl/test_cipher.rb @@ -295,6 +295,13 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal tag1, tag2 end + def test_non_aead_cipher_set_auth_data + assert_raise(OpenSSL::Cipher::CipherError) { + cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt + cipher.auth_data = "123" + } + end + private def new_encryptor(algo, **kwargs) diff --git a/test/openssl/test_kdf.rb b/test/openssl/test_kdf.rb index d91fa3cf5d..5e1db80c5f 100644 --- a/test/openssl/test_kdf.rb +++ b/test/openssl/test_kdf.rb @@ -131,6 +131,48 @@ class OpenSSL::TestKDF < OpenSSL::TestCase assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) end + def test_hkdf_rfc5869_test_case_1 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha256" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + salt = B("000102030405060708090a0b0c") + info = B("f0f1f2f3f4f5f6f7f8f9") + l = 42 + + okm = B("3cb25f25faacd57a90434f64d0362f2a" \ + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" \ + "34007208d5b887185865") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + def test_hkdf_rfc5869_test_case_3 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha256" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + salt = B("") + info = B("") + l = 42 + + okm = B("8da4e775a563c18f715f802a063c5a31" \ + "b8a11f5c5ee1879ec3454e5f3c738d2d" \ + "9d201395faa4b61a96c8") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + def test_hkdf_rfc5869_test_case_4 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha1" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b") + salt = B("000102030405060708090a0b0c") + info = B("f0f1f2f3f4f5f6f7f8f9") + l = 42 + + okm = B("085a01ea1b10f36933068b56efa5ad81" \ + "a4f14b822f5b091568a9cdd4f155fda2" \ + "c22e422478d305f3f896") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + private def B(ary) diff --git a/test/openssl/test_ocsp.rb b/test/openssl/test_ocsp.rb index 9d48496de5..50ad6c31f5 100644 --- a/test/openssl/test_ocsp.rb +++ b/test/openssl/test_ocsp.rb @@ -122,12 +122,12 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) ret = req.verify([@cert], store) - if ret || openssl?(1, 0, 2) || libressl?(2, 4, 2) + if ret || openssl?(1, 0, 2) assert_equal true, ret else # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when # OCSP_NOINTERN is not specified. - # fixed by OpenSSL 1.0.1j, 1.0.2 and LibreSSL 2.4.2 + # fixed by OpenSSL 1.0.1j, 1.0.2 pend "RT2560: ocsp_req_find_signer" end @@ -262,11 +262,6 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, []) bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil) - if bres.responses[2].check_validity # thisUpdate is in future; must fail - # LibreSSL bug; skip for now - pend "OCSP_check_validity() is broken" - end - single1 = bres.responses[0] assert_equal false, single1.check_validity assert_equal false, single1.check_validity(30) @@ -275,6 +270,8 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal true, single2.check_validity assert_equal true, single2.check_validity(0, 500) assert_equal false, single2.check_validity(0, 200) + single3 = bres.responses[2] + assert_equal false, single3.check_validity end def test_response diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb index 55b62321b8..29d5c9bbb1 100644 --- a/test/openssl/test_pair.rb +++ b/test/openssl/test_pair.rb @@ -362,6 +362,15 @@ module OpenSSL::TestPairM } end + def test_write_multiple_arguments + ssl_pair {|s1, s2| + str1 = "foo"; str2 = "bar" + assert_equal 6, s1.write(str1, str2) + s1.close + assert_equal "foobar", s2.read + } + end + def test_partial_tls_record_read_nonblock ssl_pair { |s1, s2| # the beginning of a TLS record diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb index 49ab379251..d9bea1a622 100644 --- a/test/openssl/test_pkey_rsa.rb +++ b/test/openssl/test_pkey_rsa.rb @@ -113,6 +113,39 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase } end + def test_sign_verify_pss + key = Fixtures.pkey("rsa1024") + data = "Sign me!" + invalid_data = "Sign me?" + + signature = key.sign_pss("SHA256", data, salt_length: 20, mgf1_hash: "SHA1") + assert_equal 128, signature.bytesize + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1") + assert_equal false, + key.verify_pss("SHA256", signature, invalid_data, salt_length: 20, mgf1_hash: "SHA1") + + signature = key.sign_pss("SHA256", data, salt_length: :digest, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: 32, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1") + assert_equal false, + key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1") + + signature = key.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: 94, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1") + + assert_raise(OpenSSL::PKey::RSAError) { + key.sign_pss("SHA256", data, salt_length: 95, mgf1_hash: "SHA1") + } + end + def test_RSAPrivateKey rsa1024 = Fixtures.pkey("rsa1024") asn1 = OpenSSL::ASN1::Sequence([ diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 4f3df9dd1d..b3f3143f4f 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -54,6 +54,87 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end + def test_add_certificate + ctx_proc = -> ctx { + # Unset values set by start_server + ctx.cert = ctx.key = ctx.extra_chain_cert = nil + ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA + } + start_server(ctx_proc: ctx_proc) do |port| + server_connect(port) { |ssl| + assert_equal @svr_cert.subject, ssl.peer_cert.subject + assert_equal [@svr_cert.subject, @ca_cert.subject], + ssl.peer_cert_chain.map(&:subject) + } + end + end + + def test_add_certificate_multiple_certs + pend "EC is not supported" unless defined?(OpenSSL::PKey::EC) + pend "TLS 1.2 is not supported" unless tls12_supported? + + # SSL_CTX_set0_chain() is needed for setting multiple certificate chains + add0_chain_supported = openssl?(1, 0, 2) + + if add0_chain_supported + ca2_key = Fixtures.pkey("rsa1024") + ca2_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["keyUsage", "cRLSign, keyCertSign", true], + ] + ca2_dn = OpenSSL::X509::Name.parse_rfc2253("CN=CA2") + ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil) + else + # Use the same CA as @svr_cert + ca2_key = @ca_key; ca2_cert = @ca_cert + end + + ecdsa_key = Fixtures.pkey("p256") + exts = [ + ["keyUsage", "digitalSignature", false], + ] + ecdsa_dn = OpenSSL::X509::Name.parse_rfc2253("CN=localhost2") + ecdsa_cert = issue_cert(ecdsa_dn, ecdsa_key, 456, exts, ca2_cert, ca2_key) + + if !add0_chain_supported + # Testing the warning emitted when 'extra' chain is replaced + tctx = OpenSSL::SSL::SSLContext.new + tctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) + assert_warning(/set0_chain/) { + tctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) + } + end + + ctx_proc = -> ctx { + # Unset values set by start_server + ctx.cert = ctx.key = ctx.extra_chain_cert = nil + ctx.ecdh_curves = "P-256" unless openssl?(1, 0, 2) + ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA + EnvUtil.suppress_warning do # !add0_chain_supported + ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) + end + } + start_server(ctx_proc: ctx_proc) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = :TLS1_2 # TODO: We need this to force certificate type + ctx.ciphers = "aECDSA" + server_connect(port, ctx) { |ssl| + assert_equal ecdsa_cert.subject, ssl.peer_cert.subject + assert_equal [ecdsa_cert.subject, ca2_cert.subject], + ssl.peer_cert_chain.map(&:subject) + } + + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = :TLS1_2 + ctx.ciphers = "aRSA" + server_connect(port, ctx) { |ssl| + assert_equal @svr_cert.subject, ssl.peer_cert.subject + assert_equal [@svr_cert.subject, @ca_cert.subject], + ssl.peer_cert_chain.map(&:subject) + } + end + end + def test_sysread_and_syswrite start_server { |port| server_connect(port) { |ssl| @@ -1222,6 +1303,59 @@ end end end + def test_fallback_scsv + pend "Fallback SCSV is not supported" unless OpenSSL::SSL::SSLContext.method_defined?( :enable_fallback_scsv) + + start_server do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + # Here is OK + # TLS1.2 supported and this is what we ask the first time + server_connect(port, ctx) + end + + ctx_proc = proc { |ctx| + ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + } + start_server(ctx_proc: ctx_proc) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.enable_fallback_scsv + ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + # Here is OK too + # TLS1.2 not supported, fallback to TLS1.1 and signaling the fallback + # Server doesn't support better, so connection OK + server_connect(port, ctx) + end + + # Here is not OK + # TLS1.2 is supported, fallback to TLS1.1 (downgrade attack) and signaling the fallback + # Server support better, so refuse the connection + sock1, sock2 = socketpair + begin + ctx1 = OpenSSL::SSL::SSLContext.new + s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) + + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.enable_fallback_scsv + ctx2.max_version = OpenSSL::SSL::TLS1_1_VERSION + s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) + t = Thread.new { + assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { + s2.connect + } + } + + assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { + s1.accept + } + + assert t.join + ensure + sock1.close + sock2.close + end + end + def test_dh_callback pend "TLS 1.2 is not supported" unless tls12_supported? @@ -1336,11 +1470,24 @@ end return end assert_equal(1, ctx.security_level) - # 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 = Fixtures.pkey("rsa1024") } - pend "FIXME: SSLContext#key= currently does not raise because SSL_CTX_use_certificate() is delayed" + + dsa512 = Fixtures.pkey("dsa512") + dsa512_cert = issue_cert(@svr, dsa512, 50, [], @ca_cert, @ca_key) + rsa1024 = Fixtures.pkey("rsa1024") + rsa1024_cert = issue_cert(@svr, rsa1024, 51, [], @ca_cert, @ca_key) + + assert_raise(OpenSSL::SSL::SSLError) { + # 512 bit DSA key is rejected because it offers < 80 bits of security + ctx.add_certificate(dsa512_cert, dsa512) + } + assert_nothing_raised { + ctx.add_certificate(rsa1024_cert, rsa1024) + } + ctx.security_level = 2 + assert_raise(OpenSSL::SSL::SSLError) { + # < 112 bits of security + ctx.add_certificate(rsa1024_cert, rsa1024) + } end def test_dup diff --git a/test/openssl/test_x509attr.rb b/test/openssl/test_x509attr.rb index 108162f407..c6c48e86ab 100644 --- a/test/openssl/test_x509attr.rb +++ b/test/openssl/test_x509attr.rb @@ -62,6 +62,23 @@ class OpenSSL::TestX509Attribute < OpenSSL::TestCase attr = OpenSSL::X509::Attribute.new("challengePassword", val) assert_equal(attr.to_der, attr.dup.to_der) end + + def test_eq + val1 = OpenSSL::ASN1::Set([ + OpenSSL::ASN1::UTF8String("abc123") + ]) + attr1 = OpenSSL::X509::Attribute.new("challengePassword", val1) + attr2 = OpenSSL::X509::Attribute.new("challengePassword", val1) + ef = OpenSSL::X509::ExtensionFactory.new + val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ + ef.create_extension("keyUsage", "keyCertSign", true) + ])]) + attr3 = OpenSSL::X509::Attribute.new("extReq", val2) + + assert_equal false, attr1 == 12345 + assert_equal true, attr1 == attr2 + assert_equal false, attr1 == attr3 + end end end diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb index 289994d17b..40a5b0ad74 100644 --- a/test/openssl/test_x509cert.rb +++ b/test/openssl/test_x509cert.rb @@ -169,6 +169,26 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase } end + def test_eq + now = Time.now + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil, + not_before: now, not_after: now + 3600) + cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + digest: "sha512", not_before: now, not_after: now + 3600) + + assert_equal false, cert1 == 12345 + assert_equal true, cert1 == cert2 + assert_equal false, cert1 == cert3 + assert_equal false, cert1 == cert4 + assert_equal false, cert3 == cert4 + end + private def certificate_error_returns_false diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb index 1914a651cf..03fdf64dd4 100644 --- a/test/openssl/test_x509crl.rb +++ b/test/openssl/test_x509crl.rb @@ -197,6 +197,58 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase assert_equal(false, crl.verify(@dsa512)) end + def test_revoked_to_der + # revokedCertificates SEQUENCE OF SEQUENCE { + # userCertificate CertificateSerialNumber, + # revocationDate Time, + # crlEntryExtensions Extensions OPTIONAL + # -- if present, version MUST be v2 + # } OPTIONAL, + + now = Time.utc(2000, 1, 1) + rev1 = OpenSSL::X509::Revoked.new + rev1.serial = 123 + rev1.time = now + ext = OpenSSL::X509::Extension.new("CRLReason", OpenSSL::ASN1::Enumerated(1)) + rev1.extensions = [ext] + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(123), + OpenSSL::ASN1::UTCTime(now), + OpenSSL::ASN1::Sequence([ext.to_der]) + ]) + + assert_equal asn1.to_der, rev1.to_der + end + + def test_eq + now = Time.now + + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil) + crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256") + rev1 = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 1 + rev.time = now + } + crl1.add_revoked(rev1) + crl2 = OpenSSL::X509::CRL.new(crl1.to_der) + + # CRL + assert_equal false, crl1 == 12345 + assert_equal true, crl1 == crl2 + rev2 = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 2 + rev.time = now + } + crl2.add_revoked(rev2) + assert_equal false, crl1 == crl2 + + # Revoked + assert_equal false, rev1 == 12345 + assert_equal true, rev1 == crl2.revoked[0] + assert_equal false, rev1 == crl2.revoked[1] + assert_equal true, rev2 == crl2.revoked[1] + end + private def crl_error_returns_false diff --git a/test/openssl/test_x509ext.rb b/test/openssl/test_x509ext.rb index f384a25e8c..91ce202fec 100644 --- a/test/openssl/test_x509ext.rb +++ b/test/openssl/test_x509ext.rb @@ -75,6 +75,17 @@ class OpenSSL::TestX509Extension < OpenSSL::TestCase assert_equal(@basic_constraints.to_der, ext.to_der) assert_equal(ext.to_der, ext.dup.to_der) end + + def test_eq + ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + ef = OpenSSL::X509::ExtensionFactory.new + ext2 = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + ext3 = ef.create_extension("basicConstraints", "critical, CA:TRUE") + + assert_equal false, ext1 == 12345 + assert_equal true, ext1 == ext2 + assert_equal false, ext1 == ext3 + end end end diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb index a21d45da19..2c447ccdd5 100644 --- a/test/openssl/test_x509req.rb +++ b/test/openssl/test_x509req.rb @@ -141,6 +141,16 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase assert_equal(req.to_der, req.dup.to_der) end + def test_eq + req1 = issue_csr(0, @dn, @rsa1024, "sha1") + req2 = issue_csr(0, @dn, @rsa1024, "sha1") + req3 = issue_csr(0, @dn, @rsa1024, "sha256") + + assert_equal false, req1 == 12345 + assert_equal true, req1 == req2 + assert_equal false, req1 == req3 + end + private def request_error_returns_false diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb index f59d53b0d1..a359949061 100644 --- a/test/openssl/utils.rb +++ b/test/openssl/utils.rb @@ -67,7 +67,7 @@ module OpenSSL::TestUtils cert.serial = serial cert.subject = dn cert.issuer = issuer.subject - cert.public_key = key.public_key + cert.public_key = key now = Time.now cert.not_before = not_before || now - 3600 cert.not_after = not_after || now + 3600 -- cgit v1.2.3