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 #include <stdio.h>
24 
25 #if HAVE_ERRNO_H
26 #include <errno.h>
27 #endif /* HAVE_ERRNO_H */
28 
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif /* HAVE_UNISTD_H */
32 
33 #if HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif /* HAVE_STDLIB_H */
36 
37 #if HAVE_STRING_H
38 #include <string.h>
39 #endif /* HAVE_STRING_H */
40 
41 #if HAVE_DIRENT_H
42 #include <dirent.h>
43 #endif /* HAVE_DIRENT_H */
44 
45 #if HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif /* HAVE_SYS_STAT_H */
48 
49 #include <freetds/tds.h>
50 #include <freetds/string.h>
51 #include <freetds/tls.h>
52 #include "replacements.h"
53 
54 #include <assert.h>
55 
56 /**
57  * \addtogroup network
58  * @{
59  */
60 
61 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
62 
63 #ifdef HAVE_GNUTLS
64 #define SSL_RET ssize_t
65 #define SSL_PULL_ARGS gnutls_transport_ptr ptr, void *data, size_t len
66 #define SSL_PUSH_ARGS gnutls_transport_ptr ptr, const void *data, size_t len
67 #define SSL_PTR ptr
68 #else
69 #define SSL_RET int
70 #define SSL_PULL_ARGS BIO *bio, char *data, int len
71 #define SSL_PUSH_ARGS BIO *bio, const char *data, int len
72 #define SSL_PTR bio->ptr
73 #endif
74 
75 static SSL_RET
tds_pull_func_login(SSL_PULL_ARGS)76 tds_pull_func_login(SSL_PULL_ARGS)
77 {
78 	TDSSOCKET *tds = (TDSSOCKET *) SSL_PTR;
79 	int have;
80 
81 	tdsdump_log(TDS_DBG_INFO1, "in tds_pull_func_login\n");
82 
83 	/* here we are initializing (crypted inside TDS packets) */
84 
85 	/* if we have some data send it */
86 	/* here MARS is not already initialized so test is correct */
87 	/* TODO test even after initializing ?? */
88 	if (tds->out_pos > 8)
89 		tds_flush_packet(tds);
90 
91 	for(;;) {
92 		have = tds->in_len - tds->in_pos;
93 		tdsdump_log(TDS_DBG_INFO1, "have %d\n", have);
94 		assert(have >= 0);
95 		if (have > 0)
96 			break;
97 		tdsdump_log(TDS_DBG_INFO1, "before read\n");
98 		if (tds_read_packet(tds) < 0)
99 			return -1;
100 		tdsdump_log(TDS_DBG_INFO1, "after read\n");
101 	}
102 	if (len > have)
103 		len = have;
104 	tdsdump_log(TDS_DBG_INFO1, "read %lu bytes\n", (unsigned long int) len);
105 	memcpy(data, tds->in_buf + tds->in_pos, len);
106 	tds->in_pos += len;
107 	return len;
108 }
109 
110 static SSL_RET
tds_push_func_login(SSL_PUSH_ARGS)111 tds_push_func_login(SSL_PUSH_ARGS)
112 {
113 	TDSSOCKET *tds = (TDSSOCKET *) SSL_PTR;
114 
115 	tdsdump_log(TDS_DBG_INFO1, "in tds_push_func_login\n");
116 
117 	/* initializing SSL, write crypted data inside normal TDS packets */
118 	tds_put_n(tds, data, len);
119 	return len;
120 }
121 
122 static SSL_RET
tds_pull_func(SSL_PULL_ARGS)123 tds_pull_func(SSL_PULL_ARGS)
124 {
125 	TDSCONNECTION *conn = (TDSCONNECTION *) SSL_PTR;
126 	TDSSOCKET *tds;
127 
128 	tdsdump_log(TDS_DBG_INFO1, "in tds_pull_func\n");
129 
130 #if ENABLE_ODBC_MARS
131 	tds = conn->in_net_tds;
132 	assert(tds);
133 #else
134 	tds = (TDSSOCKET *) conn;
135 #endif
136 
137 	/* already initialized (crypted TDS packets) */
138 
139 	/* read directly from socket */
140 	/* TODO we block write on other sessions */
141 	/* also we should already have tested for data on socket */
142 	return tds_goodread(tds, (unsigned char*) data, len);
143 }
144 
145 static SSL_RET
tds_push_func(SSL_PUSH_ARGS)146 tds_push_func(SSL_PUSH_ARGS)
147 {
148 	TDSCONNECTION *conn = (TDSCONNECTION *) SSL_PTR;
149 	TDSSOCKET *tds;
150 
151 	tdsdump_log(TDS_DBG_INFO1, "in tds_push_func\n");
152 
153 	/* write to socket directly */
154 	/* TODO use cork if available here to flush only on last chunk of packet ?? */
155 #if ENABLE_ODBC_MARS
156 	tds = conn->in_net_tds;
157 	/* FIXME with SMP trick to detect final is not ok */
158 	return tds_goodwrite(tds, (const unsigned char*) data, len,
159 			     conn->send_packets->next == NULL);
160 #else
161 	tds = (TDSSOCKET *) conn;
162 	return tds_goodwrite(tds, (const unsigned char*) data, len, tds->out_buf[1]);
163 #endif
164 }
165 
166 static int tls_initialized = 0;
167 static tds_mutex tls_mutex = TDS_MUTEX_INITIALIZER;
168 
169 #ifdef HAVE_GNUTLS
170 
171 static void
tds_tls_log(int level,const char * s)172 tds_tls_log( int level, const char* s)
173 {
174 	tdsdump_log(TDS_DBG_INFO1, "GNUTLS: level %d:\n  %s", level, s);
175 }
176 
177 #ifdef TDS_ATTRIBUTE_DESTRUCTOR
178 static void __attribute__((destructor))
tds_tls_deinit(void)179 tds_tls_deinit(void)
180 {
181 	if (tls_initialized)
182 		gnutls_global_deinit();
183 }
184 #endif
185 
186 #if defined(_THREAD_SAFE) && defined(TDS_HAVE_PTHREAD_MUTEX)
187 GCRY_THREAD_OPTION_PTHREAD_IMPL;
188 #define tds_gcry_init() gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread)
189 #else
190 #define tds_gcry_init() do {} while(0)
191 #endif
192 
193 /* This piece of code is copied from GnuTLS new sources to handle IP in the certificate */
194 #if GNUTLS_VERSION_NUMBER < 0x030306
195 static int
check_ip(gnutls_x509_crt_t cert,const void * ip,unsigned ip_size)196 check_ip(gnutls_x509_crt_t cert, const void *ip, unsigned ip_size)
197 {
198 	char temp[16];
199 	size_t temp_size;
200 	unsigned i;
201 	int ret = 0;
202 
203 	/* try matching against:
204 	 *  1) a IPaddress alternative name (subjectAltName) extension
205 	 *     in the certificate
206 	 */
207 
208 	/* Check through all included subjectAltName extensions, comparing
209 	 * against all those of type IPAddress.
210 	 */
211 	for (i = 0; ret >= 0; ++i) {
212 		temp_size = sizeof(temp);
213 		ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
214 							   temp,
215 							   &temp_size,
216 							   NULL);
217 
218 		if (ret == GNUTLS_SAN_IPADDRESS) {
219 			if (temp_size == ip_size && memcmp(temp, ip, ip_size) == 0)
220 				return 1;
221 		} else if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
222 			ret = 0;
223 		}
224 	}
225 
226 	/* not found a matching IP */
227 	return 0;
228 }
229 
230 static int
tds_check_ip(gnutls_x509_crt_t cert,const char * hostname)231 tds_check_ip(gnutls_x509_crt_t cert, const char *hostname)
232 {
233 	int ret;
234 	union {
235 		struct in_addr v4;
236 		struct in6_addr v6;
237 	} ip;
238 	unsigned ip_size;
239 
240 	/* check whether @hostname is an ip address */
241 	if (strchr(hostname, ':') != NULL) {
242 		ip_size = 16;
243 		ret = inet_pton(AF_INET6, hostname, &ip.v6);
244 	} else {
245 		ip_size = 4;
246 		ret = inet_pton(AF_INET, hostname, &ip.v4);
247 	}
248 
249 	if (ret != 0)
250 		ret = check_ip(cert, &ip, ip_size);
251 
252 	/* There are several misconfigured servers, that place their IP
253 	 * in the DNS field of subjectAlternativeName. Don't break these
254 	 * configurations and verify the IP as it would have been a DNS name. */
255 
256 	return ret;
257 }
258 
259 /* function for replacing old GnuTLS version */
260 static int
tds_x509_crt_check_hostname(gnutls_x509_crt_t cert,const char * hostname)261 tds_x509_crt_check_hostname(gnutls_x509_crt_t cert, const char *hostname)
262 {
263 	int ret;
264 
265 	ret = tds_check_ip(cert, hostname);
266 	if (ret)
267 		return ret;
268 
269 	return gnutls_x509_crt_check_hostname(cert, hostname);
270 }
271 #define gnutls_x509_crt_check_hostname tds_x509_crt_check_hostname
272 
273 #endif
274 
275 #if GNUTLS_VERSION_MAJOR < 3
276 static int
tds_certificate_set_x509_system_trust(gnutls_certificate_credentials cred)277 tds_certificate_set_x509_system_trust(gnutls_certificate_credentials cred)
278 {
279 	static const char ca_directory[] = "/etc/ssl/certs";
280 	DIR *dir;
281 	struct dirent *dent;
282 #ifdef HAVE_READDIR_R
283 	struct dirent ent;
284 #endif
285 	int rc;
286 	int ncerts;
287 	size_t ca_file_length;
288 	char *ca_file;
289 
290 
291 	dir = opendir(ca_directory);
292 	if (!dir)
293 		return 0;
294 
295 	ca_file_length = strlen(ca_directory) + sizeof(dent->d_name) + 2;
296 	ca_file = alloca(ca_file_length);
297 
298 	ncerts = 0;
299 	for (;;) {
300 		struct stat st;
301 
302 #ifdef HAVE_READDIR_R
303 		if (readdir_r(dir, &ent, &dent))
304 			dent = NULL;
305 #else
306 		dent = readdir(dir);
307 #endif
308 		if (!dent)
309 			break;
310 
311 		snprintf(ca_file, ca_file_length, "%s/%s", ca_directory, dent->d_name);
312 		if (stat(ca_file, &st) != 0)
313 			continue;
314 
315 		if (!S_ISREG(st.st_mode))
316 			continue;
317 
318 		rc = gnutls_certificate_set_x509_trust_file(cred, ca_file, GNUTLS_X509_FMT_PEM);
319 		if (rc >= 0)
320 			ncerts += rc;
321 	}
322 
323 	closedir(dir);
324 	return ncerts;
325 }
326 #define gnutls_certificate_set_x509_system_trust tds_certificate_set_x509_system_trust
327 
328 #endif
329 
330 static int
tds_verify_certificate(gnutls_session_t session)331 tds_verify_certificate(gnutls_session_t session)
332 {
333 	unsigned int status;
334 	int ret;
335 	TDSSOCKET *tds = (TDSSOCKET *) gnutls_transport_get_ptr(session);
336 
337 	if (!tds->login)
338 		return GNUTLS_E_CERTIFICATE_ERROR;
339 
340 	ret = gnutls_certificate_verify_peers2(session, &status);
341 	if (ret < 0) {
342 		tdsdump_log(TDS_DBG_ERROR, "Error verifying certificate: %s\n", gnutls_strerror(ret));
343 		return GNUTLS_E_CERTIFICATE_ERROR;
344 	}
345 
346 	/* Certificate is not trusted */
347 	if (status != 0) {
348 		tdsdump_log(TDS_DBG_ERROR, "Certificate status: %u\n", status);
349 		return GNUTLS_E_CERTIFICATE_ERROR;
350 	}
351 
352 	/* check hostname */
353 	if (tds->login->check_ssl_hostname) {
354 		const gnutls_datum_t *cert_list;
355 		unsigned int list_size;
356 		gnutls_x509_crt_t cert;
357 
358 		cert_list = gnutls_certificate_get_peers(session, &list_size);
359 		if (!cert_list) {
360 			tdsdump_log(TDS_DBG_ERROR, "Error getting TLS session peers\n");
361 			return GNUTLS_E_CERTIFICATE_ERROR;
362 		}
363 		gnutls_x509_crt_init(&cert);
364 		gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
365 		ret = gnutls_x509_crt_check_hostname(cert, tds_dstr_cstr(&tds->login->server_host_name));
366 		gnutls_x509_crt_deinit(cert);
367 		if (!ret) {
368 			tdsdump_log(TDS_DBG_ERROR, "Certificate hostname does not match\n");
369 			return GNUTLS_E_CERTIFICATE_ERROR;
370 		}
371 	}
372 
373 	/* notify gnutls to continue handshake normally */
374 	return 0;
375 }
376 
377 TDSRET
tds_ssl_init(TDSSOCKET * tds)378 tds_ssl_init(TDSSOCKET *tds)
379 {
380 	gnutls_session session;
381 	gnutls_certificate_credentials xcred;
382 	int ret;
383 	const char *tls_msg;
384 
385 	xcred = NULL;
386 	session = NULL;
387 	tls_msg = "initializing tls";
388 
389 	if (!tls_initialized) {
390 		ret = 0;
391 		tds_mutex_lock(&tls_mutex);
392 		if (!tls_initialized) {
393 			tds_gcry_init();
394 			ret = gnutls_global_init();
395 			if (ret == 0)
396 				tls_initialized = 1;
397 		}
398 		tds_mutex_unlock(&tls_mutex);
399 		if (ret != 0)
400 			goto cleanup;
401 	}
402 
403 	if (tds_write_dump && tls_initialized < 2) {
404 		gnutls_global_set_log_level(11);
405 		gnutls_global_set_log_function(tds_tls_log);
406 		tls_initialized = 2;
407 	}
408 
409 	tls_msg = "allocating credentials";
410 	ret = gnutls_certificate_allocate_credentials(&xcred);
411 	if (ret != 0)
412 		goto cleanup;
413 
414 	if (!tds_dstr_isempty(&tds->login->cafile)) {
415 		tls_msg = "loading CA file";
416 		if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
417 			ret = gnutls_certificate_set_x509_system_trust(xcred);
418 		else
419 			ret = gnutls_certificate_set_x509_trust_file(xcred, tds_dstr_cstr(&tds->login->cafile), GNUTLS_X509_FMT_PEM);
420 		if (ret <= 0)
421 			goto cleanup;
422 		if (!tds_dstr_isempty(&tds->login->crlfile)) {
423 			tls_msg = "loading CRL file";
424 			ret = gnutls_certificate_set_x509_crl_file(xcred, tds_dstr_cstr(&tds->login->crlfile), GNUTLS_X509_FMT_PEM);
425 			if (ret <= 0)
426 				goto cleanup;
427 		}
428 		gnutls_certificate_set_verify_function(xcred, tds_verify_certificate);
429 	}
430 
431 	/* Initialize TLS session */
432 	tls_msg = "initializing session";
433 	ret = gnutls_init(&session, GNUTLS_CLIENT);
434 	if (ret != 0)
435 		goto cleanup;
436 
437 	gnutls_transport_set_ptr(session, tds);
438 	gnutls_transport_set_pull_function(session, tds_pull_func_login);
439 	gnutls_transport_set_push_function(session, tds_push_func_login);
440 
441 	/* NOTE: there functions return int however they cannot fail */
442 
443 	/* use default priorities... */
444 	gnutls_set_default_priority(session);
445 
446 	/* ... but overwrite some */
447 	ret = gnutls_priority_set_direct (session, "NORMAL:%COMPAT:-VERS-SSL3.0", NULL);
448 	if (ret != 0)
449 		goto cleanup;
450 
451 	/* mssql does not like padding too much */
452 #ifdef HAVE_GNUTLS_RECORD_DISABLE_PADDING
453 	gnutls_record_disable_padding(session);
454 #endif
455 
456 	/* put the anonymous credentials to the current session */
457 	tls_msg = "setting credential";
458 	ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
459 	if (ret != 0)
460 		goto cleanup;
461 
462 	/* Perform the TLS handshake */
463 	tls_msg = "handshake";
464 	ret = gnutls_handshake (session);
465 	if (ret != 0)
466 		goto cleanup;
467 
468 	tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");
469 
470 	gnutls_transport_set_ptr(session, tds->conn);
471 	gnutls_transport_set_pull_function(session, tds_pull_func);
472 	gnutls_transport_set_push_function(session, tds_push_func);
473 
474 	tds->conn->tls_session = session;
475 	tds->conn->tls_credentials = xcred;
476 
477 	return TDS_SUCCESS;
478 
479 cleanup:
480 	if (session)
481 		gnutls_deinit(session);
482 	if (xcred)
483 		gnutls_certificate_free_credentials(xcred);
484 	tdsdump_log(TDS_DBG_ERROR, "%s failed: %s\n", tls_msg, gnutls_strerror (ret));
485 	return TDS_FAIL;
486 }
487 
488 void
tds_ssl_deinit(TDSCONNECTION * conn)489 tds_ssl_deinit(TDSCONNECTION *conn)
490 {
491 	if (conn->tls_session) {
492 		gnutls_deinit((gnutls_session) conn->tls_session);
493 		conn->tls_session = NULL;
494 	}
495 	if (conn->tls_credentials) {
496 		gnutls_certificate_free_credentials((gnutls_certificate_credentials) conn->tls_credentials);
497 		conn->tls_credentials = NULL;
498 	}
499 }
500 
501 #else
502 static long
tds_ssl_ctrl_login(BIO * b,int cmd,long num,void * ptr)503 tds_ssl_ctrl_login(BIO *b, int cmd, long num, void *ptr)
504 {
505 	TDSSOCKET *tds = (TDSSOCKET *) b->ptr;
506 
507 	switch (cmd) {
508 	case BIO_CTRL_FLUSH:
509 		if (tds->out_pos > 8)
510 			tds_flush_packet(tds);
511 		return 1;
512 	}
513 	return 0;
514 }
515 
516 static int
tds_ssl_free(BIO * a)517 tds_ssl_free(BIO *a)
518 {
519 	/* nothing to do but required */
520 	return 1;
521 }
522 
523 static BIO_METHOD tds_method_login =
524 {
525 	BIO_TYPE_MEM,
526 	"tds",
527 	tds_push_func_login,
528 	tds_pull_func_login,
529 	NULL,
530 	NULL,
531 	tds_ssl_ctrl_login,
532 	NULL,
533 	tds_ssl_free,
534 	NULL,
535 };
536 
537 static BIO_METHOD tds_method =
538 {
539 	BIO_TYPE_MEM,
540 	"tds",
541 	tds_push_func,
542 	tds_pull_func,
543 	NULL,
544 	NULL,
545 	NULL,
546 	NULL,
547 	tds_ssl_free,
548 	NULL,
549 };
550 
551 
552 static SSL_CTX *
tds_init_openssl(void)553 tds_init_openssl(void)
554 {
555 	const SSL_METHOD *meth;
556 
557 	if (!tls_initialized) {
558 		tds_mutex_lock(&tls_mutex);
559 		if (!tls_initialized) {
560 			SSL_library_init();
561 			tls_initialized = 1;
562 		}
563 		tds_mutex_unlock(&tls_mutex);
564 	}
565 	meth = TLSv1_client_method ();
566 	if (meth == NULL)
567 		return NULL;
568 	return SSL_CTX_new (meth);
569 }
570 
571 static int
check_wildcard(const char * host,const char * match)572 check_wildcard(const char *host, const char *match)
573 {
574 	const char *p, *w;
575 	size_t n, lh, lm;
576 
577 	/* U-label (binary) */
578 	for (p = match; *p; ++p)
579 		if ((unsigned char) *p >= 0x80)
580 			return strcmp(host, match) == 0;
581 
582 	for (;;) {
583 		/* A-label (starts with xn--) */
584 		if (strncasecmp(match, "xn--", 4) == 0)
585 			break;
586 
587 		/* match must not be in domain and domain should contains 2 parts */
588 		w = strchr(match, '*');
589 		p = strchr(match, '.');
590 		if (!w || !p		/* no wildcard or domain */
591 		    || p[1] == '.'	/* empty domain */
592 		    || w > p || strchr(p, '*') != NULL)	/* wildcard in domain */
593 			break;
594 		p = strchr(p+1, '.');
595 		if (!p || p[1] == 0)	/* not another domain */
596 			break;
597 
598 		/* check start */
599 		n = w - match;	/* prefix len */
600 		if (n > 0 && strncasecmp(host, match, n) != 0)
601 			return 0;
602 
603 		/* check end */
604 		lh = strlen(host);
605 		lm = strlen(match);
606 		n = lm - n - 1;	/* suffix len */
607 		if (lm - 1 > lh || strcasecmp(host+lh-n, match+lm-n) != 0 || host[0] == '.')
608 			return 0;
609 
610 		return 1;
611 	}
612 	return strcasecmp(host, match) == 0;
613 }
614 
615 #if ENABLE_EXTRA_CHECKS
616 static void
tds_check_wildcard_test(void)617 tds_check_wildcard_test(void)
618 {
619 	assert(check_wildcard("foo", "foo") == 1);
620 	assert(check_wildcard("FOO", "foo") == 1);
621 	assert(check_wildcard("foo", "FOO") == 1);
622 	assert(check_wildcard("\x90oo", "\x90OO") == 0);
623 	assert(check_wildcard("xn--foo", "xn--foo") == 1);
624 	assert(check_wildcard("xn--FOO", "XN--foo") == 1);
625 	assert(check_wildcard("xn--a.example.org", "xn--*.example.org") == 0);
626 	assert(check_wildcard("a.*", "a.*") == 1);
627 	assert(check_wildcard("a.b", "a.*") == 0);
628 	assert(check_wildcard("ab", "a*") == 0);
629 	assert(check_wildcard("a.example.", "*.example.") == 0);
630 	assert(check_wildcard("a.example.com", "*.example.com") == 1);
631 	assert(check_wildcard("a.b.example.com", "a.*.example.com") == 0);
632 	assert(check_wildcard("foo.example.com", "foo*.example.com") == 1);
633 	assert(check_wildcard("fou.example.com", "foo*.example.com") == 0);
634 	assert(check_wildcard("baz.example.com", "*baz.example.com") == 1);
635 	assert(check_wildcard("buzz.example.com", "b*z.example.com") == 1);
636 	assert(check_wildcard("bz.example.com", "b*z.example.com") == 1);
637 	assert(check_wildcard(".example.com", "*.example.com") == 0);
638 	assert(check_wildcard("example.com", "*.example.com") == 0);
639 }
640 #else
641 #define tds_check_wildcard_test() do { } while(0)
642 #endif
643 
644 static int
check_name_match(ASN1_STRING * name,const char * hostname)645 check_name_match(ASN1_STRING *name, const char *hostname)
646 {
647 	char *name_utf8 = NULL;
648 	int ret, name_len;
649 
650 	name_len = ASN1_STRING_to_UTF8((unsigned char **) &name_utf8, name);
651 	if (name_len < 0)
652 		return 0;
653 
654 	tdsdump_log(TDS_DBG_INFO1, "Got name %s\n", name_utf8);
655 	ret = 0;
656 	if (strlen(name_utf8) == name_len && check_wildcard(name_utf8, hostname) == 0)
657 		ret = 1;
658 	OPENSSL_free(name_utf8);
659 	return ret;
660 }
661 
662 static int
check_alt_names(X509 * cert,const char * hostname)663 check_alt_names(X509 *cert, const char *hostname)
664 {
665 	STACK_OF(GENERAL_NAME) *alt_names;
666 	int i, num;
667 	int ret = 1;
668 	union {
669 		struct in_addr v4;
670 		struct in6_addr v6;
671 	} ip;
672 	unsigned ip_size = 0;
673 
674 	/* check whether @hostname is an ip address */
675 	if (strchr(hostname, ':') != NULL) {
676 		ip_size = 16;
677 		ret = inet_pton(AF_INET6, hostname, &ip.v6);
678 	} else {
679 		ip_size = 4;
680 		ret = inet_pton(AF_INET, hostname, &ip.v4);
681 	}
682 	if (ret == 0)
683 		return -1;
684 
685 	ret = -1;
686 
687 	alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
688 	if (!alt_names)
689 		return ret;
690 
691 	num = sk_GENERAL_NAME_num(alt_names);
692 	tdsdump_log(TDS_DBG_INFO1, "Alt names number %d\n", num);
693 	for (i = 0; i < num; ++i) {
694 		const char *altptr;
695 		size_t altlen;
696 
697 		const GENERAL_NAME *name = sk_GENERAL_NAME_value(alt_names, i);
698 		if (!name)
699 			continue;
700 
701 		altptr = (const char *) ASN1_STRING_data(name->d.ia5);
702 		altlen = (size_t) ASN1_STRING_length(name->d.ia5);
703 
704 		if (name->type == GEN_DNS && ip_size == 0) {
705 			ret = 0;
706 			if (!check_name_match(name->d.dNSName, hostname))
707 				continue;
708 		} else if (name->type == GEN_IPADD && ip_size != 0) {
709 			ret = 0;
710 			if (altlen != ip_size || memcmp(altptr, &ip, altlen) != 0)
711 				continue;
712 		} else {
713 			continue;
714 		}
715 
716 		sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
717 		return 1;
718 	}
719 	sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
720 	return ret;
721 }
722 
723 static int
check_hostname(X509 * cert,const char * hostname)724 check_hostname(X509 *cert, const char *hostname)
725 {
726 	int ret, i;
727 	X509_NAME *subject;
728 	ASN1_STRING *name;
729 
730 	/* check by subject */
731 	ret = check_alt_names(cert, hostname);
732 	if (ret >= 0)
733 		return ret;
734 
735 	/* check by common name (old method) */
736 	subject= X509_get_subject_name(cert);
737 	if (!subject)
738 		return 0;
739 
740 	i = -1;
741 	while (X509_NAME_get_index_by_NID(subject, NID_commonName, i) >=0)
742 		i = X509_NAME_get_index_by_NID(subject, NID_commonName, i);
743 	if (i < 0)
744 		return 0;
745 
746 	name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i));
747 	if (!name)
748 		return 0;
749 
750 	return check_name_match(name, hostname);
751 }
752 
753 int
tds_ssl_init(TDSSOCKET * tds)754 tds_ssl_init(TDSSOCKET *tds)
755 {
756 #define OPENSSL_CIPHERS \
757 	"DHE-RSA-AES256-SHA DHE-DSS-AES256-SHA " \
758 	"AES256-SHA EDH-RSA-DES-CBC3-SHA " \
759 	"EDH-DSS-DES-CBC3-SHA DES-CBC3-SHA " \
760 	"DES-CBC3-MD5 DHE-RSA-AES128-SHA " \
761 	"DHE-DSS-AES128-SHA AES128-SHA RC2-CBC-MD5 RC4-SHA RC4-MD5"
762 
763 	SSL *con;
764 	SSL_CTX *ctx;
765 	BIO *b, *b2;
766 
767 	int ret;
768 	const char *tls_msg;
769 
770 	con = NULL;
771 	b = NULL;
772 	b2 = NULL;
773 	ret = 1;
774 
775 	tds_check_wildcard_test();
776 
777 	tds_ssl_deinit(tds->conn);
778 
779 	tls_msg = "initializing tls";
780 	ctx = tds_init_openssl();
781 	if (!ctx)
782 		goto cleanup;
783 
784 	if (!tds_dstr_isempty(&tds->login->cafile)) {
785 		tls_msg = "loading CA file";
786 		if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
787 			ret = SSL_CTX_set_default_verify_paths(ctx);
788 		else
789 			ret = SSL_CTX_load_verify_locations(ctx, tds_dstr_cstr(&tds->login->cafile), NULL);
790 		if (ret != 1)
791 			goto cleanup;
792 		if (!tds_dstr_isempty(&tds->login->crlfile)) {
793 			X509_STORE *store = SSL_CTX_get_cert_store(ctx);
794 			X509_LOOKUP *lookup;
795 
796 			tls_msg = "loading CRL file";
797 			if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()))
798 			    || (!X509_load_crl_file(lookup, tds_dstr_cstr(&tds->login->crlfile), X509_FILETYPE_PEM)))
799 				goto cleanup;
800 
801 			X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
802 		}
803 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
804 	}
805 
806 	/* Initialize TLS session */
807 	tls_msg = "initializing session";
808 	con = SSL_new(ctx);
809 	if (!con)
810 		goto cleanup;
811 
812 	tls_msg = "creating bio";
813 	b = BIO_new(&tds_method_login);
814 	if (!b)
815 		goto cleanup;
816 
817 	b2 = BIO_new(&tds_method);
818 	if (!b2)
819 		goto cleanup;
820 
821 	b->shutdown=1;
822 	b->init=1;
823 	b->num= -1;
824 	b->ptr = tds;
825 	BIO_set_conn_hostname(b, tds_dstr_cstr(&tds->login->server_host_name));
826 	SSL_set_bio(con, b, b);
827 	b = NULL;
828 
829 	/* use priorities... */
830 	SSL_set_cipher_list(con, OPENSSL_CIPHERS);
831 
832 #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
833 	/* this disable a security improvement but allow connection... */
834 	SSL_set_options(con, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
835 #endif
836 
837 	/* Perform the TLS handshake */
838 	tls_msg = "handshake";
839 	SSL_set_connect_state(con);
840 	ret = SSL_connect(con) != 1 || con->state != SSL_ST_OK;
841 	if (ret != 0)
842 		goto cleanup;
843 
844 	/* check certificate hostname */
845 	if (!tds_dstr_isempty(&tds->login->cafile) && tds->login->check_ssl_hostname) {
846 		X509 *cert;
847 
848 		cert =  SSL_get_peer_certificate(con);
849 		tls_msg = "checking hostname";
850 		if (!cert || !check_hostname(cert, tds_dstr_cstr(&tds->login->server_host_name)))
851 			goto cleanup;
852 	}
853 
854 	tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");
855 
856 	b2->shutdown = 1;
857 	b2->init = 1;
858 	b2->num = -1;
859 	b2->ptr = tds->conn;
860 	SSL_set_bio(con, b2, b2);
861 
862 	tds->conn->tls_session = con;
863 	tds->conn->tls_ctx = ctx;
864 
865 	return TDS_SUCCESS;
866 
867 cleanup:
868 	if (b2)
869 		BIO_free(b2);
870 	if (b)
871 		BIO_free(b);
872 	if (con) {
873 		SSL_shutdown(con);
874 		SSL_free(con);
875 	}
876 	SSL_CTX_free(ctx);
877 	tdsdump_log(TDS_DBG_ERROR, "%s failed\n", tls_msg);
878 	return TDS_FAIL;
879 }
880 
881 void
tds_ssl_deinit(TDSCONNECTION * conn)882 tds_ssl_deinit(TDSCONNECTION *conn)
883 {
884 	if (conn->tls_session) {
885 		/* NOTE do not call SSL_shutdown here */
886 		SSL_free(conn->tls_session);
887 		conn->tls_session = NULL;
888 	}
889 	if (conn->tls_ctx) {
890 		SSL_CTX_free(conn->tls_ctx);
891 		conn->tls_ctx = NULL;
892 	}
893 }
894 #endif
895 
896 #endif
897 /** @} */
898 
899