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