From 551d00cb2f1708ec39f83c3b75abfbf4ffffbd8b Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 11 Feb 2019 11:54:11 -0700 Subject: [PATCH 1/6] rename `parse_raw` methods `parse_rfc4253` --- lib/ssh_data/certificate.rb | 8 ++++---- lib/ssh_data/public_key.rb | 8 ++++---- spec/encoding_spec.rb | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/ssh_data/certificate.rb b/lib/ssh_data/certificate.rb index e07a594..6aa9fc7 100644 --- a/lib/ssh_data/certificate.rb +++ b/lib/ssh_data/certificate.rb @@ -26,7 +26,7 @@ class Certificate # Returns a Certificate instance. def self.parse(cert, unsafe_no_verify: false) algo, raw, _ = SSHData.key_parts(cert) - parsed = parse_raw(raw, unsafe_no_verify: unsafe_no_verify) + parsed = parse_rfc4253(raw, unsafe_no_verify: unsafe_no_verify) if parsed.algo != algo raise DecodeError, "algo mismatch: #{parsed.algo.inspect}!=#{algo.inspect}" @@ -35,14 +35,14 @@ def self.parse(cert, unsafe_no_verify: false) parsed end - # Parse an SSH certificate. + # Parse an RFC 4253 binary SSH certificate. # - # cert - A raw binary certificate String. + # cert - A RFC 4253 binary certificate String. # unsafe_no_verify: - Bool of whether to skip verifying certificate # signature (Default false) # # Returns a Certificate instance. - def self.parse_raw(raw, unsafe_no_verify: false) + def self.parse_rfc4253(raw, unsafe_no_verify: false) data, read = Encoding.decode_certificate(raw) if read != raw.bytesize diff --git a/lib/ssh_data/public_key.rb b/lib/ssh_data/public_key.rb index fb509e8..ae17dbb 100644 --- a/lib/ssh_data/public_key.rb +++ b/lib/ssh_data/public_key.rb @@ -16,7 +16,7 @@ module PublicKey # Returns a PublicKey::Base subclass instance. def self.parse(key) algo, raw, _ = SSHData.key_parts(key) - parsed = parse_raw(raw) + parsed = parse_rfc4253(raw) if parsed.algo != algo raise DecodeError, "algo mismatch: #{parsed.algo.inspect}!=#{algo.inspect}" @@ -25,12 +25,12 @@ def self.parse(key) parsed end - # Parse an SSH public key. + # Parse an RFC 4253 binary SSH public key. # - # key - A raw binary public key String. + # key - A RFC 4253 binary public key String. # # Returns a PublicKey::Base subclass instance. - def self.parse_raw(raw) + def self.parse_rfc4253(raw) data, read = Encoding.decode_public_key(raw) if read != raw.bytesize diff --git a/spec/encoding_spec.rb b/spec/encoding_spec.rb index 2933a9b..d24cbf4 100644 --- a/spec/encoding_spec.rb +++ b/spec/encoding_spec.rb @@ -110,7 +110,7 @@ expect(rsa_data[:public_keys]).to be_a(Array) expect(rsa_data[:public_keys].length).to eq(1) expect { - SSHData::PublicKey.parse_raw(rsa_data[:public_keys].first) + SSHData::PublicKey.parse_rfc4253(rsa_data[:public_keys].first) }.not_to raise_error expect(rsa_data[:checkint1]).to be_a(Integer) @@ -133,7 +133,7 @@ expect(dsa_data[:public_keys]).to be_a(Array) expect(dsa_data[:public_keys].length).to eq(1) expect { - SSHData::PublicKey.parse_raw(dsa_data[:public_keys].first) + SSHData::PublicKey.parse_rfc4253(dsa_data[:public_keys].first) }.not_to raise_error expect(dsa_data[:checkint1]).to be_a(Integer) @@ -156,7 +156,7 @@ expect(ecdsa_data[:public_keys]).to be_a(Array) expect(ecdsa_data[:public_keys].length).to eq(1) expect { - SSHData::PublicKey.parse_raw(ecdsa_data[:public_keys].first) + SSHData::PublicKey.parse_rfc4253(ecdsa_data[:public_keys].first) }.not_to raise_error expect(ecdsa_data[:checkint1]).to be_a(Integer) @@ -179,7 +179,7 @@ expect(ed25519_data[:public_keys]).to be_a(Array) expect(ed25519_data[:public_keys].length).to eq(1) expect { - SSHData::PublicKey.parse_raw(ed25519_data[:public_keys].first) + SSHData::PublicKey.parse_rfc4253(ed25519_data[:public_keys].first) }.not_to raise_error expect(ed25519_data[:checkint1]).to be_a(Integer) From 27ba7d8e0982ce2fd989bf8b225362df56b5425b Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 11 Feb 2019 11:56:05 -0700 Subject: [PATCH 2/6] fix some comments and variable names --- lib/ssh_data.rb | 13 +++++++------ lib/ssh_data/certificate.rb | 7 ++++--- lib/ssh_data/private_key.rb | 7 ++++++- lib/ssh_data/public_key.rb | 7 ++++--- spec/certificate_spec.rb | 10 +++++----- spec/fixtures/gen.sh | 4 ++-- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/ssh_data.rb b/lib/ssh_data.rb index ad69858..0097a63 100644 --- a/lib/ssh_data.rb +++ b/lib/ssh_data.rb @@ -2,15 +2,16 @@ require "base64" module SSHData - # Break down a public key or certificate into its algorith, raw key, and host. + # Break down a key in OpenSSH authorized_keys format (see sshd(8) manual + # page). # - # key - An SSH formatted public key or certificate, including algo, encoded - # key and optional user/host names. + # key - An OpenSSH formatted public key or certificate, including algo, + # base64 encoded key and optional comment. # # Returns an Array containing the algorithm String , the raw key or - # certificate String and the host String or nil. + # certificate String and the comment String or nil. def key_parts(key) - algo, b64, host = key.strip.split(" ", 3) + algo, b64, comment = key.strip.split(" ", 3) if algo.nil? || b64.nil? raise DecodeError, "bad data format" end @@ -21,7 +22,7 @@ def key_parts(key) raise DecodeError, "bad data format" end - [algo, raw, host] + [algo, raw, comment] end extend self diff --git a/lib/ssh_data/certificate.rb b/lib/ssh_data/certificate.rb index 6aa9fc7..f3c5dbb 100644 --- a/lib/ssh_data/certificate.rb +++ b/lib/ssh_data/certificate.rb @@ -16,10 +16,11 @@ class Certificate :valid_principals, :valid_after, :valid_before, :critical_options, :extensions, :reserved, :ca_key, :signature - # Parse an SSH certificate. + # Parse an OpenSSH certificate in authorized_keys format (see sshd(8) manual + # page). # - # cert - An SSH formatted certificate, including key algo, - # encoded key and optional user/host names. + # cert - An OpenSSH formatted certificate, including key algo, + # base64 encoded key and optional comment. # unsafe_no_verify: - Bool of whether to skip verifying certificate signature # (Default false) # diff --git a/lib/ssh_data/private_key.rb b/lib/ssh_data/private_key.rb index 934599e..af90836 100644 --- a/lib/ssh_data/private_key.rb +++ b/lib/ssh_data/private_key.rb @@ -8,7 +8,7 @@ module PrivateKey # Parse an SSH private key. # - # key - An PEM encoded OpenSSH private key. + # key - A PEM or OpenSSH encoded private key. # # Returns an Array of PrivateKey::Base subclass instances. def self.parse(key) @@ -31,6 +31,11 @@ def self.parse(key) raise DecodeError, "bad private key. maybe encrypted?" end + # Parse an OpenSSH formatted private key. + # + # key - An OpenSSH encoded private key. + # + # Returns an Array of PrivateKey::Base subclass instances. def self.parse_openssh(key) raw = Encoding.decode_pem(key, OPENSSH_PEM_TYPE) diff --git a/lib/ssh_data/public_key.rb b/lib/ssh_data/public_key.rb index ae17dbb..9769afc 100644 --- a/lib/ssh_data/public_key.rb +++ b/lib/ssh_data/public_key.rb @@ -8,10 +8,11 @@ module PublicKey ALGO_ECDSA521 = "ecdsa-sha2-nistp521" ALGO_ED25519 = "ssh-ed25519" - # Parse an SSH public key. + # Parse an OpenSSH public key in authorized_keys format (see sshd(8) manual + # page). # - # key - An SSH formatted public key, including algo, encoded key and optional - # user/host names. + # key - An OpenSSH formatted public key, including algo, base64 encoded key + # and optional comment. # # Returns a PublicKey::Base subclass instance. def self.parse(key) diff --git a/spec/certificate_spec.rb b/spec/certificate_spec.rb index c6f4f2d..5916883 100644 --- a/spec/certificate_spec.rb +++ b/spec/certificate_spec.rb @@ -29,11 +29,11 @@ end it "raises on trailing data" do - algo, b64, host = fixture("rsa_leaf_for_rsa_ca-cert.pub").split(" ", 3) + algo, b64, comment = fixture("rsa_leaf_for_rsa_ca-cert.pub").split(" ", 3) raw = Base64.decode64(b64) raw += "foobar" b64 = Base64.strict_encode64(raw) - cert = [algo, b64, host].join(" ") + cert = [algo, b64, comment].join(" ") expect { described_class.parse(cert, unsafe_no_verify: true) @@ -41,15 +41,15 @@ end it "raises on type mismatch" do - _, b64, host = fixture("rsa_leaf_for_rsa_ca-cert.pub").split(" ", 3) - cert = [SSHData::Certificate::ALGO_ED25519, b64, host].join(" ") + _, b64, comment = fixture("rsa_leaf_for_rsa_ca-cert.pub").split(" ", 3) + cert = [SSHData::Certificate::ALGO_ED25519, b64, comment].join(" ") expect { described_class.parse(cert, unsafe_no_verify: true) }.to raise_error(SSHData::DecodeError) end - it "doesn't require the user/host names" do + it "doesn't require the comment" do type, b64, _ = fixture("rsa_leaf_for_rsa_ca-cert.pub").split(" ", 3) cert = [type, b64].join(" ") diff --git a/spec/fixtures/gen.sh b/spec/fixtures/gen.sh index 888503f..a2b4d20 100755 --- a/spec/fixtures/gen.sh +++ b/spec/fixtures/gen.sh @@ -41,14 +41,14 @@ ruby < Date: Mon, 11 Feb 2019 12:06:20 -0700 Subject: [PATCH 3/6] rename PublicKey and Certificate `parse` methods `parse_openssh` --- README.md | 4 ++-- lib/ssh_data/certificate.rb | 2 +- lib/ssh_data/public_key.rb | 2 +- spec/certificate_spec.rb | 26 +++++++++++++------------- spec/public_key/dsa_spec.rb | 4 ++-- spec/public_key/ecdsa_spec.rb | 8 ++++---- spec/public_key/ed25519_spec.rb | 6 +++--- spec/public_key/rsa_spec.rb | 4 ++-- spec/public_key_spec.rb | 4 ++-- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index eace9f5..91cedbc 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ gem install ssh_data require "ssh_data" key_data = File.read("~/.ssh/id_rsa.pub") -key = SSHData::PublicKey.parse(key_data) +key = SSHData::PublicKey.parse_openssh(key_data) #=> cert_data = = File.read("~/.ssh/id_rsa-cert.pub") -cert = SSHData::Certificate.parse(cert_data) +cert = SSHData::Certificate.parse_openssh(cert_data) #=> cert.key_id diff --git a/lib/ssh_data/certificate.rb b/lib/ssh_data/certificate.rb index f3c5dbb..90107bd 100644 --- a/lib/ssh_data/certificate.rb +++ b/lib/ssh_data/certificate.rb @@ -25,7 +25,7 @@ class Certificate # (Default false) # # Returns a Certificate instance. - def self.parse(cert, unsafe_no_verify: false) + def self.parse_openssh(cert, unsafe_no_verify: false) algo, raw, _ = SSHData.key_parts(cert) parsed = parse_rfc4253(raw, unsafe_no_verify: unsafe_no_verify) diff --git a/lib/ssh_data/public_key.rb b/lib/ssh_data/public_key.rb index 9769afc..1c6c0ab 100644 --- a/lib/ssh_data/public_key.rb +++ b/lib/ssh_data/public_key.rb @@ -15,7 +15,7 @@ module PublicKey # and optional comment. # # Returns a PublicKey::Base subclass instance. - def self.parse(key) + def self.parse_openssh(key) algo, raw, _ = SSHData.key_parts(key) parsed = parse_rfc4253(raw) diff --git a/spec/certificate_spec.rb b/spec/certificate_spec.rb index 5916883..a0f9f0d 100644 --- a/spec/certificate_spec.rb +++ b/spec/certificate_spec.rb @@ -1,28 +1,28 @@ require_relative "./spec_helper" describe SSHData::Certificate do - let(:rsa_cert) { described_class.parse(fixture("rsa_leaf_for_rsa_ca-cert.pub")) } - let(:dsa_cert) { described_class.parse(fixture("dsa_leaf_for_rsa_ca-cert.pub")) } - let(:ecdsa_cert) { described_class.parse(fixture("ecdsa_leaf_for_rsa_ca-cert.pub")) } - let(:ed25519_cert) { described_class.parse(fixture("ed25519_leaf_for_rsa_ca-cert.pub")) } + let(:rsa_cert) { described_class.parse_openssh(fixture("rsa_leaf_for_rsa_ca-cert.pub")) } + let(:dsa_cert) { described_class.parse_openssh(fixture("dsa_leaf_for_rsa_ca-cert.pub")) } + let(:ecdsa_cert) { described_class.parse_openssh(fixture("ecdsa_leaf_for_rsa_ca-cert.pub")) } + let(:ed25519_cert) { described_class.parse_openssh(fixture("ed25519_leaf_for_rsa_ca-cert.pub")) } - let(:rsa_ca_cert) { described_class.parse(fixture("rsa_leaf_for_rsa_ca-cert.pub")) } - let(:dsa_ca_cert) { described_class.parse(fixture("rsa_leaf_for_dsa_ca-cert.pub")) } - let(:ecdsa_ca_cert) { described_class.parse(fixture("rsa_leaf_for_ecdsa_ca-cert.pub")) } - let(:ed25519_ca_cert) { described_class.parse(fixture("rsa_leaf_for_ed25519_ca-cert.pub")) } + let(:rsa_ca_cert) { described_class.parse_openssh(fixture("rsa_leaf_for_rsa_ca-cert.pub")) } + let(:dsa_ca_cert) { described_class.parse_openssh(fixture("rsa_leaf_for_dsa_ca-cert.pub")) } + let(:ecdsa_ca_cert) { described_class.parse_openssh(fixture("rsa_leaf_for_ecdsa_ca-cert.pub")) } + let(:ed25519_ca_cert) { described_class.parse_openssh(fixture("rsa_leaf_for_ed25519_ca-cert.pub")) } let(:min_time) { Time.at(0) } let(:max_time) { Time.at((2**64)-1) } it "raises on invalid signatures" do expect { - described_class.parse(fixture("bad_signature-cert.pub")) + described_class.parse_openssh(fixture("bad_signature-cert.pub")) }.to raise_error(SSHData::VerifyError) end it "doesn't validate signatures if provided unsafe_no_verify flag" do expect { - described_class.parse(fixture("bad_signature-cert.pub"), + described_class.parse_openssh(fixture("bad_signature-cert.pub"), unsafe_no_verify: true ) }.not_to raise_error @@ -36,7 +36,7 @@ cert = [algo, b64, comment].join(" ") expect { - described_class.parse(cert, unsafe_no_verify: true) + described_class.parse_openssh(cert, unsafe_no_verify: true) }.to raise_error(SSHData::DecodeError) end @@ -45,7 +45,7 @@ cert = [SSHData::Certificate::ALGO_ED25519, b64, comment].join(" ") expect { - described_class.parse(cert, unsafe_no_verify: true) + described_class.parse_openssh(cert, unsafe_no_verify: true) }.to raise_error(SSHData::DecodeError) end @@ -54,7 +54,7 @@ cert = [type, b64].join(" ") expect { - described_class.parse(cert, unsafe_no_verify: true) + described_class.parse_openssh(cert, unsafe_no_verify: true) }.not_to raise_error end diff --git a/spec/public_key/dsa_spec.rb b/spec/public_key/dsa_spec.rb index 5d2f57c..4d12373 100644 --- a/spec/public_key/dsa_spec.rb +++ b/spec/public_key/dsa_spec.rb @@ -11,7 +11,7 @@ let(:ssh_sig) { described_class.ssh_signature(openssl_sig) } let(:sig) { SSHData::Encoding.encode_signature(SSHData::PublicKey::ALGO_DSA, ssh_sig) } - let(:openssh_key) { SSHData::PublicKey.parse(fixture("dsa_leaf_for_rsa_ca.pub")) } + let(:openssh_key) { SSHData::PublicKey.parse_openssh(fixture("dsa_leaf_for_rsa_ca.pub")) } subject do described_class.new( @@ -92,7 +92,7 @@ it "can verify certificate signatures" do expect { - SSHData::Certificate.parse(fixture("rsa_leaf_for_dsa_ca-cert.pub"), + SSHData::Certificate.parse_openssh(fixture("rsa_leaf_for_dsa_ca-cert.pub"), unsafe_no_verify: false ) }.not_to raise_error diff --git a/spec/public_key/ecdsa_spec.rb b/spec/public_key/ecdsa_spec.rb index 78d4d63..fc0176b 100644 --- a/spec/public_key/ecdsa_spec.rb +++ b/spec/public_key/ecdsa_spec.rb @@ -1,7 +1,7 @@ require_relative "../spec_helper" describe SSHData::PublicKey::ECDSA do - let(:openssh_key) { SSHData::PublicKey.parse(fixture("ecdsa_leaf_for_rsa_ca.pub")) } + let(:openssh_key) { SSHData::PublicKey.parse_openssh(fixture("ecdsa_leaf_for_rsa_ca.pub")) } it "can parse openssh-generate keys" do expect { openssh_key }.not_to raise_error @@ -13,7 +13,7 @@ it "can verify certificate signatures" do expect { - SSHData::Certificate.parse(fixture("rsa_leaf_for_ecdsa_ca-cert.pub"), + SSHData::Certificate.parse_openssh(fixture("rsa_leaf_for_ecdsa_ca-cert.pub"), unsafe_no_verify: false ) }.not_to raise_error @@ -29,7 +29,7 @@ ].join)].join(" ") expect { - SSHData::PublicKey.parse(malformed) + SSHData::PublicKey.parse_openssh(malformed) }.to raise_error(SSHData::DecodeError) end @@ -107,7 +107,7 @@ ].join)].join(" ") expect { - SSHData::PublicKey.parse(malformed) + SSHData::PublicKey.parse_openssh(malformed) }.to raise_error(SSHData::DecodeError) end end diff --git a/spec/public_key/ed25519_spec.rb b/spec/public_key/ed25519_spec.rb index f426059..0ada4e8 100644 --- a/spec/public_key/ed25519_spec.rb +++ b/spec/public_key/ed25519_spec.rb @@ -8,7 +8,7 @@ let(:raw_sig) { signing_key.sign(msg) } let(:sig) { SSHData::Encoding.encode_signature(SSHData::PublicKey::ALGO_ED25519, raw_sig) } - let(:openssh_key) { SSHData::PublicKey.parse(fixture("ed25519_leaf_for_rsa_ca.pub")) } + let(:openssh_key) { SSHData::PublicKey.parse_openssh(fixture("ed25519_leaf_for_rsa_ca.pub")) } subject do described_class.new( @@ -59,7 +59,7 @@ it "can verify certificate signatures" do expect { - SSHData::Certificate.parse(fixture("rsa_leaf_for_ed25519_ca-cert.pub"), + SSHData::Certificate.parse_openssh(fixture("rsa_leaf_for_ed25519_ca-cert.pub"), unsafe_no_verify: false ) }.not_to raise_error @@ -72,7 +72,7 @@ begin expect { - SSHData::Certificate.parse(fixture("rsa_leaf_for_ed25519_ca-cert.pub"), + SSHData::Certificate.parse_openssh(fixture("rsa_leaf_for_ed25519_ca-cert.pub"), unsafe_no_verify: false ) }.to raise_error(SSHData::VerifyError) diff --git a/spec/public_key/rsa_spec.rb b/spec/public_key/rsa_spec.rb index 379051d..5b4f930 100644 --- a/spec/public_key/rsa_spec.rb +++ b/spec/public_key/rsa_spec.rb @@ -10,7 +10,7 @@ let(:raw_sig) { private_key.sign(digest, msg) } let(:sig) { SSHData::Encoding.encode_signature(SSHData::PublicKey::ALGO_RSA, raw_sig) } - let(:openssh_key) { SSHData::PublicKey.parse(fixture("rsa_leaf_for_rsa_ca.pub")) } + let(:openssh_key) { SSHData::PublicKey.parse_openssh(fixture("rsa_leaf_for_rsa_ca.pub")) } subject do described_class.new( @@ -65,7 +65,7 @@ it "can verify certificate signatures" do expect { - SSHData::Certificate.parse(fixture("rsa_leaf_for_rsa_ca-cert.pub"), + SSHData::Certificate.parse_openssh(fixture("rsa_leaf_for_rsa_ca-cert.pub"), unsafe_no_verify: false ) }.not_to raise_error diff --git a/spec/public_key_spec.rb b/spec/public_key_spec.rb index 9f0521f..4e3c68d 100644 --- a/spec/public_key_spec.rb +++ b/spec/public_key_spec.rb @@ -5,11 +5,11 @@ name = File.basename(path) it "generates a MD5 fingerprint matching ssh-keygen for #{name}" do - expect(described_class.parse(fixture(name)).fingerprint(md5: true)).to eq(ssh_keygen_fingerprint(name, :md5)) + expect(described_class.parse_openssh(fixture(name)).fingerprint(md5: true)).to eq(ssh_keygen_fingerprint(name, :md5)) end it "generates a SHA256 fingerprint matching ssh-keygen for #{name}" do - expect(described_class.parse(fixture(name)).fingerprint).to eq(ssh_keygen_fingerprint(name, :sha256)) + expect(described_class.parse_openssh(fixture(name)).fingerprint).to eq(ssh_keygen_fingerprint(name, :sha256)) end end end From 74e9910aa0a09b799be7abf62532bfe4fcfa5f2d Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 11 Feb 2019 12:15:28 -0700 Subject: [PATCH 4/6] re-encode public keys back into authorized_keys format --- lib/ssh_data/public_key/base.rb | 9 +++++++++ spec/public_key_spec.rb | 21 ++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/ssh_data/public_key/base.rb b/lib/ssh_data/public_key/base.rb index 7b2f63c..ce16e43 100644 --- a/lib/ssh_data/public_key/base.rb +++ b/lib/ssh_data/public_key/base.rb @@ -40,6 +40,15 @@ def raw raise "implement me" end + # OpenSSH public key in authorized_keys format (see sshd(8) manual page). + # + # comment - Optional String comment to append. + # + # Returns a String key. + def openssh(comment: nil) + [algo, Base64.strict_encode64(raw), comment].compact.join(" ") + end + # Is this public key equal to another public key? # # other - Another SSHData::PublicKey::Base instance to compare with. diff --git a/spec/public_key_spec.rb b/spec/public_key_spec.rb index 4e3c68d..f855eb3 100644 --- a/spec/public_key_spec.rb +++ b/spec/public_key_spec.rb @@ -4,12 +4,23 @@ Dir["spec/fixtures/*ca.pub"].each do |path| name = File.basename(path) - it "generates a MD5 fingerprint matching ssh-keygen for #{name}" do - expect(described_class.parse_openssh(fixture(name)).fingerprint(md5: true)).to eq(ssh_keygen_fingerprint(name, :md5)) - end + describe name do + let(:openssh) { fixture(name).strip } + let(:comment) { SSHData.key_parts(openssh).last } + + subject { described_class.parse_openssh(openssh) } + + it "generates a MD5 fingerprint matching ssh-keygen" do + expect(subject.fingerprint(md5: true)).to eq(ssh_keygen_fingerprint(name, :md5)) + end + + it "generates a SHA256 fingerprint matching ssh-keygen" do + expect(subject.fingerprint).to eq(ssh_keygen_fingerprint(name, :sha256)) + end - it "generates a SHA256 fingerprint matching ssh-keygen for #{name}" do - expect(described_class.parse_openssh(fixture(name)).fingerprint).to eq(ssh_keygen_fingerprint(name, :sha256)) + it "can re-encode back into authorized_keys format" do + expect(subject.openssh(comment: comment)).to eq(openssh) + end end end end From ce0f60ee15a26eee0a97681213456b166ca5ed60 Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 11 Feb 2019 12:22:01 -0700 Subject: [PATCH 5/6] keep the old `parse` methods since those are being used currently --- lib/ssh_data/certificate.rb | 3 +++ lib/ssh_data/public_key.rb | 3 +++ spec/certificate_spec.rb | 6 ++++++ spec/public_key_spec.rb | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/lib/ssh_data/certificate.rb b/lib/ssh_data/certificate.rb index 90107bd..fd9b51b 100644 --- a/lib/ssh_data/certificate.rb +++ b/lib/ssh_data/certificate.rb @@ -36,6 +36,9 @@ def self.parse_openssh(cert, unsafe_no_verify: false) parsed end + # Deprecated + singleton_class.send(:alias_method, :parse, :parse_openssh) + # Parse an RFC 4253 binary SSH certificate. # # cert - A RFC 4253 binary certificate String. diff --git a/lib/ssh_data/public_key.rb b/lib/ssh_data/public_key.rb index 1c6c0ab..405192b 100644 --- a/lib/ssh_data/public_key.rb +++ b/lib/ssh_data/public_key.rb @@ -26,6 +26,9 @@ def self.parse_openssh(key) parsed end + # Deprecated + singleton_class.send(:alias_method, :parse, :parse_openssh) + # Parse an RFC 4253 binary SSH public key. # # key - A RFC 4253 binary public key String. diff --git a/spec/certificate_spec.rb b/spec/certificate_spec.rb index a0f9f0d..c2fc29a 100644 --- a/spec/certificate_spec.rb +++ b/spec/certificate_spec.rb @@ -14,6 +14,12 @@ let(:min_time) { Time.at(0) } let(:max_time) { Time.at((2**64)-1) } + it "supports the deprecated Certificate.parse method" do + expect { + described_class.parse(fixture("rsa_leaf_for_rsa_ca-cert.pub")) + }.not_to raise_error + end + it "raises on invalid signatures" do expect { described_class.parse_openssh(fixture("bad_signature-cert.pub")) diff --git a/spec/public_key_spec.rb b/spec/public_key_spec.rb index f855eb3..7671572 100644 --- a/spec/public_key_spec.rb +++ b/spec/public_key_spec.rb @@ -1,6 +1,12 @@ require_relative "./spec_helper" describe SSHData::PublicKey do + it "supports the deprecated PublicKey.parse method" do + expect { + described_class.parse(fixture("rsa_leaf_for_rsa_ca.pub")) + }.not_to raise_error + end + Dir["spec/fixtures/*ca.pub"].each do |path| name = File.basename(path) From 6c2bb0d5689ce1a745f59186c9b20ac42894bf7a Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 11 Feb 2019 12:44:29 -0700 Subject: [PATCH 6/6] add ALGOS constant to Certificate and PublicKey --- lib/ssh_data/certificate.rb | 5 +++++ lib/ssh_data/public_key.rb | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/lib/ssh_data/certificate.rb b/lib/ssh_data/certificate.rb index fd9b51b..97ef2a4 100644 --- a/lib/ssh_data/certificate.rb +++ b/lib/ssh_data/certificate.rb @@ -12,6 +12,11 @@ class Certificate ALGO_ECDSA521 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" ALGO_ED25519 = "ssh-ed25519-cert-v01@openssh.com" + ALGOS = [ + ALGO_RSA, ALGO_DSA, ALGO_ECDSA256, ALGO_ECDSA384, ALGO_ECDSA521, + ALGO_ED25519 + ] + attr_reader :algo, :nonce, :public_key, :serial, :type, :key_id, :valid_principals, :valid_after, :valid_before, :critical_options, :extensions, :reserved, :ca_key, :signature diff --git a/lib/ssh_data/public_key.rb b/lib/ssh_data/public_key.rb index 405192b..56f89cf 100644 --- a/lib/ssh_data/public_key.rb +++ b/lib/ssh_data/public_key.rb @@ -8,6 +8,11 @@ module PublicKey ALGO_ECDSA521 = "ecdsa-sha2-nistp521" ALGO_ED25519 = "ssh-ed25519" + ALGOS = [ + ALGO_RSA, ALGO_DSA, ALGO_ECDSA256, ALGO_ECDSA384, ALGO_ECDSA521, + ALGO_ED25519 + ] + # Parse an OpenSSH public key in authorized_keys format (see sshd(8) manual # page). #