sshkey 1.8.0 → 1.9.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7c6a9c5ef164d05f4575e492f588a6e6aee6506e
4
- data.tar.gz: bc65fc61b32246e9a5fa1de721188923abad2fc9
3
+ metadata.gz: e557b4605e1f00d77de9e7b939f79a5ba9601cdf
4
+ data.tar.gz: 6764a84f581a544e0adea8958731eb01bd35a550
5
5
  SHA512:
6
- metadata.gz: dfb36e68eaf79b51f30b4655acbf3da004b64faea378148e12bc8fe5831fe68d89eb636119cd2212d5adbad9bbb7fbb303b25f5e8464e169b508569f01050874
7
- data.tar.gz: 458c373b8e718990b7667931d260dc02af65a7d463842135c5a7a9fef35a8fe43451bae4e67d5ea742425a2c10b8ab2c76f136176e0d1dfeed873e168d827ee7
6
+ metadata.gz: dd96a9bacc99265e0f211b40a4c0d4a860ed4f6e5ffb7197277f5fdf11800776f6dbf687288b4c2b4bf3829e02273b2dcaa7b5c8fec662fda8b695b6f5861c5c
7
+ data.tar.gz: 8d68590c6f42a5d3868eaa0c39a8880c8c2666c5f63ac9d53df9cee0cba7f7827a3f3f3343166adecdca88e05de7599b0c7c163327ca12f72f3f04f2a0e0b965
@@ -1,14 +1,13 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - 1.8.7
5
- - 1.9.2
6
4
  - 1.9.3
7
- - 2.0
8
- - 2.1
9
- - 2.2
5
+ - 2.0.0
6
+ - 2.1.9
7
+ - 2.2.6
8
+ - 2.3.3
9
+ - 2.4.0
10
10
  - ruby-head
11
- - ree
12
11
  - jruby
13
12
  - jruby-head
14
13
 
@@ -17,4 +16,5 @@ matrix:
17
16
  - rvm: ruby-head
18
17
  - rvm: jruby-head
19
18
 
20
- sudo: false
19
+ sudo: required
20
+ dist: trusty
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011-2014 James Miller
1
+ Copyright (c) 2011-2016 James Miller
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -6,7 +6,7 @@ Generate private and public SSH keys (RSA and DSA supported) using pure Ruby.
6
6
 
7
7
  ## Requirements
8
8
 
9
- Tested / supported on CRuby 1.8.7+ and JRuby.
9
+ Tested / supported on CRuby 1.9.3+ and JRuby.
10
10
 
11
11
  ## Installation
12
12
 
@@ -61,11 +61,11 @@ k.ssh_public_key
61
61
 
62
62
  #### Encryption
63
63
 
64
- If a passcode is set when a key is generated or by setting the `passcode` accessor, you can
64
+ If a passphrase is set when a key is generated or by setting the `passphrase` accessor, you can
65
65
  fetch the encrypted version of the private key.
66
66
 
67
67
  ```ruby
68
- k.passcode = "foo"
68
+ k.passphrase = "foo"
69
69
  # => "foo"
70
70
 
71
71
  k.encrypted_private_key
@@ -211,4 +211,4 @@ SSHKey.ssh_public_key_to_ssh2_public_key "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ
211
211
 
212
212
  ## Copyright
213
213
 
214
- Copyright (c) 2011-2015 James Miller
214
+ Copyright (c) 2011-2016 James Miller
@@ -7,7 +7,14 @@ require 'digest/sha1'
7
7
  require 'sshkey/exception'
8
8
 
9
9
  class SSHKey
10
- SSH_TYPES = {"rsa" => "ssh-rsa", "dsa" => "ssh-dss"}
10
+ SSH_TYPES = {
11
+ "ssh-rsa" => "rsa",
12
+ "ssh-dss" => "dsa",
13
+ "ssh-ed25519" => "ed25519",
14
+ "ecdsa-sha2-nistp256" => "ecdsa",
15
+ "ecdsa-sha2-nistp384" => "ecdsa",
16
+ "ecdsa-sha2-nistp521" => "ecdsa",
17
+ }
11
18
  SSH_CONVERSION = {"rsa" => ["e", "n"], "dsa" => ["p", "q", "g", "pub_key"]}
12
19
  SSH2_LINE_LENGTH = 70 # +1 (for line wrap '/' character) must be <= 72
13
20
 
@@ -50,7 +57,17 @@ class SSHKey
50
57
  #
51
58
  def valid_ssh_public_key?(ssh_public_key)
52
59
  ssh_type, encoded_key = parse_ssh_public_key(ssh_public_key)
53
- SSH_CONVERSION[SSH_TYPES.invert[ssh_type]].size == unpacked_byte_array(ssh_type, encoded_key).size
60
+ sections = unpacked_byte_array(ssh_type, encoded_key)
61
+ case ssh_type
62
+ when "ssh-rsa", "ssh-dss"
63
+ sections.size == SSH_CONVERSION[SSH_TYPES[ssh_type]].size
64
+ when "ssh-ed25519"
65
+ sections.size == 1 && sections[0].num_bytes == 32 # https://tools.ietf.org/id/draft-bjh21-ssh-ed25519-00.html#rfc.section.4
66
+ when "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521"
67
+ sections.size == 2 # https://tools.ietf.org/html/rfc5656#section-3.1
68
+ else
69
+ false
70
+ end
54
71
  rescue
55
72
  false
56
73
  end
@@ -124,7 +141,7 @@ class SSHKey
124
141
  private
125
142
 
126
143
  def unpacked_byte_array(ssh_type, encoded_key)
127
- prefix = [7].pack("N") + ssh_type
144
+ prefix = [ssh_type.length].pack("N") + ssh_type
128
145
  decoded = Base64.decode64(encoded_key)
129
146
 
130
147
  # Base64 decoding is too permissive, so we should validate if encoding is correct
@@ -158,7 +175,7 @@ class SSHKey
158
175
 
159
176
  parsed = public_key.split(" ")
160
177
  parsed.each_with_index do |el, index|
161
- return parsed[index..(index+1)] if SSH_TYPES.invert[el]
178
+ return parsed[index..(index+1)] if SSH_TYPES[el]
162
179
  end
163
180
  raise PublicKeyError, "cannot determine key type"
164
181
  end
@@ -231,7 +248,7 @@ class SSHKey
231
248
 
232
249
  # SSH public key
233
250
  def ssh_public_key
234
- [directives.join(",").strip, SSH_TYPES[type], Base64.encode64(ssh_public_key_conversion).gsub("\n", ""), comment].join(" ").strip
251
+ [directives.join(",").strip, SSH_TYPES.invert[type], Base64.encode64(ssh_public_key_conversion).gsub("\n", ""), comment].join(" ").strip
235
252
  end
236
253
 
237
254
  # SSH2 public key (RFC4716)
@@ -344,7 +361,7 @@ class SSHKey
344
361
  # For instance, the "ssh-rsa" string is encoded as the following byte array
345
362
  # [0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a']
346
363
  def ssh_public_key_conversion
347
- typestr = SSH_TYPES[type]
364
+ typestr = SSH_TYPES.invert[type]
348
365
  methods = SSH_CONVERSION[type]
349
366
  pubkey = key_object.public_key
350
367
  methods.inject([7].pack("N") + typestr) do |pubkeystr, m|
@@ -1,3 +1,3 @@
1
1
  class SSHKey
2
- VERSION = "1.8.0"
2
+ VERSION = "1.9.0"
3
3
  end
@@ -79,17 +79,28 @@ EOF
79
79
  SSH_PUBLIC_KEY2 = 'AAAAB3NzaC1yc2EAAAABIwAAAQEAxl6TpN7uFiY/JZ8qDnD7UrxDP+ABeh2PVg8Du1LEgXNk0+YWCeP5S6oHklqaWeDlbmAs1oHsBwCMAVpMa5tgONOLvz4JgwgkiqQEbKR8ofWJ+LADUElvqRVGmGiNEMLI6GJWeneL4sjmbb8d6U+M53c6iWG0si9XE5m7teBQSsCl0Tk3qMIkQGw5zpJeCXjZ8KpJhIJRYgexFkGgPlYRV+UYIhxpUW90t0Ra5i6JOFYwq98k5S/6SJIZQ/A9F4JNzwLw3eVxZj0yVHWxkGz1+TyELNY1kOyMxnZaqSfGzSQJTrnIXpdweVHuYh1LtOgedRQhCyiELeSMGwio1vRPKw=='
80
80
  SSH_PUBLIC_KEY3 = 'AAAAB3NzaC1kc3MAAACBALyVy5dwVwgL3CxXzsvo8DBh58qArQLBNIPW/f9pptmy7jD5QXzOw+12w0/z4lZ86ncoVutRMf44OABcX9ovhRl+luxB7jjpkVXy/p2ZaqPbeyTQUtdTmXa2y4n053Jd61VeMG+iLP7+viT+Ib96y9aVUYQfCrl5heBDUZ9cAFjdAAAAFQDFXnO7JJpFKwkeoor4GWGHtz0D2QAAAIEAqel0RUBO0MY5b3DZ69J/mRzUifN1O6twk4er2ph0JpryuUwZohLpcVZwqoGWmPQy/ZHmV1b3RtT9GWUa+HUqKdMhFVOx/iq1khVfLi83whjMMvXj3ecqd0yzGxGHnSsjVKefa2ywCLHrh4nlUVIaXI5gQpgMyVbMcromDe1WZzoAAACBAIwTRPAEcroqOzaebiVspFcmsXxDQ4wXQZQdho1ExW6FKS8s7/6pItmZYXTvJDwLXgq2/iK1fRRcKk2PJEaSuJR7WeNGsJKfWmQ2UbOhqA3wWLDazIZtcMKjFzD0hM4E8qgjHjMvKDE6WgT6SFP+tqx3nnh7pJWwsbGjSMQexpyR'
81
81
 
82
+ SSH_PUBLIC_KEY_ED25519 = 'AAAAC3NzaC1lZDI1NTE5AAAAIBrNsRCISAtKXV5OVxqV6unVcdis5Uh3oiC6B7CMB7HQ'
83
+ SSH_PUBLIC_KEY_ECDSA_256 = 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHJFDZ5qymZfIzoJcxYeu3C9HjJ08QAbqR28C2zSMLwcb3ZzWdRApnj6wEgRvizsBmr9zyPKb2u5Rp0vjJtQcZo='
84
+ SSH_PUBLIC_KEY_ECDSA_384 = 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBP+GtUCOR8aW7xTtpkbJS0qqNZ98PgbUNtTFhE+Oe+khgoFMX+o0JG5bckVuvtkRl8dr+63kUK0QPTtzP9O5yixB9CYnB8CgCgYo1FCXZuJIImf12wW5nWKglrCH4kV1Qg=='
85
+ SSH_PUBLIC_KEY_ECDSA_521 = 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACsunidnIZ77AjCHSDp/xknLGDW3M0Ia7nxLdImmp0XGbxtbwYm2ga5XUzV9dMO9wF9ICC3OuH6g9DtGOBNPru1PwFDjaPISGgm0vniEzWazLsvjJVLThOA3VyYLxmtjm0WfS+/DfxgWVS6oeCTnDjjoVVpwU/fDbUbYPPRZI84/hOGNA=='
86
+
82
87
  KEY1_MD5_FINGERPRINT = "2a:89:84:c9:29:05:d1:f8:49:79:1c:ba:73:99:eb:af"
83
88
  KEY2_MD5_FINGERPRINT = "3c:af:74:87:cc:cc:a1:12:05:1a:09:b7:7b:ce:ed:ce"
84
89
  KEY3_MD5_FINGERPRINT = "14:f6:6a:12:96:be:44:32:e6:3c:77:43:94:52:f5:7a"
90
+ ED25519_MD5_FINGERPRINT = "6f:1a:8a:c1:4f:13:5c:36:6e:3f:be:eb:49:3b:8e:3e"
91
+ ECDSA_256_MD5_FINGERPRINT = "d9:3a:7f:de:b2:65:04:ac:62:05:1a:1e:97:e9:2b:9d"
85
92
 
86
93
  KEY1_SHA1_FINGERPRINT = "e4:f9:79:f2:fe:d6:be:2d:ef:2e:c2:fa:aa:f8:b0:17:34:fe:0d:c0"
87
94
  KEY2_SHA1_FINGERPRINT = "9a:52:78:2b:6b:cb:39:b7:85:ed:90:8a:28:62:aa:b3:98:88:e6:07"
88
95
  KEY3_SHA1_FINGERPRINT = "15:68:c6:72:ac:18:d1:fc:ab:a2:b7:b5:8c:d1:fe:8f:b9:ae:a9:47"
96
+ ED25519_SHA1_FINGERPRINT = "57:41:7c:d0:e2:53:28:87:7e:87:53:d4:69:ef:ef:63:ec:c0:0e:5e"
97
+ ECDSA_256_SHA1_FINGERPRINT = "94:e8:92:2b:1b:ec:49:de:ff:85:ea:6e:10:d6:8d:87:7a:67:40:ee"
89
98
 
90
99
  KEY1_SHA256_FINGERPRINT = "js3llFehloxCfsVuDw5xu3NtS9AOAxcXY8WL6vkDIts="
91
100
  KEY2_SHA256_FINGERPRINT = "23f/6U/LdxIFx1CQFKHylw76n+LIHYoY4nRxKcFoos4="
92
101
  KEY3_SHA256_FINGERPRINT = "mPqEPQlOPGORrTJrU17sPax1jOqeutZja6MOsFIca+8="
102
+ ED25519_SHA256_FINGERPRINT = "gyzHUKl1eO8Bk1Cvn4joRgxRlXo1+1HJ3Vho/hAtKEg="
103
+ ECDSA_256_SHA256_FINGERPRINT = "ncy2crhoL44R58GCZPQ5chPRrjlQKKgu07FDNelDmdk="
93
104
 
94
105
  KEY1_RANDOMART = <<-EOF.rstrip
95
106
  +--[ RSA 2048]----+
@@ -311,17 +322,34 @@ EOF
311
322
  assert !SSHKey.valid_ssh_public_key?(invalid5)
312
323
  end
313
324
 
325
+ def test_ssh_public_key_validation_elliptic
326
+ assert SSHKey.valid_ssh_public_key?("ssh-ed25519 #{SSH_PUBLIC_KEY_ED25519} me@example.com")
327
+ assert SSHKey.valid_ssh_public_key?("ecdsa-sha2-nistp256 #{SSH_PUBLIC_KEY_ECDSA_256}")
328
+ assert SSHKey.valid_ssh_public_key?("ecdsa-sha2-nistp384 #{SSH_PUBLIC_KEY_ECDSA_384} me@example.com")
329
+ assert SSHKey.valid_ssh_public_key?(%Q{from="trusted.eng.cam.ac.uk",no-port-forwarding,no-pty ecdsa-sha2-nistp521 #{SSH_PUBLIC_KEY_ECDSA_521} me@example.com})
330
+
331
+ assert !SSHKey.valid_ssh_public_key?("ssh-ed25519 #{SSH_PUBLIC_KEY_ED25519}= me@example.com") # bad base64
332
+ assert !SSHKey.valid_ssh_public_key?("ssh-ed25519 #{SSH_PUBLIC_KEY_ECDSA_384} me@example.com") # mismatched key format
333
+ assert !SSHKey.valid_ssh_public_key?("ecdsa-sha2-nistp256 #{SSH_PUBLIC_KEY_ECDSA_384} me@example.com") # mismatched key format
334
+ assert !SSHKey.valid_ssh_public_key?("ssh-ed25519 asdf me@example.com") # gibberish key data
335
+ assert !SSHKey.valid_ssh_public_key?("ecdsa-sha2-nistp256 asdf me@example.com") # gibberish key data
336
+ end
337
+
314
338
  def test_ssh_public_key_validation_with_newlines
315
339
  expected1 = "ssh-rsa #{SSH_PUBLIC_KEY1}\n"
340
+ expected2 = "ssh-ed25519 #{SSH_PUBLIC_KEY_ED25519} me@example.com\n"
316
341
  invalid1 = "ssh-rsa #{SSH_PUBLIC_KEY1}\nme@example.com"
317
342
  invalid2 = "ssh-rsa #{SSH_PUBLIC_KEY1}\n me@example.com"
318
343
  invalid3 = "ssh-rsa #{SSH_PUBLIC_KEY1} \nme@example.com"
344
+ invalid4 = "ecdsa-sha2-nistp256 #{SSH_PUBLIC_KEY_ECDSA_256}\nme@example.com"
319
345
 
320
346
  assert SSHKey.valid_ssh_public_key?(expected1)
347
+ assert SSHKey.valid_ssh_public_key?(expected2)
321
348
 
322
349
  assert !SSHKey.valid_ssh_public_key?(invalid1)
323
350
  assert !SSHKey.valid_ssh_public_key?(invalid2)
324
351
  assert !SSHKey.valid_ssh_public_key?(invalid3)
352
+ assert !SSHKey.valid_ssh_public_key?(invalid4)
325
353
  end
326
354
 
327
355
  def test_ssh_public_key_bits
@@ -389,6 +417,8 @@ end
389
417
  assert_equal KEY2_MD5_FINGERPRINT, SSHKey.md5_fingerprint("ssh-rsa #{SSH_PUBLIC_KEY2} me@me.com")
390
418
  assert_equal KEY3_MD5_FINGERPRINT, SSHKey.md5_fingerprint(SSH_PRIVATE_KEY3)
391
419
  assert_equal KEY3_MD5_FINGERPRINT, SSHKey.md5_fingerprint("ssh-dss #{SSH_PUBLIC_KEY3}")
420
+ assert_equal ED25519_MD5_FINGERPRINT, SSHKey.md5_fingerprint("ssh-ed25519 #{SSH_PUBLIC_KEY_ED25519}")
421
+ assert_equal ECDSA_256_MD5_FINGERPRINT, SSHKey.md5_fingerprint("ecdsa-sha2-nistp256 #{SSH_PUBLIC_KEY_ECDSA_256} me@me.com")
392
422
 
393
423
  assert_equal KEY1_SHA1_FINGERPRINT, SSHKey.sha1_fingerprint(SSH_PRIVATE_KEY1)
394
424
  assert_equal KEY1_SHA1_FINGERPRINT, SSHKey.sha1_fingerprint("ssh-rsa #{SSH_PUBLIC_KEY1}")
@@ -396,6 +426,8 @@ end
396
426
  assert_equal KEY2_SHA1_FINGERPRINT, SSHKey.sha1_fingerprint("ssh-rsa #{SSH_PUBLIC_KEY2} me@me.com")
397
427
  assert_equal KEY3_SHA1_FINGERPRINT, SSHKey.sha1_fingerprint(SSH_PRIVATE_KEY3)
398
428
  assert_equal KEY3_SHA1_FINGERPRINT, SSHKey.sha1_fingerprint("ssh-dss #{SSH_PUBLIC_KEY3}")
429
+ assert_equal ED25519_SHA1_FINGERPRINT, SSHKey.sha1_fingerprint("ssh-ed25519 #{SSH_PUBLIC_KEY_ED25519}")
430
+ assert_equal ECDSA_256_SHA1_FINGERPRINT, SSHKey.sha1_fingerprint("ecdsa-sha2-nistp256 #{SSH_PUBLIC_KEY_ECDSA_256} me@me.com")
399
431
 
400
432
  assert_equal KEY1_SHA256_FINGERPRINT, SSHKey.sha256_fingerprint(SSH_PRIVATE_KEY1)
401
433
  assert_equal KEY1_SHA256_FINGERPRINT, SSHKey.sha256_fingerprint("ssh-rsa #{SSH_PUBLIC_KEY1}")
@@ -403,6 +435,8 @@ end
403
435
  assert_equal KEY2_SHA256_FINGERPRINT, SSHKey.sha256_fingerprint("ssh-rsa #{SSH_PUBLIC_KEY2} me@me.com")
404
436
  assert_equal KEY3_SHA256_FINGERPRINT, SSHKey.sha256_fingerprint(SSH_PRIVATE_KEY3)
405
437
  assert_equal KEY3_SHA256_FINGERPRINT, SSHKey.sha256_fingerprint("ssh-dss #{SSH_PUBLIC_KEY3}")
438
+ assert_equal ED25519_SHA256_FINGERPRINT, SSHKey.sha256_fingerprint("ssh-ed25519 #{SSH_PUBLIC_KEY_ED25519}")
439
+ assert_equal ECDSA_256_SHA256_FINGERPRINT, SSHKey.sha256_fingerprint("ecdsa-sha2-nistp256 #{SSH_PUBLIC_KEY_ECDSA_256} me@me.com")
406
440
  end
407
441
 
408
442
  def test_bits
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sshkey
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Miller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-01 00:00:00.000000000 Z
11
+ date: 2017-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  version: '0'
77
77
  requirements: []
78
78
  rubyforge_project: sshkey
79
- rubygems_version: 2.4.5.1
79
+ rubygems_version: 2.6.8
80
80
  signing_key:
81
81
  specification_version: 4
82
82
  summary: SSH private/public key generator in Ruby