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