class OpenSSL::SSL::SSLContext
An SSLContext используется для установки различных параметров, касающихся сертификатов, алгоритмов, проверки, кэширования сеансов и т. д. SSLContext используется для создания SSLSocket.
Все атрибуты должны быть установлены до создания SSLSocket, так как SSLContext после этого будет заморожен.
Постоянные
- METHODS
-
Список доступных методов SSL/TLS
- 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) строк. Каждая строка представляет протокол, который будет рекламироваться как список поддерживаемых протоколов для переговорной процедуры протоколов прикладного уровня (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.
Сертификат контекста.
Объект OpenSSL::X509::Store, используемый для проверки сертификатов.
Сертификат или массив сертификатов, которые будут отправлены клиенту.
Обратный вызов, вызываемый, когда сервер запрашивает клиентский сертификат, и сертификат не задан.
Обратный вызов вызывается с объектом Session и должен возвращать массив, содержащий OpenSSL::X509::Certificate и OpenSSL::PKey. Возврат любого другого значения приостанавливает рукопожатие.
Массив дополнительных сертификатов X509, которые нужно добавить в цепочку сертификатов.
Закрытый ключ контекста.
Перечисляемый объект (Enumerable) строк. Каждая строка представляет протокол, который будет рекламироваться как список поддерживаемых протоколов для переговорной процедуры следующего протокола (Next Protocol Negotiation). Поддерживается в OpenSSL версии 1.0.1 и выше. Не оказывает влияния на сторону клиента. Если не задано явно, расширение NPN не будет отправлено сервером в рукопожатии.
Пример
ctx.npn_protocols = ["http/1.1", "spdy/2"]
Обратный вызов, вызываемый на стороне клиента, когда клиенту нужно выбрать протокол из списка, отправленного сервером. Клиент ДОЛЖЕН выбрать протокол из списка, рекламируемого сервером. Если ни один не приемлем, возникновение ошибки в обратном вызове приведет к сбою рукопожатия. Отсутствие явного задания этого обратного вызова означает отсутствие поддержки расширения NPN на клиенте — любые рекламируемые сервером протоколы будут проигнорированы.
Пример
ctx.npn_select_cb = lambda do |protocols| # inspect the protocols and select one protocols.first end
Обратный вызов, вызываемый всякий раз, когда инициируется новое рукопожатие. Может использоваться для полной отмены повторного согласования.
Обратный вызов вызывается с активным SSLSocket. Возвращаемое значение обратного вызова не имеет значения; нормальное возвращение указывает «одобрение» повторного согласования и продолжение процесса. Чтобы запретить повторное согласование и отменить процесс, в обратном вызове может быть поднято исключение.
Отключение повторного согласования клиента
При работе сервера часто бывает желательно полностью отключить повторное согласование клиента. Вы можете использовать обратный вызов следующим образом, чтобы реализовать эту функцию:
num_handshakes = 0
ctx.renegotiation_cb = lambda do |ssl|
num_handshakes += 1
raise RuntimeError.new("Client renegotiation disabled") if num_handshakes > 1
end
Обратный вызов, вызываемый во время подключения для различения нескольких имён серверов.
Обратный вызов вызывается с SSLSocket и именем сервера. Обратный вызов должен вернуть SSLContext для имени сервера или nil.
Устанавливает контекст, в котором сессия может быть повторно использована. Это позволяет различать сессии для нескольких приложений, например, по имени.
Обратный вызов, вызываемый, когда было согласовано новое сеансовое соединение.
Обратный вызов вызывается с SSLSocket. Если возвращено значение false, сессия будет удалена из внутреннего кэша.
Обратный вызов, вызываемый, когда сессия удаляется из внутреннего кэша.
Обратный вызов вызывается с SSLContext и Session.
ВАЖНОЕ ПРИМЕЧАНИЕ: В настоящее время безопасно использовать это в многопоточной программе нельзя. Обратный вызов вызывается внутри глобальной блокировки, и он может случайно привести к тупику при переключении потоков Ruby.
Максимальная продолжительность сессии в секундах.
Максимальная продолжительность сессии в секундах.
Обратный вызов, вызываемый при необходимости параметров DH.
Обратный вызов вызывается с Session для обмена ключами, флагом, указывающим на использование шифра экспорта, и требуемой длиной ключа.
Обратный вызов должен вернуть экземпляр OpenSSL::PKey::DH с правильной длиной ключа.
Обратный вызов, вызываемый при необходимости параметров ECDH.
Обратный вызов вызывается с Session для обмена ключами, флагом, указывающим на использование шифра экспорта, и требуемой длиной ключа.
Обратный вызов устарел. Он не работает с последними версиями OpenSSL. Используйте #ecdh_curves= вместо этого.
Обратный вызов для дополнительной проверки сертификата. Вызов выполняется для каждого сертификата в цепочке.
Обратный вызов вызывается с двумя значениями. preverify_ok указывает, была ли проверка пройдена (true) или нет (false). store_context — это OpenSSL::X509::StoreContext, содержащий контекст, используемый для проверки сертификата.
Если обратный вызов возвращает false, проверка цепочки немедленно останавливается, и отправляется предупреждение bad_certificate.
Количество сертификатов CA для проверки при проверке цепочки сертификатов.
Нужно ли проверять, является ли сертификат сервера действительным для указанного имени хоста.
Для работы необходимо установить #verify_mode в VERIFY_PEER и указать имя хоста сервера с помощью OpenSSL::SSL::SSLSocket#hostname=.
Режим проверки сессии.
Допустимые режимы: 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 97 def initialize(version = nil) self.options |= OpenSSL::SSL::OP_ALL self.ssl_version = version if version end
Список допустимых методов можно получить с помощью OpenSSL::SSL::SSLContext::METHODS
Методы экземпляра публичного интерфейса
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, elem;
int i;
rb_check_frozen(self);
if (NIL_P(v))
return v;
else if (RB_TYPE_P(v, T_ARRAY)) {
str = rb_str_new(0, 0);
for (i = 0; i < RARRAY_LEN(v); i++) {
elem = rb_ary_entry(v, i);
if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);
elem = rb_String(elem);
rb_str_append(str, elem);
if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
}
} else {
str = v;
StringValue(str);
}
GetSSLCTX(self, ctx);
if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) {
ossl_raise(eSSLError, "SSL_CTX_set_cipher_list");
}
return v;
} Устанавливает список доступных наборов шифрования для данного контекста. Обратите внимание, что в контексте сервера для некоторых наборов шифрования необходимы соответствующие сертификаты. Например, набор шифрования RSA может быть выбран только при наличии сертификата RSA.
static VALUE
ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
{
SSL_CTX *ctx;
rb_check_frozen(self);
GetSSLCTX(self, ctx);
StringValueCStr(arg);
#if defined(HAVE_SSL_CTX_SET1_CURVES_LIST)
if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg)))
ossl_raise(eSSLError, NULL);
#else
/* OpenSSL does not have SSL_CTX_set1_curves_list()... Fallback to
* SSL_CTX_set_tmp_ecdh(). So only the first curve is used. */
{
VALUE curve, splitted;
EC_KEY *ec;
int nid;
splitted = rb_str_split(arg, ":");
if (!RARRAY_LEN(splitted))
ossl_raise(eSSLError, "invalid input format");
curve = RARRAY_AREF(splitted, 0);
StringValueCStr(curve);
/* SSL_CTX_set1_curves_list() accepts NIST names */
nid = EC_curve_nist2nid(RSTRING_PTR(curve));
if (nid == NID_undef)
nid = OBJ_txt2nid(RSTRING_PTR(curve));
if (nid == NID_undef)
ossl_raise(eSSLError, "unknown curve name");
ec = EC_KEY_new_by_curve_name(nid);
if (!ec)
ossl_raise(eSSLError, NULL);
EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
if (!SSL_CTX_set_tmp_ecdh(ctx, ec)) {
EC_KEY_free(ec);
ossl_raise(eSSLError, "SSL_CTX_set_tmp_ecdh");
}
EC_KEY_free(ec);
# if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
/* tmp_ecdh and ecdh_auto conflict. tmp_ecdh is ignored when ecdh_auto
* is enabled. So disable ecdh_auto. */
if (!SSL_CTX_set_ecdh_auto(ctx, 0))
ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
# endif
}
#endif
return arg;
} Устанавливает список «поддерживаемых эллиптических кривых» для этого контекста.
Для клиента TLS список используется непосредственно в расширении Поддерживаемые эллиптические кривые. Для сервера список используется библиотекой OpenSSL для определения набора общих кривых. OpenSSL выберет наиболее подходящую из них.
Обратите внимание, что это работает по-разному со старой версией OpenSSL (≤ 1.0.1). Может быть установлена только одна кривая, и это не оказывает влияния на клиентов TLS.
Пример
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_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_get_options(VALUE self)
{
SSL_CTX *ctx;
GetSSLCTX(self, ctx);
return LONG2NUM(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, NUM2LONG(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
} Возвращает уровень безопасности для контекста.
См. также #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);
SafeGetSSLSession(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;
} Возвращает Хэш, содержащий следующие ключи:
- :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);
SafeGetSSLSession(arg, sess);
return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;
} Удаляет session из кэша сеансов.
# File ext/openssl/lib/openssl/ssl.rb, line 114
def set_params(params={})
params = DEFAULT_PARAMS.merge(params)
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
#if !defined(OPENSSL_NO_EC)
/* We added SSLContext#tmp_ecdh_callback= in Ruby 2.3.0,
* but SSL_CTX_set_tmp_ecdh_callback() was removed in OpenSSL 1.1.0. */
if (RTEST(rb_attr_get(self, id_i_tmp_ecdh_callback))) {
# if defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
rb_warn("#tmp_ecdh_callback= is deprecated; use #ecdh_curves= instead");
SSL_CTX_set_tmp_ecdh_callback(ctx, ossl_tmp_ecdh_callback);
# if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
/* tmp_ecdh_callback and ecdh_auto conflict; OpenSSL ignores
* tmp_ecdh_callback. So disable ecdh_auto. */
if (!SSL_CTX_set_ecdh_auto(ctx, 0))
ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
# endif
# else
ossl_raise(eSSLError, "OpenSSL does not support tmp_ecdh_callback; "
"use #ecdh_curves= instead");
# endif
}
#endif /* OPENSSL_NO_EC */
val = rb_attr_get(self, id_i_cert_store);
if (!NIL_P(val)) {
X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
SSL_CTX_set_cert_store(ctx, store);
#if !defined(HAVE_X509_STORE_UP_REF)
/*
* WORKAROUND:
* X509_STORE can count references, but
* X509_STORE_free() doesn't care it.
* So we won't increment it but mark it by ex_data.
*/
SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void *)1);
#else /* Fixed in OpenSSL 1.0.2; bff9ce4db38b (master), 5b4b9ce976fc (1.0.2) */
X509_STORE_up_ref(store);
#endif
}
val = rb_attr_get(self, id_i_extra_chain_cert);
if(!NIL_P(val)){
rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
}
/* private key may be bundled in certificate file. */
val = rb_attr_get(self, id_i_cert);
cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */
val = rb_attr_get(self, id_i_key);
key = NIL_P(val) ? NULL : GetPrivPKeyPtr(val); /* NO DUP NEEDED */
if (cert && key) {
if (!SSL_CTX_use_certificate(ctx, cert)) {
/* Adds a ref => Safe to FREE */
ossl_raise(eSSLError, "SSL_CTX_use_certificate");
}
if (!SSL_CTX_use_PrivateKey(ctx, key)) {
/* Adds a ref => Safe to FREE */
ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
}
if (!SSL_CTX_check_private_key(ctx)) {
ossl_raise(eSSLError, "SSL_CTX_check_private_key");
}
}
val = rb_attr_get(self, id_i_client_ca);
if(!NIL_P(val)){
if (RB_TYPE_P(val, T_ARRAY)) {
for(i = 0; i < RARRAY_LEN(val); i++){
client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
/* Copies X509_NAME => FREE it. */
ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
}
}
}
else{
client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
/* Copies X509_NAME => FREE it. */
ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
}
}
}
val = rb_attr_get(self, id_i_ca_file);
ca_file = NIL_P(val) ? NULL : StringValueCStr(val);
val = rb_attr_get(self, id_i_ca_path);
ca_path = NIL_P(val) ? NULL : StringValueCStr(val);
if(ca_file || ca_path){
if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
rb_warning("can't set verify locations");
}
val = rb_attr_get(self, id_i_verify_mode);
verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
if (RTEST(rb_attr_get(self, id_i_client_cert_cb)))
SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
val = rb_attr_get(self, id_i_timeout);
if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
val = rb_attr_get(self, id_i_verify_depth);
if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val));
#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB
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 *)encoded);
OSSL_Debug("SSL NPN advertise callback added");
}
if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) {
SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
OSSL_Debug("SSL NPN select callback added");
}
#endif
#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
val = rb_attr_get(self, id_i_alpn_protocols);
if (!NIL_P(val)) {
VALUE rprotos = ssl_encode_npn_protocols(val);
/* returns 0 on success */
if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
RSTRING_LENINT(rprotos)))
ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
OSSL_Debug("SSL ALPN values added");
}
if (RTEST(rb_attr_get(self, id_i_alpn_select_cb))) {
SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
OSSL_Debug("SSL ALPN select callback added");
}
#endif
rb_obj_freeze(self);
val = rb_attr_get(self, id_i_session_id_context);
if (!NIL_P(val)){
StringValue(val);
if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
RSTRING_LENINT(val))){
ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
}
}
if (RTEST(rb_attr_get(self, id_i_session_get_cb))) {
SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
OSSL_Debug("SSL SESSION get callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_new_cb))) {
SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
OSSL_Debug("SSL SESSION new callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_remove_cb))) {
SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
OSSL_Debug("SSL SESSION remove callback added");
}
#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
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");
}
#endif
return Qtrue;
} Этот метод вызывается автоматически при создании нового SSLSocket. Однако он не потокобезопасен и должен вызываться перед созданием объектов SSLSocket в многопоточной программе.
static VALUE
ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
{
SSL_CTX *ctx;
const char *s;
VALUE m = ssl_method;
int i;
GetSSLCTX(self, ctx);
if (RB_TYPE_P(ssl_method, T_SYMBOL))
m = rb_sym2str(ssl_method);
s = StringValueCStr(m);
for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) {
#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION)
int version = ossl_ssl_method_tab[i].version;
#endif
SSL_METHOD *method = ossl_ssl_method_tab[i].func();
if (SSL_CTX_set_ssl_version(ctx, method) != 1)
ossl_raise(eSSLError, "SSL_CTX_set_ssl_version");
#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION)
if (!SSL_CTX_set_min_proto_version(ctx, version))
ossl_raise(eSSLError, "SSL_CTX_set_min_proto_version");
if (!SSL_CTX_set_max_proto_version(ctx, version))
ossl_raise(eSSLError, "SSL_CTX_set_max_proto_version");
#endif
return ssl_method;
}
}
ossl_raise(rb_eArgError, "unknown SSL method `%"PRIsVALUE"'.", m);
} Устанавливает версию протокола SSL/TLS для контекста. Это принудительно заставляет подключения использовать только указанную версию протокола.
Вы можете получить список допустимых версий с помощью OpenSSL::SSL::SSLContext::METHODS
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.