2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 #define OPENSSL_NO_KRB5
6 #include "wvsslstream.h"
9 #include "wvlistener.h"
10 #include "wvstrutils.h"
11 #include "wvmoniker.h"
12 #include "wvlinkerhack.h"
13 #include <openssl/ssl.h>
14 #include <openssl/err.h>
27 #define errno GetLastError()
29 #define EAGAIN WSAEWOULDBLOCK
35 static IWvStream
*creator(WvStringParm s
, IObject
*_obj
)
37 return new WvSSLStream(IWvStream::create(s
, _obj
), NULL
, 0, false);
40 static IWvStream
*screator(WvStringParm s
, IObject
*_obj
)
42 return new WvSSLStream(IWvStream::create(s
, _obj
),
43 new WvX509Mgr(encode_hostname_as_DN(fqdomainname()), 1024),
47 static WvMoniker
<IWvStream
> reg("ssl", creator
);
48 static WvMoniker
<IWvStream
> sreg("sslserv", screator
);
50 static IWvListener
*listener(WvStringParm s
, IObject
*obj
)
52 IWvListener
*l
= IWvListener::create(s
, obj
);
54 l
->addwrap(wv::bind(&IWvStream::create
, "sslserv", _1
));
58 static WvMoniker
<IWvListener
> lreg("ssl", listener
);
61 #define MAX_BOUNCE_AMOUNT (16384) // 1 SSLv3/TLSv1 record
63 static int ssl_stream_count
= 0;
65 static int wv_verify_cb(int preverify_ok
, X509_STORE_CTX
*ctx
)
67 // This is just returns true, since what we really want
68 // is for the WvSSLValidateCallback to do this work
72 WvSSLStream::WvSSLStream(IWvStream
*_slave
, WvX509Mgr
*_x509
,
73 WvSSLValidateCallback _vcb
, bool _is_server
) :
74 WvStreamClone(_slave
),
75 debug(WvString("WvSSLStream %s", ++ssl_stream_count
), WvLog::Debug5
),
76 write_bouncebuf(MAX_BOUNCE_AMOUNT
), write_eat(0),
77 read_bouncebuf(MAX_BOUNCE_AMOUNT
), read_pending(false)
81 x509
->addRef(); // openssl may keep a pointer to this object
84 is_server
= _is_server
;
88 sslconnected
= ssl_stop_read
= ssl_stop_write
= false;
92 if (x509
&& !x509
->isok())
94 seterr("Certificate + key pair invalid.");
98 if (is_server
&& !x509
)
100 seterr("Certificate not available: server mode not possible!");
106 debug("Configured algorithms and methods for server mode.\n");
108 ctx
= SSL_CTX_new(SSLv23_server_method());
111 ERR_print_errors_fp(stderr
);
112 debug("Can't get SSL context! Error: %s\n",
113 ERR_reason_error_string(ERR_get_error()));
114 seterr("Can't get SSL context!");
118 // Allow SSL Writes to only write part of a request...
119 SSL_CTX_set_mode(ctx
, SSL_MODE_ENABLE_PARTIAL_WRITE
);
121 // Tell SSL to use 128 bit or better ciphers - this appears to
122 // be necessary for some reason... *sigh*
123 SSL_CTX_set_cipher_list(ctx
, "HIGH");
125 // Enable the workarounds for broken clients and servers
126 // and disable the insecure SSLv2 protocol
127 SSL_CTX_set_options(ctx
, SSL_OP_ALL
|SSL_OP_NO_SSLv2
);
129 if (!x509
->bind_ssl(ctx
))
131 seterr("Unable to bind Certificate to SSL Context!");
136 SSL_CTX_set_verify(ctx
, SSL_VERIFY_PEER
|SSL_VERIFY_CLIENT_ONCE
,
139 debug("Server mode ready.\n");
143 debug("Configured algorithms and methods for client mode.\n");
145 ctx
= SSL_CTX_new(SSLv23_client_method());
148 seterr("Can't get SSL context!");
151 if (x509
&& !x509
->bind_ssl(ctx
))
153 seterr("Unable to bind Certificate to SSL Context!");
158 //SSL_CTX_set_read_ahead(ctx, 1);
164 seterr("Can't create SSL object!");
169 SSL_set_verify(ssl
, SSL_VERIFY_PEER
|SSL_VERIFY_CLIENT_ONCE
,
172 connect_wants
.readable
= true;
173 connect_wants
.writable
= true; // force ssl initiation ASAP
174 connect_wants
.isexception
= false;
175 debug("SSL stream initialized.\n");
179 WvSSLStream::~WvSSLStream()
183 debug("Deleting SSL connection.\n");
185 debug("Error was: %s\n", errstr());
192 void WvSSLStream::printerr(WvStringParm func
)
194 unsigned long l
= ERR_get_error();
195 char buf
[121]; // man ERR_error_string says must be > 120.
197 SSL_load_error_strings();
200 ERR_error_string(l
, buf
);
201 debug("%s error: %s\n", func
, buf
);
208 size_t WvSSLStream::uread(void *buf
, size_t len
)
212 if (len
== 0) return 0;
214 // if SSL buffers stuff on its own, select() may not wake us up
215 // the next time around unless we're sure there is nothing left
221 // handle SSL_read quirk
222 if (read_bouncebuf
.used() != 0)
224 // copy out cached data
225 size_t amount
= len
< read_bouncebuf
.used() ?
226 len
: read_bouncebuf
.used();
227 read_bouncebuf
.move(buf
, amount
);
229 // locate next chunk in buffer
234 read_pending
= false;
237 buf
= (unsigned char *)buf
+ amount
;
239 // FIXME: this shouldn't be necessary, but it resolves weird
240 // problems when the other end disconnects in the middle of
241 // SSL negotiation, but only on emakela's machine. I don't
242 // know why. -- apenwarr (2004/02/10)
247 read_bouncebuf
.zap(); // force use of same position in buffer
248 size_t avail
= read_bouncebuf
.free();
249 unsigned char *data
= read_bouncebuf
.alloc(avail
);
252 int result
= SSL_read(ssl
, data
, avail
);
253 // debug("<< SSL_read result %s for %s bytes (wanted %s)\n",
254 // result, avail, len);
258 read_bouncebuf
.unalloc(avail
);
259 int sslerrcode
= SSL_get_error(ssl
, result
);
262 case SSL_ERROR_WANT_READ
:
263 debug("<< SSL_read() needs to wait for writable.\n");
264 break; // wait for later
265 case SSL_ERROR_WANT_WRITE
:
266 debug("<< SSL_read() needs to wait for readable.\n");
267 break; // wait for later
270 break; // no error, but can't make progress
272 case SSL_ERROR_ZERO_RETURN
:
273 debug("<< EOF: zero return\n");
275 // don't do this if we're returning nonzero!
276 // (SSL has no way to do a one-way shutdown, so if SSL
277 // detects a read problem, it's also a write problem.)
278 if (!total
) { noread(); nowrite(); }
281 case SSL_ERROR_SYSCALL
:
286 debug("<< EOF: syscall error "
287 "(%s/%s, %s/%s) total=%s\n",
288 stop_read
, stop_write
,
289 isok(), cloned
&& cloned
->isok(), total
);
291 // don't do this if we're returning nonzero!
292 // (SSL has no way to do a one-way shutdown, so
293 // if SSL detects a read problem, it's also a
295 if (!total
) { noread(); nowrite(); }
300 debug("<< SSL_read() err=%s (%s)\n",
302 seterr_both(err
, WvString("SSL read: %s",
308 printerr("SSL_read");
309 seterr("SSL read error #%s", sslerrcode
);
312 read_pending
= false;
313 break; // wait for next iteration
315 // debug("<< read result was %s\n", result);
319 read_bouncebuf
.unalloc(avail
- result
);
322 // debug("<< read %s bytes (%s, %s)\n",
323 // total, isok(), cloned && cloned->isok());
328 size_t WvSSLStream::uwrite(const void *buf
, size_t len
)
332 debug(">> writing, but not connected yet (%s); enqueue.\n", getwfd());
333 unconnected_buf
.put(buf
, len
);
337 if (len
== 0) return 0;
339 // debug(">> I want to write %s bytes.\n", len);
343 // eat any data that was precached and already written
344 if (write_eat
>= len
)
352 buf
= (const unsigned char *)buf
+ write_eat
;
358 // FIXME: WOW!!! Ummm... hope this never spins...
362 // handle SSL_write quirk
363 if (write_bouncebuf
.used() == 0)
367 // copy new data into the bounce buffer only if empty
368 // if it were not empty, then SSL_write probably returned
369 // SSL_ERROR_WANT_WRITE on the previous call and we
370 // must invoke it with precisely the same arguments
371 size_t amount
= len
< write_bouncebuf
.free() ?
372 len
: write_bouncebuf
.free();
373 write_bouncebuf
.put(buf
, amount
);
374 // note: we don't adjust the total yet...
375 } // otherwise we use what we cached last time in bounce buffer
378 size_t used
= write_bouncebuf
.used();
379 const unsigned char *data
= write_bouncebuf
.get(used
);
382 int result
= SSL_write(ssl
, data
, used
);
383 // debug("<< SSL_write result %s for %s bytes\n",
387 int sslerrcode
= SSL_get_error(ssl
, result
);
388 write_bouncebuf
.unget(used
);
391 case SSL_ERROR_WANT_READ
:
392 debug(">> SSL_write() needs to wait for readable.\n");
393 break; // wait for later
394 case SSL_ERROR_WANT_WRITE
:
395 // debug(">> SSL_write() needs to wait for writable.\n");
396 break; // wait for later
398 case SSL_ERROR_SYSCALL
:
399 debug(">> ERROR: SSL_write() failed on socket error.\n");
400 seterr(WvString("SSL write error: %s", strerror(errno
)));
403 // This case can cause truncated web pages... give more info
405 debug(">> ERROR: SSL_write() failed on internal error.\n");
406 seterr(WvString("SSL write error: %s",
407 ERR_error_string(ERR_get_error(), NULL
)));
411 break; // no error, but can't make progress
413 case SSL_ERROR_ZERO_RETURN
:
414 debug(">> SSL_write zero return: EOF\n");
419 printerr("SSL_write");
420 seterr(WvString("SSL write error #%s", sslerrcode
));
423 break; // wait for next iteration
426 assert((size_t)result
== used
);
427 write_bouncebuf
.zap(); // force use of same position in buffer
429 // locate next chunk to be written
430 // note: we assume that initial contents of buf and of the
431 // bouncebuf match since if we got SSL_ERROR_WANT_WRITE
432 // we did not claim to actually have written the chunk
433 // that we cached so we will have gotten it again here
434 if (size_t(result
) >= len
)
436 // if we cached more previously than we were given, claim
437 // we wrote what we got and remember to eat the rest later
438 write_eat
= result
- len
;
442 total
+= size_t(result
);
443 len
-= size_t(result
);
444 buf
= (const unsigned char *)buf
+ size_t(result
);
447 //debug(">> wrote %s bytes\n", total);
451 void WvSSLStream::close()
453 debug("Closing SSL connection (ok=%s,sr=%s,sw=%s,child=%s).\n",
454 isok(), stop_read
, stop_write
, cloned
&& cloned
->isok());
462 sslconnected
= false;
465 WvStreamClone::close();
475 bool WvSSLStream::isok() const
477 return ssl
&& WvStreamClone::isok();
481 void WvSSLStream::noread()
483 // WARNING: openssl always needs two-way socket communications even for
484 // one-way encrypted communications, so we don't pass noread/nowrite
485 // along to the child stream. This should be mostly okay, though,
486 // because we'll still send it close() once we have both noread() and
488 ssl_stop_read
= true;
491 WvStreamClone::nowrite();
492 WvStreamClone::noread();
497 void WvSSLStream::nowrite()
499 // WARNING: see note in noread()
500 ssl_stop_write
= true;
503 WvStreamClone::noread();
504 WvStreamClone::nowrite();
509 void WvSSLStream::pre_select(SelectInfo
&si
)
511 SelectRequest oldwant
= si
.wants
;
512 bool oldinherit
= si
.inherit_request
;
515 si
.wants
= connect_wants
;
516 si
.inherit_request
= true; // ignore force_select() until connected
519 // the SSL library might be keeping its own internal buffers
520 // or we might have left buffered data behind deliberately
521 if (si
.wants
.readable
&& (read_pending
|| read_bouncebuf
.used()))
523 // debug("pre_select: try reading again immediately.\n");
525 si
.inherit_request
= oldinherit
;
530 WvStreamClone::pre_select(si
);
531 si
.inherit_request
= oldinherit
;
536 bool WvSSLStream::post_select(SelectInfo
&si
)
538 SelectRequest oldwant
= si
.wants
;
539 bool oldinherit
= si
.inherit_request
;
543 si
.wants
= connect_wants
;
544 si
.inherit_request
= true; // ignore force_select() until connected
547 bool result
= WvStreamClone::post_select(si
);
549 si
.inherit_request
= oldinherit
;
551 // SSL takes a few round trips to
552 // initialize itself, and we mustn't block in the constructor, so keep
553 // trying here... it is also turning into a rather cool place
554 // to do the validation of the connection ;)
555 if (!sslconnected
&& cloned
&& cloned
->isok() && result
)
557 debug("!sslconnected in post_select (r=%s/%s, w=%s/%s, t=%s)\n",
558 cloned
->isreadable(), si
.wants
.readable
,
559 cloned
->iswritable(), si
.wants
.writable
,
562 connect_wants
.writable
= false;
564 // for ssl streams to work, we have to be cloning a stream that
565 // actually uses a single, valid fd.
566 WvFDStream
*fdstream
= static_cast<WvFDStream
*>(cloned
);
567 int fd
= fdstream
->getfd();
571 // debug("SSL connected on fd %s.\n", fd);
577 // If we are a server, get ready to accept an incoming SSL
579 err
= SSL_accept(ssl
);
582 err
= SSL_connect(ssl
);
587 debug("Still waiting for SSL negotiation.\n");
590 printerr(is_server
? "SSL_accept" : "SSL_connect");
591 seterr(WvString("SSL negotiation failed (%s)!", err
));
595 printerr(is_server
? "SSL_accept" : "SSL_connect");
599 else // We're connected, so let's do some checks ;)
601 debug("SSL connection using cipher %s.\n", SSL_get_cipher(ssl
));
604 WvX509
*peercert
= new WvX509(SSL_get_peer_certificate(ssl
));
605 debug("SSL Peer is: %s\n", peercert
->get_subject());
606 if (peercert
->isok() && peercert
->validate() && vcb(peercert
))
609 debug("SSL finished negotiating - certificate is valid.\n");
613 if (!peercert
->isok())
614 seterr("Peer cert: %s", peercert
->errstr());
616 seterr("Peer certificate is invalid!");
623 debug("SSL finished negotiating "
624 "- certificate validation disabled.\n");
631 if ((si
.wants
.readable
|| readcb
)
632 && (read_pending
|| read_bouncebuf
.used()))
639 void WvSSLStream::setconnected(bool conn
)
642 if (conn
) write(unconnected_buf
);