gwenhywfar  4.3.3
syncio_tls.c
Go to the documentation of this file.
1 /***************************************************************************
2  begin : Wed Apr 28 2010
3  copyright : (C) 2010 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 
34 #include "syncio_tls_p.h"
35 #include "i18n_l.h"
36 
37 #include <gwenhywfar/misc.h>
38 #include <gwenhywfar/debug.h>
39 #include <gwenhywfar/gui.h>
40 #include <gwenhywfar/gui.h>
41 #include <gwenhywfar/pathmanager.h>
42 #include <gwenhywfar/directory.h>
43 #include <gwenhywfar/gwenhywfar.h>
44 #include <gwenhywfar/text.h>
45 
46 #include <assert.h>
47 #include <errno.h>
48 #include <string.h>
49 
50 #include <gnutls/gnutls.h>
51 #include <gnutls/x509.h>
52 
53 
54 
55 GWEN_INHERIT(GWEN_SYNCIO, GWEN_SYNCIO_TLS)
56 
57 
59  GWEN_SYNCIO *sio;
60  GWEN_SYNCIO_TLS *xio;
61 
62  assert(baseIo);
64  GWEN_NEW_OBJECT(GWEN_SYNCIO_TLS, xio);
65  GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio, xio, GWEN_SyncIo_Tls_FreeData);
66 
71 
72  return sio;
73 }
74 
75 
76 
77 void GWENHYWFAR_CB GWEN_SyncIo_Tls_FreeData(void *bp, void *p) {
78  GWEN_SYNCIO_TLS *xio;
79 
80  xio=(GWEN_SYNCIO_TLS*) p;
81  GWEN_FREE_OBJECT(xio);
82 }
83 
84 
85 
87  GWEN_SYNCIO_TLS *xio;
88 
89  assert(sio);
90  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
91  assert(xio);
92 
93  return xio->localCertFile;
94 }
95 
96 
97 
98 void GWEN_SyncIo_Tls_SetLocalCertFile(GWEN_SYNCIO *sio, const char *s) {
99  GWEN_SYNCIO_TLS *xio;
100 
101  assert(sio);
102  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
103  assert(xio);
104 
105  free(xio->localCertFile);
106  if (s) xio->localCertFile=strdup(s);
107  else xio->localCertFile=NULL;
108 }
109 
110 
111 
113  GWEN_SYNCIO_TLS *xio;
114 
115  assert(sio);
116  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
117  assert(xio);
118 
119  return xio->localKeyFile;
120 }
121 
122 
123 
124 void GWEN_SyncIo_Tls_SetLocalKeyFile(GWEN_SYNCIO *sio, const char *s) {
125  GWEN_SYNCIO_TLS *xio;
126 
127  assert(sio);
128  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
129  assert(xio);
130 
131  free(xio->localKeyFile);
132  if (s) xio->localKeyFile=strdup(s);
133  else xio->localKeyFile=NULL;
134 }
135 
136 
137 
139  GWEN_SYNCIO_TLS *xio;
140 
141  assert(sio);
142  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
143  assert(xio);
144 
145  return xio->localTrustFile;
146 }
147 
148 
149 
151  GWEN_SYNCIO_TLS *xio;
152 
153  assert(sio);
154  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
155  assert(xio);
156 
157  free(xio->localTrustFile);
158  if (s) xio->localTrustFile=strdup(s);
159  else xio->localTrustFile=NULL;
160 }
161 
162 
163 
165  GWEN_SYNCIO_TLS *xio;
166 
167  assert(sio);
168  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
169  assert(xio);
170 
171  return xio->dhParamFile;
172 }
173 
174 
175 
176 void GWEN_SyncIo_Tls_SetDhParamFile(GWEN_SYNCIO *sio, const char *s) {
177  GWEN_SYNCIO_TLS *xio;
178 
179  assert(sio);
180  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
181  assert(xio);
182 
183  free(xio->dhParamFile);
184  if (s) xio->dhParamFile=strdup(s);
185  else xio->dhParamFile=NULL;
186 }
187 
188 
189 
191  GWEN_SYNCIO_TLS *xio;
192 
193  assert(sio);
194  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
195  assert(xio);
196 
197  return xio->hostName;
198 }
199 
200 
201 
203  GWEN_SYNCIO_TLS *xio;
204 
205  assert(sio);
206  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
207  assert(xio);
208 
209  free(xio->hostName);
210  if (s) xio->hostName=strdup(s);
211  else xio->hostName=NULL;
212 }
213 
214 
215 
217  GWEN_SYNCIO_TLS *xio;
218 
219  assert(sio);
220  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
221  assert(xio);
222 
223  return xio->peerCertDescr;
224 }
225 
226 
227 
228 int GWEN_SyncIo_Tls__readFile(const char *fname, GWEN_BUFFER *buf) {
229  FILE *f;
230 
231  f=fopen(fname, "r");
232  if (f==NULL)
233  return GWEN_ERROR_IO;
234 
235  while(!feof(f)) {
236  int rv;
237 
238  GWEN_Buffer_AllocRoom(buf, 512);
239  rv=fread(GWEN_Buffer_GetPosPointer(buf), 1, 512, f);
240  if (rv==0)
241  break;
242  else if (rv<0) {
243  DBG_INFO(GWEN_LOGDOMAIN, "fread(%s): %s", fname, strerror(errno));
244  fclose(f);
245  return GWEN_ERROR_IO;
246  }
247  else {
248  GWEN_Buffer_IncrementPos(buf, rv);
250  }
251  }
252  fclose(f);
253  return 0;
254 }
255 
256 
257 
259  GWEN_SYNCIO_TLS *xio;
260  int rv;
261  uint32_t lflags;
262 
263  assert(sio);
264  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
265  assert(xio);
266 
267  lflags=GWEN_SyncIo_GetFlags(sio);
268  DBG_INFO(GWEN_LOGDOMAIN, "Preparing SSL (%08x)", lflags);
269 
270  /* init session */
271  if (lflags & GWEN_SYNCIO_FLAGS_PASSIVE) {
272  DBG_INFO(GWEN_LOGDOMAIN, "Init as server");
273  rv=gnutls_init(&xio->session, GNUTLS_SERVER);
274  }
275  else {
276  DBG_INFO(GWEN_LOGDOMAIN, "Init as client");
277  rv=gnutls_init(&xio->session, GNUTLS_CLIENT);
278  }
279  if (rv) {
280  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_init: %d (%s)", rv, gnutls_strerror(rv));
281  return GWEN_ERROR_GENERIC;
282  }
283 
284  /* set default priority */
285  rv=gnutls_set_default_priority(xio->session);
286  if (rv) {
287  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_set_default_priority: %d (%s)", rv, gnutls_strerror(rv));
288  gnutls_deinit(xio->session);
289  return GWEN_ERROR_GENERIC;
290  }
291 
292  /* possibly force protocol priority */
293  if (lflags & GWEN_SYNCIO_TLS_FLAGS_FORCE_SSL_V3) {
294  const int proto_prio[2] = { GNUTLS_SSL3, 0 };
295 
296  DBG_INFO(GWEN_LOGDOMAIN, "Forcing SSL v3");
297  rv=gnutls_protocol_set_priority(xio->session, proto_prio);
298  if (rv) {
299  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_protocol_set_priority: %d (%s)", rv, gnutls_strerror(rv));
300  gnutls_deinit(xio->session);
301  return GWEN_ERROR_GENERIC;
302  }
303  }
304 
305  /* protect against too-many-known-ca problem */
306  gnutls_handshake_set_max_packet_length(xio->session, 64*1024);
307 
308  /* let a server request peer certs */
309  if ((lflags & GWEN_SYNCIO_FLAGS_PASSIVE) &&
311  gnutls_certificate_server_set_request(xio->session, GNUTLS_CERT_REQUIRE);
312 
313  /* prepare cert credentials */
314  rv=gnutls_certificate_allocate_credentials(&xio->credentials);
315  if (rv) {
316  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_allocate_credentials: %d (%s)", rv, gnutls_strerror(rv));
317  gnutls_deinit(xio->session);
318  return GWEN_ERROR_GENERIC;
319  }
320 
321  /* possibly set key file and cert file */
322  if (xio->localCertFile && xio->localKeyFile) {
323  rv=gnutls_certificate_set_x509_key_file(xio->credentials,
324  xio->localCertFile,
325  xio->localKeyFile,
326  GNUTLS_X509_FMT_PEM);
327  if (rv<0) {
328  if (rv) {
329  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_key_file: %d (%s)", rv, gnutls_strerror(rv));
330  gnutls_certificate_free_credentials(xio->credentials);
331  gnutls_deinit(xio->session);
332  return GWEN_ERROR_GENERIC;
333  }
334  }
335  }
336 
337  /* find default trust file if none is selected */
339  int trustFileSet=0;
340 
341 #if 0
342 # ifndef OS_WIN32
343  /* try to find OpenSSL cert file */
344  if (trustFileSet==0) {
345  GWEN_STRINGLIST *paths;
346  GWEN_BUFFER *nbuf;
347 
348  paths=GWEN_StringList_new();
349  GWEN_StringList_AppendString(paths, "/etc/ssl/certs", 0, 0);
350 
351  nbuf=GWEN_Buffer_new(0, 256, 0, 1);
353  "ca-certificates.crt",
354  nbuf);
355  GWEN_StringList_free(paths);
356  if (rv==0) {
358  "Using default ca-bundle from [%s]",
359  GWEN_Buffer_GetStart(nbuf));
361  trustFileSet=1;
362  }
363  }
364 # endif
365 #endif
366 
367  if (trustFileSet==0) {
368  GWEN_STRINGLIST *paths;
369 
370  /* try to find our trust file */
372  if (paths) {
373  GWEN_BUFFER *nbuf;
374 
375  nbuf=GWEN_Buffer_new(0, 256, 0, 1);
377  "ca-bundle.crt",
378  nbuf);
379  GWEN_StringList_free(paths);
380  if (rv==0) {
382  "Using default ca-bundle from [%s]",
383  GWEN_Buffer_GetStart(nbuf));
385  trustFileSet=1;
386  }
387  GWEN_Buffer_free(nbuf);
388  }
389  }
390 
391  if (trustFileSet==0) {
392  DBG_WARN(GWEN_LOGDOMAIN, "No default bundle file found");
393  }
394  }
395 
396  /* possibly set trust file */
397  if (xio->localTrustFile) {
398  rv=gnutls_certificate_set_x509_trust_file(xio->credentials,
399  xio->localTrustFile,
400  GNUTLS_X509_FMT_PEM);
401  if (rv<=0) {
403  "gnutls_certificate_set_x509_trust_file(%s): %d (%s)",
404  (xio->localTrustFile)?(xio->localTrustFile):"-none-",
405  rv, gnutls_strerror(rv));
406  gnutls_certificate_free_credentials(xio->credentials);
407  gnutls_deinit(xio->session);
408  return GWEN_ERROR_GENERIC;
409  }
410  else {
412  "Added %d trusted certs", rv);
413  }
414  }
415 
416  /* possibly set DH params */
417  if (xio->dhParamFile) {
418  GWEN_BUFFER *dbuf;
419 
420  dbuf=GWEN_Buffer_new(0, 256, 0, 1);
421  rv=GWEN_SyncIo_Tls__readFile(xio->dhParamFile, dbuf);
422  if (rv) {
423  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
424  GWEN_Buffer_free(dbuf);
425  gnutls_certificate_free_credentials(xio->credentials);
426  gnutls_deinit(xio->session);
427  return rv;
428  }
429  else {
430  gnutls_datum d;
431  gnutls_dh_params dh_params=NULL;
432 
433  rv=gnutls_dh_params_init(&dh_params);
434  if (rv<0) {
435  GWEN_Buffer_free(dbuf);
436  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_init: %d (%s)", rv, gnutls_strerror(rv));
437  gnutls_certificate_free_credentials(xio->credentials);
438  gnutls_deinit(xio->session);
439  return GWEN_ERROR_GENERIC;
440  }
441 
442  d.size=GWEN_Buffer_GetUsedBytes(dbuf);
443  d.data=(unsigned char*)GWEN_Buffer_GetStart(dbuf);
444 
445  rv=gnutls_dh_params_import_pkcs3(dh_params, &d, GNUTLS_X509_FMT_PEM);
446  if (rv<0) {
447  GWEN_Buffer_free(dbuf);
448  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_import_pkcs3: %d (%s)", rv, gnutls_strerror(rv));
449  gnutls_certificate_free_credentials(xio->credentials);
450  gnutls_deinit(xio->session);
451  return GWEN_ERROR_GENERIC;
452  }
453  GWEN_Buffer_free(dbuf);
454 
455  gnutls_certificate_set_dh_params(xio->credentials, dh_params);
456  }
457  }
458 
459  /* set credentials in TLS session */
460  rv=gnutls_credentials_set(xio->session, GNUTLS_CRD_CERTIFICATE, xio->credentials);
461  if (rv<0) {
462  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_credentials_set: %d (%s)", rv, gnutls_strerror(rv));
463  gnutls_certificate_free_credentials(xio->credentials);
464  gnutls_deinit(xio->session);
465  return GWEN_ERROR_GENERIC;
466  }
467 
468  /* we use our own push/pull functions */
469  gnutls_transport_set_ptr(xio->session, (gnutls_transport_ptr_t)sio);
470  gnutls_transport_set_push_function(xio->session, GWEN_SyncIo_Tls_Push);
471  gnutls_transport_set_pull_function(xio->session, GWEN_SyncIo_Tls_Pull);
472 #if GNUTLS_VERSION_NUMBER < 0x030003
473  gnutls_transport_set_lowat(xio->session, 0);
474 #endif
475 
476  xio->prepared=1;
477 
478  return 0;
479 }
480 
481 
482 
484  GWEN_SYNCIO_TLS *xio;
485 
486  assert(sio);
487  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
488  assert(xio);
489 
490  if (xio->prepared) {
491  gnutls_certificate_free_credentials(xio->credentials);
492  gnutls_deinit(xio->session);
493  xio->prepared=0;
494  }
495 }
496 
497 
498 
500  GWEN_SYNCIO_TLS *xio;
501  const gnutls_datum_t *cert_list;
502  unsigned int cert_list_size;
503  size_t size;
504  GWEN_SSLCERTDESCR *certDescr;
505  char buffer1[64];
506  time_t t0;
507  int rv;
508  uint32_t lflags;
509  uint32_t errFlags=0;
510  int i;
511  unsigned int status;
512  GWEN_BUFFER *sbuf=NULL;
513 
514  assert(sio);
515  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
516  assert(xio);
517 
518  lflags=GWEN_SyncIo_GetFlags(sio);
519 
520  if (xio->peerCertDescr) {
521  GWEN_SslCertDescr_free(xio->peerCertDescr);
522  xio->peerCertDescr=NULL;
523  }
524  xio->peerCertFlags=0;
525 
526  t0=time(NULL);
527  if (t0<0) {
528  DBG_WARN(GWEN_LOGDOMAIN, "Could not get system time");
529  errFlags|=GWEN_SSL_CERT_FLAGS_SYSTEM;
530  }
531 
532  /* create new cert description, check cert on the fly */
533  certDescr=GWEN_SslCertDescr_new();
534 
535  /* some general tests */
537  gnutls_certificate_set_verify_flags(xio->credentials,
538  GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
539 
540  rv=gnutls_certificate_verify_peers2(xio->session, &status);
541  if (rv<0) {
542  DBG_INFO(GWEN_LOGDOMAIN, "gnutls_certificate_verify_peers2: %d (%s)", rv, gnutls_strerror(rv));
543  GWEN_SslCertDescr_free(certDescr);
545  }
546 
547  if (gnutls_certificate_type_get(xio->session)!=GNUTLS_CRT_X509) {
548  DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not X.509");
549 
550  GWEN_SslCertDescr_free(certDescr);
552  }
553 
554  if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
555  DBG_INFO(GWEN_LOGDOMAIN, "Signer not found");
557  I18N("Signer not found"));
559  }
560 
561  if (status & GNUTLS_CERT_INVALID) {
562  DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not trusted");
564  I18N("Certificate is not trusted"));
565  errFlags|=GWEN_SSL_CERT_FLAGS_INVALID;
566  }
567 
568  if (status & GNUTLS_CERT_REVOKED) {
569  DBG_INFO(GWEN_LOGDOMAIN, "Certificate has been revoked");
571  I18N("Certificate has been revoked"));
572  errFlags|=GWEN_SSL_CERT_FLAGS_REVOKED;
573  }
574 
575  cert_list=gnutls_certificate_get_peers(xio->session, &cert_list_size);
576  if (cert_list==NULL || cert_list_size==0) {
577  DBG_INFO(GWEN_LOGDOMAIN, "No peer certificates found");
578  return GWEN_ERROR_NO_DATA;
579  }
580 
581  for (i=0; i<cert_list_size; i++) {
582  gnutls_x509_crt_t cert;
583  time_t t;
584 
585  rv=gnutls_x509_crt_init(&cert);
586  if (rv!=0) {
587  DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_init: %d (%s)", rv, gnutls_strerror(rv));
588  return GWEN_ERROR_GENERIC;
589  }
590 
591  rv=gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
592  if (rv!=0) {
593  DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_import: %d (%s)", rv, gnutls_strerror(rv));
594  gnutls_x509_crt_deinit(cert);
595  return GWEN_ERROR_GENERIC;
596  }
597 
598  if (i==0) {
599  /* get fingerprint */
600  size=16;
601  rv=gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, buffer1, &size);
602  if (rv!=0) {
603  DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_fingerprint: %d (%s)", rv, gnutls_strerror(rv));
604  GWEN_SslCertDescr_free(certDescr);
605  gnutls_x509_crt_deinit(cert);
606  return GWEN_ERROR_GENERIC;
607  }
608  else {
609  GWEN_BUFFER *dbuf;
610 
611  dbuf=GWEN_Buffer_new(0, 256, 0, 1);
612  if (GWEN_Text_ToHexBuffer(/* GCC4 pointer-signedness fix: */ buffer1,
613  size, dbuf, 2, ':', 0)) {
615  "Could not convert fingerprint to hex");
616  }
617  else {
619  }
620  GWEN_Buffer_free(dbuf);
621  }
622 
623  if (xio->hostName) {
624  DBG_INFO(GWEN_LOGDOMAIN, "Checking hostname [%s]", xio->hostName);
625  if (!gnutls_x509_crt_check_hostname(cert, xio->hostName)) {
627  "Certificate was not issued for this host");
629  I18N("Certificate was not issued for this host"));
631  }
632  else {
633  DBG_INFO(GWEN_LOGDOMAIN, "Cert is for this server");
634  }
635  }
636  else {
638  "Hostname is not set, unable to verify the sender");
640  I18N("No hostname to verify the sender!"));
641  }
642 
643  }
644 
645  /* get activation time */
646  t=gnutls_x509_crt_get_activation_time(cert);
647  if (t<0) {
648  DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_activation_time: %d (%s)", rv, gnutls_strerror(rv));
650  }
651  else {
652  if (t>t0) {
653  DBG_INFO(GWEN_LOGDOMAIN, "Cert is not yet active");
655  }
656  if (i==0) {
657  GWEN_TIME *ti;
658 
659  ti=GWEN_Time_fromSeconds(t);
660  if (ti)
661  GWEN_SslCertDescr_SetNotBefore(certDescr, ti);
662  GWEN_Time_free(ti);
663  }
664  }
665 
666  /* get expiration time */
667  t=gnutls_x509_crt_get_expiration_time(cert);
668  if (t<0) {
669  DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_expiration_time: %d (%s)", rv, gnutls_strerror(rv));
671  }
672  else {
673  if (t<t0) {
674  DBG_INFO(GWEN_LOGDOMAIN, "Cert has expired");
675  errFlags|=GWEN_SSL_CERT_FLAGS_EXPIRED;
676  }
677  if (i==0) {
678  GWEN_TIME *ti;
679 
680  ti=GWEN_Time_fromSeconds(t);
681  if (ti)
682  GWEN_SslCertDescr_SetNotAfter(certDescr, ti);
683  GWEN_Time_free(ti);
684  }
685  }
686 
687  if (i==0) {
688  /* get owner information, but only for first cert */
689  size=sizeof(buffer1)-1;
690  rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, buffer1, &size);
691  if (rv==0) {
692  GWEN_SslCertDescr_SetCommonName(certDescr, buffer1);
693  if (xio->hostName && strcasecmp(xio->hostName, buffer1)!=0) {
694  DBG_INFO(GWEN_LOGDOMAIN, "Owner of certificate does not match hostname");
696  }
697  }
698 
699  size=sizeof(buffer1)-1;
700  rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, buffer1, &size);
701  if (rv==0)
702  GWEN_SslCertDescr_SetOrganizationName(certDescr, buffer1);
703 
704  size=sizeof(buffer1)-1;
705  rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, buffer1, &size);
706  if (rv==0)
708 
709  size=sizeof(buffer1)-1;
710  rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, buffer1, &size);
711  if (rv==0)
712  GWEN_SslCertDescr_SetLocalityName(certDescr, buffer1);
713 
714  size=sizeof(buffer1)-1;
715  rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, buffer1, &size);
716  if (rv==0)
717  GWEN_SslCertDescr_SetStateOrProvinceName(certDescr, buffer1);
718 
719  size=sizeof(buffer1)-1;
720  rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, buffer1, &size);
721  if (rv==0)
722  GWEN_SslCertDescr_SetCountryName(certDescr, buffer1);
723  }
724 
725  gnutls_x509_crt_deinit(cert);
726  }
727 
728  /* done */
729  if (errFlags)
730  GWEN_SslCertDescr_SetIsError(certDescr, 1);
731  else
732  errFlags|=GWEN_SSL_CERT_FLAGS_OK;
733 
734  sbuf=GWEN_Buffer_new(0, 256, 0, 1);
735 
736  if (errFlags & GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND) {
737  if (GWEN_Buffer_GetUsedBytes(sbuf))
738  GWEN_Buffer_AppendString(sbuf, "; ");
739  GWEN_Buffer_AppendString(sbuf, I18N("Signer not found"));
740  }
741 
742  if (errFlags & GWEN_SSL_CERT_FLAGS_INVALID) {
743  if (GWEN_Buffer_GetUsedBytes(sbuf))
744  GWEN_Buffer_AppendString(sbuf, "; ");
745  GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not trusted"));
746  }
747 
748  if (errFlags & GWEN_SSL_CERT_FLAGS_REVOKED) {
749  if (GWEN_Buffer_GetUsedBytes(sbuf))
750  GWEN_Buffer_AppendString(sbuf, "; ");
751  GWEN_Buffer_AppendString(sbuf, I18N("Certificate has been revoked"));
752  }
753 
754  if (errFlags & GWEN_SSL_CERT_FLAGS_EXPIRED) {
755  if (GWEN_Buffer_GetUsedBytes(sbuf))
756  GWEN_Buffer_AppendString(sbuf, "; ");
757  GWEN_Buffer_AppendString(sbuf, I18N("Certificate has expired"));
758  }
759 
760  if (errFlags & GWEN_SSL_CERT_FLAGS_NOT_ACTIVE) {
761  if (GWEN_Buffer_GetUsedBytes(sbuf))
762  GWEN_Buffer_AppendString(sbuf, "; ");
763  GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not active yet"));
764  }
765 
766  if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME) {
767  if (GWEN_Buffer_GetUsedBytes(sbuf))
768  GWEN_Buffer_AppendString(sbuf, "; ");
769  GWEN_Buffer_AppendString(sbuf, I18N("Certificate owner does not match hostname"));
770  }
771 
772  if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_DATA) {
773  if (GWEN_Buffer_GetUsedBytes(sbuf))
774  GWEN_Buffer_AppendString(sbuf, "; ");
775  GWEN_Buffer_AppendString(sbuf, I18N("Certificate contains invalid information"));
776  }
777 
778  if (errFlags & GWEN_SSL_CERT_FLAGS_SYSTEM) {
779  if (GWEN_Buffer_GetUsedBytes(sbuf))
780  GWEN_Buffer_AppendString(sbuf, "; ");
781  GWEN_Buffer_AppendString(sbuf, I18N("A system error occurred while checking the certificate"));
782  }
783 
784  if (errFlags & GWEN_SSL_CERT_FLAGS_OK) {
785  if (GWEN_Buffer_GetUsedBytes(sbuf))
786  GWEN_Buffer_AppendString(sbuf, "; ");
787  GWEN_Buffer_AppendString(sbuf, I18N("The certificate is valid"));
788  }
789 
791  GWEN_SslCertDescr_SetStatusFlags(certDescr, errFlags);
792  GWEN_Buffer_free(sbuf);
793 
794  xio->peerCertDescr=certDescr;
795  xio->peerCertFlags=errFlags;
796 
797  return 0;
798 }
799 
800 
801 
802 ssize_t GWEN_SyncIo_Tls_Pull(gnutls_transport_ptr_t p, void *buf, size_t len) {
803  GWEN_SYNCIO *sio;
804  GWEN_SYNCIO_TLS *xio;
805  GWEN_SYNCIO *baseIo;
806  int rv;
807 
808  sio=(GWEN_SYNCIO*) p;
809  assert(sio);
810  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
811  assert(xio);
812 
813  DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: %d bytes", (int)len);
814  baseIo=GWEN_SyncIo_GetBaseIo(sio);
815  assert(baseIo);
816 
817  rv=GWEN_SyncIo_Read(baseIo, buf, len);
818  if (rv<0) {
819  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
820 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
821  gnutls_transport_set_errno(xio->session, errno);
822 #endif
823  return (ssize_t)-1;
824  }
825 
826 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
827  gnutls_transport_set_errno(xio->session, 0);
828 #else
829  errno=0;
830 #endif
831  DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: returning %d bytes", rv);
832  /*GWEN_Text_DumpString(buf, rv, 2);*/
833  return rv;
834 }
835 
836 
837 
838 ssize_t GWEN_SyncIo_Tls_Push(gnutls_transport_ptr_t p, const void *buf, size_t len) {
839  GWEN_SYNCIO *sio;
840  GWEN_SYNCIO_TLS *xio;
841  GWEN_SYNCIO *baseIo;
842  int rv;
843 
844  sio=(GWEN_SYNCIO*) p;
845  assert(sio);
846  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
847  assert(xio);
848 
849  DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: %d bytes", (int)len);
850  baseIo=GWEN_SyncIo_GetBaseIo(sio);
851  assert(baseIo);
852 
853  rv=GWEN_SyncIo_Write(baseIo, buf, len);
854  if (rv<0) {
855  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
856 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
857  gnutls_transport_set_errno(xio->session, errno);
858 #endif
859  return (ssize_t)-1;
860  }
861 
862 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
863  gnutls_transport_set_errno(xio->session, 0);
864 #endif
865  DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: returning %d bytes", rv);
866  /*GWEN_Text_DumpString(buf, rv, 2);*/
867  return rv;
868 }
869 
870 
871 
873  GWEN_SYNCIO_TLS *xio;
874  GWEN_SYNCIO *baseIo;
875  int rv;
876 
877  assert(sio);
878  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
879  assert(xio);
880 
881  baseIo=GWEN_SyncIo_GetBaseIo(sio);
882  assert(baseIo);
883 
886  DBG_ERROR(GWEN_LOGDOMAIN, "Base layer is not connected");
888  }
889  }
890  else {
891  DBG_INFO(GWEN_LOGDOMAIN, "Connecting base layer");
892  rv=GWEN_SyncIo_Connect(baseIo);
893  if (rv<0) {
894  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
895  return rv;
896  }
897  DBG_INFO(GWEN_LOGDOMAIN, "Base layer connected");
898  }
899 
900  rv=GWEN_SyncIo_Tls_Prepare(sio);
901  if (rv<0) {
902  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
903  GWEN_SyncIo_Disconnect(baseIo);
904  return rv;
905  }
906 
907  do {
908  rv=gnutls_handshake(xio->session);
909  } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
910 
911  if (rv) {
912  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_handshake: %d (%s) [%s]",
913  rv, gnutls_strerror(rv), gnutls_error_is_fatal(rv)?"fatal":"non-fatal");
914  if (rv==GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
917  I18N("A TLS handshake error occurred. "
918  "If you are using AqBanking you should "
919  "consider enabling the option "
920  "\"force SSLv3\" in the user settings "
921  "dialog."));
922  }
923  else {
926  I18N("TLS Handshake Error: %d (%s)"),
927  rv,
928  gnutls_strerror(rv));
929  }
932  GWEN_SyncIo_Disconnect(baseIo);
933  return GWEN_ERROR_SSL;
934  }
935  else {
936  /* check certificate */
939  if (rv<0) {
941  DBG_ERROR(GWEN_LOGDOMAIN, "No peer certificate when needed, aborting connection");
944  GWEN_SyncIo_Disconnect(baseIo);
946  }
947  else {
948  DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (insecure)");
950  return 0;
951  }
952  }
953  else {
954  /* present cert to the user */
955  rv=GWEN_Gui_CheckCert(xio->peerCertDescr, sio, 0);
956  if (rv<0) {
957  DBG_ERROR(GWEN_LOGDOMAIN, "Peer cert not accepted (%d), aborting", rv);
960  GWEN_SyncIo_Disconnect(baseIo);
962  }
963  else {
964  DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (secure)");
967  return 0;
968  }
969  }
970  }
971 }
972 
973 
974 
976  GWEN_SYNCIO_TLS *xio;
977  GWEN_SYNCIO *baseIo;
978  int rv;
979 
980  assert(sio);
981  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
982  assert(xio);
983 
984  baseIo=GWEN_SyncIo_GetBaseIo(sio);
985  assert(baseIo);
986 
988  DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
990  GWEN_SyncIo_Disconnect(baseIo);
992  }
993 
994  do {
995  rv=gnutls_bye(xio->session, GNUTLS_SHUT_RDWR);
996  } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
997 
998  if (rv) {
999  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_bye: %d (%s)", rv, gnutls_strerror(rv));
1002  I18N("Error on gnutls_bye: %d (%s)"),
1003  rv,
1004  gnutls_strerror(rv));
1007  GWEN_SyncIo_Disconnect(baseIo);
1008  return GWEN_ERROR_SSL;
1009  }
1010 
1013  GWEN_SyncIo_Disconnect(baseIo);
1014  return 0;
1015 }
1016 
1017 
1018 
1020  uint8_t *buffer,
1021  uint32_t size) {
1022  GWEN_SYNCIO_TLS *xio;
1023  GWEN_SYNCIO *baseIo;
1024  int rv;
1025 
1026  assert(sio);
1027  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1028  assert(xio);
1029 
1030  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1031  assert(baseIo);
1032 
1034  DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
1036  GWEN_SyncIo_Disconnect(baseIo);
1037  return GWEN_ERROR_NOT_CONNECTED;
1038  }
1039 
1040  do {
1041  rv=gnutls_record_recv(xio->session, buffer, size);
1042  } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
1043 
1044  if (rv<0) {
1045  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_record_recv: %d (%s)", rv, gnutls_strerror(rv));
1046 #if 0
1049  I18N("Error on gnutls_record_recv: %d (%s)"),
1050  rv,
1051  gnutls_strerror(rv));
1052 #endif
1055  GWEN_SyncIo_Disconnect(baseIo);
1056  return GWEN_ERROR_SSL;
1057  }
1058 
1059 #ifdef GWEN_TLS_DEBUG
1060  DBG_ERROR(0, "Received this:");
1061  GWEN_Text_DumpString((const char*) buffer, rv, 2);
1062 #endif
1063 
1064  return rv;
1065 }
1066 
1067 
1068 
1070  const uint8_t *buffer,
1071  uint32_t size) {
1072  GWEN_SYNCIO_TLS *xio;
1073  GWEN_SYNCIO *baseIo;
1074  int rv;
1075 
1076  assert(sio);
1077  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
1078  assert(xio);
1079 
1080 #ifdef GWEN_TLS_DEBUG
1081  DBG_ERROR(0, "Sending this:");
1082  GWEN_Text_DumpString((const char*) buffer, size, 2);
1083 #endif
1084 
1085  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1086  assert(baseIo);
1087 
1089  DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
1091  GWEN_SyncIo_Disconnect(baseIo);
1092  return GWEN_ERROR_NOT_CONNECTED;
1093  }
1094 
1095  do {
1096  rv=gnutls_record_send(xio->session, buffer, size);
1097  } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
1098 
1099  if (rv<0) {
1100  DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_record_send: %d (%s)", rv, gnutls_strerror(rv));
1103  I18N("Error on gnutls_record_send: %d (%s)"),
1104  rv,
1105  gnutls_strerror(rv));
1108  GWEN_SyncIo_Disconnect(baseIo);
1109  return GWEN_ERROR_SSL;
1110  }
1111 
1112  return rv;
1113 }
1114 
1115 
1116 
1117 
1118 
1119 
1120