Ruby PKCS7 在数据包含换行符时无法验证。

huangapple go评论108阅读模式
英文:

Ruby PKCS7 fails to verify when data contains line breaks

问题

I find that when I call OpenSSL::PKCS7#verify, if the data to be verified contains line breaks, then verify returns false:

  1. require 'openssl'
  2. def test(data)
  3. store = OpenSSL::X509::Store.new
  4. signed = OpenSSL::PKCS7.sign(@cert, @key, data).to_der
  5. pkcs7 = OpenSSL::PKCS7.new(signed)
  6. valid = pkcs7.verify(pkcs7.certificates, store, data, OpenSSL::PKCS7::NOVERIFY)
  7. end
  8. @key = OpenSSL::PKey::RSA.new 2048
  9. @cert = OpenSSL::X509::Certificate.new
  10. @cert.serial = 0
  11. @cert.public_key = @key.public_key
  12. @cert not_before = Time.now
  13. @cert.not_after = Time now + 2**12
  14. @cert.sign @key, OpenSSL::Digest.new('SHA256')
  15. test("foo") # => true
  16. test("foo\n") # => false

(I even have the NOVERIFY flag in the function call!)

Why does the presence of a line break change the behavior? It has this effect regardless of where I put the line break in the data string. How can I verify a signature if the input string contains a line break?

This is Ruby 2.6.8p205.

英文:

I find that when I call OpenSSL::PKCS7#verify, if the data to be verified contains line breaks, then verify returns false:

  1. require 'openssl'
  2. def test(data)
  3. store = OpenSSL::X509::Store.new
  4. signed = OpenSSL::PKCS7.sign(@cert, @key, data).to_der
  5. pkcs7 = OpenSSL::PKCS7.new(signed)
  6. valid = pkcs7.verify(pkcs7.certificates, store, data, OpenSSL::PKCS7::NOVERIFY)
  7. end
  8. @key = OpenSSL::PKey::RSA.new 2048
  9. @cert = OpenSSL::X509::Certificate.new
  10. @cert.serial = 0
  11. @cert.public_key = @key.public_key
  12. @cert.not_before = Time.now
  13. @cert.not_after = Time.now + 2**12
  14. @cert.sign @key, OpenSSL::Digest.new('SHA256')
  15. test("foo") # => true
  16. test("foo\n") # => false

(I even have the NOVERIFY flag in the function call!)

Why does the presence of a line break change the behaviour? It has this effect regardless of where I put the line break in the data string. How can I verify a signature if the input string contains a line break?

This is Ruby 2.6.8p205.

答案1

得分: 1

以下是翻译好的部分:

"在经过一番仔细思考后,这似乎是预期行为。它在签名之前将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
[2] https://github.com/openssl/openssl/issues/9336
[3] https://opensource.apple.com/source/ruby/ruby-75/ruby/test/openssl/test_pkcs7.rb"

英文:

After a lot of head scratching this seems to be expected behavior.
It's converting LF to CRLF before signing:

  1. test("foo") # => true
  2. test("foo\n") # => false
  3. test("foo\r\n") # => true

To fix you need to use the BINARY flag:

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

Now:

  1. test("foo") # => true
  2. test("foo\n") # => true
  3. test("foo\r\n") # => true

Sources for this info:

> Normally the supplied content is translated into MIME canonical format (as required by the S/MIME specifications). If PKCS7_BINARY is set no translation occurs. This option should be used if the supplied data is in binary format otherwise the translation will corrupt it.

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

huangapple
  • 本文由 发表于 2023年4月10日 23:09:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/75978271.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定