Class: Capsium::Package::OpenPgpSigner

Inherits:
Object
  • Object
show all
Defined in:
lib/capsium/package/open_pgp_signer.rb,
sig/capsium/package/open_pgp_signer.rbs

Overview

Signs and verifies Capsium packages with OpenPGP detached signatures (ARCHITECTURE.md section 6a) through librnp. Parallel to the RSA-SHA256/X.509 Signer with the same construction semantics and the same error taxonomy.

Constant Summary collapse

ALGORITHM =

Returns:

  • (String)
"OpenPGP"
CERTIFICATE_TYPE =

Returns:

  • (String)
"OpenPGP"
HASH =

Returns:

  • (String)
"SHA256"
PUBLIC_KEY_FILE =

Package-relative name of the embedded armored OpenPGP public key recorded in security.json digitalSignatures.publicKey.

Returns:

  • (String)
"signature.pub.asc"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(package_path) ⇒ OpenPgpSigner

Returns a new instance of OpenPgpSigner.

Parameters:

  • package_path (String)


37
38
39
# File 'lib/capsium/package/open_pgp_signer.rb', line 37

def initialize(package_path)
  @package_path = package_path
end

Instance Attribute Details

#package_pathString (readonly)

Returns the value of attribute package_path.

Returns:

  • (String)


35
36
37
# File 'lib/capsium/package/open_pgp_signer.rb', line 35

def package_path
  @package_path
end

Class Method Details

.sign_package(path, secret_key_path) ⇒ String

Signs a package directory in place, or a .cap file (unpacked, signed, recompressed), with the OpenPGP secret key at secret_key_path. Returns the signed path.

Parameters:

  • path (String)
  • secret_key_path (String)

Returns:

  • (String)


44
45
46
47
48
49
# File 'lib/capsium/package/open_pgp_signer.rb', line 44

def self.sign_package(path, secret_key_path)
  return new(path).sign(secret_key_path) unless cap?(path)

  Packager.new.transform_cap(path) { |dir| new(dir).sign(secret_key_path) }
  path
end

.verify_package(path, public_key_path = nil) ⇒ Boolean

Verifies the declared OpenPGP signature of a package directory or .cap file (false on mismatch; raises typed Signer::SignatureError subclasses on structural problems).

Parameters:

  • path (String)
  • public_key_path (String, nil) (defaults to: nil)

Returns:

  • (Boolean)


56
57
58
59
60
# File 'lib/capsium/package/open_pgp_signer.rb', line 56

def self.verify_package(path, public_key_path = nil)
  return new(path).verify(public_key_path) unless cap?(path)

  Packager.new.with_unpacked_cap(path) { |dir| new(dir).verify(public_key_path) }
end

Instance Method Details

#sign(secret_key_path) ⇒ String

Signs the package directory in place: embeds the armored public key, regenerates security.json (checksums plus digitalSignatures with certificateType "OpenPGP") and writes the armored detached OpenPGP signature to signature.sig. Returns the path of the written signature file.

Parameters:

  • secret_key_path (String)

Returns:

  • (String)


71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/capsium/package/open_pgp_signer.rb', line 71

def sign(secret_key_path)
  loaded = OpenPgp.load_key(secret_key_path, secret: true)
  File.write(public_key_path, loaded.key.export_public(armored: true))
  security = Security.generate(@package_path, digital_signatures: digital_signatures)
  security.save_to_file
  signature = loaded.rnp.detached_sign(
    input: Rnp::Input.from_string(payload(security)),
    signers: loaded.key, hash: HASH, armored: true
  )
  File.write(signature_path, signature)
  signature_path
end

#signed?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/capsium/package/open_pgp_signer.rb', line 100

def signed?
  declared_security.signed?
end

#verify(public_key_path = nil) ⇒ Boolean

True when the declared signature verifies against the payload; false on mismatch.

Parameters:

  • public_key_path (String, nil) (defaults to: nil)

Returns:

  • (Boolean)


86
87
88
89
90
91
# File 'lib/capsium/package/open_pgp_signer.rb', line 86

def verify(public_key_path = nil)
  signature = read_signature
  data = payload(declared_security)
  loaded = verification_key(public_key_path)
  signature_matches(loaded, data, signature)
end

#verify!(public_key_path = nil) ⇒ Boolean

Parameters:

  • public_key_path (String, nil) (defaults to: nil)

Returns:

  • (Boolean)

Raises:



93
94
95
96
97
98
# File 'lib/capsium/package/open_pgp_signer.rb', line 93

def verify!(public_key_path = nil)
  return true if verify(public_key_path)

  raise Signer::SignatureMismatchError,
        "digital signature does not match the package contents"
end