IBR-DTNSuite
0.8
|
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 }