Class: Capsium::Package::Signer
- Inherits:
-
Object
- Object
- Capsium::Package::Signer
- Defined in:
- lib/capsium/package/signer.rb,
sig/capsium/package/signer.rbs
Overview
Signs and verifies Capsium packages with RSA-SHA256 digital signatures (05x-packaging "Digital Signature Using X.509", 05x-security "Digital Signatures"). The signed payload is the concatenation, in sorted package-relative path order, of the raw bytes of every file covered by the security.json integrity checksums (everything except security.json and signature.sig).
Defined Under Namespace
Classes: SignatureError, SignatureMismatchError, UnsignedPackageError
Constant Summary collapse
- ALGORITHM =
"RSA-SHA256"- MIN_KEY_BITS =
2048- PUBLIC_KEY_FILE =
Package-relative name of the embedded public key PEM recorded in security.json digitalSignatures.publicKey.
"signature.pub.pem"
Instance Attribute Summary collapse
-
#package_path ⇒ String
readonly
Returns the value of attribute package_path.
Class Method Summary collapse
-
.sign_package(path, private_key_path, certificate_path = nil) ⇒ String
Signs a package directory in place, or a .cap file (unpacked, signed, recompressed).
-
.signer_class_for(package_path) ⇒ singleton(Signer), singleton(OpenPgpSigner)
The signer class matching a package's declared signature scheme: OpenPgpSigner when security.json declares digitalSignatures.certificateType "OpenPGP", Signer otherwise.
-
.verify_package(path, public_key_path = nil) ⇒ Boolean
Verifies the declared signature of a package directory or .cap file (false on mismatch; raises typed SignatureError subclasses on structural problems, e.g. an unsigned package).
Instance Method Summary collapse
-
#initialize(package_path) ⇒ Signer
constructor
A new instance of Signer.
-
#sign(private_key_path, certificate_path = nil) ⇒ String
Signs the package directory in place: embeds the public key PEM, regenerates security.json (checksums plus digitalSignatures) and writes the raw RSA-SHA256 signature to signature.sig.
- #signed? ⇒ Boolean
-
#verify(public_key_path = nil) ⇒ Boolean
True when the declared signature verifies against the payload; false on mismatch.
- #verify!(public_key_path = nil) ⇒ Boolean
Constructor Details
#initialize(package_path) ⇒ Signer
Returns a new instance of Signer.
42 43 44 |
# File 'lib/capsium/package/signer.rb', line 42 def initialize(package_path) @package_path = package_path end |
Instance Attribute Details
#package_path ⇒ String (readonly)
Returns the value of attribute package_path.
40 41 42 |
# File 'lib/capsium/package/signer.rb', line 40 def package_path @package_path end |
Class Method Details
.sign_package(path, private_key_path, certificate_path = nil) ⇒ String
Signs a package directory in place, or a .cap file (unpacked, signed, recompressed). Returns the signed path.
48 49 50 51 52 53 |
# File 'lib/capsium/package/signer.rb', line 48 def self.sign_package(path, private_key_path, certificate_path = nil) return new(path).sign(private_key_path, certificate_path) unless cap?(path) Packager.new.transform_cap(path) { |dir| new(dir).sign(private_key_path, certificate_path) } path end |
.signer_class_for(package_path) ⇒ singleton(Signer), singleton(OpenPgpSigner)
The signer class matching a package's declared signature scheme: OpenPgpSigner when security.json declares digitalSignatures.certificateType "OpenPGP", Signer otherwise.
71 72 73 74 75 76 77 |
# File 'lib/capsium/package/signer.rb', line 71 def self.signer_class_for(package_path) security = Security.new(File.join(package_path, Package::SECURITY_FILE)) return OpenPgpSigner if security.digital_signatures&.certificate_type == OpenPgpSigner::CERTIFICATE_TYPE self end |
.verify_package(path, public_key_path = nil) ⇒ Boolean
Verifies the declared signature of a package directory or .cap file (false on mismatch; raises typed SignatureError subclasses on structural problems, e.g. an unsigned package). The signer is selected from the declared digitalSignatures certificateType: OpenPGP packages verify through OpenPgpSigner.
60 61 62 63 64 65 66 |
# File 'lib/capsium/package/signer.rb', line 60 def self.verify_package(path, public_key_path = nil) return signer_class_for(path).new(path).verify(public_key_path) unless cap?(path) Packager.new.with_unpacked_cap(path) do |dir| signer_class_for(dir).new(dir).verify(public_key_path) end end |
Instance Method Details
#sign(private_key_path, certificate_path = nil) ⇒ String
Signs the package directory in place: embeds the public key PEM, regenerates security.json (checksums plus digitalSignatures) and writes the raw RSA-SHA256 signature to signature.sig. Returns the path of the written signature file.
89 90 91 92 93 94 95 96 |
# File 'lib/capsium/package/signer.rb', line 89 def sign(private_key_path, certificate_path = nil) private_key = load_private_key(private_key_path) File.write(public_key_path, public_pem_for(private_key, certificate_path)) security = Security.generate(@package_path, digital_signatures: digital_signatures) security.save_to_file File.binwrite(signature_path, private_key.sign("SHA256", payload(security))) signature_path end |
#signed? ⇒ Boolean
116 117 118 |
# File 'lib/capsium/package/signer.rb', line 116 def signed? declared_security.signed? end |
#verify(public_key_path = nil) ⇒ Boolean
True when the declared signature verifies against the payload; false on mismatch. Raises typed SignatureError subclasses on structural problems.
101 102 103 104 105 106 107 |
# File 'lib/capsium/package/signer.rb', line 101 def verify(public_key_path = nil) signature = read_signature data = payload(declared_security) public_key(public_key_path).verify("SHA256", signature, data) rescue OpenSSL::PKey::PKeyError false end |
#verify!(public_key_path = nil) ⇒ Boolean
109 110 111 112 113 114 |
# File 'lib/capsium/package/signer.rb', line 109 def verify!(public_key_path = nil) return true if verify(public_key_path) raise SignatureMismatchError, "digital signature does not match the package contents" end |