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

 

Introduction

Documentation

Support

Miscellaneous