--- /dev/null
+
+/*
+ */
+
+#ifndef SQUID_LRUMAP_H
+#define SQUID_LRUMAP_H
+
+#include "SquidTime.h"
+#if HAVE_LIST
+#include <list>
+#endif
+#if HAVE_MAP
+#include <map>
+#endif
+
+template <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() {delete value;}
+ private:
+ Entry(LruMap<EntryValue, EntryCost>::Entry &);
+ LruMap<EntryValue, EntryCost>::Entry & operator = (LruMap<EntryValue, EntryCost>::Entry &);
+ public:
+ std::string key; ///< the key of entry
+ EntryValue *value; ///< A pointer to the stored value
+ time_t date; ///< The date the entry created
+ };
+ typedef std::list<Entry *> Queue;
+ typedef typename std::list<Entry *>::iterator QueueIterator;
+
+ /// key:queue_item mapping for fast lookups by key
+ typedef std::map<std::string, QueueIterator> Map;
+ typedef typename Map::iterator MapIterator;
+ typedef std::pair<std::string, QueueIterator> MapPair;
+
+
+ LruMap(int ttl, size_t size);
+ ~LruMap();
+ /// Search for an entry, and return a pointer
+ EntryValue *get(const char *key);
+ /// Add an entry to the map
+ bool add(const char *key, EntryValue *t);
+ /// Delete an entry from the map
+ bool del(const char *key);
+ /// (Re-)set the maximum size for this map
+ void setMemLimit(size_t aSize);
+ /// The available size for the map
+ size_t memLimit() const {return memLimit_;}
+ /// The free space of the map
+ size_t freeMem() const { return (memLimit() - size());}
+ /// The current size of the map
+ size_t size() const {return (entries_ * EntryCost);}
+ /// The number of stored entries
+ int entries() const {return entries_;}
+private:
+ LruMap(LruMap<EntryValue, EntryCost> const &);
+ LruMap<EntryValue, EntryCost> & operator = (LruMap<EntryValue, EntryCost> const &);
+
+ bool expired(Entry &e);
+ void trim();
+ void touch(const MapIterator &i);
+ bool del(const MapIterator &i);
+ void findEntry(const char *key, LruMap::MapIterator &i);
+
+ Map storage; ///< The Key/value * pairs
+ Queue index; ///< LRU cache index
+ int ttl;///< >0 ttl for caching, == 0 cache is disabled, < 0 store for ever
+ size_t memLimit_; ///< The maximum memory to use
+ int entries_; ///< The stored entries
+};
+
+template <class EntryValue, size_t EntryCost>
+LruMap<EntryValue, EntryCost>::LruMap(int aTtl, size_t aSize): entries_(0)
+{
+ ttl = aTtl;
+
+ setMemLimit(aSize);
+}
+
+template <class EntryValue, size_t EntryCost>
+LruMap<EntryValue, EntryCost>::~LruMap()
+{
+ for (QueueIterator i = index.begin(); i != index.end(); ++i) {
+ delete *i;
+ }
+}
+
+template <class EntryValue, size_t EntryCost>
+void
+LruMap<EntryValue, EntryCost>::setMemLimit(size_t aSize)
+{
+ if (aSize > 0)
+ memLimit_ = aSize;
+ else
+ memLimit_ = 0;
+}
+
+template <class EntryValue, size_t EntryCost>
+void
+LruMap<EntryValue, EntryCost>::findEntry(const char *key, LruMap::MapIterator &i)
+{
+ i = storage.find(key);
+ if (i == storage.end()) {
+ return;
+ }
+ index.push_front(*(i->second));
+ index.erase(i->second);
+ i->second = index.begin();
+
+ LruMap::Entry *e = *i->second;
+
+ if (e && expired(*e)) {
+ del(i);
+ e = NULL;
+ }
+}
+
+template <class EntryValue, size_t EntryCost>
+EntryValue *
+LruMap<EntryValue, EntryCost>::get(const char *key)
+{
+ LruMap::MapIterator i;
+ findEntry(key, i);
+ LruMap::Entry *e = *i->second;
+ if (i != storage.end()) {
+ touch(i);
+ return e->value;
+ }
+ return NULL;
+}
+
+template <class EntryValue, size_t EntryCost>
+bool
+LruMap<EntryValue, EntryCost>::add(const char *key, EntryValue *t)
+{
+ if (ttl == 0)
+ return false;
+
+ del(key);
+ trim();
+ index.push_front(new Entry(key, t));
+ storage.insert(MapPair(key, index.begin()));
+
+ ++entries_;
+ return true;
+}
+
+template <class EntryValue, size_t EntryCost>
+bool
+LruMap<EntryValue, EntryCost>::expired(LruMap::Entry &entry)
+{
+ if (ttl < 0)
+ return false;
+
+ return (entry.date + ttl < squid_curtime);
+}
+
+template <class EntryValue, size_t EntryCost>
+bool
+LruMap<EntryValue, EntryCost>::del(LruMap::MapIterator const &i)
+{
+ if (i != storage.end()) {
+ delete *(i->second);
+ index.erase(i->second);
+ storage.erase(i);
+ --entries_;
+ return true;
+ }
+ return false;
+}
+
+template <class EntryValue, size_t EntryCost>
+bool
+LruMap<EntryValue, EntryCost>::del(const char *key)
+{
+ LruMap::MapIterator i;
+ findEntry(key, i);
+ return del(i);
+}
+
+template <class EntryValue, size_t EntryCost>
+void
+LruMap<EntryValue, EntryCost>::trim()
+{
+ while(memLimit() > 0 && size() >= memLimit()) {
+ LruMap::QueueIterator i = index.end();
+ --i;
+ if (i != index.end()) {
+ del((*i)->key.c_str());
+ }
+ }
+}
+
+template <class EntryValue, size_t EntryCost>
+void
+LruMap<EntryValue, EntryCost>::touch(LruMap::MapIterator const &i)
+{
+ // this must not be done when nothing is being cached.
+ if (ttl == 0)
+ return;
+
+ index.push_front(*(i->second));
+ index.erase(i->second);
+ i->second = index.begin();
+}
+
+#endif
CbcPointer.h \
InstanceId.h \
Lock.h \
+ LruMap.h \
RunnersRegistry.cc \
RunnersRegistry.h \
Subscription.h \
LOC: Ssl::TheConfig.ssl_crt_validator
DOC_START
Specify the location and options of the executable for ssl_crt_validator
- process.
+ process. Usage:
+ sslcrtvalidator_program [ttl=n] [cache=n] path ...
+
+ Options:
+ ttl=n TTL in seconds for cached results.The default is 60 secs
+ cache=n limit the result cache size. The default value is 2048
DOC_END
NAME: sslcrtvalidator_children
debugs(33, 5, HERE << "Finding SSL certificate for " << sslBumpCertKey << " in cache");
Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
- SSL_CTX * dynCtx = ssl_ctx_cache.find(sslBumpCertKey.termedBuf());
- if (dynCtx) {
+ SSL_CTX * dynCtx = NULL;
+ Ssl::SSL_CTX_Pointer *cachedCtx = ssl_ctx_cache.get(sslBumpCertKey.termedBuf());
+ if (cachedCtx && (dynCtx = cachedCtx->get())) {
debugs(33, 5, HERE << "SSL certificate for " << sslBumpCertKey << " have found in cache");
if (Ssl::verifySslCertificate(dynCtx, certProperties)) {
debugs(33, 5, HERE << "Cached SSL certificate for " << sslBumpCertKey << " is valid");
return;
} else {
debugs(33, 5, HERE << "Cached SSL certificate for " << sslBumpCertKey << " is out of date. Delete this certificate from cache");
- ssl_ctx_cache.remove(sslBumpCertKey.termedBuf());
+ ssl_ctx_cache.del(sslBumpCertKey.termedBuf());
}
} else {
debugs(33, 5, HERE << "SSL certificate for " << sslBumpCertKey << " haven't found in cache");
Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
assert(sslBumpCertKey.defined() && sslBumpCertKey[0] != '\0');
if (sslContext) {
- if (!ssl_ctx_cache.add(sslBumpCertKey.termedBuf(), sslContext)) {
+ if (!ssl_ctx_cache.add(sslBumpCertKey.termedBuf(), new Ssl::SSL_CTX_Pointer(sslContext))) {
// If it is not in storage delete after using. Else storage deleted it.
fd_table[clientConnection->fd].dynamicSslContext = sslContext;
}
if (Ssl::TheConfig.ssl_crt_validator) {
Ssl::CertValidationRequest validationRequest;
- // WARNING: The STACK_OF(*) OpenSSL objects does not support locking.
- // If we need to support locking we need to sk_X509_dup the STACK_OF(X509)
- // list and lock all of the X509 members of the list.
- // Currently we do not use any locking for any of the members of the
- // Ssl::CertValidationRequest class. If the ssl object gone, the value returned
- // from SSL_get_peer_cert_chain may not exist any more. In this code the
+ // WARNING: Currently we do not use any locking for any of the
+ // members of the Ssl::CertValidationRequest class. In this code the
// Ssl::CertValidationRequest object used only to pass data to
// Ssl::CertValidationHelper::submit method.
- validationRequest.peerCerts = SSL_get_peer_cert_chain(ssl);
+ validationRequest.ssl = ssl;
validationRequest.domainName = request->GetHost();
if (Ssl::Errors *errs = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
// validationRequest disappears on return so no need to cbdataReference
validationRequest.errors = NULL;
try {
debugs(83, 5, "Sending SSL certificate for validation to ssl_crtvd.");
- Ssl::CertValidationMsg requestMsg(Ssl::CrtdMessage::REQUEST);
- requestMsg.setCode(Ssl::CertValidationMsg::code_cert_validate);
- requestMsg.composeRequest(validationRequest);
- debugs(83, 5, "SSL crtvd request: " << requestMsg.compose().c_str());
- Ssl::CertValidationHelper::GetInstance()->sslSubmit(requestMsg, sslCrtvdHandleReplyWrapper, this);
+ Ssl::CertValidationHelper::GetInstance()->sslSubmit(validationRequest, sslCrtvdHandleReplyWrapper, this);
return;
} catch (const std::exception &e) {
debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtvd " <<
}
void
-FwdState::sslCrtvdHandleReplyWrapper(void *data, const HelperReply &reply)
+FwdState::sslCrtvdHandleReplyWrapper(void *data, Ssl::CertValidationResponse const &validationResponse)
{
FwdState * fwd = (FwdState *)(data);
- fwd->sslCrtvdHandleReply(reply);
+ fwd->sslCrtvdHandleReply(validationResponse);
}
void
-FwdState::sslCrtvdHandleReply(const HelperReply &reply)
+FwdState::sslCrtvdHandleReply(Ssl::CertValidationResponse const &validationResponse)
{
Ssl::Errors *errs = NULL;
Ssl::ErrorDetail *errDetails = NULL;
if (!Comm::IsConnOpen(serverConnection())) {
return;
}
- SSL *ssl = fd_table[serverConnection()->fd].ssl;
- if (!reply.other().hasContent()) {
- debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper return <NULL> reply");
- validatorFailed = true;
- } else if (reply.result == HelperReply::BrokenHelper) {
- debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content());
+ debugs(83,5, request->GetHost() << " cert validation result: " << validationResponse.resultCode);
+
+ if (validationResponse.resultCode == HelperReply::Error)
+ errs = sslCrtvdCheckForErrors(validationResponse, errDetails);
+ else if (validationResponse.resultCode != HelperReply::Okay)
validatorFailed = true;
- } else {
- Ssl::CertValidationMsg replyMsg(Ssl::CrtdMessage::REPLY);
- Ssl::CertValidationResponse validationResponse;
- std::string error;
- STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(ssl);
- if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
- !replyMsg.parseResponse(validationResponse, peerCerts, error) ) {
- debugs(83, 5, "Reply from ssl_crtvd for " << request->GetHost() << " is incorrect");
- validatorFailed = true;
- } else {
- if (reply.result == HelperReply::Okay) {
- debugs(83, 5, "Certificate for " << request->GetHost() << " was successfully validated from ssl_crtvd");
- } else if (reply.result == HelperReply::Error) {
- debugs(83, 5, "Certificate for " << request->GetHost() << " found buggy by ssl_crtvd");
- errs = sslCrtvdCheckForErrors(validationResponse, errDetails);
- } else {
- debugs(83, 5, "Certificate for " << request->GetHost() << " cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
- validatorFailed = true;
- }
- if (!errDetails && !validatorFailed) {
- dispatch();
- return;
- }
- }
+ if (!errDetails && !validatorFailed) {
+ dispatch();
+ return;
}
ErrorState *anErr = NULL;
/// The first honored error, if any, is returned via errDetails parameter.
/// The method returns all seen errors except SSL_ERROR_NONE as Ssl::Errors.
Ssl::Errors *
-FwdState::sslCrtvdCheckForErrors(Ssl::CertValidationResponse &resp, Ssl::ErrorDetail *& errDetails)
+FwdState::sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &resp, Ssl::ErrorDetail *& errDetails)
{
Ssl::Errors *errs = NULL;
#if USE_SSL
/// Callback function called when squid receive message from cert validator helper
- static void sslCrtvdHandleReplyWrapper(void *data, const HelperReply &reply);
+ static void sslCrtvdHandleReplyWrapper(void *data, Ssl::CertValidationResponse const &);
/// Process response from cert validator helper
- void sslCrtvdHandleReply(const HelperReply &reply);
+ void sslCrtvdHandleReply(Ssl::CertValidationResponse const &);
/// Check SSL errors returned from cert validator against sslproxy_cert_error access list
- Ssl::Errors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse &, Ssl::ErrorDetail *&);
+ Ssl::Errors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, Ssl::ErrorDetail *&);
#endif
private:
// hidden for safer management of self; use static fwdStart
}
}
- if (vcert.peerCerts) {
+ STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(vcert.ssl);
+ if (peerCerts) {
body +="\n";
Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
- for (int i = 0; i < sk_X509_num(vcert.peerCerts); ++i) {
- X509 *cert = sk_X509_value(vcert.peerCerts, i);
+ for (int i = 0; i < sk_X509_num(peerCerts); ++i) {
+ X509 *cert = sk_X509_value(peerCerts, i);
PEM_write_bio_X509(bio.get(), cert);
body = body + "cert_" + xitoa(i) + "=";
char *ptr;
class CertValidationRequest
{
public:
- STACK_OF(X509) *peerCerts; ///< The list of sent by SSL server
+ SSL *ssl;
Errors *errors; ///< The list of errors detected
std::string domainName; ///< The server name
- CertValidationRequest() : peerCerts(NULL), errors(NULL) {}
+ CertValidationRequest() : ssl(NULL), errors(NULL) {}
};
/**
/// If none found a new RecvdError item added with the given id;
RecvdError &getError(int errorId);
RecvdErrors errors; ///< The list of parsed errors
+ HelperReply::Result_ resultCode; ///< The helper result code
};
/**
for (std::map<Ip::Address, LocalContextStorage *>::iterator i = TheGlobalContextStorage.storage.begin(); i != TheGlobalContextStorage.storage.end(); ++i) {
stream << i->first << delimiter;
LocalContextStorage & ssl_store_policy(*(i->second));
- stream << ssl_store_policy.max_memory / 1024 << delimiter;
- stream << ssl_store_policy.memory_used / SSL_CTX_SIZE << delimiter;
+ stream << ssl_store_policy.memLimit() / 1024 << delimiter;
+ stream << ssl_store_policy.entries() << delimiter;
stream << SSL_CTX_SIZE / 1024 << delimiter;
- stream << ssl_store_policy.memory_used / 1024 << delimiter;
- stream << (ssl_store_policy.max_memory - ssl_store_policy.memory_used) / 1024 << endString;
+ stream << ssl_store_policy.size() / 1024 << delimiter;
+ stream << ssl_store_policy.freeMem() / 1024 << endString;
}
stream << endString;
stream.flush();
}
-Ssl::LocalContextStorage::LocalContextStorage(size_t aMax_memory)
- : max_memory(aMax_memory), memory_used(0)
-{}
-
-Ssl::LocalContextStorage::~LocalContextStorage()
-{
- for (QueueIterator i = lru_queue.begin(); i != lru_queue.end(); ++i) {
- delete *i;
- }
-}
-
-SSL_CTX * Ssl::LocalContextStorage::add(const char * host_name, SSL_CTX * ssl_ctx)
-{
- if (max_memory < SSL_CTX_SIZE) {
- return NULL;
- }
- remove(host_name);
- while (SSL_CTX_SIZE + memory_used > max_memory) {
- purgeOne();
- }
- lru_queue.push_front(new Item(ssl_ctx, host_name));
- storage.insert(MapPair(host_name, lru_queue.begin()));
- memory_used += SSL_CTX_SIZE;
- return ssl_ctx;
-}
-
-SSL_CTX * Ssl::LocalContextStorage::find(char const * host_name)
-{
- MapIterator i = storage.find(host_name);
- if (i == storage.end()) {
- return NULL;
- }
- lru_queue.push_front(*(i->second));
- lru_queue.erase(i->second);
- i->second = lru_queue.begin();
- return (*lru_queue.begin())->ssl_ctx;
-}
-
-void Ssl::LocalContextStorage::remove(char const * host_name)
-{
- deleteAt(storage.find(host_name));
-}
-
-void Ssl::LocalContextStorage::purgeOne()
-{
- QueueIterator i = lru_queue.end();
- --i;
- if (i != lru_queue.end()) {
- remove((*i)->host_name.c_str());
- }
-}
-
-void Ssl::LocalContextStorage::deleteAt(LocalContextStorage::MapIterator i)
-{
- if (i != storage.end()) {
-
- delete *(i->second);
- lru_queue.erase(i->second);
- storage.erase(i);
- memory_used -= SSL_CTX_SIZE;
- }
-}
-
-void Ssl::LocalContextStorage::SetSize(size_t aMax_memory)
-{
- max_memory = aMax_memory;
-}
-
-Ssl::LocalContextStorage::Item::Item(SSL_CTX * aSsl_ctx, std::string const & aName)
- : ssl_ctx(aSsl_ctx), host_name(aName)
-{}
-
-Ssl::LocalContextStorage::Item::~Item()
-{
- SSL_CTX_free(ssl_ctx);
-}
-
///////////////////////////////////////////////////////
Ssl::GlobalContextStorage::GlobalContextStorage()
if (conf_i == configureStorage.end()) {
storage.erase(i);
} else {
- i->second->SetSize(conf_i->second);
+ i->second->setMemLimit(conf_i->second);
}
}
// add new local storages.
for (std::map<Ip::Address, size_t>::iterator conf_i = configureStorage.begin(); conf_i != configureStorage.end(); ++conf_i ) {
if (storage.find(conf_i->first) == storage.end()) {
- storage.insert(std::pair<Ip::Address, LocalContextStorage *>(conf_i->first, new LocalContextStorage(conf_i->second)));
+ storage.insert(std::pair<Ip::Address, LocalContextStorage *>(conf_i->first, new LocalContextStorage(-1, conf_i->second)));
}
}
}
#if USE_SSL
+#include "base/LruMap.h"
#include "SquidTime.h"
#include "CacheManager.h"
#include "ip/Address.h"
#include "mgr/Action.h"
#include "mgr/Command.h"
+#include "ssl/gadgets.h"
#if HAVE_MAP
#include <map>
#endif
virtual bool aggregatable() const { return false; }
};
-/**
- * Memory cache for store generated SSL context. Enforces total size limits
- * using an LRU algorithm.
- */
-class LocalContextStorage
-{
- friend class CertificateStorageAction;
-public:
- /// Cache item is an (SSL_CTX, host name) tuple.
- class Item
- {
- public:
- Item(SSL_CTX * aSsl_ctx, std::string const & aName);
- ~Item();
- public:
- SSL_CTX * ssl_ctx; ///< The SSL context.
- std::string host_name; ///< The host name of the SSL context.
- };
-
- typedef std::list<Item *> Queue;
- typedef Queue::iterator QueueIterator;
-
- /// host_name:queue_item mapping for fast lookups by host name
- typedef std::map<std::string, QueueIterator> Map;
- typedef Map::iterator MapIterator;
- typedef std::pair<std::string, QueueIterator> MapPair;
-
- LocalContextStorage(size_t aMax_memory);
- ~LocalContextStorage();
- /// Set maximum memory size for this storage.
- void SetSize(size_t aMax_memory);
- /// Return a pointer to the added ssl_ctx or NULL if fails (eg. max cache size equal 0).
- SSL_CTX * add(char const * host_name, SSL_CTX * ssl_ctx);
- /// Find SSL_CTX in storage by host name. Lru queue will be updated.
- SSL_CTX * find(char const * host_name);
- void remove(char const * host_name); ///< Delete the SSL context by hostname
-
-private:
- void purgeOne(); ///< Delete oldest object.
- /// Delete object by iterator. It is used in deletePurge() and remove(...) methods.
- void deleteAt(MapIterator i);
-
- size_t max_memory; ///< Max cache size.
- size_t memory_used; ///< Used cache size.
- Map storage; ///< The hostnames/SSL_CTX * pairs
- Queue lru_queue; ///< LRU cache index
-};
+typedef LruMap<SSL_CTX_Pointer, SSL_CTX_SIZE> LocalContextStorage;
/// Class for storing/manipulating LocalContextStorage per local listening address/port.
class GlobalContextStorage
#include "SquidString.h"
#include "SquidTime.h"
#include "SwapDir.h"
+#include "ssl/cert_validate_message.h"
#include "wordlist.h"
#include "SquidConfig.h"
+LruMap<Ssl::CertValidationResponse> *Ssl::CertValidationHelper::HelperCache = NULL;
+
#if USE_SSL_CRTD
Ssl::Helper * Ssl::Helper::GetInstance()
{
// going to use the '\1' char as the end-of-message mark.
ssl_crt_validator->eom = '\1';
assert(ssl_crt_validator->cmdline == NULL);
+
+ int ttl = 60;
+ size_t cache = 2048;
{
char *tmp = xstrdup(Ssl::TheConfig.ssl_crt_validator);
char *tmp_begin = tmp;
char * token = NULL;
+ bool parseParams = true;
while ((token = strwordtok(NULL, &tmp))) {
+ if (parseParams) {
+ if (strncmp(token, "ttl=", 4) == 0) {
+ ttl = atoi(token + 4);
+ continue;
+ } else if (strncmp(token, "cache=", 6) == 0) {
+ cache = atoi(token + 6);
+ continue;
+ } else
+ parseParams = false;
+ }
wordlistAdd(&ssl_crt_validator->cmdline, token);
}
xfree(tmp_begin);
}
helperOpenServers(ssl_crt_validator);
+
+ //WARNING: initializing static member in an object initialization method
+ assert(HelperCache == NULL);
+ HelperCache = new LruMap<Ssl::CertValidationResponse>(ttl, cache);
}
void Ssl::CertValidationHelper::Shutdown()
wordlistDestroy(&ssl_crt_validator->cmdline);
delete ssl_crt_validator;
ssl_crt_validator = NULL;
+
+ // CertValidationHelper::HelperCache is a static member, it is not good policy to
+ // reset it here. Will work because the current Ssl::CertValidationHelper is
+ // always the same static object.
+ delete HelperCache;
+ HelperCache = NULL;
+}
+
+struct submitData {
+ std::string query;
+ Ssl::CertValidationHelper::CVHCB *callback;
+ void *data;
+ SSL *ssl;
+ CBDATA_CLASS2(submitData);
+};
+CBDATA_CLASS_INIT(submitData);
+
+static void
+sslCrtvdHandleReplyWrapper(void *data, const HelperReply &reply)
+{
+ Ssl::CertValidationMsg replyMsg(Ssl::CrtdMessage::REPLY);
+ Ssl::CertValidationResponse *validationResponse = new Ssl::CertValidationResponse;
+ std::string error;
+
+ submitData *crtdvdData = static_cast<submitData *>(data);
+ STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(crtdvdData->ssl);
+ if (reply.result == HelperReply::BrokenHelper) {
+ debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content());
+ validationResponse->resultCode = HelperReply::BrokenHelper;
+ } else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
+ !replyMsg.parseResponse(*validationResponse, peerCerts, error) ) {
+ debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
+ debugs(83, DBG_IMPORTANT, "Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
+ validationResponse->resultCode = HelperReply::BrokenHelper;
+ }
+ else
+ validationResponse->resultCode = reply.result;
+
+ crtdvdData->callback(crtdvdData->data, *validationResponse);
+
+ if (Ssl::CertValidationHelper::HelperCache &&
+ (validationResponse->resultCode == HelperReply::Okay || validationResponse->resultCode == HelperReply::Error)) {
+ Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query.c_str(), validationResponse);
+ } else
+ delete validationResponse;
+
+ cbdataReferenceDone(crtdvdData->data);
+ SSL_free(crtdvdData->ssl);
+ delete crtdvdData;
}
-void Ssl::CertValidationHelper::sslSubmit(CrtdMessage const & message, HLPCB * callback, void * data)
+void Ssl::CertValidationHelper::sslSubmit(Ssl::CertValidationRequest const &request, Ssl::CertValidationHelper::CVHCB * callback, void * data)
{
static time_t first_warn = 0;
assert(ssl_crt_validator);
if (squid_curtime - first_warn > 3 * 60)
fatal("ssl_crtvd queue being overloaded for long time");
debugs(83, DBG_IMPORTANT, "WARNING: ssl_crtvd queue overload, rejecting");
- HelperReply failReply;
- failReply.result = HelperReply::BrokenHelper;
- failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
- callback(data, failReply);
+ Ssl::CertValidationResponse resp;
+ resp.resultCode = HelperReply::BrokenHelper;
+ callback(data, resp);
return;
}
-
first_warn = 0;
- std::string msg = message.compose();
- msg += '\n';
- helperSubmit(ssl_crt_validator, msg.c_str(), callback, data);
+
+ Ssl::CertValidationMsg message(Ssl::CrtdMessage::REQUEST);
+ message.setCode(Ssl::CertValidationMsg::code_cert_validate);
+ message.composeRequest(request);
+ debugs(83, 5, "SSL crtvd request: " << message.compose().c_str());
+
+ submitData *crtdvdData = new submitData;
+ crtdvdData->query = message.compose();
+ crtdvdData->query += '\n';
+ crtdvdData->callback = callback;
+ crtdvdData->data = cbdataReference(data);
+ crtdvdData->ssl = request.ssl;
+ CRYPTO_add(&crtdvdData->ssl->references,1,CRYPTO_LOCK_SSL);
+ Ssl::CertValidationResponse const*validationResponse;
+
+ if (CertValidationHelper::HelperCache &&
+ (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query.c_str()))) {
+ callback(data, *validationResponse);
+ cbdataReferenceDone(crtdvdData->data);
+ SSL_free(crtdvdData->ssl);
+ delete crtdvdData;
+ return;
+ }
+ helperSubmit(ssl_crt_validator, crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData);
}
#ifndef SQUID_SSL_HELPER_H
#define SQUID_SSL_HELPER_H
+#include "base/LruMap.h"
#include "../helper.h"
+#include "ssl/cert_validate_message.h"
#include "ssl/crtd_message.h"
namespace Ssl
};
#endif
+class CertValidationRequest;
+class CertValidationResponse;
class CertValidationHelper
{
public:
+ typedef void CVHCB(void *, Ssl::CertValidationResponse const &);
static CertValidationHelper * GetInstance(); ///< Instance class.
void Init(); ///< Init helper structure.
void Shutdown(); ///< Shutdown helper structure.
- /// Submit crtd message to external crtd server.
- void sslSubmit(CrtdMessage const & message, HLPCB * callback, void *data);
+ /// Submit crtd request message to external crtd server.
+ void sslSubmit(Ssl::CertValidationRequest const & request, CVHCB * callback, void *data);
private:
CertValidationHelper();
~CertValidationHelper();
helper * ssl_crt_validator; ///< helper for management of ssl_crtd.
+public:
+ static LruMap<Ssl::CertValidationResponse> *HelperCache; ///< cache for cert validation helper
};
} //namespace Ssl
//Ssl::CertificateStorageAction::CertificateStorageAction(const Mgr::Command::Pointer &cmd) STUB
Ssl::CertificateStorageAction::Pointer Ssl::CertificateStorageAction::Create(const Mgr::Command::Pointer &cmd) STUB_RETSTATREF(Ssl::CertificateStorageAction::Pointer)
void Ssl::CertificateStorageAction::dump(StoreEntry *sentry) STUB
-Ssl::LocalContextStorage::Item::Item(SSL_CTX * aSsl_ctx, std::string const & aName) STUB
-Ssl::LocalContextStorage::Item::~Item() STUB
-Ssl::LocalContextStorage::LocalContextStorage(size_t aMax_memory) STUB
-Ssl::LocalContextStorage::~LocalContextStorage() STUB
-void Ssl::LocalContextStorage::SetSize(size_t aMax_memory) STUB
-SSL_CTX * Ssl::LocalContextStorage::add(char const * host_name, SSL_CTX * ssl_ctx) STUB_RETVAL(NULL)
-SSL_CTX * Ssl::LocalContextStorage::find(char const * host_name) STUB_RETVAL(NULL)
-void Ssl::LocalContextStorage::remove(char const * host_name) STUB
-//Ssl::GlobalContextStorage::GlobalContextStorage() STUB
-//Ssl::GlobalContextStorage::~GlobalContextStorage() STUB
void Ssl::GlobalContextStorage::addLocalStorage(Ip::Address const & address, size_t size_of_store) STUB
Ssl::LocalContextStorage & Ssl::GlobalContextStorage::getLocalStorage(Ip::Address const & address)
-{ fatal(STUB_API " required"); static Ssl::LocalContextStorage v(0); return v; }
+{ fatal(STUB_API " required"); static Ssl::LocalContextStorage v(0,0); return v; }
void Ssl::GlobalContextStorage::reconfigureStart() STUB
//Ssl::GlobalContextStorage Ssl::TheGlobalContextStorage;