gwenhywfar 5.14.1
syncio_tls.c
Go to the documentation of this file.
1/***************************************************************************
2 begin : Wed Apr 28 2010
3 copyright : (C) 2010, 2016 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 * *
23 ***************************************************************************/
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29#define DISABLE_DEBUGLOG
30
31/*#define GWEN_TLS_DEBUG*/
32
33/* #define GWEN_TLS_USE_OLD_CODE */
34
35#include "syncio_tls_p.h"
36#include "i18n_l.h"
37
38#include <gwenhywfar/misc.h>
39#include <gwenhywfar/debug.h>
40#include <gwenhywfar/gui.h>
41#include <gwenhywfar/gui.h>
42#include <gwenhywfar/pathmanager.h>
43#include <gwenhywfar/directory.h>
44#include <gwenhywfar/gwenhywfar.h>
45#include <gwenhywfar/text.h>
46
47#include <assert.h>
48#include <errno.h>
49#include <string.h>
50#include <stdlib.h>
51
52#include <gnutls/gnutls.h>
53#include <gnutls/x509.h>
54#include <gcrypt.h>
55
56
57
58GWEN_INHERIT(GWEN_SYNCIO, GWEN_SYNCIO_TLS)
59
60
61#ifndef OS_WIN32
63 "/etc/ssl/certs/ca-certificates.crt",
64 "/etc/ssl/ca-bundle.pem",
65 NULL
66};
67#endif
68
69
70
71
73{
74 GWEN_SYNCIO *sio;
75 GWEN_SYNCIO_TLS *xio;
76
77 assert(baseIo);
79 GWEN_NEW_OBJECT(GWEN_SYNCIO_TLS, xio);
81
82 /* preset data */
84
85 /* set virtual functions */
90
91 return sio;
92}
93
94
95
97{
98 GWEN_SYNCIO_TLS *xio;
99
100 xio=(GWEN_SYNCIO_TLS *) p;
101 free(xio->localCertFile);
102 free(xio->localKeyFile);
103 free(xio->localTrustFile);
104 free(xio->dhParamFile);
105 free(xio->hostName);
106 GWEN_SslCertDescr_free(xio->peerCertDescr);
107 GWEN_FREE_OBJECT(xio);
108}
109
110
111
113{
114 GWEN_SYNCIO_TLS *xio;
116
117 assert(sio);
118 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
119 assert(xio);
120
121 oldF=xio->checkCertFn;
122 xio->checkCertFn=f;
123 return oldF;
124}
125
126
127
129 const GWEN_SSLCERTDESCR *cert)
130{
131 GWEN_SYNCIO_TLS *xio;
132
133 assert(sio);
134 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
135 assert(xio);
136
137 DBG_WARN(GWEN_LOGDOMAIN, "No checkCertFn set, using GWEN_GUI");
138 return GWEN_Gui_CheckCert(cert, sio, 0);
139}
140
141
142
144{
145 GWEN_SYNCIO_TLS *xio;
146
147 assert(sio);
148 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
149 assert(xio);
150
151 if (xio->checkCertFn) {
152 /* try my own checkCert function first */
153 return xio->checkCertFn(sio, cert);
154 }
155 else {
156 /* none set, call the check cert function of GWEN_GUI (for older code) */
157 DBG_ERROR(GWEN_LOGDOMAIN, "No checkCertFn set, falling back to GUI (SNH!)");
158 return GWEN_SyncIo_Tls_Internal_CheckCert(sio, cert);
159 }
160}
161
162
163
165{
166 GWEN_SYNCIO_TLS *xio;
167
168 assert(sio);
169 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
170 assert(xio);
171
172 return xio->localCertFile;
173}
174
175
176
178{
179 GWEN_SYNCIO_TLS *xio;
180
181 assert(sio);
182 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
183 assert(xio);
184
185 free(xio->localCertFile);
186 if (s)
187 xio->localCertFile=strdup(s);
188 else
189 xio->localCertFile=NULL;
190}
191
192
193
195{
196 GWEN_SYNCIO_TLS *xio;
197
198 assert(sio);
199 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
200 assert(xio);
201
202 return xio->localKeyFile;
203}
204
205
206
208{
209 GWEN_SYNCIO_TLS *xio;
210
211 assert(sio);
212 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
213 assert(xio);
214
215 free(xio->localKeyFile);
216 if (s)
217 xio->localKeyFile=strdup(s);
218 else
219 xio->localKeyFile=NULL;
220}
221
222
223
225{
226 GWEN_SYNCIO_TLS *xio;
227
228 assert(sio);
229 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
230 assert(xio);
231
232 return xio->localTrustFile;
233}
234
235
236
238{
239 GWEN_SYNCIO_TLS *xio;
240
241 assert(sio);
242 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
243 assert(xio);
244
245 free(xio->localTrustFile);
246 if (s)
247 xio->localTrustFile=strdup(s);
248 else
249 xio->localTrustFile=NULL;
250}
251
252
253
255{
256 GWEN_SYNCIO_TLS *xio;
257
258 assert(sio);
259 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
260 assert(xio);
261
262 return xio->dhParamFile;
263}
264
265
266
268{
269 GWEN_SYNCIO_TLS *xio;
270
271 assert(sio);
272 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
273 assert(xio);
274
275 free(xio->dhParamFile);
276 if (s)
277 xio->dhParamFile=strdup(s);
278 else
279 xio->dhParamFile=NULL;
280}
281
282
283
285{
286 GWEN_SYNCIO_TLS *xio;
287
288 assert(sio);
289 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
290 assert(xio);
291
292 return xio->hostName;
293}
294
295
296
298{
299 GWEN_SYNCIO_TLS *xio;
300
301 assert(sio);
302 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
303 assert(xio);
304
305 free(xio->hostName);
306 if (s)
307 xio->hostName=strdup(s);
308 else
309 xio->hostName=NULL;
310}
311
312
313
315{
316 GWEN_SYNCIO_TLS *xio;
317
318 assert(sio);
319 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
320 assert(xio);
321
322 return xio->peerCertDescr;
323}
324
325
326
327int GWEN_SyncIo_Tls__readFile(const char *fname, GWEN_BUFFER *buf)
328{
329 FILE *f;
330
331 f=fopen(fname, "r");
332 if (f==NULL)
333 return GWEN_ERROR_IO;
334
335 while (!feof(f)) {
336 int rv;
337
338 GWEN_Buffer_AllocRoom(buf, 512);
339 rv=fread(GWEN_Buffer_GetPosPointer(buf), 1, 512, f);
340 if (rv==0)
341 break;
342 else if (rv<0) {
343 DBG_INFO(GWEN_LOGDOMAIN, "fread(%s): %s", fname, strerror(errno));
344 fclose(f);
345 return GWEN_ERROR_IO;
346 }
347 else {
350 }
351 }
352 fclose(f);
353 return 0;
354}
355
356
357
358
359#if GWEN_TLS_USE_SYSTEM_CERTIFICATES
360# ifndef OS_WIN32
361static int GWEN_SyncIo_Tls_AddCaCertFolder(GWEN_SYNCIO *sio, const char *folder)
362{
363 GWEN_SYNCIO_TLS *xio;
364 int rv;
365 int successfullTustFileCount=0;
366
367 assert(sio);
368 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
369 assert(xio);
370
371 if (folder && *folder) {
372 GWEN_STRINGLIST *fileList;
373
374 fileList=GWEN_StringList_new();
375 rv=GWEN_Directory_GetMatchingFilesRecursively(folder, fileList, "*.crt");
376 if (rv<0) {
378 "Error reading list of certificate files (%d) in folder [%s]",
379 rv, folder);
380 }
381 else {
383
384 se=GWEN_StringList_FirstEntry(fileList);
385 while (se) {
386 const char *s;
387
389 if (s && *s) {
390 rv=gnutls_certificate_set_x509_trust_file(xio->credentials,
391 s,
392 GNUTLS_X509_FMT_PEM);
393 if (rv<=0) {
395 "gnutls_certificate_set_x509_trust_file(%s): %d (%s)",
396 s, rv, gnutls_strerror(rv));
397 }
398 else {
399 DBG_INFO(GWEN_LOGDOMAIN, "Added %d trusted certs from [%s]", rv, s);
400 successfullTustFileCount++;
401 }
402 }
403
405 } /* while */
406 }
407 GWEN_StringList_free(fileList);
408 }
409
410 if (successfullTustFileCount==0) {
411 DBG_ERROR(GWEN_LOGDOMAIN, "No files added from folder [%s]", folder);
412 }
413
414 return successfullTustFileCount;
415}
416# endif
417#endif
418
419
420
422{
423 GWEN_SYNCIO_TLS *xio;
424 int rv;
425 uint32_t lflags;
426 const char *custom_ciphers;
427 const char *errPos=NULL;
428
429 assert(sio);
430 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
431 assert(xio);
432
433 lflags=GWEN_SyncIo_GetFlags(sio);
434 DBG_INFO(GWEN_LOGDOMAIN, "Preparing SSL (%08x)", lflags);
435
436 /* init session */
437 if (lflags & GWEN_SYNCIO_FLAGS_PASSIVE) {
438 DBG_INFO(GWEN_LOGDOMAIN, "Init as server");
439 rv=gnutls_init(&xio->session, GNUTLS_SERVER);
440 }
441 else {
442 DBG_INFO(GWEN_LOGDOMAIN, "Init as client");
443 rv=gnutls_init(&xio->session, GNUTLS_CLIENT);
444 }
445 if (rv) {
446 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_init: %d (%s)", rv, gnutls_strerror(rv));
447 return GWEN_ERROR_GENERIC;
448 }
449
450 /* set cipher priorities */
451 custom_ciphers=getenv("GWEN_TLS_CIPHER_PRIORITIES");
452 /* TODO: make custom ciphers configurable as priority string? */
453 if (custom_ciphers && *custom_ciphers) { /* use cipher list from env var */
454 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Info, I18N("TLS: SSL cipher priority list: %s"), custom_ciphers);
455 rv=gnutls_priority_set_direct(xio->session, custom_ciphers, &errPos);
456 if (rv!=GNUTLS_E_SUCCESS) {
457 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_priority_set_direct using '%s' failed: %s (%d) [%s]",
458 custom_ciphers, gnutls_strerror(rv), rv, errPos?errPos:"");
459 gnutls_deinit(xio->session);
460 return GWEN_ERROR_GENERIC;
461 }
462 }
463 else { /* use default ciphers from GnuTLS */
464 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Notice, I18N("Using GnuTLS default ciphers."));
465 rv=gnutls_set_default_priority(xio->session);
466 if (rv!=GNUTLS_E_SUCCESS) {
467 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_set_default_priority failed: %s (%d)", gnutls_strerror(rv), rv);
468 gnutls_deinit(xio->session);
469 return GWEN_ERROR_GENERIC;
470 }
471 }
472
473 /* protect against too-many-known-ca problem */
474 gnutls_handshake_set_max_packet_length(xio->session, 64*1024);
475
476 /* let a server request peer certs */
477 if ((lflags & GWEN_SYNCIO_FLAGS_PASSIVE) &&
479 gnutls_certificate_server_set_request(xio->session, GNUTLS_CERT_REQUIRE);
480
481 /* prepare cert credentials */
482 rv=gnutls_certificate_allocate_credentials(&xio->credentials);
483 if (rv) {
484 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_allocate_credentials: %d (%s)", rv, gnutls_strerror(rv));
485 gnutls_deinit(xio->session);
486 return GWEN_ERROR_GENERIC;
487 }
488
489 /* possibly set key file and cert file */
490 if (xio->localCertFile && xio->localKeyFile) {
491 rv=gnutls_certificate_set_x509_key_file(xio->credentials,
492 xio->localCertFile,
493 xio->localKeyFile,
494 GNUTLS_X509_FMT_PEM);
495 if (rv<0) {
496 if (rv) {
497 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_key_file: %d (%s)", rv, gnutls_strerror(rv));
498 gnutls_certificate_free_credentials(xio->credentials);
499 gnutls_deinit(xio->session);
500 return GWEN_ERROR_GENERIC;
501 }
502 }
503 }
504
505 /* find default trust file if none is selected */
507 int trustFileSet=0;
508
509#if GWEN_TLS_USE_SYSTEM_CERTIFICATES
510 /* disable setting of default trust file as discussed on aqbanking-users.
511 * The rationale is that without this file being set gnutls should behave
512 * correctly on each system.
513 * On Linux systems it should use the standard mechanism of the underlying
514 * distribution. On Windows the default CA store should be used (if given
515 * "--with-default-trust-store-file" to "./configure" of GNUTLS).
516 */
517 if (trustFileSet==0) {
518 /* Adds the system's default trusted CAs in order to verify client or server certificates. */
519 rv=gnutls_certificate_set_x509_system_trust(xio->credentials);
520 if (rv<=0) {
521 DBG_WARN(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_system_trust: %d (%s)", rv, gnutls_strerror(rv));
522 }
523 else {
524 DBG_INFO(GWEN_LOGDOMAIN, "Added %d default trusted certs from system", rv);
525 trustFileSet=1;
526 }
527 }
528#endif
529
530 /* try to find OpenSSL certificates */
531# ifdef OS_WIN32
532 if (trustFileSet==0) {
533 char defaultPath[2*_MAX_PATH+1];
534 const char *defaultFile = "ca-bundle.crt";
535 GWEN_STRINGLIST *paths;
536 GWEN_BUFFER *nbuf;
537
538 if (GWEN_Directory_GetPrefixDirectory(defaultPath, sizeof(defaultPath))) {
539 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_key_file: could not get install prefix");
540 return GWEN_ERROR_GENERIC;
541 }
542 if (strcat_s(defaultPath, sizeof(defaultPath), "\\share\\gwenhywfar")) {
543 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_key_file: no memory on creating search path");
544 return GWEN_ERROR_GENERIC;
545 }
546
547 paths=GWEN_StringList_new();
548 GWEN_StringList_AppendString(paths, defaultPath, 0, 0);
549
550 nbuf=GWEN_Buffer_new(0, 256, 0, 1);
551 rv=GWEN_Directory_FindFileInPaths(paths, defaultFile, nbuf);
553 if (rv==0) {
555 "Using default ca-bundle from [%s]",
557
558 rv=gnutls_certificate_set_x509_trust_file(xio->credentials,
560 GNUTLS_X509_FMT_PEM);
561 if (rv<=0) {
563 "gnutls_certificate_set_x509_trust_file(%s): %d (%s)",
564 GWEN_Buffer_GetStart(nbuf), rv, gnutls_strerror(rv));
565 }
566 else {
568 "Added %d trusted certs from [%s]", rv, GWEN_Buffer_GetStart(nbuf));
569 trustFileSet=1;
570 }
571 }
572 GWEN_Buffer_free(nbuf);
573 }
574# endif
575
576
577# ifndef OS_WIN32
578 /* try to finde certificate bundle */
579 if (trustFileSet==0) {
580 int i;
581 const char *sCertFile=NULL;
582
583 for (i=0; ; i++) {
584 sCertFile=SYNCIO_TLS_SYSTEM_CERTFILES[i];
585 if (sCertFile==NULL)
586 break;
588 DBG_INFO(GWEN_LOGDOMAIN, "Found system-wide cert bundle in %s", sCertFile);
589 break;
590 }
591 }
592
593 if (sCertFile && *sCertFile) {
594 rv=gnutls_certificate_set_x509_trust_file(xio->credentials, sCertFile, GNUTLS_X509_FMT_PEM);
595 if (rv<=0) {
596 DBG_WARN(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_trust_file(%s): %d (%s)", sCertFile, rv, gnutls_strerror(rv));
597 }
598 else {
599 DBG_INFO(GWEN_LOGDOMAIN, "Added %d trusted certs from [%s]", rv, sCertFile);
600 trustFileSet=1;
601 }
602 }
603 else {
604 DBG_ERROR(GWEN_LOGDOMAIN, "No system-wide certificate bundle found.");
605 }
606 }
607
608 /* try to find ca-certificates (at least available on Debian systems) */
609 if (trustFileSet==0) {
610 rv=GWEN_Directory_GetPath("/usr/share/ca-certificates", GWEN_PATH_FLAGS_NAMEMUSTEXIST);
611 if (rv>=0) {
612 rv=GWEN_SyncIo_Tls_AddCaCertFolder(sio, "/usr/share/ca-certificates");
613 if (rv<=0) {
614 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
615 }
616 else {
617 trustFileSet=1;
618 }
619 }
620 }
621
622# endif
623
624
625 if (trustFileSet==0) {
626
627 /* TODO: use gnutls_certificate_set_x509_system_trust() */
628 trustFileSet=1;
629 }
630
631
632
633 if (trustFileSet==0) {
634 DBG_WARN(GWEN_LOGDOMAIN, "No default bundle file found");
635 }
636 }
637
638 /* possibly set trust file */
639 if (xio->localTrustFile) {
640 rv=gnutls_certificate_set_x509_trust_file(xio->credentials,
641 xio->localTrustFile,
642 GNUTLS_X509_FMT_PEM);
643 if (rv<=0) {
645 "gnutls_certificate_set_x509_trust_file(%s): %d (%s)",
646 (xio->localTrustFile)?(xio->localTrustFile):"-none-",
647 rv, gnutls_strerror(rv));
648 gnutls_certificate_free_credentials(xio->credentials);
649 gnutls_deinit(xio->session);
650 return GWEN_ERROR_GENERIC;
651 }
652 else {
654 "Added %d trusted certs", rv);
655 }
656 }
657
658 /* possibly set DH params */
659 if (xio->dhParamFile) {
660 GWEN_BUFFER *dbuf;
661
662 dbuf=GWEN_Buffer_new(0, 256, 0, 1);
663 rv=GWEN_SyncIo_Tls__readFile(xio->dhParamFile, dbuf);
664 if (rv) {
665 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
666 GWEN_Buffer_free(dbuf);
667 gnutls_certificate_free_credentials(xio->credentials);
668 gnutls_deinit(xio->session);
669 return rv;
670 }
671 else {
672 gnutls_datum_t d;
673 gnutls_dh_params_t dh_params=NULL;
674
675 rv=gnutls_dh_params_init(&dh_params);
676 if (rv<0) {
677 GWEN_Buffer_free(dbuf);
678 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_init: %d (%s)", rv, gnutls_strerror(rv));
679 gnutls_certificate_free_credentials(xio->credentials);
680 gnutls_deinit(xio->session);
681 return GWEN_ERROR_GENERIC;
682 }
683
684 d.size=GWEN_Buffer_GetUsedBytes(dbuf);
685 d.data=(unsigned char *)GWEN_Buffer_GetStart(dbuf);
686
687 rv=gnutls_dh_params_import_pkcs3(dh_params, &d, GNUTLS_X509_FMT_PEM);
688 if (rv<0) {
689 GWEN_Buffer_free(dbuf);
690 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_import_pkcs3: %d (%s)", rv, gnutls_strerror(rv));
691 gnutls_certificate_free_credentials(xio->credentials);
692 gnutls_deinit(xio->session);
693 return GWEN_ERROR_GENERIC;
694 }
695 GWEN_Buffer_free(dbuf);
696
697 gnutls_certificate_set_dh_params(xio->credentials, dh_params);
698 }
699 }
700
701 /* set credentials in TLS session */
702 rv=gnutls_credentials_set(xio->session, GNUTLS_CRD_CERTIFICATE, xio->credentials);
703 if (rv<0) {
704 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_credentials_set: %d (%s)", rv, gnutls_strerror(rv));
705 gnutls_certificate_free_credentials(xio->credentials);
706 gnutls_deinit(xio->session);
707 return GWEN_ERROR_GENERIC;
708 }
709
710 /* if hostname set try to set it */
711 if (xio->hostName) {
712 rv=gnutls_server_name_set(xio->session, GNUTLS_NAME_DNS, xio->hostName, strlen(xio->hostName));
713 if (rv!=GNUTLS_E_SUCCESS) {
714 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_server_name_set: %d (%s), ignoring", rv, gnutls_strerror(rv));
715 }
716 }
717
718 /* we use our own push/pull functions */
719 gnutls_transport_set_ptr(xio->session, (gnutls_transport_ptr_t)sio);
720 gnutls_transport_set_push_function(xio->session, GWEN_SyncIo_Tls_Push);
721 gnutls_transport_set_pull_function(xio->session, GWEN_SyncIo_Tls_Pull);
722#if GNUTLS_VERSION_NUMBER < 0x020c00
723 /* This function must be set to 0 in GNUTLS versions < 2.12.0 because we use
724 * custom push/pull functions.
725 * In GNUTLS 2.12.x this is set to 0 and since version 3 this functions is removed
726 * completely.
727 * So we only call this function now for GNUTLS < 2.12.0.
728 */
729 gnutls_transport_set_lowat(xio->session, 0);
730#endif
731
732 xio->prepared=1;
733
734 return 0;
735}
736
737
738
740{
741 GWEN_SYNCIO_TLS *xio;
742
743 assert(sio);
744 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
745 assert(xio);
746
747 if (xio->prepared) {
748 gnutls_certificate_free_credentials(xio->credentials);
749 gnutls_deinit(xio->session);
750 xio->prepared=0;
751 }
752}
753
754
755
757{
758 GWEN_SYNCIO_TLS *xio;
759 const gnutls_datum_t *cert_list;
760 unsigned int cert_list_size;
761 size_t size;
762 GWEN_SSLCERTDESCR *certDescr;
763 char buffer1[64];
764 time_t t0;
765 int rv;
766 uint32_t lflags;
767 uint32_t errFlags=0;
768 int i;
769 unsigned int status;
770 GWEN_BUFFER *sbuf=NULL;
771
772 assert(sio);
773 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
774 assert(xio);
775
776 lflags=GWEN_SyncIo_GetFlags(sio);
777
778 if (xio->peerCertDescr) {
779 GWEN_SslCertDescr_free(xio->peerCertDescr);
780 xio->peerCertDescr=NULL;
781 }
782 xio->peerCertFlags=0;
783
784 t0=time(NULL);
785 if (t0<0) {
786 DBG_WARN(GWEN_LOGDOMAIN, "Could not get system time");
788 }
789
790 /* create new cert description, check cert on the fly */
791 certDescr=GWEN_SslCertDescr_new();
792
793 /* some general tests */
795 gnutls_certificate_set_verify_flags(xio->credentials,
796 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
797
798 rv=gnutls_certificate_verify_peers2(xio->session, &status);
799 if (rv<0) {
800 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_certificate_verify_peers2: %d (%s)", rv, gnutls_strerror(rv));
801 GWEN_SslCertDescr_free(certDescr);
803 }
804
805 if (gnutls_certificate_type_get(xio->session)!=GNUTLS_CRT_X509) {
806 DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not X.509");
807
808 GWEN_SslCertDescr_free(certDescr);
810 }
811
812 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
813 DBG_INFO(GWEN_LOGDOMAIN, "Signer not found");
815 I18N("Signer not found"));
817 }
818
819 if (status & GNUTLS_CERT_SIGNATURE_FAILURE) {
820 DBG_INFO(GWEN_LOGDOMAIN, "Certificate signature failure");
822 I18N("Certificate signature failure"));
824 }
825
826 if (status & GNUTLS_CERT_INVALID) {
827 DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not trusted");
829 I18N("Certificate is not trusted"));
831 }
832
833 if (status & GNUTLS_CERT_REVOKED) {
834 DBG_INFO(GWEN_LOGDOMAIN, "Certificate has been revoked");
836 I18N("Certificate has been revoked"));
838 }
839
840 cert_list=gnutls_certificate_get_peers(xio->session, &cert_list_size);
841 if (cert_list==NULL || cert_list_size==0) {
842 DBG_INFO(GWEN_LOGDOMAIN, "No peer certificates found");
843 return GWEN_ERROR_NO_DATA;
844 }
845
846 for (i=0; i<(int) cert_list_size; i++) {
847 gnutls_x509_crt_t cert;
848 time_t t;
849
850 rv=gnutls_x509_crt_init(&cert);
851 if (rv!=0) {
852 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_init: %d (%s)", rv, gnutls_strerror(rv));
853 return GWEN_ERROR_GENERIC;
854 }
855
856 rv=gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); /* TODO: shouldn't we use the index?? */
857 if (rv!=0) {
858 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_import: %d (%s)", rv, gnutls_strerror(rv));
859 gnutls_x509_crt_deinit(cert);
860 return GWEN_ERROR_GENERIC;
861 }
862
863 if (i==0) {
864 gnutls_datum_t n= {NULL, 0};
865 gnutls_datum_t e= {NULL, 0};
866
867 /* get public key from cert, if any */
868 rv=gnutls_x509_crt_get_pk_rsa_raw(cert, &n, &e);
869 if (rv!=0) {
870 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_pk_rsa_raw: %d (%s)", rv, gnutls_strerror(rv));
871 }
872 else {
873 GWEN_BUFFER *kbuf;
874
875 DBG_INFO(GWEN_LOGDOMAIN, "Key stored within certificate, extracting (modlen=%d, explen=%d)",
876 n.size, e.size);
877
878 kbuf=GWEN_Buffer_new(0, 256, 0, 1);
879
880 if (n.data && n.size) {
881 /* store public modulus */
882 GWEN_Text_ToHexBuffer((const char *)(n.data), n.size, kbuf, 0, 0, 0);
884 GWEN_Buffer_Reset(kbuf);
885 }
886
887 if (e.data && e.size) {
888 /* store public exponent */
889 GWEN_Text_ToHexBuffer((const char *)(e.data), e.size, kbuf, 0, 0, 0);
891 GWEN_Buffer_Reset(kbuf);
892 }
893
894 GWEN_Buffer_free(kbuf);
895 if (n.data)
896 gcry_free(n.data);
897 if (e.data)
898 gcry_free(e.data);
899 }
900
901 /* get fingerprint (MD5) */
902 size=16;
903 rv=gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, buffer1, &size);
904 if (rv!=0) {
905 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_fingerprint(MD5): %d (%s)", rv, gnutls_strerror(rv));
906 GWEN_SslCertDescr_free(certDescr);
907 gnutls_x509_crt_deinit(cert);
908 return GWEN_ERROR_GENERIC;
909 }
910 else {
911 GWEN_BUFFER *dbuf;
912
913 dbuf=GWEN_Buffer_new(0, 256, 0, 1);
914 if (GWEN_Text_ToHexBuffer(/* GCC4 pointer-signedness fix: */ buffer1,
915 size, dbuf, 2, ':', 0)) {
917 "Could not convert fingerprint to hex");
918 }
919 else {
921 }
922 GWEN_Buffer_free(dbuf);
923 }
924
925 /* get fingerprint (SHA1) */
926 size=sizeof(buffer1);
927 rv=gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, buffer1, &size);
928 if (rv!=0) {
929 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_fingerprint(SHA1): %d (%s)", rv, gnutls_strerror(rv));
930 GWEN_SslCertDescr_free(certDescr);
931 gnutls_x509_crt_deinit(cert);
932 return GWEN_ERROR_GENERIC;
933 }
934 else {
935 GWEN_BUFFER *dbuf;
936
937 dbuf=GWEN_Buffer_new(0, 256, 0, 1);
938 if (GWEN_Text_ToHexBuffer(/* GCC4 pointer-signedness fix: */ buffer1,
939 size, dbuf, 2, ':', 0)) {
941 "Could not convert fingerprint to hex");
942 }
943 else {
945 }
946 GWEN_Buffer_free(dbuf);
947 }
948
949 /* get fingerprint (SHA512) */
950 size=sizeof(buffer1);
951 rv=gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA512, buffer1, &size);
952 if (rv!=0) {
953 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_fingerprint(SHA512): %d (%s)", rv, gnutls_strerror(rv));
954 GWEN_SslCertDescr_free(certDescr);
955 gnutls_x509_crt_deinit(cert);
956 return GWEN_ERROR_GENERIC;
957 }
958 else {
959 GWEN_BUFFER *dbuf;
960
961 dbuf=GWEN_Buffer_new(0, 256, 0, 1);
962 if (GWEN_Text_ToHexBuffer(/* GCC4 pointer-signedness fix: */ buffer1,
963 size, dbuf, 2, ':', 0)) {
965 "Could not convert fingerprint to hex");
966 }
967 else {
969 }
970 GWEN_Buffer_free(dbuf);
971 }
972
973
974 if (xio->hostName) {
975 DBG_INFO(GWEN_LOGDOMAIN, "Checking hostname [%s]", xio->hostName);
976 if (!gnutls_x509_crt_check_hostname(cert, xio->hostName)) {
978 "Certificate was not issued for this host");
980 I18N("Certificate was not issued for this host"));
982 }
983 else {
984 DBG_INFO(GWEN_LOGDOMAIN, "Cert is for this server");
985 }
986 }
987 else {
989 "Hostname is not set, unable to verify the sender");
991 I18N("No hostname to verify the sender!"));
992 }
993
994 }
995
996 /* get activation time */
997 t=gnutls_x509_crt_get_activation_time(cert);
998 if (t<0) {
999 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_activation_time: %d (%s)", rv, gnutls_strerror(rv));
1001 }
1002 else {
1003 if (t>t0) {
1004 DBG_INFO(GWEN_LOGDOMAIN, "Cert is not yet active");
1006 }
1007 if (i==0) {
1008 GWEN_TIME *ti;
1009
1011 if (ti)
1012 GWEN_SslCertDescr_SetNotBefore(certDescr, ti);
1013 GWEN_Time_free(ti);
1014 }
1015 }
1016
1017 /* get expiration time */
1018 t=gnutls_x509_crt_get_expiration_time(cert);
1019 if (t<0) {
1020 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_expiration_time: %d (%s)", rv, gnutls_strerror(rv));
1022 }
1023 else {
1024 if (t<t0) {
1025 DBG_INFO(GWEN_LOGDOMAIN, "Cert has expired");
1027 }
1028 if (i==0) {
1029 GWEN_TIME *ti;
1030
1032 if (ti)
1033 GWEN_SslCertDescr_SetNotAfter(certDescr, ti);
1034 GWEN_Time_free(ti);
1035 }
1036 }
1037
1038 if (i==0) {
1039 /* get owner information, but only for first cert */
1040 size=sizeof(buffer1)-1;
1041 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, buffer1, &size);
1042 if (rv==0) {
1043 GWEN_SslCertDescr_SetCommonName(certDescr, buffer1);
1044 }
1045
1046 size=sizeof(buffer1)-1;
1047 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, buffer1, &size);
1048 if (rv==0)
1049 GWEN_SslCertDescr_SetOrganizationName(certDescr, buffer1);
1050
1051 size=sizeof(buffer1)-1;
1052 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, buffer1, &size);
1053 if (rv==0)
1055
1056 size=sizeof(buffer1)-1;
1057 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, buffer1, &size);
1058 if (rv==0)
1059 GWEN_SslCertDescr_SetLocalityName(certDescr, buffer1);
1060
1061 size=sizeof(buffer1)-1;
1062 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, buffer1, &size);
1063 if (rv==0)
1064 GWEN_SslCertDescr_SetStateOrProvinceName(certDescr, buffer1);
1065
1066 size=sizeof(buffer1)-1;
1067 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, buffer1, &size);
1068 if (rv==0)
1069 GWEN_SslCertDescr_SetCountryName(certDescr, buffer1);
1070 }
1071
1072 gnutls_x509_crt_deinit(cert);
1073 }
1074
1075 /* done */
1076 if (errFlags)
1077 GWEN_SslCertDescr_SetIsError(certDescr, 1);
1078 else
1079 errFlags|=GWEN_SSL_CERT_FLAGS_OK;
1080
1081 sbuf=GWEN_Buffer_new(0, 256, 0, 1);
1082
1083 if (errFlags & GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND) {
1084 if (GWEN_Buffer_GetUsedBytes(sbuf))
1085 GWEN_Buffer_AppendString(sbuf, "; ");
1086 GWEN_Buffer_AppendString(sbuf, I18N("Signer not found"));
1087 }
1088
1089 if (errFlags & GWEN_SSL_CERT_FLAGS_INVALID) {
1090 if (GWEN_Buffer_GetUsedBytes(sbuf))
1091 GWEN_Buffer_AppendString(sbuf, "; ");
1092 GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not trusted"));
1093 }
1094
1095 if (errFlags & GWEN_SSL_CERT_FLAGS_REVOKED) {
1096 if (GWEN_Buffer_GetUsedBytes(sbuf))
1097 GWEN_Buffer_AppendString(sbuf, "; ");
1098 GWEN_Buffer_AppendString(sbuf, I18N("Certificate has been revoked"));
1099 }
1100
1101 if (errFlags & GWEN_SSL_CERT_FLAGS_EXPIRED) {
1102 if (GWEN_Buffer_GetUsedBytes(sbuf))
1103 GWEN_Buffer_AppendString(sbuf, "; ");
1104 GWEN_Buffer_AppendString(sbuf, I18N("Certificate has expired"));
1105 }
1106
1107 if (errFlags & GWEN_SSL_CERT_FLAGS_NOT_ACTIVE) {
1108 if (GWEN_Buffer_GetUsedBytes(sbuf))
1109 GWEN_Buffer_AppendString(sbuf, "; ");
1110 GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not active yet"));
1111 }
1112
1113 if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME) {
1114 if (GWEN_Buffer_GetUsedBytes(sbuf))
1115 GWEN_Buffer_AppendString(sbuf, "; ");
1116 GWEN_Buffer_AppendString(sbuf, I18N("Certificate owner does not match hostname"));
1117 }
1118
1119 if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_DATA) {
1120 if (GWEN_Buffer_GetUsedBytes(sbuf))
1121 GWEN_Buffer_AppendString(sbuf, "; ");
1122 GWEN_Buffer_AppendString(sbuf, I18N("Certificate contains invalid information"));
1123 }
1124
1125 if (errFlags & GWEN_SSL_CERT_FLAGS_SYSTEM) {
1126 if (GWEN_Buffer_GetUsedBytes(sbuf))
1127 GWEN_Buffer_AppendString(sbuf, "; ");
1128 GWEN_Buffer_AppendString(sbuf, I18N("A system error occurred while checking the certificate"));
1129 }
1130
1131 if (errFlags & GWEN_SSL_CERT_FLAGS_OK) {
1132 if (GWEN_Buffer_GetUsedBytes(sbuf))
1133 GWEN_Buffer_AppendString(sbuf, "; ");
1134 GWEN_Buffer_AppendString(sbuf, I18N("The certificate is valid"));
1135 }
1136
1138 GWEN_SslCertDescr_SetStatusFlags(certDescr, errFlags);
1139 GWEN_Buffer_free(sbuf);
1140
1141#if 0
1142 if (1) {
1143 GWEN_DB_NODE *dbTest;
1144
1145 dbTest=GWEN_DB_Group_new("Cert");
1146 GWEN_SslCertDescr_toDb(certDescr, dbTest);
1147 GWEN_DB_Dump(dbTest, 2);
1148 GWEN_DB_Group_free(dbTest);
1149 }
1150#endif
1151
1152 xio->peerCertDescr=certDescr;
1153 xio->peerCertFlags=errFlags;
1154
1155 return 0;
1156}
1157
1158
1159
1160ssize_t GWEN_SyncIo_Tls_Pull(gnutls_transport_ptr_t p, void *buf, size_t len)
1161{
1162 GWEN_SYNCIO *sio;
1163 GWEN_SYNCIO_TLS *xio;
1164 GWEN_SYNCIO *baseIo;
1165 int rv;
1166
1167 sio=(GWEN_SYNCIO *) p;
1168 assert(sio);
1169 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1170 assert(xio);
1171
1172 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: %d bytes", (int)len);
1173 baseIo=GWEN_SyncIo_GetBaseIo(sio);
1174 assert(baseIo);
1175
1176 rv=GWEN_SyncIo_Read(baseIo, buf, len);
1177 if (rv<0) {
1178 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1179 gnutls_transport_set_errno(xio->session, errno);
1180 return (ssize_t)-1;
1181 }
1182
1183 gnutls_transport_set_errno(xio->session, 0);
1184 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: returning %d bytes", rv);
1185 /*GWEN_Text_DumpString(buf, rv, 2);*/
1186 return rv;
1187}
1188
1189
1190
1191ssize_t GWEN_SyncIo_Tls_Push(gnutls_transport_ptr_t p, const void *buf, size_t len)
1192{
1193 GWEN_SYNCIO *sio;
1194 GWEN_SYNCIO_TLS *xio;
1195 GWEN_SYNCIO *baseIo;
1196 int rv;
1197
1198 sio=(GWEN_SYNCIO *) p;
1199 assert(sio);
1200 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1201 assert(xio);
1202
1203 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: %d bytes", (int)len);
1204 baseIo=GWEN_SyncIo_GetBaseIo(sio);
1205 assert(baseIo);
1206
1207 rv=GWEN_SyncIo_Write(baseIo, buf, len);
1208 if (rv<0) {
1209 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1210 gnutls_transport_set_errno(xio->session, errno);
1211 return (ssize_t)-1;
1212 }
1213
1214 gnutls_transport_set_errno(xio->session, 0);
1215 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: returning %d bytes", rv);
1216 /*GWEN_Text_DumpString(buf, rv, 2);*/
1217 return rv;
1218}
1219
1220
1221
1223{
1224 GWEN_SYNCIO_TLS *xio;
1225 const char *s;
1226 gnutls_kx_algorithm_t kx;
1227 GWEN_BUFFER *cbuf;
1228 GWEN_BUFFER *sbuf;
1229
1230 assert(sio);
1231 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1232 assert(xio);
1233
1234 cbuf=GWEN_Buffer_new(0, 256, 0, 1);
1235 sbuf=GWEN_Buffer_new(0, 256, 0, 1);
1236
1237 /* protocol */
1238 s=gnutls_protocol_get_name(gnutls_protocol_get_version(xio->session));
1239 if (s && *s) {
1240 if (GWEN_Buffer_GetUsedBytes(cbuf))
1241 GWEN_Buffer_AppendString(cbuf, " ");
1242 GWEN_Buffer_AppendString(cbuf, "Protocol: ");
1243 GWEN_Buffer_AppendString(cbuf, s);
1244
1245 GWEN_Buffer_AppendString(sbuf, s);
1246 }
1247 GWEN_Buffer_AppendString(sbuf, ":");
1248
1249 /* key exchange algorithm */
1250 kx=gnutls_kx_get(xio->session);
1251 s=gnutls_kx_get_name(kx);
1252 if (s && *s) {
1253 if (GWEN_Buffer_GetUsedBytes(cbuf))
1254 GWEN_Buffer_AppendString(cbuf, " ");
1255 GWEN_Buffer_AppendString(cbuf, "Key exchange algorithm: ");
1256 GWEN_Buffer_AppendString(cbuf, s);
1257 GWEN_Buffer_AppendString(sbuf, s);
1258 }
1259 GWEN_Buffer_AppendString(sbuf, "-");
1260
1261 /* cipher */
1262 s=gnutls_cipher_get_name(gnutls_cipher_get(xio->session));
1263 if (s && *s) {
1264 if (GWEN_Buffer_GetUsedBytes(cbuf))
1265 GWEN_Buffer_AppendString(cbuf, " ");
1266 GWEN_Buffer_AppendString(cbuf, "cipher algorithm: ");
1267 GWEN_Buffer_AppendString(cbuf, s);
1268 GWEN_Buffer_AppendString(sbuf, s);
1269 }
1270 GWEN_Buffer_AppendString(sbuf, ":");
1271
1272 /* MAC algorithm */
1273 s=gnutls_mac_get_name(gnutls_mac_get(xio->session));
1274 if (s && *s) {
1275 if (GWEN_Buffer_GetUsedBytes(cbuf))
1276 GWEN_Buffer_AppendString(cbuf, " ");
1277 GWEN_Buffer_AppendString(cbuf, "MAC algorithm: ");
1278 GWEN_Buffer_AppendString(cbuf, s);
1279 GWEN_Buffer_AppendString(sbuf, s);
1280 }
1281
1282
1284 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Info, I18N("TLS: SSL-Ciphers negotiated: %s"), GWEN_Buffer_GetStart(sbuf));
1285 GWEN_Buffer_free(cbuf);
1286 GWEN_Buffer_free(sbuf);
1287
1288 /* possibly show warning */
1289 switch (gnutls_cipher_get(xio->session)) {
1290 case GNUTLS_CIPHER_ARCFOUR_128:
1291 case GNUTLS_CIPHER_3DES_CBC:
1292 case GNUTLS_CIPHER_AES_128_CBC:
1293 case GNUTLS_CIPHER_ARCFOUR_40:
1294 case GNUTLS_CIPHER_CAMELLIA_128_CBC:
1295 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error, I18N("TLS: Warning - The server has chosen unsafe SSL-Ciphers!"));
1296 break;
1297 case GNUTLS_CIPHER_AES_256_CBC:
1298 case GNUTLS_CIPHER_CAMELLIA_256_CBC:
1299 case GNUTLS_CIPHER_RC2_40_CBC:
1300 case GNUTLS_CIPHER_DES_CBC:
1301#ifdef GNUTLS_CIPHER_AES_192_CBC
1302 case GNUTLS_CIPHER_AES_192_CBC: /* new in gnutls-2.9.8, so i.e. not available in gnutls-2.8.x */
1303#endif
1304 default:
1305 break;
1306 }
1307}
1308
1309
1310
1312{
1313 GWEN_SYNCIO_TLS *xio;
1314 GWEN_SYNCIO *baseIo;
1315 int rv;
1316
1317 assert(sio);
1318 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1319 assert(xio);
1320
1321 baseIo=GWEN_SyncIo_GetBaseIo(sio);
1322 assert(baseIo);
1323
1326 DBG_ERROR(GWEN_LOGDOMAIN, "Base layer is not connected");
1328 }
1329 }
1330 else {
1331 DBG_INFO(GWEN_LOGDOMAIN, "Connecting base layer");
1332 rv=GWEN_SyncIo_Connect(baseIo);
1333 if (rv<0) {
1334 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1335 return rv;
1336 }
1337 DBG_INFO(GWEN_LOGDOMAIN, "Base layer connected");
1338 }
1339
1341 if (rv<0) {
1342 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1343 GWEN_SyncIo_Disconnect(baseIo);
1344 return rv;
1345 }
1346
1347 do {
1348 rv=gnutls_handshake(xio->session);
1349 }
1350 while (rv==GNUTLS_E_AGAIN || rv==GNUTLS_E_INTERRUPTED);
1351
1352 if (rv) {
1353 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_handshake: %d (%s) [%s]",
1354 rv, gnutls_strerror(rv), gnutls_error_is_fatal(rv)?"fatal":"non-fatal");
1355 if (rv==GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
1358 I18N("A TLS handshake error occurred. "
1359 "If you are using AqBanking you should "
1360 "consider enabling the option "
1361 "\"force SSLv3\" in the user settings "
1362 "dialog."));
1363 }
1364 else {
1367 I18N("TLS Handshake Error: %d (%s)"),
1368 rv,
1369 gnutls_strerror(rv));
1370 }
1373 GWEN_SyncIo_Disconnect(baseIo);
1374 return GWEN_ERROR_SSL;
1375 }
1376 else {
1377 /* show session info */
1379
1380 /* check certificate */
1383 if (rv<0) {
1385 DBG_ERROR(GWEN_LOGDOMAIN, "No peer certificate when needed, aborting connection");
1388 GWEN_SyncIo_Disconnect(baseIo);
1390 }
1391 else {
1392 DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (insecure)");
1394 return 0;
1395 }
1396 }
1397 else {
1398 /* present cert to the user */
1399 rv=GWEN_SyncIo_Tls_CheckCert(sio, xio->peerCertDescr);
1400 if (rv<0) {
1401 DBG_ERROR(GWEN_LOGDOMAIN, "Peer cert not accepted (%d), aborting", rv);
1404 GWEN_SyncIo_Disconnect(baseIo);
1406 }
1407 else {
1408 DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (secure)");
1411 return 0;
1412 }
1413 }
1414 }
1415}
1416
1417
1418
1420{
1421 GWEN_SYNCIO_TLS *xio;
1422 GWEN_SYNCIO *baseIo;
1423 int rv;
1424
1425 assert(sio);
1426 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1427 assert(xio);
1428
1429 baseIo=GWEN_SyncIo_GetBaseIo(sio);
1430 assert(baseIo);
1431
1433 DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
1435 GWEN_SyncIo_Disconnect(baseIo);
1437 }
1438
1439 do {
1440 rv=gnutls_bye(xio->session, GNUTLS_SHUT_RDWR);
1441 }
1442 while (rv==GNUTLS_E_AGAIN || rv==GNUTLS_E_INTERRUPTED);
1443
1444 if (rv) {
1445 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_bye: %d (%s)", rv, gnutls_strerror(rv));
1448 I18N("Error on gnutls_bye: %d (%s)"),
1449 rv,
1450 gnutls_strerror(rv));
1453 GWEN_SyncIo_Disconnect(baseIo);
1454 return GWEN_ERROR_SSL;
1455 }
1456
1459 GWEN_SyncIo_Disconnect(baseIo);
1460 return 0;
1461}
1462
1463
1464
1466 uint8_t *buffer,
1467 uint32_t size)
1468{
1469 GWEN_SYNCIO_TLS *xio;
1470 GWEN_SYNCIO *baseIo;
1471 int rv;
1472
1473 assert(sio);
1474 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1475 assert(xio);
1476
1477 baseIo=GWEN_SyncIo_GetBaseIo(sio);
1478 assert(baseIo);
1479
1481 DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
1483 GWEN_SyncIo_Disconnect(baseIo);
1485 }
1486
1487 do {
1488 rv=gnutls_record_recv(xio->session, buffer, size);
1489 }
1490 while (rv==GNUTLS_E_AGAIN || rv==GNUTLS_E_INTERRUPTED);
1491
1492 if (rv<0) {
1493 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_record_recv: %d (%s)", rv, gnutls_strerror(rv));
1494#if 0
1497 I18N("Error on gnutls_record_recv: %d (%s)"),
1498 rv,
1499 gnutls_strerror(rv));
1500#endif
1503 GWEN_SyncIo_Disconnect(baseIo);
1504#ifdef GNUTLS_E_PREMATURE_TERMINATION
1505 if (rv==GNUTLS_E_PREMATURE_TERMINATION) {
1507 DBG_ERROR(GWEN_LOGDOMAIN, "Detected premature disconnect by server (violates specs!), ignoring.");
1508 return 0; /* report EOF */
1509 }
1510 else {
1511 DBG_ERROR(GWEN_LOGDOMAIN, "Detected premature disconnect by server (violates specs!)");
1513 }
1514 }
1515#endif
1516 return GWEN_ERROR_SSL;
1517 }
1518
1519#ifdef GWEN_TLS_DEBUG
1520 DBG_ERROR(0, "Received this:");
1521 GWEN_Text_DumpString((const char *) buffer, rv, 2);
1522#endif
1523
1524 return rv;
1525}
1526
1527
1528
1530 const uint8_t *buffer,
1531 uint32_t size)
1532{
1533 GWEN_SYNCIO_TLS *xio;
1534 GWEN_SYNCIO *baseIo;
1535 int rv;
1536
1537 assert(sio);
1538 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1539 assert(xio);
1540
1541#ifdef GWEN_TLS_DEBUG
1542 DBG_ERROR(0, "Sending this:");
1543 GWEN_Text_DumpString((const char *) buffer, size, 2);
1544#endif
1545
1546 baseIo=GWEN_SyncIo_GetBaseIo(sio);
1547 assert(baseIo);
1548
1550 DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
1552 GWEN_SyncIo_Disconnect(baseIo);
1554 }
1555
1556 do {
1557 rv=gnutls_record_send(xio->session, buffer, size);
1558 }
1559 while (rv==GNUTLS_E_AGAIN || rv==GNUTLS_E_INTERRUPTED);
1560
1561 if (rv<0) {
1562 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_record_send: %d (%s)", rv, gnutls_strerror(rv));
1565 I18N("Error on gnutls_record_send: %d (%s)"),
1566 rv,
1567 gnutls_strerror(rv));
1570 GWEN_SyncIo_Disconnect(baseIo);
1571 return GWEN_ERROR_SSL;
1572 }
1573
1574 return rv;
1575}
1576
1577
1578
1579
1580
1581
1582
#define NULL
Definition binreloc.c:300
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition buffer.c:42
int GWEN_Buffer_IncrementPos(GWEN_BUFFER *bf, uint32_t i)
Definition buffer.c:451
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition buffer.c:653
int GWEN_Buffer_AdjustUsedBytes(GWEN_BUFFER *bf)
Definition buffer.c:468
char * GWEN_Buffer_GetPosPointer(const GWEN_BUFFER *bf)
Definition buffer.c:548
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition buffer.c:89
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition buffer.c:992
uint32_t GWEN_Buffer_GetUsedBytes(const GWEN_BUFFER *bf)
Definition buffer.c:277
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition buffer.c:235
int GWEN_Buffer_AllocRoom(GWEN_BUFFER *bf, uint32_t size)
Definition buffer.c:285
GWEN_DB_NODE * GWEN_DB_Group_new(const char *name)
Definition db.c:173
void GWEN_DB_Dump(GWEN_DB_NODE *n, int insert)
Definition db.c:1420
void GWEN_DB_Group_free(GWEN_DB_NODE *n)
Definition db.c:421
struct GWEN_DB_NODE GWEN_DB_NODE
Definition db.h:228
#define DBG_VERBOUS(dbg_logger, format,...)
Definition debug.h:224
#define DBG_INFO(dbg_logger, format,...)
Definition debug.h:181
#define DBG_NOTICE(dbg_logger, format,...)
Definition debug.h:152
#define DBG_ERROR(dbg_logger, format,...)
Definition debug.h:97
#define DBG_WARN(dbg_logger, format,...)
Definition debug.h:125
GWENHYWFAR_API int GWEN_Directory_GetPrefixDirectory(char *buffer, unsigned int size)
GWENHYWFAR_API int GWEN_Directory_GetMatchingFilesRecursively(const char *folder, GWEN_STRINGLIST *sl, const char *mask)
GWENHYWFAR_API int GWEN_Directory_FindFileInPaths(const GWEN_STRINGLIST *paths, const char *filePath, GWEN_BUFFER *fbuf)
GWENHYWFAR_API int GWEN_Directory_GetPath(const char *path, unsigned int flags)
#define I18N(m)
Definition error.c:42
#define GWEN_ERROR_SSL
Definition error.h:105
#define GWEN_ERROR_SSL_SECURITY
Definition error.h:129
#define GWEN_ERROR_NOT_CONNECTED
Definition error.h:120
#define GWEN_ERROR_IO
Definition error.h:123
#define GWEN_ERROR_SSL_PREMATURE_CLOSE
Definition error.h:133
#define GWEN_ERROR_GENERIC
Definition error.h:62
#define GWEN_ERROR_NO_DATA
Definition error.h:94
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition buffer.h:38
GWENHYWFAR_API int GWEN_Gui_CheckCert(const GWEN_SSLCERTDESCR *cert, GWEN_SYNCIO *sio, uint32_t guiid)
Definition gui_cert.c:30
GWENHYWFAR_API int GWEN_Gui_ProgressLog(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text)
GWENHYWFAR_API int GWEN_Gui_ProgressLog2(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text,...)
#define GWEN_UNUSED
#define GWENHYWFAR_CB
struct GWEN_TIME GWEN_TIME
Definition gwentime.h:43
GWENHYWFAR_API void GWEN_Time_free(GWEN_TIME *t)
GWENHYWFAR_API GWEN_TIME * GWEN_Time_fromSeconds(uint32_t s)
#define GWEN_INHERIT_SETDATA(bt, t, element, data, fn)
Definition inherit.h:300
#define GWEN_INHERIT(bt, t)
Definition inherit.h:264
#define GWEN_INHERIT_GETDATA(bt, t, element)
Definition inherit.h:279
#define GWEN_LOGDOMAIN
Definition logger.h:32
@ GWEN_LoggerLevel_Warning
Definition logger.h:66
@ GWEN_LoggerLevel_Notice
Definition logger.h:67
@ GWEN_LoggerLevel_Info
Definition logger.h:68
@ GWEN_LoggerLevel_Error
Definition logger.h:65
#define GWEN_FREE_OBJECT(varname)
Definition memory.h:61
#define GWEN_NEW_OBJECT(typ, varname)
Definition memory.h:55
#define GWEN_PATH_FLAGS_VARIABLE
Definition path.h:111
#define GWEN_PATH_FLAGS_NAMEMUSTEXIST
Definition path.h:84
void GWEN_SslCertDescr_SetIsError(GWEN_SSLCERTDESCR *st, int d)
void GWEN_SslCertDescr_SetFingerPrintSha1(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetOrganizationName(GWEN_SSLCERTDESCR *st, const char *d)
GWEN_SSLCERTDESCR * GWEN_SslCertDescr_new(void)
void GWEN_SslCertDescr_SetNotAfter(GWEN_SSLCERTDESCR *st, const GWEN_TIME *d)
void GWEN_SslCertDescr_SetFingerPrint(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetPubKeyExponent(GWEN_SSLCERTDESCR *st, const char *d)
int GWEN_SslCertDescr_toDb(const GWEN_SSLCERTDESCR *st, GWEN_DB_NODE *db)
void GWEN_SslCertDescr_SetStatusFlags(GWEN_SSLCERTDESCR *st, uint32_t d)
void GWEN_SslCertDescr_SetCommonName(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetLocalityName(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetOrganizationalUnitName(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetNotBefore(GWEN_SSLCERTDESCR *st, const GWEN_TIME *d)
void GWEN_SslCertDescr_free(GWEN_SSLCERTDESCR *st)
void GWEN_SslCertDescr_SetCountryName(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetFingerPrintSha512(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetPubKeyModulus(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetStatusText(GWEN_SSLCERTDESCR *st, const char *d)
void GWEN_SslCertDescr_SetStateOrProvinceName(GWEN_SSLCERTDESCR *st, const char *d)
struct GWEN_SSLCERTDESCR GWEN_SSLCERTDESCR
#define GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME
#define GWEN_SSL_CERT_FLAGS_OK
#define GWEN_SSL_CERT_FLAGS_NOT_ACTIVE
#define GWEN_SSL_CERT_FLAGS_REVOKED
#define GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND
#define GWEN_SSL_CERT_FLAGS_EXPIRED
#define GWEN_SSL_CERT_FLAGS_SYSTEM
#define GWEN_SSL_CERT_FLAGS_BAD_DATA
#define GWEN_SSL_CERT_FLAGS_INVALID
void GWEN_StringList_free(GWEN_STRINGLIST *sl)
Definition stringlist.c:62
const char * GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se)
Definition stringlist.c:406
GWEN_STRINGLISTENTRY * GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se)
Definition stringlist.c:398
int GWEN_StringList_AppendString(GWEN_STRINGLIST *sl, const char *s, int take, int checkDouble)
Definition stringlist.c:245
GWEN_STRINGLISTENTRY * GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl)
Definition stringlist.c:390
GWEN_STRINGLIST * GWEN_StringList_new(void)
Definition stringlist.c:50
struct GWEN_STRINGLISTENTRYSTRUCT GWEN_STRINGLISTENTRY
Definition stringlist.h:53
struct GWEN_STRINGLISTSTRUCT GWEN_STRINGLIST
Definition stringlist.h:56
uint32_t GWEN_SyncIo_GetFlags(const GWEN_SYNCIO *sio)
Definition syncio.c:161
int GWEN_SyncIo_Connect(GWEN_SYNCIO *sio)
Definition syncio.c:97
void GWEN_SyncIo_AddFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition syncio.c:179
GWEN_SYNCIO * GWEN_SyncIo_new(const char *typeName, GWEN_SYNCIO *baseIo)
Definition syncio.c:51
int GWEN_SyncIo_Write(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
Definition syncio.c:147
GWEN_SYNCIO_READ_FN GWEN_SyncIo_SetReadFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_READ_FN fn)
Definition syncio.c:291
GWEN_SYNCIO * GWEN_SyncIo_GetBaseIo(const GWEN_SYNCIO *sio)
Definition syncio.c:224
GWEN_SYNCIO_DISCONNECT_FN GWEN_SyncIo_SetDisconnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_DISCONNECT_FN fn)
Definition syncio.c:265
void GWEN_SyncIo_SubFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition syncio.c:188
GWEN_SYNCIO_WRITE_FN GWEN_SyncIo_SetWriteFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_WRITE_FN fn)
Definition syncio.c:304
GWEN_SYNCIO_STATUS GWEN_SyncIo_GetStatus(const GWEN_SYNCIO *sio)
Definition syncio.c:197
int GWEN_SyncIo_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition syncio.c:133
GWEN_SYNCIO_CONNECT_FN GWEN_SyncIo_SetConnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_CONNECT_FN fn)
Definition syncio.c:252
void GWEN_SyncIo_SetStatus(GWEN_SYNCIO *sio, GWEN_SYNCIO_STATUS st)
Definition syncio.c:206
int GWEN_SyncIo_Disconnect(GWEN_SYNCIO *sio)
Definition syncio.c:109
#define GWEN_SYNCIO_FLAGS_PASSIVE
Definition syncio.h:57
struct GWEN_SYNCIO GWEN_SYNCIO
Definition syncio.h:40
@ GWEN_SyncIo_Status_Connected
Definition syncio.h:49
@ GWEN_SyncIo_Status_Disconnected
Definition syncio.h:48
int GWEN_SyncIo_Tls_CheckCert(GWEN_SYNCIO *sio, const GWEN_SSLCERTDESCR *cert)
Definition syncio_tls.c:143
GWEN_SIO_TLS_CHECKCERT_FN GWEN_SyncIo_Tls_SetCheckCertFn(GWEN_SYNCIO *sio, GWEN_SIO_TLS_CHECKCERT_FN f)
Definition syncio_tls.c:112
GWEN_SSLCERTDESCR * GWEN_SyncIo_Tls_GetPeerCertDescr(const GWEN_SYNCIO *sio)
Definition syncio_tls.c:314
int GWEN_SyncIo_Tls_GetPeerCert(GWEN_SYNCIO *sio)
Definition syncio_tls.c:756
void GWEN_SyncIo_Tls_UndoPrepare(GWEN_SYNCIO *sio)
Definition syncio_tls.c:739
int GWENHYWFAR_CB GWEN_SyncIo_Tls_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
const char * GWEN_SyncIo_Tls_GetLocalTrustFile(const GWEN_SYNCIO *sio)
Definition syncio_tls.c:224
ssize_t GWEN_SyncIo_Tls_Push(gnutls_transport_ptr_t p, const void *buf, size_t len)
GWEN_SYNCIO * GWEN_SyncIo_Tls_new(GWEN_SYNCIO *baseIo)
Definition syncio_tls.c:72
void GWENHYWFAR_CB GWEN_SyncIo_Tls_FreeData(GWEN_UNUSED void *bp, void *p)
Definition syncio_tls.c:96
const char * GWEN_SyncIo_Tls_GetLocalKeyFile(const GWEN_SYNCIO *sio)
Definition syncio_tls.c:194
void GWEN_SyncIo_Tls_SetLocalTrustFile(GWEN_SYNCIO *sio, const char *s)
Definition syncio_tls.c:237
void GWEN_SyncIo_Tls_SetLocalCertFile(GWEN_SYNCIO *sio, const char *s)
Definition syncio_tls.c:177
ssize_t GWEN_SyncIo_Tls_Pull(gnutls_transport_ptr_t p, void *buf, size_t len)
void GWEN_SyncIo_Tls_ShowCipherInfo(GWEN_SYNCIO *sio)
void GWEN_SyncIo_Tls_SetDhParamFile(GWEN_SYNCIO *sio, const char *s)
Definition syncio_tls.c:267
const char * GWEN_SyncIo_Tls_GetLocalCertFile(const GWEN_SYNCIO *sio)
Definition syncio_tls.c:164
void GWEN_SyncIo_Tls_SetLocalKeyFile(GWEN_SYNCIO *sio, const char *s)
Definition syncio_tls.c:207
void GWEN_SyncIo_Tls_SetRemoteHostName(GWEN_SYNCIO *sio, const char *s)
Definition syncio_tls.c:297
const char * SYNCIO_TLS_SYSTEM_CERTFILES[]
Definition syncio_tls.c:62
GWENHYWFAR_CB int GWEN_SyncIo_Tls_Internal_CheckCert(GWEN_SYNCIO *sio, const GWEN_SSLCERTDESCR *cert)
Definition syncio_tls.c:128
int GWEN_SyncIo_Tls__readFile(const char *fname, GWEN_BUFFER *buf)
Definition syncio_tls.c:327
const char * GWEN_SyncIo_Tls_GetRemoteHostName(const GWEN_SYNCIO *sio)
Definition syncio_tls.c:284
int GWEN_SyncIo_Tls_Prepare(GWEN_SYNCIO *sio)
Definition syncio_tls.c:421
int GWENHYWFAR_CB GWEN_SyncIo_Tls_Disconnect(GWEN_SYNCIO *sio)
int GWENHYWFAR_CB GWEN_SyncIo_Tls_Connect(GWEN_SYNCIO *sio)
int GWENHYWFAR_CB GWEN_SyncIo_Tls_Write(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
const char * GWEN_SyncIo_Tls_GetDhParamFile(const GWEN_SYNCIO *sio)
Definition syncio_tls.c:254
#define GWEN_SYNCIO_TLS_FLAGS_REQUEST_CERT
Definition syncio_tls.h:36
#define GWEN_SYNCIO_TLS_TYPE
Definition syncio_tls.h:33
#define GWEN_SYNCIO_TLS_FLAGS_ALLOW_V1_CA_CRT
Definition syncio_tls.h:38
#define GWEN_SYNCIO_TLS_FLAGS_IGN_PREMATURE_CLOSE
Definition syncio_tls.h:45
#define GWEN_SYNCIO_TLS_FLAGS_NEED_PEER_CERT
Definition syncio_tls.h:39
#define GWEN_SYNCIO_TLS_FLAGS_ADD_TRUSTED_CAS
Definition syncio_tls.h:40
#define GWEN_SYNCIO_TLS_FLAGS_SECURE
Definition syncio_tls.h:47
int GWENHYWFAR_CB(* GWEN_SIO_TLS_CHECKCERT_FN)(GWEN_SYNCIO *sio, const GWEN_SSLCERTDESCR *cert)
Definition syncio_tls.h:84
int GWEN_Text_ToHexBuffer(const char *src, unsigned l, GWEN_BUFFER *buf, unsigned int groupsize, char delimiter, int skipLeadingZeroes)
Definition text.c:777
void GWEN_Text_DumpString(const char *s, unsigned int l, unsigned int insert)
Definition text.c:1283