Ssl::SSL_CTX_Pointer staticSslContext; ///< for HTTPS accelerator or static sslBump
Ssl::X509_Pointer signingCert; ///< x509 certificate for signing generated certificates
Ssl::EVP_PKEY_Pointer signPkey; ///< private key for sighing generated certificates
+ Ssl::X509_STACK_Pointer certsToChain; ///< x509 certificates to send with the generated cert
#endif
CBDATA_CLASS2(http_port_list);
s->cafile, s->capath, s->crlfile, s->dhfile,
s->sslContextSessionId));
- Ssl::readCertAndPrivateKeyFromFiles(s->signingCert, s->signPkey, s->cert, s->key);
+ Ssl::readCertChainAndPrivateKeyFromFiles(s->signingCert, s->signPkey, s->certsToChain, s->cert, s->key);
}
}
debugs(33, 5, HERE << "Certificate for " << sslHostName << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
} else {
debugs(33, 5, HERE << "Certificate for " << sslHostName << " was successfully recieved from ssl_crtd");
- getSslContextDone(Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str()), true);
+ SSL_CTX *ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str());
+ getSslContextDone(ctx, true);
return;
}
}
{
// Try to add generated ssl context to storage.
if (port->generateHostCertificates && isNew) {
+
+ Ssl::addChainToSslContext(sslContext, port->certsToChain.get());
+
Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
if (sslContext && sslHostName != "") {
if (!ssl_ctx_cache.add(sslHostName.termedBuf(), sslContext)) {
#include "config.h"
#include "ssl/gadgets.h"
+#if HAVE_OPENSSL_X509V3_H
+#include <openssl/x509v3.h>
+#endif
/**
\ingroup ServerProtocolSSLInternal
return certificate;
}
-/**
- \ingroup ServerProtocolSSLInternal
- * Read private key from file. Make sure that this is not encrypted file.
- */
-static EVP_PKEY * readSslPrivateKey(char const * keyFilename)
+EVP_PKEY * Ssl::readSslPrivateKey(char const * keyFilename)
{
if (!keyFilename)
return NULL;
CtoCpp1(X509_free, X509 *)
typedef TidyPointer<X509, X509_free_cpp> X509_Pointer;
+CtoCpp1(sk_X509_free, STACK_OF(X509) *)
+typedef TidyPointer<STACK_OF(X509), sk_X509_free_cpp> X509_STACK_Pointer;
+
CtoCpp1(EVP_PKEY_free, EVP_PKEY *)
typedef TidyPointer<EVP_PKEY, EVP_PKEY_free_cpp> EVP_PKEY_Pointer;
*/
bool generateSslCertificateAndPrivateKey(char const *host, X509_Pointer const & signedX509, EVP_PKEY_Pointer const & signedPkey, X509_Pointer & cert, EVP_PKEY_Pointer & pkey, BIGNUM const* serial);
+/**
+ \ingroup SslCrtdSslAPI
+ * Read private key from file. Make sure that this is not encrypted file.
+ */
+EVP_PKEY * readSslPrivateKey(char const * keyFilename);
+
/**
\ingroup SslCrtdSslAPI
* Read certificate and private key from files.
#endif
}
+void Ssl::addChainToSslContext(SSL_CTX *sslContext, STACK_OF(X509) *chain)
+{
+ if (!chain)
+ return;
+
+ for (int i = 0; i < sk_X509_num(chain); i++) {
+ X509 *cert = sk_X509_value(chain, i);
+ if (SSL_CTX_add_extra_chain_cert(sslContext, cert)) {
+ // increase the certificate lock
+ CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
+ } else {
+ const int ssl_error = ERR_get_error();
+ debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL));
+ }
+ }
+}
+
+/**
+ \ingroup ServerProtocolSSLInternal
+ * Read certificate from file.
+ * See also: static readSslX509Certificate function, gadgets.cc file
+ */
+static X509 * readSslX509CertificatesChain(char const * certFilename, STACK_OF(X509)* chain)
+{
+ if (!certFilename)
+ return NULL;
+ Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
+ if (!bio)
+ return NULL;
+ if (!BIO_read_filename(bio.get(), certFilename))
+ return NULL;
+ X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
+
+ if (certificate && chain) {
+
+ if (X509_check_issued(certificate, certificate) == X509_V_OK)
+ debugs(83, 5, "Certificate is self-signed, will not be chained");
+ else {
+ if(sk_X509_push(chain, certificate))
+ CRYPTO_add(&(certificate->references), 1, CRYPTO_LOCK_X509);
+ else
+ debugs(83, DBG_IMPORTANT, "WARNING: unable to add signing certificate to cert chain");
+ // and add to the chain any certificate loaded from the file
+ while (X509 *ca = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL)) {
+ if (!sk_X509_push(chain, ca))
+ debugs(83, DBG_IMPORTANT, "WARNING: unable to add CA certificate to cert chain");
+ }
+ }
+ }
+
+ return certificate;
+}
+
+void Ssl::readCertChainAndPrivateKeyFromFiles(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, X509_STACK_Pointer & chain, char const * certFilename, char const * keyFilename)
+{
+ if (keyFilename == NULL)
+ keyFilename = certFilename;
+ if (!chain)
+ chain.reset(sk_X509_new_null());
+ if (!chain)
+ debugs(83, DBG_IMPORTANT, "WARNING: unable to allocate memory for cert chain");
+ pkey.reset(readSslPrivateKey(keyFilename));
+ cert.reset(readSslX509CertificatesChain(certFilename, chain.get()));
+ if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
+ pkey.reset(NULL);
+ cert.reset(NULL);
+ }
+}
+
#endif /* USE_SSL */
*/
SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data);
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Adds the certificates in certList to the certificate chain of the SSL context
+ */
+void addChainToSslContext(SSL_CTX *sslContext, STACK_OF(X509) *certList);
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Read certificate, private key and any certificates which must be chained from files.
+ * See also: Ssl::readCertAndPrivateKeyFromFiles function, defined in gadgets.h
+ * \param certFilename name of file with certificate and certificates which must be chainned.
+ * \param keyFilename name of file with private key.
+ */
+void readCertChainAndPrivateKeyFromFiles(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, X509_STACK_Pointer & chain, char const * certFilename, char const * keyFilename);
+
/**
\ingroup ServerProtocolSSLAPI
* Iterates over the X509 common and alternate names and to see if matches with given data