This creates a new config option - ssl_cipher - that can be used to set the Cipher used by the SSL system and so also the AES+RSA security plugin which now technically should also be renamed to something else, but that's probably a bad idea.
Valid ciphers are checked against OpenSSL::Cipher.ciphers Signed-off-by: R.I.Pienaar <[email protected]> --- Local-branch: feature/master/7191 lib/mcollective/config.rb | 6 ++- lib/mcollective/ssl.rb | 14 ++++++-- spec/unit/ssl_spec.rb | 45 +++++++++++++++++++++++++++++- website/changelog.md | 1 + website/reference/basic/configuration.md | 1 + 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/lib/mcollective/config.rb b/lib/mcollective/config.rb index ea84166..8574472 100644 --- a/lib/mcollective/config.rb +++ b/lib/mcollective/config.rb @@ -8,7 +8,7 @@ module MCollective :securityprovider, :factsource, :registration, :registerinterval, :topicsep, :classesfile, :rpcauditprovider, :rpcaudit, :configdir, :rpcauthprovider, :rpcauthorization, :color, :configfile, :rpchelptemplate, :rpclimitmethod, - :logger_type, :fact_cache_time, :collectives, :main_collective + :logger_type, :fact_cache_time, :collectives, :main_collective, :ssl_cipher def initialize @configured = false @@ -89,7 +89,8 @@ module MCollective @logger_type = val when "fact_cache_time" @fact_cache_time = val.to_i - + when "ssl_cipher" + @ssl_cipher = val else raise("Unknown config parameter #{key}") end @@ -143,6 +144,7 @@ module MCollective @loglevel = "info" @collectives = ["mcollective"] @main_collective = @collectives.first + @ssl_cipher = "aes-256-cbc" end def read_plugin_config_dir(dir) diff --git a/lib/mcollective/ssl.rb b/lib/mcollective/ssl.rb index 3f31392..bb22871 100644 --- a/lib/mcollective/ssl.rb +++ b/lib/mcollective/ssl.rb @@ -31,14 +31,20 @@ module MCollective # There are matching methods for using a public key to encrypt # data to be decrypted using a private key class SSL - attr_reader :public_key_file, :private_key_file + attr_reader :public_key_file, :private_key_file, :ssl_cipher - def initialize(pubkey=nil, privkey=nil, passphrase=nil) + def initialize(pubkey=nil, privkey=nil, passphrase=nil, cipher=nil) @public_key_file = pubkey @private_key_file = privkey @public_key = read_key(:public, pubkey) @private_key = read_key(:private, privkey, passphrase) + + @ssl_cipher = "aes-256-cbc" + @ssl_cipher = Config.instance.ssl_cipher if Config.instance.ssl_cipher + @ssl_cipher = cipher if cipher + + raise "The supplied cipher '#{@ssl_cipher}' is not supported" unless OpenSSL::Cipher.ciphers.include?(@ssl_cipher) end # Encrypts supplied data using AES and then encrypts using RSA @@ -135,7 +141,7 @@ module MCollective # encrypts a string, returns a hash of key, iv and data def aes_encrypt(plain_string) - cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc') + cipher = OpenSSL::Cipher::Cipher.new(ssl_cipher) cipher.encrypt key = cipher.random_key @@ -149,7 +155,7 @@ module MCollective # decrypts a string given key, iv and data def aes_decrypt(key, crypt_string) - cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc') + cipher = OpenSSL::Cipher::Cipher.new(ssl_cipher) cipher.decrypt cipher.key = key diff --git a/spec/unit/ssl_spec.rb b/spec/unit/ssl_spec.rb index 8b7b38e..cc1c6e5 100644 --- a/spec/unit/ssl_spec.rb +++ b/spec/unit/ssl_spec.rb @@ -44,6 +44,37 @@ module MCollective @ssl.decrypt_with_public(@ssl.encrypt_with_private("foo", false), false).should == "foo" end + describe "#initialize" do + it "should default to aes-256-cbc" do + @ssl.ssl_cipher.should == "aes-256-cbc" + end + + it "should take the configured value when present" do + Config.any_instance.stubs("ssl_cipher").returns("aes-128-cbc") + @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem") + + @ssl.ssl_cipher.should == "aes-128-cbc" + end + + it "should set the supplied ssl cipher" do + @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "aes-128-cbc") + @ssl.ssl_cipher.should == "aes-128-cbc" + end + + it "should prefer the supplied key size over configured key size" do + Config.any_instance.stubs("aes_key_size").returns("foo-foo-foo") + @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "aes-128-cbc") + + @ssl.ssl_cipher.should == "aes-128-cbc" + end + + it "should fail on invalid key sizes" do + expect { + @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "foo-foo-foo") + }.to raise_error("The supplied cipher 'foo-foo-foo' is not supported") + end + end + describe "#read_key" do it "should fail on non exiting files" do expect { @@ -94,12 +125,24 @@ module MCollective end describe "#aes_decrypt" do - it "should decrypted correctly given key and data" do + it "should decrypt correctly given key and data" do key = @ssl.base64_decode("rAaCyW6qB0XqZNa9hji0qHwrI3P47t8diLNXoemW9ss=") data = @ssl.base64_decode("mSthvO/wSl0ArNOcgysTVw==") @ssl.aes_decrypt(key, data).should == "foo" end + + it "should decrypt correctly given key, data and key size" do + key = @ssl.base64_decode("VEma3a/R7fjw2M4d0NIctA==") + data = @ssl.base64_decode("FkH6qLvKTn7a+uNPe8ciHA==") + + # the default aes-256-cbc should fail here, the key above is 128 bit + expect { @ssl.aes_decrypt(key, data) }.to raise_error(/key length too short: no start line/) + + # new ssl instance configured for aes-128-cbc, should work + @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "aes-128-cbc") + @ssl.aes_decrypt(key, data).should == "foo" + end end describe "#decrypt_with_public" do diff --git a/website/changelog.md b/website/changelog.md index 365cde7..fb48042 100644 --- a/website/changelog.md +++ b/website/changelog.md @@ -11,6 +11,7 @@ title: Changelog |Date|Description|Ticket| |----|-----------|------| +|2011/04/20|Make the SSL Cipher used a config option|7191| |2011/04/20|Add a clear method to the PluginManager that deletes all plugins, improve test isolation|7176| |2011/04/19|Abstract the creation of request and reply hashes to simplify connector plugin development|5701| |2011/04/15|Improve the shellsafe validator and add a Util method to do shell escaping|7066| diff --git a/website/reference/basic/configuration.md b/website/reference/basic/configuration.md index 1598a27..37f7307 100644 --- a/website/reference/basic/configuration.md +++ b/website/reference/basic/configuration.md @@ -42,6 +42,7 @@ Configuration is a simple *key = val* style configuration file. |securityprovider|Psk|Which security model to use, see [SSL Security Plugin][SSLSecurity] and [AES Security Plugin][AESSecurity] for details on others| |rpchelptemplate|/etc/mcollective/rpc-help.erb|The path to the erb template used for generating help| |loggertype|file|Valid logger types, currently file, syslog or console| +|ssl_cipher|aes-256-cbc|This sets the cipher in use by the SSL code, see _man enc_ for a list supported by OpenSSL| ## Server Configuration The server configuration file should be root only readable -- 1.7.1 -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
