File: | programs/pluto/ikev1_spdb_struct.c |
Warning: | line 145, column 7 Null pointer passed as an argument to a 'nonnull' parameter |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Security Policy Data Base (such as it is) | |||
2 | * | |||
3 | * Copyright (C) 1998-2001,2013 D. Hugh Redelmeier <hugh@mimosa.com> | |||
4 | * Copyright (C) 2012-2013 Paul Wouters <paul@libreswan.org> | |||
5 | * Copyright (C) 2012 Avesh Agarwal <avagarwa@redhat.com> | |||
6 | * Copyright (C) 2013 Matt Rogers <mrogers@redhat.com> | |||
7 | * Copyright (C) 2016-2019 Andrew Cagney <cagney@gnu.org> | |||
8 | * Copyright (C) 2019 Paul Wouters <pwouters@redhat.com> | |||
9 | * | |||
10 | * This program is free software; you can redistribute it and/or modify it | |||
11 | * under the terms of the GNU General Public License as published by the | |||
12 | * Free Software Foundation; either version 2 of the License, or (at your | |||
13 | * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>. | |||
14 | * | |||
15 | * This program is distributed in the hope that it will be useful, but | |||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |||
17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
18 | * for more details. | |||
19 | */ | |||
20 | ||||
21 | #include <stdio.h> | |||
22 | #include <string.h> | |||
23 | #include <stdlib.h> | |||
24 | #include <sys/socket.h> | |||
25 | #include <netinet/in.h> | |||
26 | #include <arpa/inet.h> | |||
27 | ||||
28 | #include "sysdep.h" | |||
29 | #include "constants.h" | |||
30 | ||||
31 | #include "defs.h" | |||
32 | #include "id.h" | |||
33 | #include "x509.h" | |||
34 | #include "certs.h" | |||
35 | #include "connections.h" /* needs id.h */ | |||
36 | #include "state.h" | |||
37 | #include "packet.h" | |||
38 | #include "keys.h" | |||
39 | #include "kernel.h" /* needs connections.h */ | |||
40 | #include "log.h" | |||
41 | #include "spdb.h" | |||
42 | #include "whack.h" /* for RC_LOG_SERIOUS */ | |||
43 | #include "plutoalg.h" | |||
44 | #include "crypto.h" | |||
45 | ||||
46 | #include "ikev1.h" | |||
47 | #include "kernel_alg.h" | |||
48 | #include "ike_alg.h" | |||
49 | #include "ike_alg_encrypt.h" | |||
50 | #include "ike_alg_integ.h" | |||
51 | #include "db_ops.h" | |||
52 | #include "lswfips.h" /* for libreswan_fipsmode */ | |||
53 | #include "crypt_prf.h" | |||
54 | #include "ikev1_message.h" | |||
55 | #include "ip_endpoint.h" | |||
56 | #include "nat_traversal.h" | |||
57 | ||||
58 | ||||
59 | #ifndef HAVE_LABELED_IPSEC1 | |||
60 | static bool_Bool parse_secctx_attr(pb_stream *pbs UNUSED__attribute__ ((unused)), struct state *st UNUSED__attribute__ ((unused))) | |||
61 | { | |||
62 | /* | |||
63 | * We received a security label but don't support it, | |||
64 | * so fail the IKE negotiation | |||
65 | */ | |||
66 | loglog(RC_LOG_SERIOUS, "Received Sec Ctx Textual Label but support for labeled ipsec not compiled in"); | |||
67 | return FALSE0; | |||
68 | } | |||
69 | #else | |||
70 | #include "security_selinux.h" | |||
71 | static bool_Bool parse_secctx_attr(pb_stream *pbs, struct state *st) | |||
72 | { | |||
73 | struct xfrm_user_sec_ctx_ike uctx; | |||
74 | ||||
75 | if (!in_struct(&uctx.ctx, &sec_ctx_desc, pbs, NULL((void*)0))) | |||
76 | return FALSE0; | |||
77 | ||||
78 | if (pbs_left(pbs)((size_t)((pbs)->roof - (pbs)->cur)) != uctx.ctx.ctx_len) { | |||
79 | /* ??? should we ignore padding? */ | |||
80 | loglog(RC_LOG_SERIOUS, "Sec Ctx Textual Label length mismatch (length=%u; packet space = %u)", | |||
81 | uctx.ctx.ctx_len, (unsigned)pbs_left(pbs)((size_t)((pbs)->roof - (pbs)->cur))); | |||
82 | return FALSE0; | |||
83 | } | |||
84 | ||||
85 | if (uctx.ctx.ctx_len > MAX_SECCTX_LEN4096) { | |||
86 | loglog(RC_LOG_SERIOUS, "Sec Ctx Textual Label too long (%u > %u)", | |||
87 | uctx.ctx.ctx_len, MAX_SECCTX_LEN4096); | |||
88 | return FALSE0; | |||
89 | } | |||
90 | ||||
91 | zero(&uctx.sec_ctx_value)memset((&uctx.sec_ctx_value), '\0', sizeof(*(&uctx.sec_ctx_value ))); /* abundance of caution */ | |||
92 | ||||
93 | if (!in_raw(uctx.sec_ctx_value, uctx.ctx.ctx_len, pbs, | |||
94 | "Sec Ctx Textual Label")) | |||
95 | return FALSE0; | |||
96 | ||||
97 | /* | |||
98 | * The label should have been NUL-terminated. | |||
99 | * We will generously add one if it is missing and there is room. | |||
100 | */ | |||
101 | if (uctx.ctx.ctx_len == 0 || | |||
102 | uctx.sec_ctx_value[uctx.ctx.ctx_len - 1] != '\0') { | |||
103 | if (uctx.ctx.ctx_len == MAX_SECCTX_LEN4096) { | |||
104 | loglog(RC_LOG_SERIOUS, "Sec Ctx Textual Label missing terminal NUL and there is no space to add it"); | |||
105 | return FALSE0; | |||
106 | } | |||
107 | DBG_log("Sec Ctx Textual Label missing terminal NUL; we are adding it"); | |||
108 | uctx.sec_ctx_value[uctx.ctx.ctx_len] = '\0'; | |||
109 | uctx.ctx.ctx_len++; | |||
110 | } | |||
111 | ||||
112 | if (strlen(uctx.sec_ctx_value) + 1 != uctx.ctx.ctx_len) { | |||
113 | loglog(RC_LOG_SERIOUS, "Error: Sec Ctx Textual Label contains embedded NUL"); | |||
114 | return FALSE0; | |||
115 | } | |||
116 | ||||
117 | if (st->sec_ctx == NULL((void*)0) && st->st_state->kind == STATE_QUICK_R0) { | |||
118 | DBG_log("Received sec ctx in responder state"); | |||
119 | ||||
120 | /* | |||
121 | * verify that the received security label is | |||
122 | * within range of this connection's policy's security label | |||
123 | */ | |||
124 | if (st->st_connection->policy_label == NULL((void*)0)) { | |||
125 | loglog(RC_LOG_SERIOUS, "This state (connection) is not labeled ipsec enabled, so cannot proceed"); | |||
126 | return FALSE0; | |||
127 | } else if (within_range(uctx.sec_ctx_value, | |||
128 | st->st_connection->policy_label)) { | |||
129 | DBG_log("security context verification succeeded"); | |||
130 | } else { | |||
131 | loglog(RC_LOG_SERIOUS, "security context verification failed"); | |||
132 | return FALSE0; | |||
133 | } | |||
134 | /* | |||
135 | * Note: this clones the whole of uctx.sec_ctx_value. | |||
136 | * It would be reasonable to clone only the part that's used. | |||
137 | */ | |||
138 | st->sec_ctx = clone_thing(uctx, "struct xfrm_user_sec_ctx_ike")((__typeof__(&(uctx))) clone_bytes((const void *)&(uctx ), sizeof(uctx), ("struct xfrm_user_sec_ctx_ike"))); | |||
139 | } else if (st->st_state->kind == STATE_QUICK_R0) { | |||
140 | /* ??? can this happen? */ | |||
141 | /* ??? should we check that this label and first one match? */ | |||
142 | DBG_log("Received sec ctx in responder state again: ignoring this one"); | |||
143 | } else if (st->st_state->kind == STATE_QUICK_I1) { | |||
144 | dbg("initiator state received security context from responder state, now verifying if both are same"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("initiator state received security context from responder state, now verifying if both are same" ); } }; | |||
145 | if (streq(st->sec_ctx->sec_ctx_value, uctx.sec_ctx_value)(strcmp((st->sec_ctx->sec_ctx_value), (uctx.sec_ctx_value )) == 0)) { | |||
| ||||
146 | DBG_log("security contexts are verified in the initiator state"); | |||
147 | } else { | |||
148 | loglog(RC_LOG_SERIOUS, "security context verification failed in the initiator state (shouldn't reach here unless responder (or something in between) is modifying the security context"); | |||
149 | return FALSE0; | |||
150 | } | |||
151 | } | |||
152 | return TRUE1; | |||
153 | } | |||
154 | #endif | |||
155 | ||||
156 | /** output an attribute (within an SA) */ | |||
157 | /* Note: ikev2_out_attr is a clone, with the same bugs */ | |||
158 | static bool_Bool out_attr(int type, | |||
159 | unsigned long val, | |||
160 | struct_desc *attr_desc, | |||
161 | enum_names *const *attr_val_descs, | |||
162 | pb_stream *pbs) | |||
163 | { | |||
164 | if (val >> 16 == 0) { | |||
165 | /* short value: use TV form */ | |||
166 | struct isakmp_attribute attr = { | |||
167 | .isaat_af_type = type | ISAKMP_ATTR_AF_TV0x8000, | |||
168 | .isaat_lv = val, | |||
169 | }; | |||
170 | if (!out_struct(&attr, attr_desc, pbs, NULL((void*)0))) | |||
171 | return FALSE0; | |||
172 | } else { | |||
173 | /* This is a real fudge! Since we rarely use long attributes | |||
174 | * and since this is the only place where we can cause an | |||
175 | * ISAKMP message length to be other than a multiple of 4 octets, | |||
176 | * we force the length of the value to be a multiple of 4 octets. | |||
177 | * Furthermore, we only handle values up to 4 octets in length. | |||
178 | * Voila: a fixed format! | |||
179 | */ | |||
180 | pb_stream val_pbs; | |||
181 | uint32_t nval = htonl(val); | |||
182 | ||||
183 | passert((type & ISAKMP_ATTR_AF_MASK) == 0){ _Bool assertion__ = (type & 0x8000) == 0; if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 183}, "%s", "(type & ISAKMP_ATTR_AF_MASK) == 0" ); } }; | |||
184 | struct isakmp_attribute attr = { | |||
185 | .isaat_af_type = type | ISAKMP_ATTR_AF_TLV0, | |||
186 | .isaat_lv = sizeof(nval), | |||
187 | }; | |||
188 | if (!out_struct(&attr, attr_desc, pbs, &val_pbs) || | |||
189 | !out_raw(&nval, sizeof(nval), &val_pbs, | |||
190 | "long attribute value")) | |||
191 | return FALSE0; | |||
192 | ||||
193 | close_output_pbs(&val_pbs); | |||
194 | } | |||
195 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
196 | enum_names *d = attr_val_descs[type]; | |||
197 | if (d != NULL((void*)0)) | |||
198 | DBG_log(" [%lu is %s]", | |||
199 | val, enum_show(d, val)); | |||
200 | } | |||
201 | return TRUE1; | |||
202 | } | |||
203 | ||||
204 | /* | |||
205 | * Determine if the proposal is acceptable (or need to keep looking). | |||
206 | * | |||
207 | * As a rule, this doesn't log - instead it assumes things were | |||
208 | * reported earlier. | |||
209 | */ | |||
210 | ||||
211 | static bool_Bool ikev1_verify_esp(const struct connection *c, | |||
212 | const struct trans_attrs *ta, | |||
213 | struct logger *logger) | |||
214 | { | |||
215 | if (!(c->policy & POLICY_ENCRYPT((lset_t)1 << (POLICY_ENCRYPT_IX)))) { | |||
216 | dbg("ignoring ESP proposal as POLICY_ENCRYPT unset"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal as POLICY_ENCRYPT unset" ); } }; | |||
217 | return false0; /* try another */ | |||
218 | } | |||
219 | ||||
220 | /* | |||
221 | * Check encryption. | |||
222 | * | |||
223 | * For the key-length, its assumed that the caller checked for | |||
224 | * and patched up either a missing or zero key-length, setting | |||
225 | * .enckeylen to the correct value (which might still be 0). | |||
226 | */ | |||
227 | if (ta->ta_encrypt == NULL((void*)0)) { | |||
228 | /* | |||
229 | * No encryption. Either because its lookup failed or | |||
230 | * because it was NULLed to force the proposal's | |||
231 | * rejection. | |||
232 | */ | |||
233 | dbg({ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal with NULLed or unknown encryption" ); } } | |||
234 | "ignoring ESP proposal with NULLed or unknown encryption"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal with NULLed or unknown encryption" ); } }; | |||
235 | return false0; /* try another */ | |||
236 | } | |||
237 | if (!kernel_alg_encrypt_ok(ta->ta_encrypt)) { | |||
238 | /* | |||
239 | * No kernel support. Needed because ALG_INFO==NULL | |||
240 | * will act as a wild card. XXX: but is ALG_INFO ever | |||
241 | * NULL? | |||
242 | */ | |||
243 | dbg("ignoring ESP proposal with alg %s not present in kernel",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal with alg %s not present in kernel" , ta->ta_encrypt->common.fqn); } } | |||
244 | ta->ta_encrypt->common.fqn){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal with alg %s not present in kernel" , ta->ta_encrypt->common.fqn); } }; | |||
245 | return false0; | |||
246 | } | |||
247 | if (!encrypt_has_key_bit_length(ta->ta_encrypt, ta->enckeylen)) { | |||
248 | loglog(RC_LOG_SERIOUS, | |||
249 | "kernel algorithm does not like: %s key_len %u is incorrect", | |||
250 | ta->ta_encrypt->common.fqn, ta->enckeylen); | |||
251 | endpoint_buf epb; | |||
252 | loglog(RC_LOG_SERIOUS, | |||
253 | "unsupported ESP Transform %s from %s", | |||
254 | ta->ta_encrypt->common.fqn, | |||
255 | str_sensitive_endpoint(&c->spd.that.host_addr, &epb)); | |||
256 | return false0; /* try another */ | |||
257 | } | |||
258 | ||||
259 | /* | |||
260 | * Check integrity. | |||
261 | */ | |||
262 | if (ta->ta_integ == NULL((void*)0)) { | |||
263 | /* | |||
264 | * No integrity. Since, for ESP, when integrity is | |||
265 | * missing, it is forced to .ta_integ=NONE (i.e., not | |||
266 | * NULL), a NULL here must indicate that integrity was | |||
267 | * present but the lookup failed. | |||
268 | */ | |||
269 | dbg("ignoring ESP proposal with unknown integrity"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal with unknown integrity" ); } }; | |||
270 | return false0; /* try another */ | |||
271 | } | |||
272 | if (ta->ta_integ != &ike_alg_integ_none && !kernel_alg_integ_ok(ta->ta_integ)) { | |||
273 | /* | |||
274 | * No kernel support. Needed because ALG_INFO==NULL | |||
275 | * will act as a wild card. | |||
276 | * | |||
277 | * XXX: but is ALG_INFO ever NULL? | |||
278 | * | |||
279 | * XXX: check for NONE comes from old code just | |||
280 | * assumed NONE was supported. | |||
281 | */ | |||
282 | dbg("ignoring ESP proposal with alg %s not present in kernel",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal with alg %s not present in kernel" , ta->ta_integ->common.fqn); } } | |||
283 | ta->ta_integ->common.fqn){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring ESP proposal with alg %s not present in kernel" , ta->ta_integ->common.fqn); } }; | |||
284 | return false0; | |||
285 | } | |||
286 | ||||
287 | /* | |||
288 | * Check for screwups. Perhaps the parser rejcts this, anyone | |||
289 | * know? | |||
290 | */ | |||
291 | if (ta->ta_prf != NULL((void*)0)) { | |||
292 | pexpect_fail(logger, HERE(where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 292}, "ESP IPsec Transform refused: contains unexpected PRF %s", | |||
293 | ta->ta_prf->common.fqn); | |||
294 | return false0; | |||
295 | } | |||
296 | if (ta->ta_dh != NULL((void*)0)) { | |||
297 | pexpect_fail(logger, HERE(where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 297}, "ESP IPsec Transform refused: contains unexpected DH %s", | |||
298 | ta->ta_dh->common.fqn); | |||
299 | return false0; | |||
300 | } | |||
301 | ||||
302 | if (c->child_proposals.p == NULL((void*)0)) { | |||
303 | dbg("ESP IPsec Transform verified unconditionally; no alg_info to check against"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ESP IPsec Transform verified unconditionally; no alg_info to check against" ); } }; | |||
304 | return true1; | |||
305 | } | |||
306 | ||||
307 | FOR_EACH_PROPOSAL(c->child_proposals.p, proposal)for (struct proposal *proposal = next_proposal(c->child_proposals .p, ((void*)0)); proposal != ((void*)0); proposal = next_proposal (c->child_proposals.p, proposal)) { | |||
308 | struct v1_proposal algs = v1_proposal(proposal); | |||
309 | if (algs.encrypt == ta->ta_encrypt && | |||
310 | (algs.enckeylen == 0 || | |||
311 | ta->enckeylen == 0 || | |||
312 | algs.enckeylen == ta->enckeylen) && | |||
313 | algs.integ == ta->ta_integ) { | |||
314 | dbg("ESP IPsec Transform verified; matches alg_info entry"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ESP IPsec Transform verified; matches alg_info entry" ); } }; | |||
315 | return true1; | |||
316 | } | |||
317 | } | |||
318 | return false0; | |||
319 | } | |||
320 | ||||
321 | static bool_Bool ikev1_verify_ah(const struct connection *c, | |||
322 | const struct trans_attrs *ta, | |||
323 | struct logger *logger) | |||
324 | { | |||
325 | if (!(c->policy & POLICY_AUTHENTICATE((lset_t)1 << (POLICY_AUTHENTICATE_IX)))) { | |||
326 | dbg("ignoring AH proposal as POLICY_AUTHENTICATE unset"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring AH proposal as POLICY_AUTHENTICATE unset" ); } }; | |||
327 | return false0; /* try another */ | |||
328 | } | |||
329 | if (ta->ta_encrypt != NULL((void*)0)) { | |||
330 | pexpect_fail(logger, HERE(where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 330}, | |||
331 | "AH IPsec Transform refused: contains unexpected encryption %s", | |||
332 | ta->ta_encrypt->common.fqn); | |||
333 | return false0; | |||
334 | } | |||
335 | if (ta->ta_prf != NULL((void*)0)) { | |||
336 | pexpect_fail(logger, HERE(where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 336}, "AH IPsec Transform refused: contains unexpected PRF %s", | |||
337 | ta->ta_prf->common.fqn); | |||
338 | return false0; | |||
339 | } | |||
340 | if (ta->ta_integ == NULL((void*)0)) { | |||
341 | pexpect_fail(logger, HERE(where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 341}, "AH IPsec Transform refused: missing integrity algorithm"); | |||
342 | return false0; | |||
343 | } | |||
344 | if (ta->ta_dh != NULL((void*)0)) { | |||
345 | pexpect_fail(logger, HERE(where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 345}, "AH IPsec Transform refused: contains unexpected DH %s", | |||
346 | ta->ta_dh->common.fqn); | |||
347 | return false0; | |||
348 | } | |||
349 | if (c->child_proposals.p == NULL((void*)0)) { | |||
350 | dbg("AH IPsec Transform verified unconditionally; no alg_info to check against"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("AH IPsec Transform verified unconditionally; no alg_info to check against" ); } }; | |||
351 | return true1; | |||
352 | } | |||
353 | ||||
354 | FOR_EACH_PROPOSAL(c->child_proposals.p, proposal)for (struct proposal *proposal = next_proposal(c->child_proposals .p, ((void*)0)); proposal != ((void*)0); proposal = next_proposal (c->child_proposals.p, proposal)) { /* really AH */ | |||
355 | struct v1_proposal algs = v1_proposal(proposal); | |||
356 | if (algs.integ == ta->ta_integ) { | |||
357 | dbg("ESP IPsec Transform verified; matches alg_info entry"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ESP IPsec Transform verified; matches alg_info entry" ); } }; | |||
358 | return true1; | |||
359 | } | |||
360 | } | |||
361 | ||||
362 | libreswan_log("AH IPsec Transform refused: %s",loglog(RC_LOG, "AH IPsec Transform refused: %s", ta->ta_integ ->common.fqn) | |||
363 | ta->ta_integ->common.fqn)loglog(RC_LOG, "AH IPsec Transform refused: %s", ta->ta_integ ->common.fqn); | |||
364 | return false0; | |||
365 | } | |||
366 | ||||
367 | /** | |||
368 | * Output an SA, as described by a db_sa. | |||
369 | * This has the side-effect of allocating SPIs for us. | |||
370 | * | |||
371 | */ | |||
372 | bool_Bool ikev1_out_sa(pb_stream *outs, | |||
373 | const struct db_sa *sadb, | |||
374 | struct state *st, | |||
375 | bool_Bool oakley_mode, | |||
376 | bool_Bool aggressive_mode) | |||
377 | { | |||
378 | struct db_sa *revised_sadb; | |||
379 | ||||
380 | if (oakley_mode) { | |||
381 | /* | |||
382 | * Construct the proposals by combining ALG_INFO_IKE | |||
383 | * with the AUTH (proof of identity) extracted from | |||
384 | * the (default?) SADB. As if by magic, attrs[2] is | |||
385 | * always the authentication method. | |||
386 | * | |||
387 | * XXX: Should replace SADB with a simple map to the | |||
388 | * auth method. | |||
389 | */ | |||
390 | struct db_attr *auth = &sadb->prop_conjs[0].props[0].trans[0].attrs[2]; | |||
391 | passert(auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD){ _Bool assertion__ = auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 391}, "%s", "auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD" ); } }; | |||
392 | enum ikev1_auth_method auth_method = auth->val; | |||
393 | /* | |||
394 | * Aggr-Mode - Max transforms == 2 - Multiple | |||
395 | * transforms, 1 DH group | |||
396 | */ | |||
397 | revised_sadb = v1_ike_alg_make_sadb(st->st_connection->ike_proposals, | |||
398 | auth_method, | |||
399 | aggressive_mode, | |||
400 | st->st_logger); | |||
401 | } else { | |||
402 | revised_sadb = kernel_alg_makedb(st->st_connection->policy, | |||
403 | st->st_connection->child_proposals, | |||
404 | true1, st->st_logger); | |||
405 | ||||
406 | /* add IPcomp proposal if policy asks for it */ | |||
407 | ||||
408 | if (revised_sadb != NULL((void*)0) && (st->st_policy & POLICY_COMPRESS((lset_t)1 << (POLICY_COMPRESS_IX)))) { | |||
409 | struct db_trans *ipcomp_trans = alloc_thing(((struct db_trans*) alloc_bytes(sizeof(struct db_trans), ("ipcomp_trans" ))) | |||
410 | struct db_trans, "ipcomp_trans")((struct db_trans*) alloc_bytes(sizeof(struct db_trans), ("ipcomp_trans" ))); | |||
411 | ||||
412 | /* allocate space for 2 proposals */ | |||
413 | struct db_prop *ipcomp_prop = | |||
414 | alloc_bytes(sizeof(struct db_prop) * 2, | |||
415 | "ipcomp_prop"); | |||
416 | ||||
417 | passert(revised_sadb->prop_conjs->prop_cnt == 1){ _Bool assertion__ = revised_sadb->prop_conjs->prop_cnt == 1; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 417} , "%s", "revised_sadb->prop_conjs->prop_cnt == 1"); } }; | |||
418 | ||||
419 | /* construct the IPcomp proposal */ | |||
420 | ipcomp_trans->transid = IPCOMP_DEFLATE; | |||
421 | ipcomp_trans->attrs = NULL((void*)0); | |||
422 | ipcomp_trans->attr_cnt = 0; | |||
423 | ||||
424 | /* copy the original proposal */ | |||
425 | ipcomp_prop[0].protoid = | |||
426 | revised_sadb->prop_conjs->props-> | |||
427 | protoid; | |||
428 | ipcomp_prop[0].trans = | |||
429 | revised_sadb->prop_conjs->props->trans; | |||
430 | ipcomp_prop[0].trans_cnt = | |||
431 | revised_sadb->prop_conjs->props-> | |||
432 | trans_cnt; | |||
433 | ||||
434 | /* and add our IPcomp proposal */ | |||
435 | ipcomp_prop[1].protoid = PROTO_IPCOMP4; | |||
436 | ipcomp_prop[1].trans = ipcomp_trans; | |||
437 | ipcomp_prop[1].trans_cnt = 1; | |||
438 | ||||
439 | /* free the old proposal, and ... */ | |||
440 | pfree(revised_sadb->prop_conjs->props); | |||
441 | ||||
442 | /* ... use our new one instead */ | |||
443 | revised_sadb->prop_conjs->props = ipcomp_prop; | |||
444 | revised_sadb->prop_conjs->prop_cnt += 1; | |||
445 | } | |||
446 | } | |||
447 | ||||
448 | /* more sanity */ | |||
449 | if (revised_sadb != NULL((void*)0)) | |||
450 | sadb = revised_sadb; | |||
451 | ||||
452 | /* SA header out */ | |||
453 | pb_stream sa_pbs; | |||
454 | { | |||
455 | struct isakmp_sa sa = { | |||
456 | .isasa_doi = ISAKMP_DOI_IPSEC1 /* all we know */ | |||
457 | }; | |||
458 | if (!out_struct(&sa, &isakmp_sa_desc, outs, &sa_pbs)) | |||
459 | goto fail; | |||
460 | } | |||
461 | ||||
462 | /* within SA: situation out */ | |||
463 | { | |||
464 | static const uint32_t situation = SIT_IDENTITY_ONLY0x01; | |||
465 | ||||
466 | if (!out_struct(&situation, &ipsec_sit_desc, &sa_pbs, NULL((void*)0))) | |||
467 | goto fail; | |||
468 | } | |||
469 | ||||
470 | /* within SA: Proposal Payloads | |||
471 | * | |||
472 | * Multiple Proposals with the same number are simultaneous | |||
473 | * (conjuncts) and must deal with different protocols (AH or ESP). | |||
474 | * Proposals with different numbers are alternatives (disjuncts), | |||
475 | * in preference order. | |||
476 | * Proposal numbers must be monotonic. | |||
477 | * See RFC 2408 "ISAKMP" 4.2 | |||
478 | */ | |||
479 | ||||
480 | bool_Bool ah_spi_generated = FALSE0, | |||
481 | esp_spi_generated = FALSE0, | |||
482 | ipcomp_cpi_generated = FALSE0; | |||
483 | ||||
484 | for (unsigned pcn = 0; pcn < sadb->prop_conj_cnt; pcn++) { | |||
485 | const struct db_prop_conj *const pc = &sadb->prop_conjs[pcn]; | |||
486 | int valid_prop_cnt = pc->prop_cnt; | |||
487 | ||||
488 | dbg("%s() pcn: %d has %d valid proposals", __func__, pcn, valid_prop_cnt){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s() pcn: %d has %d valid proposals", __func__ , pcn, valid_prop_cnt); } }; | |||
489 | ||||
490 | for (unsigned pn = 0; pn < pc->prop_cnt; pn++) { | |||
491 | const struct db_prop *const p = &pc->props[pn]; | |||
492 | pb_stream proposal_pbs; | |||
493 | ||||
494 | /* | |||
495 | * set the tunnel_mode bit on the last proposal only, and | |||
496 | * only if we are trying to negotiate tunnel mode in the first | |||
497 | * place. | |||
498 | */ | |||
499 | const bool_Bool tunnel_mode = (valid_prop_cnt == 1) && | |||
500 | (st->st_policy & POLICY_TUNNEL((lset_t)1 << (POLICY_TUNNEL_IX))); | |||
501 | ||||
502 | /* | |||
503 | * pick the part of the proposal we are trying to work on | |||
504 | */ | |||
505 | ||||
506 | dbg("%s() pcn: %d pn: %d<%d valid_count: %d trans_cnt: %d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s() pcn: %d pn: %d<%d valid_count: %d trans_cnt: %d" , __func__, pcn, pn, pc->prop_cnt, valid_prop_cnt, p->trans_cnt ); } } | |||
507 | __func__, pcn, pn, pc->prop_cnt, valid_prop_cnt,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s() pcn: %d pn: %d<%d valid_count: %d trans_cnt: %d" , __func__, pcn, pn, pc->prop_cnt, valid_prop_cnt, p->trans_cnt ); } } | |||
508 | p->trans_cnt){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s() pcn: %d pn: %d<%d valid_count: %d trans_cnt: %d" , __func__, pcn, pn, pc->prop_cnt, valid_prop_cnt, p->trans_cnt ); } }; | |||
509 | ||||
510 | /* but, skip things if the transform count is zero */ | |||
511 | if (p->trans_cnt == 0) | |||
512 | continue; | |||
513 | ||||
514 | /* Proposal header */ | |||
515 | { | |||
516 | valid_prop_cnt--; | |||
517 | ||||
518 | struct isakmp_proposal proposal = { | |||
519 | .isap_proposal = pcn, | |||
520 | .isap_protoid = p->protoid, | |||
521 | .isap_spisize = oakley_mode ? 0 : | |||
522 | p->protoid == PROTO_IPCOMP4 ? | |||
523 | IPCOMP_CPI_SIZE2 : | |||
524 | IPSEC_DOI_SPI_SIZE4, | |||
525 | .isap_pnp = valid_prop_cnt > 0 ? | |||
526 | ISAKMP_NEXT_P : ISAKMP_NEXT_NONE, | |||
527 | .isap_notrans = p->trans_cnt | |||
528 | }; | |||
529 | ||||
530 | if (!out_struct(&proposal, &isakmp_proposal_desc, | |||
531 | &sa_pbs, &proposal_pbs)) | |||
532 | goto fail; | |||
533 | } | |||
534 | ||||
535 | /* Per-protocols stuff: | |||
536 | * Set trans_desc. | |||
537 | * Set attr_desc. | |||
538 | * Set attr_val_descs. | |||
539 | * If not oakley_mode, emit SPI. | |||
540 | * We allocate SPIs on demand. | |||
541 | * All ESPs in an SA will share a single SPI. | |||
542 | * All AHs in an SAwill share a single SPI. | |||
543 | * AHs' SPI will be distinct from ESPs'. | |||
544 | * ??? If multiple ESPs are composed, how should their SPIs | |||
545 | * be allocated? | |||
546 | */ | |||
547 | const struct_desc *trans_desc; | |||
548 | const struct_desc *attr_desc; | |||
549 | enum_names *const *attr_val_descs; | |||
550 | ||||
551 | { | |||
552 | ipsec_spi_t *spi_ptr = NULL((void*)0); | |||
553 | const struct ip_protocol *proto = NULL((void*)0); | |||
554 | bool_Bool *spi_generated = NULL((void*)0); | |||
555 | ||||
556 | switch (p->protoid) { | |||
557 | case PROTO_ISAKMP1: | |||
558 | passert(oakley_mode){ _Bool assertion__ = oakley_mode; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 558}, "%s", "oakley_mode"); } }; | |||
559 | trans_desc = | |||
560 | &isakmp_isakmp_transform_desc; | |||
561 | attr_desc = | |||
562 | &isakmp_oakley_attribute_desc; | |||
563 | attr_val_descs = oakley_attr_val_descs; | |||
564 | /* no SPI needed */ | |||
565 | break; | |||
566 | ||||
567 | case PROTO_IPSEC_AH2: | |||
568 | passert(!oakley_mode){ _Bool assertion__ = !oakley_mode; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 568}, "%s", "!oakley_mode"); } }; | |||
569 | trans_desc = &isakmp_ah_transform_desc; | |||
570 | attr_desc = | |||
571 | &isakmp_ipsec_attribute_desc; | |||
572 | attr_val_descs = ipsec_attr_val_descs; | |||
573 | spi_ptr = &st->st_ah.our_spi; | |||
574 | spi_generated = &ah_spi_generated; | |||
575 | proto = &ip_protocol_ah; | |||
576 | break; | |||
577 | ||||
578 | case PROTO_IPSEC_ESP3: | |||
579 | passert(!oakley_mode){ _Bool assertion__ = !oakley_mode; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 579}, "%s", "!oakley_mode"); } }; | |||
580 | trans_desc = | |||
581 | &isakmp_esp_transform_desc; | |||
582 | attr_desc = | |||
583 | &isakmp_ipsec_attribute_desc; | |||
584 | attr_val_descs = ipsec_attr_val_descs; | |||
585 | spi_ptr = &st->st_esp.our_spi; | |||
586 | spi_generated = &esp_spi_generated; | |||
587 | proto = &ip_protocol_esp; | |||
588 | break; | |||
589 | ||||
590 | case PROTO_IPCOMP4: | |||
591 | passert(!oakley_mode){ _Bool assertion__ = !oakley_mode; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 591}, "%s", "!oakley_mode"); } }; | |||
592 | trans_desc = | |||
593 | &isakmp_ipcomp_transform_desc; | |||
594 | attr_desc = | |||
595 | &isakmp_ipsec_attribute_desc; | |||
596 | attr_val_descs = ipsec_attr_val_descs; | |||
597 | ||||
598 | /* | |||
599 | * a CPI isn't quite the same as an SPI | |||
600 | * so we use specialized code to emit it. | |||
601 | */ | |||
602 | if (!ipcomp_cpi_generated) { | |||
603 | st->st_ipcomp.our_spi = | |||
604 | get_my_cpi( | |||
605 | &st->st_connection->spd, | |||
606 | tunnel_mode); | |||
607 | if (st->st_ipcomp.our_spi == 0) | |||
608 | goto fail; /* problem generating CPI */ | |||
609 | ||||
610 | ipcomp_cpi_generated = TRUE1; | |||
611 | } | |||
612 | /* | |||
613 | * CPI is stored in network low order end of an | |||
614 | * ipsec_spi_t. So we start a couple of bytes in. | |||
615 | */ | |||
616 | if (!out_raw((u_char *)&st->st_ipcomp.our_spi + | |||
617 | IPSEC_DOI_SPI_SIZE4 - | |||
618 | IPCOMP_CPI_SIZE2, | |||
619 | IPCOMP_CPI_SIZE2, | |||
620 | &proposal_pbs, "CPI")) | |||
621 | goto fail; | |||
622 | break; | |||
623 | ||||
624 | default: | |||
625 | bad_case(p->protoid)libreswan_bad_case("p->protoid", (p->protoid), (where_t ) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 625}); | |||
626 | } | |||
627 | ||||
628 | if (spi_ptr != NULL((void*)0)) { | |||
629 | if (!*spi_generated) { | |||
630 | *spi_ptr = get_ipsec_spi(0, | |||
631 | proto, | |||
632 | &st->st_connection->spd, | |||
633 | tunnel_mode); | |||
634 | *spi_generated = TRUE1; | |||
635 | } | |||
636 | if (!out_raw((u_char *)spi_ptr, | |||
637 | IPSEC_DOI_SPI_SIZE4, | |||
638 | &proposal_pbs, "SPI")) | |||
639 | goto fail; | |||
640 | } | |||
641 | } | |||
642 | ||||
643 | /* within proposal: Transform Payloads */ | |||
644 | for (unsigned tn = 0; tn != p->trans_cnt; tn++) { | |||
645 | const struct db_trans *const t = &p->trans[tn]; | |||
646 | pb_stream trans_pbs; | |||
647 | ||||
648 | { | |||
649 | const struct isakmp_transform trans = { | |||
650 | .isat_tnp = (tn == p->trans_cnt - 1) ? | |||
651 | ISAKMP_NEXT_NONE : | |||
652 | ISAKMP_NEXT_T, | |||
653 | .isat_transnum = tn, | |||
654 | .isat_transid = t->transid | |||
655 | }; | |||
656 | ||||
657 | if (!out_struct(&trans, trans_desc, | |||
658 | &proposal_pbs, &trans_pbs)) | |||
659 | goto fail; | |||
660 | } | |||
661 | ||||
662 | /* Within transform: Attributes. */ | |||
663 | ||||
664 | /* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is | |||
665 | * automatically generated because it must be the same | |||
666 | * in every transform. Except IPCOMP. | |||
667 | */ | |||
668 | if (p->protoid != PROTO_IPCOMP4 && | |||
669 | st->st_pfs_group != NULL((void*)0)) { | |||
670 | passert(!oakley_mode){ _Bool assertion__ = !oakley_mode; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 670}, "%s", "!oakley_mode"); } }; | |||
671 | passert(st->st_pfs_group != &unset_group){ _Bool assertion__ = st->st_pfs_group != &unset_group ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 671}, "%s", "st->st_pfs_group != &unset_group" ); } }; | |||
672 | if (!out_attr(GROUP_DESCRIPTION, | |||
673 | st->st_pfs_group->group, | |||
674 | attr_desc, | |||
675 | attr_val_descs, | |||
676 | &trans_pbs)) | |||
677 | goto fail; | |||
678 | } | |||
679 | ||||
680 | /* automatically generate duration | |||
681 | * and, for Phase 2 / Quick Mode, encapsulation. | |||
682 | */ | |||
683 | if (oakley_mode) { | |||
684 | if (!out_attr(OAKLEY_LIFE_TYPE, | |||
685 | OAKLEY_LIFE_SECONDS1, | |||
686 | attr_desc, | |||
687 | attr_val_descs, | |||
688 | &trans_pbs) || | |||
689 | !out_attr(OAKLEY_LIFE_DURATION, | |||
690 | deltasecs(st->st_connection->sa_ike_life_seconds), | |||
691 | attr_desc, | |||
692 | attr_val_descs, | |||
693 | &trans_pbs)) | |||
694 | goto fail; | |||
695 | } else { | |||
696 | /* RFC 2407 (IPSEC DOI) 4.5 specifies that | |||
697 | * the default is "unspecified (host-dependent)". | |||
698 | * This makes little sense, so we always specify it. | |||
699 | * | |||
700 | * Unlike other IPSEC transforms, IPCOMP defaults | |||
701 | * to Transport Mode, so we can exploit the default | |||
702 | * (draft-shacham-ippcp-rfc2393bis-05.txt 4.1). | |||
703 | */ | |||
704 | if (p->protoid != PROTO_IPCOMP4 || | |||
705 | st->st_policy & POLICY_TUNNEL((lset_t)1 << (POLICY_TUNNEL_IX))) { | |||
706 | if (!out_attr( | |||
707 | ENCAPSULATION_MODE, | |||
708 | NAT_T_ENCAPSULATION_MODE(( ((st)->hidden_variables.st_nat_traversal & ( ((lset_t )1 << (NATED_HOST)) | ((lset_t)1 << (NATED_PEER)) )) ? ( ((st->st_policy) & ((lset_t)1 << (POLICY_TUNNEL_IX ))) ? ( ((st)->hidden_variables.st_nat_traversal & ( ( (lset_t)1 << (NAT_TRAVERSAL_METHOD_IETF_RFC)) )) ? 3 : 61443 ) : ( ((st)->hidden_variables.st_nat_traversal & ( (( lset_t)1 << (NAT_TRAVERSAL_METHOD_IETF_RFC)) )) ? 4 : 61444 ) ) : ( ((st)->st_policy & ((lset_t)1 << (POLICY_TUNNEL_IX ))) ? 1 : 2 ) ) | |||
709 | st,( ((st)->hidden_variables.st_nat_traversal & ( ((lset_t )1 << (NATED_HOST)) | ((lset_t)1 << (NATED_PEER)) )) ? ( ((st->st_policy) & ((lset_t)1 << (POLICY_TUNNEL_IX ))) ? ( ((st)->hidden_variables.st_nat_traversal & ( ( (lset_t)1 << (NAT_TRAVERSAL_METHOD_IETF_RFC)) )) ? 3 : 61443 ) : ( ((st)->hidden_variables.st_nat_traversal & ( (( lset_t)1 << (NAT_TRAVERSAL_METHOD_IETF_RFC)) )) ? 4 : 61444 ) ) : ( ((st)->st_policy & ((lset_t)1 << (POLICY_TUNNEL_IX ))) ? 1 : 2 ) ) | |||
710 | st->st_policy)( ((st)->hidden_variables.st_nat_traversal & ( ((lset_t )1 << (NATED_HOST)) | ((lset_t)1 << (NATED_PEER)) )) ? ( ((st->st_policy) & ((lset_t)1 << (POLICY_TUNNEL_IX ))) ? ( ((st)->hidden_variables.st_nat_traversal & ( ( (lset_t)1 << (NAT_TRAVERSAL_METHOD_IETF_RFC)) )) ? 3 : 61443 ) : ( ((st)->hidden_variables.st_nat_traversal & ( (( lset_t)1 << (NAT_TRAVERSAL_METHOD_IETF_RFC)) )) ? 4 : 61444 ) ) : ( ((st)->st_policy & ((lset_t)1 << (POLICY_TUNNEL_IX ))) ? 1 : 2 ) ), | |||
711 | attr_desc, | |||
712 | attr_val_descs, | |||
713 | &trans_pbs)) | |||
714 | goto fail; | |||
715 | } | |||
716 | if (!out_attr(SA_LIFE_TYPE, | |||
717 | SA_LIFE_TYPE_SECONDS1, | |||
718 | attr_desc, | |||
719 | attr_val_descs, | |||
720 | &trans_pbs) || | |||
721 | !out_attr(SA_LIFE_DURATION, | |||
722 | deltasecs(st->st_connection->sa_ipsec_life_seconds), | |||
723 | attr_desc, | |||
724 | attr_val_descs, | |||
725 | &trans_pbs)) | |||
726 | goto fail; | |||
727 | ||||
728 | if (st->sec_ctx != NULL((void*)0) && | |||
729 | st->st_connection->policy_label != NULL((void*)0)) { | |||
730 | passert(st->sec_ctx->ctx.ctx_len <= MAX_SECCTX_LEN){ _Bool assertion__ = st->sec_ctx->ctx.ctx_len <= 4096 ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 730}, "%s", "st->sec_ctx->ctx.ctx_len <= MAX_SECCTX_LEN" ); } }; | |||
731 | ||||
732 | pb_stream val_pbs; | |||
733 | struct isakmp_attribute attr = { | |||
734 | .isaat_af_type = secctx_attr_type | | |||
735 | ISAKMP_ATTR_AF_TLV0, | |||
736 | }; | |||
737 | ||||
738 | if (!out_struct(&attr, | |||
739 | attr_desc, | |||
740 | &trans_pbs, | |||
741 | &val_pbs) || | |||
742 | !out_struct(&st->sec_ctx->ctx, | |||
743 | &sec_ctx_desc, | |||
744 | &val_pbs, | |||
745 | NULL((void*)0)) || | |||
746 | !out_raw(st->sec_ctx-> | |||
747 | sec_ctx_value, | |||
748 | st->sec_ctx->ctx.ctx_len, &val_pbs, | |||
749 | " variable length sec ctx")) | |||
750 | goto fail; | |||
751 | ||||
752 | close_output_pbs(&val_pbs); | |||
753 | } | |||
754 | } | |||
755 | ||||
756 | /* | |||
757 | * spit out attributes from table | |||
758 | * | |||
759 | * XXX: Assume that the code | |||
760 | * constructing the attribute table | |||
761 | * handled optional and extra key | |||
762 | * lengths (and if it is wrong it is | |||
763 | * deliberate). I.e., don't try to | |||
764 | * also handle it here. | |||
765 | * | |||
766 | * OTOH, do completely override | |||
767 | * key-lengths when so impaired. | |||
768 | */ | |||
769 | enum impair_emit impair_key_length_attribute = | |||
770 | (oakley_mode ? impair.ike_key_length_attribute | |||
771 | : impair.child_key_length_attribute); | |||
772 | long key_length_to_impair = -1; | |||
773 | for (unsigned an = 0; an != t->attr_cnt; an++) { | |||
774 | const struct db_attr *a = &t->attrs[an]; | |||
775 | /* | |||
776 | * Strip out or duplicate | |||
777 | * key-length attribute? | |||
778 | */ | |||
779 | if (impair_key_length_attribute > 0 && | |||
780 | (oakley_mode ? a->type.oakley == OAKLEY_KEY_LENGTH | |||
781 | : a->type.ipsec == KEY_LENGTH)) { | |||
782 | key_length_to_impair = a->val; | |||
783 | libreswan_log("IMPAIR: stripping key-length")loglog(RC_LOG, "IMPAIR: stripping key-length"); | |||
784 | continue; | |||
785 | } | |||
786 | if (!out_attr(oakley_mode ? a->type.oakley : a->type.ipsec , | |||
787 | a->val, | |||
788 | attr_desc, | |||
789 | attr_val_descs, | |||
790 | &trans_pbs)) | |||
791 | goto fail; | |||
792 | } | |||
793 | /* | |||
794 | * put back a key-length? | |||
795 | */ | |||
796 | switch (impair_key_length_attribute) { | |||
797 | case IMPAIR_EMIT_NO: | |||
798 | break; | |||
799 | case IMPAIR_EMIT_EMPTY: | |||
800 | /* | |||
801 | * XXX: how? IKEv2 sends a | |||
802 | * long form packet of no | |||
803 | * length. | |||
804 | */ | |||
805 | libreswan_log("IMPAIR: key-length-attribute:empty not implemented")loglog(RC_LOG, "IMPAIR: key-length-attribute:empty not implemented" ); | |||
806 | break; | |||
807 | case IMPAIR_EMIT_OMIT: | |||
808 | libreswan_log("IMPAIR: not sending key-length attribute")loglog(RC_LOG, "IMPAIR: not sending key-length attribute"); | |||
809 | break; | |||
810 | case IMPAIR_EMIT_DUPLICATE: | |||
811 | if (key_length_to_impair >= 0) { | |||
812 | libreswan_log("IMPAIR: duplicating key-length")loglog(RC_LOG, "IMPAIR: duplicating key-length"); | |||
813 | for (unsigned dup = 0; dup < 2; dup++) { | |||
814 | if (!out_attr(oakley_mode ? OAKLEY_KEY_LENGTH : KEY_LENGTH, | |||
815 | key_length_to_impair, | |||
816 | attr_desc, | |||
817 | attr_val_descs, | |||
818 | &trans_pbs)) | |||
819 | goto fail; | |||
820 | } | |||
821 | } else { | |||
822 | libreswan_log("IMPAIR: no key-length to duplicate")loglog(RC_LOG, "IMPAIR: no key-length to duplicate"); | |||
823 | } | |||
824 | break; | |||
825 | case IMPAIR_EMIT_ROOF: | |||
826 | default: | |||
827 | { | |||
828 | unsigned keylen = impair_key_length_attribute - IMPAIR_EMIT_ROOF; | |||
829 | libreswan_log("IMPAIR: sending key-length attribute value %u",loglog(RC_LOG, "IMPAIR: sending key-length attribute value %u" , keylen) | |||
830 | keylen)loglog(RC_LOG, "IMPAIR: sending key-length attribute value %u" , keylen); | |||
831 | if (!out_attr(oakley_mode ? OAKLEY_KEY_LENGTH : KEY_LENGTH, | |||
832 | keylen, attr_desc, attr_val_descs, | |||
833 | &trans_pbs)) | |||
834 | goto fail; | |||
835 | break; | |||
836 | } | |||
837 | } | |||
838 | close_output_pbs(&trans_pbs); | |||
839 | } | |||
840 | close_output_pbs(&proposal_pbs); | |||
841 | } | |||
842 | /* end of a conjunction of proposals */ | |||
843 | } | |||
844 | close_output_pbs(&sa_pbs); | |||
845 | free_sa(&revised_sadb); | |||
846 | return TRUE1; | |||
847 | ||||
848 | fail: | |||
849 | free_sa(&revised_sadb); | |||
850 | return FALSE0; | |||
851 | } | |||
852 | ||||
853 | /** Handle long form of duration attribute. | |||
854 | * The code is can only handle values that can fit in unsigned long. | |||
855 | * "Clamping" is probably an acceptable way to impose this limitation. | |||
856 | * | |||
857 | * @param pbs PB Stream | |||
858 | * @return uint32_t duration, in seconds. | |||
859 | */ | |||
860 | static uint32_t decode_long_duration(pb_stream *pbs) | |||
861 | { | |||
862 | uint32_t val = 0; | |||
863 | ||||
864 | /* ignore leading zeros */ | |||
865 | while (pbs_left(pbs)((size_t)((pbs)->roof - (pbs)->cur)) != 0 && *pbs->cur == '\0') | |||
866 | pbs->cur++; | |||
867 | ||||
868 | if (pbs_left(pbs)((size_t)((pbs)->roof - (pbs)->cur)) > sizeof(val)) { | |||
869 | /* "clamp" too large value to max representable value */ | |||
870 | val -= 1; /* portable way to get to maximum value */ | |||
871 | dbg(" too large duration clamped to: %" PRIu32, val){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" too large duration clamped to: %" "u", val ); } }; | |||
872 | } else { | |||
873 | /* decode number */ | |||
874 | while (pbs_left(pbs)((size_t)((pbs)->roof - (pbs)->cur)) != 0) | |||
875 | val = (val << BITS_PER_BYTE8) | *pbs->cur++; | |||
876 | dbg(" long duration: %" PRIu32, val){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log(" long duration: %" "u", val); } }; | |||
877 | } | |||
878 | return val; | |||
879 | } | |||
880 | ||||
881 | /* Preparse the body of an IKEv1 ISAKMP SA Payload and find which policy is | |||
882 | * required to match the packet. Errors are just ignored and will be detected | |||
883 | * and handled later in parse_isakmp_sa_body(). | |||
884 | * | |||
885 | * All we want for the moment is to know whether peer is using RSA or PSK. | |||
886 | * NOTE: sa_pbs is passed by value so the caller's PBS is unchanged! | |||
887 | */ | |||
888 | lset_t preparse_isakmp_sa_body(pb_stream sa_pbs /* by value! */) | |||
889 | { | |||
890 | pb_stream proposal_pbs; | |||
891 | struct isakmp_proposal proposal; | |||
892 | pb_stream trans_pbs; | |||
893 | struct isakmp_transform trans; | |||
894 | struct isakmp_attribute a; | |||
895 | pb_stream attr_pbs; | |||
896 | uint32_t ipsecdoisit; | |||
897 | unsigned trans_left; | |||
898 | lset_t policy = LEMPTY((lset_t)0); | |||
899 | ||||
900 | if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, &sa_pbs, NULL((void*)0))) | |||
901 | return LEMPTY((lset_t)0); | |||
902 | ||||
903 | if (!in_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, | |||
904 | &proposal_pbs)) | |||
905 | return LEMPTY((lset_t)0); | |||
906 | ||||
907 | if (proposal.isap_spisize > MAX_ISAKMP_SPI_SIZE(2 * 8)) | |||
908 | return LEMPTY((lset_t)0); | |||
909 | ||||
910 | if (proposal.isap_spisize > 0) { | |||
911 | u_char junk_spi[MAX_ISAKMP_SPI_SIZE(2 * 8)]; | |||
912 | ||||
913 | if (!in_raw(junk_spi, proposal.isap_spisize, &proposal_pbs, | |||
914 | "Oakley SPI")) | |||
915 | return LEMPTY((lset_t)0); | |||
916 | } | |||
917 | ||||
918 | trans_left = proposal.isap_notrans; | |||
919 | while (trans_left-- != 0) { | |||
920 | if (!in_struct(&trans, &isakmp_isakmp_transform_desc, | |||
921 | &proposal_pbs, | |||
922 | &trans_pbs)) | |||
923 | return LEMPTY((lset_t)0); | |||
924 | ||||
925 | while (pbs_left(&trans_pbs)((size_t)((&trans_pbs)->roof - (&trans_pbs)->cur )) >= isakmp_oakley_attribute_desc.size) { | |||
926 | if (!in_struct(&a, &isakmp_oakley_attribute_desc, | |||
927 | &trans_pbs, | |||
928 | &attr_pbs)) | |||
929 | return LEMPTY((lset_t)0); | |||
930 | ||||
931 | switch (a.isaat_af_type) { | |||
932 | case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV0x8000: | |||
933 | switch (a.isaat_lv) { | |||
934 | case XAUTHInitPreShared: | |||
935 | policy |= POLICY_XAUTH((lset_t)1 << (POLICY_XAUTH_IX)); | |||
936 | /* fallthrough */ | |||
937 | case OAKLEY_PRESHARED_KEY: | |||
938 | policy |= POLICY_PSK((lset_t)1 << (POLICY_PSK_IX)); | |||
939 | break; | |||
940 | case XAUTHInitRSA: | |||
941 | policy |= POLICY_XAUTH((lset_t)1 << (POLICY_XAUTH_IX)); | |||
942 | /* fallthrough */ | |||
943 | case OAKLEY_RSA_SIG: | |||
944 | policy |= POLICY_RSASIG((lset_t)1 << (POLICY_RSASIG_IX)); | |||
945 | break; | |||
946 | } | |||
947 | break; | |||
948 | } | |||
949 | } | |||
950 | } | |||
951 | ||||
952 | /* | |||
953 | * These policy bits will be used in a call to find_host_connection. | |||
954 | * The meaning is: each of these present bits must be present | |||
955 | * in a connection's policy. | |||
956 | * | |||
957 | * If both PSK and RSASIG are present now, that means that | |||
958 | * either is acceptable. The right way to express this is | |||
959 | * to turn both off! | |||
960 | */ | |||
961 | if (LIN(POLICY_PSK | POLICY_RSASIG, policy)(((((lset_t)1 << (POLICY_PSK_IX)) | ((lset_t)1 << (POLICY_RSASIG_IX))) & (policy)) == (((lset_t)1 << (POLICY_PSK_IX)) | ((lset_t)1 << (POLICY_RSASIG_IX))))) | |||
962 | policy &= ~(POLICY_PSK((lset_t)1 << (POLICY_PSK_IX)) | POLICY_RSASIG((lset_t)1 << (POLICY_RSASIG_IX))); | |||
963 | ||||
964 | return policy; | |||
965 | } | |||
966 | ||||
967 | static bool_Bool ikev1_verify_ike(const struct trans_attrs *ta, | |||
968 | struct ike_proposals ike_proposals, | |||
969 | struct logger *logger) | |||
970 | { | |||
971 | if (ta->ta_encrypt == NULL((void*)0)) { | |||
972 | log_message(RC_LOG_SERIOUS, logger, | |||
973 | "OAKLEY proposal refused: missing encryption"); | |||
974 | return false0; | |||
975 | } | |||
976 | if (ta->ta_prf == NULL((void*)0)) { | |||
977 | log_message(RC_LOG_SERIOUS, logger, | |||
978 | "OAKLEY proposal refused: missing PRF"); | |||
979 | return false0; | |||
980 | } | |||
981 | if (ta->ta_integ != NULL((void*)0)) { | |||
982 | pexpect_fail(logger, HERE(where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 982}, "OAKLEY proposal refused: contains unexpected integrity %s", | |||
983 | ta->ta_prf->common.fqn); | |||
984 | return false0; | |||
985 | } | |||
986 | if (ta->ta_dh == NULL((void*)0)) { | |||
987 | log_message(RC_LOG_SERIOUS, logger, "OAKLEY proposal refused: missing DH"); | |||
988 | return false0; | |||
989 | } | |||
990 | if (ike_proposals.p == NULL((void*)0)) { | |||
991 | dbg("OAKLEY proposal verified unconditionally; no alg_info to check against"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("OAKLEY proposal verified unconditionally; no alg_info to check against" ); } }; | |||
992 | return true1; | |||
993 | } | |||
994 | ||||
995 | /* | |||
996 | * simple test to toss low key_len, will accept it only | |||
997 | * if specified in "esp" string | |||
998 | */ | |||
999 | bool_Bool ealg_insecure = (ta->enckeylen < 128); | |||
1000 | ||||
1001 | FOR_EACH_PROPOSAL(ike_proposals.p, proposal)for (struct proposal *proposal = next_proposal(ike_proposals. p, ((void*)0)); proposal != ((void*)0); proposal = next_proposal (ike_proposals.p, proposal)) { | |||
1002 | struct v1_proposal algs = v1_proposal(proposal); | |||
1003 | if (algs.encrypt == ta->ta_encrypt && | |||
1004 | (algs.enckeylen == 0 || | |||
1005 | ta->enckeylen == 0 || | |||
1006 | algs.enckeylen == ta->enckeylen) && | |||
1007 | algs.prf == ta->ta_prf && | |||
1008 | algs.dh == ta->ta_dh) { | |||
1009 | if (ealg_insecure) { | |||
1010 | loglog(RC_LOG_SERIOUS, | |||
1011 | "You should NOT use insecure/broken IKE algorithms (%s)!", | |||
1012 | ta->ta_encrypt->common.fqn); | |||
1013 | } else { | |||
1014 | dbg("OAKLEY proposal verified; matching alg_info found"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("OAKLEY proposal verified; matching alg_info found" ); } }; | |||
1015 | return true1; | |||
1016 | } | |||
1017 | } | |||
1018 | } | |||
1019 | libreswan_log("Oakley Transform [%s (%d), %s, %s] refused%s",loglog(RC_LOG, "Oakley Transform [%s (%d), %s, %s] refused%s" , ta->ta_encrypt->common.fqn, ta->enckeylen, ta-> ta_prf->common.fqn, ta->ta_dh->common.fqn, ealg_insecure ? " due to insecure key_len and enc. alg. not listed in \"ike\" string" : "") | |||
1020 | ta->ta_encrypt->common.fqn, ta->enckeylen,loglog(RC_LOG, "Oakley Transform [%s (%d), %s, %s] refused%s" , ta->ta_encrypt->common.fqn, ta->enckeylen, ta-> ta_prf->common.fqn, ta->ta_dh->common.fqn, ealg_insecure ? " due to insecure key_len and enc. alg. not listed in \"ike\" string" : "") | |||
1021 | ta->ta_prf->common.fqn, ta->ta_dh->common.fqn,loglog(RC_LOG, "Oakley Transform [%s (%d), %s, %s] refused%s" , ta->ta_encrypt->common.fqn, ta->enckeylen, ta-> ta_prf->common.fqn, ta->ta_dh->common.fqn, ealg_insecure ? " due to insecure key_len and enc. alg. not listed in \"ike\" string" : "") | |||
1022 | ealg_insecure ?loglog(RC_LOG, "Oakley Transform [%s (%d), %s, %s] refused%s" , ta->ta_encrypt->common.fqn, ta->enckeylen, ta-> ta_prf->common.fqn, ta->ta_dh->common.fqn, ealg_insecure ? " due to insecure key_len and enc. alg. not listed in \"ike\" string" : "") | |||
1023 | " due to insecure key_len and enc. alg. not listed in \"ike\" string" :loglog(RC_LOG, "Oakley Transform [%s (%d), %s, %s] refused%s" , ta->ta_encrypt->common.fqn, ta->enckeylen, ta-> ta_prf->common.fqn, ta->ta_dh->common.fqn, ealg_insecure ? " due to insecure key_len and enc. alg. not listed in \"ike\" string" : "") | |||
1024 | "")loglog(RC_LOG, "Oakley Transform [%s (%d), %s, %s] refused%s" , ta->ta_encrypt->common.fqn, ta->enckeylen, ta-> ta_prf->common.fqn, ta->ta_dh->common.fqn, ealg_insecure ? " due to insecure key_len and enc. alg. not listed in \"ike\" string" : ""); | |||
1025 | return false0; | |||
1026 | } | |||
1027 | ||||
1028 | /** | |||
1029 | * Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode). | |||
1030 | * Various shortcuts are taken. In particular, the policy, such as | |||
1031 | * it is, is hardwired. | |||
1032 | * | |||
1033 | * If r_sa is non-NULL, the body of an SA representing the selected | |||
1034 | * proposal is emitted. | |||
1035 | * | |||
1036 | * If "selection" is true, the SA is supposed to represent the | |||
1037 | * single transform that the peer has accepted. | |||
1038 | * ??? We only check that it is acceptable, not that it is one that we offered! | |||
1039 | * | |||
1040 | * It also means that we are inR1, and this as implications when we are | |||
1041 | * doing XAUTH, as it changes the meaning of the XAUTHInit/XAUTHResp. | |||
1042 | * | |||
1043 | * Only IPsec DOI is accepted (what is the ISAKMP DOI?). | |||
1044 | * Error response is rudimentary. | |||
1045 | * | |||
1046 | * This routine is used by main_inI1_outR1() and main_inR1_outI2(). | |||
1047 | */ | |||
1048 | notification_t parse_isakmp_sa_body(pb_stream *sa_pbs, /* body of input SA Payload */ | |||
1049 | const struct isakmp_sa *sa, /* header of input SA Payload */ | |||
1050 | pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */ | |||
1051 | bool_Bool selection, /* if this SA is a selection, only one transform | |||
1052 | * can appear. */ | |||
1053 | struct state *const st) /* current state object */ | |||
1054 | { | |||
1055 | const struct connection *const c = st->st_connection; | |||
1056 | bool_Bool xauth_init = FALSE0, | |||
1057 | xauth_resp = FALSE0; | |||
1058 | const char *const role = selection ? "initiator" : "responder"; | |||
1059 | const chunk_t *pss = &empty_chunk; | |||
1060 | ||||
1061 | passert(c != NULL){ _Bool assertion__ = c != ((void*)0); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1061}, "%s", "c != NULL"); } }; | |||
1062 | ||||
1063 | /* calculate the per-end policy that might apply */ | |||
1064 | const struct spd_route *spd; | |||
1065 | ||||
1066 | for (spd = &c->spd; spd != NULL((void*)0); spd = spd->spd_next) { | |||
1067 | if (selection) { | |||
1068 | /* | |||
1069 | * this is the initiator, we have proposed, they have answered, | |||
1070 | * and we must decide if they proposed what we wanted. | |||
1071 | */ | |||
1072 | xauth_init |= spd->this.xauth_client; | |||
1073 | xauth_resp |= spd->this.xauth_server; | |||
1074 | } else { | |||
1075 | /* | |||
1076 | * this is the responder, they have proposed to us, what | |||
1077 | * are we willing to be? | |||
1078 | */ | |||
1079 | xauth_init |= spd->this.xauth_server; | |||
1080 | xauth_resp |= spd->this.xauth_client; | |||
1081 | } | |||
1082 | } | |||
1083 | ||||
1084 | /* DOI */ | |||
1085 | if (sa->isasa_doi != ISAKMP_DOI_IPSEC1) { | |||
1086 | log_state(RC_LOG_SERIOUS, st, "Unknown/unsupported DOI %s", | |||
1087 | enum_show(&doi_names, sa->isasa_doi)); | |||
1088 | /* XXX Could send notification back */ | |||
1089 | return DOI_NOT_SUPPORTED; /* reject whole SA */ | |||
1090 | } | |||
1091 | ||||
1092 | /* Situation */ | |||
1093 | uint32_t ipsecdoisit; | |||
1094 | ||||
1095 | if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL((void*)0))) | |||
1096 | return SITUATION_NOT_SUPPORTED; /* reject whole SA */ | |||
1097 | ||||
1098 | if (ipsecdoisit != SIT_IDENTITY_ONLY0x01) { | |||
1099 | log_state(RC_LOG_SERIOUS, st, "unsupported IPsec DOI situation (%s)", | |||
1100 | bitnamesof(sit_bit_names, ipsecdoisit)); | |||
1101 | /* XXX Could send notification back */ | |||
1102 | return SITUATION_NOT_SUPPORTED; /* reject whole SA */ | |||
1103 | } | |||
1104 | ||||
1105 | /* The rules for ISAKMP SAs are scattered. | |||
1106 | * RFC 2409 "IKE" section 5 says that there | |||
1107 | * can only be one SA, and it can have only one proposal in it. | |||
1108 | * There may well be multiple transforms. | |||
1109 | */ | |||
1110 | struct isakmp_proposal proposal; | |||
1111 | pb_stream proposal_pbs; | |||
1112 | ||||
1113 | if (!in_struct(&proposal, &isakmp_proposal_desc, sa_pbs, | |||
1114 | &proposal_pbs)) { | |||
1115 | return PAYLOAD_MALFORMED; /* reject whole SA */ | |||
1116 | } | |||
1117 | ||||
1118 | if (proposal.isap_pnp != ISAKMP_NEXT_NONE) { | |||
1119 | log_state(RC_LOG_SERIOUS, st, | |||
1120 | "Proposal Payload must be alone in Oakley SA; found %s following Proposal", | |||
1121 | enum_show(&ikev1_payload_names, proposal.isap_pnp)); | |||
1122 | return PAYLOAD_MALFORMED; /* reject whole SA */ | |||
1123 | } | |||
1124 | ||||
1125 | if (proposal.isap_protoid != PROTO_ISAKMP1) { | |||
1126 | log_state(RC_LOG_SERIOUS, st, | |||
1127 | "unexpected Protocol ID (%s) found in Oakley Proposal", | |||
1128 | enum_show(&ikev1_protocol_names, proposal.isap_protoid)); | |||
1129 | return INVALID_PROTOCOL_ID; /* reject whole SA */ | |||
1130 | } | |||
1131 | ||||
1132 | /* Just what should we accept for the SPI field? | |||
1133 | * The RFC is sort of contradictory. We will ignore the SPI | |||
1134 | * as long as it is of the proper size. | |||
1135 | * | |||
1136 | * From RFC2408 2.4 Identifying Security Associations: | |||
1137 | * During phase 1 negotiations, the initiator and responder cookies | |||
1138 | * determine the ISAKMP SA. Therefore, the SPI field in the Proposal | |||
1139 | * payload is redundant and MAY be set to 0 or it MAY contain the | |||
1140 | * transmitting entity's cookie. | |||
1141 | * | |||
1142 | * From RFC2408 3.5 Proposal Payload: | |||
1143 | * o SPI Size (1 octet) - Length in octets of the SPI as defined by | |||
1144 | * the Protocol-Id. In the case of ISAKMP, the Initiator and | |||
1145 | * Responder cookie pair from the ISAKMP Header is the ISAKMP SPI, | |||
1146 | * therefore, the SPI Size is irrelevant and MAY be from zero (0) to | |||
1147 | * sixteen (16). If the SPI Size is non-zero, the content of the | |||
1148 | * SPI field MUST be ignored. If the SPI Size is not a multiple of | |||
1149 | * 4 octets it will have some impact on the SPI field and the | |||
1150 | * alignment of all payloads in the message. The Domain of | |||
1151 | * Interpretation (DOI) will dictate the SPI Size for other | |||
1152 | * protocols. | |||
1153 | */ | |||
1154 | if (proposal.isap_spisize == 0) { | |||
1155 | /* empty (0) SPI -- fine */ | |||
1156 | } else if (proposal.isap_spisize <= MAX_ISAKMP_SPI_SIZE(2 * 8)) { | |||
1157 | u_char junk_spi[MAX_ISAKMP_SPI_SIZE(2 * 8)]; | |||
1158 | diag_t d = pbs_in_raw(&proposal_pbs, junk_spi, proposal.isap_spisize, "Oakley SPI"); | |||
1159 | if (d != NULL((void*)0)) { | |||
1160 | log_diag(RC_LOG_SERIOUS, st->st_logger, &d, "%s", ""); | |||
1161 | return PAYLOAD_MALFORMED; /* reject whole SA */ | |||
1162 | } | |||
1163 | } else { | |||
1164 | log_state(RC_LOG_SERIOUS, st, | |||
1165 | "invalid SPI size (%u) in Oakley Proposal", | |||
1166 | (unsigned)proposal.isap_spisize); | |||
1167 | return INVALID_SPI; /* reject whole SA */ | |||
1168 | } | |||
1169 | ||||
1170 | if (selection && proposal.isap_notrans != 1) { | |||
1171 | log_state(RC_LOG_SERIOUS, st, | |||
1172 | "a single Transform is required in a selecting Oakley Proposal; found %u", | |||
1173 | (unsigned)proposal.isap_notrans); | |||
1174 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1175 | } | |||
1176 | ||||
1177 | /* for each transform payload... */ | |||
1178 | ||||
1179 | int last_transnum = -1; | |||
1180 | unsigned no_trans_left = proposal.isap_notrans; | |||
1181 | ||||
1182 | for (;;) { | |||
1183 | if (no_trans_left == 0) { | |||
1184 | log_state(RC_LOG_SERIOUS, st, | |||
1185 | "number of Transform Payloads disagrees with Oakley Proposal Payload"); | |||
1186 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1187 | } | |||
1188 | ||||
1189 | uint16_t life_type = 0; /* initialized to silence GCC */ | |||
1190 | ||||
1191 | /* initialize only optional field in ta */ | |||
1192 | struct trans_attrs ta = { | |||
1193 | .life_seconds = deltatime(IKE_SA_LIFETIME_DEFAULTsecs_per_hour) /* When this SA expires (seconds) */ | |||
1194 | }; | |||
1195 | ||||
1196 | struct isakmp_transform trans; | |||
1197 | pb_stream trans_pbs; | |||
1198 | ||||
1199 | if (!in_struct(&trans, &isakmp_isakmp_transform_desc, | |||
1200 | &proposal_pbs, &trans_pbs)) { | |||
1201 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1202 | } | |||
1203 | ||||
1204 | if (trans.isat_transnum <= last_transnum) { | |||
1205 | /* picky, picky, picky */ | |||
1206 | log_state(RC_LOG_SERIOUS, st, | |||
1207 | "Transform Numbers are not monotonically increasing in Oakley Proposal"); | |||
1208 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1209 | } | |||
1210 | last_transnum = trans.isat_transnum; | |||
1211 | ||||
1212 | if (trans.isat_transid != KEY_IKE1) { | |||
1213 | log_state(RC_LOG_SERIOUS, st, | |||
1214 | "expected KEY_IKE but found %s in Oakley Transform", | |||
1215 | enum_show(&isakmp_transformid_names, | |||
1216 | trans.isat_transid)); | |||
1217 | return INVALID_TRANSFORM_ID; /* reject whole SA */ | |||
1218 | } | |||
1219 | ||||
1220 | u_char *attr_start = trans_pbs.cur; | |||
1221 | size_t attr_len = pbs_left(&trans_pbs)((size_t)((&trans_pbs)->roof - (&trans_pbs)->cur )); | |||
1222 | ||||
1223 | /* process all the attributes that make up the transform */ | |||
1224 | ||||
1225 | lset_t seen_attrs = LEMPTY((lset_t)0); | |||
1226 | lset_t seen_durations = LEMPTY((lset_t)0); | |||
1227 | bool_Bool ok = true1; | |||
1228 | #define UGH(FMT, ...){ ok = 0; log_state(RC_LOG_SERIOUS, st, FMT". Attribute %s", ..., enum_show(&oakley_attr_names, a.isaat_af_type)); } \ | |||
1229 | { \ | |||
1230 | ok = false0; \ | |||
1231 | log_state(RC_LOG_SERIOUS, st, \ | |||
1232 | FMT". Attribute %s", \ | |||
1233 | ##__VA_ARGS__, \ | |||
1234 | enum_show(&oakley_attr_names, a.isaat_af_type)); \ | |||
1235 | } | |||
1236 | ||||
1237 | while (pbs_left(&trans_pbs)((size_t)((&trans_pbs)->roof - (&trans_pbs)->cur )) >= isakmp_oakley_attribute_desc.size) { | |||
1238 | struct isakmp_attribute a; | |||
1239 | pb_stream attr_pbs; | |||
1240 | uint32_t val; /* room for larger values */ | |||
1241 | ||||
1242 | diag_t d = pbs_in_struct(&trans_pbs, &isakmp_oakley_attribute_desc, | |||
1243 | &a, sizeof(a), &attr_pbs); | |||
1244 | if (d != NULL((void*)0)) { | |||
1245 | log_diag(RC_LOG_SERIOUS, st->st_logger, &d, "invalid transform: "); | |||
1246 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1247 | } | |||
1248 | ||||
1249 | passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) <{ _Bool assertion__ = (a.isaat_af_type & 0x7FFF) < 64; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1250}, "%s", "(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < LELEM_ROOF" ); } } | |||
1250 | LELEM_ROOF){ _Bool assertion__ = (a.isaat_af_type & 0x7FFF) < 64; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1250}, "%s", "(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < LELEM_ROOF" ); } }; | |||
1251 | ||||
1252 | if (LHAS(seen_attrs, a.isaat_af_type &(((seen_attrs) & ((lset_t)1 << (a.isaat_af_type & 0x7FFF))) != ((lset_t)0)) | |||
1253 | ISAKMP_ATTR_RTYPE_MASK)(((seen_attrs) & ((lset_t)1 << (a.isaat_af_type & 0x7FFF))) != ((lset_t)0))) { | |||
1254 | log_state(RC_LOG_SERIOUS, st, | |||
1255 | "repeated %s attribute in Oakley Transform %u", | |||
1256 | enum_show(&oakley_attr_names, | |||
1257 | a.isaat_af_type), | |||
1258 | trans.isat_transnum); | |||
1259 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1260 | } | |||
1261 | ||||
1262 | seen_attrs |= LELEM(((lset_t)1 << (a.isaat_af_type & 0x7FFF)) | |||
1263 | a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK)((lset_t)1 << (a.isaat_af_type & 0x7FFF)); | |||
1264 | ||||
1265 | val = a.isaat_lv; | |||
1266 | ||||
1267 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
1268 | enum_names *vdesc = oakley_attr_val_descs | |||
1269 | [a.isaat_af_type & | |||
1270 | ISAKMP_ATTR_RTYPE_MASK0x7FFF]; | |||
1271 | ||||
1272 | if (vdesc != NULL((void*)0)) { | |||
1273 | const char *nm = | |||
1274 | enum_name(vdesc, | |||
1275 | val); | |||
1276 | ||||
1277 | if (nm != NULL((void*)0)) { | |||
1278 | DBG_log(" [%u is %s]", | |||
1279 | (unsigned)val, | |||
1280 | nm); | |||
1281 | } | |||
1282 | } | |||
1283 | } | |||
1284 | ||||
1285 | switch (a.isaat_af_type) { | |||
1286 | case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV0x8000: | |||
1287 | { | |||
1288 | const struct encrypt_desc *encrypter = ikev1_get_ike_encrypt_desc(val); | |||
1289 | if (encrypter == NULL((void*)0)) { | |||
1290 | UGH("%s is not supported",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "%s is not supported" ". Attribute %s", enum_show(&oakley_enc_names, val), enum_show (&oakley_attr_names, a.isaat_af_type)); } | |||
1291 | enum_show(&oakley_enc_names, val)){ ok = 0; log_state(RC_LOG_SERIOUS, st, "%s is not supported" ". Attribute %s", enum_show(&oakley_enc_names, val), enum_show (&oakley_attr_names, a.isaat_af_type)); }; | |||
1292 | break; | |||
1293 | } | |||
1294 | ta.ta_encrypt = encrypter; | |||
1295 | ta.enckeylen = ta.ta_encrypt->keydeflen; | |||
1296 | break; | |||
1297 | } | |||
1298 | ||||
1299 | case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV0x8000: | |||
1300 | ta.ta_prf = ikev1_get_ike_prf_desc(val); | |||
1301 | if (ta.ta_prf == NULL((void*)0)) { | |||
1302 | UGH("%s is not supported",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "%s is not supported" ". Attribute %s", enum_show(&oakley_hash_names, val), enum_show (&oakley_attr_names, a.isaat_af_type)); } | |||
1303 | enum_show(&oakley_hash_names, val)){ ok = 0; log_state(RC_LOG_SERIOUS, st, "%s is not supported" ". Attribute %s", enum_show(&oakley_hash_names, val), enum_show (&oakley_attr_names, a.isaat_af_type)); }; | |||
1304 | } | |||
1305 | break; | |||
1306 | ||||
1307 | case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV0x8000: | |||
1308 | { | |||
1309 | lset_t iap = st->st_policy & | |||
1310 | POLICY_ID_AUTH_MASK(((lset_t)1 << (POLICY_AUTH_NULL_IX)) - ((lset_t)1 << (POLICY_PSK_IX)) + ((lset_t)1 << (POLICY_AUTH_NULL_IX) )); | |||
1311 | ||||
1312 | /* check that authentication method is acceptable */ | |||
1313 | switch (val) { | |||
1314 | case XAUTHInitPreShared: | |||
1315 | if (!xauth_init) { | |||
1316 | UGH("policy does not allow Extended Authentication (XAUTH) of initiator (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1317 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1318 | break; | |||
1319 | } | |||
1320 | ta.doing_xauth = TRUE1; | |||
1321 | goto psk_common; | |||
1322 | ||||
1323 | case XAUTHRespPreShared: | |||
1324 | if (!xauth_resp) { | |||
1325 | UGH("policy does not allow Extended Authentication (XAUTH) of responder (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1326 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1327 | break; | |||
1328 | } | |||
1329 | ta.doing_xauth = TRUE1; | |||
1330 | goto psk_common; | |||
1331 | ||||
1332 | case OAKLEY_PRESHARED_KEY: | |||
1333 | if (xauth_init) { | |||
1334 | UGH("policy mandates Extended Authentication (XAUTH) with PSK of initiator (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with PSK of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1335 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with PSK of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1336 | break; | |||
1337 | } | |||
1338 | if (xauth_resp) { | |||
1339 | UGH("policy mandates Extended Authentication (XAUTH) with PSK of responder (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with PSK of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1340 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with PSK of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1341 | break; | |||
1342 | } | |||
1343 | psk_common: | |||
1344 | ||||
1345 | if ((iap & POLICY_PSK((lset_t)1 << (POLICY_PSK_IX))) == LEMPTY((lset_t)0)) { | |||
1346 | UGH("policy does not allow OAKLEY_PRESHARED_KEY authentication"){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow OAKLEY_PRESHARED_KEY authentication" ". Attribute %s", enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1347 | } else { | |||
1348 | /* check that we can find a proper preshared secret */ | |||
1349 | pss = get_psk(c, st->st_logger); | |||
1350 | ||||
1351 | if (pss == NULL((void*)0)) | |||
1352 | { | |||
1353 | id_buf mid; | |||
1354 | id_buf hid; | |||
1355 | ||||
1356 | UGH("Can't authenticate: no preshared key found for `%s' and `%s'",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "Can't authenticate: no preshared key found for `%s' and `%s'" ". Attribute %s", str_id(&c->spd.this.id, &mid), ( (c)->kind == CK_INSTANCE && ( !((&(c)->spd .that.id)->kind == ID_IPV4_ADDR || (&(c)->spd.that. id)->kind == ID_IPV6_ADDR) || sameaddr(&(c)->spd.that .id.ip_addr, &(c)->spd.that.host_addr) ) ) ? "%any" : str_id (&c->spd.that.id, &hid), enum_show(&oakley_attr_names , a.isaat_af_type)); } | |||
1357 | str_id(&c->spd.this.id, &mid),{ ok = 0; log_state(RC_LOG_SERIOUS, st, "Can't authenticate: no preshared key found for `%s' and `%s'" ". Attribute %s", str_id(&c->spd.this.id, &mid), ( (c)->kind == CK_INSTANCE && ( !((&(c)->spd .that.id)->kind == ID_IPV4_ADDR || (&(c)->spd.that. id)->kind == ID_IPV6_ADDR) || sameaddr(&(c)->spd.that .id.ip_addr, &(c)->spd.that.host_addr) ) ) ? "%any" : str_id (&c->spd.that.id, &hid), enum_show(&oakley_attr_names , a.isaat_af_type)); } | |||
1358 | remote_id_was_instantiated(c) ?{ ok = 0; log_state(RC_LOG_SERIOUS, st, "Can't authenticate: no preshared key found for `%s' and `%s'" ". Attribute %s", str_id(&c->spd.this.id, &mid), ( (c)->kind == CK_INSTANCE && ( !((&(c)->spd .that.id)->kind == ID_IPV4_ADDR || (&(c)->spd.that. id)->kind == ID_IPV6_ADDR) || sameaddr(&(c)->spd.that .id.ip_addr, &(c)->spd.that.host_addr) ) ) ? "%any" : str_id (&c->spd.that.id, &hid), enum_show(&oakley_attr_names , a.isaat_af_type)); } | |||
1359 | "%any" :{ ok = 0; log_state(RC_LOG_SERIOUS, st, "Can't authenticate: no preshared key found for `%s' and `%s'" ". Attribute %s", str_id(&c->spd.this.id, &mid), ( (c)->kind == CK_INSTANCE && ( !((&(c)->spd .that.id)->kind == ID_IPV4_ADDR || (&(c)->spd.that. id)->kind == ID_IPV6_ADDR) || sameaddr(&(c)->spd.that .id.ip_addr, &(c)->spd.that.host_addr) ) ) ? "%any" : str_id (&c->spd.that.id, &hid), enum_show(&oakley_attr_names , a.isaat_af_type)); } | |||
1360 | str_id(&c->spd.that.id, &hid)){ ok = 0; log_state(RC_LOG_SERIOUS, st, "Can't authenticate: no preshared key found for `%s' and `%s'" ". Attribute %s", str_id(&c->spd.this.id, &mid), ( (c)->kind == CK_INSTANCE && ( !((&(c)->spd .that.id)->kind == ID_IPV4_ADDR || (&(c)->spd.that. id)->kind == ID_IPV6_ADDR) || sameaddr(&(c)->spd.that .id.ip_addr, &(c)->spd.that.host_addr) ) ) ? "%any" : str_id (&c->spd.that.id, &hid), enum_show(&oakley_attr_names , a.isaat_af_type)); }; | |||
1361 | } else { | |||
1362 | DBG(DBG_PRIVATE, DBG_dump_hunk("User PSK:", *pss)){ if ((cur_debugging & (((lset_t)1 << (DBG_PRIVATE_IX ))))) { { typeof(*pss) hunk_ = *pss; DBG_dump("User PSK:", hunk_ .ptr, hunk_.len); }; } }; | |||
1363 | } | |||
1364 | ta.auth = OAKLEY_PRESHARED_KEY; | |||
1365 | } | |||
1366 | break; | |||
1367 | ||||
1368 | case XAUTHInitRSA: | |||
1369 | if (!xauth_init) { | |||
1370 | UGH("policy does not allow Extended Authentication (XAUTH) with RSA of initiator (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) with RSA of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1371 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) with RSA of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1372 | break; | |||
1373 | } | |||
1374 | ta.doing_xauth = TRUE1; | |||
1375 | goto rsasig_common; | |||
1376 | ||||
1377 | case XAUTHRespRSA: | |||
1378 | if (!xauth_resp) { | |||
1379 | UGH("policy does not allow Extended Authentication (XAUTH) with RSA of responder (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) with RSA of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1380 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow Extended Authentication (XAUTH) with RSA of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1381 | break; | |||
1382 | } | |||
1383 | ta.doing_xauth = TRUE1; | |||
1384 | goto rsasig_common; | |||
1385 | ||||
1386 | case OAKLEY_RSA_SIG: | |||
1387 | if (xauth_init) { | |||
1388 | UGH("policy mandates Extended Authentication (XAUTH) with RSA of initiator (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with RSA of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1389 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with RSA of initiator (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1390 | break; | |||
1391 | } | |||
1392 | if (xauth_resp) { | |||
1393 | UGH("policy mandates Extended Authentication (XAUTH) with RSA of responder (we are %s)",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with RSA of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); } | |||
1394 | role){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy mandates Extended Authentication (XAUTH) with RSA of responder (we are %s)" ". Attribute %s", role, enum_show(&oakley_attr_names, a. isaat_af_type)); }; | |||
1395 | break; | |||
1396 | } | |||
1397 | rsasig_common: | |||
1398 | /* Accept if policy specifies RSASIG or is default */ | |||
1399 | if ((iap & POLICY_RSASIG((lset_t)1 << (POLICY_RSASIG_IX))) == LEMPTY((lset_t)0)) { | |||
1400 | UGH("policy does not allow OAKLEY_RSA_SIG authentication"){ ok = 0; log_state(RC_LOG_SERIOUS, st, "policy does not allow OAKLEY_RSA_SIG authentication" ". Attribute %s", enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1401 | } else { | |||
1402 | /* We'd like to check | |||
1403 | * that we can find a | |||
1404 | * public key for peer | |||
1405 | * and a private key | |||
1406 | * for us that is | |||
1407 | * suitable, but we | |||
1408 | * don't yet have | |||
1409 | * peer's ID Payload, | |||
1410 | * so it seems futile | |||
1411 | * to try. We can | |||
1412 | * assume that if he | |||
1413 | * proposes it, he | |||
1414 | * thinks we've got | |||
1415 | * it. If we proposed | |||
1416 | * it, perhaps we know | |||
1417 | * what we're doing. | |||
1418 | */ | |||
1419 | ta.auth = OAKLEY_RSA_SIG; | |||
1420 | } | |||
1421 | break; | |||
1422 | ||||
1423 | default: | |||
1424 | UGH("Pluto does not support %s authentication",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "Pluto does not support %s authentication" ". Attribute %s", enum_show(&oakley_auth_names, val), enum_show (&oakley_attr_names, a.isaat_af_type)); } | |||
1425 | enum_show(&oakley_auth_names, val)){ ok = 0; log_state(RC_LOG_SERIOUS, st, "Pluto does not support %s authentication" ". Attribute %s", enum_show(&oakley_auth_names, val), enum_show (&oakley_attr_names, a.isaat_af_type)); }; | |||
1426 | break; | |||
1427 | } | |||
1428 | } | |||
1429 | break; | |||
1430 | ||||
1431 | case OAKLEY_GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV0x8000: | |||
1432 | ta.ta_dh = ikev1_get_ike_dh_desc(val); | |||
1433 | if (ta.ta_dh == NULL((void*)0)) { | |||
1434 | UGH("OAKLEY_GROUP %d not supported", val){ ok = 0; log_state(RC_LOG_SERIOUS, st, "OAKLEY_GROUP %d not supported" ". Attribute %s", val, enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1435 | break; | |||
1436 | } | |||
1437 | break; | |||
1438 | ||||
1439 | case OAKLEY_LIFE_TYPE | ISAKMP_ATTR_AF_TV0x8000: | |||
1440 | switch (val) { | |||
1441 | case OAKLEY_LIFE_SECONDS1: | |||
1442 | case OAKLEY_LIFE_KILOBYTES2: | |||
1443 | if (LHAS(seen_durations, val)(((seen_durations) & ((lset_t)1 << (val))) != ((lset_t )0))) { | |||
1444 | log_state(RC_LOG_SERIOUS, st, | |||
1445 | "attribute OAKLEY_LIFE_TYPE value %s repeated", | |||
1446 | enum_show(&oakley_lifetime_names, val)); | |||
1447 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1448 | } | |||
1449 | seen_durations |= LELEM(val)((lset_t)1 << (val)); | |||
1450 | life_type = val; | |||
1451 | break; | |||
1452 | default: | |||
1453 | UGH("unknown value %s",{ ok = 0; log_state(RC_LOG_SERIOUS, st, "unknown value %s"". Attribute %s" , enum_show(&oakley_lifetime_names, val), enum_show(& oakley_attr_names, a.isaat_af_type)); } | |||
1454 | enum_show(&oakley_lifetime_names, val)){ ok = 0; log_state(RC_LOG_SERIOUS, st, "unknown value %s"". Attribute %s" , enum_show(&oakley_lifetime_names, val), enum_show(& oakley_attr_names, a.isaat_af_type)); }; | |||
1455 | break; | |||
1456 | } | |||
1457 | break; | |||
1458 | ||||
1459 | case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TLV0: | |||
1460 | val = decode_long_duration(&attr_pbs); | |||
1461 | /* FALL THROUGH */ | |||
1462 | case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TV0x8000: | |||
1463 | if (!LHAS(seen_attrs, OAKLEY_LIFE_TYPE)(((seen_attrs) & ((lset_t)1 << (OAKLEY_LIFE_TYPE))) != ((lset_t)0))) { | |||
1464 | UGH("OAKLEY_LIFE_DURATION attribute not preceded by OAKLEY_LIFE_TYPE attribute"){ ok = 0; log_state(RC_LOG_SERIOUS, st, "OAKLEY_LIFE_DURATION attribute not preceded by OAKLEY_LIFE_TYPE attribute" ". Attribute %s", enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1465 | break; | |||
1466 | } | |||
1467 | seen_attrs &= | |||
1468 | ~(LELEM(OAKLEY_LIFE_DURATION)((lset_t)1 << (OAKLEY_LIFE_DURATION)) | | |||
1469 | LELEM(OAKLEY_LIFE_TYPE)((lset_t)1 << (OAKLEY_LIFE_TYPE))); | |||
1470 | ||||
1471 | switch (life_type) { | |||
1472 | case OAKLEY_LIFE_SECONDS1: | |||
1473 | if (val > IKE_SA_LIFETIME_MAXIMUMsecs_per_day) { | |||
1474 | log_state(RC_LOG, st, | |||
1475 | "warning: peer requested IKE lifetime of %" PRIu32"u" " seconds which we capped at our limit of %d seconds", | |||
1476 | val, IKE_SA_LIFETIME_MAXIMUMsecs_per_day); | |||
1477 | val = IKE_SA_LIFETIME_MAXIMUMsecs_per_day; | |||
1478 | } | |||
1479 | ta.life_seconds = deltatime(val); | |||
1480 | break; | |||
1481 | case OAKLEY_LIFE_KILOBYTES2: | |||
1482 | ta.life_kilobytes = val; | |||
1483 | break; | |||
1484 | default: | |||
1485 | bad_case(life_type)libreswan_bad_case("life_type", (life_type), (where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1485 }); | |||
1486 | } | |||
1487 | break; | |||
1488 | ||||
1489 | case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV0x8000: | |||
1490 | if (!LHAS(seen_attrs, OAKLEY_ENCRYPTION_ALGORITHM)(((seen_attrs) & ((lset_t)1 << (OAKLEY_ENCRYPTION_ALGORITHM ))) != ((lset_t)0))) { | |||
1491 | UGH("OAKLEY_KEY_LENGTH attribute not preceded by OAKLEY_ENCRYPTION_ALGORITHM attribute"){ ok = 0; log_state(RC_LOG_SERIOUS, st, "OAKLEY_KEY_LENGTH attribute not preceded by OAKLEY_ENCRYPTION_ALGORITHM attribute" ". Attribute %s", enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1492 | break; | |||
1493 | } | |||
1494 | /* because the encrypt algorithm wasn't valid? */ | |||
1495 | if (ta.ta_encrypt == NULL((void*)0)) { | |||
1496 | UGH("NULL encrypter with seen OAKLEY_ENCRYPTION_ALGORITHM"){ ok = 0; log_state(RC_LOG_SERIOUS, st, "NULL encrypter with seen OAKLEY_ENCRYPTION_ALGORITHM" ". Attribute %s", enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1497 | break; | |||
1498 | } | |||
1499 | /* | |||
1500 | * check if this keylen is compatible | |||
1501 | * with specified ike_proposals. | |||
1502 | */ | |||
1503 | if (!encrypt_has_key_bit_length(ta.ta_encrypt, val)) { | |||
1504 | UGH("peer proposed key_len not valid for encrypt algo setup specified"){ ok = 0; log_state(RC_LOG_SERIOUS, st, "peer proposed key_len not valid for encrypt algo setup specified" ". Attribute %s", enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1505 | break; | |||
1506 | } | |||
1507 | ||||
1508 | ta.enckeylen = val; | |||
1509 | break; | |||
1510 | ||||
1511 | default: | |||
1512 | UGH("unsupported OAKLEY attribute"){ ok = 0; log_state(RC_LOG_SERIOUS, st, "unsupported OAKLEY attribute" ". Attribute %s", enum_show(&oakley_attr_names, a.isaat_af_type )); }; | |||
1513 | break; | |||
1514 | } | |||
1515 | ||||
1516 | if (!ok) { | |||
1517 | break; | |||
1518 | } | |||
1519 | } | |||
1520 | ||||
1521 | /* If ugh != NULL, an attr error has been detected and reported */ | |||
1522 | ||||
1523 | /* | |||
1524 | * this do {} while (FALSE) construct allows code to use "break" | |||
1525 | * to reject this transform and to move on to next (if any). | |||
1526 | */ | |||
1527 | ||||
1528 | while (ok) { | |||
1529 | ||||
1530 | if ((st->st_policy & POLICY_PSK((lset_t)1 << (POLICY_PSK_IX))) && | |||
1531 | pss != &empty_chunk && | |||
1532 | pss != NULL((void*)0) && | |||
1533 | ta.ta_prf != NULL((void*)0)) { | |||
1534 | const size_t key_size_min = crypt_prf_fips_key_size_min(ta.ta_prf); | |||
1535 | ||||
1536 | if (pss->len < key_size_min) { | |||
1537 | if (libreswan_fipsmode()) { | |||
1538 | log_state(RC_LOG_SERIOUS, st, | |||
1539 | "FIPS Error: connection %s PSK length of %zu bytes is too short for %s PRF in FIPS mode (%zu bytes required)", | |||
1540 | st->st_connection->name, | |||
1541 | pss->len, | |||
1542 | ta.ta_prf->common.fqn, | |||
1543 | key_size_min); | |||
1544 | break; /* reject transform */ | |||
1545 | } else { | |||
1546 | log_state(RC_LOG, st, | |||
1547 | "WARNING: connection %s PSK length of %zu bytes is too short for %s PRF in FIPS mode (%zu bytes required)", | |||
1548 | st->st_connection->name, | |||
1549 | pss->len, | |||
1550 | ta.ta_prf->common.fqn, | |||
1551 | key_size_min); | |||
1552 | } | |||
1553 | } | |||
1554 | } | |||
1555 | ||||
1556 | /* | |||
1557 | * ML: at last check for allowed transforms in ike_proposals | |||
1558 | */ | |||
1559 | if (!ikev1_verify_ike(&ta, c->ike_proposals, st->st_logger)) { | |||
1560 | /* | |||
1561 | * already logged; UGH acts as a skip | |||
1562 | * rest of checks flag | |||
1563 | */ | |||
1564 | break; /* reject transform */ | |||
1565 | } | |||
1566 | ||||
1567 | /* a little more checking is in order */ | |||
1568 | { | |||
1569 | lset_t missing = | |||
1570 | ~seen_attrs & | |||
1571 | (LELEM(OAKLEY_ENCRYPTION_ALGORITHM)((lset_t)1 << (OAKLEY_ENCRYPTION_ALGORITHM)) | | |||
1572 | LELEM(OAKLEY_HASH_ALGORITHM)((lset_t)1 << (OAKLEY_HASH_ALGORITHM)) | | |||
1573 | LELEM(OAKLEY_AUTHENTICATION_METHOD)((lset_t)1 << (OAKLEY_AUTHENTICATION_METHOD)) | | |||
1574 | LELEM(OAKLEY_GROUP_DESCRIPTION)((lset_t)1 << (OAKLEY_GROUP_DESCRIPTION))); | |||
1575 | ||||
1576 | if (missing) { | |||
1577 | log_state(RC_LOG_SERIOUS, st, | |||
1578 | "missing mandatory attribute(s) %s in Oakley Transform %u", | |||
1579 | bitnamesof(oakley_attr_bit_names, missing), | |||
1580 | trans.isat_transnum); | |||
1581 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1582 | } | |||
1583 | } | |||
1584 | ||||
1585 | /* | |||
1586 | * We must have liked this transform. | |||
1587 | * Let's finish early and leave. | |||
1588 | */ | |||
1589 | ||||
1590 | dbg("Oakley Transform %u accepted", trans.isat_transnum){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Oakley Transform %u accepted", trans.isat_transnum ); } }; | |||
1591 | ||||
1592 | if (r_sa_pbs != NULL((void*)0)) { | |||
1593 | ||||
1594 | /* Situation */ | |||
1595 | passert(out_struct(&ipsecdoisit, &ipsec_sit_desc,{ _Bool assertion__ = out_struct(&ipsecdoisit, &ipsec_sit_desc , r_sa_pbs, ((void*)0)); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1596}, "%s", "out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)" ); } } | |||
1596 | r_sa_pbs, NULL)){ _Bool assertion__ = out_struct(&ipsecdoisit, &ipsec_sit_desc , r_sa_pbs, ((void*)0)); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1596}, "%s", "out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)" ); } }; | |||
1597 | ||||
1598 | /* Proposal */ | |||
1599 | struct isakmp_proposal r_proposal = proposal; | |||
1600 | r_proposal.isap_spisize = 0; | |||
1601 | r_proposal.isap_notrans = 1; | |||
1602 | pb_stream r_proposal_pbs; | |||
1603 | passert(out_struct(&r_proposal,{ _Bool assertion__ = out_struct(&r_proposal, &isakmp_proposal_desc , r_sa_pbs, &r_proposal_pbs); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1606}, "%s", "out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)" ); } } | |||
1604 | &isakmp_proposal_desc,{ _Bool assertion__ = out_struct(&r_proposal, &isakmp_proposal_desc , r_sa_pbs, &r_proposal_pbs); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1606}, "%s", "out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)" ); } } | |||
1605 | r_sa_pbs,{ _Bool assertion__ = out_struct(&r_proposal, &isakmp_proposal_desc , r_sa_pbs, &r_proposal_pbs); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1606}, "%s", "out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)" ); } } | |||
1606 | &r_proposal_pbs)){ _Bool assertion__ = out_struct(&r_proposal, &isakmp_proposal_desc , r_sa_pbs, &r_proposal_pbs); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1606}, "%s", "out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)" ); } }; | |||
1607 | ||||
1608 | /* Transform */ | |||
1609 | struct isakmp_transform r_trans = trans; | |||
1610 | r_trans.isat_tnp = ISAKMP_NEXT_NONE; | |||
1611 | pb_stream r_trans_pbs; | |||
1612 | passert(out_struct(&r_trans,{ _Bool assertion__ = out_struct(&r_trans, &isakmp_isakmp_transform_desc , &r_proposal_pbs, &r_trans_pbs); if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1615}, "%s", "out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs)" ); } } | |||
1613 | &isakmp_isakmp_transform_desc,{ _Bool assertion__ = out_struct(&r_trans, &isakmp_isakmp_transform_desc , &r_proposal_pbs, &r_trans_pbs); if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1615}, "%s", "out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs)" ); } } | |||
1614 | &r_proposal_pbs,{ _Bool assertion__ = out_struct(&r_trans, &isakmp_isakmp_transform_desc , &r_proposal_pbs, &r_trans_pbs); if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1615}, "%s", "out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs)" ); } } | |||
1615 | &r_trans_pbs)){ _Bool assertion__ = out_struct(&r_trans, &isakmp_isakmp_transform_desc , &r_proposal_pbs, &r_trans_pbs); if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1615}, "%s", "out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs)" ); } }; | |||
1616 | ||||
1617 | passert(out_raw(attr_start, attr_len,{ _Bool assertion__ = out_raw(attr_start, attr_len, &r_trans_pbs , "attributes"); if (!assertion__) { lsw_passert_fail((where_t ) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1618}, "%s", "out_raw(attr_start, attr_len, &r_trans_pbs, \"attributes\")" ); } } | |||
1618 | &r_trans_pbs, "attributes")){ _Bool assertion__ = out_raw(attr_start, attr_len, &r_trans_pbs , "attributes"); if (!assertion__) { lsw_passert_fail((where_t ) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1618}, "%s", "out_raw(attr_start, attr_len, &r_trans_pbs, \"attributes\")" ); } }; | |||
1619 | close_output_pbs(&r_trans_pbs); | |||
1620 | close_output_pbs(&r_proposal_pbs); | |||
1621 | close_output_pbs(r_sa_pbs); | |||
1622 | } | |||
1623 | ||||
1624 | /* ??? If selection, we used to save the proposal in state. | |||
1625 | * We never used it. From proposal_pbs.start, | |||
1626 | * length pbs_room(&proposal_pbs) | |||
1627 | */ | |||
1628 | ||||
1629 | /* copy over the results */ | |||
1630 | st->st_oakley = ta; | |||
1631 | return NOTHING_WRONG; /* accept SA */ | |||
1632 | } | |||
1633 | ||||
1634 | /* transform rejected: on to next transform */ | |||
1635 | ||||
1636 | no_trans_left--; | |||
1637 | ||||
1638 | if (trans.isat_tnp == ISAKMP_NEXT_NONE) { | |||
1639 | if (no_trans_left != 0) { | |||
1640 | log_state(RC_LOG_SERIOUS, st, | |||
1641 | "number of Transform Payloads disagrees with Oakley Proposal Payload"); | |||
1642 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1643 | } | |||
1644 | break; | |||
1645 | } | |||
1646 | if (trans.isat_tnp != ISAKMP_NEXT_T) { | |||
1647 | log_state(RC_LOG_SERIOUS, st, | |||
1648 | "unexpected %s payload in Oakley Proposal", | |||
1649 | enum_show(&ikev1_payload_names, proposal.isap_pnp)); | |||
1650 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
1651 | } | |||
1652 | } | |||
1653 | log_state(RC_LOG_SERIOUS, st, "no acceptable Oakley Transform"); | |||
1654 | return NO_PROPOSAL_CHOSEN; /* reject whole SA */ | |||
1655 | } | |||
1656 | ||||
1657 | /* Initialize st_oakley field of state for use when initiating in | |||
1658 | * aggressive mode. | |||
1659 | * | |||
1660 | * This should probably get more of its parameters, like what group to use, | |||
1661 | * from the connection specification, but it's not there yet. | |||
1662 | * This should ideally be done by passing them via whack. | |||
1663 | * | |||
1664 | */ | |||
1665 | ||||
1666 | /* XXX MCR. I suspect that actually all of this is redundant */ | |||
1667 | bool_Bool init_aggr_st_oakley(struct state *st, lset_t policy) | |||
1668 | { | |||
1669 | const struct connection *c = st->st_connection; | |||
1670 | ||||
1671 | /* | |||
1672 | * Construct the proposals by combining IKE_PROPOSALS with the | |||
1673 | * AUTH (proof of identity) extracted from the aggressive mode | |||
1674 | * SADB. As if by magic, attrs[2] is always the | |||
1675 | * authentication method. | |||
1676 | * | |||
1677 | * XXX: Should replace IKEv1_oakley_am_sadb() with a simple | |||
1678 | * map to the auth method. | |||
1679 | */ | |||
1680 | struct db_sa *revised_sadb; | |||
1681 | { | |||
1682 | const struct db_sa *sadb = IKEv1_oakley_am_sadb(policy, c); | |||
1683 | const struct db_attr *auth = &sadb->prop_conjs[0].props[0].trans[0].attrs[2]; | |||
1684 | passert(auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD){ _Bool assertion__ = auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1684}, "%s", "auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD" ); } }; | |||
1685 | enum ikev1_auth_method auth_method = auth->val; | |||
1686 | /* | |||
1687 | * Max transforms == 2 - Multiple transforms, 1 DH | |||
1688 | * group | |||
1689 | */ | |||
1690 | revised_sadb = v1_ike_alg_make_sadb(c->ike_proposals, | |||
1691 | auth_method, TRUE1, | |||
1692 | st->st_logger); | |||
1693 | } | |||
1694 | ||||
1695 | if (revised_sadb == NULL((void*)0)) | |||
1696 | return FALSE0; | |||
1697 | ||||
1698 | passert(revised_sadb->prop_conj_cnt == 1){ _Bool assertion__ = revised_sadb->prop_conj_cnt == 1; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1698}, "%s", "revised_sadb->prop_conj_cnt == 1" ); } }; | |||
1699 | const struct db_prop_conj *cprop = &revised_sadb->prop_conjs[0]; | |||
1700 | ||||
1701 | passert(cprop->prop_cnt == 1){ _Bool assertion__ = cprop->prop_cnt == 1; if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1701}, "%s", "cprop->prop_cnt == 1" ); } }; | |||
1702 | const struct db_prop *prop = &cprop->props[0]; | |||
1703 | ||||
1704 | const struct db_trans *trans = &prop->trans[0]; | |||
1705 | ||||
1706 | passert(trans->attr_cnt == 4 || trans->attr_cnt == 5){ _Bool assertion__ = trans->attr_cnt == 4 || trans->attr_cnt == 5; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1706 }, "%s", "trans->attr_cnt == 4 || trans->attr_cnt == 5" ); } }; | |||
1707 | ||||
1708 | const struct db_attr *enc = &trans->attrs[0]; | |||
1709 | const struct db_attr *hash = &trans->attrs[1]; | |||
1710 | const struct db_attr *auth = &trans->attrs[2]; | |||
1711 | const struct db_attr *grp = &trans->attrs[3]; | |||
1712 | ||||
1713 | dbg("initiating aggressive mode with IKE=E=%d-H=%d-M=%d",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("initiating aggressive mode with IKE=E=%d-H=%d-M=%d" , enc->val, hash->val, grp->val); } } | |||
1714 | enc->val, hash->val, grp->val){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("initiating aggressive mode with IKE=E=%d-H=%d-M=%d" , enc->val, hash->val, grp->val); } }; | |||
1715 | ||||
1716 | passert(enc->type.oakley == OAKLEY_ENCRYPTION_ALGORITHM){ _Bool assertion__ = enc->type.oakley == OAKLEY_ENCRYPTION_ALGORITHM ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1716}, "%s", "enc->type.oakley == OAKLEY_ENCRYPTION_ALGORITHM" ); } }; | |||
1717 | ||||
1718 | ||||
1719 | struct trans_attrs ta = { | |||
1720 | /* When this SA expires (seconds) */ | |||
1721 | .life_seconds = c->sa_ike_life_seconds, | |||
1722 | .life_kilobytes = 1000000, | |||
1723 | .ta_encrypt = ikev1_get_ike_encrypt_desc(enc->val) | |||
1724 | }; | |||
1725 | ||||
1726 | passert(ta.ta_encrypt != NULL){ _Bool assertion__ = ta.ta_encrypt != ((void*)0); if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1726}, "%s", "ta.ta_encrypt != NULL" ); } }; | |||
1727 | ||||
1728 | if (trans->attr_cnt == 5) { | |||
1729 | struct db_attr *enc_keylen; | |||
1730 | enc_keylen = &trans->attrs[4]; | |||
1731 | ta.enckeylen = enc_keylen->val; | |||
1732 | } else { | |||
1733 | ta.enckeylen = ta.ta_encrypt->keydeflen; | |||
1734 | } | |||
1735 | ||||
1736 | passert(hash->type.oakley == OAKLEY_HASH_ALGORITHM){ _Bool assertion__ = hash->type.oakley == OAKLEY_HASH_ALGORITHM ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1736}, "%s", "hash->type.oakley == OAKLEY_HASH_ALGORITHM" ); } }; | |||
1737 | ta.ta_prf = ikev1_get_ike_prf_desc(hash->val); | |||
1738 | passert(ta.ta_prf != NULL){ _Bool assertion__ = ta.ta_prf != ((void*)0); if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1738}, "%s", "ta.ta_prf != NULL" ); } }; | |||
1739 | ||||
1740 | passert(auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD){ _Bool assertion__ = auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1740}, "%s", "auth->type.oakley == OAKLEY_AUTHENTICATION_METHOD" ); } }; | |||
1741 | ta.auth = auth->val; /* OAKLEY_AUTHENTICATION_METHOD */ | |||
1742 | ||||
1743 | passert(grp->type.oakley == OAKLEY_GROUP_DESCRIPTION){ _Bool assertion__ = grp->type.oakley == OAKLEY_GROUP_DESCRIPTION ; if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1743}, "%s", "grp->type.oakley == OAKLEY_GROUP_DESCRIPTION" ); } }; | |||
1744 | ta.ta_dh = ikev1_get_ike_dh_desc(grp->val); /* OAKLEY_GROUP_DESCRIPTION */ | |||
1745 | passert(ta.ta_dh != NULL){ _Bool assertion__ = ta.ta_dh != ((void*)0); if (!assertion__ ) { lsw_passert_fail((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1745}, "%s", "ta.ta_dh != NULL" ); } }; | |||
1746 | ||||
1747 | st->st_oakley = ta; | |||
1748 | ||||
1749 | return TRUE1; | |||
1750 | } | |||
1751 | ||||
1752 | /** | |||
1753 | * Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode). | |||
1754 | * | |||
1755 | * The main routine is parse_ipsec_sa_body; other functions defined | |||
1756 | * between here and there are just helpers. | |||
1757 | * | |||
1758 | * Various shortcuts are taken. In particular, the policy, such as | |||
1759 | * it is, is hardwired. | |||
1760 | * | |||
1761 | * If r_sa is non-NULL, the body of an SA representing the selected | |||
1762 | * proposal is emitted into it. | |||
1763 | * | |||
1764 | * If "selection" is true, the SA is supposed to represent the | |||
1765 | * single transform that the peer has accepted. | |||
1766 | * ??? We only check that it is acceptable, not that it is one that we offered! | |||
1767 | * | |||
1768 | * Only IPsec DOI is accepted (what is the ISAKMP DOI?). | |||
1769 | * Error response is rudimentary. | |||
1770 | * | |||
1771 | * Since all ISAKMP groups in all SA Payloads must match, st->st_pfs_group | |||
1772 | * holds this across multiple payloads. | |||
1773 | * &unset_group signifies not yet "set"; NULL signifies NONE. | |||
1774 | * | |||
1775 | * This routine is used by quick_inI1_outR1() and quick_inR1_outI2(). | |||
1776 | */ | |||
1777 | ||||
1778 | static bool_Bool parse_ipsec_transform(struct isakmp_transform *trans, | |||
1779 | struct ipsec_trans_attrs *attrs, | |||
1780 | pb_stream *prop_pbs, | |||
1781 | pb_stream *trans_pbs, | |||
1782 | struct_desc *trans_desc, | |||
1783 | int previous_transnum, /* or -1 if none */ | |||
1784 | bool_Bool selection, | |||
1785 | bool_Bool is_last, | |||
1786 | uint8_t proto, | |||
1787 | struct state *st) /* current state object */ | |||
1788 | { | |||
1789 | lset_t seen_attrs = LEMPTY((lset_t)0), | |||
1790 | seen_durations = LEMPTY((lset_t)0); | |||
1791 | bool_Bool seen_secctx_attr = FALSE0; | |||
1792 | uint16_t life_type = 0; /* initialized to silence GCC */ | |||
1793 | const struct dh_desc *pfs_group = NULL((void*)0); | |||
1794 | ||||
1795 | if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs)) | |||
| ||||
1796 | return FALSE0; | |||
1797 | ||||
1798 | if (trans->isat_transnum <= previous_transnum) { | |||
1799 | loglog(RC_LOG_SERIOUS, | |||
1800 | "Transform Numbers in Proposal are not monotonically increasing"); | |||
1801 | return FALSE0; | |||
1802 | } | |||
1803 | ||||
1804 | switch (trans->isat_tnp) { | |||
1805 | case ISAKMP_NEXT_T: | |||
1806 | if (is_last) { | |||
1807 | loglog(RC_LOG_SERIOUS, | |||
1808 | "Proposal Payload has more Transforms than specified"); | |||
1809 | return FALSE0; | |||
1810 | } | |||
1811 | break; | |||
1812 | case ISAKMP_NEXT_NONE: | |||
1813 | if (!is_last) { | |||
1814 | loglog(RC_LOG_SERIOUS, | |||
1815 | "Proposal Payload has fewer Transforms than specified"); | |||
1816 | return FALSE0; | |||
1817 | } | |||
1818 | break; | |||
1819 | default: | |||
1820 | loglog(RC_LOG_SERIOUS, | |||
1821 | "expecting Transform Payload, but found %s in Proposal", | |||
1822 | enum_show(&ikev1_payload_names, trans->isat_tnp)); | |||
1823 | return FALSE0; | |||
1824 | } | |||
1825 | ||||
1826 | *attrs = (struct ipsec_trans_attrs) { | |||
1827 | .spi = 0, /* spi */ | |||
1828 | .life_seconds = DELTATIME_INIT(IPSEC_SA_LIFETIME_DEFAULT){ .dt = { .tv_sec = (secs_per_hour * 8), } }, /* life_seconds */ | |||
1829 | .life_kilobytes = SA_LIFE_DURATION_K_DEFAULT0xFFFFFFFFlu, /* life_kilobytes */ | |||
1830 | .mode = ENCAPSULATION_MODE_UNSPECIFIED0, /* encapsulation */ | |||
1831 | }; | |||
1832 | ||||
1833 | switch (proto) { | |||
1834 | case PROTO_IPCOMP4: | |||
1835 | attrs->transattrs.ta_comp = trans->isat_transid; | |||
1836 | break; | |||
1837 | case PROTO_IPSEC_ESP3: | |||
1838 | attrs->transattrs.ta_encrypt = ikev1_get_kernel_encrypt_desc(trans->isat_transid); | |||
1839 | break; | |||
1840 | case PROTO_IPSEC_AH2: | |||
1841 | break; | |||
1842 | default: | |||
1843 | bad_case(proto)libreswan_bad_case("proto", (proto), (where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1843}); | |||
1844 | } | |||
1845 | ||||
1846 | while (pbs_left(trans_pbs)((size_t)((trans_pbs)->roof - (trans_pbs)->cur)) >= isakmp_ipsec_attribute_desc.size) { | |||
1847 | struct isakmp_attribute a; | |||
1848 | pb_stream attr_pbs; | |||
1849 | enum_names *vdesc; | |||
1850 | uint16_t ty; | |||
1851 | uint32_t val; /* room for larger value */ | |||
1852 | bool_Bool ipcomp_inappropriate = (proto == PROTO_IPCOMP4); /* will get reset if OK */ | |||
1853 | ||||
1854 | if (!in_struct(&a, &isakmp_ipsec_attribute_desc, trans_pbs, | |||
1855 | &attr_pbs)) | |||
1856 | return FALSE0; | |||
1857 | ||||
1858 | ty = a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK0x7FFF; | |||
1859 | val = a.isaat_lv; | |||
1860 | ||||
1861 | if (ty == secctx_attr_type) { | |||
1862 | if (seen_secctx_attr) { | |||
1863 | loglog(RC_LOG_SERIOUS, | |||
1864 | "repeated SECCTX attribute in IPsec Transform %u", | |||
1865 | trans->isat_transnum); | |||
1866 | return FALSE0; | |||
1867 | } | |||
1868 | seen_secctx_attr = TRUE1; | |||
1869 | vdesc = NULL((void*)0); | |||
1870 | } else { | |||
1871 | passert(ty < LELEM_ROOF){ _Bool assertion__ = ty < 64; if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1871}, "%s", "ty < LELEM_ROOF"); } }; | |||
1872 | if (LHAS(seen_attrs, ty)(((seen_attrs) & ((lset_t)1 << (ty))) != ((lset_t)0 ))) { | |||
1873 | loglog(RC_LOG_SERIOUS, | |||
1874 | "repeated %s attribute in IPsec Transform %u", | |||
1875 | enum_show(&ipsec_attr_names, a.isaat_af_type), | |||
1876 | trans->isat_transnum); | |||
1877 | return FALSE0; | |||
1878 | } | |||
1879 | ||||
1880 | seen_attrs |= LELEM(ty)((lset_t)1 << (ty)); | |||
1881 | passert(ty < ipsec_attr_val_descs_roof){ _Bool assertion__ = ty < ipsec_attr_val_descs_roof; if ( !assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 1881}, "%s", "ty < ipsec_attr_val_descs_roof" ); } }; | |||
1882 | vdesc = ipsec_attr_val_descs[ty]; | |||
1883 | } | |||
1884 | ||||
1885 | if (vdesc != NULL((void*)0)) { | |||
1886 | /* reject unknown enum values */ | |||
1887 | if (enum_name(vdesc, val) == NULL((void*)0)) { | |||
1888 | loglog(RC_LOG_SERIOUS, | |||
1889 | "invalid value %" PRIu32"u" " for attribute %s in IPsec Transform", | |||
1890 | val, | |||
1891 | enum_show(&ipsec_attr_names, | |||
1892 | a.isaat_af_type)); | |||
1893 | return FALSE0; | |||
1894 | } | |||
1895 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
1896 | if ((a.isaat_af_type & | |||
1897 | ISAKMP_ATTR_AF_MASK0x8000) == | |||
1898 | ISAKMP_ATTR_AF_TV0x8000) { | |||
1899 | DBG_log(" [%" PRIu32"u" " is %s]", | |||
1900 | val, | |||
1901 | enum_show(vdesc, val)); | |||
1902 | } | |||
1903 | } | |||
1904 | } | |||
1905 | ||||
1906 | switch (a.isaat_af_type) { | |||
1907 | case SA_LIFE_TYPE | ISAKMP_ATTR_AF_TV0x8000: | |||
1908 | ipcomp_inappropriate = FALSE0; | |||
1909 | if (LHAS(seen_durations, val)(((seen_durations) & ((lset_t)1 << (val))) != ((lset_t )0))) { | |||
1910 | loglog(RC_LOG_SERIOUS, | |||
1911 | "attribute SA_LIFE_TYPE value %s repeated in message", | |||
1912 | enum_show(&sa_lifetime_names, val)); | |||
1913 | return FALSE0; | |||
1914 | } | |||
1915 | seen_durations |= LELEM(val)((lset_t)1 << (val)); | |||
1916 | life_type = val; | |||
1917 | break; | |||
1918 | ||||
1919 | case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV0: | |||
1920 | val = decode_long_duration(&attr_pbs); | |||
1921 | /* FALL THROUGH */ | |||
1922 | case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TV0x8000: | |||
1923 | ipcomp_inappropriate = FALSE0; | |||
1924 | if (!LHAS(seen_attrs, SA_LIFE_TYPE)(((seen_attrs) & ((lset_t)1 << (SA_LIFE_TYPE))) != ( (lset_t)0))) { | |||
1925 | loglog(RC_LOG_SERIOUS, | |||
1926 | "SA_LIFE_DURATION IPsec attribute not preceded by SA_LIFE_TYPE attribute"); | |||
1927 | return FALSE0; | |||
1928 | } | |||
1929 | seen_attrs &= | |||
1930 | ~(LELEM(SA_LIFE_DURATION)((lset_t)1 << (SA_LIFE_DURATION)) | | |||
1931 | LELEM(SA_LIFE_TYPE)((lset_t)1 << (SA_LIFE_TYPE))); | |||
1932 | ||||
1933 | switch (life_type) { | |||
1934 | case SA_LIFE_TYPE_SECONDS1: | |||
1935 | { | |||
1936 | /* | |||
1937 | * Silently limit duration to our maximum. | |||
1938 | * | |||
1939 | * Note: | |||
1940 | * | |||
1941 | * GCC now complains about comparisons between | |||
1942 | * signed and unsigned values. This is good: | |||
1943 | * should the comparison be done as if the | |||
1944 | * unsigned representation were signed or as if | |||
1945 | * the signed representation were unsigned? | |||
1946 | * The C standard has an arbitrary answer. | |||
1947 | * So GCC's warning should be heeded. | |||
1948 | * | |||
1949 | * We know that time_t can represent all | |||
1950 | * values between 0 and SA_LIFE_DURATION_MAXIMUM. | |||
1951 | * It is safe to cast val (of type uint32_t) | |||
1952 | * to time_t (some signed type) AFTER checking | |||
1953 | * that val does not exceed | |||
1954 | * SA_LIFE_DURATION_MAXIMUM. | |||
1955 | */ | |||
1956 | unsigned int lifemax = IPSEC_SA_LIFETIME_MAXIMUMsecs_per_day; | |||
1957 | if (libreswan_fipsmode()) | |||
1958 | lifemax = FIPS_IPSEC_SA_LIFETIME_MAXIMUMsecs_per_hour * 8; | |||
1959 | attrs->life_seconds = val > lifemax ? | |||
1960 | deltatime(lifemax) : | |||
1961 | (time_t)val > deltasecs(st->st_connection->sa_ipsec_life_seconds) ? | |||
1962 | st->st_connection->sa_ipsec_life_seconds : | |||
1963 | deltatime(val); | |||
1964 | break; | |||
1965 | } | |||
1966 | case SA_LIFE_TYPE_KBYTES2: | |||
1967 | attrs->life_kilobytes = val; | |||
1968 | break; | |||
1969 | default: | |||
1970 | bad_case(life_type)libreswan_bad_case("life_type", (life_type), (where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 1970 }); | |||
1971 | } | |||
1972 | break; | |||
1973 | ||||
1974 | case GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV0x8000: | |||
1975 | if (proto == PROTO_IPCOMP4) { | |||
1976 | /* Accept reluctantly. Should not happen, according to | |||
1977 | * draft-shacham-ippcp-rfc2393bis-05.txt 4.1. | |||
1978 | */ | |||
1979 | ipcomp_inappropriate = FALSE0; | |||
1980 | loglog(RC_COMMENT, | |||
1981 | "IPCA (IPcomp SA) contains GROUP_DESCRIPTION. Ignoring inappropriate attribute."); | |||
1982 | } | |||
1983 | pfs_group = ikev1_get_ike_dh_desc(val); | |||
1984 | if (pfs_group == NULL((void*)0)) { | |||
1985 | loglog(RC_LOG_SERIOUS, | |||
1986 | "OAKLEY_GROUP %" PRIu32"u" " not supported for PFS", | |||
1987 | val); | |||
1988 | return FALSE0; | |||
1989 | } | |||
1990 | break; | |||
1991 | ||||
1992 | case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV0x8000: | |||
1993 | ipcomp_inappropriate = FALSE0; | |||
1994 | switch (val) { | |||
1995 | case ENCAPSULATION_MODE_TUNNEL1: | |||
1996 | case ENCAPSULATION_MODE_TRANSPORT2: | |||
1997 | dbg("NAT-T non-encap: Installing IPsec SA without ENCAP, st->hidden_variables.st_nat_traversal is %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T non-encap: Installing IPsec SA without ENCAP, st->hidden_variables.st_nat_traversal is %s" , bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal )); } } | |||
1998 | bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T non-encap: Installing IPsec SA without ENCAP, st->hidden_variables.st_nat_traversal is %s" , bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal )); } }; | |||
1999 | break; | |||
2000 | ||||
2001 | case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS61444: | |||
2002 | case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS61443: | |||
2003 | dbg("NAT-T draft: Installing IPsec SA with ENCAP, st->hidden_variables.st_nat_traversal is %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T draft: Installing IPsec SA with ENCAP, st->hidden_variables.st_nat_traversal is %s" , bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal )); } } | |||
2004 | bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T draft: Installing IPsec SA with ENCAP, st->hidden_variables.st_nat_traversal is %s" , bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal )); } }; | |||
2005 | break; | |||
2006 | ||||
2007 | case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC4: | |||
2008 | case ENCAPSULATION_MODE_UDP_TUNNEL_RFC3: | |||
2009 | dbg("NAT-T RFC: Installing IPsec SA with ENCAP, st->hidden_variables.st_nat_traversal is %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T RFC: Installing IPsec SA with ENCAP, st->hidden_variables.st_nat_traversal is %s" , bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal )); } } | |||
2010 | bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT-T RFC: Installing IPsec SA with ENCAP, st->hidden_variables.st_nat_traversal is %s" , bitnamesof(natt_bit_names, st->hidden_variables.st_nat_traversal )); } }; | |||
2011 | break; | |||
2012 | ||||
2013 | default: | |||
2014 | /* should already be filtered out by enum checker */ | |||
2015 | bad_case(val)libreswan_bad_case("val", (val), (where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 2015}); | |||
2016 | } | |||
2017 | ||||
2018 | /* normalize the actual attribute value */ | |||
2019 | switch (val) { | |||
2020 | case ENCAPSULATION_MODE_TRANSPORT2: | |||
2021 | case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS61444: | |||
2022 | case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC4: | |||
2023 | val = ENCAPSULATION_MODE_TRANSPORT2; | |||
2024 | break; | |||
2025 | case ENCAPSULATION_MODE_TUNNEL1: | |||
2026 | case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS61443: | |||
2027 | case ENCAPSULATION_MODE_UDP_TUNNEL_RFC3: | |||
2028 | val = ENCAPSULATION_MODE_TUNNEL1; | |||
2029 | break; | |||
2030 | } | |||
2031 | attrs->mode = val; | |||
2032 | break; | |||
2033 | ||||
2034 | case AUTH_ALGORITHM | ISAKMP_ATTR_AF_TV0x8000: | |||
2035 | attrs->transattrs.ta_integ = ikev1_get_kernel_integ_desc(val); | |||
2036 | if (attrs->transattrs.ta_integ == NULL((void*)0)) { | |||
2037 | /* | |||
2038 | * Caller will also see NULL and | |||
2039 | * assume that things should stumble | |||
2040 | * on to the next algorithm. | |||
2041 | * | |||
2042 | * Either straight AH, or ESP | |||
2043 | * containing AUTH; or what? | |||
2044 | */ | |||
2045 | loglog(RC_LOG_SERIOUS, | |||
2046 | "IKEv1 %s integrity algorithm %s not supported", | |||
2047 | (proto == PROTO_IPSEC_ESP3 ? "ESP" : "AH"), | |||
2048 | enum_show(&ah_transformid_names, val)); | |||
2049 | } | |||
2050 | break; | |||
2051 | ||||
2052 | case KEY_LENGTH | ISAKMP_ATTR_AF_TV0x8000: | |||
2053 | if (attrs->transattrs.ta_encrypt == NULL((void*)0)) { | |||
2054 | loglog(RC_LOG_SERIOUS, | |||
2055 | "IKEv1 key-length attribute without encryption algorithm"); | |||
2056 | return false0; | |||
2057 | } | |||
2058 | if (!encrypt_has_key_bit_length(attrs->transattrs.ta_encrypt, val)) { | |||
2059 | loglog(RC_LOG_SERIOUS, | |||
2060 | "IKEv1 key-length attribute without encryption algorithm"); | |||
2061 | return false0; | |||
2062 | } | |||
2063 | attrs->transattrs.enckeylen = val; | |||
2064 | break; | |||
2065 | ||||
2066 | default: | |||
2067 | if (a.isaat_af_type == | |||
2068 | (secctx_attr_type | ISAKMP_ATTR_AF_TLV0)) { | |||
2069 | pb_stream *pbs = &attr_pbs; | |||
2070 | ||||
2071 | if (!parse_secctx_attr(pbs, st)) | |||
2072 | return FALSE0; | |||
2073 | } else { | |||
2074 | loglog(RC_LOG_SERIOUS, | |||
2075 | "unsupported IPsec attribute %s", | |||
2076 | enum_show(&ipsec_attr_names, a.isaat_af_type)); | |||
2077 | return FALSE0; | |||
2078 | } | |||
2079 | } | |||
2080 | ||||
2081 | if (ipcomp_inappropriate) { | |||
2082 | loglog(RC_LOG_SERIOUS, | |||
2083 | "IPsec attribute %s inappropriate for IPCOMP", | |||
2084 | enum_show(&ipsec_attr_names, a.isaat_af_type)); | |||
2085 | return FALSE0; | |||
2086 | } | |||
2087 | } | |||
2088 | ||||
2089 | /* Although an IPCOMP SA (IPCA) ought not to have a pfs_group, | |||
2090 | * if it does, demand that it be consistent. | |||
2091 | * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1. | |||
2092 | */ | |||
2093 | if (proto != PROTO_IPCOMP4 || pfs_group != NULL((void*)0)) { | |||
2094 | if (st->st_pfs_group == &unset_group) | |||
2095 | st->st_pfs_group = pfs_group; | |||
2096 | ||||
2097 | if (st->st_pfs_group != pfs_group) { | |||
2098 | loglog(RC_LOG_SERIOUS, | |||
2099 | "GROUP_DESCRIPTION inconsistent with that of %s in IPsec SA", | |||
2100 | selection ? "the Proposal" : "a previous Transform"); | |||
2101 | return FALSE0; | |||
2102 | } | |||
2103 | } | |||
2104 | ||||
2105 | if (LHAS(seen_attrs, SA_LIFE_DURATION)(((seen_attrs) & ((lset_t)1 << (SA_LIFE_DURATION))) != ((lset_t)0))) { | |||
2106 | loglog(RC_LOG_SERIOUS, | |||
2107 | "SA_LIFE_TYPE IPsec attribute not followed by SA_LIFE_DURATION attribute in message"); | |||
2108 | return FALSE0; | |||
2109 | } | |||
2110 | ||||
2111 | if (!LHAS(seen_attrs, ENCAPSULATION_MODE)(((seen_attrs) & ((lset_t)1 << (ENCAPSULATION_MODE) )) != ((lset_t)0))) { | |||
2112 | if (proto == PROTO_IPCOMP4) { | |||
2113 | /* draft-shacham-ippcp-rfc2393bis-05.txt 4.1: | |||
2114 | * "If the Encapsulation Mode is unspecified, | |||
2115 | * the default value of Transport Mode is assumed." | |||
2116 | * This contradicts/overrides the DOI (quoted below). | |||
2117 | */ | |||
2118 | attrs->mode = ENCAPSULATION_MODE_TRANSPORT2; | |||
2119 | } else { | |||
2120 | /* ??? Technically, RFC 2407 (IPSEC DOI) 4.5 specifies that | |||
2121 | * the default is "unspecified (host-dependent)". | |||
2122 | * This makes little sense, so we demand that it be specified. | |||
2123 | */ | |||
2124 | loglog(RC_LOG_SERIOUS, | |||
2125 | "IPsec Transform must specify ENCAPSULATION_MODE"); | |||
2126 | return FALSE0; | |||
2127 | } | |||
2128 | } | |||
2129 | ||||
2130 | /* | |||
2131 | * For ESP, check if the encryption key length is required. | |||
2132 | * | |||
2133 | * If a required key length was missing force the proposal to | |||
2134 | * be rejected by settinf .ta_encrypt=NULL. | |||
2135 | * | |||
2136 | * If an optional key-length is missing set it to the correct | |||
2137 | * value (.keydeflen) (which can be 0). This is safe since | |||
2138 | * the code echoing back the proposal never emits a keylen | |||
2139 | * when .keylen_omitted | |||
2140 | */ | |||
2141 | if (proto == PROTO_IPSEC_ESP3 && !LHAS(seen_attrs, KEY_LENGTH)(((seen_attrs) & ((lset_t)1 << (KEY_LENGTH))) != (( lset_t)0)) && | |||
2142 | attrs->transattrs.ta_encrypt != NULL((void*)0)) { | |||
2143 | if (attrs->transattrs.ta_encrypt->keylen_omitted) { | |||
2144 | attrs->transattrs.enckeylen = attrs->transattrs.ta_encrypt->keydeflen; | |||
2145 | } else { | |||
2146 | /* ealg requires a key length attr */ | |||
2147 | loglog(RC_LOG_SERIOUS, | |||
2148 | "IPsec encryption transform %s did not specify required KEY_LENGTH attribute", | |||
2149 | attrs->transattrs.ta_encrypt->common.fqn); | |||
2150 | attrs->transattrs.ta_encrypt = NULL((void*)0); /* force rejection */ | |||
2151 | } | |||
2152 | } | |||
2153 | ||||
2154 | /* | |||
2155 | * For ESP, if the integrity algorithm (AUTH_ALGORITHM) was | |||
2156 | * completely missing, set it to NONE. | |||
2157 | * | |||
2158 | * This way the caller has sufficient information to | |||
2159 | * differentiate between missing integrity (NONE) and unknown | |||
2160 | * integrity (NULL) and decide if the proposals combination of | |||
2161 | * ESP/AH AEAD and NONE is valid. | |||
2162 | * | |||
2163 | * For instance, AEAD+[NONE]. | |||
2164 | */ | |||
2165 | if (proto == PROTO_IPSEC_ESP3 && !LHAS(seen_attrs, AUTH_ALGORITHM)(((seen_attrs) & ((lset_t)1 << (AUTH_ALGORITHM))) != ((lset_t)0))) { | |||
2166 | dbg("ES missing INTEG aka AUTH, setting it to NONE"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ES missing INTEG aka AUTH, setting it to NONE" ); } }; | |||
2167 | attrs->transattrs.ta_integ = &ike_alg_integ_none; | |||
2168 | } | |||
2169 | ||||
2170 | if (proto == PROTO_IPSEC_AH2) { | |||
2171 | if (!LHAS(seen_attrs, AUTH_ALGORITHM)(((seen_attrs) & ((lset_t)1 << (AUTH_ALGORITHM))) != ((lset_t)0))) { | |||
2172 | loglog(RC_LOG_SERIOUS, | |||
2173 | "AUTH_ALGORITHM attribute missing in AH Transform"); | |||
2174 | return false0; | |||
2175 | } | |||
2176 | } | |||
2177 | ||||
2178 | return TRUE1; | |||
2179 | } | |||
2180 | ||||
2181 | static void echo_proposal(struct isakmp_proposal r_proposal, /* proposal to emit */ | |||
2182 | struct isakmp_transform r_trans, /* winning transformation within it */ | |||
2183 | uint8_t pnp, /* Next Payload for proposal */ | |||
2184 | pb_stream *r_sa_pbs, /* SA PBS into which to emit */ | |||
2185 | struct ipsec_proto_info *pi, /* info about this protocol instance */ | |||
2186 | struct_desc *trans_desc, /* descriptor for this transformation */ | |||
2187 | pb_stream *trans_pbs, /* PBS for incoming transform */ | |||
2188 | const struct spd_route *sr, /* host details for the association */ | |||
2189 | bool_Bool tunnel_mode) /* true for inner most tunnel SA */ | |||
2190 | { | |||
2191 | pb_stream r_proposal_pbs; | |||
2192 | pb_stream r_trans_pbs; | |||
2193 | ||||
2194 | /* Proposal */ | |||
2195 | r_proposal.isap_pnp = pnp; | |||
2196 | r_proposal.isap_notrans = 1; | |||
2197 | passert(out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs,{ _Bool assertion__ = out_struct(&r_proposal, &isakmp_proposal_desc , r_sa_pbs, &r_proposal_pbs); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2198}, "%s", "out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)" ); } } | |||
2198 | &r_proposal_pbs)){ _Bool assertion__ = out_struct(&r_proposal, &isakmp_proposal_desc , r_sa_pbs, &r_proposal_pbs); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2198}, "%s", "out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)" ); } }; | |||
2199 | ||||
2200 | /* allocate and emit our CPI/SPI */ | |||
2201 | if (r_proposal.isap_protoid == PROTO_IPCOMP4) { | |||
2202 | /* CPI is stored in network low order end of an | |||
2203 | * ipsec_spi_t. So we start a couple of bytes in. | |||
2204 | * Note: we may fail to generate a satisfactory CPI, | |||
2205 | * but we'll ignore that. | |||
2206 | */ | |||
2207 | pi->our_spi = get_my_cpi(sr, tunnel_mode); | |||
2208 | passert(out_raw((u_char *) &pi->our_spi +{ _Bool assertion__ = out_raw((u_char *) &pi->our_spi + 4 - 2, 2, &r_proposal_pbs, "CPI"); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2211}, "%s", "out_raw((u_char *) &pi->our_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE, IPCOMP_CPI_SIZE, &r_proposal_pbs, \"CPI\")" ); } } | |||
2209 | IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE,{ _Bool assertion__ = out_raw((u_char *) &pi->our_spi + 4 - 2, 2, &r_proposal_pbs, "CPI"); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2211}, "%s", "out_raw((u_char *) &pi->our_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE, IPCOMP_CPI_SIZE, &r_proposal_pbs, \"CPI\")" ); } } | |||
2210 | IPCOMP_CPI_SIZE,{ _Bool assertion__ = out_raw((u_char *) &pi->our_spi + 4 - 2, 2, &r_proposal_pbs, "CPI"); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2211}, "%s", "out_raw((u_char *) &pi->our_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE, IPCOMP_CPI_SIZE, &r_proposal_pbs, \"CPI\")" ); } } | |||
2211 | &r_proposal_pbs, "CPI")){ _Bool assertion__ = out_raw((u_char *) &pi->our_spi + 4 - 2, 2, &r_proposal_pbs, "CPI"); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2211}, "%s", "out_raw((u_char *) &pi->our_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE, IPCOMP_CPI_SIZE, &r_proposal_pbs, \"CPI\")" ); } }; | |||
2212 | } else { | |||
2213 | pi->our_spi = get_ipsec_spi(pi->attrs.spi, | |||
2214 | r_proposal.isap_protoid == PROTO_IPSEC_AH2 ? | |||
2215 | &ip_protocol_ah : &ip_protocol_esp, | |||
2216 | sr, | |||
2217 | tunnel_mode); | |||
2218 | /* XXX should check for errors */ | |||
2219 | passert(out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE,{ _Bool assertion__ = out_raw((u_char *) &pi->our_spi, 4, &r_proposal_pbs, "SPI"); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2220}, "%s", "out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE, &r_proposal_pbs, \"SPI\")" ); } } | |||
2220 | &r_proposal_pbs, "SPI")){ _Bool assertion__ = out_raw((u_char *) &pi->our_spi, 4, &r_proposal_pbs, "SPI"); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2220}, "%s", "out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE, &r_proposal_pbs, \"SPI\")" ); } }; | |||
2221 | } | |||
2222 | ||||
2223 | /* Transform */ | |||
2224 | r_trans.isat_tnp = ISAKMP_NEXT_NONE; | |||
2225 | passert(out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs)){ _Bool assertion__ = out_struct(&r_trans, trans_desc, & r_proposal_pbs, &r_trans_pbs); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2225}, "%s", "out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs)" ); } }; | |||
2226 | ||||
2227 | /* Transform Attributes: pure echo */ | |||
2228 | trans_pbs->cur = trans_pbs->start + sizeof(struct isakmp_transform); | |||
2229 | passert(out_raw(trans_pbs->cur, pbs_left(trans_pbs),{ _Bool assertion__ = out_raw(trans_pbs->cur, ((size_t)((trans_pbs )->roof - (trans_pbs)->cur)), &r_trans_pbs, "attributes" ); if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 2230}, "%s", "out_raw(trans_pbs->cur, pbs_left(trans_pbs), &r_trans_pbs, \"attributes\")" ); } } | |||
2230 | &r_trans_pbs, "attributes")){ _Bool assertion__ = out_raw(trans_pbs->cur, ((size_t)((trans_pbs )->roof - (trans_pbs)->cur)), &r_trans_pbs, "attributes" ); if (!assertion__) { lsw_passert_fail((where_t) { .func = __func__ , .basename = "ikev1_spdb_struct.c" , .line = 2230}, "%s", "out_raw(trans_pbs->cur, pbs_left(trans_pbs), &r_trans_pbs, \"attributes\")" ); } }; | |||
2231 | ||||
2232 | close_output_pbs(&r_trans_pbs); | |||
2233 | close_output_pbs(&r_proposal_pbs); | |||
2234 | } | |||
2235 | ||||
2236 | notification_t parse_ipsec_sa_body(pb_stream *sa_pbs, /* body of input SA Payload */ | |||
2237 | const struct isakmp_sa *sa, /* header of input SA Payload */ | |||
2238 | pb_stream *r_sa_pbs, /* if non-NULL, where to emit body of winning SA */ | |||
2239 | bool_Bool selection, /* if this SA is a selection, only one transform may appear */ | |||
2240 | struct state *st) /* current state object */ | |||
2241 | { | |||
2242 | const struct connection *c = st->st_connection; | |||
2243 | uint32_t ipsecdoisit; | |||
2244 | pb_stream next_proposal_pbs; | |||
2245 | ||||
2246 | struct isakmp_proposal next_proposal; | |||
2247 | ipsec_spi_t next_spi; | |||
2248 | ||||
2249 | bool_Bool next_full = TRUE1; | |||
2250 | ||||
2251 | /* DOI */ | |||
2252 | if (sa->isasa_doi != ISAKMP_DOI_IPSEC1) { | |||
2253 | loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", | |||
2254 | enum_show(&doi_names, sa->isasa_doi)); | |||
2255 | /* XXX Could send notification back */ | |||
2256 | return DOI_NOT_SUPPORTED; /* reject whole SA */ | |||
2257 | } | |||
2258 | ||||
2259 | /* Situation */ | |||
2260 | if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL((void*)0))) | |||
2261 | return SITUATION_NOT_SUPPORTED; /* reject whole SA */ | |||
2262 | ||||
2263 | if (ipsecdoisit != SIT_IDENTITY_ONLY0x01) { | |||
2264 | loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)", | |||
2265 | bitnamesof(sit_bit_names, ipsecdoisit)); | |||
2266 | /* XXX Could send notification back */ | |||
2267 | return SITUATION_NOT_SUPPORTED; /* reject whole SA */ | |||
2268 | } | |||
2269 | ||||
2270 | /* The rules for IPsec SAs are scattered. | |||
2271 | * RFC 2408 "ISAKMP" section 4.2 gives some info. | |||
2272 | * There may be multiple proposals. Those with identical proposal | |||
2273 | * numbers must be considered as conjuncts. Those with different | |||
2274 | * numbers are disjuncts. | |||
2275 | * Each proposal may have several transforms, each considered | |||
2276 | * an alternative. | |||
2277 | * Each transform may have several attributes, all applying. | |||
2278 | * | |||
2279 | * To handle the way proposals are combined, we need to do a | |||
2280 | * look-ahead. | |||
2281 | */ | |||
2282 | ||||
2283 | if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, | |||
2284 | &next_proposal_pbs)) | |||
2285 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2286 | ||||
2287 | /* for each conjunction of proposals... */ | |||
2288 | while (next_full) { | |||
2289 | int propno = next_proposal.isap_proposal; | |||
2290 | pb_stream | |||
2291 | ah_prop_pbs, | |||
2292 | esp_prop_pbs, | |||
2293 | ipcomp_prop_pbs; | |||
2294 | struct isakmp_proposal | |||
2295 | ah_proposal, | |||
2296 | esp_proposal, | |||
2297 | ipcomp_proposal; | |||
2298 | ipsec_spi_t | |||
2299 | ah_spi = 0, | |||
2300 | esp_spi = 0, | |||
2301 | ipcomp_cpi = 0; | |||
2302 | bool_Bool | |||
2303 | ah_seen = FALSE0, | |||
2304 | esp_seen = FALSE0, | |||
2305 | ipcomp_seen = FALSE0; | |||
2306 | const ip_protocol *inner_proto = NULL((void*)0); | |||
2307 | bool_Bool tunnel_mode = FALSE0; | |||
2308 | uint16_t well_known_cpi = 0; | |||
2309 | ||||
2310 | pb_stream | |||
2311 | ah_trans_pbs, | |||
2312 | esp_trans_pbs, | |||
2313 | ipcomp_trans_pbs; | |||
2314 | struct isakmp_transform | |||
2315 | ah_trans, | |||
2316 | esp_trans, | |||
2317 | ipcomp_trans; | |||
2318 | struct ipsec_trans_attrs | |||
2319 | ah_attrs, | |||
2320 | esp_attrs, | |||
2321 | ipcomp_attrs; | |||
2322 | ||||
2323 | zero(&ah_proposal)memset((&ah_proposal), '\0', sizeof(*(&ah_proposal))); /* OK: no pointer fields */ | |||
2324 | zero(&esp_proposal)memset((&esp_proposal), '\0', sizeof(*(&esp_proposal) )); /* OK: no pointer fields */ | |||
2325 | zero(&ipcomp_proposal)memset((&ipcomp_proposal), '\0', sizeof(*(&ipcomp_proposal ))); /* OK: no pointer fields */ | |||
2326 | ||||
2327 | /* for each proposal in the conjunction */ | |||
2328 | do { | |||
2329 | if (next_proposal.isap_protoid == PROTO_IPCOMP4) { | |||
2330 | /* IPCOMP CPI */ | |||
2331 | if (next_proposal.isap_spisize == | |||
2332 | IPSEC_DOI_SPI_SIZE4) { | |||
2333 | /* This code is to accommodate those peculiar | |||
2334 | * implementations that send a CPI in the bottom of an | |||
2335 | * SPI-sized field. | |||
2336 | * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1 | |||
2337 | */ | |||
2338 | uint8_t filler[IPSEC_DOI_SPI_SIZE4 - | |||
2339 | IPCOMP_CPI_SIZE2]; | |||
2340 | ||||
2341 | if (!in_raw(filler, sizeof(filler), | |||
2342 | &next_proposal_pbs, | |||
2343 | "CPI filler") || | |||
2344 | !all_zero(filler, sizeof(filler))) | |||
2345 | return INVALID_SPI; /* reject whole SA */ | |||
2346 | } else if (next_proposal.isap_spisize != | |||
2347 | IPCOMP_CPI_SIZE2) { | |||
2348 | loglog(RC_LOG_SERIOUS, | |||
2349 | "IPsec Proposal with improper CPI size (%u)", | |||
2350 | next_proposal.isap_spisize); | |||
2351 | return INVALID_SPI; /* reject whole SA */ | |||
2352 | } | |||
2353 | ||||
2354 | /* We store CPI in the low order of a network order | |||
2355 | * ipsec_spi_t. So we start a couple of bytes in. | |||
2356 | */ | |||
2357 | zero(&next_spi)memset((&next_spi), '\0', sizeof(*(&next_spi))); | |||
2358 | if (!in_raw((u_char *)&next_spi + | |||
2359 | IPSEC_DOI_SPI_SIZE4 - | |||
2360 | IPCOMP_CPI_SIZE2, | |||
2361 | IPCOMP_CPI_SIZE2, | |||
2362 | &next_proposal_pbs, "CPI")) | |||
2363 | return INVALID_SPI; /* reject whole SA */ | |||
2364 | ||||
2365 | /* If sanity ruled, CPIs would have to be such that | |||
2366 | * the SAID (the triple (CPI, IPCOM, destination IP)) | |||
2367 | * would be unique, just like for SPIs. But there is a | |||
2368 | * perversion where CPIs can be well-known and consequently | |||
2369 | * the triple is not unique. We hide this fact from | |||
2370 | * ourselves by fudging the top 16 bits to make | |||
2371 | * the property true internally! | |||
2372 | */ | |||
2373 | switch (ntohl(next_spi)) { | |||
2374 | case IPCOMP_DEFLATE: | |||
2375 | well_known_cpi = ntohl(next_spi); | |||
2376 | next_spi = uniquify_peer_cpi(next_spi, st, 0); | |||
2377 | if (next_spi == 0) { | |||
2378 | loglog(RC_LOG_SERIOUS, | |||
2379 | "IPsec Proposal contains well-known CPI that I cannot uniquify"); | |||
2380 | return INVALID_SPI; /* reject whole SA */ | |||
2381 | } | |||
2382 | break; | |||
2383 | default: | |||
2384 | if (ntohl(next_spi) < | |||
2385 | IPCOMP_FIRST_NEGOTIATED256 || | |||
2386 | ntohl(next_spi) > | |||
2387 | IPCOMP_LAST_NEGOTIATED61439) { | |||
2388 | loglog(RC_LOG_SERIOUS, | |||
2389 | "IPsec Proposal contains CPI from non-negotiated range (0x%" PRIx32"x" ")", | |||
2390 | ntohl(next_spi)); | |||
2391 | return INVALID_SPI; /* reject whole SA */ | |||
2392 | } | |||
2393 | break; | |||
2394 | } | |||
2395 | /* end of IPCOMP CPI handling */ | |||
2396 | } else { | |||
2397 | /* AH or ESP SPI */ | |||
2398 | if (next_proposal.isap_spisize != | |||
2399 | IPSEC_DOI_SPI_SIZE4) { | |||
2400 | loglog(RC_LOG_SERIOUS, | |||
2401 | "IPsec Proposal with improper SPI size (%u)", | |||
2402 | next_proposal.isap_spisize); | |||
2403 | return INVALID_SPI; /* reject whole SA */ | |||
2404 | } | |||
2405 | ||||
2406 | if (!in_raw((u_char *)&next_spi, | |||
2407 | sizeof(next_spi), | |||
2408 | &next_proposal_pbs, "SPI")) | |||
2409 | return INVALID_SPI; /* reject whole SA */ | |||
2410 | ||||
2411 | /* SPI value 0 is invalid and values 1-255 are reserved to IANA. | |||
2412 | * RFC 2402 (ESP) 2.4, RFC 2406 (AH) 2.1 | |||
2413 | * IPCOMP??? | |||
2414 | */ | |||
2415 | if (ntohl(next_spi) < IPSEC_DOI_SPI_MIN0x100) { | |||
2416 | loglog(RC_LOG_SERIOUS, | |||
2417 | "IPsec Proposal contains invalid SPI (0x%" PRIx32"x" ")", | |||
2418 | ntohl(next_spi)); | |||
2419 | return INVALID_SPI; /* reject whole SA */ | |||
2420 | } | |||
2421 | } | |||
2422 | ||||
2423 | if (next_proposal.isap_notrans == 0) { | |||
2424 | loglog(RC_LOG_SERIOUS, | |||
2425 | "IPsec Proposal contains no Transforms (skipped)"); | |||
2426 | continue; | |||
2427 | } | |||
2428 | ||||
2429 | switch (next_proposal.isap_protoid) { | |||
2430 | case PROTO_IPSEC_AH2: | |||
2431 | if (ah_seen) { | |||
2432 | loglog(RC_LOG_SERIOUS, | |||
2433 | "IPsec SA contains two simultaneous AH Proposals"); | |||
2434 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2435 | } | |||
2436 | ah_seen = TRUE1; | |||
2437 | ah_prop_pbs = next_proposal_pbs; | |||
2438 | ah_proposal = next_proposal; | |||
2439 | ah_spi = next_spi; | |||
2440 | break; | |||
2441 | ||||
2442 | case PROTO_IPSEC_ESP3: | |||
2443 | if (esp_seen) { | |||
2444 | loglog(RC_LOG_SERIOUS, | |||
2445 | "IPsec SA contains two simultaneous ESP Proposals"); | |||
2446 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2447 | } | |||
2448 | esp_seen = TRUE1; | |||
2449 | esp_prop_pbs = next_proposal_pbs; | |||
2450 | esp_proposal = next_proposal; | |||
2451 | esp_spi = next_spi; | |||
2452 | break; | |||
2453 | ||||
2454 | case PROTO_IPCOMP4: | |||
2455 | if (ipcomp_seen) { | |||
2456 | loglog(RC_LOG_SERIOUS, | |||
2457 | "IPsec SA contains two simultaneous IPCOMP Proposals"); | |||
2458 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2459 | } | |||
2460 | ipcomp_seen = TRUE1; | |||
2461 | ipcomp_prop_pbs = next_proposal_pbs; | |||
2462 | ipcomp_proposal = next_proposal; | |||
2463 | ipcomp_cpi = next_spi; | |||
2464 | break; | |||
2465 | ||||
2466 | default: | |||
2467 | loglog(RC_LOG_SERIOUS, | |||
2468 | "unexpected Protocol ID (%s) in IPsec Proposal", | |||
2469 | enum_show(&ikev1_protocol_names, | |||
2470 | next_proposal.isap_protoid)); | |||
2471 | return INVALID_PROTOCOL_ID; /* reject whole SA */ | |||
2472 | } | |||
2473 | ||||
2474 | /* refill next_proposal */ | |||
2475 | if (next_proposal.isap_pnp == ISAKMP_NEXT_NONE) { | |||
2476 | next_full = FALSE0; | |||
2477 | break; | |||
2478 | } else if (next_proposal.isap_pnp != ISAKMP_NEXT_P) { | |||
2479 | loglog(RC_LOG_SERIOUS, | |||
2480 | "unexpected in Proposal: %s", | |||
2481 | enum_show(&ikev1_payload_names, | |||
2482 | next_proposal.isap_pnp)); | |||
2483 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2484 | } | |||
2485 | ||||
2486 | if (!in_struct(&next_proposal, &isakmp_proposal_desc, | |||
2487 | sa_pbs, &next_proposal_pbs)) | |||
2488 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2489 | } while (next_proposal.isap_proposal == propno); | |||
2490 | ||||
2491 | /* Now that we have all conjuncts, we should try | |||
2492 | * the Cartesian product of each's transforms! | |||
2493 | * At the moment, we take short-cuts on account of | |||
2494 | * our rudimentary hard-wired policy. | |||
2495 | * For now, we find an acceptable AH (if any) | |||
2496 | * and then an acceptable ESP. The only interaction | |||
2497 | * is that the ESP acceptance can know whether there | |||
2498 | * was an acceptable AH and hence not require an AUTH. | |||
2499 | */ | |||
2500 | ||||
2501 | if (ah_seen) { | |||
2502 | int previous_transnum = -1; | |||
2503 | int tn; | |||
2504 | ||||
2505 | for (tn = 0; tn != ah_proposal.isap_notrans; tn++) { | |||
2506 | if (!parse_ipsec_transform(&ah_trans, | |||
2507 | &ah_attrs, | |||
2508 | &ah_prop_pbs, | |||
2509 | &ah_trans_pbs, | |||
2510 | &isakmp_ah_transform_desc, | |||
2511 | previous_transnum, | |||
2512 | selection, | |||
2513 | tn == ah_proposal.isap_notrans - 1, | |||
2514 | PROTO_IPSEC_AH2, | |||
2515 | st)) | |||
2516 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2517 | ||||
2518 | previous_transnum = ah_trans.isat_transnum; | |||
2519 | ||||
2520 | /* | |||
2521 | * Since, for AH, when integrity is | |||
2522 | * missing, the proposal gets rejected | |||
2523 | * outright, a NULL here must indicate | |||
2524 | * that integrity was present but the | |||
2525 | * lookup failed. | |||
2526 | */ | |||
2527 | if (ah_attrs.transattrs.ta_integ == NULL((void*)0)) { | |||
2528 | /* error already logged */ | |||
2529 | dbg("ignoring AH proposal with unknown integrity"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ignoring AH proposal with unknown integrity") ; } }; | |||
2530 | continue; /* try another */ | |||
2531 | } | |||
2532 | ||||
2533 | /* we must understand ah_attrs.transid | |||
2534 | * COMBINED with ah_attrs.transattrs.ta_ikev1_integ_hash. | |||
2535 | * See RFC 2407 "IPsec DOI" section 4.4.3 | |||
2536 | * The following combinations are legal, | |||
2537 | * but we don't implement all of them: | |||
2538 | * It seems as if each auth algorithm | |||
2539 | * only applies to one ah transid. | |||
2540 | * AH_MD5, AUTH_ALGORITHM_HMAC_MD5 | |||
2541 | * AH_MD5, AUTH_ALGORITHM_KPDK (unimplemented) | |||
2542 | * AH_SHA, AUTH_ALGORITHM_HMAC_SHA1 | |||
2543 | * AH_DES, AUTH_ALGORITHM_DES_MAC (unimplemented) | |||
2544 | */ | |||
2545 | if (ah_trans.isat_transid != ah_attrs.transattrs.ta_integ->integ_ikev1_ah_transform) { | |||
2546 | loglog(RC_LOG_SERIOUS, | |||
2547 | "%s attribute inappropriate in %s Transform", | |||
2548 | ah_attrs.transattrs.ta_integ->common.fqn, | |||
2549 | enum_show(&ah_transformid_names, | |||
2550 | ah_trans.isat_transid)); | |||
2551 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2552 | } | |||
2553 | break; /* we seem to be happy */ | |||
2554 | } | |||
2555 | if (tn == ah_proposal.isap_notrans) | |||
2556 | continue; /* we didn't find a nice one */ | |||
2557 | ||||
2558 | /* Check AH proposal with configuration */ | |||
2559 | if (!ikev1_verify_ah(c, &ah_attrs.transattrs, st->st_logger)) { | |||
2560 | continue; | |||
2561 | } | |||
2562 | ah_attrs.spi = ah_spi; | |||
2563 | inner_proto = &ip_protocol_ah; | |||
2564 | if (ah_attrs.mode == | |||
2565 | ENCAPSULATION_MODE_TUNNEL1) | |||
2566 | tunnel_mode = TRUE1; | |||
2567 | } | |||
2568 | ||||
2569 | if (esp_seen) { | |||
2570 | int previous_transnum = -1; | |||
2571 | int tn; | |||
2572 | ||||
2573 | for (tn = 0; tn != esp_proposal.isap_notrans; tn++) { | |||
2574 | if (!parse_ipsec_transform( | |||
2575 | &esp_trans, | |||
2576 | &esp_attrs, | |||
2577 | &esp_prop_pbs, | |||
2578 | &esp_trans_pbs, | |||
2579 | &isakmp_esp_transform_desc, | |||
2580 | previous_transnum, | |||
2581 | selection, | |||
2582 | tn == esp_proposal.isap_notrans - 1, | |||
2583 | PROTO_IPSEC_ESP3, | |||
2584 | st)) | |||
2585 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2586 | ||||
2587 | previous_transnum = esp_trans.isat_transnum; | |||
2588 | ||||
2589 | /* | |||
2590 | * check for allowed transforms in alg_info_esp | |||
2591 | */ | |||
2592 | if (!ikev1_verify_esp(c, &esp_attrs.transattrs, st->st_logger)) { | |||
2593 | continue; /* try another */ | |||
2594 | } | |||
2595 | ||||
2596 | /* | |||
2597 | * XXX: this is testing for AH, is | |||
2598 | * conbining even supported? If not, | |||
2599 | * the test should be pushed into | |||
2600 | * ikev1_verify_esp(). | |||
2601 | */ | |||
2602 | if (esp_attrs.transattrs.ta_integ == &ike_alg_integ_none) { | |||
2603 | if (!encrypt_desc_is_aead(esp_attrs.transattrs.ta_encrypt) && | |||
2604 | !ah_seen) { | |||
2605 | LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[( (size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*)0); jambuf_to_debug_stream (buf), buf = ((void*)0)) { | |||
2606 | jam_string(buf, "ESP from "); | |||
2607 | jam_endpoint(buf, &c->spd.that.host_addr); | |||
2608 | jam_string(buf, " must either have AUTH or be combined with AH"); | |||
2609 | } | |||
2610 | continue; /* try another */ | |||
2611 | } | |||
2612 | } | |||
2613 | ||||
2614 | if (ah_seen && | |||
2615 | ah_attrs.mode != | |||
2616 | esp_attrs.mode) { | |||
2617 | loglog(RC_LOG_SERIOUS, | |||
2618 | "Skipped bogus proposal where AH and ESP transforms disagree about mode"); | |||
2619 | continue; /* try another */ | |||
2620 | } | |||
2621 | ||||
2622 | break; /* we seem to be happy */ | |||
2623 | } | |||
2624 | if (tn == esp_proposal.isap_notrans) | |||
2625 | continue; /* we didn't find a nice one */ | |||
2626 | ||||
2627 | esp_attrs.spi = esp_spi; | |||
2628 | inner_proto = &ip_protocol_esp; | |||
2629 | if (esp_attrs.mode == | |||
2630 | ENCAPSULATION_MODE_TUNNEL1) | |||
2631 | tunnel_mode = TRUE1; | |||
2632 | } else if (st->st_policy & POLICY_ENCRYPT((lset_t)1 << (POLICY_ENCRYPT_IX))) { | |||
2633 | connection_buf cib; | |||
2634 | address_buf b; | |||
2635 | dbg("policy for "PRI_CONNECTION" requires encryption but ESP not in Proposal from %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("policy for ""\"%s\"%s"" requires encryption but ESP not in Proposal from %s" , (c)->name, str_connection_instance(c, &cib), str_address (&c->spd.that.host_addr, &b)); } } | |||
2636 | pri_connection(c, &cib),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("policy for ""\"%s\"%s"" requires encryption but ESP not in Proposal from %s" , (c)->name, str_connection_instance(c, &cib), str_address (&c->spd.that.host_addr, &b)); } } | |||
2637 | str_address(&c->spd.that.host_addr, &b)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("policy for ""\"%s\"%s"" requires encryption but ESP not in Proposal from %s" , (c)->name, str_connection_instance(c, &cib), str_address (&c->spd.that.host_addr, &b)); } }; | |||
2638 | continue; /* we needed encryption, but didn't find ESP */ | |||
2639 | } else if ((st->st_policy & POLICY_AUTHENTICATE((lset_t)1 << (POLICY_AUTHENTICATE_IX))) && !ah_seen) { | |||
2640 | connection_buf cib; | |||
2641 | address_buf b; | |||
2642 | dbg("policy for \"%s\"%s requires authentication but none in Proposal from %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("policy for \"%s\"%s requires authentication but none in Proposal from %s" , (c)->name, str_connection_instance(c, &cib), str_address (&c->spd.that.host_addr, &b)); } } | |||
2643 | pri_connection(c, &cib),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("policy for \"%s\"%s requires authentication but none in Proposal from %s" , (c)->name, str_connection_instance(c, &cib), str_address (&c->spd.that.host_addr, &b)); } } | |||
2644 | str_address(&c->spd.that.host_addr, &b)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("policy for \"%s\"%s requires authentication but none in Proposal from %s" , (c)->name, str_connection_instance(c, &cib), str_address (&c->spd.that.host_addr, &b)); } }; | |||
2645 | continue; /* we need authentication, but we found neither ESP nor AH */ | |||
2646 | } | |||
2647 | ||||
2648 | if (ipcomp_seen) { | |||
2649 | int previous_transnum = -1; | |||
2650 | int tn; | |||
2651 | ||||
2652 | if (!(st->st_policy & POLICY_COMPRESS((lset_t)1 << (POLICY_COMPRESS_IX)))) { | |||
2653 | ipstr_buf b; | |||
2654 | char cib[CONN_INST_BUF(2 + 10 + 1 + sizeof(subnet_buf) + 7 + sizeof(address_reversed_buf ) + 3 + sizeof(subnet_buf) + 1 + 1)]; | |||
2655 | ||||
2656 | libreswan_log(loglog(RC_LOG, "compression proposed by %s, but policy for \"%s\"%s forbids it" , ipstr(&c->spd.that.host_addr, &b), c->name, fmt_conn_instance (c, cib)) | |||
2657 | "compression proposed by %s, but policy for \"%s\"%s forbids it",loglog(RC_LOG, "compression proposed by %s, but policy for \"%s\"%s forbids it" , ipstr(&c->spd.that.host_addr, &b), c->name, fmt_conn_instance (c, cib)) | |||
2658 | ipstr(&c->spd.that.host_addr, &b),loglog(RC_LOG, "compression proposed by %s, but policy for \"%s\"%s forbids it" , ipstr(&c->spd.that.host_addr, &b), c->name, fmt_conn_instance (c, cib)) | |||
2659 | c->name, fmt_conn_instance(c, cib))loglog(RC_LOG, "compression proposed by %s, but policy for \"%s\"%s forbids it" , ipstr(&c->spd.that.host_addr, &b), c->name, fmt_conn_instance (c, cib)); | |||
2660 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2661 | } | |||
2662 | ||||
2663 | if (!can_do_IPcomp) { | |||
2664 | ipstr_buf b; | |||
2665 | ||||
2666 | libreswan_log(loglog(RC_LOG, "compression proposed by %s, but kernel has no IPCOMP support" , ipstr(&c->spd.that.host_addr, &b)) | |||
2667 | "compression proposed by %s, but kernel has no IPCOMP support",loglog(RC_LOG, "compression proposed by %s, but kernel has no IPCOMP support" , ipstr(&c->spd.that.host_addr, &b)) | |||
2668 | ipstr(&c->spd.that.host_addr, &b))loglog(RC_LOG, "compression proposed by %s, but kernel has no IPCOMP support" , ipstr(&c->spd.that.host_addr, &b)); | |||
2669 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2670 | } | |||
2671 | ||||
2672 | if (well_known_cpi != 0 && !ah_seen && !esp_seen) { | |||
2673 | libreswan_log(loglog(RC_LOG, "illegal proposal: bare IPCOMP used with well-known CPI" ) | |||
2674 | "illegal proposal: bare IPCOMP used with well-known CPI")loglog(RC_LOG, "illegal proposal: bare IPCOMP used with well-known CPI" ); | |||
2675 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2676 | } | |||
2677 | ||||
2678 | for (tn = 0; tn != ipcomp_proposal.isap_notrans; | |||
2679 | tn++) { | |||
2680 | if (!parse_ipsec_transform( | |||
2681 | &ipcomp_trans, | |||
2682 | &ipcomp_attrs, | |||
2683 | &ipcomp_prop_pbs, | |||
2684 | &ipcomp_trans_pbs, | |||
2685 | &isakmp_ipcomp_transform_desc, | |||
2686 | previous_transnum, | |||
2687 | selection, | |||
2688 | tn == ipcomp_proposal.isap_notrans - 1, | |||
2689 | PROTO_IPCOMP4, | |||
2690 | st)) | |||
2691 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2692 | ||||
2693 | previous_transnum = ipcomp_trans.isat_transnum; | |||
2694 | ||||
2695 | if (well_known_cpi != 0 && | |||
2696 | ipcomp_attrs.transattrs.ta_comp != well_known_cpi) { | |||
2697 | libreswan_log(loglog(RC_LOG, "illegal proposal: IPCOMP well-known CPI disagrees with transform" ) | |||
2698 | "illegal proposal: IPCOMP well-known CPI disagrees with transform")loglog(RC_LOG, "illegal proposal: IPCOMP well-known CPI disagrees with transform" ); | |||
2699 | return BAD_PROPOSAL_SYNTAX; /* reject whole SA */ | |||
2700 | } | |||
2701 | ||||
2702 | switch (ipcomp_attrs.transattrs.ta_comp) { | |||
2703 | case IPCOMP_DEFLATE: /* all we can handle! */ | |||
2704 | break; | |||
2705 | ||||
2706 | default: | |||
2707 | { | |||
2708 | address_buf b; | |||
2709 | dbg("unsupported IPCOMP Transform %d from %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unsupported IPCOMP Transform %d from %s", ipcomp_attrs .transattrs.ta_comp, str_address(&c->spd.that.host_addr , &b)); } } | |||
2710 | ipcomp_attrs.transattrs.ta_comp,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unsupported IPCOMP Transform %d from %s", ipcomp_attrs .transattrs.ta_comp, str_address(&c->spd.that.host_addr , &b)); } } | |||
2711 | str_address(&c->spd.that.host_addr, &b)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unsupported IPCOMP Transform %d from %s", ipcomp_attrs .transattrs.ta_comp, str_address(&c->spd.that.host_addr , &b)); } }; | |||
2712 | continue; /* try another */ | |||
2713 | } | |||
2714 | } | |||
2715 | ||||
2716 | if (ah_seen && | |||
2717 | ah_attrs.mode != | |||
2718 | ipcomp_attrs.mode) { | |||
2719 | /* ??? This should be an error, but is it? */ | |||
2720 | dbg("AH and IPCOMP transforms disagree about mode; TUNNEL presumed"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("AH and IPCOMP transforms disagree about mode; TUNNEL presumed" ); } }; | |||
2721 | } else if (esp_seen && | |||
2722 | esp_attrs.mode != | |||
2723 | ipcomp_attrs.mode) { | |||
2724 | /* ??? This should be an error, but is it? */ | |||
2725 | dbg("ESP and IPCOMP transforms disagree about mode; TUNNEL presumed"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ESP and IPCOMP transforms disagree about mode; TUNNEL presumed" ); } }; | |||
2726 | } | |||
2727 | ||||
2728 | break; /* we seem to be happy */ | |||
2729 | } | |||
2730 | if (tn == ipcomp_proposal.isap_notrans) | |||
2731 | continue; /* we didn't find a nice one */ | |||
2732 | ipcomp_attrs.spi = ipcomp_cpi; | |||
2733 | inner_proto = &ip_protocol_comp; | |||
2734 | if (ipcomp_attrs.mode == | |||
2735 | ENCAPSULATION_MODE_TUNNEL1) | |||
2736 | tunnel_mode = TRUE1; | |||
2737 | } | |||
2738 | ||||
2739 | /* Eureka: we liked what we saw -- accept it. */ | |||
2740 | ||||
2741 | if (r_sa_pbs != NULL((void*)0)) { | |||
2742 | /* emit what we've accepted */ | |||
2743 | ||||
2744 | /* Situation */ | |||
2745 | passert(out_struct(&ipsecdoisit, &ipsec_sit_desc,{ _Bool assertion__ = out_struct(&ipsecdoisit, &ipsec_sit_desc , r_sa_pbs, ((void*)0)); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2746}, "%s", "out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)" ); } } | |||
2746 | r_sa_pbs, NULL)){ _Bool assertion__ = out_struct(&ipsecdoisit, &ipsec_sit_desc , r_sa_pbs, ((void*)0)); if (!assertion__) { lsw_passert_fail ((where_t) { .func = __func__, .basename = "ikev1_spdb_struct.c" , .line = 2746}, "%s", "out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)" ); } }; | |||
2747 | ||||
2748 | /* AH proposal */ | |||
2749 | if (ah_seen) { | |||
2750 | echo_proposal(ah_proposal, | |||
2751 | ah_trans, | |||
2752 | esp_seen || ipcomp_seen ? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE, | |||
2753 | r_sa_pbs, | |||
2754 | &st->st_ah, | |||
2755 | &isakmp_ah_transform_desc, | |||
2756 | &ah_trans_pbs, | |||
2757 | &st->st_connection->spd, | |||
2758 | tunnel_mode && | |||
2759 | inner_proto == &ip_protocol_ah); | |||
2760 | } | |||
2761 | ||||
2762 | /* ESP proposal */ | |||
2763 | if (esp_seen) { | |||
2764 | echo_proposal(esp_proposal, | |||
2765 | esp_trans, | |||
2766 | ipcomp_seen ? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE, | |||
2767 | r_sa_pbs, | |||
2768 | &st->st_esp, | |||
2769 | &isakmp_esp_transform_desc, | |||
2770 | &esp_trans_pbs, | |||
2771 | &st->st_connection->spd, | |||
2772 | tunnel_mode && | |||
2773 | inner_proto == &ip_protocol_esp); | |||
2774 | } | |||
2775 | ||||
2776 | /* IPCOMP proposal */ | |||
2777 | if (ipcomp_seen) { | |||
2778 | echo_proposal(ipcomp_proposal, | |||
2779 | ipcomp_trans, | |||
2780 | ISAKMP_NEXT_NONE, | |||
2781 | r_sa_pbs, | |||
2782 | &st->st_ipcomp, | |||
2783 | &isakmp_ipcomp_transform_desc, | |||
2784 | &ipcomp_trans_pbs, | |||
2785 | &st->st_connection->spd, | |||
2786 | tunnel_mode && | |||
2787 | inner_proto == &ip_protocol_comp); | |||
2788 | } | |||
2789 | ||||
2790 | close_output_pbs(r_sa_pbs); | |||
2791 | } | |||
2792 | ||||
2793 | /* save decoded version of winning SA in state */ | |||
2794 | ||||
2795 | st->st_ah.present = ah_seen; | |||
2796 | if (ah_seen) { | |||
2797 | st->st_ah.attrs = ah_attrs; | |||
2798 | st->st_ah.our_lastused = mononow(); | |||
2799 | st->st_ah.peer_lastused = mononow(); | |||
2800 | } | |||
2801 | ||||
2802 | st->st_esp.present = esp_seen; | |||
2803 | if (esp_seen) { | |||
2804 | st->st_esp.attrs = esp_attrs; | |||
2805 | st->st_esp.our_lastused = mononow(); | |||
2806 | st->st_esp.peer_lastused = mononow(); | |||
2807 | } | |||
2808 | ||||
2809 | st->st_ipcomp.present = ipcomp_seen; | |||
2810 | if (ipcomp_seen) { | |||
2811 | st->st_ipcomp.attrs = ipcomp_attrs; | |||
2812 | st->st_ipcomp.our_lastused = mononow(); | |||
2813 | st->st_ipcomp.peer_lastused = mononow(); | |||
2814 | } | |||
2815 | ||||
2816 | return NOTHING_WRONG; /* accept this transform! */ | |||
2817 | } | |||
2818 | ||||
2819 | loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA"); | |||
2820 | return NO_PROPOSAL_CHOSEN; /* reject whole SA */ | |||
2821 | } |