ssl_scan 0.0.1
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 +7 -0
 - data/.gitignore +17 -0
 - data/Gemfile +4 -0
 - data/LICENSE.txt +22 -0
 - data/README.md +51 -0
 - data/Rakefile +1 -0
 - data/bin/ssl_scan +4 -0
 - data/lib/ssl_scan/client.rb +0 -0
 - data/lib/ssl_scan/compat.rb +388 -0
 - data/lib/ssl_scan/exceptions.rb +274 -0
 - data/lib/ssl_scan/io/bidirectional_pipe.rb +161 -0
 - data/lib/ssl_scan/io/datagram_abstraction.rb +35 -0
 - data/lib/ssl_scan/io/ring_buffer.rb +369 -0
 - data/lib/ssl_scan/io/stream.rb +312 -0
 - data/lib/ssl_scan/io/stream_abstraction.rb +209 -0
 - data/lib/ssl_scan/io/stream_server.rb +221 -0
 - data/lib/ssl_scan/result.rb +165 -0
 - data/lib/ssl_scan/scanner.rb +241 -0
 - data/lib/ssl_scan/socket/comm/local.rb +526 -0
 - data/lib/ssl_scan/socket/comm.rb +120 -0
 - data/lib/ssl_scan/socket/ip.rb +131 -0
 - data/lib/ssl_scan/socket/parameters.rb +363 -0
 - data/lib/ssl_scan/socket/range_walker.rb +470 -0
 - data/lib/ssl_scan/socket/ssl_tcp.rb +345 -0
 - data/lib/ssl_scan/socket/ssl_tcp_server.rb +188 -0
 - data/lib/ssl_scan/socket/subnet_walker.rb +76 -0
 - data/lib/ssl_scan/socket/switch_board.rb +289 -0
 - data/lib/ssl_scan/socket/tcp.rb +79 -0
 - data/lib/ssl_scan/socket/tcp_server.rb +67 -0
 - data/lib/ssl_scan/socket/udp.rb +165 -0
 - data/lib/ssl_scan/socket.rb +773 -0
 - data/lib/ssl_scan/sync/thread_safe.rb +83 -0
 - data/lib/ssl_scan/version.rb +9 -0
 - data/lib/ssl_scan.rb +11 -0
 - data/sslscan.gemspec +23 -0
 - metadata +107 -0
 
| 
         @@ -0,0 +1,209 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding: binary -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'fcntl'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Rex
         
     | 
| 
      
 7 
     | 
    
         
            +
            module IO
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ###
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            # This class provides an abstraction to a stream based
         
     | 
| 
      
 12 
     | 
    
         
            +
            # connection through the use of a streaming socketpair.
         
     | 
| 
      
 13 
     | 
    
         
            +
            #
         
     | 
| 
      
 14 
     | 
    
         
            +
            ###
         
     | 
| 
      
 15 
     | 
    
         
            +
            module StreamAbstraction
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              ###
         
     | 
| 
      
 18 
     | 
    
         
            +
              #
         
     | 
| 
      
 19 
     | 
    
         
            +
              # Extension information for required Stream interface.
         
     | 
| 
      
 20 
     | 
    
         
            +
              #
         
     | 
| 
      
 21 
     | 
    
         
            +
              ###
         
     | 
| 
      
 22 
     | 
    
         
            +
              module Ext
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                #
         
     | 
| 
      
 25 
     | 
    
         
            +
                # Initializes peer information.
         
     | 
| 
      
 26 
     | 
    
         
            +
                #
         
     | 
| 
      
 27 
     | 
    
         
            +
                def initinfo(peer,local)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @peer = peer
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @local = local
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                #
         
     | 
| 
      
 33 
     | 
    
         
            +
                # Symbolic peer information.
         
     | 
| 
      
 34 
     | 
    
         
            +
                #
         
     | 
| 
      
 35 
     | 
    
         
            +
                def peerinfo
         
     | 
| 
      
 36 
     | 
    
         
            +
                  (@peer || "Remote Pipe")
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                #
         
     | 
| 
      
 40 
     | 
    
         
            +
                # Symbolic local information.
         
     | 
| 
      
 41 
     | 
    
         
            +
                #
         
     | 
| 
      
 42 
     | 
    
         
            +
                def localinfo
         
     | 
| 
      
 43 
     | 
    
         
            +
                  (@local || "Local Pipe")
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              #
         
     | 
| 
      
 48 
     | 
    
         
            +
              # This method creates a streaming socket pair and initializes it.
         
     | 
| 
      
 49 
     | 
    
         
            +
              #
         
     | 
| 
      
 50 
     | 
    
         
            +
              def initialize_abstraction
         
     | 
| 
      
 51 
     | 
    
         
            +
                self.lsock, self.rsock = Rex::Socket.tcp_socket_pair()
         
     | 
| 
      
 52 
     | 
    
         
            +
                self.lsock.extend(Rex::IO::Stream)
         
     | 
| 
      
 53 
     | 
    
         
            +
                self.lsock.extend(Ext)
         
     | 
| 
      
 54 
     | 
    
         
            +
                self.rsock.extend(Rex::IO::Stream)
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                self.monitor_rsock
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              #
         
     | 
| 
      
 60 
     | 
    
         
            +
              # This method cleans up the abstraction layer.
         
     | 
| 
      
 61 
     | 
    
         
            +
              #
         
     | 
| 
      
 62 
     | 
    
         
            +
              def cleanup_abstraction
         
     | 
| 
      
 63 
     | 
    
         
            +
                self.lsock.close if (self.lsock)
         
     | 
| 
      
 64 
     | 
    
         
            +
                self.rsock.close if (self.rsock)
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                self.lsock = nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                self.rsock = nil
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
              #
         
     | 
| 
      
 71 
     | 
    
         
            +
              # Low-level write to the local side.
         
     | 
| 
      
 72 
     | 
    
         
            +
              #
         
     | 
| 
      
 73 
     | 
    
         
            +
              def syswrite(buffer)
         
     | 
| 
      
 74 
     | 
    
         
            +
                lsock.syswrite(buffer)
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              #
         
     | 
| 
      
 78 
     | 
    
         
            +
              # Low-level read from the local side.
         
     | 
| 
      
 79 
     | 
    
         
            +
              #
         
     | 
| 
      
 80 
     | 
    
         
            +
              def sysread(length)
         
     | 
| 
      
 81 
     | 
    
         
            +
                lsock.sysread(length)
         
     | 
| 
      
 82 
     | 
    
         
            +
              end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
              #
         
     | 
| 
      
 85 
     | 
    
         
            +
              # Shuts down the local side of the stream abstraction.
         
     | 
| 
      
 86 
     | 
    
         
            +
              #
         
     | 
| 
      
 87 
     | 
    
         
            +
              def shutdown(how)
         
     | 
| 
      
 88 
     | 
    
         
            +
                lsock.shutdown(how)
         
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
              #
         
     | 
| 
      
 92 
     | 
    
         
            +
              # Closes both sides of the stream abstraction.
         
     | 
| 
      
 93 
     | 
    
         
            +
              #
         
     | 
| 
      
 94 
     | 
    
         
            +
              def close
         
     | 
| 
      
 95 
     | 
    
         
            +
                cleanup_abstraction
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
              #
         
     | 
| 
      
 99 
     | 
    
         
            +
              # Symbolic peer information.
         
     | 
| 
      
 100 
     | 
    
         
            +
              #
         
     | 
| 
      
 101 
     | 
    
         
            +
              def peerinfo
         
     | 
| 
      
 102 
     | 
    
         
            +
                "Remote-side of Pipe"
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
              #
         
     | 
| 
      
 106 
     | 
    
         
            +
              # Symbolic local information.
         
     | 
| 
      
 107 
     | 
    
         
            +
              #
         
     | 
| 
      
 108 
     | 
    
         
            +
              def localinfo
         
     | 
| 
      
 109 
     | 
    
         
            +
                "Local-side of Pipe"
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
              #
         
     | 
| 
      
 113 
     | 
    
         
            +
              # The left side of the stream.
         
     | 
| 
      
 114 
     | 
    
         
            +
              #
         
     | 
| 
      
 115 
     | 
    
         
            +
              attr_reader :lsock
         
     | 
| 
      
 116 
     | 
    
         
            +
              #
         
     | 
| 
      
 117 
     | 
    
         
            +
              # The right side of the stream.
         
     | 
| 
      
 118 
     | 
    
         
            +
              #
         
     | 
| 
      
 119 
     | 
    
         
            +
              attr_reader :rsock
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            protected
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
              def monitor_rsock
         
     | 
| 
      
 124 
     | 
    
         
            +
                self.monitor_thread = Rex::ThreadFactory.spawn("StreamMonitorRemote", false) {
         
     | 
| 
      
 125 
     | 
    
         
            +
                  loop do
         
     | 
| 
      
 126 
     | 
    
         
            +
                    closed = false
         
     | 
| 
      
 127 
     | 
    
         
            +
                    buf    = nil
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                    if not self.rsock
         
     | 
| 
      
 130 
     | 
    
         
            +
                      wlog("monitor_rsock: the remote socket is nil, exiting loop")
         
     | 
| 
      
 131 
     | 
    
         
            +
                      break
         
     | 
| 
      
 132 
     | 
    
         
            +
                    end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 135 
     | 
    
         
            +
                      s = Rex::ThreadSafe.select( [ self.rsock ], nil, nil, 0.2 )
         
     | 
| 
      
 136 
     | 
    
         
            +
                      if( s == nil || s[0] == nil )
         
     | 
| 
      
 137 
     | 
    
         
            +
                        next
         
     | 
| 
      
 138 
     | 
    
         
            +
                      end
         
     | 
| 
      
 139 
     | 
    
         
            +
                    rescue Exception => e
         
     | 
| 
      
 140 
     | 
    
         
            +
                      wlog("monitor_rsock: exception during select: #{e.class} #{e}")
         
     | 
| 
      
 141 
     | 
    
         
            +
                      closed = true
         
     | 
| 
      
 142 
     | 
    
         
            +
                    end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                    if( closed == false )
         
     | 
| 
      
 145 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 146 
     | 
    
         
            +
                        buf = self.rsock.sysread( 32768 )
         
     | 
| 
      
 147 
     | 
    
         
            +
                        if buf == nil
         
     | 
| 
      
 148 
     | 
    
         
            +
                          closed = true
         
     | 
| 
      
 149 
     | 
    
         
            +
                          wlog("monitor_rsock: closed remote socket due to nil read")
         
     | 
| 
      
 150 
     | 
    
         
            +
                        end
         
     | 
| 
      
 151 
     | 
    
         
            +
                      rescue EOFError => e
         
     | 
| 
      
 152 
     | 
    
         
            +
                        closed = true
         
     | 
| 
      
 153 
     | 
    
         
            +
                        dlog("monitor_rsock: EOF in rsock")
         
     | 
| 
      
 154 
     | 
    
         
            +
                      rescue ::Exception => e
         
     | 
| 
      
 155 
     | 
    
         
            +
                        closed = true
         
     | 
| 
      
 156 
     | 
    
         
            +
                        wlog("monitor_rsock: exception during read: #{e.class} #{e}")
         
     | 
| 
      
 157 
     | 
    
         
            +
                      end
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                    if( closed == false )
         
     | 
| 
      
 161 
     | 
    
         
            +
                      total_sent   = 0
         
     | 
| 
      
 162 
     | 
    
         
            +
                      total_length = buf.length
         
     | 
| 
      
 163 
     | 
    
         
            +
                      while( total_sent < total_length )
         
     | 
| 
      
 164 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 165 
     | 
    
         
            +
                          data = buf[total_sent, buf.length]
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                          # Note that this must be write() NOT syswrite() or put() or anything like it.
         
     | 
| 
      
 168 
     | 
    
         
            +
                          # Using syswrite() breaks SSL streams.
         
     | 
| 
      
 169 
     | 
    
         
            +
                          sent = self.write( data )
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                          # sf: Only remove the data off the queue is write was successfull.
         
     | 
| 
      
 172 
     | 
    
         
            +
                          #     This way we naturally perform a resend if a failure occured.
         
     | 
| 
      
 173 
     | 
    
         
            +
                          #     Catches an edge case with meterpreter TCP channels where remote send
         
     | 
| 
      
 174 
     | 
    
         
            +
                          #     failes gracefully and a resend is required.
         
     | 
| 
      
 175 
     | 
    
         
            +
                          if (sent.nil?)
         
     | 
| 
      
 176 
     | 
    
         
            +
                            closed = true
         
     | 
| 
      
 177 
     | 
    
         
            +
                            wlog("monitor_rsock: failed writing, socket must be dead")
         
     | 
| 
      
 178 
     | 
    
         
            +
                            break
         
     | 
| 
      
 179 
     | 
    
         
            +
                          elsif (sent > 0)
         
     | 
| 
      
 180 
     | 
    
         
            +
                            total_sent += sent
         
     | 
| 
      
 181 
     | 
    
         
            +
                          end
         
     | 
| 
      
 182 
     | 
    
         
            +
                        rescue ::IOError, ::EOFError => e
         
     | 
| 
      
 183 
     | 
    
         
            +
                          closed = true
         
     | 
| 
      
 184 
     | 
    
         
            +
                          wlog("monitor_rsock: exception during write: #{e.class} #{e}")
         
     | 
| 
      
 185 
     | 
    
         
            +
                          break
         
     | 
| 
      
 186 
     | 
    
         
            +
                        end
         
     | 
| 
      
 187 
     | 
    
         
            +
                      end
         
     | 
| 
      
 188 
     | 
    
         
            +
                    end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                    if( closed )
         
     | 
| 
      
 191 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 192 
     | 
    
         
            +
                        self.close_write if self.respond_to?('close_write')
         
     | 
| 
      
 193 
     | 
    
         
            +
                      rescue IOError
         
     | 
| 
      
 194 
     | 
    
         
            +
                      end
         
     | 
| 
      
 195 
     | 
    
         
            +
                      break
         
     | 
| 
      
 196 
     | 
    
         
            +
                    end
         
     | 
| 
      
 197 
     | 
    
         
            +
                  end
         
     | 
| 
      
 198 
     | 
    
         
            +
                }
         
     | 
| 
      
 199 
     | 
    
         
            +
              end
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
            protected
         
     | 
| 
      
 202 
     | 
    
         
            +
              attr_accessor :monitor_thread
         
     | 
| 
      
 203 
     | 
    
         
            +
              attr_writer :lsock
         
     | 
| 
      
 204 
     | 
    
         
            +
              attr_writer :rsock
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
            end
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            end; end
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,221 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding: binary -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'thread'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module SSLScan
         
     | 
| 
      
 5 
     | 
    
         
            +
            module IO
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            ###
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            # This mixin provides the framework and interface for implementing a streaming
         
     | 
| 
      
 10 
     | 
    
         
            +
            # server that can listen for and accept stream client connections.  Stream
         
     | 
| 
      
 11 
     | 
    
         
            +
            # servers extend this class and are required to implement the following
         
     | 
| 
      
 12 
     | 
    
         
            +
            # methods:
         
     | 
| 
      
 13 
     | 
    
         
            +
            #
         
     | 
| 
      
 14 
     | 
    
         
            +
            #   accept
         
     | 
| 
      
 15 
     | 
    
         
            +
            #   fd
         
     | 
| 
      
 16 
     | 
    
         
            +
            #
         
     | 
| 
      
 17 
     | 
    
         
            +
            ###
         
     | 
| 
      
 18 
     | 
    
         
            +
            module StreamServer
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              ##
         
     | 
| 
      
 21 
     | 
    
         
            +
              #
         
     | 
| 
      
 22 
     | 
    
         
            +
              # Abstract methods
         
     | 
| 
      
 23 
     | 
    
         
            +
              #
         
     | 
| 
      
 24 
     | 
    
         
            +
              ##
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              ##
         
     | 
| 
      
 27 
     | 
    
         
            +
              #
         
     | 
| 
      
 28 
     | 
    
         
            +
              # Default server monitoring and client management implementation follows
         
     | 
| 
      
 29 
     | 
    
         
            +
              # below.
         
     | 
| 
      
 30 
     | 
    
         
            +
              #
         
     | 
| 
      
 31 
     | 
    
         
            +
              ##
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              #
         
     | 
| 
      
 34 
     | 
    
         
            +
              # This callback is notified when a client connects.
         
     | 
| 
      
 35 
     | 
    
         
            +
              #
         
     | 
| 
      
 36 
     | 
    
         
            +
              def on_client_connect(client)
         
     | 
| 
      
 37 
     | 
    
         
            +
                if (on_client_connect_proc)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  on_client_connect_proc.call(client)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              #
         
     | 
| 
      
 43 
     | 
    
         
            +
              # This callback is notified when a client connection has data that needs to
         
     | 
| 
      
 44 
     | 
    
         
            +
              # be processed.
         
     | 
| 
      
 45 
     | 
    
         
            +
              #
         
     | 
| 
      
 46 
     | 
    
         
            +
              def on_client_data(client)
         
     | 
| 
      
 47 
     | 
    
         
            +
                if (on_client_data_proc)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  on_client_data_proc.call(client)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              #
         
     | 
| 
      
 53 
     | 
    
         
            +
              # This callback is notified when a client connection has closed.
         
     | 
| 
      
 54 
     | 
    
         
            +
              #
         
     | 
| 
      
 55 
     | 
    
         
            +
              def on_client_close(client)
         
     | 
| 
      
 56 
     | 
    
         
            +
                if (on_client_close_proc)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  on_client_close_proc.call(client)
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              #
         
     | 
| 
      
 62 
     | 
    
         
            +
              # Start monitoring the listener socket for connections and keep track of
         
     | 
| 
      
 63 
     | 
    
         
            +
              # all client connections.
         
     | 
| 
      
 64 
     | 
    
         
            +
              #
         
     | 
| 
      
 65 
     | 
    
         
            +
              def start
         
     | 
| 
      
 66 
     | 
    
         
            +
                self.clients = []
         
     | 
| 
      
 67 
     | 
    
         
            +
                self.client_waiter = ::Queue.new
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                self.listener_thread = SSLScan::ThreadFactory.spawn("StreamServerListener", false) {
         
     | 
| 
      
 70 
     | 
    
         
            +
                  monitor_listener
         
     | 
| 
      
 71 
     | 
    
         
            +
                }
         
     | 
| 
      
 72 
     | 
    
         
            +
                self.clients_thread = SSLScan::ThreadFactory.spawn("StreamServerClientMonitor", false) {
         
     | 
| 
      
 73 
     | 
    
         
            +
                  monitor_clients
         
     | 
| 
      
 74 
     | 
    
         
            +
                }
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              #
         
     | 
| 
      
 78 
     | 
    
         
            +
              # Terminates the listener monitoring threads and closes all active clients.
         
     | 
| 
      
 79 
     | 
    
         
            +
              #
         
     | 
| 
      
 80 
     | 
    
         
            +
              def stop
         
     | 
| 
      
 81 
     | 
    
         
            +
                self.listener_thread.kill
         
     | 
| 
      
 82 
     | 
    
         
            +
                self.clients_thread.kill
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                self.clients.each { |cli|
         
     | 
| 
      
 85 
     | 
    
         
            +
                  close_client(cli)
         
     | 
| 
      
 86 
     | 
    
         
            +
                }
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
              #
         
     | 
| 
      
 90 
     | 
    
         
            +
              # This method closes a client connection and cleans up the resources
         
     | 
| 
      
 91 
     | 
    
         
            +
              # associated with it.
         
     | 
| 
      
 92 
     | 
    
         
            +
              #
         
     | 
| 
      
 93 
     | 
    
         
            +
              def close_client(client)
         
     | 
| 
      
 94 
     | 
    
         
            +
                if (client)
         
     | 
| 
      
 95 
     | 
    
         
            +
                  clients.delete(client)
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 98 
     | 
    
         
            +
                    client.close
         
     | 
| 
      
 99 
     | 
    
         
            +
                  rescue IOError
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              #
         
     | 
| 
      
 105 
     | 
    
         
            +
              # This method waits on the server listener thread
         
     | 
| 
      
 106 
     | 
    
         
            +
              #
         
     | 
| 
      
 107 
     | 
    
         
            +
              def wait
         
     | 
| 
      
 108 
     | 
    
         
            +
                self.listener_thread.join if self.listener_thread
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
              ##
         
     | 
| 
      
 112 
     | 
    
         
            +
              #
         
     | 
| 
      
 113 
     | 
    
         
            +
              # Callback procedures.
         
     | 
| 
      
 114 
     | 
    
         
            +
              #
         
     | 
| 
      
 115 
     | 
    
         
            +
              ##
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
              #
         
     | 
| 
      
 118 
     | 
    
         
            +
              # This callback procedure can be set and will be called when new clients
         
     | 
| 
      
 119 
     | 
    
         
            +
              # connect.
         
     | 
| 
      
 120 
     | 
    
         
            +
              #
         
     | 
| 
      
 121 
     | 
    
         
            +
              attr_accessor :on_client_connect_proc
         
     | 
| 
      
 122 
     | 
    
         
            +
              #
         
     | 
| 
      
 123 
     | 
    
         
            +
              # This callback procedure can be set and will be called when clients
         
     | 
| 
      
 124 
     | 
    
         
            +
              # have data to be processed.
         
     | 
| 
      
 125 
     | 
    
         
            +
              #
         
     | 
| 
      
 126 
     | 
    
         
            +
              attr_accessor :on_client_data_proc
         
     | 
| 
      
 127 
     | 
    
         
            +
              #
         
     | 
| 
      
 128 
     | 
    
         
            +
              # This callback procedure can be set and will be called when a client
         
     | 
| 
      
 129 
     | 
    
         
            +
              # disconnects from the server.
         
     | 
| 
      
 130 
     | 
    
         
            +
              #
         
     | 
| 
      
 131 
     | 
    
         
            +
              attr_accessor :on_client_close_proc
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
              attr_accessor :clients # :nodoc:
         
     | 
| 
      
 134 
     | 
    
         
            +
              attr_accessor :listener_thread, :clients_thread # :nodoc:
         
     | 
| 
      
 135 
     | 
    
         
            +
              attr_accessor :client_waiter
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
            protected
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
              #
         
     | 
| 
      
 140 
     | 
    
         
            +
              # This method monitors the listener socket for new connections and calls
         
     | 
| 
      
 141 
     | 
    
         
            +
              # the +on_client_connect+ callback routine.
         
     | 
| 
      
 142 
     | 
    
         
            +
              #
         
     | 
| 
      
 143 
     | 
    
         
            +
              def monitor_listener
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                while true
         
     | 
| 
      
 146 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 147 
     | 
    
         
            +
                    cli = accept
         
     | 
| 
      
 148 
     | 
    
         
            +
                    if not cli
         
     | 
| 
      
 149 
     | 
    
         
            +
                      elog("The accept() returned nil in stream server listener monitor:  #{fd.inspect}")
         
     | 
| 
      
 150 
     | 
    
         
            +
                      ::IO.select(nil, nil, nil, 0.10)
         
     | 
| 
      
 151 
     | 
    
         
            +
                      next
         
     | 
| 
      
 152 
     | 
    
         
            +
                    end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                    # Append to the list of clients
         
     | 
| 
      
 155 
     | 
    
         
            +
                    self.clients << cli
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                    # Initialize the connection processing
         
     | 
| 
      
 158 
     | 
    
         
            +
                    on_client_connect(cli)
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                    # Notify the client monitor
         
     | 
| 
      
 161 
     | 
    
         
            +
                    self.client_waiter.push(cli)
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                  # Skip exceptions caused by accept() [ SSL ]
         
     | 
| 
      
 164 
     | 
    
         
            +
                  rescue ::EOFError, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED
         
     | 
| 
      
 165 
     | 
    
         
            +
                  rescue ::Interrupt
         
     | 
| 
      
 166 
     | 
    
         
            +
                    raise $!
         
     | 
| 
      
 167 
     | 
    
         
            +
                  rescue ::Exception
         
     | 
| 
      
 168 
     | 
    
         
            +
                    elog("Error in stream server server monitor: #{$!}")
         
     | 
| 
      
 169 
     | 
    
         
            +
                    rlog(ExceptionCallStack)
         
     | 
| 
      
 170 
     | 
    
         
            +
                    break
         
     | 
| 
      
 171 
     | 
    
         
            +
                  end
         
     | 
| 
      
 172 
     | 
    
         
            +
                end
         
     | 
| 
      
 173 
     | 
    
         
            +
              end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
              #
         
     | 
| 
      
 176 
     | 
    
         
            +
              # This method monitors client connections for data and calls the
         
     | 
| 
      
 177 
     | 
    
         
            +
              # +on_client_data+ routine when new data arrives.
         
     | 
| 
      
 178 
     | 
    
         
            +
              #
         
     | 
| 
      
 179 
     | 
    
         
            +
              def monitor_clients
         
     | 
| 
      
 180 
     | 
    
         
            +
                begin
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                  # Wait for a notify if our client list is empty
         
     | 
| 
      
 183 
     | 
    
         
            +
                  if (clients.length == 0)
         
     | 
| 
      
 184 
     | 
    
         
            +
                    self.client_waiter.pop
         
     | 
| 
      
 185 
     | 
    
         
            +
                    next
         
     | 
| 
      
 186 
     | 
    
         
            +
                  end
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                  sd = SSLScan::ThreadSafe.select(clients, nil, nil, nil)
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                  sd[0].each { |cfd|
         
     | 
| 
      
 191 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 192 
     | 
    
         
            +
                      on_client_data(cfd)
         
     | 
| 
      
 193 
     | 
    
         
            +
                    rescue ::EOFError, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED
         
     | 
| 
      
 194 
     | 
    
         
            +
                      on_client_close(cfd)
         
     | 
| 
      
 195 
     | 
    
         
            +
                      close_client(cfd)
         
     | 
| 
      
 196 
     | 
    
         
            +
                    rescue ::Interrupt
         
     | 
| 
      
 197 
     | 
    
         
            +
                      raise $!
         
     | 
| 
      
 198 
     | 
    
         
            +
                    rescue ::Exception
         
     | 
| 
      
 199 
     | 
    
         
            +
                      close_client(cfd)
         
     | 
| 
      
 200 
     | 
    
         
            +
                      elog("Error in stream server client monitor: #{$!}")
         
     | 
| 
      
 201 
     | 
    
         
            +
                      rlog(ExceptionCallStack)
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                    end
         
     | 
| 
      
 204 
     | 
    
         
            +
                  }
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                rescue ::SSLScan::StreamClosedError => e
         
     | 
| 
      
 207 
     | 
    
         
            +
                  # Remove the closed stream from the list
         
     | 
| 
      
 208 
     | 
    
         
            +
                  clients.delete(e.stream)
         
     | 
| 
      
 209 
     | 
    
         
            +
                rescue ::Interrupt
         
     | 
| 
      
 210 
     | 
    
         
            +
                  raise $!
         
     | 
| 
      
 211 
     | 
    
         
            +
                rescue ::Exception
         
     | 
| 
      
 212 
     | 
    
         
            +
                  elog("Error in stream server client monitor: #{$!}")
         
     | 
| 
      
 213 
     | 
    
         
            +
                  rlog(ExceptionCallStack)
         
     | 
| 
      
 214 
     | 
    
         
            +
                end while true
         
     | 
| 
      
 215 
     | 
    
         
            +
              end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
            end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
            end
         
     | 
| 
      
 220 
     | 
    
         
            +
            end
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,165 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module SSLScan
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Result
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                attr_accessor :openssl_sslv2
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :ciphers
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :supported_versions
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize()
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @cert = nil
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @ciphers = Set.new
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @supported_versions = [:SSLv2, :SSLv3, :TLSv1]
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def cert
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @cert
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def cert=(input)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  unless input.kind_of? OpenSSL::X509::Certificate or input.nil?
         
     | 
| 
      
 21 
     | 
    
         
            +
                    raise ArgumentError, "Must be an X509 Cert!"
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @cert = input
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def sslv2
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @ciphers.reject{|cipher| cipher[:version] != :SSLv2 }
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def sslv3
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @ciphers.reject{|cipher| cipher[:version] != :SSLv3 }
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def tlsv1
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @ciphers.reject{|cipher| cipher[:version] != :TLSv1 }
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def weak_ciphers
         
     | 
| 
      
 39 
     | 
    
         
            +
                  accepted.reject{|cipher| cipher[:weak] == false }
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def strong_ciphers
         
     | 
| 
      
 43 
     | 
    
         
            +
                  accepted.reject{|cipher| cipher[:weak] }
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # Returns all accepted ciphers matching the supplied version
         
     | 
| 
      
 47 
     | 
    
         
            +
                # @param version [Symbol, Array] The SSL Version to filter on
         
     | 
| 
      
 48 
     | 
    
         
            +
                # @raise [ArgumentError] if the version supplied is invalid
         
     | 
| 
      
 49 
     | 
    
         
            +
                # @return [Array] An array of accepted cipher details matching the supplied versions
         
     | 
| 
      
 50 
     | 
    
         
            +
                def accepted(version = :all)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  enum_ciphers(:accepted, version)
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                # Returns all rejected ciphers matching the supplied version
         
     | 
| 
      
 55 
     | 
    
         
            +
                # @param version [Symbol, Array] The SSL Version to filter on
         
     | 
| 
      
 56 
     | 
    
         
            +
                # @raise [ArgumentError] if the version supplied is invalid
         
     | 
| 
      
 57 
     | 
    
         
            +
                # @return [Array] An array of rejected cipher details matching the supplied versions
         
     | 
| 
      
 58 
     | 
    
         
            +
                def rejected(version = :all)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  enum_ciphers(:rejected, version)
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def each_accepted(version = :all)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  accepted(version).each do |cipher_result|
         
     | 
| 
      
 64 
     | 
    
         
            +
                    yield cipher_result
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                def each_rejected(version = :all)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  rejected(version).each do |cipher_result|
         
     | 
| 
      
 70 
     | 
    
         
            +
                    yield cipher_result
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                def supports_sslv2?
         
     | 
| 
      
 75 
     | 
    
         
            +
                  !(accepted(:SSLv2).empty?)
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                def supports_sslv3?
         
     | 
| 
      
 79 
     | 
    
         
            +
                  !(accepted(:SSLv3).empty?)
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                def supports_tlsv1?
         
     | 
| 
      
 83 
     | 
    
         
            +
                  !(accepted(:TLSv1).empty?)
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def supports_ssl?
         
     | 
| 
      
 87 
     | 
    
         
            +
                  supports_sslv2? or supports_sslv3? or supports_tlsv1?
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                def supports_weak_ciphers?
         
     | 
| 
      
 91 
     | 
    
         
            +
                  !(weak_ciphers.empty?)
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                def standards_compliant?
         
     | 
| 
      
 95 
     | 
    
         
            +
                  if supports_ssl?
         
     | 
| 
      
 96 
     | 
    
         
            +
                    return false if supports_sslv2?
         
     | 
| 
      
 97 
     | 
    
         
            +
                    return false if supports_weak_ciphers?
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
                  true
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                # Adds the details of a cipher test to the Result object.
         
     | 
| 
      
 103 
     | 
    
         
            +
                # @param version [Symbol] the SSL Version
         
     | 
| 
      
 104 
     | 
    
         
            +
                # @param cipher [String] the SSL cipher
         
     | 
| 
      
 105 
     | 
    
         
            +
                # @param key_length [Fixnum] the length of encryption key
         
     | 
| 
      
 106 
     | 
    
         
            +
                # @param status [Symbol] :accepted or :rejected
         
     | 
| 
      
 107 
     | 
    
         
            +
                def add_cipher(version, cipher, key_length, status)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  unless @supported_versions.include? version
         
     | 
| 
      
 109 
     | 
    
         
            +
                    raise ArgumentError, "Must be a supported SSL Version"
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include? cipher
         
     | 
| 
      
 112 
     | 
    
         
            +
                    raise ArgumentError, "Must be a valid SSL Cipher for #{version}!"
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
                  unless key_length.kind_of? Fixnum
         
     | 
| 
      
 115 
     | 
    
         
            +
                    raise ArgumentError, "Must supply a valid key length"
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
                  unless [:accepted, :rejected].include? status
         
     | 
| 
      
 118 
     | 
    
         
            +
                    raise ArgumentError, "Status must be either :accepted or :rejected"
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                  strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  # OpenSSL Directive For Strong Ciphers
         
     | 
| 
      
 123 
     | 
    
         
            +
                  # See: http://www.rapid7.com/vulndb/lookup/ssl-weak-ciphers
         
     | 
| 
      
 124 
     | 
    
         
            +
                  strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM"
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  if strong_cipher_ctx.ciphers.flatten.include? cipher
         
     | 
| 
      
 127 
     | 
    
         
            +
                    weak = false
         
     | 
| 
      
 128 
     | 
    
         
            +
                  else
         
     | 
| 
      
 129 
     | 
    
         
            +
                    weak = true
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status}
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @ciphers << cipher_details
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                protected
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                # @param state [Symbol] Either :accepted or :rejected
         
     | 
| 
      
 139 
     | 
    
         
            +
                # @param version [Symbol, Array] The SSL Version to filter on (:SSLv2, :SSLv3, :TLSv1, :all)
         
     | 
| 
      
 140 
     | 
    
         
            +
                # @return [Set] The Set of cipher results matching the filter criteria
         
     | 
| 
      
 141 
     | 
    
         
            +
                def enum_ciphers(state, version = :all)
         
     | 
| 
      
 142 
     | 
    
         
            +
                  case version
         
     | 
| 
      
 143 
     | 
    
         
            +
                  when Symbol
         
     | 
| 
      
 144 
     | 
    
         
            +
                    case version
         
     | 
| 
      
 145 
     | 
    
         
            +
                    when :all
         
     | 
| 
      
 146 
     | 
    
         
            +
                      return @ciphers.select { |cipher| cipher[:status] == state }
         
     | 
| 
      
 147 
     | 
    
         
            +
                    when :SSLv2, :SSLv3, :TLSv1
         
     | 
| 
      
 148 
     | 
    
         
            +
                      return @ciphers.select { |cipher| cipher[:status] == state and cipher[:version] == version }
         
     | 
| 
      
 149 
     | 
    
         
            +
                    else
         
     | 
| 
      
 150 
     | 
    
         
            +
                      raise ArgumentError, "Invalid SSL Version Supplied: #{version}"
         
     | 
| 
      
 151 
     | 
    
         
            +
                    end
         
     | 
| 
      
 152 
     | 
    
         
            +
                  when Array
         
     | 
| 
      
 153 
     | 
    
         
            +
                    version = version.reject{|v| !(@supported_versions.include? v)}
         
     | 
| 
      
 154 
     | 
    
         
            +
                    if version.empty?
         
     | 
| 
      
 155 
     | 
    
         
            +
                      return @ciphers.select{|cipher| cipher[:status] == state}
         
     | 
| 
      
 156 
     | 
    
         
            +
                    else
         
     | 
| 
      
 157 
     | 
    
         
            +
                      return @ciphers.select{|cipher| cipher[:status] == state and version.include? cipher[:version]}
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 159 
     | 
    
         
            +
                  else
         
     | 
| 
      
 160 
     | 
    
         
            +
                    raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}"
         
     | 
| 
      
 161 
     | 
    
         
            +
                  end
         
     | 
| 
      
 162 
     | 
    
         
            +
                end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
              end
         
     | 
| 
      
 165 
     | 
    
         
            +
            end
         
     |