Class: Puma::MiniSSL::Engine
| Relationships & Source Files | |
| Inherits: | Object |
| Defined in: | ext/puma_http11/mini_ssl.c |
Class Method Summary
Instance Attribute Summary
- #init? ⇒ Boolean readonly
Instance Method Summary
Class Method Details
.client
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 297
VALUE engine_init_client(VALUE klass) {
VALUE obj;
ms_conn* conn = engine_alloc(klass, &obj);
#ifdef HAVE_DTLS_METHOD
conn->ctx = SSL_CTX_new(DTLS_method());
#else
conn->ctx = SSL_CTX_new(DTLSv1_method());
#endif
conn->ssl = SSL_new(conn->ctx);
SSL_set_app_data(conn->ssl, NULL);
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
SSL_set_bio(conn->ssl, conn->read, conn->write);
SSL_set_connect_state(conn->ssl);
return obj;
}
.server(mini_ssl_ctx)
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 162
VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
VALUE obj, session_id_bytes;
SSL_CTX* ctx;
SSL* ssl;
int min, ssl_options;
ms_conn* conn = engine_alloc(self, &obj);
ID sym_key = rb_intern("key");
VALUE key = rb_funcall(mini_ssl_ctx, sym_key, 0);
StringValue(key);
ID sym_cert = rb_intern("cert");
VALUE cert = rb_funcall(mini_ssl_ctx, sym_cert, 0);
StringValue(cert);
ID sym_ca = rb_intern("ca");
VALUE ca = rb_funcall(mini_ssl_ctx, sym_ca, 0);
ID sym_verify_mode = rb_intern("verify_mode");
VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
ID sym_no_tlsv1 = rb_intern("no_tlsv1");
VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0);
ID sym_no_tlsv1_1 = rb_intern("no_tlsv1_1");
VALUE no_tlsv1_1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1_1, 0);
#ifdef HAVE_TLS_SERVER_METHOD
ctx = SSL_CTX_new(TLS_server_method());
#else
ctx = SSL_CTX_new(SSLv23_server_method());
#endif
conn->ctx = ctx;
SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert));
SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
if (!NIL_P(ca)) {
StringValue(ca);
SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
}
ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
if (RTEST(no_tlsv1_1)) {
min = TLS1_2_VERSION;
}
else if (RTEST(no_tlsv1)) {
min = TLS1_1_VERSION;
}
else {
min = TLS1_VERSION;
}
SSL_CTX_set_min_proto_version(ctx, min);
SSL_CTX_set_options(ctx, ssl_options);
#else
/* As of 1.0.2f, SSL_OP_SINGLE_DH_USE key use is always on */
ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE;
if (RTEST(no_tlsv1)) {
ssl_options |= SSL_OP_NO_TLSv1;
}
if(RTEST(no_tlsv1_1)) {
ssl_options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
}
SSL_CTX_set_options(ctx, ssl_options);
#endif
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
if (!NIL_P(ssl_cipher_filter)) {
StringValue(ssl_cipher_filter);
SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
}
else {
SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
}
// Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
session_id_bytes = rb_funcall(
#ifdef HAVE_RANDOM_BYTES
rb_cRandom,
#else
rb_const_get(rb_cRandom, rb_intern_const("DEFAULT")),
#endif
rb_intern_const("bytes"),
1, ULL2NUM(SSL_MAX_SSL_SESSION_ID_LENGTH));
SSL_CTX_set_session_id_context(ctx,
(unsigned char *) RSTRING_PTR(session_id_bytes),
SSL_MAX_SSL_SESSION_ID_LENGTH);
DH *dh = get_dh2048();
SSL_CTX_set_tmp_dh(ctx, dh);
#if OPENSSL_VERSION_NUMBER < 0x10002000L
// Remove this case if OpenSSL 1.0.1 (now EOL) support is no
// longer needed.
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ecdh) {
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
}
#elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
// Prior to OpenSSL 1.1.0, servers must manually enable server-side ECDH
// negotiation.
SSL_CTX_set_ecdh_auto(ctx, 1);
#endif
ssl = SSL_new(ctx);
conn->ssl = ssl;
SSL_set_app_data(ssl, NULL);
if (NIL_P(verify_mode)) {
/* SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); */
} else {
SSL_set_verify(ssl, NUM2INT(verify_mode), engine_verify_callback);
}
SSL_set_bio(ssl, conn->read, conn->write);
SSL_set_accept_state(ssl);
return obj;
}
Instance Attribute Details
#init? ⇒ Boolean (readonly)
[ GitHub ]
# File 'ext/puma_http11/mini_ssl.c', line 453
VALUE engine_init(VALUE self) {
ms_conn* conn;
Data_Get_Struct(self, ms_conn, conn);
return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
}
Instance Method Details
#extract
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 416
VALUE engine_extract(VALUE self) {
ms_conn* conn;
int bytes;
size_t pending;
char buf[512];
Data_Get_Struct(self, ms_conn, conn);
pending = BIO_pending(conn->write);
if(pending > 0) {
bytes = BIO_read(conn->write, buf, sizeof(buf));
if(bytes > 0) {
return rb_str_new(buf, bytes);
} else if(!BIO_should_retry(conn->write)) {
raise_error(conn->ssl, bytes);
}
}
return Qnil;
}
#inject(str)
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 315
VALUE engine_inject(VALUE self, VALUE str) {
ms_conn* conn;
long used;
Data_Get_Struct(self, ms_conn, conn);
StringValue(str);
used = BIO_write(conn->read, RSTRING_PTR(str), (int)RSTRING_LEN(str));
if(used == 0 || used == -1) {
return Qfalse;
}
return INT2FIX(used);
}
#peercert
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 461
VALUE engine_peercert(VALUE self) {
ms_conn* conn;
X509* cert;
int bytes;
unsigned char* buf = NULL;
ms_cert_buf* cert_buf = NULL;
VALUE rb_cert_buf;
Data_Get_Struct(self, ms_conn, conn);
cert = SSL_get_peer_certificate(conn->ssl);
if(!cert) {
/*
* See if there was a failed certificate associated with this client.
*/
cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
if(!cert_buf) {
return Qnil;
}
buf = cert_buf->buf;
bytes = cert_buf->bytes;
} else {
bytes = i2d_X509(cert, &buf);
X509_free(cert);
if(bytes < 0) {
return Qnil;
}
}
rb_cert_buf = rb_str_new((const char*)(buf), bytes);
if(!cert_buf) {
OPENSSL_free(buf);
}
return rb_cert_buf;
}
#read
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 366
VALUE engine_read(VALUE self) {
ms_conn* conn;
char buf[512];
int bytes, error;
Data_Get_Struct(self, ms_conn, conn);
ERR_clear_error();
bytes = SSL_read(conn->ssl, (void*)buf, sizeof(buf));
if(bytes > 0) {
return rb_str_new(buf, bytes);
}
if(SSL_want_read(conn->ssl)) return Qnil;
error = SSL_get_error(conn->ssl, bytes);
if(error == SSL_ERROR_ZERO_RETURN) {
rb_eof_error();
} else {
raise_error(conn->ssl, bytes);
}
return Qnil;
}
#shutdown
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 437
VALUE engine_shutdown(VALUE self) {
ms_conn* conn;
int ok;
Data_Get_Struct(self, ms_conn, conn);
ERR_clear_error();
ok = SSL_shutdown(conn->ssl);
if (ok == 0) {
return Qfalse;
}
return Qtrue;
}
#write(str)
[ GitHub ]# File 'ext/puma_http11/mini_ssl.c', line 394
VALUE engine_write(VALUE self, VALUE str) {
ms_conn* conn;
int bytes;
Data_Get_Struct(self, ms_conn, conn);
StringValue(str);
ERR_clear_error();
bytes = SSL_write(conn->ssl, (void*)RSTRING_PTR(str), (int)RSTRING_LEN(str));
if(bytes > 0) {
return INT2FIX(bytes);
}
if(SSL_want_write(conn->ssl)) return Qnil;
raise_error(conn->ssl, bytes);
return Qnil;
}