class OpenSSL::SSL::SSLContext
An SSLContext используется для установки различных параметров, касающихся сертификатов, алгоритмов, проверки, кэширования сеансов и т. д. SSLContext используется для создания SSLSocket.
Все атрибуты должны быть установлены перед созданием SSLSocket, так как SSLContext будет заморожен после этого.
Постоянные
- DEFAULT_2048
- 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() с версии 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 представляет протокол, который будет объявлен как список поддерживаемых протоколов для согласования следующего протокола (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.
Количество сертификатов УЦ для проверки цепочки сертификатов.
Необходимо ли проверять, соответствует ли сертификат сервера имени хоста.
Для работы этого параметра 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.options |= OpenSSL::SSL::OP_ALL 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.
Этот метод вызывается автоматически при создании нового SSLSocket. Однако он не является потокобезопасным и должен быть вызван перед созданием объектов SSLSocket в многопоточной программе.
# File ext/openssl/lib/openssl/ssl.rb, line 190 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 178 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.
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 146
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.
Если передан хэш 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))
rb_warning("can't set 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 209
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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.