00001
00002
00003
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
00052
00053
00054
00055
00056 ~WvTclParseValues()
00057 { WVRELEASE(m); }
00058 };
00059
00060 static WvTclParseValues *parse_wvtcl_sslcert(WvStringParm s)
00061 {
00062
00063
00064
00065
00066 WvList<WvString> l;
00067 wvtcl_decode(l, s);
00068 if (l.count() > 3 || l.count() < 2)
00069 return NULL;
00070
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()) {
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
00138 connmoniker = *li.last();
00139 li.unlink(li.last());
00140 } else if (li.count() != 2) {
00141
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
00163
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();
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
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
00219 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
00220
00221
00222
00223 SSL_CTX_set_cipher_list(ctx, "HIGH");
00224
00225
00226
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
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
00268
00269
00270
00271
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;
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];
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
00317
00318 read_pending = true;
00319
00320 size_t total = 0;
00321 for (;;)
00322 {
00323
00324 if (read_bouncebuf.used() != 0)
00325 {
00326
00327 size_t amount = len < read_bouncebuf.used() ?
00328 len : read_bouncebuf.used();
00329 read_bouncebuf.move(buf, amount);
00330
00331
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
00342
00343
00344
00345 break;
00346 }
00347
00348
00349 read_bouncebuf.zap();
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
00356
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;
00367 case SSL_ERROR_WANT_WRITE:
00368 debug("<< SSL_read() needs to wait for readable.\n");
00369 break;
00370
00371 case SSL_ERROR_NONE:
00372 break;
00373
00374 case SSL_ERROR_ZERO_RETURN:
00375 debug("<< EOF: zero return\n");
00376
00377
00378
00379
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
00394
00395
00396
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;
00416 }
00417
00418
00419 if (result < 0)
00420 result = 0;
00421 read_bouncebuf.unalloc(avail - result);
00422 }
00423
00424
00425
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
00442
00443 size_t total = 0;
00444
00445
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
00461
00462 for (;;)
00463 {
00464
00465 if (write_bouncebuf.used() == 0)
00466 {
00467 if (len == 0) break;
00468
00469
00470
00471
00472
00473 size_t amount = len < write_bouncebuf.free() ?
00474 len : write_bouncebuf.free();
00475 write_bouncebuf.put(buf, amount);
00476
00477 }
00478
00479
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
00486
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;
00496 case SSL_ERROR_WANT_WRITE:
00497
00498 break;
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
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;
00514
00515 case SSL_ERROR_ZERO_RETURN:
00516 debug(">> SSL_write zero return: EOF\n");
00517 close();
00518 break;
00519
00520 default:
00521 printerr("SSL_write");
00522 seterr(WvString("SSL write error #%s", sslerrcode));
00523 break;
00524 }
00525 break;
00526 }
00527 else
00528 assert((size_t)result == used);
00529 write_bouncebuf.zap();
00530
00531
00532
00533
00534
00535
00536 if (size_t(result) >= len)
00537 {
00538
00539
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
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
00586
00587
00588
00589
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
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;
00619 }
00620
00621
00622
00623 if (si.wants.readable && (read_pending || read_bouncebuf.used()))
00624 {
00625
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;
00647 }
00648
00649 bool result = WvStreamClone::post_select(si);
00650 si.wants = oldwant;
00651 si.inherit_request = oldinherit;
00652
00653
00654
00655
00656
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
00667
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
00674
00675 int err;
00676
00677 if (is_server)
00678 {
00679
00680
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
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
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