File: | programs/pluto/ipsec_doi.c |
Warning: | line 314, column 2 Value stored to 'ini' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * IPsec DOI and Oakley resolution routines |
3 | * |
4 | * Copyright (C) 1997 Angelos D. Keromytis. |
5 | * Copyright (C) 1998-2002,2010-2017 D. Hugh Redelmeier <hugh@mimosa.com> |
6 | * Copyright (C) 2003-2006 Michael Richardson <mcr@xelerance.com> |
7 | * Copyright (C) 2003-2011 Paul Wouters <paul@xelerance.com> |
8 | * Copyright (C) 2010-2011 Tuomo Soini <tis@foobar.fi> |
9 | * Copyright (C) 2009 Avesh Agarwal <avagarwa@redhat.com> |
10 | * Copyright (C) 2012-2018 Paul Wouters <pwouters@redhat.com> |
11 | * Copyright (C) 2013 David McCullough <ucdevel@gmail.com> |
12 | * Copyright (C) 2013 Matt Rogers <mrogers@redhat.com> |
13 | * Copyright (C) 2014-2019 Andrew Cagney <cagney@gnu.org> |
14 | * Copyright (C) 2017-2018 Antony Antony <antony@phenome.org> |
15 | * Copyright (C) 2017 Mayank Totale <mtotale@gmail.com> |
16 | * |
17 | * This program is free software; you can redistribute it and/or modify it |
18 | * under the terms of the GNU General Public License as published by the |
19 | * Free Software Foundation; either version 2 of the License, or (at your |
20 | * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>. |
21 | * |
22 | * This program is distributed in the hope that it will be useful, but |
23 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
24 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
25 | * for more details. |
26 | * |
27 | */ |
28 | |
29 | #include <stdio.h> |
30 | #include <string.h> |
31 | #include <stddef.h> |
32 | #include <stdlib.h> |
33 | #include <unistd.h> |
34 | #include <sys/socket.h> |
35 | #include <netinet/in.h> |
36 | #include <arpa/inet.h> |
37 | #include <resolv.h> |
38 | |
39 | #include "sysdep.h" |
40 | #include "constants.h" |
41 | #include "defs.h" |
42 | #include "state.h" |
43 | #include "id.h" |
44 | #include "x509.h" |
45 | #include "certs.h" |
46 | #include "connections.h" /* needs id.h */ |
47 | #include "packet.h" |
48 | #include "keys.h" |
49 | #include "demux.h" /* needs packet.h */ |
50 | #include "kernel.h" /* needs connections.h */ |
51 | #include "log.h" |
52 | #include "server.h" |
53 | #include "timer.h" |
54 | #include "rnd.h" |
55 | #include "ipsec_doi.h" /* needs demux.h and state.h */ |
56 | #include "ikev1_quick.h" |
57 | #include "whack.h" |
58 | #include "fetch.h" |
59 | #include "asn1.h" |
60 | #include "crypto.h" |
61 | #include "secrets.h" |
62 | #include "crypt_dh.h" |
63 | #include "ike_alg.h" |
64 | #include "ike_alg_integ.h" |
65 | #include "ike_alg_encrypt.h" |
66 | #include "kernel_alg.h" |
67 | #include "plutoalg.h" |
68 | #include "ikev1.h" |
69 | #include "ikev1_continuations.h" |
70 | #include "ikev2.h" |
71 | #include "ikev2_send.h" |
72 | #include "ikev1_xauth.h" |
73 | #include "ip_info.h" |
74 | #include "vendor.h" |
75 | #include "nat_traversal.h" |
76 | #include "ikev1_dpd.h" |
77 | #include "pluto_x509.h" |
78 | #include "ip_address.h" |
79 | #include "pluto_stats.h" |
80 | #include "chunk.h" |
81 | #include "pending.h" |
82 | #include "iface.h" |
83 | #include "ikev2_delete.h" /* for record_v2_delete(); but call is dying */ |
84 | #include "orient.h" |
85 | #include "initiate.h" |
86 | #include "ikev2_ike_sa_init.h" |
87 | |
88 | /* |
89 | * Start from policy in (ipsec) state, not connection. This ensures |
90 | * that rekeying doesn't downgrade security. I admit that this |
91 | * doesn't capture everything. |
92 | */ |
93 | lset_t capture_child_rekey_policy(struct state *st) |
94 | { |
95 | lset_t policy = st->st_policy; |
96 | |
97 | if (st->st_pfs_group != NULL((void*)0)) |
98 | policy |= POLICY_PFS((lset_t)1 << (POLICY_PFS_IX)); |
99 | if (st->st_ah.present) { |
100 | policy |= POLICY_AUTHENTICATE((lset_t)1 << (POLICY_AUTHENTICATE_IX)); |
101 | if (st->st_ah.attrs.mode == ENCAPSULATION_MODE_TUNNEL) |
102 | policy |= POLICY_TUNNEL((lset_t)1 << (POLICY_TUNNEL_IX)); |
103 | } |
104 | if (st->st_esp.present && |
105 | st->st_esp.attrs.transattrs.ta_encrypt != &ike_alg_encrypt_null) { |
106 | policy |= POLICY_ENCRYPT((lset_t)1 << (POLICY_ENCRYPT_IX)); |
107 | if (st->st_esp.attrs.mode == ENCAPSULATION_MODE_TUNNEL) |
108 | policy |= POLICY_TUNNEL((lset_t)1 << (POLICY_TUNNEL_IX)); |
109 | } |
110 | if (st->st_ipcomp.present) { |
111 | policy |= POLICY_COMPRESS((lset_t)1 << (POLICY_COMPRESS_IX)); |
112 | if (st->st_ipcomp.attrs.mode == ENCAPSULATION_MODE_TUNNEL) |
113 | policy |= POLICY_TUNNEL((lset_t)1 << (POLICY_TUNNEL_IX)); |
114 | } |
115 | |
116 | return policy; |
117 | } |
118 | |
119 | /* Replace SA with a fresh one that is similar |
120 | * |
121 | * Shares some logic with ipsecdoi_initiate, but not the same! |
122 | * - we must not reuse the ISAKMP SA if we are trying to replace it! |
123 | * - if trying to replace IPSEC SA, use ipsecdoi_initiate to build |
124 | * ISAKMP SA if needed. |
125 | * - duplicate whack fd, if live. |
126 | * Does not delete the old state -- someone else will do that. |
127 | */ |
128 | void ipsecdoi_replace(struct state *st, unsigned long try) |
129 | { |
130 | /* |
131 | * start billing the new state. The old state also gets |
132 | * billed for this function call, oops. |
133 | */ |
134 | threadtime_t inception = threadtime_start(); |
135 | |
136 | if (IS_IKE_SA(st)((st)->st_clonedfrom == 0)) { |
137 | /* start from policy in connection */ |
138 | |
139 | struct connection *c = st->st_connection; |
140 | |
141 | lset_t policy = c->policy & ~POLICY_IPSEC_MASK(((lset_t)1 << (POLICY_NOPMTUDISC_IX)) - ((lset_t)1 << (POLICY_ENCRYPT_IX)) + ((lset_t)1 << (POLICY_NOPMTUDISC_IX ))); |
142 | |
143 | switch(st->st_ike_versionst_connection->ike_version) { |
144 | case IKEv2: |
145 | if (IS_IKE_SA_ESTABLISHED(st)((st)->st_state->kind == STATE_V2_ESTABLISHED_IKE_SA)) |
146 | log_state(RC_LOG, st, "initiate reauthentication of IKE SA"); |
147 | ikev2_out_IKE_SA_INIT_I(c, st, policy, try, &inception, |
148 | HUNK_AS_SHUNK(c->spd.this.sec_label)({ typeof(c->spd.this.sec_label) h_ = (c->spd.this.sec_label ); shunk2(h_.ptr, h_.len); }), |
149 | /*background?*/false0, st->st_logger); |
150 | break; |
151 | #ifdef USE_IKEv11 |
152 | case IKEv1: |
153 | if (policy & POLICY_AGGRESSIVE((lset_t)1 << (POLICY_AGGRESSIVE_IX))) { |
154 | aggr_outI1(st->st_logger->object_whackfd, c, st, |
155 | policy, try, &inception, |
156 | HUNK_AS_SHUNK(c->spd.this.sec_label)({ typeof(c->spd.this.sec_label) h_ = (c->spd.this.sec_label ); shunk2(h_.ptr, h_.len); })); |
157 | } else { |
158 | main_outI1(st->st_logger->object_whackfd, c, st, |
159 | policy, try, &inception, |
160 | HUNK_AS_SHUNK(c->spd.this.sec_label)({ typeof(c->spd.this.sec_label) h_ = (c->spd.this.sec_label ); shunk2(h_.ptr, h_.len); })); |
161 | } |
162 | break; |
163 | #endif |
164 | default: |
165 | dbg("unsupported IKE version '%d', cannot initiate", st->st_ike_version){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unsupported IKE version '%d', cannot initiate" , st->st_connection->ike_version); } }; |
166 | } |
167 | } else { |
168 | |
169 | /* |
170 | * Start from policy in (ipsec) state, not connection. |
171 | * This ensures that rekeying doesn't downgrade |
172 | * security. I admit that this doesn't capture |
173 | * everything. |
174 | */ |
175 | lset_t policy = capture_child_rekey_policy(st); |
176 | |
177 | if (st->st_ike_versionst_connection->ike_version == IKEv1) |
178 | passert(HAS_IPSEC_POLICY(policy))({ _Bool assertion__ = (((policy) & (((lset_t)1 << ( POLICY_NOPMTUDISC_IX)) - ((lset_t)1 << (POLICY_ENCRYPT_IX )) + ((lset_t)1 << (POLICY_NOPMTUDISC_IX)))) != 0); if ( !assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ipsec_doi.c", . line = 178, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_passert(logger_, here, "%s", "(((policy) & (((lset_t)1 << (POLICY_NOPMTUDISC_IX)) - ((lset_t)1 << (POLICY_ENCRYPT_IX)) + ((lset_t)1 << (POLICY_NOPMTUDISC_IX)))) != 0)" ); } (void) 1; }); |
179 | |
180 | ipsecdoi_initiate(st->st_connection, policy, try, st->st_serialno, &inception, |
181 | null_shunk, /*background?*/false0, st->st_logger); |
182 | } |
183 | } |
184 | |
185 | /* |
186 | * look for the existence of a non-expiring preloaded public key |
187 | */ |
188 | bool_Bool has_preloaded_public_key(const struct state *st) |
189 | { |
190 | const struct connection *c = st->st_connection; |
191 | |
192 | /* do not consider rw connections since |
193 | * the peer's identity must be known |
194 | */ |
195 | if (c->kind == CK_PERMANENT) { |
196 | /* look for a matching RSA public key */ |
197 | for (const struct pubkey_list *p = pluto_pubkeys; p != NULL((void*)0); |
198 | p = p->next) { |
199 | const struct pubkey *key = p->key; |
200 | |
201 | if (key->type == &pubkey_type_rsa && |
202 | same_id(&c->spd.that.id, &key->id) && |
203 | is_realtime_epoch(key->until_time)) { |
204 | /* found a preloaded public key */ |
205 | return true1; |
206 | } |
207 | } |
208 | } |
209 | return false0; |
210 | } |
211 | |
212 | void initialize_new_state(struct state *st, |
213 | lset_t policy, |
214 | int try) |
215 | { |
216 | /* |
217 | * reset our choice of interface |
218 | * |
219 | * XXX: why? suspect this has the side effect of restoring / |
220 | * updating connection's ends? |
221 | */ |
222 | struct connection *c = st->st_connection; |
223 | pexpect(oriented(c))({ _Bool assertion__ = oriented(c); if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ipsec_doi.c", .line = 223, }; & here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "oriented(c)"); } assertion__ ; }); |
224 | c->interface = NULL((void*)0); |
225 | orient(c, st->st_logger); |
226 | st->st_interface = c->interface; |
227 | passert(st->st_interface != NULL)({ _Bool assertion__ = st->st_interface != ((void*)0); if ( !assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ipsec_doi.c", . line = 227, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_passert(logger_, here, "%s", "st->st_interface != ((void*)0)" ); } (void) 1; }); |
228 | st->st_remote_endpoint = endpoint_from_address_protocol_port(c->spd.that.host_addr, |
229 | c->interface->protocol, |
230 | ip_hport(c->spd.that.host_port)); |
231 | endpoint_buf eb; |
232 | dbg("in %s with remote endpoint set to %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("in %s with remote endpoint set to %s", __func__ , str_endpoint(&st->st_remote_endpoint, &eb)); } } |
233 | __func__, str_endpoint(&st->st_remote_endpoint, &eb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("in %s with remote endpoint set to %s", __func__ , str_endpoint(&st->st_remote_endpoint, &eb)); } }; |
234 | |
235 | st->st_policy = policy & ~POLICY_IPSEC_MASK(((lset_t)1 << (POLICY_NOPMTUDISC_IX)) - ((lset_t)1 << (POLICY_ENCRYPT_IX)) + ((lset_t)1 << (POLICY_NOPMTUDISC_IX ))); /* clear bits */ |
236 | st->st_try = try; |
237 | |
238 | for (const struct spd_route *sr = &c->spd; |
239 | sr != NULL((void*)0); sr = sr->spd_next) { |
240 | if (sr->this.xauth_client) { |
241 | if (sr->this.xauth_username != NULL((void*)0)) { |
242 | jam_str(st->st_xauth_username, sizeof(st->st_xauth_username), sr->this.xauth_username); |
243 | break; |
244 | } |
245 | } |
246 | } |
247 | |
248 | binlog_refresh_state(st)binlog_state((st), (st)->st_state->kind); |
249 | } |
250 | |
251 | void jam_child_sa_details(struct jambuf *buf, struct state *st) |
252 | { |
253 | struct connection *const c = st->st_connection; |
254 | const char *ini = "{"; |
255 | |
256 | if (st->st_esp.present) { |
257 | bool_Bool nat = (st->hidden_variables.st_nat_traversal & NAT_T_DETECTED( ((lset_t)1 << (NATED_HOST)) | ((lset_t)1 << (NATED_PEER )) )) != 0; |
258 | bool_Bool tfc = c->sa_tfcpad != 0 && !st->st_seen_no_tfc; |
259 | bool_Bool esn = st->st_esp.attrs.transattrs.esn_enabled; |
260 | bool_Bool tcp = st->st_interface->protocol == &ip_protocol_tcpip_protocols[IPPROTO_TCP]; |
261 | |
262 | if (nat) |
263 | dbg("NAT-T: NAT Traversal detected - their IKE port is '%d'",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T: NAT Traversal detected - their IKE port is '%d'" , c->spd.that.host_port); } } |
264 | c->spd.that.host_port){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T: NAT Traversal detected - their IKE port is '%d'" , c->spd.that.host_port); } }; |
265 | |
266 | dbg("NAT-T: encaps is '%s'",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T: encaps is '%s'", c->encaps == yna_auto ? "auto" : bool_str(c->encaps == yna_yes)); } } |
267 | c->encaps == yna_auto ? "auto" : bool_str(c->encaps == yna_yes)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T: encaps is '%s'", c->encaps == yna_auto ? "auto" : bool_str(c->encaps == yna_yes)); } }; |
268 | |
269 | jam(buf, "%sESP%s%s%s=>0x%08" PRIx32"x" " <0x%08" PRIx32"x" "", |
270 | ini, |
271 | tcp ? "inTCP" : nat ? "inUDP" : "", |
272 | esn ? "/ESN" : "", |
273 | tfc ? "/TFC" : "", |
274 | ntohl(st->st_esp.attrs.spi), |
275 | ntohl(st->st_esp.our_spi)); |
276 | jam(buf, " xfrm=%s", st->st_esp.attrs.transattrs.ta_encrypt->common.fqn); |
277 | /* log keylen when it is required and/or "interesting" */ |
278 | if (!st->st_esp.attrs.transattrs.ta_encrypt->keylen_omitted || |
279 | (st->st_esp.attrs.transattrs.enckeylen != 0 && |
280 | st->st_esp.attrs.transattrs.enckeylen != st->st_esp.attrs.transattrs.ta_encrypt->keydeflen)) { |
281 | jam(buf, "_%u", st->st_esp.attrs.transattrs.enckeylen); |
282 | } |
283 | jam(buf, "-%s", st->st_esp.attrs.transattrs.ta_integ->common.fqn); |
284 | |
285 | if ((st->st_ike_versionst_connection->ike_version == IKEv2) && st->st_pfs_group != NULL((void*)0)) { |
286 | jam_string(buf, "-"); |
287 | jam_string(buf, st->st_pfs_group->common.fqn); |
288 | } |
289 | |
290 | ini = " "; |
291 | } |
292 | |
293 | if (st->st_ah.present) { |
294 | jam(buf, "%sAH%s=>0x%08" PRIx32"x" " <0x%08" PRIx32"x" " xfrm=%s", |
295 | ini, |
296 | st->st_ah.attrs.transattrs.esn_enabled ? "/ESN" : "", |
297 | ntohl(st->st_ah.attrs.spi), |
298 | ntohl(st->st_ah.our_spi), |
299 | st->st_ah.attrs.transattrs.ta_integ->common.fqn); |
300 | |
301 | ini = " "; |
302 | } |
303 | |
304 | if (st->st_ipcomp.present) { |
305 | jam(buf, "%sIPCOMP=>0x%08" PRIx32"x" " <0x%08" PRIx32"x", |
306 | ini, |
307 | ntohl(st->st_ipcomp.attrs.spi), |
308 | ntohl(st->st_ipcomp.our_spi)); |
309 | |
310 | ini = " "; |
311 | } |
312 | |
313 | jam_string(buf, ini); |
314 | ini = " "; |
Value stored to 'ini' is never read | |
315 | jam_string(buf, "NATOA="); |
316 | /* XXX: can lswlog_ip() be used? */ |
317 | ipstr_buf ipb; |
318 | jam_string(buf, |
319 | (address_is_unset(&st->hidden_variables.st_nat_oa) || |
320 | address_is_any(st->hidden_variables.st_nat_oa)) ? "none" : |
321 | ipstr(&st->hidden_variables.st_nat_oa, &ipb)); |
322 | |
323 | jam_string(buf, " NATD="); |
324 | |
325 | if (address_is_unset(&st->hidden_variables.st_natd) || |
326 | address_is_any(st->hidden_variables.st_natd)) { |
327 | jam_string(buf, "none"); |
328 | } else { |
329 | /* XXX: can lswlog_ip() be used? need to check st_remoteport */ |
330 | jam(buf, "%s:%d", |
331 | str_address_sensitive(&st->hidden_variables.st_natd, &ipb), |
332 | endpoint_hport(st->st_remote_endpoint)); |
333 | } |
334 | |
335 | jam(buf, (st->st_ike_versionst_connection->ike_version == IKEv1 && !st->hidden_variables.st_peer_supports_dpd) ? " DPD=unsupported" : |
336 | dpd_active_locally(st) ? " DPD=active" : " DPD=passive"); |
337 | |
338 | if (st->st_xauth_username[0] != '\0') { |
339 | jam_string(buf, " username="); |
340 | jam_string(buf, st->st_xauth_username); |
341 | } |
342 | |
343 | jam_string(buf, "}"); |
344 | } |
345 | |
346 | void jam_parent_sa_details(struct jambuf *buf, struct state *st) |
347 | { |
348 | passert(st->st_oakley.ta_encrypt != NULL)({ _Bool assertion__ = st->st_oakley.ta_encrypt != ((void* )0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ipsec_doi.c" , .line = 348, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "st->st_oakley.ta_encrypt != ((void*)0)" ); } (void) 1; }); |
349 | passert(st->st_oakley.ta_prf != NULL)({ _Bool assertion__ = st->st_oakley.ta_prf != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ipsec_doi.c" , .line = 349, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "st->st_oakley.ta_prf != ((void*)0)" ); } (void) 1; }); |
350 | passert(st->st_oakley.ta_dh != NULL)({ _Bool assertion__ = st->st_oakley.ta_dh != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ipsec_doi.c" , .line = 350, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "st->st_oakley.ta_dh != ((void*)0)" ); } (void) 1; }); |
351 | |
352 | jam_string(buf, "{"); |
353 | |
354 | if (st->st_ike_versionst_connection->ike_version == IKEv1) { |
355 | jam(buf, "auth="); |
356 | jam_enum_short(buf, &oakley_auth_names, st->st_oakley.auth); |
357 | jam(buf, " "); |
358 | } |
359 | |
360 | jam(buf, "cipher=%s", st->st_oakley.ta_encrypt->common.fqn); |
361 | if (st->st_oakley.enckeylen > 0) { |
362 | /* XXX: also check omit key? */ |
363 | jam(buf, "_%d", st->st_oakley.enckeylen); |
364 | } |
365 | |
366 | /* |
367 | * Note: for IKEv1 and AEAD encrypters, |
368 | * st->st_oakley.ta_integ is 'none'! |
369 | */ |
370 | jam_string(buf, " integ="); |
371 | if (st->st_ike_versionst_connection->ike_version == IKEv2) { |
372 | if (st->st_oakley.ta_integ == &ike_alg_integ_none) { |
373 | jam_string(buf, "n/a"); |
374 | } else { |
375 | jam_string(buf, st->st_oakley.ta_integ->common.fqn); |
376 | } |
377 | } else { |
378 | /* |
379 | * For IKEv1, since the INTEG algorithm is potentially |
380 | * (always?) NULL. Display the PRF. The choice and |
381 | * behaviour are historic. |
382 | */ |
383 | jam_string(buf, st->st_oakley.ta_prf->common.fqn); |
384 | } |
385 | |
386 | if (st->st_ike_versionst_connection->ike_version == IKEv2) { |
387 | jam(buf, " prf=%s", st->st_oakley.ta_prf->common.fqn); |
388 | } |
389 | |
390 | jam(buf, " group=%s}", st->st_oakley.ta_dh->common.fqn); |
391 | } |