File: | src/sbin/isakmpd/ike_phase_1.c |
Warning: | line 1235, column 3 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ike_phase_1.c,v 1.78 2018/09/20 11:49:55 jsg Exp $ */ | |||
2 | /* $EOM: ike_phase_1.c,v 1.31 2000/12/11 23:47:56 niklas Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. | |||
6 | * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. | |||
7 | * Copyright (c) 2001, 2004 Håkan Olsson. All rights reserved. | |||
8 | * | |||
9 | * Redistribution and use in source and binary forms, with or without | |||
10 | * modification, are permitted provided that the following conditions | |||
11 | * are met: | |||
12 | * 1. Redistributions of source code must retain the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer. | |||
14 | * 2. Redistributions in binary form must reproduce the above copyright | |||
15 | * notice, this list of conditions and the following disclaimer in the | |||
16 | * documentation and/or other materials provided with the distribution. | |||
17 | * | |||
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
28 | */ | |||
29 | ||||
30 | /* | |||
31 | * This code was written under funding by Ericsson Radio Systems. | |||
32 | */ | |||
33 | ||||
34 | #include <sys/types.h> | |||
35 | #include <netinet/in.h> | |||
36 | #include <arpa/inet.h> | |||
37 | #include <stdlib.h> | |||
38 | #include <string.h> | |||
39 | ||||
40 | #include "attribute.h" | |||
41 | #include "conf.h" | |||
42 | #include "constants.h" | |||
43 | #include "crypto.h" | |||
44 | #include "dh.h" | |||
45 | #include "doi.h" | |||
46 | #include "dpd.h" | |||
47 | #include "exchange.h" | |||
48 | #include "hash.h" | |||
49 | #include "ike_auth.h" | |||
50 | #include "ike_phase_1.h" | |||
51 | #include "ipsec.h" | |||
52 | #include "ipsec_doi.h" | |||
53 | #include "isakmp.h" | |||
54 | #include "log.h" | |||
55 | #include "message.h" | |||
56 | #include "nat_traversal.h" | |||
57 | #include "prf.h" | |||
58 | #include "sa.h" | |||
59 | #include "transport.h" | |||
60 | #include "util.h" | |||
61 | #include "vendor.h" | |||
62 | ||||
63 | static int attribute_unacceptable(u_int16_t, u_int8_t *, u_int16_t, | |||
64 | void *); | |||
65 | static int ike_phase_1_validate_prop(struct exchange *, struct sa *, | |||
66 | struct sa *); | |||
67 | ||||
68 | /* Offer a set of transforms to the responder in the MSG message. */ | |||
69 | int | |||
70 | ike_phase_1_initiator_send_SA(struct message *msg) | |||
71 | { | |||
72 | struct exchange *exchange = msg->exchange; | |||
73 | struct ipsec_exch *ie = exchange->data; | |||
74 | u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr; | |||
75 | u_int8_t **transform = 0; | |||
76 | size_t transforms_len = 0, proposal_len, sa_len; | |||
77 | size_t *transform_len = 0; | |||
78 | struct conf_list *conf, *life_conf; | |||
79 | struct conf_list_node *xf, *life; | |||
80 | int value, update_nextp; | |||
81 | size_t i; | |||
82 | struct payload *p; | |||
83 | struct proto *proto; | |||
84 | struct proto_attr *pa; | |||
85 | int group_desc = -1, new_group_desc; | |||
86 | ||||
87 | /* Get the list of transforms. */ | |||
88 | conf = conf_get_list(exchange->policy, "Transforms"); | |||
89 | if (!conf) | |||
90 | return -1; | |||
91 | ||||
92 | transform = calloc(conf->cnt, sizeof *transform); | |||
93 | if (!transform) { | |||
94 | log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " | |||
95 | "failed", (u_long)conf->cnt, (u_long)sizeof *transform); | |||
96 | goto bail_out; | |||
97 | } | |||
98 | transform_len = calloc(conf->cnt, sizeof *transform_len); | |||
99 | if (!transform_len) { | |||
100 | log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " | |||
101 | "failed", (u_long)conf->cnt, | |||
102 | (u_long)sizeof *transform_len); | |||
103 | goto bail_out; | |||
104 | } | |||
105 | for (xf = TAILQ_FIRST(&conf->fields)((&conf->fields)->tqh_first), i = 0; i < conf->cnt; | |||
106 | i++, xf = TAILQ_NEXT(xf, link)((xf)->link.tqe_next)) { | |||
107 | /* XXX The sizing needs to be dynamic. */ | |||
108 | transform[i] = malloc(ISAKMP_TRANSFORM_SA_ATTRS_OFF8 + | |||
109 | 16 * ISAKMP_ATTR_VALUE_OFF4); | |||
110 | if (!transform[i]) { | |||
111 | log_error("ike_phase_1_initiator_send_SA: malloc (%d) " | |||
112 | "failed", ISAKMP_TRANSFORM_SA_ATTRS_OFF8 + | |||
113 | 16 * ISAKMP_ATTR_VALUE_OFF4); | |||
114 | goto bail_out; | |||
115 | } | |||
116 | SET_ISAKMP_TRANSFORM_NO(transform[i], i)field_set_num (isakmp_transform_fld + 0, transform[i], i); | |||
117 | SET_ISAKMP_TRANSFORM_ID(transform[i], IPSEC_TRANSFORM_KEY_IKE)field_set_num (isakmp_transform_fld + 1, transform[i], 1); | |||
118 | SET_ISAKMP_TRANSFORM_RESERVED(transform[i], 0)field_set_num (isakmp_transform_fld + 2, transform[i], 0); | |||
119 | ||||
120 | attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF8; | |||
121 | ||||
122 | if (attribute_set_constant(xf->field, "ENCRYPTION_ALGORITHM", | |||
123 | ike_encrypt_cst, IKE_ATTR_ENCRYPTION_ALGORITHM1, &attr)) | |||
124 | goto bail_out; | |||
125 | ||||
126 | if (attribute_set_constant(xf->field, "HASH_ALGORITHM", | |||
127 | ike_hash_cst, IKE_ATTR_HASH_ALGORITHM2, &attr)) | |||
128 | goto bail_out; | |||
129 | ||||
130 | if (attribute_set_constant(xf->field, "AUTHENTICATION_METHOD", | |||
131 | ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD3, &attr)) | |||
132 | goto bail_out; | |||
133 | ||||
134 | if (attribute_set_constant(xf->field, "GROUP_DESCRIPTION", | |||
135 | ike_group_desc_cst, IKE_ATTR_GROUP_DESCRIPTION4, &attr)) { | |||
136 | /* | |||
137 | * If no group description exists, try looking for | |||
138 | * a user-defined one. | |||
139 | */ | |||
140 | if (attribute_set_constant(xf->field, "GROUP_TYPE", | |||
141 | ike_group_cst, IKE_ATTR_GROUP_TYPE5, &attr)) | |||
142 | goto bail_out; | |||
143 | ||||
144 | #if 0 | |||
145 | if (attribute_set_bignum(xf->field, "GROUP_PRIME", | |||
146 | IKE_ATTR_GROUP_PRIME6, &attr)) | |||
147 | goto bail_out; | |||
148 | ||||
149 | if (attribute_set_bignum(xf->field, | |||
150 | "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_28, | |||
151 | &attr)) | |||
152 | goto bail_out; | |||
153 | ||||
154 | if (attribute_set_bignum(xf->field, | |||
155 | "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_28, | |||
156 | &attr)) | |||
157 | goto bail_out; | |||
158 | ||||
159 | if (attribute_set_bignum(xf->field, "GROUP_CURVE_A", | |||
160 | IKE_ATTR_GROUP_CURVE_A9, &attr)) | |||
161 | goto bail_out; | |||
162 | ||||
163 | if (attribute_set_bignum(xf->field, "GROUP_CURVE_B", | |||
164 | IKE_ATTR_GROUP_CURVE_B10, &attr)) | |||
165 | goto bail_out; | |||
166 | #endif | |||
167 | } | |||
168 | /* | |||
169 | * Life durations are special, we should be able to specify | |||
170 | * several, one per type. | |||
171 | */ | |||
172 | life_conf = conf_get_list(xf->field, "Life"); | |||
173 | if (life_conf) { | |||
174 | for (life = TAILQ_FIRST(&life_conf->fields)((&life_conf->fields)->tqh_first); life; | |||
175 | life = TAILQ_NEXT(life, link)((life)->link.tqe_next)) { | |||
176 | attribute_set_constant(life->field, | |||
177 | "LIFE_TYPE", ike_duration_cst, | |||
178 | IKE_ATTR_LIFE_TYPE11, &attr); | |||
179 | ||||
180 | /* | |||
181 | * XXX Deals with 16 and 32 bit lifetimes | |||
182 | * only | |||
183 | */ | |||
184 | value = conf_get_num(life->field, | |||
185 | "LIFE_DURATION", 0); | |||
186 | if (value) { | |||
187 | if (value <= 0xffff) | |||
188 | attr = attribute_set_basic( | |||
189 | attr, | |||
190 | IKE_ATTR_LIFE_DURATION12, | |||
191 | value); | |||
192 | else { | |||
193 | value = htonl(value)(__uint32_t)(__builtin_constant_p(value) ? (__uint32_t)(((__uint32_t )(value) & 0xff) << 24 | ((__uint32_t)(value) & 0xff00) << 8 | ((__uint32_t)(value) & 0xff0000) >> 8 | ((__uint32_t)(value) & 0xff000000) >> 24) : __swap32md (value)); | |||
194 | attr = attribute_set_var(attr, | |||
195 | IKE_ATTR_LIFE_DURATION12, | |||
196 | (u_int8_t *)&value, | |||
197 | sizeof value); | |||
198 | } | |||
199 | } | |||
200 | } | |||
201 | conf_free_list(life_conf); | |||
202 | } | |||
203 | attribute_set_constant(xf->field, "PRF", ike_prf_cst, | |||
204 | IKE_ATTR_PRF13, &attr); | |||
205 | ||||
206 | value = conf_get_num(xf->field, "KEY_LENGTH", 0); | |||
207 | if (value) | |||
208 | attr = attribute_set_basic(attr, IKE_ATTR_KEY_LENGTH14, | |||
209 | value); | |||
210 | ||||
211 | value = conf_get_num(xf->field, "FIELD_SIZE", 0); | |||
212 | if (value) | |||
213 | attr = attribute_set_basic(attr, IKE_ATTR_FIELD_SIZE15, | |||
214 | value); | |||
215 | ||||
216 | value = conf_get_num(xf->field, "GROUP_ORDER", 0); | |||
217 | if (value) | |||
218 | attr = attribute_set_basic(attr, IKE_ATTR_GROUP_ORDER16, | |||
219 | value); | |||
220 | ||||
221 | /* Record the real transform size. */ | |||
222 | transforms_len += transform_len[i] = attr - transform[i]; | |||
223 | ||||
224 | /* XXX I don't like exchange-specific stuff in here. */ | |||
225 | if (exchange->type == ISAKMP_EXCH_AGGRESSIVE4) { | |||
226 | /* | |||
227 | * Make sure that if a group description is specified, | |||
228 | * it is specified for all transforms equally. | |||
229 | */ | |||
230 | attr = (u_int8_t *)conf_get_str(xf->field, | |||
231 | "GROUP_DESCRIPTION"); | |||
232 | new_group_desc = | |||
233 | attr ? constant_value(ike_group_desc_cst, | |||
234 | (char *)attr) : 0; | |||
235 | if (group_desc == -1) | |||
236 | group_desc = new_group_desc; | |||
237 | else if (group_desc != new_group_desc) { | |||
238 | log_print("ike_phase_1_initiator_send_SA: " | |||
239 | "differing group descriptions in a " | |||
240 | "proposal"); | |||
241 | goto bail_out; | |||
242 | } | |||
243 | } | |||
244 | /* | |||
245 | * We need to check that we actually support our | |||
246 | * configuration. | |||
247 | */ | |||
248 | if (attribute_map(transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
249 | transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
250 | exchange->doi->is_attribute_incompatible, msg)) { | |||
251 | log_print("ike_phase_1_initiator_send_SA: " | |||
252 | "section [%s] has unsupported attribute(s)", | |||
253 | xf->field); | |||
254 | goto bail_out; | |||
255 | } | |||
256 | } | |||
257 | ||||
258 | /* XXX I don't like exchange-specific stuff in here. */ | |||
259 | if (exchange->type == ISAKMP_EXCH_AGGRESSIVE4) | |||
260 | ie->group = group_get(group_desc); | |||
261 | ||||
262 | proposal_len = ISAKMP_PROP_SPI_OFF8; | |||
263 | proposal = malloc(proposal_len); | |||
264 | if (!proposal) { | |||
265 | log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", | |||
266 | (unsigned long)proposal_len); | |||
267 | goto bail_out; | |||
268 | } | |||
269 | SET_ISAKMP_PROP_NO(proposal, 1)field_set_num (isakmp_prop_fld + 0, proposal, 1); | |||
270 | SET_ISAKMP_PROP_PROTO(proposal, ISAKMP_PROTO_ISAKMP)field_set_num (isakmp_prop_fld + 1, proposal, 1); | |||
271 | SET_ISAKMP_PROP_SPI_SZ(proposal, 0)field_set_num (isakmp_prop_fld + 2, proposal, 0); | |||
272 | SET_ISAKMP_PROP_NTRANSFORMS(proposal, conf->cnt)field_set_num (isakmp_prop_fld + 3, proposal, conf->cnt); | |||
273 | ||||
274 | /* XXX I would like to see this factored out. */ | |||
275 | proto = calloc(1, sizeof *proto); | |||
276 | if (!proto) { | |||
277 | log_error("ike_phase_1_initiator_send_SA: " | |||
278 | "calloc (1, %lu) failed", (unsigned long)sizeof *proto); | |||
279 | goto bail_out; | |||
280 | } | |||
281 | proto->no = 1; | |||
282 | proto->proto = ISAKMP_PROTO_ISAKMP1; | |||
283 | proto->sa = TAILQ_FIRST(&exchange->sa_list)((&exchange->sa_list)->tqh_first); | |||
284 | proto->xf_cnt = conf->cnt; | |||
285 | TAILQ_INIT(&proto->xfs)do { (&proto->xfs)->tqh_first = ((void *)0); (& proto->xfs)->tqh_last = &(&proto->xfs)->tqh_first ; } while (0); | |||
286 | for (i = 0; i < proto->xf_cnt; i++) { | |||
287 | pa = calloc(1, sizeof *pa); | |||
288 | if (!pa) | |||
289 | goto bail_out; | |||
290 | pa->len = transform_len[i]; | |||
291 | pa->attrs = malloc(pa->len); | |||
292 | if (!pa->attrs) { | |||
293 | free(pa); | |||
294 | goto bail_out; | |||
295 | } | |||
296 | memcpy(pa->attrs, transform[i], pa->len); | |||
297 | TAILQ_INSERT_TAIL(&proto->xfs, pa, next)do { (pa)->next.tqe_next = ((void *)0); (pa)->next.tqe_prev = (&proto->xfs)->tqh_last; *(&proto->xfs)-> tqh_last = (pa); (&proto->xfs)->tqh_last = &(pa )->next.tqe_next; } while (0); | |||
298 | } | |||
299 | TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, proto,do { (proto)->link.tqe_next = ((void *)0); (proto)->link .tqe_prev = (&((&exchange->sa_list)->tqh_first) ->protos)->tqh_last; *(&((&exchange->sa_list )->tqh_first)->protos)->tqh_last = (proto); (&(( &exchange->sa_list)->tqh_first)->protos)->tqh_last = &(proto)->link.tqe_next; } while (0) | |||
300 | link)do { (proto)->link.tqe_next = ((void *)0); (proto)->link .tqe_prev = (&((&exchange->sa_list)->tqh_first) ->protos)->tqh_last; *(&((&exchange->sa_list )->tqh_first)->protos)->tqh_last = (proto); (&(( &exchange->sa_list)->tqh_first)->protos)->tqh_last = &(proto)->link.tqe_next; } while (0); | |||
301 | ||||
302 | sa_len = ISAKMP_SA_SIT_OFF8 + IPSEC_SIT_SIT_LEN4; | |||
303 | sa_buf = malloc(sa_len); | |||
304 | if (!sa_buf) { | |||
305 | log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", | |||
306 | (unsigned long)sa_len); | |||
307 | goto bail_out; | |||
308 | } | |||
309 | SET_ISAKMP_SA_DOI(sa_buf, IPSEC_DOI_IPSEC)field_set_num (isakmp_sa_fld + 0, sa_buf, 1); | |||
310 | SET_IPSEC_SIT_SIT(sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY)field_set_num (ipsec_sit_fld + 0, sa_buf + 8, 1); | |||
311 | ||||
312 | /* | |||
313 | * Add the payloads. As this is a SA, we need to recompute the | |||
314 | * lengths of the payloads containing others. | |||
315 | */ | |||
316 | if (message_add_payload(msg, ISAKMP_PAYLOAD_SA1, sa_buf, sa_len, 1)) | |||
317 | goto bail_out; | |||
318 | SET_ISAKMP_GEN_LENGTH(sa_buf,field_set_num (isakmp_gen_fld + 2, sa_buf, sa_len + proposal_len + transforms_len) | |||
319 | sa_len + proposal_len + transforms_len)field_set_num (isakmp_gen_fld + 2, sa_buf, sa_len + proposal_len + transforms_len); | |||
320 | sa_buf = 0; | |||
321 | ||||
322 | saved_nextp = msg->nextp; | |||
323 | if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL2, proposal, | |||
324 | proposal_len, 0)) | |||
325 | goto bail_out; | |||
326 | SET_ISAKMP_GEN_LENGTH(proposal, proposal_len + transforms_len)field_set_num (isakmp_gen_fld + 2, proposal, proposal_len + transforms_len ); | |||
327 | proposal = 0; | |||
328 | ||||
329 | update_nextp = 0; | |||
330 | for (i = 0; i < conf->cnt; i++) { | |||
331 | if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM3, | |||
332 | transform[i], transform_len[i], update_nextp)) | |||
333 | goto bail_out; | |||
334 | update_nextp = 1; | |||
335 | transform[i] = 0; | |||
336 | } | |||
337 | msg->nextp = saved_nextp; | |||
338 | ||||
339 | /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len. */ | |||
340 | ie->sa_i_b_len = sa_len + proposal_len + transforms_len - | |||
341 | ISAKMP_GEN_SZ4; | |||
342 | ie->sa_i_b = malloc(ie->sa_i_b_len); | |||
343 | if (!ie->sa_i_b) { | |||
344 | log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", | |||
345 | (unsigned long)ie->sa_i_b_len); | |||
346 | goto bail_out; | |||
347 | } | |||
348 | memcpy(ie->sa_i_b, | |||
349 | payload_first(msg, ISAKMP_PAYLOAD_SA1)->p + ISAKMP_GEN_SZ4, | |||
350 | sa_len - ISAKMP_GEN_SZ4); | |||
351 | memcpy(ie->sa_i_b + sa_len - ISAKMP_GEN_SZ4, | |||
352 | payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL2)->p, proposal_len); | |||
353 | transforms_len = 0; | |||
354 | for (i = 0, p = TAILQ_FIRST(&msg->payload[ISAKMP_PAYLOAD_TRANSFORM])((&msg->payload[3])->tqh_first); | |||
355 | i < conf->cnt; i++, p = TAILQ_NEXT(p, link)((p)->link.tqe_next)) { | |||
356 | memcpy(ie->sa_i_b + sa_len + proposal_len + transforms_len - | |||
357 | ISAKMP_GEN_SZ4, p->p, transform_len[i]); | |||
358 | transforms_len += transform_len[i]; | |||
359 | } | |||
360 | ||||
361 | /* Advertise OpenBSD isakmpd. */ | |||
362 | if (add_vendor_openbsd(msg)) | |||
363 | goto bail_out; | |||
364 | ||||
365 | /* Advertise NAT-T capability. */ | |||
366 | if (nat_t_add_vendor_payloads(msg)) | |||
367 | goto bail_out; | |||
368 | ||||
369 | /* Advertise DPD capability. */ | |||
370 | if (dpd_add_vendor_payload(msg)) | |||
371 | goto bail_out; | |||
372 | ||||
373 | conf_free_list(conf); | |||
374 | free(transform); | |||
375 | free(transform_len); | |||
376 | return 0; | |||
377 | ||||
378 | bail_out: | |||
379 | free(sa_buf); | |||
380 | free(proposal); | |||
381 | if (transform) { | |||
382 | for (i = 0; i < conf->cnt; i++) | |||
383 | free(transform[i]); | |||
384 | free(transform); | |||
385 | } | |||
386 | free(transform_len); | |||
387 | conf_free_list(conf); | |||
388 | return -1; | |||
389 | } | |||
390 | ||||
391 | /* Figure out what transform the responder chose. */ | |||
392 | int | |||
393 | ike_phase_1_initiator_recv_SA(struct message *msg) | |||
394 | { | |||
395 | struct exchange *exchange = msg->exchange; | |||
396 | struct sa *sa = TAILQ_FIRST(&exchange->sa_list)((&exchange->sa_list)->tqh_first); | |||
397 | struct ipsec_exch *ie = exchange->data; | |||
398 | struct ipsec_sa *isa = sa->data; | |||
399 | struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA1); | |||
400 | struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL2); | |||
401 | struct payload *xf = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM3); | |||
402 | ||||
403 | /* | |||
404 | * IKE requires that only one SA with only one proposal exists and | |||
405 | * since we are getting an answer on our transform offer, only one | |||
406 | * transform. | |||
407 | */ | |||
408 | if (TAILQ_NEXT(sa_p, link)((sa_p)->link.tqe_next) || TAILQ_NEXT(prop, link)((prop)->link.tqe_next) || | |||
409 | TAILQ_NEXT(xf, link)((xf)->link.tqe_next)) { | |||
410 | log_print("ike_phase_1_initiator_recv_SA: " | |||
411 | "multiple SA, proposal or transform payloads in phase 1"); | |||
412 | /* XXX Is there a better notification type? */ | |||
413 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
414 | return -1; | |||
415 | } | |||
416 | /* Check that the chosen transform matches an offer. */ | |||
417 | if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || | |||
418 | !TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)) | |||
419 | return -1; | |||
420 | ||||
421 | ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first), xf->p); | |||
422 | ||||
423 | /* XXX I don't like exchange-specific stuff in here. */ | |||
424 | if (exchange->type != ISAKMP_EXCH_AGGRESSIVE4) | |||
425 | ie->group = group_get(isa->group_desc); | |||
426 | ||||
427 | /* Mark the SA as handled. */ | |||
428 | sa_p->flags |= PL_MARK1; | |||
429 | ||||
430 | return 0; | |||
431 | } | |||
432 | ||||
433 | /* Send our public DH value and a nonce to the responder. */ | |||
434 | int | |||
435 | ike_phase_1_initiator_send_KE_NONCE(struct message *msg) | |||
436 | { | |||
437 | struct ipsec_exch *ie = msg->exchange->data; | |||
438 | ||||
439 | ie->g_x_len = dh_getlen(ie->group); | |||
440 | ||||
441 | /* XXX I want a better way to specify the nonce's size. */ | |||
442 | return ike_phase_1_send_KE_NONCE(msg, 16); | |||
443 | } | |||
444 | ||||
445 | /* Accept responder's public DH value and nonce. */ | |||
446 | int | |||
447 | ike_phase_1_initiator_recv_KE_NONCE(struct message *msg) | |||
448 | { | |||
449 | if (ike_phase_1_recv_KE_NONCE(msg)) | |||
450 | return -1; | |||
451 | ||||
452 | return ike_phase_1_post_exchange_KE_NONCE(msg); | |||
453 | } | |||
454 | ||||
455 | /* | |||
456 | * Accept a set of transforms offered by the initiator and chose one we can | |||
457 | * handle. | |||
458 | */ | |||
459 | int | |||
460 | ike_phase_1_responder_recv_SA(struct message *msg) | |||
461 | { | |||
462 | struct exchange *exchange = msg->exchange; | |||
463 | struct sa *sa = TAILQ_FIRST(&exchange->sa_list)((&exchange->sa_list)->tqh_first); | |||
464 | struct ipsec_sa *isa = sa->data; | |||
465 | struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA1); | |||
466 | struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL2); | |||
467 | struct ipsec_exch *ie = exchange->data; | |||
468 | ||||
469 | /* Mark the SA as handled. */ | |||
470 | sa_p->flags |= PL_MARK1; | |||
471 | ||||
472 | /* IKE requires that only one SA with only one proposal exists. */ | |||
473 | if (TAILQ_NEXT(sa_p, link)((sa_p)->link.tqe_next) || TAILQ_NEXT(prop, link)((prop)->link.tqe_next)) { | |||
474 | log_print("ike_phase_1_responder_recv_SA: " | |||
475 | "multiple SA or proposal payloads in phase 1"); | |||
476 | /* XXX Is there a better notification type? */ | |||
477 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
478 | return -1; | |||
479 | } | |||
480 | /* Chose a transform from the SA. */ | |||
481 | if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || | |||
482 | !TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)) | |||
483 | return -1; | |||
484 | ||||
485 | /* XXX Move into message_negotiate_sa? */ | |||
486 | ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first), | |||
487 | TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)->chosen->p); | |||
488 | ||||
489 | ie->group = group_get(isa->group_desc); | |||
490 | ||||
491 | /* | |||
492 | * Check that the mandatory attributes: encryption, hash, | |||
493 | * authentication method and Diffie-Hellman group description, has | |||
494 | * been supplied. | |||
495 | */ | |||
496 | if (!exchange->crypto || !ie->hash || !ie->ike_auth || !ie->group) { | |||
497 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
498 | return -1; | |||
499 | } | |||
500 | /* Save the body for later hash computation. */ | |||
501 | ie->sa_i_b_len = GET_ISAKMP_GEN_LENGTH(sa_p->p)field_get_num (isakmp_gen_fld + 2, sa_p->p) - ISAKMP_GEN_SZ4; | |||
502 | ie->sa_i_b = malloc(ie->sa_i_b_len); | |||
503 | if (!ie->sa_i_b) { | |||
504 | /* XXX How to notify peer? */ | |||
505 | log_error("ike_phase_1_responder_recv_SA: malloc (%lu) failed", | |||
506 | (unsigned long)ie->sa_i_b_len); | |||
507 | return -1; | |||
508 | } | |||
509 | memcpy(ie->sa_i_b, sa_p->p + ISAKMP_GEN_SZ4, ie->sa_i_b_len); | |||
510 | return 0; | |||
511 | } | |||
512 | ||||
513 | /* Reply with the transform we chose. */ | |||
514 | int | |||
515 | ike_phase_1_responder_send_SA(struct message *msg) | |||
516 | { | |||
517 | /* Add the SA payload with the transform that was chosen. */ | |||
518 | if (message_add_sa_payload(msg)) | |||
519 | return -1; | |||
520 | ||||
521 | /* Advertise OpenBSD isakmpd. */ | |||
522 | if (add_vendor_openbsd(msg)) | |||
523 | return -1; | |||
524 | ||||
525 | /* Advertise NAT-T capability. */ | |||
526 | if (nat_t_add_vendor_payloads(msg)) | |||
527 | return -1; | |||
528 | ||||
529 | /* Advertise DPD capability. */ | |||
530 | if (dpd_add_vendor_payload(msg)) | |||
531 | return -1; | |||
532 | return 0; | |||
533 | } | |||
534 | ||||
535 | /* Send our public DH value and a nonce to the peer. */ | |||
536 | int | |||
537 | ike_phase_1_send_KE_NONCE(struct message *msg, size_t nonce_sz) | |||
538 | { | |||
539 | /* Public DH key. */ | |||
540 | if (ipsec_gen_g_x(msg)) { | |||
541 | /* XXX How to log and notify peer? */ | |||
542 | return -1; | |||
543 | } | |||
544 | /* Generate a nonce, and add it to the message. */ | |||
545 | if (exchange_gen_nonce(msg, nonce_sz)) { | |||
546 | /* XXX Log? */ | |||
547 | return -1; | |||
548 | } | |||
549 | /* Are there any CERTREQs to send? */ | |||
550 | if (exchange_add_certreqs(msg)) { | |||
551 | /* XXX Log? */ | |||
552 | return -1; | |||
553 | } | |||
554 | /* Try to add certificates which are acceptable for the CERTREQs */ | |||
555 | if (exchange_add_certs(msg)) { | |||
556 | /* XXX Log? */ | |||
557 | return -1; | |||
558 | } | |||
559 | /* If this exchange uses NAT-Traversal, add NAT-D payloads now. */ | |||
560 | if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER0x0008) | |||
561 | if (nat_t_exchange_add_nat_d(msg)) { | |||
562 | /* XXX Log? */ | |||
563 | return -1; | |||
564 | } | |||
565 | return 0; | |||
566 | } | |||
567 | ||||
568 | /* Receive our peer's public DH value and nonce. */ | |||
569 | int | |||
570 | ike_phase_1_recv_KE_NONCE(struct message *msg) | |||
571 | { | |||
572 | /* Copy out the initiator's DH public value. */ | |||
573 | if (ipsec_save_g_x(msg)) { | |||
574 | /* XXX How to log and notify peer? */ | |||
575 | return -1; | |||
576 | } | |||
577 | /* Copy out the initiator's nonce. */ | |||
578 | if (exchange_save_nonce(msg)) { | |||
579 | /* XXX How to log and notify peer? */ | |||
580 | return -1; | |||
581 | } | |||
582 | /* Copy out the initiator's cert requests. */ | |||
583 | if (exchange_save_certreq(msg)) { | |||
584 | /* XXX How to log and notify peer? */ | |||
585 | return -1; | |||
586 | } | |||
587 | /* MainMode: Check for NAT-D payloads and contents. */ | |||
588 | if (msg->exchange->type == ISAKMP_EXCH_ID_PROT2 && | |||
589 | msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER0x0008) | |||
590 | (void)nat_t_exchange_check_nat_d(msg); | |||
591 | return 0; | |||
592 | } | |||
593 | ||||
594 | /* | |||
595 | * Compute DH values and key material. This is done in a post-send function | |||
596 | * as that means we can do parallel work in both the initiator and responder | |||
597 | * thus speeding up exchanges. | |||
598 | */ | |||
599 | int | |||
600 | ike_phase_1_post_exchange_KE_NONCE(struct message *msg) | |||
601 | { | |||
602 | struct exchange *exchange = msg->exchange; | |||
603 | struct ipsec_exch *ie = exchange->data; | |||
604 | struct prf *prf; | |||
605 | struct hash *hash = ie->hash; | |||
606 | enum cryptoerr err; | |||
607 | ||||
608 | /* Compute Diffie-Hellman shared value. */ | |||
609 | ie->g_xy_len = dh_secretlen(ie->group); | |||
610 | ie->g_xy = malloc(ie->g_xy_len); | |||
611 | if (!ie->g_xy) { | |||
612 | /* XXX How to notify peer? */ | |||
613 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
614 | "malloc (%lu) failed", (unsigned long)ie->g_xy_len); | |||
615 | return -1; | |||
616 | } | |||
617 | if (dh_create_shared(ie->group, ie->g_xy, | |||
618 | exchange->initiator ? ie->g_xr : ie->g_xi)) { | |||
619 | log_print("ike_phase_1_post_exchange_KE_NONCE: " | |||
620 | "dh_create_shared failed"); | |||
621 | return -1; | |||
622 | } | |||
623 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy" , ie->g_xy, ie->g_xy_len) | |||
624 | "ike_phase_1_post_exchange_KE_NONCE: g^xy", ie->g_xy,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy" , ie->g_xy, ie->g_xy_len) | |||
625 | ie->g_xy_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy" , ie->g_xy, ie->g_xy_len); | |||
626 | ||||
627 | /* Compute the SKEYID depending on the authentication method. */ | |||
628 | ie->skeyid = ie->ike_auth->gen_skeyid(exchange, &ie->skeyid_len); | |||
629 | if (!ie->skeyid) { | |||
630 | /* XXX Log and teardown? */ | |||
631 | return -1; | |||
632 | } | |||
633 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID" , ie->skeyid, ie->skeyid_len) | |||
634 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID" , ie->skeyid, ie->skeyid_len) | |||
635 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID" , ie->skeyid, ie->skeyid_len); | |||
636 | ||||
637 | /* SKEYID_d. */ | |||
638 | ie->skeyid_d = malloc(ie->skeyid_len); | |||
639 | if (!ie->skeyid_d) { | |||
640 | /* XXX How to notify peer? */ | |||
641 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
642 | "malloc (%lu) failed", (unsigned long)ie->skeyid_len); | |||
643 | return -1; | |||
644 | } | |||
645 | prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); | |||
646 | if (!prf) { | |||
647 | /* XXX Log and teardown? */ | |||
648 | return -1; | |||
649 | } | |||
650 | prf->Init(prf->prfctx); | |||
651 | prf->Update(prf->prfctx, ie->g_xy, ie->g_xy_len); | |||
652 | prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); | |||
653 | prf->Update(prf->prfctx, (unsigned char *)"\0", 1); | |||
654 | prf->Final(ie->skeyid_d, prf->prfctx); | |||
655 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d" , ie->skeyid_d, ie->skeyid_len) | |||
656 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d", ie->skeyid_d,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d" , ie->skeyid_d, ie->skeyid_len) | |||
657 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d" , ie->skeyid_d, ie->skeyid_len); | |||
658 | ||||
659 | /* SKEYID_a. */ | |||
660 | ie->skeyid_a = malloc(ie->skeyid_len); | |||
661 | if (!ie->skeyid_a) { | |||
662 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
663 | "malloc (%lu) failed", (unsigned long)ie->skeyid_len); | |||
664 | prf_free(prf); | |||
665 | return -1; | |||
666 | } | |||
667 | prf->Init(prf->prfctx); | |||
668 | prf->Update(prf->prfctx, ie->skeyid_d, ie->skeyid_len); | |||
669 | prf->Update(prf->prfctx, ie->g_xy, ie->g_xy_len); | |||
670 | prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); | |||
671 | prf->Update(prf->prfctx, (unsigned char *)"\1", 1); | |||
672 | prf->Final(ie->skeyid_a, prf->prfctx); | |||
673 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a" , ie->skeyid_a, ie->skeyid_len) | |||
674 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a", ie->skeyid_a,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a" , ie->skeyid_a, ie->skeyid_len) | |||
675 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a" , ie->skeyid_a, ie->skeyid_len); | |||
676 | ||||
677 | /* SKEYID_e. */ | |||
678 | ie->skeyid_e = malloc(ie->skeyid_len); | |||
679 | if (!ie->skeyid_e) { | |||
680 | /* XXX How to notify peer? */ | |||
681 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
682 | "malloc (%lu) failed", (unsigned long)ie->skeyid_len); | |||
683 | prf_free(prf); | |||
684 | return -1; | |||
685 | } | |||
686 | prf->Init(prf->prfctx); | |||
687 | prf->Update(prf->prfctx, ie->skeyid_a, ie->skeyid_len); | |||
688 | prf->Update(prf->prfctx, ie->g_xy, ie->g_xy_len); | |||
689 | prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); | |||
690 | prf->Update(prf->prfctx, (unsigned char *)"\2", 1); | |||
691 | prf->Final(ie->skeyid_e, prf->prfctx); | |||
692 | prf_free(prf); | |||
693 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e" , ie->skeyid_e, ie->skeyid_len) | |||
694 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e", ie->skeyid_e,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e" , ie->skeyid_e, ie->skeyid_len) | |||
695 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e" , ie->skeyid_e, ie->skeyid_len); | |||
696 | ||||
697 | /* Key length determination. */ | |||
698 | if (!exchange->key_length) | |||
699 | exchange->key_length = exchange->crypto->keymax; | |||
700 | ||||
701 | /* Derive a longer key from skeyid_e */ | |||
702 | if (ie->skeyid_len < exchange->key_length) { | |||
703 | u_int16_t len, keylen; | |||
704 | u_int8_t *key, *p; | |||
705 | ||||
706 | prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid_e, | |||
707 | ie->skeyid_len); | |||
708 | if (!prf) { | |||
709 | /* XXX - notify peer */ | |||
710 | return -1; | |||
711 | } | |||
712 | /* Make keylen a multiple of prf->blocksize */ | |||
713 | keylen = exchange->key_length; | |||
714 | if (keylen % prf->blocksize) | |||
715 | keylen += prf->blocksize - (keylen % prf->blocksize); | |||
716 | ||||
717 | key = malloc(keylen); | |||
718 | if (!key) { | |||
719 | /* XXX - Notify peer. */ | |||
720 | prf_free(prf); | |||
721 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
722 | "malloc (%d) failed", keylen); | |||
723 | return -1; | |||
724 | } | |||
725 | prf->Init(prf->prfctx); | |||
726 | prf->Update(prf->prfctx, (unsigned char *)"\0", 1); | |||
727 | prf->Final(key, prf->prfctx); | |||
728 | ||||
729 | for (len = prf->blocksize, p = key; len < exchange->key_length; | |||
730 | len += prf->blocksize, p += prf->blocksize) { | |||
731 | prf->Init(prf->prfctx); | |||
732 | prf->Update(prf->prfctx, p, prf->blocksize); | |||
733 | prf->Final(p + prf->blocksize, prf->prfctx); | |||
734 | } | |||
735 | prf_free(prf); | |||
736 | ||||
737 | /* Setup our keystate using the derived encryption key. */ | |||
738 | exchange->keystate = crypto_init(exchange->crypto, key, | |||
739 | exchange->key_length, &err); | |||
740 | ||||
741 | free(key); | |||
742 | } else | |||
743 | /* Setup our keystate using the raw skeyid_e. */ | |||
744 | exchange->keystate = crypto_init(exchange->crypto, | |||
745 | ie->skeyid_e, exchange->key_length, &err); | |||
746 | ||||
747 | /* Special handling for DES weak keys. */ | |||
748 | if (!exchange->keystate && err == EWEAKKEY && | |||
749 | (exchange->key_length << 1) <= ie->skeyid_len) { | |||
750 | log_print("ike_phase_1_post_exchange_KE_NONCE: " | |||
751 | "weak key, trying subseq. skeyid_e"); | |||
752 | exchange->keystate = crypto_init(exchange->crypto, | |||
753 | ie->skeyid_e + exchange->key_length, | |||
754 | exchange->key_length, &err); | |||
755 | } | |||
756 | if (!exchange->keystate) { | |||
757 | log_print("ike_phase_1_post_exchange_KE_NONCE: " | |||
758 | "exchange->crypto->init () failed: %d", err); | |||
759 | ||||
760 | /* | |||
761 | * XXX We really need to know if problems are of transient | |||
762 | * nature or fatal (like failed assertions etc.) | |||
763 | */ | |||
764 | return -1; | |||
765 | } | |||
766 | /* Setup IV. XXX Only for CBC transforms, no? */ | |||
767 | hash->Init(hash->ctx); | |||
768 | hash->Update(hash->ctx, ie->g_xi, ie->g_x_len); | |||
769 | hash->Update(hash->ctx, ie->g_xr, ie->g_x_len); | |||
770 | hash->Final(hash->digest, hash->ctx); | |||
771 | crypto_init_iv(exchange->keystate, hash->digest, | |||
772 | exchange->crypto->blocksize); | |||
773 | return 0; | |||
774 | } | |||
775 | ||||
776 | int | |||
777 | ike_phase_1_responder_send_ID_AUTH(struct message *msg) | |||
778 | { | |||
779 | if (ike_phase_1_send_ID(msg)) | |||
780 | return -1; | |||
781 | ||||
782 | return ike_phase_1_send_AUTH(msg); | |||
783 | } | |||
784 | ||||
785 | int | |||
786 | ike_phase_1_send_ID(struct message *msg) | |||
787 | { | |||
788 | struct exchange *exchange = msg->exchange; | |||
789 | u_int8_t *buf; | |||
790 | char header[80]; | |||
791 | ssize_t sz; | |||
792 | struct sockaddr *src; | |||
793 | int initiator = exchange->initiator; | |||
794 | u_int8_t **id; | |||
795 | size_t *id_len; | |||
796 | char *my_id = 0, *data; | |||
797 | u_int8_t id_type; | |||
798 | sa_family_t af = 0; | |||
799 | ||||
800 | /* Choose the right fields to fill-in. */ | |||
801 | id = initiator ? &exchange->id_i : &exchange->id_r; | |||
802 | id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len; | |||
803 | ||||
804 | if (exchange->name) | |||
805 | my_id = conf_get_str(exchange->name, "ID"); | |||
806 | ||||
807 | if (!my_id) | |||
808 | my_id = conf_get_str("General", "Default-phase-1-ID"); | |||
809 | ||||
810 | msg->transport->vtbl->get_src(msg->transport, &src); | |||
811 | sz = my_id ? ipsec_id_size(my_id, &id_type) : sockaddr_addrlen(src); | |||
812 | if (sz == -1) | |||
813 | return -1; | |||
814 | ||||
815 | sz += ISAKMP_ID_DATA_OFF8; | |||
816 | buf = malloc(sz); | |||
817 | if (!buf) { | |||
818 | log_error("ike_phase_1_send_ID: malloc (%lu) failed", | |||
819 | (unsigned long)sz); | |||
820 | return -1; | |||
821 | } | |||
822 | SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 0, buf + 5, 0); | |||
823 | SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 1, buf + 5, 0); | |||
824 | if (my_id) { | |||
825 | SET_ISAKMP_ID_TYPE(buf, id_type)field_set_num (isakmp_id_fld + 0, buf, id_type); | |||
826 | switch (id_type) { | |||
827 | case IPSEC_ID_IPV4_ADDR1: | |||
828 | case IPSEC_ID_IPV4_ADDR_SUBNET4: | |||
829 | af = AF_INET2; | |||
830 | break; | |||
831 | case IPSEC_ID_IPV6_ADDR5: | |||
832 | case IPSEC_ID_IPV6_ADDR_SUBNET6: | |||
833 | af = AF_INET624; | |||
834 | break; | |||
835 | } | |||
836 | switch (id_type) { | |||
837 | case IPSEC_ID_IPV4_ADDR1: | |||
838 | case IPSEC_ID_IPV6_ADDR5: | |||
839 | data = conf_get_str(my_id, "Address"); | |||
840 | if (!data) { | |||
841 | log_print("ike_phase_1_send_ID: section %s " | |||
842 | "has no \"Address\" tag", my_id); | |||
843 | free(buf); | |||
844 | return -1; | |||
845 | } | |||
846 | if (text2sockaddr(data, NULL((void *)0), &src, af, 0)) { | |||
847 | log_error("ike_phase_1_send_ID: " | |||
848 | "text2sockaddr() failed"); | |||
849 | free(buf); | |||
850 | return -1; | |||
851 | } | |||
852 | memcpy(buf + ISAKMP_ID_DATA_OFF8, | |||
853 | sockaddr_addrdata(src), sockaddr_addrlen(src)); | |||
854 | free(src); | |||
855 | break; | |||
856 | ||||
857 | case IPSEC_ID_IPV4_ADDR_SUBNET4: | |||
858 | case IPSEC_ID_IPV6_ADDR_SUBNET6: | |||
859 | /* Network */ | |||
860 | data = conf_get_str(my_id, "Network"); | |||
861 | if (!data) { | |||
862 | log_print("ike_phase_1_send_ID: section %s " | |||
863 | "has no \"Network\" tag", my_id); | |||
864 | free(buf); | |||
865 | return -1; | |||
866 | } | |||
867 | if (text2sockaddr(data, NULL((void *)0), &src, af, 0)) { | |||
868 | log_error("ike_phase_1_send_ID: " | |||
869 | "text2sockaddr() failed"); | |||
870 | free(buf); | |||
871 | return -1; | |||
872 | } | |||
873 | memcpy(buf + ISAKMP_ID_DATA_OFF8, | |||
874 | sockaddr_addrdata(src), sockaddr_addrlen(src)); | |||
875 | free(src); | |||
876 | /* Netmask */ | |||
877 | data = conf_get_str(my_id, "Netmask"); | |||
878 | if (!data) { | |||
879 | log_print("ike_phase_1_send_ID: section %s " | |||
880 | "has no \"Netmask\" tag", my_id); | |||
881 | free(buf); | |||
882 | return -1; | |||
883 | } | |||
884 | if (text2sockaddr(data, NULL((void *)0), &src, af, 1)) { | |||
885 | log_error("ike_phase_1_send_ID: " | |||
886 | "text2sockaddr() failed"); | |||
887 | free(buf); | |||
888 | return -1; | |||
889 | } | |||
890 | memcpy(buf + ISAKMP_ID_DATA_OFF8 + | |||
891 | sockaddr_addrlen(src), sockaddr_addrdata(src), | |||
892 | sockaddr_addrlen(src)); | |||
893 | free(src); | |||
894 | break; | |||
895 | ||||
896 | case IPSEC_ID_FQDN2: | |||
897 | case IPSEC_ID_USER_FQDN3: | |||
898 | case IPSEC_ID_KEY_ID11: | |||
899 | data = conf_get_str(my_id, "Name"); | |||
900 | if (!data) { | |||
901 | log_print("ike_phase_1_send_ID: section %s " | |||
902 | "has no \"Name\" tag", my_id); | |||
903 | free(buf); | |||
904 | return -1; | |||
905 | } | |||
906 | memcpy(buf + ISAKMP_ID_DATA_OFF8, data, | |||
907 | sz - ISAKMP_ID_DATA_OFF8); | |||
908 | break; | |||
909 | ||||
910 | default: | |||
911 | log_print("ike_phase_1_send_ID: " | |||
912 | "unsupported ID type %d", id_type); | |||
913 | free(buf); | |||
914 | return -1; | |||
915 | } | |||
916 | } else { | |||
917 | switch (src->sa_family) { | |||
918 | case AF_INET2: | |||
919 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR)field_set_num (isakmp_id_fld + 0, buf, 1); | |||
920 | break; | |||
921 | case AF_INET624: | |||
922 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR)field_set_num (isakmp_id_fld + 0, buf, 5); | |||
923 | break; | |||
924 | } | |||
925 | /* Already in network byteorder. */ | |||
926 | memcpy(buf + ISAKMP_ID_DATA_OFF8, sockaddr_addrdata(src), | |||
927 | sockaddr_addrlen(src)); | |||
928 | } | |||
929 | ||||
930 | if (message_add_payload(msg, ISAKMP_PAYLOAD_ID5, buf, sz, 1)) { | |||
931 | free(buf); | |||
932 | return -1; | |||
933 | } | |||
934 | *id_len = sz - ISAKMP_GEN_SZ4; | |||
935 | *id = malloc(*id_len); | |||
936 | if (!*id) { | |||
937 | log_error("ike_phase_1_send_ID: malloc (%lu) failed", | |||
938 | (unsigned long)*id_len); | |||
939 | return -1; | |||
940 | } | |||
941 | memcpy(*id, buf + ISAKMP_GEN_SZ4, *id_len); | |||
942 | snprintf(header, sizeof header, "ike_phase_1_send_ID: %s", | |||
943 | constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(buf)field_get_num (isakmp_id_fld + 0, buf))); | |||
944 | LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF,log_debug_buf (LOG_NEGOTIATION, 40, header, buf + 8, sz - 8) | |||
945 | sz - ISAKMP_ID_DATA_OFF))log_debug_buf (LOG_NEGOTIATION, 40, header, buf + 8, sz - 8); | |||
946 | return 0; | |||
947 | } | |||
948 | ||||
949 | int | |||
950 | ike_phase_1_send_AUTH(struct message *msg) | |||
951 | { | |||
952 | struct exchange *exchange = msg->exchange; | |||
953 | struct ipsec_exch *ie = exchange->data; | |||
954 | ||||
955 | if (ie->ike_auth->encode_hash(msg)) { | |||
956 | /* XXX Log? */ | |||
957 | return -1; | |||
958 | } | |||
959 | /* | |||
960 | * XXX Many people say the COMMIT flag is just junk, especially in | |||
961 | * Phase 1. | |||
962 | */ | |||
963 | #ifdef notyet | |||
964 | if ((exchange->flags & EXCHANGE_FLAG_COMMITTED(0x0001 | 0x0002)) == 0) | |||
965 | exchange->flags |= EXCHANGE_FLAG_I_COMMITTED0x0001; | |||
966 | #endif | |||
967 | ||||
968 | return 0; | |||
969 | } | |||
970 | ||||
971 | /* Receive ID and HASH and check that the exchange has been consistent. */ | |||
972 | int | |||
973 | ike_phase_1_recv_ID_AUTH(struct message *msg) | |||
974 | { | |||
975 | if (ike_phase_1_recv_ID(msg)) | |||
976 | return -1; | |||
977 | ||||
978 | return ike_phase_1_recv_AUTH(msg); | |||
979 | } | |||
980 | ||||
981 | /* Receive ID. */ | |||
982 | int | |||
983 | ike_phase_1_recv_ID(struct message *msg) | |||
984 | { | |||
985 | struct exchange *exchange = msg->exchange; | |||
986 | struct payload *payload; | |||
987 | char header[80], *rs = 0, *rid = 0, *p; | |||
988 | int initiator = exchange->initiator; | |||
989 | u_int8_t **id, id_type; | |||
990 | size_t *id_len; | |||
991 | ssize_t sz; | |||
992 | struct sockaddr *sa; | |||
993 | sa_family_t af = 0; | |||
994 | ||||
995 | payload = payload_first(msg, ISAKMP_PAYLOAD_ID5); | |||
996 | ||||
997 | if (exchange->name) | |||
998 | rs = conf_get_str(exchange->name, "Remote-ID"); | |||
999 | ||||
1000 | if (rs) { | |||
1001 | sz = ipsec_id_size(rs, &id_type); | |||
1002 | if (sz == -1) { | |||
1003 | log_print("ike_phase_1_recv_ID: could not handle " | |||
1004 | "specified Remote-ID [%s]", rs); | |||
1005 | return -1; | |||
1006 | } | |||
1007 | rid = malloc(sz); | |||
1008 | if (!rid) { | |||
1009 | log_error("ike_phase_1_recv_ID: malloc (%lu) failed", | |||
1010 | (unsigned long)sz); | |||
1011 | return -1; | |||
1012 | } | |||
1013 | switch (id_type) { | |||
1014 | case IPSEC_ID_IPV4_ADDR1: | |||
1015 | af = AF_INET2; | |||
1016 | break; | |||
1017 | case IPSEC_ID_IPV6_ADDR5: | |||
1018 | af = AF_INET624; | |||
1019 | break; | |||
1020 | } | |||
1021 | switch (id_type) { | |||
1022 | case IPSEC_ID_IPV4_ADDR1: | |||
1023 | case IPSEC_ID_IPV6_ADDR5: | |||
1024 | p = conf_get_str(rs, "Address"); | |||
1025 | if (!p) { | |||
1026 | log_print("ike_phase_1_recv_ID: failed to get " | |||
1027 | "Address in Remote-ID section [%s]", rs); | |||
1028 | free(rid); | |||
1029 | return -1; | |||
1030 | } | |||
1031 | if (text2sockaddr(p, 0, &sa, af, 0) == -1) { | |||
1032 | log_print("ike_phase_1_recv_ID: " | |||
1033 | "failed to parse address %s", p); | |||
1034 | free(rid); | |||
1035 | return -1; | |||
1036 | } | |||
1037 | if ((id_type == IPSEC_ID_IPV4_ADDR1 && | |||
1038 | sa->sa_family != AF_INET2) || | |||
1039 | (id_type == IPSEC_ID_IPV6_ADDR5 && | |||
1040 | sa->sa_family != AF_INET624)) { | |||
1041 | log_print("ike_phase_1_recv_ID: " | |||
1042 | "address %s not of expected family", p); | |||
1043 | free(rid); | |||
1044 | free(sa); | |||
1045 | return -1; | |||
1046 | } | |||
1047 | memcpy(rid, sockaddr_addrdata(sa), | |||
1048 | sockaddr_addrlen(sa)); | |||
1049 | free(sa); | |||
1050 | break; | |||
1051 | ||||
1052 | case IPSEC_ID_FQDN2: | |||
1053 | case IPSEC_ID_USER_FQDN3: | |||
1054 | case IPSEC_ID_KEY_ID11: | |||
1055 | p = conf_get_str(rs, "Name"); | |||
1056 | if (!p) { | |||
1057 | log_print("ike_phase_1_recv_ID: failed to " | |||
1058 | "get Name in Remote-ID section [%s]", rs); | |||
1059 | free(rid); | |||
1060 | return -1; | |||
1061 | } | |||
1062 | memcpy(rid, p, sz); | |||
1063 | break; | |||
1064 | ||||
1065 | default: | |||
1066 | log_print("ike_phase_1_recv_ID: " | |||
1067 | "unsupported ID type %d", id_type); | |||
1068 | free(rid); | |||
1069 | return -1; | |||
1070 | } | |||
1071 | ||||
1072 | /* Compare expected/desired and received remote ID */ | |||
1073 | if (memcmp(rid, payload->p + ISAKMP_ID_DATA_OFF8, sz) != 0) { | |||
1074 | free(rid); | |||
1075 | log_print("ike_phase_1_recv_ID: " | |||
1076 | "received remote ID other than expected %s", p); | |||
1077 | return -1; | |||
1078 | } | |||
1079 | free(rid); | |||
1080 | } | |||
1081 | /* Choose the right fields to fill in */ | |||
1082 | id = initiator ? &exchange->id_r : &exchange->id_i; | |||
1083 | id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len; | |||
1084 | ||||
1085 | *id_len = GET_ISAKMP_GEN_LENGTH(payload->p)field_get_num (isakmp_gen_fld + 2, payload->p) - ISAKMP_GEN_SZ4; | |||
1086 | *id = malloc(*id_len); | |||
1087 | if (!*id) { | |||
1088 | log_error("ike_phase_1_recv_ID: malloc (%lu) failed", | |||
1089 | (unsigned long)*id_len); | |||
1090 | return -1; | |||
1091 | } | |||
1092 | memcpy(*id, payload->p + ISAKMP_GEN_SZ4, *id_len); | |||
1093 | snprintf(header, sizeof header, "ike_phase_1_recv_ID: %s", | |||
1094 | constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(payload->p)field_get_num (isakmp_id_fld + 0, payload->p))); | |||
1095 | LOG_DBG_BUF((LOG_NEGOTIATION, 40, header,log_debug_buf (LOG_NEGOTIATION, 40, header, payload->p + 8 , *id_len + 4 - 8) | |||
1096 | payload->p + ISAKMP_ID_DATA_OFF,log_debug_buf (LOG_NEGOTIATION, 40, header, payload->p + 8 , *id_len + 4 - 8) | |||
1097 | *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF))log_debug_buf (LOG_NEGOTIATION, 40, header, payload->p + 8 , *id_len + 4 - 8); | |||
1098 | payload->flags |= PL_MARK1; | |||
1099 | return 0; | |||
1100 | } | |||
1101 | ||||
1102 | /* Receive HASH and check that the exchange has been consistent. */ | |||
1103 | int | |||
1104 | ike_phase_1_recv_AUTH(struct message *msg) | |||
1105 | { | |||
1106 | struct exchange *exchange = msg->exchange; | |||
1107 | struct ipsec_exch *ie = exchange->data; | |||
1108 | struct prf *prf; | |||
1109 | struct hash *hash = ie->hash; | |||
1110 | char header[80]; | |||
1111 | size_t hashsize = hash->hashsize; | |||
1112 | int initiator = exchange->initiator; | |||
1113 | u_int8_t **hash_p, *id; | |||
1114 | size_t id_len; | |||
1115 | ||||
1116 | /* Choose the right fields to fill in */ | |||
1117 | hash_p = initiator ? &ie->hash_r : &ie->hash_i; | |||
1118 | id = initiator ? exchange->id_r : exchange->id_i; | |||
1119 | id_len = initiator ? exchange->id_r_len : exchange->id_i_len; | |||
1120 | ||||
1121 | /* The decoded hash will be in ie->hash_r or ie->hash_i */ | |||
1122 | if (ie->ike_auth->decode_hash(msg)) { | |||
1123 | message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION18, 0, 1, | |||
1124 | 0); | |||
1125 | return -1; | |||
1126 | } | |||
1127 | /* Allocate the prf and start calculating his HASH. */ | |||
1128 | prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); | |||
1129 | if (!prf) { | |||
1130 | /* XXX Log? */ | |||
1131 | return -1; | |||
1132 | } | |||
1133 | prf->Init(prf->prfctx); | |||
1134 | prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len); | |||
1135 | prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len); | |||
1136 | prf->Update(prf->prfctx, exchange->cookies + | |||
1137 | (initiator ? ISAKMP_HDR_RCOOKIE_OFF8 : ISAKMP_HDR_ICOOKIE_OFF0), | |||
1138 | ISAKMP_HDR_ICOOKIE_LEN8); | |||
1139 | prf->Update(prf->prfctx, exchange->cookies + | |||
1140 | (initiator ? ISAKMP_HDR_ICOOKIE_OFF0 : ISAKMP_HDR_RCOOKIE_OFF8), | |||
1141 | ISAKMP_HDR_ICOOKIE_LEN8); | |||
1142 | prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len); | |||
1143 | prf->Update(prf->prfctx, id, id_len); | |||
1144 | prf->Final(hash->digest, prf->prfctx); | |||
1145 | prf_free(prf); | |||
1146 | snprintf(header, sizeof header, "ike_phase_1_recv_AUTH: " | |||
1147 | "computed HASH_%c", initiator ? 'R' : 'I'); | |||
1148 | LOG_DBG_BUF((LOG_NEGOTIATION, 80, header, hash->digest, hashsize))log_debug_buf (LOG_NEGOTIATION, 80, header, hash->digest, hashsize ); | |||
1149 | ||||
1150 | /* Check that the hash we got matches the one we computed. */ | |||
1151 | if (memcmp(*hash_p, hash->digest, hashsize) != 0) { | |||
1152 | /* XXX Log? */ | |||
1153 | return -1; | |||
1154 | } | |||
1155 | ||||
1156 | /* Mark message as authenticated. */ | |||
1157 | msg->flags |= MSG_AUTHENTICATED0x10; | |||
1158 | ||||
1159 | return 0; | |||
1160 | } | |||
1161 | ||||
1162 | struct attr_node { | |||
1163 | LIST_ENTRY(attr_node)struct { struct attr_node *le_next; struct attr_node **le_prev ; } link; | |||
1164 | u_int16_t type; | |||
1165 | }; | |||
1166 | ||||
1167 | struct validation_state { | |||
1168 | struct conf_list_node *xf; | |||
1169 | LIST_HEAD(attr_head, attr_node)struct attr_head { struct attr_node *lh_first; } attrs; | |||
1170 | char *life; | |||
1171 | }; | |||
1172 | ||||
1173 | /* Validate a proposal inside SA according to EXCHANGE's policy. */ | |||
1174 | static int | |||
1175 | ike_phase_1_validate_prop(struct exchange *exchange, struct sa *sa, | |||
1176 | struct sa *isakmp_sa) | |||
1177 | { | |||
1178 | struct conf_list *conf, *tags; | |||
1179 | struct conf_list_node *xf, *tag; | |||
1180 | struct proto *proto; | |||
1181 | struct validation_state vs; | |||
1182 | struct attr_node *node, *next_node; | |||
1183 | ||||
1184 | /* Get the list of transforms. */ | |||
1185 | conf = conf_get_list(exchange->policy, "Transforms"); | |||
1186 | if (!conf) | |||
| ||||
1187 | return 0; | |||
1188 | ||||
1189 | for (xf = TAILQ_FIRST(&conf->fields)((&conf->fields)->tqh_first); xf; xf = TAILQ_NEXT(xf, link)((xf)->link.tqe_next)) { | |||
1190 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); proto; | |||
1191 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) { | |||
1192 | /* Mark all attributes in our policy as unseen. */ | |||
1193 | LIST_INIT(&vs.attrs)do { ((&vs.attrs)->lh_first) = ((void *)0); } while (0 ); | |||
1194 | vs.xf = xf; | |||
1195 | vs.life = 0; | |||
1196 | if (attribute_map(proto->chosen->p + | |||
1197 | ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
1198 | GET_ISAKMP_GEN_LENGTH(proto->chosen->p)field_get_num (isakmp_gen_fld + 2, proto->chosen->p) - | |||
1199 | ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
1200 | attribute_unacceptable, &vs)) | |||
1201 | goto try_next; | |||
1202 | ||||
1203 | /* Sweep over unseen tags in this section. */ | |||
1204 | tags = conf_get_tag_list(xf->field); | |||
1205 | if (tags) { | |||
1206 | for (tag = TAILQ_FIRST(&tags->fields)((&tags->fields)->tqh_first); tag; | |||
1207 | tag = TAILQ_NEXT(tag, link)((tag)->link.tqe_next)) | |||
1208 | /* | |||
1209 | * XXX Should we care about attributes | |||
1210 | * we have, they do not provide? | |||
1211 | */ | |||
1212 | for (node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
1213 | node; node = next_node) { | |||
1214 | next_node = | |||
1215 | LIST_NEXT(node, link)((node)->link.le_next); | |||
1216 | if (node->type == | |||
1217 | constant_value(ike_attr_cst, | |||
1218 | tag->field)) { | |||
1219 | LIST_REMOVE(node, link)do { if ((node)->link.le_next != ((void *)0)) (node)->link .le_next->link.le_prev = (node)->link.le_prev; *(node)-> link.le_prev = (node)->link.le_next; ; ; } while (0); | |||
1220 | free(node); | |||
1221 | } | |||
1222 | } | |||
1223 | conf_free_list(tags); | |||
1224 | } | |||
1225 | /* Are there leftover tags in this section? */ | |||
1226 | node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
1227 | if (node) | |||
1228 | goto try_next; | |||
1229 | } | |||
1230 | ||||
1231 | /* All protocols were OK, we succeeded. */ | |||
1232 | LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: "log_debug (LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: " "success") | |||
1233 | "success"))log_debug (LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: " "success"); | |||
1234 | conf_free_list(conf); | |||
1235 | free(vs.life); | |||
| ||||
1236 | return 1; | |||
1237 | ||||
1238 | try_next: | |||
1239 | /* Are there leftover tags in this section? */ | |||
1240 | node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
1241 | while (node) { | |||
1242 | LIST_REMOVE(node, link)do { if ((node)->link.le_next != ((void *)0)) (node)->link .le_next->link.le_prev = (node)->link.le_prev; *(node)-> link.le_prev = (node)->link.le_next; ; ; } while (0); | |||
1243 | free(node); | |||
1244 | node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
1245 | } | |||
1246 | free(vs.life); | |||
1247 | } | |||
1248 | ||||
1249 | LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure"))log_debug (LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure" ); | |||
1250 | conf_free_list(conf); | |||
1251 | return 0; | |||
1252 | } | |||
1253 | ||||
1254 | /* | |||
1255 | * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward. | |||
1256 | * The VVS argument holds a validation state kept across invocations. | |||
1257 | * If the attribute is unacceptable to use, return non-zero, otherwise zero. | |||
1258 | */ | |||
1259 | static int | |||
1260 | attribute_unacceptable(u_int16_t type, u_int8_t *value, u_int16_t len, | |||
1261 | void *vvs) | |||
1262 | { | |||
1263 | struct validation_state *vs = vvs; | |||
1264 | struct conf_list *life_conf; | |||
1265 | struct conf_list_node *xf = vs->xf, *life; | |||
1266 | char *tag = constant_lookup(ike_attr_cst, type); | |||
1267 | char *str; | |||
1268 | struct constant_map *map; | |||
1269 | struct attr_node *node; | |||
1270 | int rv, dur = 0; | |||
1271 | ||||
1272 | if (!tag) { | |||
1273 | log_print("attribute_unacceptable: " | |||
1274 | "attribute type %d not known", type); | |||
1275 | return 1; | |||
1276 | } | |||
1277 | switch (type) { | |||
1278 | case IKE_ATTR_ENCRYPTION_ALGORITHM1: | |||
1279 | case IKE_ATTR_HASH_ALGORITHM2: | |||
1280 | case IKE_ATTR_AUTHENTICATION_METHOD3: | |||
1281 | case IKE_ATTR_GROUP_DESCRIPTION4: | |||
1282 | case IKE_ATTR_GROUP_TYPE5: | |||
1283 | case IKE_ATTR_PRF13: | |||
1284 | str = conf_get_str(xf->field, tag); | |||
1285 | if (!str) { | |||
1286 | /* This attribute does not exist in this policy. */ | |||
1287 | log_print("attribute_unacceptable: " | |||
1288 | "attr %s does not exist in %s", tag, xf->field); | |||
1289 | return 1; | |||
1290 | } | |||
1291 | map = constant_link_lookup(ike_attr_cst, type); | |||
1292 | if (!map) | |||
1293 | return 1; | |||
1294 | ||||
1295 | if ((constant_value(map, str) == decode_16(value)) || | |||
1296 | (!strcmp(str, "ANY"))) { | |||
1297 | /* Mark this attribute as seen. */ | |||
1298 | node = malloc(sizeof *node); | |||
1299 | if (!node) { | |||
1300 | log_error("attribute_unacceptable: " | |||
1301 | "malloc (%lu) failed", | |||
1302 | (unsigned long)sizeof *node); | |||
1303 | return 1; | |||
1304 | } | |||
1305 | node->type = type; | |||
1306 | LIST_INSERT_HEAD(&vs->attrs, node, link)do { if (((node)->link.le_next = (&vs->attrs)->lh_first ) != ((void *)0)) (&vs->attrs)->lh_first->link.le_prev = &(node)->link.le_next; (&vs->attrs)->lh_first = (node); (node)->link.le_prev = &(&vs->attrs) ->lh_first; } while (0); | |||
1307 | return 0; | |||
1308 | } | |||
1309 | log_print("attribute_unacceptable: %s: got %s, expected %s", | |||
1310 | tag, constant_name(map, decode_16(value)), str); | |||
1311 | return 1; | |||
1312 | ||||
1313 | case IKE_ATTR_GROUP_PRIME6: | |||
1314 | case IKE_ATTR_GROUP_GENERATOR_17: | |||
1315 | case IKE_ATTR_GROUP_GENERATOR_28: | |||
1316 | case IKE_ATTR_GROUP_CURVE_A9: | |||
1317 | case IKE_ATTR_GROUP_CURVE_B10: | |||
1318 | /* XXX Bignums not handled yet. */ | |||
1319 | log_print("attribute_unacceptable: " | |||
1320 | "bignum type %d not supported", type); | |||
1321 | return 1; | |||
1322 | ||||
1323 | case IKE_ATTR_LIFE_TYPE11: | |||
1324 | case IKE_ATTR_LIFE_DURATION12: | |||
1325 | life_conf = conf_get_list(xf->field, "Life"); | |||
1326 | if (life_conf && | |||
1327 | !strcmp(conf_get_str(xf->field, "Life"), "ANY")) { | |||
1328 | conf_free_list(life_conf); | |||
1329 | return 0; | |||
1330 | } | |||
1331 | ||||
1332 | rv = 1; | |||
1333 | if (!life_conf) { | |||
1334 | /* Life attributes given, but not in our policy. */ | |||
1335 | log_print("attribute_unacceptable: " | |||
1336 | "life attribute received, none in policy"); | |||
1337 | return 1; | |||
1338 | } | |||
1339 | /* | |||
1340 | * Each lifetime type must match, otherwise we turn the | |||
1341 | * proposal down. In order to do this we need to find the | |||
1342 | * specific section of our policy's "Life" list and match | |||
1343 | * its duration. | |||
1344 | */ | |||
1345 | switch (type) { | |||
1346 | case IKE_ATTR_LIFE_TYPE11: | |||
1347 | for (life = TAILQ_FIRST(&life_conf->fields)((&life_conf->fields)->tqh_first); life; | |||
1348 | life = TAILQ_NEXT(life, link)((life)->link.tqe_next)) { | |||
1349 | str = conf_get_str(life->field, "LIFE_TYPE"); | |||
1350 | if (!str) { | |||
1351 | log_print("attribute_unacceptable: " | |||
1352 | "section [%s] has no LIFE_TYPE", | |||
1353 | life->field); | |||
1354 | continue; | |||
1355 | } | |||
1356 | ||||
1357 | /* | |||
1358 | * If this is the type we are looking at, | |||
1359 | * save a pointer to this section in vs->life. | |||
1360 | */ | |||
1361 | if (constant_value(ike_duration_cst, str) == | |||
1362 | decode_16(value)) { | |||
1363 | vs->life = strdup(life->field); | |||
1364 | rv = 0; | |||
1365 | goto bail_out; | |||
1366 | } | |||
1367 | } | |||
1368 | log_print("attribute_unacceptable: " | |||
1369 | "unrecognized LIFE_TYPE %d", decode_16(value)); | |||
1370 | vs->life = 0; | |||
1371 | break; | |||
1372 | ||||
1373 | case IKE_ATTR_LIFE_DURATION12: | |||
1374 | if (!vs->life) { | |||
1375 | log_print("attribute_unacceptable: " | |||
1376 | "LIFE_DURATION without LIFE_TYPE"); | |||
1377 | rv = 1; | |||
1378 | goto bail_out; | |||
1379 | } | |||
1380 | str = conf_get_str(vs->life, "LIFE_DURATION"); | |||
1381 | if (str) { | |||
1382 | if (!strcmp(str, "ANY")) | |||
1383 | rv = 0; | |||
1384 | else { | |||
1385 | dur = (len == 4) ? decode_32(value) : | |||
1386 | decode_16(value); | |||
1387 | if ((rv = !conf_match_num(vs->life, | |||
1388 | "LIFE_DURATION", dur))) { | |||
1389 | log_print( | |||
1390 | "attribute_unacceptable: " | |||
1391 | "LIFE_DURATION: got %d, " | |||
1392 | " expected %s", dur, str); | |||
1393 | } | |||
1394 | } | |||
1395 | } else { | |||
1396 | log_print("attribute_unacceptable: " | |||
1397 | "section [%s] has no LIFE_DURATION", | |||
1398 | vs->life); | |||
1399 | rv = 1; | |||
1400 | } | |||
1401 | ||||
1402 | free(vs->life); | |||
1403 | vs->life = 0; | |||
1404 | break; | |||
1405 | } | |||
1406 | ||||
1407 | bail_out: | |||
1408 | conf_free_list(life_conf); | |||
1409 | return rv; | |||
1410 | ||||
1411 | case IKE_ATTR_KEY_LENGTH14: | |||
1412 | case IKE_ATTR_FIELD_SIZE15: | |||
1413 | case IKE_ATTR_GROUP_ORDER16: | |||
1414 | if (conf_match_num(xf->field, tag, decode_16(value))) { | |||
1415 | /* Mark this attribute as seen. */ | |||
1416 | node = malloc(sizeof *node); | |||
1417 | if (!node) { | |||
1418 | log_error("attribute_unacceptable: " | |||
1419 | "malloc (%lu) failed", | |||
1420 | (unsigned long)sizeof *node); | |||
1421 | return 1; | |||
1422 | } | |||
1423 | node->type = type; | |||
1424 | LIST_INSERT_HEAD(&vs->attrs, node, link)do { if (((node)->link.le_next = (&vs->attrs)->lh_first ) != ((void *)0)) (&vs->attrs)->lh_first->link.le_prev = &(node)->link.le_next; (&vs->attrs)->lh_first = (node); (node)->link.le_prev = &(&vs->attrs) ->lh_first; } while (0); | |||
1425 | return 0; | |||
1426 | } | |||
1427 | return 1; | |||
1428 | default: | |||
1429 | log_print("attribute_unacceptable: unexpected type %d", | |||
1430 | type); | |||
1431 | } | |||
1432 | return 1; | |||
1433 | } |