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