00001 #include "wvsslstream.h"
00002 #include <ssl.h>
00003 #include <err.h>
00004 #include <assert.h>
00005
00006 WvSSLStream::WvSSLStream(WvStream *_slave, WvX509Mgr *x509, bool _verify,
00007 bool _is_server)
00008 : WvStreamClone(&slave), debug("WvSSLStream",WvLog::Debug5)
00009 {
00010 slave = _slave;
00011 verify = _verify;
00012 is_server = _is_server;
00013 read_again = false;
00014 writeonly = 1400;
00015
00016 if (is_server && (x509 == NULL))
00017 {
00018 seterr("Certificate not available, so server mode not possible");
00019 return;
00020 }
00021
00022 SSL_load_error_strings();
00023 SSL_library_init();
00024 debug("SSL Library Initialization Finished\n");
00025
00026 ctx = NULL;
00027 ssl = NULL;
00028 sslconnected = false;
00029
00030 if (is_server)
00031 {
00032 meth = SSLv23_server_method();
00033 debug("Setting Algorithms, and Methods Complete\n");
00034
00035 ctx = SSL_CTX_new(meth);
00036 if (!ctx)
00037 {
00038 seterr("Can't get SSL context!");
00039 return;
00040 }
00041
00042 SSL_CTX_set_mode(ctx,SSL_MODE_ENABLE_PARTIAL_WRITE);
00043
00044 if (SSL_CTX_use_certificate(ctx, x509->cert) <= 0)
00045 {
00046 seterr("Error loading Certificate!");
00047 return;
00048 }
00049 debug("Setting Certificate Complete\n");
00050
00051 if (SSL_CTX_use_RSAPrivateKey(ctx, x509->keypair->rsa) <= 0)
00052 {
00053 seterr("Error loading RSA Private Key!");
00054 return;
00055 }
00056 debug("Setting Private Key Complete\n");
00057 debug("Ready to go for Server mode\n");
00058 }
00059 else
00060 {
00061 meth = SSLv23_client_method();
00062 debug("Setting Algorithms, and Methods Complete\n");
00063
00064 ctx = SSL_CTX_new(meth);
00065 if (!ctx)
00066 {
00067 seterr("Can't get SSL context!");
00068 return;
00069 }
00070
00071 debug("SSL Context Set up\n");
00072
00073 }
00074 ssl = SSL_new(ctx);
00075 if (!ssl)
00076 {
00077 seterr("Can't create SSL object!");
00078 return;
00079 }
00080
00081 debug("SSL Connector initialized\n");
00082
00083
00084 slave->force_select(false, true);
00085 }
00086
00087
00088 WvSSLStream::~WvSSLStream()
00089 {
00090 debug("Shutting down SSL Connection\n");
00091 close();
00092
00093 if (slave)
00094 delete slave;
00095 }
00096
00097
00098 size_t WvSSLStream::uread(void *buf, size_t len)
00099 {
00100 if (!sslconnected)
00101 return 0;
00102
00103 int result = SSL_read(ssl, (char *)buf, len);
00104
00105 if (len > 0 && result == 0)
00106 close();
00107 else if (result < 0)
00108 {
00109 if (errno != EAGAIN)
00110 seterr(errno);
00111 return 0;
00112 }
00113
00114 if (len)
00115 {
00116 if ((size_t)result == len)
00117 read_again = true;
00118 else
00119 read_again = false;
00120 }
00121
00122 debug("<< %s bytes\n", result);
00123
00124 return result;
00125 }
00126
00127
00128 size_t WvSSLStream::uwrite(const void *buf, size_t len)
00129 {
00130
00131 if (!sslconnected)
00132 {
00133 debug(">> Attempting to write to a non-ready SSL Connection/n");
00134 return 0;
00135 }
00136
00137 debug(">> I want to write %s bytes\n",len);
00138
00139
00140
00141 memcpy(bouncebuffer,buf,(writeonly < len) ? writeonly : len);
00142
00143 int result = SSL_write(ssl, bouncebuffer, (writeonly < len) ? writeonly : len);
00144
00145 if (len > 0 && result == 0)
00146 close();
00147 else if (result < 0)
00148 {
00149 switch(SSL_get_error(ssl,result))
00150 {
00151 case SSL_ERROR_WANT_WRITE:
00152 debug(">> ERROR: SSL_write() cannot complete at this time...retry!\n");
00153 writeonly = len;
00154 break;
00155 case SSL_ERROR_NONE:
00156
00157 debug(">> Hmmm... something got confused... no SSL Errors!\n");
00158 break;
00159 default:
00160 debug(">> ERROR: SSL_write() call failed\n");
00161 seterr("SSL Write failed - bailing out of the SSL Session");
00162 break;
00163 }
00164 return 0;
00165 }
00166 else
00167 {
00168 writeonly = 1400;
00169 }
00170
00171 debug(">> SSL wrote %s bytes \t WvStreams wanted to write %s bytes\n",
00172 result, len);
00173
00174 return result;
00175 }
00176
00177
00178 void WvSSLStream::close()
00179 {
00180 if (ssl)
00181 {
00182 SSL_shutdown(ssl);
00183 SSL_free(ssl);
00184 ssl = NULL;
00185 }
00186
00187 WvStreamClone::close();
00188
00189 if (ctx)
00190 {
00191 SSL_CTX_free(ctx);
00192 ctx = NULL;
00193 }
00194 }
00195
00196
00197 bool WvSSLStream::pre_select(SelectInfo &si)
00198 {
00199
00200
00201 if (si.wants.readable && read_again)
00202 {
00203 debug("Have to try reading again!\n");
00204 return true;
00205 }
00206
00207 return WvStreamClone::pre_select(si);
00208
00209 }
00210
00211
00212 bool WvSSLStream::post_select(SelectInfo &si)
00213 {
00214 bool result = WvStreamClone::post_select(si);
00215
00216
00217
00218
00219
00220 if (!sslconnected && slave && slave->isok() && result)
00221 {
00222 slave->undo_force_select(false, true, false);
00223
00224
00225
00226 assert(getrfd() >= 0);
00227 assert(getwfd() >= 0);
00228 assert(getwfd() == getrfd());
00229 SSL_set_fd(ssl, getrfd());
00230 debug("SSL Connected to WvStream %s\n", getrfd());
00231
00232 int err;
00233
00234 if (is_server)
00235 {
00236
00237
00238 err = SSL_accept(ssl);
00239 }
00240 else
00241 err = SSL_connect(ssl);
00242
00243 if (err < 0)
00244 {
00245 if (errno == EAGAIN)
00246 debug("Still Waiting for SSL Connection\n");
00247 else
00248 seterr("SSL negotiation failed!");
00249 }
00250 else
00251 {
00252 debug("SSL Connection using %s\n", SSL_get_cipher(ssl));
00253 if (verify)
00254 {
00255 WvX509Mgr peercert(SSL_get_peer_certificate(ssl));
00256 if (peercert.validate() && !peercert.err)
00257 {
00258 sslconnected = true;
00259 debug("SSL Connection now running\n");
00260 }
00261 else
00262 {
00263 if (peercert.err)
00264 seterr(peercert.errstr);
00265 else
00266 seterr("Peer Certificate cannot be validated");
00267 }
00268 }
00269 else
00270 {
00271 sslconnected = true;
00272 debug("SSL Connection now running\n");
00273 }
00274 }
00275
00276 return false;
00277 }
00278 else
00279 return result;
00280 }
00281