Class: DRb::DRbSSLSocket::SSLConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/drb/ssl.rb

Overview

SSLConfig handles the needed SSL information for establishing a DRbSSLSocket connection, including generating the X509 / RSA pair.

An instance of this config can be passed to DRbSSLSocket.new, DRbSSLSocket.open and DRbSSLSocket.open_server

See DRb::DRbSSLSocket::SSLConfig.new for more details

Constant Summary collapse

DEFAULT =

Default values for a SSLConfig instance.

See DRb::DRbSSLSocket::SSLConfig.new for more details

{
  :SSLCertificate       => nil,
  :SSLPrivateKey        => nil,
  :SSLClientCA          => nil,
  :SSLCACertificatePath => nil,
  :SSLCACertificateFile => nil,
  :SSLTmpDhCallback     => nil,
  :SSLVerifyMode        => ::OpenSSL::SSL::VERIFY_NONE,
  :SSLVerifyDepth       => nil,
  :SSLVerifyCallback    => nil,   # custom verification
  :SSLCertificateStore  => nil,
  # Must specify if you use auto generated certificate.
  :SSLCertName          => nil,   # e.g. [["CN","fqdn.example.com"]]
  :SSLCertComment       => "Generated by Ruby/OpenSSL"
}

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ SSLConfig

Create a new DRb::DRbSSLSocket::SSLConfig instance

The DRb::DRbSSLSocket will take either a config Hash or an instance of SSLConfig, and will setup the certificate for its session for the configuration. If want it to generate a generic certificate, the bare minimum is to provide the :SSLCertName

Config options

From config Hash:

:SSLCertificate

An instance of OpenSSL::X509::Certificate. If this is not provided, then a generic X509 is generated, with a correspond :SSLPrivateKey

:SSLPrivateKey

A private key instance, like OpenSSL::PKey::RSA. This key must be the key that signed the :SSLCertificate

:SSLClientCA

An OpenSSL::X509::Certificate, or Array of certificates that will used as ClientCAs in the SSL Context

:SSLCACertificatePath

A path to the directory of CA certificates. The certificates must be in PEM format.

:SSLCACertificateFile

A path to a CA certificate file, in PEM format.

:SSLTmpDhCallback

A DH callback. See OpenSSL::SSL::SSLContext.tmp_dh_callback

:SSLVerifyMode

This is the SSL verification mode. See OpenSSL::SSL::VERIFY_* for available modes. The default is OpenSSL::SSL::VERIFY_NONE

:SSLVerifyDepth

Number of CA certificates to walk, when verifying a certificate chain.

:SSLVerifyCallback

A callback to be used for additional verification. See OpenSSL::SSL::SSLContext.verify_callback

:SSLCertificateStore

A OpenSSL::X509::Store used for verification of certificates

:SSLCertName

Issuer name for the certificate. This is required when generating the certificate (if :SSLCertificate and :SSLPrivateKey were not given). The value of this is to be an Array of pairs:

[["C", "Raleigh"], ["ST","North Carolina"],
 ["CN","fqdn.example.com"]]

See also OpenSSL::X509::Name

:SSLCertComment

A comment to be used for generating the certificate. The default is “Generated by Ruby/OpenSSL”

Example

These values can be added after the fact, like a Hash.

require 'drb/ssl'
c = DRb::DRbSSLSocket::SSLConfig.new {}
c[:SSLCertificate] =
  OpenSSL::X509::Certificate.new(File.read('mycert.crt'))
c[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.read('mycert.key'))
c[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER
c[:SSLCACertificatePath] = "/etc/ssl/certs/"
c.setup_certificate

or

require 'drb/ssl'
c = DRb::DRbSSLSocket::SSLConfig.new({
        :SSLCertName => [["CN" => DRb::DRbSSLSocket.getservername]]
        })
c.setup_certificate


127
128
129
130
131
132
# File 'lib/drb/ssl.rb', line 127

def initialize(config)
  @config  = config
  @cert    = config[:SSLCertificate]
  @pkey    = config[:SSLPrivateKey]
  @ssl_ctx = nil
end

Instance Method Details

#[](key) ⇒ Object

A convenience method to access the values like a Hash



135
136
137
# File 'lib/drb/ssl.rb', line 135

def [](key);
  @config[key] || DEFAULT[key]
end

#accept(tcp) ⇒ Object

Accept connection to IO tcp, with context of the current certificate configuration



150
151
152
153
154
155
# File 'lib/drb/ssl.rb', line 150

def accept(tcp)
  ssl = OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx)
  ssl.sync = true
  ssl.accept
  ssl
end

#connect(tcp) ⇒ Object

Connect to IO tcp, with context of the current certificate configuration



141
142
143
144
145
146
# File 'lib/drb/ssl.rb', line 141

def connect(tcp)
  ssl = ::OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx)
  ssl.sync = true
  ssl.connect
  ssl
end

#setup_certificateObject

Ensures that :SSLCertificate and :SSLPrivateKey have been provided or that a new certificate is generated with the other parameters provided.



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/drb/ssl.rb', line 160

def setup_certificate
  if @cert && @pkey
    return
  end

  rsa = OpenSSL::PKey::RSA.new(2048){|p, n|
    next unless self[:verbose]
    case p
    when 0; $stderr.putc "."  # BN_generate_prime
    when 1; $stderr.putc "+"  # BN_generate_prime
    when 2; $stderr.putc "*"  # searching good prime,
                              # n = #of try,
                              # but also data from BN_generate_prime
    when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
                              # but also data from BN_generate_prime
    else;   $stderr.putc "*"  # BN_generate_prime
    end
  }

  cert = OpenSSL::X509::Certificate.new
  cert.version = 3
  cert.serial = 0
  name = OpenSSL::X509::Name.new(self[:SSLCertName])
  cert.subject = name
  cert.issuer = name
  cert.not_before = Time.now
  cert.not_after = Time.now + (365*24*60*60)
  cert.public_key = rsa.public_key

  ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
  cert.extensions = [
    ef.create_extension("basicConstraints","CA:FALSE"),
    ef.create_extension("subjectKeyIdentifier", "hash") ]
  ef.issuer_certificate = cert
  cert.add_extension(ef.create_extension("authorityKeyIdentifier",
                                         "keyid:always,issuer:always"))
  if comment = self[:SSLCertComment]
    cert.add_extension(ef.create_extension("nsComment", comment))
  end
  cert.sign(rsa, "SHA256")

  @cert = cert
  @pkey = rsa
end

#setup_ssl_contextObject

Establish the OpenSSL::SSL::SSLContext with the configuration parameters provided.



207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/drb/ssl.rb', line 207

def setup_ssl_context
  ctx = ::OpenSSL::SSL::SSLContext.new
  ctx.cert            = @cert
  ctx.key             = @pkey
  ctx.client_ca       = self[:SSLClientCA]
  ctx.ca_path         = self[:SSLCACertificatePath]
  ctx.ca_file         = self[:SSLCACertificateFile]
  ctx.tmp_dh_callback = self[:SSLTmpDhCallback]
  ctx.verify_mode     = self[:SSLVerifyMode]
  ctx.verify_depth    = self[:SSLVerifyDepth]
  ctx.verify_callback = self[:SSLVerifyCallback]
  ctx.cert_store      = self[:SSLCertificateStore]
  @ssl_ctx = ctx
end