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