-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathintercept_config.c
164 lines (152 loc) · 6.89 KB
/
intercept_config.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
* ratched - TLS connection router that performs a man-in-the-middle attack
* Copyright (C) 2017-2017 Johannes Bauer
*
* This file is part of ratched.
*
* ratched is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; this program is ONLY licensed under
* version 3 of the License, later versions are explicitly excluded.
*
* ratched is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ratched; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Johannes Bauer <[email protected]>
**/
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "intercept_config.h"
#include "logging.h"
#include "keyvaluelist.h"
#include "parse.h"
const char *interception_mode_to_str(enum interception_mode_t value) {
switch (value) {
case INTERCEPTION_MODE_UNDEFINED: return "INTERCEPTION_MODE_UNDEFINED";
case OPPORTUNISTIC_TLS_INTERCEPTION: return "OPPORTUNISTIC_TLS_INTERCEPTION";
case MANDATORY_TLS_INTERCEPTION: return "MANDATORY_TLS_INTERCEPTION";
case TRAFFIC_FORWARDING: return "TRAFFIC_FORWARDING";
case REJECT_CONNECTION: return "REJECT_CONNECTION";
}
return "?";
}
static bool side_plausibility_check(const char *hostname, const char *sidename, const struct intercept_side_config_t *side) {
if ((side->cert_filename == NULL) ^ (side->key_filename == NULL)) {
logmsg(LLVL_ERROR, "%s: When specifying a %s certificate, you also need to specify a corresponding private key.", hostname, sidename);
return false;
}
if ((side->cert_filename == NULL) && (side->chain_filename)) {
logmsg(LLVL_WARN, "%s: Specifying a %s certificate chain file without specifying a %s certificate does not make sense.", hostname, sidename, sidename);
return false;
}
return true;
}
struct intercept_config_t* intercept_config_new(const char *connection_params, bool contains_hostname) {
struct intercept_config_t *config = calloc(1, sizeof(struct intercept_config_t));
if (!config) {
logmsg(LLVL_FATAL, "Cannot calloc(3) intercept_config_t: %s", strerror(errno));
return NULL;
}
/* Defaults */
config->server.ocsp_status = true;
const struct lookup_entry_t intercept_options[] = {
{ "o", OPPORTUNISTIC_TLS_INTERCEPTION },
{ "oti", OPPORTUNISTIC_TLS_INTERCEPTION },
{ "opportunistic", OPPORTUNISTIC_TLS_INTERCEPTION },
{ "m", MANDATORY_TLS_INTERCEPTION },
{ "mti", MANDATORY_TLS_INTERCEPTION },
{ "mandatory", MANDATORY_TLS_INTERCEPTION },
{ "fwd", TRAFFIC_FORWARDING },
{ "forward", TRAFFIC_FORWARDING },
{ "reject", REJECT_CONNECTION },
{ "no", REJECT_CONNECTION },
{ "none", REJECT_CONNECTION },
{ 0 }
};
const struct lookup_entry_t tls_version_flags[] = {
{ "ssl2", TLS_VERSION_SSL2 },
{ "ssl3", TLS_VERSION_SSL3 },
{ "tls10", TLS_VERSION_TLS10 },
{ "tls11", TLS_VERSION_TLS11 },
{ "tls12", TLS_VERSION_TLS12 },
{ "tls13", TLS_VERSION_TLS13 },
{ 0 }
};
struct keyvaluelist_def_t definition[] = {
{ .key = "intercept", .parser = keyvalue_lookup, .target = &config->interception_mode, .argument = (void*)&intercept_options },
{ .key = "s_tlsversions", .parser = keyvalue_flags, .target = &config->server.tls_versions, .argument = (void*)&tls_version_flags },
{ .key = "s_reqclientcert", .parser = keyvalue_bool, .target = &config->server.request_client_cert },
{ .key = "s_send_rot", .parser = keyvalue_bool, .target = &config->server.include_root_ca_cert },
{ .key = "s_certfile", .parser = keyvalue_string, .target = &config->server.cert_filename },
{ .key = "s_keyfile", .parser = keyvalue_string, .target = &config->server.key_filename },
{ .key = "s_chainfile", .parser = keyvalue_string, .target = &config->server.chain_filename },
{ .key = "s_cacert", .parser = keyvalue_string, .target = &config->server.ca_cert_filename },
{ .key = "s_cakey", .parser = keyvalue_string, .target = &config->server.ca_key_filename },
{ .key = "s_ciphers", .parser = keyvalue_string, .target = &config->server.ciphersuites },
{ .key = "s_groups", .parser = keyvalue_string, .target = &config->server.supported_groups },
{ .key = "s_sigalgs", .parser = keyvalue_string, .target = &config->server.signature_algorithms },
{ .key = "s_ocsp", .parser = keyvalue_bool, .target = &config->server.ocsp_status },
{ .key = "c_tlsversions", .parser = keyvalue_flags, .target = &config->client.tls_versions, .argument = (void*)&tls_version_flags },
{ .key = "c_certfile", .parser = keyvalue_string, .target = &config->client.cert_filename },
{ .key = "c_keyfile", .parser = keyvalue_string, .target = &config->client.key_filename },
{ .key = "c_chainfile", .parser = keyvalue_string, .target = &config->client.chain_filename },
{ .key = "c_ciphers", .parser = keyvalue_string, .target = &config->client.ciphersuites },
{ .key = "c_groups", .parser = keyvalue_string, .target = &config->client.supported_groups },
{ .key = "c_sigalgs", .parser = keyvalue_string, .target = &config->client.signature_algorithms },
{ 0 }
};
if (parse_keyvalue_list(connection_params, contains_hostname ? 1 : 0, definition, &config->hostname) == -1) {
intercept_config_free(config);
return NULL;
}
if (contains_hostname) {
/* Try to also parse as an IP entry */
parse_ipv4(config->hostname, &config->ipv4_nbo);
}
if (!side_plausibility_check(contains_hostname ? config->hostname : "default config", "server", &config->server)) {
intercept_config_free(config);
return NULL;
}
if (!side_plausibility_check(contains_hostname ? config->hostname : "default config", "client", &config->client)) {
intercept_config_free(config);
return NULL;
}
if (config->client.cert_filename) {
/* Having a CertificateRequest is implied when using a client
* certificate */
if (!config->server.request_client_cert) {
logmsg(LLVL_DEBUG, "%s: Provided a client certificate -> CertificateRequest message on server side is implied.", contains_hostname ? config->hostname : "default config");
}
config->server.request_client_cert = true;
}
return config;
}
static void intercept_side_config_free(struct intercept_side_config_t *side) {
free(side->cert_filename);
free(side->key_filename);
free(side->chain_filename);
free(side->ca_cert_filename);
free(side->ca_key_filename);
free(side->ciphersuites);
free(side->supported_groups);
memset(side, 0, sizeof(struct intercept_side_config_t));
}
void intercept_config_free(struct intercept_config_t *config) {
if (!config) {
return;
}
free(config->hostname);
intercept_side_config_free(&config->server);
intercept_side_config_free(&config->client);
free(config);
}