Class: SSHData::Signature
- Inherits:
-
Object
- Object
- SSHData::Signature
- Defined in:
- lib/ssh_data/signature.rb
Constant Summary collapse
- PEM_TYPE =
"SSH SIGNATURE"
- SIGNATURE_PREAMBLE =
"SSHSIG"
- MIN_SUPPORTED_VERSION =
1
- MAX_SUPPORTED_VERSION =
1
- SUPPORTED_HASH_ALGORITHMS =
Spec: no SHA1 or SHA384. In practice, OpenSSH is always going to use SHA512. Note the actual signing / verify primitive may use a different hash algorithm. github.com/openssh/openssh-portable/blob/b7ffbb17e37f59249c31f1ff59d6c5d80888f689/PROTOCOL.sshsig#L67
{ "sha256" => OpenSSL::Digest::SHA256, "sha512" => OpenSSL::Digest::SHA512, }
- PERMITTED_RSA_SIGNATURE_ALGORITHMS =
[ PublicKey::ALGO_RSA_SHA2_256, PublicKey::ALGO_RSA_SHA2_512, ]
Instance Attribute Summary collapse
-
#hash_algorithm ⇒ Object
readonly
Returns the value of attribute hash_algorithm.
-
#namespace ⇒ Object
readonly
Returns the value of attribute namespace.
-
#reserved ⇒ Object
readonly
Returns the value of attribute reserved.
-
#signature ⇒ Object
readonly
Returns the value of attribute signature.
-
#sigversion ⇒ Object
readonly
Returns the value of attribute sigversion.
Class Method Summary collapse
- .parse_blob(blob) ⇒ Object
-
.parse_pem(pem) ⇒ Object
Parses a PEM armored SSH signature.
Instance Method Summary collapse
-
#initialize(sigversion:, publickey:, namespace:, reserved:, hash_algorithm:, signature:) ⇒ Signature
constructor
A new instance of Signature.
-
#public_key ⇒ Object
Gets the public key from the signature.
- #verify(signed_data, **opts) ⇒ Object
Constructor Details
#initialize(sigversion:, publickey:, namespace:, reserved:, hash_algorithm:, signature:) ⇒ Signature
Returns a new instance of Signature.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/ssh_data/signature.rb', line 50 def initialize(sigversion:, publickey:, namespace:, reserved:, hash_algorithm:, signature:) if sigversion > MAX_SUPPORTED_VERSION || sigversion < MIN_SUPPORTED_VERSION raise UnsupportedError, "Signature version is not supported" end unless SUPPORTED_HASH_ALGORITHMS.has_key?(hash_algorithm) raise UnsupportedError, "Hash algorithm #{hash_algorithm} is not supported." end # Spec: empty namespaces are not permitted. # https://github.com/openssh/openssh-portable/blob/b7ffbb17e37f59249c31f1ff59d6c5d80888f689/PROTOCOL.sshsig#L57 raise UnsupportedError, "A namespace is required." if namespace.empty? # Spec: ignore 'reserved', don't need to validate that it is empty. @sigversion = sigversion @publickey = publickey @namespace = namespace @reserved = reserved @hash_algorithm = hash_algorithm @signature = signature end |
Instance Attribute Details
#hash_algorithm ⇒ Object (readonly)
Returns the value of attribute hash_algorithm.
23 24 25 |
# File 'lib/ssh_data/signature.rb', line 23 def hash_algorithm @hash_algorithm end |
#namespace ⇒ Object (readonly)
Returns the value of attribute namespace.
23 24 25 |
# File 'lib/ssh_data/signature.rb', line 23 def namespace @namespace end |
#reserved ⇒ Object (readonly)
Returns the value of attribute reserved.
23 24 25 |
# File 'lib/ssh_data/signature.rb', line 23 def reserved @reserved end |
#signature ⇒ Object (readonly)
Returns the value of attribute signature.
23 24 25 |
# File 'lib/ssh_data/signature.rb', line 23 def signature @signature end |
#sigversion ⇒ Object (readonly)
Returns the value of attribute sigversion.
23 24 25 |
# File 'lib/ssh_data/signature.rb', line 23 def sigversion @sigversion end |
Class Method Details
.parse_blob(blob) ⇒ Object
40 41 42 43 44 45 46 47 48 |
# File 'lib/ssh_data/signature.rb', line 40 def self.parse_blob(blob) data, read = Encoding.decode_openssh_signature(blob) if read != blob.bytesize raise DecodeError, "unexpected trailing data" end new(**data) end |
.parse_pem(pem) ⇒ Object
Parses a PEM armored SSH signature. pem - A PEM encoded SSH signature.
Returns a Signature instance.
29 30 31 32 33 34 35 36 37 38 |
# File 'lib/ssh_data/signature.rb', line 29 def self.parse_pem(pem) pem_type = Encoding.pem_type(pem) if pem_type != PEM_TYPE raise DecodeError, "Mismatched PEM type. Expecting '#{PEM_TYPE}', actually '#{pem_type}'." end blob = Encoding.decode_pem(pem, pem_type) self.parse_blob(blob) end |
Instance Method Details
#public_key ⇒ Object
Gets the public key from the signature. If the signature was created from a certificate, this will be an SSHData::Certificate. Otherwise, this will be a PublicKey algorithm.
110 111 112 |
# File 'lib/ssh_data/signature.rb', line 110 def public_key @data_public_key ||= load_public_key end |
#verify(signed_data, **opts) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/ssh_data/signature.rb', line 73 def verify(signed_data, **opts) signing_key = public_key # Unwrap the signing key if this signature was created from a certificate. key = signing_key.is_a?(Certificate) ? signing_key.public_key : signing_key digest_algorithm = SUPPORTED_HASH_ALGORITHMS[@hash_algorithm] if key.is_a?(PublicKey::RSA) sig_algo, * = Encoding.decode_signature(@signature) # Spec: If the signature is an RSA signature, the legacy 'ssh-rsa' # identifer is not permitted. # https://github.com/openssh/openssh-portable/blob/b7ffbb17e37f59249c31f1ff59d6c5d80888f689/PROTOCOL.sshsig#L72 unless PERMITTED_RSA_SIGNATURE_ALGORITHMS.include?(sig_algo) raise UnsupportedError, "RSA signature #{sig_algo} is not supported." end end = digest_algorithm.digest(signed_data) blob = SIGNATURE_PREAMBLE + Encoding.encode_string(@namespace) + Encoding.encode_string(@reserved || "") + Encoding.encode_string(@hash_algorithm) + Encoding.encode_string() if key.class.include?(::SSHData::PublicKey::SecurityKey) key.verify(blob, @signature, **opts) else key.verify(blob, @signature) end end |