putty-key 1.1.0 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +14 -0
- data/Gemfile +28 -1
- data/LICENSE +1 -1
- data/Rakefile +2 -2
- data/lib/putty/key/openssl.rb +290 -49
- data/lib/putty/key/ppk.rb +14 -2
- data/lib/putty/key/version.rb +1 -1
- data/putty-key.gemspec +1 -1
- data/test/test_helper.rb +10 -3
- data.tar.gz.sig +0 -0
- metadata +5 -5
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1c65726c4468a416efcd8617dab76d88660cf732254089a5a342c16f9eabc5d
|
4
|
+
data.tar.gz: cb96dba0c50957fea7add686d9447fcbb65d42bd1bc5bfbd61d81feb98c79a69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa668b32837bb8aacd74d1623ede0b0bef2b6b38c06927b684ee69beb767d611bff059cb4a20b2ffce699523f217af8e815896187ebf1b0cb2b0aabb452ea61d
|
7
|
+
data.tar.gz: d1aec232b10f62cdaa62368144d550dee02de413509869731809cf1f314b3e538fa60b77a373751dffa45e36b0bdca06b08041d282c30cdf4e0d4a588779e261
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changes #
|
2
2
|
|
3
|
+
## Version 1.1.2 - 16-Oct-2024 ##
|
4
|
+
|
5
|
+
* Fix `Java::JavaLang::NullPointerException` being raised instead of
|
6
|
+
`PuTTY::Key::InvalidStateError` by `OpenSSL::PKey::EC#to_ppk` on JRuby 9.4
|
7
|
+
when the key is not initialized.
|
8
|
+
|
9
|
+
|
10
|
+
## Version 1.1.1 - 23-Oct-2022 ##
|
11
|
+
|
12
|
+
* Add support for Ruby 3.2.
|
13
|
+
* Add support for OpenSSL 3 (requires either Ruby 3.1+, or version 3.0.0+ of the
|
14
|
+
openssl gem).
|
15
|
+
|
16
|
+
|
3
17
|
## Version 1.1.0 - 24-May-2021 ##
|
4
18
|
|
5
19
|
* Add support for [format 3 .ppk files](https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ppk3.html)
|
data/Gemfile
CHANGED
@@ -12,6 +12,33 @@ group :test do
|
|
12
12
|
|
13
13
|
# coveralls is no longer maintained, but supports Ruby < 2.3.
|
14
14
|
# coveralls_reborn is maintained, but requires Ruby >= 2.3.
|
15
|
-
gem 'coveralls', '
|
15
|
+
gem 'coveralls', git: 'https://github.com/philr/coveralls-ruby.git', require: false if RUBY_VERSION < '2.3'
|
16
16
|
gem 'coveralls_reborn', '~> 0.13', require: false if RUBY_VERSION >= '2.3'
|
17
|
+
|
18
|
+
# term-ansicolor is a dependency of coveralls. All versions are falsely
|
19
|
+
# declared as compatible with any Ruby version.
|
20
|
+
#
|
21
|
+
# Limit to an earlier compatible version.
|
22
|
+
if RUBY_VERSION < '2.5'
|
23
|
+
gem 'term-ansicolor', '< 1.9'
|
24
|
+
end
|
25
|
+
|
26
|
+
# tins is a dependency of coveralls. From 1.33.0 it depends on bigdecimal,
|
27
|
+
# which can't be installed on old JRuby versions.
|
28
|
+
#
|
29
|
+
# Limit to an earlier compatible version.
|
30
|
+
if RUBY_ENGINE == 'jruby'
|
31
|
+
gem 'tins', '< 1.33'
|
32
|
+
end
|
33
|
+
|
34
|
+
# The source version of ffi 1.15.5 is declared as compatible with Ruby >= 2.3.
|
35
|
+
# The binary version of 1.15.5 is declared as compatible with Ruby >= 2.4, so
|
36
|
+
# doesn't get used. The using the source version results in a segmentation
|
37
|
+
# fault during libffi initialization.
|
38
|
+
#
|
39
|
+
# Binaries of 15.5.0 to 15.5.4 are declared as compatible with Ruby >= 2.3,
|
40
|
+
# but don't get used with Bundler 2.3.23 and Ruby 2.3 on Windows.
|
41
|
+
#
|
42
|
+
# Limit to earlier compatible versions.
|
43
|
+
gem 'ffi', '< 1.15.0' if RUBY_VERSION < '2.4' && RUBY_PLATFORM =~ /mingw/
|
17
44
|
end
|
data/LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -4,11 +4,11 @@ require 'rubygems/package_task'
|
|
4
4
|
require 'rake/testtask'
|
5
5
|
|
6
6
|
BASE_DIR = File.expand_path(File.dirname(__FILE__))
|
7
|
+
GEMSPEC_PATH = File.join(BASE_DIR, 'putty-key.gemspec')
|
8
|
+
spec = TOPLEVEL_BINDING.eval(File.read(GEMSPEC_PATH), GEMSPEC_PATH)
|
7
9
|
|
8
10
|
task :default => :test
|
9
11
|
|
10
|
-
spec = eval(File.read('putty-key.gemspec'))
|
11
|
-
|
12
12
|
# Attempt to find the private key and return a spec with added options for
|
13
13
|
# signing the gem if found.
|
14
14
|
def add_signing_key(spec)
|
data/lib/putty/key/openssl.rb
CHANGED
@@ -25,10 +25,271 @@ module PuTTY
|
|
25
25
|
|
26
26
|
private_constant :SSH_CURVES
|
27
27
|
|
28
|
+
# Either a real JRuby NullPointerException, or a fake class that won't be
|
29
|
+
# raised. Can be rescued to handle NullPointerException on jruby.
|
30
|
+
JavaNullPointerException = RUBY_ENGINE == 'jruby' ? Java::JavaLang::NullPointerException : Class.new(Exception)
|
31
|
+
private_constant :JavaNullPointerException
|
32
|
+
|
33
|
+
# OpenSSL version helper methods.
|
34
|
+
#
|
35
|
+
# @private
|
36
|
+
module Version
|
37
|
+
class << self
|
38
|
+
# Determines if the Ruby OpenSSL wrapper is using the OpenSSL library
|
39
|
+
# (not LibreSSL and not JRuby) and if the version matches the required
|
40
|
+
# version.
|
41
|
+
#
|
42
|
+
# @param major [Integer] The required major version. `nil` if any
|
43
|
+
# version of OpenSSL is sufficient.
|
44
|
+
# @param minor [Integer] The required minor version.
|
45
|
+
# @param fix [Integer] The required fix version.
|
46
|
+
# @param patch [Integer] The required patch version.
|
47
|
+
# @return [Boolean] `true` if the requirements are met, otherwise
|
48
|
+
# `false`.
|
49
|
+
def openssl?(major = nil, minor = 0, fix = 0, patch = 0)
|
50
|
+
return false if ::OpenSSL::OPENSSL_VERSION.include?('LibreSSL')
|
51
|
+
return false if ::OpenSSL::OPENSSL_VERSION.include?('JRuby')
|
52
|
+
return true unless major
|
53
|
+
required_version = major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10
|
54
|
+
::OpenSSL::OPENSSL_VERSION_NUMBER >= required_version
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
private_constant :Version
|
59
|
+
|
60
|
+
# Methods to build OpenSSL private keys from a {PPK}.
|
61
|
+
#
|
62
|
+
# @private
|
63
|
+
module PKeyBuilding
|
64
|
+
class << self
|
65
|
+
# Creates a new OpenSSL DSA private key for the given DSA {PPK}.
|
66
|
+
#
|
67
|
+
# @param ppk [PPK] A DSA {PPK}.
|
68
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
69
|
+
def ppk_to_dsa(ppk)
|
70
|
+
_, p, q, g, pub_key = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint, :mpint, :mpint)
|
71
|
+
priv_key = Util.ssh_unpack(ppk.private_blob, :mpint).first
|
72
|
+
dsa_from_params(p, q, g, pub_key, priv_key)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Creates a new OpenSSL RSA private key for the given RSA {PPK}.
|
76
|
+
#
|
77
|
+
# @param ppk [PPK] An RSA {PPK}.
|
78
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
79
|
+
def ppk_to_rsa(ppk)
|
80
|
+
_, e, n = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint)
|
81
|
+
d, p, q, iqmp = Util.ssh_unpack(ppk.private_blob, :mpint, :mpint, :mpint, :mpint)
|
82
|
+
dmp1 = d % (p - 1)
|
83
|
+
dmq1 = d % (q - 1)
|
84
|
+
rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Creates a new OpenSSL EC private key for the given EC {PPK}.
|
88
|
+
#
|
89
|
+
# @param ppk [PPK] An EC {PPK}.
|
90
|
+
# @param ppk_curve [String] The PPK curve name extracted from the
|
91
|
+
# PPK algorithm name.
|
92
|
+
# @return [::OpenSSL::PKey::EC] The OpenSSL EC private key.
|
93
|
+
def ppk_to_ec(ppk, ppk_curve)
|
94
|
+
curve = OPENSSL_CURVES[ppk_curve]
|
95
|
+
_, _, pub_key = Util.ssh_unpack(ppk.public_blob, :string, :string, :mpint)
|
96
|
+
priv_key = Util.ssh_unpack(ppk.private_blob, :mpint).first
|
97
|
+
ec_from_params(curve, pub_key, priv_key)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
if Version.openssl?(3)
|
103
|
+
# OpenSSL v3 private keys are immutable. The Ruby OpenSSL wrapper
|
104
|
+
# doesn't provide a method to construct private keys using the
|
105
|
+
# parameters. Build DER (ASN.1) encoded versions of the keys.
|
106
|
+
#
|
107
|
+
# In theory this should be usable universally. However
|
108
|
+
# ::OpenSSL::PKey::EC::Point#to_octet_string is only supported from
|
109
|
+
# Ruby >= 2.4 and there are issues with JRuby's OpenSSL library
|
110
|
+
# (that doesn't make use of OpenSSL).
|
111
|
+
|
112
|
+
# :nocov_no_openssl3:
|
113
|
+
|
114
|
+
# Creates a new OpenSSL DSA private key with the given parameters.
|
115
|
+
#
|
116
|
+
# @param p [::OpenSSL::BN] The p parameter (prime).
|
117
|
+
# @param q [::OpenSSL::BN] The q parameter (prime).
|
118
|
+
# @param g [::OpenSSL::BN] The g parameter.
|
119
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
120
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
121
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
122
|
+
def dsa_from_params(p, q, g, pub_key, priv_key)
|
123
|
+
# https://www.openssl.org/docs/man3.0/man1/openssl-dsa.html (outform parameter).
|
124
|
+
sequence = [
|
125
|
+
::OpenSSL::ASN1::Integer.new(0),
|
126
|
+
::OpenSSL::ASN1::Integer.new(p),
|
127
|
+
::OpenSSL::ASN1::Integer.new(q),
|
128
|
+
::OpenSSL::ASN1::Integer.new(g),
|
129
|
+
::OpenSSL::ASN1::Integer.new(pub_key),
|
130
|
+
::OpenSSL::ASN1::Integer.new(priv_key)
|
131
|
+
]
|
132
|
+
|
133
|
+
::OpenSSL::PKey::DSA.new(::OpenSSL::ASN1::Sequence.new(sequence).to_der)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Creates a new OpenSSL RSA private key with the given parameters.
|
137
|
+
#
|
138
|
+
# @param e [::OpenSSL::BN] The public key exponent.
|
139
|
+
# @param n [::OpenSSL::BN] The modulus.
|
140
|
+
# @param d [::OpenSSL::BN] The private key exponent.
|
141
|
+
# @param p [::OpenSSL::BN] The p prime.
|
142
|
+
# @param q [::OpenSSL::BN] The q prime.
|
143
|
+
# @param iqmp [::OpenSSL::BN] The inverse of q, mod p.
|
144
|
+
# @param dmp1 [::OpenSSL::BN] `d` mod (`p` - 1).
|
145
|
+
# @param dmq1 [::OpenSSL::BN] `d` mod (`q` - 1).
|
146
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
147
|
+
def rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
148
|
+
# RFC 3447 Appendix A.1.2
|
149
|
+
sequence = [
|
150
|
+
::OpenSSL::ASN1::Integer.new(0),
|
151
|
+
::OpenSSL::ASN1::Integer.new(n),
|
152
|
+
::OpenSSL::ASN1::Integer.new(e),
|
153
|
+
::OpenSSL::ASN1::Integer.new(d),
|
154
|
+
::OpenSSL::ASN1::Integer.new(p),
|
155
|
+
::OpenSSL::ASN1::Integer.new(q),
|
156
|
+
::OpenSSL::ASN1::Integer.new(dmp1),
|
157
|
+
::OpenSSL::ASN1::Integer.new(dmq1),
|
158
|
+
::OpenSSL::ASN1::Integer.new(iqmp)
|
159
|
+
]
|
160
|
+
|
161
|
+
::OpenSSL::PKey::RSA.new(::OpenSSL::ASN1::Sequence.new(sequence).to_der)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Creates a new OpenSSL EC private key with the given parameters.
|
165
|
+
#
|
166
|
+
# @param curve [String] The name of the OpenSSL EC curve.
|
167
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
168
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
169
|
+
# @return [::OpenSSL::PKey::EC] The OpenSSL EC private key.
|
170
|
+
def ec_from_params(curve, pub_key, priv_key)
|
171
|
+
group = ::OpenSSL::PKey::EC::Group.new(curve)
|
172
|
+
point = ::OpenSSL::PKey::EC::Point.new(group, pub_key)
|
173
|
+
point_string = point.to_octet_string(:uncompressed)
|
174
|
+
|
175
|
+
# RFC 5915 Section 3
|
176
|
+
sequence = [
|
177
|
+
::OpenSSL::ASN1::Integer.new(1),
|
178
|
+
::OpenSSL::ASN1::OctetString.new(priv_key.to_s(2)),
|
179
|
+
::OpenSSL::ASN1::ObjectId.new(curve, 0, :EXPLICIT),
|
180
|
+
::OpenSSL::ASN1::BitString.new(point_string, 1, :EXPLICIT)
|
181
|
+
]
|
182
|
+
|
183
|
+
::OpenSSL::PKey::EC.new(::OpenSSL::ASN1::Sequence.new(sequence).to_der)
|
184
|
+
end
|
185
|
+
# :nocov_no_openssl3:
|
186
|
+
else
|
187
|
+
# :nocov_openssl3:
|
188
|
+
if ::OpenSSL::PKey::DSA.new.respond_to?(:set_key)
|
189
|
+
# :nocov_no_openssl_pkey_dsa_set_key:
|
190
|
+
|
191
|
+
# Creates a new OpenSSL DSA private key with the given parameters.
|
192
|
+
#
|
193
|
+
# @param p [::OpenSSL::BN] The p parameter.
|
194
|
+
# @param q [::OpenSSL::BN] The q parameter.
|
195
|
+
# @param g [::OpenSSL::BN] The g parameter.
|
196
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
197
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
198
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
199
|
+
def dsa_from_params(p, q, g, pub_key, priv_key)
|
200
|
+
::OpenSSL::PKey::DSA.new.tap do |pkey|
|
201
|
+
pkey.set_key(pub_key, priv_key)
|
202
|
+
pkey.set_pqg(p, q, g)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
# :nocov_no_openssl_pkey_dsa_set_key:
|
206
|
+
else
|
207
|
+
# :nocov_openssl_pkey_dsa_set_key:
|
208
|
+
# Creates a new OpenSSL DSA private key with the given parameters.
|
209
|
+
#
|
210
|
+
# @param p [::OpenSSL::BN] The p parameter.
|
211
|
+
# @param q [::OpenSSL::BN] The q parameter.
|
212
|
+
# @param g [::OpenSSL::BN] The g parameter.
|
213
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
214
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
215
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
216
|
+
def dsa_from_params(p, q, g, pub_key, priv_key)
|
217
|
+
::OpenSSL::PKey::DSA.new.tap do |pkey|
|
218
|
+
pkey.p, pkey.q, pkey.g, pkey.pub_key, pkey.priv_key = p, q, g, pub_key, priv_key
|
219
|
+
end
|
220
|
+
end
|
221
|
+
# :nocov_openssl_pkey_dsa_set_key:
|
222
|
+
end
|
223
|
+
|
224
|
+
if ::OpenSSL::PKey::RSA.new.respond_to?(:set_factors)
|
225
|
+
# :nocov_no_openssl_pkey_rsa_set_factors:
|
226
|
+
|
227
|
+
# Creates a new OpenSSL RSA private key with the given parameters.
|
228
|
+
#
|
229
|
+
# @param e [::OpenSSL::BN] The public key exponent.
|
230
|
+
# @param n [::OpenSSL::BN] The modulus.
|
231
|
+
# @param d [::OpenSSL::BN] The private key exponent.
|
232
|
+
# @param p [::OpenSSL::BN] The p prime.
|
233
|
+
# @param q [::OpenSSL::BN] The q prime.
|
234
|
+
# @param iqmp [::OpenSSL::BN] The inverse of q, mod p.
|
235
|
+
# @param dmp1 [::OpenSSL::BN] `d` mod (`p` - 1).
|
236
|
+
# @param dmq1 [::OpenSSL::BN] `d` mod (`q` - 1).
|
237
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
238
|
+
def rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
239
|
+
::OpenSSL::PKey::RSA.new.tap do |pkey|
|
240
|
+
pkey.set_factors(p, q)
|
241
|
+
pkey.set_key(n, e, d)
|
242
|
+
pkey.set_crt_params(dmp1, dmq1, iqmp)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
# :nocov_no_openssl_pkey_rsa_set_factors:
|
246
|
+
else
|
247
|
+
# :nocov_openssl_pkey_rsa_set_factors:
|
248
|
+
|
249
|
+
# Creates a new OpenSSL RSA private key with the given parameters.
|
250
|
+
#
|
251
|
+
# @param e [::OpenSSL::BN] The public key exponent.
|
252
|
+
# @param n [::OpenSSL::BN] The modulus.
|
253
|
+
# @param d [::OpenSSL::BN] The private key exponent.
|
254
|
+
# @param p [::OpenSSL::BN] The p prime.
|
255
|
+
# @param q [::OpenSSL::BN] The q prime.
|
256
|
+
# @param iqmp [::OpenSSL::BN] The inverse of q, mod p.
|
257
|
+
# @param dmp1 [::OpenSSL::BN] `d` mod (`p` - 1).
|
258
|
+
# @param dmq1 [::OpenSSL::BN] `d` mod (`q` - 1).
|
259
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
260
|
+
def rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
261
|
+
::OpenSSL::PKey::RSA.new.tap do |pkey|
|
262
|
+
pkey.e, pkey.n, pkey.d, pkey.p, pkey.q, pkey.iqmp, pkey.dmp1, pkey.dmq1 = e, n, d, p, q, iqmp, dmp1, dmq1
|
263
|
+
end
|
264
|
+
end
|
265
|
+
# :nocov_openssl_pkey_rsa_set_factors:
|
266
|
+
end
|
267
|
+
|
268
|
+
# Creates a new OpenSSL EC private key with the given parameters.
|
269
|
+
#
|
270
|
+
# @param curve [String] The name of the OpenSSL EC curve.
|
271
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
272
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
273
|
+
# @return [::OpenSSL::PKey::EC] The OpenSSL EC private key.
|
274
|
+
def ec_from_params(curve, pub_key, priv_key)
|
275
|
+
# Old versions of jruby-openssl don't include an EC class (version 0.9.16).
|
276
|
+
ec_class = (::OpenSSL::PKey::EC rescue raise ArgumentError, "Unsupported algorithm: #{ppk.algorithm}")
|
277
|
+
|
278
|
+
ec_class.new(curve).tap do |pkey|
|
279
|
+
group = pkey.group || ::OpenSSL::PKey::EC::Group.new(curve)
|
280
|
+
pkey.public_key = ::OpenSSL::PKey::EC::Point.new(group, pub_key)
|
281
|
+
pkey.private_key = priv_key
|
282
|
+
end
|
283
|
+
end
|
284
|
+
# :nocov_openssl3:
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
private_constant :PKeyBuilding
|
289
|
+
|
28
290
|
# The {ClassMethods} module is used to extend `OpenSSL::PKey` when
|
29
291
|
# using the PuTTY::Key refinement or calling {PuTTY::Key.global_install}.
|
30
292
|
# This adds a `from_ppk` class method to `OpenSSL::PKey`.
|
31
|
-
#
|
32
293
|
module ClassMethods
|
33
294
|
# Creates a new `OpenSSL::PKey` from a PuTTY private key (instance of
|
34
295
|
# {PPK}).
|
@@ -50,53 +311,11 @@ module PuTTY
|
|
50
311
|
|
51
312
|
case ppk.algorithm
|
52
313
|
when 'ssh-dss'
|
53
|
-
|
54
|
-
_, p, q, g, pub_key = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint, :mpint, :mpint)
|
55
|
-
priv_key = Util.ssh_unpack(ppk.private_blob, :mpint).first
|
56
|
-
|
57
|
-
if pkey.respond_to?(:set_key)
|
58
|
-
# :nocov_no_openssl_pkey_dsa_set_key:
|
59
|
-
pkey.set_key(pub_key, priv_key)
|
60
|
-
pkey.set_pqg(p, q, g)
|
61
|
-
# :nocov_no_openssl_pkey_dsa_set_key:
|
62
|
-
else
|
63
|
-
# :nocov_openssl_pkey_dsa_set_key:
|
64
|
-
pkey.p, pkey.q, pkey.g, pkey.pub_key, pkey.priv_key = p, q, g, pub_key, priv_key
|
65
|
-
# :nocov_openssl_pkey_dsa_set_key:
|
66
|
-
end
|
67
|
-
end
|
314
|
+
PKeyBuilding.ppk_to_dsa(ppk)
|
68
315
|
when 'ssh-rsa'
|
69
|
-
|
70
|
-
_, e, n = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint)
|
71
|
-
d, p, q, iqmp = Util.ssh_unpack(ppk.private_blob, :mpint, :mpint, :mpint, :mpint)
|
72
|
-
|
73
|
-
dmp1 = d % (p - 1)
|
74
|
-
dmq1 = d % (q - 1)
|
75
|
-
|
76
|
-
if pkey.respond_to?(:set_factors)
|
77
|
-
# :nocov_no_openssl_pkey_rsa_set_factors:
|
78
|
-
pkey.set_factors(p, q)
|
79
|
-
pkey.set_key(n, e, d)
|
80
|
-
pkey.set_crt_params(dmp1, dmq1, iqmp)
|
81
|
-
# :nocov_no_openssl_pkey_rsa_set_factors:
|
82
|
-
else
|
83
|
-
# :nocov_openssl_pkey_rsa_set_factors:
|
84
|
-
pkey.e, pkey.n, pkey.d, pkey.p, pkey.q, pkey.iqmp, pkey.dmp1, pkey.dmq1 = e, n, d, p, q, iqmp, dmp1, dmq1
|
85
|
-
# :nocov_openssl_pkey_rsa_set_factors:
|
86
|
-
end
|
87
|
-
end
|
316
|
+
PKeyBuilding.ppk_to_rsa(ppk)
|
88
317
|
when /\Aecdsa-sha2-(nistp(?:256|384|521))\z/
|
89
|
-
|
90
|
-
|
91
|
-
# Old versions of jruby-openssl don't include an EC class (version 0.9.16).
|
92
|
-
ec_class = (::OpenSSL::PKey::EC rescue raise ArgumentError, "Unsupported algorithm: #{ppk.algorithm}")
|
93
|
-
|
94
|
-
ec_class.new(curve).tap do |pkey|
|
95
|
-
_, _, point = Util.ssh_unpack(ppk.public_blob, :string, :string, :mpint)
|
96
|
-
group = pkey.group || ::OpenSSL::PKey::EC::Group.new(curve)
|
97
|
-
pkey.public_key = ::OpenSSL::PKey::EC::Point.new(group, point)
|
98
|
-
pkey.private_key = Util.ssh_unpack(ppk.private_blob, :mpint).first
|
99
|
-
end
|
318
|
+
PKeyBuilding.ppk_to_ec(ppk, $1)
|
100
319
|
else
|
101
320
|
raise ArgumentError, "Unsupported algorithm: #{ppk.algorithm}"
|
102
321
|
end
|
@@ -141,7 +360,12 @@ module PuTTY
|
|
141
360
|
# @raise [UnsupportedCurveError] If the key uses a curve that is not
|
142
361
|
# supported by PuTTY.
|
143
362
|
def to_ppk
|
144
|
-
|
363
|
+
g = group
|
364
|
+
curve = g && begin
|
365
|
+
g.curve_name
|
366
|
+
rescue JavaNullPointerException
|
367
|
+
nil
|
368
|
+
end
|
145
369
|
raise InvalidStateError, 'The key has not been fully initialized (a curve name must be assigned)' unless curve
|
146
370
|
ssh_curve = SSH_CURVES[curve]
|
147
371
|
raise UnsupportedCurveError, "The curve '#{curve}' is not supported" unless ssh_curve
|
@@ -201,13 +425,30 @@ module PuTTY
|
|
201
425
|
end
|
202
426
|
|
203
427
|
OpenSSL.const_get(:PKEY_CLASSES).each do |name, openssl_class|
|
428
|
+
mod = OpenSSL.const_get(name)
|
204
429
|
refine openssl_class do
|
205
|
-
|
430
|
+
if defined?(::Refinement) && kind_of?(::Refinement)
|
431
|
+
# :nocov_no_refinement_class:
|
432
|
+
import_methods(mod)
|
433
|
+
# :nocov_no_refinement_class:
|
434
|
+
else
|
435
|
+
# :nocov_refinement_class:
|
436
|
+
include mod
|
437
|
+
# :nocov_refinement_class:
|
438
|
+
end
|
206
439
|
end if respond_to?(:refine, true)
|
207
440
|
end
|
208
441
|
|
209
442
|
refine ::OpenSSL::PKey.singleton_class do
|
210
|
-
|
443
|
+
if defined?(::Refinement) && kind_of?(::Refinement)
|
444
|
+
# :nocov_no_refinement_class:
|
445
|
+
import_methods(OpenSSL::ClassMethods)
|
446
|
+
# :nocov_no_refinement_class:
|
447
|
+
else
|
448
|
+
# :nocov_refinement_class:
|
449
|
+
include OpenSSL::ClassMethods
|
450
|
+
# :nocov_refinement_class:
|
451
|
+
end
|
211
452
|
end if respond_to?(:refine, true)
|
212
453
|
end
|
213
454
|
end
|
data/lib/putty/key/ppk.rb
CHANGED
@@ -319,7 +319,19 @@ module PuTTY
|
|
319
319
|
def derive_keys(format, cipher = nil, passphrase = nil, argon2_params = nil)
|
320
320
|
if format >= 3
|
321
321
|
return derive_format_3_keys(cipher, passphrase, argon2_params) if cipher
|
322
|
-
|
322
|
+
|
323
|
+
# An empty string should work for the MAC, but ::OpenSSL::HMAC fails
|
324
|
+
# when used with OpenSSL 3:
|
325
|
+
#
|
326
|
+
# EVP_PKEY_new_mac_key: malloc failure (OpenSSL::HMACError).
|
327
|
+
#
|
328
|
+
# See https://github.com/ruby/openssl/pull/538 and
|
329
|
+
# https://github.com/openssl/openssl/issues/13089.
|
330
|
+
#
|
331
|
+
# Ruby 3.1.3 should contain the workaround from ruby/openssl PR 538.
|
332
|
+
#
|
333
|
+
# Use "\0" as the MAC key for a workaround for Ruby < 3.1.3.
|
334
|
+
return ["\0".b, nil, nil, nil]
|
323
335
|
end
|
324
336
|
|
325
337
|
mac_key = derive_format_2_mac_key(passphrase)
|
@@ -481,7 +493,7 @@ module PuTTY
|
|
481
493
|
# after padding bytes have been appended prior to encryption).
|
482
494
|
#
|
483
495
|
# @param format [Integer] The format of the .ppk file.
|
484
|
-
# @param
|
496
|
+
# @param mac_key [String] The HMAC key.
|
485
497
|
# @param encryption_type [String] The value of the Encryption field.
|
486
498
|
# @param padded_private_blob [String] The private blob after padding bytes
|
487
499
|
# have been appended prior to encryption.
|
data/lib/putty/key/version.rb
CHANGED
data/putty-key.gemspec
CHANGED
data/test/test_helper.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'putty/key'
|
4
|
+
|
3
5
|
TEST_TYPE = (ENV['TEST_TYPE'] || 'refinement').to_sym
|
4
6
|
raise "Unrecognized TEST_TYPE: #{TEST_TYPE}" unless [:refinement, :global].include?(TEST_TYPE)
|
5
7
|
|
@@ -15,6 +17,13 @@ if TEST_COVERAGE
|
|
15
17
|
"#{object.respond_to?(method) ? '' : 'no_'}#{Regexp.escape(object.class.name.downcase.gsub('::', '_'))}_#{Regexp.escape(method)}"
|
16
18
|
end
|
17
19
|
|
20
|
+
feature_support = [
|
21
|
+
['openssl3', PuTTY::Key::OpenSSL.const_get(:Version).openssl?(3)],
|
22
|
+
['refinement_class', defined?(Refinement)]
|
23
|
+
].map do |feature, available|
|
24
|
+
"#{available ? '' : 'no_'}#{feature}"
|
25
|
+
end
|
26
|
+
|
18
27
|
SimpleCov.command_name TEST_TYPE.to_s
|
19
28
|
|
20
29
|
SimpleCov.formatters = [
|
@@ -23,13 +32,11 @@ if TEST_COVERAGE
|
|
23
32
|
|
24
33
|
SimpleCov.start do
|
25
34
|
add_filter 'test'
|
26
|
-
nocov_token "nocov_(#{method_support.join('|')})"
|
35
|
+
nocov_token "nocov_(#{(method_support + feature_support).join('|')})"
|
27
36
|
project_name 'PuTTY::Key'
|
28
37
|
end
|
29
38
|
end
|
30
39
|
|
31
|
-
require 'putty/key'
|
32
|
-
|
33
40
|
require 'fileutils'
|
34
41
|
require 'minitest/autorun'
|
35
42
|
require 'tmpdir'
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: putty-key
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philip Ross
|
@@ -29,7 +29,7 @@ cert_chain:
|
|
29
29
|
J3Zn/kSTjTekiaspyGbczC3PUaeJNxr+yCvR4sk71Xmk/GaKKGOHedJ1uj/LAXrA
|
30
30
|
MR0mpl7b8zCg0PFC1J73uw==
|
31
31
|
-----END CERTIFICATE-----
|
32
|
-
date:
|
32
|
+
date: 2024-10-16 00:00:00.000000000 Z
|
33
33
|
dependencies:
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: ffi
|
@@ -139,9 +139,9 @@ licenses:
|
|
139
139
|
metadata:
|
140
140
|
bug_tracker_uri: https://github.com/philr/putty-key/issues
|
141
141
|
changelog_uri: https://github.com/philr/putty-key/blob/master/CHANGES.md
|
142
|
-
documentation_uri: https://rubydoc.info/gems/putty-key/1.1.
|
142
|
+
documentation_uri: https://rubydoc.info/gems/putty-key/1.1.2
|
143
143
|
homepage_uri: https://github.com/philr/putty-key
|
144
|
-
source_code_uri: https://github.com/philr/putty-key/tree/v1.1.
|
144
|
+
source_code_uri: https://github.com/philr/putty-key/tree/v1.1.2
|
145
145
|
post_install_message:
|
146
146
|
rdoc_options:
|
147
147
|
- "--title"
|
@@ -164,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
164
|
version: '0'
|
165
165
|
requirements:
|
166
166
|
- libargon2 to handle format 3 .ppk files
|
167
|
-
rubygems_version: 3.
|
167
|
+
rubygems_version: 3.5.16
|
168
168
|
signing_key:
|
169
169
|
specification_version: 4
|
170
170
|
summary: PuTTY private key (.ppk) library. Supports reading and writing with a refinement
|
metadata.gz.sig
CHANGED
Binary file
|