]> jfr.im git - solanum.git/blobdiff - librb/src/openssl.c
[openssl] Forward-port some more cleanups from fixes to 3.5
[solanum.git] / librb / src / openssl.c
index eea76c6f98c70bb490743e62a40b08486a4a245c..79326bda9faad943fed2dd59fc0e9137bc31cee3 100644 (file)
@@ -20,7 +20,6 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
  *  USA
  *
- *  $Id: commio.c 24808 2008-01-02 08:17:05Z androsyn $
  */
 
 #include <librb_config.h>
 #  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
@@ -313,120 +324,131 @@ get_ssl_error(unsigned long err)
 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;
        }
 
@@ -436,32 +458,26 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, c
                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;
 }
 
@@ -576,7 +592,7 @@ rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
 
 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)
@@ -586,8 +602,7 @@ rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
        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
@@ -687,9 +702,59 @@ rb_get_ssl_strerror(rb_fde_t *F)
        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;
 
@@ -697,44 +762,45 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
                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;
 }
 
@@ -766,4 +832,4 @@ rb_ssl_get_cipher(rb_fde_t *F)
        return SSL_CIPHER_get_name(sslciph);
 }
 
-#endif /* HAVE_OPESSL */
+#endif /* HAVE_OPENSSL */