diff options
-rw-r--r-- | .github/workflows/test.yml | 21 | ||||
-rw-r--r-- | ext/openssl/ossl_cipher.c | 18 | ||||
-rw-r--r-- | ext/openssl/ossl_pkcs7.c | 8 | ||||
-rw-r--r-- | lib/openssl/buffering.rb | 17 | ||||
-rw-r--r-- | test/openssl/test_asn1.rb | 8 | ||||
-rw-r--r-- | test/openssl/test_cipher.rb | 16 | ||||
-rw-r--r-- | test/openssl/test_pkcs7.rb | 15 | ||||
-rw-r--r-- | test/openssl/test_x509req.rb | 7 |
8 files changed, 74 insertions, 36 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e8c22369..075bac8e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,12 +51,6 @@ jobs: run: echo "RUBY_OPENSSL_EXTCFLAGS=-Werror" >> $GITHUB_ENV if: ${{ !matrix.skip-warnings }} - # Enable provider search path for OpenSSL 3.0 in MSYS2. - # Remove when Ruby 3.2 build is updated - - name: enable windows provider search path - run: echo "OPENSSL_MODULES=$($env:RI_DEVKIT)\$($env:MSYSTEM_PREFIX)\lib\ossl-modules" >> $env:GITHUB_ENV - if: runner.os == 'Windows' && matrix.ruby == '3.2' - - name: compile run: rake compile @@ -77,18 +71,21 @@ jobs: # https://www.openssl.org/source/ - openssl-1.0.2u # EOL - openssl-1.1.0l # EOL - - openssl-1.1.1v - - openssl-3.0.10 - - openssl-3.1.2 + - openssl-1.1.1w # EOL + - openssl-3.0.13 + - openssl-3.1.5 + - openssl-3.2.1 + - openssl-3.3.0 # http://www.libressl.org/releases.html - libressl-3.1.5 # EOL - libressl-3.2.7 # EOL - libressl-3.3.6 # EOL - libressl-3.4.3 # EOL - libressl-3.5.3 # EOL - - libressl-3.6.3 - - libressl-3.7.3 - - libressl-3.8.0 # Development release + - libressl-3.6.3 # EOL + - libressl-3.7.3 # EOL + - libressl-3.8.4 + - libressl-3.9.1 fips-enabled: [ false ] include: - { os: ubuntu-latest, ruby: "3.0", openssl: openssl-3.0.10, fips-enabled: true, append-configure: 'enable-fips', name-extra: 'fips' } diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index 110610e1..506a0e71 100644 --- a/ext/openssl/ossl_cipher.c +++ b/ext/openssl/ossl_cipher.c @@ -386,11 +386,23 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) in = (unsigned char *)RSTRING_PTR(data); in_len = RSTRING_LEN(data); GetCipher(self, ctx); - out_len = in_len+EVP_CIPHER_CTX_block_size(ctx); - if (out_len <= 0) { + + /* + * As of OpenSSL 3.2, there is no reliable way to determine the required + * output buffer size for arbitrary cipher modes. + * https://github.com/openssl/openssl/issues/22628 + * + * in_len+block_size is usually sufficient, but AES key wrap with padding + * ciphers require in_len+15 even though they have a block size of 8 bytes. + * + * Using EVP_MAX_BLOCK_LENGTH (32) as a safe upper bound for ciphers + * currently implemented in OpenSSL, but this can change in the future. + */ + if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) { ossl_raise(rb_eRangeError, "data too big to make output buffer: %ld bytes", in_len); } + out_len = in_len + EVP_MAX_BLOCK_LENGTH; if (NIL_P(str)) { str = rb_str_new(0, out_len); @@ -401,7 +413,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len)) ossl_raise(eCipherError, NULL); - assert(out_len < RSTRING_LEN(str)); + assert(out_len <= RSTRING_LEN(str)); rb_str_set_len(str, out_len); return str; diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index 78dcbd66..aeeb4bf5 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -165,7 +165,11 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg) out = NULL; pkcs7 = SMIME_read_PKCS7(in, &out); BIO_free(in); - if(!pkcs7) ossl_raise(ePKCS7Error, NULL); + if (!pkcs7) + ossl_raise(ePKCS7Error, "Could not parse the PKCS7"); + if (!pkcs7->d.ptr) + ossl_raise(ePKCS7Error, "No content in PKCS7"); + data = out ? ossl_membio2str(out) : Qnil; SetPKCS7(ret, pkcs7); ossl_pkcs7_set_data(ret, data); @@ -346,6 +350,8 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self) BIO_free(in); if (!p7) ossl_raise(rb_eArgError, "Could not parse the PKCS7"); + if (!p7->d.ptr) + ossl_raise(rb_eArgError, "No content in PKCS7"); RTYPEDDATA_DATA(self) = p7; PKCS7_free(p7_orig); diff --git a/lib/openssl/buffering.rb b/lib/openssl/buffering.rb index 9570f14f..4df90746 100644 --- a/lib/openssl/buffering.rb +++ b/lib/openssl/buffering.rb @@ -345,13 +345,18 @@ module OpenSSL::Buffering @wbuffer << s @wbuffer.force_encoding(Encoding::BINARY) @sync ||= false - if @sync or @wbuffer.size > BLOCK_SIZE - until @wbuffer.empty? - begin - nwrote = syswrite(@wbuffer) - rescue Errno::EAGAIN - retry + buffer_size = @wbuffer.size + if @sync or buffer_size > BLOCK_SIZE + nwrote = 0 + begin + while nwrote < buffer_size do + begin + nwrote += syswrite(@wbuffer[nwrote, buffer_size - nwrote]) + rescue Errno::EAGAIN + retry + end end + ensure @wbuffer[0, nwrote] = "" end end diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb index 6eb45094..7b1722e5 100644 --- a/test/openssl/test_asn1.rb +++ b/test/openssl/test_asn1.rb @@ -406,10 +406,6 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase rescue OpenSSL::ASN1::ASN1Error pend "No negative time_t support?" end - # Seconds is omitted. LibreSSL 3.6.0 requires it - return if libressl? - decode_test B(%w{ 17 0B }) + "1609082343Z".b, - OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 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")) @@ -428,10 +424,6 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase 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)) - # LibreSSL 3.6.0 requires the seconds element - return if libressl? - 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")) diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb index 8faa5706..41885fd5 100644 --- a/test/openssl/test_cipher.rb +++ b/test/openssl/test_cipher.rb @@ -331,6 +331,22 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal tag1, tag2 end + def test_aes_keywrap_pad + # RFC 5649 Section 6; The second example + kek = ["5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"].pack("H*") + key = ["466f7250617369"].pack("H*") + wrap = ["afbeb0f07dfbf5419200f2ccb50bb24f"].pack("H*") + + begin + cipher = OpenSSL::Cipher.new("id-aes192-wrap-pad").encrypt + rescue OpenSSL::Cipher::CipherError, RuntimeError + omit "id-aes192-wrap-pad is not supported: #$!" + end + cipher.key = kek + ct = cipher.update(key) << cipher.final + assert_equal wrap, ct + end + def test_non_aead_cipher_set_auth_data assert_raise(OpenSSL::Cipher::CipherError) { cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt diff --git a/test/openssl/test_pkcs7.rb b/test/openssl/test_pkcs7.rb index ba8b93d0..96f3f1f6 100644 --- a/test/openssl/test_pkcs7.rb +++ b/test/openssl/test_pkcs7.rb @@ -155,6 +155,21 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase assert_equal(data, p7.decrypt(@rsa1024)) end + def test_empty_signed_data_ruby_bug_19974 + data = "-----BEGIN PKCS7-----\nMAsGCSqGSIb3DQEHAg==\n-----END PKCS7-----\n" + assert_raise(ArgumentError) { OpenSSL::PKCS7.new(data) } + + data = <<END +MIME-Version: 1.0 +Content-Disposition: attachment; filename="smime.p7m" +Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m" +Content-Transfer-Encoding: base64 + +#{data} +END + assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.read_smime(data) } + end + def test_graceful_parsing_failure #[ruby-core:43250] contents = File.read(__FILE__) assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) } diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb index ff17c411..b98754b8 100644 --- a/test/openssl/test_x509req.rb +++ b/test/openssl/test_x509req.rb @@ -39,11 +39,6 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase assert_equal(0, req.version) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(0, req.version) - - req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) - assert_equal(1, req.version) - req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(1, req.version) end def test_subject @@ -106,7 +101,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase 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 + req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBarFooBar") assert_equal(false, req.verify(@rsa1024)) rescue OpenSSL::X509::RequestError # RHEL 9 disables SHA1 end |