Skip to content

Commit

Permalink
Use different algorithms depending on the ssh version
Browse files Browse the repository at this point in the history
  • Loading branch information
artem-sidorenko committed Jan 24, 2017
1 parent b882cdd commit d9e6205
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ override['ssh-hardening']['ssh']['server']['listen_to'] = node['ipaddress']
* `['ssh-hardening']['ssh']['client']['remote_hosts']` - `[]` - one or more hosts, to which ssh-client can connect to.
* `['ssh-hardening']['ssh']['client']['password_authentication']` - `false`. Set to `true` if password authentication should be enabled.
* `['ssh-hardening']['ssh']['client']['roaming']` - `false`. Set to `true` if experimental client roaming should be enabled. This is known to cause potential issues with secrets being disclosed to malicious servers and defaults to being disabled.
* `['ssh-hardening']['ssh']['server']['host_key_files']` - `nil` to calculate best hostkey configuration based on server version, otherwise specify an array with file paths (e.g. `/etc/ssh/ssh_host_rsa_key`)
* `['ssh-hardening']['ssh']['server']['dh_min_prime_size']` - `2048` - Minimal acceptable prime length in bits in `/etc/ssh/moduli`. Primes below this number will get removed. (See [this](https://entropux.net/article/openssh-moduli/) for more information and background)
* `['ssh-hardening']['ssh']['server']['dh_build_primes']` - `false` - If own primes should be built. This rebuild happens only once and takes a lot of time (~ 1.5 - 2h on the modern hardware for 4096 length).
* `['ssh-hardening']['ssh']['server']['dh_build_primes_size']` - `4096` - Prime length which should be generated. This option is only valid if `dh_build_primes` is enabled.
Expand Down
2 changes: 1 addition & 1 deletion attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
default['ssh-hardening']['ssh']['server']['dh_min_prime_size'] = 2048
default['ssh-hardening']['ssh']['server']['dh_build_primes'] = false
default['ssh-hardening']['ssh']['server']['dh_build_primes_size'] = 4096
default['ssh-hardening']['ssh']['server']['host_key_files'] = ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key']
default['ssh-hardening']['ssh']['server']['host_key_files'] = nil
default['ssh-hardening']['ssh']['server']['client_alive_interval'] = 600 # 10min
default['ssh-hardening']['ssh']['server']['client_alive_count'] = 3 # ~> 3 x interval
default['ssh-hardening']['ssh']['server']['allow_root_with_key'] = false
Expand Down
15 changes: 15 additions & 0 deletions libraries/devsec_ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ class Ssh # rubocop:disable Metrics/ClassLength
5.3 => 'yes',
5.9 => 'sandbox'
}.freeze
# Hostkey algorithms
# In the current implementation they are server specific so we need own data hash for it
HOSTKEY_ALGORITHMS ||= {
5.3 => %w(rsa),
6.0 => %w(rsa ecdsa),
6.6 => %w(rsa ecdsa ed25519)
}.freeze

class << self
def get_server_privilege_separarion # rubocop:disable Style/AccessorMethodName
Expand All @@ -80,6 +87,14 @@ def get_server_privilege_separarion # rubocop:disable Style/AccessorMethodName
ret
end

def get_server_algorithms # rubocop:disable Style/AccessorMethodName
Chef::Log.debug('Called get_server_algorithms')
found_ssh_version = find_ssh_version(get_ssh_server_version, HOSTKEY_ALGORITHMS.keys)
ret = HOSTKEY_ALGORITHMS[found_ssh_version]
Chef::Log.debug("Using configuration for ssh version #{found_ssh_version}, value: #{ret}")
ret
end

def get_client_macs(enable_weak = false)
get_crypto_data(:macs, :client, enable_weak)
end
Expand Down
3 changes: 2 additions & 1 deletion recipes/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@
mac: node['ssh-hardening']['ssh']['server']['mac'] || DevSec::Ssh.get_server_macs(node['ssh-hardening']['ssh']['server']['weak_hmac']),
kex: node['ssh-hardening']['ssh']['server']['kex'] || DevSec::Ssh.get_server_kexs(node['ssh-hardening']['ssh']['server']['weak_kex']),
cipher: node['ssh-hardening']['ssh']['server']['cipher'] || DevSec::Ssh.get_server_ciphers(node['ssh-hardening']['ssh']['server']['cbc_required']),
use_priv_sep: node['ssh-hardening']['ssh']['use_privilege_separation'] || DevSec::Ssh.get_server_privilege_separarion
use_priv_sep: node['ssh-hardening']['ssh']['use_privilege_separation'] || DevSec::Ssh.get_server_privilege_separarion,
hostkeys: node['ssh-hardening']['ssh']['server']['host_key_files'] || DevSec::Ssh.get_server_algorithms.map { |alg| "/etc/ssh/ssh_host_#{alg}_key"}
)
notifies :restart, 'service[sshd]'
end
Expand Down
21 changes: 21 additions & 0 deletions spec/libraries/devsec_ssh_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,27 @@ def self.debug(*); end
end
end

describe 'get_server_algorithms' do
DevSec::Ssh::HOSTKEY_ALGORITHMS.each do |openssh_version, conf_data|
context "when openssh is >= #{openssh_version}" do
before :each do
# mock get_ssh_server_version. We test it somewhere else
expect(subject).to receive(:get_ssh_server_version) { openssh_version }
end

it "get the config value #{conf_data}" do
expect(subject.get_server_algorithms).to eq conf_data
end
end
end
context 'when openssh has a totaly unsupported version, e.g. 3.0' do
it 'should raise an exception' do
expect(subject).to receive(:get_ssh_server_version) { 3.0 }
expect { subject.get_server_algorithms }.to raise_exception(/Unsupported ssh version/)
end
end
end

# Here we test the public functions:
# get_[client|server]_[kexs|macs|ciphers]
# In order to cover all possible combinations, we need a complex nested loops:-\
Expand Down
2 changes: 1 addition & 1 deletion templates/default/opensshd.conf.erb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ListenAddress <%= ssh_ip %>
<% end %>

# List HostKeys here.
<% Array(@node['ssh-hardening']['ssh']['server']['host_key_files']).each do |host_key_file| %>
<% @hostkeys.each do |host_key_file| %>
HostKey <%= host_key_file %> # Req 20
<% end %>

Expand Down

0 comments on commit d9e6205

Please sign in to comment.