getSslContextDone(NULL);
}
-void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties, Ssl::CrtdMessage::BodyParams &certAdaptParams)
+void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties)
{
- // Build a key to use for storing/retrieving certificates to cache
- sslBumpCertKey = sslCommonName.defined() ? sslCommonName : sslConnectHostOrIp;
- certProperties.commonName = sslBumpCertKey.termedBuf();
+ certProperties.commonName = sslCommonName.defined() ? sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
// fake certificate adaptation requires bump-server-first mode
if (!bumpServerFirstErrorEntry())
const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
const char *param = ca->param;
- // if already set ignore
- if (certAdaptParams.find(alg) != certAdaptParams.end())
- continue;
-
// if not param defined for Common Name adaptation use hostname from
// the CONNECT request
- if (ca->alg == Ssl::algSetCommonName) {
+ if (ca->alg == Ssl::algSetCommonName && !certProperties.setCommonName) {
if (!param)
param = sslConnectHostOrIp.termedBuf();
certProperties.commonName = param;
certProperties.setCommonName = true;
}
- else if(ca->alg == Ssl::algSetValidAfter)
+ else if(ca->alg == Ssl::algSetValidAfter && !certProperties.setValidAfter)
certProperties.setValidAfter = true;
- else if(ca->alg == Ssl::algSetValidBefore)
+ else if(ca->alg == Ssl::algSetValidBefore && !certProperties.setValidBefore)
certProperties.setValidBefore = true;
assert(alg && param);
debugs(33, 5, HERE << "Matches certificate adaptation aglorithm: " <<
alg << " param: " << param);
-
- // append to the certificate adaptation parameters
- certAdaptParams.insert( std::make_pair(alg, param));
-
- // And also build the key used to store certificate to cache.
- sslBumpCertKey.append("+");
- sslBumpCertKey.append(alg);
- sslBumpCertKey.append("=");
- sslBumpCertKey.append(param);
}
}
certProperties.signAlgorithm = Ssl::algSignEnd;
for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
if (sg->aclList && checklist.fastCheck(sg->aclList) == ACCESS_ALLOWED) {
- const char *sgAlg = Ssl::CertSignAlgorithmStr[sg->alg];
certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
- certAdaptParams.insert( std::make_pair(Ssl::CrtdMessage::param_Sign, sgAlg));
- sslBumpCertKey.append("+Sign=");
- sslBumpCertKey.append(sgAlg);
break;
}
}
ConnStateData::getSslContextStart()
{
if (port->generateHostCertificates) {
- Ssl::CrtdMessage::BodyParams certAdaptParams;
Ssl::CertificateProperties certProperties;
- buildSslCertGenerationParams(certProperties, certAdaptParams);
+ buildSslCertGenerationParams(certProperties);
+ sslBumpCertKey = certProperties.dbKey().c_str();
assert(sslBumpCertKey.defined() && sslBumpCertKey[0] != '\0');
debugs(33, 5, HERE << "Finding SSL certificate for " << sslBumpCertKey << " in cache");
debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
Ssl::CrtdMessage request_message;
request_message.setCode(Ssl::CrtdMessage::code_new_certificate);
- Ssl::CrtdMessage::BodyParams map;
- map.insert(std::make_pair(Ssl::CrtdMessage::param_host, certProperties.commonName));
- /*Append parameters for cert adaptation*/
- map.insert(certAdaptParams.begin(), certAdaptParams.end());
- std::string bufferToWrite;
- Ssl::writeCertAndPrivateKeyToMemory(certProperties.signWithX509, certProperties.signWithPkey, bufferToWrite);
- if (certProperties.mimicCert.get()) {
- Ssl::appendCertToMemory(certProperties.mimicCert, bufferToWrite);
- debugs(33, 5, HERE << "Appended certificate to mimic: " << bufferToWrite);
- }
- request_message.composeBody(map, bufferToWrite);
+ request_message.composeRequest(certProperties);
debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
Ssl::Helper::GetInstance()->sslSubmit(request_message, sslCrtdHandleReplyWrapper, this);
return;
void setBumpSslErrorList(Ssl::Errors *errNoList) {bumpSslErrorNoList = cbdataReference(errNoList);}
/// Fill the certAdaptParams with the required data for certificate adaptation
/// and create the key for storing/retrieve the certificate to/from the cache
- void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties, Ssl::CrtdMessage::BodyParams &certAdaptParams);
+ void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
bool serveDelayedError(ClientSocketContext *context);
#else
bool switchedToHttps() const { return false; }
body += '\n' + other_part;
}
+bool Ssl::CrtdMessage::parseRequest(Ssl::CertificateProperties &certProperties, std::string error)
+{
+ Ssl::CrtdMessage::BodyParams map;
+ std::string certs_part;
+ parseBody(map, certs_part);
+ Ssl::CrtdMessage::BodyParams::iterator i = map.find(Ssl::CrtdMessage::param_host);
+ if (i == map.end()) {
+ error = "Parse request: Cannot find \"host\" parameter in request message";
+ return false;
+ }
+ certProperties.commonName = i->second;
+
+ i = map.find(Ssl::CrtdMessage::param_SetValidAfter);
+ if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
+ certProperties.setValidAfter = true;
+
+ i = map.find(Ssl::CrtdMessage::param_SetValidBefore);
+ if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
+ certProperties.setValidBefore = true;
+
+ i = map.find(Ssl::CrtdMessage::param_SetCommonName);
+ if (i != map.end()) {
+ // use this as Common Name instead of the hostname
+ // defined with host or Common Name from mimic cert
+ certProperties.commonName = i->second;
+ certProperties.setCommonName = true;
+ }
+
+ i = map.find(Ssl::CrtdMessage::param_Sign);
+ if (i != map.end()) {
+ if ((certProperties.signAlgorithm = Ssl::certSignAlgorithmId(i->second.c_str())) == Ssl::algSignEnd) {
+ error = "Parse request: Wrong signing algoritm: " + i->second;
+ return false;
+ }
+ }
+ else
+ certProperties.signAlgorithm = Ssl::algSignTrusted;
+
+ if (certProperties.signAlgorithm != Ssl::algSignSelf &&
+ !Ssl::readCertAndPrivateKeyFromMemory(certProperties.signWithX509, certProperties.signWithPkey, certs_part.c_str())) {
+ error = "Parse request: Broken signing certificate!";
+ return false;
+ }
+
+ static const std::string CERT_BEGIN_STR("-----BEGIN CERTIFICATE");
+ size_t pos;
+ if ((pos = certs_part.find(CERT_BEGIN_STR)) != std::string::npos) {
+ pos += CERT_BEGIN_STR.length();
+ if ((pos= certs_part.find(CERT_BEGIN_STR, pos)) != std::string::npos)
+ Ssl::readCertFromMemory(certProperties.mimicCert, certs_part.c_str() + pos);
+ }
+ return true;
+}
+
+void Ssl::CrtdMessage::composeRequest(Ssl::CertificateProperties const &certProperties)
+{
+ body.clear();
+ body = Ssl::CrtdMessage::param_host + "=" + certProperties.commonName;
+ if (certProperties.setCommonName)
+ body += "\n" + Ssl::CrtdMessage::param_SetCommonName + "=" + certProperties.commonName;
+ if (certProperties.setValidAfter)
+ body += "\n" + Ssl::CrtdMessage::param_SetValidAfter + "=on";
+ if (certProperties.setValidBefore)
+ body += "\n" + Ssl::CrtdMessage::param_SetValidBefore + "=on";
+ if(certProperties.signAlgorithm != Ssl::algSignEnd)
+ body += "\n" + Ssl::CrtdMessage::param_Sign + "=" + certSignAlgorithm(certProperties.signAlgorithm);
+
+ std::string certsPart;
+ bool ret = Ssl::writeCertAndPrivateKeyToMemory(certProperties.signWithX509, certProperties.signWithPkey, certsPart);
+ assert(ret);
+ if (certProperties.mimicCert.get()) {
+ ret = Ssl::appendCertToMemory(certProperties.mimicCert, certsPart);
+ assert(ret);
+ }
+ body += "\n" + certsPart;
+}
+
const std::string Ssl::CrtdMessage::code_new_certificate("new_certificate");
const std::string Ssl::CrtdMessage::param_host("host");
const std::string Ssl::CrtdMessage::param_SetValidAfter(Ssl::CertAdaptAlgorithmStr[algSetValidAfter]);
namespace Ssl
{
+class CertificateProperties;
+
/**
* This class is responsible for composing and parsing messages destined to, or comming
* from an ssl_crtd server. Format of these mesages is:
The other multistring part of body. \endverbatim
*/
void composeBody(BodyParams const & map, std::string const & other_part);
+
+ bool parseRequest(Ssl::CertificateProperties &, std::string error);
+ void composeRequest(Ssl::CertificateProperties const &);
+
/// String code for "new_certificate" messages
static const std::string code_new_certificate;
/// Parameter name for passing hostname
signAlgorithm(Ssl::algSignEnd)
{}
+std::string & Ssl::CertificateProperties::dbKey() const
+{
+ static std::string certKey;
+ certKey.reserve(4096);
+ if (mimicCert.get()) {
+ char buf[1024];
+ certKey = X509_NAME_oneline(X509_get_subject_name(mimicCert.get()), buf, sizeof(buf));
+ }
+
+ if (certKey.empty())
+ certKey = "/CN=" + commonName;
+
+ if (setValidAfter)
+ certKey.append("+SetValidAfter=on", 17);
+
+ if (setValidBefore)
+ certKey.append("+SetValidBefore=on", 18);
+
+ if (setCommonName) {
+ certKey.append("+SetCommonName=", 15);
+ certKey.append(commonName);
+ }
+
+ if (signAlgorithm != Ssl::algSignEnd) {
+ certKey.append("+Sign=", 6);
+ certKey.append(certSignAlgorithm(signAlgorithm));
+ }
+
+ return certKey;
+}
+
static bool buildCertificate(Ssl::X509_Pointer & cert, Ssl::CertificateProperties const &properties)
{
// not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
bool setCommonName; ///< Replace the CN field of the mimicing subject with the given
std::string commonName; ///< A CN to use for the generated certificate
CertSignAlgorithm signAlgorithm; ///< The signing algorithm 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 &);
\endverbatim
*/
-#define CERT_BEGIN_STR "-----BEGIN CERTIFICATE"
static const char *const B_KBYTES_STR = "KB";
static const char *const B_MBYTES_STR = "MB";
static const char *const B_GBYTES_STR = "GB";
\ingroup ssl_crtd
* Proccess new request message.
*/
-static bool proccessNewRequest(Ssl::CrtdMessage const & request_message, std::string const & db_path, size_t max_db_size, size_t fs_block_size)
+static bool proccessNewRequest(Ssl::CrtdMessage & request_message, std::string const & db_path, size_t max_db_size, size_t fs_block_size)
{
- Ssl::CrtdMessage::BodyParams map;
Ssl::CertificateProperties certProperties;
- std::string body_part;
- request_message.parseBody(map, body_part);
-
- Ssl::CrtdMessage::BodyParams::iterator i = map.find(Ssl::CrtdMessage::param_host);
- if (i == map.end())
- throw std::runtime_error("Cannot find \"" + Ssl::CrtdMessage::param_host + "\" parameter in request message.");
- certProperties.commonName = i->second;
+ std::string error;
+ if (!request_message.parseRequest(certProperties, error))
+ throw std::runtime_error("Error while parsing the crtd request" + error);
Ssl::CertificateDb db(db_path, max_db_size, fs_block_size);
-
Ssl::X509_Pointer cert;
Ssl::EVP_PKEY_Pointer pkey;
+ std::string &cert_subject = certProperties.dbKey();
- const char *s;
- std::string cert_subject;
- if ((s = strstr(body_part.c_str(), CERT_BEGIN_STR))) {
- s += strlen(CERT_BEGIN_STR);
- if ((s = strstr(s, CERT_BEGIN_STR))) {
- Ssl::readCertFromMemory(certProperties.mimicCert, s);
- if (certProperties.mimicCert.get()) {
- char buf[1024];
- cert_subject = X509_NAME_oneline(X509_get_subject_name(certProperties.mimicCert.get()), buf, sizeof(buf));
- }
- }
- }
-
- if (cert_subject.empty())
- cert_subject = "/CN=" + certProperties.commonName;
-
- i = map.find(Ssl::CrtdMessage::param_SetValidAfter);
- if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0) {
- cert_subject.append("+SetValidAfter=on");
- certProperties.setValidAfter = true;
- }
-
- i = map.find(Ssl::CrtdMessage::param_SetValidBefore);
- if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0) {
- cert_subject.append("+SetValidBefore=on");
- certProperties.setValidBefore = true;
- }
-
- i = map.find(Ssl::CrtdMessage::param_SetCommonName);
- if (i != map.end()) {
- cert_subject.append("+SetCommonName=");
- cert_subject.append(i->second);
- // use this as Common Name instead of the hostname
- // defined with host or Common Name from mimic cert
- certProperties.commonName = i->second;
- certProperties.setCommonName = true;
- }
-
- i = map.find(Ssl::CrtdMessage::param_Sign);
- if (i != map.end()) {
- cert_subject.append("+Sign=");
- cert_subject.append(i->second);
- if ((certProperties.signAlgorithm = Ssl::certSignAlgorithmId(i->second.c_str())) == Ssl::algSignEnd)
- throw std::runtime_error("Wrong signing algoritm:" + i->second);
- }
- else
- certProperties.signAlgorithm = Ssl::algSignTrusted;
-
db.find(cert_subject, cert, pkey);
if (cert.get() && certProperties.mimicCert.get()) {
}
}
- if (!cert || !pkey) {
- if (certProperties.signAlgorithm != Ssl::algSignSelf) {
- if (!Ssl::readCertAndPrivateKeyFromMemory(certProperties.signWithX509, certProperties.signWithPkey, body_part.c_str()))
- throw std::runtime_error("Broken signing certificate!");
- } /*else Squid did not send certificate to sign the generated certificate*/
-
+ if (!cert || !pkey) {
certProperties.serial.reset(db.getCurrentSerialNumber());
if (!Ssl::generateSslCertificate(cert, pkey, certProperties))