From 3295157f78615c091b02aee60a7069b3159f57b1 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Feb 2013 13:25:49 -0600 Subject: [PATCH] More support for various checks --- lib/rex/sslscan/result.rb | 80 +++++++---- spec/lib/rex/sslscan/result_spec.rb | 198 +++++++++++++++++++++++++--- 2 files changed, 236 insertions(+), 42 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index f54d50d3d4..d1755e251f 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -28,32 +28,20 @@ class Result @ciphers.reject{|cipher| cipher[:version] != :SSLv2 } end - def add_cipher(version, cipher, key_length, status) - unless @supported_versions.include? version - raise ArgumentError, "Must be a supported SSL Version" - end - unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include? cipher - raise ArgumentError, "Must be a valid SSL Cipher for #{version}!" - end - unless key_length.kind_of? Fixnum - raise ArgumentError, "Must supply a valid key length" - end - unless [:accepted, :rejected].include? status - raise ArgumentError, "status Must be either :accepted or :rejected" - end + def sslv3 + @ciphers.reject{|cipher| cipher[:version] != :SSLv3 } + end - strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version) - strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM" - - if strong_cipher_ctx.ciphers.flatten.include? cipher - weak = false - else - weak = true - end + def tlsv1 + @ciphers.reject{|cipher| cipher[:version] != :TLSv1 } + end - cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status} - @ciphers << cipher_details - @ciphers.uniq! + def weak_ciphers + @ciphers.reject{|cipher| cipher[:weak] == false } + end + + def strong_ciphers + @ciphers.reject{|cipher| cipher[:weak] } end def accepted(version = :all) @@ -67,7 +55,7 @@ class Result raise ArgumentError, "Invalid SSL Version Supplied: #{version}" end elsif version.kind_of? Array - version.reject!{|version| @supported_versions.include? version} + version.reject!{|v| !(@supported_versions.include? v)} if version.empty? return @ciphers.reject{|cipher| cipher[:status] == :rejected} else @@ -89,7 +77,7 @@ class Result raise ArgumentError, "Invalid SSL Version Supplied: #{version}" end elsif version.kind_of? Array - version.reject!{|version| @supported_versions.include? version} + version.reject!{|v| !(@supported_versions.include? v)} if version.empty? return @ciphers.reject{|cipher| cipher[:status] == :accepted} else @@ -127,5 +115,45 @@ class Result def supports_ssl? supports_sslv2? or supports_sslv3? or supports_tlsv1? end + + def supports_weak_ciphers? + !(weak_ciphers.empty?) + end + + def standards_compliant? + if supports_ssl? + return false if supports_sslv2? + return false if supports_weak_ciphers? + end + true + end + + def add_cipher(version, cipher, key_length, status) + unless @supported_versions.include? version + raise ArgumentError, "Must be a supported SSL Version" + end + unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include? cipher + raise ArgumentError, "Must be a valid SSL Cipher for #{version}!" + end + unless key_length.kind_of? Fixnum + raise ArgumentError, "Must supply a valid key length" + end + unless [:accepted, :rejected].include? status + raise ArgumentError, "status Must be either :accepted or :rejected" + end + + strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version) + strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM" + + if strong_cipher_ctx.ciphers.flatten.include? cipher + weak = false + else + weak = true + end + + cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status} + @ciphers << cipher_details + @ciphers.uniq! + end end end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 0d9ac8b553..4809e38c43 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -6,6 +6,19 @@ describe Rex::SSLScan::Result do it { should respond_to :cert } it { should respond_to :ciphers } + it { should respond_to :sslv2 } + it {should respond_to :sslv3 } + it {should respond_to :tlsv1 } + it {should respond_to :accepted } + it {should respond_to :rejected } + it {should respond_to :weak_ciphers } + it {should respond_to :strong_ciphers } + it {should respond_to :supports_sslv2? } + it {should respond_to :supports_sslv3? } + it {should respond_to :supports_tlsv1? } + it {should respond_to :supports_ssl? } + it {should respond_to :supports_weak_ciphers? } + it {should respond_to :standards_compliant? } context "with no values set" do it "should return nil for the cert" do @@ -23,6 +36,50 @@ describe Rex::SSLScan::Result do it "should return an empty array for rejected" do subject.rejected.should == [] end + + it "should return an empty array for #sslv2" do + subject.sslv2.should == [] + end + + it "should return an empty array for #sslv3" do + subject.sslv3.should == [] + end + + it "should return an empty array for #tlsv1" do + subject.sslv2.should == [] + end + + it "should return an empty array for #weak_ciphers" do + subject.weak_ciphers.should == [] + end + + it "should return an empty array for #strong_ciphers" do + subject.strong_ciphers.should == [] + end + + it "should return false for #supports_ssl?" do + subject.supports_ssl?.should == false + end + + it "should return false for #supports_ssl?v2" do + subject.supports_sslv2?.should == false + end + + it "should return false for #supports_sslv3?" do + subject.supports_sslv3?.should == false + end + + it "should return false for #supports_tlsv1?" do + subject.supports_tlsv1?.should == false + end + + it "should return false for #supports_weak_ciphers?" do + subject.supports_weak_ciphers?.should == false + end + + it "should return true for #standards_compliant?" do + subject.standards_compliant?.should == true + end end context "setting the cert" do @@ -194,18 +251,52 @@ describe Rex::SSLScan::Result do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) end - it "should return an array of cipher detail hashes" do - subject.each_accepted do |cipher_details| - cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + context "with no version selected" do + it "should return an array of cipher detail hashes" do + subject.each_accepted do |cipher_details| + cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + end + end + + it "should return all of the accepted cipher details" do + count = 0 + subject.each_accepted do |cipher_details| + count = count+1 + end + count.should == 4 end end - it "should return all of the accepted cipher details" do - count = 0 - subject.each_accepted do |cipher_details| - count = count+1 + context "when specifying one SSL version" do + it "should raise an exception if not given a symbol" do + expect{ subject.each_accepted('sslv2')}.to raise_error + end + + it "should raise an exception if given an invalid SSL version" do + expect{ subject.each_accepted(:TLSv3)}.to raise_error + end + + it "should return only ciphers matching the version" do + subject.each_accepted(:SSLv2) do |cipher_details| + cipher_details[:version].should == :SSLv2 + end + end + end + + context "when specifying multiple SSL Versions in an array" do + it "should return all versions if no valid versions were supplied" do + count = 0 + subject.each_accepted([:TLSv3, :TLSv4]) do |cipher_details| + count = count+1 + end + count.should == 4 + end + + it "should return only the ciphers for the specified version" do + subject.each_accepted([:SSLv3,:TLSv1]) do |cipher_details| + cipher_details[:version].should_not == :SSLv2 + end end - count.should == 4 end end @@ -217,18 +308,52 @@ describe Rex::SSLScan::Result do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) end - it "should return an array of cipher detail hashes" do - subject.each_rejected do |cipher_details| - cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + context "with no version selected" do + it "should return an array of cipher detail hashes" do + subject.each_rejected do |cipher_details| + cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + end + end + + it "should return all of the rejected cipher details" do + count = 0 + subject.each_rejected do |cipher_details| + count = count+1 + end + count.should == 4 end end - it "should return all of the rejected cipher details" do - count = 0 - subject.each_rejected do |cipher_details| - count = count+1 + context "when specifying one SSL version" do + it "should raise an exception if not given a symbol" do + expect{ subject.each_rejected('sslv2')}.to raise_error + end + + it "should raise an exception if given an invalid SSL version" do + expect{ subject.each_rejected(:TLSv3)}.to raise_error + end + + it "should return only ciphers matching the version" do + subject.each_rejected(:SSLv2) do |cipher_details| + cipher_details[:version].should == :SSLv2 + end + end + end + + context "when specifying multiple SSL Versions in an array" do + it "should return all versions if no valid versions were supplied" do + count = 0 + subject.each_rejected([:TLSv3, :TLSv4]) do |cipher_details| + count = count+1 + end + count.should == 4 + end + + it "should return only the ciphers for the specified version" do + subject.each_rejected([:SSLv3,:TLSv1]) do |cipher_details| + cipher_details[:version].should_not == :SSLv2 + end end - count.should == 4 end end @@ -271,4 +396,45 @@ describe Rex::SSLScan::Result do end end + context "checking for weak ciphers" do + context "when weak ciphers are supported" do + before(:each) do + subject.add_cipher(:SSLv2, "DES-CBC-MD5", 56, :accepted) + subject.add_cipher(:SSLv2, "EXP-RC2-CBC-MD5", 40, :accepted) + end + it "should return an array of weak ciphers from #weak_ciphers" do + weak = subject.weak_ciphers + weak.class.should == Array + weak.each do |cipher| + cipher[:weak].should == true + end + weak.count.should == 2 + end + + it "should return true from #supports_weak_ciphers" do + subject.supports_weak_ciphers?.should == true + end + end + + context "when no weak ciphers are supported" do + before(:each) do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + end + it "should return an empty array from #weak_ciphers" do + subject.weak_ciphers.should == [] + end + + it "should return false from #supports_weak_ciphers" do + subject.supports_weak_ciphers?.should == false + end + end + end + + context "checking for standards compliance" do + + end + end \ No newline at end of file