Spec-Zone.ru › Ruby 2.4

class OpenSSL::SSL::SSLContext

Parent:
Object

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

Серверные сеансы добавляются в кэш сеансов

Атрибуты

alpn_protocols[RW]

Перечисляемый объект (Enumerable) строк. Каждая строка представляет протокол, который будет рекламироваться как список поддерживаемых протоколов для переговорной процедуры протоколов прикладного уровня (Application-Layer Protocol Negotiation). Поддерживается в OpenSSL версии 1.0.2 и выше. Не оказывает влияния на сторону сервера. Если не задано явно, расширение ALPN не будет включено в рукопожатие.

Пример

ctx.alpn_protocols = ["http/1.1", "spdy/2", "h2"]
alpn_select_cb[RW]

Обратный вызов, вызываемый на стороне сервера, когда серверу нужно выбрать протокол из списка, отправленного клиентом. Поддерживается в OpenSSL версии 1.0.2 и выше. Обратный вызов должен вернуть протокол из списка, рекламируемого клиентом. Если ни один не приемлем, возникновение ошибки в обратном вызове приведет к сбою рукопожатия. Отсутствие явного задания этого обратного вызова означает отсутствие поддержки расширения ALPN на сервере — любые рекламируемые клиентом протоколы будут проигнорированы.

Пример

ctx.alpn_select_cb = lambda do |protocols|
  # inspect the protocols and select one
  protocols.first
end
ca_file[RW]

Путь к файлу, содержащему сертификат CA в формате PEM.

ca_path[RW]

Путь к каталогу, содержащему сертификаты CA в формате PEM.

Файлы ищутся по значению хэша имени субъекта в формате X509.

cert[RW]

Сертификат контекста.

cert_store[RW]

Объект OpenSSL::X509::Store, используемый для проверки сертификатов.

client_ca[RW]

Сертификат или массив сертификатов, которые будут отправлены клиенту.

client_cert_cb[RW]

Обратный вызов, вызываемый, когда сервер запрашивает клиентский сертификат, и сертификат не задан.

Обратный вызов вызывается с объектом Session и должен возвращать массив, содержащий OpenSSL::X509::Certificate и OpenSSL::PKey. Возврат любого другого значения приостанавливает рукопожатие.

extra_chain_cert[RW]

Массив дополнительных сертификатов X509, которые нужно добавить в цепочку сертификатов.

key[RW]

Закрытый ключ контекста.

npn_protocols[RW]

Перечисляемый объект (Enumerable) строк. Каждая строка представляет протокол, который будет рекламироваться как список поддерживаемых протоколов для переговорной процедуры следующего протокола (Next Protocol Negotiation). Поддерживается в OpenSSL версии 1.0.1 и выше. Не оказывает влияния на сторону клиента. Если не задано явно, расширение NPN не будет отправлено сервером в рукопожатии.

Пример

ctx.npn_protocols = ["http/1.1", "spdy/2"]
npn_select_cb[RW]

Обратный вызов, вызываемый на стороне клиента, когда клиенту нужно выбрать протокол из списка, отправленного сервером. Клиент ДОЛЖЕН выбрать протокол из списка, рекламируемого сервером. Если ни один не приемлем, возникновение ошибки в обратном вызове приведет к сбою рукопожатия. Отсутствие явного задания этого обратного вызова означает отсутствие поддержки расширения NPN на клиенте — любые рекламируемые сервером протоколы будут проигнорированы.

Пример

ctx.npn_select_cb = lambda do |protocols|
  # inspect the protocols and select one
  protocols.first
end
renegotiation_cb[RW]

Обратный вызов, вызываемый всякий раз, когда инициируется новое рукопожатие. Может использоваться для полной отмены повторного согласования.

Обратный вызов вызывается с активным SSLSocket. Возвращаемое значение обратного вызова не имеет значения; нормальное возвращение указывает «одобрение» повторного согласования и продолжение процесса. Чтобы запретить повторное согласование и отменить процесс, в обратном вызове может быть поднято исключение.

Отключение повторного согласования клиента

При работе сервера часто бывает желательно полностью отключить повторное согласование клиента. Вы можете использовать обратный вызов следующим образом, чтобы реализовать эту функцию:

num_handshakes = 0
ctx.renegotiation_cb = lambda do |ssl|
  num_handshakes += 1
  raise RuntimeError.new("Client renegotiation disabled") if num_handshakes > 1
end
servername_cb[RW]

Обратный вызов, вызываемый во время подключения для различения нескольких имён серверов.

Обратный вызов вызывается с SSLSocket и именем сервера. Обратный вызов должен вернуть SSLContext для имени сервера или nil.

session_get_cb[RW]

Обратный вызов, вызываемый на сервере, когда клиент предлагает сессию, но сессия не найдена в внутренней кэше сервера.

Обратный вызов вызывается с SSLSocket и идентификатором сессии. Обратный вызов может вернуть Session из внешнего кэша.

session_id_context[RW]

Устанавливает контекст, в котором сессия может быть повторно использована. Это позволяет различать сессии для нескольких приложений, например, по имени.

session_new_cb[RW]

Обратный вызов, вызываемый, когда было согласовано новое сеансовое соединение.

Обратный вызов вызывается с SSLSocket. Если возвращено значение false, сессия будет удалена из внутреннего кэша.

session_remove_cb[RW]

Обратный вызов, вызываемый, когда сессия удаляется из внутреннего кэша.

Обратный вызов вызывается с SSLContext и Session.

ВАЖНОЕ ПРИМЕЧАНИЕ: В настоящее время безопасно использовать это в многопоточной программе нельзя. Обратный вызов вызывается внутри глобальной блокировки, и он может случайно привести к тупику при переключении потоков Ruby.

ssl_timeout[RW]

Максимальная продолжительность сессии в секундах.

timeout[RW]

Максимальная продолжительность сессии в секундах.

tmp_dh_callback[RW]

Обратный вызов, вызываемый при необходимости параметров DH.

Обратный вызов вызывается с Session для обмена ключами, флагом, указывающим на использование шифра экспорта, и требуемой длиной ключа.

Обратный вызов должен вернуть экземпляр OpenSSL::PKey::DH с правильной длиной ключа.

tmp_ecdh_callback[RW]

Обратный вызов, вызываемый при необходимости параметров ECDH.

Обратный вызов вызывается с Session для обмена ключами, флагом, указывающим на использование шифра экспорта, и требуемой длиной ключа.

Обратный вызов устарел. Он не работает с последними версиями OpenSSL. Используйте #ecdh_curves= вместо этого.

verify_callback[RW]

Обратный вызов для дополнительной проверки сертификата. Вызов выполняется для каждого сертификата в цепочке.

Обратный вызов вызывается с двумя значениями. preverify_ok указывает, была ли проверка пройдена (true) или нет (false). store_context — это OpenSSL::X509::StoreContext, содержащий контекст, используемый для проверки сертификата.

Если обратный вызов возвращает false, проверка цепочки немедленно останавливается, и отправляется предупреждение bad_certificate.

verify_depth[RW]

Количество сертификатов CA для проверки при проверке цепочки сертификатов.

verify_hostname[RW]

Нужно ли проверять, является ли сертификат сервера действительным для указанного имени хоста.

Для работы необходимо установить #verify_mode в VERIFY_PEER и указать имя хоста сервера с помощью OpenSSL::SSL::SSLSocket#hostname=.

verify_mode[RW]

Режим проверки сессии.

Допустимые режимы: VERIFY_NONE, VERIFY_PEER, VERIFY_CLIENT_ONCE, VERIFY_FAIL_IF_NO_PEER_CERT, определённые в OpenSSL::SSL.

По умолчанию режим VERIFY_NONE, что не выполняет никакой проверки.

Подробности см. в SSL_CTX_set_verify(3).

Методы открытого класса

new → ctx Показать исходный код
new(:TLSv1) → ctx
new("SSLv23_client") → ctx
# 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

Методы экземпляра публичного интерфейса

ciphers → [[name, version, bits, alg_bits], ...] Показать исходный код
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;
}

Список настроенных для этого контекста наборов шифрования.

ciphers = "cipher1:cipher2:..." Показать исходный код
ciphers = [name, ...]
ciphers = [[name, version, bits, alg_bits], ...]
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.

ecdh_curves = curve_list → curve_list Показать исходный код
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)
flush_sessions(time | nil) → self Показать исходный код
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.

заморозить()
Псевдоним для: setup
параметры() Показать исходный код
static VALUE
ossl_sslctx_get_options(VALUE self)
{
    SSL_CTX *ctx;
    GetSSLCTX(self, ctx);
    return LONG2NUM(SSL_CTX_get_options(ctx));
}

Получает различные параметры OpenSSL.

параметры=(p1) Показать исходный код
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.

security_level → Целое число Показать исходный код
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=.

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).

session_add(session) → true | false Показать исходный код
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 в кэш сеансов.

session_cache_mode → Целое число Показать исходный код
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));
}

Текущий режим кэширования сеансов.

session_cache_mode=(целое число) → Целое число Показать исходный код
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).

session_cache_size → Целое число Показать исходный код
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));
}

Возвращает текущий размер кэша сессий. Ноль используется для обозначения неограниченного размера кэша.

session_cache_size=(целое число) → Целое число Показать исходный код
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;
}

Устанавливает размер кэша сессий. Возвращает ранее допустимый размер кэша сессий. Ноль используется для обозначения неограниченного размера кэша сессий.

session_cache_stats → Хэш Показать исходный код
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

Количество предложенных клиентами сессий, найденных в кэше, но истекших из-за таймаутов

session_remove(session) → true | false Показать исходный код
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 из кэша сеансов.

set_params(params = {}) → params Показать исходный код
# 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 не заданы, используется системный кэш сертификатов по умолчанию.

setup → Qtrue # первый раз Показать исходный код
setup → nil # в дальнейшем
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 в многопоточной программе.

Также используется как: заморозить
ssl_version = :TLSv1 Показать исходный код
ssl_version = "SSLv23_client"
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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API