123456789_123456789_123456789_123456789_123456789_

Class: OpenSSL::SSL::SSLContext

Relationships & Source Files
Inherits: Object
Defined in: ext/openssl/ossl_ssl.c,
ext/openssl/lib/openssl/ssl.rb

Overview

An SSLContext is used to set various options regarding certificates, algorithms, verification, session caching, etc. The SSLContext is used to create an SSLSocket.

All attributes must be set before creating an SSLSocket as the SSLContext will be frozen afterward.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.newctx .new(:TLSv1) ⇒ ctx .new("SSLv23") ⇒ ctx

Creates a new ::OpenSSL::SSL context.

If an argument is given, #ssl_version= is called with the value. Note that this form is deprecated. New applications should use #min_version= and #max_version= as necessary.

[ GitHub ]

  
# File 'ext/openssl/lib/openssl/ssl.rb', line 121

def initialize(version = nil)
  self.options |= OpenSSL::SSL::OP_ALL
  self.ssl_version = version if version
end

Instance Attribute Details

#ciphersArray, ... (rw)

The list of cipher suites configured for this context.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 981

static VALUE
ossl_sslctx_get_ciphers(VALUE self)
{
    SSL_CTX *ctx;
    STACK_OF(SSL_CIPHER) *ciphers;
    const SSL_CIPHER *cipher;
    VALUE ary;
    int i, num;

    GetSSLCTX(self, ctx);
    ciphers = SSL_CTX_get_ciphers(ctx);
    if (!ciphers)
        return rb_ary_new();

    num = sk_SSL_CIPHER_num(ciphers);
    ary = rb_ary_new2(num);
    for(i = 0; i < num; i++){
        cipher = sk_SSL_CIPHER_value(ciphers, i);
        rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher));
    }
    return ary;
}

#ciphers=("cipher1:cipher2:...") (rw) #ciphers=([name, ...]) #ciphers=([[name, version, bits, alg_bits], ...])

Sets the list of available cipher suites for this context. Note in a server context some ciphers require the appropriate certificates. For example, an RSA cipher suite can only be chosen when an RSA certificate is available.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1014

static VALUE
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
{
    SSL_CTX *ctx;
    VALUE str, elem;
    int i;

    rb_check_frozen(self);
    if (NIL_P(v))
	return v;
    else if (RB_TYPE_P(v, T_ARRAY)) {
        str = rb_str_new(0, 0);
        for (i = 0; i < RARRAY_LEN(v); i++) {
            elem = rb_ary_entry(v, i);
            if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);
            elem = rb_String(elem);
            rb_str_append(str, elem);
            if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
        }
    } else {
        str = v;
        StringValue(str);
    }

    GetSSLCTX(self, ctx);
    if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) {
        ossl_raise(eSSLError, "SSL_CTX_set_cipher_list");
    }

    return v;
}

#ecdh_curves=(curve_list) ⇒ curve_list (writeonly)

Sets the list of “supported elliptic curves” for this context.

For a TLS client, the list is directly used in the Supported Elliptic Curves Extension. For a server, the list is used by ::OpenSSL to determine the set of shared curves. ::OpenSSL will pick the most appropriate one from it.

Note that this works differently with old ::OpenSSL (<= 1.0.1). Only one curve can be set, and this has no effect for TLS clients.

Example

ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.ecdh_curves = "X25519:P-256:P-224"
svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1)
Thread.new { svr.accept }

ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.ecdh_curves = "P-256"
cli = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx2)
cli.connect

p cli.tmp_key.group.curve_name
# => "prime256v1" (is an alias for NIST P-256)
[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1074

static VALUE
ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;

    rb_check_frozen(self);
    GetSSLCTX(self, ctx);
    StringValueCStr(arg);

#if defined(HAVE_SSL_CTX_SET1_CURVES_LIST)
    if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg)))
	ossl_raise(eSSLError, NULL);
#else
    /* OpenSSL does not have SSL_CTX_set1_curves_list()... Fallback to
     * SSL_CTX_set_tmp_ecdh(). So only the first curve is used. */
    {
	VALUE curve, splitted;
	EC_KEY *ec;
	int nid;

	splitted = rb_str_split(arg, ":");
	if (!RARRAY_LEN(splitted))
	    ossl_raise(eSSLError, "invalid input format");
	curve = RARRAY_AREF(splitted, 0);
	StringValueCStr(curve);

	/* SSL_CTX_set1_curves_list() accepts NIST names */
	nid = EC_curve_nist2nid(RSTRING_PTR(curve));
	if (nid == NID_undef)
	    nid = OBJ_txt2nid(RSTRING_PTR(curve));
	if (nid == NID_undef)
	    ossl_raise(eSSLError, "unknown curve name");

	ec = EC_KEY_new_by_curve_name(nid);
	if (!ec)
	    ossl_raise(eSSLError, NULL);
	EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
	if (!SSL_CTX_set_tmp_ecdh(ctx, ec)) {
	    EC_KEY_free(ec);
	    ossl_raise(eSSLError, "SSL_CTX_set_tmp_ecdh");
	}
	EC_KEY_free(ec);
# if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
	/* tmp_ecdh and ecdh_auto conflict. tmp_ecdh is ignored when ecdh_auto
	 * is enabled. So disable ecdh_auto. */
	if (!SSL_CTX_set_ecdh_auto(ctx, 0))
	    ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
# endif
    }
#endif

    return arg;
}

#max_version=(OpenSSL::SSL::TLS1_2_VERSION) (writeonly) #max_version=(:TLS1_2) #max_version=(nil)

Sets the upper bound of the supported SSL/TLS protocol version. See #min_version= for the possible values.

[ GitHub ]

  
# File 'ext/openssl/lib/openssl/ssl.rb', line 182

def max_version=(version)
  set_minmax_proto_version(@min_proto_version ||= nil, version)
  @max_proto_version = version
end

#min_version=(OpenSSL::SSL::TLS1_2_VERSION) (writeonly) #min_version=(:TLS1_2) #min_version=(nil)

Sets the lower bound on the supported SSL/TLS protocol version. The version may be specified by an integer constant named OpenSSL::SSL::*_VERSION, a Symbol, or nil which means “any version”.

Be careful that you don’t overwrite OpenSSL::SSL::OP_NO_SSL,TLSv* options by #options= once you have called #min_version= or #max_version=.

Example

ctx = OpenSSL::SSL::SSLContext.new
ctx.min_version = OpenSSL::SSL::TLS1_1_VERSION
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION

sock = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx)
sock.connect # Initiates a connection using either TLS 1.1 or TLS 1.2
[ GitHub ]

  
# File 'ext/openssl/lib/openssl/ssl.rb', line 170

def min_version=(version)
  set_minmax_proto_version(version, @max_proto_version ||= nil)
  @min_proto_version = version
end

#options (rw)

Gets various ::OpenSSL options.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 732

static VALUE
ossl_sslctx_get_options(VALUE self)
{
    SSL_CTX *ctx;
    GetSSLCTX(self, ctx);
    /*
     * Do explicit cast because SSL_CTX_get_options() returned (signed) long in
     * OpenSSL before 1.1.0.
     */
    return ULONG2NUM((unsigned long)SSL_CTX_get_options(ctx));
}

#options=(options) (rw)

Sets various ::OpenSSL options.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 747

static VALUE
ossl_sslctx_set_options(VALUE self, VALUE options)
{
    SSL_CTX *ctx;

    rb_check_frozen(self);
    GetSSLCTX(self, ctx);

    SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx));

    if (NIL_P(options)) {
	SSL_CTX_set_options(ctx, SSL_OP_ALL);
    } else {
	SSL_CTX_set_options(ctx, NUM2ULONG(options));
    }

    return self;
}

#security_levelInteger (rw)

Returns the security level for the context.

See also #security_level=.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1139

static VALUE
ossl_sslctx_get_security_level(VALUE self)
{
    SSL_CTX *ctx;

    GetSSLCTX(self, ctx);

#if defined(HAVE_SSL_CTX_GET_SECURITY_LEVEL)
    return INT2NUM(SSL_CTX_get_security_level(ctx));
#else
    (void)ctx;
    return INT2FIX(0);
#endif
}

#security_level=(integer) (rw)

Sets the security level for the context. ::OpenSSL limits parameters according to the level. The “parameters” include: ciphersuites, curves, key sizes, certificate signature algorithms, protocol version and so on. For example, level 1 rejects parameters offering below 80 bits of security, such as ciphersuites using MD5 for the MAC or RSA keys shorter than 1024 bits.

Note that attempts to set such parameters with insufficient security are also blocked. You need to lower the level first.

This feature is not supported in ::OpenSSL < 1.1.0, and setting the level to other than 0 will raise NotImplementedError. Level 0 means everything is permitted, the same behavior as previous versions of ::OpenSSL.

See the manpage of SSL_CTX_set_security_level(3) for details.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1173

static VALUE
ossl_sslctx_set_security_level(VALUE self, VALUE value)
{
    SSL_CTX *ctx;

    rb_check_frozen(self);
    GetSSLCTX(self, ctx);

#if defined(HAVE_SSL_CTX_GET_SECURITY_LEVEL)
    SSL_CTX_set_security_level(ctx, NUM2INT(value));
#else
    (void)ctx;
    if (NUM2INT(value) != 0)
	ossl_raise(rb_eNotImpError, "setting security level to other than 0 is "
		   "not supported in this version of OpenSSL");
#endif

    return value;
}

#servername_cb (rw)

A callback invoked at connect time to distinguish between multiple server names.

The callback is invoked with an SSLSocket and a server name. The callback must return an SSLContext for the server name or nil.

[ GitHub ]

  
# File 'ext/openssl/lib/openssl/ssl.rb', line 109

attr_accessor :servername_cb

#session_cache_modeInteger (rw)

The current session cache mode.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1363

static VALUE
ossl_sslctx_get_session_cache_mode(VALUE self)
{
    SSL_CTX *ctx;

    GetSSLCTX(self, ctx);

    return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx));
}

#session_cache_mode=(integer) ⇒ Integer (rw)

Sets the ::OpenSSL::SSL session cache mode. Bitwise-or together the desired SESSION_CACHE_* constants to set. See SSL_CTX_set_session_cache_mode(3) for details.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1381

static VALUE
ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;

    GetSSLCTX(self, ctx);

    SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg));

    return arg;
}

#session_cache_sizeInteger (rw)

Returns the current session cache size. Zero is used to represent an unlimited cache size.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1400

static VALUE
ossl_sslctx_get_session_cache_size(VALUE self)
{
    SSL_CTX *ctx;

    GetSSLCTX(self, ctx);

    return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx));
}

#session_cache_size=(integer) ⇒ Integer (rw)

Sets the session cache size. Returns the previously valid session cache size. Zero is used to represent an unlimited session cache size.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1417

static VALUE
ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;

    GetSSLCTX(self, ctx);

    SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg));

    return arg;
}

#ssl_version=(:TLSv1) (writeonly) #ssl_version=("SSLv23")

Sets the SSL/TLS protocol version for the context. This forces connections to use only the specified protocol version. This is deprecated and only provided for backwards compatibility. Use #min_version= and #max_version= instead.

History

As the name hints, this used to call the SSL_CTX_set_ssl_version() function which sets the ::OpenSSL::SSL method used for connections created from the context. As of Ruby/OpenSSL 2.1, this accessor method is implemented to call #min_version= and #max_version= instead.

[ GitHub ]

  
# File 'ext/openssl/lib/openssl/ssl.rb', line 201

def ssl_version=(meth)
  meth = meth.to_s if meth.is_a?(Symbol)
  if /(?<type>_client|_server)\z/ =~ meth
    meth = $`
    if $VERBOSE
      warn "#{caller(1, 1)[0]}: method type #{type.inspect} is ignored"
    end
  end
  version = METHODS_MAP[meth.intern] or
    raise ArgumentError, "unknown SSL method `%s'" % meth
  set_minmax_proto_version(version, version)
  @min_proto_version = @max_proto_version = version
end

#tmp_dh_callback (rw)

A callback invoked when DH parameters are required.

The callback is invoked with the Session for the key exchange, an flag indicating the use of an export cipher and the keylength required.

The callback must return an ::OpenSSL::PKey::DH instance of the correct key length.

[ GitHub ]

  
# File 'ext/openssl/lib/openssl/ssl.rb', line 102

attr_accessor :tmp_dh_callback

Instance Method Details

#add_certificate(certiticate, pkey [, extra_certs]) ⇒ self

Adds a certificate to the context. pkey must be a corresponding private key with certificate.

Multiple certificates with different public key type can be added by repeated calls of this method, and ::OpenSSL will choose the most appropriate certificate during the handshake.

#cert=, #key=, and #extra_chain_cert= are old accessor methods for setting certificate and internally call this method.

Parameters

certificate

A certificate. An instance of OpenSSL::X509::Certificate.

pkey

The private key for certificate. An instance of OpenSSL::PKey::PKey.

extra_certs

Optional. An array of OpenSSL::X509::Certificate. When sending a certificate chain, the certificates specified by this are sent following certificate, in the order in the array.

Example

rsa_cert = OpenSSL::X509::Certificate.new(...)
rsa_pkey = OpenSSL::PKey.read(...)
ca_intermediate_cert = OpenSSL::X509::Certificate.new(...)
ctx.add_certificate(rsa_cert, rsa_pkey, [ca_intermediate_cert])

ecdsa_cert = ...
ecdsa_pkey = ...
another_ca_cert = ...
ctx.add_certificate(ecdsa_cert, ecdsa_pkey, [another_ca_cert])

Note

::OpenSSL before the version 1.0.2 could handle only one extra chain across all key types. Calling this method discards the chain set previously.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1252

static VALUE
ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)
{
    VALUE cert, key, extra_chain_ary;
    SSL_CTX *ctx;
    X509 *x509;
    STACK_OF(X509) *extra_chain = NULL;
    EVP_PKEY *pkey, *pub_pkey;

    GetSSLCTX(self, ctx);
    rb_scan_args(argc, argv, "21", &cert, &key, &extra_chain_ary);
    rb_check_frozen(self);
    x509 = GetX509CertPtr(cert);
    pkey = GetPrivPKeyPtr(key);

    /*
     * The reference counter is bumped, and decremented immediately.
     * X509_get0_pubkey() is only available in OpenSSL >= 1.1.0.
     */
    pub_pkey = X509_get_pubkey(x509);
    EVP_PKEY_free(pub_pkey);
    if (!pub_pkey)
	rb_raise(rb_eArgError, "certificate does not contain public key");
    if (EVP_PKEY_cmp(pub_pkey, pkey) != 1)
	rb_raise(rb_eArgError, "public key mismatch");

    if (argc >= 3)
	extra_chain = ossl_x509_ary2sk(extra_chain_ary);

    if (!SSL_CTX_use_certificate(ctx, x509)) {
	sk_X509_pop_free(extra_chain, X509_free);
	ossl_raise(eSSLError, "SSL_CTX_use_certificate");
    }
    if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
	sk_X509_pop_free(extra_chain, X509_free);
	ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
    }

    if (extra_chain) {
#if OPENSSL_VERSION_NUMBER >= 0x10002000 && !defined(LIBRESSL_VERSION_NUMBER)
	if (!SSL_CTX_set0_chain(ctx, extra_chain)) {
	    sk_X509_pop_free(extra_chain, X509_free);
	    ossl_raise(eSSLError, "SSL_CTX_set0_chain");
	}
#else
	STACK_OF(X509) *orig_extra_chain;
	X509 *x509_tmp;

	/* First, clear the existing chain */
	SSL_CTX_get_extra_chain_certs(ctx, &orig_extra_chain);
	if (orig_extra_chain && sk_X509_num(orig_extra_chain)) {
	    rb_warning("SSL_CTX_set0_chain() is not available; " \
		       "clearing previously set certificate chain");
	    SSL_CTX_clear_extra_chain_certs(ctx);
	}
	while ((x509_tmp = sk_X509_shift(extra_chain))) {
	    /* Transfers ownership */
	    if (!SSL_CTX_add_extra_chain_cert(ctx, x509_tmp)) {
		X509_free(x509_tmp);
		sk_X509_pop_free(extra_chain, X509_free);
		ossl_raise(eSSLError, "SSL_CTX_add_extra_chain_cert");
	    }
	}
	sk_X509_free(extra_chain);
#endif
    }
    return self;
}

#enable_fallback_scsvnil

Activate TLS_FALLBACK_SCSV for this context. See RFC 7507.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1201

static VALUE
ossl_sslctx_enable_fallback_scsv(VALUE self)
{
    SSL_CTX *ctx;

    GetSSLCTX(self, ctx);
    SSL_CTX_set_mode(ctx, SSL_MODE_SEND_FALLBACK_SCSV);

    return Qnil;
}

#flush_sessions(time) ⇒ self

Removes sessions in the internal cache that have expired at time.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1483

static VALUE
ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
{
    VALUE arg1;
    SSL_CTX *ctx;
    time_t tm = 0;

    rb_scan_args(argc, argv, "01", &arg1);

    GetSSLCTX(self, ctx);

    if (NIL_P(arg1)) {
        tm = time(0);
    } else if (rb_obj_is_instance_of(arg1, rb_cTime)) {
        tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0));
    } else {
        ossl_raise(rb_eArgError, "arg must be Time or nil");
    }

    SSL_CTX_flush_sessions(ctx, (long)tm);

    return self;
}

#setupQtrue #firstt time #setupnil #thereafterr

Alias for #setup.

#session_add(session) ⇒ Boolean

Adds session to the session cache.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1327

static VALUE
ossl_sslctx_session_add(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;
    SSL_SESSION *sess;

    GetSSLCTX(self, ctx);
    GetSSLSession(arg, sess);

    return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;
}

#session_cache_statsHash

Returns a Hash containing the following keys:

:accept

Number of started SSL/TLS handshakes in server mode

:accept_good

Number of established SSL/TLS sessions in server mode

:accept_renegotiate

Number of start renegotiations in server mode

:cache_full

Number of sessions that were removed due to cache overflow

:cache_hits

Number of successfully reused connections

:cache_misses

Number of sessions proposed by clients that were not found in the cache

:cache_num

Number of sessions in the internal session cache

:cb_hits

Number of sessions retrieved from the external cache in server mode

:connect

Number of started SSL/TLS handshakes in client mode

:connect_good

Number of established SSL/TLS sessions in client mode

:connect_renegotiate

Number of start renegotiations in client mode

:timeouts

Number of sessions proposed by clients that were found in the cache but had expired due to timeouts

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1451

static VALUE
ossl_sslctx_get_session_cache_stats(VALUE self)
{
    SSL_CTX *ctx;
    VALUE hash;

    GetSSLCTX(self, ctx);

    hash = rb_hash_new();
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
    rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));

    return hash;
}

#session_remove(session) ⇒ Boolean

Removes session from the session cache.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 1345

static VALUE
ossl_sslctx_session_remove(VALUE self, VALUE arg)
{
    SSL_CTX *ctx;
    SSL_SESSION *sess;

    GetSSLCTX(self, ctx);
    GetSSLSession(arg, sess);

    return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;
}

#set_minmax_proto_version(min, max) ⇒ nil (private)

Sets the minimum and maximum supported protocol versions. See #min_version= and #max_version=.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 152

static VALUE
ossl_sslctx_set_minmax_proto_version(VALUE self, VALUE min_v, VALUE max_v)
{
    SSL_CTX *ctx;
    int min, max;

    GetSSLCTX(self, ctx);
    min = parse_proto_version(min_v);
    max = parse_proto_version(max_v);

#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
    if (!SSL_CTX_set_min_proto_version(ctx, min))
	ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version");
    if (!SSL_CTX_set_max_proto_version(ctx, max))
	ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version");
#else
    {
	unsigned long sum = 0, opts = 0;
	int i;
	static const struct {
	    int ver;
	    unsigned long opts;
	} options_map[] = {
	    { SSL2_VERSION, SSL_OP_NO_SSLv2 },
	    { SSL3_VERSION, SSL_OP_NO_SSLv3 },
	    { TLS1_VERSION, SSL_OP_NO_TLSv1 },
	    { TLS1_1_VERSION, SSL_OP_NO_TLSv1_1 },
	    { TLS1_2_VERSION, SSL_OP_NO_TLSv1_2 },
# if defined(TLS1_3_VERSION)
	    { TLS1_3_VERSION, SSL_OP_NO_TLSv1_3 },
# endif
	};

	for (i = 0; i < numberof(options_map); i++) {
	    sum |= options_map[i].opts;
            if ((min && min > options_map[i].ver) ||
                (max && max < options_map[i].ver)) {
		opts |= options_map[i].opts;
            }
	}
	SSL_CTX_clear_options(ctx, sum);
	SSL_CTX_set_options(ctx, opts);
    }
#endif

    return Qnil;
}

#set_params(params = {}) ⇒ params

Sets saner defaults optimized for the use with HTTP-like protocols.

If a Hash params is given, the parameters are overridden with it. The keys in params must be assignment methods on SSLContext.

If the verify_mode is not VERIFY_NONE and ca_file, ca_path and cert_store are not set then the system default certificate store is used.

[ GitHub ]

  
# File 'ext/openssl/lib/openssl/ssl.rb', line 138

def set_params(params={})
  params = DEFAULT_PARAMS.merge(params)
  self.options = params.delete(:options) # set before min_version/max_version
  params.each{|name, value| self.__send__("#{name}=", value) }
  if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
    unless self.ca_file or self.ca_path or self.cert_store
      self.cert_store = DEFAULT_CERT_STORE
    end
  end
  return params
end

#setupQtrue #firstt time #setupnil #thereafterr
Also known as: #freeze

This method is called automatically when a new SSLSocket is created. However, it is not thread-safe and must be called before creating SSLSocket objects in a multi-threaded program.

[ GitHub ]

  
# File 'ext/openssl/ossl_ssl.c', line 775

static VALUE
ossl_sslctx_setup(VALUE self)
{
    SSL_CTX *ctx;
    X509 *cert = NULL, *client_ca = NULL;
    EVP_PKEY *key = NULL;
    char *ca_path = NULL, *ca_file = NULL;
    int verify_mode;
    long i;
    VALUE val;

    if(OBJ_FROZEN(self)) return Qnil;
    GetSSLCTX(self, ctx);

#if !defined(OPENSSL_NO_DH)
    SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
#endif

#if !defined(OPENSSL_NO_EC)
    /* We added SSLContext#tmp_ecdh_callback= in Ruby 2.3.0,
     * but SSL_CTX_set_tmp_ecdh_callback() was removed in OpenSSL 1.1.0. */
    if (RTEST(rb_attr_get(self, id_i_tmp_ecdh_callback))) {
# if defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
	rb_warn("#tmp_ecdh_callback= is deprecated; use #ecdh_curves= instead");
	SSL_CTX_set_tmp_ecdh_callback(ctx, ossl_tmp_ecdh_callback);
#  if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
	/* tmp_ecdh_callback and ecdh_auto conflict; OpenSSL ignores
	 * tmp_ecdh_callback. So disable ecdh_auto. */
	if (!SSL_CTX_set_ecdh_auto(ctx, 0))
	    ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
#  endif
# else
	ossl_raise(eSSLError, "OpenSSL does not support tmp_ecdh_callback; "
		   "use #ecdh_curves= instead");
# endif
    }
#endif /* OPENSSL_NO_EC */

    val = rb_attr_get(self, id_i_cert_store);
    if (!NIL_P(val)) {
	X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
	SSL_CTX_set_cert_store(ctx, store);
#if !defined(HAVE_X509_STORE_UP_REF)
	/*
         * WORKAROUND:
	 *   X509_STORE can count references, but
	 *   X509_STORE_free() doesn't care it.
	 *   So we won't increment it but mark it by ex_data.
	 */
        SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_store_p, ctx);
#else /* Fixed in OpenSSL 1.0.2; bff9ce4db38b (master), 5b4b9ce976fc (1.0.2) */
	X509_STORE_up_ref(store);
#endif
    }

    val = rb_attr_get(self, id_i_extra_chain_cert);
    if(!NIL_P(val)){
	rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
    }

    /* private key may be bundled in certificate file. */
    val = rb_attr_get(self, id_i_cert);
    cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */
    val = rb_attr_get(self, id_i_key);
    key = NIL_P(val) ? NULL : GetPrivPKeyPtr(val); /* NO DUP NEEDED */
    if (cert && key) {
        if (!SSL_CTX_use_certificate(ctx, cert)) {
            /* Adds a ref => Safe to FREE */
            ossl_raise(eSSLError, "SSL_CTX_use_certificate");
        }
        if (!SSL_CTX_use_PrivateKey(ctx, key)) {
            /* Adds a ref => Safe to FREE */
            ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
        }
        if (!SSL_CTX_check_private_key(ctx)) {
            ossl_raise(eSSLError, "SSL_CTX_check_private_key");
        }
    }

    val = rb_attr_get(self, id_i_client_ca);
    if(!NIL_P(val)){
	if (RB_TYPE_P(val, T_ARRAY)) {
	    for(i = 0; i < RARRAY_LEN(val); i++){
		client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
        	if (!SSL_CTX_add_client_CA(ctx, client_ca)){
		    /* Copies X509_NAME => FREE it. */
        	    ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
        	}
	    }
        }
	else{
	    client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
            if (!SSL_CTX_add_client_CA(ctx, client_ca)){
		/* Copies X509_NAME => FREE it. */
        	ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
            }
	}
    }

    val = rb_attr_get(self, id_i_ca_file);
    ca_file = NIL_P(val) ? NULL : StringValueCStr(val);
    val = rb_attr_get(self, id_i_ca_path);
    ca_path = NIL_P(val) ? NULL : StringValueCStr(val);
    if(ca_file || ca_path){
	if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
	    rb_warning("can't set verify locations");
    }

    val = rb_attr_get(self, id_i_verify_mode);
    verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
    SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
    if (RTEST(rb_attr_get(self, id_i_client_cert_cb)))
	SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);

    val = rb_attr_get(self, id_i_timeout);
    if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));

    val = rb_attr_get(self, id_i_verify_depth);
    if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val));

#ifndef OPENSSL_NO_NEXTPROTONEG
    val = rb_attr_get(self, id_i_npn_protocols);
    if (!NIL_P(val)) {
	VALUE encoded = ssl_encode_npn_protocols(val);
	rb_ivar_set(self, id_npn_protocols_encoded, encoded);
	SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)encoded);
	OSSL_Debug("SSL NPN advertise callback added");
    }
    if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) {
	SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
	OSSL_Debug("SSL NPN select callback added");
    }
#endif

#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
    val = rb_attr_get(self, id_i_alpn_protocols);
    if (!NIL_P(val)) {
	VALUE rprotos = ssl_encode_npn_protocols(val);

	/* returns 0 on success */
	if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
				    RSTRING_LENINT(rprotos)))
	    ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
	OSSL_Debug("SSL ALPN values added");
    }
    if (RTEST(rb_attr_get(self, id_i_alpn_select_cb))) {
	SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
	OSSL_Debug("SSL ALPN select callback added");
    }
#endif

    rb_obj_freeze(self);

    val = rb_attr_get(self, id_i_session_id_context);
    if (!NIL_P(val)){
	StringValue(val);
	if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
					    RSTRING_LENINT(val))){
	    ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
	}
    }

    if (RTEST(rb_attr_get(self, id_i_session_get_cb))) {
	SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
	OSSL_Debug("SSL SESSION get callback added");
    }
    if (RTEST(rb_attr_get(self, id_i_session_new_cb))) {
	SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
	OSSL_Debug("SSL SESSION new callback added");
    }
    if (RTEST(rb_attr_get(self, id_i_session_remove_cb))) {
	SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
	OSSL_Debug("SSL SESSION remove callback added");
    }

    val = rb_attr_get(self, id_i_servername_cb);
    if (!NIL_P(val)) {
        SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
	OSSL_Debug("SSL TLSEXT servername callback added");
    }

    return Qtrue;
}

#ssl_timeout

Alias for timeout.

[ GitHub ]

#ssl_timeout=

Alias for timeout=.

[ GitHub ]