Coverage Report

Created: 2023-06-07 06:46

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