class OpenSSL::SSL::SSLContext
SSLContext используется для настройки различных параметров сертификатов, алгоритмов, проверки, кэширования сеансов и т. д. SSLContext используется для создания SSLSocket.
Все атрибуты необходимо задать до создания SSLSocket, поскольку после этого SSLContext будет заморожен.
Константы
- DH_ffdhe2048
- METHODS
-
Список доступных методов SSL/TLS. Эта константа предоставляется только для обратной совместимости.
- METHODS_MAP
- SESSION_CACHE_BOTH
-
Сеансы клиента и сервера добавляются в кэш сеансов
- SESSION_CACHE_CLIENT
-
Сеансы клиента добавляются в кэш сеансов
- SESSION_CACHE_NO_AUTO_CLEAR
-
Обычно кэш сеансов проверяется на наличие истёкших сеансов каждые 255 подключений. Поскольку это может привести к задержке, которую нельзя контролировать, автоматическую очистку можно отключить и явно вызвать
flush_sessions. - SESSION_CACHE_NO_INTERNAL
-
Включает параметры
SESSION_CACHE_NO_INTERNAL_LOOKUPиSESSION_CACHE_NO_INTERNAL_STORE. - SESSION_CACHE_NO_INTERNAL_LOOKUP
-
Всегда выполнять поиск сеансов во внешнем хранилище, даже если они находятся во внутреннем кэше.
Этот флаг не влияет на клиентов
- SESSION_CACHE_NO_INTERNAL_STORE
-
Никогда не сохранять сеансы автоматически во внутреннем хранилище.
- SESSION_CACHE_OFF
-
Кэширование сеансов клиента или сервера отключено
- SESSION_CACHE_SERVER
-
Сеансы сервера добавляются в кэш сеансов
Атрибуты
Enumerable строк. Каждая String представляет протокол, который будет объявлен в списке протоколов, поддерживаемых для согласования протокола прикладного уровня (ALPN). Поддерживается в OpenSSL версии 1.0.2 и выше. Не влияет на серверную сторону. Если не задан явно, расширение ALPN не будет включено в рукопожатие.
Пример
ctx.alpn_protocols = ["http/1.1", "spdy/2", "h2"]
Обратный вызов, вызываемый на серверной стороне, когда серверу необходимо выбрать протокол из списка, отправленного клиентом. Поддерживается в OpenSSL версии 1.0.2 и выше. Обратный вызов должен возвращать один из протоколов, объявленных клиентом. Если ни один из них не подходит, ошибка, вызванная в обратном вызове, приведёт к сбою рукопожатия. Если этот обратный вызов явно не задан, расширение ALPN на сервере не поддерживается — все протоколы, объявленные клиентом, будут проигнорированы.
Пример
ctx.alpn_select_cb = lambda do |protocols| # inspect the protocols and select one protocols.first end
Путь к файлу, содержащему сертификат УЦ в формате PEM
Путь к каталогу, содержащему сертификаты УЦ в формате PEM.
Файлы ищутся по хэш-значению имени субъекта X509.
Сертификат контекста
Атрибуты cert, key и extra_chain_cert устарели. Вместо них рекомендуется использовать add_certificate.
OpenSSL::X509::Store, используемое для проверки сертификатов.
Сертификат или Array сертификатов, которые будут отправлены клиенту.
Обратный вызов, вызываемый, когда сервер запрашивает сертификат клиента, но сертификат не задан.
Обратный вызов вызывается с объектом Session и должен возвращать Array, содержащий OpenSSL::X509::Certificate и OpenSSL::PKey. Если возвращается любое другое значение, рукопожатие приостанавливается.
Array дополнительных сертификатов X509, добавляемых в цепочку сертификатов.
Атрибуты cert, key и extra_chain_cert устарели. Вместо них рекомендуется использовать add_certificate.
Закрытый ключ контекста
Атрибуты cert, key и extra_chain_cert устарели. Вместо них рекомендуется использовать add_certificate.
Обратный вызов, вызываемый при создании или получении ключевого материала TLS, чтобы приложения могли сохранять этот материал для отладки.
Обратный вызов вызывается с объектом SSLSocket и строкой, содержащей ключевой материал в формате, используемом NSS для отладочного вывода SSLKEYLOGFILE.
Совместимо только с OpenSSL версии >= 1.1.1. Хотя LibreSSL реализует SSL_CTX_set_keylog_callback() начиная с версии 3.4.2, эта функция ничего не делает (см. github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).
Пример
context.keylog_cb = proc do |_sock, line|
File.open('ssl_keylog_file', "a") do |f|
f.write("#{line}\n")
end
end
Enumerable строк. Каждая String представляет протокол, который будет объявлен в списке протоколов, поддерживаемых для согласования следующего протокола (NPN). Поддерживается в OpenSSL версии 1.0.1 и выше. Не влияет на клиентскую сторону. Если не задан явно, сервер не отправит расширение NPN в рукопожатии.
Пример
ctx.npn_protocols = ["http/1.1", "spdy/2"]
Обратный вызов, вызываемый на клиентской стороне, когда клиенту необходимо выбрать протокол из списка, отправленного сервером. Поддерживается в OpenSSL версии 1.0.1 и выше. Клиент ДОЛЖЕН выбрать один из протоколов, объявленных сервером. Если ни один из них не подходит, ошибка, вызванная в обратном вызове, приведёт к сбою рукопожатия. Если этот обратный вызов явно не задан, расширение NPN на клиенте не поддерживается — все протоколы, объявленные сервером, будут проигнорированы.
Пример
ctx.npn_select_cb = lambda do |protocols| # inspect the protocols and select one protocols.first end
Обратный вызов, вызываемый при каждом начале нового рукопожатия в уже установленном соединении. Может использоваться для полного отключения повторного согласования.
Обратный вызов вызывается с активным объектом SSLSocket. Возвращаемое значение обратного вызова игнорируется. Нормальный возврат означает «одобрение» повторного согласования, и процесс будет продолжен. Чтобы запретить повторное согласование и отменить процесс, вызовите исключение внутри обратного вызова.
Отключение повторного согласования клиентом
При работе сервера часто требуется полностью отключить повторное согласование со стороны клиента. Для реализации этой возможности можно использовать следующий обратный вызов:
ctx.renegotiation_cb = lambda do |ssl| raise RuntimeError, "Client renegotiation disabled" end
Обратный вызов, вызываемый при подключении для различения нескольких имён серверов.
Обратный вызов вызывается с объектом SSLSocket и именем сервера. Он должен возвращать SSLContext для этого имени сервера или nil.
Задаёт контекст, в котором можно повторно использовать сеанс. Это позволяет различать сеансы нескольких приложений, например, по имени.
Обратный вызов, вызываемый при согласовании нового сеанса.
Обратный вызов вызывается с объектом SSLSocket. Если возвращается false, сеанс будет удалён из внутреннего кэша.
Обратный вызов, вызываемый при удалении сеанса из внутреннего кэша.
Обратный вызов вызывается с объектом SSLContext и объектом Session.
ВАЖНОЕ ЗАМЕЧАНИЕ: В настоящее время безопасно использовать этот механизм в многопоточном приложении невозможно. Обратный вызов вызывается внутри глобальной блокировки и может случайным образом привести к взаимной блокировке при переключении потоков Ruby.
Максимальный срок действия сеанса в секундах.
Максимальный срок действия сеанса в секундах.
Обратный вызов, вызываемый, когда для эфемерного обмена ключами DH требуются параметры DH.
Обратный вызов вызывается с объектом SSLSocket, флагом, указывающим на использование экспортного шифра, и требуемой длиной ключа.
Обратный вызов должен возвращать экземпляр OpenSSL::PKey::DH с соответствующей длиной ключа.
Устарел в версии 3.0. Вместо него используйте tmp_dh=.
Обратный вызов для дополнительной проверки сертификатов. Обратный вызов вызывается для каждого сертификата в цепочке.
Обратный вызов вызывается с двумя значениями. preverify_ok указывает, прошла ли проверка (true) или нет (false). store_context — это OpenSSL::X509::StoreContext, содержащий контекст, использованный для проверки сертификата.
Если обратный вызов возвращает false, проверка цепочки немедленно прекращается, после чего отправляется оповещение bad_certificate.
Количество сертификатов УЦ, которые следует пройти при проверке цепочки сертификатов.
Проверять ли, действителен ли сертификат сервера для имени хоста.
Для работы этой функции verify_mode должен быть установлен в VERIFY_PEER, а имя хоста сервера должно быть задано с помощью OpenSSL::SSL::SSLSocket#hostname=.
Режим проверки Session.
Допустимые режимы: VERIFY_NONE, VERIFY_PEER, VERIFY_CLIENT_ONCE, VERIFY_FAIL_IF_NO_PEER_CERT; они определены в OpenSSL::SSL
По умолчанию используется режим VERIFY_NONE, который вообще не выполняет проверку.
Подробности см. в SSL_CTX_set_verify(3).
Открытые методы класса
# File ext/openssl/lib/openssl/ssl.rb, line 127 def initialize(version = nil) self.ssl_version = version if version self.verify_mode = OpenSSL::SSL::VERIFY_NONE self.verify_hostname = false end
Создаёт новый контекст SSL.
Если передан аргумент, вызывается ssl_version= с этим значением. Обратите внимание, что эта форма устарела. В новых приложениях при необходимости следует использовать min_version= и max_version=.
Открытые методы экземпляра
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_eq(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 && !SSL_CTX_set0_chain(ctx, extra_chain)) {
sk_X509_pop_free(extra_chain, X509_free);
ossl_raise(eSSLError, "SSL_CTX_set0_chain");
}
return self;
} Добавляет сертификат в контекст. pkey должен быть соответствующим закрытым ключом для certificate.
Повторными вызовами этого метода можно добавить несколько сертификатов с разными типами открытых ключей, а OpenSSL выберет наиболее подходящий сертификат во время рукопожатия.
cert=, key= и extra_chain_cert= — устаревшие методы доступа для установки сертификата, которые внутри вызывают этот метод.
Параметры
- certificate
-
Сертификат. Экземпляр
OpenSSL::X509::Certificate. - pkey
-
Закрытый ключ для certificate. Экземпляр
OpenSSL::PKey::PKey. - extra_certs
-
Необязательный параметр. Массив
OpenSSL::X509::Certificate. При отправке цепочки сертификатов указанные здесь сертификаты отправляются после certificate в порядке, заданном в массиве.
Пример
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])
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;
} Список наборов шифров, настроенных для этого контекста.
static VALUE
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
{
SSL_CTX *ctx;
VALUE str;
rb_check_frozen(self);
if (NIL_P(v))
return v;
str = build_cipher_string(v);
GetSSLCTX(self, ctx);
if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str)))
ossl_raise(eSSLError, "SSL_CTX_set_cipher_list");
return v;
} Задает список доступных наборов шифров для этого контекста. Обратите внимание, что в контексте сервера для некоторых шифров требуются соответствующие сертификаты. Например, набор шифров RSA можно выбрать только при наличии сертификата RSA.
static VALUE
ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
{
SSL_CTX *ctx;
VALUE str;
rb_check_frozen(self);
if (NIL_P(v))
return v;
str = build_cipher_string(v);
GetSSLCTX(self, ctx);
if (!SSL_CTX_set_ciphersuites(ctx, StringValueCStr(str)))
ossl_raise(eSSLError, "SSL_CTX_set_ciphersuites");
return v;
} Задает список доступных наборов шифров TLSv1.3 для этого контекста.
static VALUE
ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
{
SSL_CTX *ctx;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
StringValueCStr(arg);
if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg)))
ossl_raise(eSSLError, NULL);
return arg;
} Задает список «поддерживаемых эллиптических кривых» для этого контекста.
Для клиента TLS этот список напрямую используется в расширении Supported Elliptic Curves. Для сервера OpenSSL использует список, чтобы определить набор общих кривых. OpenSSL выберет из него наиболее подходящую кривую.
Пример
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)
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;
} Включает TLS_FALLBACK_SCSV для этого контекста. См. RFC 7507.
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;
} Удаляет из внутреннего кэша сеансы, срок действия которых истек к моменту time.
# File ext/openssl/lib/openssl/ssl.rb, line 189 def max_version=(version) set_minmax_proto_version(@min_proto_version ||= nil, version) @max_proto_version = version end
Задает верхнюю границу поддерживаемой версии протокола SSL/TLS. Возможные значения см. в разделе min_version=.
# File ext/openssl/lib/openssl/ssl.rb, line 177 def min_version=(version) set_minmax_proto_version(version, @max_proto_version ||= nil) @min_proto_version = version end
Задает нижнюю границу поддерживаемой версии протокола SSL/TLS. Версию можно указать целочисленной константой с именем OpenSSL::SSL::*_VERSION, объектом Symbol или nil, что означает «любая версия».
Будьте осторожны: после вызова min_version= или max_version= не перезаписывайте параметры OpenSSL::SSL::OP_NO_{SSL,TLS}v* с помощью options=.
Пример
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
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));
} Возвращает различные параметры OpenSSL.
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;
} Задает различные параметры OpenSSL. Параметры представляют собой битовое поле, значения которого можно объединять побитовым оператором ИЛИ (|). Доступные параметры определены как константы в OpenSSL::SSL и начинаются с OP_.
Для обратной совместимости передача nil имеет тот же эффект, что и передача OpenSSL::SSL::OP_ALL.
См. также страницу руководства SSL_CTX_set_options(3).
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
} Возвращает уровень безопасности контекста.
См. также OpenSSL::SSL::SSLContext#security_level=.
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;
} Задает уровень безопасности контекста. OpenSSL ограничивает параметры в соответствии с этим уровнем. К «параметрам» относятся наборы шифров, кривые, размеры ключей, алгоритмы подписи сертификатов, версия протокола и т. д. Например, уровень 1 запрещает параметры с уровнем безопасности ниже 80 бит, такие как наборы шифров с MD5 для MAC или ключи RSA короче 1024 бит.
Обратите внимание, что попытки установить параметры с недостаточным уровнем безопасности также блокируются. Сначала необходимо понизить уровень.
Эта функция не поддерживается в OpenSSL < 1.1.0, и установка уровня, отличного от 0, вызовет исключение NotImplementedError. Уровень 0 означает, что разрешено всё; поведение такое же, как в предыдущих версиях OpenSSL.
Подробности см. на странице руководства SSL_CTX_set_security_level(3).
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 в кэш сеансов.
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));
} Текущий режим кэширования сеансов.
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;
} Задает режим кэширования сеансов SSL. Чтобы задать режим, объедините побитовым ИЛИ нужные константы SESSION_CACHE_*. Подробности см. в SSL_CTX_set_session_cache_mode(3).
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));
} Возвращает текущий размер кэша сеансов. Нулевое значение означает неограниченный размер кэша.
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;
} Задает размер кэша сеансов. Возвращает предыдущее допустимое значение размера кэша сеансов. Нулевое значение означает неограниченный размер кэша сеансов.
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;
} Возвращает Hash со следующими ключами:
- :accept
-
Количество начатых рукопожатий SSL/TLS в режиме сервера
- :accept_good
-
Количество установленных сеансов SSL/TLS в режиме сервера
- :accept_renegotiate
-
Количество начатых повторных согласований в режиме сервера
- :cache_full
-
Количество сеансов, удаленных из-за переполнения кэша
- :cache_hits
-
Количество успешно повторно использованных соединений
- :cache_misses
-
Количество сеансов, предложенных клиентами, но не найденных в кэше
- :cache_num
-
Количество сеансов во внутреннем кэше сеансов
- :cb_hits
-
Количество сеансов, извлеченных из внешнего кэша в режиме сервера
- :connect
-
Количество начатых рукопожатий SSL/TLS в режиме клиента
- :connect_good
-
Количество установленных сеансов SSL/TLS в режиме клиента
- :connect_renegotiate
-
Количество начатых повторных согласований в режиме клиента
- :timeouts
-
Количество сеансов, предложенных клиентами и найденных в кэше, но срок действия которых истек по тайм-ауту
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;
} Удаляет session из кэша сеансов.
# File ext/openssl/lib/openssl/ssl.rb, line 145
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 Задает более разумные значения по умолчанию, оптимизированные для использования с протоколами, подобными HTTP.
Если указан Hash params, параметры переопределяются его значениями. Ключи в params должны соответствовать методам присваивания в SSLContext.
Если verify_mode имеет значение, отличное от VERIFY_NONE, а ca_file, ca_path и cert_store не заданы, используется системное хранилище сертификатов по умолчанию.
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
#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);
X509_STORE_up_ref(store);
}
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);
#ifdef HAVE_SSL_CTX_LOAD_VERIFY_FILE
if (ca_file && !SSL_CTX_load_verify_file(ctx, ca_file))
ossl_raise(eSSLError, "SSL_CTX_load_verify_file");
if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path))
ossl_raise(eSSLError, "SSL_CTX_load_verify_dir");
#else
if (ca_file || ca_path) {
if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
ossl_raise(eSSLError, "SSL_CTX_load_verify_locations");
}
#endif
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));
#ifdef OSSL_USE_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
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");
}
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");
}
#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
/*
* It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements
* SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see
* https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).
*/
if (RTEST(rb_attr_get(self, id_i_keylog_cb))) {
SSL_CTX_set_keylog_callback(ctx, ossl_sslctx_keylog_cb);
OSSL_Debug("SSL keylog callback added");
}
#endif
return Qtrue;
} Этот метод вызывается автоматически при создании нового SSLSocket. Однако он не является потокобезопасным, поэтому в многопоточной программе его необходимо вызвать до создания объектов SSLSocket.
# File ext/openssl/lib/openssl/ssl.rb, line 208
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 Задает версию протокола SSL/TLS для контекста. Это заставляет соединения использовать только указанную версию протокола. Метод устарел и сохранен только для обратной совместимости. Вместо него используйте min_version= и max_version=.
История
Как следует из названия, раньше этот метод вызывал функцию SSL_CTX_set_ssl_version(), которая задает метод SSL, используемый соединениями, созданными на основе контекста. Начиная с Ruby/OpenSSL 2.1 этот метод доступа реализован так, чтобы вместо этого вызывать min_version= и max_version=.
static VALUE
ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
{
SSL_CTX *ctx;
EVP_PKEY *pkey;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
pkey = GetPKeyPtr(arg);
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH)
rb_raise(eSSLError, "invalid pkey type %s (expected DH)",
OBJ_nid2sn(EVP_PKEY_base_id(pkey)));
#ifdef HAVE_SSL_SET0_TMP_DH_PKEY
if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))
ossl_raise(eSSLError, "SSL_CTX_set0_tmp_dh_pkey");
EVP_PKEY_up_ref(pkey);
#else
if (!SSL_CTX_set_tmp_dh(ctx, EVP_PKEY_get0_DH(pkey)))
ossl_raise(eSSLError, "SSL_CTX_set_tmp_dh");
#endif
return arg;
} Задает параметры DH, используемые для эфемерного обмена ключами DH. Это имеет значение только для серверов.
pkey — экземпляр OpenSSL::PKey::DH. Обратите внимание, что компоненты ключа, содержащиеся в объекте ключа (если они есть), игнорируются. Сервер всегда генерирует новую пару ключей для каждого рукопожатия.
Добавлено в версии 3.0. См. также страницу руководства SSL_set0_tmp_dh_pkey(3).
Пример:
ctx = OpenSSL::SSL::SSLContext.new
ctx.tmp_dh = OpenSSL::DH.generate(2048)
svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx)
Thread.new { svr.accept }
Закрытые методы экземпляра
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;
} Задает минимальную и максимальную поддерживаемые версии протокола. См. min_version= и max_version=.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.