ronin-rb/ronin-support

View on GitHub
lib/ronin/support/network/ssl.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# frozen_string_literal: true
#
# Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-support is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-support is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-support.  If not, see <https://www.gnu.org/licenses/>.
#

require 'ronin/support/crypto/openssl'
require 'ronin/support/crypto/key'
require 'ronin/support/network/ssl/local_key'
require 'ronin/support/network/ssl/local_cert'
require 'ronin/support/network/ssl/proxy'

module Ronin
  module Support
    module Network
      #
      # Top-level SSL methods.
      #
      module SSL
        # SSL/TLS versions
        VERSIONS = {
          1   => :TLSv1,
          1.1 => :TLSv1_1,
          1.2 => :TLSv1_2
        }

        # SSL verify modes
        VERIFY = {
          none:                 OpenSSL::SSL::VERIFY_NONE,
          peer:                 OpenSSL::SSL::VERIFY_PEER,
          fail_if_no_peer_cert: OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT,
          client_once:          OpenSSL::SSL::VERIFY_CLIENT_ONCE,
          true               => OpenSSL::SSL::VERIFY_PEER,
          false              => OpenSSL::SSL::VERIFY_NONE
        }

        #
        # The default RSA key used for all SSL server sockets.
        #
        # @return [Crypto::Key::RSA]
        #   The default RSA key.
        #
        def self.key
          @key ||= LocalKey.fetch
        end

        #
        # Overrides the default RSA key.
        #
        # @param [Crypto::Key::RSA, OpenSSL::PKey::RSA] new_key
        #   The new RSA key.
        #
        # @return [Crypto::Key::RSA, OpenSSL::PKey::RSA]
        #   The new default RSA key.
        #
        def self.key=(new_key)
          @key = new_key
        end

        #
        # The default SSL certificate used for all SSL server sockets.
        #
        # @return [Crypto::Cert]
        #   The default SSL certificate.
        #
        def self.cert
          @cert ||= LocalCert.fetch
        end

        #
        # Overrides the default SSL certificate.
        #
        # @param [Crypto::Cert, OpenSSL::X509::Certificate] new_cert
        #   The new SSL certificate.
        #
        # @return [Crypto::Cert, OpenSSL::X509::Certificate]
        #   The new default SSL certificate.
        #
        def self.cert=(new_cert)
          @cert = new_cert
        end

        #
        # Creates a new SSL Context.
        #
        # @param [1, 1.1, 1.2, String, Symbol, nil] version
        #   The SSL version to use.
        #
        # @param [Symbol, Boolean] verify
        #   Specifies whether to verify the SSL certificate.
        #   May be one of the following:
        #
        #   * `:none`
        #   * `:peer`
        #   * `:fail_if_no_peer_cert`
        #   * `:client_once`
        #
        # @param [Crypto::Key::RSA, OpenSSL::PKey::RSA, nil] key
        #   The RSA key to use for the SSL context.
        #
        # @param [String, nil] key_file
        #   The path to the RSA `.key` file.
        #
        # @param [Crypto::Cert, OpenSSL::X509::Certificate, nil] cert
        #   The X509 certificate to use for the SSL context.
        #
        # @param [String, nil] cert_file
        #   The path to the SSL `.crt` or `.pem` file.
        #
        # @param [String, nil] ca_bundle
        #   Path to the CA bundle file or directory.
        #
        # @return [OpenSSL::SSL::SSLContext]
        #   The newly created SSL Context.
        #
        # @raise [ArgumentError]
        #   `cert_file:` or `cert:` keyword arguments also require a `key_file:`
        #   or `key:` keyword argument.
        #
        # @api semipublic
        #
        # @since 1.0.0
        #
        def self.context(version:   nil,
                         verify:    :none,
                         key:       nil,
                         key_file:  nil,
                         cert:      nil,
                         cert_file: nil,
                         ca_bundle: nil)
          context = OpenSSL::SSL::SSLContext.new

          if version
            context.ssl_version = VERSIONS.fetch(version,version)
          end

          context.verify_mode = VERIFY[verify]

          if (key_file || key) && (cert_file || cert)
            context.key  = if key_file then Crypto::Key.load_file(key_file)
                           else             key
                           end

            context.cert = if cert_file then Crypto::Cert.load_file(cert_file)
                           else              cert
                           end
          elsif (key_file || key) || (cert_file || cert)
            raise(ArgumentError,"cert_file: and cert: keyword arguments also require a key_file: or key: keyword argument")
          end

          if ca_bundle
            if File.file?(ca_bundle)
              context.ca_file = ca_bundle
            elsif File.directory?(ca_bundle)
              context.ca_path = ca_bundle
            end
          end

          return context
        end
      end
    end
  end
end