класс OpenSSL::SSL::SSLContext
SSLContext используется для задания различных параметров, связанных с сертификатами, алгоритмами, проверкой, кэшированием сеансов и т. д. SSLContext используется для создания SSLSocket.
Все атрибуты должны быть заданы до создания SSLSocket, поскольку после этого SSLContext будет заморожен.
Константы
- 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
Путь к файлу, содержащему сертификат CA в формате PEM
Путь к каталогу, содержащему сертификаты CA в формате 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.
Количество сертификатов CA, проверяемых при проверке цепочки сертификатов.
Проверять ли, действителен ли сертификат сервера для имени хоста.
Для работы этой функции необходимо задать для 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 94 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);
// Assigning nil is a no-op for compatibility
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;
} Задаёт список доступных наборов шифров для TLS 1.2 и более ранних версий в этом контексте.
Обратите внимание: в контексте сервера для некоторых наборов шифров требуются соответствующие сертификаты. Например, набор шифров RSA можно выбрать, только если доступен сертификат RSA.
Этот метод не влияет на соединения TLS 1.3. См. также ciphersuites=.
static VALUE
ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
{
SSL_CTX *ctx;
VALUE str;
rb_check_frozen(self);
// Assigning nil is a no-op for compatibility
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;
} Задаёт список доступных наборов шифров TLS 1.3 для этого контекста.
static VALUE
ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)
{
SSL_CTX *ctx;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
if (!SSL_CTX_set1_client_sigalgs_list(ctx, StringValueCStr(v)))
ossl_raise(eSSLError, "SSL_CTX_set1_client_sigalgs_list");
return v;
} Задаёт список «поддерживаемых алгоритмов подписи» для аутентификации клиента в этом контексте.
Для TLS-сервера этот список отправляется клиенту в составе сообщения CertificateRequest.
Эквивалентный метод для аутентификации сервера см. в sigalgs=.
Задаёт список поддерживаемых групп для согласования ключей в этом контексте.
Для TLS-клиента этот список непосредственно используется в расширении “supported_groups”. Для сервера список используется OpenSSL для определения набора общих поддерживаемых групп. OpenSSL выберет из него наиболее подходящую группу.
ecdh_curves= — устаревший псевдоним для groups=.
См. также страницу руководства SSL_CTX_set1_groups_list(3).
Пример
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.groups = "X25519:P-256:P-224"
svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1)
Thread.new { svr.accept }
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.groups = "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.
static VALUE
ossl_sslctx_set_groups(VALUE self, VALUE arg)
{
SSL_CTX *ctx;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
StringValueCStr(arg);
if (!SSL_CTX_set1_groups_list(ctx, RSTRING_PTR(arg)))
ossl_raise(eSSLError, "SSL_CTX_set1_groups_list");
return arg;
} Задаёт список поддерживаемых групп для согласования ключей в этом контексте.
Для TLS-клиента этот список непосредственно используется в расширении “supported_groups”. Для сервера список используется OpenSSL для определения набора общих поддерживаемых групп. OpenSSL выберет из него наиболее подходящую группу.
ecdh_curves= — устаревший псевдоним для groups=.
См. также страницу руководства SSL_CTX_set1_groups_list(3).
Пример
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.groups = "X25519:P-256:P-224"
svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1)
Thread.new { svr.accept }
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.groups = "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_set_max_version(VALUE self, VALUE v)
{
SSL_CTX *ctx;
int version;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
version = parse_proto_version(v);
if (!SSL_CTX_set_max_proto_version(ctx, version))
ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version");
return v;
} Задаёт верхнюю границу поддерживаемой версии протокола SSL/TLS. Возможные значения см. в min_version=.
static VALUE
ossl_sslctx_set_min_version(VALUE self, VALUE v)
{
SSL_CTX *ctx;
int version;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
version = parse_proto_version(v);
if (!SSL_CTX_set_min_proto_version(ctx, version))
ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version");
return v;
} Задаёт нижнюю границу поддерживаемой версии протокола SSL/TLS. Версию можно указать целочисленной константой с именем OpenSSL::SSL::*_VERSION, объектом Symbol или nil, что означает «любая версия».
Пример
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);
return INT2NUM(SSL_CTX_get_security_level(ctx));
} Возвращает уровень безопасности контекста.
См. также 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);
SSL_CTX_set_security_level(ctx, NUM2INT(value));
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 112
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
if not defined?(Ractor) or Ractor.current == Ractor.main
self.cert_store = DEFAULT_CERT_STORE
else
self.cert_store = Ractor.current[:__openssl_default_store__] ||=
OpenSSL::X509::Store.new.tap { |store|
store.set_default_paths
}
end
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)
if (!NIL_P(rb_attr_get(self, id_i_tmp_dh_callback))) {
SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
SSL_CTX_set_dh_auto(ctx, 0);
}
#endif
#if !defined(OPENSSL_IS_AWSLC) /* AWS-LC has no support for TLS 1.3 PHA. */
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 !OSSL_IS_LIBRESSL
/*
* 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.
static VALUE
ossl_sslctx_set_sigalgs(VALUE self, VALUE v)
{
SSL_CTX *ctx;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
if (!SSL_CTX_set1_sigalgs_list(ctx, StringValueCStr(v)))
ossl_raise(eSSLError, "SSL_CTX_set1_sigalgs_list");
return v;
} Задаёт список «поддерживаемых алгоритмов подписи» для этого контекста.
Для TLS-клиента этот список используется в расширении “signature_algorithms” сообщения ClientHello. Для сервера список используется OpenSSL для определения набора общих алгоритмов подписи. OpenSSL выберет из него наиболее подходящий алгоритм.
Эквивалентный метод для аутентификации клиента см. в client_sigalgs=.
# File ext/openssl/lib/openssl/ssl.rb, line 145
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
self.min_version = self.max_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_CTX_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
// Turn off the "auto" DH parameters set by ossl_sslctx_s_alloc()
SSL_CTX_set_dh_auto(ctx, 0);
return arg;
} Задаёт параметры DH, используемые для эфемерного обмена ключами DH. Это относится только к серверам.
pkey — экземпляр OpenSSL::PKey::DH. Обратите внимание, что компоненты ключа, содержащиеся в объекте ключа, если они есть, игнорируются. Сервер всегда генерирует новую пару ключей для каждого рукопожатия.
Добавлено в версии 3.0. См. также страницу руководства SSL_CTX_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 }
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.