WvStreams
wvsslstream.cc
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