AH_TEMPLATE(HAVE_LIBCRYPTO_X509_UP_REF, "Define to 1 if the X509_up_ref() OpenSSL API function exists")
AH_TEMPLATE(HAVE_LIBCRYPTO_X509_CRL_UP_REF, "Define to 1 if the X509_CRL_up_ref() OpenSSL API function exists")
AH_TEMPLATE(HAVE_LIBCRYPTO_DH_UP_REF, "Define to 1 if the DH_up_ref() OpenSSL API function exists")
+ AH_TEMPLATE(HAVE_LIBCRYPTO_X509_GET0_SIGNATURE, "Define to 1 if the X509_get0_signature() OpenSSL API function exists")
SQUID_STATE_SAVE(check_openssl_libcrypto_api)
LIBS="$LIBS $SSLLIB"
AC_CHECK_LIB(crypto, EVP_PKEY_get0_RSA, AC_DEFINE(HAVE_LIBCRYPTO_EVP_PKEY_GET0_RSA, 1))
AC_CHECK_LIB(crypto, X509_up_ref, AC_DEFINE(HAVE_LIBCRYPTO_X509_UP_REF, 1))
AC_CHECK_LIB(crypto, X509_CRL_up_ref, AC_DEFINE(HAVE_LIBCRYPTO_X509_CRL_UP_REF, 1))
AC_CHECK_LIB(crypto, DH_up_ref, AC_DEFINE(HAVE_LIBCRYPTO_DH_UP_REF, 1))
+ AC_CHECK_LIB(crypto, X509_get0_signature, AC_DEFINE(HAVE_LIBCRYPTO_X509_GET0_SIGNATURE, 1))
SQUID_STATE_ROLLBACK(check_openssl_libcrypto_api)
])
#include <list>
#include <map>
-template <class EntryValue, size_t EntryCost = sizeof(EntryValue)> class LruMap
+template <class Key, class EntryValue, size_t EntryCost = sizeof(EntryValue)> class LruMap
{
public:
class Entry
{
public:
- Entry(const char *aKey, EntryValue *t): key(aKey), value(t), date(squid_curtime) {}
+ Entry(const Key &aKey, EntryValue *t): key(aKey), value(t), date(squid_curtime) {}
~Entry() {delete value;}
private:
Entry(Entry &);
Entry & operator = (Entry &);
public:
- std::string key; ///< the key of entry
+ Key key; ///< the key of entry
EntryValue *value; ///< A pointer to the stored value
time_t date; ///< The date the entry created
};
typedef typename std::list<Entry *>::iterator QueueIterator;
/// key:queue_item mapping for fast lookups by key
- typedef std::map<std::string, QueueIterator> Map;
+ typedef std::map<Key, QueueIterator> Map;
typedef typename Map::iterator MapIterator;
- typedef std::pair<std::string, QueueIterator> MapPair;
+ typedef std::pair<Key, QueueIterator> MapPair;
LruMap(int ttl, size_t size);
~LruMap();
/// Search for an entry, and return a pointer
- EntryValue *get(const char *key);
+ EntryValue *get(const Key &key);
/// Add an entry to the map
- bool add(const char *key, EntryValue *t);
+ bool add(const Key &key, EntryValue *t);
/// Delete an entry from the map
- bool del(const char *key);
+ bool del(const Key &key);
/// (Re-)set the maximum size for this map
void setMemLimit(size_t aSize);
/// The available size for the map
void trim();
void touch(const MapIterator &i);
bool del(const MapIterator &i);
- void findEntry(const char *key, LruMap::MapIterator &i);
+ void findEntry(const Key &key, LruMap::MapIterator &i);
Map storage; ///< The Key/value * pairs
Queue index; ///< LRU cache index
int entries_; ///< The stored entries
};
-template <class EntryValue, size_t EntryCost>
-LruMap<EntryValue, EntryCost>::LruMap(int aTtl, size_t aSize): entries_(0)
+template <class Key, class EntryValue, size_t EntryCost>
+ LruMap<Key, EntryValue, EntryCost>::LruMap(int aTtl, size_t aSize): entries_(0)
{
ttl = aTtl;
setMemLimit(aSize);
}
-template <class EntryValue, size_t EntryCost>
-LruMap<EntryValue, EntryCost>::~LruMap()
+template <class Key, class EntryValue, size_t EntryCost>
+LruMap<Key, EntryValue, EntryCost>::~LruMap()
{
for (QueueIterator i = index.begin(); i != index.end(); ++i) {
delete *i;
}
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
void
-LruMap<EntryValue, EntryCost>::setMemLimit(size_t aSize)
+LruMap<Key, EntryValue, EntryCost>::setMemLimit(size_t aSize)
{
if (aSize > 0)
memLimit_ = aSize;
memLimit_ = 0;
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
void
-LruMap<EntryValue, EntryCost>::findEntry(const char *key, LruMap::MapIterator &i)
+LruMap<Key, EntryValue, EntryCost>::findEntry(const Key &key, LruMap::MapIterator &i)
{
i = storage.find(key);
if (i == storage.end()) {
i = storage.end();
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
EntryValue *
-LruMap<EntryValue, EntryCost>::get(const char *key)
+LruMap<Key, EntryValue, EntryCost>::get(const Key &key)
{
MapIterator i;
findEntry(key, i);
return NULL;
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
bool
-LruMap<EntryValue, EntryCost>::add(const char *key, EntryValue *t)
+LruMap<Key, EntryValue, EntryCost>::add(const Key &key, EntryValue *t)
{
if (ttl == 0)
return false;
return true;
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
bool
-LruMap<EntryValue, EntryCost>::expired(const LruMap::Entry &entry) const
+LruMap<Key, EntryValue, EntryCost>::expired(const LruMap::Entry &entry) const
{
if (ttl < 0)
return false;
return (entry.date + ttl < squid_curtime);
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
bool
-LruMap<EntryValue, EntryCost>::del(LruMap::MapIterator const &i)
+LruMap<Key, EntryValue, EntryCost>::del(LruMap::MapIterator const &i)
{
if (i != storage.end()) {
Entry *e = *i->second;
return false;
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
bool
-LruMap<EntryValue, EntryCost>::del(const char *key)
+LruMap<Key, EntryValue, EntryCost>::del(const Key &key)
{
MapIterator i;
findEntry(key, i);
return del(i);
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
void
-LruMap<EntryValue, EntryCost>::trim()
+LruMap<Key, EntryValue, EntryCost>::trim()
{
while (size() >= memLimit()) {
QueueIterator i = index.end();
--i;
if (i != index.end()) {
- del((*i)->key.c_str());
+ del((*i)->key);
}
}
}
-template <class EntryValue, size_t EntryCost>
+template <class Key, class EntryValue, size_t EntryCost>
void
-LruMap<EntryValue, EntryCost>::touch(LruMap::MapIterator const &i)
+LruMap<Key, EntryValue, EntryCost>::touch(LruMap::MapIterator const &i)
{
// this must not be done when nothing is being cached.
if (ttl == 0)
Security::ContextPointer ctx(Security::GetFrom(fd_table[clientConnection->fd].ssl));
Ssl::configureUnconfiguredSslContext(ctx, signAlgorithm, *port);
} else {
- Security::ContextPointer ctx(Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port));
- getSslContextDone(ctx, true);
+ Security::ContextPointer ctx(Ssl::GenerateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port, (signAlgorithm == Ssl::algSignTrusted)));
+ if (ctx && !sslBumpCertKey.isEmpty())
+ storeTlsContextToCache(sslBumpCertKey, ctx);
+ getSslContextDone(ctx);
}
return;
}
{
certProperties.commonName = sslCommonName_.isEmpty() ? sslConnectHostOrIp.termedBuf() : sslCommonName_.c_str();
- const bool triedToConnect = sslServerBump && sslServerBump->entry;
- const bool connectedOK = triedToConnect && sslServerBump->entry->isEmpty();
- if (connectedOK) {
+ const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
+ if (connectedOk) {
if (X509 *mimicCert = sslServerBump->serverCert.get())
certProperties.mimicCert.resetAndLock(mimicCert);
certProperties.signHash = Ssl::DefaultSignHash;
}
+Security::ContextPointer
+ConnStateData::getTlsContextFromCache(const SBuf &cacheKey, const Ssl::CertificateProperties &certProperties)
+{
+ debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
+ Ssl::LocalContextStorage * ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
+ if (Security::ContextPointer *ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
+ if (Ssl::verifySslCertificate(*ctx, certProperties)) {
+ debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
+ return *ctx;
+ } else {
+ debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
+ if (ssl_ctx_cache)
+ ssl_ctx_cache->del(cacheKey);
+ }
+ }
+ return Security::ContextPointer(nullptr);
+}
+
+void
+ConnStateData::storeTlsContextToCache(const SBuf &cacheKey, Security::ContextPointer &ctx)
+{
+ Ssl::LocalContextStorage *ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
+ if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, new Security::ContextPointer(ctx))) {
+ // If it is not in storage delete after using. Else storage deleted it.
+ fd_table[clientConnection->fd].dynamicTlsContext = ctx;
+ }
+}
+
void
ConnStateData::getSslContextStart()
{
if (port->generateHostCertificates) {
Ssl::CertificateProperties certProperties;
buildSslCertGenerationParams(certProperties);
- sslBumpCertKey = certProperties.dbKey().c_str();
- assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
// Disable caching for bumpPeekAndSplice mode
if (!(sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare))) {
- debugs(33, 5, "Finding SSL certificate for " << sslBumpCertKey << " in cache");
- Ssl::LocalContextStorage * ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
- Security::ContextPointer *cachedCtx = ssl_ctx_cache ? ssl_ctx_cache->get(sslBumpCertKey.termedBuf()) : nullptr;
- if (cachedCtx) {
- debugs(33, 5, "SSL certificate for " << sslBumpCertKey << " found in cache");
- if (Ssl::verifySslCertificate(*cachedCtx, certProperties)) {
- debugs(33, 5, "Cached SSL certificate for " << sslBumpCertKey << " is valid");
- getSslContextDone(*cachedCtx);
- return;
- } else {
- debugs(33, 5, "Cached SSL certificate for " << sslBumpCertKey << " is out of date. Delete this certificate from cache");
- if (ssl_ctx_cache)
- ssl_ctx_cache->del(sslBumpCertKey.termedBuf());
- }
- } else {
- debugs(33, 5, "SSL certificate for " << sslBumpCertKey << " haven't found in cache");
+ sslBumpCertKey.clear();
+ Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
+ assert(!sslBumpCertKey.isEmpty());
+
+ Security::ContextPointer ctx(getTlsContextFromCache(sslBumpCertKey, certProperties));
+ if (ctx) {
+ getSslContextDone(ctx);
+ return;
}
}
Security::ContextPointer ctx(Security::GetFrom(fd_table[clientConnection->fd].ssl));
Ssl::configureUnconfiguredSslContext(ctx, certProperties.signAlgorithm, *port);
} else {
- Security::ContextPointer dynCtx(Ssl::generateSslContext(certProperties, *port));
- getSslContextDone(dynCtx, true);
+ Security::ContextPointer dynCtx(Ssl::GenerateSslContext(certProperties, *port, (signAlgorithm == Ssl::algSignTrusted)));
+ if (dynCtx && !sslBumpCertKey.isEmpty())
+ storeTlsContextToCache(sslBumpCertKey, dynCtx);
+ getSslContextDone(dynCtx);
}
return;
}
}
void
-ConnStateData::getSslContextDone(Security::ContextPointer &ctx, bool isNew)
+ConnStateData::getSslContextDone(Security::ContextPointer &ctx)
{
- // Try to add generated ssl context to storage.
- if (port->generateHostCertificates && isNew) {
-
- if (ctx && (signAlgorithm == Ssl::algSignTrusted)) {
- Ssl::chainCertificatesToSSLContext(ctx, *port);
- } else if (signAlgorithm == Ssl::algSignTrusted) {
- debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain because SSL context chain is invalid!");
- }
- //else it is self-signed or untrusted do not attrach any certificate
-
- Ssl::LocalContextStorage *ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
- assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
- if (ctx) {
- if (!ssl_ctx_cache || !ssl_ctx_cache->add(sslBumpCertKey.termedBuf(), new Security::ContextPointer(ctx))) {
- // If it is not in storage delete after using. Else storage deleted it.
- fd_table[clientConnection->fd].dynamicTlsContext = ctx;
- }
- } else {
- debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslConnectHostOrIp);
- }
+ if (port->generateHostCertificates && !ctx) {
+ debugs(33, 2, "Failed to generate TLS cotnext for " << sslConnectHostOrIp);
}
// If generated ssl context = NULL, try to use static ssl context.
/// Start to create dynamic Security::ContextPointer for host or uses static port SSL context.
void getSslContextStart();
- /**
- * Done create dynamic ssl certificate.
- *
- * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
- */
- void getSslContextDone(Security::ContextPointer &, bool isNew = false);
+
+ /// finish configuring the newly created SSL context"
+ void getSslContextDone(Security::ContextPointer &);
+
/// Callback function. It is called when squid receive message from ssl_crtd.
static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
/// Proccess response from ssl_crtd.
bool parseProxy2p0();
bool proxyProtocolError(const char *reason);
+#if USE_OPENSSL
+ /// \returns a pointer to the matching cached TLS context or nil
+ Security::ContextPointer getTlsContextFromCache(const SBuf &cacheKey, const Ssl::CertificateProperties &certProperties);
+
+ /// Attempts to add a given TLS context to the cache, replacing the old
+ /// same-key context, if any
+ void storeTlsContextToCache(const SBuf &cacheKey, Security::ContextPointer &ctx);
+#endif
+
/// whether PROXY protocol header is still expected
bool needProxyProtocolHeader_;
/// TLS client delivered SNI value. Empty string if none has been received.
SBuf tlsClientSni_;
- String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
+ SBuf sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
/// HTTPS server cert. fetching state for bump-ssl-server-first
Ssl::ServerBump *sslServerBump;
Row row(rrow, cnlNumber); // row wrapper used to free the rrow
- const Columns db_indexes[]= {cnlSerial, cnlName};
+ const Columns db_indexes[]= {cnlSerial, cnlKey};
for (unsigned int i = 0; i < countof(db_indexes); ++i) {
void *data = NULL;
#if SQUID_SSLTXTDB_PSTRINGDATA
}
unsigned long Ssl::CertificateDb::index_name_hash(const char **a) {
- return(lh_strhash(a[Ssl::CertificateDb::cnlName]));
+ return(lh_strhash(a[Ssl::CertificateDb::cnlKey]));
}
int Ssl::CertificateDb::index_name_cmp(const char **a, const char **b) {
- return(strcmp(a[Ssl::CertificateDb::cnlName], b[CertificateDb::cnlName]));
+ return(strcmp(a[Ssl::CertificateDb::cnlKey], b[CertificateDb::cnlKey]));
}
const std::string Ssl::CertificateDb::db_file("index.txt");
throw std::runtime_error("security_file_certgen is missing the required parameter. There should be -s and -M parameters together.");
}
-bool Ssl::CertificateDb::find(std::string const & host_name, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey) {
+bool
+Ssl::CertificateDb::find(std::string const &key, const Security::CertPointer &expectedOrig, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
+{
const Locker locker(dbLock, Here);
load();
- return pure_find(host_name, cert, pkey);
+ return pure_find(key, expectedOrig, cert, pkey);
}
bool Ssl::CertificateDb::purgeCert(std::string const & key) {
if (!db)
return false;
- if (!deleteByHostname(key))
+ if (!deleteByKey(key))
return false;
save();
return true;
}
-bool Ssl::CertificateDb::addCertAndPrivateKey(Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, std::string const & useName) {
+bool
+Ssl::CertificateDb::addCertAndPrivateKey(std::string const & useKey, const Security::CertPointer & cert, const Ssl::EVP_PKEY_Pointer & pkey, const Security::CertPointer &orig) {
const Locker locker(dbLock, Here);
load();
if (!db || !cert || !pkey)
return false;
+ if(useKey.empty())
+ return false;
+
// Functor to wrap xfree() for std::unique_ptr
typedef HardFun<void, const void*, &xfree> CharDeleter;
return true;
}
- {
- std::unique_ptr<char, CharDeleter> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0));
- Security::CertPointer findCert;
- Ssl::EVP_PKEY_Pointer findPkey;
- if (pure_find(useName.empty() ? subject.get() : useName, findCert, findPkey)) {
- // Replace with database certificate
- cert = std::move(findCert);
- pkey = std::move(findPkey);
- 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);
- }
+ // Remove any entry with given key
+ deleteByKey(useKey);
// check db size while trying to minimize calls to size()
size_t dbSize = size();
dbSize = size(); // get the current database size
}
- row.setValue(cnlType, "V");
ASN1_UTCTIME * tm = X509_get_notAfter(cert.get());
row.setValue(cnlExp_date, std::string(reinterpret_cast<char *>(tm->data), tm->length).c_str());
- row.setValue(cnlFile, "unknown");
- if (!useName.empty())
- row.setValue(cnlName, useName.c_str());
- else {
- std::unique_ptr<char, CharDeleter> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0));
- row.setValue(cnlName, subject.get());
- }
+ std::unique_ptr<char, CharDeleter> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0));
+ row.setValue(cnlName, subject.get());
+ row.setValue(cnlKey, useKey.c_str());
if (!TXT_DB_insert(db.get(), row.getRow())) {
// failed to add index (???) but we may have already modified
row.reset();
std::string filename(cert_full + "/" + serial_string + ".pem");
- if (!writeCertAndPrivateKeyToFile(cert, pkey, filename.c_str())) {
+ if (!WriteEntry(filename.c_str(), cert, pkey, orig)) {
//remove row from txt_db and save
sq_TXT_DB_delete(db.get(), (const char **)rrow);
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);
throw std::runtime_error("Cannot open " + db_full + " to open");
}
-void Ssl::CertificateDb::check(std::string const & db_path, size_t max_db_size, size_t fs_block_size) {
+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();
return dbSize;
}
-bool Ssl::CertificateDb::pure_find(std::string const & host_name, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey) {
+bool
+Ssl::CertificateDb::pure_find(std::string const &key, const Security::CertPointer &expectedOrig, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
+{
if (!db)
return false;
Row row;
- row.setValue(cnlName, host_name.c_str());
+ row.setValue(cnlKey, key.c_str());
- char **rrow = TXT_DB_get_by_index(db.get(), cnlName, row.getRow());
+ char **rrow = TXT_DB_get_by_index(db.get(), cnlKey, row.getRow());
if (rrow == NULL)
return false;
if (!sslDateIsInTheFuture(rrow[cnlExp_date]))
return false;
+ Security::CertPointer storedOrig;
// read cert and pkey from file.
std::string filename(cert_full + "/" + rrow[cnlSerial] + ".pem");
- readCertAndPrivateKeyFromFiles(cert, pkey, filename.c_str(), NULL);
- if (!cert || !pkey)
+ if (!ReadEntry(filename.c_str(), cert, pkey, storedOrig))
return false;
- return true;
+
+ if (!storedOrig && !expectedOrig)
+ return true;
+ else
+ return Ssl::CertificatesCmp(expectedOrig, storedOrig);
}
size_t Ssl::CertificateDb::size() {
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)))
+ if (!corrupt && !TXT_DB_create_index(temp_db.get(), cnlKey, NULL, LHASH_HASH_FN(index_name_hash), LHASH_COMP_FN(index_name_cmp)))
corrupt = true;
if (corrupt)
return true;
}
-bool Ssl::CertificateDb::deleteByHostname(std::string const & host) {
+bool
+Ssl::CertificateDb::deleteByKey(std::string const & key) {
if (!db)
return false;
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]) {
+ if (key == current_row[cnlKey]) {
deleteRow(current_row, i);
return true;
}
return enabled_disk_store;
}
+bool
+Ssl::CertificateDb::WriteEntry(const std::string &filename, const Security::CertPointer & cert, const Ssl::EVP_PKEY_Pointer & pkey, const Security::CertPointer &orig)
+{
+ Ssl::BIO_Pointer bio;
+ if (!Ssl::OpenCertsFileForWriting(bio, filename.c_str()))
+ return false;
+ if (!Ssl::WriteX509Certificate(bio, cert))
+ return false;
+ if (!Ssl::WritePrivateKey(bio, pkey))
+ return false;
+ if (orig && !Ssl::WriteX509Certificate(bio, orig))
+ return false;
+ return true;
+}
+
+bool
+Ssl::CertificateDb::ReadEntry(std::string filename, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, Security::CertPointer &orig)
+{
+ Ssl::BIO_Pointer bio;
+ if (!Ssl::OpenCertsFileForReading(bio, filename.c_str()))
+ return false;
+ if (!Ssl::ReadX509Certificate(bio, cert))
+ return false;
+ if (!Ssl::ReadPrivateKey(bio, pkey, NULL))
+ return false;
+ // The orig certificate is not mandatory
+ (void)Ssl::ReadX509Certificate(bio, orig);
+ return true;
+}
public:
/// Names of db columns.
enum Columns {
- cnlType = 0,
+ cnlKey = 0, //< The key to use for storing/retrieving entries from DB.
cnlExp_date,
cnlRev_date,
cnlSerial,
- cnlFile,
cnlName,
cnlNumber
};
};
CertificateDb(std::string const & db_path, size_t aMax_db_size, size_t aFs_block_size);
- /// Find certificate and private key for host name
- bool find(std::string const & host_name, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
+ /// finds matching generated certificate and its private key
+ bool find(std::string const & key, const Security::CertPointer &expectedOrig, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
/// Delete a certificate from database
bool purgeCert(std::string const & key);
/// Save certificate to disk.
- bool addCertAndPrivateKey(Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, std::string const & useName);
+ bool addCertAndPrivateKey(std::string const & useKey, const Security::CertPointer & cert, const Ssl::EVP_PKEY_Pointer & pkey, const Security::CertPointer &orig);
+
+ bool IsEnabledDiskStore() const; ///< Check enabled of dist store.
+
/// Create and initialize a database under the db_path
- static void create(std::string const & db_path);
+ static void Create(std::string const & db_path);
/// Check the database stored under the db_path.
- static void check(std::string const & db_path, size_t max_db_size, size_t fs_block_size);
- bool IsEnabledDiskStore() const; ///< Check enabled of dist store.
+ static void Check(std::string const & db_path, size_t max_db_size, size_t fs_block_size);
private:
void load(); ///< Load db from disk.
void save(); ///< Save db to disk.
size_t getFileSize(std::string const & filename); ///< get file size on disk.
size_t rebuildSize(); ///< Rebuild size_file
/// Only find certificate in current db and return it.
- bool pure_find(std::string const & host_name, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
+ bool pure_find(std::string const & key, const Security::CertPointer & expectedOrig, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
void deleteRow(const char **row, int rowIndex); ///< Delete a row from TXT_DB
bool deleteInvalidCertificate(); ///< Delete invalid certificate.
bool deleteOldestCertificate(); ///< Delete oldest certificate.
- bool deleteByHostname(std::string const & host); ///< Delete using host name.
+ bool deleteByKey(std::string const & key); ///< Delete using key.
bool hasRows() const; ///< Whether the TXT_DB has stored items.
+ /// stores the db entry into a file
+ static bool WriteEntry(const std::string &filename, const Security::CertPointer & cert, const Ssl::EVP_PKEY_Pointer & pkey, const Security::CertPointer &orig);
+
+ /// loads a db entry from the file
+ static bool ReadEntry(std::string filename, Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, Security::CertPointer &orig);
+
/// Removes the first matching row from TXT_DB. Ignores failures.
static void sq_TXT_DB_delete(TXT_DB *db, const char **row);
/// Remove the row on position idx from TXT_DB. Ignores failures.
Security::CertPointer cert;
Ssl::EVP_PKEY_Pointer pkey;
- std::string &cert_subject = certProperties.dbKey();
+ Security::CertPointer orig;
+ std::string &certKey = Ssl::OnDiskCertificateDbKey(certProperties);
bool dbFailed = false;
try {
- db.find(cert_subject, cert, pkey);
+ db.find(certKey, certProperties.mimicCert, cert, pkey);
} catch (std::runtime_error &err) {
dbFailed = true;
error = err.what();
}
- if (cert) {
- if (!Ssl::certificateMatchesProperties(cert.get(), certProperties)) {
- // The certificate changed (renewed or other reason).
- // Generete a new one with the updated fields.
- cert.reset();
- pkey.reset();
- db.purgeCert(cert_subject);
- }
- }
-
if (!cert || !pkey) {
if (!Ssl::generateSslCertificate(cert, pkey, certProperties))
throw std::runtime_error("Cannot create ssl certificate or private key.");
if (!dbFailed && db.IsEnabledDiskStore()) {
try {
- if (!db.addCertAndPrivateKey(cert, pkey, cert_subject)) {
+ if (!db.addCertAndPrivateKey(certKey, cert, pkey, certProperties.mimicCert)) {
dbFailed = true;
error = "Cannot add certificate to db.";
}
if (create_new_db) {
std::cout << "Initialization SSL db..." << std::endl;
- Ssl::CertificateDb::create(db_path);
+ Ssl::CertificateDb::Create(db_path);
std::cout << "Done" << std::endl;
exit(EXIT_SUCCESS);
}
}
{
- Ssl::CertificateDb::check(db_path, max_db_size, fs_block_size);
+ Ssl::CertificateDb::Check(db_path, max_db_size, fs_block_size);
}
// Initialize SSL subsystem
SSL_load_error_strings();
#include "HttpRequest.h"
#include "ip/Address.h"
#include "security/forward.h"
+#include "Store.h"
class ConnStateData;
class store_client;
void attachServerSession(const Security::SessionPointer &); ///< Sets the server TLS session object
const Security::CertErrors *sslErrors() const; ///< SSL [certificate validation] errors
+ /// whether there was a successful connection to (and peeking at) the origin server
+ bool connectedOk() const {return entry && entry->isEmpty();}
+
/// faked, minimal request; required by Client API
HttpRequest::Pointer request;
StoreEntry *entry; ///< for receiving Squid-generated error messages
virtual bool aggregatable() const { return false; }
};
-typedef LruMap<Security::ContextPointer, SSL_CTX_SIZE> LocalContextStorage;
+typedef LruMap<SBuf, Security::ContextPointer, SSL_CTX_SIZE> LocalContextStorage;
/// Class for storing/manipulating LocalContextStorage per local listening address/port.
class GlobalContextStorage
#include "squid.h"
#include "ssl/gadgets.h"
+#include <openssl/asn1.h>
#if HAVE_OPENSSL_X509V3_H
#include <openssl/x509v3.h>
#endif
return true;
}
-bool Ssl::writeCertAndPrivateKeyToFile(Security::CertPointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, char const * filename)
-{
- if (!pkey || !cert)
- return false;
-
- Ssl::BIO_Pointer bio(BIO_new(BIO_s_file()));
- if (!bio)
- return false;
- if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
- return false;
-
- if (!PEM_write_bio_X509(bio.get(), cert.get()))
- return false;
-
- if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
- return false;
-
- return true;
-}
-
bool Ssl::readCertAndPrivateKeyFromMemory(Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * bufferToRead)
{
Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
signHash(NULL)
{}
-std::string & Ssl::CertificateProperties::dbKey() const
+static void
+printX509Signature(const Security::CertPointer &cert, std::string &out)
+{
+ ASN1_BIT_STRING *sig = nullptr;
+#if HAVE_LIBCRYPTO_X509_GET0_SIGNATURE
+ X509_ALGOR *sig_alg;
+ X509_get0_signature(&sig, &sig_alg, cert.get());
+#else
+ sig = cert->signature;
+#endif
+
+ if (sig && sig->data) {
+ const unsigned char *s = sig->data;
+ for (int i = 0; i < sig->length; ++i) {
+ char hex[3];
+ snprintf(hex, sizeof(hex), "%02x", s[i]);
+ out.append(hex);
+ }
+ }
+}
+
+std::string &
+Ssl::OnDiskCertificateDbKey(const Ssl::CertificateProperties &properties)
{
static std::string certKey;
certKey.clear();
certKey.reserve(4096);
- if (mimicCert.get()) {
- char buf[1024];
- certKey.append(X509_NAME_oneline(X509_get_subject_name(mimicCert.get()), buf, sizeof(buf)));
- }
+ if (properties.mimicCert.get())
+ printX509Signature(properties.mimicCert, certKey);
if (certKey.empty()) {
certKey.append("/CN=", 4);
- certKey.append(commonName);
+ certKey.append(properties.commonName);
}
- if (setValidAfter)
+ if (properties.setValidAfter)
certKey.append("+SetValidAfter=on", 17);
- if (setValidBefore)
+ if (properties.setValidBefore)
certKey.append("+SetValidBefore=on", 18);
- if (setCommonName) {
+ if (properties.setCommonName) {
certKey.append("+SetCommonName=", 15);
- certKey.append(commonName);
+ certKey.append(properties.commonName);
}
- if (signAlgorithm != Ssl::algSignEnd) {
+ if (properties.signAlgorithm != Ssl::algSignEnd) {
certKey.append("+Sign=", 6);
- certKey.append(certSignAlgorithm(signAlgorithm));
+ certKey.append(certSignAlgorithm(properties.signAlgorithm));
}
- if (signHash != NULL) {
+ if (properties.signHash != NULL) {
certKey.append("+SignHash=", 10);
- certKey.append(EVP_MD_name(signHash));
+ certKey.append(EVP_MD_name(properties.signHash));
}
return certKey;
return generateFakeSslCertificate(certToStore, pkeyToStore, properties, serial);
}
-/**
- \ingroup ServerProtocolSSLInternal
- * Read certificate from file.
- */
-static X509 * readSslX509Certificate(char const * certFilename)
+bool
+Ssl::OpenCertsFileForReading(Ssl::BIO_Pointer &bio, const char *filename)
{
- if (!certFilename)
- return NULL;
- Ssl::BIO_Pointer bio(BIO_new(BIO_s_file()));
+ bio.reset(BIO_new(BIO_s_file()));
if (!bio)
- return NULL;
- if (!BIO_read_filename(bio.get(), certFilename))
- return NULL;
- X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
- return certificate;
+ return false;
+ if (!BIO_read_filename(bio.get(), filename))
+ return false;
+ return true;
}
-EVP_PKEY * Ssl::readSslPrivateKey(char const * keyFilename, pem_password_cb *passwd_callback)
+bool
+Ssl::ReadX509Certificate(Ssl::BIO_Pointer &bio, Security::CertPointer & cert)
+{
+ assert(bio);
+ if (X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL)) {
+ cert.resetWithoutLocking(certificate);
+ return true;
+ }
+ return false;
+}
+
+bool
+Ssl::ReadPrivateKey(Ssl::BIO_Pointer &bio, Ssl::EVP_PKEY_Pointer &pkey, pem_password_cb *passwd_callback)
+{
+ assert(bio);
+ if (EVP_PKEY *akey = PEM_read_bio_PrivateKey(bio.get(), NULL, passwd_callback, NULL)) {
+ pkey.resetWithoutLocking(akey);
+ return true;
+ }
+ return false;
+}
+
+void
+Ssl::ReadPrivateKeyFromFile(char const * keyFilename, Ssl::EVP_PKEY_Pointer &pkey, pem_password_cb *passwd_callback)
{
if (!keyFilename)
- return NULL;
- Ssl::BIO_Pointer bio(BIO_new(BIO_s_file()));
+ return;
+ Ssl::BIO_Pointer bio;
+ if (!OpenCertsFileForReading(bio, keyFilename))
+ return;
+ ReadPrivateKey(bio, pkey, passwd_callback);
+}
+
+bool
+Ssl::OpenCertsFileForWriting(Ssl::BIO_Pointer &bio, const char *filename)
+{
+ bio.reset(BIO_new(BIO_s_file()));
if (!bio)
- return NULL;
- if (!BIO_read_filename(bio.get(), keyFilename))
- return NULL;
- EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio.get(), NULL, passwd_callback, NULL);
- return pkey;
+ return false;
+ if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
+ return false;
+ return true;
}
-void Ssl::readCertAndPrivateKeyFromFiles(Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename)
+bool
+Ssl::WriteX509Certificate(Ssl::BIO_Pointer &bio, const Security::CertPointer & cert)
{
- if (keyFilename == NULL)
- keyFilename = certFilename;
- pkey.resetWithoutLocking(readSslPrivateKey(keyFilename));
- cert.resetWithoutLocking(readSslX509Certificate(certFilename));
- if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
- pkey.reset();
- cert.reset();
- }
+ if (!cert || !bio)
+ return false;
+ if (!PEM_write_bio_X509(bio.get(), cert.get()))
+ return false;
+ return true;
+}
+
+bool
+Ssl::WritePrivateKey(Ssl::BIO_Pointer &bio, const Ssl::EVP_PKEY_Pointer &pkey)
+{
+ if (!pkey || !bio)
+ return false;
+ if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
+ return false;
+ return true;
}
bool Ssl::sslDateIsInTheFuture(char const * date)
return getSubjectEntry(x509, NID_organizationName);
}
+
+bool
+Ssl::CertificatesCmp(const Security::CertPointer &cert1, const Security::CertPointer &cert2)
+{
+ if (!cert1 || ! cert2)
+ return false;
+
+ int cert1Len;
+ unsigned char *cert1Asn = NULL;
+ cert1Len = ASN1_item_i2d((ASN1_VALUE *)cert1.get(), &cert1Asn, ASN1_ITEM_rptr(X509));
+
+ int cert2Len;
+ unsigned char *cert2Asn = NULL;
+ cert2Len = ASN1_item_i2d((ASN1_VALUE *)cert2.get(), &cert2Asn, ASN1_ITEM_rptr(X509));
+
+ if (cert1Len != cert2Len)
+ return false;
+
+ bool ret = (memcmp(cert1Asn, cert2Asn, cert1Len) == 0);
+
+ OPENSSL_free(cert1Asn);
+ OPENSSL_free(cert2Asn);
+
+ return ret;
+}
*/
bool appendCertToMemory(Security::CertPointer const & cert, std::string & bufferToWrite);
-/**
- \ingroup SslCrtdSslAPI
- * Write private key and SSL certificate to file.
- */
-bool writeCertAndPrivateKeyToFile(Security::CertPointer const & cert, EVP_PKEY_Pointer const & pkey, char const * filename);
-
/**
\ingroup SslCrtdSslAPI
* Write private key and SSL certificate to memory.
*/
bool readCertFromMemory(Security::CertPointer & cert, char const * bufferToRead);
+/**
+ \ingroup SslCrtdSslAPI
+ * Read private key from file.
+ */
+void ReadPrivateKeyFromFile(char const * keyFilename, EVP_PKEY_Pointer &pkey, pem_password_cb *passwd_callback);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Initialize the bio with the file 'filename' openned for reading
+ */
+bool OpenCertsFileForReading(BIO_Pointer &bio, const char *filename);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Read a certificate from bio
+ */
+bool ReadX509Certificate(BIO_Pointer &bio, Security::CertPointer & cert);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Read a private key from bio
+ */
+bool ReadPrivateKey(BIO_Pointer &bio, EVP_PKEY_Pointer &pkey, pem_password_cb *passwd_callback);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Initialize the bio with the file 'filename' openned for writting
+ */
+
+bool OpenCertsFileForWriting(BIO_Pointer &bio, const char *filename);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Write certificate to BIO.
+ */
+bool WriteX509Certificate(BIO_Pointer &bio, const Security::CertPointer & cert);
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Write private key to BIO.
+ */
+bool WritePrivateKey(BIO_Pointer &bio, const EVP_PKEY_Pointer &pkey);
+
/**
\ingroup SslCrtdSslAPI
* Supported certificate signing algorithms
std::string commonName; ///< A CN to use for the generated certificate
CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
const EVP_MD *signHash; ///< The signing hash to use
- /// Returns certificate database primary key. New fake certificates
- /// purge old fake certificates with the same key.
- std::string & dbKey() const;
private:
CertificateProperties(CertificateProperties &);
CertificateProperties &operator =(CertificateProperties const &);
};
+/// \ingroup SslCrtdSslAPI
+/// \returns certificate database key
+std::string & OnDiskCertificateDbKey(const CertificateProperties &);
+
/**
\ingroup SslCrtdSslAPI
* Decide on the kind of certificate and generate a CA- or self-signed one.
*/
bool generateSslCertificate(Security::CertPointer & cert, EVP_PKEY_Pointer & pkey, CertificateProperties const &properties);
-/**
- \ingroup SslCrtdSslAPI
- * Read private key from file. Make sure that this is not encrypted file.
- */
-EVP_PKEY * readSslPrivateKey(char const * keyFilename, pem_password_cb *passwd_callback = NULL);
-
-/**
- \ingroup SslCrtdSslAPI
- * Read certificate and private key from files.
- * \param certFilename name of file with certificate.
- * \param keyFilename name of file with private key.
- */
-void readCertAndPrivateKeyFromFiles(Security::CertPointer & cert, EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename);
-
/**
\ingroup SslCrtdSslAPI
* Verify date. Date format it ASN1_UTCTIME. if there is out of date error,
*/
const char *getOrganization(X509 *x509);
+/// \ingroup ServerProtocolSSLAPI
+/// \return whether both certificates exist and are the same (e.g., have identical ASN.1 images)
+bool CertificatesCmp(const Security::CertPointer &cert1, const Security::CertPointer &cert2);
} // namespace Ssl
#endif // SQUID_SSL_GADGETS_H
CBDATA_CLASS(submitData);
public:
- std::string query;
+ SBuf query;
AsyncCall::Pointer callback;
Security::SessionPointer ssl;
};
if (Ssl::CertValidationHelper::HelperCache &&
(validationResponse->resultCode == ::Helper::Okay || validationResponse->resultCode == ::Helper::Error)) {
Ssl::CertValidationResponse::Pointer *item = new Ssl::CertValidationResponse::Pointer(validationResponse);
- if (!Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query.c_str(), item))
+ if (!Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query, item))
delete item;
}
debugs(83, 5, "SSL crtvd request: " << message.compose().c_str());
submitData *crtdvdData = new submitData;
- crtdvdData->query = message.compose();
- crtdvdData->query += '\n';
+ crtdvdData->query.assign(message.compose().c_str());
+ crtdvdData->query.append('\n');
crtdvdData->callback = callback;
crtdvdData->ssl = request.ssl;
Ssl::CertValidationResponse::Pointer const*validationResponse;
if (CertValidationHelper::HelperCache &&
- (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query.c_str()))) {
+ (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query))) {
CertValidationHelper::CbDialer *dialer = dynamic_cast<CertValidationHelper::CbDialer*>(callback->getDialer());
Must(dialer);
helper * ssl_crt_validator; ///< helper for management of ssl_crtd.
public:
- typedef LruMap<Ssl::CertValidationResponse::Pointer, sizeof(Ssl::CertValidationResponse::Pointer) + sizeof(Ssl::CertValidationResponse)> LruCache;
+ typedef LruMap<SBuf, Ssl::CertValidationResponse::Pointer, sizeof(Ssl::CertValidationResponse::Pointer) + sizeof(Ssl::CertValidationResponse)> LruCache;
static LruCache *HelperCache; ///< cache for cert validation helper
};
}
Security::ContextPointer
-Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port)
+Ssl::GenerateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port, bool trusted)
{
Security::CertPointer cert;
Ssl::EVP_PKEY_Pointer pkey;
if (!readCertAndPrivateKeyFromMemory(cert, pkey, data) || !cert || !pkey)
return Security::ContextPointer();
- return createSSLContext(cert, pkey, port);
+ Security::ContextPointer ctx(createSSLContext(cert, pkey, port));
+ if (ctx && trusted)
+ Ssl::chainCertificatesToSSLContext(ctx, port);
+ return ctx;
}
Security::ContextPointer
-Ssl::generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port)
+Ssl::GenerateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port, bool trusted)
{
Security::CertPointer cert;
Ssl::EVP_PKEY_Pointer pkey;
if (!generateSslCertificate(cert, pkey, properties) || !cert || !pkey)
return Security::ContextPointer();
- return createSSLContext(cert, pkey, port);
+ Security::ContextPointer ctx(createSSLContext(cert, pkey, port));
+ if (ctx && trusted)
+ Ssl::chainCertificatesToSSLContext(ctx, port);
+ return ctx;
}
void
return false;
ASN1_TIME * time_notBefore = X509_get_notBefore(cert);
ASN1_TIME * time_notAfter = X509_get_notAfter(cert);
- bool ret = (X509_cmp_current_time(time_notBefore) < 0 && X509_cmp_current_time(time_notAfter) > 0);
- if (!ret)
- return false;
-
- return certificateMatchesProperties(cert, properties);
+ return (X509_cmp_current_time(time_notBefore) < 0 && X509_cmp_current_time(time_notAfter) > 0);
}
bool
// XXX: ssl_ask_password_cb needs SSL_CTX_set_default_passwd_cb_userdata()
// so this may not fully work iff Config.Program.ssl_password is set.
pem_password_cb *cb = ::Config.Program.ssl_password ? &ssl_ask_password_cb : NULL;
- pkey.resetWithoutLocking(readSslPrivateKey(keyFilename, cb));
+ Ssl::ReadPrivateKeyFromFile(keyFilename, pkey, cb);
cert.resetWithoutLocking(readSslX509CertificatesChain(certFilename, chain.get()));
if (!cert) {
debugs(83, DBG_IMPORTANT, "WARNING: missing cert in '" << certFilename << "'");
return Ssl::generateSslCertificate(untrustedCert, untrustedPkey, certProperties);
}
+void Ssl::InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key)
+{
+ bool origSignatureAsKey = false;
+ if (certProperties.mimicCert.get()) {
+ ASN1_BIT_STRING *sig = nullptr;
+#if HAVE_LIBCRYPTO_X509_GET0_SIGNATURE
+ X509_ALGOR *sig_alg;
+ X509_get0_signature(&sig, &sig_alg, certProperties.mimicCert.get());
+#else
+ sig = certProperties.mimicCert->signature;
+#endif
+ if (sig) {
+ origSignatureAsKey = true;
+ key.append((const char *)sig->data, sig->length);
+ }
+ }
+
+ if (!origSignatureAsKey || certProperties.setCommonName) {
+ // Use common name instead
+ key.append(certProperties.commonName.c_str());
+ }
+ key.append(certProperties.setCommonName ? '1' : '0');
+ key.append(certProperties.setValidAfter ? '1' : '0');
+ key.append(certProperties.setValidBefore ? '1' : '0');
+ key.append(certProperties.signAlgorithm != Ssl:: algSignEnd ? certSignAlgorithm(certProperties.signAlgorithm) : "-");
+ key.append(certProperties.signHash ? EVP_MD_name(certProperties.signHash) : "-");
+
+ if (certProperties.mimicCert) {
+ BIO *bio = BIO_new_SBuf(&key);
+ ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bio, (ASN1_VALUE *)certProperties.mimicCert.get());
+ }
+}
+
+static int
+bio_sbuf_create(BIO* bio)
+{
+ BIO_set_init(bio, 0);
+ BIO_set_data(bio, NULL);
+ return 1;
+}
+
+static int
+bio_sbuf_destroy(BIO* bio)
+{
+ if (!bio)
+ return 0;
+ return 1;
+}
+
+int
+bio_sbuf_write(BIO* bio, const char* data, int len)
+{
+ SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
+ buf->append(data, len);
+ return len;
+}
+
+int
+bio_sbuf_puts(BIO* bio, const char* data)
+{
+ SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
+ size_t oldLen = buf->length();
+ buf->append(data);
+ return buf->length() - oldLen;
+}
+
+long
+bio_sbuf_ctrl(BIO* bio, int cmd, long num, void* ptr) {
+ SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ buf->clear();
+ return 1;
+ case BIO_CTRL_FLUSH:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+#if HAVE_LIBCRYPTO_BIO_METH_NEW
+static BIO_METHOD *BioSBufMethods = nullptr;
+#else
+static BIO_METHOD BioSBufMethods = {
+ BIO_TYPE_MEM,
+ "Squid SBuf",
+ bio_sbuf_write,
+ nullptr,
+ bio_sbuf_puts,
+ nullptr,
+ bio_sbuf_ctrl,
+ bio_sbuf_create,
+ bio_sbuf_destroy,
+ NULL,
+
+};
+#endif
+
+BIO *Ssl::BIO_new_SBuf(SBuf *buf)
+{
+#if HAVE_LIBCRYPTO_BIO_METH_NEW
+ if (!BioSBufMethods) {
+ BioSBufMethods = BIO_meth_new(BIO_TYPE_MEM, "Squid-SBuf");
+ BIO_meth_set_write(BioSBufMethods, bio_sbuf_write);
+ BIO_meth_set_read(BioSBufMethods, nullptr);
+ BIO_meth_set_puts(BioSBufMethods, bio_sbuf_puts);
+ BIO_meth_set_gets(BioSBufMethods, nullptr);
+ BIO_meth_set_ctrl(BioSBufMethods, bio_sbuf_ctrl);
+ BIO_meth_set_create(BioSBufMethods, bio_sbuf_create);
+ BIO_meth_set_destroy(BioSBufMethods, bio_sbuf_destroy);
+ }
+#else
+ BIO *bio = BIO_new(&BioSBufMethods);
+#endif
+ if (!bio)
+ return nullptr;
+ BIO_set_data(bio, buf);
+ BIO_set_init(bio, 1);
+ return bio;
+}
+
#endif /* USE_OPENSSL */
\ingroup ServerProtocolSSLAPI
* Decide on the kind of certificate and generate a CA- or self-signed one
*/
-Security::ContextPointer generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port);
+Security::ContextPointer GenerateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port, bool trusted);
/**
\ingroup ServerProtocolSSLAPI
* Read private key and certificate from memory and generate SSL context
* using their.
*/
-Security::ContextPointer generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port);
+Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port, bool trusted);
/**
\ingroup ServerProtocolSSLAPI
*/
bool setClientSNI(SSL *ssl, const char *fqdn);
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Generates a unique key based on CertificateProperties object and store it to key
+ */
+void InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key);
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ Generates an OpenSSL BIO for writting to an SBuf object
+ */
+BIO *BIO_new_SBuf(SBuf *buf);
} //namespace Ssl
#if _SQUID_WINDOWS_
#if USE_OPENSSL
void ConnStateData::httpsPeeked(PinnedIdleContext) STUB
void ConnStateData::getSslContextStart() STUB
-void ConnStateData::getSslContextDone(Security::ContextPointer &, bool) STUB
+void ConnStateData::getSslContextDone(Security::ContextPointer &) STUB
void ConnStateData::sslCrtdHandleReplyWrapper(void *, const Helper::Reply &) STUB
void ConnStateData::sslCrtdHandleReply(const Helper::Reply &) STUB
void ConnStateData::switchToHttps(HttpRequest *, Ssl::BumpMode) STUB
//GETX509ATTRIBUTE GetX509Fingerprint;
std::vector<const char *> BumpModeStr = {""};
bool generateUntrustedCert(Security::CertPointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, Security::CertPointer const & cert, EVP_PKEY_Pointer const & pkey) STUB_RETVAL(false)
-Security::ContextPointer generateSslContext(CertificateProperties const &, AnyP::PortCfg &) STUB_RETVAL(Security::ContextPointer())
+Security::ContextPointer GenerateSslContext(CertificateProperties const &, AnyP::PortCfg &, bool) STUB_RETVAL(Security::ContextPointer())
bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &) STUB_RETVAL(false)
-Security::ContextPointer generateSslContextUsingPkeyAndCertFromMemory(const char *, AnyP::PortCfg &) STUB_RETVAL(Security::ContextPointer())
+Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char *, AnyP::PortCfg &, bool) STUB_RETVAL(Security::ContextPointer())
void addChainToSslContext(Security::ContextPointer &, STACK_OF(X509) *) STUB
void readCertChainAndPrivateKeyFromFiles(Security::CertPointer & cert, EVP_PKEY_Pointer & pkey, X509_STACK_Pointer & chain, char const * certFilename, char const * keyFilename) STUB
int matchX509CommonNames(X509 *peer_cert, void *check_data, int (*check_func)(void *check_data, ASN1_STRING *cn_data)) STUB_RETVAL(0)