1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

(#9241) Add SSL verification

Without this patch we were blindly trusting the remote end of our API
connection is who they claim to be.  This is an insecure state because
we leave ourselves open to a man in the middle attack.

This patch adds a vsphere_expected_pubkey_hash setting for the Vsphere
provider.  This setting is expected to be the SHA256 hex digest string
of the PEM encoded text of the RSA public key.

The first time an end user connects this string is displayed to them in
the error message.  They need simply copy and paste it into ~/.fog to
securely connect to the remote end.

For example:

   :vspherebadpw:
     :vsphere_server: vc01.acme.lan
     :vsphere_username: api_login
     :vsphere_password: badpassword
     :vsphere_expected_pubkey_hash: 431dd...
This commit is contained in:
Jeff McCune 2011-08-30 12:25:28 -07:00
parent 98637d39da
commit ec32398811
2 changed files with 40 additions and 8 deletions

View file

@ -7,6 +7,7 @@ module Fog
module Errors module Errors
class ServiceError < Fog::Errors::Error; end class ServiceError < Fog::Errors::Error; end
class SecurityError < ServiceError; end
end end
service(:compute, 'vsphere/compute') service(:compute, 'vsphere/compute')

View file

@ -1,10 +1,12 @@
require 'digest/sha2'
module Fog module Fog
module Compute module Compute
class Vsphere < Fog::Service class Vsphere < Fog::Service
requires :vsphere_username, :vsphere_password, :vsphere_server requires :vsphere_username, :vsphere_password, :vsphere_server
recognizes :vsphere_port, :vsphere_path, :vsphere_ns recognizes :vsphere_port, :vsphere_path, :vsphere_ns
recognizes :vsphere_rev, :vsphere_ssl recognizes :vsphere_rev, :vsphere_ssl, :vsphere_expected_pubkey_hash
class Mock class Mock
@ -16,6 +18,9 @@ module Fog
class Real class Real
attr_reader :vsphere_is_vcenter
attr_reader :vsphere_rev
def initialize(options={}) def initialize(options={})
require 'rbvmomi' require 'rbvmomi'
@vsphere_username = options[:vsphere_username] @vsphere_username = options[:vsphere_username]
@ -26,15 +31,31 @@ module Fog
@vsphere_ns = options[:vsphere_ns] || 'urn:vim25' @vsphere_ns = options[:vsphere_ns] || 'urn:vim25'
@vsphere_rev = options[:vsphere_rev] || '4.0' @vsphere_rev = options[:vsphere_rev] || '4.0'
@vsphere_ssl = options[:vsphere_ssl] || true @vsphere_ssl = options[:vsphere_ssl] || true
@vsphere_expected_pubkey_hash = options[:vsphere_expected_pubkey_hash]
@vsphere_must_reauthenticate = false @vsphere_must_reauthenticate = false
@connection = RbVmomi::VIM.new :host => @vsphere_server, @connection = nil
:port => @vsphere_port, # This is a state variable to allow digest validation of the SSL cert
:path => @vsphere_path, bad_cert = false
:ns => @vsphere_ns, loop do
:rev => @vsphere_rev, begin
:ssl => @vsphere_ssl, @connection = RbVmomi::VIM.new :host => @vsphere_server,
:insecure => true :port => @vsphere_port,
:path => @vsphere_path,
:ns => @vsphere_ns,
:rev => @vsphere_rev,
:ssl => @vsphere_ssl,
:insecure => bad_cert
break
rescue OpenSSL::SSL::SSLError
raise if bad_cert
bad_cert = true
end
end
if bad_cert then
validate_ssl_connection
end
# Negotiate the API revision # Negotiate the API revision
if not options[:vsphere_rev] if not options[:vsphere_rev]
@ -66,6 +87,16 @@ module Fog
end end
end end
# Verify a SSL certificate based on the hashed public key
def validate_ssl_connection
pubkey = @connection.http.peer_cert.public_key
pubkey_hash = Digest::SHA2.hexdigest(pubkey.to_s)
expected_pubkey_hash = @vsphere_expected_pubkey_hash
if pubkey_hash != expected_pubkey_hash then
raise Fog::Vsphere::Errors::SecurityError, "The remote system presented a public key with hash #{pubkey_hash} but we're expecting a hash of #{expected_pubkey_hash || '<unset>'}. If you are sure the remote system is authentic set vsphere_expected_pubkey_hash: <the hash printed in this message> in ~/.fog"
end
end
end end
end end