1 /***********************************************************************************************************************************
2 TLS Client
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5 
6 #include <string.h>
7 #include <strings.h>
8 
9 #include <openssl/x509v3.h>
10 
11 #include "common/crypto/common.h"
12 #include "common/debug.h"
13 #include "common/log.h"
14 #include "common/io/client.h"
15 #include "common/io/io.h"
16 #include "common/io/tls/client.h"
17 #include "common/io/tls/session.h"
18 #include "common/memContext.h"
19 #include "common/stat.h"
20 #include "common/type/object.h"
21 #include "common/wait.h"
22 
23 /***********************************************************************************************************************************
24 Statistics constants
25 ***********************************************************************************************************************************/
26 STRING_EXTERN(TLS_STAT_CLIENT_STR,                                  TLS_STAT_CLIENT);
27 STRING_EXTERN(TLS_STAT_RETRY_STR,                                   TLS_STAT_RETRY);
28 STRING_EXTERN(TLS_STAT_SESSION_STR,                                 TLS_STAT_SESSION);
29 
30 /***********************************************************************************************************************************
31 Object type
32 ***********************************************************************************************************************************/
33 typedef struct TlsClient
34 {
35     MemContext *memContext;                                         // Mem context
36     const String *host;                                             // Host to use for peer verification
37     TimeMSec timeout;                                               // Timeout for any i/o operation (connect, read, etc.)
38     bool verifyPeer;                                                // Should the peer (server) certificate be verified?
39     IoClient *ioClient;                                             // Underlying client (usually a SocketClient)
40 
41     SSL_CTX *context;                                               // TLS context
42 } TlsClient;
43 
44 /***********************************************************************************************************************************
45 Macros for function logging
46 ***********************************************************************************************************************************/
47 static String *
tlsClientToLog(const THIS_VOID)48 tlsClientToLog(const THIS_VOID)
49 {
50     THIS(const TlsClient);
51 
52     return strNewFmt(
53         "{ioClient: %s, timeout: %" PRIu64", verifyPeer: %s}",
54         memContextFreeing(this->memContext) ? NULL_Z : strZ(ioClientToLog(this->ioClient)), this->timeout,
55         cvtBoolToConstZ(this->verifyPeer));
56 }
57 
58 #define FUNCTION_LOG_TLS_CLIENT_TYPE                                                                                               \
59     TlsClient *
60 #define FUNCTION_LOG_TLS_CLIENT_FORMAT(value, buffer, bufferSize)                                                                  \
61     FUNCTION_LOG_STRING_OBJECT_FORMAT(value, tlsClientToLog, buffer, bufferSize)
62 
63 /***********************************************************************************************************************************
64 Free connection
65 ***********************************************************************************************************************************/
66 static void
tlsClientFreeResource(THIS_VOID)67 tlsClientFreeResource(THIS_VOID)
68 {
69     THIS(TlsClient);
70 
71     FUNCTION_LOG_BEGIN(logLevelTrace);
72         FUNCTION_LOG_PARAM(TLS_CLIENT, this);
73     FUNCTION_LOG_END();
74 
75     ASSERT(this != NULL);
76 
77     SSL_CTX_free(this->context);
78 
79     FUNCTION_LOG_RETURN_VOID();
80 }
81 
82 /***********************************************************************************************************************************
83 Convert an ASN1 string used in certificates to a String
84 ***********************************************************************************************************************************/
85 static String *
asn1ToStr(ASN1_STRING * nameAsn1)86 asn1ToStr(ASN1_STRING *nameAsn1)
87 {
88     FUNCTION_TEST_BEGIN();
89         FUNCTION_TEST_PARAM_P(VOID, nameAsn1);
90     FUNCTION_TEST_END();
91 
92     // The name should not be null
93     if (nameAsn1 == NULL)                                                                                           // {vm_covered}
94         THROW(CryptoError, "TLS certificate name entry is missing");
95 
96     FUNCTION_TEST_RETURN(                                                                                           // {vm_covered}
97         strNewN(
98 #if OPENSSL_VERSION_NUMBER < 0x10100000L
99             (const char *)ASN1_STRING_data(nameAsn1),
100 #else
101             (const char *)ASN1_STRING_get0_data(nameAsn1),
102 #endif
103             (size_t)ASN1_STRING_length(nameAsn1)));
104 }
105 
106 /***********************************************************************************************************************************
107 Check if a name from the server certificate matches the hostname
108 
109 Matching is always case-insensitive since DNS is case insensitive.
110 ***********************************************************************************************************************************/
111 static bool
tlsClientHostVerifyName(const String * host,const String * name)112 tlsClientHostVerifyName(const String *host, const String *name)
113 {
114     FUNCTION_LOG_BEGIN(logLevelTrace);
115         FUNCTION_LOG_PARAM(STRING, host);
116         FUNCTION_LOG_PARAM(STRING, name);
117     FUNCTION_LOG_END();
118 
119     ASSERT(host != NULL);
120     ASSERT(name != NULL);
121 
122     // Reject embedded nulls in certificate common or alternative name to prevent attacks like CVE-2009-4034
123     if (strlen(strZ(name)) != strSize(name))
124         THROW(CryptoError, "TLS certificate name contains embedded null");
125 
126     bool result = false;
127 
128     // Try an exact match
129     if (strcasecmp(strZ(name), strZ(host)) == 0)                                                                    // {vm_covered}
130     {
131         result = true;                                                                                              // {vm_covered}
132     }
133     // Else check if a wildcard certificate matches the host name
134     //
135     // The rules are:
136     // 1. Only match the '*' character as wildcard
137     // 2. Only match wildcards at the start of the string
138     // 3. The '*' character does *not* match '.', meaning that we match only a single pathname component.
139     // 4. Don't support more than one '*' in a single pattern.
140     //
141     // This is roughly in line with RFC2818, but contrary to what most browsers appear to be implementing (point 3 being the
142     // difference)
143     else if (strZ(name)[0] == '*' && strZ(name)[1] == '.' && strSize(name) > 2 &&                                   // {vm_covered}
144              strSize(name) < strSize(host) &&                                                                       // {vm_covered}
145              strcasecmp(strZ(name) + 1, strZ(host) + strSize(host) - strSize(name) + 1) == 0 &&                     // {vm_covered}
146              strChr(host, '.') >= (int)(strSize(host) - strSize(name)))                                             // {vm_covered}
147     {
148         result = true;                                                                                              // {vm_covered}
149     }
150 
151     FUNCTION_LOG_RETURN(BOOL, result);
152 }
153 
154 /***********************************************************************************************************************************
155 Verify that the server certificate matches the hostname we connected to
156 
157 The certificate's Common Name and Subject Alternative Names are considered.
158 ***********************************************************************************************************************************/
159 static bool
tlsClientHostVerify(const String * host,X509 * certificate)160 tlsClientHostVerify(const String *host, X509 *certificate)
161 {
162     FUNCTION_LOG_BEGIN(logLevelTrace);
163         FUNCTION_LOG_PARAM(STRING, host);
164         FUNCTION_LOG_PARAM_P(VOID, certificate);
165     FUNCTION_LOG_END();
166 
167     ASSERT(host != NULL);
168 
169     bool result = false;
170 
171     // Error if the certificate is NULL
172     if (certificate == NULL)                                                                                        // {vm_covered}
173         THROW(CryptoError, "No certificate presented by the TLS server");                                           // {vm_covered}
174 
175     MEM_CONTEXT_TEMP_BEGIN()                                                                                        // {vm_covered}
176     {
177         // First get the subject alternative names from the certificate and compare them against the hostname
178         STACK_OF(GENERAL_NAME) *altNameStack = (STACK_OF(GENERAL_NAME) *)X509_get_ext_d2i(                          // {vm_covered}
179             certificate, NID_subject_alt_name, NULL, NULL);                                                         // {vm_covered}
180         bool altNameFound = false;                                                                                  // {vm_covered}
181 
182         if (altNameStack)                                                                                           // {vm_covered}
183         {
184             for (int altNameIdx = 0; altNameIdx < sk_GENERAL_NAME_num(altNameStack); altNameIdx++)                  // {vm_covered}
185             {
186                 const GENERAL_NAME *name = sk_GENERAL_NAME_value(altNameStack, altNameIdx);                         // {vm_covered}
187                 altNameFound = true;                                                                                // {vm_covered}
188 
189                 if (name->type == GEN_DNS)                                                                          // {vm_covered}
190                     result = tlsClientHostVerifyName(host, asn1ToStr(name->d.dNSName));                             // {vm_covered}
191 
192                 if (result != false)                                                                                // {vm_covered}
193                     break;                                                                                          // {vm_covered}
194             }
195 
196             sk_GENERAL_NAME_pop_free(altNameStack, GENERAL_NAME_free);                                              // {vm_covered}
197         }
198 
199         // If no subject alternative name was found then check the common name. Per RFC 2818 and RFC 6125, if the subjectAltName
200         // extension of type dNSName is present the CN must be ignored.
201         if (!altNameFound)                                                                                          // {vm_covered}
202         {
203             X509_NAME *subjectName = X509_get_subject_name(certificate);                                            // {vm_covered}
204             CHECK(subjectName != NULL);                                                                             // {vm_covered}
205 
206             int commonNameIndex = X509_NAME_get_index_by_NID(subjectName, NID_commonName, -1);                      // {vm_covered}
207             CHECK(commonNameIndex >= 0);                                                                            // {vm_covered}
208 
209             result = tlsClientHostVerifyName(                                                                       // {vm_covered}
210                 host,                                                                                               // {vm_covered}
211                 asn1ToStr(X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjectName, commonNameIndex))));            // {vm_covered}
212         }
213     }
214     MEM_CONTEXT_TEMP_END();                                                                                         // {vm_covered}
215 
216     FUNCTION_LOG_RETURN(BOOL, result);                                                                              // {vm_covered}
217 }
218 
219 /***********************************************************************************************************************************
220 Open connection if this is a new client or if the connection was closed by the server
221 ***********************************************************************************************************************************/
222 static IoSession *
tlsClientOpen(THIS_VOID)223 tlsClientOpen(THIS_VOID)
224 {
225     THIS(TlsClient);
226 
227     FUNCTION_LOG_BEGIN(logLevelTrace)
228         FUNCTION_LOG_PARAM(TLS_CLIENT, this);
229     FUNCTION_LOG_END();
230 
231     ASSERT(this != NULL);
232 
233     IoSession *result = NULL;
234     SSL *session = NULL;
235 
236     MEM_CONTEXT_TEMP_BEGIN()
237     {
238         bool retry;
239         Wait *wait = waitNew(this->timeout);
240 
241         do
242         {
243             // Assume there will be no retry
244             retry = false;
245 
246             TRY_BEGIN()
247             {
248                 // Open the underlying session first since this is mostly likely to fail
249                 IoSession *ioSession = ioClientOpen(this->ioClient);
250 
251                 // Create internal TLS session. If there is a failure before the TlsSession object is created there may be a leak
252                 // of the TLS session but this is likely to result in program termination so it doesn't seem worth coding for.
253                 cryptoError((session = SSL_new(this->context)) == NULL, "unable to create TLS session");
254 
255                 // Set server host name used for validation
256                 cryptoError(SSL_set_tlsext_host_name(session, strZ(this->host)) != 1, "unable to set TLS host name");
257 
258                 // Create the TLS session
259                 result = tlsSessionNew(session, ioSession, this->timeout);
260             }
261             CATCH_ANY()
262             {
263                 result = NULL;
264 
265                 // Retry if wait time has not expired
266                 if (waitMore(wait))
267                 {
268                     LOG_DEBUG_FMT("retry %s: %s", errorTypeName(errorType()), errorMessage());
269                     retry = true;
270 
271                     statInc(TLS_STAT_RETRY_STR);
272                 }
273                 else
274                     RETHROW();
275             }
276             TRY_END();
277         }
278         while (retry);
279 
280         ioSessionMove(result, memContextPrior());
281     }
282     MEM_CONTEXT_TEMP_END();
283 
284     statInc(TLS_STAT_SESSION_STR);
285 
286     // Verify that the certificate presented by the server is valid
287     if (this->verifyPeer)                                                                                           // {vm_covered}
288     {
289         // Verify that the chain of trust leads to a valid CA
290         long int verifyResult = SSL_get_verify_result(session);                                                     // {vm_covered}
291 
292         if (verifyResult != X509_V_OK)                                                                              // {vm_covered}
293         {
294             THROW_FMT(                                                                                              // {vm_covered}
295                 CryptoError, "unable to verify certificate presented by '%s': [%ld] %s",                            // {vm_covered}
296                 strZ(ioClientName(this->ioClient)), verifyResult, X509_verify_cert_error_string(verifyResult));     // {vm_covered}
297         }
298 
299         // Verify that the hostname appears in the certificate
300         X509 *certificate = SSL_get_peer_certificate(session);                                                      // {vm_covered}
301         bool nameResult = tlsClientHostVerify(this->host, certificate);                                             // {vm_covered}
302         X509_free(certificate);                                                                                     // {vm_covered}
303 
304         if (!nameResult)                                                                                            // {vm_covered}
305         {
306             THROW_FMT(                                                                                              // {vm_covered}
307                 CryptoError,                                                                                        // {vm_covered}
308                 "unable to find hostname '%s' in certificate common name or subject alternative names",             // {vm_covered}
309                 strZ(this->host));                                                                                  // {vm_covered}
310         }
311     }
312 
313     FUNCTION_LOG_RETURN(IO_SESSION, result);
314 }
315 
316 /**********************************************************************************************************************************/
317 static const String *
tlsClientName(THIS_VOID)318 tlsClientName(THIS_VOID)
319 {
320     THIS(TlsClient);
321 
322     FUNCTION_TEST_BEGIN();
323         FUNCTION_TEST_PARAM(TLS_CLIENT, this);
324     FUNCTION_TEST_END();
325 
326     ASSERT(this != NULL);
327 
328     FUNCTION_TEST_RETURN(ioClientName(this->ioClient));
329 }
330 
331 /**********************************************************************************************************************************/
332 static const IoClientInterface tlsClientInterface =
333 {
334     .type = IO_CLIENT_TLS_TYPE,
335     .name = tlsClientName,
336     .open = tlsClientOpen,
337     .toLog = tlsClientToLog,
338 };
339 
340 IoClient *
tlsClientNew(IoClient * ioClient,const String * host,TimeMSec timeout,bool verifyPeer,const String * caFile,const String * caPath)341 tlsClientNew(IoClient *ioClient, const String *host, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath)
342 {
343     FUNCTION_LOG_BEGIN(logLevelDebug)
344         FUNCTION_LOG_PARAM(IO_CLIENT, ioClient);
345         FUNCTION_LOG_PARAM(STRING, host);
346         FUNCTION_LOG_PARAM(TIME_MSEC, timeout);
347         FUNCTION_LOG_PARAM(BOOL, verifyPeer);
348         FUNCTION_LOG_PARAM(STRING, caFile);
349         FUNCTION_LOG_PARAM(STRING, caPath);
350     FUNCTION_LOG_END();
351 
352     ASSERT(ioClient != NULL);
353 
354     IoClient *this = NULL;
355 
356     MEM_CONTEXT_NEW_BEGIN("TlsClient")
357     {
358         TlsClient *driver = memNew(sizeof(TlsClient));
359 
360         *driver = (TlsClient)
361         {
362             .memContext = MEM_CONTEXT_NEW(),
363             .ioClient = ioClientMove(ioClient, MEM_CONTEXT_NEW()),
364             .host = strDup(host),
365             .timeout = timeout,
366             .verifyPeer = verifyPeer,
367         };
368 
369         // Setup TLS context
370         // -------------------------------------------------------------------------------------------------------------------------
371         cryptoInit();
372 
373         // Select the TLS method to use.  To maintain compatibility with older versions of OpenSSL we need to use an SSL method,
374         // but SSL versions will be excluded in SSL_CTX_set_options().
375         const SSL_METHOD *method = SSLv23_method();
376         cryptoError(method == NULL, "unable to load TLS method");
377 
378         // Create the TLS context
379         driver->context = SSL_CTX_new(method);
380         cryptoError(driver->context == NULL, "unable to create TLS context");
381 
382         memContextCallbackSet(driver->memContext, tlsClientFreeResource, driver);
383 
384         // Exclude SSL versions to only allow TLS and also disable compression
385         SSL_CTX_set_options(driver->context, (long)(SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION));
386 
387         // Disable auto-retry to prevent SSL_read() from hanging
388         SSL_CTX_clear_mode(driver->context, SSL_MODE_AUTO_RETRY);
389 
390         // Set location of CA certificates if the server certificate will be verified
391         // -------------------------------------------------------------------------------------------------------------------------
392         if (driver->verifyPeer)
393         {
394             // If the user specified a location
395             if (caFile != NULL || caPath != NULL)                                                                   // {vm_covered}
396             {
397                 cryptoError(                                                                                        // {vm_covered}
398                     SSL_CTX_load_verify_locations(driver->context, strZNull(caFile), strZNull(caPath)) != 1,        // {vm_covered}
399                     "unable to set user-defined CA certificate location");                                          // {vm_covered}
400             }
401             // Else use the defaults
402             else
403             {
404                 cryptoError(
405                     SSL_CTX_set_default_verify_paths(driver->context) != 1, "unable to set default CA certificate location");
406             }
407         }
408 
409         statInc(TLS_STAT_CLIENT_STR);
410 
411         // Create client interface
412         this = ioClientNew(driver, &tlsClientInterface);
413     }
414     MEM_CONTEXT_NEW_END();
415 
416     FUNCTION_LOG_RETURN(IO_CLIENT, this);
417 }
418