Class: OPA::Verifier
- Inherits:
-
Object
- Object
- OPA::Verifier
- Defined in:
- lib/opa/verifier.rb
Overview
Reads and verifies OPA archives. Supports signature verification using JAR-format signing.
Constant Summary collapse
- SUPPORTED_DIGESTS =
Signer::SUPPORTED_DIGESTS
- REJECTED_DIGESTS =
Signer::REJECTED_DIGESTS
Instance Attribute Summary collapse
-
#entries ⇒ Object
readonly
Returns the value of attribute entries.
-
#manifest ⇒ Object
readonly
Returns the value of attribute manifest.
Instance Method Summary collapse
- #data_entries ⇒ Object
-
#initialize(io_or_path) ⇒ Verifier
constructor
A new instance of Verifier.
- #prompt ⇒ Object
-
#read_entry(path) ⇒ Object
Read a specific entry from the archive.
- #session ⇒ Object
- #signed? ⇒ Boolean
-
#verify!(certificate: nil) ⇒ Object
Verify the archive signature.
Constructor Details
#initialize(io_or_path) ⇒ Verifier
Returns a new instance of Verifier.
16 17 18 19 20 21 22 23 24 |
# File 'lib/opa/verifier.rb', line 16 def initialize(io_or_path) @raw_entries = {} data = if io_or_path.is_a?(String) File.binread(io_or_path) else io_or_path.read end read_zip(data) end |
Instance Attribute Details
#entries ⇒ Object (readonly)
Returns the value of attribute entries.
14 15 16 |
# File 'lib/opa/verifier.rb', line 14 def entries @entries end |
#manifest ⇒ Object (readonly)
Returns the value of attribute manifest.
14 15 16 |
# File 'lib/opa/verifier.rb', line 14 def manifest @manifest end |
Instance Method Details
#data_entries ⇒ Object
94 95 96 97 |
# File 'lib/opa/verifier.rb', line 94 def data_entries prefix = @manifest["Data-Root"] || "data/" @raw_entries.select { |k, _| k.start_with?(prefix) } end |
#prompt ⇒ Object
84 85 86 87 |
# File 'lib/opa/verifier.rb', line 84 def prompt prompt_path = @manifest["Prompt-File"] || "prompt.md" @raw_entries[prompt_path] end |
#read_entry(path) ⇒ Object
Read a specific entry from the archive.
80 81 82 |
# File 'lib/opa/verifier.rb', line 80 def read_entry(path) @raw_entries[path] end |
#session ⇒ Object
89 90 91 92 |
# File 'lib/opa/verifier.rb', line 89 def session session_path = @manifest["Session-File"] || "session/history.json" @raw_entries[session_path] end |
#signed? ⇒ Boolean
26 27 28 |
# File 'lib/opa/verifier.rb', line 26 def signed? @raw_entries.key?("META-INF/SIGNATURE.SF") end |
#verify!(certificate: nil) ⇒ Object
Verify the archive signature. Returns true if valid. Raises OPA::SignatureError on failure.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/opa/verifier.rb', line 32 def verify!(certificate: nil) raise SignatureError, "Archive is not signed" unless signed? sf_content = @raw_entries["META-INF/SIGNATURE.SF"] sf_attrs = parse_sf(sf_content) # Find and verify the signature block block_entry = find_signature_block raise SignatureError, "No signature block file found" unless block_entry block_data = @raw_entries[block_entry] verify_pkcs7_signature(block_data, sf_content, certificate) # Verify manifest digest manifest_content = @raw_entries["META-INF/MANIFEST.MF"] digest_name = detect_digest_algorithm(sf_attrs[:main]) verify_digest(digest_name, manifest_content, sf_attrs[:main]["#{digest_name}-Digest-Manifest"], "Manifest digest mismatch") # Verify individual entry digests sf_attrs[:entries].each do |name, attrs| entry_digest_name = detect_digest_algorithm(attrs) manifest_section = extract_manifest_section(manifest_content, name) raise SignatureError, "No manifest section for #{name}" unless manifest_section verify_digest(entry_digest_name, manifest_section, attrs["#{entry_digest_name}-Digest"], "Section digest mismatch for #{name}") end # Verify manifest entry digests against actual content @manifest.entries.each do |name, attrs| entry_digest_name = detect_digest_algorithm(attrs) next unless entry_digest_name expected = attrs["#{entry_digest_name}-Digest"] next unless expected actual_content = @raw_entries[name] raise SignatureError, "Missing entry: #{name}" unless actual_content verify_digest(entry_digest_name, actual_content, expected, "Content digest mismatch for #{name}") end true end |