]> git.ipfire.org Git - thirdparty/squid.git/blob - src/security/cert_generators/file/certificate_db.cc
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / security / cert_generators / file / certificate_db.cc
1 /*
2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #include "squid.h"
10 #include "base/HardFun.h"
11 #include "security/cert_generators/file/certificate_db.h"
12
13 #include <cerrno>
14 #include <fstream>
15 #include <memory>
16 #include <stdexcept>
17 #if HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif
20 #if HAVE_FCNTL_H
21 #include <fcntl.h>
22 #endif
23 #if HAVE_SYS_FILE_H
24 #include <sys/file.h>
25 #endif
26
27 #define HERE "(security_file_certgen) " << __FILE__ << ':' << __LINE__ << ": "
28
29 Ssl::Lock::Lock(std::string const &aFilename) :
30 filename(aFilename),
31 #if _SQUID_WINDOWS_
32 hFile(INVALID_HANDLE_VALUE)
33 #else
34 fd(-1)
35 #endif
36 {
37 }
38
39 bool Ssl::Lock::locked() const
40 {
41 #if _SQUID_WINDOWS_
42 return hFile != INVALID_HANDLE_VALUE;
43 #else
44 return fd != -1;
45 #endif
46 }
47
48 void Ssl::Lock::lock()
49 {
50
51 #if _SQUID_WINDOWS_
52 hFile = CreateFile(TEXT(filename.c_str()), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
53 if (hFile == INVALID_HANDLE_VALUE)
54 #else
55 fd = open(filename.c_str(), O_RDWR);
56 if (fd == -1)
57 #endif
58 throw std::runtime_error("Failed to open file " + filename);
59
60 #if _SQUID_WINDOWS_
61 if (!LockFile(hFile, 0, 0, 1, 0))
62 #elif _SQUID_SOLARIS_
63 if (lockf(fd, F_LOCK, 0) != 0)
64 #else
65 if (flock(fd, LOCK_EX) != 0)
66 #endif
67 throw std::runtime_error("Failed to get a lock of " + filename);
68 }
69
70 void Ssl::Lock::unlock()
71 {
72 #if _SQUID_WINDOWS_
73 if (hFile != INVALID_HANDLE_VALUE) {
74 UnlockFile(hFile, 0, 0, 1, 0);
75 CloseHandle(hFile);
76 hFile = INVALID_HANDLE_VALUE;
77 }
78 #else
79 if (fd != -1) {
80 #if _SQUID_SOLARIS_
81 lockf(fd, F_ULOCK, 0);
82 #else
83 flock(fd, LOCK_UN);
84 #endif
85 close(fd);
86 fd = -1;
87 }
88 #endif
89 else
90 throw std::runtime_error("Lock is already unlocked for " + filename);
91 }
92
93 Ssl::Lock::~Lock()
94 {
95 if (locked())
96 unlock();
97 }
98
99 Ssl::Locker::Locker(Lock &aLock, const char *aFileName, int aLineNo):
100 weLocked(false), lock(aLock), fileName(aFileName), lineNo(aLineNo)
101 {
102 if (!lock.locked()) {
103 lock.lock();
104 weLocked = true;
105 }
106 }
107
108 Ssl::Locker::~Locker()
109 {
110 if (weLocked)
111 lock.unlock();
112 }
113
114 Ssl::CertificateDb::Row::Row()
115 : width(cnlNumber)
116 {
117 row = (char **)OPENSSL_malloc(sizeof(char *) * (width + 1));
118 for (size_t i = 0; i < width + 1; ++i)
119 row[i] = NULL;
120 }
121
122 Ssl::CertificateDb::Row::Row(char **aRow, size_t aWidth): width(aWidth)
123 {
124 row = aRow;
125 }
126
127 Ssl::CertificateDb::Row::~Row()
128 {
129 if (!row)
130 return;
131
132 void *max;
133 if ((max = (void *)row[width]) != NULL) {
134 // It is an openSSL allocated row. The TXT_DB_read function stores the
135 // index and row items one one memory segment. The row[width] points
136 // to the end of buffer. We have to check for items in the array which
137 // are not stored in this segment. These items should released.
138 for (size_t i = 0; i < width + 1; ++i) {
139 if (((row[i] < (char *)row) || (row[i] > max)) && (row[i] != NULL))
140 OPENSSL_free(row[i]);
141 }
142 } else {
143 for (size_t i = 0; i < width + 1; ++i) {
144 if (row[i])
145 OPENSSL_free(row[i]);
146 }
147 }
148 OPENSSL_free(row);
149 }
150
151 void Ssl::CertificateDb::Row::reset()
152 {
153 row = NULL;
154 }
155
156 void Ssl::CertificateDb::Row::setValue(size_t cell, char const * value)
157 {
158 assert(cell < width);
159 if (row[cell]) {
160 free(row[cell]);
161 }
162 if (value) {
163 row[cell] = static_cast<char *>(OPENSSL_malloc(sizeof(char) * (strlen(value) + 1)));
164 memcpy(row[cell], value, sizeof(char) * (strlen(value) + 1));
165 } else
166 row[cell] = NULL;
167 }
168
169 char ** Ssl::CertificateDb::Row::getRow()
170 {
171 return row;
172 }
173
174 void Ssl::CertificateDb::sq_TXT_DB_delete(TXT_DB *db, const char **row)
175 {
176 if (!db)
177 return;
178
179 #if SQUID_SSLTXTDB_PSTRINGDATA
180 for (int i = 0; i < sk_OPENSSL_PSTRING_num(db->data); ++i) {
181 #if SQUID_STACKOF_PSTRINGDATA_HACK
182 const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db->data), i));
183 #else
184 const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db->data, i));
185 #endif
186 #else
187 for (int i = 0; i < sk_num(db->data); ++i) {
188 const char ** current_row = ((const char **)sk_value(db->data, i));
189 #endif
190 if (current_row == row) {
191 sq_TXT_DB_delete_row(db, i);
192 return;
193 }
194 }
195 }
196
197 #define countof(arr) (sizeof(arr)/sizeof(*arr))
198 void Ssl::CertificateDb::sq_TXT_DB_delete_row(TXT_DB *db, int idx) {
199 char **rrow;
200 #if SQUID_SSLTXTDB_PSTRINGDATA
201 rrow = (char **)sk_OPENSSL_PSTRING_delete(db->data, idx);
202 #else
203 rrow = (char **)sk_delete(db->data, idx);
204 #endif
205
206 if (!rrow)
207 return;
208
209 Row row(rrow, cnlNumber); // row wrapper used to free the rrow
210
211 const Columns db_indexes[]= {cnlSerial, cnlKey};
212 for (unsigned int i = 0; i < countof(db_indexes); ++i) {
213 void *data = NULL;
214 #if SQUID_SSLTXTDB_PSTRINGDATA
215 if (LHASH_OF(OPENSSL_STRING) *fieldIndex = db->index[db_indexes[i]])
216 data = lh_OPENSSL_STRING_delete(fieldIndex, rrow);
217 #else
218 if (LHASH *fieldIndex = db->index[db_indexes[i]])
219 data = lh_delete(fieldIndex, rrow);
220 #endif
221 if (data)
222 assert(data == rrow);
223 }
224 }
225
226 unsigned long Ssl::CertificateDb::index_serial_hash(const char **a) {
227 const char *n = a[Ssl::CertificateDb::cnlSerial];
228 while (*n == '0')
229 ++n;
230 return lh_strhash(n);
231 }
232
233 int Ssl::CertificateDb::index_serial_cmp(const char **a, const char **b) {
234 const char *aa, *bb;
235 for (aa = a[Ssl::CertificateDb::cnlSerial]; *aa == '0'; ++aa);
236 for (bb = b[Ssl::CertificateDb::cnlSerial]; *bb == '0'; ++bb);
237 return strcmp(aa, bb);
238 }
239
240 unsigned long Ssl::CertificateDb::index_name_hash(const char **a) {
241 return(lh_strhash(a[Ssl::CertificateDb::cnlKey]));
242 }
243
244 int Ssl::CertificateDb::index_name_cmp(const char **a, const char **b) {
245 return(strcmp(a[Ssl::CertificateDb::cnlKey], b[CertificateDb::cnlKey]));
246 }
247
248 const std::string Ssl::CertificateDb::db_file("index.txt");
249 const std::string Ssl::CertificateDb::cert_dir("certs");
250 const std::string Ssl::CertificateDb::size_file("size");
251
252 Ssl::CertificateDb::CertificateDb(std::string const & aDb_path, size_t aMax_db_size, size_t aFs_block_size)
253 : db_path(aDb_path),
254 db_full(aDb_path + "/" + db_file),
255 cert_full(aDb_path + "/" + cert_dir),
256 size_full(aDb_path + "/" + size_file),
257 max_db_size(aMax_db_size),
258 fs_block_size((aFs_block_size ? aFs_block_size : 2048)),
259 dbLock(db_full),
260 enabled_disk_store(true) {
261 if (db_path.empty() && !max_db_size)
262 enabled_disk_store = false;
263 else if ((db_path.empty() && max_db_size) || (!db_path.empty() && !max_db_size))
264 throw std::runtime_error("security_file_certgen is missing the required parameter. There should be -s and -M parameters together.");
265 }
266
267 bool
268 Ssl::CertificateDb::find(std::string const &key, const Security::CertPointer &expectedOrig, Security::CertPointer &cert, Security::PrivateKeyPointer &pkey)
269 {
270 const Locker locker(dbLock, Here);
271 load();
272 return pure_find(key, expectedOrig, cert, pkey);
273 }
274
275 bool Ssl::CertificateDb::purgeCert(std::string const & key) {
276 const Locker locker(dbLock, Here);
277 load();
278 if (!db)
279 return false;
280
281 if (!deleteByKey(key))
282 return false;
283
284 save();
285 return true;
286 }
287
288 bool
289 Ssl::CertificateDb::addCertAndPrivateKey(std::string const &useKey, const Security::CertPointer &cert, const Security::PrivateKeyPointer &pkey, const Security::CertPointer &orig)
290 {
291 const Locker locker(dbLock, Here);
292 load();
293 if (!db || !cert || !pkey)
294 return false;
295
296 if(useKey.empty())
297 return false;
298
299 // Functor to wrap xfree() for std::unique_ptr
300 typedef HardFun<void, const void*, &xfree> CharDeleter;
301
302 Row row;
303 ASN1_INTEGER * ai = X509_get_serialNumber(cert.get());
304 std::string serial_string;
305 Ssl::BIGNUM_Pointer serial(ASN1_INTEGER_to_BN(ai, NULL));
306 {
307 std::unique_ptr<char, CharDeleter> hex_bn(BN_bn2hex(serial.get()));
308 serial_string = std::string(hex_bn.get());
309 }
310 row.setValue(cnlSerial, serial_string.c_str());
311 char ** rrow = TXT_DB_get_by_index(db.get(), cnlSerial, row.getRow());
312 // We are creating certificates with unique serial numbers. If the serial
313 // number is found in the database, the same certificate is already stored.
314 if (rrow != NULL) {
315 // TODO: check if the stored row is valid.
316 return true;
317 }
318
319 // Remove any entry with given key
320 deleteByKey(useKey);
321
322 // check db size while trying to minimize calls to size()
323 size_t dbSize = size();
324 if ((dbSize == 0 && hasRows()) ||
325 (dbSize > 0 && !hasRows()) ||
326 (dbSize > 10 * max_db_size)) {
327 // Invalid database size, rebuild
328 dbSize = rebuildSize();
329 }
330 while (dbSize > max_db_size && deleteInvalidCertificate()) {
331 dbSize = size(); // get the current database size
332 // and try to find another invalid certificate if needed
333 }
334 // there are no more invalid ones, but there must be valid certificates
335 while (dbSize > max_db_size) {
336 if (!deleteOldestCertificate()) {
337 rebuildSize(); // No certificates in database.Update the size file.
338 save(); // Some entries may have been removed. Update the index file.
339 return false; // errors prevented us from freeing enough space
340 }
341 dbSize = size(); // get the current database size
342 }
343
344 ASN1_UTCTIME * tm = X509_get_notAfter(cert.get());
345 row.setValue(cnlExp_date, std::string(reinterpret_cast<char *>(tm->data), tm->length).c_str());
346 std::unique_ptr<char, CharDeleter> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0));
347 row.setValue(cnlName, subject.get());
348 row.setValue(cnlKey, useKey.c_str());
349
350 if (!TXT_DB_insert(db.get(), row.getRow())) {
351 // failed to add index (???) but we may have already modified
352 // the database so save before exit
353 save();
354 return false;
355 }
356 rrow = row.getRow();
357 row.reset();
358
359 std::string filename(cert_full + "/" + serial_string + ".pem");
360 if (!WriteEntry(filename.c_str(), cert, pkey, orig)) {
361 //remove row from txt_db and save
362 sq_TXT_DB_delete(db.get(), (const char **)rrow);
363 save();
364 return false;
365 }
366 addSize(filename);
367
368 save();
369 return true;
370 }
371
372 void
373 Ssl::CertificateDb::Create(std::string const & db_path) {
374 if (db_path == "")
375 throw std::runtime_error("Path to db is empty");
376 std::string db_full(db_path + "/" + db_file);
377 std::string cert_full(db_path + "/" + cert_dir);
378 std::string size_full(db_path + "/" + size_file);
379
380 if (mkdir(db_path.c_str(), 0777))
381 throw std::runtime_error("Cannot create " + db_path);
382
383 if (mkdir(cert_full.c_str(), 0777))
384 throw std::runtime_error("Cannot create " + cert_full);
385
386 std::ofstream size(size_full.c_str());
387 if (size)
388 size << 0;
389 else
390 throw std::runtime_error("Cannot open " + size_full + " to open");
391 std::ofstream db(db_full.c_str());
392 if (!db)
393 throw std::runtime_error("Cannot open " + db_full + " to open");
394 }
395
396 void
397 Ssl::CertificateDb::Check(std::string const & db_path, size_t max_db_size, size_t fs_block_size) {
398 CertificateDb db(db_path, max_db_size, fs_block_size);
399 db.load();
400
401 // Call readSize to force rebuild size file in the case it is corrupted
402 (void)db.readSize();
403 }
404
405 size_t Ssl::CertificateDb::rebuildSize()
406 {
407 size_t dbSize = 0;
408 #if SQUID_SSLTXTDB_PSTRINGDATA
409 for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
410 #if SQUID_STACKOF_PSTRINGDATA_HACK
411 const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
412 #else
413 const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
414 #endif
415 #else
416 for (int i = 0; i < sk_num(db.get()->data); ++i) {
417 const char ** current_row = ((const char **)sk_value(db.get()->data, i));
418 #endif
419 const std::string filename(cert_full + "/" + current_row[cnlSerial] + ".pem");
420 const size_t fSize = getFileSize(filename);
421 dbSize += fSize;
422 }
423 writeSize(dbSize);
424 return dbSize;
425 }
426
427 bool
428 Ssl::CertificateDb::pure_find(std::string const &key, const Security::CertPointer &expectedOrig, Security::CertPointer &cert, Security::PrivateKeyPointer &pkey)
429 {
430 if (!db)
431 return false;
432
433 Row row;
434 row.setValue(cnlKey, key.c_str());
435
436 char **rrow = TXT_DB_get_by_index(db.get(), cnlKey, row.getRow());
437 if (rrow == NULL)
438 return false;
439
440 if (!sslDateIsInTheFuture(rrow[cnlExp_date]))
441 return false;
442
443 Security::CertPointer storedOrig;
444 // read cert and pkey from file.
445 std::string filename(cert_full + "/" + rrow[cnlSerial] + ".pem");
446 if (!ReadEntry(filename.c_str(), cert, pkey, storedOrig))
447 return false;
448
449 if (!storedOrig && !expectedOrig)
450 return true;
451 else
452 return Ssl::CertificatesCmp(expectedOrig, storedOrig);
453 }
454
455 size_t Ssl::CertificateDb::size() {
456 return readSize();
457 }
458
459 void Ssl::CertificateDb::addSize(std::string const & filename) {
460 // readSize will rebuild 'size' file if missing or it is corrupted
461 size_t dbSize = readSize();
462 dbSize += getFileSize(filename);
463 writeSize(dbSize);
464 }
465
466 void Ssl::CertificateDb::subSize(std::string const & filename) {
467 // readSize will rebuild 'size' file if missing or it is corrupted
468 size_t dbSize = readSize();
469 const size_t fileSize = getFileSize(filename);
470 dbSize = dbSize > fileSize ? dbSize - fileSize : 0;
471 writeSize(dbSize);
472 }
473
474 size_t Ssl::CertificateDb::readSize() {
475 std::ifstream ifstr(size_full.c_str());
476 size_t db_size = 0;
477 if (!ifstr || !(ifstr >> db_size))
478 return rebuildSize();
479 return db_size;
480 }
481
482 void Ssl::CertificateDb::writeSize(size_t db_size) {
483 std::ofstream ofstr(size_full.c_str());
484 if (!ofstr)
485 throw std::runtime_error("cannot write \"" + size_full + "\" file");
486 ofstr << db_size;
487 }
488
489 size_t Ssl::CertificateDb::getFileSize(std::string const & filename) {
490 std::ifstream file(filename.c_str(), std::ios::binary);
491 if (!file)
492 return 0;
493 file.seekg(0, std::ios_base::end);
494 const std::streampos file_size = file.tellg();
495 if (file_size < 0)
496 return 0;
497 return ((static_cast<size_t>(file_size) + fs_block_size - 1) / fs_block_size) * fs_block_size;
498 }
499
500 void Ssl::CertificateDb::load() {
501 // Load db from file.
502 Ssl::BIO_Pointer in(BIO_new(BIO_s_file()));
503 if (!in || BIO_read_filename(in.get(), db_full.c_str()) <= 0)
504 throw std::runtime_error("Uninitialized SSL certificate database directory: " + db_path + ". To initialize, run \"security_file_certgen -c -s " + db_path + "\".");
505
506 bool corrupt = false;
507 Ssl::TXT_DB_Pointer temp_db(TXT_DB_read(in.get(), cnlNumber));
508 if (!temp_db)
509 corrupt = true;
510
511 // Create indexes in db.
512 if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlSerial, NULL, LHASH_HASH_FN(index_serial_hash), LHASH_COMP_FN(index_serial_cmp)))
513 corrupt = true;
514
515 if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlKey, NULL, LHASH_HASH_FN(index_name_hash), LHASH_COMP_FN(index_name_cmp)))
516 corrupt = true;
517
518 if (corrupt)
519 throw std::runtime_error("The SSL certificate database " + db_path + " is corrupted. Please rebuild");
520
521 db.reset(temp_db.release());
522 }
523
524 void Ssl::CertificateDb::save() {
525 if (!db)
526 throw std::runtime_error("The certificates database is not loaded");;
527
528 // To save the db to file, create a new BIO with BIO file methods.
529 Ssl::BIO_Pointer out(BIO_new(BIO_s_file()));
530 if (!out || !BIO_write_filename(out.get(), const_cast<char *>(db_full.c_str())))
531 throw std::runtime_error("Failed to initialize " + db_full + " file for writing");;
532
533 if (TXT_DB_write(out.get(), db.get()) < 0)
534 throw std::runtime_error("Failed to write " + db_full + " file");
535 }
536
537 // Normally defined in defines.h file
538 void Ssl::CertificateDb::deleteRow(const char **row, int rowIndex) {
539 const std::string filename(cert_full + "/" + row[cnlSerial] + ".pem");
540 sq_TXT_DB_delete_row(db.get(), rowIndex);
541
542 subSize(filename);
543 int ret = remove(filename.c_str());
544 if (ret < 0 && errno != ENOENT)
545 throw std::runtime_error("Failed to remove certficate file " + filename + " from db");
546 }
547
548 bool Ssl::CertificateDb::deleteInvalidCertificate() {
549 if (!db)
550 return false;
551
552 bool removed_one = false;
553 #if SQUID_SSLTXTDB_PSTRINGDATA
554 for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
555 #if SQUID_STACKOF_PSTRINGDATA_HACK
556 const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
557 #else
558 const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
559 #endif
560 #else
561 for (int i = 0; i < sk_num(db.get()->data); ++i) {
562 const char ** current_row = ((const char **)sk_value(db.get()->data, i));
563 #endif
564
565 if (!sslDateIsInTheFuture(current_row[cnlExp_date])) {
566 deleteRow(current_row, i);
567 removed_one = true;
568 break;
569 }
570 }
571
572 if (!removed_one)
573 return false;
574 return true;
575 }
576
577 bool Ssl::CertificateDb::deleteOldestCertificate()
578 {
579 if (!hasRows())
580 return false;
581
582 #if SQUID_SSLTXTDB_PSTRINGDATA
583 #if SQUID_STACKOF_PSTRINGDATA_HACK
584 const char **row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), 0));
585 #else
586 const char **row = (const char **)sk_OPENSSL_PSTRING_value(db.get()->data, 0);
587 #endif
588 #else
589 const char **row = (const char **)sk_value(db.get()->data, 0);
590 #endif
591
592 deleteRow(row, 0);
593
594 return true;
595 }
596
597 bool
598 Ssl::CertificateDb::deleteByKey(std::string const & key) {
599 if (!db)
600 return false;
601
602 #if SQUID_SSLTXTDB_PSTRINGDATA
603 for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
604 #if SQUID_STACKOF_PSTRINGDATA_HACK
605 const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
606 #else
607 const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
608 #endif
609 #else
610 for (int i = 0; i < sk_num(db.get()->data); ++i) {
611 const char ** current_row = ((const char **)sk_value(db.get()->data, i));
612 #endif
613 if (key == current_row[cnlKey]) {
614 deleteRow(current_row, i);
615 return true;
616 }
617 }
618 return false;
619 }
620
621 bool Ssl::CertificateDb::hasRows() const
622 {
623 if (!db)
624 return false;
625
626 #if SQUID_SSLTXTDB_PSTRINGDATA
627 if (sk_OPENSSL_PSTRING_num(db.get()->data) == 0)
628 #else
629 if (sk_num(db.get()->data) == 0)
630 #endif
631 return false;
632 return true;
633 }
634
635 bool Ssl::CertificateDb::IsEnabledDiskStore() const {
636 return enabled_disk_store;
637 }
638
639 bool
640 Ssl::CertificateDb::WriteEntry(const std::string &filename, const Security::CertPointer &cert, const Security::PrivateKeyPointer &pkey, const Security::CertPointer &orig)
641 {
642 Ssl::BIO_Pointer bio;
643 if (!Ssl::OpenCertsFileForWriting(bio, filename.c_str()))
644 return false;
645 if (!Ssl::WriteX509Certificate(bio, cert))
646 return false;
647 if (!Ssl::WritePrivateKey(bio, pkey))
648 return false;
649 if (orig && !Ssl::WriteX509Certificate(bio, orig))
650 return false;
651 return true;
652 }
653
654 bool
655 Ssl::CertificateDb::ReadEntry(std::string filename, Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, Security::CertPointer &orig)
656 {
657 Ssl::BIO_Pointer bio;
658 if (!Ssl::OpenCertsFileForReading(bio, filename.c_str()))
659 return false;
660 if (!Ssl::ReadX509Certificate(bio, cert))
661 return false;
662 if (!Ssl::ReadPrivateKey(bio, pkey, NULL))
663 return false;
664 // The orig certificate is not mandatory
665 (void)Ssl::ReadX509Certificate(bio, orig);
666 return true;
667 }
668