DANE: remove excess compile-time checks
[exim.git] / src / src / tls.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* This module provides TLS (aka SSL) support for Exim. The code for OpenSSL is
9based on a patch that was originally contributed by Steve Haslam. It was
10adapted from stunnel, a GPL program by Michal Trojnara. The code for GNU TLS is
6aa6fc9c 11based on a patch contributed by Nikos Mavrogiannopoulos. Because these packages
059ec3d9
PH
12are so very different, the functions for each are kept in separate files. The
13relevant file is #included as required, after any any common functions.
14
15No cryptographic code is included in Exim. All this module does is to call
16functions from the OpenSSL or GNU TLS libraries. */
17
18
19#include "exim.h"
65867078 20#include "transports/smtp.h"
059ec3d9 21
01603eec 22#if defined(MACRO_PREDEF) && !defined(DISABLE_TLS)
b10c87b3
JH
23# include "macro_predef.h"
24# ifdef USE_GNUTLS
25# include "tls-gnu.c"
26# else
8442641e
JH
27# include "tls-openssl.c"
28# endif
29#endif
30
31#ifndef MACRO_PREDEF
32
059ec3d9
PH
33/* This module is compiled only when it is specifically requested in the
34build-time configuration. However, some compilers don't like compiling empty
35modules, so keep them happy with a dummy when skipping the rest. Make it
36reference itself to stop picky compilers complaining that it is unused, and put
37in a dummy argument to stop even pickier compilers complaining about infinite
38loops. */
39
01603eec 40#ifdef DISABLE_TLS
059ec3d9
PH
41static void dummy(int x) { dummy(x-1); }
42#else
43
44/* Static variables that are used for buffering data by both sets of
4fe99a6c 45functions and the common functions below.
059ec3d9 46
4fe99a6c
PP
47We're moving away from this; GnuTLS is already using a state, which
48can switch, so we can do TLS callouts during ACLs. */
059ec3d9 49
17c76198 50static const int ssl_xfer_buffer_size = 4096;
4fe99a6c
PP
51#ifndef USE_GNUTLS
52static uschar *ssl_xfer_buffer = NULL;
059ec3d9
PH
53static int ssl_xfer_buffer_lwm = 0;
54static int ssl_xfer_buffer_hwm = 0;
8b77d27a
JH
55static int ssl_xfer_eof = FALSE;
56static BOOL ssl_xfer_error = FALSE;
4fe99a6c 57#endif
059ec3d9 58
44bbabb5 59uschar *tls_channelbinding_b64 = NULL;
059ec3d9
PH
60
61
62/*************************************************
63* Expand string; give error on failure *
64*************************************************/
65
66/* If expansion is forced to fail, set the result NULL and return TRUE.
67Other failures return FALSE. For a server, an SMTP response is given.
68
69Arguments:
70 s the string to expand; if NULL just return TRUE
71 name name of string being expanded (for error)
72 result where to put the result
73
74Returns: TRUE if OK; result may still be NULL after forced failure
75*/
76
77static BOOL
cf0c6164 78expand_check(const uschar *s, const uschar *name, uschar **result, uschar ** errstr)
059ec3d9 79{
cf0c6164
JH
80if (!s)
81 *result = NULL;
82else if ( !(*result = expand_string(US s)) /* need to clean up const more */
8768d548 83 && !f.expand_string_forcedfail
cf0c6164 84 )
059ec3d9 85 {
cf0c6164
JH
86 *errstr = US"Internal error";
87 log_write(0, LOG_MAIN|LOG_PANIC, "expansion of %s failed: %s", name,
88 expand_string_message);
89 return FALSE;
059ec3d9
PH
90 }
91return TRUE;
92}
93
94
e9477a08
JH
95/*************************************************
96* Timezone environment flipping *
97*************************************************/
98
99static uschar *
100to_tz(uschar * tz)
101{
dfe7d917
JH
102uschar * old = US getenv("TZ");
103(void) setenv("TZ", CCS tz, 1);
271019bd 104tzset();
dfe7d917 105return old;
e9477a08 106}
dfe7d917 107
e9477a08
JH
108static void
109restore_tz(uschar * tz)
110{
dfe7d917
JH
111if (tz)
112 (void) setenv("TZ", CCS tz, 1);
113else
93a680e4 114 (void) os_unsetenv(US"TZ");
271019bd 115tzset();
e9477a08
JH
116}
117
059ec3d9
PH
118/*************************************************
119* Many functions are package-specific *
120*************************************************/
121
122#ifdef USE_GNUTLS
27f19eb4
JH
123# include "tls-gnu.c"
124# include "tlscert-gnu.c"
4fe99a6c 125
27f19eb4
JH
126# define ssl_xfer_buffer (state_server.xfer_buffer)
127# define ssl_xfer_buffer_lwm (state_server.xfer_buffer_lwm)
128# define ssl_xfer_buffer_hwm (state_server.xfer_buffer_hwm)
129# define ssl_xfer_eof (state_server.xfer_eof)
130# define ssl_xfer_error (state_server.xfer_error)
4fe99a6c 131
059ec3d9 132#else
27f19eb4
JH
133# include "tls-openssl.c"
134# include "tlscert-openssl.c"
059ec3d9
PH
135#endif
136
137
138
139/*************************************************
140* TLS version of ungetc *
141*************************************************/
142
143/* Puts a character back in the input buffer. Only ever
144called once.
389ca47a 145Only used by the server-side TLS.
059ec3d9
PH
146
147Arguments:
148 ch the character
149
150Returns: the character
151*/
152
153int
154tls_ungetc(int ch)
155{
156ssl_xfer_buffer[--ssl_xfer_buffer_lwm] = ch;
157return ch;
158}
159
160
161
162/*************************************************
163* TLS version of feof *
164*************************************************/
165
166/* Tests for a previous EOF
389ca47a 167Only used by the server-side TLS.
059ec3d9
PH
168
169Arguments: none
170Returns: non-zero if the eof flag is set
171*/
172
173int
174tls_feof(void)
175{
8b77d27a 176return (int)ssl_xfer_eof;
059ec3d9
PH
177}
178
179
180
181/*************************************************
182* TLS version of ferror *
183*************************************************/
184
185/* Tests for a previous read error, and returns with errno
186restored to what it was when the error was detected.
389ca47a 187Only used by the server-side TLS.
059ec3d9
PH
188
189>>>>> Hmm. Errno not handled yet. Where do we get it from? >>>>>
190
191Arguments: none
192Returns: non-zero if the error flag is set
193*/
194
195int
196tls_ferror(void)
197{
8b77d27a 198return (int)ssl_xfer_error;
059ec3d9
PH
199}
200
58eb016e
PH
201
202/*************************************************
203* TLS version of smtp_buffered *
204*************************************************/
205
206/* Tests for unused chars in the TLS input buffer.
389ca47a 207Only used by the server-side TLS.
58eb016e
PH
208
209Arguments: none
210Returns: TRUE/FALSE
211*/
212
213BOOL
214tls_smtp_buffered(void)
215{
216return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm;
217}
218
219
01603eec 220#endif /*DISABLE_TLS*/
059ec3d9 221
35aba663
JH
222void
223tls_modify_variables(tls_support * dest_tsp)
224{
225modify_variable(US"tls_bits", &dest_tsp->bits);
226modify_variable(US"tls_certificate_verified", &dest_tsp->certificate_verified);
227modify_variable(US"tls_cipher", &dest_tsp->cipher);
228modify_variable(US"tls_peerdn", &dest_tsp->peerdn);
01603eec 229#if !defined(DISABLE_TLS) && !defined(USE_GNUTLS)
35aba663
JH
230modify_variable(US"tls_sni", &dest_tsp->sni);
231#endif
232}
233
417bfce4 234
01603eec 235#ifndef DISABLE_TLS
812a6045
JH
236/************************************************
237* TLS certificate name operations *
238************************************************/
239
240/* Convert an rfc4514 DN to an exim comma-sep list.
241Backslashed commas need to be replaced by doublecomma
242for Exim's list quoting. We modify the given string
243inplace.
244*/
245
246static void
247dn_to_list(uschar * dn)
248{
d7978c0f 249for (uschar * cp = dn; *cp; cp++)
812a6045
JH
250 if (cp[0] == '\\' && cp[1] == ',')
251 *cp++ = ',';
252}
253
254
255/* Extract fields of a given type from an RFC4514-
256format Distinguished Name. Return an Exim list.
257NOTE: We modify the supplied dn string during operation.
258
259Arguments:
260 dn Distinguished Name string
bfbad1dd 261 mod list containing optional output list-sep and
812a6045
JH
262 field selector match, comma-separated
263Return:
264 allocated string with list of matching fields,
265 field type stripped
266*/
267
268uschar *
55414b25 269tls_field_from_dn(uschar * dn, const uschar * mod)
812a6045
JH
270{
271int insep = ',';
272uschar outsep = '\n';
273uschar * ele;
274uschar * match = NULL;
275int len;
acec9514 276gstring * list = NULL;
812a6045 277
7437665e 278while ((ele = string_nextinlist(&mod, &insep, NULL, 0)))
812a6045
JH
279 if (ele[0] != '>')
280 match = ele; /* field tag to match */
281 else if (ele[1])
bfbad1dd 282 outsep = ele[1]; /* nondefault output separator */
812a6045
JH
283
284dn_to_list(dn);
285insep = ',';
bfbad1dd 286len = match ? Ustrlen(match) : -1;
55414b25 287while ((ele = string_nextinlist(CUSS &dn, &insep, NULL, 0)))
bfbad1dd
JH
288 if ( !match
289 || Ustrncmp(ele, match, len) == 0 && ele[len] == '='
290 )
acec9514
JH
291 list = string_append_listele(list, outsep, ele+len+1);
292return string_from_gstring(list);
812a6045
JH
293}
294
295
e51c7be2
JH
296/* Compare a domain name with a possibly-wildcarded name. Wildcards
297are restricted to a single one, as the first element of patterns
298having at least three dot-separated elements. Case-independent.
299Return TRUE for a match
300*/
301static BOOL
302is_name_match(const uschar * name, const uschar * pat)
303{
304uschar * cp;
305return *pat == '*' /* possible wildcard match */
306 ? *++pat == '.' /* starts star, dot */
307 && !Ustrchr(++pat, '*') /* has no more stars */
308 && Ustrchr(pat, '.') /* and has another dot. */
309 && (cp = Ustrchr(name, '.'))/* The name has at least one dot */
310 && strcmpic(++cp, pat) == 0 /* and we only compare after it. */
311 : !Ustrchr(pat+1, '*')
312 && strcmpic(name, pat) == 0;
313}
314
315/* Compare a list of names with the dnsname elements
316of the Subject Alternate Name, if any, and the
317Subject otherwise.
318
319Arguments:
320 namelist names to compare
321 cert certificate
322
323Returns:
324 TRUE/FALSE
325*/
326
327BOOL
55414b25 328tls_is_name_for_cert(const uschar * namelist, void * cert)
e51c7be2
JH
329{
330uschar * altnames = tls_cert_subject_altname(cert, US"dns");
331uschar * subjdn;
332uschar * certname;
333int cmp_sep = 0;
334uschar * cmpname;
335
336if ((altnames = tls_cert_subject_altname(cert, US"dns")))
337 {
338 int alt_sep = '\n';
7437665e 339 while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0)))
e51c7be2 340 {
55414b25 341 const uschar * an = altnames;
7437665e 342 while ((certname = string_nextinlist(&an, &alt_sep, NULL, 0)))
e51c7be2
JH
343 if (is_name_match(cmpname, certname))
344 return TRUE;
345 }
346 }
347
348else if ((subjdn = tls_cert_subject(cert, NULL)))
349 {
350 int sn_sep = ',';
e51c7be2
JH
351
352 dn_to_list(subjdn);
67791ce4 353 while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0)))
e51c7be2 354 {
55414b25 355 const uschar * sn = subjdn;
7437665e 356 while ((certname = string_nextinlist(&sn, &sn_sep, NULL, 0)))
e51c7be2
JH
357 if ( *certname++ == 'C'
358 && *certname++ == 'N'
359 && *certname++ == '='
360 && is_name_match(cmpname, certname)
361 )
362 return TRUE;
363 }
364 }
365return FALSE;
366}
01603eec 367#endif /*!DISABLE_TLS*/
8442641e 368#endif /*!MACRO_PREDEF*/
812a6045
JH
369
370/* vi: aw ai sw=2
371*/
059ec3d9 372/* End of tls.c */