класс 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 представляет протокол, который будет объявлен в качестве списка поддерживаемых протоколов для Application-Layer Protocol Negotiation. Поддерживается в 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() начиная с v3.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 представляет протокол, который будет объявлен в качестве списка поддерживаемых протоколов для Next Protocol Negotiation. Поддерживается в 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 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, что означает «любая версия».
Будьте осторожны, чтобы не переписывать параметры OpenSSL::SSL::OP_NO_{SSL,TLS}v* с помощью options= после вызова min_version= или max_version=.
Пример
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–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.