1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 83    SSL accelerator support */
10 
11 #ifndef SQUID_SSL_SUPPORT_H
12 #define SQUID_SSL_SUPPORT_H
13 
14 #if USE_OPENSSL
15 
16 #include "base/CbDataList.h"
17 #include "comm/forward.h"
18 #include "compat/openssl.h"
19 #include "sbuf/SBuf.h"
20 #include "security/forward.h"
21 #include "ssl/gadgets.h"
22 
23 #if HAVE_OPENSSL_X509V3_H
24 #include <openssl/x509v3.h>
25 #endif
26 #if HAVE_OPENSSL_ERR_H
27 #include <openssl/err.h>
28 #endif
29 #if HAVE_OPENSSL_ENGINE_H
30 #include <openssl/engine.h>
31 #endif
32 #include <queue>
33 #include <map>
34 
35 /**
36  \defgroup ServerProtocolSSLAPI Server-Side SSL API
37  \ingroup ServerProtocol
38  */
39 
40 // Custom SSL errors; assumes all official errors are positive
41 #define SQUID_X509_V_ERR_INFINITE_VALIDATION -4
42 #define SQUID_X509_V_ERR_CERT_CHANGE -3
43 #define SQUID_ERR_SSL_HANDSHAKE -2
44 #define SQUID_X509_V_ERR_DOMAIN_MISMATCH -1
45 // All SSL errors range: from smallest (negative) custom to largest SSL error
46 #define SQUID_SSL_ERROR_MIN SQUID_X509_V_ERR_CERT_CHANGE
47 #define SQUID_SSL_ERROR_MAX INT_MAX
48 
49 // Maximum certificate validation callbacks. OpenSSL versions exceeding this
50 // limit are deemed stuck in an infinite validation loop (OpenSSL bug #3090)
51 // and will trigger the SQUID_X509_V_ERR_INFINITE_VALIDATION error.
52 // Can be set to a number up to UINT32_MAX
53 #ifndef SQUID_CERT_VALIDATION_ITERATION_MAX
54 #define SQUID_CERT_VALIDATION_ITERATION_MAX 16384
55 #endif
56 
57 namespace AnyP
58 {
59 class PortCfg;
60 };
61 
62 namespace Ipc
63 {
64 class MemMap;
65 }
66 
67 namespace Ssl
68 {
69 
70 /// callback for receiving password to access password secured PEM files
71 /// XXX: Requires SSL_CTX_set_default_passwd_cb_userdata()!
72 int AskPasswordCb(char *buf, int size, int rwflag, void *userdata);
73 
74 /// initialize the SSL library global state.
75 /// call before generating any SSL context
76 void Initialize();
77 
78 class ErrorDetail;
79 class CertValidationResponse;
80 typedef RefCount<CertValidationResponse> CertValidationResponsePointer;
81 
82 /// initialize a TLS server context with OpenSSL specific settings
83 bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &);
84 
85 /// initialize a TLS client context with OpenSSL specific settings
86 bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long flags);
87 
88 /// set the certificate verify callback for a context
89 void SetupVerifyCallback(Security::ContextPointer &);
90 
91 /// if required, setup callback for generating ephemeral RSA keys
92 void MaybeSetupRsaCallback(Security::ContextPointer &);
93 
94 } //namespace Ssl
95 
96 /// \ingroup ServerProtocolSSLAPI
97 const char *sslGetUserEmail(SSL *ssl);
98 
99 /// \ingroup ServerProtocolSSLAPI
100 const char *sslGetUserAttribute(SSL *ssl, const char *attribute_name);
101 
102 /// \ingroup ServerProtocolSSLAPI
103 const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name);
104 
105 /// \ingroup ServerProtocolSSLAPI
106 const char *sslGetUserCertificatePEM(SSL *ssl);
107 
108 /// \ingroup ServerProtocolSSLAPI
109 const char *sslGetUserCertificateChainPEM(SSL *ssl);
110 
111 namespace Ssl
112 {
113 /// \ingroup ServerProtocolSSLAPI
114 typedef char const *GETX509ATTRIBUTE(X509 *, const char *);
115 
116 /// \ingroup ServerProtocolSSLAPI
117 GETX509ATTRIBUTE GetX509UserAttribute;
118 
119 /// \ingroup ServerProtocolSSLAPI
120 GETX509ATTRIBUTE GetX509CAAttribute;
121 
122 /// \ingroup ServerProtocolSSLAPI
123 GETX509ATTRIBUTE GetX509Fingerprint;
124 
125 extern const EVP_MD *DefaultSignHash;
126 
127 /**
128   \ingroup ServerProtocolSSLAPI
129  * Supported ssl-bump modes
130  */
131 enum BumpMode {bumpNone = 0, bumpClientFirst, bumpServerFirst, bumpPeek, bumpStare, bumpBump, bumpSplice, bumpTerminate, /*bumpErr,*/ bumpEnd};
132 
133 enum BumpStep {bumpStep1, bumpStep2, bumpStep3};
134 
135 /**
136  \ingroup  ServerProtocolSSLAPI
137  * Short names for ssl-bump modes
138  */
139 extern std::vector<const char *>BumpModeStr;
140 
141 /**
142  \ingroup ServerProtocolSSLAPI
143  * Return the short name of the ssl-bump mode "bm"
144  */
bumpMode(int bm)145 inline const char *bumpMode(int bm)
146 {
147     return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr.at(bm) : NULL;
148 }
149 
150 /// certificates indexed by issuer name
151 typedef std::multimap<SBuf, X509 *> CertsIndexedList;
152 
153 /**
154  * Load PEM-encoded certificates from the given file.
155  */
156 bool loadCerts(const char *certsFile, Ssl::CertsIndexedList &list);
157 
158 /**
159  * Load PEM-encoded certificates to the squid untrusteds certificates
160  * internal DB from the given file.
161  */
162 bool loadSquidUntrusted(const char *path);
163 
164 /**
165  * Removes all certificates from squid untrusteds certificates
166  * internal DB and frees all memory
167  */
168 void unloadSquidUntrusted();
169 
170 /**
171  * Add the certificate cert to ssl object untrusted certificates.
172  * Squid uses an attached to SSL object list of untrusted certificates,
173  * with certificates which can be used to complete incomplete chains sent
174  * by the SSL server.
175  */
176 void SSL_add_untrusted_cert(SSL *ssl, X509 *cert);
177 
178 /**
179  * Searches in serverCertificates list for the cert issuer and if not found
180  * and Authority Info Access of cert provides a URI return it.
181  */
182 const char *uriOfIssuerIfMissing(X509 *cert,  Security::CertList const &serverCertificates, const Security::ContextPointer &context);
183 
184 /**
185  * Fill URIs queue with the uris of missing certificates from serverCertificate chain
186  * if this information provided by Authority Info Access.
187  */
188 void missingChainCertificatesUrls(std::queue<SBuf> &URIs, Security::CertList const &serverCertificates, const Security::ContextPointer &context);
189 
190 /**
191   \ingroup ServerProtocolSSLAPI
192   * Generate a certificate to be used as untrusted signing certificate, based on a trusted CA
193 */
194 bool generateUntrustedCert(Security::CertPointer & untrustedCert, Security::PrivateKeyPointer & untrustedPkey, Security::CertPointer const & cert, Security::PrivateKeyPointer const & pkey);
195 
196 /// certificates indexed by issuer name
197 typedef std::multimap<SBuf, X509 *> CertsIndexedList;
198 
199 /**
200  \ingroup ServerProtocolSSLAPI
201  * Load PEM-encoded certificates from the given file.
202  */
203 bool loadCerts(const char *certsFile, Ssl::CertsIndexedList &list);
204 
205 /**
206  \ingroup ServerProtocolSSLAPI
207  * Load PEM-encoded certificates to the squid untrusteds certificates
208  * internal DB from the given file.
209  */
210 bool loadSquidUntrusted(const char *path);
211 
212 /**
213  \ingroup ServerProtocolSSLAPI
214  * Removes all certificates from squid untrusteds certificates
215  * internal DB and frees all memory
216  */
217 void unloadSquidUntrusted();
218 
219 /**
220   \ingroup ServerProtocolSSLAPI
221   * Decide on the kind of certificate and generate a CA- or self-signed one
222 */
223 Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool trusted);
224 
225 /**
226   \ingroup ServerProtocolSSLAPI
227   * Check if the certificate of the given context is still valid
228   \param sslContext The context to check
229   \param properties Check if the context certificate matches the given properties
230   \return true if the contexts certificate is valid, false otherwise
231  */
232 bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &);
233 
234 /**
235   \ingroup ServerProtocolSSLAPI
236   * Read private key and certificate from memory and generate SSL context
237   * using their.
238  */
239 Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char * data, Security::ServerOptions &, bool trusted);
240 
241 /**
242   \ingroup ServerProtocolSSLAPI
243   * Create an SSL context using the provided certificate and key
244  */
245 Security::ContextPointer createSSLContext(Security::CertPointer & x509, Security::PrivateKeyPointer & pkey, Security::ServerOptions &);
246 
247 /**
248  \ingroup ServerProtocolSSLAPI
249  * Chain signing certificate and chained certificates to an SSL Context
250  */
251 void chainCertificatesToSSLContext(Security::ContextPointer &, Security::ServerOptions &);
252 
253 /**
254  \ingroup ServerProtocolSSLAPI
255  * Configure a previously unconfigured SSL context object.
256  */
257 void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &);
258 
259 /**
260   \ingroup ServerProtocolSSLAPI
261   * Generates a certificate and a private key using provided properies and set it
262   * to SSL object.
263  */
264 bool configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &port);
265 
266 /**
267   \ingroup ServerProtocolSSLAPI
268   * Read private key and certificate from memory and set it to SSL object
269   * using their.
270  */
271 bool configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &port);
272 
273 /**
274   \ingroup ServerProtocolSSLAPI
275   * Configures sslContext to use squid untrusted certificates internal list
276   * to complete certificate chains when verifies SSL servers certificates.
277  */
278 void useSquidUntrusted(SSL_CTX *sslContext);
279 
280 /**
281    \ingroup ServerProtocolSSLAPI
282    * Iterates over the X509 common and alternate names and to see if  matches with given data
283    * using the check_func.
284    \param peer_cert  The X509 cert to check
285    \param check_data The data with which the X509 CNs compared
286    \param check_func The function used to match X509 CNs. The CN data passed as ASN1_STRING data
287    \return   1 if any of the certificate CN matches, 0 if none matches.
288  */
289 int matchX509CommonNames(X509 *peer_cert, void *check_data, int (*check_func)(void *check_data,  ASN1_STRING *cn_data));
290 
291 /**
292    \ingroup ServerProtocolSSLAPI
293    * Check if the certificate is valid for a server
294    \param cert  The X509 cert to check.
295    \param server The server name.
296    \return   true if the certificate is valid for the server or false otherwise.
297  */
298 bool checkX509ServerValidity(X509 *cert, const char *server);
299 
300 /**
301    \ingroup ServerProtocolSSLAPI
302    * Convert a given ASN1_TIME to a string form.
303    \param tm the time in ASN1_TIME form
304    \param buf the buffer to write the output
305    \param len write at most len bytes
306    \return The number of bytes written
307  */
308 int asn1timeToString(ASN1_TIME *tm, char *buf, int len);
309 
310 /**
311    \ingroup ServerProtocolSSLAPI
312    * Sets the hostname for the Server Name Indication (SNI) TLS extension
313    * if supported by the used openssl toolkit.
314 */
315 void setClientSNI(SSL *ssl, const char *fqdn);
316 
317 /**
318   \ingroup ServerProtocolSSLAPI
319   * Generates a unique key based on CertificateProperties object and store it to key
320  */
321 void InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key);
322 
323 /**
324   \ingroup ServerProtocolSSLAPI
325   Creates and returns an OpenSSL BIO object for writing to `buf` (or throws).
326   TODO: Add support for reading from `buf`.
327  */
328 BIO *BIO_new_SBuf(SBuf *buf);
329 } //namespace Ssl
330 
331 #if _SQUID_WINDOWS_
332 
333 #if defined(__cplusplus)
334 
335 /** \cond AUTODOCS-IGNORE */
336 namespace Squid
337 {
338 /** \endcond */
339 
340 /// \ingroup ServerProtocolSSLAPI
341 inline
SSL_set_fd(SSL * ssl,int fd)342 int SSL_set_fd(SSL *ssl, int fd)
343 {
344     return ::SSL_set_fd(ssl, _get_osfhandle(fd));
345 }
346 
347 /// \ingroup ServerProtocolSSLAPI
348 #define SSL_set_fd(ssl,fd) Squid::SSL_set_fd(ssl,fd)
349 
350 } /* namespace Squid */
351 
352 #else
353 
354 /// \ingroup ServerProtocolSSLAPI
355 #define SSL_set_fd(s,f) (SSL_set_fd(s, _get_osfhandle(f)))
356 
357 #endif /* __cplusplus */
358 
359 #endif /* _SQUID_WINDOWS_ */
360 
361 #endif /* USE_OPENSSL */
362 #endif /* SQUID_SSL_SUPPORT_H */
363 
364