Skip to content

Commit

Permalink
Merge pull request #5 from tomascco:test-pkcs7-signature
Browse files Browse the repository at this point in the history
Test PKCS7 Signature
  • Loading branch information
tomascco authored Oct 22, 2023
2 parents 402ff60 + c18eda8 commit e7da383
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 16 deletions.
1 change: 1 addition & 0 deletions lib/rubrik.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ class Error < StandardError; end
require_relative "rubrik/document/increment"
require_relative "rubrik/document/serialize_object"
require_relative "rubrik/fill_signature"
require_relative "rubrik/pkcs7_signature"
require_relative "rubrik/sign"
5 changes: 1 addition & 4 deletions lib/rubrik/fill_signature.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# typed: true
# frozen_string_literal: true

require "openssl"

module Rubrik
module FillSignature
extend T::Sig
Expand Down Expand Up @@ -55,8 +53,7 @@ def call(io, signature_value_ref:, private_key:, public_key:, certificate_chain:
io.pos = second_offset
data_to_sign += T.must(io.read(second_length))

signature = OpenSSL::PKCS7.sign(public_key, private_key, data_to_sign, certificate_chain,
OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY).to_der
signature = PKCS7Signature.call(data_to_sign, private_key:, certificate: public_key)
hex_signature = T.let(signature, String).unpack1("H*")

padded_contents_field = "<#{hex_signature.ljust(Document::SIGNATURE_SIZE, "0")}>"
Expand Down
24 changes: 24 additions & 0 deletions lib/rubrik/pkcs7_signature.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# typed: true
# frozen_string_literal: true

require "openssl"

module Rubrik
module PKCS7Signature
extend T::Sig
extend self

OPEN_SSL_FLAGS = OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY

sig {params(
data: String,
private_key: OpenSSL::PKey::RSA,
certificate: OpenSSL::X509::Certificate,
certificate_chain: T::Array[OpenSSL::X509::Certificate]
).returns(String)
}
def call(data, private_key:, certificate:, certificate_chain: [])
OpenSSL::PKCS7.sign(certificate, private_key, data, certificate_chain, OPEN_SSL_FLAGS).to_der
end
end
end
29 changes: 29 additions & 0 deletions test/pkcs7_signature_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true
# typed: true

require "test_helper"

class Rubrik::PKCS7SignatureTest < Rubrik::Test
def test_signature_generation
# Arrange
certificate_file = File.open("test/support/demo_cert.pem", "rb")

private_key = OpenSSL::PKey::RSA.new(certificate_file, "")
certificate_file.rewind
certificate = OpenSSL::X509::Certificate.new(certificate_file)

# Act
raw_result = Rubrik::PKCS7Signature.call("test", private_key:, certificate:)

# Assert
result = OpenSSL::ASN1.decode(raw_result)

assert_kind_of(OpenSSL::ASN1::Sequence, result)

content_type = result.value.first
assert_equal("pkcs7-signedData", content_type.value)

ensure
certificate_file&.close
end
end
24 changes: 12 additions & 12 deletions test/rubrik/sign_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ def test_document_with_interactive_form

expected_output.readlines.zip(output_pdf.readlines).each do |(expected_line, actual_line)|
# We must erase the signature because it is timestampped
if T.must(actual_line).match?("/Type /Sig")
T.must(actual_line).sub!(/<[a-f0-9]+>/, "")
T.must(expected_line).sub!(/<[a-f0-9]+>/, "")
if actual_line&.match?("/Type /Sig")
actual_line.sub!(/<[a-f0-9]+>/, "")
expected_line.sub!(/<[a-f0-9]+>/, "")
# The signature field name is also random
elsif T.must(actual_line).match?("Signature-[a-f0-9]{4}")
T.must(actual_line).sub!(/Signature-[a-f0-9]{4}/, "")
T.must(expected_line).sub!(/Signature-[a-f0-9]{4}/, "")
elsif actual_line&.match?(/Signature-[a-f0-9]{4}/)
actual_line.sub!(/Signature-[a-f0-9]{4}/, "")
expected_line.sub!(/Signature-[a-f0-9]{4}/, "")
end

assert_equal(expected_line, actual_line)
Expand Down Expand Up @@ -59,13 +59,13 @@ def test_document_without_interactive_form

expected_output.readlines.zip(output_pdf.readlines).each do |(expected_line, actual_line)|
# We can't verify the signature because it changes on every run
if T.must(actual_line).match?("/Type /Sig")
T.must(actual_line).sub!(/<[a-f0-9]+>/, "")
T.must(expected_line).sub!(/<[a-f0-9]+>/, "")
if actual_line&.match?("/Type /Sig")
actual_line.sub!(/<[a-f0-9]+>/, "")
expected_line.sub!(/<[a-f0-9]+>/, "")
# The signature field name is also random
elsif T.must(actual_line).match?("Signature-[a-f0-9]{4}")
T.must(actual_line).sub!(/Signature-[a-f0-9]{4}/, "")
T.must(expected_line).sub!(/Signature-[a-f0-9]{4}/, "")
elsif actual_line&.match?(/Signature-[a-f0-9]{4}/)
actual_line.sub!(/Signature-[a-f0-9]{4}/, "")
expected_line.sub!(/Signature-[a-f0-9]{4}/, "")
end

assert_equal(expected_line, actual_line)
Expand Down

0 comments on commit e7da383

Please sign in to comment.