IBR-DTNSuite  0.12
SecurityCertificateManager.cpp
Go to the documentation of this file.
1 /*
2  * SecurityCertificateManager.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Stephen Roettger <roettger@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
23 #include "Configuration.h"
24 
25 #include <cstdlib>
26 
27 #include <ibrcommon/Logger.h>
29 
30 namespace dtn
31 {
32  namespace security
33  {
34  const std::string SecurityCertificateManager::TAG = "SecurityCertificateManager";
35 
37  : _initialized(false), _cert(NULL), _privateKey(NULL)
38  {
39  }
40 
42  }
43 
45  {
46  return _initialized;
47  }
48 
50  {
51  return _cert;
52  }
53 
55  {
56  return _privateKey;
57  }
58 
60  {
61  return _trustedCAPath;
62  }
63 
65  {
66  ibrcommon::File certificate = conf.getSecurity().getCertificate();
67  ibrcommon::File privateKey = conf.getSecurity().getKey();
68  ibrcommon::File trustedCAPath = conf.getSecurity().getTrustedCAPath();
69 
70  try {
71  FILE *fp = NULL;
72  X509 *cert = NULL;
73  EVP_PKEY *key = NULL;
74 
75  /* read the certificate */
76  fp = fopen(certificate.getPath().c_str(), "r");
77  if(!fp || !PEM_read_X509(fp, &cert, NULL, NULL)){
78  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "Could not read the certificate File: " << certificate.getPath() << "." << IBRCOMMON_LOGGER_ENDL;
79  if(fp){
80  fclose(fp);
81  }
82  throw ibrcommon::IOException("Could not read the certificate.");
83  }
84  fclose(fp);
85 
86  /* read the private key */
87  fp = fopen(privateKey.getPath().c_str(), "r");
88  if(!fp || !PEM_read_PrivateKey(fp, &key, NULL, NULL)){
89  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "Could not read the PrivateKey File: " << privateKey.getPath() << "." << IBRCOMMON_LOGGER_ENDL;
90  if(fp){
91  fclose(fp);
92  }
93  throw ibrcommon::IOException("Could not read the PrivateKey.");
94  }
95  fclose(fp);
96 
97  /* check trustedCAPath */
98  if(!trustedCAPath.isDirectory()){
99  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "the trustedCAPath is not valid: " << trustedCAPath.getPath() << "." << IBRCOMMON_LOGGER_ENDL;
100  throw ibrcommon::IOException("Invalid trustedCAPath.");
101  }
102 
103  _cert = cert;
104  _privateKey = key;
105  _trustedCAPath = trustedCAPath;
106  _initialized = true;
107  } catch (const ibrcommon::IOException &ex) {
108 
109  }
110  }
111 
113  {
114  ibrcommon::MutexLock l(_initialization_lock);
115 
116  if (_initialized) {
117  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, info) << "already initialized." << IBRCOMMON_LOGGER_ENDL;
118  return;
119  }
120  else {
121  // load configuration
123 
124  ibrcommon::TLSStream::init(_cert, _privateKey, _trustedCAPath, !dtn::daemon::Configuration::getInstance().getSecurity().TLSEncryptionDisabled());
125 
126  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, info) << "Initialization succeeded." << IBRCOMMON_LOGGER_ENDL;
127  }
128  }
129 
131  {
132  /* nothing to do */
133  }
134 
135  const std::string
137  {
138  return SecurityCertificateManager::TAG;
139  }
140 
141  void
142  SecurityCertificateManager::validateSubject(X509 *certificate, const std::string &cn) throw (SecurityCertificateException)
143  {
144  if(!certificate || cn.empty()){
145  throw SecurityCertificateException("certificate or common-name is empty");
146  }
147 
148  X509_NAME *cert_name;
149  X509_NAME_ENTRY *name_entry;
150  ASN1_STRING *eid_string;
151  int lastpos = -1;
152  unsigned char *utf8_eid;
153  int utf8_eid_len;
154 
155  /* retrieve the X509_NAME structure */
156  if(!(cert_name = X509_get_subject_name(certificate))){
157  throw SecurityCertificateException("Failed to retrieve the X509_NAME structure.");
158  }
159 
160  /* convert the eid to an ASN1_STRING, it is needed later for comparison. */
161  eid_string = ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING);
162  if(!eid_string){
163  throw SecurityCertificateException("Error while creating an ASN1_STRING.");
164  }
165  /* TODO this function returns an int, but the return value is undocumented */
166  /* the -1 indicates, that strlen() should be used to calculate the data length */
167  ASN1_STRING_set(eid_string, cn.c_str(), -1);
168 
169  utf8_eid_len = ASN1_STRING_to_UTF8(&utf8_eid, eid_string);
170  if(utf8_eid_len <= 0){
171  std::stringstream ss; ss << "ASN1_STRING_to_UTF8() returned " << utf8_eid_len << ".";
172  throw SecurityCertificateException(ss.str());
173  }
174 
175  /* process all entries that are of type NID_commonName */
176  while(true){
177  lastpos = X509_NAME_get_index_by_NID(cert_name, NID_commonName, lastpos);
178  if(lastpos == -1){
179  break;
180  }
181 
182  /* get the NAME_ENTRY structure */
183  name_entry = X509_NAME_get_entry(cert_name, lastpos);
184  if(!name_entry){
185  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "X509_NAME_get_entry returned NULL unexpectedly." << IBRCOMMON_LOGGER_ENDL;
186  continue;
187  }
188 
189  /* retrieve the string */
190  ASN1_STRING *asn1 = X509_NAME_ENTRY_get_data(name_entry);
191  if(!asn1){
192  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "X509_NAME_ENTRY_get_data returned NULL unexpectedly." << IBRCOMMON_LOGGER_ENDL;
193  continue;
194  }
195 
196  unsigned char *utf8_cert_name;
197  int utf8_cert_len;
198  utf8_cert_len = ASN1_STRING_to_UTF8(&utf8_cert_name, asn1);
199  if(utf8_cert_len <= 0){
200  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "ASN1_STRING_to_UTF8() returned " << utf8_cert_len << "." << IBRCOMMON_LOGGER_ENDL;
201  continue;
202  }
203 
204  /* check if the string fits the given EID */
205  if(utf8_cert_len != utf8_eid_len){
206  continue;
207  }
208  if(memcmp(utf8_eid, utf8_cert_name, utf8_eid_len) == 0){
209  OPENSSL_free(utf8_cert_name);
210  OPENSSL_free(utf8_eid);
211  return;
212  }
213  OPENSSL_free(utf8_cert_name);
214  }
215 
216  OPENSSL_free(utf8_eid);
217 
218  char *subject_line = X509_NAME_oneline(cert_name, NULL, 0);
219  std::stringstream ss;
220 
221  if (subject_line) {
222  ss << "Certificate does not fit. Expected: " << cn << ", Certificate Subject: " << subject_line << ".";
223  delete subject_line;
224  }
225 
226  throw SecurityCertificateException(ss.str());
227  }
228  }
229 }