io_tls.c

Go to the documentation of this file.
00001 /***************************************************************************
00002     copyright   : (C) 2007 by Martin Preuss
00003     email       : martin@libchipcard.de
00004 
00005  ***************************************************************************
00006  *          Please see toplevel file COPYING for license details           *
00007  ***************************************************************************/
00008 
00009 
00010 #ifdef HAVE_CONFIG_H
00011 # include <config.h>
00012 #endif
00013 
00014 
00015 #include "io_tls_p.h"
00016 #include <gwenhywfar/iolayer_be.h>
00017 #include <gwenhywfar/io_codec_be.h>
00018 #include <gwenhywfar/iorequest_be.h>
00019 #include <gwenhywfar/io_socket.h>
00020 
00021 #include "i18n_l.h"
00022 #include <gwenhywfar/gwenhywfar.h>
00023 #include <gwenhywfar/misc.h>
00024 #include <gwenhywfar/debug.h>
00025 #include <gwenhywfar/gui.h>
00026 #include <gwenhywfar/pathmanager.h>
00027 #include <gwenhywfar/directory.h>
00028 
00029 #include <assert.h>
00030 #include <errno.h>
00031 
00032 #include <gnutls/gnutls.h>
00033 #include <gnutls/x509.h>
00034 
00035 
00036 #include <gwenhywfar/text.h> /* debug */
00037 
00038 
00039 /*#define DEBUG_TLS*/
00040 
00041 
00042 
00043 GWEN_INHERIT(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS)
00044 
00045 
00046 #ifndef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00047 /* #warning "gnutls_transport_set_errno is not defined" */
00048 #endif
00049 
00050 
00051 
00052 
00053 GWEN_IO_LAYER *GWEN_Io_LayerTls_new(GWEN_IO_LAYER *baseLayer) {
00054   GWEN_IO_LAYER *io;
00055   GWEN_IO_LAYER_TLS *xio;
00056 
00057   io=GWEN_Io_LayerCodec_new(GWEN_IO_LAYER_TLS_TYPE, baseLayer);
00058   assert(io);
00059   GWEN_NEW_OBJECT(GWEN_IO_LAYER_TLS, xio);
00060   assert(xio);
00061   GWEN_INHERIT_SETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io, xio, GWEN_Io_LayerTls_freeData);
00062 
00063   xio->workOnRequestsFn=GWEN_Io_Layer_SetWorkOnRequestsFn(io, GWEN_Io_LayerTls_WorkOnRequests);
00064   xio->addRequestFn=GWEN_Io_Layer_SetAddRequestFn(io, GWEN_Io_LayerTls_AddRequest);
00065   xio->delRequestFn=GWEN_Io_Layer_SetDelRequestFn(io, GWEN_Io_LayerTls_DelRequest);
00066   xio->hasWaitingRequestsFn=GWEN_Io_Layer_SetHasWaitingRequestsFn(io, GWEN_Io_LayerTls_HasWaitingRequests);
00067 
00068   GWEN_Io_LayerCodec_SetEncodeFn(io, GWEN_Io_LayerTls_Encode);
00069   GWEN_Io_LayerCodec_SetDecodeFn(io, GWEN_Io_LayerTls_Decode);
00070 
00071   return io;
00072 }
00073 
00074 
00075 
00076 GWENHYWFAR_CB
00077 void GWEN_Io_LayerTls_freeData(void *bp, void *p) {
00078   GWEN_IO_LAYER *io;
00079   GWEN_IO_LAYER_TLS *xio;
00080 
00081   io=(GWEN_IO_LAYER*) bp;
00082   assert(io);
00083   xio=(GWEN_IO_LAYER_TLS*) p;
00084   assert(xio);
00085 
00086   free(xio->dhParamFile);
00087   free(xio->localCertFile);
00088   free(xio->localKeyFile);
00089   free(xio->localTrustFile);
00090   free(xio->hostName);
00091   if (xio->prepared) {
00092     gnutls_deinit(xio->session);
00093     gnutls_certificate_free_credentials(xio->credentials);
00094     xio->prepared=0;
00095   }
00096 
00097   GWEN_SslCertDescr_free(xio->peerCertDescr);
00098 
00099 }
00100 
00101 
00102 
00103 const char *GWEN_Io_LayerTls_GetLocalCertFile(const GWEN_IO_LAYER *io) {
00104   GWEN_IO_LAYER_TLS *xio;
00105 
00106   assert(io);
00107   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00108   assert(xio);
00109 
00110   return xio->localCertFile;
00111 }
00112 
00113 
00114 
00115 void GWEN_Io_LayerTls_SetLocalCertFile(GWEN_IO_LAYER *io, const char *s) {
00116   GWEN_IO_LAYER_TLS *xio;
00117 
00118   assert(io);
00119   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00120   assert(xio);
00121 
00122   free(xio->localCertFile);
00123   if (s) xio->localCertFile=strdup(s);
00124   else xio->localCertFile=NULL;
00125 }
00126 
00127 
00128 
00129 const char *GWEN_Io_LayerTls_GetLocalKeyFile(const GWEN_IO_LAYER *io) {
00130   GWEN_IO_LAYER_TLS *xio;
00131 
00132   assert(io);
00133   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00134   assert(xio);
00135 
00136   return xio->localKeyFile;
00137 }
00138 
00139 
00140 
00141 void GWEN_Io_LayerTls_SetLocalKeyFile(GWEN_IO_LAYER *io, const char *s) {
00142   GWEN_IO_LAYER_TLS *xio;
00143 
00144   assert(io);
00145   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00146   assert(xio);
00147 
00148   free(xio->localKeyFile);
00149   if (s) xio->localKeyFile=strdup(s);
00150   else xio->localKeyFile=NULL;
00151 }
00152 
00153 
00154 
00155 const char *GWEN_Io_LayerTls_GetLocalTrustFile(const GWEN_IO_LAYER *io) {
00156   GWEN_IO_LAYER_TLS *xio;
00157 
00158   assert(io);
00159   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00160   assert(xio);
00161 
00162   return xio->localTrustFile;
00163 }
00164 
00165 
00166 
00167 void GWEN_Io_LayerTls_SetLocalTrustFile(GWEN_IO_LAYER *io, const char *s) {
00168   GWEN_IO_LAYER_TLS *xio;
00169 
00170   assert(io);
00171   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00172   assert(xio);
00173 
00174   free(xio->localTrustFile);
00175   if (s) xio->localTrustFile=strdup(s);
00176   else xio->localTrustFile=NULL;
00177 }
00178 
00179 
00180 
00181 const char *GWEN_Io_LayerTls_GetDhParamFile(const GWEN_IO_LAYER *io) {
00182   GWEN_IO_LAYER_TLS *xio;
00183 
00184   assert(io);
00185   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00186   assert(xio);
00187 
00188   return xio->dhParamFile;
00189 }
00190 
00191 
00192 
00193 void GWEN_Io_LayerTls_SetDhParamFile(GWEN_IO_LAYER *io, const char *s) {
00194   GWEN_IO_LAYER_TLS *xio;
00195 
00196   assert(io);
00197   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00198   assert(xio);
00199 
00200   free(xio->dhParamFile);
00201   if (s) xio->dhParamFile=strdup(s);
00202   else xio->dhParamFile=NULL;
00203 }
00204 
00205 
00206 
00207 const char *GWEN_Io_LayerTls_GetRemoteHostName(const GWEN_IO_LAYER *io) {
00208   GWEN_IO_LAYER_TLS *xio;
00209 
00210   assert(io);
00211   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00212   assert(xio);
00213 
00214   return xio->hostName;
00215 }
00216 
00217 
00218 
00219 void GWEN_Io_LayerTls_SetRemoteHostName(GWEN_IO_LAYER *io, const char *s) {
00220   GWEN_IO_LAYER_TLS *xio;
00221 
00222   assert(io);
00223   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00224   assert(xio);
00225 
00226   free(xio->hostName);
00227   if (s) xio->hostName=strdup(s);
00228   else xio->hostName=NULL;
00229 }
00230 
00231 
00232 
00233 GWEN_SSLCERTDESCR *GWEN_Io_LayerTls_GetPeerCertDescr(const GWEN_IO_LAYER *io) {
00234   GWEN_IO_LAYER_TLS *xio;
00235 
00236   assert(io);
00237   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00238   assert(xio);
00239 
00240   return xio->peerCertDescr;
00241 }
00242 
00243 
00244 
00245 int GWEN_Io_LayerTls__readFile(const char *fname, GWEN_BUFFER *buf) {
00246   FILE *f;
00247 
00248   f=fopen(fname, "r");
00249   if (f==NULL)
00250     return GWEN_ERROR_IO;
00251 
00252   while(!feof(f)) {
00253     int rv;
00254 
00255     GWEN_Buffer_AllocRoom(buf, 512);
00256     rv=fread(GWEN_Buffer_GetPosPointer(buf), 1, 512, f);
00257     if (rv==0)
00258       break;
00259     else if (rv<0) {
00260       DBG_INFO(GWEN_LOGDOMAIN, "fread(%s): %s", fname, strerror(errno));
00261       fclose(f);
00262       return GWEN_ERROR_IO;
00263     }
00264     else {
00265       GWEN_Buffer_IncrementPos(buf, rv);
00266       GWEN_Buffer_AdjustUsedBytes(buf);
00267     }
00268   }
00269   fclose(f);
00270   return 0;
00271 }
00272 
00273 
00274 
00275 int GWEN_Io_LayerTls_Prepare(GWEN_IO_LAYER *io) {
00276   GWEN_IO_LAYER_TLS *xio;
00277   int rv;
00278   uint32_t lflags;
00279 
00280   assert(io);
00281   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00282   assert(xio);
00283 
00284   lflags=GWEN_Io_Layer_GetFlags(io);
00285   DBG_INFO(GWEN_LOGDOMAIN, "Preparing SSL (%08x)", lflags);
00286 
00287   /* init session */
00288   if (lflags & GWEN_IO_LAYER_FLAGS_PASSIVE) {
00289     DBG_INFO(GWEN_LOGDOMAIN, "Init as server");
00290     rv=gnutls_init(&xio->session, GNUTLS_SERVER);
00291   }
00292   else {
00293     DBG_INFO(GWEN_LOGDOMAIN, "Init as client");
00294     rv=gnutls_init(&xio->session, GNUTLS_CLIENT);
00295   }
00296   if (rv) {
00297     DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_init: %d (%s)", rv, gnutls_strerror(rv));
00298     return GWEN_ERROR_GENERIC;
00299   }
00300 
00301   /* set default priority */
00302   rv=gnutls_set_default_priority(xio->session);
00303   if (rv) {
00304     DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_set_default_priority: %d (%s)", rv, gnutls_strerror(rv));
00305     gnutls_deinit(xio->session);
00306     return GWEN_ERROR_GENERIC;
00307   }
00308 
00309   /* possibly force protocol priority */
00310   if (lflags & GWEN_IO_LAYER_TLS_FLAGS_FORCE_SSL_V3) {
00311     const int proto_prio[2] = { GNUTLS_SSL3, 0 };
00312 
00313     DBG_INFO(GWEN_LOGDOMAIN, "Forcing SSL v3");
00314     rv=gnutls_protocol_set_priority(xio->session, proto_prio);
00315     if (rv) {
00316       DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_protocol_set_priority: %d (%s)", rv, gnutls_strerror(rv));
00317       gnutls_deinit(xio->session);
00318       return GWEN_ERROR_GENERIC;
00319     }
00320   }
00321 
00322   /* protect against too-many-known-ca problem */
00323   gnutls_handshake_set_max_packet_length(xio->session, 64*1024);
00324 
00325   /* let a server request peer certs */
00326   if ((lflags & GWEN_IO_LAYER_FLAGS_PASSIVE) &&
00327       (lflags & GWEN_IO_LAYER_TLS_FLAGS_REQUEST_CERT))
00328     gnutls_certificate_server_set_request(xio->session, GNUTLS_CERT_REQUIRE);
00329 
00330   /* prepare cert credentials */
00331   rv=gnutls_certificate_allocate_credentials(&xio->credentials);
00332   if (rv) {
00333     DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_allocate_credentials: %d (%s)", rv, gnutls_strerror(rv));
00334     gnutls_deinit(xio->session);
00335     return GWEN_ERROR_GENERIC;
00336   }
00337 
00338   /* possibly set key file and cert file */
00339   if (xio->localCertFile && xio->localKeyFile) {
00340     rv=gnutls_certificate_set_x509_key_file(xio->credentials,
00341                                             xio->localCertFile,
00342                                             xio->localKeyFile,
00343                                             GNUTLS_X509_FMT_PEM);
00344     if (rv<0) {
00345       if (rv) {
00346         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_key_file: %d (%s)", rv, gnutls_strerror(rv));
00347         gnutls_certificate_free_credentials(xio->credentials);
00348         gnutls_deinit(xio->session);
00349         return GWEN_ERROR_GENERIC;
00350       }
00351     }
00352   }
00353 
00354   /* find default trust file if none is selected */
00355   if (lflags & GWEN_IO_LAYER_TLS_FLAGS_ADD_TRUSTED_CAS) {
00356     GWEN_STRINGLIST *paths;
00357 
00358     /* try to find out trust file */
00359     paths=GWEN_PathManager_GetPaths(GWEN_PM_LIBNAME, GWEN_PM_DATADIR);
00360     if (paths) {
00361       GWEN_BUFFER *nbuf;
00362 
00363       nbuf=GWEN_Buffer_new(0, 256, 0, 1);
00364       rv=GWEN_Directory_FindFileInPaths(paths,
00365                                         "ca-bundle.crt",
00366                                         nbuf);
00367       GWEN_StringList_free(paths);
00368       if (rv==0) {
00369         DBG_INFO(GWEN_LOGDOMAIN,
00370                  "Using default ca-bundle from [%s]",
00371                  GWEN_Buffer_GetStart(nbuf));
00372         GWEN_Io_LayerTls_SetLocalTrustFile(io, GWEN_Buffer_GetStart(nbuf));
00373       }
00374       else {
00375         DBG_WARN(GWEN_LOGDOMAIN, "Default bundle file not found");
00376       }
00377       GWEN_Buffer_free(nbuf);
00378     }
00379   }
00380 
00381   /* possibly set trust file */
00382   if (xio->localTrustFile) {
00383     rv=gnutls_certificate_set_x509_trust_file(xio->credentials,
00384                                               xio->localTrustFile,
00385                                               GNUTLS_X509_FMT_PEM);
00386     if (rv<=0) {
00387       DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_trust_file: %d (%s)", rv, gnutls_strerror(rv));
00388       gnutls_certificate_free_credentials(xio->credentials);
00389       gnutls_deinit(xio->session);
00390       return GWEN_ERROR_GENERIC;
00391     }
00392     else {
00393       DBG_INFO(GWEN_LOGDOMAIN,
00394                "Added %d trusted certs", rv);
00395     }
00396   }
00397 
00398   /* possibly set DH params */
00399   if (xio->dhParamFile) {
00400     GWEN_BUFFER *dbuf;
00401 
00402     dbuf=GWEN_Buffer_new(0, 256, 0, 1);
00403     rv=GWEN_Io_LayerTls__readFile(xio->dhParamFile, dbuf);
00404     if (rv) {
00405       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00406       GWEN_Buffer_free(dbuf);
00407       gnutls_certificate_free_credentials(xio->credentials);
00408       gnutls_deinit(xio->session);
00409       return rv;
00410     }
00411     else {
00412       gnutls_datum d;
00413       gnutls_dh_params dh_params=NULL;
00414 
00415       rv=gnutls_dh_params_init(&dh_params);
00416       if (rv<0) {
00417         GWEN_Buffer_free(dbuf);
00418         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_init: %d (%s)", rv, gnutls_strerror(rv));
00419         gnutls_certificate_free_credentials(xio->credentials);
00420         gnutls_deinit(xio->session);
00421         return GWEN_ERROR_GENERIC;
00422       }
00423 
00424       d.size=GWEN_Buffer_GetUsedBytes(dbuf);
00425       d.data=(unsigned char*)GWEN_Buffer_GetStart(dbuf);
00426 
00427       rv=gnutls_dh_params_import_pkcs3(dh_params, &d, GNUTLS_X509_FMT_PEM);
00428       if (rv<0) {
00429         GWEN_Buffer_free(dbuf);
00430         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_import_pkcs3: %d (%s)", rv, gnutls_strerror(rv));
00431         gnutls_certificate_free_credentials(xio->credentials);
00432         gnutls_deinit(xio->session);
00433         return GWEN_ERROR_GENERIC;
00434       }
00435       GWEN_Buffer_free(dbuf);
00436 
00437       gnutls_certificate_set_dh_params(xio->credentials, dh_params);
00438     }
00439   }
00440 
00441   /* set credentials in TLS session */
00442   rv=gnutls_credentials_set(xio->session, GNUTLS_CRD_CERTIFICATE, xio->credentials);
00443   if (rv<0) {
00444     DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_credentials_set: %d (%s)", rv, gnutls_strerror(rv));
00445     gnutls_certificate_free_credentials(xio->credentials);
00446     gnutls_deinit(xio->session);
00447     return GWEN_ERROR_GENERIC;
00448   }
00449 
00450   /* we use our own push/pull functions */
00451   gnutls_transport_set_ptr(xio->session, (gnutls_transport_ptr_t)io);
00452   gnutls_transport_set_push_function(xio->session, GWEN_Io_LayerTls_Push);
00453   gnutls_transport_set_pull_function(xio->session, GWEN_Io_LayerTls_Pull);
00454   gnutls_transport_set_lowat(xio->session, 0);
00455 
00456   xio->prepared=1;
00457 
00458   return 0;
00459 }
00460 
00461 
00462 
00463 int GWEN_Io_LayerTls_GetPeerCert(GWEN_IO_LAYER *io, uint32_t guiid) {
00464   GWEN_IO_LAYER_TLS *xio;
00465   const gnutls_datum_t *cert_list;
00466   unsigned int cert_list_size;
00467   size_t size;
00468   GWEN_SSLCERTDESCR *certDescr;
00469   char buffer1[64];
00470   time_t t0;
00471   int rv;
00472   uint32_t lflags;
00473   uint32_t errFlags=0;
00474   int i;
00475   unsigned int status;
00476   GWEN_BUFFER *sbuf=NULL;
00477 
00478   assert(io);
00479   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00480   assert(xio);
00481 
00482   lflags=GWEN_Io_Layer_GetFlags(io);
00483 
00484   if (xio->peerCertDescr) {
00485     GWEN_SslCertDescr_free(xio->peerCertDescr);
00486     xio->peerCertDescr=NULL;
00487   }
00488   xio->peerCertFlags=0;
00489 
00490   t0=time(NULL);
00491   if (t0<0) {
00492     DBG_WARN(GWEN_LOGDOMAIN, "Could not get system time");
00493     errFlags|=GWEN_SSL_CERT_FLAGS_SYSTEM;
00494   }
00495 
00496   /* create new cert description, check cert on the fly */
00497   certDescr=GWEN_SslCertDescr_new();
00498 
00499   /* some general tests */
00500   if (lflags & GWEN_IO_LAYER_TLS_FLAGS_ALLOW_V1_CA_CRT)
00501     gnutls_certificate_set_verify_flags(xio->credentials,
00502                                         GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
00503 
00504   rv=gnutls_certificate_verify_peers2(xio->session, &status);
00505   if (rv<0) {
00506     DBG_INFO(GWEN_LOGDOMAIN, "gnutls_certificate_verify_peers2: %d (%s)", rv, gnutls_strerror(rv));
00507     GWEN_SslCertDescr_free(certDescr);
00508     return GWEN_ERROR_SSL_SECURITY;
00509   }
00510 
00511   if (gnutls_certificate_type_get(xio->session)!=GNUTLS_CRT_X509) {
00512     DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not X.509");
00513 
00514     GWEN_SslCertDescr_free(certDescr);
00515     return GWEN_ERROR_SSL_SECURITY;
00516   }
00517 
00518   if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
00519     DBG_INFO(GWEN_LOGDOMAIN, "Signer not found");
00520     GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00521                          I18N("Signer not found"));
00522     errFlags|=GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND;
00523   }
00524 
00525   if (status & GNUTLS_CERT_INVALID) {
00526     DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not trusted");
00527     GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00528                          I18N("Certificate is not trusted"));
00529     errFlags|=GWEN_SSL_CERT_FLAGS_INVALID;
00530   }
00531 
00532   if (status & GNUTLS_CERT_REVOKED) {
00533     DBG_INFO(GWEN_LOGDOMAIN, "Certificate has been revoked");
00534     GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00535                          I18N("Certificate has been revoked"));
00536     errFlags|=GWEN_SSL_CERT_FLAGS_REVOKED;
00537   }
00538 
00539   cert_list=gnutls_certificate_get_peers(xio->session, &cert_list_size);
00540   if (cert_list==NULL || cert_list_size==0) {
00541     DBG_INFO(GWEN_LOGDOMAIN, "No peer certificates found");
00542     return GWEN_ERROR_NO_DATA;
00543   }
00544 
00545   for (i=0; i<cert_list_size; i++) {
00546     gnutls_x509_crt_t cert;
00547     time_t t;
00548 
00549     rv=gnutls_x509_crt_init(&cert);
00550     if (rv!=0) {
00551       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_init: %d (%s)", rv, gnutls_strerror(rv));
00552       return GWEN_ERROR_GENERIC;
00553     }
00554 
00555     rv=gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
00556     if (rv!=0) {
00557       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_import: %d (%s)", rv, gnutls_strerror(rv));
00558       gnutls_x509_crt_deinit(cert);
00559       return GWEN_ERROR_GENERIC;
00560     }
00561 
00562     if (i==0) {
00563       /* get fingerprint */
00564       size=16;
00565       rv=gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, buffer1, &size);
00566       if (rv!=0) {
00567         DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_fingerprint: %d (%s)", rv, gnutls_strerror(rv));
00568         GWEN_SslCertDescr_free(certDescr);
00569         gnutls_x509_crt_deinit(cert);
00570         return GWEN_ERROR_GENERIC;
00571       }
00572       else {
00573         GWEN_BUFFER *dbuf;
00574 
00575         dbuf=GWEN_Buffer_new(0, 256, 0, 1);
00576         if (GWEN_Text_ToHexBuffer(/* GCC4 pointer-signedness fix: */ buffer1,
00577                                   size, dbuf, 2, ':', 0)) {
00578           DBG_ERROR(GWEN_LOGDOMAIN,
00579                     "Could not convert fingerprint to hex");
00580         }
00581         else {
00582           GWEN_SslCertDescr_SetFingerPrint(certDescr, GWEN_Buffer_GetStart(dbuf));
00583         }
00584         GWEN_Buffer_free(dbuf);
00585       }
00586 
00587       if (xio->hostName) {
00588         DBG_INFO(GWEN_LOGDOMAIN, "Checking hostname [%s]", xio->hostName);
00589         if (!gnutls_x509_crt_check_hostname(cert, xio->hostName)) {
00590           DBG_WARN(GWEN_LOGDOMAIN,
00591                    "Certificate was not issued for this host");
00592           GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00593                                I18N("Certificate was not issued for this host"));
00594           errFlags|=GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME;
00595         }
00596         else {
00597           DBG_INFO(GWEN_LOGDOMAIN, "Cert is for this server");
00598         }
00599       }
00600       else {
00601         DBG_WARN(GWEN_LOGDOMAIN,
00602                  "Hostname is not set, unable to verify the sender");
00603         GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00604                              I18N("No hostname to verify the sender!"));
00605       }
00606 
00607     }
00608 
00609     /* get activation time */
00610     t=gnutls_x509_crt_get_activation_time(cert);
00611     if (t<0) {
00612       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_activation_time: %d (%s)", rv, gnutls_strerror(rv));
00613       errFlags|=GWEN_SSL_CERT_FLAGS_BAD_DATA;
00614     }
00615     else {
00616       if (t>t0) {
00617         DBG_INFO(GWEN_LOGDOMAIN, "Cert is not yet active");
00618         errFlags|=GWEN_SSL_CERT_FLAGS_NOT_ACTIVE;
00619       }
00620       if (i==0) {
00621         GWEN_TIME *ti;
00622 
00623         ti=GWEN_Time_fromSeconds(t);
00624         if (ti)
00625           GWEN_SslCertDescr_SetNotBefore(certDescr, ti);
00626         GWEN_Time_free(ti);
00627       }
00628     }
00629 
00630     /* get expiration time */
00631     t=gnutls_x509_crt_get_expiration_time(cert);
00632     if (t<0) {
00633       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_expiration_time: %d (%s)", rv, gnutls_strerror(rv));
00634       errFlags|=GWEN_SSL_CERT_FLAGS_BAD_DATA;
00635     }
00636     else {
00637       if (t<t0) {
00638         DBG_INFO(GWEN_LOGDOMAIN, "Cert has expired");
00639         errFlags|=GWEN_SSL_CERT_FLAGS_EXPIRED;
00640       }
00641       if (i==0) {
00642         GWEN_TIME *ti;
00643 
00644         ti=GWEN_Time_fromSeconds(t);
00645         if (ti)
00646           GWEN_SslCertDescr_SetNotAfter(certDescr, ti);
00647         GWEN_Time_free(ti);
00648       }
00649     }
00650 
00651     if (i==0) {
00652       /* get owner information, but only for first cert */
00653       size=sizeof(buffer1)-1;
00654       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, buffer1, &size);
00655       if (rv==0) {
00656         GWEN_SslCertDescr_SetCommonName(certDescr, buffer1);
00657         if (xio->hostName && strcasecmp(xio->hostName, buffer1)!=0) {
00658           DBG_INFO(GWEN_LOGDOMAIN, "Owner of certificate does not match hostname");
00659           errFlags|=GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME;
00660         }
00661       }
00662 
00663       size=sizeof(buffer1)-1;
00664       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, buffer1, &size);
00665       if (rv==0)
00666         GWEN_SslCertDescr_SetOrganizationName(certDescr, buffer1);
00667 
00668       size=sizeof(buffer1)-1;
00669       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, buffer1, &size);
00670       if (rv==0)
00671         GWEN_SslCertDescr_SetOrganizationalUnitName(certDescr, buffer1);
00672 
00673       size=sizeof(buffer1)-1;
00674       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, buffer1, &size);
00675       if (rv==0)
00676         GWEN_SslCertDescr_SetLocalityName(certDescr, buffer1);
00677 
00678       size=sizeof(buffer1)-1;
00679       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, buffer1, &size);
00680       if (rv==0)
00681         GWEN_SslCertDescr_SetStateOrProvinceName(certDescr, buffer1);
00682 
00683       size=sizeof(buffer1)-1;
00684       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, buffer1, &size);
00685       if (rv==0)
00686         GWEN_SslCertDescr_SetCountryName(certDescr, buffer1);
00687     }
00688 
00689     gnutls_x509_crt_deinit(cert);
00690   }
00691 
00692   /* done */
00693   if (errFlags)
00694     GWEN_SslCertDescr_SetIsError(certDescr, 1);
00695   else
00696     errFlags|=GWEN_SSL_CERT_FLAGS_OK;
00697 
00698   sbuf=GWEN_Buffer_new(0, 256, 0, 1);
00699 
00700   if (errFlags & GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND) {
00701     if (GWEN_Buffer_GetUsedBytes(sbuf))
00702       GWEN_Buffer_AppendString(sbuf, "; ");
00703     GWEN_Buffer_AppendString(sbuf, I18N("Signer not found"));
00704   }
00705 
00706   if (errFlags & GWEN_SSL_CERT_FLAGS_INVALID) {
00707     if (GWEN_Buffer_GetUsedBytes(sbuf))
00708       GWEN_Buffer_AppendString(sbuf, "; ");
00709     GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not trusted"));
00710   }
00711 
00712   if (errFlags & GWEN_SSL_CERT_FLAGS_REVOKED) {
00713     if (GWEN_Buffer_GetUsedBytes(sbuf))
00714       GWEN_Buffer_AppendString(sbuf, "; ");
00715     GWEN_Buffer_AppendString(sbuf, I18N("Certificate has been revoked"));
00716   }
00717 
00718   if (errFlags & GWEN_SSL_CERT_FLAGS_EXPIRED) {
00719     if (GWEN_Buffer_GetUsedBytes(sbuf))
00720       GWEN_Buffer_AppendString(sbuf, "; ");
00721     GWEN_Buffer_AppendString(sbuf, I18N("Certificate has expired"));
00722   }
00723 
00724   if (errFlags & GWEN_SSL_CERT_FLAGS_NOT_ACTIVE) {
00725     if (GWEN_Buffer_GetUsedBytes(sbuf))
00726       GWEN_Buffer_AppendString(sbuf, "; ");
00727     GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not active yet"));
00728   }
00729 
00730   if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME) {
00731     if (GWEN_Buffer_GetUsedBytes(sbuf))
00732       GWEN_Buffer_AppendString(sbuf, "; ");
00733     GWEN_Buffer_AppendString(sbuf, I18N("Certificate owner does not match hostname"));
00734   }
00735 
00736   if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_DATA) {
00737     if (GWEN_Buffer_GetUsedBytes(sbuf))
00738       GWEN_Buffer_AppendString(sbuf, "; ");
00739     GWEN_Buffer_AppendString(sbuf, I18N("Certificate contains invalid information"));
00740   }
00741 
00742   if (errFlags & GWEN_SSL_CERT_FLAGS_SYSTEM) {
00743     if (GWEN_Buffer_GetUsedBytes(sbuf))
00744       GWEN_Buffer_AppendString(sbuf, "; ");
00745     GWEN_Buffer_AppendString(sbuf, I18N("A system error occurred while checking the certificate"));
00746   }
00747 
00748   if (errFlags & GWEN_SSL_CERT_FLAGS_OK) {
00749     if (GWEN_Buffer_GetUsedBytes(sbuf))
00750       GWEN_Buffer_AppendString(sbuf, "; ");
00751     GWEN_Buffer_AppendString(sbuf, I18N("The certificate is valid"));
00752   }
00753 
00754   GWEN_SslCertDescr_SetStatusText(certDescr, GWEN_Buffer_GetStart(sbuf));
00755   GWEN_SslCertDescr_SetStatusFlags(certDescr, errFlags);
00756   GWEN_Buffer_free(sbuf);
00757 
00758   xio->peerCertDescr=certDescr;
00759   xio->peerCertFlags=errFlags;
00760 
00761   return 0;
00762 }
00763 
00764 
00765 
00766 ssize_t GWEN_Io_LayerTls_Pull(gnutls_transport_ptr_t p, void *buf, size_t len) {
00767   GWEN_IO_LAYER *io;
00768   GWEN_IO_LAYER_TLS *xio;
00769   int rv;
00770 
00771   io=(GWEN_IO_LAYER*) p;
00772   assert(io);
00773   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00774   assert(xio);
00775 
00776   DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: %d bytes", (int)len);
00777   rv=GWEN_Io_LayerCodec_EnsureReadOk(io);
00778   if (rv) {
00779     if (rv==GWEN_ERROR_TRY_AGAIN || rv==GWEN_ERROR_IN_PROGRESS) {
00780 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00781       gnutls_transport_set_errno(xio->session, EAGAIN);
00782 #else
00783       errno=EAGAIN;
00784 #endif
00785       return (ssize_t)-1;
00786     }
00787     else {
00788       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00789 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00790       gnutls_transport_set_errno(xio->session, EINVAL);
00791 #else
00792       errno=EINVAL;
00793 #endif
00794       return (ssize_t)-1;
00795     }
00796   }
00797   else {
00798     GWEN_RINGBUFFER *rbuf;
00799     uint32_t maxBytes;
00800     const uint8_t *src;
00801 
00802     rbuf=GWEN_Io_LayerCodec_GetReadBuffer(io);
00803     assert(buf);
00804     maxBytes=GWEN_RingBuffer_GetMaxUnsegmentedRead(rbuf);
00805     if (maxBytes>len)
00806       maxBytes=len;
00807     src=(const uint8_t*)GWEN_RingBuffer_GetReadPointer(rbuf);
00808     if (maxBytes) {
00809       memmove(buf, src, maxBytes);
00810       GWEN_RingBuffer_SkipBytesRead(rbuf, maxBytes);
00811     }
00812     else {
00813       DBG_DEBUG(GWEN_LOGDOMAIN, "End of stream reached.");
00814     }
00815 
00816 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00817     gnutls_transport_set_errno(xio->session, 0);
00818 #else
00819     errno=0;
00820 #endif
00821     DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: returning %d bytes", maxBytes);
00822     /*GWEN_Text_DumpString(buf, maxBytes, stderr, 2);*/
00823     return maxBytes;
00824   }
00825 }
00826 
00827 
00828 
00829 ssize_t GWEN_Io_LayerTls_Push(gnutls_transport_ptr_t p, const void *buf, size_t len) {
00830   GWEN_IO_LAYER *io;
00831   GWEN_IO_LAYER_TLS *xio;
00832   int rv;
00833 
00834   io=(GWEN_IO_LAYER*) p;
00835   assert(io);
00836   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00837   assert(xio);
00838 
00839   DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: %d bytes", (int)len);
00840   /*GWEN_Text_DumpString(buf, len, stderr, 2);*/
00841 
00842   rv=GWEN_Io_LayerCodec_CheckWriteOut(io);
00843   if (rv) {
00844     if (rv==GWEN_ERROR_TRY_AGAIN || rv==GWEN_ERROR_IN_PROGRESS) {
00845       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00846 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00847       gnutls_transport_set_errno(xio->session, EAGAIN);
00848 #else
00849       errno=EAGAIN;
00850 #endif
00851       return (ssize_t)-1;
00852     }
00853     else {
00854       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00855 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00856       gnutls_transport_set_errno(xio->session, EINVAL);
00857 #else
00858       errno=EINVAL;
00859 #endif
00860       return (ssize_t)-1;
00861     }
00862   }
00863   else {
00864     GWEN_RINGBUFFER *rbuf;
00865     uint32_t maxBytes;
00866     uint8_t *dst;
00867     uint32_t guiid=0;
00868 
00869     if (xio->connectRequest)
00870       guiid=GWEN_Io_Request_GetGuiId(xio->connectRequest);
00871     else if (xio->connectRequest)
00872       guiid=GWEN_Io_Request_GetGuiId(xio->disconnectRequest);
00873 
00874     rbuf=GWEN_Io_LayerCodec_GetWriteBuffer(io);
00875     assert(rbuf);
00876     maxBytes=GWEN_RingBuffer_GetMaxUnsegmentedWrite(rbuf);
00877     if (maxBytes>len)
00878       maxBytes=len;
00879     dst=(uint8_t*)GWEN_RingBuffer_GetWritePointer(rbuf);
00880     if (maxBytes) {
00881       memmove(dst, buf, maxBytes);
00882       GWEN_RingBuffer_SkipBytesWrite(rbuf, maxBytes);
00883     }
00884 
00885 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00886     gnutls_transport_set_errno(xio->session, 0);
00887 #else
00888     errno=0;
00889 #endif
00890     DBG_DEBUG(GWEN_LOGDOMAIN, "TLS PUSH: written %d bytes", maxBytes);
00891     return maxBytes;
00892   }
00893 }
00894 
00895 
00896 
00897 int GWEN_Io_LayerTls_Encode(GWEN_IO_LAYER *io, const uint8_t *pBuffer, uint32_t lBuffer) {
00898   GWEN_IO_LAYER_TLS *xio;
00899   ssize_t rv;
00900 
00901   assert(io);
00902   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00903   assert(xio);
00904 
00905   rv=gnutls_record_send(xio->session, pBuffer, lBuffer);
00906   if (rv<0) {
00907     if (rv==GNUTLS_E_AGAIN)
00908       return GWEN_ERROR_TRY_AGAIN;
00909     else if (rv==GNUTLS_E_INTERRUPTED)
00910       return GWEN_ERROR_INTERRUPTED;
00911     else {
00912       DBG_ERROR(GWEN_LOGDOMAIN,
00913                 "gnutls_record_send: %d (%s) [encoding %d bytes]",
00914                 (int)rv, gnutls_strerror(rv), lBuffer);
00915       return GWEN_ERROR_IO;
00916     }
00917   }
00918 #ifdef DEBUG_TLS
00919   else {
00920     DBG_ERROR(0, "Sent this:");
00921     GWEN_Text_DumpString((const char*)pBuffer, rv,
00922                          stderr, 2);
00923   }
00924 #endif
00925   return rv;
00926 }
00927 
00928 
00929 
00930 int GWEN_Io_LayerTls_Decode(GWEN_IO_LAYER *io, uint8_t *pBuffer, uint32_t lBuffer) {
00931   GWEN_IO_LAYER_TLS *xio;
00932   ssize_t rv;
00933 
00934   assert(io);
00935   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00936   assert(xio);
00937 
00938   rv=gnutls_record_recv(xio->session, pBuffer, lBuffer);
00939   if (rv<0) {
00940     if (rv==GNUTLS_E_AGAIN)
00941       return GWEN_ERROR_TRY_AGAIN;
00942     else if (rv==GNUTLS_E_INTERRUPTED)
00943       return GWEN_ERROR_INTERRUPTED;
00944     else if (rv==GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
00945       DBG_DEBUG(GWEN_LOGDOMAIN,
00946                 "Unexpected packet length, assuming EOF met");
00947       return GWEN_ERROR_EOF;
00948     }
00949     else {
00950       DBG_ERROR(GWEN_LOGDOMAIN,
00951                 "gnutls_record_recv: %d (%s) [decoding %d bytes]",
00952                 (int)rv, gnutls_strerror(rv), lBuffer);
00953       return GWEN_ERROR_IO;
00954     }
00955   }
00956   else if (rv==0) {
00957     DBG_INFO(GWEN_LOGDOMAIN, "EOF met");
00958     return GWEN_ERROR_EOF;
00959   }
00960 #ifdef DEBUG_TLS
00961   else {
00962     DBG_ERROR(0, "Received this:");
00963     GWEN_Text_DumpString((const char*)pBuffer, rv,
00964                          stderr, 2);
00965   }
00966 #endif
00967 
00968   return rv;
00969 }
00970 
00971 
00972 
00973 int GWEN_Io_LayerTls_AddRequest(GWEN_IO_LAYER *io, GWEN_IO_REQUEST *r) {
00974   GWEN_IO_LAYER_TLS *xio;
00975   GWEN_IO_LAYER_STATUS st;
00976   uint32_t lflags;
00977 
00978   assert(io);
00979   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00980   assert(xio);
00981 
00982   st=GWEN_Io_Layer_GetStatus(io);
00983   lflags=GWEN_Io_Layer_GetFlags(io);
00984 
00985   switch(GWEN_Io_Request_GetType(r)) {
00986   case GWEN_Io_Request_TypeConnect:
00987     /* check status */
00988     if (st!=GWEN_Io_Layer_StatusUnconnected &&
00989         st!=GWEN_Io_Layer_StatusDisconnected) {
00990       DBG_INFO(GWEN_LOGDOMAIN, "Socket is not open");
00991       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_INVALID);
00992       return GWEN_ERROR_NOT_OPEN;
00993     }
00994 
00995     /* check whether we already have a read request */
00996     if (xio->connectRequest) {
00997       DBG_INFO(GWEN_LOGDOMAIN, "There already is a connect request");
00998       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_IN_PROGRESS);
00999       return GWEN_ERROR_IN_PROGRESS;
01000     }
01001     else {
01002       /* prepare structures if necessary */
01003       GWEN_Io_LayerCodec_Reset(io);
01004       if (xio->prepared==0) {
01005         int rv;
01006 
01007         rv=GWEN_Io_LayerTls_Prepare(io);
01008         if (rv) {
01009           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, rv);
01010           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01011           return rv;
01012         }
01013       }
01014 
01015       /* enqueue request */
01016       xio->connectRequest=r;
01017       GWEN_Io_Request_Attach(xio->connectRequest);
01018       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusConnecting);
01019     }
01020     break;
01021 
01022   case GWEN_Io_Request_TypeDisconnect:
01023     /* check status */
01024     if (st!=GWEN_Io_Layer_StatusConnected) {
01025       DBG_INFO(GWEN_LOGDOMAIN, "File is not open");
01026       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_OPEN);
01027       GWEN_Io_LayerCodec_Reset(io);
01028       return GWEN_ERROR_NOT_OPEN;
01029     }
01030     else {
01031       /* enqueue request */
01032       xio->disconnectRequest=r;
01033       GWEN_Io_Request_Attach(xio->disconnectRequest);
01034       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnecting);
01035     }
01036     break;
01037 
01038   default:
01039     if (xio->addRequestFn)
01040       return xio->addRequestFn(io, r);
01041     else {
01042       DBG_INFO(GWEN_LOGDOMAIN, "This request type is not supported (%d)", GWEN_Io_Request_GetType(r));
01043       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_SUPPORTED);
01044       return GWEN_ERROR_NOT_SUPPORTED;
01045     }
01046   }
01047 
01048   return 0;
01049 }
01050 
01051 
01052 
01053 int GWEN_Io_LayerTls_DelRequest(GWEN_IO_LAYER *io, GWEN_IO_REQUEST *r) {
01054   GWEN_IO_LAYER_TLS *xio;
01055 
01056   assert(io);
01057   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
01058   assert(xio);
01059 
01060   switch(GWEN_Io_Request_GetType(r)) {
01061   case GWEN_Io_Request_TypeConnect:
01062     if (xio->connectRequest==r) {
01063       DBG_DEBUG(GWEN_LOGDOMAIN, "Aborted connect request");
01064       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01065       GWEN_Io_LayerCodec_AbortRequests(io, GWEN_ERROR_ABORTED);
01066       xio->connectRequest=NULL;
01067       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
01068       GWEN_Io_Request_free(r);
01069       if (xio->prepared) {
01070         gnutls_deinit(xio->session);
01071         gnutls_certificate_free_credentials(xio->credentials);
01072         xio->prepared=0;
01073       }
01074     }
01075     else {
01076       /* not my request */
01077       DBG_INFO(GWEN_LOGDOMAIN, "Connect request not registered with this io layer");
01078       return GWEN_ERROR_INVALID;
01079     }
01080     break;
01081 
01082   case GWEN_Io_Request_TypeDisconnect:
01083     if (xio->disconnectRequest==r) {
01084       DBG_DEBUG(GWEN_LOGDOMAIN, "Aborted disconnect request");
01085 
01086       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01087       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
01088       GWEN_Io_Request_free(r);
01089     }
01090     else {
01091       /* not my request */
01092       DBG_INFO(GWEN_LOGDOMAIN, "Disconnect request not registered with this io layer");
01093       return GWEN_ERROR_INVALID;
01094     }
01095     break;
01096 
01097   default:
01098     if (xio->delRequestFn)
01099       return xio->delRequestFn(io, r);
01100     else {
01101       DBG_INFO(GWEN_LOGDOMAIN, "This request type is not supported (%d)", GWEN_Io_Request_GetType(r));
01102       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_SUPPORTED);
01103       return GWEN_ERROR_NOT_SUPPORTED;
01104     }
01105   }
01106 
01107   return 0;
01108 }
01109 
01110 
01111 
01112 int GWEN_Io_LayerTls_HasWaitingRequests(GWEN_IO_LAYER *io) {
01113   GWEN_IO_LAYER_TLS *xio;
01114 
01115   assert(io);
01116   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
01117   assert(xio);
01118 
01119   if (xio->waitingForGui)
01120     return 0;
01121 
01122   if (xio->connectRequest || xio->disconnectRequest)
01123     return 1;
01124   if (xio->hasWaitingRequestsFn)
01125     return xio->hasWaitingRequestsFn(io);
01126 
01127   return 0;
01128 }
01129 
01130 
01131 
01132 GWEN_IO_LAYER_WORKRESULT GWEN_Io_LayerTls_WorkOnRequests(GWEN_IO_LAYER *io) {
01133   GWEN_IO_LAYER_TLS *xio;
01134   int doneSomething=0;
01135 
01136   assert(io);
01137   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
01138   assert(xio);
01139 
01140   if (xio->waitingForGui)
01141     /* this worker is waiting for GUI, don't actually work here */
01142     return GWEN_Io_Layer_WorkResultBlocking;
01143 
01144   /* work on connect request */
01145   if (xio->connectRequest) {
01146     GWEN_IO_REQUEST *r;
01147     int rv;
01148 
01149     r=xio->connectRequest;
01150     GWEN_Io_LayerCodec_SetCurrentGuiId(io, GWEN_Io_Request_GetGuiId(r));
01151     rv=gnutls_handshake(xio->session);
01152     if (rv<0) {
01153       if (rv!=GNUTLS_E_AGAIN &&
01154           rv!=GNUTLS_E_INTERRUPTED) {
01155         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_handshake: %d (%s) [%s]",
01156                   rv, gnutls_strerror(rv), gnutls_error_is_fatal(rv)?"fatal":"non-fatal");
01157         if (rv==GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
01158           GWEN_Gui_ProgressLog(GWEN_Io_Request_GetGuiId(r),
01159                                GWEN_LoggerLevel_Error,
01160                                I18N("A TLS handshake error occurred. "
01161                                     "If you are using AqBanking you should "
01162                                     "consider enabling the option "
01163                                     "\"force SSLv3\" in the user settings "
01164                                     "dialog."));
01165         }
01166         else {
01167           GWEN_BUFFER *tbuf;
01168           char numbuf[32];
01169 
01170           tbuf=GWEN_Buffer_new(0, 256, 0, 1);
01171           GWEN_Buffer_AppendString(tbuf, I18N("TLS Handshake Error:"));
01172           snprintf(numbuf, sizeof(numbuf)-1, " %d ", rv);
01173           GWEN_Buffer_AppendString(tbuf, numbuf);
01174           GWEN_Buffer_AppendString(tbuf, "(");
01175           GWEN_Buffer_AppendString(tbuf, gnutls_strerror(rv));
01176           GWEN_Buffer_AppendString(tbuf, ")");
01177           GWEN_Gui_ProgressLog(GWEN_Io_Request_GetGuiId(r),
01178                                GWEN_LoggerLevel_Error,
01179                                GWEN_Buffer_GetStart(tbuf));
01180           GWEN_Buffer_free(tbuf);
01181         }
01182         GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01183         xio->connectRequest=NULL;
01184         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL);
01185         GWEN_Io_Request_free(r);
01186         if (xio->prepared) {
01187           gnutls_deinit(xio->session);
01188           gnutls_certificate_free_credentials(xio->credentials);
01189           xio->prepared=0;
01190         }
01191         doneSomething=1;
01192       }
01193     }
01194     else {
01195       /* check certificate */
01196       doneSomething=1;
01197       GWEN_Io_Layer_SubFlags(io, GWEN_IO_LAYER_TLS_FLAGS_SECURE);
01198       rv=GWEN_Io_LayerTls_GetPeerCert(io, GWEN_Io_Request_GetGuiId(r));
01199       if (rv) {
01200         if (GWEN_Io_Layer_GetFlags(io) & GWEN_IO_LAYER_TLS_FLAGS_NEED_PEER_CERT) {
01201           DBG_INFO(GWEN_LOGDOMAIN, "No peer certificate when needed, aborting connection");
01202           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01203           xio->connectRequest=NULL;
01204           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL_SECURITY);
01205           GWEN_Io_Request_free(r);
01206           if (xio->prepared) {
01207             gnutls_deinit(xio->session);
01208             gnutls_certificate_free_credentials(xio->credentials);
01209             xio->prepared=0;
01210           }
01211         }
01212         else {
01213           DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (insecure)");
01214           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusConnected);
01215           xio->connectRequest=NULL;
01216           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
01217           GWEN_Io_Request_free(r);
01218         }
01219       }
01220       else {
01221           /* present cert to the user */
01222         xio->waitingForGui=1;
01223         rv=GWEN_Gui_CheckCert(xio->peerCertDescr, io, GWEN_Io_Request_GetGuiId(r));
01224         xio->waitingForGui=0;
01225         if (rv) {
01226           DBG_INFO(GWEN_LOGDOMAIN, "Peer cert not accepted (%d), aborting", rv);
01227           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01228           xio->connectRequest=NULL;
01229           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL_SECURITY);
01230           GWEN_Io_Request_free(r);
01231           if (xio->prepared) {
01232             gnutls_deinit(xio->session);
01233             gnutls_certificate_free_credentials(xio->credentials);
01234             xio->prepared=0;
01235           }
01236         }
01237         else {
01238           DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (secure)");
01239           GWEN_Io_Layer_AddFlags(io, GWEN_IO_LAYER_TLS_FLAGS_SECURE);
01240           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusConnected);
01241           xio->connectRequest=NULL;
01242           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
01243           GWEN_Io_Request_free(r);
01244         }
01245       }
01246     }
01247   }
01248   if (xio->disconnectRequest) {
01249     GWEN_IO_REQUEST *r;
01250     int rv;
01251 
01252     r=xio->disconnectRequest;
01253     GWEN_Io_LayerCodec_SetCurrentGuiId(io, GWEN_Io_Request_GetGuiId(r));
01254     rv=gnutls_bye(xio->session, GNUTLS_SHUT_RDWR);
01255     if (rv<0) {
01256       if (rv!=GNUTLS_E_AGAIN &&
01257           rv!=GNUTLS_E_INTERRUPTED) {
01258         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_bye: %d (%s)", rv, gnutls_strerror(rv));
01259         GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01260         xio->disconnectRequest=NULL;
01261         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL);
01262         GWEN_Io_Request_free(r);
01263         GWEN_Io_LayerCodec_Reset(io);
01264         if (xio->prepared) {
01265           gnutls_deinit(xio->session);
01266           gnutls_certificate_free_credentials(xio->credentials);
01267           xio->prepared=0;
01268         }
01269         doneSomething=1;
01270       }
01271     }
01272     else {
01273       DBG_INFO(GWEN_LOGDOMAIN, "SSL disconnected");
01274       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01275       xio->disconnectRequest=NULL;
01276       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
01277       GWEN_Io_Request_free(r);
01278       GWEN_Io_LayerCodec_Reset(io);
01279       if (xio->prepared) {
01280         gnutls_deinit(xio->session);
01281         gnutls_certificate_free_credentials(xio->credentials);
01282         xio->prepared=0;
01283       }
01284       doneSomething=1;
01285     }
01286   }
01287 
01288   if (GWEN_Io_Layer_GetStatus(io)==GWEN_Io_Layer_StatusListening) {
01289     GWEN_IO_LAYER *newIo;
01290 
01291     newIo=GWEN_Io_Layer_GetNextIncomingLayer(GWEN_Io_Layer_GetBaseLayer(io));
01292     if (newIo) {
01293       GWEN_IO_LAYER *newNewIo;
01294       uint32_t fl;
01295 
01296       fl=GWEN_Io_Layer_GetFlags(io);
01297       newNewIo=GWEN_Io_LayerTls_new(newIo);
01298       GWEN_Io_Layer_AddFlags(newNewIo, GWEN_IO_LAYER_FLAGS_PASSIVE);
01299       GWEN_Io_Layer_AddFlags(newNewIo, fl & 0xffff);
01300       if (xio->localCertFile)
01301         GWEN_Io_LayerTls_SetLocalCertFile(newNewIo, xio->localCertFile);
01302       if (xio->localKeyFile)
01303         GWEN_Io_LayerTls_SetLocalKeyFile(newNewIo, xio->localKeyFile);
01304       if (xio->localTrustFile)
01305         GWEN_Io_LayerTls_SetLocalTrustFile(newNewIo, xio->localTrustFile);
01306       if (xio->dhParamFile)
01307         GWEN_Io_LayerTls_SetDhParamFile(newNewIo, xio->dhParamFile);
01308 
01309       if ((fl & GWEN_IO_LAYER_TLS_FLAGS_SET_PASSV_HOST_NAME) ||
01310           (fl & GWEN_IO_LAYER_TLS_FLAGS_SET_PASSV_HOST_IP)) {
01311         GWEN_IO_LAYER *sp;
01312 
01313         /* try to retrieve the address from socket io layer if there is any */
01314         sp=GWEN_Io_Layer_FindBaseLayerByType(newIo, GWEN_IO_LAYER_SOCKET_TYPE);
01315         if (sp) {
01316           GWEN_INETADDRESS *addr;
01317 
01318           addr=GWEN_Io_LayerSocket_GetPeerAddr(sp);
01319           if (addr) {
01320             char addrBuffer[128];
01321 
01322             if (fl & GWEN_IO_LAYER_TLS_FLAGS_SET_PASSV_HOST_NAME)
01323               GWEN_InetAddr_GetName(addr, addrBuffer, sizeof(addrBuffer)-1);
01324             else
01325               GWEN_InetAddr_GetAddress(addr, addrBuffer, sizeof(addrBuffer)-1);
01326             addrBuffer[sizeof(addrBuffer)-1]=0;
01327             if (*addrBuffer) {
01328               DBG_INFO(GWEN_LOGDOMAIN, "Setting remote addr to [%s]", addrBuffer);
01329               GWEN_Io_LayerTls_SetRemoteHostName(newNewIo, addrBuffer);
01330             }
01331           }
01332         }
01333       }
01334 
01335       GWEN_Io_Layer_AddIncomingLayer(io, newNewIo);
01336       doneSomething=1;
01337     }
01338   }
01339 
01340   if (xio->workOnRequestsFn &&
01341       xio->workOnRequestsFn(io)!=GWEN_Io_Layer_WorkResultBlocking) {
01342     doneSomething=1;
01343   }
01344 
01345   return (doneSomething==0)?GWEN_Io_Layer_WorkResultBlocking:GWEN_Io_Layer_WorkResultOk;
01346 }
01347 
01348 
01349 
01350 
01351 
01352 
01353 
01354 
01355 
01356 
01357 
01358 
01359 
01360 
01361 
01362 
01363 
01364 

Generated on Sat Jan 2 09:32:35 2010 for gwenhywfar by  doxygen 1.6.1