00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029 #define DISABLE_DEBUGLOG
00030
00031
00032
00033
00034 #include "syncio_tls_p.h"
00035 #include "i18n_l.h"
00036
00037 #include <gwenhywfar/misc.h>
00038 #include <gwenhywfar/debug.h>
00039 #include <gwenhywfar/gui.h>
00040 #include <gwenhywfar/gui.h>
00041 #include <gwenhywfar/pathmanager.h>
00042 #include <gwenhywfar/directory.h>
00043 #include <gwenhywfar/gwenhywfar.h>
00044 #include <gwenhywfar/text.h>
00045
00046 #include <assert.h>
00047 #include <errno.h>
00048 #include <string.h>
00049
00050 #include <gnutls/gnutls.h>
00051 #include <gnutls/x509.h>
00052
00053
00054
00055 GWEN_INHERIT(GWEN_SYNCIO, GWEN_SYNCIO_TLS)
00056
00057
00058 GWEN_SYNCIO *GWEN_SyncIo_Tls_new(GWEN_SYNCIO *baseIo) {
00059 GWEN_SYNCIO *sio;
00060 GWEN_SYNCIO_TLS *xio;
00061
00062 assert(baseIo);
00063 sio=GWEN_SyncIo_new(GWEN_SYNCIO_TLS_TYPE, baseIo);
00064 GWEN_NEW_OBJECT(GWEN_SYNCIO_TLS, xio);
00065 GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio, xio, GWEN_SyncIo_Tls_FreeData);
00066
00067 GWEN_SyncIo_SetConnectFn(sio, GWEN_SyncIo_Tls_Connect);
00068 GWEN_SyncIo_SetDisconnectFn(sio, GWEN_SyncIo_Tls_Disconnect);
00069 GWEN_SyncIo_SetReadFn(sio, GWEN_SyncIo_Tls_Read);
00070 GWEN_SyncIo_SetWriteFn(sio, GWEN_SyncIo_Tls_Write);
00071
00072 return sio;
00073 }
00074
00075
00076
00077 void GWENHYWFAR_CB GWEN_SyncIo_Tls_FreeData(void *bp, void *p) {
00078 GWEN_SYNCIO_TLS *xio;
00079
00080 xio=(GWEN_SYNCIO_TLS*) p;
00081 GWEN_FREE_OBJECT(xio);
00082 }
00083
00084
00085
00086 const char *GWEN_SyncIo_Tls_GetLocalCertFile(const GWEN_SYNCIO *sio) {
00087 GWEN_SYNCIO_TLS *xio;
00088
00089 assert(sio);
00090 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00091 assert(xio);
00092
00093 return xio->localCertFile;
00094 }
00095
00096
00097
00098 void GWEN_SyncIo_Tls_SetLocalCertFile(GWEN_SYNCIO *sio, const char *s) {
00099 GWEN_SYNCIO_TLS *xio;
00100
00101 assert(sio);
00102 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00103 assert(xio);
00104
00105 free(xio->localCertFile);
00106 if (s) xio->localCertFile=strdup(s);
00107 else xio->localCertFile=NULL;
00108 }
00109
00110
00111
00112 const char *GWEN_SyncIo_Tls_GetLocalKeyFile(const GWEN_SYNCIO *sio) {
00113 GWEN_SYNCIO_TLS *xio;
00114
00115 assert(sio);
00116 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00117 assert(xio);
00118
00119 return xio->localKeyFile;
00120 }
00121
00122
00123
00124 void GWEN_SyncIo_Tls_SetLocalKeyFile(GWEN_SYNCIO *sio, const char *s) {
00125 GWEN_SYNCIO_TLS *xio;
00126
00127 assert(sio);
00128 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00129 assert(xio);
00130
00131 free(xio->localKeyFile);
00132 if (s) xio->localKeyFile=strdup(s);
00133 else xio->localKeyFile=NULL;
00134 }
00135
00136
00137
00138 const char *GWEN_SyncIo_Tls_GetLocalTrustFile(const GWEN_SYNCIO *sio) {
00139 GWEN_SYNCIO_TLS *xio;
00140
00141 assert(sio);
00142 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00143 assert(xio);
00144
00145 return xio->localTrustFile;
00146 }
00147
00148
00149
00150 void GWEN_SyncIo_Tls_SetLocalTrustFile(GWEN_SYNCIO *sio, const char *s) {
00151 GWEN_SYNCIO_TLS *xio;
00152
00153 assert(sio);
00154 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00155 assert(xio);
00156
00157 free(xio->localTrustFile);
00158 if (s) xio->localTrustFile=strdup(s);
00159 else xio->localTrustFile=NULL;
00160 }
00161
00162
00163
00164 const char *GWEN_SyncIo_Tls_GetDhParamFile(const GWEN_SYNCIO *sio) {
00165 GWEN_SYNCIO_TLS *xio;
00166
00167 assert(sio);
00168 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00169 assert(xio);
00170
00171 return xio->dhParamFile;
00172 }
00173
00174
00175
00176 void GWEN_SyncIo_Tls_SetDhParamFile(GWEN_SYNCIO *sio, const char *s) {
00177 GWEN_SYNCIO_TLS *xio;
00178
00179 assert(sio);
00180 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00181 assert(xio);
00182
00183 free(xio->dhParamFile);
00184 if (s) xio->dhParamFile=strdup(s);
00185 else xio->dhParamFile=NULL;
00186 }
00187
00188
00189
00190 const char *GWEN_SyncIo_Tls_GetRemoteHostName(const GWEN_SYNCIO *sio) {
00191 GWEN_SYNCIO_TLS *xio;
00192
00193 assert(sio);
00194 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00195 assert(xio);
00196
00197 return xio->hostName;
00198 }
00199
00200
00201
00202 void GWEN_SyncIo_Tls_SetRemoteHostName(GWEN_SYNCIO *sio, const char *s) {
00203 GWEN_SYNCIO_TLS *xio;
00204
00205 assert(sio);
00206 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00207 assert(xio);
00208
00209 free(xio->hostName);
00210 if (s) xio->hostName=strdup(s);
00211 else xio->hostName=NULL;
00212 }
00213
00214
00215
00216 GWEN_SSLCERTDESCR *GWEN_SyncIo_Tls_GetPeerCertDescr(const GWEN_SYNCIO *sio) {
00217 GWEN_SYNCIO_TLS *xio;
00218
00219 assert(sio);
00220 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00221 assert(xio);
00222
00223 return xio->peerCertDescr;
00224 }
00225
00226
00227
00228 int GWEN_SyncIo_Tls__readFile(const char *fname, GWEN_BUFFER *buf) {
00229 FILE *f;
00230
00231 f=fopen(fname, "r");
00232 if (f==NULL)
00233 return GWEN_ERROR_IO;
00234
00235 while(!feof(f)) {
00236 int rv;
00237
00238 GWEN_Buffer_AllocRoom(buf, 512);
00239 rv=fread(GWEN_Buffer_GetPosPointer(buf), 1, 512, f);
00240 if (rv==0)
00241 break;
00242 else if (rv<0) {
00243 DBG_INFO(GWEN_LOGDOMAIN, "fread(%s): %s", fname, strerror(errno));
00244 fclose(f);
00245 return GWEN_ERROR_IO;
00246 }
00247 else {
00248 GWEN_Buffer_IncrementPos(buf, rv);
00249 GWEN_Buffer_AdjustUsedBytes(buf);
00250 }
00251 }
00252 fclose(f);
00253 return 0;
00254 }
00255
00256
00257
00258 int GWEN_SyncIo_Tls_Prepare(GWEN_SYNCIO *sio) {
00259 GWEN_SYNCIO_TLS *xio;
00260 int rv;
00261 uint32_t lflags;
00262
00263 assert(sio);
00264 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00265 assert(xio);
00266
00267 lflags=GWEN_SyncIo_GetFlags(sio);
00268 DBG_INFO(GWEN_LOGDOMAIN, "Preparing SSL (%08x)", lflags);
00269
00270
00271 if (lflags & GWEN_SYNCIO_FLAGS_PASSIVE) {
00272 DBG_INFO(GWEN_LOGDOMAIN, "Init as server");
00273 rv=gnutls_init(&xio->session, GNUTLS_SERVER);
00274 }
00275 else {
00276 DBG_INFO(GWEN_LOGDOMAIN, "Init as client");
00277 rv=gnutls_init(&xio->session, GNUTLS_CLIENT);
00278 }
00279 if (rv) {
00280 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_init: %d (%s)", rv, gnutls_strerror(rv));
00281 return GWEN_ERROR_GENERIC;
00282 }
00283
00284
00285 rv=gnutls_set_default_priority(xio->session);
00286 if (rv) {
00287 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_set_default_priority: %d (%s)", rv, gnutls_strerror(rv));
00288 gnutls_deinit(xio->session);
00289 return GWEN_ERROR_GENERIC;
00290 }
00291
00292
00293 if (lflags & GWEN_SYNCIO_TLS_FLAGS_FORCE_SSL_V3) {
00294 const int proto_prio[2] = { GNUTLS_SSL3, 0 };
00295
00296 DBG_INFO(GWEN_LOGDOMAIN, "Forcing SSL v3");
00297 rv=gnutls_protocol_set_priority(xio->session, proto_prio);
00298 if (rv) {
00299 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_protocol_set_priority: %d (%s)", rv, gnutls_strerror(rv));
00300 gnutls_deinit(xio->session);
00301 return GWEN_ERROR_GENERIC;
00302 }
00303 }
00304
00305
00306 gnutls_handshake_set_max_packet_length(xio->session, 64*1024);
00307
00308
00309 if ((lflags & GWEN_SYNCIO_FLAGS_PASSIVE) &&
00310 (lflags & GWEN_SYNCIO_TLS_FLAGS_REQUEST_CERT))
00311 gnutls_certificate_server_set_request(xio->session, GNUTLS_CERT_REQUIRE);
00312
00313
00314 rv=gnutls_certificate_allocate_credentials(&xio->credentials);
00315 if (rv) {
00316 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_allocate_credentials: %d (%s)", rv, gnutls_strerror(rv));
00317 gnutls_deinit(xio->session);
00318 return GWEN_ERROR_GENERIC;
00319 }
00320
00321
00322 if (xio->localCertFile && xio->localKeyFile) {
00323 rv=gnutls_certificate_set_x509_key_file(xio->credentials,
00324 xio->localCertFile,
00325 xio->localKeyFile,
00326 GNUTLS_X509_FMT_PEM);
00327 if (rv<0) {
00328 if (rv) {
00329 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_certificate_set_x509_key_file: %d (%s)", rv, gnutls_strerror(rv));
00330 gnutls_certificate_free_credentials(xio->credentials);
00331 gnutls_deinit(xio->session);
00332 return GWEN_ERROR_GENERIC;
00333 }
00334 }
00335 }
00336
00337
00338 if (lflags & GWEN_SYNCIO_TLS_FLAGS_ADD_TRUSTED_CAS) {
00339 int trustFileSet=0;
00340
00341 #if 0
00342 # ifndef OS_WIN32
00343
00344 if (trustFileSet==0) {
00345 GWEN_STRINGLIST *paths;
00346 GWEN_BUFFER *nbuf;
00347
00348 paths=GWEN_StringList_new();
00349 GWEN_StringList_AppendString(paths, "/etc/ssl/certs", 0, 0);
00350
00351 nbuf=GWEN_Buffer_new(0, 256, 0, 1);
00352 rv=GWEN_Directory_FindFileInPaths(paths,
00353 "ca-certificates.crt",
00354 nbuf);
00355 GWEN_StringList_free(paths);
00356 if (rv==0) {
00357 DBG_INFO(GWEN_LOGDOMAIN,
00358 "Using default ca-bundle from [%s]",
00359 GWEN_Buffer_GetStart(nbuf));
00360 GWEN_SyncIo_Tls_SetLocalTrustFile(sio, GWEN_Buffer_GetStart(nbuf));
00361 trustFileSet=1;
00362 }
00363 }
00364 # endif
00365 #endif
00366
00367 if (trustFileSet==0) {
00368 GWEN_STRINGLIST *paths;
00369
00370
00371 paths=GWEN_PathManager_GetPaths(GWEN_PM_LIBNAME, GWEN_PM_DATADIR);
00372 if (paths) {
00373 GWEN_BUFFER *nbuf;
00374
00375 nbuf=GWEN_Buffer_new(0, 256, 0, 1);
00376 rv=GWEN_Directory_FindFileInPaths(paths,
00377 "ca-bundle.crt",
00378 nbuf);
00379 GWEN_StringList_free(paths);
00380 if (rv==0) {
00381 DBG_INFO(GWEN_LOGDOMAIN,
00382 "Using default ca-bundle from [%s]",
00383 GWEN_Buffer_GetStart(nbuf));
00384 GWEN_SyncIo_Tls_SetLocalTrustFile(sio, GWEN_Buffer_GetStart(nbuf));
00385 trustFileSet=1;
00386 }
00387 GWEN_Buffer_free(nbuf);
00388 }
00389 }
00390
00391 if (trustFileSet==0) {
00392 DBG_WARN(GWEN_LOGDOMAIN, "No default bundle file found");
00393 }
00394 }
00395
00396
00397 if (xio->localTrustFile) {
00398 rv=gnutls_certificate_set_x509_trust_file(xio->credentials,
00399 xio->localTrustFile,
00400 GNUTLS_X509_FMT_PEM);
00401 if (rv<=0) {
00402 DBG_ERROR(GWEN_LOGDOMAIN,
00403 "gnutls_certificate_set_x509_trust_file(%s): %d (%s)",
00404 (xio->localTrustFile)?(xio->localTrustFile):"-none-",
00405 rv, gnutls_strerror(rv));
00406 gnutls_certificate_free_credentials(xio->credentials);
00407 gnutls_deinit(xio->session);
00408 return GWEN_ERROR_GENERIC;
00409 }
00410 else {
00411 DBG_INFO(GWEN_LOGDOMAIN,
00412 "Added %d trusted certs", rv);
00413 }
00414 }
00415
00416
00417 if (xio->dhParamFile) {
00418 GWEN_BUFFER *dbuf;
00419
00420 dbuf=GWEN_Buffer_new(0, 256, 0, 1);
00421 rv=GWEN_SyncIo_Tls__readFile(xio->dhParamFile, dbuf);
00422 if (rv) {
00423 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00424 GWEN_Buffer_free(dbuf);
00425 gnutls_certificate_free_credentials(xio->credentials);
00426 gnutls_deinit(xio->session);
00427 return rv;
00428 }
00429 else {
00430 gnutls_datum d;
00431 gnutls_dh_params dh_params=NULL;
00432
00433 rv=gnutls_dh_params_init(&dh_params);
00434 if (rv<0) {
00435 GWEN_Buffer_free(dbuf);
00436 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_init: %d (%s)", rv, gnutls_strerror(rv));
00437 gnutls_certificate_free_credentials(xio->credentials);
00438 gnutls_deinit(xio->session);
00439 return GWEN_ERROR_GENERIC;
00440 }
00441
00442 d.size=GWEN_Buffer_GetUsedBytes(dbuf);
00443 d.data=(unsigned char*)GWEN_Buffer_GetStart(dbuf);
00444
00445 rv=gnutls_dh_params_import_pkcs3(dh_params, &d, GNUTLS_X509_FMT_PEM);
00446 if (rv<0) {
00447 GWEN_Buffer_free(dbuf);
00448 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_dh_params_import_pkcs3: %d (%s)", rv, gnutls_strerror(rv));
00449 gnutls_certificate_free_credentials(xio->credentials);
00450 gnutls_deinit(xio->session);
00451 return GWEN_ERROR_GENERIC;
00452 }
00453 GWEN_Buffer_free(dbuf);
00454
00455 gnutls_certificate_set_dh_params(xio->credentials, dh_params);
00456 }
00457 }
00458
00459
00460 rv=gnutls_credentials_set(xio->session, GNUTLS_CRD_CERTIFICATE, xio->credentials);
00461 if (rv<0) {
00462 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_credentials_set: %d (%s)", rv, gnutls_strerror(rv));
00463 gnutls_certificate_free_credentials(xio->credentials);
00464 gnutls_deinit(xio->session);
00465 return GWEN_ERROR_GENERIC;
00466 }
00467
00468
00469 gnutls_transport_set_ptr(xio->session, (gnutls_transport_ptr_t)sio);
00470 gnutls_transport_set_push_function(xio->session, GWEN_SyncIo_Tls_Push);
00471 gnutls_transport_set_pull_function(xio->session, GWEN_SyncIo_Tls_Pull);
00472 #if GNUTLS_VERSION_NUMBER < 0x030003
00473 gnutls_transport_set_lowat(xio->session, 0);
00474 #endif
00475
00476 xio->prepared=1;
00477
00478 return 0;
00479 }
00480
00481
00482
00483 void GWEN_SyncIo_Tls_UndoPrepare(GWEN_SYNCIO *sio) {
00484 GWEN_SYNCIO_TLS *xio;
00485
00486 assert(sio);
00487 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00488 assert(xio);
00489
00490 if (xio->prepared) {
00491 gnutls_certificate_free_credentials(xio->credentials);
00492 gnutls_deinit(xio->session);
00493 xio->prepared=0;
00494 }
00495 }
00496
00497
00498
00499 int GWEN_SyncIo_Tls_GetPeerCert(GWEN_SYNCIO *sio) {
00500 GWEN_SYNCIO_TLS *xio;
00501 const gnutls_datum_t *cert_list;
00502 unsigned int cert_list_size;
00503 size_t size;
00504 GWEN_SSLCERTDESCR *certDescr;
00505 char buffer1[64];
00506 time_t t0;
00507 int rv;
00508 uint32_t lflags;
00509 uint32_t errFlags=0;
00510 int i;
00511 unsigned int status;
00512 GWEN_BUFFER *sbuf=NULL;
00513
00514 assert(sio);
00515 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00516 assert(xio);
00517
00518 lflags=GWEN_SyncIo_GetFlags(sio);
00519
00520 if (xio->peerCertDescr) {
00521 GWEN_SslCertDescr_free(xio->peerCertDescr);
00522 xio->peerCertDescr=NULL;
00523 }
00524 xio->peerCertFlags=0;
00525
00526 t0=time(NULL);
00527 if (t0<0) {
00528 DBG_WARN(GWEN_LOGDOMAIN, "Could not get system time");
00529 errFlags|=GWEN_SSL_CERT_FLAGS_SYSTEM;
00530 }
00531
00532
00533 certDescr=GWEN_SslCertDescr_new();
00534
00535
00536 if (lflags & GWEN_SYNCIO_TLS_FLAGS_ALLOW_V1_CA_CRT)
00537 gnutls_certificate_set_verify_flags(xio->credentials,
00538 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
00539
00540 rv=gnutls_certificate_verify_peers2(xio->session, &status);
00541 if (rv<0) {
00542 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_certificate_verify_peers2: %d (%s)", rv, gnutls_strerror(rv));
00543 GWEN_SslCertDescr_free(certDescr);
00544 return GWEN_ERROR_SSL_SECURITY;
00545 }
00546
00547 if (gnutls_certificate_type_get(xio->session)!=GNUTLS_CRT_X509) {
00548 DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not X.509");
00549
00550 GWEN_SslCertDescr_free(certDescr);
00551 return GWEN_ERROR_SSL_SECURITY;
00552 }
00553
00554 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
00555 DBG_INFO(GWEN_LOGDOMAIN, "Signer not found");
00556 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Warning,
00557 I18N("Signer not found"));
00558 errFlags|=GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND;
00559 }
00560
00561 if (status & GNUTLS_CERT_INVALID) {
00562 DBG_INFO(GWEN_LOGDOMAIN, "Certificate is not trusted");
00563 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Warning,
00564 I18N("Certificate is not trusted"));
00565 errFlags|=GWEN_SSL_CERT_FLAGS_INVALID;
00566 }
00567
00568 if (status & GNUTLS_CERT_REVOKED) {
00569 DBG_INFO(GWEN_LOGDOMAIN, "Certificate has been revoked");
00570 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Warning,
00571 I18N("Certificate has been revoked"));
00572 errFlags|=GWEN_SSL_CERT_FLAGS_REVOKED;
00573 }
00574
00575 cert_list=gnutls_certificate_get_peers(xio->session, &cert_list_size);
00576 if (cert_list==NULL || cert_list_size==0) {
00577 DBG_INFO(GWEN_LOGDOMAIN, "No peer certificates found");
00578 return GWEN_ERROR_NO_DATA;
00579 }
00580
00581 for (i=0; i<cert_list_size; i++) {
00582 gnutls_x509_crt_t cert;
00583 time_t t;
00584
00585 rv=gnutls_x509_crt_init(&cert);
00586 if (rv!=0) {
00587 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_init: %d (%s)", rv, gnutls_strerror(rv));
00588 return GWEN_ERROR_GENERIC;
00589 }
00590
00591 rv=gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
00592 if (rv!=0) {
00593 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_import: %d (%s)", rv, gnutls_strerror(rv));
00594 gnutls_x509_crt_deinit(cert);
00595 return GWEN_ERROR_GENERIC;
00596 }
00597
00598 if (i==0) {
00599
00600 size=16;
00601 rv=gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, buffer1, &size);
00602 if (rv!=0) {
00603 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_fingerprint: %d (%s)", rv, gnutls_strerror(rv));
00604 GWEN_SslCertDescr_free(certDescr);
00605 gnutls_x509_crt_deinit(cert);
00606 return GWEN_ERROR_GENERIC;
00607 }
00608 else {
00609 GWEN_BUFFER *dbuf;
00610
00611 dbuf=GWEN_Buffer_new(0, 256, 0, 1);
00612 if (GWEN_Text_ToHexBuffer( buffer1,
00613 size, dbuf, 2, ':', 0)) {
00614 DBG_ERROR(GWEN_LOGDOMAIN,
00615 "Could not convert fingerprint to hex");
00616 }
00617 else {
00618 GWEN_SslCertDescr_SetFingerPrint(certDescr, GWEN_Buffer_GetStart(dbuf));
00619 }
00620 GWEN_Buffer_free(dbuf);
00621 }
00622
00623 if (xio->hostName) {
00624 DBG_INFO(GWEN_LOGDOMAIN, "Checking hostname [%s]", xio->hostName);
00625 if (!gnutls_x509_crt_check_hostname(cert, xio->hostName)) {
00626 DBG_WARN(GWEN_LOGDOMAIN,
00627 "Certificate was not issued for this host");
00628 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Warning,
00629 I18N("Certificate was not issued for this host"));
00630 errFlags|=GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME;
00631 }
00632 else {
00633 DBG_INFO(GWEN_LOGDOMAIN, "Cert is for this server");
00634 }
00635 }
00636 else {
00637 DBG_WARN(GWEN_LOGDOMAIN,
00638 "Hostname is not set, unable to verify the sender");
00639 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Warning,
00640 I18N("No hostname to verify the sender!"));
00641 }
00642
00643 }
00644
00645
00646 t=gnutls_x509_crt_get_activation_time(cert);
00647 if (t<0) {
00648 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_activation_time: %d (%s)", rv, gnutls_strerror(rv));
00649 errFlags|=GWEN_SSL_CERT_FLAGS_BAD_DATA;
00650 }
00651 else {
00652 if (t>t0) {
00653 DBG_INFO(GWEN_LOGDOMAIN, "Cert is not yet active");
00654 errFlags|=GWEN_SSL_CERT_FLAGS_NOT_ACTIVE;
00655 }
00656 if (i==0) {
00657 GWEN_TIME *ti;
00658
00659 ti=GWEN_Time_fromSeconds(t);
00660 if (ti)
00661 GWEN_SslCertDescr_SetNotBefore(certDescr, ti);
00662 GWEN_Time_free(ti);
00663 }
00664 }
00665
00666
00667 t=gnutls_x509_crt_get_expiration_time(cert);
00668 if (t<0) {
00669 DBG_INFO(GWEN_LOGDOMAIN, "gnutls_x509_crt_get_expiration_time: %d (%s)", rv, gnutls_strerror(rv));
00670 errFlags|=GWEN_SSL_CERT_FLAGS_BAD_DATA;
00671 }
00672 else {
00673 if (t<t0) {
00674 DBG_INFO(GWEN_LOGDOMAIN, "Cert has expired");
00675 errFlags|=GWEN_SSL_CERT_FLAGS_EXPIRED;
00676 }
00677 if (i==0) {
00678 GWEN_TIME *ti;
00679
00680 ti=GWEN_Time_fromSeconds(t);
00681 if (ti)
00682 GWEN_SslCertDescr_SetNotAfter(certDescr, ti);
00683 GWEN_Time_free(ti);
00684 }
00685 }
00686
00687 if (i==0) {
00688
00689 size=sizeof(buffer1)-1;
00690 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, buffer1, &size);
00691 if (rv==0) {
00692 GWEN_SslCertDescr_SetCommonName(certDescr, buffer1);
00693 if (xio->hostName && strcasecmp(xio->hostName, buffer1)!=0) {
00694 DBG_INFO(GWEN_LOGDOMAIN, "Owner of certificate does not match hostname");
00695 errFlags|=GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME;
00696 }
00697 }
00698
00699 size=sizeof(buffer1)-1;
00700 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, buffer1, &size);
00701 if (rv==0)
00702 GWEN_SslCertDescr_SetOrganizationName(certDescr, buffer1);
00703
00704 size=sizeof(buffer1)-1;
00705 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, buffer1, &size);
00706 if (rv==0)
00707 GWEN_SslCertDescr_SetOrganizationalUnitName(certDescr, buffer1);
00708
00709 size=sizeof(buffer1)-1;
00710 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, buffer1, &size);
00711 if (rv==0)
00712 GWEN_SslCertDescr_SetLocalityName(certDescr, buffer1);
00713
00714 size=sizeof(buffer1)-1;
00715 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, buffer1, &size);
00716 if (rv==0)
00717 GWEN_SslCertDescr_SetStateOrProvinceName(certDescr, buffer1);
00718
00719 size=sizeof(buffer1)-1;
00720 rv=gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, buffer1, &size);
00721 if (rv==0)
00722 GWEN_SslCertDescr_SetCountryName(certDescr, buffer1);
00723 }
00724
00725 gnutls_x509_crt_deinit(cert);
00726 }
00727
00728
00729 if (errFlags)
00730 GWEN_SslCertDescr_SetIsError(certDescr, 1);
00731 else
00732 errFlags|=GWEN_SSL_CERT_FLAGS_OK;
00733
00734 sbuf=GWEN_Buffer_new(0, 256, 0, 1);
00735
00736 if (errFlags & GWEN_SSL_CERT_FLAGS_SIGNER_NOT_FOUND) {
00737 if (GWEN_Buffer_GetUsedBytes(sbuf))
00738 GWEN_Buffer_AppendString(sbuf, "; ");
00739 GWEN_Buffer_AppendString(sbuf, I18N("Signer not found"));
00740 }
00741
00742 if (errFlags & GWEN_SSL_CERT_FLAGS_INVALID) {
00743 if (GWEN_Buffer_GetUsedBytes(sbuf))
00744 GWEN_Buffer_AppendString(sbuf, "; ");
00745 GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not trusted"));
00746 }
00747
00748 if (errFlags & GWEN_SSL_CERT_FLAGS_REVOKED) {
00749 if (GWEN_Buffer_GetUsedBytes(sbuf))
00750 GWEN_Buffer_AppendString(sbuf, "; ");
00751 GWEN_Buffer_AppendString(sbuf, I18N("Certificate has been revoked"));
00752 }
00753
00754 if (errFlags & GWEN_SSL_CERT_FLAGS_EXPIRED) {
00755 if (GWEN_Buffer_GetUsedBytes(sbuf))
00756 GWEN_Buffer_AppendString(sbuf, "; ");
00757 GWEN_Buffer_AppendString(sbuf, I18N("Certificate has expired"));
00758 }
00759
00760 if (errFlags & GWEN_SSL_CERT_FLAGS_NOT_ACTIVE) {
00761 if (GWEN_Buffer_GetUsedBytes(sbuf))
00762 GWEN_Buffer_AppendString(sbuf, "; ");
00763 GWEN_Buffer_AppendString(sbuf, I18N("Certificate is not active yet"));
00764 }
00765
00766 if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_HOSTNAME) {
00767 if (GWEN_Buffer_GetUsedBytes(sbuf))
00768 GWEN_Buffer_AppendString(sbuf, "; ");
00769 GWEN_Buffer_AppendString(sbuf, I18N("Certificate owner does not match hostname"));
00770 }
00771
00772 if (errFlags & GWEN_SSL_CERT_FLAGS_BAD_DATA) {
00773 if (GWEN_Buffer_GetUsedBytes(sbuf))
00774 GWEN_Buffer_AppendString(sbuf, "; ");
00775 GWEN_Buffer_AppendString(sbuf, I18N("Certificate contains invalid information"));
00776 }
00777
00778 if (errFlags & GWEN_SSL_CERT_FLAGS_SYSTEM) {
00779 if (GWEN_Buffer_GetUsedBytes(sbuf))
00780 GWEN_Buffer_AppendString(sbuf, "; ");
00781 GWEN_Buffer_AppendString(sbuf, I18N("A system error occurred while checking the certificate"));
00782 }
00783
00784 if (errFlags & GWEN_SSL_CERT_FLAGS_OK) {
00785 if (GWEN_Buffer_GetUsedBytes(sbuf))
00786 GWEN_Buffer_AppendString(sbuf, "; ");
00787 GWEN_Buffer_AppendString(sbuf, I18N("The certificate is valid"));
00788 }
00789
00790 GWEN_SslCertDescr_SetStatusText(certDescr, GWEN_Buffer_GetStart(sbuf));
00791 GWEN_SslCertDescr_SetStatusFlags(certDescr, errFlags);
00792 GWEN_Buffer_free(sbuf);
00793
00794 xio->peerCertDescr=certDescr;
00795 xio->peerCertFlags=errFlags;
00796
00797 return 0;
00798 }
00799
00800
00801
00802 ssize_t GWEN_SyncIo_Tls_Pull(gnutls_transport_ptr_t p, void *buf, size_t len) {
00803 GWEN_SYNCIO *sio;
00804 GWEN_SYNCIO_TLS *xio;
00805 GWEN_SYNCIO *baseIo;
00806 int rv;
00807
00808 sio=(GWEN_SYNCIO*) p;
00809 assert(sio);
00810 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00811 assert(xio);
00812
00813 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: %d bytes", (int)len);
00814 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00815 assert(baseIo);
00816
00817 rv=GWEN_SyncIo_Read(baseIo, buf, len);
00818 if (rv<0) {
00819 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00820 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00821 gnutls_transport_set_errno(xio->session, errno);
00822 #endif
00823 return (ssize_t)-1;
00824 }
00825
00826 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00827 gnutls_transport_set_errno(xio->session, 0);
00828 #else
00829 errno=0;
00830 #endif
00831 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PULL: returning %d bytes", rv);
00832
00833 return rv;
00834 }
00835
00836
00837
00838 ssize_t GWEN_SyncIo_Tls_Push(gnutls_transport_ptr_t p, const void *buf, size_t len) {
00839 GWEN_SYNCIO *sio;
00840 GWEN_SYNCIO_TLS *xio;
00841 GWEN_SYNCIO *baseIo;
00842 int rv;
00843
00844 sio=(GWEN_SYNCIO*) p;
00845 assert(sio);
00846 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00847 assert(xio);
00848
00849 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: %d bytes", (int)len);
00850 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00851 assert(baseIo);
00852
00853 rv=GWEN_SyncIo_Write(baseIo, buf, len);
00854 if (rv<0) {
00855 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00856 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00857 gnutls_transport_set_errno(xio->session, errno);
00858 #endif
00859 return (ssize_t)-1;
00860 }
00861
00862 #ifdef HAVE_GNUTLS_TRANSPORT_SET_ERRNO
00863 gnutls_transport_set_errno(xio->session, 0);
00864 #endif
00865 DBG_VERBOUS(GWEN_LOGDOMAIN, "TLS PUSH: returning %d bytes", rv);
00866
00867 return rv;
00868 }
00869
00870
00871
00872 int GWENHYWFAR_CB GWEN_SyncIo_Tls_Connect(GWEN_SYNCIO *sio) {
00873 GWEN_SYNCIO_TLS *xio;
00874 GWEN_SYNCIO *baseIo;
00875 int rv;
00876
00877 assert(sio);
00878 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00879 assert(xio);
00880
00881 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00882 assert(baseIo);
00883
00884 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_PASSIVE) {
00885 if (GWEN_SyncIo_GetStatus(baseIo)!=GWEN_SyncIo_Status_Connected) {
00886 DBG_ERROR(GWEN_LOGDOMAIN, "Base layer is not connected");
00887 return GWEN_ERROR_NOT_CONNECTED;
00888 }
00889 }
00890 else {
00891 DBG_INFO(GWEN_LOGDOMAIN, "Connecting base layer");
00892 rv=GWEN_SyncIo_Connect(baseIo);
00893 if (rv<0) {
00894 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00895 return rv;
00896 }
00897 DBG_INFO(GWEN_LOGDOMAIN, "Base layer connected");
00898 }
00899
00900 rv=GWEN_SyncIo_Tls_Prepare(sio);
00901 if (rv<0) {
00902 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00903 GWEN_SyncIo_Disconnect(baseIo);
00904 return rv;
00905 }
00906
00907 do {
00908 rv=gnutls_handshake(xio->session);
00909 } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
00910
00911 if (rv) {
00912 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_handshake: %d (%s) [%s]",
00913 rv, gnutls_strerror(rv), gnutls_error_is_fatal(rv)?"fatal":"non-fatal");
00914 if (rv==GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
00915 GWEN_Gui_ProgressLog(0,
00916 GWEN_LoggerLevel_Error,
00917 I18N("A TLS handshake error occurred. "
00918 "If you are using AqBanking you should "
00919 "consider enabling the option "
00920 "\"force SSLv3\" in the user settings "
00921 "dialog."));
00922 }
00923 else {
00924 GWEN_Gui_ProgressLog2(0,
00925 GWEN_LoggerLevel_Error,
00926 I18N("TLS Handshake Error: %d (%s)"),
00927 rv,
00928 gnutls_strerror(rv));
00929 }
00930 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
00931 GWEN_SyncIo_Tls_UndoPrepare(sio);
00932 GWEN_SyncIo_Disconnect(baseIo);
00933 return GWEN_ERROR_SSL;
00934 }
00935 else {
00936
00937 GWEN_SyncIo_SubFlags(sio, GWEN_SYNCIO_TLS_FLAGS_SECURE);
00938 rv=GWEN_SyncIo_Tls_GetPeerCert(sio);
00939 if (rv<0) {
00940 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_TLS_FLAGS_NEED_PEER_CERT) {
00941 DBG_ERROR(GWEN_LOGDOMAIN, "No peer certificate when needed, aborting connection");
00942 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
00943 GWEN_SyncIo_Tls_UndoPrepare(sio);
00944 GWEN_SyncIo_Disconnect(baseIo);
00945 return GWEN_ERROR_SSL_SECURITY;
00946 }
00947 else {
00948 DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (insecure)");
00949 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Connected);
00950 return 0;
00951 }
00952 }
00953 else {
00954
00955 rv=GWEN_Gui_CheckCert(xio->peerCertDescr, sio, 0);
00956 if (rv<0) {
00957 DBG_ERROR(GWEN_LOGDOMAIN, "Peer cert not accepted (%d), aborting", rv);
00958 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
00959 GWEN_SyncIo_Tls_UndoPrepare(sio);
00960 GWEN_SyncIo_Disconnect(baseIo);
00961 return GWEN_ERROR_SSL_SECURITY;
00962 }
00963 else {
00964 DBG_INFO(GWEN_LOGDOMAIN, "SSL connected (secure)");
00965 GWEN_SyncIo_AddFlags(sio, GWEN_SYNCIO_TLS_FLAGS_SECURE);
00966 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Connected);
00967 return 0;
00968 }
00969 }
00970 }
00971 }
00972
00973
00974
00975 int GWENHYWFAR_CB GWEN_SyncIo_Tls_Disconnect(GWEN_SYNCIO *sio) {
00976 GWEN_SYNCIO_TLS *xio;
00977 GWEN_SYNCIO *baseIo;
00978 int rv;
00979
00980 assert(sio);
00981 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
00982 assert(xio);
00983
00984 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00985 assert(baseIo);
00986
00987 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) {
00988 DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
00989 GWEN_SyncIo_Tls_UndoPrepare(sio);
00990 GWEN_SyncIo_Disconnect(baseIo);
00991 return GWEN_ERROR_NOT_CONNECTED;
00992 }
00993
00994 do {
00995 rv=gnutls_bye(xio->session, GNUTLS_SHUT_RDWR);
00996 } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
00997
00998 if (rv) {
00999 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_bye: %d (%s)", rv, gnutls_strerror(rv));
01000 GWEN_Gui_ProgressLog2(0,
01001 GWEN_LoggerLevel_Info,
01002 I18N("Error on gnutls_bye: %d (%s)"),
01003 rv,
01004 gnutls_strerror(rv));
01005 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
01006 GWEN_SyncIo_Tls_UndoPrepare(sio);
01007 GWEN_SyncIo_Disconnect(baseIo);
01008 return GWEN_ERROR_SSL;
01009 }
01010
01011 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
01012 GWEN_SyncIo_Tls_UndoPrepare(sio);
01013 GWEN_SyncIo_Disconnect(baseIo);
01014 return 0;
01015 }
01016
01017
01018
01019 int GWENHYWFAR_CB GWEN_SyncIo_Tls_Read(GWEN_SYNCIO *sio,
01020 uint8_t *buffer,
01021 uint32_t size) {
01022 GWEN_SYNCIO_TLS *xio;
01023 GWEN_SYNCIO *baseIo;
01024 int rv;
01025
01026 assert(sio);
01027 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
01028 assert(xio);
01029
01030 baseIo=GWEN_SyncIo_GetBaseIo(sio);
01031 assert(baseIo);
01032
01033 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) {
01034 DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
01035 GWEN_SyncIo_Tls_UndoPrepare(sio);
01036 GWEN_SyncIo_Disconnect(baseIo);
01037 return GWEN_ERROR_NOT_CONNECTED;
01038 }
01039
01040 do {
01041 rv=gnutls_record_recv(xio->session, buffer, size);
01042 } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
01043
01044 if (rv<0) {
01045 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_record_recv: %d (%s)", rv, gnutls_strerror(rv));
01046 #if 0
01047 GWEN_Gui_ProgressLog2(0,
01048 GWEN_LoggerLevel_Error,
01049 I18N("Error on gnutls_record_recv: %d (%s)"),
01050 rv,
01051 gnutls_strerror(rv));
01052 #endif
01053 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
01054 GWEN_SyncIo_Tls_UndoPrepare(sio);
01055 GWEN_SyncIo_Disconnect(baseIo);
01056 return GWEN_ERROR_SSL;
01057 }
01058
01059 #ifdef GWEN_TLS_DEBUG
01060 DBG_ERROR(0, "Received this:");
01061 GWEN_Text_DumpString((const char*) buffer, rv, 2);
01062 #endif
01063
01064 return rv;
01065 }
01066
01067
01068
01069 int GWENHYWFAR_CB GWEN_SyncIo_Tls_Write(GWEN_SYNCIO *sio,
01070 const uint8_t *buffer,
01071 uint32_t size) {
01072 GWEN_SYNCIO_TLS *xio;
01073 GWEN_SYNCIO *baseIo;
01074 int rv;
01075
01076 assert(sio);
01077 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_TLS, sio);
01078 assert(xio);
01079
01080 #ifdef GWEN_TLS_DEBUG
01081 DBG_ERROR(0, "Sending this:");
01082 GWEN_Text_DumpString((const char*) buffer, size, 2);
01083 #endif
01084
01085 baseIo=GWEN_SyncIo_GetBaseIo(sio);
01086 assert(baseIo);
01087
01088 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) {
01089 DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
01090 GWEN_SyncIo_Tls_UndoPrepare(sio);
01091 GWEN_SyncIo_Disconnect(baseIo);
01092 return GWEN_ERROR_NOT_CONNECTED;
01093 }
01094
01095 do {
01096 rv=gnutls_record_send(xio->session, buffer, size);
01097 } while (rv==GNUTLS_E_AGAIN && rv==GNUTLS_E_INTERRUPTED);
01098
01099 if (rv<0) {
01100 DBG_ERROR(GWEN_LOGDOMAIN, "gnutls_record_send: %d (%s)", rv, gnutls_strerror(rv));
01101 GWEN_Gui_ProgressLog2(0,
01102 GWEN_LoggerLevel_Error,
01103 I18N("Error on gnutls_record_send: %d (%s)"),
01104 rv,
01105 gnutls_strerror(rv));
01106 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
01107 GWEN_SyncIo_Tls_UndoPrepare(sio);
01108 GWEN_SyncIo_Disconnect(baseIo);
01109 return GWEN_ERROR_SSL;
01110 }
01111
01112 return rv;
01113 }
01114
01115
01116
01117
01118
01119
01120