Class: Capsium::Package::Signer

Inherits:
Object
  • Object
show all
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 =

Returns:

  • (String)
"RSA-SHA256"
MIN_KEY_BITS =

Returns:

  • (Integer)
2048
PUBLIC_KEY_FILE =

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

Returns:

  • (String)
"signature.pub.pem"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(package_path) ⇒ Signer

Returns a new instance of Signer.

Parameters:

  • package_path (String)


42
43
44
# File 'lib/capsium/package/signer.rb', line 42

def initialize(package_path)
  @package_path = package_path
end

Instance Attribute Details

#package_pathString (readonly)

Returns the value of attribute package_path.

Returns:

  • (String)


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.

Parameters:

  • path (String)
  • private_key_path (String)
  • certificate_path (String, nil) (defaults to: nil)

Returns:

  • (String)


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

.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).

Parameters:

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

Returns:

  • (Boolean)


58
59
60
61
62
# File 'lib/capsium/package/signer.rb', line 58

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(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.

Parameters:

  • private_key_path (String)
  • certificate_path (String, nil) (defaults to: nil)

Returns:

  • (String)


74
75
76
77
78
79
80
81
# File 'lib/capsium/package/signer.rb', line 74

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

Returns:

  • (Boolean)


101
102
103
# File 'lib/capsium/package/signer.rb', line 101

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.

Parameters:

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

Returns:

  • (Boolean)


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

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

Parameters:

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

Returns:

  • (Boolean)

Raises:



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

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

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