Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/logsrvd/tls_init.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2019-2022 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include <config.h>
20
21
#ifdef HAVE_STDBOOL_H
22
# include <stdbool.h>
23
#else
24
# include <compat/stdbool.h>
25
#endif /* HAVE_STDBOOL_H */
26
#if defined(HAVE_STDINT_H)
27
# include <stdint.h>
28
#elif defined(HAVE_INTTYPES_H)
29
# include <inttypes.h>
30
#endif
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <fcntl.h>
35
#include <unistd.h>
36
37
#include <sudo_compat.h>
38
#include <sudo_debug.h>
39
#include <sudo_event.h>
40
#include <sudo_fatal.h>
41
#include <sudo_gettext.h>
42
43
#include <tls_common.h>
44
#include <hostcheck.h>
45
46
#define DEFAULT_CIPHER_LST12 "HIGH:!aNULL"
47
#define DEFAULT_CIPHER_LST13 "TLS_AES_256_GCM_SHA384"
48
49
#if defined(HAVE_OPENSSL)
50
# include <openssl/bio.h>
51
# include <openssl/dh.h>
52
53
static bool
54
verify_cert_chain(SSL_CTX *ctx, const char *cert_file)
55
{
56
#ifdef HAVE_SSL_CTX_GET0_CERTIFICATE
57
const char *errstr;
58
bool ret = false;
59
X509_STORE_CTX *store_ctx = NULL;
60
X509_STORE *ca_store;
61
STACK_OF(X509) *chain_certs;
62
X509 *x509;
63
debug_decl(verify_cert_chain, SUDO_DEBUG_UTIL);
64
65
if ((x509 = SSL_CTX_get0_certificate(ctx)) == NULL) {
66
errstr = ERR_reason_error_string(ERR_get_error());
67
sudo_warnx("SSL_CTX_get0_certificate: %s",
68
errstr ? errstr : strerror(errno));
69
goto done;
70
}
71
72
if ((store_ctx = X509_STORE_CTX_new()) == NULL) {
73
errstr = ERR_reason_error_string(ERR_get_error());
74
sudo_warnx("X509_STORE_CTX_new: %s",
75
errstr ? errstr : strerror(errno));
76
goto done;
77
}
78
79
if (!SSL_CTX_get0_chain_certs(ctx, &chain_certs)) {
80
errstr = ERR_reason_error_string(ERR_get_error());
81
sudo_warnx("SSL_CTX_get0_chain_certs: %s: %s", cert_file,
82
errstr ? errstr : strerror(errno));
83
goto done;
84
}
85
86
ca_store = SSL_CTX_get_cert_store(ctx);
87
#ifdef X509_V_FLAG_X509_STRICT
88
if (ca_store != NULL)
89
X509_STORE_set_flags(ca_store, X509_V_FLAG_X509_STRICT);
90
#endif
91
92
if (!X509_STORE_CTX_init(store_ctx, ca_store, x509, chain_certs)) {
93
errstr = ERR_reason_error_string(ERR_get_error());
94
sudo_warnx("X509_STORE_CTX_init: %s",
95
errstr ? errstr : strerror(errno));
96
goto done;
97
}
98
99
if (X509_verify_cert(store_ctx) <= 0) {
100
errstr =
101
X509_verify_cert_error_string(X509_STORE_CTX_get_error(store_ctx));
102
sudo_warnx("X509_verify_cert: %s: %s", cert_file, errstr);
103
goto done;
104
}
105
106
ret = true;
107
done:
108
X509_STORE_CTX_free(store_ctx);
109
110
debug_return_bool(ret);
111
#else
112
/* TODO: verify server cert with old OpenSSL */
113
return true;
114
#endif /* HAVE_SSL_CTX_GET0_CERTIFICATE */
115
}
116
117
static bool
118
init_tls_ciphersuites(SSL_CTX *ctx, const char *ciphers_v12,
119
const char *ciphers_v13)
120
{
121
const char *errstr;
122
int success = 0;
123
debug_decl(init_tls_ciphersuites, SUDO_DEBUG_UTIL);
124
125
if (ciphers_v12 != NULL) {
126
/* try to set TLS v1.2 ciphersuite list from config if given */
127
success = SSL_CTX_set_cipher_list(ctx, ciphers_v12);
128
if (success) {
129
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
130
"TLS 1.2 ciphersuite list set to %s", ciphers_v12);
131
} else {
132
errstr = ERR_reason_error_string(ERR_get_error());
133
sudo_warnx(U_("unable to set TLS 1.2 ciphersuite to %s: %s"),
134
ciphers_v12, errstr ? errstr : strerror(errno));
135
}
136
}
137
if (!success) {
138
/* fallback to default ciphersuites for TLS v1.2 */
139
if (SSL_CTX_set_cipher_list(ctx, DEFAULT_CIPHER_LST12) <= 0) {
140
errstr = ERR_reason_error_string(ERR_get_error());
141
sudo_warnx(U_("unable to set TLS 1.2 ciphersuite to %s: %s"),
142
DEFAULT_CIPHER_LST12, errstr ? errstr : strerror(errno));
143
debug_return_bool(false);
144
} else {
145
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
146
"TLS v1.2 ciphersuite list set to %s (default)",
147
DEFAULT_CIPHER_LST12);
148
}
149
}
150
151
# if defined(HAVE_SSL_CTX_SET_CIPHERSUITES)
152
success = 0;
153
if (ciphers_v13 != NULL) {
154
/* try to set TLSv1.3 ciphersuite list from config */
155
success = SSL_CTX_set_ciphersuites(ctx, ciphers_v13);
156
if (success) {
157
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
158
"TLS v1.3 ciphersuite list set to %s", ciphers_v13);
159
} else {
160
errstr = ERR_reason_error_string(ERR_get_error());
161
sudo_warnx(U_("unable to set TLS 1.3 ciphersuite to %s: %s"),
162
ciphers_v13, errstr ? errstr : strerror(errno));
163
}
164
}
165
if (!success) {
166
/* fallback to default ciphersuites for TLS v1.3 */
167
if (SSL_CTX_set_ciphersuites(ctx, DEFAULT_CIPHER_LST13) <= 0) {
168
errstr = ERR_reason_error_string(ERR_get_error());
169
sudo_warnx(U_("unable to set TLS 1.3 ciphersuite to %s: %s"),
170
DEFAULT_CIPHER_LST13, errstr ? errstr : strerror(errno));
171
debug_return_bool(false);
172
} else {
173
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
174
"TLS v1.3 ciphersuite list set to %s (default)",
175
DEFAULT_CIPHER_LST13);
176
}
177
}
178
# endif
179
180
debug_return_bool(true);
181
}
182
183
/*
184
* Load diffie-hellman parameters from bio and store in ctx.
185
* Returns true on success, else false.
186
*/
187
#ifdef HAVE_SSL_CTX_SET0_TMP_DH_PKEY
188
static bool
189
set_dhparams_bio(SSL_CTX *ctx, BIO *bio)
190
{
191
EVP_PKEY *dhparams;
192
bool ret = false;
193
debug_decl(set_dhparams_bio, SUDO_DEBUG_UTIL);
194
195
dhparams = PEM_read_bio_Parameters(bio, NULL);
196
if (dhparams != NULL) {
197
/* dhparams is owned by ctx on success. */
198
ret = SSL_CTX_set0_tmp_dh_pkey(ctx, dhparams);
199
if (!ret) {
200
const char *errstr = ERR_reason_error_string(ERR_get_error());
201
sudo_warnx(U_("unable to set diffie-hellman parameters: %s"),
202
errstr ? errstr : strerror(errno));
203
EVP_PKEY_free(dhparams);
204
}
205
}
206
debug_return_bool(ret);
207
}
208
#else
209
static bool
210
set_dhparams_bio(SSL_CTX *ctx, BIO *bio)
211
{
212
DH *dhparams;
213
bool ret = false;
214
debug_decl(set_dhparams_bio, SUDO_DEBUG_UTIL);
215
216
dhparams = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
217
if (dhparams != NULL) {
218
/* LEAK: dhparams leaked on config reload */
219
ret = SSL_CTX_set_tmp_dh(ctx, dhparams);
220
if (!ret) {
221
const char *errstr = ERR_reason_error_string(ERR_get_error());
222
sudo_warnx(U_("unable to set diffie-hellman parameters: %s"),
223
errstr ? errstr : strerror(errno));
224
DH_free(dhparams);
225
}
226
}
227
debug_return_bool(ret);
228
}
229
#endif /* HAVE_SSL_CTX_SET0_TMP_DH_PKEY */
230
231
/*
232
* Load diffie-hellman parameters from the specified file and store in ctx.
233
* Returns true on success, else false.
234
*/
235
static bool
236
set_dhparams(SSL_CTX *ctx, const char *dhparam_file)
237
{
238
BIO *bio;
239
bool ret = false;
240
debug_decl(set_dhparams, SUDO_DEBUG_UTIL);
241
242
bio = BIO_new_file(dhparam_file, "r");
243
if (bio != NULL) {
244
if (set_dhparams_bio(ctx, bio)) {
245
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
246
"loaded diffie-hellman parameters from %s", dhparam_file);
247
ret = true;
248
}
249
BIO_free(bio);
250
} else {
251
sudo_warn(U_("unable to open %s"), dhparam_file);
252
}
253
254
debug_return_bool(ret);
255
}
256
257
SSL_CTX *
258
init_tls_context(const char *ca_bundle_file, const char *cert_file,
259
const char *key_file, const char *dhparam_file, const char *ciphers_v12,
260
const char *ciphers_v13, bool verify_cert)
261
{
262
SSL_CTX *ctx = NULL;
263
const char *errstr;
264
static bool initialized;
265
debug_decl(init_tls_context, SUDO_DEBUG_UTIL);
266
267
/* Only initialize the SSL library once. */
268
if (!initialized) {
269
SSL_library_init();
270
OpenSSL_add_all_algorithms();
271
SSL_load_error_strings();
272
initialized = true;
273
}
274
275
/* Create the ssl context and enforce TLS 1.2 or higher. */
276
if ((ctx = SSL_CTX_new(TLS_method())) == NULL) {
277
errstr = ERR_reason_error_string(ERR_get_error());
278
sudo_warnx(U_("unable to create TLS context: %s"),
279
errstr ? errstr : strerror(errno));
280
goto bad;
281
}
282
#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
283
if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) {
284
errstr = ERR_reason_error_string(ERR_get_error());
285
sudo_warnx(U_("unable to set minimum protocol version to TLS 1.2: %s"),
286
errstr ? errstr : strerror(errno));
287
goto bad;
288
}
289
#else
290
SSL_CTX_set_options(ctx,
291
SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1);
292
#endif
293
294
if (ca_bundle_file != NULL) {
295
STACK_OF(X509_NAME) *cacerts =
296
SSL_load_client_CA_file(ca_bundle_file);
297
298
if (cacerts == NULL) {
299
errstr = ERR_reason_error_string(ERR_get_error());
300
sudo_warnx(U_("%s: %s"), ca_bundle_file,
301
errstr ? errstr : strerror(errno));
302
goto bad;
303
}
304
SSL_CTX_set_client_CA_list(ctx, cacerts);
305
306
if (SSL_CTX_load_verify_locations(ctx, ca_bundle_file, NULL) <= 0) {
307
errstr = ERR_reason_error_string(ERR_get_error());
308
sudo_warnx("SSL_CTX_load_verify_locations: %s: %s", ca_bundle_file,
309
errstr ? errstr : strerror(errno));
310
goto bad;
311
}
312
} else {
313
if (!SSL_CTX_set_default_verify_paths(ctx)) {
314
errstr = ERR_reason_error_string(ERR_get_error());
315
sudo_warnx("SSL_CTX_set_default_verify_paths: %s",
316
errstr ? errstr : strerror(errno));
317
goto bad;
318
}
319
}
320
321
if (cert_file != NULL) {
322
if (!SSL_CTX_use_certificate_chain_file(ctx, cert_file)) {
323
errstr = ERR_reason_error_string(ERR_get_error());
324
sudo_warnx(U_("%s: %s"), cert_file,
325
errstr ? errstr : strerror(errno));
326
goto bad;
327
}
328
if (key_file == NULL) {
329
/* No explicit key file set, try to use the cert file. */
330
key_file = cert_file;
331
}
332
if (!SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) ||
333
!SSL_CTX_check_private_key(ctx)) {
334
errstr = ERR_reason_error_string(ERR_get_error());
335
sudo_warnx(U_("%s: %s"), key_file,
336
errstr ? errstr : strerror(errno));
337
goto bad;
338
}
339
340
/* Optionally verify the certificate we are using. */
341
if (verify_cert) {
342
if (!verify_cert_chain(ctx, cert_file))
343
goto bad;
344
} else {
345
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
346
"skipping local cert check");
347
}
348
}
349
350
/* Initialize TLS 1.2 1.3 ciphersuites. */
351
if (!init_tls_ciphersuites(ctx, ciphers_v12, ciphers_v13)) {
352
goto bad;
353
}
354
355
/*
356
* Load diffie-hellman parameters from a file if specified.
357
* Failure to open the file is not a fatal error.
358
*/
359
if (dhparam_file != NULL) {
360
if (!set_dhparams(ctx, dhparam_file)) {
361
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
362
"unable to load dhparam file, using default parameters");
363
}
364
} else {
365
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
366
"dhparam file not specified, using default parameters");
367
}
368
369
goto done;
370
371
bad:
372
SSL_CTX_free(ctx);
373
ctx = NULL;
374
375
done:
376
debug_return_ptr(ctx);
377
}
378
#endif /* HAVE_OPENSSL */
379
380