Class: BetterCap::Proxy::HTTP::SSL::Authority

Inherits:
Object
  • Object
show all
Defined in:
lib/bettercap/proxy/http/ssl/authority.rb

Overview

This class represents bettercap's HTTPS CA.

Constant Summary collapse

DEFAULT =

Default CA file.

File.join( Dir.home, '.bettercap', 'bettercap-ca.pem' )

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename = nil) ⇒ Authority

Create an instance of this class loading the certificate and key from filename which is expected to be a PEM formatted file. If filename is nil, Authority::DEFAULT will be used instead.


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/bettercap/proxy/http/ssl/authority.rb', line 119

def initialize( filename = nil )
  install_ca
  filename ||= Authority::DEFAULT

  Logger.info "[#{'SSL'.green}] Loading HTTPS Certification Authority from '#{filename}' ..."

  begin
    pem = File.read(filename)

    @certificate = OpenSSL::X509::Certificate.new(pem)
    @key         = OpenSSL::PKey::RSA.new(pem)
    @store       = Store.new
    @cache       = {}
    @lock        = Mutex.new
  rescue Errno::ENOENT
    raise BetterCap::Error, "'#{filename}' - No such file or directory."

  rescue OpenSSL::X509::CertificateError
    raise BetterCap::Error, "'#{filename}' - Missing or invalid certificate."

  rescue OpenSSL::PKey::RSAError
    raise BetterCap::Error, "'#{filename}' - Missing or invalid key."
  end
end

Instance Attribute Details

#certificateObject (readonly)

CA certificate.


112
113
114
# File 'lib/bettercap/proxy/http/ssl/authority.rb', line 112

def certificate
  @certificate
end

#keyObject (readonly)

CA key.


114
115
116
# File 'lib/bettercap/proxy/http/ssl/authority.rb', line 114

def key
  @key
end

Instance Method Details

#install_caObject


162
163
164
165
166
167
168
169
170
171
172
# File 'lib/bettercap/proxy/http/ssl/authority.rb', line 162

def install_ca
  unless File.exist?( Authority::DEFAULT )
    root   = File.join( Dir.home, '.bettercap' )
    source = File.dirname(__FILE__) + '/bettercap-ca.pem'

    Logger.info "[#{'SSL'.green}] Installing CA to #{root} ..."

    FileUtils.mkdir_p( root )
    FileUtils.cp( source, root )
  end
end

#spoof(hostname, port = 443) ⇒ Object

Fetch the certificate from hostname:port, sign it with our own CA and return it.


146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/bettercap/proxy/http/ssl/authority.rb', line 146

def spoof( hostname, port = 443 )
  @lock.synchronize {
    unless @cache.has_key?(hostname)
      # 1. fetch real server certificate
      s_cert = @store.find( hostname, port )
      # 2. Sign it with our CA.
      s_cert.public_key = @key.public_key
      s_cert.issuer     = @certificate.subject
      s_cert.sign( @key, OpenSSL::Digest::SHA256.new )
      # 3. Profit ^_^
      @cache[hostname] = s_cert
    end
  }
  @cache[hostname]
end