00001
00002
00003
00004
00005 #define OPENSSL_NO_KRB5
00006
#include "wvsslstream.h"
00007
#include "wvx509.h"
00008
#include "wvcrypto.h"
00009
#include "wvmoniker.h"
00010
#include <openssl/ssl.h>
00011
#include <openssl/err.h>
00012
#include <assert.h>
00013
00014
#ifdef _WIN32
00015
#undef errno
00016
#define errno GetLastError()
00017
typedef DWORD error_t;
00018
#define EAGAIN WSAEWOULDBLOCK
00019
#endif
00020
00021 static IWvStream *
creator(
WvStringParm s,
IObject *obj,
void *userdata)
00022 {
00023
if (!obj)
00024 obj = wvcreate<IWvStream>(s);
00025
return new WvSSLStream(mutate<IWvStream>(obj),
00026 (
WvX509Mgr *)userdata,
false,
false);
00027 }
00028
00029 static IWvStream *
screator(
WvStringParm s,
IObject *obj,
void *userdata)
00030 {
00031
if (!obj)
00032 obj = wvcreate<IWvStream>(s);
00033
return new WvSSLStream(mutate<IWvStream>(obj),
00034 (
WvX509Mgr *)userdata,
false,
true);
00035 }
00036
00037
static WvMoniker<IWvStream> reg(
"ssl", creator);
00038
static WvMoniker<IWvStream> sreg(
"sslserv", screator);
00039
00040
00041
00042 #define MAX_BOUNCE_AMOUNT (16384) // 1 SSLv3/TLSv1 record
00043
00044 WvSSLStream::WvSSLStream(
IWvStream *_slave,
WvX509Mgr *x509,
00045
bool _verify,
bool _is_server) :
00046
WvStreamClone(_slave), debug("
WvSSLStream",
WvLog::Debug5),
00047 write_bouncebuf(
MAX_BOUNCE_AMOUNT), write_eat(0),
00048 read_bouncebuf(
MAX_BOUNCE_AMOUNT), read_pending(false)
00049 {
00050 verify = _verify;
00051 is_server = _is_server;
00052
00053
wvssl_init();
00054
00055
if (is_server && (x509 == NULL))
00056 {
00057 seterr(
"Certificate not available: server mode not possible!");
00058
return;
00059 }
00060
00061
ctx = NULL;
00062
ssl = NULL;
00063 sslconnected =
false;
00064
00065
if (is_server)
00066 {
00067
meth = SSLv23_server_method();
00068 debug(
"Configured algorithms and methods for server mode.\n");
00069
00070
ctx = SSL_CTX_new(
meth);
00071
if (!
ctx)
00072 {
00073 seterr(
"Can't get SSL context!");
00074
return;
00075 }
00076
00077
00078 SSL_CTX_set_mode(
ctx,SSL_MODE_ENABLE_PARTIAL_WRITE);
00079
00080
00081
00082 SSL_CTX_set_cipher_list(
ctx,
"HIGH");
00083
00084
00085
00086 SSL_CTX_set_options(
ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
00087
00088
if (SSL_CTX_use_certificate(
ctx, x509->cert) <= 0)
00089 {
00090 seterr(
"Error loading certificate!");
00091
return;
00092 }
00093 debug(
"Certificate activated.\n");
00094
00095
if (SSL_CTX_use_RSAPrivateKey(
ctx, x509->rsa->rsa) <= 0)
00096 {
00097 seterr(
"Error loading RSA private key!");
00098
return;
00099 }
00100 debug(
"RSA private key activated.\n");
00101 debug(
"Server mode ready.\n");
00102 }
00103
else
00104 {
00105
meth = SSLv23_client_method();
00106 debug(
"Configured algorithms and methods for client mode.\n");
00107
00108
ctx = SSL_CTX_new(
meth);
00109
if (!
ctx)
00110 {
00111 seterr(
"Can't get SSL context!");
00112
return;
00113 }
00114 }
00115
00116 ERR_clear_error();
00117
ssl = SSL_new(
ctx);
00118
if (!
ssl)
00119 {
00120 seterr(
"Can't create SSL object!");
00121
return;
00122 }
00123
00124 debug(
"SSL stream initialized.\n");
00125
00126
00127 force_select(
false,
true);
00128 }
00129
00130
00131 WvSSLStream::~WvSSLStream()
00132 {
00133
close();
00134
00135 debug(
"Shutting down SSL connection.\n");
00136
if (
geterr())
00137 debug(
"Error was: %s\n",
errstr());
00138
00139
wvssl_free();
00140 }
00141
00142
00143
void WvSSLStream::printerr(
WvStringParm func)
00144 {
00145
unsigned long l = ERR_get_error();
00146
char buf[121];
00147
00148 SSL_load_error_strings();
00149
while (l)
00150 {
00151 ERR_error_string(l, buf);
00152 debug(
"%s error: %s\n", func, buf);
00153 l = ERR_get_error();
00154 }
00155 ERR_free_strings();
00156 }
00157
00158
00159 size_t
WvSSLStream::uread(
void *buf, size_t len)
00160 {
00161
if (!sslconnected)
00162
return 0;
00163
if (len == 0)
return 0;
00164
00165
00166
00167 read_pending =
true;
00168
00169 size_t total = 0;
00170
for (;;)
00171 {
00172
00173
if (read_bouncebuf.
used() != 0)
00174 {
00175
00176 size_t amount = len < read_bouncebuf.
used() ?
00177 len : read_bouncebuf.
used();
00178 read_bouncebuf.
move(buf, amount);
00179
00180
00181 len -= amount;
00182 total += amount;
00183
if (len == 0)
00184
break;
00185 buf = (
unsigned char *)buf + amount;
00186 }
00187
00188
00189 read_bouncebuf.
zap();
00190 size_t avail = read_bouncebuf.
free();
00191
unsigned char *data = read_bouncebuf.
alloc(avail);
00192
00193 ERR_clear_error();
00194
int result = SSL_read(
ssl, data, avail);
00195
if (result <= 0)
00196 {
00197 error_t err = errno;
00198 read_bouncebuf.
unalloc(avail);
00199
int errcode = SSL_get_error(
ssl, result);
00200
switch (errcode)
00201 {
00202
case SSL_ERROR_WANT_READ:
00203
case SSL_ERROR_WANT_WRITE:
00204
00205
break;
00206
00207
case SSL_ERROR_NONE:
00208
break;
00209
00210
case SSL_ERROR_ZERO_RETURN:
00211 debug(
"<< EOF: zero return\n");
00212
close();
00213
break;
00214
00215
case SSL_ERROR_SYSCALL:
00216
if (!err)
00217 {
00218
if (result == 0)
00219 {
00220 debug(
"<< EOF: syscall error\n");
00221
close();
00222 }
00223
break;
00224 }
00225 debug(
"<< SSL_read() %s\n", strerror(errno));
00226
00227
default:
00228 printerr(
"SSL_read");
00229 seterr(
"SSL read error #%s", errcode);
00230
break;
00231 }
00232 read_pending =
false;
00233
break;
00234 }
00235
00236
00237
if (result < 0)
00238 result = 0;
00239 read_bouncebuf.
unalloc(avail - result);
00240 }
00241
00242
00243
return total;
00244 }
00245
00246
00247 size_t
WvSSLStream::uwrite(
const void *buf, size_t len)
00248 {
00249
if (!sslconnected)
00250 {
00251 debug(
">> writing, but not connected yet (%s); enqueue.\n",
getwfd());
00252 unconnected_buf.
put(buf, len);
00253
return len;
00254 }
00255
00256
if (len == 0)
return 0;
00257
00258
00259
00260 size_t total = 0;
00261
00262
00263
if (write_eat >= len)
00264 {
00265 write_eat -= len;
00266 total = len;
00267 len = 0;
00268 }
00269
else
00270 {
00271 buf = (
const unsigned char *)buf + write_eat;
00272 total = write_eat;
00273 len -= write_eat;
00274 write_eat = 0;
00275 }
00276
00277
00278
00279
for (;;)
00280 {
00281
00282
if (write_bouncebuf.
used() == 0)
00283 {
00284
if (len == 0)
break;
00285
00286
00287
00288
00289
00290 size_t amount = len < write_bouncebuf.
free() ?
00291 len : write_bouncebuf.
free();
00292 write_bouncebuf.
put(buf, amount);
00293
00294 }
00295
00296
00297 size_t used = write_bouncebuf.
used();
00298
const unsigned char *data = write_bouncebuf.
get(used);
00299
00300 ERR_clear_error();
00301
int result = SSL_write(
ssl, data, used);
00302
if (result <= 0)
00303 {
00304
int errcode = SSL_get_error(
ssl, result);
00305 write_bouncebuf.
unget(used);
00306
switch (errcode)
00307 {
00308
case SSL_ERROR_WANT_READ:
00309
case SSL_ERROR_WANT_WRITE:
00310 debug(
">> SSL_write() needs to wait for writable.\n");
00311
break;
00312
00313
case SSL_ERROR_SYSCALL:
00314 debug(
">> ERROR: SSL_write() failed on socket error.\n");
00315 seterr(
WvString(
"SSL write error: %s", strerror(errno)));
00316
break;
00317
00318
00319
case SSL_ERROR_SSL:
00320 debug(
">> ERROR: SSL_write() failed on internal error.\n");
00321 seterr(
WvString(
"SSL write error: %s",
00322 ERR_error_string(ERR_get_error(), NULL)));
00323
break;
00324
00325
case SSL_ERROR_NONE:
00326
break;
00327
00328
case SSL_ERROR_ZERO_RETURN:
00329
close();
00330
break;
00331
00332
default:
00333 printerr(
"SSL_write");
00334 seterr(
WvString(
"SSL write error #%s", errcode));
00335
break;
00336 }
00337
break;
00338 }
00339 write_bouncebuf.
zap();
00340
00341
00342
00343
00344
00345
00346
if (size_t(result) >= len)
00347 {
00348
00349
00350 write_eat = result - len;
00351 total += len;
00352
break;
00353 }
00354 total += size_t(result);
00355 len -= size_t(result);
00356 buf = (
const unsigned char *)buf + size_t(result);
00357 }
00358
00359
00360
return total;
00361 }
00362
00363 void WvSSLStream::close()
00364 {
00365
if (
ssl)
00366 {
00367 ERR_clear_error();
00368 SSL_shutdown(
ssl);
00369 SSL_free(
ssl);
00370
ssl = NULL;
00371 sslconnected =
false;
00372 }
00373
00374
WvStreamClone::close();
00375
00376
if (
ctx)
00377 {
00378 SSL_CTX_free(
ctx);
00379
ctx = NULL;
00380 }
00381 }
00382
00383
00384 bool WvSSLStream::isok()
const
00385
{
00386
return ssl &&
WvStreamClone::isok();
00387 }
00388
00389
00390 bool WvSSLStream::pre_select(SelectInfo &si)
00391 {
00392
00393
00394
if (si.wants.readable && (read_pending || read_bouncebuf.
used()))
00395 {
00396
00397
return true;
00398 }
00399
00400
bool result = WvStreamClone::pre_select(si);
00401
00402
return result;
00403 }
00404
00405
00406 bool WvSSLStream::post_select(SelectInfo &si)
00407 {
00408
bool result = WvStreamClone::post_select(si);
00409
00410
00411
00412
00413
00414
00415
00416
if (!sslconnected && cloned && cloned->
isok() && result)
00417 {
00418
00419
00420 undo_force_select(
false,
true,
false);
00421
00422
00423
00424
WvFDStream *fdstream = static_cast<WvFDStream*>(cloned);
00425
int fd = fdstream->
getfd();
00426 assert(fd >= 0);
00427 ERR_clear_error();
00428 SSL_set_fd(
ssl, fd);
00429
00430
00431
int err;
00432
00433
if (is_server)
00434 {
00435
00436
00437 err = SSL_accept(
ssl);
00438 }
00439
else
00440 err = SSL_connect(
ssl);
00441
00442
if (err < 0)
00443 {
00444
if (errno == EAGAIN)
00445 debug(
"Still waiting for SSL negotiation.\n");
00446
else if (!errno)
00447 {
00448 printerr(is_server ?
"SSL_accept" :
"SSL_connect");
00449 seterr(
WvString(
"SSL negotiation failed (%s)!", err));
00450 }
00451
else
00452 {
00453 printerr(is_server ?
"SSL_accept" :
"SSL_connect");
00454 seterr(errno);
00455 }
00456 }
00457
else
00458 {
00459 debug(
"SSL connection using cipher %s.\n", SSL_get_cipher(
ssl));
00460
if (verify)
00461 {
00462
WvX509Mgr peercert(SSL_get_peer_certificate(
ssl));
00463
if (peercert.
isok() && peercert.
validate())
00464 {
00465 setconnected(
true);
00466 debug(
"SSL finished negotiating - certificate is valid.\n");
00467 }
00468
else
00469 {
00470
if (!peercert.
isok())
00471 seterr(peercert.
errstr());
00472
else
00473 seterr(
"Peer certificate is invalid!");
00474 }
00475 }
00476
else
00477 {
00478 setconnected(
true);
00479 debug(
"SSL finished negotiating "
00480
"- certificate validation disabled.\n");
00481 }
00482 }
00483
00484
return false;
00485 }
00486
else
00487
return result;
00488 }
00489
00490
00491
void WvSSLStream::setconnected(
bool conn)
00492 {
00493 sslconnected = conn;
00494
if (conn) write(unconnected_buf);
00495 }
00496