Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/logsrvd/tls_client.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
#include <errno.h>
22
#ifdef HAVE_STDBOOL_H
23
# include <stdbool.h>
24
#else
25
# include <compat/stdbool.h>
26
#endif /* HAVE_STDBOOL_H */
27
#if defined(HAVE_STDINT_H)
28
# include <stdint.h>
29
#elif defined(HAVE_INTTYPES_H)
30
# include <inttypes.h>
31
#endif
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <time.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
#include <sudo_util.h>
43
44
#include "logsrv_util.h"
45
#include <tls_common.h>
46
#include <hostcheck.h>
47
48
#if defined(HAVE_OPENSSL)
49
50
/*
51
* Check that the server's certificate is valid and that it
52
* contains the server name or IP address.
53
* Returns 0 if the cert is invalid, else 1.
54
*/
55
static int
56
verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx)
57
{
58
HostnameValidationResult result;
59
struct peer_info *peer_info;
60
SSL *ssl;
61
X509 *current_cert;
62
X509 *peer_cert;
63
debug_decl(verify_peer_identity, SUDO_DEBUG_UTIL);
64
65
current_cert = X509_STORE_CTX_get_current_cert(ctx);
66
67
/* If pre-verification of the cert failed, just propagate that result back */
68
if (preverify_ok != 1) {
69
int err = X509_STORE_CTX_get_error(ctx);
70
char current_cert_name[256] = "";
71
if (current_cert != NULL)
72
X509_NAME_oneline(X509_get_subject_name(current_cert), current_cert_name, sizeof(current_cert_name));
73
74
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
75
"TLS verification failed for cert '%s': '%d:%s'", current_cert_name,
76
err, X509_verify_cert_error_string(err));
77
debug_return_int(0);
78
}
79
80
/*
81
* Since this callback is called for each cert in the chain,
82
* check that current cert is the peer's certificate.
83
*/
84
peer_cert = X509_STORE_CTX_get0_cert(ctx);
85
if (current_cert != peer_cert) {
86
debug_return_int(1);
87
}
88
89
/* Fetch the attached peer_info from the ssl connection object. */
90
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
91
if (ssl == NULL) {
92
debug_return_int(0);
93
}
94
peer_info = SSL_get_ex_data(ssl, 1);
95
if (peer_info == NULL) {
96
debug_return_int(0);
97
}
98
99
/* Validate the cert based on the host name and IP address. */
100
result = validate_hostname(peer_cert, peer_info->name, peer_info->ipaddr);
101
102
debug_return_int(result == MatchFound);
103
}
104
105
void
106
tls_connect_cb(int sock, int what, void *v)
107
{
108
struct tls_client_closure *tls_client = v;
109
struct sudo_event_base *evbase = tls_client->evbase;
110
const struct timespec *timeout = NULL;
111
const char *errstr;
112
int con_stat;
113
debug_decl(tls_connect_cb, SUDO_DEBUG_UTIL);
114
115
if (what == SUDO_EV_TIMEOUT) {
116
sudo_warnx("%s", U_("TLS handshake timeout occurred"));
117
goto bad;
118
}
119
120
if (sudo_timespecisset(&tls_client->connect_timeout))
121
timeout = &tls_client->connect_timeout;
122
123
con_stat = SSL_connect(tls_client->ssl);
124
125
if (con_stat == 1) {
126
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
127
"SSL_connect successful");
128
tls_client->tls_connect_state = true;
129
} else {
130
switch (SSL_get_error(tls_client->ssl, con_stat)) {
131
/* TLS handshake is not finished, reschedule event */
132
case SSL_ERROR_WANT_READ:
133
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
134
"SSL_connect returns SSL_ERROR_WANT_READ");
135
if (what != SUDO_EV_READ) {
136
if (sudo_ev_set(tls_client->tls_connect_ev,
137
SSL_get_fd(tls_client->ssl), SUDO_EV_READ,
138
tls_connect_cb, tls_client) == -1) {
139
sudo_warnx("%s", U_("unable to set event"));
140
goto bad;
141
}
142
}
143
if (sudo_ev_add(evbase, tls_client->tls_connect_ev, timeout, false) == -1) {
144
sudo_warnx("%s", U_("unable to add event to queue"));
145
goto bad;
146
}
147
break;
148
case SSL_ERROR_WANT_WRITE:
149
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
150
"SSL_connect returns SSL_ERROR_WANT_WRITE");
151
if (what != SUDO_EV_WRITE) {
152
if (sudo_ev_set(tls_client->tls_connect_ev,
153
SSL_get_fd(tls_client->ssl), SUDO_EV_WRITE,
154
tls_connect_cb, tls_client) == -1) {
155
sudo_warnx("%s", U_("unable to set event"));
156
goto bad;
157
}
158
}
159
if (sudo_ev_add(evbase, tls_client->tls_connect_ev, timeout, false) == -1) {
160
sudo_warnx("%s", U_("unable to add event to queue"));
161
goto bad;
162
}
163
break;
164
case SSL_ERROR_SYSCALL:
165
sudo_warnx(U_("TLS connection failed: %s"), strerror(errno));
166
goto bad;
167
default:
168
errstr = ERR_reason_error_string(ERR_get_error());
169
sudo_warnx(U_("TLS connection failed: %s"),
170
errstr ? errstr : strerror(errno));
171
goto bad;
172
}
173
}
174
175
if (tls_client->tls_connect_state) {
176
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
177
"TLS version: %s, negotiated cipher suite: %s",
178
SSL_get_version(tls_client->ssl), SSL_get_cipher(tls_client->ssl));
179
180
/* Done with TLS connect, send ClientHello */
181
sudo_ev_free(tls_client->tls_connect_ev);
182
tls_client->tls_connect_ev = NULL;
183
if (!tls_client->start_fn(tls_client))
184
goto bad;
185
}
186
187
debug_return;
188
189
bad:
190
sudo_ev_loopbreak(evbase);
191
debug_return;
192
}
193
194
bool
195
tls_ctx_client_setup(SSL_CTX *ssl_ctx, int sock,
196
struct tls_client_closure *closure)
197
{
198
const char *errstr;
199
bool ret = false;
200
debug_decl(tls_ctx_client_setup, SUDO_DEBUG_UTIL);
201
202
if ((closure->ssl = SSL_new(ssl_ctx)) == NULL) {
203
errstr = ERR_reason_error_string(ERR_get_error());
204
sudo_warnx(U_("unable to allocate ssl object: %s"),
205
errstr ? errstr : strerror(errno));
206
goto done;
207
}
208
209
if (SSL_set_ex_data(closure->ssl, 1, closure->peer_name) <= 0) {
210
errstr = ERR_reason_error_string(ERR_get_error());
211
sudo_warnx(U_("Unable to attach user data to the ssl object: %s"),
212
errstr ? errstr : strerror(errno));
213
goto done;
214
}
215
216
if (SSL_set_fd(closure->ssl, sock) <= 0) {
217
errstr = ERR_reason_error_string(ERR_get_error());
218
sudo_warnx(U_("Unable to attach socket to the ssl object: %s"),
219
errstr ? errstr : strerror(errno));
220
goto done;
221
}
222
223
if (sudo_ev_add(closure->evbase, closure->tls_connect_ev, NULL, false) == -1) {
224
sudo_warnx("%s", U_("unable to add event to queue"));
225
goto done;
226
}
227
228
ret = true;
229
230
done:
231
debug_return_bool(ret);
232
}
233
234
bool
235
tls_client_setup(int sock, const char *ca_bundle_file, const char *cert_file,
236
const char *key_file, const char *dhparam_file, const char *ciphers_v12,
237
const char *ciphers_v13, bool verify_server, bool check_peer,
238
struct tls_client_closure *closure)
239
{
240
SSL_CTX *ssl_ctx;
241
debug_decl(tls_client_setup, SUDO_DEBUG_UTIL);
242
243
ssl_ctx = init_tls_context(ca_bundle_file, cert_file, key_file,
244
dhparam_file, ciphers_v12, ciphers_v13, verify_server);
245
if (ssl_ctx == NULL) {
246
sudo_warnx("%s", U_("unable to initialize TLS context"));
247
debug_return_bool(false);
248
}
249
250
if (check_peer) {
251
/* Verify server cert during the handshake. */
252
SSL_CTX_set_verify(ssl_ctx,
253
SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
254
verify_peer_identity);
255
}
256
257
debug_return_bool(tls_ctx_client_setup(ssl_ctx, sock, closure));
258
}
259
#endif /* HAVE_OPENSSL */
260
261