LCOV - code coverage report
Current view: top level - src/tds - tls.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 294 380 77.4 %
Date: 2025-07-16 09:22:05 Functions: 18 21 85.7 %

          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       18728 : tds_pull_func_login(SSL_PULL_ARGS)
     124             : {
     125       18728 :         TDSSOCKET *tds = (TDSSOCKET *) SSL_PTR;
     126             :         int have;
     127             : 
     128       18728 :         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       18728 :         if (tds->out_pos > 8)
     136        4328 :                 tds_flush_packet(tds);
     137             : 
     138             :         for(;;) {
     139       23056 :                 have = tds->in_len - tds->in_pos;
     140       23056 :                 assert(have >= 0);
     141       23056 :                 if (have > 0)
     142             :                         break;
     143        4328 :                 if (tds_read_packet(tds) < 0)
     144             :                         return -1;
     145             :         }
     146       18728 :         if (len > have)
     147           0 :                 len = have;
     148       18728 :         memcpy(data, tds->in_buf + tds->in_pos, len);
     149       18728 :         tds->in_pos += len;
     150       18728 :         return len;
     151             : }
     152             : 
     153             : static SSL_RET
     154        6492 : tds_push_func_login(SSL_PUSH_ARGS)
     155             : {
     156        6492 :         TDSSOCKET *tds = (TDSSOCKET *) SSL_PTR;
     157             : 
     158        6492 :         tdsdump_log(TDS_DBG_FUNC, "in tds_push_func_login\n");
     159             : 
     160             :         /* initializing SSL, write crypted data inside normal TDS packets */
     161        6492 :         tds_put_n(tds, data, len);
     162        6492 :         return len;
     163             : }
     164             : 
     165             : static SSL_RET
     166       86640 : tds_pull_func(SSL_PULL_ARGS)
     167             : {
     168       86640 :         TDSCONNECTION *conn = (TDSCONNECTION *) SSL_PTR;
     169             :         TDSSOCKET *tds;
     170             : 
     171       86640 :         tdsdump_log(TDS_DBG_FUNC, "in tds_pull_func\n");
     172             : 
     173       86640 :         tds = CONN2TDS(conn);
     174       86640 :         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       86640 :         return tds_goodread(tds, (unsigned char*) data, len);
     182             : }
     183             : 
     184             : static SSL_RET
     185       36122 : tds_push_func(SSL_PUSH_ARGS)
     186             : {
     187       36122 :         TDSCONNECTION *conn = (TDSCONNECTION *) SSL_PTR;
     188             :         TDSSOCKET *tds;
     189             : 
     190       36122 :         tdsdump_log(TDS_DBG_FUNC, "in tds_push_func\n");
     191             : 
     192             :         /* write to socket directly */
     193       36122 :         tds = CONN2TDS(conn);
     194       36122 :         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        1082 :         tds_mutex_lock(&conn->list_mtx);
     205        1082 :         conn->in_net_tds = tds;
     206        1082 :         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        2164 :         if (!tds_dstr_isempty(&login->certificate_host_name))
     219           0 :                 return tds_dstr_cstr(&login->certificate_host_name);
     220             : 
     221        1082 :         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        1102 : tds_tls_deinit(void)
     235             : {
     236        1102 :         if (tls_initialized)
     237         574 :                 gnutls_global_deinit();
     238        1102 : }
     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        1082 : 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        1082 :         xcred = NULL;
     498        1082 :         session = NULL; 
     499        1082 :         tls_msg = "initializing tls";
     500             : 
     501        1082 :         if (!tls_initialized) {
     502         574 :                 ret = 0;
     503         574 :                 tds_mutex_lock(&tls_mutex);
     504         574 :                 if (!tls_initialized) {
     505             :                         tds_gcry_init();
     506         574 :                         ret = gnutls_global_init();
     507         574 :                         if (ret == 0)
     508         574 :                                 tls_initialized = 1;
     509             :                 }
     510         574 :                 tds_mutex_unlock(&tls_mutex);
     511         574 :                 if (ret != 0)
     512             :                         goto cleanup;
     513             :         }
     514             : 
     515        1082 :         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        1082 :         tls_msg = "allocating credentials";
     522        1082 :         ret = gnutls_certificate_allocate_credentials(&xcred);
     523        1082 :         if (ret != 0)
     524             :                 goto cleanup;
     525             : 
     526             :         /* Initialize TLS session */
     527        1082 :         tls_msg = "initializing session";
     528        1082 :         ret = gnutls_init(&session, GNUTLS_CLIENT);
     529        1082 :         if (ret != 0)
     530             :                 goto cleanup;
     531             : 
     532        1082 :         if (!full) {
     533        1082 :                 gnutls_transport_set_ptr(session, tds);
     534        1082 :                 gnutls_transport_set_pull_function(session, tds_pull_func_login);
     535        1082 :                 gnutls_transport_set_push_function(session, tds_push_func_login);
     536        1082 :                 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        2164 :         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             :         /* NOTE: these functions return int however they cannot fail */
     564             : 
     565             :         /* use default priorities... */
     566        1082 :         gnutls_set_default_priority(session);
     567             : 
     568             : #ifdef HAVE_GNUTLS_SET_DEFAULT_PRIORITY_APPEND
     569             :         gnutls_session_enable_compatibility_mode(session);
     570             : #define set_ciphers(session, ciphers) \
     571             :         gnutls_set_default_priority_append(session, "" ciphers, NULL, 0)
     572             : #else
     573             : #define set_ciphers(session, ciphers) \
     574             :         gnutls_priority_set_direct(session, "NORMAL:%COMPAT:" ciphers, NULL)
     575             : #endif
     576             : 
     577             :         /* ... but overwrite some */
     578        1082 :         if (tds->login && tds->login->enable_tls_v1)
     579         723 :                 ret = set_ciphers(session, "-VERS-SSL3.0:+VERS-TLS1.0:+VERS-TLS1.1");
     580         359 :         else if (tds->login && tds->login->enable_tls_v1_1)
     581           0 :                 ret = set_ciphers(session, "-VERS-SSL3.0:-VERS-TLS1.0:+VERS-TLS1.1");
     582             :         else
     583         359 :                 ret = set_ciphers(session, "-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1");
     584        1082 :         if (ret != 0)
     585             :                 goto cleanup;
     586             : 
     587             :         /* mssql does not like padding too much */
     588             : #ifdef HAVE_GNUTLS_RECORD_DISABLE_PADDING
     589        1082 :         gnutls_record_disable_padding(session);
     590             : #endif
     591             : 
     592             :         /* put the anonymous credentials to the current session */
     593        1082 :         tls_msg = "setting credential";
     594        1082 :         ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
     595        1082 :         if (ret != 0)
     596             :                 goto cleanup;
     597             : 
     598             : #ifdef HAVE_GNUTLS_ALPN_SET_PROTOCOLS
     599        1082 :         if (IS_TDS80_PLUS(tds->conn)) {
     600             :                 static const unsigned char alpn[] = { TDS8_ALPN_ARRAY };
     601             :                 static const gnutls_datum_t tds8_alpn = { (void*) alpn, sizeof(alpn) };
     602           0 :                 gnutls_alpn_set_protocols(session, &tds8_alpn, 1, 0);
     603             :         }
     604             : #endif
     605             : 
     606        1082 :         if (full)
     607           0 :                 set_current_tds(tds->conn, tds);
     608             : 
     609             :         /* Perform the TLS handshake */
     610        1082 :         tls_msg = "handshake";
     611        1082 :         ret = gnutls_handshake (session);
     612        1082 :         if (ret != 0)
     613             :                 goto cleanup;
     614             : 
     615             : #ifndef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION
     616             :         if (!tds_dstr_isempty(&tds->login->cafile)) {
     617             :                 ret = tds_verify_certificate(session, tds);
     618             :                 if (ret != 0)
     619             :                         goto cleanup;
     620             :         }
     621             : #endif
     622             : 
     623        1082 :         tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");
     624             : 
     625        1082 :         if (!full) {
     626             :                 /* some TLS implementations send some sort of paddind at the end, remove it */
     627        1082 :                 tds->in_pos = tds->in_len;
     628             : 
     629        1082 :                 gnutls_transport_set_ptr(session, tds->conn);
     630        1082 :                 gnutls_transport_set_pull_function(session, tds_pull_func);
     631        1082 :                 gnutls_transport_set_push_function(session, tds_push_func);
     632             :         }
     633             : 
     634        2164 :         set_current_tds(tds->conn, NULL);
     635             : 
     636        1082 :         tds->conn->tls_session = session;
     637        1082 :         tds->conn->tls_credentials = xcred;
     638             : 
     639        1082 :         return TDS_SUCCESS;
     640             : 
     641           0 : cleanup:
     642           0 :         if (session)
     643           0 :                 gnutls_deinit(session);
     644           0 :         set_current_tds(tds->conn, NULL);
     645           0 :         if (xcred)
     646           0 :                 gnutls_certificate_free_credentials(xcred);
     647           0 :         tdsdump_log(TDS_DBG_ERROR, "%s failed: %s\n", tls_msg, gnutls_strerror (ret));
     648             :         return TDS_FAIL;
     649             : }
     650             : 
     651             : void
     652        4872 : tds_ssl_deinit(TDSCONNECTION *conn)
     653             : {
     654        4872 :         if (conn->tls_session) {
     655        1076 :                 gnutls_deinit((gnutls_session_t) conn->tls_session);
     656        1076 :                 conn->tls_session = NULL;
     657             :         }
     658        4872 :         if (conn->tls_credentials) {
     659        1076 :                 gnutls_certificate_free_credentials((gnutls_certificate_credentials_t) conn->tls_credentials);
     660        1076 :                 conn->tls_credentials = NULL;
     661             :         }
     662        4872 :         conn->encrypt_single_packet = 0;
     663        4872 : }
     664             : 
     665             : #else /* !HAVE_GNUTLS */
     666             : static long
     667        5410 : tds_ssl_ctrl_login(BIO *b TDS_UNUSED, int cmd, long num TDS_UNUSED, void *ptr TDS_UNUSED)
     668             : {
     669        5410 :         switch (cmd) {
     670             :         case BIO_CTRL_FLUSH:
     671             :                 return 1;
     672             :         }
     673        3246 :         return 0;
     674             : }
     675             : 
     676             : static int
     677        2158 : tds_ssl_free(BIO *a TDS_UNUSED)
     678             : {
     679             :         /* nothing to do but required */
     680        2158 :         return 1;
     681             : }
     682             : 
     683             : #if OPENSSL_VERSION_NUMBER < 0x1010000FL || defined(LIBRESSL_VERSION_NUMBER)
     684             : static BIO_METHOD tds_method_login[1] = {
     685             : {
     686             :         BIO_TYPE_MEM,
     687             :         "tds",
     688             :         tds_push_func_login,
     689             :         tds_pull_func_login,
     690             :         NULL,
     691             :         NULL,
     692             :         tds_ssl_ctrl_login,
     693             :         NULL,
     694             :         tds_ssl_free,
     695             :         NULL,
     696             : }};
     697             : 
     698             : static BIO_METHOD tds_method[1] = {
     699             : {
     700             :         BIO_TYPE_MEM,
     701             :         "tds",
     702             :         tds_push_func,
     703             :         tds_pull_func,
     704             :         NULL,
     705             :         NULL,
     706             :         NULL,
     707             :         NULL,
     708             :         tds_ssl_free,
     709             :         NULL,
     710             : }};
     711             : 
     712             : static inline void
     713             : tds_init_ssl_methods(void)
     714             : {
     715             : }
     716             : #else
     717             : static BIO_METHOD *tds_method_login;
     718             : static BIO_METHOD *tds_method;
     719             : 
     720             : static void
     721         574 : tds_init_ssl_methods(void)
     722             : {
     723             :         BIO_METHOD *meth;
     724             : 
     725         574 :         tds_method_login = meth = BIO_meth_new(BIO_TYPE_MEM, "tds");
     726         574 :         BIO_meth_set_write(meth, tds_push_func_login);
     727         574 :         BIO_meth_set_read(meth, tds_pull_func_login);
     728         574 :         BIO_meth_set_ctrl(meth, tds_ssl_ctrl_login);
     729         574 :         BIO_meth_set_destroy(meth, tds_ssl_free);
     730             : 
     731         574 :         tds_method = meth = BIO_meth_new(BIO_TYPE_MEM, "tds");
     732         574 :         BIO_meth_set_write(meth, tds_push_func);
     733         574 :         BIO_meth_set_read(meth, tds_pull_func);
     734         574 :         BIO_meth_set_ctrl(meth, tds_ssl_ctrl_login);
     735         574 :         BIO_meth_set_destroy(meth, tds_ssl_free);
     736         574 : }
     737             : 
     738             : #  ifdef TDS_ATTRIBUTE_DESTRUCTOR
     739             : static void __attribute__((destructor))
     740        1102 : tds_deinit_openssl_methods(void)
     741             : {
     742        1102 :         BIO_meth_free(tds_method_login);
     743        1102 :         BIO_meth_free(tds_method);
     744        1102 : }
     745             : #  endif
     746             : #endif
     747             : 
     748             : #if OPENSSL_VERSION_NUMBER < 0x1010000FL || defined(LIBRESSL_VERSION_NUMBER)
     749             : static tds_mutex *openssl_locks;
     750             : 
     751             : static void
     752             : openssl_locking_callback(int mode, int type, const char *file TDS_UNUSED, int line TDS_UNUSED)
     753             : {
     754             :         if (mode & CRYPTO_LOCK)
     755             :                 tds_mutex_lock(&openssl_locks[type]);
     756             :         else
     757             :                 tds_mutex_unlock(&openssl_locks[type]);
     758             : }
     759             : 
     760             : static void
     761             : tds_init_openssl_thread(void)
     762             : {
     763             :         int i, n = CRYPTO_num_locks();
     764             : 
     765             :         /* if already set do not overwrite,
     766             :          * application or another library took care of */
     767             :         if (CRYPTO_get_locking_callback())
     768             :                 return;
     769             : 
     770             :         openssl_locks = tds_new(tds_mutex, n);
     771             :         for (i=0; i < n; ++i)
     772             :                 tds_mutex_init(&openssl_locks[i]);
     773             : 
     774             :         /* read back in the attempt to avoid race conditions
     775             :          * this is not safe but there are no race free ways */
     776             :         if (CRYPTO_get_locking_callback() == NULL)
     777             :                 CRYPTO_set_locking_callback(openssl_locking_callback);
     778             :         if (CRYPTO_get_locking_callback() == openssl_locking_callback)
     779             :                 return;
     780             : 
     781             :         for (i=0; i < n; ++i)
     782             :                 tds_mutex_free(&openssl_locks[i]);
     783             :         free(openssl_locks);
     784             :         openssl_locks = NULL;
     785             : }
     786             : 
     787             : #ifdef TDS_ATTRIBUTE_DESTRUCTOR
     788             : static void __attribute__((destructor))
     789             : tds_deinit_openssl(void)
     790             : {
     791             :         int i, n;
     792             : 
     793             :         if (!tls_initialized
     794             :             || CRYPTO_get_locking_callback() != openssl_locking_callback)
     795             :                 return;
     796             : 
     797             :         CRYPTO_set_locking_callback(NULL);
     798             :         n = CRYPTO_num_locks();
     799             :         for (i=0; i < n; ++i)
     800             :                 tds_mutex_free(&openssl_locks[i]);
     801             :         free(openssl_locks);
     802             :         openssl_locks = NULL;
     803             : }
     804             : #endif
     805             : 
     806             : #else
     807             : static inline void
     808             : tds_init_openssl_thread(void)
     809             : {
     810             : }
     811             : #endif
     812             : 
     813             : static SSL_CTX *
     814        1082 : tds_init_openssl(void)
     815             : {
     816             :         const SSL_METHOD *meth;
     817             : 
     818        1082 :         if (!tls_initialized) {
     819         574 :                 tds_mutex_lock(&tls_mutex);
     820         574 :                 if (!tls_initialized) {
     821         574 :                         SSL_library_init();
     822             :                         tds_init_openssl_thread();
     823         574 :                         tds_init_ssl_methods();
     824         574 :                         tls_initialized = 1;
     825             :                 }
     826         574 :                 tds_mutex_unlock(&tls_mutex);
     827             :         }
     828        1082 :         meth = TLS_client_method();
     829        1082 :         if (meth == NULL)
     830             :                 return NULL;
     831        1082 :         return SSL_CTX_new (meth);
     832             : }
     833             : 
     834             : static int
     835       21680 : check_wildcard(const char *host, const char *match)
     836             : {
     837             :         const char *p, *w;
     838             :         size_t n, lh, lm;
     839             : 
     840             :         /* U-label (binary) */
     841      227600 :         for (p = match; *p; ++p)
     842      207002 :                 if ((unsigned char) *p >= 0x80)
     843        1082 :                         return strcmp(host, match) == 0;
     844             : 
     845             :         for (;;) {
     846             :                 /* A-label (starts with xn--) */
     847       20598 :                 if (strncasecmp(match, "xn--", 4) == 0)
     848             :                         break;
     849             : 
     850             :                 /* match must not be in domain and domain should contains 2 parts */
     851       17352 :                 w = strchr(match, '*');
     852       17352 :                 p = strchr(match, '.');
     853       17352 :                 if (!w || !p            /* no wildcard or domain */
     854       12984 :                     || p[1] == '.'      /* empty domain */
     855       12984 :                     || w > p || strchr(p, '*') != NULL)      /* wildcard in domain */
     856             :                         break;
     857        9738 :                 p = strchr(p+1, '.');
     858        9738 :                 if (!p || p[1] == 0)    /* not another domain */
     859             :                         break;
     860             : 
     861             :                 /* check start */
     862        8656 :                 n = w - match;  /* prefix len */
     863        8656 :                 if (n > 0 && strncasecmp(host, match, n) != 0)
     864             :                         return 0;
     865             : 
     866             :                 /* check end */
     867        7574 :                 lh = strlen(host);
     868        7574 :                 lm = strlen(match);
     869        7574 :                 n = lm - n - 1; /* suffix len */
     870        7574 :                 if (lm - 1 > lh || strcasecmp(host+lh-n, match+lm-n) != 0 || host[0] == '.')
     871             :                         return 0;
     872             : 
     873        5410 :                 return 1;
     874             :         }
     875       11942 :         return strcasecmp(host, match) == 0;
     876             : }
     877             : 
     878             : #if ENABLE_EXTRA_CHECKS
     879             : static void
     880        1082 : tds_check_wildcard_test(void)
     881             : {
     882        1082 :         assert(check_wildcard("foo", "foo") == 1);
     883        1082 :         assert(check_wildcard("FOO", "foo") == 1);
     884        1082 :         assert(check_wildcard("foo", "FOO") == 1);
     885        1082 :         assert(check_wildcard("\x90oo", "\x90OO") == 0);
     886        1082 :         assert(check_wildcard("xn--foo", "xn--foo") == 1);
     887        1082 :         assert(check_wildcard("xn--FOO", "XN--foo") == 1);
     888        1082 :         assert(check_wildcard("xn--a.example.org", "xn--*.example.org") == 0);
     889        1082 :         assert(check_wildcard("a.*", "a.*") == 1);
     890        1082 :         assert(check_wildcard("a.b", "a.*") == 0);
     891        1082 :         assert(check_wildcard("ab", "a*") == 0);
     892        1082 :         assert(check_wildcard("a.example.", "*.example.") == 0);
     893        1082 :         assert(check_wildcard("a.example.com", "*.example.com") == 1);
     894        1082 :         assert(check_wildcard("a.b.example.com", "a.*.example.com") == 0);
     895        1082 :         assert(check_wildcard("foo.example.com", "foo*.example.com") == 1);
     896        1082 :         assert(check_wildcard("fou.example.com", "foo*.example.com") == 0);
     897        1082 :         assert(check_wildcard("baz.example.com", "*baz.example.com") == 1);
     898        1082 :         assert(check_wildcard("buzz.example.com", "b*z.example.com") == 1);
     899        1082 :         assert(check_wildcard("bz.example.com", "b*z.example.com") == 1);
     900        1082 :         assert(check_wildcard(".example.com", "*.example.com") == 0);
     901        1082 :         assert(check_wildcard("example.com", "*.example.com") == 0);
     902        1082 : }
     903             : #else
     904             : #define tds_check_wildcard_test() do { } while(0)
     905             : #endif
     906             : 
     907             : static int
     908          40 : check_name_match(ASN1_STRING *name, const char *hostname)
     909             : {
     910          40 :         char *name_utf8 = NULL, *tmp_name;
     911             :         int ret, name_len;
     912             : 
     913          40 :         name_len = ASN1_STRING_to_UTF8((unsigned char **) &name_utf8, name);
     914          40 :         if (name_len < 0)
     915             :                 return 0;
     916             : 
     917          40 :         tmp_name = tds_strndup(name_utf8, name_len);
     918          40 :         OPENSSL_free(name_utf8);
     919          40 :         if (!tmp_name)
     920             :                 return 0;
     921             : 
     922          40 :         name_utf8 = tmp_name;
     923             : 
     924          40 :         tdsdump_log(TDS_DBG_INFO1, "Got name %s\n", name_utf8);
     925          40 :         ret = 0;
     926          40 :         if (strlen(name_utf8) == name_len && check_wildcard(name_utf8, hostname))
     927          10 :                 ret = 1;
     928          40 :         free(name_utf8);
     929          40 :         return ret;
     930             : }
     931             : 
     932             : static int
     933          45 : check_alt_names(X509 *cert, const char *hostname)
     934             : {
     935             :         STACK_OF(GENERAL_NAME) *alt_names;
     936             :         int i, num;
     937          45 :         int ret = 1;
     938             :         union {
     939             :                 struct in_addr v4;
     940             :                 struct in6_addr v6;
     941             :         } ip;
     942          45 :         unsigned ip_size = 0;
     943             : 
     944             :         /* check whether @hostname is an ip address */
     945          45 :         if (strchr(hostname, ':') != NULL) {
     946          15 :                 ip_size = 16;
     947          15 :                 ret = inet_pton(AF_INET6, hostname, &ip.v6);
     948             :         } else {
     949          30 :                 ip_size = 4;
     950          30 :                 ret = inet_pton(AF_INET, hostname, &ip.v4);
     951             :         }
     952          45 :         if (ret == 0)
     953          15 :                 ip_size = 0;
     954             : 
     955          45 :         alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
     956          45 :         if (!alt_names)
     957             :                 return -1;
     958             : 
     959          45 :         num = sk_GENERAL_NAME_num(alt_names);
     960          45 :         tdsdump_log(TDS_DBG_INFO1, "Alt names number %d\n", num);
     961         130 :         for (i = 0; i < num; ++i) {
     962             :                 const char *altptr;
     963             :                 size_t altlen;
     964             : 
     965         150 :                 const GENERAL_NAME *name = sk_GENERAL_NAME_value(alt_names, i);
     966         150 :                 if (!name)
     967           0 :                         continue;
     968             : 
     969         150 :                 altptr = (const char *) ASN1_STRING_get0_data(name->d.ia5);
     970         150 :                 altlen = (size_t) ASN1_STRING_length(name->d.ia5);
     971             : 
     972         150 :                 if (name->type == GEN_DNS && ip_size == 0) {
     973          15 :                         if (!check_name_match(name->d.dNSName, hostname))
     974          10 :                                 continue;
     975         135 :                 } else if (name->type == GEN_IPADD && ip_size != 0) {
     976          75 :                         if (altlen != ip_size || memcmp(altptr, &ip, altlen) != 0)
     977          60 :                                 continue;
     978             :                 } else {
     979          60 :                         continue;
     980             :                 }
     981             : 
     982          20 :                 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
     983          20 :                 return 1;
     984             :         }
     985          25 :         sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
     986          25 :         return -1;
     987             : }
     988             : 
     989             : static int
     990          45 : check_hostname(X509 *cert, const char *hostname)
     991             : {
     992             :         int ret, i;
     993             :         X509_NAME *subject;
     994             :         ASN1_STRING *name;
     995             : 
     996             :         /* check by subject */
     997          45 :         ret = check_alt_names(cert, hostname);
     998          45 :         if (ret >= 0)
     999             :                 return ret;
    1000             : 
    1001             :         /* check by common name (old method) */
    1002          25 :         subject = X509_get_subject_name(cert);
    1003          25 :         if (!subject)
    1004             :                 return 0;
    1005             : 
    1006             :         i = -1;
    1007          50 :         while (X509_NAME_get_index_by_NID(subject, NID_commonName, i) >= 0)
    1008          25 :                 i = X509_NAME_get_index_by_NID(subject, NID_commonName, i);
    1009          25 :         if (i < 0)
    1010             :                 return 0;
    1011             : 
    1012          25 :         name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i));
    1013          25 :         if (!name)
    1014             :                 return 0;
    1015             : 
    1016          25 :         return check_name_match(name, hostname);
    1017             : }
    1018             : 
    1019             : int
    1020        1082 : tds_ssl_init(TDSSOCKET *tds, bool full)
    1021             : {
    1022             : #define DEFAULT_OPENSSL_CTX_OPTIONS \
    1023             :         (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1)
    1024             : #define DEFAULT_OPENSSL_CIPHERS "HIGH:!SSLv2:!aNULL:-DH"
    1025             : 
    1026             :         SSL *con;
    1027             :         SSL_CTX *ctx;
    1028             :         BIO *b, *b2;
    1029             : 
    1030             :         int ret, connect_ret;
    1031             :         const char *tls_msg;
    1032             : 
    1033        1082 :         unsigned long ctx_options = DEFAULT_OPENSSL_CTX_OPTIONS;
    1034             : 
    1035        1082 :         con = NULL;
    1036        1082 :         b = NULL;
    1037        1082 :         b2 = NULL;
    1038        1082 :         ret = 1;
    1039             : 
    1040        1082 :         tds_check_wildcard_test();
    1041             : 
    1042        1082 :         tds_ssl_deinit(tds->conn);
    1043             : 
    1044        1082 :         tls_msg = "initializing tls";
    1045        1082 :         ctx = tds_init_openssl();
    1046        1082 :         if (!ctx)
    1047             :                 goto cleanup;
    1048             : 
    1049        1082 :         if (tds->login && tds->login->enable_tls_v1)
    1050         723 :                 ctx_options &= ~SSL_OP_NO_TLSv1;
    1051        1082 :         if (tds->login && tds->login->enable_tls_v1_1)
    1052           0 :                 ctx_options &= ~SSL_OP_NO_TLSv1_1;
    1053        1082 :         SSL_CTX_set_options(ctx, ctx_options);
    1054             : 
    1055        2164 :         if (!tds_dstr_isempty(&tds->login->cafile)) {
    1056           0 :                 tls_msg = "loading CA file";
    1057           0 :                 if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
    1058           0 :                         ret = SSL_CTX_set_default_verify_paths(ctx);
    1059             :                 else
    1060           0 :                         ret = SSL_CTX_load_verify_locations(ctx, tds_dstr_cstr(&tds->login->cafile), NULL);
    1061           0 :                 if (ret != 1)
    1062             :                         goto cleanup;
    1063           0 :                 if (!tds_dstr_isempty(&tds->login->crlfile)) {
    1064           0 :                         X509_STORE *store = SSL_CTX_get_cert_store(ctx);
    1065             :                         X509_LOOKUP *lookup;
    1066             : 
    1067           0 :                         tls_msg = "loading CRL file";
    1068           0 :                         if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()))
    1069           0 :                             || (!X509_load_crl_file(lookup, tds_dstr_cstr(&tds->login->crlfile), X509_FILETYPE_PEM)))
    1070             :                                 goto cleanup;
    1071             : 
    1072           0 :                         X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
    1073             :                 }
    1074           0 :                 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    1075             :         }
    1076             : 
    1077             :         /* Initialize TLS session */
    1078        1082 :         tls_msg = "initializing session";
    1079        1082 :         con = SSL_new(ctx);
    1080        1082 :         if (!con)
    1081             :                 goto cleanup;
    1082             : 
    1083        1082 :         tls_msg = "creating bio";
    1084        1082 :         b = BIO_new(full ? tds_method : tds_method_login);
    1085        1082 :         if (!b)
    1086             :                 goto cleanup;
    1087             : 
    1088        1082 :         if (!full) {
    1089        1082 :                 b2 = BIO_new(tds_method);
    1090        1082 :                 if (!b2)
    1091             :                         goto cleanup;
    1092             :         }
    1093             : 
    1094        1082 :         BIO_set_init(b, 1);
    1095        1082 :         BIO_set_data(b, full ? (void *) tds->conn : (void *) tds);
    1096        2164 :         BIO_set_conn_hostname(b, wanted_certificate_hostname(tds->login));
    1097        1082 :         SSL_set_bio(con, b, b);
    1098        1082 :         b = NULL;
    1099             : 
    1100             :         /* use default priorities unless overridden by openssl ciphers setting in freetds.conf file... */
    1101        2164 :         if (!tds_dstr_isempty(&tds->login->openssl_ciphers)) {
    1102           0 :                 tdsdump_log(TDS_DBG_INFO1, "setting custom openssl cipher to:%s\n", tds_dstr_cstr(&tds->login->openssl_ciphers));
    1103           0 :                 SSL_set_cipher_list(con, tds_dstr_cstr(&tds->login->openssl_ciphers) );
    1104             :         } else {
    1105        1082 :                 tdsdump_log(TDS_DBG_INFO1, "setting default openssl cipher to:%s\n", DEFAULT_OPENSSL_CIPHERS );
    1106        1082 :                 SSL_set_cipher_list(con, DEFAULT_OPENSSL_CIPHERS);
    1107             :         }
    1108             : 
    1109             : #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
    1110             :         /* this disable a security improvement but allow connection... */
    1111        1082 :         SSL_set_options(con, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
    1112             : #endif
    1113             : 
    1114             : #ifdef HAVE_SSL_SET_ALPN_PROTOS
    1115        1082 :         if (IS_TDS80_PLUS(tds->conn)) {
    1116             :                 static const unsigned char tds8_alpn[] = {
    1117             :                         TDS8_ALPN_ARRAY_LEN, TDS8_ALPN_ARRAY
    1118             :                 };
    1119           0 :                 SSL_set_alpn_protos(con, tds8_alpn, sizeof(tds8_alpn));
    1120             :         }
    1121             : #endif
    1122             : 
    1123             :         if (full)
    1124             :                 set_current_tds(tds->conn, tds);
    1125             : 
    1126             :         /* Perform the TLS handshake */
    1127        1082 :         tls_msg = "handshake";
    1128        1082 :         ERR_clear_error();
    1129        1082 :         SSL_set_connect_state(con);
    1130        1082 :         connect_ret = SSL_connect(con);
    1131        2164 :         ret = connect_ret != 1 || SSL_get_state(con) != TLS_ST_OK;
    1132             :         if (ret != 0) {
    1133           0 :                 tdsdump_log(TDS_DBG_ERROR, "handshake failed with %d %d %d\n",
    1134           0 :                             connect_ret, SSL_get_state(con), SSL_get_error(con, connect_ret));
    1135             :                 goto cleanup;
    1136             :         }
    1137             : 
    1138             :         /* flush pending data */
    1139        2164 :         if (!full && tds->out_pos > 8)
    1140           0 :                 tds_flush_packet(tds);
    1141             : 
    1142             :         /* check certificate hostname */
    1143        2164 :         if (!tds_dstr_isempty(&tds->login->cafile) && tds->login->check_ssl_hostname) {
    1144             :                 X509 *cert;
    1145             : 
    1146           0 :                 cert =  SSL_get_peer_certificate(con);
    1147           0 :                 tls_msg = "checking hostname";
    1148           0 :                 if (!cert || !check_hostname(cert, wanted_certificate_hostname(tds->login)))
    1149             :                         goto cleanup;
    1150           0 :                 X509_free(cert);
    1151             :         }
    1152             : 
    1153        1082 :         tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");
    1154             : 
    1155        1082 :         if (!full) {
    1156             :                 /* some TLS implementations send some sort of paddind at the end, remove it */
    1157        1082 :                 tds->in_pos = tds->in_len;
    1158             : 
    1159        1082 :                 BIO_set_init(b2, 1);
    1160        1082 :                 BIO_set_data(b2, tds->conn);
    1161        1082 :                 SSL_set_bio(con, b2, b2);
    1162             :         }
    1163             : 
    1164        1082 :         set_current_tds(tds->conn, NULL);
    1165             : 
    1166        1082 :         tds->conn->tls_session = con;
    1167        1082 :         tds->conn->tls_ctx = ctx;
    1168             : 
    1169        1082 :         return TDS_SUCCESS;
    1170             : 
    1171           0 : cleanup:
    1172           0 :         if (b2)
    1173           0 :                 BIO_free(b2);
    1174           0 :         if (b)
    1175           0 :                 BIO_free(b);
    1176           0 :         if (con) {
    1177           0 :                 SSL_shutdown(con);
    1178           0 :                 SSL_free(con);
    1179             :         }
    1180           0 :         set_current_tds(tds->conn, NULL);
    1181           0 :         SSL_CTX_free(ctx);
    1182           0 :         tdsdump_log(TDS_DBG_ERROR, "%s failed\n", tls_msg);
    1183             :         return TDS_FAIL;
    1184             : }
    1185             : 
    1186             : void
    1187        5909 : tds_ssl_deinit(TDSCONNECTION *conn)
    1188             : {
    1189        5909 :         if (conn->tls_session) {
    1190             :                 /* NOTE do not call SSL_shutdown here */
    1191        1076 :                 SSL_free((SSL *) conn->tls_session);
    1192        1076 :                 conn->tls_session = NULL;
    1193             :         }
    1194        5909 :         if (conn->tls_ctx) {
    1195        1076 :                 SSL_CTX_free((SSL_CTX *) conn->tls_ctx);
    1196        1076 :                 conn->tls_ctx = NULL;
    1197             :         }
    1198        5909 :         conn->encrypt_single_packet = 0;
    1199        5909 : }
    1200             : #endif
    1201             : 
    1202             : #endif
    1203             : /** @} */
    1204             : 

Generated by: LCOV version 1.13