00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #define ULXR_NEED_EXPORTS
00032 #include <ulxmlrpcpp/ulxmlrpcpp.h>
00033
00034 #ifdef ULXR_INCLUDE_SSL_STUFF
00035
00036 #include <ulxmlrpcpp/contrib/ssl_connection.h>
00037
00038 #include <openssl/err.h>
00039
00040
00041 #include <deque>
00042 #include <iostream>
00043
00044 #include <errno.h>
00045
00046
00047 namespace funtik {
00048
00049
00050 ULXR_API_IMPL0 SSLConnectionException::SSLConnectionException():
00051 ulxr::ConnectionException(ulxr::SystemError,ULXR_PCHAR("SSL error"),500)
00052 {
00053 this->_what+="SSLError:";
00054 this->_what+=get_error_queue();
00055 }
00056
00057 ULXR_API_IMPL0 SSLConnectionException::SSLConnectionException(ulxr::CppString strPhrase, int stat):
00058 ulxr::ConnectionException(ulxr::SystemError,ULXR_PCHAR("SSL error"),stat)
00059 {
00060 this->_what+=ulxr::getLatin1(strPhrase);
00061 }
00062
00063 ULXR_API_IMPL0 SSLConnectionException::SSLConnectionException(SSL *ssl, int ret_code):
00064 ulxr::ConnectionException(ulxr::SystemError,ULXR_PCHAR("SSL error"),500)
00065 {
00066 this->_what+="SSLError:";
00067 int err=SSL_get_error(ssl,ret_code);
00068 switch (err)
00069 {
00070 case SSL_ERROR_NONE:
00071 this->_what+=" SSL_ERROR_NONE";
00072 break;
00073 case SSL_ERROR_ZERO_RETURN:
00074 this->_what+=" SSL_ERROR_ZERO_RETURN";
00075 break;
00076 case SSL_ERROR_WANT_READ:
00077 this->_what+=" SSL_ERROR_WANT_READ";
00078 break;
00079 case SSL_ERROR_WANT_WRITE:
00080 this->_what+=" SSL_ERROR_WANT_WRITE";
00081 break;
00082 case SSL_ERROR_WANT_CONNECT:
00083 this->_what+=" SSL_ERROR_WANT_CONNECT";
00084 break;
00085
00086 #ifdef ULXR_HAVE_SSL_ERROR_WANT_ACCEPT
00087 case SSL_ERROR_WANT_ACCEPT:
00088 this->_what+=" SSL_ERROR_WANT_ACCEPT";
00089 break;
00090 #endif
00091
00092 case SSL_ERROR_WANT_X509_LOOKUP:
00093 this->_what+=" SSL_ERROR_WANT_X509_LOOKUP";
00094 break;
00095 case SSL_ERROR_SYSCALL:
00096 {
00097 std::string error_queue=get_error_queue();
00098 if ( !error_queue.empty())
00099 this->_what+=error_queue;
00100 else
00101 {
00102 this->_what+=" ";
00103 if (ret_code==0)
00104 this->_what+="an EOF was observed";
00105 else if (ret_code==-1)
00106 this->_what+=ulxr::getLatin1(ulxr::getLastErrorString(errno));
00107 else
00108 this->_what+="unknown error";
00109 }
00110 }
00111 break;
00112 case SSL_ERROR_SSL:
00113 this->_what+=get_error_queue();
00114 break;
00115 default:
00116 this->_what+=" unknown error code";
00117 }
00118
00119 }
00120
00121 ULXR_API_IMPL(std::string) SSLConnectionException::get_error_queue()
00122 {
00123 typedef std::deque<unsigned long> __list_type;
00124
00125 __list_type errors;
00126 unsigned long error_code;
00127 char buf[120];
00128 std::string __ret;
00129
00130 while ((error_code=ERR_get_error())!=0)
00131 errors.push_front(error_code);
00132 for (__list_type::const_iterator error=errors.begin();error!=errors.end();++error)
00133 {
00134 __ret+="\n";
00135 ERR_error_string_n(*error,buf,sizeof(buf));
00136 __ret+=buf;
00137 }
00138 return __ret;
00139 }
00140
00141 ULXR_API_IMPL(ulxr::CppString) SSLConnectionException::why() const
00142 {
00143 #ifdef ULXR_UNICODE
00144 return ulxr::getUnicode(_what.c_str());
00145 #else
00146 return _what.c_str();
00147 #endif
00148 }
00149
00150 ULXR_API_IMPL(const char *) SSLConnectionException::what() const throw()
00151 {
00152 return _what.c_str();
00153 }
00154
00155 static int s_server_session_id_context = 1;
00156 static int s_server_auth_session_id_context = 2;
00157
00158 bool SSLConnection::ssl_initialized = false;
00159
00160
00161
00162 static int password_cb(char *buf,int num, int , void *userdata)
00163 {
00164 ULXR_TRACE(ULXR_PCHAR("password_cb"));
00165 SSLConnection *conn = (SSLConnection *)userdata;
00166 std::string pass = conn->getPassword();
00167
00168 if((unsigned int)num < pass.length()+1)
00169 return 0;
00170
00171 strncpy(buf, pass.c_str(),num);
00172 return(strlen(buf));
00173 }
00174
00175
00176
00177
00178
00179
00180 ULXR_API_IMPL0 SSLConnection::SSLConnection(bool I_am_server, const ulxr::CppString &domain, unsigned port)
00181 : ulxr::TcpIpConnection(I_am_server, domain, port)
00182 {
00183 ULXR_TRACE(ULXR_PCHAR("SSLConnection"));
00184 init();
00185 }
00186
00187
00188 ULXR_API_IMPL0 SSLConnection::SSLConnection(bool I_am_server, long adr, unsigned port)
00189 : ulxr::TcpIpConnection(I_am_server, adr, port)
00190 {
00191 ULXR_TRACE(ULXR_PCHAR("SSLConnection"));
00192 init();
00193 }
00194
00195
00196 ULXR_API_IMPL(void)
00197 SSLConnection::setCryptographyData (const std::string &in_password,
00198 const std::string &in_certfile,
00199 const std::string &in_keyfile)
00200 {
00201
00202 m_strPassword = in_password;
00203
00204 if(in_certfile.size()>0)
00205 {
00206 if (SSL_CTX_use_certificate_file(ssl_ctx, in_certfile.c_str(), SSL_FILETYPE_PEM) <= 0)
00207 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("SSLConnection::setCryptographyData: problem setting up certificate from file: ")+ULXR_GET_STRING(in_certfile)), 500);
00208 m_strCertFileName = in_certfile;
00209 }
00210
00211 if(in_keyfile.size()>0)
00212 {
00213 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, in_keyfile.c_str(), SSL_FILETYPE_PEM) <= 0)
00214 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("SSLConnection::setCryptographyData: problem setting up key from file: ")+ULXR_GET_STRING(in_keyfile)), 500);
00215 m_strKeyFileName = in_keyfile;
00216 }
00217 }
00218
00219
00220
00221
00222 ULXR_API_IMPL(void) SSLConnection::initializeCTX()
00223 {
00224 ULXR_TRACE(ULXR_PCHAR("initializeCTX"));
00225
00226
00227 if (ssl_ctx != 0)
00228 SSL_CTX_free(ssl_ctx);
00229
00230 SSL_METHOD *meth = SSLv23_method();
00231
00232 ssl_ctx = SSL_CTX_new (meth);
00233
00235 if (!ssl_ctx)
00236 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("Cann`t initialize CTX context")), 500);
00237
00238
00239 SSL_CTX_set_default_passwd_cb(ssl_ctx, password_cb);
00240 SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, this);
00241
00242
00243 ssl = 0;
00244
00245 if (isServerMode())
00246 {
00247 if (0 >= SSL_CTX_set_session_id_context(ssl_ctx,
00248 (const unsigned char *)&s_server_session_id_context,
00249 sizeof s_server_session_id_context))
00250 {
00251 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("Context session error")), 500);
00252
00253 }
00254 }
00255 }
00256
00257
00258 ULXR_API_IMPL(void) SSLConnection::init()
00259 {
00260 ULXR_TRACE(ULXR_PCHAR("init"));
00261 session = 0;
00262 m_iAuthType=0;
00263 ssl_ctx=0;
00264 if (!ssl_initialized)
00265 {
00266 SSL_library_init();
00267 SSLeay_add_ssl_algorithms();
00268 SSL_load_error_strings();
00269 ssl_initialized = true;
00270 }
00271 initializeCTX();
00272 }
00273
00274
00275 ULXR_API_IMPL0 SSLConnection::~SSLConnection()
00276 {
00277 ULXR_TRACE(ULXR_PCHAR("~SSLConnection"));
00278 close();
00279
00280 if (ssl_ctx != 0)
00281 SSL_CTX_free(ssl_ctx);
00282 ssl_ctx = 0;
00283
00284 ULXR_TRACE(ULXR_PCHAR("~SSLConnection 2"));
00285
00286
00287 if (0 != session)
00288 SSL_SESSION_free(session);
00289 session = 0;
00290 }
00291
00292
00293 ULXR_API_IMPL(void) SSLConnection::close()
00294 {
00295 ULXR_TRACE(ULXR_PCHAR("close"));
00296
00297 if (!isServerMode())
00298 {
00299 if (0 != session)
00300 {
00301 SSL_SESSION_free(session);
00302 session=0;
00303 }
00304 if(0 != ssl)
00305 session = SSL_get1_session(ssl);
00306 }
00307
00308 ULXR_TRACE(ULXR_PCHAR("close 2"));
00309
00310 ulxr::TcpIpConnection::close();
00311
00312 if (ssl != 0)
00313 SSL_free(ssl);
00314 ssl = 0;
00315 }
00316
00317
00318 ULXR_API_IMPL(ssize_t) SSLConnection::low_level_write(char const *buff, long len)
00319 {
00320 ULXR_TRACE(ULXR_PCHAR("low_level_write"));
00321
00322 if (isConnecting())
00323 return TcpIpConnection::low_level_write(buff, len);
00324
00325 ssize_t ret;
00326 while (true)
00327 {
00328 ULXR_TRACE(ULXR_PCHAR("low_level_write 2"));
00329 ret = SSL_write(ssl, buff, len);
00330 ULXR_TRACE(ULXR_PCHAR("low_level_write 3 ") << ret);
00331 if (ret >= 0)
00332 break;
00333 else
00334 throw SSLConnectionException(ssl, ret);
00335
00336 }
00337 return ret;
00338 }
00339
00340
00341 ULXR_API_IMPL(bool) SSLConnection::hasPendingInput() const
00342 {
00343 if (isConnecting())
00344 return TcpIpConnection::hasPendingInput();
00345
00346 int avail = SSL_pending(ssl);
00347 ULXR_TRACE(ULXR_PCHAR("hasPendingInput ") << avail);
00348 return avail != 0;
00349 }
00350
00351
00352 ULXR_API_IMPL(ssize_t) SSLConnection::low_level_read(char *buff, long len)
00353 {
00354 ULXR_TRACE(ULXR_PCHAR("low_level_read"));
00355
00356 if (isConnecting())
00357 return TcpIpConnection::low_level_read(buff, len);
00358
00359 ssize_t ret;
00360 while (true)
00361 {
00362 ULXR_TRACE(ULXR_PCHAR("low_level_read 2"));
00363 ret = SSL_read(ssl, buff, len);
00364 ULXR_TRACE(ULXR_PCHAR("low_level_read 3 ") << ret);
00365 if (ret >= 0)
00366 break;
00367 else
00368 throw SSLConnectionException(ssl, ret);
00369 }
00370 return ret;
00371 }
00372
00373
00374 ulxr::Connection *ULXR_API_IMPL0 SSLConnection::detach()
00375 {
00376 ULXR_TRACE(ULXR_PCHAR("detach"));
00377 SSLConnection *clone = new SSLConnection(*this);
00378
00379 ssl_ctx=0;
00380 ssl=0;
00381 session=0;
00382
00383
00384 cut();
00385
00386 clone->setServerData(getServerData());
00387 if (getServerData() != 0)
00388 getServerData()->incRef();
00389
00390 return clone;
00391 }
00392
00393
00394 ULXR_API_IMPL(void) SSLConnection::createSSL()
00395 {
00396 ULXR_TRACE(ULXR_PCHAR("createSSL"));
00397 if(ssl != 0)
00398 SSL_free(ssl);
00399 ssl = SSL_new (ssl_ctx);
00400 if (ssl == 0)
00401 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("problem creating SSL conext object")), 500);
00402
00403 int err = SSL_set_fd (ssl, getHandle());
00404 if (err == 0)
00405 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("problem set file descriptor for SSL")), 500);
00406
00407 if (isServerMode())
00408 {
00409 if (0 >= SSL_set_session_id_context(ssl,
00410 (const unsigned char *)&s_server_auth_session_id_context,
00411 sizeof(s_server_auth_session_id_context)))
00412 {
00413 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("Context session error")), 500);
00414
00415 }
00416 }
00417 }
00418
00419
00420 ULXR_API_IMPL(void) SSLConnection::open()
00421 {
00422 ULXR_TRACE(ULXR_PCHAR("open"));
00423
00424 ulxr::TcpIpConnection::open();
00425
00426 doConnect();
00427
00428 int err;
00429 createSSL();
00430
00431 if (0 != session)
00432 {
00433 ULXR_TRACE(ULXR_PCHAR("SSL_set_session"));
00434 SSL_set_session(ssl, session);
00435 }
00436
00437 err = SSL_connect (ssl);
00438 X509 *peer_cert=0;
00439 try{
00440 if (err <= 0)
00441 throw SSLConnectionException(ssl, err);
00442
00443 peer_cert=SSL_get_peer_certificate(ssl);
00444 if(!checkAccess(peer_cert))
00445 throw SSLConnectionException(ULXR_PCHAR("Fault fingerprint of certificate. Access denied."),500);
00446
00447 if(peer_cert!=0)
00448 X509_free(peer_cert);
00449 }
00450 catch(SSLConnectionException& ex)
00451 {
00452
00453 if(peer_cert!=0)
00454 X509_free(peer_cert);
00455 close();
00456 throw;
00457 }
00458 }
00459
00460
00461 ULXR_API_IMPL(void) SSLConnection::accept()
00462 {
00463 ULXR_TRACE(ULXR_PCHAR("accept"));
00464
00465 ulxr::TcpIpConnection::accept();
00466 createSSL();
00467
00468 int err = SSL_accept (ssl);
00469 X509 *peer_cert=0;
00470 try{
00471 if (err <= 0)
00472 throw SSLConnectionException(ssl, err);
00473
00474 peer_cert=SSL_get_peer_certificate(ssl);
00475 if(!checkAccess(peer_cert))
00476 throw SSLConnectionException(ULXR_PCHAR("Fault fingerprint of certificate. Access denied."),500);
00477
00478 if(peer_cert!=0)
00479 X509_free(peer_cert);
00480 }
00481 catch(SSLConnectionException& ex)
00482 {
00483
00484 if(peer_cert!=0)
00485 X509_free(peer_cert);
00486 close();
00487 throw;
00488 }
00489
00490 ULXR_TRACE(ULXR_PCHAR("SSL connection using ") << ULXR_GET_STRING(SSL_get_cipher (ssl)));
00491 }
00492
00493
00494 ULXR_API_IMPL(ulxr::CppString) SSLConnection::getInterfaceName()
00495 {
00496 ULXR_TRACE(ULXR_PCHAR("getInterfaceName"));
00497 return ULXR_PCHAR("ssl");
00498 }
00499
00500
00501
00502 ULXR_API_IMPL(void) SSLConnection::cut()
00503 {
00504 ULXR_TRACE(ULXR_PCHAR("cut"));
00505 ulxr::TcpIpConnection::cut();
00506 initializeCTX();
00507 }
00508
00509
00510 ULXR_API_IMPL(std::string) SSLConnection::getPassword() const
00511 {
00512 return m_strPassword;
00513 }
00514
00515
00516 ULXR_API_IMPL(SSL *) SSLConnection::getSslObject() const
00517 {
00518 return ssl;
00519 }
00520
00521
00522 ULXR_API_IMPL(SSL_CTX *) SSLConnection::getSslContextObject() const
00523 {
00524 return ssl_ctx;
00525 }
00526
00527
00528 ULXR_API_IMPL(SSL_SESSION *) SSLConnection::getSslSessionObject() const
00529 {
00530 return session;
00531 }
00532
00533 ULXR_API_IMPL(void ) SSLConnection::setPassword(const std::string &strPassword)
00534 {
00535 m_strPassword=strPassword;
00536 }
00537
00538 ULXR_API_IMPL(void) SSLConnection::setCertFile(const std::string &strCertFileName)
00539 {
00540
00541
00542 if (SSL_CTX_use_certificate_file(ssl_ctx, strCertFileName.c_str(), SSL_FILETYPE_PEM) <= 0)
00543 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("SSLConnection::setCertFile: problem setting up certificate from file: ")+ULXR_GET_STRING(strCertFileName)), 500);
00544 m_strCertFileName=strCertFileName;
00545 }
00546
00547 ULXR_API_IMPL(void) SSLConnection::setKeyFile(const std::string &strKeyFileName)
00548 {
00549 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, strKeyFileName.c_str(), SSL_FILETYPE_PEM) <= 0)
00550 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("SSLConnection::setKeyFile: problem setting up key from file: ")+ULXR_GET_STRING(strKeyFileName)), 500);
00551 m_strKeyFileName=strKeyFileName;
00552 }
00553
00554 ULXR_API_IMPL(std::string) SSLConnection::getKeyFileName() const
00555 {
00556 return m_strKeyFileName;
00557 }
00558
00559 ULXR_API_IMPL(std::string) SSLConnection::getCertFileName() const
00560 {
00561 return m_strCertFileName;
00562 }
00563
00564
00565
00566 ULXR_API_IMPL(void ) SSLConnection::disableAuth(int iType)
00567 {
00568 if ( 0 == iType )
00569 {
00570 m_iAuthType=0;
00571 }
00572 else
00573 {
00574 m_iAuthType^=iType;
00575 }
00576
00577 activateAuth();
00578 }
00579
00580 ULXR_API_IMPL(void) SSLConnection::enableAuth(int iType)
00581 {
00582 m_iAuthType|=iType;
00583
00584 activateAuth();
00585 }
00586
00587 ULXR_API_IMPL(void) SSLConnection::setCAFile(const std::string &strCAFileName)
00588 {
00589 m_strCAFileName=strCAFileName;
00590
00591 if (!SSL_CTX_load_verify_locations(ssl_ctx, m_strCAFileName.c_str(),NULL))
00592 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("TLS engine: cannot load list of CA data from: ")+ULXR_GET_STRING(m_strCAFileName)), 500);
00593
00594
00595
00596
00597 STACK_OF(X509_NAME)* cert_names=SSL_load_client_CA_file(m_strCAFileName.c_str());
00598 if(cert_names == 0)
00599 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("TLS engine: cannot load list of CA data from: ")+ULXR_GET_STRING(m_strCAFileName)), 500);
00600
00601 SSL_CTX_set_client_CA_list(ssl_ctx, cert_names);
00602
00603
00604
00605
00606
00607 if (SSL_CTX_get_client_CA_list(ssl_ctx) == 0)
00608 throw SSLConnectionException(ulxr_i18n(ULXR_PCHAR("Could not set client CA list from: ")+ULXR_GET_STRING(m_strCAFileName)), 500);
00609
00610
00611 }
00612
00613
00614 ULXR_API_IMPL(void ) SSLConnection::addFingerprintData(const std::string &strFingerprint)
00615 {
00616 m_mapFingerpintData[strFingerprint]=1;
00617 }
00618
00619 ULXR_API_IMPL(void) SSLConnection::addRevocationData(const std::string &strRevocation)
00620 {
00621 m_mapRevocationData[strRevocation]=1;
00622 }
00623
00624 ULXR_API_IMPL(void) SSLConnection::resetFingerprintData()
00625 {
00626 m_mapFingerpintData.clear();
00627 }
00628
00629 ULXR_API_IMPL(void) SSLConnection::resetRevocationData()
00630 {
00631 m_mapRevocationData.clear();
00632 }
00633
00634
00635 ULXR_API_IMPL(std::string) SSLConnection::calculateFingerprint(X509 * poCertificate) const
00636 {
00637 unsigned int n;
00638 unsigned char md[EVP_MAX_MD_SIZE];
00639 char fingerprint[EVP_MAX_MD_SIZE * 3];
00640 static const char hexcodes[] = "0123456789ABCDEF";
00641
00642 if (X509_digest(poCertificate, EVP_md5(), md, &n))
00643 {
00644 for (int j = 0; j < (int) n; j++)
00645 {
00646 fingerprint[j * 3] =
00647 hexcodes[(md[j] & 0xf0) >> 4];
00648 fingerprint[(j * 3) + 1] =
00649 hexcodes[(md[j] & 0x0f)];
00650 if (j + 1 != (int) n)
00651 fingerprint[(j * 3) + 2] = ':';
00652 else
00653 fingerprint[(j * 3) + 2] = '\0';
00654 }
00655 }
00656 return std::string(fingerprint);
00657 }
00658
00659
00660 ULXR_API_IMPL(bool) SSLConnection::checkFingerprint(std::string strFingerprint) const
00661 {
00662
00663 if(m_mapFingerpintData.find(strFingerprint) == m_mapFingerpintData.end())
00664 return false;
00665
00666 return true;
00667 }
00668
00669
00670 ULXR_API_IMPL(bool) SSLConnection::checkRevocationFingerprint(std::string strFingerprint) const
00671 {
00672 if(m_mapRevocationData.find(strFingerprint) == m_mapRevocationData.end())
00673 return false;
00674
00675 return true;
00676 }
00677
00678 ULXR_API_IMPL(bool) SSLConnection::checkAccess(X509 * poCertificate)
00679 {
00680 bool bReturn=true;
00681 std::string strCertFingerprint="";
00682
00683
00684
00685 if((0 !=(m_iAuthType&SSLConnection::FINGERPRINT_AUTH)) && bReturn)
00686 {
00687 if(poCertificate == NULL)
00688 bReturn=false;
00689 else
00690 {
00691 strCertFingerprint=strCertFingerprint.size()?strCertFingerprint:calculateFingerprint(poCertificate);
00692 if(checkFingerprint(strCertFingerprint))
00693 bReturn=true;
00694 else bReturn=false;
00695 }
00696 }
00697
00698
00699 if((0 !=(m_iAuthType&SSLConnection::CHECK_REVOCATIONCERT)) && bReturn)
00700 {
00701 if(poCertificate == NULL)
00702 bReturn=false;
00703 else
00704 {
00705 strCertFingerprint=strCertFingerprint.size()?strCertFingerprint:calculateFingerprint(poCertificate);
00706 if(!checkRevocationFingerprint(strCertFingerprint))
00707 bReturn=true;
00708 else bReturn=false;
00709 }
00710 }
00711 return bReturn;
00712 }
00713
00714 ULXR_API_IMPL(void) SSLConnection::activateAuth()
00715 {
00716
00717 if(0 !=m_iAuthType && ssl_ctx)
00718 {
00719
00720 SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,NULL);
00721 }
00722 else
00723 {
00724
00725 SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_NONE,NULL);
00726 }
00727
00728 }
00729
00730
00731 }
00732
00733
00734 #endif // ULXR_INCLUDE_SSL_STUFF
00735
00736
00737
00738