net-ssh 7.3.3 → 7.3.4

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
  SHA256:
3
- metadata.gz: 0d9097275f7c3c0123783d9c29f8c4c4bfe3a3c8d68410357078e91859950f3f
4
- data.tar.gz: b5a1013faa8b1cfbe5645e849329c99b62db9d944894287747a12c33f5356d9a
3
+ metadata.gz: 266fc4529dfdc0019be7f3f24cad0a04fc227a9a928331fbe308fc9b6e61dd2d
4
+ data.tar.gz: b17aca117814cbe3076639b016f316b35ecbdd32e7f31b8ef1693cddb0292604
5
5
  SHA512:
6
- metadata.gz: 04ceefc617349311ddceebb606aa003dec8c6aa671363a13f939486d1bdfa5b55c49a56096651d8667f30f57ea109728e3cdae1f25545aa3c1c892b1db2948bf
7
- data.tar.gz: 3a9f23ad8a0843628f5dc500c83ceabca815756f925fbddc9725a12e0e19a9eeacf42f26f924b9c038edf8e95f832720c2297b0d0c8fdfcd6844f94d72f834b9
6
+ metadata.gz: a2dab75570a4fc5173a97b6622fc4420da55b56b93ab75e984017d57162b23b8d3cca677f8abddb24169e82ddd3c24984e193a1aa914a3e6f76e2088e67f3031
7
+ data.tar.gz: 76f38fb763930c2d88faaac257920c7c648d20e3fde474ac16cf2aad02b2cf4244cb0cdb52ae4467379491d3c8cf9e8ad3cc322af1902a49a90f5d3920fcea2f
checksums.yaml.gz.sig CHANGED
Binary file
data/.rubocop_todo.yml CHANGED
@@ -758,10 +758,12 @@ Style/OpenStructUse:
758
758
  Exclude:
759
759
  - 'test/authentication/test_ed25519.rb'
760
760
  - 'test/common.rb'
761
+ - 'test/test_known_hosts.rb'
761
762
  - 'test/transport/kex/test_curve25519_sha256.rb'
762
763
  - 'test/transport/kex/test_diffie_hellman_group1_sha1.rb'
763
764
  - 'test/transport/kex/test_ecdh_sha2_nistp256.rb'
764
765
  - 'test/verifiers/test_always.rb'
766
+ - 'test/verifiers/test_cert_authority_checks.rb'
765
767
 
766
768
  # Offense count: 16
767
769
  # Configuration parameters: AllowedMethods.
data/CHANGES.txt CHANGED
@@ -1,3 +1,7 @@
1
+ === 7.3.4
2
+
3
+ * Verify @cert-authority host certificate constraints — principals (shell-glob, matching OpenSSH), validity window, host type, and critical options — instead of trusting any CA-signed certificate for any host [#1010]
4
+
1
5
  === 7.3.3
2
6
 
3
7
  * Support .pub file as IdentityFile to filter/prioritize agent keys (1Password SSH agent use case) [#942]
@@ -61,6 +61,37 @@ module Net
61
61
  false
62
62
  end
63
63
  end
64
+
65
+ # Returns true if the certificate lists no principals (unrestricted) or
66
+ # if the given hostname matches a listed principal. Host-certificate
67
+ # principals are shell-glob patterns, matching OpenSSH, whose
68
+ # sshkey_cert_check_host passes wildcard_pattern=1 so principals like
69
+ # "*.example.com" are matched with match_pattern rather than strcmp.
70
+ def matches_principal?(server_key, hostname)
71
+ server_key.valid_principals.empty? ||
72
+ server_key.valid_principals.any? { |principal| File.fnmatch(principal, hostname) }
73
+ end
74
+
75
+ # Returns true if the certificate's validity window covers the current time.
76
+ def matches_validity?(server_key)
77
+ return false if server_key.valid_after && server_key.valid_after > Time.now
78
+ return false if server_key.valid_before && server_key.valid_before < Time.now
79
+
80
+ true
81
+ end
82
+
83
+ # Returns true if the certificate is a host certificate. A user
84
+ # certificate (type :user) must never authenticate a host.
85
+ def matches_type?(server_key)
86
+ server_key.type == :host
87
+ end
88
+
89
+ # Returns true if every critical option in the certificate is one we can
90
+ # enforce. net-ssh enforces none, so any critical option is unsupported
91
+ # and, as OpenSSH does, must cause the certificate to be rejected.
92
+ def critical_options_supported?(server_key)
93
+ server_key.critical_options.empty?
94
+ end
64
95
  end
65
96
  end
66
97
 
@@ -89,6 +120,17 @@ module Net
89
120
  def empty?
90
121
  @host_keys.empty?
91
122
  end
123
+
124
+ # Returns the bare hostname, stripping port and IP portions from the
125
+ # comma-separated host string used internally.
126
+ #
127
+ # Examples:
128
+ # "server.example.com" => "server.example.com"
129
+ # "server.example.com,1.2.3.4" => "server.example.com"
130
+ # "[server.example.com]:2222" => "server.example.com"
131
+ def hostname
132
+ @host.split(",").first.gsub(/\[|\]:\d+/, "")
133
+ end
92
134
  end
93
135
 
94
136
  # Searches an OpenSSH-style known-host file for a given host, and returns all
@@ -19,10 +19,8 @@ module Net
19
19
  # We've never seen this host before, so raise an exception.
20
20
  process_cache_miss(host_keys, arguments, HostKeyUnknown, "is unknown") if host_keys.empty?
21
21
 
22
- # If we found any matches, check to see that the key type and
23
- # blob also match.
24
-
25
- found = host_keys.any? do |key|
22
+ # Find the known-hosts entry whose key matches the presented certificate.
23
+ found_key = host_keys.find do |key|
26
24
  if key.respond_to?(:matches_key?)
27
25
  key.matches_key?(arguments[:key])
28
26
  else
@@ -30,11 +28,17 @@ module Net
30
28
  end
31
29
  end
32
30
 
33
- # If a match was found, return true. Otherwise, raise an exception
34
- # indicating that the key was not recognized.
35
- process_cache_miss(host_keys, arguments, HostKeyMismatch, "does not match") unless found
31
+ # No matching entry found — key is not recognized.
32
+ process_cache_miss(host_keys, arguments, HostKeyMismatch, "does not match") unless found_key
33
+
34
+ # For @cert-authority entries, enforce the certificate constraints
35
+ # OpenSSH checks in sshkey_cert_check_authority. A certificate signed by
36
+ # the trusted CA but failing any of these is rejected with
37
+ # HostKeyMismatch (not HostKeyUnknown) so AcceptNew does not swallow the
38
+ # failure and remember the rejected certificate.
39
+ verify_certificate!(found_key, host_keys, arguments)
36
40
 
37
- found
41
+ true
38
42
  end
39
43
 
40
44
  def verify_signature(&block)
@@ -43,6 +47,37 @@ module Net
43
47
 
44
48
  private
45
49
 
50
+ # Enforces the @cert-authority certificate constraints for entries that
51
+ # implement them (Net::SSH::HostKeyEntries::CertAuthority). Non-certificate
52
+ # entries do not respond to these predicates and are left untouched.
53
+ def verify_certificate!(entry, host_keys, arguments)
54
+ cert = arguments[:key]
55
+
56
+ if entry.respond_to?(:matches_validity?) && !entry.matches_validity?(cert)
57
+ reason = if cert.valid_before && cert.valid_before < Time.now
58
+ "Certificate has expired"
59
+ else
60
+ "Certificate is not yet valid"
61
+ end
62
+ process_cache_miss(host_keys, arguments, HostKeyMismatch, reason)
63
+ end
64
+
65
+ if entry.respond_to?(:matches_principal?) && !entry.matches_principal?(cert, host_keys.hostname)
66
+ process_cache_miss(host_keys, arguments, HostKeyMismatch,
67
+ "Certificate invalid: name is not a listed principal")
68
+ end
69
+
70
+ if entry.respond_to?(:matches_type?) && !entry.matches_type?(cert)
71
+ process_cache_miss(host_keys, arguments, HostKeyMismatch,
72
+ "Certificate invalid: not a host certificate")
73
+ end
74
+
75
+ return unless entry.respond_to?(:critical_options_supported?) && !entry.critical_options_supported?(cert)
76
+
77
+ process_cache_miss(host_keys, arguments, HostKeyMismatch,
78
+ "Certificate invalid: unsupported critical option")
79
+ end
80
+
46
81
  def process_cache_miss(host_keys, args, exc_class, message)
47
82
  exception = exc_class.new("fingerprint #{args[:fingerprint]} " +
48
83
  "#{message} for #{host_keys.host.inspect}")
@@ -52,7 +52,7 @@ module Net
52
52
  MINOR = 3
53
53
 
54
54
  # The tiny component of this version of the Net::SSH library
55
- TINY = 3
55
+ TINY = 4
56
56
 
57
57
  # The prerelease component of this version of the Net::SSH library
58
58
  # nil allowed
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.3.3
4
+ version: 7.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamis Buck
@@ -32,7 +32,7 @@ cert_chain:
32
32
  ufHf4AX2UIkJbh7zCPkiNCqIr7MSWLNFG/9lOlHYsEJM8XujT1ofPobYx6YSFx/C
33
33
  7HBrI7UX7awt6UvBZebhcHzyMHxg/B5PVQllPA==
34
34
  -----END CERTIFICATE-----
35
- date: 2026-06-27 00:00:00.000000000 Z
35
+ date: 2026-10-04 00:00:00.000000000 Z
36
36
  dependencies:
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: bcrypt_pbkdf
metadata.gz.sig CHANGED
Binary file