/* 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 */ // NewPKIStore.cpp: implementation of the NewPKIStore class. // ////////////////////////////////////////////////////////////////////// #include "NewPKIStore.h" #include #include "svintl.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// NewPKIStore::NewPKIStore(const mString & EntityName, ENGINE * e, unsigned long Type) { m_EntityName = EntityName; m_DbConn = NULL; m_Type = Type; m_Jobs = NULL; m_Engine = e; m_Logging = NULL; } NewPKIStore::~NewPKIStore() { if(m_DbConn) delete m_DbConn; } unsigned long NewPKIStore::get_Type() { return m_Type; } bool NewPKIStore::CommonCreateTables(const SQL_Connection * DbConn) { if( (m_Type & NEWPKISTORE_TYPE_REQUESTER) ) { if(!CreateRequester(DbConn)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } } if( (m_Type & NEWPKISTORE_TYPE_RESPONDER) ) { if(!CreateResponder(DbConn)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } } return true; } bool NewPKIStore::BINARYtoString(const unsigned char * datas, int len, mString &strId) { //Convert the transactionID to hex char tt[STR_LONG_LEN]; strId = ""; for(int i=0; i < len; i++) { sprintf(tt, "%.2x", datas[i]); strId += tt; } return true; } unsigned char * NewPKIStore::StringtoBINARY(const mString & strId, int & len) { char tt[3]; unsigned char c; unsigned char * dstBuffer; unsigned char * Result; const char * srcBuffer; int i; Result = (unsigned char*)malloc(strId.size()/2 + 1); if(!Result) { NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); return NULL; } if(!strId.size()) { Result[0] = '\0'; len = 0; return Result; } srcBuffer = strId.c_str(); len = strId.size(); tt[2]=0; for(i=0; i < len; i=i+2) { memcpy(tt, &(srcBuffer[i]), 2); c = (unsigned char)strtoul(tt, NULL, 16); dstBuffer = &Result[i/2]; memcpy(dstBuffer, &c, sizeof(c)); } len = i/2; return Result; } ASN1_BIT_STRING * NewPKIStore::StringtoASN1_BIT_STRING(const mString & strId) { unsigned char * Result; ASN1_BIT_STRING * ret; int len; Result = StringtoBINARY(strId, len); if(!Result) return NULL; ret = ASN1_BIT_STRING_new(); if(!ret) { NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); free(Result); return NULL; } if(ASN1_BIT_STRING_set(ret, (unsigned char*)Result, len) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); free(Result); ASN1_BIT_STRING_free(ret); return NULL; } free(Result); return ret; } bool NewPKIStore::ASN1_BIT_STRINGtoString(const ASN1_BIT_STRING * bit, mString &strId) { //Convert the transactionID to hex return BINARYtoString(bit->data, bit->length, strId); } bool NewPKIStore::StringtoTransactionID(const mString & strId, Asn1OctetString & transactionID) { unsigned char * Result; int len; Result = StringtoBINARY(strId, len); if(!Result) return false; transactionID.Assign(Result, len); return true; } bool NewPKIStore::transactionIDtoString(const Asn1OctetString & transactionID, mString &strId) { //Convert the transactionID to hex if(transactionID.get_BufferLen() > MAX_TID_LEN) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); return false; } return BINARYtoString(transactionID.get_Buffer(), transactionID.get_BufferLen(), strId); } bool NewPKIStore::EVP_PKEYtoHash(const EVP_PKEY * pubKey, mString &strKey) { X509_PUBKEY * x_pubkey=NULL; if(X509_PUBKEY_set(&x_pubkey, (EVP_PKEY*)pubKey) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!X509_PUBKEYtoHash(x_pubkey, strKey)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); X509_PUBKEY_free(x_pubkey); return false; } X509_PUBKEY_free(x_pubkey); return true; } bool NewPKIStore::X509_PUBKEYtoHash(const X509_PUBKEY * pubKey, mString &strKey) { unsigned char sha1[SHA_DIGEST_LENGTH]; if(!SHA1(pubKey->public_key->data, pubKey->public_key->length, sha1)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } strKey = ""; return BINARYtoString(sha1, SHA_DIGEST_LENGTH, strKey); } bool NewPKIStore::X509_NAMEtoHash(const X509_NAME * dn, mString &strHash) { unsigned char * datas, * p; int len; unsigned char sha1[SHA_DIGEST_LENGTH]; if( (len = i2d_X509_NAME((X509_NAME*)dn, NULL)) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } datas = (unsigned char*)malloc(len); if(!datas) { NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); return false; } p = datas; if( (len = i2d_X509_NAME((X509_NAME*)dn, &p)) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); free(datas); return false; } if(!SHA1(datas, len, sha1)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); free(datas); return false; } free(datas); strHash = ""; return BINARYtoString(sha1, SHA_DIGEST_LENGTH, strHash); } void NewPKIStore::SetEntityCert(const PKI_CERT & EntityCert) { m_EntityCert = EntityCert; } bool NewPKIStore::CreateRequester(const SQL_Connection * DbConn) { SQL sql(DbConn); long i; char * CommonCreates[] = {NEWPKISTORE_CREATE_2, NULL}; //We execute each request for(i=0; CommonCreates[i]; i++) { if(!sql.Execute(CommonCreates[i])) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } } return true; } bool NewPKIStore::CreateResponder(const SQL_Connection * DbConn) { SQL sql(DbConn); long i; char * CommonCreates[] = {NEWPKISTORE_CREATE_1, NULL}; //We execute each request for(i=0; CommonCreates[i]; i++) { if(!sql.Execute(CommonCreates[i])) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } } return true; } bool NewPKIStore::SetDbConn(const SQL_Connection * DbConn) { if(m_DbConn) { delete m_DbConn; m_DbConn = NULL; } try { m_DbConn = DbConn->Clone(); } catch(ExceptionNewPKI e) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!m_DbConn) { NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); return false; } return true; } bool NewPKIStore::Responder_InsertRequest(const WorkingRequest & Request) { if( !(m_Type & NEWPKISTORE_TYPE_RESPONDER) ) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); return false; } SQL sql(m_DbConn); mString req; mString req_pem; mString strTransactionId; time_t startTime; if(!transactionIDtoString(Request.get_transactionid(), strTransactionId)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!Request.to_PEM(req_pem)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } req.sprintf(RESPONDER_NEWPKISTORE_INSERT_REQ, strTransactionId.c_str(), TRANSACTION_STATUS_WAITING, req_pem.c_str()); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } // Every 100000 requests we request the table to be optimized if( (sql.GetLastID() % 100000) == 0 ) { time(&startTime); NewpkiDebug(LOG_LEVEL_INFO, m_EntityName.c_str(), _sv("Optimizing responder's requests table...")); if(!sql.OptimizeTable(RESPONDER_TABLE)) { req = ""; ERR_to_mstring(req); NewpkiDebug(LOG_LEVEL_WARNING, m_EntityName.c_str(), _sv("Failed to optimize responder's requests table - Reason: %s"), req.c_str()); ERR_clear_error(); } else { NewpkiDebug(LOG_LEVEL_INFO, m_EntityName.c_str(), _sv("Optimized responder's requests table in %ld secondes"), time(NULL) - startTime); } } return true; } bool NewPKIStore::Responder_GetRequests(mVector & Requests) { if( !(m_Type & NEWPKISTORE_TYPE_RESPONDER) ) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); return false; } long NumRows; SQL sql(m_DbConn); mString req; long i; mString strReq; size_t index; req.sprintf(RESPONDER_NEWPKISTORE_GET_REQS_BY_STATE, TRANSACTION_STATUS_WAITING); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!sql.NumRows(&NumRows)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } index = 0; for(i=0; i & Responses, int lindex, int max) { if( !(m_Type & NEWPKISTORE_TYPE_RESPONDER) ) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); return false; } long NumRows; SQL sql(m_DbConn); mString req; long i; mString strReq; size_t index; mString strLimit; if(max) strLimit.sprintf("LIMIT %d,%d", lindex, max); req.sprintf(RESPONDER_NEWPKISTORE_GET_RESP_BY_STATE, TRANSACTION_STATUS_PROCESSED, strLimit.c_str()); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!sql.NumRows(&NumRows)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } index = 0; for(i=0; i & Requests, int lindex, int max) { if( !(m_Type & NEWPKISTORE_TYPE_REQUESTER) ) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); return false; } long NumRows; SQL sql(m_DbConn); mString req; long i; mString strReq; size_t index; mString strLimit; if(max) strLimit.sprintf("LIMIT %d,%d", lindex, max); req.sprintf(REQUESTER_NEWPKISTORE_GET_REQS_BY_STATE, TRANSACTION_STATUS_WAITING, strLimit.c_str()); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!sql.NumRows(&NumRows)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } index = 0; for(i=0; ipublic_key->data, m_EntityCert.GetPrivateKey().GetPublicKey()->public_key->length, currPtr)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } currPtr += SHA_DIGEST_LENGTH; if(!SHA1(recipient->public_key->data, recipient->public_key->length, currPtr)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } currPtr += SHA_DIGEST_LENGTH; if(!SHA1(sender->public_key->data, sender->public_key->length, currPtr)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } currPtr += SHA_DIGEST_LENGTH; memcpy(currPtr, &counter, sizeof(counter)); currPtr += sizeof(counter); RAND_bytes(currPtr, 250); // Calculate the SHA1 of the whole thing to be sure it's not to big if(!SHA1(new_transactionID, sizeof(new_transactionID), sha1)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!transactionID.Copy(sha1, sizeof(sha1))) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } return true; } void NewPKIStore::set_Jobs(AsynchJobs *Jobs) { m_Jobs = Jobs; } bool NewPKIStore::SendMail(const mString &Author, const MailInfo &Mail, bool AdminMail) { if(!m_Jobs) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_PARAM); return false; } return m_Jobs->SendMail(Author, Mail, AdminMail); } bool NewPKIStore::MailerIsUp() { return (m_Jobs && m_Jobs->MailerIsUp()); } void NewPKIStore::set_Logging(const EntityLog *Logging) { m_Logging = Logging; }