Ruby PKCS7无法验证数据是否包含换行符

gdrx4gfi  于 2023-04-11  发布在  Ruby
关注(0)|答案(1)|浏览(111)

我发现当我调用OpenSSL::PKCS7#verify时,如果要验证的数据包含换行符,那么verify返回false:

require 'openssl'

def test(data)
  store = OpenSSL::X509::Store.new
  signed = OpenSSL::PKCS7.sign(@cert, @key, data).to_der
  pkcs7 = OpenSSL::PKCS7.new(signed)
  valid = pkcs7.verify(pkcs7.certificates, store, data, OpenSSL::PKCS7::NOVERIFY)
end

@key = OpenSSL::PKey::RSA.new 2048
@cert = OpenSSL::X509::Certificate.new
@cert.serial = 0
@cert.public_key = @key.public_key
@cert.not_before = Time.now
@cert.not_after = Time.now + 2**12
@cert.sign @key, OpenSSL::Digest.new('SHA256')

test("foo")   # => true
test("foo\n") # => false

(我甚至在函数调用中有NOVERIFY标志!)
为什么换行符的存在会改变行为?无论我把换行符放在数据字符串的什么地方,它都有这种效果。如果输入字符串包含换行符,我如何验证签名?

  • 这是Ruby 2.6.8p205。*
6ojccjat

6ojccjat1#

经过大量的挠头,这似乎是预期的行为。
在签名之前将LF转换为CRLF:

test("foo")     # => true
test("foo\n")   # => false
test("foo\r\n") # => true

要解决这个问题,你需要使用BINARY标志:

signed = OpenSSL::PKCS7.sign(@cert, @key, data, nil, OpenSSL::PKCS7::BINARY).to_der

现在:

test("foo")     # => true
test("foo\n")   # => true
test("foo\r\n") # => true

此信息的来源:

通常情况下,提供的内容会被转换为MIME规范格式(S/MIME规范要求)。如果设置了PKCS7_BINARY,则不会发生转换。如果提供的数据是二进制格式,则应使用此选项,否则转换会损坏数据。

[1][https://www.openssl.org/docs/man3.1/man3/PKCS7_sign.html](https://www.openssl.org/docs/man3.1/man3/PKCS7_sign.html)
[2][https://github.com/openssl/openssl/issues/9336](https://github.com/openssl/openssl/issues/9336)
[3][https://opensource.apple.com/source/ruby/ruby-75/ruby/test/openssl/test_pkcs7.rb](https://opensource.apple.com/source/ruby/ruby-75/ruby/test/openssl/test_pkcs7.rb)

相关问题