diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2024-05-02 16:20:05 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2024-05-02 16:20:05 +0900 |
commit | 386a73512f9b82238b90fd89d39782e4e1d45490 (patch) | |
tree | d51bb3d93876453bf533f22ec099deaf12575d7b | |
parent | abacf2f7e70b6b7b82dbe982e6727b943a7f873b (diff) | |
parent | a8ef53494026057038e763af4f33aa9442249498 (diff) | |
download | ruby-openssl-386a73512f9b82238b90fd89d39782e4e1d45490.tar.gz |
Merge branch 'maint-3.2'
* maint-3.2:
Fix modular square root test with LibreSSL >= 3.8
pkcs7: raise PKCS7Error for PKCS7 without content in PKCS7.read_smime
pkcs7: raise ArgumentError for PKCS7 with no content in PKCS7.new
cipher: fix buffer overflow in Cipher#update
ssl: allow failure on test_connect_certificate_verify_failed_exception_message
.github/workflows/test.yml: synchronize with master
Only CSR version 1 (encoded as 0) is allowed by PKIX standards
test_asn1.rb: Remove the assertions of the time string format without second.
test/openssl/test_asn1.rb: skip failing tests on LibreSSL 3.6.0
Use EVP_Digest{Sign,Verify} when available
Fix performance regression in do_write(s)
-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_cipher.rb | 16 | ||||
-rw-r--r-- | test/openssl/test_pkcs7.rb | 15 |
5 files changed, 64 insertions, 10 deletions
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index 1910a5cd..6f74c925 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 68aa7bc9..216c51e3 100644 --- a/lib/openssl/buffering.rb +++ b/lib/openssl/buffering.rb @@ -349,13 +349,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_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) } |