/* Copyright (C) 2003 Frédéric Giudicelli (contact_nos@yahoo.com). All rights reserved. This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) This program is released under the GPL with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // SockServerADMIN.cpp: implementation of the SockServerADMIN class. // ////////////////////////////////////////////////////////////////////// #include "SockServerADMIN.h" #include "svintl.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// SockServerADMIN::SockServerADMIN():SOCK_SERVER(MAX_ADMIN_CONNECTIONS) { m_ctx = NULL; } SockServerADMIN::~SockServerADMIN() { if(m_ctx) SSL_CTX_free(m_ctx); } void SockServerADMIN::OnServerStopped() { } bool SockServerADMIN::ReadRequest(BIO * ssl_bio, SOCKET hSocket, AdminRequest & req) { fd_set rfds; struct timeval tv; int sockt_state; ADMIN_REQUEST * lReq; time_t startWait; time(&startWait); do { FD_ZERO(&rfds); FD_SET(hSocket, &rfds); tv.tv_sec = 0; tv.tv_usec = 100; sockt_state = select(hSocket + 1, &rfds, NULL, NULL, &tv); // We have a maximum of 5 mins inactivity if(time(NULL) - startWait > 300) return false; } while(sockt_state == 0 && !ShouldStop()); // Where we asked to stop or was there an error ? if(ShouldStop() || sockt_state != 1) { return false; } lReq = d2i_ADMIN_REQUEST_bio(ssl_bio, NULL); if(!lReq) return false; if(!req.load_Datas(lReq)) { ASN1_item_free((ASN1_VALUE*)lReq, AdminRequest::get_ASN1_ITEM()); return false; } ASN1_item_free((ASN1_VALUE*)lReq, AdminRequest::get_ASN1_ITEM()); return true; } void SockServerADMIN::OnConnection(const char * Ip, SOCKET connection) { SSL * ssl; BIO * ssl_bio; AdminRequest req; AdminResponse response; ADMIN_RESPONSE * lResponse; X509 * ClientCert; PKI_CERT UserCert; int ret; char * subject; char * issuer; mString errorstr; if(!m_ctx) { return; } if( !(ssl_bio=BIO_new(BIO_f_ssl())) ) { return; } if( !(ssl=SSL_new(m_ctx)) ) { BIO_free_all(ssl_bio); return; } SSL_set_fd(ssl, connection); if(BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE) <= 0) { BIO_free_all(ssl_bio); return; } if(BIO_set_ssl_mode(ssl_bio, 0) <= 0) { BIO_free_all(ssl_bio); return; } ERR_clear_error(); if( (ret = SSL_accept(ssl)) <= 0) { switch(SSL_get_error(ssl, ret)) { case SSL_ERROR_SSL: ERR_to_mstring(errorstr); break; case SSL_ERROR_SYSCALL: errorstr = strerror(errno); break; default: errorstr = _sv("Other"); break; } NewpkiDebug(LOG_LEVEL_ERROR, m_Conf.get_ServerName().c_str(), _sv("%.20d - SSL_accept failed : %d -> %s\n"), connection, SSL_get_error(ssl, ret), errorstr.c_str()); BIO_free_all(ssl_bio); return; } ClientCert = SSL_get_peer_certificate(ssl); if(ClientCert) { if(!UserCert.SetCert(ClientCert)) { BIO_free_all(ssl_bio); return; } issuer = X509_NAME_oneline (X509_get_issuer_name(ClientCert),0,0); subject = X509_NAME_oneline (X509_get_subject_name(ClientCert),0,0); NewpkiDebug(LOG_LEVEL_DEBUG, m_Conf.get_ServerName().c_str(), _sv("%.20d - SSLv3 Connection from: \n\tissuer : %s\n\tsubject : %s\n"), connection, issuer?issuer:_sv("Unknown"), subject?subject:_sv("Unknown")); if(issuer) OPENSSL_free(issuer); if(subject) OPENSSL_free(subject); X509_free(ClientCert); } ERR_clear_error(); while(ReadRequest(ssl_bio, connection, req)) { if(!m_Central->OnADMIN_REQUEST(response, Ip, UserCert, req)) { break; } req.Clear(); lResponse = NULL; if(!response.give_Datas(&lResponse)) { if(lResponse) ASN1_item_free((ASN1_VALUE*)lResponse, AdminResponse::get_ASN1_ITEM()); break; } if(!i2d_ADMIN_RESPONSE_bio(ssl_bio, lResponse)) { ASN1_item_free((ASN1_VALUE*)lResponse, AdminResponse::get_ASN1_ITEM()); break; } ASN1_item_free((ASN1_VALUE*)lResponse, AdminResponse::get_ASN1_ITEM()); response.get_body().Clear(); } #ifdef _DEBUG ERR_print_errors_fp(stdout); #endif AddRecvBytes(BIO_number_read(ssl_bio)); AddSentBytes(BIO_number_written(ssl_bio)); BIO_free_all(ssl_bio); m_Central->OnConnectionClosed(); } void SockServerADMIN::OnServerStarted() { } bool SockServerADMIN::Load(PKIX_Central *Central) { m_Central = Central; m_Central->GetSSL_Cert(m_SslCert); unsigned char sid[SSL_MAX_SSL_SESSION_ID_LENGTH]; SSL_METHOD * meth; meth = SSLv23_server_method(); if(!meth) { NEWPKIerr(PKI_ERROR_TXT, ERROR_UNKNOWN); return false; } m_ctx = SSL_CTX_new (meth); if(!m_ctx) { NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); return false; } if (SSL_CTX_use_certificate(m_ctx, m_SslCert.GetX509()) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if (SSL_CTX_use_PrivateKey(m_ctx, (EVP_PKEY*)m_SslCert.GetPrivateKey().GetRsaKey()) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if (SSL_CTX_check_private_key(m_ctx) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } RAND_bytes(sid, sizeof(sid)); SSL_CTX_set_mode(m_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_session_cache_mode(m_ctx, SSL_SESS_CACHE_SERVER); SSL_CTX_set_session_id_context(m_ctx, sid, sizeof(sid)); SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback); // SSL_CTX_set_info_callback(HandlesList[hThread].GetSSL_CTX(), info_callback); return true; } int SockServerADMIN::verify_callback(int ok, X509_STORE_CTX *m_ctx) { return 1; } void SockServerADMIN::info_callback(const SSL *s, int where, int ret) { if(where & SSL_CB_LOOP) NewpkiDebug(LOG_LEVEL_DEBUG, "SSL INFO", _sv("%.20d - SSL state (%s): %s"), SSL_get_fd((SSL*)s), where & SSL_ST_CONNECT ? "connect" : where & SSL_ST_ACCEPT ? "accept" : "undefined", SSL_state_string_long(s)); else if(where & SSL_CB_ALERT) NewpkiDebug(LOG_LEVEL_DEBUG, "SSL INFO", _sv("%.20d - SSL alert (%s): %s: %s"), SSL_get_fd((SSL*)s), where & SSL_CB_READ ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); /* else if(where==SSL_CB_HANDSHAKE_DONE) print_stats(s->m_ctx);* */ }