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

Generated by: LCOV version 1.13