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     rv=gnutls_protocol_set_priority(xio->session, proto_prio);
00314     if (rv) {
00315       DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_protocol_set_priority: %d (%s)", rv, gnutls_strerror(rv));
00316       gnutls_deinit(xio->session);
00317       return GWEN_ERROR_GENERIC;
00318     }
00319   }
00320 
00321   /* protect against too-many-known-ca problem */
00322   gnutls_handshake_set_max_packet_length(xio->session, 64*1024);
00323 
00324   /* let a server request peer certs */
00325   if ((lflags & GWEN_IO_LAYER_FLAGS_PASSIVE) &&
00326       (lflags & GWEN_IO_LAYER_TLS_FLAGS_REQUEST_CERT))
00327     gnutls_certificate_server_set_request(xio->session, GNUTLS_CERT_REQUIRE);
00328 
00329   /* prepare cert credentials */
00330   rv=gnutls_certificate_allocate_credentials(&xio->credentials);
00331   if (rv) {
00332     DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_allocate_credentials: %d (%s)", rv, gnutls_strerror(rv));
00333     gnutls_deinit(xio->session);
00334     return GWEN_ERROR_GENERIC;
00335   }
00336 
00337   /* possibly set key file and cert file */
00338   if (xio->localCertFile && xio->localKeyFile) {
00339     rv=gnutls_certificate_set_x509_key_file(xio->credentials,
00340                                             xio->localCertFile,
00341                                             xio->localKeyFile,
00342                                             GNUTLS_X509_FMT_PEM);
00343     if (rv<0) {
00344       if (rv) {
00345         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_key_file: %d (%s)", rv, gnutls_strerror(rv));
00346         gnutls_certificate_free_credentials(xio->credentials);
00347         gnutls_deinit(xio->session);
00348         return GWEN_ERROR_GENERIC;
00349       }
00350     }
00351   }
00352 
00353   /* find default trust file if none is selected */
00354   if (lflags & GWEN_IO_LAYER_TLS_FLAGS_ADD_TRUSTED_CAS) {
00355     GWEN_STRINGLIST *paths;
00356 
00357     /* try to find out trust file */
00358     paths=GWEN_PathManager_GetPaths(GWEN_PM_LIBNAME, GWEN_PM_DATADIR);
00359     if (paths) {
00360       GWEN_BUFFER *nbuf;
00361 
00362       nbuf=GWEN_Buffer_new(0, 256, 0, 1);
00363       rv=GWEN_Directory_FindFileInPaths(paths,
00364                                         "ca-bundle.crt",
00365                                         nbuf);
00366       GWEN_StringList_free(paths);
00367       if (rv==0) {
00368         DBG_INFO(GWEN_LOGDOMAIN,
00369                  "Using default ca-bundle from [%s]",
00370                  GWEN_Buffer_GetStart(nbuf));
00371         GWEN_Io_LayerTls_SetLocalTrustFile(io, GWEN_Buffer_GetStart(nbuf));
00372       }
00373       else {
00374         DBG_WARN(GWEN_LOGDOMAIN, "Default bundle file not found");
00375       }
00376       GWEN_Buffer_free(nbuf);
00377     }
00378   }
00379 
00380   /* possibly set trust file */
00381   if (xio->localTrustFile) {
00382     rv=gnutls_certificate_set_x509_trust_file(xio->credentials,
00383                                               xio->localTrustFile,
00384                                               GNUTLS_X509_FMT_PEM);
00385     if (rv<=0) {
00386       DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_trust_file: %d (%s)", rv, gnutls_strerror(rv));
00387       gnutls_certificate_free_credentials(xio->credentials);
00388       gnutls_deinit(xio->session);
00389       return GWEN_ERROR_GENERIC;
00390     }
00391     else {
00392       DBG_INFO(GWEN_LOGDOMAIN,
00393                "Added %d trusted certs", rv);
00394     }
00395   }
00396 
00397   /* possibly set DH params */
00398   if (xio->dhParamFile) {
00399     GWEN_BUFFER *dbuf;
00400 
00401     dbuf=GWEN_Buffer_new(0, 256, 0, 1);
00402     rv=GWEN_Io_LayerTls__readFile(xio->dhParamFile, dbuf);
00403     if (rv) {
00404       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00405       GWEN_Buffer_free(dbuf);
00406       gnutls_certificate_free_credentials(xio->credentials);
00407       gnutls_deinit(xio->session);
00408       return rv;
00409     }
00410     else {
00411       gnutls_datum d;
00412       gnutls_dh_params dh_params=NULL;
00413 
00414       rv=gnutls_dh_params_init(&dh_params);
00415       if (rv<0) {
00416         GWEN_Buffer_free(dbuf);
00417         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_init: %d (%s)", rv, gnutls_strerror(rv));
00418         gnutls_certificate_free_credentials(xio->credentials);
00419         gnutls_deinit(xio->session);
00420         return GWEN_ERROR_GENERIC;
00421       }
00422 
00423       d.size=GWEN_Buffer_GetUsedBytes(dbuf);
00424       d.data=(unsigned char*)GWEN_Buffer_GetStart(dbuf);
00425 
00426       rv=gnutls_dh_params_import_pkcs3(dh_params, &d, GNUTLS_X509_FMT_PEM);
00427       if (rv<0) {
00428         GWEN_Buffer_free(dbuf);
00429         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_import_pkcs3: %d (%s)", rv, gnutls_strerror(rv));
00430         gnutls_certificate_free_credentials(xio->credentials);
00431         gnutls_deinit(xio->session);
00432         return GWEN_ERROR_GENERIC;
00433       }
00434       GWEN_Buffer_free(dbuf);
00435 
00436       gnutls_certificate_set_dh_params(xio->credentials, dh_params);
00437     }
00438   }
00439 
00440   /* set credentials in TLS session */
00441   rv=gnutls_credentials_set(xio->session, GNUTLS_CRD_CERTIFICATE, xio->credentials);
00442   if (rv<0) {
00443     DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_credentials_set: %d (%s)", rv, gnutls_strerror(rv));
00444     gnutls_certificate_free_credentials(xio->credentials);
00445     gnutls_deinit(xio->session);
00446     return GWEN_ERROR_GENERIC;
00447   }
00448 
00449   /* we use our own push/pull functions */
00450   gnutls_transport_set_ptr(xio->session, (gnutls_transport_ptr_t)io);
00451   gnutls_transport_set_push_function(xio->session, GWEN_Io_LayerTls_Push);
00452   gnutls_transport_set_pull_function(xio->session, GWEN_Io_LayerTls_Pull);
00453   gnutls_transport_set_lowat(xio->session, 0);
00454 
00455   xio->prepared=1;
00456 
00457   return 0;
00458 }
00459 
00460 
00461 
00462 int GWEN_Io_LayerTls_GetPeerCert(GWEN_IO_LAYER *io, uint32_t guiid) {
00463   GWEN_IO_LAYER_TLS *xio;
00464   const gnutls_datum_t *cert_list;
00465   unsigned int cert_list_size;
00466   size_t size;
00467   GWEN_SSLCERTDESCR *certDescr;
00468   char buffer1[64];
00469   time_t t0;
00470   int rv;
00471   uint32_t lflags;
00472   uint32_t errFlags=0;
00473   int i;
00474   unsigned int status;
00475   GWEN_BUFFER *sbuf=NULL;
00476 
00477   assert(io);
00478   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00479   assert(xio);
00480 
00481   lflags=GWEN_Io_Layer_GetFlags(io);
00482 
00483   if (xio->peerCertDescr) {
00484     GWEN_SslCertDescr_free(xio->peerCertDescr);
00485     xio->peerCertDescr=NULL;
00486   }
00487   xio->peerCertFlags=0;
00488 
00489   t0=time(NULL);
00490   if (t0<0) {
00491     DBG_WARN(GWEN_LOGDOMAIN, "Could not get system time");
00492     errFlags|=GWEN_SSL_CERT_FLAGS_SYSTEM;
00493   }
00494 
00495   /* create new cert description, check cert on the fly */
00496   certDescr=GWEN_SslCertDescr_new();
00497 
00498   /* some general tests */
00499   if (lflags & GWEN_IO_LAYER_TLS_FLAGS_ALLOW_V1_CA_CRT)
00500     gnutls_certificate_set_verify_flags(xio->credentials,
00501                                         GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
00502 
00503   rv=gnutls_certificate_verify_peers2(xio->session, &status);
00504   if (rv<0) {
00505     DBG_INFO(GWEN_LOGDOMAIN, "gnutls_certificate_verify_peers2: %d (%s)", rv, gnutls_strerror(rv));
00506     GWEN_SslCertDescr_free(certDescr);
00507     return GWEN_ERROR_SSL_SECURITY;
00508   }
00509 
00510   if (gnutls_certificate_type_get(xio->session)!=GNUTLS_CRT_X509) {
00511     DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not X.509");
00512 
00513     GWEN_SslCertDescr_free(certDescr);
00514     return GWEN_ERROR_SSL_SECURITY;
00515   }
00516 
00517   if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
00518     DBG_INFO(GWEN_LOGDOMAIN, "Signer not found");
00519     GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00520                          I18N("Signer not found"));
00521     errFlags|=GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND;
00522   }
00523 
00524   if (status & GNUTLS_CERT_INVALID) {
00525     DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not trusted");
00526     GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00527                          I18N("Certificate is not trusted"));
00528     errFlags|=GWEN_SSL_CERT_FLAGS_INVALID;
00529   }
00530 
00531   if (status & GNUTLS_CERT_REVOKED) {
00532     DBG_INFO(GWEN_LOGDOMAIN, "Certificate has been revoked");
00533     GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00534                          I18N("Certificate has been revoked"));
00535     errFlags|=GWEN_SSL_CERT_FLAGS_REVOKED;
00536   }
00537 
00538   cert_list=gnutls_certificate_get_peers(xio->session, &cert_list_size);
00539   if (cert_list==NULL || cert_list_size==0) {
00540     DBG_INFO(GWEN_LOGDOMAIN, "No peer certificates found");
00541     return GWEN_ERROR_NO_DATA;
00542   }
00543 
00544   for (i=0; i<cert_list_size; i++) {
00545     gnutls_x509_crt_t cert;
00546     time_t t;
00547 
00548     rv=gnutls_x509_crt_init(&cert);
00549     if (rv!=0) {
00550       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_init: %d (%s)", rv, gnutls_strerror(rv));
00551       return GWEN_ERROR_GENERIC;
00552     }
00553 
00554     rv=gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
00555     if (rv!=0) {
00556       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_import: %d (%s)", rv, gnutls_strerror(rv));
00557       gnutls_x509_crt_deinit(cert);
00558       return GWEN_ERROR_GENERIC;
00559     }
00560 
00561     if (i==0) {
00562       /* get fingerprint */
00563       size=16;
00564       rv=gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, buffer1, &size);
00565       if (rv!=0) {
00566         DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_fingerprint: %d (%s)", rv, gnutls_strerror(rv));
00567         GWEN_SslCertDescr_free(certDescr);
00568         gnutls_x509_crt_deinit(cert);
00569         return GWEN_ERROR_GENERIC;
00570       }
00571       else {
00572         GWEN_BUFFER *dbuf;
00573 
00574         dbuf=GWEN_Buffer_new(0, 256, 0, 1);
00575         if (GWEN_Text_ToHexBuffer(/* GCC4 pointer-signedness fix: */ buffer1,
00576                                   size, dbuf, 2, ':', 0)) {
00577           DBG_ERROR(GWEN_LOGDOMAIN,
00578                     "Could not convert fingerprint to hex");
00579         }
00580         else {
00581           GWEN_SslCertDescr_SetFingerPrint(certDescr, GWEN_Buffer_GetStart(dbuf));
00582         }
00583         GWEN_Buffer_free(dbuf);
00584       }
00585 
00586       if (xio->hostName) {
00587         DBG_INFO(GWEN_LOGDOMAIN, "Checking hostname [%s]", xio->hostName);
00588         if (!gnutls_x509_crt_check_hostname(cert, xio->hostName)) {
00589           DBG_WARN(GWEN_LOGDOMAIN,
00590                    "Certificate was not issued for this host");
00591           GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00592                                I18N("Certificate was not issued for this host"));
00593           errFlags|=GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME;
00594         }
00595         else {
00596           DBG_INFO(GWEN_LOGDOMAIN, "Cert is for this server");
00597         }
00598       }
00599       else {
00600         DBG_WARN(GWEN_LOGDOMAIN,
00601                  "Hostname is not set, unable to verify the sender");
00602         GWEN_Gui_ProgressLog(guiid, GWEN_LoggerLevel_Warning,
00603                              I18N("No hostname to verify the sender!"));
00604       }
00605 
00606     }
00607 
00608     /* get activation time */
00609     t=gnutls_x509_crt_get_activation_time(cert);
00610     if (t<0) {
00611       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_activation_time: %d (%s)", rv, gnutls_strerror(rv));
00612       errFlags|=GWEN_SSL_CERT_FLAGS_BAD_DATA;
00613     }
00614     else {
00615       if (t>t0) {
00616         DBG_INFO(GWEN_LOGDOMAIN, "Cert is not yet active");
00617         errFlags|=GWEN_SSL_CERT_FLAGS_NOT_ACTIVE;
00618       }
00619       if (i==0) {
00620         GWEN_TIME *ti;
00621 
00622         ti=GWEN_Time_fromSeconds(t);
00623         if (ti)
00624           GWEN_SslCertDescr_SetNotBefore(certDescr, ti);
00625         GWEN_Time_free(ti);
00626       }
00627     }
00628 
00629     /* get expiration time */
00630     t=gnutls_x509_crt_get_expiration_time(cert);
00631     if (t<0) {
00632       DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_expiration_time: %d (%s)", rv, gnutls_strerror(rv));
00633       errFlags|=GWEN_SSL_CERT_FLAGS_BAD_DATA;
00634     }
00635     else {
00636       if (t<t0) {
00637         DBG_INFO(GWEN_LOGDOMAIN, "Cert has expired");
00638         errFlags|=GWEN_SSL_CERT_FLAGS_EXPIRED;
00639       }
00640       if (i==0) {
00641         GWEN_TIME *ti;
00642 
00643         ti=GWEN_Time_fromSeconds(t);
00644         if (ti)
00645           GWEN_SslCertDescr_SetNotAfter(certDescr, ti);
00646         GWEN_Time_free(ti);
00647       }
00648     }
00649 
00650     if (i==0) {
00651       /* get owner information, but only for first cert */
00652       size=sizeof(buffer1)-1;
00653       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, buffer1, &size);
00654       if (rv==0) {
00655         GWEN_SslCertDescr_SetCommonName(certDescr, buffer1);
00656         if (xio->hostName && strcasecmp(xio->hostName, buffer1)!=0) {
00657           DBG_INFO(GWEN_LOGDOMAIN, "Owner of certificate does not match hostname");
00658           errFlags|=GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME;
00659         }
00660       }
00661 
00662       size=sizeof(buffer1)-1;
00663       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, buffer1, &size);
00664       if (rv==0)
00665         GWEN_SslCertDescr_SetOrganizationName(certDescr, buffer1);
00666 
00667       size=sizeof(buffer1)-1;
00668       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, buffer1, &size);
00669       if (rv==0)
00670         GWEN_SslCertDescr_SetOrganizationalUnitName(certDescr, buffer1);
00671 
00672       size=sizeof(buffer1)-1;
00673       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, buffer1, &size);
00674       if (rv==0)
00675         GWEN_SslCertDescr_SetLocalityName(certDescr, buffer1);
00676 
00677       size=sizeof(buffer1)-1;
00678       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, buffer1, &size);
00679       if (rv==0)
00680         GWEN_SslCertDescr_SetStateOrProvinceName(certDescr, buffer1);
00681 
00682       size=sizeof(buffer1)-1;
00683       rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, buffer1, &size);
00684       if (rv==0)
00685         GWEN_SslCertDescr_SetCountryName(certDescr, buffer1);
00686     }
00687 
00688     gnutls_x509_crt_deinit(cert);
00689   }
00690 
00691   /* done */
00692   if (errFlags)
00693     GWEN_SslCertDescr_SetIsError(certDescr, 1);
00694   else
00695     errFlags|=GWEN_SSL_CERT_FLAGS_OK;
00696 
00697   sbuf=GWEN_Buffer_new(0, 256, 0, 1);
00698 
00699   if (errFlags & GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND) {
00700     if (GWEN_Buffer_GetUsedBytes(sbuf))
00701       GWEN_Buffer_AppendString(sbuf, "; ");
00702     GWEN_Buffer_AppendString(sbuf, I18N("Signer not found"));
00703   }
00704 
00705   if (errFlags & GWEN_SSL_CERT_FLAGS_INVALID) {
00706     if (GWEN_Buffer_GetUsedBytes(sbuf))
00707       GWEN_Buffer_AppendString(sbuf, "; ");
00708     GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not trusted"));
00709   }
00710 
00711   if (errFlags & GWEN_SSL_CERT_FLAGS_REVOKED) {
00712     if (GWEN_Buffer_GetUsedBytes(sbuf))
00713       GWEN_Buffer_AppendString(sbuf, "; ");
00714     GWEN_Buffer_AppendString(sbuf, I18N("Certificate has been revoked"));
00715   }
00716 
00717   if (errFlags & GWEN_SSL_CERT_FLAGS_EXPIRED) {
00718     if (GWEN_Buffer_GetUsedBytes(sbuf))
00719       GWEN_Buffer_AppendString(sbuf, "; ");
00720     GWEN_Buffer_AppendString(sbuf, I18N("Certificate has expired"));
00721   }
00722 
00723   if (errFlags & GWEN_SSL_CERT_FLAGS_NOT_ACTIVE) {
00724     if (GWEN_Buffer_GetUsedBytes(sbuf))
00725       GWEN_Buffer_AppendString(sbuf, "; ");
00726     GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not active yet"));
00727   }
00728 
00729   if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME) {
00730     if (GWEN_Buffer_GetUsedBytes(sbuf))
00731       GWEN_Buffer_AppendString(sbuf, "; ");
00732     GWEN_Buffer_AppendString(sbuf, I18N("Certificate owner does not match hostname"));
00733   }
00734 
00735   if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_DATA) {
00736     if (GWEN_Buffer_GetUsedBytes(sbuf))
00737       GWEN_Buffer_AppendString(sbuf, "; ");
00738     GWEN_Buffer_AppendString(sbuf, I18N("Certificate contains invalid information"));
00739   }
00740 
00741   if (errFlags & GWEN_SSL_CERT_FLAGS_SYSTEM) {
00742     if (GWEN_Buffer_GetUsedBytes(sbuf))
00743       GWEN_Buffer_AppendString(sbuf, "; ");
00744     GWEN_Buffer_AppendString(sbuf, I18N("A system error occurred while checking the certificate"));
00745   }
00746 
00747   if (errFlags & GWEN_SSL_CERT_FLAGS_OK) {
00748     if (GWEN_Buffer_GetUsedBytes(sbuf))
00749       GWEN_Buffer_AppendString(sbuf, "; ");
00750     GWEN_Buffer_AppendString(sbuf, I18N("The certificate is valid"));
00751   }
00752 
00753   GWEN_SslCertDescr_SetStatusText(certDescr, GWEN_Buffer_GetStart(sbuf));
00754   GWEN_SslCertDescr_SetStatusFlags(certDescr, errFlags);
00755   GWEN_Buffer_free(sbuf);
00756 
00757   xio->peerCertDescr=certDescr;
00758   xio->peerCertFlags=errFlags;
00759 
00760   return 0;
00761 }
00762 
00763 
00764 
00765 ssize_t GWEN_Io_LayerTls_Pull(gnutls_transport_ptr_t p, void *buf, size_t len) {
00766   GWEN_IO_LAYER *io;
00767   GWEN_IO_LAYER_TLS *xio;
00768   int rv;
00769 
00770   io=(GWEN_IO_LAYER*) p;
00771   assert(io);
00772   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00773   assert(xio);
00774 
00775   DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: %d bytes", (int)len);
00776   rv=GWEN_Io_LayerCodec_EnsureReadOk(io);
00777   if (rv) {
00778     if (rv==GWEN_ERROR_TRY_AGAIN || rv==GWEN_ERROR_IN_PROGRESS) {
00779 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00780       gnutls_transport_set_errno(xio->session, EAGAIN);
00781 #else
00782       errno=EAGAIN;
00783 #endif
00784       return (ssize_t)-1;
00785     }
00786     else {
00787       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00788 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00789       gnutls_transport_set_errno(xio->session, EINVAL);
00790 #else
00791       errno=EINVAL;
00792 #endif
00793       return (ssize_t)-1;
00794     }
00795   }
00796   else {
00797     GWEN_RINGBUFFER *rbuf;
00798     uint32_t maxBytes;
00799     const uint8_t *src;
00800 
00801     rbuf=GWEN_Io_LayerCodec_GetReadBuffer(io);
00802     assert(buf);
00803     maxBytes=GWEN_RingBuffer_GetMaxUnsegmentedRead(rbuf);
00804     if (maxBytes>len)
00805       maxBytes=len;
00806     src=(const uint8_t*)GWEN_RingBuffer_GetReadPointer(rbuf);
00807     if (maxBytes) {
00808       memmove(buf, src, maxBytes);
00809       GWEN_RingBuffer_SkipBytesRead(rbuf, maxBytes);
00810     }
00811     else {
00812       DBG_DEBUG(GWEN_LOGDOMAIN, "End of stream reached.");
00813     }
00814 
00815 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00816     gnutls_transport_set_errno(xio->session, 0);
00817 #else
00818     errno=0;
00819 #endif
00820     DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: returning %d bytes", maxBytes);
00821     /*GWEN_Text_DumpString(buf, maxBytes, stderr, 2);*/
00822     return maxBytes;
00823   }
00824 }
00825 
00826 
00827 
00828 ssize_t GWEN_Io_LayerTls_Push(gnutls_transport_ptr_t p, const void *buf, size_t len) {
00829   GWEN_IO_LAYER *io;
00830   GWEN_IO_LAYER_TLS *xio;
00831   int rv;
00832 
00833   io=(GWEN_IO_LAYER*) p;
00834   assert(io);
00835   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00836   assert(xio);
00837 
00838   DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: %d bytes", (int)len);
00839   /*GWEN_Text_DumpString(buf, len, stderr, 2);*/
00840 
00841   rv=GWEN_Io_LayerCodec_CheckWriteOut(io);
00842   if (rv) {
00843     if (rv==GWEN_ERROR_TRY_AGAIN) {
00844       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00845 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00846       gnutls_transport_set_errno(xio->session, EAGAIN);
00847 #else
00848       errno=EAGAIN;
00849 #endif
00850       return (ssize_t)-1;
00851     }
00852     else {
00853       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00854 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00855       gnutls_transport_set_errno(xio->session, EINVAL);
00856 #else
00857       errno=EINVAL;
00858 #endif
00859       return (ssize_t)-1;
00860     }
00861   }
00862   else {
00863     GWEN_RINGBUFFER *rbuf;
00864     uint32_t maxBytes;
00865     uint8_t *dst;
00866     uint32_t guiid=0;
00867 
00868     if (xio->connectRequest)
00869       guiid=GWEN_Io_Request_GetGuiId(xio->connectRequest);
00870     else if (xio->connectRequest)
00871       guiid=GWEN_Io_Request_GetGuiId(xio->disconnectRequest);
00872 
00873     rbuf=GWEN_Io_LayerCodec_GetWriteBuffer(io);
00874     assert(rbuf);
00875     maxBytes=GWEN_RingBuffer_GetMaxUnsegmentedWrite(rbuf);
00876     if (maxBytes>len)
00877       maxBytes=len;
00878     dst=(uint8_t*)GWEN_RingBuffer_GetWritePointer(rbuf);
00879     if (maxBytes) {
00880       memmove(dst, buf, maxBytes);
00881       GWEN_RingBuffer_SkipBytesWrite(rbuf, maxBytes);
00882     }
00883 
00884 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00885     gnutls_transport_set_errno(xio->session, 0);
00886 #else
00887     errno=0;
00888 #endif
00889     DBG_DEBUG(GWEN_LOGDOMAIN, "TLS PUSH: written %d bytes", maxBytes);
00890     return maxBytes;
00891   }
00892 }
00893 
00894 
00895 
00896 int GWEN_Io_LayerTls_Encode(GWEN_IO_LAYER *io, const uint8_t *pBuffer, uint32_t lBuffer) {
00897   GWEN_IO_LAYER_TLS *xio;
00898   ssize_t rv;
00899 
00900   assert(io);
00901   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00902   assert(xio);
00903 
00904   rv=gnutls_record_send(xio->session, pBuffer, lBuffer);
00905   if (rv<0) {
00906     if (rv==GNUTLS_E_AGAIN)
00907       return GWEN_ERROR_TRY_AGAIN;
00908     else if (rv==GNUTLS_E_INTERRUPTED)
00909       return GWEN_ERROR_INTERRUPTED;
00910     else {
00911       DBG_ERROR(GWEN_LOGDOMAIN,
00912                 "gnutls_record_send: %d (%s) [encoding %d bytes]",
00913                 (int)rv, gnutls_strerror(rv), lBuffer);
00914       return GWEN_ERROR_IO;
00915     }
00916   }
00917 #ifdef DEBUG_TLS
00918   else {
00919     DBG_ERROR(0, "Sent this:");
00920     GWEN_Text_DumpString((const char*)pBuffer, rv,
00921                          stderr, 2);
00922   }
00923 #endif
00924   return rv;
00925 }
00926 
00927 
00928 
00929 int GWEN_Io_LayerTls_Decode(GWEN_IO_LAYER *io, uint8_t *pBuffer, uint32_t lBuffer) {
00930   GWEN_IO_LAYER_TLS *xio;
00931   ssize_t rv;
00932 
00933   assert(io);
00934   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00935   assert(xio);
00936 
00937   rv=gnutls_record_recv(xio->session, pBuffer, lBuffer);
00938   if (rv<0) {
00939     if (rv==GNUTLS_E_AGAIN)
00940       return GWEN_ERROR_TRY_AGAIN;
00941     else if (rv==GNUTLS_E_INTERRUPTED)
00942       return GWEN_ERROR_INTERRUPTED;
00943     else if (rv==GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
00944       DBG_DEBUG(GWEN_LOGDOMAIN,
00945                 "Unexpected packet length, assuming EOF met");
00946       return GWEN_ERROR_EOF;
00947     }
00948     else {
00949       DBG_ERROR(GWEN_LOGDOMAIN,
00950                 "gnutls_record_recv: %d (%s) [decoding %d bytes]",
00951                 (int)rv, gnutls_strerror(rv), lBuffer);
00952       return GWEN_ERROR_IO;
00953     }
00954   }
00955   else if (rv==0) {
00956     DBG_INFO(GWEN_LOGDOMAIN, "EOF met");
00957     return GWEN_ERROR_EOF;
00958   }
00959 #ifdef DEBUG_TLS
00960   else {
00961     DBG_ERROR(0, "Received this:");
00962     GWEN_Text_DumpString((const char*)pBuffer, rv,
00963                          stderr, 2);
00964   }
00965 #endif
00966 
00967   return rv;
00968 }
00969 
00970 
00971 
00972 int GWEN_Io_LayerTls_AddRequest(GWEN_IO_LAYER *io, GWEN_IO_REQUEST *r) {
00973   GWEN_IO_LAYER_TLS *xio;
00974   GWEN_IO_LAYER_STATUS st;
00975   uint32_t lflags;
00976 
00977   assert(io);
00978   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
00979   assert(xio);
00980 
00981   st=GWEN_Io_Layer_GetStatus(io);
00982   lflags=GWEN_Io_Layer_GetFlags(io);
00983 
00984   switch(GWEN_Io_Request_GetType(r)) {
00985   case GWEN_Io_Request_TypeConnect:
00986     /* check status */
00987     if (st!=GWEN_Io_Layer_StatusUnconnected &&
00988         st!=GWEN_Io_Layer_StatusDisconnected) {
00989       DBG_INFO(GWEN_LOGDOMAIN, "Socket is not open");
00990       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_INVALID);
00991       return GWEN_ERROR_NOT_OPEN;
00992     }
00993 
00994     /* check whether we already have a read request */
00995     if (xio->connectRequest) {
00996       DBG_INFO(GWEN_LOGDOMAIN, "There already is a connect request");
00997       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_IN_PROGRESS);
00998       return GWEN_ERROR_IN_PROGRESS;
00999     }
01000     else {
01001       /* prepare structures if necessary */
01002       GWEN_Io_LayerCodec_Reset(io);
01003       if (xio->prepared==0) {
01004         int rv;
01005 
01006         rv=GWEN_Io_LayerTls_Prepare(io);
01007         if (rv) {
01008           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, rv);
01009           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01010           return rv;
01011         }
01012       }
01013 
01014       /* enqueue request */
01015       xio->connectRequest=r;
01016       GWEN_Io_Request_Attach(xio->connectRequest);
01017       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusConnecting);
01018     }
01019     break;
01020 
01021   case GWEN_Io_Request_TypeDisconnect:
01022     /* check status */
01023     if (st!=GWEN_Io_Layer_StatusConnected) {
01024       DBG_INFO(GWEN_LOGDOMAIN, "File is not open");
01025       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_OPEN);
01026       GWEN_Io_LayerCodec_Reset(io);
01027       return GWEN_ERROR_NOT_OPEN;
01028     }
01029     else {
01030       /* enqueue request */
01031       xio->disconnectRequest=r;
01032       GWEN_Io_Request_Attach(xio->disconnectRequest);
01033       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnecting);
01034     }
01035     break;
01036 
01037   default:
01038     if (xio->addRequestFn)
01039       return xio->addRequestFn(io, r);
01040     else {
01041       DBG_INFO(GWEN_LOGDOMAIN, "This request type is not supported (%d)", GWEN_Io_Request_GetType(r));
01042       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_SUPPORTED);
01043       return GWEN_ERROR_NOT_SUPPORTED;
01044     }
01045   }
01046 
01047   return 0;
01048 }
01049 
01050 
01051 
01052 int GWEN_Io_LayerTls_DelRequest(GWEN_IO_LAYER *io, GWEN_IO_REQUEST *r) {
01053   GWEN_IO_LAYER_TLS *xio;
01054 
01055   assert(io);
01056   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
01057   assert(xio);
01058 
01059   switch(GWEN_Io_Request_GetType(r)) {
01060   case GWEN_Io_Request_TypeConnect:
01061     if (xio->connectRequest==r) {
01062       DBG_DEBUG(GWEN_LOGDOMAIN, "Aborted connect request");
01063       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01064       GWEN_Io_LayerCodec_AbortRequests(io, GWEN_ERROR_ABORTED);
01065       xio->connectRequest=NULL;
01066       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
01067       GWEN_Io_Request_free(r);
01068       if (xio->prepared) {
01069         gnutls_deinit(xio->session);
01070         gnutls_certificate_free_credentials(xio->credentials);
01071         xio->prepared=0;
01072       }
01073     }
01074     else {
01075       /* not my request */
01076       DBG_INFO(GWEN_LOGDOMAIN, "Connect request not registered with this io layer");
01077       return GWEN_ERROR_INVALID;
01078     }
01079     break;
01080 
01081   case GWEN_Io_Request_TypeDisconnect:
01082     if (xio->disconnectRequest==r) {
01083       DBG_DEBUG(GWEN_LOGDOMAIN, "Aborted connect request");
01084 
01085       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01086       if (xio->connectRequest) {
01087         GWEN_IO_REQUEST *r;
01088 
01089         r=xio->connectRequest;
01090         xio->connectRequest=NULL;
01091         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_ABORTED);
01092         GWEN_Io_Request_free(r);
01093       }
01094     }
01095     else {
01096       /* not my request */
01097       DBG_INFO(GWEN_LOGDOMAIN, "Disconnect request not registered with this io layer");
01098       return GWEN_ERROR_INVALID;
01099     }
01100     break;
01101 
01102   default:
01103     if (xio->delRequestFn)
01104       return xio->delRequestFn(io, r);
01105     else {
01106       DBG_INFO(GWEN_LOGDOMAIN, "This request type is not supported (%d)", GWEN_Io_Request_GetType(r));
01107       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_NOT_SUPPORTED);
01108       return GWEN_ERROR_NOT_SUPPORTED;
01109     }
01110   }
01111 
01112   return 0;
01113 }
01114 
01115 
01116 
01117 int GWEN_Io_LayerTls_HasWaitingRequests(GWEN_IO_LAYER *io) {
01118   GWEN_IO_LAYER_TLS *xio;
01119 
01120   assert(io);
01121   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
01122   assert(xio);
01123 
01124   if (xio->connectRequest || xio->disconnectRequest)
01125     return 1;
01126   if (xio->hasWaitingRequestsFn)
01127     return xio->hasWaitingRequestsFn(io);
01128 
01129   return 0;
01130 }
01131 
01132 
01133 
01134 GWEN_IO_LAYER_WORKRESULT GWEN_Io_LayerTls_WorkOnRequests(GWEN_IO_LAYER *io) {
01135   GWEN_IO_LAYER_TLS *xio;
01136   int doneSomething=0;
01137 
01138   assert(io);
01139   xio=GWEN_INHERIT_GETDATA(GWEN_IO_LAYER, GWEN_IO_LAYER_TLS, io);
01140   assert(xio);
01141 
01142   /* work on connect request */
01143   if (xio->connectRequest) {
01144     GWEN_IO_REQUEST *r;
01145     int rv;
01146 
01147     r=xio->connectRequest;
01148     GWEN_Io_LayerCodec_SetCurrentGuiId(io, GWEN_Io_Request_GetGuiId(r));
01149     rv=gnutls_handshake(xio->session);
01150     if (rv<0) {
01151       if (rv!=GNUTLS_E_AGAIN &&
01152           rv!=GNUTLS_E_INTERRUPTED) {
01153         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_handshake: %d (%s) [%s]",
01154                   rv, gnutls_strerror(rv), gnutls_error_is_fatal(rv)?"fatal":"non-fatal");
01155         GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01156         xio->connectRequest=NULL;
01157         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL);
01158         GWEN_Io_Request_free(r);
01159         if (xio->prepared) {
01160           gnutls_deinit(xio->session);
01161           gnutls_certificate_free_credentials(xio->credentials);
01162           xio->prepared=0;
01163         }
01164         doneSomething=1;
01165       }
01166     }
01167     else {
01168       /* check certificate */
01169       doneSomething=1;
01170       GWEN_Io_Layer_SubFlags(io, GWEN_IO_LAYER_TLS_FLAGS_SECURE);
01171       rv=GWEN_Io_LayerTls_GetPeerCert(io, GWEN_Io_Request_GetGuiId(r));
01172       if (rv) {
01173         if (GWEN_Io_Layer_GetFlags(io) & GWEN_IO_LAYER_TLS_FLAGS_NEED_PEER_CERT) {
01174           DBG_INFO(GWEN_LOGDOMAIN, "No peer certificate when needed, aborting connection");
01175           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01176           xio->connectRequest=NULL;
01177           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL_SECURITY);
01178           GWEN_Io_Request_free(r);
01179           if (xio->prepared) {
01180             gnutls_deinit(xio->session);
01181             gnutls_certificate_free_credentials(xio->credentials);
01182             xio->prepared=0;
01183           }
01184         }
01185         else {
01186           DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (insecure)");
01187           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusConnected);
01188           xio->connectRequest=NULL;
01189           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
01190           GWEN_Io_Request_free(r);
01191         }
01192       }
01193       else {
01194         /* present cert to the user */
01195         rv=GWEN_Gui_CheckCert(xio->peerCertDescr, io, GWEN_Io_Request_GetGuiId(r));
01196         if (rv) {
01197           DBG_INFO(GWEN_LOGDOMAIN, "Peer cert not accepted (%d), aborting", rv);
01198           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01199           xio->connectRequest=NULL;
01200           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL_SECURITY);
01201           GWEN_Io_Request_free(r);
01202           if (xio->prepared) {
01203             gnutls_deinit(xio->session);
01204             gnutls_certificate_free_credentials(xio->credentials);
01205             xio->prepared=0;
01206           }
01207         }
01208         else {
01209           DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (secure)");
01210           GWEN_Io_Layer_AddFlags(io, GWEN_IO_LAYER_TLS_FLAGS_SECURE);
01211           GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusConnected);
01212           xio->connectRequest=NULL;
01213           GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
01214           GWEN_Io_Request_free(r);
01215         }
01216       }
01217     }
01218   }
01219   if (xio->disconnectRequest) {
01220     GWEN_IO_REQUEST *r;
01221     int rv;
01222 
01223     r=xio->disconnectRequest;
01224     GWEN_Io_LayerCodec_SetCurrentGuiId(io, GWEN_Io_Request_GetGuiId(r));
01225     rv=gnutls_bye(xio->session, GNUTLS_SHUT_RDWR);
01226     if (rv<0) {
01227       if (rv!=GNUTLS_E_AGAIN &&
01228           rv!=GNUTLS_E_INTERRUPTED) {
01229         DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_bye: %d (%s)", rv, gnutls_strerror(rv));
01230         GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01231         xio->disconnectRequest=NULL;
01232         GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, GWEN_ERROR_SSL);
01233         GWEN_Io_Request_free(r);
01234         GWEN_Io_LayerCodec_Reset(io);
01235         if (xio->prepared) {
01236           gnutls_deinit(xio->session);
01237           gnutls_certificate_free_credentials(xio->credentials);
01238           xio->prepared=0;
01239         }
01240         doneSomething=1;
01241       }
01242     }
01243     else {
01244       DBG_INFO(GWEN_LOGDOMAIN, "SSL disconnected");
01245       GWEN_Io_Layer_SetStatus(io, GWEN_Io_Layer_StatusDisconnected);
01246       xio->disconnectRequest=NULL;
01247       GWEN_Io_Request_Finished(r, GWEN_Io_Request_StatusFinished, 0);
01248       GWEN_Io_Request_free(r);
01249       GWEN_Io_LayerCodec_Reset(io);
01250       if (xio->prepared) {
01251         gnutls_deinit(xio->session);
01252         gnutls_certificate_free_credentials(xio->credentials);
01253         xio->prepared=0;
01254       }
01255       doneSomething=1;
01256     }
01257   }
01258 
01259   if (GWEN_Io_Layer_GetStatus(io)==GWEN_Io_Layer_StatusListening) {
01260     GWEN_IO_LAYER *newIo;
01261 
01262     newIo=GWEN_Io_Layer_GetNextIncomingLayer(GWEN_Io_Layer_GetBaseLayer(io));
01263     if (newIo) {
01264       GWEN_IO_LAYER *newNewIo;
01265       uint32_t fl;
01266 
01267       fl=GWEN_Io_Layer_GetFlags(io);
01268       newNewIo=GWEN_Io_LayerTls_new(newIo);
01269       GWEN_Io_Layer_AddFlags(newNewIo, GWEN_IO_LAYER_FLAGS_PASSIVE);
01270       GWEN_Io_Layer_AddFlags(newNewIo, fl & 0xffff);
01271       if (xio->localCertFile)
01272         GWEN_Io_LayerTls_SetLocalCertFile(newNewIo, xio->localCertFile);
01273       if (xio->localKeyFile)
01274         GWEN_Io_LayerTls_SetLocalKeyFile(newNewIo, xio->localKeyFile);
01275       if (xio->localTrustFile)
01276         GWEN_Io_LayerTls_SetLocalTrustFile(newNewIo, xio->localTrustFile);
01277       if (xio->dhParamFile)
01278         GWEN_Io_LayerTls_SetDhParamFile(newNewIo, xio->dhParamFile);
01279 
01280       if ((fl & GWEN_IO_LAYER_TLS_FLAGS_SET_PASSV_HOST_NAME) ||
01281           (fl & GWEN_IO_LAYER_TLS_FLAGS_SET_PASSV_HOST_IP)) {
01282         GWEN_IO_LAYER *sp;
01283 
01284         /* try to retrieve the address from socket io layer if there is any */
01285         sp=GWEN_Io_Layer_FindBaseLayerByType(newIo, GWEN_IO_LAYER_SOCKET_TYPE);
01286         if (sp) {
01287           GWEN_INETADDRESS *addr;
01288 
01289           addr=GWEN_Io_LayerSocket_GetPeerAddr(sp);
01290           if (addr) {
01291             char addrBuffer[128];
01292 
01293             if (fl & GWEN_IO_LAYER_TLS_FLAGS_SET_PASSV_HOST_NAME)
01294               GWEN_InetAddr_GetName(addr, addrBuffer, sizeof(addrBuffer)-1);
01295             else
01296               GWEN_InetAddr_GetAddress(addr, addrBuffer, sizeof(addrBuffer)-1);
01297             addrBuffer[sizeof(addrBuffer)-1]=0;
01298             if (*addrBuffer) {
01299               DBG_INFO(GWEN_LOGDOMAIN, "Setting remote addr to [%s]", addrBuffer);
01300               GWEN_Io_LayerTls_SetRemoteHostName(newNewIo, addrBuffer);
01301             }
01302           }
01303         }
01304       }
01305 
01306       GWEN_Io_Layer_AddIncomingLayer(io, newNewIo);
01307       doneSomething=1;
01308     }
01309   }
01310 
01311   if (xio->workOnRequestsFn &&
01312       xio->workOnRequestsFn(io)!=GWEN_Io_Layer_WorkResultBlocking) {
01313     doneSomething=1;
01314   }
01315 
01316   return (doneSomething==0)?GWEN_Io_Layer_WorkResultBlocking:GWEN_Io_Layer_WorkResultOk;
01317 }
01318 
01319 
01320 
01321 
01322 
01323 
01324 
01325 
01326 
01327 
01328 
01329 
01330 
01331 
01332 
01333 
01334 
01335 

Generated on Wed Sep 3 15:21:58 2008 for gwenhywfar by  doxygen 1.5.6