summaryrefslogtreecommitdiff
path: root/ext/openssl/ossl_ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/openssl/ossl_ssl.c')
-rw-r--r--ext/openssl/ossl_ssl.c319
1 files changed, 286 insertions, 33 deletions
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 7fe06c0937..99a4fe3e97 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -152,7 +152,7 @@ ossl_sslctx_s_alloc(VALUE klass)
* ctx.ssl_version = :TLSv1
* ctx.ssl_version = "SSLv23_client"
*
- * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS
+ * You can get a list of valid versions with OpenSSL::SSL::SSLContext::METHODS
*/
static VALUE
ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
@@ -527,7 +527,8 @@ ssl_servername_cb(SSL *ssl, int *ad, void *arg)
* ctx.setup => nil # thereafter
*
* This method is called automatically when a new SSLSocket is created.
- * Normally you do not need to call this method (unless you are writing an extension in C).
+ * Normally you do not need to call this method (unless you are writing an
+ * extension in C).
*/
static VALUE
ossl_sslctx_setup(VALUE self)
@@ -687,6 +688,8 @@ ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher)
/*
* call-seq:
* ctx.ciphers => [[name, version, bits, alg_bits], ...]
+ *
+ * The list of ciphers configured for this context.
*/
static VALUE
ossl_sslctx_get_ciphers(VALUE self)
@@ -769,6 +772,7 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
* call-seq:
* ctx.session_add(session) -> true | false
*
+ * Adds +session+ to the session cache
*/
static VALUE
ossl_sslctx_session_add(VALUE self, VALUE arg)
@@ -786,6 +790,7 @@ ossl_sslctx_session_add(VALUE self, VALUE arg)
* call-seq:
* ctx.session_remove(session) -> true | false
*
+ * Removes +session+ from the session cache
*/
static VALUE
ossl_sslctx_session_remove(VALUE self, VALUE arg)
@@ -801,8 +806,9 @@ ossl_sslctx_session_remove(VALUE self, VALUE arg)
/*
* call-seq:
- * ctx.session_cache_mode -> integer
+ * ctx.session_cache_mode -> Integer
*
+ * The current session cache mode.
*/
static VALUE
ossl_sslctx_get_session_cache_mode(VALUE self)
@@ -816,8 +822,11 @@ ossl_sslctx_get_session_cache_mode(VALUE self)
/*
* call-seq:
- * ctx.session_cache_mode=(integer) -> integer
+ * ctx.session_cache_mode=(integer) -> Integer
*
+ * Sets the SSL session cache mode. Bitwise-or together the desired
+ * SESSION_CACHE_* constants to set. See SSL_CTX_set_session_cache_mode(3) for
+ * details.
*/
static VALUE
ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
@@ -833,8 +842,10 @@ ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
/*
* call-seq:
- * ctx.session_cache_size -> integer
+ * ctx.session_cache_size -> Integer
*
+ * Returns the current session cache size. Zero is used to represent an
+ * unlimited cache size.
*/
static VALUE
ossl_sslctx_get_session_cache_size(VALUE self)
@@ -848,8 +859,10 @@ ossl_sslctx_get_session_cache_size(VALUE self)
/*
* call-seq:
- * ctx.session_cache_size=(integer) -> integer
+ * ctx.session_cache_size=(integer) -> Integer
*
+ * Sets the session cache size. Returns the previously valid session cache
+ * size. Zero is used to represent an unlimited session cache size.
*/
static VALUE
ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
@@ -867,6 +880,23 @@ ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
* call-seq:
* ctx.session_cache_stats -> Hash
*
+ * Returns a Hash containing the following keys:
+ *
+ * :accept:: Number of started SSL/TLS handshakes in server mode
+ * :accept_good:: Number of established SSL/TLS sessions in server mode
+ * :accept_renegotiate:: Number of start renegotiations in server mode
+ * :cache_full:: Number of sessions that were removed due to cache overflow
+ * :cache_hits:: Number of successfully reused connections
+ * :cache_misses:: Number of sessions proposed by clients that were not found
+ * in the cache
+ * :cache_num:: Number of sessions in the internal session cache
+ * :cb_hits:: Number of sessions retrieved from the external cache in server
+ * mode
+ * :connect:: Number of started SSL/TLS handshakes in client mode
+ * :connect_good:: Number of established SSL/TLS sessions in client mode
+ * :connect_renegotiate:: Number of start renegotiations in client mode
+ * :timeouts:: Number of sessions proposed by clients that were found in the
+ * cache but had expired due to timeouts
*/
static VALUE
ossl_sslctx_get_session_cache_stats(VALUE self)
@@ -898,6 +928,7 @@ ossl_sslctx_get_session_cache_stats(VALUE self)
* call-seq:
* ctx.flush_sessions(time | nil) -> self
*
+ * Removes sessions in the internal cache that have expired at +time+.
*/
static VALUE
ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
@@ -953,9 +984,11 @@ ossl_ssl_s_alloc(VALUE klass)
* SSLSocket.new(io) => aSSLSocket
* SSLSocket.new(io, ctx) => aSSLSocket
*
- * === Parameters
- * * +io+ is a real ruby IO object. Not an IO like object that responds to read/write.
- * * +ctx+ is an OpenSSLSSL::SSLContext.
+ * Creates a new SSL socket from +io+ which must be a real ruby 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.
*
@@ -1101,6 +1134,9 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, int nonblock)
/*
* call-seq:
* ssl.connect => self
+ *
+ * Initiates an SSL/TLS handshake with a server. The handshake may be started
+ * after unencrypted data has been sent over the socket.
*/
static VALUE
ossl_ssl_connect(VALUE self)
@@ -1113,7 +1149,7 @@ ossl_ssl_connect(VALUE self)
* call-seq:
* ssl.connect_nonblock => self
*
- * initiate the TLS/SSL handshake as a client in non-blocking manner.
+ * Initiates the SSL/TLS handshake as a client in non-blocking manner.
*
* # emulates blocking connect
* begin
@@ -1137,6 +1173,9 @@ ossl_ssl_connect_nonblock(VALUE self)
/*
* call-seq:
* ssl.accept => self
+ *
+ * Waits for a SSL/TLS client to initiate a handshake. The handshake may be
+ * started after unencrypted data has been sent over the socket.
*/
static VALUE
ossl_ssl_accept(VALUE self)
@@ -1149,7 +1188,7 @@ ossl_ssl_accept(VALUE self)
* call-seq:
* ssl.accept_nonblock => self
*
- * initiate the TLS/SSL handshake as a server in non-blocking manner.
+ * Initiates the SSL/TLS handshake as a server in non-blocking manner.
*
* # emulates blocking accept
* begin
@@ -1235,9 +1274,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
* ssl.sysread(length) => string
* ssl.sysread(length, buffer) => buffer
*
- * === Parameters
- * * +length+ is a positive integer.
- * * +buffer+ is a string used to store the result.
+ * 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)
@@ -1250,9 +1288,11 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self)
* ssl.sysread_nonblock(length) => string
* ssl.sysread_nonblock(length, buffer) => buffer
*
- * === Parameters
- * * +length+ is a positive integer.
- * * +buffer+ is a string used to store the result.
+ * A non-blocking version of #sysread. Raises an SSLError if reading would
+ * block.
+ *
+ * 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_nonblock(int argc, VALUE *argv, VALUE self)
@@ -1304,7 +1344,9 @@ ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
/*
* call-seq:
- * ssl.syswrite(string) => integer
+ * ssl.syswrite(string) => Integer
+ *
+ * Writes +string+ to the SSL connection.
*/
static VALUE
ossl_ssl_write(VALUE self, VALUE str)
@@ -1314,7 +1356,10 @@ ossl_ssl_write(VALUE self, VALUE str)
/*
* call-seq:
- * ssl.syswrite_nonblock(string) => integer
+ * ssl.syswrite_nonblock(string) => Integer
+ *
+ * Writes +string+ to the SSL connection in a non-blocking manner. Raises an
+ * SSLError if writing would block.
*/
static VALUE
ossl_ssl_write_nonblock(VALUE self, VALUE str)
@@ -1325,6 +1370,8 @@ ossl_ssl_write_nonblock(VALUE self, VALUE str)
/*
* call-seq:
* ssl.sysclose => nil
+ *
+ * Shuts down the SSL connection and prepares it for another connection.
*/
static VALUE
ossl_ssl_close(VALUE self)
@@ -1342,6 +1389,8 @@ ossl_ssl_close(VALUE self)
/*
* call-seq:
* ssl.cert => cert or nil
+ *
+ * The X509 certificate for this socket endpoint.
*/
static VALUE
ossl_ssl_get_cert(VALUE self)
@@ -1370,6 +1419,8 @@ ossl_ssl_get_cert(VALUE self)
/*
* call-seq:
* ssl.peer_cert => cert or nil
+ *
+ * The X509 certificate for this socket's peer.
*/
static VALUE
ossl_ssl_get_peer_cert(VALUE self)
@@ -1399,6 +1450,8 @@ ossl_ssl_get_peer_cert(VALUE self)
/*
* call-seq:
* ssl.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)
@@ -1429,6 +1482,8 @@ ossl_ssl_get_peer_cert_chain(VALUE self)
/*
* call-seq:
* ssl.cipher => [name, version, bits, alg_bits]
+ *
+ * The cipher being used for the current connection
*/
static VALUE
ossl_ssl_get_cipher(VALUE self)
@@ -1449,6 +1504,8 @@ ossl_ssl_get_cipher(VALUE self)
/*
* call-seq:
* ssl.state => string
+ *
+ * A description of the current connection state.
*/
static VALUE
ossl_ssl_get_state(VALUE self)
@@ -1471,7 +1528,9 @@ ossl_ssl_get_state(VALUE self)
/*
* call-seq:
- * ssl.pending => integer
+ * ssl.pending => Integer
+ *
+ * The number of bytes that are immediately available for reading
*/
static VALUE
ossl_ssl_pending(VALUE self)
@@ -1488,9 +1547,10 @@ ossl_ssl_pending(VALUE self)
}
/*
- * call-seq:
- * ssl.session_reused? -> true | false
+ * call-seq:
+ * ssl.session_reused? -> true | false
*
+ * Returns true if a reused session was negotiated during the handshake.
*/
static VALUE
ossl_ssl_session_reused(VALUE self)
@@ -1511,9 +1571,10 @@ ossl_ssl_session_reused(VALUE self)
}
/*
- * call-seq:
- * ssl.session = session -> session
+ * call-seq:
+ * ssl.session = session -> session
*
+ * Sets the Session to be used when the connection is established.
*/
static VALUE
ossl_ssl_set_session(VALUE self, VALUE arg1)
@@ -1538,6 +1599,15 @@ ossl_ssl_set_session(VALUE self, VALUE arg1)
return arg1;
}
+/*
+ * call-seq:
+ * ssl.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)
{
@@ -1558,8 +1628,8 @@ Init_ossl_ssl()
int i;
VALUE ary;
-#if 0 /* let rdoc know about mOSSL */
- mOSSL = rb_define_module("OpenSSL");
+#if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
#endif
ID_callback_state = rb_intern("@callback_state");
@@ -1577,18 +1647,161 @@ Init_ossl_ssl()
Init_ossl_ssl_session();
- /* class SSLContext
+ /* Document-class: OpenSSL::SSL::SSLContext
*
- * The following attributes are available but don't show up in rdoc.
- * All attributes must be set before calling SSLSocket.new(io, ctx).
+ * An SSLContext is used to set various options regarding certificates,
+ * algorithms, verification, session caching, etc. The SSLContext is
+ * used to create an SSLSocket.
+ *
+ * All attributes must be set before creating an SSLSocket as the
+ * SSLContext will be frozen afterward.
+ *
+ * The following attributes are available but don't show up in rdoc:
* * ssl_version, cert, key, client_ca, ca_file, ca_path, timeout,
* * verify_mode, verify_depth client_cert_cb, tmp_dh_callback,
* * session_id_context, session_add_cb, session_new_cb, session_remove_cb
*/
cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject);
rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc);
- for(i = 0; i < numberof(ossl_sslctx_attrs); i++)
- rb_attr(cSSLContext, rb_intern(ossl_sslctx_attrs[i]), 1, 1, Qfalse);
+
+ /*
+ * Context certificate
+ */
+ rb_attr(cSSLContext, rb_intern("cert"), 1, 1, Qfalse);
+
+ /*
+ * Context private key
+ */
+ rb_attr(cSSLContext, rb_intern("key"), 1, 1, Qfalse);
+
+ /*
+ * A certificate or Array of certificates that will be sent to the client.
+ */
+ rb_attr(cSSLContext, rb_intern("client_ca"), 1, 1, Qfalse);
+
+ /*
+ * The path to a file containing a PEM-format CA certificate
+ */
+ rb_attr(cSSLContext, rb_intern("ca_file"), 1, 1, Qfalse);
+
+ /*
+ * The path to a directory containing CA certificates in PEM format.
+ *
+ * Files are looked up by subject's X509 name's hash value.
+ */
+ rb_attr(cSSLContext, rb_intern("ca_path"), 1, 1, Qfalse);
+
+ /*
+ * Maximum session lifetime.
+ */
+ rb_attr(cSSLContext, rb_intern("timeout"), 1, 1, Qfalse);
+
+ /*
+ * Session verification mode.
+ *
+ * Valid modes are VERIFY_NONE, VERIFY_PEER, VERIFY_CLIENT_ONCE,
+ * VERIFY_FAIL_IF_NO_PEER_CERT and defined on OpenSSL::SSL
+ */
+ rb_attr(cSSLContext, rb_intern("verify_mode"), 1, 1, Qfalse);
+
+ /*
+ * Number of CA certificates to walk when verifying a certificate chain.
+ */
+ rb_attr(cSSLContext, rb_intern("verify_depth"), 1, 1, Qfalse);
+
+ /*
+ * A callback for additional certificate verification. The callback is
+ * invoked for each certificate in the chain.
+ *
+ * The callback is invoked with two values. +preverify_ok+ indicates
+ * indicates if the verification was passed (true) or not (false).
+ * +store_context+ is an OpenSSL::X509::StoreContext containing the
+ * context used for certificate verification.
+ *
+ * If the callback returns false verification is stopped.
+ */
+ rb_attr(cSSLContext, rb_intern("verify_callback"), 1, 1, Qfalse);
+
+ /*
+ * Sets various OpenSSL options.
+ */
+ rb_attr(cSSLContext, rb_intern("options"), 1, 1, Qfalse);
+
+ /*
+ * An OpenSSL::X509::Store used for certificate verification
+ */
+ rb_attr(cSSLContext, rb_intern("cert_store"), 1, 1, Qfalse);
+
+ /*
+ * An Array of extra X509 certificates to be added to the certificate
+ * chain.
+ */
+ rb_attr(cSSLContext, rb_intern("extra_chain_cert"), 1, 1, Qfalse);
+
+ /*
+ * A callback invoked when a client certificate is requested by a server
+ * and no certificate has been set.
+ *
+ * The callback is invoked with a Session and must return an Array
+ * containing an OpenSSL::X509::Certificate and an OpenSSL::PKey. If any
+ * other value is returned the handshake is suspended.
+ */
+ rb_attr(cSSLContext, rb_intern("client_cert_cb"), 1, 1, Qfalse);
+
+ /*
+ * A callback invoked when DH parameters are required.
+ *
+ * The callback is invoked with the Session for the key exchange, an
+ * flag indicating the use of an export cipher and the keylength
+ * required.
+ *
+ * The callback must return an OpenSSL::PKey::DH instance of the correct
+ * key length.
+ */
+ rb_attr(cSSLContext, rb_intern("tmp_dh_callback"), 1, 1, Qfalse);
+
+ /*
+ * Sets the context in which a session can be reused. This allows
+ * sessions for multiple applications to be distinguished, for exapmle, by
+ * name.
+ */
+ rb_attr(cSSLContext, rb_intern("session_id_context"), 1, 1, Qfalse);
+
+ /*
+ * A callback invoked on a server when a session is proposed by the client
+ * but the session could not be found in the server's internal cache.
+ *
+ * The callback is invoked with the SSLSocket and session id. The
+ * callback may return a Session from an external cache.
+ */
+ rb_attr(cSSLContext, rb_intern("session_get_cb"), 1, 1, Qfalse);
+
+ /*
+ * A callback invoked when a new session was negotiatied.
+ *
+ * The callback is invoked with an SSLSocket. If false is returned the
+ * session will be removed from the internal cache.
+ */
+ rb_attr(cSSLContext, rb_intern("session_new_cb"), 1, 1, Qfalse);
+
+ /*
+ * A callback invoked when a session is removed from the internal cache.
+ *
+ * The callback is invoked with an SSLContext and a Session.
+ */
+ rb_attr(cSSLContext, rb_intern("session_remove_cb"), 1, 1, Qfalse);
+
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+ /*
+ * A callback invoked at connect time to distinguish between multiple
+ * server names.
+ *
+ * The callback is invoked with an SSLSocket and a server name. The
+ * callback must return an SSLContext for the server name or nil.
+ */
+ rb_attr(cSSLContext, rb_intern("servername_cb"), 1, 1, Qfalse);
+#endif
+
rb_define_alias(cSSLContext, "ssl_timeout", "timeout");
rb_define_alias(cSSLContext, "ssl_timeout=", "timeout=");
rb_define_method(cSSLContext, "initialize", ossl_sslctx_initialize, -1);
@@ -1599,14 +1812,53 @@ Init_ossl_ssl()
rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
+ /*
+ * No session caching for client or server
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF));
+
+ /*
+ * Client sessions are added to the session cache
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */
+
+ /*
+ * Server sessions are added to the session cache
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER));
+
+ /*
+ * Both client and server sessions are added to the session cache
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */
+
+ /*
+ * Normally the sesison cache is checked for expired sessions every 255
+ * connections. Since this may lead to a delay that cannot be controlled,
+ * the automatic flushing may be disabled and #flush_sessions can be
+ * called explicitly.
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR));
+
+ /*
+ * Always perform external lookups of sessions even if they are in the
+ * internal cache.
+ *
+ * This flag has no effect on clients
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP));
+
+ /*
+ * Never automatically store sessions in the internal store.
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE));
+
+ /*
+ * Enables both SESSION_CACHE_NO_INTERNAL_LOOKUP and
+ * SESSION_CACHE_NO_INTERNAL_STORE.
+ */
rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL));
+
rb_define_method(cSSLContext, "session_add", ossl_sslctx_session_add, 1);
rb_define_method(cSSLContext, "session_remove", ossl_sslctx_session_remove, 1);
rb_define_method(cSSLContext, "session_cache_mode", ossl_sslctx_get_session_cache_mode, 0);
@@ -1621,10 +1873,11 @@ Init_ossl_ssl()
rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name)));
}
rb_obj_freeze(ary);
- /* holds a list of available SSL/TLS methods */
+ /* The list of available SSL/TLS methods */
rb_define_const(cSSLContext, "METHODS", ary);
- /* class SSLSocket
+ /*
+ * Document-class: OpenSSL::SSL::SSLSocket
*
* The following attributes are available but don't show up in rdoc.
* * io, context, sync_close