Skip to content

Commit 23967c7

Browse files
authored
Merge pull request #9 from github/rsa-sha2
Support RSA SHA2 variants
2 parents 5594f61 + 8d95e57 commit 23967c7

20 files changed

Lines changed: 249 additions & 15 deletions

lib/ssh_data/certificate.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,12 @@ def rfc4253
148148
# Sign this certificate with a private key.
149149
#
150150
# private_key - An SSHData::PrivateKey::Base subclass instance.
151+
# algo: - Optionally specify the signature algorithm to use.
151152
#
152153
# Returns nothing.
153-
def sign(private_key)
154+
def sign(private_key, algo: nil)
154155
@ca_key = private_key.public_key
155-
@signature = private_key.sign(signed_data)
156+
@signature = private_key.sign(signed_data, algo: algo)
156157
end
157158

158159
# Verify the certificate's signature.

lib/ssh_data/private_key/base.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,21 @@ def self.generate(**kwargs)
1818
# Make an SSH signature.
1919
#
2020
# signed_data - The String message over which to calculated the signature.
21+
# algo: - Optionally specify the signature algorithm to use.
2122
#
2223
# Returns a binary String signature.
23-
def sign(signed_data)
24+
def sign(signed_data, algo: nil)
2425
raise "implement me"
2526
end
2627

2728
# Issue a certificate using this private key.
2829
#
29-
# kwargs - See SSHData::Certificate.new.
30+
# signature_algo: - Optionally specify the signature algorithm to use.
31+
# kwargs - See SSHData::Certificate.new.
3032
#
3133
# Returns a SSHData::Certificate instance.
32-
def issue_certificate(**kwargs)
33-
Certificate.new(**kwargs).tap { |c| c.sign(self) }
34+
def issue_certificate(signature_algo: nil, **kwargs)
35+
Certificate.new(**kwargs).tap { |c| c.sign(self, algo: signature_algo) }
3436
end
3537
end
3638
end

lib/ssh_data/private_key/dsa.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ def initialize(algo:, p:, q:, g:, x:, y:, comment:)
5050
# signed_data - The String message over which to calculated the signature.
5151
#
5252
# Returns a binary String signature.
53-
def sign(signed_data)
53+
def sign(signed_data, algo: nil)
54+
algo ||= self.algo
55+
raise AlgorithmError unless algo == self.algo
5456
openssl_sig = openssl.sign(OpenSSL::Digest::SHA1.new, signed_data)
5557
raw_sig = PublicKey::DSA.ssh_signature(openssl_sig)
5658
Encoding.encode_signature(algo, raw_sig)

lib/ssh_data/private_key/ecdsa.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ def initialize(algo:, curve:, public_key:, private_key:, comment:)
6868
# signed_data - The String message over which to calculated the signature.
6969
#
7070
# Returns a binary String signature.
71-
def sign(signed_data)
71+
def sign(signed_data, algo: nil)
72+
algo ||= self.algo
73+
raise AlgorithmError unless algo == self.algo
7274
openssl_sig = openssl.sign(public_key.digest.new, signed_data)
7375
raw_sig = PublicKey::ECDSA.ssh_signature(openssl_sig)
7476
Encoding.encode_signature(algo, raw_sig)

lib/ssh_data/private_key/ed25519.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ def initialize(algo:, pk:, sk:, comment:)
5555
# signed_data - The String message over which to calculated the signature.
5656
#
5757
# Returns a binary String signature.
58-
def sign(signed_data)
58+
def sign(signed_data, algo: nil)
59+
algo ||= self.algo
60+
raise AlgorithmError unless algo == self.algo
5961
raw_sig = ed25519_key.sign(signed_data)
6062
Encoding.encode_signature(algo, raw_sig)
6163
end

lib/ssh_data/private_key/rsa.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,11 @@ def initialize(algo:, n:, e:, d:, iqmp:, p:, q:, comment:)
6161
# signed_data - The String message over which to calculated the signature.
6262
#
6363
# Returns a binary String signature.
64-
def sign(signed_data)
65-
raw_sig = openssl.sign(OpenSSL::Digest::SHA1.new, signed_data)
64+
def sign(signed_data, algo: nil)
65+
algo ||= self.algo
66+
digest = PublicKey::RSA::ALGO_DIGESTS[algo]
67+
raise AlgorithmError if digest.nil?
68+
raw_sig = openssl.sign(digest.new, signed_data)
6669
Encoding.encode_signature(algo, raw_sig)
6770
end
6871

lib/ssh_data/public_key.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ module PublicKey
88
ALGO_ECDSA521 = "ecdsa-sha2-nistp521"
99
ALGO_ED25519 = "ssh-ed25519"
1010

11+
# RSA SHA2 *signature* algorithms used with ALGO_RSA keys.
12+
# https://tools.ietf.org/html/draft-rsa-dsa-sha2-256-02
13+
ALGO_RSA_SHA2_256 = "rsa-sha2-256"
14+
ALGO_RSA_SHA2_512 = "rsa-sha2-512"
15+
1116
ALGOS = [
1217
ALGO_RSA, ALGO_DSA, ALGO_ECDSA256, ALGO_ECDSA384, ALGO_ECDSA521,
1318
ALGO_ED25519

lib/ssh_data/public_key/rsa.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ module PublicKey
33
class RSA < Base
44
attr_reader :e, :n, :openssl
55

6+
ALGO_DIGESTS = {
7+
ALGO_RSA => OpenSSL::Digest::SHA1,
8+
ALGO_RSA_SHA2_256 => OpenSSL::Digest::SHA256,
9+
ALGO_RSA_SHA2_512 => OpenSSL::Digest::SHA512
10+
}
11+
612
def initialize(algo:, e:, n:)
713
unless algo == ALGO_RSA
814
raise DecodeError, "bad algorithm: #{algo.inspect}"
@@ -25,11 +31,13 @@ def initialize(algo:, e:, n:)
2531
# Returns boolean.
2632
def verify(signed_data, signature)
2733
sig_algo, raw_sig, _ = Encoding.decode_signature(signature)
28-
if sig_algo != ALGO_RSA
34+
digest = ALGO_DIGESTS[sig_algo]
35+
36+
if digest.nil?
2937
raise DecodeError, "bad signature algorithm: #{sig_algo.inspect}"
3038
end
3139

32-
openssl.verify(OpenSSL::Digest::SHA1.new, raw_sig, signed_data)
40+
openssl.verify(digest.new, raw_sig, signed_data)
3341
end
3442

3543
# RFC4253 binary encoding of the public key.

spec/certificate_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,22 @@
6666
SSHData::PublicKey::RSA # ca key type
6767
]
6868

69+
test_cases << [
70+
:rsa_cert_sha2_256_sig, # name
71+
"rsa_leaf_for_rsa_ca_sha2_256-cert.pub", # fixture
72+
SSHData::Certificate::ALGO_RSA, # algo
73+
SSHData::PublicKey::RSA, # public key type
74+
SSHData::PublicKey::RSA # ca key type
75+
]
76+
77+
test_cases << [
78+
:rsa_cert_sha2_512_sig, # name
79+
"rsa_leaf_for_rsa_ca_sha2_512-cert.pub", # fixture
80+
SSHData::Certificate::ALGO_RSA, # algo
81+
SSHData::PublicKey::RSA, # public key type
82+
SSHData::PublicKey::RSA # ca key type
83+
]
84+
6985
test_cases << [
7086
:dsa_cert, # name
7187
"dsa_leaf_for_rsa_ca-cert.pub", # fixture
@@ -155,6 +171,22 @@
155171
expect(subject.verify).to eq(true)
156172
end
157173

174+
it "can be signed with an RSA key using ALGO_RSA_SHA2_256" do
175+
expect {
176+
subject.sign(rsa_ca, algo: SSHData::PublicKey::ALGO_RSA_SHA2_256)
177+
}.to change {subject.signature}
178+
179+
expect(subject.verify).to eq(true)
180+
end
181+
182+
it "can be signed with an RSA key using ALGO_RSA_SHA2_512" do
183+
expect {
184+
subject.sign(rsa_ca, algo: SSHData::PublicKey::ALGO_RSA_SHA2_512)
185+
}.to change {subject.signature}
186+
187+
expect(subject.verify).to eq(true)
188+
end
189+
158190
it "can be signed with an DSA key" do
159191
expect { subject.sign(dsa_ca) }.to change {subject.signature}
160192
expect(subject.verify).to eq(true)

spec/fixtures/gen.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ ssh-keygen -ted25519 -N "" -f ./ed25519_ca
1010
ssh-keygen -trsa -N "" -f ./rsa_leaf_for_rsa_ca
1111
ssh-keygen -s rsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O extension:baz=qwer -O permit-X11-forwarding rsa_leaf_for_rsa_ca.pub
1212

13+
ssh-keygen -trsa -N "" -f ./rsa_leaf_for_rsa_ca_sha2_256
14+
ssh-keygen -trsa-sha2-256 -s rsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O extension:baz=qwer -O permit-X11-forwarding rsa_leaf_for_rsa_ca_sha2_256.pub
15+
16+
ssh-keygen -trsa -N "" -f ./rsa_leaf_for_rsa_ca_sha2_512
17+
ssh-keygen -trsa-sha2-512 -s rsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O extension:baz=qwer -O permit-X11-forwarding rsa_leaf_for_rsa_ca_sha2_512.pub
18+
1319
ssh-keygen -trsa -N "" -f ./rsa_leaf_for_dsa_ca
1420
ssh-keygen -s dsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O extension:baz=qwer -O permit-X11-forwarding rsa_leaf_for_dsa_ca.pub
1521

0 commit comments

Comments
 (0)