IBR-DTNSuite  0.8
daemon/src/security/SecurityCertificateManager.cpp
Go to the documentation of this file.
00001 /*
00002  * SecurityCertificateManager.cpp
00003  *
00004  *  Created on: Apr 2, 2011
00005  *      Author: roettger
00006  */
00007 
00008 #include "security/SecurityCertificateManager.h"
00009 #include "Configuration.h"
00010 
00011 #include <cstdlib>
00012 
00013 #include <ibrcommon/Logger.h>
00014 
00015 namespace dtn
00016 {
00017         namespace security
00018         {
00019                 SecurityCertificateManager::SecurityCertificateManager()
00020                         : _initialized(false), _cert(NULL), _privateKey(NULL)
00021                 {
00022                 }
00023 
00024                 SecurityCertificateManager::~SecurityCertificateManager() {
00025                 }
00026 
00027                 bool SecurityCertificateManager::isInitialized()
00028                 {
00029                         return _initialized;
00030                 }
00031 
00032                 X509 *SecurityCertificateManager::getCert()
00033                 {
00034                         return _cert;
00035                 }
00036 
00037                 EVP_PKEY *SecurityCertificateManager::getPrivateKey()
00038                 {
00039                         return _privateKey;
00040                 }
00041 
00042                 ibrcommon::File SecurityCertificateManager::getTrustedCAPath() const
00043                 {
00044                         return _trustedCAPath;
00045                 }
00046 
00047                 void
00048                 SecurityCertificateManager::initialize()
00049                 {
00050                         ibrcommon::File certificate = dtn::daemon::Configuration::getInstance().getSecurity().getCertificate();
00051                         ibrcommon::File privateKey = dtn::daemon::Configuration::getInstance().getSecurity().getKey();
00052                         ibrcommon::File trustedCAPath = dtn::daemon::Configuration::getInstance().getSecurity().getTrustedCAPath();
00053 
00054                         FILE *fp = NULL;
00055                         X509 *cert = NULL;
00056                         EVP_PKEY *key = NULL;
00057 
00058                         ibrcommon::MutexLock l(_initialization_lock);
00059                         if(_initialized){
00060                                 IBRCOMMON_LOGGER(info) << "SecurityCertificateManager: already initialized." << IBRCOMMON_LOGGER_ENDL;
00061                                 return;
00062                         }
00063 
00064                         /* read the certificate */
00065                         fp = fopen(certificate.getPath().c_str(), "r");
00066                         if(!fp || !PEM_read_X509(fp, &cert, NULL, NULL)){
00067                                 IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: Could not read the certificate File: " << certificate.getPath() << "." << IBRCOMMON_LOGGER_ENDL;
00068                                 if(fp){
00069                                         fclose(fp);
00070                                 }
00071                                 throw ibrcommon::IOException("Could not read the certificate.");
00072                         }
00073                         fclose(fp);
00074 
00075                         /* read the private key */
00076                         fp = fopen(privateKey.getPath().c_str(), "r");
00077                         if(!fp || !PEM_read_PrivateKey(fp, &key, NULL, NULL)){
00078                                 IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: Could not read the PrivateKey File: " << privateKey.getPath() << "." << IBRCOMMON_LOGGER_ENDL;
00079                                 if(fp){
00080                                         fclose(fp);
00081                                 }
00082                                 throw ibrcommon::IOException("Could not read the PrivateKey.");
00083                         }
00084                         fclose(fp);
00085 
00086                         /* check trustedCAPath */
00087                         if(!trustedCAPath.isDirectory()){
00088                                 IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: the trustedCAPath is not valid: " << trustedCAPath.getPath() << "." << IBRCOMMON_LOGGER_ENDL;
00089                                 throw ibrcommon::IOException("Invalid trustedCAPath.");
00090                         }
00091 
00092                         _cert = cert;
00093                         _privateKey = key;
00094                         _trustedCAPath = trustedCAPath;
00095                         _initialized = true;
00096 
00097                         IBRCOMMON_LOGGER(info) << "SecurityCertificateManager: Initialization succeeded." << IBRCOMMON_LOGGER_ENDL;
00098                 }
00099 
00100                 void
00101                 SecurityCertificateManager::startup()
00102                 {
00103                         if(_initialized){
00104                                 CertificateManagerInitEvent::raise(_cert, _privateKey, _trustedCAPath);
00105                         }
00106                 }
00107 
00108                 void
00109                 SecurityCertificateManager::terminate()
00110                 {
00111                         /* nothing to do */
00112                 }
00113 
00114                 const std::string
00115                 SecurityCertificateManager::getName() const
00116                 {
00117                         return "SecurityCertificateManager";
00118                 }
00119 
00120                 bool
00121                 SecurityCertificateManager::validateSubject(X509 *certificate, const dtn::data::EID &eid)
00122                 {
00123                         if(!certificate || eid.getString().empty()){
00124                                 return false;
00125                         }
00126 
00127                         X509_NAME *cert_name;
00128                         X509_NAME_ENTRY *name_entry;
00129                         ASN1_STRING *eid_string;
00130                         int lastpos = -1;
00131                         int entry_count;
00132                         unsigned char *utf8_eid;
00133                         int utf8_eid_len;
00134 
00135                         /* retrieve the X509_NAME structure */
00136                         if(!(cert_name = X509_get_subject_name(certificate))){
00137                                 return false;
00138                         }
00139 
00140                         /* convert the eid to an ASN1_STRING, it is needed later for comparison. */
00141                         eid_string = ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING);
00142                         if(!eid_string){
00143                                 IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: Error while creating an ASN1_STRING." << IBRCOMMON_LOGGER_ENDL;
00144                                 return false;
00145                         }
00146                         /* TODO this function returns an int, but the return value is undocumented */
00147                         /* the -1 indicates, that strlen() should be used to calculate the data length */
00148                         ASN1_STRING_set(eid_string, eid.getString().c_str(), -1);
00149 
00150                         utf8_eid_len = ASN1_STRING_to_UTF8(&utf8_eid, eid_string);
00151                         if(utf8_eid_len <= 0){
00152                                 IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: ASN1_STRING_to_UTF8() returned " << utf8_eid_len << "." << IBRCOMMON_LOGGER_ENDL;
00153                                 return false;
00154                         }
00155 
00156                         /* process all entries that are of type NID_commonName */
00157                         while(true){
00158                                 lastpos = X509_NAME_get_index_by_NID(cert_name, NID_commonName, lastpos);
00159                                 if(lastpos == -1){
00160                                         break;
00161                                 }
00162 
00163                                 /* get the NAME_ENTRY structure */
00164                                 name_entry = X509_NAME_get_entry(cert_name, lastpos);
00165                                 if(!name_entry){
00166                                         IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: X509_NAME_get_entry returned NULL unexpectedly." << IBRCOMMON_LOGGER_ENDL;
00167                                         continue;
00168                                 }
00169 
00170                                 /* retrieve the string */
00171                                 ASN1_STRING *asn1 = X509_NAME_ENTRY_get_data(name_entry);
00172                                 if(!asn1){
00173                                         IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: X509_NAME_ENTRY_get_data returned NULL unexpectedly." << IBRCOMMON_LOGGER_ENDL;
00174                                         continue;
00175                                 }
00176 
00177                                 unsigned char *utf8_cert_name;
00178                                 int utf8_cert_len;
00179                                 utf8_cert_len = ASN1_STRING_to_UTF8(&utf8_cert_name, asn1);
00180                                 if(utf8_cert_len <= 0){
00181                                         IBRCOMMON_LOGGER(error) << "SecurityCertificateManager: ASN1_STRING_to_UTF8() returned " << utf8_cert_len << "." << IBRCOMMON_LOGGER_ENDL;
00182                                         continue;
00183                                 }
00184 
00185                                 /* check if the string fits the given EID */
00186                                 if(utf8_cert_len != utf8_eid_len){
00187                                         continue;
00188                                 }
00189                                 if(memcmp(utf8_eid, utf8_cert_name, utf8_eid_len) == 0){
00190                                         OPENSSL_free(utf8_cert_name);
00191                                         OPENSSL_free(utf8_eid);
00192                                         return true;
00193                                 }
00194                                 OPENSSL_free(utf8_cert_name);
00195                         }
00196 
00197                         OPENSSL_free(utf8_eid);
00198 
00199                         char *subject_line = X509_NAME_oneline(cert_name, NULL, 0);
00200                         if(subject_line){
00201                                 IBRCOMMON_LOGGER(warning) << "SecurityCertificateManager: Certificate does not fit. EID: " << eid.getString() << ", Certificate Subject: " << subject_line << "." << IBRCOMMON_LOGGER_ENDL;
00202                                 delete subject_line;
00203                         }
00204                         return false;
00205                 }
00206         }
00207 }