LCOV - code coverage report
Current view: top level - src/tds - tls.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 308 401 76.8 %
Date: 2025-12-12 14:13:32 Functions: 19 22 86.4 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Brian Bruns
       3             :  * Copyright (C) 2004-2015  Ziglio Frediano
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU Library General Public
       7             :  * License as published by the Free Software Foundation; either
       8             :  * version 2 of the License, or (at your option) any later version.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * Library General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU Library General Public
      16             :  * License along with this library; if not, write to the
      17             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18             :  * Boston, MA 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : /* enabled some additional definitions for inet_pton */
      24             : #define _WIN32_WINNT 0x600
      25             : 
      26             : #include <stdio.h>
      27             : 
      28             : #if HAVE_ERRNO_H
      29             : #include <errno.h>
      30             : #endif /* HAVE_ERRNO_H */
      31             : 
      32             : #if HAVE_UNISTD_H
      33             : #include <unistd.h>
      34             : #endif /* HAVE_UNISTD_H */
      35             : 
      36             : #if HAVE_STDLIB_H
      37             : #include <stdlib.h>
      38             : #endif /* HAVE_STDLIB_H */
      39             : 
      40             : #if HAVE_STRING_H
      41             : #include <string.h>
      42             : #endif /* HAVE_STRING_H */
      43             : 
      44             : #if HAVE_DIRENT_H
      45             : #include <dirent.h>
      46             : #endif /* HAVE_DIRENT_H */
      47             : 
      48             : #if HAVE_SYS_STAT_H
      49             : #include <sys/stat.h>
      50             : #endif /* HAVE_SYS_STAT_H */
      51             : 
      52             : #ifdef HAVE_SYS_SOCKET_H
      53             : #include <sys/socket.h>
      54             : #endif
      55             : 
      56             : #include <freetds/tds.h>
      57             : #include <freetds/utils/string.h>
      58             : #include <freetds/utils.h>
      59             : #include <freetds/tls.h>
      60             : #include <freetds/alloca.h>
      61             : #include <freetds/replacements.h>
      62             : 
      63             : #include <assert.h>
      64             : 
      65             : /**
      66             :  * \addtogroup network
      67             :  * @{ 
      68             :  */
      69             : 
      70             : #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
      71             : 
      72             : #ifdef HAVE_GNUTLS
      73             : #define SSL_RET ssize_t
      74             : #define SSL_PULL_ARGS gnutls_transport_ptr_t ptr, void *data, size_t len
      75             : #define SSL_PUSH_ARGS gnutls_transport_ptr_t ptr, const void *data, size_t len
      76             : #define SSL_PTR ptr
      77             : #else
      78             : 
      79             : /* some compatibility layer */
      80             : #if !HAVE_BIO_GET_DATA
      81             : static inline void
      82             : BIO_set_init(BIO *b, int init)
      83             : {
      84             :         b->init = init;
      85             : }
      86             : 
      87             : static inline void
      88             : BIO_set_data(BIO *b, void *ptr)
      89             : {
      90             :         b->ptr = ptr;
      91             : }
      92             : 
      93             : static inline void *
      94             : BIO_get_data(const BIO *b)
      95             : {
      96             :         return b->ptr;
      97             : }
      98             : #define TLS_client_method SSLv23_client_method
      99             : #define TLS_ST_OK SSL_ST_OK
     100             : #endif
     101             : 
     102             : #define SSL_RET int
     103             : #define SSL_PULL_ARGS BIO *bio, char *data, int len
     104             : #define SSL_PUSH_ARGS BIO *bio, const char *data, int len
     105             : #define SSL_PTR BIO_get_data(bio)
     106             : #endif
     107             : 
     108             : #if !HAVE_ASN1_STRING_GET0_DATA
     109             : #define ASN1_STRING_get0_data(x) ASN1_STRING_data(x)
     110             : #endif
     111             : 
     112             : #if ENABLE_ODBC_MARS
     113             : #define CONN2TDS(conn) (conn->in_net_tds)
     114             : #else
     115             : #define CONN2TDS(conn) ((TDSSOCKET *) conn)
     116             : #endif
     117             : 
     118             : /* tds/8.0 */
     119             : #define TDS8_ALPN_ARRAY 't', 'd', 's', '/', '8', '.', '0'
     120             : #define TDS8_ALPN_ARRAY_LEN 7
     121             : 
     122             : static SSL_RET
     123       18916 : tds_pull_func_login(SSL_PULL_ARGS)
     124             : {
     125       18916 :         TDSSOCKET *tds = (TDSSOCKET *) SSL_PTR;
     126             :         int have;
     127             : 
     128       18916 :         tdsdump_log(TDS_DBG_FUNC, "in tds_pull_func_login\n");
     129             :         
     130             :         /* here we are initializing (crypted inside TDS packets) */
     131             : 
     132             :         /* if we have some data send it */
     133             :         /* here MARS is not already initialized so test is correct */
     134             :         /* TODO test even after initializing ?? */
     135       18916 :         if (tds->out_pos > 8)
     136        4364 :                 tds_flush_packet(tds);
     137             : 
     138             :         for(;;) {
     139       23280 :                 have = tds->in_len - tds->in_pos;
     140       23280 :                 assert(have >= 0);
     141       23280 :                 if (have > 0)
     142             :                         break;
     143        4364 :                 if (tds_read_packet(tds) < 0)
     144             :                         return -1;
     145             :         }
     146       18916 :         if (len > have)
     147           0 :                 len = have;
     148       18916 :         memcpy(data, tds->in_buf + tds->in_pos, len);
     149       18916 :         tds->in_pos += len;
     150       18916 :         return len;
     151             : }
     152             : 
     153             : static SSL_RET
     154        6546 : tds_push_func_login(SSL_PUSH_ARGS)
     155             : {
     156        6546 :         TDSSOCKET *tds = (TDSSOCKET *) SSL_PTR;
     157             : 
     158        6546 :         tdsdump_log(TDS_DBG_FUNC, "in tds_push_func_login\n");
     159             : 
     160             :         /* initializing SSL, write crypted data inside normal TDS packets */
     161        6546 :         tds_put_n(tds, data, len);
     162        6546 :         return len;
     163             : }
     164             : 
     165             : static SSL_RET
     166       87441 : tds_pull_func(SSL_PULL_ARGS)
     167             : {
     168       87441 :         TDSCONNECTION *conn = (TDSCONNECTION *) SSL_PTR;
     169             :         TDSSOCKET *tds;
     170             : 
     171       87441 :         tdsdump_log(TDS_DBG_FUNC, "in tds_pull_func\n");
     172             : 
     173       87441 :         tds = CONN2TDS(conn);
     174       87441 :         assert(tds);
     175             : 
     176             :         /* already initialized (crypted TDS packets) */
     177             : 
     178             :         /* read directly from socket */
     179             :         /* TODO we block write on other sessions */
     180             :         /* also we should already have tested for data on socket */
     181       87441 :         return tds_goodread(tds, (unsigned char*) data, len);
     182             : }
     183             : 
     184             : static SSL_RET
     185       36222 : tds_push_func(SSL_PUSH_ARGS)
     186             : {
     187       36222 :         TDSCONNECTION *conn = (TDSCONNECTION *) SSL_PTR;
     188             :         TDSSOCKET *tds;
     189             : 
     190       36222 :         tdsdump_log(TDS_DBG_FUNC, "in tds_push_func\n");
     191             : 
     192             :         /* write to socket directly */
     193       36222 :         tds = CONN2TDS(conn);
     194       36222 :         return tds_goodwrite(tds, (const unsigned char*) data, len);
     195             : }
     196             : 
     197             : static int tls_initialized = 0;
     198             : static tds_mutex tls_mutex = TDS_MUTEX_INITIALIZER;
     199             : 
     200             : #if ENABLE_ODBC_MARS
     201             : static void
     202             : set_current_tds(TDSCONNECTION *conn, TDSSOCKET *tds)
     203             : {
     204        1091 :         tds_mutex_lock(&conn->list_mtx);
     205        1091 :         conn->in_net_tds = tds;
     206        1091 :         tds_mutex_unlock(&conn->list_mtx);
     207             : }
     208             : #else
     209             : static inline void
     210             : set_current_tds(TDSCONNECTION *conn TDS_UNUSED, TDSSOCKET *tds TDS_UNUSED)
     211             : {
     212             : }
     213             : #endif
     214             : 
     215             : static const char *
     216             : wanted_certificate_hostname(TDSLOGIN *login)
     217             : {
     218        2182 :         if (!tds_dstr_isempty(&login->certificate_host_name))
     219           0 :                 return tds_dstr_cstr(&login->certificate_host_name);
     220             : 
     221        1091 :         return tds_dstr_cstr(&login->server_host_name);
     222             : }
     223             : 
     224             : #ifdef HAVE_GNUTLS
     225             : 
     226             : static void
     227         366 : tds_tls_log( int level, const char* s)
     228             : {
     229         366 :         tdsdump_log(TDS_DBG_INFO1, "GNUTLS: level %d:\n  %s", level, s);
     230         366 : }
     231             : 
     232             : #ifdef TDS_ATTRIBUTE_DESTRUCTOR
     233             : static void __attribute__((destructor))
     234        1127 : tds_tls_deinit(void)
     235             : {
     236        1127 :         if (tls_initialized)
     237         580 :                 gnutls_global_deinit();
     238        1127 : }
     239             : #endif
     240             : 
     241             : #if defined(_THREAD_SAFE) && defined(TDS_HAVE_PTHREAD_MUTEX) && !defined(GNUTLS_USE_NETTLE)
     242             : GCRY_THREAD_OPTION_PTHREAD_IMPL;
     243             : #define tds_gcry_init() gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread)
     244             : #else
     245             : #define tds_gcry_init() do {} while(0)
     246             : #endif
     247             : 
     248             : /* This piece of code is copied from GnuTLS new sources to handle IP in the certificate */
     249             : #if GNUTLS_VERSION_NUMBER < 0x030306
     250             : static int
     251             : check_ip(gnutls_x509_crt_t cert, const void *ip, unsigned ip_size)
     252             : {
     253             :         char temp[16];
     254             :         size_t temp_size;
     255             :         unsigned i;
     256             :         int ret = 0;
     257             : 
     258             :         /* try matching against:
     259             :          *  1) a IPaddress alternative name (subjectAltName) extension
     260             :          *     in the certificate
     261             :          */
     262             : 
     263             :         /* Check through all included subjectAltName extensions, comparing
     264             :          * against all those of type IPAddress.
     265             :          */
     266             :         for (i = 0; ret >= 0; ++i) {
     267             :                 temp_size = sizeof(temp);
     268             :                 ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
     269             :                                                            temp,
     270             :                                                            &temp_size,
     271             :                                                            NULL);
     272             : 
     273             :                 if (ret == GNUTLS_SAN_IPADDRESS) {
     274             :                         if (temp_size == ip_size && memcmp(temp, ip, ip_size) == 0)
     275             :                                 return 1;
     276             :                 } else if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
     277             :                         ret = 0;
     278             :                 }
     279             :         }
     280             : 
     281             :         /* not found a matching IP */
     282             :         return 0;
     283             : }
     284             : 
     285             : static int
     286             : tds_check_ip(gnutls_x509_crt_t cert, const char *hostname)
     287             : {
     288             :         int ret;
     289             :         union {
     290             :                 struct in_addr v4;
     291             :                 struct in6_addr v6;
     292             :         } ip;
     293             :         unsigned ip_size;
     294             : 
     295             :         /* check whether @hostname is an ip address */
     296             :         if (strchr(hostname, ':') != NULL) {
     297             :                 ip_size = 16;
     298             :                 ret = inet_pton(AF_INET6, hostname, &ip.v6);
     299             :         } else {
     300             :                 ip_size = 4;
     301             :                 ret = inet_pton(AF_INET, hostname, &ip.v4);
     302             :         }
     303             : 
     304             :         if (ret != 0)
     305             :                 ret = check_ip(cert, &ip, ip_size);
     306             : 
     307             :         /* There are several misconfigured servers, that place their IP
     308             :          * in the DNS field of subjectAlternativeName. Don't break these
     309             :          * configurations and verify the IP as it would have been a DNS name. */
     310             : 
     311             :         return ret;
     312             : }
     313             : 
     314             : /* function for replacing old GnuTLS version */
     315             : static int
     316             : tds_x509_crt_check_hostname(gnutls_x509_crt_t cert, const char *hostname)
     317             : {
     318             :         int ret;
     319             : 
     320             :         ret = tds_check_ip(cert, hostname);
     321             :         if (ret)
     322             :                 return ret;
     323             : 
     324             :         return gnutls_x509_crt_check_hostname(cert, hostname);
     325             : }
     326             : #define gnutls_x509_crt_check_hostname tds_x509_crt_check_hostname
     327             : 
     328             : #endif
     329             : 
     330             : #if GNUTLS_VERSION_MAJOR < 3
     331             : static int
     332             : tds_certificate_set_x509_system_trust(gnutls_certificate_credentials_t cred)
     333             : {
     334             :         static const char ca_directory[] = "/etc/ssl/certs";
     335             :         DIR *dir;
     336             :         struct dirent *dent;
     337             : #ifdef HAVE_READDIR_R
     338             :         struct dirent ent;
     339             : #endif
     340             :         int rc;
     341             :         int ncerts;
     342             :         size_t ca_file_length;
     343             :         char *ca_file;
     344             : 
     345             : 
     346             :         dir = opendir(ca_directory);
     347             :         if (!dir)
     348             :                 return 0;
     349             : 
     350             :         ca_file_length = strlen(ca_directory) + sizeof(dent->d_name) + 2;
     351             :         ca_file = alloca(ca_file_length);
     352             : 
     353             :         ncerts = 0;
     354             :         for (;;) {
     355             :                 struct stat st;
     356             : 
     357             : #ifdef HAVE_READDIR_R
     358             :                 if (readdir_r(dir, &ent, &dent))
     359             :                         dent = NULL;
     360             : #else
     361             :                 dent = readdir(dir);
     362             : #endif
     363             :                 if (!dent)
     364             :                         break;
     365             : 
     366             :                 snprintf(ca_file, ca_file_length, "%s/%s", ca_directory, dent->d_name);
     367             :                 if (stat(ca_file, &st) != 0)
     368             :                         continue;
     369             : 
     370             :                 if (!S_ISREG(st.st_mode))
     371             :                         continue;
     372             : 
     373             :                 rc = gnutls_certificate_set_x509_trust_file(cred, ca_file, GNUTLS_X509_FMT_PEM);
     374             :                 if (rc >= 0)
     375             :                         ncerts += rc;
     376             :         }
     377             : 
     378             :         closedir(dir);
     379             :         return ncerts;
     380             : }
     381             : #define gnutls_certificate_set_x509_system_trust tds_certificate_set_x509_system_trust
     382             : 
     383             : #endif
     384             : 
     385             : static int
     386           0 : tds_verify_certificate(gnutls_session_t session, TDSSOCKET *tds)
     387             : {
     388             :         unsigned int status;
     389             :         int ret;
     390             : 
     391             : #ifdef ENABLE_DEVELOPING
     392             :         unsigned int list_size;
     393             :         const gnutls_datum_t *cert_list;
     394             : #endif
     395             : 
     396           0 :         if (!tds->login) {
     397           0 :                 tdsdump_log(TDS_DBG_ERROR, "No login while checking certificate\n");
     398             :                 return GNUTLS_E_CERTIFICATE_ERROR;
     399             :         }
     400             : 
     401           0 :         ret = gnutls_certificate_verify_peers2(session, &status);
     402           0 :         if (ret < 0) {
     403           0 :                 tdsdump_log(TDS_DBG_ERROR, "Error verifying certificate: %s\n", gnutls_strerror(ret));
     404             :                 return GNUTLS_E_CERTIFICATE_ERROR;
     405             :         }
     406             : 
     407             : #ifdef ENABLE_DEVELOPING
     408             :         cert_list = gnutls_certificate_get_peers(session, &list_size);
     409             :         if (cert_list) {
     410             :                 gnutls_x509_crt_t cert;
     411             :                 gnutls_datum_t cinfo;
     412             :                 char buf[8192];
     413             :                 size_t size;
     414             : 
     415             :                 gnutls_x509_crt_init(&cert);
     416             : 
     417             :                 gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
     418             : 
     419             :                 /* This is the preferred way of printing short information about
     420             :                  * a certificate. */
     421             :                 size = sizeof(buf);
     422             :                 ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, buf, &size);
     423             :                 if (ret == 0) {
     424             :                         FILE *f = fopen("cert.dat", "wb");
     425             :                         if (f) {
     426             :                                 fwrite(buf, size, 1, f);
     427             :                                 fclose(f);
     428             :                         }
     429             :                 }
     430             : 
     431             :                 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo);
     432             :                 if (ret == 0) {
     433             :                         tdsdump_log(TDS_DBG_INFO1, "Certificate info: %s\n", cinfo.data);
     434             :                         gnutls_free(cinfo.data);
     435             :                 }
     436             : 
     437             :                 gnutls_x509_crt_deinit(cert);
     438             :         }
     439             : #endif
     440             : 
     441             :         /* Certificate is not trusted */
     442           0 :         if (status != 0) {
     443           0 :                 tdsdump_log(TDS_DBG_ERROR, "Certificate status: %u\n", status);
     444             :                 return GNUTLS_E_CERTIFICATE_ERROR;
     445             :         }
     446             : 
     447             :         /* check hostname */
     448           0 :         if (tds->login->check_ssl_hostname) {
     449             :                 const gnutls_datum_t *cert_list;
     450             :                 unsigned int list_size;
     451             :                 gnutls_x509_crt_t cert;
     452             : 
     453           0 :                 cert_list = gnutls_certificate_get_peers(session, &list_size);
     454           0 :                 if (!cert_list) {
     455           0 :                         tdsdump_log(TDS_DBG_ERROR, "Error getting TLS session peers\n");
     456           0 :                         return GNUTLS_E_CERTIFICATE_ERROR;
     457             :                 }
     458           0 :                 gnutls_x509_crt_init(&cert);
     459           0 :                 gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
     460           0 :                 ret = gnutls_x509_crt_check_hostname(cert, wanted_certificate_hostname(tds->login));
     461           0 :                 gnutls_x509_crt_deinit(cert);
     462           0 :                 if (!ret) {
     463           0 :                         tdsdump_log(TDS_DBG_ERROR, "Certificate hostname does not match\n");
     464             :                         return GNUTLS_E_CERTIFICATE_ERROR;
     465             :                 }
     466             :         }
     467             : 
     468             :         /* notify gnutls to continue handshake normally */
     469             :         return 0;
     470             : }
     471             : 
     472             : static int
     473           0 : tds_verify_certificate_tds(gnutls_session_t session)
     474             : {
     475           0 :         TDSSOCKET *tds = (TDSSOCKET *) gnutls_transport_get_ptr(session);
     476             : 
     477           0 :         return tds_verify_certificate(session, tds);
     478             : }
     479             : 
     480             : static int
     481           0 : tds_verify_certificate_conn(gnutls_session_t session)
     482             : {
     483           0 :         TDSCONNECTION *conn = (TDSCONNECTION*) gnutls_transport_get_ptr(session);
     484             : 
     485           0 :         return tds_verify_certificate(session, CONN2TDS(conn));
     486             : }
     487             : 
     488             : TDSRET
     489        1091 : tds_ssl_init(TDSSOCKET *tds, bool full)
     490             : {
     491             :         gnutls_session_t session;
     492             :         gnutls_certificate_credentials_t xcred;
     493             :         int ret;
     494             :         const char *tls_msg;
     495             :         int (*verify_func)(gnutls_session_t session);
     496             : 
     497        1091 :         xcred = NULL;
     498        1091 :         session = NULL; 
     499        1091 :         tls_msg = "initializing tls";
     500             : 
     501        1091 :         if (!tls_initialized) {
     502         580 :                 ret = 0;
     503         580 :                 tds_mutex_lock(&tls_mutex);
     504         580 :                 if (!tls_initialized) {
     505             :                         tds_gcry_init();
     506         580 :                         ret = gnutls_global_init();
     507         580 :                         if (ret == 0)
     508         580 :                                 tls_initialized = 1;
     509             :                 }
     510         580 :                 tds_mutex_unlock(&tls_mutex);
     511         580 :                 if (ret != 0)
     512             :                         goto cleanup;
     513             :         }
     514             : 
     515        1091 :         if (tds_write_dump && tls_initialized < 2) {
     516           2 :                 gnutls_global_set_log_level(11);
     517           2 :                 gnutls_global_set_log_function(tds_tls_log);
     518           2 :                 tls_initialized = 2;
     519             :         }
     520             : 
     521        1091 :         tls_msg = "allocating credentials";
     522        1091 :         ret = gnutls_certificate_allocate_credentials(&xcred);
     523        1091 :         if (ret != 0)
     524             :                 goto cleanup;
     525             : 
     526             :         /* Initialize TLS session */
     527        1091 :         tls_msg = "initializing session";
     528        1091 :         ret = gnutls_init(&session, GNUTLS_CLIENT);
     529        1091 :         if (ret != 0)
     530             :                 goto cleanup;
     531             : 
     532        1091 :         if (!full) {
     533        1091 :                 gnutls_transport_set_ptr(session, tds);
     534        1091 :                 gnutls_transport_set_pull_function(session, tds_pull_func_login);
     535        1091 :                 gnutls_transport_set_push_function(session, tds_push_func_login);
     536        1091 :                 verify_func = tds_verify_certificate_tds;
     537             :         } else {
     538           0 :                 gnutls_transport_set_ptr(session, tds->conn);
     539           0 :                 gnutls_transport_set_pull_function(session, tds_pull_func);
     540           0 :                 gnutls_transport_set_push_function(session, tds_push_func);
     541           0 :                 verify_func = tds_verify_certificate_conn;
     542             :         }
     543             : 
     544        2182 :         if (!tds_dstr_isempty(&tds->login->cafile)) {
     545           0 :                 tls_msg = "loading CA file";
     546           0 :                 if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
     547           0 :                         ret = gnutls_certificate_set_x509_system_trust(xcred);
     548             :                 else
     549           0 :                         ret = gnutls_certificate_set_x509_trust_file(xcred, tds_dstr_cstr(&tds->login->cafile), GNUTLS_X509_FMT_PEM);
     550           0 :                 if (ret <= 0)
     551             :                         goto cleanup;
     552           0 :                 if (!tds_dstr_isempty(&tds->login->crlfile)) {
     553           0 :                         tls_msg = "loading CRL file";
     554           0 :                         ret = gnutls_certificate_set_x509_crl_file(xcred, tds_dstr_cstr(&tds->login->crlfile), GNUTLS_X509_FMT_PEM);
     555           0 :                         if (ret <= 0)
     556             :                                 goto cleanup;
     557             :                 }
     558             : #ifdef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION
     559           0 :                 gnutls_certificate_set_verify_function(xcred, verify_func);
     560             : #endif
     561             :         }
     562             : 
     563             :         /* use default priorities unless overridden by gnutls ciphers setting in freetds.conf file... */
     564        2182 :         if (!tds_dstr_isempty(&tds->login->gnutls_ciphers)) {
     565           0 :                 tdsdump_log(TDS_DBG_INFO1, "setting custom gnutls ciphers to:%s\n", tds_dstr_cstr(&tds->login->gnutls_ciphers));
     566           0 :                 gnutls_priority_set_direct(session, tds_dstr_cstr(&tds->login->gnutls_ciphers), NULL);
     567             :         } else {
     568             :                 /* NOTE: these functions return int however they cannot fail */
     569             : 
     570             :                 /* use default priorities... */
     571        1091 :                 gnutls_set_default_priority(session);
     572             : 
     573             : #ifdef HAVE_GNUTLS_SET_DEFAULT_PRIORITY_APPEND
     574             :                 gnutls_session_enable_compatibility_mode(session);
     575             : #define set_ciphers(session, ciphers) \
     576             :         gnutls_set_default_priority_append(session, "" ciphers, NULL, 0)
     577             : #else
     578             : #define set_ciphers(session, ciphers) \
     579             :         gnutls_priority_set_direct(session, "NORMAL:%COMPAT:" ciphers, NULL)
     580             : #endif
     581             : 
     582             :                 /* ... but overwrite some */
     583        1091 :                 if (tds->login && tds->login->enable_tls_v1)
     584         727 :                         ret = set_ciphers(session, "-VERS-SSL3.0:+VERS-TLS1.0:+VERS-TLS1.1");
     585         364 :                 else if (tds->login && tds->login->enable_tls_v1_1)
     586           0 :                         ret = set_ciphers(session, "-VERS-SSL3.0:-VERS-TLS1.0:+VERS-TLS1.1");
     587             :                 else
     588         364 :                         ret = set_ciphers(session, "-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1");
     589        1091 :                 if (ret != 0)
     590             :                         goto cleanup;
     591             :         }
     592             : 
     593             :         /* mssql does not like padding too much */
     594             : #ifdef HAVE_GNUTLS_RECORD_DISABLE_PADDING
     595        1091 :         gnutls_record_disable_padding(session);
     596             : #endif
     597             : 
     598             :         /* put the anonymous credentials to the current session */
     599        1091 :         tls_msg = "setting credential";
     600        1091 :         ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
     601        1091 :         if (ret != 0)
     602             :                 goto cleanup;
     603             : 
     604             : #ifdef HAVE_GNUTLS_ALPN_SET_PROTOCOLS
     605        1091 :         if (IS_TDS80_PLUS(tds->conn)) {
     606             :                 static const unsigned char alpn[] = { TDS8_ALPN_ARRAY };
     607             :                 static const gnutls_datum_t tds8_alpn = { (void*) alpn, sizeof(alpn) };
     608           0 :                 gnutls_alpn_set_protocols(session, &tds8_alpn, 1, 0);
     609             :         }
     610             : #endif
     611             : 
     612        1091 :         if (full)
     613           0 :                 set_current_tds(tds->conn, tds);
     614             : 
     615             :         /* Perform the TLS handshake */
     616        1091 :         tls_msg = "handshake";
     617        1091 :         ret = gnutls_handshake (session);
     618        1091 :         if (ret != 0)
     619             :                 goto cleanup;
     620             : 
     621             : #ifndef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION
     622             :         if (!tds_dstr_isempty(&tds->login->cafile)) {
     623             :                 ret = tds_verify_certificate(session, tds);
     624             :                 if (ret != 0)
     625             :                         goto cleanup;
     626             :         }
     627             : #endif
     628             : 
     629        1091 :         tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");
     630             : 
     631        1091 :         if (!full) {
     632             :                 /* some TLS implementations send some sort of paddind at the end, remove it */
     633        1091 :                 tds->in_pos = tds->in_len;
     634             : 
     635        1091 :                 gnutls_transport_set_ptr(session, tds->conn);
     636        1091 :                 gnutls_transport_set_pull_function(session, tds_pull_func);
     637        1091 :                 gnutls_transport_set_push_function(session, tds_push_func);
     638             :         }
     639             : 
     640        2182 :         set_current_tds(tds->conn, NULL);
     641             : 
     642        1091 :         tds->conn->tls_session = session;
     643        1091 :         tds->conn->tls_credentials = xcred;
     644             : 
     645        1091 :         return TDS_SUCCESS;
     646             : 
     647           0 : cleanup:
     648           0 :         if (session)
     649           0 :                 gnutls_deinit(session);
     650           0 :         set_current_tds(tds->conn, NULL);
     651           0 :         if (xcred)
     652           0 :                 gnutls_certificate_free_credentials(xcred);
     653           0 :         tdsdump_log(TDS_DBG_ERROR, "%s failed: %s\n", tls_msg, gnutls_strerror (ret));
     654             :         return TDS_FAIL;
     655             : }
     656             : 
     657             : void
     658        4904 : tds_ssl_deinit(TDSCONNECTION *conn)
     659             : {
     660        4904 :         if (conn->tls_session) {
     661        1085 :                 gnutls_deinit((gnutls_session_t) conn->tls_session);
     662        1085 :                 conn->tls_session = NULL;
     663             :         }
     664        4904 :         if (conn->tls_credentials) {
     665        1085 :                 gnutls_certificate_free_credentials((gnutls_certificate_credentials_t) conn->tls_credentials);
     666        1085 :                 conn->tls_credentials = NULL;
     667             :         }
     668        4904 :         conn->encrypt_single_packet = 0;
     669        4904 : }
     670             : 
     671             : size_t
     672         360 : tds_ssl_get_cb(TDSCONNECTION *conn, void *cb, size_t cblen)
     673             : {
     674             :         int rc;
     675             :         gnutls_datum_t unique;
     676             : 
     677             :         /* No CBT, skip channel binding */
     678         360 :         if (!conn->tls_session)
     679             :                 return 0;
     680             : 
     681         360 :         rc = gnutls_session_channel_binding((gnutls_session_t) conn->tls_session, GNUTLS_CB_TLS_UNIQUE, &unique);
     682         360 :         if (rc) {
     683           0 :                 tdsdump_log(TDS_DBG_ERROR, "tds_ssl_get_cb: failed to get tls-unique: %s\n", gnutls_strerror(rc));
     684             :                 return 0;
     685             :         }
     686         360 :         if (unique.size > cblen) {
     687           0 :                 tdsdump_log(TDS_DBG_ERROR, "tds_ssl_get_cb: buffer overflow getting get tls-unique\n");
     688             :                 return 0;
     689             :         }
     690         360 :         memcpy(cb, unique.data, unique.size);
     691         360 :         gnutls_free(unique.data);
     692         360 :         return unique.size;
     693             : }
     694             : 
     695             : #else /* !HAVE_GNUTLS */
     696             : static long
     697        5455 : tds_ssl_ctrl_login(BIO *b TDS_UNUSED, int cmd, long num TDS_UNUSED, void *ptr TDS_UNUSED)
     698             : {
     699        5455 :         switch (cmd) {
     700             :         case BIO_CTRL_FLUSH:
     701             :                 return 1;
     702             :         }
     703        3273 :         return 0;
     704             : }
     705             : 
     706             : static int
     707        2176 : tds_ssl_free(BIO *a TDS_UNUSED)
     708             : {
     709             :         /* nothing to do but required */
     710        2176 :         return 1;
     711             : }
     712             : 
     713             : #if OPENSSL_VERSION_NUMBER < 0x1010000FL || defined(LIBRESSL_VERSION_NUMBER)
     714             : static BIO_METHOD tds_method_login[1] = {
     715             : {
     716             :         BIO_TYPE_MEM,
     717             :         "tds",
     718             :         tds_push_func_login,
     719             :         tds_pull_func_login,
     720             :         NULL,
     721             :         NULL,
     722             :         tds_ssl_ctrl_login,
     723             :         NULL,
     724             :         tds_ssl_free,
     725             :         NULL,
     726             : }};
     727             : 
     728             : static BIO_METHOD tds_method[1] = {
     729             : {
     730             :         BIO_TYPE_MEM,
     731             :         "tds",
     732             :         tds_push_func,
     733             :         tds_pull_func,
     734             :         NULL,
     735             :         NULL,
     736             :         NULL,
     737             :         NULL,
     738             :         tds_ssl_free,
     739             :         NULL,
     740             : }};
     741             : 
     742             : static inline void
     743             : tds_init_ssl_methods(void)
     744             : {
     745             : }
     746             : #else
     747             : static BIO_METHOD *tds_method_login;
     748             : static BIO_METHOD *tds_method;
     749             : 
     750             : static void
     751         580 : tds_init_ssl_methods(void)
     752             : {
     753             :         BIO_METHOD *meth;
     754             : 
     755         580 :         tds_method_login = meth = BIO_meth_new(BIO_TYPE_MEM, "tds");
     756         580 :         BIO_meth_set_write(meth, tds_push_func_login);
     757         580 :         BIO_meth_set_read(meth, tds_pull_func_login);
     758         580 :         BIO_meth_set_ctrl(meth, tds_ssl_ctrl_login);
     759         580 :         BIO_meth_set_destroy(meth, tds_ssl_free);
     760             : 
     761         580 :         tds_method = meth = BIO_meth_new(BIO_TYPE_MEM, "tds");
     762         580 :         BIO_meth_set_write(meth, tds_push_func);
     763         580 :         BIO_meth_set_read(meth, tds_pull_func);
     764         580 :         BIO_meth_set_ctrl(meth, tds_ssl_ctrl_login);
     765         580 :         BIO_meth_set_destroy(meth, tds_ssl_free);
     766         580 : }
     767             : 
     768             : #  ifdef TDS_ATTRIBUTE_DESTRUCTOR
     769             : static void __attribute__((destructor))
     770        1127 : tds_deinit_openssl_methods(void)
     771             : {
     772        1127 :         BIO_meth_free(tds_method_login);
     773        1127 :         BIO_meth_free(tds_method);
     774        1127 : }
     775             : #  endif
     776             : #endif
     777             : 
     778             : #if OPENSSL_VERSION_NUMBER < 0x1010000FL || defined(LIBRESSL_VERSION_NUMBER)
     779             : static tds_mutex *openssl_locks;
     780             : 
     781             : static void
     782             : openssl_locking_callback(int mode, int type, const char *file TDS_UNUSED, int line TDS_UNUSED)
     783             : {
     784             :         if (mode & CRYPTO_LOCK)
     785             :                 tds_mutex_lock(&openssl_locks[type]);
     786             :         else
     787             :                 tds_mutex_unlock(&openssl_locks[type]);
     788             : }
     789             : 
     790             : static void
     791             : tds_init_openssl_thread(void)
     792             : {
     793             :         int i, n = CRYPTO_num_locks();
     794             : 
     795             :         /* if already set do not overwrite,
     796             :          * application or another library took care of */
     797             :         if (CRYPTO_get_locking_callback())
     798             :                 return;
     799             : 
     800             :         openssl_locks = tds_new(tds_mutex, n);
     801             :         for (i=0; i < n; ++i)
     802             :                 tds_mutex_init(&openssl_locks[i]);
     803             : 
     804             :         /* read back in the attempt to avoid race conditions
     805             :          * this is not safe but there are no race free ways */
     806             :         if (CRYPTO_get_locking_callback() == NULL)
     807             :                 CRYPTO_set_locking_callback(openssl_locking_callback);
     808             :         if (CRYPTO_get_locking_callback() == openssl_locking_callback)
     809             :                 return;
     810             : 
     811             :         for (i=0; i < n; ++i)
     812             :                 tds_mutex_free(&openssl_locks[i]);
     813             :         free(openssl_locks);
     814             :         openssl_locks = NULL;
     815             : }
     816             : 
     817             : #ifdef TDS_ATTRIBUTE_DESTRUCTOR
     818             : static void __attribute__((destructor))
     819             : tds_deinit_openssl(void)
     820             : {
     821             :         int i, n;
     822             : 
     823             :         if (!tls_initialized
     824             :             || CRYPTO_get_locking_callback() != openssl_locking_callback)
     825             :                 return;
     826             : 
     827             :         CRYPTO_set_locking_callback(NULL);
     828             :         n = CRYPTO_num_locks();
     829             :         for (i=0; i < n; ++i)
     830             :                 tds_mutex_free(&openssl_locks[i]);
     831             :         free(openssl_locks);
     832             :         openssl_locks = NULL;
     833             : }
     834             : #endif
     835             : 
     836             : #else
     837             : static inline void
     838             : tds_init_openssl_thread(void)
     839             : {
     840             : }
     841             : #endif
     842             : 
     843             : static SSL_CTX *
     844        1091 : tds_init_openssl(void)
     845             : {
     846             :         const SSL_METHOD *meth;
     847             : 
     848        1091 :         if (!tls_initialized) {
     849         580 :                 tds_mutex_lock(&tls_mutex);
     850         580 :                 if (!tls_initialized) {
     851         580 :                         SSL_library_init();
     852             :                         tds_init_openssl_thread();
     853         580 :                         tds_init_ssl_methods();
     854         580 :                         tls_initialized = 1;
     855             :                 }
     856         580 :                 tds_mutex_unlock(&tls_mutex);
     857             :         }
     858        1091 :         meth = TLS_client_method();
     859        1091 :         if (meth == NULL)
     860             :                 return NULL;
     861        1091 :         return SSL_CTX_new (meth);
     862             : }
     863             : 
     864             : static int
     865       21860 : check_wildcard(const char *host, const char *match)
     866             : {
     867             :         const char *p, *w;
     868             :         size_t n, lh, lm;
     869             : 
     870             :         /* U-label (binary) */
     871      229490 :         for (p = match; *p; ++p)
     872      208721 :                 if ((unsigned char) *p >= 0x80)
     873        1091 :                         return strcmp(host, match) == 0;
     874             : 
     875             :         for (;;) {
     876             :                 /* A-label (starts with xn--) */
     877       20769 :                 if (strncasecmp(match, "xn--", 4) == 0)
     878             :                         break;
     879             : 
     880             :                 /* match must not be in domain and domain should contains 2 parts */
     881       17496 :                 w = strchr(match, '*');
     882       17496 :                 p = strchr(match, '.');
     883       17496 :                 if (!w || !p            /* no wildcard or domain */
     884       13092 :                     || p[1] == '.'      /* empty domain */
     885       13092 :                     || w > p || strchr(p, '*') != NULL)      /* wildcard in domain */
     886             :                         break;
     887        9819 :                 p = strchr(p+1, '.');
     888        9819 :                 if (!p || p[1] == 0)    /* not another domain */
     889             :                         break;
     890             : 
     891             :                 /* check start */
     892        8728 :                 n = w - match;  /* prefix len */
     893        8728 :                 if (n > 0 && strncasecmp(host, match, n) != 0)
     894             :                         return 0;
     895             : 
     896             :                 /* check end */
     897        7637 :                 lh = strlen(host);
     898        7637 :                 lm = strlen(match);
     899        7637 :                 n = lm - n - 1; /* suffix len */
     900        7637 :                 if (lm - 1 > lh || strcasecmp(host+lh-n, match+lm-n) != 0 || host[0] == '.')
     901             :                         return 0;
     902             : 
     903        5455 :                 return 1;
     904             :         }
     905       12041 :         return strcasecmp(host, match) == 0;
     906             : }
     907             : 
     908             : #if ENABLE_EXTRA_CHECKS
     909             : static void
     910        1091 : tds_check_wildcard_test(void)
     911             : {
     912        1091 :         assert(check_wildcard("foo", "foo") == 1);
     913        1091 :         assert(check_wildcard("FOO", "foo") == 1);
     914        1091 :         assert(check_wildcard("foo", "FOO") == 1);
     915        1091 :         assert(check_wildcard("\x90oo", "\x90OO") == 0);
     916        1091 :         assert(check_wildcard("xn--foo", "xn--foo") == 1);
     917        1091 :         assert(check_wildcard("xn--FOO", "XN--foo") == 1);
     918        1091 :         assert(check_wildcard("xn--a.example.org", "xn--*.example.org") == 0);
     919        1091 :         assert(check_wildcard("a.*", "a.*") == 1);
     920        1091 :         assert(check_wildcard("a.b", "a.*") == 0);
     921        1091 :         assert(check_wildcard("ab", "a*") == 0);
     922        1091 :         assert(check_wildcard("a.example.", "*.example.") == 0);
     923        1091 :         assert(check_wildcard("a.example.com", "*.example.com") == 1);
     924        1091 :         assert(check_wildcard("a.b.example.com", "a.*.example.com") == 0);
     925        1091 :         assert(check_wildcard("foo.example.com", "foo*.example.com") == 1);
     926        1091 :         assert(check_wildcard("fou.example.com", "foo*.example.com") == 0);
     927        1091 :         assert(check_wildcard("baz.example.com", "*baz.example.com") == 1);
     928        1091 :         assert(check_wildcard("buzz.example.com", "b*z.example.com") == 1);
     929        1091 :         assert(check_wildcard("bz.example.com", "b*z.example.com") == 1);
     930        1091 :         assert(check_wildcard(".example.com", "*.example.com") == 0);
     931        1091 :         assert(check_wildcard("example.com", "*.example.com") == 0);
     932        1091 : }
     933             : #else
     934             : #define tds_check_wildcard_test() do { } while(0)
     935             : #endif
     936             : 
     937             : static int
     938          40 : check_name_match(ASN1_STRING *name, const char *hostname)
     939             : {
     940          40 :         char *name_utf8 = NULL, *tmp_name;
     941             :         int ret, name_len;
     942             : 
     943          40 :         name_len = ASN1_STRING_to_UTF8((unsigned char **) &name_utf8, name);
     944          40 :         if (name_len < 0)
     945             :                 return 0;
     946             : 
     947          40 :         tmp_name = tds_strndup(name_utf8, name_len);
     948          40 :         OPENSSL_free(name_utf8);
     949          40 :         if (!tmp_name)
     950             :                 return 0;
     951             : 
     952          40 :         name_utf8 = tmp_name;
     953             : 
     954          40 :         tdsdump_log(TDS_DBG_INFO1, "Got name %s\n", name_utf8);
     955          40 :         ret = 0;
     956          40 :         if (strlen(name_utf8) == name_len && check_wildcard(name_utf8, hostname))
     957          10 :                 ret = 1;
     958          40 :         free(name_utf8);
     959          40 :         return ret;
     960             : }
     961             : 
     962             : static int
     963          45 : check_alt_names(X509 *cert, const char *hostname)
     964             : {
     965             :         STACK_OF(GENERAL_NAME) *alt_names;
     966             :         int i, num;
     967          45 :         int ret = 1;
     968             :         union {
     969             :                 struct in_addr v4;
     970             :                 struct in6_addr v6;
     971             :         } ip;
     972          45 :         unsigned ip_size = 0;
     973             : 
     974             :         /* check whether @hostname is an ip address */
     975          45 :         if (strchr(hostname, ':') != NULL) {
     976          15 :                 ip_size = 16;
     977          15 :                 ret = inet_pton(AF_INET6, hostname, &ip.v6);
     978             :         } else {
     979          30 :                 ip_size = 4;
     980          30 :                 ret = inet_pton(AF_INET, hostname, &ip.v4);
     981             :         }
     982          45 :         if (ret == 0)
     983          15 :                 ip_size = 0;
     984             : 
     985          45 :         alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
     986          45 :         if (!alt_names)
     987             :                 return -1;
     988             : 
     989          45 :         num = sk_GENERAL_NAME_num(alt_names);
     990          45 :         tdsdump_log(TDS_DBG_INFO1, "Alt names number %d\n", num);
     991         130 :         for (i = 0; i < num; ++i) {
     992             :                 const char *altptr;
     993             :                 size_t altlen;
     994             : 
     995         150 :                 const GENERAL_NAME *name = sk_GENERAL_NAME_value(alt_names, i);
     996         150 :                 if (!name)
     997           0 :                         continue;
     998             : 
     999         150 :                 altptr = (const char *) ASN1_STRING_get0_data(name->d.ia5);
    1000         150 :                 altlen = (size_t) ASN1_STRING_length(name->d.ia5);
    1001             : 
    1002         150 :                 if (name->type == GEN_DNS && ip_size == 0) {
    1003          15 :                         if (!check_name_match(name->d.dNSName, hostname))
    1004          10 :                                 continue;
    1005         135 :                 } else if (name->type == GEN_IPADD && ip_size != 0) {
    1006          75 :                         if (altlen != ip_size || memcmp(altptr, &ip, altlen) != 0)
    1007          60 :                                 continue;
    1008             :                 } else {
    1009          60 :                         continue;
    1010             :                 }
    1011             : 
    1012          20 :                 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
    1013          20 :                 return 1;
    1014             :         }
    1015          25 :         sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
    1016          25 :         return -1;
    1017             : }
    1018             : 
    1019             : static int
    1020          45 : check_hostname(X509 *cert, const char *hostname)
    1021             : {
    1022             :         int ret, i;
    1023             :         X509_NAME *subject;
    1024             :         ASN1_STRING *name;
    1025             : 
    1026             :         /* check by subject */
    1027          45 :         ret = check_alt_names(cert, hostname);
    1028          45 :         if (ret >= 0)
    1029             :                 return ret;
    1030             : 
    1031             :         /* check by common name (old method) */
    1032          25 :         subject = X509_get_subject_name(cert);
    1033          25 :         if (!subject)
    1034             :                 return 0;
    1035             : 
    1036             :         i = -1;
    1037          50 :         while (X509_NAME_get_index_by_NID(subject, NID_commonName, i) >= 0)
    1038          25 :                 i = X509_NAME_get_index_by_NID(subject, NID_commonName, i);
    1039          25 :         if (i < 0)
    1040             :                 return 0;
    1041             : 
    1042          25 :         name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i));
    1043          25 :         if (!name)
    1044             :                 return 0;
    1045             : 
    1046          25 :         return check_name_match(name, hostname);
    1047             : }
    1048             : 
    1049             : int
    1050        1091 : tds_ssl_init(TDSSOCKET *tds, bool full)
    1051             : {
    1052             : #define DEFAULT_OPENSSL_CTX_OPTIONS \
    1053             :         (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1)
    1054             : #define DEFAULT_OPENSSL_CIPHERS "HIGH:!SSLv2:!aNULL:-DH"
    1055             : 
    1056             :         SSL *con;
    1057             :         SSL_CTX *ctx;
    1058             :         BIO *b, *b2;
    1059             : 
    1060             :         int ret, connect_ret;
    1061             :         const char *tls_msg;
    1062             : 
    1063        1091 :         unsigned long ctx_options = DEFAULT_OPENSSL_CTX_OPTIONS;
    1064             : 
    1065        1091 :         con = NULL;
    1066        1091 :         b = NULL;
    1067        1091 :         b2 = NULL;
    1068        1091 :         ret = 1;
    1069             : 
    1070        1091 :         tds_check_wildcard_test();
    1071             : 
    1072        1091 :         tds_ssl_deinit(tds->conn);
    1073             : 
    1074        1091 :         tls_msg = "initializing tls";
    1075        1091 :         ctx = tds_init_openssl();
    1076        1091 :         if (!ctx)
    1077             :                 goto cleanup;
    1078             : 
    1079        1091 :         if (tds->login && tds->login->enable_tls_v1)
    1080         727 :                 ctx_options &= ~SSL_OP_NO_TLSv1;
    1081        1091 :         if (tds->login && tds->login->enable_tls_v1_1)
    1082           0 :                 ctx_options &= ~SSL_OP_NO_TLSv1_1;
    1083        1091 :         SSL_CTX_set_options(ctx, ctx_options);
    1084             : 
    1085        2182 :         if (!tds_dstr_isempty(&tds->login->cafile)) {
    1086           0 :                 tls_msg = "loading CA file";
    1087           0 :                 if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
    1088           0 :                         ret = SSL_CTX_set_default_verify_paths(ctx);
    1089             :                 else
    1090           0 :                         ret = SSL_CTX_load_verify_locations(ctx, tds_dstr_cstr(&tds->login->cafile), NULL);
    1091           0 :                 if (ret != 1)
    1092             :                         goto cleanup;
    1093           0 :                 if (!tds_dstr_isempty(&tds->login->crlfile)) {
    1094           0 :                         X509_STORE *store = SSL_CTX_get_cert_store(ctx);
    1095             :                         X509_LOOKUP *lookup;
    1096             : 
    1097           0 :                         tls_msg = "loading CRL file";
    1098           0 :                         if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()))
    1099           0 :                             || (!X509_load_crl_file(lookup, tds_dstr_cstr(&tds->login->crlfile), X509_FILETYPE_PEM)))
    1100             :                                 goto cleanup;
    1101             : 
    1102           0 :                         X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
    1103             :                 }
    1104           0 :                 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    1105             :         }
    1106             : 
    1107             :         /* Initialize TLS session */
    1108        1091 :         tls_msg = "initializing session";
    1109        1091 :         con = SSL_new(ctx);
    1110        1091 :         if (!con)
    1111             :                 goto cleanup;
    1112             : 
    1113        1091 :         tls_msg = "creating bio";
    1114        1091 :         b = BIO_new(full ? tds_method : tds_method_login);
    1115        1091 :         if (!b)
    1116             :                 goto cleanup;
    1117             : 
    1118        1091 :         if (!full) {
    1119        1091 :                 b2 = BIO_new(tds_method);
    1120        1091 :                 if (!b2)
    1121             :                         goto cleanup;
    1122             :         }
    1123             : 
    1124        1091 :         BIO_set_init(b, 1);
    1125        1091 :         BIO_set_data(b, full ? (void *) tds->conn : (void *) tds);
    1126        2182 :         BIO_set_conn_hostname(b, wanted_certificate_hostname(tds->login));
    1127        1091 :         SSL_set_bio(con, b, b);
    1128        1091 :         b = NULL;
    1129             : 
    1130             :         /* use default priorities unless overridden by openssl ciphers setting in freetds.conf file... */
    1131        2182 :         if (!tds_dstr_isempty(&tds->login->openssl_ciphers)) {
    1132           0 :                 tdsdump_log(TDS_DBG_INFO1, "setting custom openssl cipher to:%s\n", tds_dstr_cstr(&tds->login->openssl_ciphers));
    1133           0 :                 SSL_set_cipher_list(con, tds_dstr_cstr(&tds->login->openssl_ciphers) );
    1134             :         } else {
    1135        1091 :                 tdsdump_log(TDS_DBG_INFO1, "setting default openssl cipher to:%s\n", DEFAULT_OPENSSL_CIPHERS );
    1136        1091 :                 SSL_set_cipher_list(con, DEFAULT_OPENSSL_CIPHERS);
    1137             :         }
    1138             : 
    1139             : #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
    1140             :         /* this disable a security improvement but allow connection... */
    1141        1091 :         SSL_set_options(con, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
    1142             : #endif
    1143             : 
    1144             : #ifdef HAVE_SSL_SET_ALPN_PROTOS
    1145        1091 :         if (IS_TDS80_PLUS(tds->conn)) {
    1146             :                 static const unsigned char tds8_alpn[] = {
    1147             :                         TDS8_ALPN_ARRAY_LEN, TDS8_ALPN_ARRAY
    1148             :                 };
    1149           0 :                 SSL_set_alpn_protos(con, tds8_alpn, sizeof(tds8_alpn));
    1150             :         }
    1151             : #endif
    1152             : 
    1153             :         if (full)
    1154             :                 set_current_tds(tds->conn, tds);
    1155             : 
    1156             :         /* Perform the TLS handshake */
    1157        1091 :         tls_msg = "handshake";
    1158        1091 :         ERR_clear_error();
    1159        1091 :         SSL_set_connect_state(con);
    1160        1091 :         connect_ret = SSL_connect(con);
    1161        2182 :         ret = connect_ret != 1 || SSL_get_state(con) != TLS_ST_OK;
    1162             :         if (ret != 0) {
    1163           0 :                 tdsdump_log(TDS_DBG_ERROR, "handshake failed with %d %d %d\n",
    1164           0 :                             connect_ret, SSL_get_state(con), SSL_get_error(con, connect_ret));
    1165             :                 goto cleanup;
    1166             :         }
    1167             : 
    1168             :         /* flush pending data */
    1169        2182 :         if (!full && tds->out_pos > 8)
    1170           0 :                 tds_flush_packet(tds);
    1171             : 
    1172             :         /* check certificate hostname */
    1173        2182 :         if (!tds_dstr_isempty(&tds->login->cafile) && tds->login->check_ssl_hostname) {
    1174             :                 X509 *cert;
    1175             : 
    1176           0 :                 cert =  SSL_get_peer_certificate(con);
    1177           0 :                 tls_msg = "checking hostname";
    1178           0 :                 if (!cert || !check_hostname(cert, wanted_certificate_hostname(tds->login)))
    1179             :                         goto cleanup;
    1180           0 :                 X509_free(cert);
    1181             :         }
    1182             : 
    1183        1091 :         tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");
    1184             : 
    1185        1091 :         if (!full) {
    1186             :                 /* some TLS implementations send some sort of paddind at the end, remove it */
    1187        1091 :                 tds->in_pos = tds->in_len;
    1188             : 
    1189        1091 :                 BIO_set_init(b2, 1);
    1190        1091 :                 BIO_set_data(b2, tds->conn);
    1191        1091 :                 SSL_set_bio(con, b2, b2);
    1192             :         }
    1193             : 
    1194        1091 :         set_current_tds(tds->conn, NULL);
    1195             : 
    1196        1091 :         tds->conn->tls_session = con;
    1197        1091 :         tds->conn->tls_ctx = ctx;
    1198             : 
    1199        1091 :         return TDS_SUCCESS;
    1200             : 
    1201           0 : cleanup:
    1202           0 :         if (b2)
    1203           0 :                 BIO_free(b2);
    1204           0 :         if (b)
    1205           0 :                 BIO_free(b);
    1206           0 :         if (con) {
    1207           0 :                 SSL_shutdown(con);
    1208           0 :                 SSL_free(con);
    1209             :         }
    1210           0 :         set_current_tds(tds->conn, NULL);
    1211           0 :         SSL_CTX_free(ctx);
    1212           0 :         tdsdump_log(TDS_DBG_ERROR, "%s failed\n", tls_msg);
    1213             :         return TDS_FAIL;
    1214             : }
    1215             : 
    1216             : void
    1217        5950 : tds_ssl_deinit(TDSCONNECTION *conn)
    1218             : {
    1219        5950 :         if (conn->tls_session) {
    1220             :                 /* NOTE do not call SSL_shutdown here */
    1221        1085 :                 SSL_free((SSL *) conn->tls_session);
    1222        1085 :                 conn->tls_session = NULL;
    1223             :         }
    1224        5950 :         if (conn->tls_ctx) {
    1225        1085 :                 SSL_CTX_free((SSL_CTX *) conn->tls_ctx);
    1226        1085 :                 conn->tls_ctx = NULL;
    1227             :         }
    1228        5950 :         conn->encrypt_single_packet = 0;
    1229        5950 : }
    1230             : 
    1231             : size_t
    1232         360 : tds_ssl_get_cb(TDSCONNECTION *conn, void *cb, size_t cblen)
    1233             : {
    1234             :         SSL *ssl;
    1235             :         size_t tls_unique_len;
    1236             : 
    1237             :         /* No CBT, skip channel binding */
    1238         360 :         if (!conn->tls_session)
    1239             :                 return 0;
    1240             : 
    1241         360 :         ssl = (SSL *) conn->tls_session;
    1242             : 
    1243             :         /* Get tls-unique from OpenSSL */
    1244         360 :         tls_unique_len = SSL_get_finished(ssl, cb, cblen);
    1245         360 :         if (tls_unique_len == 0) {
    1246             :                 /* Try peer finished as fallback */
    1247           0 :                 tls_unique_len = SSL_get_peer_finished(ssl, cb, cblen);
    1248           0 :                 if (tls_unique_len == 0) {
    1249           0 :                         tdsdump_log(TDS_DBG_ERROR, "tds_ssl_get_cb: failed to get tls-unique from OpenSSL\n");
    1250             :                         /* No tls-unique available, skip channel binding */
    1251             :                         return 0;
    1252             :                 }
    1253             :         }
    1254             :         return tls_unique_len;
    1255             : }
    1256             : #endif
    1257             : 
    1258             : #endif
    1259             : /** @} */
    1260             : 

Generated by: LCOV version 1.13