putty-key 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +7 -0
- data/Gemfile +12 -1
- data/LICENSE +1 -1
- data/lib/putty/key/openssl.rb +279 -48
- data/lib/putty/key/ppk.rb +14 -2
- data/lib/putty/key/version.rb +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: 7206dacd7197ee9c1344a8cbf607c72614ab3031241bb72a32648bbe62cd784a
|
4
|
+
data.tar.gz: d2835eaa489968b975a93c7cb89e8d7b1dde7e52dc597cc48b54c2b3d9c59c5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bc6d6331bd8e27ebb082a3bee81b71953cc75e7eea0c80cb6aa3577b4f47a22b379683188a800321848aecffd6e5e6ead37fc1691593c717f9a5b189a03f671
|
7
|
+
data.tar.gz: 5e9b7f92503ba1d3ee96089d42fc20f0ab59203c80c6eca9c2e284df67dacf877356ef6a8bbadca8ac569250f9b965b290f5904bfd6885f9f1648e76c0a39dfc
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changes #
|
2
2
|
|
3
|
+
## Version 1.1.1 - 23-Oct-2022 ##
|
4
|
+
|
5
|
+
* Add support for Ruby 3.2.
|
6
|
+
* Add support for OpenSSL 3 (requires either Ruby 3.1+, or version 3.0.0+ of the
|
7
|
+
openssl gem).
|
8
|
+
|
9
|
+
|
3
10
|
## Version 1.1.0 - 24-May-2021 ##
|
4
11
|
|
5
12
|
* Add support for [format 3 .ppk files](https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ppk3.html)
|
data/Gemfile
CHANGED
@@ -12,6 +12,17 @@ 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
|
+
# The source version of ffi 1.15.5 is declared as compatible with Ruby >= 2.3.
|
19
|
+
# The binary version of 1.15.5 is declared as compatible with Ruby >= 2.4, so
|
20
|
+
# doesn't get used. The using the source version results in a segmentation
|
21
|
+
# fault during libffi initialization.
|
22
|
+
#
|
23
|
+
# Binaries of 15.5.0 to 15.5.4 are declared as compatible with Ruby >= 2.3,
|
24
|
+
# but don't get used with Bundler 2.3.23 and Ruby 2.3 on Windows.
|
25
|
+
#
|
26
|
+
# Limit to earlier compatible versions.
|
27
|
+
gem 'ffi', '< 1.15.0' if RUBY_VERSION < '2.4' && RUBY_PLATFORM =~ /mingw/
|
17
28
|
end
|
data/LICENSE
CHANGED
data/lib/putty/key/openssl.rb
CHANGED
@@ -25,10 +25,266 @@ module PuTTY
|
|
25
25
|
|
26
26
|
private_constant :SSH_CURVES
|
27
27
|
|
28
|
+
# OpenSSL version helper methods.
|
29
|
+
#
|
30
|
+
# @private
|
31
|
+
module Version
|
32
|
+
class << self
|
33
|
+
# Determines if the Ruby OpenSSL wrapper is using the OpenSSL library
|
34
|
+
# (not LibreSSL and not JRuby) and if the version matches the required
|
35
|
+
# version.
|
36
|
+
#
|
37
|
+
# @param major [Integer] The required major version. `nil` if any
|
38
|
+
# version of OpenSSL is sufficient.
|
39
|
+
# @param minor [Integer] The required minor version.
|
40
|
+
# @param fix [Integer] The required fix version.
|
41
|
+
# @param patch [Integer] The required patch version.
|
42
|
+
# @return [Boolean] `true` if the requirements are met, otherwise
|
43
|
+
# `false`.
|
44
|
+
def openssl?(major = nil, minor = 0, fix = 0, patch = 0)
|
45
|
+
return false if ::OpenSSL::OPENSSL_VERSION.include?('LibreSSL')
|
46
|
+
return false if ::OpenSSL::OPENSSL_VERSION.include?('JRuby')
|
47
|
+
return true unless major
|
48
|
+
required_version = major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10
|
49
|
+
::OpenSSL::OPENSSL_VERSION_NUMBER >= required_version
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
private_constant :Version
|
54
|
+
|
55
|
+
# Methods to build OpenSSL private keys from a {PPK}.
|
56
|
+
#
|
57
|
+
# @private
|
58
|
+
module PKeyBuilding
|
59
|
+
class << self
|
60
|
+
# Creates a new OpenSSL DSA private key for the given DSA {PPK}.
|
61
|
+
#
|
62
|
+
# @param ppk [PPK] A DSA {PPK}.
|
63
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
64
|
+
def ppk_to_dsa(ppk)
|
65
|
+
_, p, q, g, pub_key = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint, :mpint, :mpint)
|
66
|
+
priv_key = Util.ssh_unpack(ppk.private_blob, :mpint).first
|
67
|
+
dsa_from_params(p, q, g, pub_key, priv_key)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Creates a new OpenSSL RSA private key for the given RSA {PPK}.
|
71
|
+
#
|
72
|
+
# @param ppk [PPK] An RSA {PPK}.
|
73
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
74
|
+
def ppk_to_rsa(ppk)
|
75
|
+
_, e, n = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint)
|
76
|
+
d, p, q, iqmp = Util.ssh_unpack(ppk.private_blob, :mpint, :mpint, :mpint, :mpint)
|
77
|
+
dmp1 = d % (p - 1)
|
78
|
+
dmq1 = d % (q - 1)
|
79
|
+
rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Creates a new OpenSSL EC private key for the given EC {PPK}.
|
83
|
+
#
|
84
|
+
# @param ppk [PPK] An EC {PPK}.
|
85
|
+
# @param ppk_curve [String] The PPK curve name extracted from the
|
86
|
+
# PPK algorithm name.
|
87
|
+
# @return [::OpenSSL::PKey::EC] The OpenSSL EC private key.
|
88
|
+
def ppk_to_ec(ppk, ppk_curve)
|
89
|
+
curve = OPENSSL_CURVES[ppk_curve]
|
90
|
+
_, _, pub_key = Util.ssh_unpack(ppk.public_blob, :string, :string, :mpint)
|
91
|
+
priv_key = Util.ssh_unpack(ppk.private_blob, :mpint).first
|
92
|
+
ec_from_params(curve, pub_key, priv_key)
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
if Version.openssl?(3)
|
98
|
+
# OpenSSL v3 private keys are immutable. The Ruby OpenSSL wrapper
|
99
|
+
# doesn't provide a method to construct private keys using the
|
100
|
+
# parameters. Build DER (ASN.1) encoded versions of the keys.
|
101
|
+
#
|
102
|
+
# In theory this should be usable universally. However
|
103
|
+
# ::OpenSSL::PKey::EC::Point#to_octet_string is only supported from
|
104
|
+
# Ruby >= 2.4 and there are issues with JRuby's OpenSSL library
|
105
|
+
# (that doesn't make use of OpenSSL).
|
106
|
+
|
107
|
+
# :nocov_no_openssl3:
|
108
|
+
|
109
|
+
# Creates a new OpenSSL DSA private key with the given parameters.
|
110
|
+
#
|
111
|
+
# @param p [::OpenSSL::BN] The p parameter (prime).
|
112
|
+
# @param q [::OpenSSL::BN] The q parameter (prime).
|
113
|
+
# @param g [::OpenSSL::BN] The g parameter.
|
114
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
115
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
116
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
117
|
+
def dsa_from_params(p, q, g, pub_key, priv_key)
|
118
|
+
# https://www.openssl.org/docs/man3.0/man1/openssl-dsa.html (outform parameter).
|
119
|
+
sequence = [
|
120
|
+
::OpenSSL::ASN1::Integer.new(0),
|
121
|
+
::OpenSSL::ASN1::Integer.new(p),
|
122
|
+
::OpenSSL::ASN1::Integer.new(q),
|
123
|
+
::OpenSSL::ASN1::Integer.new(g),
|
124
|
+
::OpenSSL::ASN1::Integer.new(pub_key),
|
125
|
+
::OpenSSL::ASN1::Integer.new(priv_key)
|
126
|
+
]
|
127
|
+
|
128
|
+
::OpenSSL::PKey::DSA.new(::OpenSSL::ASN1::Sequence.new(sequence).to_der)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Creates a new OpenSSL RSA private key with the given parameters.
|
132
|
+
#
|
133
|
+
# @param e [::OpenSSL::BN] The public key exponent.
|
134
|
+
# @param n [::OpenSSL::BN] The modulus.
|
135
|
+
# @param d [::OpenSSL::BN] The private key exponent.
|
136
|
+
# @param p [::OpenSSL::BN] The p prime.
|
137
|
+
# @param q [::OpenSSL::BN] The q prime.
|
138
|
+
# @param iqmp [::OpenSSL::BN] The inverse of q, mod p.
|
139
|
+
# @param dmp1 [::OpenSSL::BN] `d` mod (`p` - 1).
|
140
|
+
# @param dmq1 [::OpenSSL::BN] `d` mod (`q` - 1).
|
141
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
142
|
+
def rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
143
|
+
# RFC 3447 Appendix A.1.2
|
144
|
+
sequence = [
|
145
|
+
::OpenSSL::ASN1::Integer.new(0),
|
146
|
+
::OpenSSL::ASN1::Integer.new(n),
|
147
|
+
::OpenSSL::ASN1::Integer.new(e),
|
148
|
+
::OpenSSL::ASN1::Integer.new(d),
|
149
|
+
::OpenSSL::ASN1::Integer.new(p),
|
150
|
+
::OpenSSL::ASN1::Integer.new(q),
|
151
|
+
::OpenSSL::ASN1::Integer.new(dmp1),
|
152
|
+
::OpenSSL::ASN1::Integer.new(dmq1),
|
153
|
+
::OpenSSL::ASN1::Integer.new(iqmp)
|
154
|
+
]
|
155
|
+
|
156
|
+
::OpenSSL::PKey::RSA.new(::OpenSSL::ASN1::Sequence.new(sequence).to_der)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Creates a new OpenSSL EC private key with the given parameters.
|
160
|
+
#
|
161
|
+
# @param curve [String] The name of the OpenSSL EC curve.
|
162
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
163
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
164
|
+
# @return [::OpenSSL::PKey::EC] The OpenSSL EC private key.
|
165
|
+
def ec_from_params(curve, pub_key, priv_key)
|
166
|
+
group = ::OpenSSL::PKey::EC::Group.new(curve)
|
167
|
+
point = ::OpenSSL::PKey::EC::Point.new(group, pub_key)
|
168
|
+
point_string = point.to_octet_string(:uncompressed)
|
169
|
+
|
170
|
+
# RFC 5915 Section 3
|
171
|
+
sequence = [
|
172
|
+
::OpenSSL::ASN1::Integer.new(1),
|
173
|
+
::OpenSSL::ASN1::OctetString.new(priv_key.to_s(2)),
|
174
|
+
::OpenSSL::ASN1::ObjectId.new(curve, 0, :EXPLICIT),
|
175
|
+
::OpenSSL::ASN1::BitString.new(point_string, 1, :EXPLICIT)
|
176
|
+
]
|
177
|
+
|
178
|
+
::OpenSSL::PKey::EC.new(::OpenSSL::ASN1::Sequence.new(sequence).to_der)
|
179
|
+
end
|
180
|
+
# :nocov_no_openssl3:
|
181
|
+
else
|
182
|
+
# :nocov_openssl3:
|
183
|
+
if ::OpenSSL::PKey::DSA.new.respond_to?(:set_key)
|
184
|
+
# :nocov_no_openssl_pkey_dsa_set_key:
|
185
|
+
|
186
|
+
# Creates a new OpenSSL DSA private key with the given parameters.
|
187
|
+
#
|
188
|
+
# @param p [::OpenSSL::BN] The p parameter.
|
189
|
+
# @param q [::OpenSSL::BN] The q parameter.
|
190
|
+
# @param g [::OpenSSL::BN] The g parameter.
|
191
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
192
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
193
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
194
|
+
def dsa_from_params(p, q, g, pub_key, priv_key)
|
195
|
+
::OpenSSL::PKey::DSA.new.tap do |pkey|
|
196
|
+
pkey.set_key(pub_key, priv_key)
|
197
|
+
pkey.set_pqg(p, q, g)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
# :nocov_no_openssl_pkey_dsa_set_key:
|
201
|
+
else
|
202
|
+
# :nocov_openssl_pkey_dsa_set_key:
|
203
|
+
# Creates a new OpenSSL DSA private key with the given parameters.
|
204
|
+
#
|
205
|
+
# @param p [::OpenSSL::BN] The p parameter.
|
206
|
+
# @param q [::OpenSSL::BN] The q parameter.
|
207
|
+
# @param g [::OpenSSL::BN] The g parameter.
|
208
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
209
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
210
|
+
# @return [::OpenSSL::PKey::DSA] The OpenSSL DSA private key.
|
211
|
+
def dsa_from_params(p, q, g, pub_key, priv_key)
|
212
|
+
::OpenSSL::PKey::DSA.new.tap do |pkey|
|
213
|
+
pkey.p, pkey.q, pkey.g, pkey.pub_key, pkey.priv_key = p, q, g, pub_key, priv_key
|
214
|
+
end
|
215
|
+
end
|
216
|
+
# :nocov_openssl_pkey_dsa_set_key:
|
217
|
+
end
|
218
|
+
|
219
|
+
if ::OpenSSL::PKey::RSA.new.respond_to?(:set_factors)
|
220
|
+
# :nocov_no_openssl_pkey_rsa_set_factors:
|
221
|
+
|
222
|
+
# Creates a new OpenSSL RSA private key with the given parameters.
|
223
|
+
#
|
224
|
+
# @param e [::OpenSSL::BN] The public key exponent.
|
225
|
+
# @param n [::OpenSSL::BN] The modulus.
|
226
|
+
# @param d [::OpenSSL::BN] The private key exponent.
|
227
|
+
# @param p [::OpenSSL::BN] The p prime.
|
228
|
+
# @param q [::OpenSSL::BN] The q prime.
|
229
|
+
# @param iqmp [::OpenSSL::BN] The inverse of q, mod p.
|
230
|
+
# @param dmp1 [::OpenSSL::BN] `d` mod (`p` - 1).
|
231
|
+
# @param dmq1 [::OpenSSL::BN] `d` mod (`q` - 1).
|
232
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
233
|
+
def rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
234
|
+
::OpenSSL::PKey::RSA.new.tap do |pkey|
|
235
|
+
pkey.set_factors(p, q)
|
236
|
+
pkey.set_key(n, e, d)
|
237
|
+
pkey.set_crt_params(dmp1, dmq1, iqmp)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
# :nocov_no_openssl_pkey_rsa_set_factors:
|
241
|
+
else
|
242
|
+
# :nocov_openssl_pkey_rsa_set_factors:
|
243
|
+
|
244
|
+
# Creates a new OpenSSL RSA private key with the given parameters.
|
245
|
+
#
|
246
|
+
# @param e [::OpenSSL::BN] The public key exponent.
|
247
|
+
# @param n [::OpenSSL::BN] The modulus.
|
248
|
+
# @param d [::OpenSSL::BN] The private key exponent.
|
249
|
+
# @param p [::OpenSSL::BN] The p prime.
|
250
|
+
# @param q [::OpenSSL::BN] The q prime.
|
251
|
+
# @param iqmp [::OpenSSL::BN] The inverse of q, mod p.
|
252
|
+
# @param dmp1 [::OpenSSL::BN] `d` mod (`p` - 1).
|
253
|
+
# @param dmq1 [::OpenSSL::BN] `d` mod (`q` - 1).
|
254
|
+
# @return [::OpenSSL::PKey::RSA] The OpenSSL RSA private key.
|
255
|
+
def rsa_from_params(e, n, d, p, q, iqmp, dmp1, dmq1)
|
256
|
+
::OpenSSL::PKey::RSA.new.tap do |pkey|
|
257
|
+
pkey.e, pkey.n, pkey.d, pkey.p, pkey.q, pkey.iqmp, pkey.dmp1, pkey.dmq1 = e, n, d, p, q, iqmp, dmp1, dmq1
|
258
|
+
end
|
259
|
+
end
|
260
|
+
# :nocov_openssl_pkey_rsa_set_factors:
|
261
|
+
end
|
262
|
+
|
263
|
+
# Creates a new OpenSSL EC private key with the given parameters.
|
264
|
+
#
|
265
|
+
# @param curve [String] The name of the OpenSSL EC curve.
|
266
|
+
# @param pub_key [::OpenSSL::BN] The public key.
|
267
|
+
# @param priv_key [::OpenSSL::BN] The private key.
|
268
|
+
# @return [::OpenSSL::PKey::EC] The OpenSSL EC private key.
|
269
|
+
def ec_from_params(curve, pub_key, priv_key)
|
270
|
+
# Old versions of jruby-openssl don't include an EC class (version 0.9.16).
|
271
|
+
ec_class = (::OpenSSL::PKey::EC rescue raise ArgumentError, "Unsupported algorithm: #{ppk.algorithm}")
|
272
|
+
|
273
|
+
ec_class.new(curve).tap do |pkey|
|
274
|
+
group = pkey.group || ::OpenSSL::PKey::EC::Group.new(curve)
|
275
|
+
pkey.public_key = ::OpenSSL::PKey::EC::Point.new(group, pub_key)
|
276
|
+
pkey.private_key = priv_key
|
277
|
+
end
|
278
|
+
end
|
279
|
+
# :nocov_openssl3:
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
private_constant :PKeyBuilding
|
284
|
+
|
28
285
|
# The {ClassMethods} module is used to extend `OpenSSL::PKey` when
|
29
286
|
# using the PuTTY::Key refinement or calling {PuTTY::Key.global_install}.
|
30
287
|
# This adds a `from_ppk` class method to `OpenSSL::PKey`.
|
31
|
-
#
|
32
288
|
module ClassMethods
|
33
289
|
# Creates a new `OpenSSL::PKey` from a PuTTY private key (instance of
|
34
290
|
# {PPK}).
|
@@ -50,53 +306,11 @@ module PuTTY
|
|
50
306
|
|
51
307
|
case ppk.algorithm
|
52
308
|
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
|
309
|
+
PKeyBuilding.ppk_to_dsa(ppk)
|
68
310
|
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
|
311
|
+
PKeyBuilding.ppk_to_rsa(ppk)
|
88
312
|
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
|
313
|
+
PKeyBuilding.ppk_to_ec(ppk, $1)
|
100
314
|
else
|
101
315
|
raise ArgumentError, "Unsupported algorithm: #{ppk.algorithm}"
|
102
316
|
end
|
@@ -201,13 +415,30 @@ module PuTTY
|
|
201
415
|
end
|
202
416
|
|
203
417
|
OpenSSL.const_get(:PKEY_CLASSES).each do |name, openssl_class|
|
418
|
+
mod = OpenSSL.const_get(name)
|
204
419
|
refine openssl_class do
|
205
|
-
|
420
|
+
if defined?(::Refinement) && kind_of?(::Refinement)
|
421
|
+
# :nocov_no_refinement_class:
|
422
|
+
import_methods(mod)
|
423
|
+
# :nocov_no_refinement_class:
|
424
|
+
else
|
425
|
+
# :nocov_refinement_class:
|
426
|
+
include mod
|
427
|
+
# :nocov_refinement_class:
|
428
|
+
end
|
206
429
|
end if respond_to?(:refine, true)
|
207
430
|
end
|
208
431
|
|
209
432
|
refine ::OpenSSL::PKey.singleton_class do
|
210
|
-
|
433
|
+
if defined?(::Refinement) && kind_of?(::Refinement)
|
434
|
+
# :nocov_no_refinement_class:
|
435
|
+
import_methods(OpenSSL::ClassMethods)
|
436
|
+
# :nocov_no_refinement_class:
|
437
|
+
else
|
438
|
+
# :nocov_refinement_class:
|
439
|
+
include OpenSSL::ClassMethods
|
440
|
+
# :nocov_refinement_class:
|
441
|
+
end
|
211
442
|
end if respond_to?(:refine, true)
|
212
443
|
end
|
213
444
|
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/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.1
|
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: 2022-10-23 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.1
|
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.1
|
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.3.7
|
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
|