00001
00002
00003
00004
00005 #define OPENSSL_NO_KRB5
00006 #include "wvsslstream.h"
00007 #include "wvx509mgr.h"
00008 #include "wvcrypto.h"
00009 #include "wvmoniker.h"
00010 #include "wvlinkerhack.h"
00011 #include <openssl/ssl.h>
00012 #include <openssl/err.h>
00013 #include <assert.h>
00014
00015 #ifndef _WIN32
00016 # if HAVE_ARGZ_H
00017 # include <argz.h>
00018 # else
00019 # if HAVE_ERRNO_H
00020 # include <errno.h>
00021 # endif
00022 # endif
00023 #else
00024 #undef errno
00025 #define errno GetLastError()
00026 #undef EAGAIN
00027 #define EAGAIN WSAEWOULDBLOCK
00028 #define error_t long
00029 #endif
00030
00031 WV_LINK(WvSSLStream);
00032
00033 static IWvStream *creator(WvStringParm s)
00034 {
00035 return new WvSSLStream(wvcreate<IWvStream>(s), NULL, 0, false);
00036 }
00037
00038 static IWvStream *screator(WvStringParm s)
00039 {
00040 return new WvSSLStream(wvcreate<IWvStream>(s), NULL, 0, true);
00041 }
00042
00043 static WvMoniker<IWvStream> reg("ssl", creator);
00044 static WvMoniker<IWvStream> sreg("sslserv", screator);
00045
00046
00047 #define MAX_BOUNCE_AMOUNT (16384) // 1 SSLv3/TLSv1 record
00048
00049 static int ssl_stream_count = 0;
00050
00051 static int wv_verify_cb(int preverify_ok, X509_STORE_CTX *ctx)
00052 {
00053
00054
00055 return 1;
00056 }
00057
00058 WvSSLStream::WvSSLStream(IWvStream *_slave, WvX509Mgr *_x509,
00059 WvSSLValidateCallback _vcb, bool _is_server) :
00060 WvStreamClone(_slave),
00061 debug(WvString("WvSSLStream %s", ++ssl_stream_count), WvLog::Debug5),
00062 write_bouncebuf(MAX_BOUNCE_AMOUNT), write_eat(0),
00063 read_bouncebuf(MAX_BOUNCE_AMOUNT), read_pending(false)
00064 {
00065 x509 = _x509;
00066 if (x509)
00067 x509->addRef();
00068
00069 vcb = _vcb;
00070 is_server = _is_server;
00071 ctx = NULL;
00072 ssl = NULL;
00073
00074 sslconnected = ssl_stop_read = ssl_stop_write = false;
00075
00076 wvssl_init();
00077
00078 if (x509 && !x509->isok())
00079 {
00080 seterr("Certificate + key pair invalid.");
00081 return;
00082 }
00083
00084 if (is_server && !x509)
00085 {
00086 seterr("Certificate not available: server mode not possible!");
00087 return;
00088 }
00089
00090 if (is_server)
00091 {
00092 debug("Configured algorithms and methods for server mode.\n");
00093
00094 ctx = SSL_CTX_new(SSLv23_server_method());
00095 if (!ctx)
00096 {
00097 ERR_print_errors_fp(stderr);
00098 debug("Can't get SSL context! Error: %s\n",
00099 ERR_reason_error_string(ERR_get_error()));
00100 seterr("Can't get SSL context!");
00101 return;
00102 }
00103
00104
00105 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
00106
00107
00108
00109 SSL_CTX_set_cipher_list(ctx, "HIGH");
00110
00111
00112
00113 SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
00114
00115 if (!x509->bind_ssl(ctx))
00116 {
00117 seterr("Unable to bind Certificate to SSL Context!");
00118 return;
00119 }
00120
00121 if (!!vcb)
00122 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
00123 wv_verify_cb);
00124
00125 debug("Server mode ready.\n");
00126 }
00127 else
00128 {
00129 debug("Configured algorithms and methods for client mode.\n");
00130
00131 ctx = SSL_CTX_new(SSLv23_client_method());
00132 if (!ctx)
00133 {
00134 seterr("Can't get SSL context!");
00135 return;
00136 }
00137 if (x509 && !x509->bind_ssl(ctx))
00138 {
00139 seterr("Unable to bind Certificate to SSL Context!");
00140 return;
00141 }
00142 }
00143
00144
00145
00146 ERR_clear_error();
00147 ssl = SSL_new(ctx);
00148 if (!ssl)
00149 {
00150 seterr("Can't create SSL object!");
00151 return;
00152 }
00153
00154 if (!!vcb)
00155 SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
00156 wv_verify_cb);
00157
00158 connect_wants.readable = true;
00159 connect_wants.writable = true;
00160 connect_wants.isexception = false;
00161 debug("SSL stream initialized.\n");
00162 }
00163
00164
00165 WvSSLStream::~WvSSLStream()
00166 {
00167 close();
00168
00169 debug("Deleting SSL connection.\n");
00170 if (geterr())
00171 debug("Error was: %s\n", errstr());
00172
00173 WVRELEASE(x509);
00174 wvssl_free();
00175 }
00176
00177
00178 void WvSSLStream::printerr(WvStringParm func)
00179 {
00180 unsigned long l = ERR_get_error();
00181 char buf[121];
00182
00183 SSL_load_error_strings();
00184 while (l)
00185 {
00186 ERR_error_string(l, buf);
00187 debug("%s error: %s\n", func, buf);
00188 l = ERR_get_error();
00189 }
00190 ERR_free_strings();
00191 }
00192
00193
00194 size_t WvSSLStream::uread(void *buf, size_t len)
00195 {
00196 if (!sslconnected)
00197 return 0;
00198 if (len == 0) return 0;
00199
00200
00201
00202 read_pending = true;
00203
00204 size_t total = 0;
00205 for (;;)
00206 {
00207
00208 if (read_bouncebuf.used() != 0)
00209 {
00210
00211 size_t amount = len < read_bouncebuf.used() ?
00212 len : read_bouncebuf.used();
00213 read_bouncebuf.move(buf, amount);
00214
00215
00216 len -= amount;
00217 total += amount;
00218 if (len == 0)
00219 {
00220 read_pending = false;
00221 break;
00222 }
00223 buf = (unsigned char *)buf + amount;
00224
00225
00226
00227
00228
00229 break;
00230 }
00231
00232
00233 read_bouncebuf.zap();
00234 size_t avail = read_bouncebuf.free();
00235 unsigned char *data = read_bouncebuf.alloc(avail);
00236
00237 ERR_clear_error();
00238 int result = SSL_read(ssl, data, avail);
00239
00240
00241 if (result <= 0)
00242 {
00243 error_t err = errno;
00244 read_bouncebuf.unalloc(avail);
00245 int sslerrcode = SSL_get_error(ssl, result);
00246 switch (sslerrcode)
00247 {
00248 case SSL_ERROR_WANT_READ:
00249 debug("<< SSL_read() needs to wait for writable.\n");
00250 break;
00251 case SSL_ERROR_WANT_WRITE:
00252 debug("<< SSL_read() needs to wait for readable.\n");
00253 break;
00254
00255 case SSL_ERROR_NONE:
00256 break;
00257
00258 case SSL_ERROR_ZERO_RETURN:
00259 debug("<< EOF: zero return\n");
00260
00261
00262
00263
00264 if (!total) { noread(); nowrite(); }
00265 break;
00266
00267 case SSL_ERROR_SYSCALL:
00268 if (!err)
00269 {
00270 if (result == 0)
00271 {
00272 debug("<< EOF: syscall error "
00273 "(%s/%s, %s/%s) total=%s\n",
00274 stop_read, stop_write,
00275 isok(), cloned && cloned->isok(), total);
00276
00277
00278
00279
00280
00281 if (!total) { noread(); nowrite(); }
00282 }
00283 }
00284 else
00285 {
00286 debug("<< SSL_read() err=%s (%s)\n",
00287 err, strerror(err));
00288 seterr_both(err, WvString("SSL read: %s",
00289 strerror(err)));
00290 }
00291 break;
00292
00293 default:
00294 printerr("SSL_read");
00295 seterr("SSL read error #%s", sslerrcode);
00296 break;
00297 }
00298 read_pending = false;
00299 break;
00300 }
00301
00302
00303 if (result < 0)
00304 result = 0;
00305 read_bouncebuf.unalloc(avail - result);
00306 }
00307
00308
00309
00310 return total;
00311 }
00312
00313
00314 size_t WvSSLStream::uwrite(const void *buf, size_t len)
00315 {
00316 if (!sslconnected)
00317 {
00318 debug(">> writing, but not connected yet (%s); enqueue.\n", getwfd());
00319 unconnected_buf.put(buf, len);
00320 return len;
00321 }
00322
00323 if (len == 0) return 0;
00324
00325
00326
00327 size_t total = 0;
00328
00329
00330 if (write_eat >= len)
00331 {
00332 write_eat -= len;
00333 total = len;
00334 len = 0;
00335 }
00336 else
00337 {
00338 buf = (const unsigned char *)buf + write_eat;
00339 total = write_eat;
00340 len -= write_eat;
00341 write_eat = 0;
00342 }
00343
00344
00345
00346 for (;;)
00347 {
00348
00349 if (write_bouncebuf.used() == 0)
00350 {
00351 if (len == 0) break;
00352
00353
00354
00355
00356
00357 size_t amount = len < write_bouncebuf.free() ?
00358 len : write_bouncebuf.free();
00359 write_bouncebuf.put(buf, amount);
00360
00361 }
00362
00363
00364 size_t used = write_bouncebuf.used();
00365 const unsigned char *data = write_bouncebuf.get(used);
00366
00367 ERR_clear_error();
00368 int result = SSL_write(ssl, data, used);
00369
00370
00371 if (result <= 0)
00372 {
00373 int sslerrcode = SSL_get_error(ssl, result);
00374 write_bouncebuf.unget(used);
00375 switch (sslerrcode)
00376 {
00377 case SSL_ERROR_WANT_READ:
00378 debug(">> SSL_write() needs to wait for readable.\n");
00379 break;
00380 case SSL_ERROR_WANT_WRITE:
00381
00382 break;
00383
00384 case SSL_ERROR_SYSCALL:
00385 debug(">> ERROR: SSL_write() failed on socket error.\n");
00386 seterr(WvString("SSL write error: %s", strerror(errno)));
00387 break;
00388
00389
00390 case SSL_ERROR_SSL:
00391 debug(">> ERROR: SSL_write() failed on internal error.\n");
00392 seterr(WvString("SSL write error: %s",
00393 ERR_error_string(ERR_get_error(), NULL)));
00394 break;
00395
00396 case SSL_ERROR_NONE:
00397 break;
00398
00399 case SSL_ERROR_ZERO_RETURN:
00400 debug(">> SSL_write zero return: EOF\n");
00401 close();
00402 break;
00403
00404 default:
00405 printerr("SSL_write");
00406 seterr(WvString("SSL write error #%s", sslerrcode));
00407 break;
00408 }
00409 break;
00410 }
00411 else
00412 assert((size_t)result == used);
00413 write_bouncebuf.zap();
00414
00415
00416
00417
00418
00419
00420 if (size_t(result) >= len)
00421 {
00422
00423
00424 write_eat = result - len;
00425 total += len;
00426 break;
00427 }
00428 total += size_t(result);
00429 len -= size_t(result);
00430 buf = (const unsigned char *)buf + size_t(result);
00431 }
00432
00433
00434 return total;
00435 }
00436
00437 void WvSSLStream::close()
00438 {
00439 debug("Closing SSL connection (ok=%s,sr=%s,sw=%s,child=%s).\n",
00440 isok(), stop_read, stop_write, cloned && cloned->isok());
00441
00442 if (ssl)
00443 {
00444 ERR_clear_error();
00445 SSL_shutdown(ssl);
00446 SSL_free(ssl);
00447 ssl = NULL;
00448 sslconnected = false;
00449 }
00450
00451 WvStreamClone::close();
00452
00453 if (ctx)
00454 {
00455 SSL_CTX_free(ctx);
00456 ctx = NULL;
00457 }
00458 }
00459
00460
00461 bool WvSSLStream::isok() const
00462 {
00463 return ssl && WvStreamClone::isok();
00464 }
00465
00466
00467 void WvSSLStream::noread()
00468 {
00469
00470
00471
00472
00473
00474 ssl_stop_read = true;
00475 if (ssl_stop_write)
00476 {
00477 WvStreamClone::nowrite();
00478 WvStreamClone::noread();
00479 }
00480 }
00481
00482
00483 void WvSSLStream::nowrite()
00484 {
00485
00486 ssl_stop_write = true;
00487 if (ssl_stop_read)
00488 {
00489 WvStreamClone::noread();
00490 WvStreamClone::nowrite();
00491 }
00492 }
00493
00494
00495 void WvSSLStream::pre_select(SelectInfo &si)
00496 {
00497 SelectRequest oldwant = si.wants;
00498 bool oldinherit = si.inherit_request;
00499 if (!sslconnected)
00500 {
00501 si.wants = connect_wants;
00502 si.inherit_request = true;
00503 }
00504
00505
00506
00507 if (si.wants.readable && (read_pending || read_bouncebuf.used()))
00508 {
00509
00510 si.msec_timeout = 0;
00511 si.inherit_request = oldinherit;
00512 si.wants = oldwant;
00513 return;
00514 }
00515
00516 WvStreamClone::pre_select(si);
00517 si.inherit_request = oldinherit;
00518 si.wants = oldwant;
00519 }
00520
00521
00522 bool WvSSLStream::post_select(SelectInfo &si)
00523 {
00524 SelectRequest oldwant = si.wants;
00525 bool oldinherit = si.inherit_request;
00526
00527 if (!sslconnected)
00528 {
00529 si.wants = connect_wants;
00530 si.inherit_request = true;
00531 }
00532
00533 bool result = WvStreamClone::post_select(si);
00534 si.wants = oldwant;
00535 si.inherit_request = oldinherit;
00536
00537
00538
00539
00540
00541 if (!sslconnected && cloned && cloned->isok() && result)
00542 {
00543 debug("!sslconnected in post_select (r=%s/%s, w=%s/%s, t=%s)\n",
00544 cloned->isreadable(), si.wants.readable,
00545 cloned->iswritable(), si.wants.writable,
00546 si.msec_timeout);
00547
00548 connect_wants.writable = false;
00549
00550
00551
00552 WvFDStream *fdstream = static_cast<WvFDStream*>(cloned);
00553 int fd = fdstream->getfd();
00554 assert(fd >= 0);
00555 ERR_clear_error();
00556 SSL_set_fd(ssl, fd);
00557
00558
00559 int err;
00560
00561 if (is_server)
00562 {
00563
00564
00565 err = SSL_accept(ssl);
00566 }
00567 else
00568 err = SSL_connect(ssl);
00569
00570 if (err < 0)
00571 {
00572 if (errno == EAGAIN)
00573 debug("Still waiting for SSL negotiation.\n");
00574 else if (!errno)
00575 {
00576 printerr(is_server ? "SSL_accept" : "SSL_connect");
00577 seterr(WvString("SSL negotiation failed (%s)!", err));
00578 }
00579 else
00580 {
00581 printerr(is_server ? "SSL_accept" : "SSL_connect");
00582 seterr(errno);
00583 }
00584 }
00585 else
00586 {
00587 debug("SSL connection using cipher %s.\n", SSL_get_cipher(ssl));
00588 if (!!vcb)
00589 {
00590 WvX509 *peercert = new WvX509(SSL_get_peer_certificate(ssl));
00591 debug("SSL Peer is: %s\n", peercert->get_subject());
00592 if (peercert->isok() && peercert->validate() && vcb(peercert))
00593 {
00594 setconnected(true);
00595 debug("SSL finished negotiating - certificate is valid.\n");
00596 }
00597 else
00598 {
00599 if (!peercert->isok())
00600 seterr("Peer cert: %s", peercert->errstr());
00601 else
00602 seterr("Peer certificate is invalid!");
00603 }
00604 WVRELEASE(peercert);
00605 }
00606 else
00607 {
00608 setconnected(true);
00609 debug("SSL finished negotiating "
00610 "- certificate validation disabled.\n");
00611 }
00612 }
00613
00614 return false;
00615 }
00616
00617 if ((si.wants.readable || readcb)
00618 && (read_pending || read_bouncebuf.used()))
00619 result = true;
00620
00621 return result;
00622 }
00623
00624
00625 void WvSSLStream::setconnected(bool conn)
00626 {
00627 sslconnected = conn;
00628 if (conn) write(unconnected_buf);
00629 }
00630