class OpenSSL::SSL::SSLSocket

Attributes

context [R]

The SSLContext object used in this connection.

hostname [R]
io [R]

The underlying IO object.

sync_close [RW]

Whether to close the underlying socket as well, when the SSL/TLS connection is shut down. This defaults to false.

to_io [R]

The underlying IO object.

Public Class Methods

new(io) → aSSLSocket
new(io, ctx) → aSSLSocket

Creates a new SSL socket from io which must be a real IO object (not an IO-like object that responds to read/write).

If ctx is provided the SSL Sockets initial params will be taken from the context.

The OpenSSL::Buffering module provides additional IO methods.

This method will freeze the SSLContext if one is provided; however, session management is still allowed in the frozen SSLContext.

static VALUE
ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
{
    VALUE io, v_ctx, verify_cb;
    SSL *ssl;
    SSL_CTX *ctx;

    TypedData_Get_Struct(self, SSL, &ossl_ssl_type, ssl);
    if (ssl)
        ossl_raise(eSSLError, "SSL already initialized");

    if (rb_scan_args(argc, argv, "11", &io, &v_ctx) == 1)
        v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);

    GetSSLCTX(v_ctx, ctx);
    rb_ivar_set(self, id_i_context, v_ctx);
    ossl_sslctx_setup(v_ctx);

    if (rb_respond_to(io, rb_intern("nonblock=")))
        rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
    Check_Type(io, T_FILE);
    rb_ivar_set(self, id_i_io, io);

    ssl = SSL_new(ctx);
    if (!ssl)
        ossl_raise(eSSLError, NULL);
    RTYPEDDATA_DATA(self) = ssl;

    SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self);
    SSL_set_info_callback(ssl, ssl_info_cb);
    verify_cb = rb_attr_get(v_ctx, id_i_verify_callback);
    // We don't need to trigger a write barrier because it's already
    // an instance variable of this object.
    SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)verify_cb);

    rb_call_super(0, NULL);

    return self;
}
open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)

Creates a new instance of SSLSocket. remotehost_ and remoteport_ are used to open TCPSocket. If localhost_ and localport_ are specified, then those parameters are used on the local end to establish the connection. If context is provided, the SSL Sockets initial params will be taken from the context.

Examples

sock = OpenSSL::SSL::SSLSocket.open('localhost', 443)
sock.connect # Initiates a connection to localhost:443

with SSLContext:

ctx = OpenSSL::SSL::SSLContext.new
sock = OpenSSL::SSL::SSLSocket.open('localhost', 443, context: ctx)
sock.connect # Initiates a connection to localhost:443 with SSLContext
# File ext/openssl/lib/openssl/ssl.rb, line 534
def open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)
  sock = ::TCPSocket.open(remote_host, remote_port, local_host, local_port)
  if context.nil?
    return OpenSSL::SSL::SSLSocket.new(sock)
  else
    return OpenSSL::SSL::SSLSocket.new(sock, context)
  end
end

Public Instance Methods

accept → self

Waits for a SSL/TLS client to initiate a handshake.

static VALUE
ossl_ssl_accept(VALUE self)
{
    ossl_ssl_setup(self);

    return ossl_start_ssl(self, SSL_accept, "SSL_accept", Qfalse);
}
accept_nonblock([options]) → self

Initiates the SSL/TLS handshake as a server in non-blocking manner.

# emulates blocking accept
begin
  ssl.accept_nonblock
rescue IO::WaitReadable
  IO.select([s2])
  retry
rescue IO::WaitWritable
  IO.select(nil, [s2])
  retry
end

By specifying a keyword argument exception to false, you can indicate that accept_nonblock should not raise an IO::WaitReadable or IO::WaitWritable exception, but return the symbol :wait_readable or :wait_writable instead.

static VALUE
ossl_ssl_accept_nonblock(int argc, VALUE *argv, VALUE self)
{
    VALUE opts;

    rb_scan_args(argc, argv, "0:", &opts);
    ossl_ssl_setup(self);

    return ossl_start_ssl(self, SSL_accept, "SSL_accept", opts);
}
alpn_protocol → String | nil

Returns the ALPN protocol string that was finally selected by the server during the handshake.

static VALUE
ossl_ssl_alpn_protocol(VALUE self)
{
    SSL *ssl;
    const unsigned char *out;
    unsigned int outlen;

    GetSSL(self, ssl);

    SSL_get0_alpn_selected(ssl, &out, &outlen);
    if (!outlen)
        return Qnil;
    else
        return rb_str_new((const char *) out, outlen);
}
cert → cert or nil

The X509 certificate for this socket endpoint.

static VALUE
ossl_ssl_get_cert(VALUE self)
{
    SSL *ssl;
    X509 *cert = NULL;

    GetSSL(self, ssl);

    /*
     * Is this OpenSSL bug? Should add a ref?
     * TODO: Ask for.
     */
    cert = SSL_get_certificate(ssl); /* NO DUPs => DON'T FREE. */

    if (!cert) {
        return Qnil;
    }
    return ossl_x509_new(cert);
}
cipher → nil or [name, version, bits, alg_bits]

Returns the cipher suite actually used in the current session, or nil if no session has been established.

static VALUE
ossl_ssl_get_cipher(VALUE self)
{
    SSL *ssl;
    const SSL_CIPHER *cipher;

    GetSSL(self, ssl);
    cipher = SSL_get_current_cipher(ssl);
    return cipher ? ossl_ssl_cipher_to_ary(cipher) : Qnil;
}
client_ca → [x509name, ...]

Returns the list of client CAs. Please note that in contrast to SSLContext#client_ca= no array of X509::Certificate is returned but X509::Name instances of the CA’s subject distinguished name.

In server mode, returns the list set by SSLContext#client_ca=. In client mode, returns the list of client CAs sent from the server.

static VALUE
ossl_ssl_get_client_ca_list(VALUE self)
{
    SSL *ssl;
    STACK_OF(X509_NAME) *ca;

    GetSSL(self, ssl);

    ca = SSL_get_client_CA_list(ssl);
    return ossl_x509name_sk2ary(ca);
}
close_read ()

Close the stream for reading. This method is ignored by OpenSSL as there is no reasonable way to implement it, but exists for compatibility with IO.

# File ext/openssl/lib/openssl/ssl.rb, line 465
def close_read
  # Unsupported and ignored.
  # Just don't read any more.
end
close_write ()

Closes the stream for writing. The behavior of this method depends on the version of OpenSSL and the TLS protocol in use.

  • Sends a ‘close_notify’ alert to the peer.

  • Does not wait for the peer’s ‘close_notify’ alert in response.

In TLS 1.2 and earlier:

  • On receipt of a ‘close_notify’ alert, responds with a ‘close_notify’ alert of its own and close down the connection immediately, discarding any pending writes.

Therefore, on TLS 1.2, this method will cause the connection to be completely shut down. On TLS 1.3, the connection will remain open for reading only.

# File ext/openssl/lib/openssl/ssl.rb, line 484
def close_write
  stop
end
connect → self

Initiates an SSL/TLS handshake with a server.

static VALUE
ossl_ssl_connect(VALUE self)
{
    ossl_ssl_setup(self);

    return ossl_start_ssl(self, SSL_connect, "SSL_connect", Qfalse);
}
connect_nonblock([options]) → self

Initiates the SSL/TLS handshake as a client in non-blocking manner.

# emulates blocking connect
begin
  ssl.connect_nonblock
rescue IO::WaitReadable
  IO.select([s2])
  retry
rescue IO::WaitWritable
  IO.select(nil, [s2])
  retry
end

By specifying a keyword argument exception to false, you can indicate that connect_nonblock should not raise an IO::WaitReadable or IO::WaitWritable exception, but return the symbol :wait_readable or :wait_writable instead.

static VALUE
ossl_ssl_connect_nonblock(int argc, VALUE *argv, VALUE self)
{
    VALUE opts;
    rb_scan_args(argc, argv, "0:", &opts);

    ossl_ssl_setup(self);

    return ossl_start_ssl(self, SSL_connect, "SSL_connect", opts);
}
export_keying_material(label, length) → String

Enables use of shared session key material in accordance with RFC 5705.

static VALUE
ossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self)
{
    SSL *ssl;
    VALUE str;
    VALUE label;
    VALUE length;
    VALUE context;
    unsigned char *p;
    size_t len;
    int use_ctx = 0;
    unsigned char *ctx = NULL;
    size_t ctx_len = 0;
    int ret;

    rb_scan_args(argc, argv, "21", &label, &length, &context);
    StringValue(label);

    GetSSL(self, ssl);

    len = (size_t)NUM2LONG(length);
    str = rb_str_new(0, len);
    p = (unsigned char *)RSTRING_PTR(str);
    if (!NIL_P(context)) {
        use_ctx = 1;
        StringValue(context);
        ctx = (unsigned char *)RSTRING_PTR(context);
        ctx_len = RSTRING_LEN(context);
    }
    ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label),
                                     RSTRING_LENINT(label), ctx, ctx_len, use_ctx);
    if (ret == 0 || ret == -1) {
        ossl_raise(eSSLError, "SSL_export_keying_material");
    }
    return str;
}
finished_message → "finished message"

Returns the last Finished message sent

static VALUE
ossl_ssl_get_finished(VALUE self)
{
    SSL *ssl;
    char sizer[1], *buf;
    size_t len;

    GetSSL(self, ssl);

    len = SSL_get_finished(ssl, sizer, 0);
    if (len == 0)
        return Qnil;

    buf = ALLOCA_N(char, len);
    SSL_get_finished(ssl, buf, len);
    return rb_str_new(buf, len);
}
hostname = hostname → hostname

Sets the server hostname used for SNI. This needs to be set before SSLSocket#connect.

static VALUE
ossl_ssl_set_hostname(VALUE self, VALUE arg)
{
    SSL *ssl;
    char *hostname = NULL;

    GetSSL(self, ssl);

    if (!NIL_P(arg))
        hostname = StringValueCStr(arg);

    if (!SSL_set_tlsext_host_name(ssl, hostname))
        ossl_raise(eSSLError, NULL);

    /* for SSLSocket#hostname */
    rb_ivar_set(self, id_i_hostname, arg);

    return arg;
}
npn_protocol → String | nil

Returns the protocol string that was finally selected by the client during the handshake.

static VALUE
ossl_ssl_npn_protocol(VALUE self)
{
    SSL *ssl;
    const unsigned char *out;
    unsigned int outlen;

    GetSSL(self, ssl);

    SSL_get0_next_proto_negotiated(ssl, &out, &outlen);
    if (!outlen)
        return Qnil;
    else
        return rb_str_new((const char *) out, outlen);
}
peer_cert → cert or nil

The X509 certificate for this socket’s peer.

static VALUE
ossl_ssl_get_peer_cert(VALUE self)
{
    SSL *ssl;
    X509 *cert = NULL;
    VALUE obj;

    GetSSL(self, ssl);

    cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */

    if (!cert) {
        return Qnil;
    }
    obj = ossl_x509_new(cert);
    X509_free(cert);

    return obj;
}
peer_cert_chain → [cert, ...] or nil

The X509 certificate chain for this socket’s peer.

static VALUE
ossl_ssl_get_peer_cert_chain(VALUE self)
{
    SSL *ssl;
    STACK_OF(X509) *chain;
    X509 *cert;
    VALUE ary;
    int i, num;

    GetSSL(self, ssl);

    chain = SSL_get_peer_cert_chain(ssl);
    if(!chain) return Qnil;
    num = sk_X509_num(chain);
    ary = rb_ary_new2(num);
    for (i = 0; i < num; i++){
        cert = sk_X509_value(chain, i);
        rb_ary_push(ary, ossl_x509_new(cert));
    }

    return ary;
}
peer_finished_message → "peer finished message"

Returns the last Finished message received

static VALUE
ossl_ssl_get_peer_finished(VALUE self)
{
    SSL *ssl;
    char sizer[1], *buf;
    size_t len;

    GetSSL(self, ssl);

    len = SSL_get_peer_finished(ssl, sizer, 0);
    if (len == 0)
        return Qnil;

    buf = ALLOCA_N(char, len);
    SSL_get_peer_finished(ssl, buf, len);
    return rb_str_new(buf, len);
}
pending → Integer

The number of bytes that are immediately available for reading.

static VALUE
ossl_ssl_pending(VALUE self)
{
    SSL *ssl;

    GetSSL(self, ssl);

    return INT2NUM(SSL_pending(ssl));
}
post_connection_check(hostname) → true

Perform hostname verification following RFC 6125.

This method MUST be called after calling connect to ensure that the hostname of a remote peer has been verified.

# File ext/openssl/lib/openssl/ssl.rb, line 435
def post_connection_check(hostname)
  if peer_cert.nil?
    msg = "Peer verification enabled, but no certificate received."
    if using_anon_cipher?
      msg += " Anonymous cipher suite #{cipher[0]} was negotiated. " \
             "Anonymous suites must be disabled to use peer verification."
    end
    raise SSLError, msg
  end

  unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
    raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
  end
  return true
end
session → aSession

Returns the SSLSession object currently used, or nil if the session is not established.

# File ext/openssl/lib/openssl/ssl.rb, line 456
def session
  SSL::Session.new(self)
rescue SSL::Session::SessionError
  nil
end
session = session → session

Sets the Session to be used when the connection is established.

static VALUE
ossl_ssl_set_session(VALUE self, VALUE arg1)
{
    SSL *ssl;
    SSL_SESSION *sess;

    GetSSL(self, ssl);
    GetSSLSession(arg1, sess);

    if (SSL_set_session(ssl, sess) != 1)
        ossl_raise(eSSLError, "SSL_set_session");

    return arg1;
}
session_reused? → true | false

Returns true if a reused session was negotiated during the handshake.

static VALUE
ossl_ssl_session_reused(VALUE self)
{
    SSL *ssl;

    GetSSL(self, ssl);

    return SSL_session_reused(ssl) ? Qtrue : Qfalse;
}
ssl_version → String

Returns a String representing the SSL/TLS version that was negotiated for the connection, for example “TLSv1.2”.

static VALUE
ossl_ssl_get_version(VALUE self)
{
    SSL *ssl;

    GetSSL(self, ssl);

    return rb_str_new2(SSL_get_version(ssl));
}
state → string

A description of the current connection state. This is for diagnostic purposes only.

static VALUE
ossl_ssl_get_state(VALUE self)
{
    SSL *ssl;
    VALUE ret;

    GetSSL(self, ssl);

    ret = rb_str_new2(SSL_state_string(ssl));
    if (ruby_verbose) {
        rb_str_cat2(ret, ": ");
        rb_str_cat2(ret, SSL_state_string_long(ssl));
    }
    return ret;
}
sysclose → nil

Sends “close notify” to the peer and tries to shut down the SSL connection gracefully.

If sync_close is set to true, the underlying IO is also closed.

# File ext/openssl/lib/openssl/ssl.rb, line 422
def sysclose
  return if closed?
  stop
  io.close if sync_close
end
sysread(length) → string
sysread(length, buffer) → buffer

Reads length bytes from the SSL connection. If a pre-allocated buffer is provided the data will be written into it.

static VALUE
ossl_ssl_read(int argc, VALUE *argv, VALUE self)
{
    return ossl_ssl_read_internal(argc, argv, self, 0);
}
syswrite(string) → Integer

Writes string to the SSL connection.

static VALUE
ossl_ssl_write(VALUE self, VALUE str)
{
    return ossl_ssl_write_internal(self, str, Qfalse);
}
tmp_key → PKey or nil

Returns the ephemeral key used in case of forward secrecy cipher.

static VALUE
ossl_ssl_tmp_key(VALUE self)
{
    SSL *ssl;
    EVP_PKEY *key;

    GetSSL(self, ssl);
    if (!SSL_get_server_tmp_key(ssl, &key))
        return Qnil;
    return ossl_pkey_new(key);
}
verify_result → Integer

Returns the result of the peer certificates verification. See verify(1) for error values and descriptions.

If no peer certificate was presented X509_V_OK is returned.

static VALUE
ossl_ssl_get_verify_result(VALUE self)
{
    SSL *ssl;

    GetSSL(self, ssl);

    return LONG2NUM(SSL_get_verify_result(ssl));
}