# endif
#endif
-static SSL_CTX *ssl_server_ctx;
-static SSL_CTX *ssl_client_ctx;
+/*
+ * Use SSL_CTX_set_ecdh_auto() in OpenSSL 1.0.2 only
+ * Use SSL_CTX_set1_curves_list() in OpenSSL 1.0.2 and above
+ * TODO: Merge this into the block above if LibreSSL implements them
+ */
+#if !defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10002000L)
+# define LRB_HAVE_TLS_SET_CURVES 1
+# if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+# define LRB_HAVE_TLS_ECDH_AUTO 1
+# endif
+#endif
+
+static SSL_CTX *ssl_server_ctx = NULL;
+static SSL_CTX *ssl_client_ctx = NULL;
static int librb_index = -1;
static unsigned long
int
rb_init_ssl(void)
{
- int ret = 1;
char librb_data[] = "librb data";
- const char librb_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL";
- SSL_load_error_strings();
- SSL_library_init();
- librb_index = SSL_get_ex_new_index(0, librb_data, NULL, NULL, NULL);
-#ifndef LRB_HAVE_TLS_METHOD_API
- ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
-#else
- ssl_server_ctx = SSL_CTX_new(TLS_server_method());
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ /*
+ * OpenSSL 1.1.0 and above automatically initialises itself with sane defaults
+ */
+ SSL_library_init();
+ SSL_load_error_strings();
#endif
- if(ssl_server_ctx == NULL)
- {
- rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
- get_ssl_error(ERR_get_error()));
- ret = 0;
- }
+ librb_index = SSL_get_ex_new_index(0, librb_data, NULL, NULL, NULL);
- long server_options = SSL_CTX_get_options(ssl_server_ctx);
+ return 1;
+}
-#ifndef LRB_HAVE_TLS_METHOD_API
- server_options |= SSL_OP_NO_SSLv2;
- server_options |= SSL_OP_NO_SSLv3;
-#endif
+int
+rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list)
+{
+ const char librb_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!aNULL";
-#ifdef SSL_OP_SINGLE_DH_USE
- server_options |= SSL_OP_SINGLE_DH_USE;
-#endif
+ #ifdef LRB_HAVE_TLS_SET_CURVES
+ const char librb_curves[] = "P-521:P-384:P-256";
+ #endif
-#ifdef SSL_OP_SINGLE_ECDH_USE
- server_options |= SSL_OP_SINGLE_ECDH_USE;
-#endif
+ if(cert == NULL)
+ {
+ rb_lib_log("rb_setup_ssl_server: No certificate file");
+ return 0;
+ }
-#ifdef SSL_OP_NO_TICKET
- server_options |= SSL_OP_NO_TICKET;
-#endif
+ if(keyfile == NULL)
+ {
+ rb_lib_log("rb_setup_ssl_server: No key file");
+ return 0;
+ }
- server_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
+ if(cipher_list == NULL)
+ cipher_list = librb_ciphers;
- SSL_CTX_set_options(ssl_server_ctx, server_options);
- SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb);
- SSL_CTX_set_session_cache_mode(ssl_server_ctx, SSL_SESS_CACHE_OFF);
- SSL_CTX_set_cipher_list(ssl_server_ctx, librb_ciphers);
+ if (ssl_server_ctx)
+ SSL_CTX_free(ssl_server_ctx);
- /* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available
- * (it's not by default on Solaris or Red Hat... fuck Red Hat and Oracle)
- */
- #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && !defined(OPENSSL_NO_ECDH)
- EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1);
- if (key) {
- SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key);
- EC_KEY_free(key);
- }
- #endif
+ if (ssl_client_ctx)
+ SSL_CTX_free(ssl_client_ctx);
-#ifndef LRB_HAVE_TLS_METHOD_API
- ssl_client_ctx = SSL_CTX_new(SSLv23_client_method());
-#else
+ #ifdef LRB_HAVE_TLS_METHOD_API
+ ssl_server_ctx = SSL_CTX_new(TLS_server_method());
ssl_client_ctx = SSL_CTX_new(TLS_client_method());
-#endif
+ #else
+ ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
+ ssl_client_ctx = SSL_CTX_new(SSLv23_client_method());
+ #endif
+
+ if(ssl_server_ctx == NULL)
+ {
+ rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
+ get_ssl_error(ERR_get_error()));
+ return 0;
+ }
if(ssl_client_ctx == NULL)
{
rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
get_ssl_error(ERR_get_error()));
- ret = 0;
+ return 0;
}
-#ifndef LRB_HAVE_TLS_METHOD_API
+ #ifndef LRB_HAVE_TLS_METHOD_API
+ SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
-#endif
+ #endif
-#ifdef SSL_OP_NO_TICKET
+ #ifdef SSL_OP_SINGLE_DH_USE
+ SSL_CTX_set_options(ssl_server_ctx, SSL_OP_SINGLE_DH_USE);
+ #endif
+
+ #ifdef SSL_OP_SINGLE_ECDH_USE
+ SSL_CTX_set_options(ssl_server_ctx, SSL_OP_SINGLE_ECDH_USE);
+ #endif
+
+ #ifdef SSL_OP_NO_TICKET
+ SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_TICKET);
SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_TICKET);
-#endif
+ #endif
- SSL_CTX_set_cipher_list(ssl_client_ctx, librb_ciphers);
+ #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
+ SSL_CTX_set_options(ssl_server_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+ #endif
- return ret;
-}
+ SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb);
+ SSL_CTX_set_session_cache_mode(ssl_server_ctx, SSL_SESS_CACHE_OFF);
+ #ifdef LRB_HAVE_TLS_SET_CURVES
+ SSL_CTX_set1_curves_list(ssl_server_ctx, librb_curves);
+ #endif
-int
-rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list)
-{
- DH *dh;
- unsigned long err;
- if(cert == NULL)
- {
- rb_lib_log("rb_setup_ssl_server: No certificate file");
- return 0;
+ #ifdef LRB_HAVE_TLS_ECDH_AUTO
+ SSL_CTX_set_ecdh_auto(ssl_server_ctx, 1);
+ #endif
+
+ /*
+ * Set manual ECDHE curve on OpenSSL 1.0.0 & 1.0.1, but make sure it's actually available
+ */
+ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && (OPENSSL_VERSION_NUMBER < 0x10002000L) && !defined(OPENSSL_NO_ECDH)
+ EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1);
+ if (key) {
+ SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key);
+ EC_KEY_free(key);
}
+ #endif
+
+ SSL_CTX_set_cipher_list(ssl_server_ctx, cipher_list);
+ SSL_CTX_set_cipher_list(ssl_client_ctx, cipher_list);
+
if(!SSL_CTX_use_certificate_chain_file(ssl_server_ctx, cert) || !SSL_CTX_use_certificate_chain_file(ssl_client_ctx, cert))
{
- err = ERR_get_error();
rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert,
- get_ssl_error(err));
- return 0;
- }
-
- if(keyfile == NULL)
- {
- rb_lib_log("rb_setup_ssl_server: No key file");
+ get_ssl_error(ERR_get_error()));
return 0;
}
-
if(!SSL_CTX_use_PrivateKey_file(ssl_server_ctx, keyfile, SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(ssl_client_ctx, keyfile, SSL_FILETYPE_PEM))
{
- err = ERR_get_error();
rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile,
- get_ssl_error(err));
+ get_ssl_error(ERR_get_error()));
return 0;
}
BIO *bio = BIO_new_file(dhfile, "r");
if(bio != NULL)
{
- dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
if(dh == NULL)
{
- err = ERR_get_error();
rb_lib_log
("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
- dhfile, get_ssl_error(err));
+ dhfile, get_ssl_error(ERR_get_error()));
BIO_free(bio);
return 0;
}
BIO_free(bio);
SSL_CTX_set_tmp_dh(ssl_server_ctx, dh);
+ DH_free(dh);
}
else
{
- err = ERR_get_error();
rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
- dhfile, get_ssl_error(err));
+ dhfile, get_ssl_error(ERR_get_error()));
}
}
- if (cipher_list != NULL)
- {
- SSL_CTX_set_cipher_list(ssl_server_ctx, cipher_list);
- }
-
return 1;
}
void
rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
- struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
+ struct sockaddr *clocal, CNCB * callback, void *data, int timeout)
{
struct ssl_connect *sconn;
if(F == NULL)
sconn->data = data;
sconn->callback = callback;
sconn->timeout = timeout;
- rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
-
+ rb_connect_tcp(F, dest, clocal, rb_ssl_tryconn, sconn, timeout);
}
void
return get_ssl_error(F->ssl_errno);
}
+static int
+make_certfp(X509 *cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
+{
+ const ASN1_ITEM *it;
+ const EVP_MD *evp;
+ void *data;
+ unsigned int len;
+
+ switch(method)
+ {
+ case RB_SSL_CERTFP_METH_CERT_SHA1:
+ it = ASN1_ITEM_rptr(X509);
+ evp = EVP_sha1();
+ data = cert;
+ len = RB_SSL_CERTFP_LEN_SHA1;
+ break;
+ case RB_SSL_CERTFP_METH_CERT_SHA256:
+ it = ASN1_ITEM_rptr(X509);
+ evp = EVP_sha256();
+ data = cert;
+ len = RB_SSL_CERTFP_LEN_SHA256;
+ break;
+ case RB_SSL_CERTFP_METH_CERT_SHA512:
+ it = ASN1_ITEM_rptr(X509);
+ evp = EVP_sha512();
+ data = cert;
+ len = RB_SSL_CERTFP_LEN_SHA512;
+ break;
+ case RB_SSL_CERTFP_METH_SPKI_SHA256:
+ it = ASN1_ITEM_rptr(X509_PUBKEY);
+ evp = EVP_sha256();
+ data = X509_get_X509_PUBKEY(cert);
+ len = RB_SSL_CERTFP_LEN_SHA256;
+ break;
+ case RB_SSL_CERTFP_METH_SPKI_SHA512:
+ it = ASN1_ITEM_rptr(X509_PUBKEY);
+ evp = EVP_sha512();
+ data = X509_get_X509_PUBKEY(cert);
+ len = RB_SSL_CERTFP_LEN_SHA512;
+ break;
+ default:
+ return 0;
+ }
+
+ if (ASN1_item_digest(it, evp, data, certfp, &len) != 1)
+ len = 0;
+ return (int) len;
+}
+
int
rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
{
+ int len = 0;
X509 *cert;
int res;
return 0;
cert = SSL_get_peer_certificate((SSL *) F->ssl);
- if(cert != NULL)
+ if(cert == NULL)
+ return 0;
+
+ res = SSL_get_verify_result((SSL *) F->ssl);
+ switch(res)
{
- res = SSL_get_verify_result((SSL *) F->ssl);
- if(
- res == X509_V_OK ||
- res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
- res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
- res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
- res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
- {
- const EVP_MD *evp;
- unsigned int len;
+ case X509_V_OK:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ len = make_certfp(cert, certfp, method);
+
+ default: /* to silence code inspectors */
+ break;
+ }
- switch(method)
- {
- case RB_SSL_CERTFP_METH_SHA1:
- evp = EVP_sha1();
- len = RB_SSL_CERTFP_LEN_SHA1;
- break;
- case RB_SSL_CERTFP_METH_SHA256:
- evp = EVP_sha256();
- len = RB_SSL_CERTFP_LEN_SHA256;
- break;
- case RB_SSL_CERTFP_METH_SHA512:
- evp = EVP_sha512();
- len = RB_SSL_CERTFP_LEN_SHA512;
- break;
- default:
- return 0;
- }
+ X509_free(cert);
+ return len;
+}
- X509_digest(cert, evp, certfp, &len);
- X509_free(cert);
- return len;
- }
+int
+rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
+{
+ X509 *cert;
+ FILE *f = fopen(filename, "r");
+
+ if (!f)
+ return -1;
+
+ cert = PEM_read_X509(f, NULL, NULL, NULL);
+ fclose(f);
+
+ if (cert) {
+ unsigned int len = make_certfp(cert, certfp, method);
X509_free(cert);
+ return len;
}
-
return 0;
}
return SSL_CIPHER_get_name(sslciph);
}
-#endif /* HAVE_OPESSL */
+#endif /* HAVE_OPENSSL */