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