Class: OpenSSL::SSL::SSLContext

Inherits:
Object
  • Object
show all
Defined in:
ext/openssl/ossl_ssl.c,
lib/openssl/ssl.rb,
ext/openssl/ossl_ssl.c

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 collapse

DEFAULT_PARAMS =

:nodoc:

{ # :nodoc:
  :min_version => OpenSSL::SSL::TLS1_VERSION,
  :verify_mode => OpenSSL::SSL::VERIFY_PEER,
  :verify_hostname => true,
  :options => -> {
    opts = OpenSSL::SSL::OP_ALL
    opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS
    opts |= OpenSSL::SSL::OP_NO_COMPRESSION
    opts
  }.call
}
DEFAULT_TMP_DH_CALLBACK =

:nodoc:

lambda { |ctx, is_export, keylen| # :nodoc:
  warn "using default DH parameters." if $VERBOSE
  DEFAULT_2048
}
DEFAULT_CERT_STORE =

:nodoc:

OpenSSL::X509::Store.new
METHODS =

The list of available SSL/TLS methods. This constant is only provided for backwards compatibility.

METHODS_MAP.flat_map { |name,|
  [name, :"#{name}_client", :"#{name}_server"]
}.freeze
SESSION_CACHE_OFF =

No session caching for client or server

LONG2NUM(SSL_SESS_CACHE_OFF)
SESSION_CACHE_CLIENT =

doesn’t actually do anything in 0.9.8e

LONG2NUM(SSL_SESS_CACHE_CLIENT)
SESSION_CACHE_SERVER =

Server sessions are added to the session cache

LONG2NUM(SSL_SESS_CACHE_SERVER)
SESSION_CACHE_BOTH =

no different than CACHE_SERVER in 0.9.8e

LONG2NUM(SSL_SESS_CACHE_BOTH)
SESSION_CACHE_NO_AUTO_CLEAR =

Normally the session cache is checked for expired sessions every 255 connections. Since this may lead to a delay that cannot be controlled, the automatic flushing may be disabled and #flush_sessions can be called explicitly.

LONG2NUM(SSL_SESS_CACHE_NO_AUTO_CLEAR)
SESSION_CACHE_NO_INTERNAL_LOOKUP =

Always perform external lookups of sessions even if they are in the internal cache.

This flag has no effect on clients

LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)
SESSION_CACHE_NO_INTERNAL_STORE =

Never automatically store sessions in the internal store.

LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL_STORE)
SESSION_CACHE_NO_INTERNAL =

Enables both SESSION_CACHE_NO_INTERNAL_LOOKUP and SESSION_CACHE_NO_INTERNAL_STORE.

LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version = nil) ⇒ SSLContext

call-seq:

SSLContext.new           -> ctx
SSLContext.new(:TLSv1)   -> ctx
SSLContext.new("SSLv23") -> ctx

Creates a new 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.



122
123
124
125
# File 'lib/openssl/ssl.rb', line 122

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

Instance Attribute Details

#servername_cbObject

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.



110
111
112
# File 'lib/openssl/ssl.rb', line 110

def servername_cb
  @servername_cb
end

#tmp_dh_callbackObject

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.



103
104
105
# File 'lib/openssl/ssl.rb', line 103

def tmp_dh_callback
  @tmp_dh_callback
end

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.

Returns:

  • (self)


1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
# File 'ext/openssl/ossl_ssl.c', line 1276

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;
}

#ciphersArray

The list of cipher suites configured for this context.

Returns:

  • (Array)


1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
# File 'ext/openssl/ossl_ssl.c', line 1005

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=(v) ⇒ Object

ctx.ciphers = [name, …]

ctx.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.



1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
# File 'ext/openssl/ossl_ssl.c', line 1038

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) ⇒ Object

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)


1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
# File 'ext/openssl/ossl_ssl.c', line 1098

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;
}

#enable_fallback_scsvnil

Activate TLS_FALLBACK_SCSV for this context. See RFC 7507.

Returns:

  • (nil)


1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
# File 'ext/openssl/ossl_ssl.c', line 1225

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.

Returns:

  • (self)


1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
# File 'ext/openssl/ossl_ssl.c', line 1507

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;
}

#max_version=(version) ⇒ Object

call-seq:

ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
ctx.max_version = :TLS1_2
ctx.max_version = nil

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



183
184
185
186
# File 'lib/openssl/ssl.rb', line 183

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

#min_version=(version) ⇒ Object

call-seq:

ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
ctx.min_version = :TLS1_2
ctx.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


171
172
173
174
# File 'lib/openssl/ssl.rb', line 171

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

#optionsObject

Gets various OpenSSL options.



752
753
754
755
756
757
758
759
760
761
762
# File 'ext/openssl/ossl_ssl.c', line 752

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) ⇒ Object

Sets various OpenSSL options.



767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
# File 'ext/openssl/ossl_ssl.c', line 767

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

Returns the security level for the context.

See also OpenSSL::SSL::SSLContext#security_level=.

Returns:



1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
# File 'ext/openssl/ossl_ssl.c', line 1163

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) ⇒ Object

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.



1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
# File 'ext/openssl/ossl_ssl.c', line 1197

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;
}

#session_add(session) ⇒ Object

Adds session to the session cache.



1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
# File 'ext/openssl/ossl_ssl.c', line 1351

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_modeInteger

The current session cache mode.

Returns:



1387
1388
1389
1390
1391
1392
1393
1394
1395
# File 'ext/openssl/ossl_ssl.c', line 1387

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

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

Returns:



1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
# File 'ext/openssl/ossl_ssl.c', line 1405

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

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

Returns:



1424
1425
1426
1427
1428
1429
1430
1431
1432
# File 'ext/openssl/ossl_ssl.c', line 1424

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

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

Returns:



1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
# File 'ext/openssl/ossl_ssl.c', line 1441

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;
}

#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

Returns:

  • (Hash)


1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
# File 'ext/openssl/ossl_ssl.c', line 1475

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) ⇒ Object

Removes session from the session cache.



1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
# File 'ext/openssl/ossl_ssl.c', line 1369

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_params(params = {}) ⇒ Object

call-seq:

ctx.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.



139
140
141
142
143
144
145
146
147
148
149
# File 'lib/openssl/ssl.rb', line 139

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 #setupObject 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.

Overloads:

  • #setupQtrue #firstt time

    Returns:

    • (Qtrue #firstt time)


795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
# File 'ext/openssl/ossl_ssl.c', line 795

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 */

#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
    SSL_CTX_set_post_handshake_auth(ctx, 1);
#endif

    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 *)self);
	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_version=(meth) ⇒ Object

call-seq:

ctx.ssl_version = :TLSv1
ctx.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 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.



202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/openssl/ssl.rb', line 202

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