英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论