LCOV - code coverage report
Current view: top level - src/tds - tls.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 223 347 64.3 %
Date: 2024-04-20 13:37:27 Functions: 15 19 78.9 %

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

Generated by: LCOV version 1.13