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