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