IBR-DTNSuite  0.10
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) {
118  return;
119  }
120 
121  // load configuration
123 
125  }
126 
127  void
129  {
130  if (_initialized) {
131  ibrcommon::TLSStream::init(_cert, _privateKey, _trustedCAPath, !dtn::daemon::Configuration::getInstance().getSecurity().TLSEncryptionDisabled());
132  }
133  }
134 
135  void
137  {
138  /* nothing to do */
139  }
140 
141  const std::string
143  {
145  }
146 
147  void
148  SecurityCertificateManager::validateSubject(X509 *certificate, const std::string &cn) throw (SecurityCertificateException)
149  {
150  if(!certificate || cn.empty()){
151  throw SecurityCertificateException("certificate or common-name is empty");
152  }
153 
154  X509_NAME *cert_name;
155  X509_NAME_ENTRY *name_entry;
156  ASN1_STRING *eid_string;
157  int lastpos = -1;
158  unsigned char *utf8_eid;
159  int utf8_eid_len;
160 
161  /* retrieve the X509_NAME structure */
162  if(!(cert_name = X509_get_subject_name(certificate))){
163  throw SecurityCertificateException("Failed to retrieve the X509_NAME structure.");
164  }
165 
166  /* convert the eid to an ASN1_STRING, it is needed later for comparison. */
167  eid_string = ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING);
168  if(!eid_string){
169  throw SecurityCertificateException("Error while creating an ASN1_STRING.");
170  }
171  /* TODO this function returns an int, but the return value is undocumented */
172  /* the -1 indicates, that strlen() should be used to calculate the data length */
173  ASN1_STRING_set(eid_string, cn.c_str(), -1);
174 
175  utf8_eid_len = ASN1_STRING_to_UTF8(&utf8_eid, eid_string);
176  if(utf8_eid_len <= 0){
177  std::stringstream ss; ss << "ASN1_STRING_to_UTF8() returned " << utf8_eid_len << ".";
178  throw SecurityCertificateException(ss.str());
179  }
180 
181  /* process all entries that are of type NID_commonName */
182  while(true){
183  lastpos = X509_NAME_get_index_by_NID(cert_name, NID_commonName, lastpos);
184  if(lastpos == -1){
185  break;
186  }
187 
188  /* get the NAME_ENTRY structure */
189  name_entry = X509_NAME_get_entry(cert_name, lastpos);
190  if(!name_entry){
191  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "X509_NAME_get_entry returned NULL unexpectedly." << IBRCOMMON_LOGGER_ENDL;
192  continue;
193  }
194 
195  /* retrieve the string */
196  ASN1_STRING *asn1 = X509_NAME_ENTRY_get_data(name_entry);
197  if(!asn1){
198  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "X509_NAME_ENTRY_get_data returned NULL unexpectedly." << IBRCOMMON_LOGGER_ENDL;
199  continue;
200  }
201 
202  unsigned char *utf8_cert_name;
203  int utf8_cert_len;
204  utf8_cert_len = ASN1_STRING_to_UTF8(&utf8_cert_name, asn1);
205  if(utf8_cert_len <= 0){
206  IBRCOMMON_LOGGER_TAG(SecurityCertificateManager::TAG, error) << "ASN1_STRING_to_UTF8() returned " << utf8_cert_len << "." << IBRCOMMON_LOGGER_ENDL;
207  continue;
208  }
209 
210  /* check if the string fits the given EID */
211  if(utf8_cert_len != utf8_eid_len){
212  continue;
213  }
214  if(memcmp(utf8_eid, utf8_cert_name, utf8_eid_len) == 0){
215  OPENSSL_free(utf8_cert_name);
216  OPENSSL_free(utf8_eid);
217  return;
218  }
219  OPENSSL_free(utf8_cert_name);
220  }
221 
222  OPENSSL_free(utf8_eid);
223 
224  char *subject_line = X509_NAME_oneline(cert_name, NULL, 0);
225  std::stringstream ss;
226 
227  if (subject_line) {
228  ss << "Certificate does not fit. Expected: " << cn << ", Certificate Subject: " << subject_line << ".";
229  delete subject_line;
230  }
231 
232  throw SecurityCertificateException(ss.str());
233  }
234  }
235 }