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

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

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:

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

(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:

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

(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:

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

To fix you need to use the BINARY flag:

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

Now:

test("foo")     # => true
test("foo\n")   # => true
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:

确定