Class: OPA::Signer
- Inherits:
-
Object
- Object
- OPA::Signer
- Defined in:
- lib/opa/signer.rb
Overview
Signs OPA archives using JAR-format digital signatures. Produces META-INF/SIGNATURE.SF and a signature block file (.RSA, .DSA, or .EC).
Constant Summary collapse
- SUPPORTED_DIGESTS =
{ "SHA-256" => OpenSSL::Digest::SHA256, "SHA-384" => OpenSSL::Digest::SHA384, "SHA-512" => OpenSSL::Digest::SHA512 }.freeze
- REJECTED_DIGESTS =
%w[MD5 SHA-1].freeze
Instance Attribute Summary collapse
-
#digest_name ⇒ Object
readonly
Returns the value of attribute digest_name.
Instance Method Summary collapse
-
#block_extension ⇒ Object
File extension for the signature block based on key type.
-
#digest(data) ⇒ Object
Compute the Base64-encoded digest of data.
-
#initialize(private_key, certificate, algorithm: "SHA-256") ⇒ Signer
constructor
A new instance of Signer.
-
#signature_block(sf_content) ⇒ Object
Create the PKCS#7 signature block over the SF content.
-
#signature_file(manifest_content) ⇒ Object
Generate the SIGNATURE.SF content from manifest content.
Constructor Details
#initialize(private_key, certificate, algorithm: "SHA-256") ⇒ Signer
Returns a new instance of Signer.
21 22 23 24 25 26 27 28 29 |
# File 'lib/opa/signer.rb', line 21 def initialize(private_key, certificate, algorithm: "SHA-256") raise ArgumentError, "Digest #{algorithm} is not allowed" if REJECTED_DIGESTS.include?(algorithm) raise ArgumentError, "Unsupported digest: #{algorithm}" unless SUPPORTED_DIGESTS.key?(algorithm) @private_key = private_key @certificate = certificate @digest_name = algorithm @digest_class = SUPPORTED_DIGESTS[algorithm] end |
Instance Attribute Details
#digest_name ⇒ Object (readonly)
Returns the value of attribute digest_name.
19 20 21 |
# File 'lib/opa/signer.rb', line 19 def digest_name @digest_name end |
Instance Method Details
#block_extension ⇒ Object
File extension for the signature block based on key type.
63 64 65 66 67 68 69 70 |
# File 'lib/opa/signer.rb', line 63 def block_extension case @private_key when OpenSSL::PKey::RSA then ".RSA" when OpenSSL::PKey::DSA then ".DSA" when OpenSSL::PKey::EC then ".EC" else ".RSA" end end |
#digest(data) ⇒ Object
Compute the Base64-encoded digest of data.
32 33 34 |
# File 'lib/opa/signer.rb', line 32 def digest(data) Base64.strict_encode64(@digest_class.digest(data)) end |
#signature_block(sf_content) ⇒ Object
Create the PKCS#7 signature block over the SF content.
56 57 58 59 60 |
# File 'lib/opa/signer.rb', line 56 def signature_block(sf_content) flags = OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::NOSMIMECAP pkcs7 = OpenSSL::PKCS7.sign(@certificate, @private_key, sf_content, [], flags) pkcs7.to_der end |
#signature_file(manifest_content) ⇒ Object
Generate the SIGNATURE.SF content from manifest content. Contains a digest of the entire manifest and per-entry section digests.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/opa/signer.rb', line 38 def signature_file(manifest_content) lines = [] lines << "Signature-Version: 1.0" lines << "#{@digest_name}-Digest-Manifest: #{digest(manifest_content)}" lines << "" # Compute per-entry section digests sections = extract_entry_sections(manifest_content) sections.each do |name, section_text| lines << "Name: #{name}" lines << "#{@digest_name}-Digest: #{digest(section_text)}" lines << "" end lines.join("\n") end |