]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/ssl/certificate_db.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ssl / certificate_db.cc
index 708d2f07f01da519735411fceafe91dfc74dede7..7be669f00687a320523c1989e6e180b454bd20ef 100644 (file)
@@ -1,18 +1,17 @@
 /*
- * $Id$
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #include "squid.h"
 #include "ssl/certificate_db.h"
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#if HAVE_FSTREAM
+
+#include <cerrno>
 #include <fstream>
-#endif
-#if HAVE_STDEXCEPT
 #include <stdexcept>
-#endif
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
 #define HERE "(ssl_crtd) " << __FILE__ << ':' << __LINE__ << ": "
 
 Ssl::Lock::Lock(std::string const &aFilename) :
-        filename(aFilename),
-#if _SQUID_MSWIN_
-        hFile(INVALID_HANDLE_VALUE)
+    filename(aFilename),
+#if _SQUID_WINDOWS_
+    hFile(INVALID_HANDLE_VALUE)
 #else
-        fd(-1)
+    fd(-1)
 #endif
 {
 }
 
 bool Ssl::Lock::locked() const
 {
-#if _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
     return hFile != INVALID_HANDLE_VALUE;
 #else
     return fd != -1;
@@ -47,27 +46,26 @@ bool Ssl::Lock::locked() const
 void Ssl::Lock::lock()
 {
 
-#if _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
     hFile = CreateFile(TEXT(filename.c_str()), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     if (hFile == INVALID_HANDLE_VALUE)
 #else
-    fd = open(filename.c_str(), 0);
+    fd = open(filename.c_str(), O_RDWR);
     if (fd == -1)
 #endif
         throw std::runtime_error("Failed to open file " + filename);
 
-
-#if _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
     if (!LockFile(hFile, 0, 0, 1, 0))
 #else
-    if (flock(fd, LOCK_EX) != 0)
+    if (lockf(fd, F_LOCK, 0) != 0)
 #endif
         throw std::runtime_error("Failed to get a lock of " + filename);
 }
 
 void Ssl::Lock::unlock()
 {
-#if _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
     if (hFile != INVALID_HANDLE_VALUE) {
         UnlockFile(hFile, 0, 0, 1, 0);
         CloseHandle(hFile);
@@ -75,7 +73,7 @@ void Ssl::Lock::unlock()
     }
 #else
     if (fd != -1) {
-        flock(fd, LOCK_UN);
+        lockf(fd, F_ULOCK, 0);
         close(fd);
         fd = -1;
     }
@@ -91,7 +89,7 @@ Ssl::Lock::~Lock()
 }
 
 Ssl::Locker::Locker(Lock &aLock, const char *aFileName, int aLineNo):
-        weLocked(false), lock(aLock), fileName(aFileName), lineNo(aLineNo)
+    weLocked(false), lock(aLock), fileName(aFileName), lineNo(aLineNo)
 {
     if (!lock.locked()) {
         lock.lock();
@@ -106,21 +104,40 @@ Ssl::Locker::~Locker()
 }
 
 Ssl::CertificateDb::Row::Row()
-        :   width(cnlNumber)
+    :   width(cnlNumber)
 {
-    row = new char *[width + 1];
-    for (size_t i = 0; i < width + 1; i++)
+    row = (char **)OPENSSL_malloc(sizeof(char *) * (width + 1));
+    for (size_t i = 0; i < width + 1; ++i)
         row[i] = NULL;
 }
 
+Ssl::CertificateDb::Row::Row(char **aRow, size_t aWidth): width(aWidth)
+{
+    row = aRow;
+}
+
 Ssl::CertificateDb::Row::~Row()
 {
-    if (row) {
-        for (size_t i = 0; i < width + 1; i++) {
-            delete[](row[i]);
+    if (!row)
+        return;
+
+    void *max;
+    if ((max = (void *)row[width]) != NULL) {
+        // It is an openSSL allocated row. The TXT_DB_read function stores the
+        // index and row items one one memory segment. The row[width] points
+        // to the end of buffer. We have to check for items in the array which
+        // are not stored in this segment. These items should released.
+        for (size_t i = 0; i < width + 1; ++i) {
+            if (((row[i] < (char *)row) || (row[i] > max)) && (row[i] != NULL))
+                OPENSSL_free(row[i]);
+        }
+    } else {
+        for (size_t i = 0; i < width + 1; ++i) {
+            if (row[i])
+                OPENSSL_free(row[i]);
         }
-        delete[](row);
     }
+    OPENSSL_free(row);
 }
 
 void Ssl::CertificateDb::Row::reset()
@@ -135,7 +152,7 @@ void Ssl::CertificateDb::Row::setValue(size_t cell, char const * value)
         free(row[cell]);
     }
     if (value) {
-        row[cell] = static_cast<char *>(malloc(sizeof(char) * (strlen(value) + 1)));
+        row[cell] = static_cast<char *>(OPENSSL_malloc(sizeof(char) * (strlen(value) + 1)));
         memcpy(row[cell], value, sizeof(char) * (strlen(value) + 1));
     } else
         row[cell] = NULL;
@@ -146,28 +163,77 @@ char ** Ssl::CertificateDb::Row::getRow()
     return row;
 }
 
-unsigned long Ssl::CertificateDb::index_serial_hash(const char **a)
+void Ssl::CertificateDb::sq_TXT_DB_delete(TXT_DB *db, const char **row)
 {
+    if (!db)
+        return;
+
+#if SQUID_SSLTXTDB_PSTRINGDATA
+    for (int i = 0; i < sk_OPENSSL_PSTRING_num(db->data); ++i) {
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+        const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db->data), i));
+#else
+        const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db->data, i));
+#endif
+#else
+    for (int i = 0; i < sk_num(db->data); ++i) {
+        const char ** current_row = ((const char **)sk_value(db->data, i));
+#endif
+        if (current_row == row) {
+            sq_TXT_DB_delete_row(db, i);
+            return;
+        }
+    }
+}
+
+#define countof(arr) (sizeof(arr)/sizeof(*arr))
+void Ssl::CertificateDb::sq_TXT_DB_delete_row(TXT_DB *db, int idx) {
+    char **rrow;
+#if SQUID_SSLTXTDB_PSTRINGDATA
+    rrow = (char **)sk_OPENSSL_PSTRING_delete(db->data, idx);
+#else
+    rrow = (char **)sk_delete(db->data, idx);
+#endif
+
+    if (!rrow)
+        return;
+
+    Row row(rrow, cnlNumber); // row wrapper used to free the rrow
+
+    const Columns db_indexes[]= {cnlSerial, cnlName};
+    for (unsigned int i = 0; i < countof(db_indexes); ++i) {
+        void *data = NULL;
+#if SQUID_SSLTXTDB_PSTRINGDATA
+        if (LHASH_OF(OPENSSL_STRING) *fieldIndex =  db->index[db_indexes[i]])
+            data = lh_OPENSSL_STRING_delete(fieldIndex, rrow);
+#else
+        if (LHASH *fieldIndex = db->index[db_indexes[i]])
+            data = lh_delete(fieldIndex, rrow);
+#endif
+        if (data)
+            assert(data == rrow);
+    }
+}
+
+unsigned long Ssl::CertificateDb::index_serial_hash(const char **a) {
     const char *n = a[Ssl::CertificateDb::cnlSerial];
-    while (*n == '0') n++;
+    while (*n == '0')
+        ++n;
     return lh_strhash(n);
 }
 
-int Ssl::CertificateDb::index_serial_cmp(const char **a, const char **b)
-{
+int Ssl::CertificateDb::index_serial_cmp(const char **a, const char **b) {
     const char *aa, *bb;
-    for (aa = a[Ssl::CertificateDb::cnlSerial]; *aa == '0'; aa++);
-    for (bb = b[Ssl::CertificateDb::cnlSerial]; *bb == '0'; bb++);
+    for (aa = a[Ssl::CertificateDb::cnlSerial]; *aa == '0'; ++aa);
+    for (bb = b[Ssl::CertificateDb::cnlSerial]; *bb == '0'; ++bb);
     return strcmp(aa, bb);
 }
 
-unsigned long Ssl::CertificateDb::index_name_hash(const char **a)
-{
+unsigned long Ssl::CertificateDb::index_name_hash(const char **a) {
     return(lh_strhash(a[Ssl::CertificateDb::cnlName]));
 }
 
-int Ssl::CertificateDb::index_name_cmp(const char **a, const char **b)
-{
+int Ssl::CertificateDb::index_name_cmp(const char **a, const char **b) {
     return(strcmp(a[Ssl::CertificateDb::cnlName], b[CertificateDb::cnlName]));
 }
 
@@ -176,31 +242,28 @@ const std::string Ssl::CertificateDb::cert_dir("certs");
 const std::string Ssl::CertificateDb::size_file("size");
 
 Ssl::CertificateDb::CertificateDb(std::string const & aDb_path, size_t aMax_db_size, size_t aFs_block_size)
-        :  db_path(aDb_path),
-        db_full(aDb_path + "/" + db_file),
-        cert_full(aDb_path + "/" + cert_dir),
-        size_full(aDb_path + "/" + size_file),
-        db(NULL),
-        max_db_size(aMax_db_size),
-        fs_block_size(aFs_block_size),
-        dbLock(db_full),
-        enabled_disk_store(true)
-{
+    :  db_path(aDb_path),
+       db_full(aDb_path + "/" + db_file),
+       cert_full(aDb_path + "/" + cert_dir),
+       size_full(aDb_path + "/" + size_file),
+       db(NULL),
+       max_db_size(aMax_db_size),
+       fs_block_size((aFs_block_size ? aFs_block_size : 2048)),
+       dbLock(db_full),
+       enabled_disk_store(true) {
     if (db_path.empty() && !max_db_size)
         enabled_disk_store = false;
     else if ((db_path.empty() && max_db_size) || (!db_path.empty() && !max_db_size))
         throw std::runtime_error("ssl_crtd is missing the required parameter. There should be -s and -M parameters together.");
 }
 
-bool Ssl::CertificateDb::find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
-{
+bool Ssl::CertificateDb::find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey) {
     const Locker locker(dbLock, Here);
     load();
     return pure_find(host_name, cert, pkey);
 }
 
-bool Ssl::CertificateDb::purgeCert(std::string const & key)
-{
+bool Ssl::CertificateDb::purgeCert(std::string const & key) {
     const Locker locker(dbLock, Here);
     load();
     if (!db)
@@ -213,8 +276,7 @@ bool Ssl::CertificateDb::purgeCert(std::string const & key)
     return true;
 }
 
-bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, std::string const & useName)
-{
+bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, std::string const & useName) {
     const Locker locker(dbLock, Here);
     load();
     if (!db || !cert || !pkey)
@@ -229,16 +291,26 @@ bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP
     }
     row.setValue(cnlSerial, serial_string.c_str());
     char ** rrow = TXT_DB_get_by_index(db.get(), cnlSerial, row.getRow());
-    // We are creating certificates with unique serial number. If the serial
-    // number found in the database, means that the certificate already exist
-    // in the database
-    if (rrow != NULL)
+    // We are creating certificates with unique serial numbers. If the serial
+    // number is found in the database, the same certificate is already stored.
+    if (rrow != NULL) {
+        // TODO: check if the stored row is valid.
         return true;
+    }
 
     {
         TidyPointer<char, tidyFree> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), NULL, 0));
-        if (pure_find(useName.empty() ? subject.get() : useName, cert, pkey))
+        Ssl::X509_Pointer findCert;
+        Ssl::EVP_PKEY_Pointer findPkey;
+        if (pure_find(useName.empty() ? subject.get() : useName, findCert, findPkey)) {
+            // Replace with database certificate
+            cert.reset(findCert.release());
+            pkey.reset(findPkey.release());
             return true;
+        }
+        // pure_find may fail because the entry is expired, or because the
+        // certs file is corrupted. Remove any entry with given hostname
+        deleteByHostname(useName.empty() ? subject.get() : useName);
     }
 
     // check db size while trying to minimize calls to size()
@@ -248,8 +320,10 @@ bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP
 
         // there are no more invalid ones, but there must be valid certificates
         do {
-            if (!deleteOldestCertificate())
+            if (!deleteOldestCertificate()) {
+                save(); // Some entries may have been removed. Update the index file.
                 return false; // errors prevented us from freeing enough space
+            }
         } while (size() > max_db_size);
         break;
     }
@@ -265,39 +339,39 @@ bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP
         row.setValue(cnlName, subject.get());
     }
 
-    if (!TXT_DB_insert(db.get(), row.getRow()))
+    if (!TXT_DB_insert(db.get(), row.getRow())) {
+        // failed to add index (???) but we may have already modified
+        // the database so save before exit
+        save();
         return false;
-
+    }
+    rrow = row.getRow();
     row.reset();
+
     std::string filename(cert_full + "/" + serial_string + ".pem");
-    if (!writeCertAndPrivateKeyToFile(cert, pkey, filename.c_str()))
+    if (!writeCertAndPrivateKeyToFile(cert, pkey, filename.c_str())) {
+        //remove row from txt_db and save
+        sq_TXT_DB_delete(db.get(), (const char **)rrow);
+        save();
         return false;
+    }
     addSize(filename);
 
     save();
     return true;
 }
 
-void Ssl::CertificateDb::create(std::string const & db_path)
-{
+void Ssl::CertificateDb::create(std::string const & db_path) {
     if (db_path == "")
         throw std::runtime_error("Path to db is empty");
     std::string db_full(db_path + "/" + db_file);
     std::string cert_full(db_path + "/" + cert_dir);
     std::string size_full(db_path + "/" + size_file);
 
-#if _SQUID_MSWIN_
-    if (mkdir(db_path.c_str()))
-#else
     if (mkdir(db_path.c_str(), 0777))
-#endif
         throw std::runtime_error("Cannot create " + db_path);
 
-#if _SQUID_MSWIN_
-    if (mkdir(cert_full.c_str()))
-#else
     if (mkdir(cert_full.c_str(), 0777))
-#endif
         throw std::runtime_error("Cannot create " + cert_full);
 
     std::ofstream size(size_full.c_str());
@@ -310,14 +384,37 @@ void Ssl::CertificateDb::create(std::string const & db_path)
         throw std::runtime_error("Cannot open " + db_full + " to open");
 }
 
-void Ssl::CertificateDb::check(std::string const & db_path, size_t max_db_size)
-{
-    CertificateDb db(db_path, max_db_size, 0);
+void Ssl::CertificateDb::check(std::string const & db_path, size_t max_db_size, size_t fs_block_size) {
+    CertificateDb db(db_path, max_db_size, fs_block_size);
     db.load();
+
+    // Call readSize to force rebuild size file in the case it is corrupted
+    (void)db.readSize();
 }
 
-bool Ssl::CertificateDb::pure_find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
+size_t Ssl::CertificateDb::rebuildSize()
 {
+    size_t dbSize = 0;
+#if SQUID_SSLTXTDB_PSTRINGDATA
+    for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+        const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
+#else
+        const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
+#endif
+#else
+    for (int i = 0; i < sk_num(db.get()->data); ++i) {
+        const char ** current_row = ((const char **)sk_value(db.get()->data, i));
+#endif
+        const std::string filename(cert_full + "/" + current_row[cnlSerial] + ".pem");
+        const size_t fSize = getFileSize(filename);
+        dbSize += fSize;
+    }
+    writeSize(dbSize);
+    return dbSize;
+}
+
+bool Ssl::CertificateDb::pure_find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey) {
     if (!db)
         return false;
 
@@ -328,10 +425,8 @@ bool Ssl::CertificateDb::pure_find(std::string const & host_name, Ssl::X509_Poin
     if (rrow == NULL)
         return false;
 
-    if (!sslDateIsInTheFuture(rrow[cnlExp_date])) {
-        deleteByHostname(rrow[cnlName]);
+    if (!sslDateIsInTheFuture(rrow[cnlExp_date]))
         return false;
-    }
 
     // read cert and pkey from file.
     std::string filename(cert_full + "/" + rrow[cnlSerial] + ".pem");
@@ -341,50 +436,49 @@ bool Ssl::CertificateDb::pure_find(std::string const & host_name, Ssl::X509_Poin
     return true;
 }
 
-size_t Ssl::CertificateDb::size() const
-{
+size_t Ssl::CertificateDb::size() {
     return readSize();
 }
 
-void Ssl::CertificateDb::addSize(std::string const & filename)
-{
-    writeSize(readSize() + getFileSize(filename));
+void Ssl::CertificateDb::addSize(std::string const & filename) {
+    // readSize will rebuild 'size' file if missing or it is corrupted
+    size_t dbSize = readSize();
+    dbSize += getFileSize(filename);
+    writeSize(dbSize);
 }
 
-void Ssl::CertificateDb::subSize(std::string const & filename)
-{
-    writeSize(readSize() - getFileSize(filename));
+void Ssl::CertificateDb::subSize(std::string const & filename) {
+    // readSize will rebuild 'size' file if missing or it is corrupted
+    size_t dbSize = readSize();
+    dbSize -= getFileSize(filename);
+    writeSize(dbSize);
 }
 
-size_t Ssl::CertificateDb::readSize() const
-{
-    std::ifstream size_file(size_full.c_str());
-    if (!size_file && enabled_disk_store)
-        throw std::runtime_error("cannot open for reading: " + size_full);
+size_t Ssl::CertificateDb::readSize() {
+    std::ifstream ifstr(size_full.c_str());
     size_t db_size = 0;
-    if (!(size_file >> db_size))
-        throw std::runtime_error("error while reading " + size_full);
+    if (!ifstr || !(ifstr >> db_size))
+        return rebuildSize();
     return db_size;
 }
 
-void Ssl::CertificateDb::writeSize(size_t db_size)
-{
-    std::ofstream size_file(size_full.c_str());
-    if (!size_file && enabled_disk_store)
+void Ssl::CertificateDb::writeSize(size_t db_size) {
+    std::ofstream ofstr(size_full.c_str());
+    if (!ofstr)
         throw std::runtime_error("cannot write \"" + size_full + "\" file");
-    size_file << db_size;
+    ofstr << db_size;
 }
 
-size_t Ssl::CertificateDb::getFileSize(std::string const & filename)
-{
+size_t Ssl::CertificateDb::getFileSize(std::string const & filename) {
     std::ifstream file(filename.c_str(), std::ios::binary);
+    if (!file)
+        return 0;
     file.seekg(0, std::ios_base::end);
     size_t file_size = file.tellg();
     return ((file_size + fs_block_size - 1) / fs_block_size) * fs_block_size;
 }
 
-void Ssl::CertificateDb::load()
-{
+void Ssl::CertificateDb::load() {
     // Load db from file.
     Ssl::BIO_Pointer in(BIO_new(BIO_s_file()));
     if (!in || BIO_read_filename(in.get(), db_full.c_str()) <= 0)
@@ -396,19 +490,11 @@ void Ssl::CertificateDb::load()
         corrupt = true;
 
     // Create indexes in db.
-#if OPENSSL_VERSION_NUMBER >= 0x1000004fL
-    if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlSerial, NULL, LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial)))
-        corrupt = true;
-
-    if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlName, NULL, LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name)))
-        corrupt = true;
-#else
     if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlSerial, NULL, LHASH_HASH_FN(index_serial_hash), LHASH_COMP_FN(index_serial_cmp)))
         corrupt = true;
 
     if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlName, NULL, LHASH_HASH_FN(index_name_hash), LHASH_COMP_FN(index_name_cmp)))
         corrupt = true;
-#endif
 
     if (corrupt)
         throw std::runtime_error("The SSL certificate database " + db_path + " is corrupted. Please rebuild");
@@ -416,8 +502,7 @@ void Ssl::CertificateDb::load()
     db.reset(temp_db.release());
 }
 
-void Ssl::CertificateDb::save()
-{
+void Ssl::CertificateDb::save() {
     if (!db)
         throw std::runtime_error("The certificates database is not loaded");;
 
@@ -431,26 +516,9 @@ void Ssl::CertificateDb::save()
 }
 
 // Normally defined in defines.h file
-#define countof(arr) (sizeof(arr)/sizeof(*arr))
-void Ssl::CertificateDb::deleteRow(const char **row, int rowIndex)
-{
+void Ssl::CertificateDb::deleteRow(const char **row, int rowIndex) {
     const std::string filename(cert_full + "/" + row[cnlSerial] + ".pem");
-#if OPENSSL_VERSION_NUMBER >= 0x1000004fL
-    sk_OPENSSL_PSTRING_delete(db.get()->data, rowIndex);
-#else
-    sk_delete(db.get()->data, rowIndex);
-#endif
-
-    const Columns db_indexes[]={cnlSerial, cnlName};
-    for (unsigned int i = 0; i < countof(db_indexes); i++) {
-#if OPENSSL_VERSION_NUMBER >= 0x1000004fL
-        if (LHASH_OF(OPENSSL_STRING) *fieldIndex =  db.get()->index[db_indexes[i]])
-            lh_OPENSSL_STRING_delete(fieldIndex, (char **)row);
-#else
-        if (LHASH *fieldIndex = db.get()->index[db_indexes[i]])
-            lh_delete(fieldIndex, row);
-#endif
-    }
+    sq_TXT_DB_delete_row(db.get(), rowIndex);
 
     subSize(filename);
     int ret = remove(filename.c_str());
@@ -458,17 +526,20 @@ void Ssl::CertificateDb::deleteRow(const char **row, int rowIndex)
         throw std::runtime_error("Failed to remove certficate file " + filename + " from db");
 }
 
-bool Ssl::CertificateDb::deleteInvalidCertificate()
-{
+bool Ssl::CertificateDb::deleteInvalidCertificate() {
     if (!db)
         return false;
 
     bool removed_one = false;
-#if OPENSSL_VERSION_NUMBER >= 0x1000004fL
-    for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); i++) {
+#if SQUID_SSLTXTDB_PSTRINGDATA
+    for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+        const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
+#else
         const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
+#endif
 #else
-    for (int i = 0; i < sk_num(db.get()->data); i++) {
+    for (int i = 0; i < sk_num(db.get()->data); ++i) {
         const char ** current_row = ((const char **)sk_value(db.get()->data, i));
 #endif
 
@@ -484,20 +555,23 @@ bool Ssl::CertificateDb::deleteInvalidCertificate()
     return true;
 }
 
-bool Ssl::CertificateDb::deleteOldestCertificate()
-{
+bool Ssl::CertificateDb::deleteOldestCertificate() {
     if (!db)
         return false;
 
-#if OPENSSL_VERSION_NUMBER >= 0x1000004fL
+#if SQUID_SSLTXTDB_PSTRINGDATA
     if (sk_OPENSSL_PSTRING_num(db.get()->data) == 0)
 #else
     if (sk_num(db.get()->data) == 0)
 #endif
         return false;
 
-#if OPENSSL_VERSION_NUMBER >= 0x1000004fL
+#if SQUID_SSLTXTDB_PSTRINGDATA
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+    const char **row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), 0));
+#else
     const char **row = (const char **)sk_OPENSSL_PSTRING_value(db.get()->data, 0);
+#endif
 #else
     const char **row = (const char **)sk_value(db.get()->data, 0);
 #endif
@@ -507,16 +581,19 @@ bool Ssl::CertificateDb::deleteOldestCertificate()
     return true;
 }
 
-bool Ssl::CertificateDb::deleteByHostname(std::string const & host)
-{
+bool Ssl::CertificateDb::deleteByHostname(std::string const & host) {
     if (!db)
         return false;
 
-#if OPENSSL_VERSION_NUMBER >= 0x1000004fL
-    for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); i++) {
+#if SQUID_SSLTXTDB_PSTRINGDATA
+    for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+        const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
+#else
         const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
+#endif
 #else
-    for (int i = 0; i < sk_num(db.get()->data); i++) {
+    for (int i = 0; i < sk_num(db.get()->data); ++i) {
         const char ** current_row = ((const char **)sk_value(db.get()->data, i));
 #endif
         if (host == current_row[cnlName]) {
@@ -527,7 +604,7 @@ bool Ssl::CertificateDb::deleteByHostname(std::string const & host)
     return false;
 }
 
-bool Ssl::CertificateDb::IsEnabledDiskStore() const
-{
+bool Ssl::CertificateDb::IsEnabledDiskStore() const {
     return enabled_disk_store;
 }
+