/* 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 */ // RaStore.cpp: implementation of the RaStore class. // ////////////////////////////////////////////////////////////////////// #include "RaStore.h" #include #include #include "svintl.h" #include using namespace std; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// RaStore::RaStore(const mString & EntityName, ENGINE * e):NewPKIStore(EntityName, e, NEWPKISTORE_TYPE_REQUESTER) { m_AclValidator = NULL; } RaStore::~RaStore() { } bool RaStore::CreateTables(const SQL_Connection * DbConn) { SQL sql(DbConn); long i; char * CommonCreates[] = {RASTORE_CREATE_1, RASTORE_CREATE_2, NULL}; if(!CommonCreateTables(DbConn)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } //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; } void RaStore::SetMinPasswdLen(unsigned long MinPasswdLen) { ConfAccessLock.LockWrite(); m_MinPasswdLen = MinPasswdLen; ConfAccessLock.UnlockWrite(); } bool RaStore::SetGroups(const mVector & groups) { ConfAccessLock.LockWrite(); m_groups = groups; ConfAccessLock.UnlockWrite(); return true; } bool RaStore::DeleteProfile(const PKI_CERT &UserCert, long ProfileId, bool CheckOwnership) { SQL sql(m_DbConn); mString req; mVector Certs; size_t i; if(CheckOwnership) { if(!GetProfileAccessCheck(UserCert, ProfileId, sql)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } // We also need to make sure there are no valid certificates // for this profile if(!GetCerts(ProfileId, Certs)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } for(i=0; i & Profiles, long index, long num) { long NumRows; SQL sql(m_DbConn); mString req; mString Where; mString tmpDatas; size_t v_index, i, j; // PKI Admins can see all the profile if(!m_AclValidator->IsPkiAdministrator(UserCert)) { Where.sprintf("WHERE (owner_type=%d AND owner_serial=%ld)", OWNER_TYPE_USER, UserCert.GetSerial()); // Create the WHERE syntax according to user's groups ConfAccessLock.LockRead(); for(i=0; i & Certs) { SQL sql(m_DbConn); mString err; mString req; long NumRows; long i; PKI_CERT ttCert; req.sprintf(RASTORE_GET_CERTS, ProfileId); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!sql.NumRows(&NumRows)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } for(i=0; iLogMessage(LogStatus, LogMessage, 0, ca_name.c_str(), cert_id); break; case LOG_STATUS_TYPE_FAILURE: m_Logging->LogMessage(LogStatus, LogMessage, 0, ca_name.c_str(), cert_id, NULL, strError.c_str()); break; default: NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); return false; } } return true; } bool RaStore::GetCertReq(const Asn1OctetString & transactionID, NewpkiProfileDatasCert & Cert) { SQL sql(m_DbConn); mString req; long NumRows; mString tid; if(!transactionIDtoString(transactionID, tid)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } req.sprintf(RASTORE_GET_CERT_BY_TID, tid.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; } if(!NumRows) { NEWPKIerr(PKI_ERROR_TXT, ERROR_NOT_ALLOWED); return false; } if(!Sql2Cert(&sql, Cert, 0)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } return true; } bool RaStore::Sql2Cert(SQL *sql, NewpkiProfileDatasCert & Cert, int index) { mString value; ASN1_BIT_STRING * flags; Cert.Clear(); if(!sql->Value(index,"id", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } Cert.set_id(value.c_ulng()); if(!sql->Value(index,"ca_name", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } Cert.set_caName(value); if(!sql->Value(index,"status", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } Cert.set_state(value.c_ulng()); if(!sql->Value(index,"type", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } Cert.set_type(value.c_ulng()); if(!sql->Value(index,"flags", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } flags = StringtoASN1_BIT_STRING(value); if(!flags) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!Cert.set_flags(flags)) { ASN1_BIT_STRING_free(flags); NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } ASN1_BIT_STRING_free(flags); if(!sql->Value(index,"admin_mail", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } Cert.set_adminMail(value); // Are we in state of having the PKCS#12 ? if(Cert.get_state() == NEWPKI_PROFILE_CERT_STATE_ACTIVE && Cert.get_type() == NEWPKI_PROFILE_CERT_TYPE_PKCS12) { // Do we have the PKCS#12 ? if(!sql->Value(index,"priv_datas", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(value.size()) { if(!Cert.get_p12().Load(value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } } } if(!sql->Value(index,"x509", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(value.size()) { if(!Cert.get_cert().SetCert(value.c_str())) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } } if(!sql->Value(index,"p7b", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(value.size()) { if(!Cert.get_p7b().Load(value.c_str())) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } } if(!sql->Value(index,"error", value)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(value.size()) Cert.set_error(value); Cert.set_isOK(); return true; } bool RaStore::SuspendCertificate(const PKI_CERT & UserCert, unsigned long id, unsigned long & serial, mString & ca_name, mString & ldap_uid) { SQL sql(m_DbConn); mString req; long NumRows; unsigned long owner_serial; unsigned long owner_type; PKI_CERT Cert; NewpkiProfile Profile; req.sprintf(RASTORE_GET_CERT_4_REV, id); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!sql.NumRows(&NumRows)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!NumRows) { NEWPKIerr(PKI_ERROR_TXT, ERROR_NOT_ALLOWED); return false; } // Check the current status of the certificate if(!sql.Value(0, "status", req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(req.c_int() != NEWPKI_PROFILE_CERT_STATE_ACTIVE) { NEWPKIerr(PKI_ERROR_TXT, ERROR_NOT_ALLOWED); return false; } if(!sql.Value(0, "owner_type", req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } owner_type = req.c_ulng(); if(!sql.Value(0, "owner_serial", req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } owner_serial = req.c_ulng(); if(!CanUserAccessProfile(UserCert, owner_serial, owner_type)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_NOT_ALLOWED); return false; } // Get the serial of the x509 if(!sql.Value(0, "x509", req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!Cert.SetCert(req.c_str())) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } serial = Cert.GetSerial(); // Get the ca_name if(!sql.Value(0, "ca_name", ca_name)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } // Get the LDAP RDN if(!sql.Value(0, "datas", req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } // We need to reconvert if from the PEM if(!Profile.from_PEM(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } ldap_uid = Profile.get_ldapUid(); Profile.Clear(); req.sprintf(RASTORE_SUSPEND_CERT, NEWPKI_PROFILE_CERT_STATE_WAITING_REV, id); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } return true; } bool RaStore::CanUserAccessProfile(const PKI_CERT & UserCert, unsigned long owner_serial, unsigned long owner_type) { size_t i, j; if(m_AclValidator->IsPkiAdministrator(UserCert)) { return true; } if(owner_type == OWNER_TYPE_USER) { if(owner_serial == UserCert.GetSerial()) { return true; } else { return false; } } ConfAccessLock.LockRead(); for(i=0; i < m_groups.size(); i++) { // is this the group ? if(m_groups[i].get_serial() == owner_serial) { for(j=0; jserial; where += "'"; if(i != Crl.RevokedCertsCount()-1) where += " OR "; } req.sprintf(RASTORE_UPDATE_FROM_CRL, NEWPKI_PROFILE_CERT_STATE_REVOKED, ca_name.c_str(), NEWPKI_PROFILE_CERT_STATE_REVOKED, where.c_str()); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } return true; } bool RaStore::OnNewProfile(const NewpkiProfile &newProfile) { PKI_CERT EmptyCert; long id; return InsertProfile(EmptyCert, newProfile, id); } bool RaStore::GetKnownUIDs(mVector & KnownUIDs) { mString req; long i; SQL sql(m_DbConn); long NumRows; req.sprintf(RASTORE_GET_KNOWN_RDNS); if(!sql.Execute(req)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } if(!sql.NumRows(&NumRows)) { NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); return false; } for(i=0; i AllowedCharsLen); tt[0] = AllowedChars[j]; strP12Password += tt; } } void RaStore::SetAclValidator(const X509_ACL_Validator *AclValidator) { m_AclValidator = AclValidator; } bool RaStore::InsertResponseCert(const NewpkiCertResponse & cert_response, const mString & ca_name, PKI_CRL & Crl, LOG_MESSAGE_TYPE & LogMessage, LOG_MESSAGE_STATUS & LogStatus, int & Status, mString & strError, const HashTable_Dn & ProfileDn, mString & strPrivDatas, mString & x509, mString & p7b, unsigned long & serial, MailInfo & CertificateMail, MailInfo & PasswordMail, bool & SendCertificate, bool & SendPkcs12Pwd, bool & GenPkcs12Pwd) { mString strP12Password; mString UserMail; mString MailBody; mString Id; mString AttachName; mString cn; PKI_PKCS12 p12; PKI_RSA PrivKey; PKI_P7B p7; HashTable_String ParentCerts; size_t i; int pos; RaStorePrivdatas PrivDatas; Asn1EncryptSign crypt; LogMessage = LOG_MESSAGE_TYPE_CERT_SIG_RESP; if(cert_response.get_lastCrl()) { if(!(Crl = cert_response.get_lastCrl()) ) ERR_clear_error(); } // Is it an error or the certificate ? switch(cert_response.get_status()) { // A certificate case CERT_RESPONSE_OK: Status = NEWPKI_PROFILE_CERT_STATE_ACTIVE; LogStatus = LOG_STATUS_TYPE_SUCCESS; x509 = cert_response.get_certificate().GetCertPEM(); serial = cert_response.get_certificate().GetSerial(); // Get the user's mail address pos = cert_response.get_certificate().GetCertDN().SeekEntryName("emailAddress", HASHTABLE_NOT_FOUND); if(pos != HASHTABLE_NOT_FOUND) UserMail = cert_response.get_certificate().GetCertDN().Get(pos); if(!UserMail.size()) { pos = ProfileDn.SeekEntryName("emailAddress", HASHTABLE_NOT_FOUND); if(pos != HASHTABLE_NOT_FOUND) UserMail = ProfileDn.Get(pos); } // Get the user's cn pos = cert_response.get_certificate().GetCertDN().SeekEntryName("commonName", HASHTABLE_NOT_FOUND); if(pos != HASHTABLE_NOT_FOUND) cn = cert_response.get_certificate().GetCertDN().Get(pos); if(!cn.size()) { pos = ProfileDn.SeekEntryName("commonName", HASHTABLE_NOT_FOUND); if(pos != HASHTABLE_NOT_FOUND) cn = ProfileDn.Get(pos); } if(!cn.size()) cn = _sv("unknown"); /******************************************** * Generate the PKCS7 * ********************************************/ p7.Clear(); p7.AddCert(cert_response.get_certificate().GetX509()); for(i=0; i