/*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
#if USE_OPENSSL
#include "base/CbDataList.h"
+#include "comm/forward.h"
+#include "compat/openssl.h"
#include "sbuf/SBuf.h"
#include "security/forward.h"
#include "ssl/gadgets.h"
\ingroup ServerProtocol
*/
-// Custom SSL errors; assumes all official errors are positive
-#define SQUID_X509_V_ERR_INFINITE_VALIDATION -4
-#define SQUID_X509_V_ERR_CERT_CHANGE -3
-#define SQUID_ERR_SSL_HANDSHAKE -2
-#define SQUID_X509_V_ERR_DOMAIN_MISMATCH -1
-// All SSL errors range: from smallest (negative) custom to largest SSL error
-#define SQUID_SSL_ERROR_MIN SQUID_X509_V_ERR_CERT_CHANGE
-#define SQUID_SSL_ERROR_MAX INT_MAX
-
// Maximum certificate validation callbacks. OpenSSL versions exceeding this
// limit are deemed stuck in an infinite validation loop (OpenSSL bug #3090)
// and will trigger the SQUID_X509_V_ERR_INFINITE_VALIDATION error.
namespace Ssl
{
+
+/// callback for receiving password to access password secured PEM files
+/// XXX: Requires SSL_CTX_set_default_passwd_cb_userdata()!
+int AskPasswordCb(char *buf, int size, int rwflag, void *userdata);
+
/// initialize the SSL library global state.
/// call before generating any SSL context
void Initialize();
-/// Squid defined error code (<0), an error code returned by SSL X509 api, or SSL_ERROR_NONE
-typedef int ssl_error_t;
-
-typedef CbDataList<Ssl::ssl_error_t> Errors;
-
-class ErrorDetail;
class CertValidationResponse;
typedef RefCount<CertValidationResponse> CertValidationResponsePointer;
-/// Creates SSL Client connection structure and initializes SSL I/O (Comm and BIO).
-/// On errors, emits DBG_IMPORTANT with details and returns NULL.
-SSL *CreateClient(Security::ContextPtr sslContext, const int fd, const char *squidCtx);
-
-/// Creates SSL Server connection structure and initializes SSL I/O (Comm and BIO).
-/// On errors, emits DBG_IMPORTANT with details and returns NULL.
-SSL *CreateServer(Security::ContextPtr sslContext, const int fd, const char *squidCtx);
+/// initialize a TLS server context with OpenSSL specific settings
+bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &);
-/// An SSL certificate-related error.
-/// Pairs an error code with the certificate experiencing the error.
-class CertError
-{
-public:
- ssl_error_t code; ///< certificate error code
- Security::CertPointer cert; ///< certificate with the above error code
- /**
- * Absolute cert position in the final certificate chain that may include
- * intermediate certificates. Chain positions start with zero and increase
- * towards the root certificate. Negative if unknown.
- */
- int depth;
- CertError(ssl_error_t anErr, X509 *aCert, int depth = -1);
- CertError(CertError const &err);
- CertError & operator = (const CertError &old);
- bool operator == (const CertError &ce) const;
- bool operator != (const CertError &ce) const;
-};
+/// initialize a TLS client context with OpenSSL specific settings
+bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, Security::ParsedPortFlags);
-/// Holds a list of certificate SSL errors
-typedef CbDataList<Ssl::CertError> CertErrors;
+/// set the certificate verify callback for a context
+void ConfigurePeerVerification(Security::ContextPointer &, const Security::ParsedPortFlags);
+void DisablePeerVerification(Security::ContextPointer &);
-void SetSessionCallbacks(Security::ContextPtr);
-extern Ipc::MemMap *SessionCache;
-extern const char *SessionCacheName;
+/// if required, setup callback for generating ephemeral RSA keys
+void MaybeSetupRsaCallback(Security::ContextPointer &);
} //namespace Ssl
-/// \ingroup ServerProtocolSSLAPI
-Security::ContextPtr sslCreateServerContext(AnyP::PortCfg &port);
-
-/// \ingroup ServerProtocolSSLAPI
-Security::ContextPtr sslCreateClientContext(Security::PeerOptions &, long options, long flags);
-
-/// \ingroup ServerProtocolSSLAPI
-int ssl_read_method(int, char *, int);
-
-/// \ingroup ServerProtocolSSLAPI
-int ssl_write_method(int, const char *, int);
-
-/// \ingroup ServerProtocolSSLAPI
-void ssl_shutdown_method(SSL *ssl);
-
/// \ingroup ServerProtocolSSLAPI
const char *sslGetUserEmail(SSL *ssl);
const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name);
/// \ingroup ServerProtocolSSLAPI
-const char *sslGetUserCertificatePEM(SSL *ssl);
+SBuf sslGetUserCertificatePEM(SSL *ssl);
/// \ingroup ServerProtocolSSLAPI
-const char *sslGetUserCertificateChainPEM(SSL *ssl);
+SBuf sslGetUserCertificateChainPEM(SSL *ssl);
namespace Ssl
{
/// \ingroup ServerProtocolSSLAPI
typedef char const *GETX509ATTRIBUTE(X509 *, const char *);
+typedef SBuf GETX509PEM(X509 *);
/// \ingroup ServerProtocolSSLAPI
GETX509ATTRIBUTE GetX509UserAttribute;
/// \ingroup ServerProtocolSSLAPI
GETX509ATTRIBUTE GetX509CAAttribute;
+/// \ingroup ServerProtocolSSLAPI
+GETX509PEM GetX509PEM;
+
/// \ingroup ServerProtocolSSLAPI
GETX509ATTRIBUTE GetX509Fingerprint;
*/
enum BumpMode {bumpNone = 0, bumpClientFirst, bumpServerFirst, bumpPeek, bumpStare, bumpBump, bumpSplice, bumpTerminate, /*bumpErr,*/ bumpEnd};
-enum BumpStep {bumpStep1, bumpStep2, bumpStep3};
-
/**
\ingroup ServerProtocolSSLAPI
* Short names for ssl-bump modes
*/
-extern const char *BumpModeStr[];
+extern std::vector<const char *>BumpModeStr;
/**
\ingroup ServerProtocolSSLAPI
*/
inline const char *bumpMode(int bm)
{
- return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr[bm] : NULL;
+ return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr.at(bm) : NULL;
}
/// certificates indexed by issuer name
typedef std::multimap<SBuf, X509 *> CertsIndexedList;
/**
- \ingroup ServerProtocolSSLAPI
* Load PEM-encoded certificates from the given file.
*/
bool loadCerts(const char *certsFile, Ssl::CertsIndexedList &list);
/**
- \ingroup ServerProtocolSSLAPI
* Load PEM-encoded certificates to the squid untrusteds certificates
* internal DB from the given file.
*/
bool loadSquidUntrusted(const char *path);
/**
- \ingroup ServerProtocolSSLAPI
* Removes all certificates from squid untrusteds certificates
* internal DB and frees all memory
*/
void unloadSquidUntrusted();
/**
- \ingroup ServerProtocolSSLAPI
* Add the certificate cert to ssl object untrusted certificates.
* Squid uses an attached to SSL object list of untrusted certificates,
* with certificates which can be used to complete incomplete chains sent
*/
void SSL_add_untrusted_cert(SSL *ssl, X509 *cert);
-/**
- \ingroup ServerProtocolSSLAPI
- * Searches in serverCertificates list for the cert issuer and if not found
- * and Authority Info Access of cert provides a URI return it.
- */
-const char *uriOfIssuerIfMissing(X509 *cert, Ssl::X509_STACK_Pointer const &serverCertificates);
+/// finds certificate issuer URI in the Authority Info Access extension
+const char *findIssuerUri(X509 *cert);
+
+/// Searches serverCertificates and local databases for the cert issuer.
+/// \param context where to retrieve the configured CA's db; may be nil
+/// \returns the found issuer certificate or nil
+Security::CertPointer findIssuerCertificate(X509 *cert, const STACK_OF(X509) *serverCertificates, const Security::ContextPointer &context);
/**
- \ingroup ServerProtocolSSLAPI
* Fill URIs queue with the uris of missing certificates from serverCertificate chain
* if this information provided by Authority Info Access.
+ \return whether at least one URI is known, including previously known ones
*/
-void missingChainCertificatesUrls(std::queue<SBuf> &URIs, Ssl::X509_STACK_Pointer const &serverCertificates);
+bool missingChainCertificatesUrls(std::queue<SBuf> &URIs, const STACK_OF(X509) &serverCertificates, const Security::ContextPointer &context);
/**
\ingroup ServerProtocolSSLAPI
* Generate a certificate to be used as untrusted signing certificate, based on a trusted CA
*/
-bool generateUntrustedCert(Security::CertPointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, Security::CertPointer const & cert, EVP_PKEY_Pointer const & pkey);
+bool generateUntrustedCert(Security::CertPointer & untrustedCert, Security::PrivateKeyPointer & untrustedPkey, Security::CertPointer const & cert, Security::PrivateKeyPointer const & pkey);
/// certificates indexed by issuer name
typedef std::multimap<SBuf, X509 *> CertsIndexedList;
\ingroup ServerProtocolSSLAPI
* Decide on the kind of certificate and generate a CA- or self-signed one
*/
-Security::ContextPtr generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port);
+Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool trusted);
/**
\ingroup ServerProtocolSSLAPI
\param properties Check if the context certificate matches the given properties
\return true if the contexts certificate is valid, false otherwise
*/
-bool verifySslCertificate(Security::ContextPtr sslContext, CertificateProperties const &properties);
+bool verifySslCertificate(const Security::ContextPointer &, CertificateProperties const &);
/**
\ingroup ServerProtocolSSLAPI
* Read private key and certificate from memory and generate SSL context
* using their.
*/
-Security::ContextPtr generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port);
+Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char * data, Security::ServerOptions &, bool trusted);
/**
\ingroup ServerProtocolSSLAPI
* Create an SSL context using the provided certificate and key
*/
-Security::ContextPtr createSSLContext(Security::CertPointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port);
+Security::ContextPointer createSSLContext(Security::CertPointer & x509, Security::PrivateKeyPointer & pkey, Security::ServerOptions &);
/**
\ingroup ServerProtocolSSLAPI
* Chain signing certificate and chained certificates to an SSL Context
*/
-void chainCertificatesToSSLContext(SSL_CTX *sslContext, AnyP::PortCfg &port);
+void chainCertificatesToSSLContext(Security::ContextPointer &, Security::ServerOptions &);
/**
\ingroup ServerProtocolSSLAPI
* Configure a previously unconfigured SSL context object.
*/
-void configureUnconfiguredSslContext(SSL_CTX *sslContext, Ssl::CertSignAlgorithm signAlgorithm,AnyP::PortCfg &port);
+void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &);
/**
\ingroup ServerProtocolSSLAPI
- * Generates a certificate and a private key using provided properies and set it
+ * Generates a certificate and a private key using provided properties and set it
* to SSL object.
*/
bool configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &port);
*/
bool configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &port);
-/**
- \ingroup ServerProtocolSSLAPI
- * Adds the certificates in certList to the certificate chain of the SSL context
- */
-void addChainToSslContext(Security::ContextPtr sslContext, STACK_OF(X509) *certList);
-
-/**
- \ingroup ServerProtocolSSLAPI
- * Configures sslContext to use squid untrusted certificates internal list
- * to complete certificate chains when verifies SSL servers certificates.
- */
-void useSquidUntrusted(SSL_CTX *sslContext);
-
/**
\ingroup ServerProtocolSSLAPI
* Configures sslContext to use squid untrusted certificates internal list
*/
void useSquidUntrusted(SSL_CTX *sslContext);
-/**
- \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(Security::CertPointer & 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
\ingroup ServerProtocolSSLAPI
* Sets the hostname for the Server Name Indication (SNI) TLS extension
* if supported by the used openssl toolkit.
- \return true if SNI set false otherwise
*/
-bool setClientSNI(SSL *ssl, const char *fqdn);
+void 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
+ Creates and returns an OpenSSL BIO object for writing to `buf` (or throws).
+ TODO: Add support for reading from `buf`.
+ */
+BIO *BIO_new_SBuf(SBuf *buf);
+
+/// Validates the given TLS connection server certificate chain in conjunction
+/// with a (possibly empty) set of "extra" intermediate certs. Also consults
+/// sslproxy_foreign_intermediate_certs. This is a C++/Squid-friendly wrapper of
+/// OpenSSL "verification callback function" (\ref OpenSSL_vcb_disambiguation).
+/// OpenSSL has a similar wrapper, ssl_verify_cert_chain(), but that wrapper is
+/// not a part of the public OpenSSL API.
+bool VerifyConnCertificates(Security::Connection &, const Ssl::X509_STACK_Pointer &extraCerts);
+
+// TODO: Move other ssl_ex_index_* validation-related information here.
+/// OpenSSL "verify_callback function" input/output parameters. This information
+/// cannot be passed through the verification API directly, so it is aggregated
+/// in this class and exchanged via ssl_ex_index_verify_callback_parameters. For
+/// OpenSSL validation callback details, see \ref OpenSSL_vcb_disambiguation.
+class VerifyCallbackParameters {
+public:
+ /// creates a VerifyCallbackParameters object and adds it to the given TLS connection
+ /// \returns the successfully created and added object
+ static VerifyCallbackParameters *New(Security::Connection &);
+
+ /// \returns the VerifyCallbackParameters object previously attached via New()
+ static VerifyCallbackParameters &At(Security::Connection &);
+
+ /// \returns the VerifyCallbackParameters object previously attached via New() or nil
+ static VerifyCallbackParameters *Find(Security::Connection &);
+
+ /* input parameters */
+
+ /// whether X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY should be cleared
+ /// (after setting hidMissingIssuer) because the validation initiator wants
+ /// to get the missing certificates and redo the validation with them
+ bool callerHandlesMissingCertificates = false;
+
+ /* output parameters */
+
+ /// whether certificate validation has failed due to missing certificate(s)
+ /// (i.e. X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY), but the failure was
+ /// cleared/hidden due to true callerHandlesMissingCertificates setting; the
+ /// certificate chain has to be deemed untrusted until revalidation (if any)
+ bool hidMissingIssuer = false;
+};
} //namespace Ssl