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 42986 : tds_pull_func(SSL_PULL_ARGS)
156 : {
157 42986 : TDSCONNECTION *conn = (TDSCONNECTION *) SSL_PTR;
158 : TDSSOCKET *tds;
159 :
160 42986 : tdsdump_log(TDS_DBG_FUNC, "in tds_pull_func\n");
161 :
162 : #if ENABLE_ODBC_MARS
163 21697 : tds = conn->in_net_tds;
164 21697 : assert(tds);
165 : #else
166 21289 : 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 42986 : 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 847 : tds_tls_deinit(void)
208 : {
209 847 : if (tls_initialized)
210 374 : gnutls_global_deinit();
211 847 : }
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 4042 : tds_ssl_deinit(TDSCONNECTION *conn)
573 : {
574 4042 : if (conn->tls_session) {
575 710 : gnutls_deinit((gnutls_session_t) conn->tls_session);
576 710 : conn->tls_session = NULL;
577 : }
578 4042 : 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 4042 : conn->encrypt_single_packet = 0;
583 4042 : }
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 :
|