WvStreams
|
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 */ 00005 #define OPENSSL_NO_KRB5 00006 #include "wvsslstream.h" 00007 #include "wvx509mgr.h" 00008 #include "wvcrypto.h" 00009 #include "wvlistener.h" 00010 #include "wvstrutils.h" 00011 #include "wvmoniker.h" 00012 #include "wvlinkerhack.h" 00013 #include <openssl/ssl.h> 00014 #include <openssl/err.h> 00015 #include <assert.h> 00016 00017 #ifndef _WIN32 00018 # if HAVE_ARGZ_H 00019 # include <argz.h> 00020 # else 00021 # if HAVE_ERRNO_H 00022 # include <errno.h> 00023 # endif 00024 # endif 00025 #else 00026 #undef errno 00027 #define errno GetLastError() 00028 #undef EAGAIN 00029 #define EAGAIN WSAEWOULDBLOCK 00030 #endif 00031 00032 WV_LINK(WvSSLStream); 00033 00034 static IWvStream *creator(WvStringParm s, IObject *_obj) 00035 { 00036 return new WvSSLStream(IWvStream::create(s, _obj), NULL, 0, false); 00037 } 00038 00039 static IWvStream *screator(WvStringParm s, IObject *_obj) 00040 { 00041 return new WvSSLStream(IWvStream::create(s, _obj), 00042 new WvX509Mgr(encode_hostname_as_DN(fqdomainname()), 1024), 00043 0, true); 00044 } 00045 00046 struct WvTclParseValues 00047 { 00048 WvX509Mgr *m; 00049 WvString s; 00050 00051 /* Kind of necessary; the WvX509Mgr object here is meant to be passed into 00052 * a WvSSLStream, which will addRef() the object. Thus, once the stream 00053 * has been created, we need to release() it here, so that once the stream 00054 * itself falls into oblivion, we have no hanging references. 00055 */ 00056 ~WvTclParseValues() 00057 { WVRELEASE(m); } 00058 }; 00059 00060 static WvTclParseValues *parse_wvtcl_sslcert(WvStringParm s) 00061 { 00062 /* The idea here is that we've got s, which is a TclStyle string of the 00063 * format (without the quotes, of course, but escaped): 00064 * "PEM-encoded SSL cert" "PEM-encoded private RSA key" "connection moniker" 00065 */ 00066 WvList<WvString> l; 00067 wvtcl_decode(l, s); 00068 if (l.count() > 3 || l.count() < 2) 00069 return NULL; /* we fscked up, no clue how to recover */ 00070 // in the case of '2', 'obj' had better be set to the calling function 00071 00072 WvTclParseValues *p = new WvTclParseValues; 00073 p->m = new WvX509Mgr; 00074 p->m->decode(WvX509::CertPEM, *l.first()); 00075 l.unlink_first(); 00076 p->m->decode(WvRSAKey::RsaPEM, *l.first()); 00077 l.unlink_first(); 00078 if (!p->m->test()) { /* RSA key and certificate don't match up?? */ 00079 delete p; 00080 return NULL; 00081 } 00082 00083 if (l.count()) 00084 p->s = *l.first(); 00085 00086 return p; 00087 } 00088 00089 static IWvStream *sslcertcreator(WvStringParm s, IObject *_obj) 00090 { 00091 WvTclParseValues *p = parse_wvtcl_sslcert(s); 00092 if (!p) { 00093 WVRELEASE(_obj); 00094 return NULL; 00095 } 00096 00097 WvSSLStream *ret = new WvSSLStream(IWvStream::create(p->s, _obj), p->m, 00098 0, false); 00099 delete p; 00100 return ret; 00101 } 00102 00103 static IWvStream *sslcertscreator(WvStringParm s, IObject *_obj) 00104 { 00105 WvTclParseValues *p = parse_wvtcl_sslcert(s); 00106 if (!p) { 00107 WVRELEASE(_obj); 00108 return NULL; 00109 } 00110 00111 WvSSLStream *ret = new WvSSLStream(IWvStream::create(p->s, _obj), p->m, 00112 0, true); 00113 delete p; 00114 return ret; 00115 } 00116 00117 static WvMoniker<IWvStream> reg("ssl", creator); 00118 static WvMoniker<IWvStream> sreg("sslserv", screator); 00119 static WvMoniker<IWvStream> sslcertreg("sslcert", sslcertcreator); 00120 static WvMoniker<IWvStream> sslcertsreg("sslcertserv", sslcertscreator); 00121 00122 static IWvListener *listener(WvStringParm s, IObject *obj) 00123 { 00124 IWvListener *l = IWvListener::create(s, obj); 00125 if (l) 00126 l->addwrap(wv::bind(&IWvStream::create, "sslserv", _1)); 00127 return l; 00128 } 00129 00130 static IWvListener *sslcertlistener(WvStringParm s, IObject *obj) 00131 { 00132 WvList<WvString> li; 00133 wvtcl_decode(li, s); 00134 WvString connmoniker; 00135 00136 if (li.count() == 3) { 00137 // We have a connection moniker as well as SSL information 00138 connmoniker = *li.last(); 00139 li.unlink(li.last()); 00140 } else if (li.count() != 2) { 00141 // something went very wrong 00142 WVRELEASE(obj); 00143 return NULL; 00144 } 00145 00146 IWvListener *l = IWvListener::create(connmoniker, obj); 00147 if (l) 00148 l->addwrap(wv::bind(&IWvStream::create, 00149 WvString("sslcertserv:%s", wvtcl_encode(li)), _1)); 00150 return l; 00151 } 00152 00153 static WvMoniker<IWvListener> lreg("ssl", listener); 00154 static WvMoniker<IWvListener> lsslcertreg("sslcert", sslcertlistener); 00155 00156 #define MAX_BOUNCE_AMOUNT (16384) // 1 SSLv3/TLSv1 record 00157 00158 static int ssl_stream_count = 0; 00159 00160 static int wv_verify_cb(int preverify_ok, X509_STORE_CTX *ctx) 00161 { 00162 // This is just returns true, since what we really want 00163 // is for the WvSSLValidateCallback to do this work 00164 return 1; 00165 } 00166 00167 WvSSLGlobalValidateCallback WvSSLStream::global_vcb = 0; 00168 00169 WvSSLStream::WvSSLStream(IWvStream *_slave, WvX509Mgr *_x509, 00170 WvSSLValidateCallback _vcb, bool _is_server) : 00171 WvStreamClone(_slave), 00172 debug(WvString("WvSSLStream %s", ++ssl_stream_count), WvLog::Debug5), 00173 write_bouncebuf(MAX_BOUNCE_AMOUNT), write_eat(0), 00174 read_bouncebuf(MAX_BOUNCE_AMOUNT), read_pending(false) 00175 { 00176 x509 = _x509; 00177 if (x509) 00178 x509->addRef(); // openssl may keep a pointer to this object 00179 00180 vcb = _vcb; 00181 if (!vcb && global_vcb) 00182 vcb = wv::bind(global_vcb, _1, this);; 00183 00184 is_server = _is_server; 00185 ctx = NULL; 00186 ssl = NULL; 00187 //meth = NULL; 00188 sslconnected = ssl_stop_read = ssl_stop_write = false; 00189 00190 wvssl_init(); 00191 00192 if (x509 && !x509->isok()) 00193 { 00194 seterr("Certificate + key pair invalid."); 00195 return; 00196 } 00197 00198 if (is_server && !x509) 00199 { 00200 seterr("Certificate not available: server mode not possible!"); 00201 return; 00202 } 00203 00204 if (is_server) 00205 { 00206 debug("Configured algorithms and methods for server mode.\n"); 00207 00208 ctx = SSL_CTX_new(SSLv23_server_method()); 00209 if (!ctx) 00210 { 00211 ERR_print_errors_fp(stderr); 00212 debug("Can't get SSL context! Error: %s\n", 00213 ERR_reason_error_string(ERR_get_error())); 00214 seterr("Can't get SSL context!"); 00215 return; 00216 } 00217 00218 // Allow SSL Writes to only write part of a request... 00219 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); 00220 00221 // Tell SSL to use 128 bit or better ciphers - this appears to 00222 // be necessary for some reason... *sigh* 00223 SSL_CTX_set_cipher_list(ctx, "HIGH"); 00224 00225 // Enable the workarounds for broken clients and servers 00226 // and disable the insecure SSLv2 protocol 00227 SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2); 00228 00229 if (!x509->bind_ssl(ctx)) 00230 { 00231 seterr("Unable to bind Certificate to SSL Context!"); 00232 return; 00233 } 00234 00235 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, 00236 wv_verify_cb); 00237 00238 debug("Server mode ready.\n"); 00239 } 00240 else 00241 { 00242 debug("Configured algorithms and methods for client mode.\n"); 00243 00244 ctx = SSL_CTX_new(SSLv23_client_method()); 00245 if (!ctx) 00246 { 00247 seterr("Can't get SSL context!"); 00248 return; 00249 } 00250 if (x509 && !x509->bind_ssl(ctx)) 00251 { 00252 seterr("Unable to bind Certificate to SSL Context!"); 00253 return; 00254 } 00255 } 00256 00257 //SSL_CTX_set_read_ahead(ctx, 1); 00258 00259 ERR_clear_error(); 00260 ssl = SSL_new(ctx); 00261 if (!ssl) 00262 { 00263 seterr("Can't create SSL object!"); 00264 return; 00265 } 00266 00267 // If we set this, it seems we always verify the client... security hole, 00268 // no? Well, if we don't set it, the server doesn't even ask the client 00269 // for a certificate, so, ya know, it's not actually any more secure. 00270 // Client doesn't need this (unless vcb is set), since it always asks the 00271 // server for a cert anyway 00272 if (!!vcb || is_server) 00273 SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, 00274 wv_verify_cb); 00275 00276 connect_wants.readable = true; 00277 connect_wants.writable = true; // force ssl initiation ASAP 00278 connect_wants.isexception = false; 00279 debug("SSL stream initialized.\n"); 00280 } 00281 00282 00283 WvSSLStream::~WvSSLStream() 00284 { 00285 close(); 00286 00287 debug("Deleting SSL connection.\n"); 00288 if (geterr()) 00289 debug("Error was: %s\n", errstr()); 00290 00291 WVRELEASE(x509); 00292 wvssl_free(); 00293 } 00294 00295 00296 void WvSSLStream::printerr(WvStringParm func) 00297 { 00298 unsigned long l = ERR_get_error(); 00299 char buf[121]; // man ERR_error_string says must be > 120. 00300 00301 while (l) 00302 { 00303 ERR_error_string(l, buf); 00304 debug("%s error: %s\n", func, buf); 00305 l = ERR_get_error(); 00306 } 00307 } 00308 00309 00310 size_t WvSSLStream::uread(void *buf, size_t len) 00311 { 00312 if (!sslconnected) 00313 return 0; 00314 if (len == 0) return 0; 00315 00316 // if SSL buffers stuff on its own, select() may not wake us up 00317 // the next time around unless we're sure there is nothing left 00318 read_pending = true; 00319 00320 size_t total = 0; 00321 for (;;) 00322 { 00323 // handle SSL_read quirk 00324 if (read_bouncebuf.used() != 0) 00325 { 00326 // copy out cached data 00327 size_t amount = len < read_bouncebuf.used() ? 00328 len : read_bouncebuf.used(); 00329 read_bouncebuf.move(buf, amount); 00330 00331 // locate next chunk in buffer 00332 len -= amount; 00333 total += amount; 00334 if (len == 0) 00335 { 00336 read_pending = false; 00337 break; 00338 } 00339 buf = (unsigned char *)buf + amount; 00340 00341 // FIXME: this shouldn't be necessary, but it resolves weird 00342 // problems when the other end disconnects in the middle of 00343 // SSL negotiation, but only on emakela's machine. I don't 00344 // know why. -- apenwarr (2004/02/10) 00345 break; 00346 } 00347 00348 // attempt to read 00349 read_bouncebuf.zap(); // force use of same position in buffer 00350 size_t avail = read_bouncebuf.free(); 00351 unsigned char *data = read_bouncebuf.alloc(avail); 00352 00353 ERR_clear_error(); 00354 int result = SSL_read(ssl, data, avail); 00355 // debug("<< SSL_read result %s for %s bytes (wanted %s)\n", 00356 // result, avail, len); 00357 if (result <= 0) 00358 { 00359 error_t err = errno; 00360 read_bouncebuf.unalloc(avail); 00361 int sslerrcode = SSL_get_error(ssl, result); 00362 switch (sslerrcode) 00363 { 00364 case SSL_ERROR_WANT_READ: 00365 debug("<< SSL_read() needs to wait for writable.\n"); 00366 break; // wait for later 00367 case SSL_ERROR_WANT_WRITE: 00368 debug("<< SSL_read() needs to wait for readable.\n"); 00369 break; // wait for later 00370 00371 case SSL_ERROR_NONE: 00372 break; // no error, but can't make progress 00373 00374 case SSL_ERROR_ZERO_RETURN: 00375 debug("<< EOF: zero return\n"); 00376 00377 // don't do this if we're returning nonzero! 00378 // (SSL has no way to do a one-way shutdown, so if SSL 00379 // detects a read problem, it's also a write problem.) 00380 if (!total) { noread(); nowrite(); } 00381 break; 00382 00383 case SSL_ERROR_SYSCALL: 00384 if (!err) 00385 { 00386 if (result == 0) 00387 { 00388 debug("<< EOF: syscall error " 00389 "(%s/%s, %s/%s) total=%s\n", 00390 stop_read, stop_write, 00391 isok(), cloned && cloned->isok(), total); 00392 00393 // don't do this if we're returning nonzero! 00394 // (SSL has no way to do a one-way shutdown, so 00395 // if SSL detects a read problem, it's also a 00396 // write problem.) 00397 if (!total) { noread(); nowrite(); } 00398 } 00399 } 00400 else 00401 { 00402 debug("<< SSL_read() err=%s (%s)\n", 00403 err, strerror(err)); 00404 seterr_both(err, WvString("SSL read: %s", 00405 strerror(err))); 00406 } 00407 break; 00408 00409 default: 00410 printerr("SSL_read"); 00411 seterr("SSL read error #%s", sslerrcode); 00412 break; 00413 } 00414 read_pending = false; 00415 break; // wait for next iteration 00416 } 00417 // debug("<< read result was %s\n", result); 00418 00419 if (result < 0) 00420 result = 0; 00421 read_bouncebuf.unalloc(avail - result); 00422 } 00423 00424 // debug("<< read %s bytes (%s, %s)\n", 00425 // total, isok(), cloned && cloned->isok()); 00426 return total; 00427 } 00428 00429 00430 size_t WvSSLStream::uwrite(const void *buf, size_t len) 00431 { 00432 if (!sslconnected) 00433 { 00434 debug(">> writing, but not connected yet (%s); enqueue.\n", getwfd()); 00435 unconnected_buf.put(buf, len); 00436 return len; 00437 } 00438 00439 if (len == 0) return 0; 00440 00441 // debug(">> I want to write %s bytes.\n", len); 00442 00443 size_t total = 0; 00444 00445 // eat any data that was precached and already written 00446 if (write_eat >= len) 00447 { 00448 write_eat -= len; 00449 total = len; 00450 len = 0; 00451 } 00452 else 00453 { 00454 buf = (const unsigned char *)buf + write_eat; 00455 total = write_eat; 00456 len -= write_eat; 00457 write_eat = 0; 00458 } 00459 00460 // FIXME: WOW!!! Ummm... hope this never spins... 00461 // 00462 for (;;) 00463 { 00464 // handle SSL_write quirk 00465 if (write_bouncebuf.used() == 0) 00466 { 00467 if (len == 0) break; 00468 00469 // copy new data into the bounce buffer only if empty 00470 // if it were not empty, then SSL_write probably returned 00471 // SSL_ERROR_WANT_WRITE on the previous call and we 00472 // must invoke it with precisely the same arguments 00473 size_t amount = len < write_bouncebuf.free() ? 00474 len : write_bouncebuf.free(); 00475 write_bouncebuf.put(buf, amount); 00476 // note: we don't adjust the total yet... 00477 } // otherwise we use what we cached last time in bounce buffer 00478 00479 // attempt to write 00480 size_t used = write_bouncebuf.used(); 00481 const unsigned char *data = write_bouncebuf.get(used); 00482 00483 ERR_clear_error(); 00484 int result = SSL_write(ssl, data, used); 00485 // debug("<< SSL_write result %s for %s bytes\n", 00486 // result, used); 00487 if (result <= 0) 00488 { 00489 int sslerrcode = SSL_get_error(ssl, result); 00490 write_bouncebuf.unget(used); 00491 switch (sslerrcode) 00492 { 00493 case SSL_ERROR_WANT_READ: 00494 debug(">> SSL_write() needs to wait for readable.\n"); 00495 break; // wait for later 00496 case SSL_ERROR_WANT_WRITE: 00497 // debug(">> SSL_write() needs to wait for writable.\n"); 00498 break; // wait for later 00499 00500 case SSL_ERROR_SYSCALL: 00501 debug(">> ERROR: SSL_write() failed on socket error.\n"); 00502 seterr(WvString("SSL write error: %s", strerror(errno))); 00503 break; 00504 00505 // This case can cause truncated web pages... give more info 00506 case SSL_ERROR_SSL: 00507 debug(">> ERROR: SSL_write() failed on internal error.\n"); 00508 seterr(WvString("SSL write error: %s", 00509 ERR_error_string(ERR_get_error(), NULL))); 00510 break; 00511 00512 case SSL_ERROR_NONE: 00513 break; // no error, but can't make progress 00514 00515 case SSL_ERROR_ZERO_RETURN: 00516 debug(">> SSL_write zero return: EOF\n"); 00517 close(); // EOF 00518 break; 00519 00520 default: 00521 printerr("SSL_write"); 00522 seterr(WvString("SSL write error #%s", sslerrcode)); 00523 break; 00524 } 00525 break; // wait for next iteration 00526 } 00527 else 00528 assert((size_t)result == used); 00529 write_bouncebuf.zap(); // force use of same position in buffer 00530 00531 // locate next chunk to be written 00532 // note: we assume that initial contents of buf and of the 00533 // bouncebuf match since if we got SSL_ERROR_WANT_WRITE 00534 // we did not claim to actually have written the chunk 00535 // that we cached so we will have gotten it again here 00536 if (size_t(result) >= len) 00537 { 00538 // if we cached more previously than we were given, claim 00539 // we wrote what we got and remember to eat the rest later 00540 write_eat = result - len; 00541 total += len; 00542 break; 00543 } 00544 total += size_t(result); 00545 len -= size_t(result); 00546 buf = (const unsigned char *)buf + size_t(result); 00547 } 00548 00549 //debug(">> wrote %s bytes\n", total); 00550 return total; 00551 } 00552 00553 void WvSSLStream::close() 00554 { 00555 debug("Closing SSL connection (ok=%s,sr=%s,sw=%s,child=%s).\n", 00556 isok(), stop_read, stop_write, cloned && cloned->isok()); 00557 00558 if (ssl) 00559 { 00560 ERR_clear_error(); 00561 SSL_shutdown(ssl); 00562 SSL_free(ssl); 00563 ssl = NULL; 00564 sslconnected = false; 00565 } 00566 00567 WvStreamClone::close(); 00568 00569 if (ctx) 00570 { 00571 SSL_CTX_free(ctx); 00572 ctx = NULL; 00573 } 00574 } 00575 00576 00577 bool WvSSLStream::isok() const 00578 { 00579 return ssl && WvStreamClone::isok(); 00580 } 00581 00582 00583 void WvSSLStream::noread() 00584 { 00585 // WARNING: openssl always needs two-way socket communications even for 00586 // one-way encrypted communications, so we don't pass noread/nowrite 00587 // along to the child stream. This should be mostly okay, though, 00588 // because we'll still send it close() once we have both noread() and 00589 // nowrite(). 00590 ssl_stop_read = true; 00591 if (ssl_stop_write) 00592 { 00593 WvStreamClone::nowrite(); 00594 WvStreamClone::noread(); 00595 } 00596 } 00597 00598 00599 void WvSSLStream::nowrite() 00600 { 00601 // WARNING: see note in noread() 00602 ssl_stop_write = true; 00603 if (ssl_stop_read) 00604 { 00605 WvStreamClone::noread(); 00606 WvStreamClone::nowrite(); 00607 } 00608 } 00609 00610 00611 void WvSSLStream::pre_select(SelectInfo &si) 00612 { 00613 SelectRequest oldwant = si.wants; 00614 bool oldinherit = si.inherit_request; 00615 if (!sslconnected) 00616 { 00617 si.wants = connect_wants; 00618 si.inherit_request = true; // ignore force_select() until connected 00619 } 00620 00621 // the SSL library might be keeping its own internal buffers 00622 // or we might have left buffered data behind deliberately 00623 if (si.wants.readable && (read_pending || read_bouncebuf.used())) 00624 { 00625 // debug("pre_select: try reading again immediately.\n"); 00626 si.msec_timeout = 0; 00627 si.inherit_request = oldinherit; 00628 si.wants = oldwant; 00629 return; 00630 } 00631 00632 WvStreamClone::pre_select(si); 00633 si.inherit_request = oldinherit; 00634 si.wants = oldwant; 00635 } 00636 00637 00638 bool WvSSLStream::post_select(SelectInfo &si) 00639 { 00640 SelectRequest oldwant = si.wants; 00641 bool oldinherit = si.inherit_request; 00642 00643 if (!sslconnected) 00644 { 00645 si.wants = connect_wants; 00646 si.inherit_request = true; // ignore force_select() until connected 00647 } 00648 00649 bool result = WvStreamClone::post_select(si); 00650 si.wants = oldwant; 00651 si.inherit_request = oldinherit; 00652 00653 // SSL takes a few round trips to 00654 // initialize itself, and we mustn't block in the constructor, so keep 00655 // trying here... it is also turning into a rather cool place 00656 // to do the validation of the connection ;) 00657 if (!sslconnected && cloned && cloned->isok() && result) 00658 { 00659 debug("!sslconnected in post_select (r=%s/%s, w=%s/%s, t=%s)\n", 00660 cloned->isreadable(), si.wants.readable, 00661 cloned->iswritable(), si.wants.writable, 00662 si.msec_timeout); 00663 00664 connect_wants.writable = false; 00665 00666 // for ssl streams to work, we have to be cloning a stream that 00667 // actually uses a single, valid fd. 00668 WvFDStream *fdstream = static_cast<WvFDStream*>(cloned); 00669 int fd = fdstream->getfd(); 00670 assert(fd >= 0); 00671 ERR_clear_error(); 00672 SSL_set_fd(ssl, fd); 00673 // debug("SSL connected on fd %s.\n", fd); 00674 00675 int err; 00676 00677 if (is_server) 00678 { 00679 // If we are a server, get ready to accept an incoming SSL 00680 // connection 00681 err = SSL_accept(ssl); 00682 } 00683 else 00684 err = SSL_connect(ssl); 00685 00686 if (err < 0) 00687 { 00688 if (errno == EAGAIN) 00689 debug("Still waiting for SSL negotiation.\n"); 00690 else if (!errno) 00691 { 00692 printerr(is_server ? "SSL_accept" : "SSL_connect"); 00693 seterr(WvString("SSL negotiation failed (%s)!", err)); 00694 } 00695 else 00696 { 00697 printerr(is_server ? "SSL_accept" : "SSL_connect"); 00698 seterr(errno); 00699 } 00700 } 00701 else // We're connected, so let's do some checks ;) 00702 { 00703 debug("SSL connection using cipher %s.\n", SSL_get_cipher(ssl)); 00704 00705 WvX509 *peercert = new WvX509(SSL_get_peer_certificate(ssl)); 00706 //Should we try to validate before storing, or not? 00707 if (peercert->isok() && peercert->validate()) 00708 setattr("peercert", peercert->encode(WvX509::CertPEM)); 00709 if (!!vcb) 00710 { 00711 debug("SSL Peer is: %s\n", peercert->get_subject()); 00712 if (peercert->isok() && peercert->validate() && vcb(peercert)) 00713 { 00714 setconnected(true); 00715 debug("SSL finished negotiating - certificate is valid.\n"); 00716 } 00717 else 00718 { 00719 if (!peercert->isok()) 00720 seterr("Peer cert: %s", peercert->errstr()); 00721 else 00722 seterr("Peer certificate is invalid!"); 00723 } 00724 } 00725 else 00726 { 00727 setconnected(true); 00728 debug("SSL finished negotiating " 00729 "- certificate validation disabled.\n"); 00730 } 00731 WVRELEASE(peercert); 00732 } 00733 00734 return false; 00735 } 00736 00737 if ((si.wants.readable || readcb) 00738 && (read_pending || read_bouncebuf.used())) 00739 result = true; 00740 00741 return result; 00742 } 00743 00744 00745 void WvSSLStream::setconnected(bool conn) 00746 { 00747 sslconnected = conn; 00748 if (conn) write(unconnected_buf); 00749 } 00750