]>
Commit | Line | Data |
---|---|---|
997358a6 MW |
1 | /* Security Policy Data Base (such as it is) |
2 | * Copyright (C) 1998-2001 D. Hugh Redelmeier. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the | |
6 | * Free Software Foundation; either version 2 of the License, or (at your | |
7 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but | |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 | * for more details. | |
13 | * | |
14 | * RCSID $Id: spdb.c,v 1.9 2006/04/22 21:59:20 as Exp $ | |
15 | */ | |
16 | ||
17 | #include <stdio.h> | |
18 | #include <string.h> | |
19 | #include <stdlib.h> | |
20 | #include <sys/socket.h> | |
21 | #include <netinet/in.h> | |
22 | #include <arpa/inet.h> | |
23 | #include <sys/queue.h> | |
24 | ||
25 | #include <freeswan.h> | |
f2c2d395 | 26 | #include <ipsec_policy.h> |
997358a6 MW |
27 | |
28 | #include "constants.h" | |
29 | #include "defs.h" | |
30 | #include "id.h" | |
31 | #include "connections.h" | |
32 | #include "state.h" | |
33 | #include "packet.h" | |
34 | #include "keys.h" | |
35 | #include "kernel.h" | |
36 | #include "log.h" | |
37 | #include "spdb.h" | |
38 | #include "whack.h" /* for RC_LOG_SERIOUS */ | |
39 | ||
40 | #include "sha1.h" | |
41 | #include "md5.h" | |
42 | #include "crypto.h" /* requires sha1.h and md5.h */ | |
43 | ||
44 | #include "alg_info.h" | |
45 | #include "kernel_alg.h" | |
46 | #include "ike_alg.h" | |
47 | #include "db_ops.h" | |
48 | #define AD(x) x, elemsof(x) /* Array Description */ | |
49 | #define AD_NULL NULL, 0 | |
50 | ||
51 | #ifdef NAT_TRAVERSAL | |
52 | #include "nat_traversal.h" | |
53 | #endif | |
54 | ||
55 | /**************** Oakely (main mode) SA database ****************/ | |
56 | ||
57 | /* arrays of attributes for transforms, preshared key */ | |
58 | ||
59 | static struct db_attr otpsk1024des3md5[] = { | |
60 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
61 | { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, | |
62 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, | |
63 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, | |
64 | }; | |
65 | ||
66 | static struct db_attr otpsk1536des3md5[] = { | |
67 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
68 | { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, | |
69 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, | |
70 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, | |
71 | }; | |
72 | ||
73 | static struct db_attr otpsk1024des3sha[] = { | |
74 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
75 | { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, | |
76 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, | |
77 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, | |
78 | }; | |
79 | ||
80 | static struct db_attr otpsk1536des3sha[] = { | |
81 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
82 | { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, | |
83 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, | |
84 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, | |
85 | }; | |
86 | ||
87 | /* arrays of attributes for transforms, RSA signatures */ | |
88 | ||
89 | static struct db_attr otrsasig1024des3md5[] = { | |
90 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
91 | { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, | |
92 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, | |
93 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, | |
94 | }; | |
95 | ||
96 | static struct db_attr otrsasig1536des3md5[] = { | |
97 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
98 | { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, | |
99 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, | |
100 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, | |
101 | }; | |
102 | ||
103 | static struct db_attr otrsasig1024des3sha[] = { | |
104 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
105 | { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, | |
106 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, | |
107 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, | |
108 | }; | |
109 | ||
110 | static struct db_attr otrsasig1536des3sha[] = { | |
111 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
112 | { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, | |
113 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, | |
114 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, | |
115 | }; | |
116 | ||
117 | /* We won't accept this, but by proposing it, we get to test | |
118 | * our rejection. We better not propose it to an IKE daemon | |
119 | * that will accept it! | |
120 | */ | |
121 | #ifdef TEST_INDECENT_PROPOSAL | |
122 | static struct db_attr otpsk1024des3tiger[] = { | |
123 | { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, | |
124 | { OAKLEY_HASH_ALGORITHM, OAKLEY_TIGER }, | |
125 | { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, | |
126 | { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, | |
127 | }; | |
128 | #endif /* TEST_INDECENT_PROPOSAL */ | |
129 | ||
130 | /* tables of transforms, in preference order (select based on AUTH) */ | |
131 | ||
132 | static struct db_trans oakley_trans_psk[] = { | |
133 | #ifdef TEST_INDECENT_PROPOSAL | |
134 | { KEY_IKE, AD(otpsk1024des3tiger) }, | |
135 | #endif | |
136 | { KEY_IKE, AD(otpsk1536des3md5) }, | |
137 | { KEY_IKE, AD(otpsk1536des3sha) }, | |
138 | { KEY_IKE, AD(otpsk1024des3sha) }, | |
139 | { KEY_IKE, AD(otpsk1024des3md5) }, | |
140 | }; | |
141 | ||
142 | static struct db_trans oakley_trans_rsasig[] = { | |
143 | { KEY_IKE, AD(otrsasig1536des3md5) }, | |
144 | { KEY_IKE, AD(otrsasig1536des3sha) }, | |
145 | { KEY_IKE, AD(otrsasig1024des3sha) }, | |
146 | { KEY_IKE, AD(otrsasig1024des3md5) }, | |
147 | }; | |
148 | ||
149 | /* In this table, either PSK or RSA sig is accepted. | |
150 | * The order matters, but I don't know what would be best. | |
151 | */ | |
152 | static struct db_trans oakley_trans_pskrsasig[] = { | |
153 | #ifdef TEST_INDECENT_PROPOSAL | |
154 | { KEY_IKE, AD(otpsk1024des3tiger) }, | |
155 | #endif | |
156 | { KEY_IKE, AD(otrsasig1536des3md5) }, | |
157 | { KEY_IKE, AD(otpsk1536des3md5) }, | |
158 | { KEY_IKE, AD(otrsasig1536des3sha) }, | |
159 | { KEY_IKE, AD(otpsk1536des3sha) }, | |
160 | { KEY_IKE, AD(otrsasig1024des3sha) }, | |
161 | { KEY_IKE, AD(otpsk1024des3sha) }, | |
162 | { KEY_IKE, AD(otrsasig1024des3md5) }, | |
163 | { KEY_IKE, AD(otpsk1024des3md5) }, | |
164 | }; | |
165 | ||
166 | /* array of proposals to be conjoined (can only be one for Oakley) */ | |
167 | ||
168 | static struct db_prop oakley_pc_psk[] = | |
169 | { { PROTO_ISAKMP, AD(oakley_trans_psk) } }; | |
170 | ||
171 | static struct db_prop oakley_pc_rsasig[] = | |
172 | { { PROTO_ISAKMP, AD(oakley_trans_rsasig) } }; | |
173 | ||
174 | static struct db_prop oakley_pc_pskrsasig[] = | |
175 | { { PROTO_ISAKMP, AD(oakley_trans_pskrsasig) } }; | |
176 | ||
177 | /* array of proposal conjuncts (can only be one) */ | |
178 | ||
179 | static struct db_prop_conj oakley_props_psk[] = { { AD(oakley_pc_psk) } }; | |
180 | ||
181 | static struct db_prop_conj oakley_props_rsasig[] = { { AD(oakley_pc_rsasig) } }; | |
182 | ||
183 | static struct db_prop_conj oakley_props_pskrsasig[] = { { AD(oakley_pc_pskrsasig) } }; | |
184 | ||
185 | /* the sadb entry, subscripted by POLICY_PSK and POLICY_RSASIG bits */ | |
186 | struct db_sa oakley_sadb[] = { | |
187 | { AD_NULL }, /* none */ | |
188 | { AD(oakley_props_psk) }, /* POLICY_PSK */ | |
189 | { AD(oakley_props_rsasig) }, /* POLICY_RSASIG */ | |
190 | { AD(oakley_props_pskrsasig) }, /* POLICY_PSK + POLICY_RSASIG */ | |
191 | }; | |
192 | ||
193 | /**************** IPsec (quick mode) SA database ****************/ | |
194 | ||
195 | /* arrays of attributes for transforms */ | |
196 | ||
197 | static struct db_attr espmd5_attr[] = { | |
198 | { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_MD5 }, | |
199 | }; | |
200 | ||
201 | static struct db_attr espsha1_attr[] = { | |
202 | { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, | |
203 | }; | |
204 | ||
205 | static struct db_attr ah_HMAC_MD5_attr[] = { | |
206 | { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_MD5 }, | |
207 | }; | |
208 | ||
209 | static struct db_attr ah_HMAC_SHA1_attr[] = { | |
210 | { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, | |
211 | }; | |
212 | ||
213 | /* arrays of transforms, each in in preference order */ | |
214 | ||
215 | static struct db_trans espa_trans[] = { | |
216 | { ESP_3DES, AD(espmd5_attr) }, | |
217 | { ESP_3DES, AD(espsha1_attr) }, | |
218 | }; | |
219 | ||
220 | static struct db_trans esp_trans[] = { | |
221 | { ESP_3DES, AD_NULL }, | |
222 | }; | |
223 | ||
224 | #ifdef SUPPORT_ESP_NULL | |
225 | static struct db_trans espnull_trans[] = { | |
226 | { ESP_NULL, AD(espmd5_attr) }, | |
227 | { ESP_NULL, AD(espsha1_attr) }, | |
228 | }; | |
229 | #endif /* SUPPORT_ESP_NULL */ | |
230 | ||
231 | static struct db_trans ah_trans[] = { | |
232 | { AH_MD5, AD(ah_HMAC_MD5_attr) }, | |
233 | { AH_SHA, AD(ah_HMAC_SHA1_attr) }, | |
234 | }; | |
235 | ||
236 | static struct db_trans ipcomp_trans[] = { | |
237 | { IPCOMP_DEFLATE, AD_NULL }, | |
238 | }; | |
239 | ||
240 | /* arrays of proposals to be conjoined */ | |
241 | ||
242 | static struct db_prop ah_pc[] = { | |
243 | { PROTO_IPSEC_AH, AD(ah_trans) }, | |
244 | }; | |
245 | ||
246 | #ifdef SUPPORT_ESP_NULL | |
247 | static struct db_prop espnull_pc[] = { | |
248 | { PROTO_IPSEC_ESP, AD(espnull_trans) }, | |
249 | }; | |
250 | #endif /* SUPPORT_ESP_NULL */ | |
251 | ||
252 | static struct db_prop esp_pc[] = { | |
253 | { PROTO_IPSEC_ESP, AD(espa_trans) }, | |
254 | }; | |
255 | ||
256 | static struct db_prop ah_esp_pc[] = { | |
257 | { PROTO_IPSEC_AH, AD(ah_trans) }, | |
258 | { PROTO_IPSEC_ESP, AD(esp_trans) }, | |
259 | }; | |
260 | ||
261 | static struct db_prop compress_pc[] = { | |
262 | { PROTO_IPCOMP, AD(ipcomp_trans) }, | |
263 | }; | |
264 | ||
265 | static struct db_prop ah_compress_pc[] = { | |
266 | { PROTO_IPSEC_AH, AD(ah_trans) }, | |
267 | { PROTO_IPCOMP, AD(ipcomp_trans) }, | |
268 | }; | |
269 | ||
270 | #ifdef SUPPORT_ESP_NULL | |
271 | static struct db_prop espnull_compress_pc[] = { | |
272 | { PROTO_IPSEC_ESP, AD(espnull_trans) }, | |
273 | { PROTO_IPCOMP, AD(ipcomp_trans) }, | |
274 | }; | |
275 | #endif /* SUPPORT_ESP_NULL */ | |
276 | ||
277 | static struct db_prop esp_compress_pc[] = { | |
278 | { PROTO_IPSEC_ESP, AD(espa_trans) }, | |
279 | { PROTO_IPCOMP, AD(ipcomp_trans) }, | |
280 | }; | |
281 | ||
282 | static struct db_prop ah_esp_compress_pc[] = { | |
283 | { PROTO_IPSEC_AH, AD(ah_trans) }, | |
284 | { PROTO_IPSEC_ESP, AD(esp_trans) }, | |
285 | { PROTO_IPCOMP, AD(ipcomp_trans) }, | |
286 | }; | |
287 | ||
288 | /* arrays of proposal alternatives (each element is a conjunction) */ | |
289 | ||
290 | static struct db_prop_conj ah_props[] = { | |
291 | { AD(ah_pc) }, | |
292 | #ifdef SUPPORT_ESP_NULL | |
293 | { AD(espnull_pc) } | |
294 | #endif | |
295 | }; | |
296 | ||
297 | static struct db_prop_conj esp_props[] = | |
298 | { { AD(esp_pc) } }; | |
299 | ||
300 | static struct db_prop_conj ah_esp_props[] = | |
301 | { { AD(ah_esp_pc) } }; | |
302 | ||
303 | static struct db_prop_conj compress_props[] = { | |
304 | { AD(compress_pc) }, | |
305 | }; | |
306 | ||
307 | static struct db_prop_conj ah_compress_props[] = { | |
308 | { AD(ah_compress_pc) }, | |
309 | #ifdef SUPPORT_ESP_NULL | |
310 | { AD(espnull_compress_pc) } | |
311 | #endif | |
312 | }; | |
313 | ||
314 | static struct db_prop_conj esp_compress_props[] = | |
315 | { { AD(esp_compress_pc) } }; | |
316 | ||
317 | static struct db_prop_conj ah_esp_compress_props[] = | |
318 | { { AD(ah_esp_compress_pc) } }; | |
319 | ||
320 | /* The IPsec sadb is subscripted by a bitset (subset of policy) | |
321 | * with members from { POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS } | |
322 | * shifted right by POLICY_IPSEC_SHIFT. | |
323 | */ | |
324 | struct db_sa ipsec_sadb[1 << 3] = { | |
325 | { AD_NULL }, /* none */ | |
326 | { AD(esp_props) }, /* POLICY_ENCRYPT */ | |
327 | { AD(ah_props) }, /* POLICY_AUTHENTICATE */ | |
328 | { AD(ah_esp_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE */ | |
329 | { AD(compress_props) }, /* POLICY_COMPRESS */ | |
330 | { AD(esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_COMPRESS */ | |
331 | { AD(ah_compress_props) }, /* POLICY_AUTHENTICATE+POLICY_COMPRESS */ | |
332 | { AD(ah_esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE+POLICY_COMPRESS */ | |
333 | }; | |
334 | ||
335 | #undef AD | |
336 | #undef AD_NULL | |
337 | ||
338 | /* output an attribute (within an SA) */ | |
339 | static bool | |
340 | out_attr(int type | |
341 | , unsigned long val | |
342 | , struct_desc *attr_desc | |
343 | , enum_names **attr_val_descs USED_BY_DEBUG | |
344 | , pb_stream *pbs) | |
345 | { | |
346 | struct isakmp_attribute attr; | |
347 | ||
348 | if (val >> 16 == 0) | |
349 | { | |
350 | /* short value: use TV form */ | |
351 | attr.isaat_af_type = type | ISAKMP_ATTR_AF_TV; | |
352 | attr.isaat_lv = val; | |
353 | if (!out_struct(&attr, attr_desc, pbs, NULL)) | |
354 | return FALSE; | |
355 | } | |
356 | else | |
357 | { | |
358 | /* This is a real fudge! Since we rarely use long attributes | |
359 | * and since this is the only place where we can cause an | |
360 | * ISAKMP message length to be other than a multiple of 4 octets, | |
361 | * we force the length of the value to be a multiple of 4 octets. | |
362 | * Furthermore, we only handle values up to 4 octets in length. | |
363 | * Voila: a fixed format! | |
364 | */ | |
365 | pb_stream val_pbs; | |
366 | u_int32_t nval = htonl(val); | |
367 | ||
368 | attr.isaat_af_type = type | ISAKMP_ATTR_AF_TLV; | |
369 | if (!out_struct(&attr, attr_desc, pbs, &val_pbs) | |
370 | || !out_raw(&nval, sizeof(nval), &val_pbs, "long attribute value")) | |
371 | return FALSE; | |
372 | close_output_pbs(&val_pbs); | |
373 | } | |
374 | DBG(DBG_EMITTING, | |
375 | enum_names *d = attr_val_descs[type]; | |
376 | ||
377 | if (d != NULL) | |
378 | DBG_log(" [%lu is %s]" | |
379 | , val, enum_show(d, val))); | |
380 | return TRUE; | |
381 | } | |
382 | #define return_on(var, val) do { var=val;goto return_out; } while(0); | |
383 | /* Output an SA, as described by a db_sa. | |
384 | * This has the side-effect of allocating SPIs for us. | |
385 | */ | |
386 | bool | |
387 | out_sa(pb_stream *outs | |
388 | , struct db_sa *sadb | |
389 | , struct state *st | |
390 | , bool oakley_mode | |
391 | , u_int8_t np) | |
392 | { | |
393 | pb_stream sa_pbs; | |
394 | int pcn; | |
395 | bool ret = FALSE; | |
396 | bool ah_spi_generated = FALSE | |
397 | , esp_spi_generated = FALSE | |
398 | , ipcomp_cpi_generated = FALSE; | |
399 | #if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG | |
400 | struct db_context *db_ctx = NULL; | |
401 | #endif | |
402 | ||
403 | /* SA header out */ | |
404 | { | |
405 | struct isakmp_sa sa; | |
406 | ||
407 | sa.isasa_np = np; | |
408 | st->st_doi = sa.isasa_doi = ISAKMP_DOI_IPSEC; /* all we know */ | |
409 | if (!out_struct(&sa, &isakmp_sa_desc, outs, &sa_pbs)) | |
410 | return_on(ret, FALSE); | |
411 | } | |
412 | ||
413 | /* within SA: situation out */ | |
414 | st->st_situation = SIT_IDENTITY_ONLY; | |
415 | if (!out_struct(&st->st_situation, &ipsec_sit_desc, &sa_pbs, NULL)) | |
416 | return_on(ret, FALSE); | |
417 | ||
418 | /* within SA: Proposal Payloads | |
419 | * | |
420 | * Multiple Proposals with the same number are simultaneous | |
421 | * (conjuncts) and must deal with different protocols (AH or ESP). | |
422 | * Proposals with different numbers are alternatives (disjuncts), | |
423 | * in preference order. | |
424 | * Proposal numbers must be monotonic. | |
425 | * See RFC 2408 "ISAKMP" 4.2 | |
426 | */ | |
427 | ||
428 | for (pcn = 0; pcn != sadb->prop_conj_cnt; pcn++) | |
429 | { | |
430 | struct db_prop_conj *pc = &sadb->prop_conjs[pcn]; | |
431 | int pn; | |
432 | ||
433 | for (pn = 0; pn != pc->prop_cnt; pn++) | |
434 | { | |
435 | struct db_prop *p = &pc->props[pn]; | |
436 | pb_stream proposal_pbs; | |
437 | struct isakmp_proposal proposal; | |
438 | struct_desc *trans_desc; | |
439 | struct_desc *attr_desc; | |
440 | enum_names **attr_val_descs; | |
441 | int tn; | |
442 | bool tunnel_mode; | |
443 | ||
444 | tunnel_mode = (pn == pc->prop_cnt-1) | |
445 | && (st->st_policy & POLICY_TUNNEL); | |
446 | ||
447 | /* Proposal header */ | |
448 | proposal.isap_np = pcn == sadb->prop_conj_cnt-1 && pn == pc->prop_cnt-1 | |
449 | ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_P; | |
450 | proposal.isap_proposal = pcn; | |
451 | proposal.isap_protoid = p->protoid; | |
452 | proposal.isap_spisize = oakley_mode ? 0 | |
453 | : p->protoid == PROTO_IPCOMP ? IPCOMP_CPI_SIZE | |
454 | : IPSEC_DOI_SPI_SIZE; | |
455 | ||
456 | /* In quick mode ONLY, create proposal for runtime kernel algos. | |
457 | * Replace ESP proposals with runtime created one | |
458 | */ | |
459 | if (!oakley_mode && p->protoid == PROTO_IPSEC_ESP) | |
460 | { | |
461 | DBG(DBG_CONTROL | DBG_CRYPT, | |
462 | if (st->st_connection->alg_info_esp) | |
463 | { | |
464 | static char buf[256]=""; | |
465 | ||
466 | alg_info_snprint(buf, sizeof (buf), | |
467 | (struct alg_info *)st->st_connection->alg_info_esp); | |
468 | DBG_log(buf); | |
469 | } | |
470 | ) | |
471 | db_ctx = kernel_alg_db_new(st->st_connection->alg_info_esp, st->st_policy); | |
472 | p = db_prop_get(db_ctx); | |
473 | ||
474 | if (!p || p->trans_cnt == 0) | |
475 | { | |
476 | loglog(RC_LOG_SERIOUS, | |
477 | "empty IPSEC SA proposal to send " | |
478 | "(no kernel algorithms for esp selection)"); | |
479 | return_on(ret, FALSE); | |
480 | } | |
481 | } | |
482 | ||
483 | if (oakley_mode && p->protoid == PROTO_ISAKMP) | |
484 | { | |
485 | DBG(DBG_CONTROL | DBG_CRYPT, | |
486 | if (st->st_connection->alg_info_ike) | |
487 | { | |
488 | static char buf[256]=""; | |
489 | ||
490 | alg_info_snprint(buf, sizeof (buf), | |
491 | (struct alg_info *)st->st_connection->alg_info_ike); | |
492 | DBG_log(buf); | |
493 | } | |
494 | ) | |
495 | db_ctx = ike_alg_db_new(st->st_connection->alg_info_ike, st->st_policy); | |
496 | p = db_prop_get(db_ctx); | |
497 | ||
498 | if (!p || p->trans_cnt == 0) | |
499 | { | |
500 | loglog(RC_LOG_SERIOUS, | |
501 | "empty ISAKMP SA proposal to send " | |
502 | "(no algorithms for ike selection?)"); | |
503 | return_on(ret, FALSE); | |
504 | } | |
505 | } | |
506 | ||
507 | proposal.isap_notrans = p->trans_cnt; | |
508 | if (!out_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, &proposal_pbs)) | |
509 | return_on(ret, FALSE); | |
510 | ||
511 | /* Per-protocols stuff: | |
512 | * Set trans_desc. | |
513 | * Set attr_desc. | |
514 | * Set attr_val_descs. | |
515 | * If not oakley_mode, emit SPI. | |
516 | * We allocate SPIs on demand. | |
517 | * All ESPs in an SA will share a single SPI. | |
518 | * All AHs in an SAwill share a single SPI. | |
519 | * AHs' SPI will be distinct from ESPs'. | |
520 | * This latter is needed because KLIPS doesn't | |
521 | * use the protocol when looking up a (dest, protocol, spi). | |
522 | * ??? If multiple ESPs are composed, how should their SPIs | |
523 | * be allocated? | |
524 | */ | |
525 | { | |
526 | ipsec_spi_t *spi_ptr = NULL; | |
527 | int proto = 0; | |
528 | bool *spi_generated = NULL; | |
529 | ||
530 | switch (p->protoid) | |
531 | { | |
532 | case PROTO_ISAKMP: | |
533 | passert(oakley_mode); | |
534 | trans_desc = &isakmp_isakmp_transform_desc; | |
535 | attr_desc = &isakmp_oakley_attribute_desc; | |
536 | attr_val_descs = oakley_attr_val_descs; | |
537 | /* no SPI needed */ | |
538 | break; | |
539 | case PROTO_IPSEC_AH: | |
540 | passert(!oakley_mode); | |
541 | trans_desc = &isakmp_ah_transform_desc; | |
542 | attr_desc = &isakmp_ipsec_attribute_desc; | |
543 | attr_val_descs = ipsec_attr_val_descs; | |
544 | spi_ptr = &st->st_ah.our_spi; | |
545 | spi_generated = &ah_spi_generated; | |
546 | proto = IPPROTO_AH; | |
547 | break; | |
548 | case PROTO_IPSEC_ESP: | |
549 | passert(!oakley_mode); | |
550 | trans_desc = &isakmp_esp_transform_desc; | |
551 | attr_desc = &isakmp_ipsec_attribute_desc; | |
552 | attr_val_descs = ipsec_attr_val_descs; | |
553 | spi_ptr = &st->st_esp.our_spi; | |
554 | spi_generated = &esp_spi_generated; | |
555 | proto = IPPROTO_ESP; | |
556 | break; | |
557 | case PROTO_IPCOMP: | |
558 | passert(!oakley_mode); | |
559 | trans_desc = &isakmp_ipcomp_transform_desc; | |
560 | attr_desc = &isakmp_ipsec_attribute_desc; | |
561 | attr_val_descs = ipsec_attr_val_descs; | |
562 | ||
563 | /* a CPI isn't quite the same as an SPI | |
564 | * so we use specialized code to emit it. | |
565 | */ | |
566 | if (!ipcomp_cpi_generated) | |
567 | { | |
568 | st->st_ipcomp.our_spi = get_my_cpi( | |
569 | &st->st_connection->spd, tunnel_mode); | |
570 | if (st->st_ipcomp.our_spi == 0) | |
571 | return_on(ret, FALSE); /* problem generating CPI */ | |
572 | ||
573 | ipcomp_cpi_generated = TRUE; | |
574 | } | |
575 | /* CPI is stored in network low order end of an | |
576 | * ipsec_spi_t. So we start a couple of bytes in. | |
577 | */ | |
578 | if (!out_raw((u_char *)&st->st_ipcomp.our_spi | |
579 | + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE | |
580 | , IPCOMP_CPI_SIZE | |
581 | , &proposal_pbs, "CPI")) | |
582 | return_on(ret, FALSE); | |
583 | break; | |
584 | default: | |
585 | bad_case(p->protoid); | |
586 | } | |
587 | if (spi_ptr != NULL) | |
588 | { | |
589 | if (!*spi_generated) | |
590 | { | |
591 | *spi_ptr = get_ipsec_spi(0 | |
592 | , proto | |
593 | , &st->st_connection->spd | |
594 | , tunnel_mode); | |
595 | if (*spi_ptr == 0) | |
596 | return FALSE; | |
597 | *spi_generated = TRUE; | |
598 | } | |
599 | if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE | |
600 | , &proposal_pbs, "SPI")) | |
601 | return_on(ret, FALSE); | |
602 | } | |
603 | } | |
604 | ||
605 | /* within proposal: Transform Payloads */ | |
606 | for (tn = 0; tn != p->trans_cnt; tn++) | |
607 | { | |
608 | struct db_trans *t = &p->trans[tn]; | |
609 | pb_stream trans_pbs; | |
610 | struct isakmp_transform trans; | |
611 | int an; | |
612 | ||
613 | trans.isat_np = (tn == p->trans_cnt - 1) | |
614 | ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_T; | |
615 | trans.isat_transnum = tn; | |
616 | trans.isat_transid = t->transid; | |
617 | if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs)) | |
618 | return_on(ret, FALSE); | |
619 | ||
620 | /* Within tranform: Attributes. */ | |
621 | ||
622 | /* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is | |
623 | * automatically generated because it must be the same | |
624 | * in every transform. Except IPCOMP. | |
625 | */ | |
626 | if (p->protoid != PROTO_IPCOMP | |
627 | && st->st_pfs_group != NULL) | |
628 | { | |
629 | passert(!oakley_mode); | |
630 | passert(st->st_pfs_group != &unset_group); | |
631 | out_attr(GROUP_DESCRIPTION, st->st_pfs_group->group | |
632 | , attr_desc, attr_val_descs | |
633 | , &trans_pbs); | |
634 | } | |
635 | ||
636 | /* automatically generate duration | |
637 | * and, for Phase 2 / Quick Mode, encapsulation. | |
638 | */ | |
639 | if (oakley_mode) | |
640 | { | |
641 | out_attr(OAKLEY_LIFE_TYPE, OAKLEY_LIFE_SECONDS | |
642 | , attr_desc, attr_val_descs | |
643 | , &trans_pbs); | |
644 | out_attr(OAKLEY_LIFE_DURATION | |
645 | , st->st_connection->sa_ike_life_seconds | |
646 | , attr_desc, attr_val_descs | |
647 | , &trans_pbs); | |
648 | } | |
649 | else | |
650 | { | |
651 | /* RFC 2407 (IPSEC DOI) 4.5 specifies that | |
652 | * the default is "unspecified (host-dependent)". | |
653 | * This makes little sense, so we always specify it. | |
654 | * | |
655 | * Unlike other IPSEC transforms, IPCOMP defaults | |
656 | * to Transport Mode, so we can exploit the default | |
657 | * (draft-shacham-ippcp-rfc2393bis-05.txt 4.1). | |
658 | */ | |
659 | if (p->protoid != PROTO_IPCOMP | |
660 | || st->st_policy & POLICY_TUNNEL) | |
661 | { | |
662 | #ifdef NAT_TRAVERSAL | |
663 | #ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT | |
664 | if ((st->nat_traversal & NAT_T_DETECTED) | |
665 | && !(st->st_policy & POLICY_TUNNEL)) | |
666 | { | |
667 | /* Inform user that we will not respect policy and only | |
668 | * propose Tunnel Mode | |
669 | */ | |
670 | loglog(RC_LOG_SERIOUS, "NAT-Traversal: " | |
671 | "Transport Mode not allowed due to security concerns -- " | |
672 | "using Tunnel mode"); | |
673 | } | |
674 | #endif | |
675 | #endif | |
676 | out_attr(ENCAPSULATION_MODE | |
677 | #ifdef NAT_TRAVERSAL | |
678 | #ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT | |
679 | , NAT_T_ENCAPSULATION_MODE(st,st->st_policy) | |
680 | #else | |
681 | /* If NAT-T is detected, use UDP_TUNNEL as long as Transport | |
682 | * Mode has security concerns. | |
683 | * | |
684 | * User has been informed of that | |
685 | */ | |
686 | , NAT_T_ENCAPSULATION_MODE(st,POLICY_TUNNEL) | |
687 | #endif | |
688 | #else /* ! NAT_TRAVERSAL */ | |
689 | , st->st_policy & POLICY_TUNNEL | |
690 | ? ENCAPSULATION_MODE_TUNNEL : ENCAPSULATION_MODE_TRANSPORT | |
691 | #endif | |
692 | , attr_desc, attr_val_descs | |
693 | , &trans_pbs); | |
694 | } | |
695 | out_attr(SA_LIFE_TYPE, SA_LIFE_TYPE_SECONDS | |
696 | , attr_desc, attr_val_descs | |
697 | , &trans_pbs); | |
698 | out_attr(SA_LIFE_DURATION | |
699 | , st->st_connection->sa_ipsec_life_seconds | |
700 | , attr_desc, attr_val_descs | |
701 | , &trans_pbs); | |
702 | } | |
703 | ||
704 | /* spit out attributes from table */ | |
705 | for (an = 0; an != t->attr_cnt; an++) | |
706 | { | |
707 | struct db_attr *a = &t->attrs[an]; | |
708 | ||
709 | out_attr(a->type, a->val | |
710 | , attr_desc, attr_val_descs | |
711 | , &trans_pbs); | |
712 | } | |
713 | ||
714 | close_output_pbs(&trans_pbs); | |
715 | } | |
716 | close_output_pbs(&proposal_pbs); | |
717 | } | |
718 | /* end of a conjunction of proposals */ | |
719 | } | |
720 | close_output_pbs(&sa_pbs); | |
721 | ret = TRUE; | |
722 | ||
723 | return_out: | |
724 | ||
725 | #if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG | |
726 | if (db_ctx) | |
727 | db_destroy(db_ctx); | |
728 | #endif | |
729 | return ret; | |
730 | } | |
731 | ||
732 | /* Handle long form of duration attribute. | |
733 | * The code is can only handle values that can fit in unsigned long. | |
734 | * "Clamping" is probably an acceptable way to impose this limitation. | |
735 | */ | |
736 | static u_int32_t | |
737 | decode_long_duration(pb_stream *pbs) | |
738 | { | |
739 | u_int32_t val = 0; | |
740 | ||
741 | /* ignore leading zeros */ | |
742 | while (pbs_left(pbs) != 0 && *pbs->cur == '\0') | |
743 | pbs->cur++; | |
744 | ||
745 | if (pbs_left(pbs) > sizeof(val)) | |
746 | { | |
747 | /* "clamp" too large value to max representable value */ | |
748 | val -= 1; /* portable way to get to maximum value */ | |
749 | DBG(DBG_PARSING, DBG_log(" too large duration clamped to: %lu" | |
750 | , (unsigned long)val)); | |
751 | } | |
752 | else | |
753 | { | |
754 | /* decode number */ | |
755 | while (pbs_left(pbs) != 0) | |
756 | val = (val << BITS_PER_BYTE) | *pbs->cur++; | |
757 | DBG(DBG_PARSING, DBG_log(" long duration: %lu", (unsigned long)val)); | |
758 | } | |
759 | return val; | |
760 | } | |
761 | ||
762 | /* Preparse the body of an ISAKMP SA Payload and | |
763 | * return body of ISAKMP Proposal Payload | |
764 | * | |
765 | * Only IPsec DOI is accepted (what is the ISAKMP DOI?). | |
766 | * Error response is rudimentary. | |
767 | */ | |
768 | notification_t | |
769 | preparse_isakmp_sa_body(const struct isakmp_sa *sa | |
770 | , pb_stream *sa_pbs | |
771 | , u_int32_t *ipsecdoisit | |
772 | , pb_stream *proposal_pbs | |
773 | , struct isakmp_proposal *proposal) | |
774 | { | |
775 | /* DOI */ | |
776 | if (sa->isasa_doi != ISAKMP_DOI_IPSEC) | |
777 | { | |
778 | loglog(RC_LOG_SERIOUS, "Unknown/unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); | |
779 | /* XXX Could send notification back */ | |
780 | return DOI_NOT_SUPPORTED; | |
781 | } | |
782 | ||
783 | /* Situation */ | |
784 | if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) | |
785 | return SITUATION_NOT_SUPPORTED; | |
786 | ||
787 | if (*ipsecdoisit != SIT_IDENTITY_ONLY) | |
788 | { | |
789 | loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" | |
790 | , bitnamesof(sit_bit_names, *ipsecdoisit)); | |
791 | /* XXX Could send notification back */ | |
792 | return SITUATION_NOT_SUPPORTED; | |
793 | } | |
794 | ||
795 | /* The rules for ISAKMP SAs are scattered. | |
796 | * RFC 2409 "IKE" section 5 says that there | |
797 | * can only be one SA, and it can have only one proposal in it. | |
798 | * There may well be multiple transforms. | |
799 | */ | |
800 | if (!in_struct(proposal, &isakmp_proposal_desc, sa_pbs, proposal_pbs)) | |
801 | return PAYLOAD_MALFORMED; | |
802 | ||
803 | if (proposal->isap_np != ISAKMP_NEXT_NONE) | |
804 | { | |
805 | loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal" | |
806 | , enum_show(&payload_names, proposal->isap_np)); | |
807 | return PAYLOAD_MALFORMED; | |
808 | } | |
809 | ||
810 | if (proposal->isap_protoid != PROTO_ISAKMP) | |
811 | { | |
812 | loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) found in Oakley Proposal" | |
813 | , enum_show(&protocol_names, proposal->isap_protoid)); | |
814 | return INVALID_PROTOCOL_ID; | |
815 | } | |
816 | ||
817 | /* Just what should we accept for the SPI field? | |
818 | * The RFC is sort of contradictory. We will ignore the SPI | |
819 | * as long as it is of the proper size. | |
820 | * | |
821 | * From RFC2408 2.4 Identifying Security Associations: | |
822 | * During phase 1 negotiations, the initiator and responder cookies | |
823 | * determine the ISAKMP SA. Therefore, the SPI field in the Proposal | |
824 | * payload is redundant and MAY be set to 0 or it MAY contain the | |
825 | * transmitting entity's cookie. | |
826 | * | |
827 | * From RFC2408 3.5 Proposal Payload: | |
828 | * o SPI Size (1 octet) - Length in octets of the SPI as defined by | |
829 | * the Protocol-Id. In the case of ISAKMP, the Initiator and | |
830 | * Responder cookie pair from the ISAKMP Header is the ISAKMP SPI, | |
831 | * therefore, the SPI Size is irrelevant and MAY be from zero (0) to | |
832 | * sixteen (16). If the SPI Size is non-zero, the content of the | |
833 | * SPI field MUST be ignored. If the SPI Size is not a multiple of | |
834 | * 4 octets it will have some impact on the SPI field and the | |
835 | * alignment of all payloads in the message. The Domain of | |
836 | * Interpretation (DOI) will dictate the SPI Size for other | |
837 | * protocols. | |
838 | */ | |
839 | if (proposal->isap_spisize == 0) | |
840 | { | |
841 | /* empty (0) SPI -- fine */ | |
842 | } | |
843 | else if (proposal->isap_spisize <= MAX_ISAKMP_SPI_SIZE) | |
844 | { | |
845 | u_char junk_spi[MAX_ISAKMP_SPI_SIZE]; | |
846 | ||
847 | if (!in_raw(junk_spi, proposal->isap_spisize, proposal_pbs, "Oakley SPI")) | |
848 | return PAYLOAD_MALFORMED; | |
849 | } | |
850 | else | |
851 | { | |
852 | loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal" | |
853 | , (unsigned)proposal->isap_spisize); | |
854 | return INVALID_SPI; | |
855 | } | |
856 | return NOTHING_WRONG; | |
857 | } | |
858 | ||
859 | static struct { | |
860 | u_int8_t *start; | |
861 | u_int8_t *cur; | |
862 | u_int8_t *roof; | |
863 | } backup; | |
864 | ||
865 | /* | |
866 | * backup the pointer into a pb_stream | |
867 | */ | |
868 | void | |
869 | backup_pbs(pb_stream *pbs) | |
870 | { | |
871 | backup.start = pbs->start; | |
872 | backup.cur = pbs->cur; | |
873 | backup.roof = pbs->roof; | |
874 | } | |
875 | ||
876 | /* | |
877 | * restore the pointer into a pb_stream | |
878 | */ | |
879 | void | |
880 | restore_pbs(pb_stream *pbs) | |
881 | { | |
882 | pbs->start = backup.start; | |
883 | pbs->cur = backup.cur; | |
884 | pbs->roof = backup.roof; | |
885 | } | |
886 | ||
887 | /* | |
888 | * Parse an ISAKMP Proposal Payload for RSA and PSK authentication policies | |
889 | */ | |
890 | notification_t | |
891 | parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, lset_t *policy) | |
892 | { | |
893 | int last_transnum = -1; | |
894 | ||
895 | *policy = LEMPTY; | |
896 | ||
897 | while (notrans--) | |
898 | { | |
899 | pb_stream trans_pbs; | |
900 | u_char *attr_start; | |
901 | size_t attr_len; | |
902 | struct isakmp_transform trans; | |
903 | ||
904 | if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs)) | |
905 | return BAD_PROPOSAL_SYNTAX; | |
906 | ||
907 | if (trans.isat_transnum <= last_transnum) | |
908 | { | |
909 | /* picky, picky, picky */ | |
910 | loglog(RC_LOG_SERIOUS, "Transform Numbers are not monotonically increasing" | |
911 | " in Oakley Proposal"); | |
912 | return BAD_PROPOSAL_SYNTAX; | |
913 | } | |
914 | last_transnum = trans.isat_transnum; | |
915 | ||
916 | if (trans.isat_transid != KEY_IKE) | |
917 | { | |
918 | loglog(RC_LOG_SERIOUS, "expected KEY_IKE but found %s in Oakley Transform" | |
919 | , enum_show(&isakmp_transformid_names, trans.isat_transid)); | |
920 | return INVALID_TRANSFORM_ID; | |
921 | } | |
922 | ||
923 | attr_start = trans_pbs.cur; | |
924 | attr_len = pbs_left(&trans_pbs); | |
925 | ||
926 | /* preprocess authentication attributes only */ | |
927 | while (pbs_left(&trans_pbs) != 0) | |
928 | { | |
929 | struct isakmp_attribute a; | |
930 | pb_stream attr_pbs; | |
931 | ||
932 | if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) | |
933 | return BAD_PROPOSAL_SYNTAX; | |
934 | ||
935 | passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); | |
936 | ||
937 | switch (a.isaat_af_type) | |
938 | { | |
939 | case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV: | |
940 | switch (a.isaat_lv) | |
941 | { | |
942 | case OAKLEY_PRESHARED_KEY: | |
943 | *policy |= POLICY_PSK; | |
944 | break; | |
945 | case OAKLEY_RSA_SIG: | |
946 | *policy |= POLICY_RSASIG; | |
947 | break; | |
948 | default: | |
949 | break; | |
950 | } | |
951 | break; | |
952 | default: | |
953 | break; | |
954 | } | |
955 | } | |
956 | } | |
957 | ||
958 | if ((*policy & POLICY_PSK) && (*policy & POLICY_RSASIG)) | |
959 | { | |
960 | DBG(DBG_CONTROL|DBG_PARSING, | |
961 | DBG_log("preparse_isakmp_policy: " | |
962 | "peer supports both PSK and RSASIG authentication") | |
963 | ) | |
964 | *policy = LEMPTY; | |
965 | } | |
966 | else | |
967 | { | |
968 | DBG(DBG_CONTROL|DBG_PARSING, | |
969 | DBG_log("preparse_isakmp_policy: peer requests %s authentication" | |
970 | , (*policy & POLICY_PSK) ? "PSK":"RSASIG") | |
971 | ) | |
972 | } | |
973 | return NOTHING_WRONG; | |
974 | } | |
975 | ||
976 | /* Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode). | |
977 | * Various shortcuts are taken. In particular, the policy, such as | |
978 | * it is, is hardwired. | |
979 | * | |
980 | * If r_sa is non-NULL, the body of an SA representing the selected | |
981 | * proposal is emitted. | |
982 | * | |
983 | * This routine is used by main_inI1_outR1() and main_inR1_outI2(). | |
984 | */ | |
985 | notification_t | |
986 | parse_isakmp_sa_body(u_int32_t ipsecdoisit | |
987 | , pb_stream *proposal_pbs | |
988 | , struct isakmp_proposal *proposal | |
989 | , pb_stream *r_sa_pbs | |
990 | , struct state *st) | |
991 | { | |
992 | struct connection *c = st->st_connection; | |
993 | unsigned no_trans_left; | |
994 | ||
995 | /* for each transform payload... */ | |
996 | no_trans_left = proposal->isap_notrans; | |
997 | ||
998 | for (;;) | |
999 | { | |
1000 | pb_stream trans_pbs; | |
1001 | u_char *attr_start; | |
1002 | size_t attr_len; | |
1003 | struct isakmp_transform trans; | |
1004 | lset_t seen_attrs = 0; | |
1005 | lset_t seen_durations = 0; | |
1006 | u_int16_t life_type = 0; | |
1007 | struct oakley_trans_attrs ta; | |
1008 | err_t ugh = NULL; /* set to diagnostic when problem detected */ | |
1009 | ||
1010 | /* initialize only optional field in ta */ | |
1011 | ta.life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; /* When this SA expires (seconds) */ | |
1012 | ||
1013 | if (no_trans_left == 0) | |
1014 | { | |
1015 | loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); | |
1016 | return BAD_PROPOSAL_SYNTAX; | |
1017 | } | |
1018 | ||
1019 | in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs); | |
1020 | attr_start = trans_pbs.cur; | |
1021 | attr_len = pbs_left(&trans_pbs); | |
1022 | ||
1023 | /* process all the attributes that make up the transform */ | |
1024 | ||
1025 | while (pbs_left(&trans_pbs) != 0) | |
1026 | { | |
1027 | struct isakmp_attribute a; | |
1028 | pb_stream attr_pbs; | |
1029 | u_int32_t val; /* room for larger values */ | |
1030 | ||
1031 | if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) | |
1032 | return BAD_PROPOSAL_SYNTAX; | |
1033 | ||
1034 | passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); | |
1035 | ||
1036 | if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK)) | |
1037 | { | |
1038 | loglog(RC_LOG_SERIOUS, "repeated %s attribute in Oakley Transform %u" | |
1039 | , enum_show(&oakley_attr_names, a.isaat_af_type) | |
1040 | , trans.isat_transnum); | |
1041 | return BAD_PROPOSAL_SYNTAX; | |
1042 | } | |
1043 | ||
1044 | seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); | |
1045 | ||
1046 | val = a.isaat_lv; | |
1047 | ||
1048 | DBG(DBG_PARSING, | |
1049 | { | |
1050 | enum_names *vdesc = oakley_attr_val_descs | |
1051 | [a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; | |
1052 | ||
1053 | if (vdesc != NULL) | |
1054 | { | |
1055 | const char *nm = enum_name(vdesc, val); | |
1056 | ||
1057 | if (nm != NULL) | |
1058 | DBG_log(" [%u is %s]", (unsigned)val, nm); | |
1059 | } | |
1060 | }); | |
1061 | ||
1062 | switch (a.isaat_af_type) | |
1063 | { | |
1064 | case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV: | |
1065 | if (ike_alg_enc_present(val)) | |
1066 | { | |
1067 | ta.encrypt = val; | |
1068 | ta.encrypter = ike_alg_get_encrypter(val); | |
1069 | ta.enckeylen = ta.encrypter->keydeflen; | |
1070 | } | |
1071 | else | |
1072 | { | |
1073 | ugh = builddiag("%s is not supported" | |
1074 | , enum_show(&oakley_enc_names, val)); | |
1075 | } | |
1076 | break; | |
1077 | ||
1078 | case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV: | |
1079 | if (ike_alg_hash_present(val)) | |
1080 | { | |
1081 | ta.hash = val; | |
1082 | ta.hasher = ike_alg_get_hasher(val); | |
1083 | } | |
1084 | else | |
1085 | { | |
1086 | ugh = builddiag("%s is not supported" | |
1087 | , enum_show(&oakley_hash_names, val)); | |
1088 | } | |
1089 | break; | |
1090 | ||
1091 | case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV: | |
1092 | { | |
1093 | /* check that authentication method is acceptable */ | |
1094 | lset_t iap = st->st_policy & POLICY_ID_AUTH_MASK; | |
1095 | ||
1096 | switch (val) | |
1097 | { | |
1098 | case OAKLEY_PRESHARED_KEY: | |
1099 | if ((iap & POLICY_PSK) == LEMPTY) | |
1100 | { | |
1101 | ugh = "policy does not allow OAKLEY_PRESHARED_KEY authentication"; | |
1102 | } | |
1103 | else | |
1104 | { | |
1105 | /* check that we can find a preshared secret */ | |
1106 | struct connection *c = st->st_connection; | |
1107 | ||
1108 | if (get_preshared_secret(c) == NULL) | |
1109 | { | |
1110 | char mid[BUF_LEN] | |
1111 | , hid[BUF_LEN]; | |
1112 | ||
1113 | idtoa(&c->spd.this.id, mid, sizeof(mid)); | |
1114 | if (his_id_was_instantiated(c)) | |
1115 | strcpy(hid, "%any"); | |
1116 | else | |
1117 | idtoa(&c->spd.that.id, hid, sizeof(hid)); | |
1118 | ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" | |
1119 | , mid, hid); | |
1120 | } | |
1121 | ta.auth = val; | |
1122 | } | |
1123 | break; | |
1124 | case OAKLEY_RSA_SIG: | |
1125 | /* Accept if policy specifies RSASIG or is default */ | |
1126 | if ((iap & POLICY_RSASIG) == LEMPTY) | |
1127 | { | |
1128 | ugh = "policy does not allow OAKLEY_RSA_SIG authentication"; | |
1129 | } | |
1130 | else | |
1131 | { | |
1132 | /* We'd like to check that we can find a public | |
1133 | * key for him and a private key for us that is | |
1134 | * suitable, but we don't yet have his | |
1135 | * Id Payload, so it seems futile to try. | |
1136 | * We can assume that if he proposes it, he | |
1137 | * thinks we've got it. If we proposed it, | |
1138 | * perhaps we know what we're doing. | |
1139 | */ | |
1140 | ta.auth = val; | |
1141 | } | |
1142 | break; | |
1143 | ||
1144 | default: | |
1145 | ugh = builddiag("Pluto does not support %s authentication" | |
1146 | , enum_show(&oakley_auth_names, val)); | |
1147 | break; | |
1148 | } | |
1149 | } | |
1150 | break; | |
1151 | ||
1152 | case OAKLEY_GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV: | |
1153 | ta.group = lookup_group(val); | |
1154 | if (ta.group == NULL) | |
1155 | { | |
1156 | ugh = "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported"; | |
1157 | } | |
1158 | break; | |
1159 | ||
1160 | case OAKLEY_LIFE_TYPE | ISAKMP_ATTR_AF_TV: | |
1161 | switch (val) | |
1162 | { | |
1163 | case OAKLEY_LIFE_SECONDS: | |
1164 | case OAKLEY_LIFE_KILOBYTES: | |
1165 | if (LHAS(seen_durations, val)) | |
1166 | { | |
1167 | loglog(RC_LOG_SERIOUS | |
1168 | , "attribute OAKLEY_LIFE_TYPE value %s repeated" | |
1169 | , enum_show(&oakley_lifetime_names, val)); | |
1170 | return BAD_PROPOSAL_SYNTAX; | |
1171 | } | |
1172 | seen_durations |= LELEM(val); | |
1173 | life_type = val; | |
1174 | break; | |
1175 | default: | |
1176 | ugh = builddiag("unknown value %s" | |
1177 | , enum_show(&oakley_lifetime_names, val)); | |
1178 | break; | |
1179 | } | |
1180 | break; | |
1181 | ||
1182 | case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: | |
1183 | val = decode_long_duration(&attr_pbs); | |
1184 | /* fall through */ | |
1185 | case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TV: | |
1186 | if (!LHAS(seen_attrs, OAKLEY_LIFE_TYPE)) | |
1187 | { | |
1188 | ugh = "OAKLEY_LIFE_DURATION attribute not preceded by OAKLEY_LIFE_TYPE attribute"; | |
1189 | break; | |
1190 | } | |
1191 | seen_attrs &= ~(LELEM(OAKLEY_LIFE_DURATION) | LELEM(OAKLEY_LIFE_TYPE)); | |
1192 | ||
1193 | switch (life_type) | |
1194 | { | |
1195 | case OAKLEY_LIFE_SECONDS: | |
1196 | if (val > OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM) | |
1197 | ugh = builddiag("peer requested %lu seconds" | |
1198 | " which exceeds our limit %d seconds" | |
1199 | , (long) val | |
1200 | , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); | |
1201 | ta.life_seconds = val; | |
1202 | break; | |
1203 | case OAKLEY_LIFE_KILOBYTES: | |
1204 | ta.life_kilobytes = val; | |
1205 | break; | |
1206 | default: | |
1207 | bad_case(life_type); | |
1208 | } | |
1209 | break; | |
1210 | ||
1211 | case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV: | |
1212 | if ((seen_attrs & LELEM(OAKLEY_ENCRYPTION_ALGORITHM)) == 0) | |
1213 | { | |
1214 | ugh = "OAKLEY_KEY_LENGTH attribute not preceded by " | |
1215 | "OAKLEY_ENCRYPTION_ALGORITHM attribute"; | |
1216 | break; | |
1217 | } | |
1218 | if (ta.encrypter == NULL) | |
1219 | { | |
1220 | ugh = "NULL encrypter with seen OAKLEY_ENCRYPTION_ALGORITHM"; | |
1221 | break; | |
1222 | } | |
1223 | /* | |
1224 | * check if this keylen is compatible with specified algorithm | |
1225 | */ | |
1226 | if (val | |
1227 | && (val < ta.encrypter->keyminlen || val > ta.encrypter->keymaxlen)) | |
1228 | { | |
1229 | ugh = "peer proposed key length not valid for " | |
1230 | "encryption algorithm specified"; | |
1231 | } | |
1232 | ta.enckeylen = val; | |
1233 | break; | |
1234 | #if 0 /* not yet supported */ | |
1235 | case OAKLEY_GROUP_TYPE | ISAKMP_ATTR_AF_TV: | |
1236 | case OAKLEY_PRF | ISAKMP_ATTR_AF_TV: | |
1237 | case OAKLEY_FIELD_SIZE | ISAKMP_ATTR_AF_TV: | |
1238 | ||
1239 | case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TV: | |
1240 | case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TLV: | |
1241 | case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TV: | |
1242 | case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TLV: | |
1243 | case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TV: | |
1244 | case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TLV: | |
1245 | case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TV: | |
1246 | case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TLV: | |
1247 | case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TV: | |
1248 | case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TLV: | |
1249 | case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TV: | |
1250 | case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TLV: | |
1251 | #endif | |
1252 | default: | |
1253 | ugh = "unsupported OAKLEY attribute"; | |
1254 | break; | |
1255 | } | |
1256 | ||
1257 | if (ugh != NULL) | |
1258 | { | |
1259 | loglog(RC_LOG_SERIOUS, "%s. Attribute %s" | |
1260 | , ugh, enum_show(&oakley_attr_names, a.isaat_af_type)); | |
1261 | break; | |
1262 | } | |
1263 | } | |
1264 | ||
1265 | /* | |
1266 | * ML: at last check for allowed transforms in alg_info_ike | |
1267 | * (ALG_INFO_F_STRICT flag) | |
1268 | */ | |
1269 | if (ugh == NULL) | |
1270 | { | |
1271 | if (!ike_alg_ok_final(ta.encrypt, ta.enckeylen, ta.hash, | |
1272 | ta.group ? ta.group->group : -1, c->alg_info_ike)) | |
1273 | { | |
1274 | ugh = "OAKLEY proposal refused"; | |
1275 | } | |
1276 | } | |
1277 | ||
1278 | if (ugh == NULL) | |
1279 | { | |
1280 | /* a little more checking is in order */ | |
1281 | { | |
1282 | lset_t missing | |
1283 | = ~seen_attrs | |
1284 | & (LELEM(OAKLEY_ENCRYPTION_ALGORITHM) | |
1285 | | LELEM(OAKLEY_HASH_ALGORITHM) | |
1286 | | LELEM(OAKLEY_AUTHENTICATION_METHOD) | |
1287 | | LELEM(OAKLEY_GROUP_DESCRIPTION)); | |
1288 | ||
1289 | if (missing) | |
1290 | { | |
1291 | loglog(RC_LOG_SERIOUS, "missing mandatory attribute(s) %s in Oakley Transform %u" | |
1292 | , bitnamesof(oakley_attr_bit_names, missing) | |
1293 | , trans.isat_transnum); | |
1294 | return BAD_PROPOSAL_SYNTAX; | |
1295 | } | |
1296 | } | |
1297 | /* We must have liked this transform. | |
1298 | * Lets finish early and leave. | |
1299 | */ | |
1300 | ||
1301 | DBG(DBG_PARSING | DBG_CRYPT | |
1302 | , DBG_log("Oakley Transform %u accepted", trans.isat_transnum)); | |
1303 | ||
1304 | if (r_sa_pbs != NULL) | |
1305 | { | |
1306 | struct isakmp_proposal r_proposal = *proposal; | |
1307 | pb_stream r_proposal_pbs; | |
1308 | struct isakmp_transform r_trans = trans; | |
1309 | pb_stream r_trans_pbs; | |
1310 | ||
1311 | /* Situation */ | |
1312 | if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)) | |
1313 | impossible(); | |
1314 | ||
1315 | /* Proposal */ | |
1316 | #ifdef EMIT_ISAKMP_SPI | |
1317 | r_proposal.isap_spisize = COOKIE_SIZE; | |
1318 | #else | |
1319 | r_proposal.isap_spisize = 0; | |
1320 | #endif | |
1321 | r_proposal.isap_notrans = 1; | |
1322 | if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)) | |
1323 | impossible(); | |
1324 | ||
1325 | /* SPI */ | |
1326 | #ifdef EMIT_ISAKMP_SPI | |
1327 | if (!out_raw(my_cookie, COOKIE_SIZE, &r_proposal_pbs, "SPI")) | |
1328 | impossible(); | |
1329 | r_proposal.isap_spisize = COOKIE_SIZE; | |
1330 | #else | |
1331 | /* none (0) */ | |
1332 | #endif | |
1333 | ||
1334 | /* Transform */ | |
1335 | r_trans.isat_np = ISAKMP_NEXT_NONE; | |
1336 | if (!out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs)) | |
1337 | impossible(); | |
1338 | ||
1339 | if (!out_raw(attr_start, attr_len, &r_trans_pbs, "attributes")) | |
1340 | impossible(); | |
1341 | close_output_pbs(&r_trans_pbs); | |
1342 | close_output_pbs(&r_proposal_pbs); | |
1343 | close_output_pbs(r_sa_pbs); | |
1344 | } | |
1345 | ||
1346 | /* copy over the results */ | |
1347 | st->st_oakley = ta; | |
1348 | return NOTHING_WRONG; | |
1349 | } | |
1350 | ||
1351 | /* on to next transform */ | |
1352 | no_trans_left--; | |
1353 | ||
1354 | if (trans.isat_np == ISAKMP_NEXT_NONE) | |
1355 | { | |
1356 | if (no_trans_left != 0) | |
1357 | { | |
1358 | loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); | |
1359 | return BAD_PROPOSAL_SYNTAX; | |
1360 | } | |
1361 | break; | |
1362 | } | |
1363 | if (trans.isat_np != ISAKMP_NEXT_T) | |
1364 | { | |
1365 | loglog(RC_LOG_SERIOUS, "unexpected %s payload in Oakley Proposal" | |
1366 | , enum_show(&payload_names, proposal->isap_np)); | |
1367 | return BAD_PROPOSAL_SYNTAX; | |
1368 | } | |
1369 | } | |
1370 | loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform"); | |
1371 | return NO_PROPOSAL_CHOSEN; | |
1372 | } | |
1373 | ||
1374 | /* Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode). | |
1375 | * | |
1376 | * The main routine is parse_ipsec_sa_body; other functions defined | |
1377 | * between here and there are just helpers. | |
1378 | * | |
1379 | * Various shortcuts are taken. In particular, the policy, such as | |
1380 | * it is, is hardwired. | |
1381 | * | |
1382 | * If r_sa is non-NULL, the body of an SA representing the selected | |
1383 | * proposal is emitted into it. | |
1384 | * | |
1385 | * If "selection" is true, the SA is supposed to represent the | |
1386 | * single tranform that the peer has accepted. | |
1387 | * ??? We only check that it is acceptable, not that it is one that we offered! | |
1388 | * | |
1389 | * Only IPsec DOI is accepted (what is the ISAKMP DOI?). | |
1390 | * Error response is rudimentary. | |
1391 | * | |
1392 | * Since all ISAKMP groups in all SA Payloads must match, st->st_pfs_group | |
1393 | * holds this across multiple payloads. | |
1394 | * &unset_group signifies not yet "set"; NULL signifies NONE. | |
1395 | * | |
1396 | * This routine is used by quick_inI1_outR1() and quick_inR1_outI2(). | |
1397 | */ | |
1398 | ||
1399 | static const struct ipsec_trans_attrs null_ipsec_trans_attrs = { | |
1400 | 0, /* transid (NULL, for now) */ | |
1401 | 0, /* spi */ | |
1402 | SA_LIFE_DURATION_DEFAULT, /* life_seconds */ | |
1403 | SA_LIFE_DURATION_K_DEFAULT, /* life_kilobytes */ | |
1404 | ENCAPSULATION_MODE_UNSPECIFIED, /* encapsulation */ | |
1405 | AUTH_ALGORITHM_NONE, /* auth */ | |
1406 | 0, /* key_len */ | |
1407 | 0, /* key_rounds */ | |
1408 | }; | |
1409 | ||
1410 | static bool | |
1411 | parse_ipsec_transform(struct isakmp_transform *trans | |
1412 | , struct ipsec_trans_attrs *attrs | |
1413 | , pb_stream *prop_pbs | |
1414 | , pb_stream *trans_pbs | |
1415 | , struct_desc *trans_desc | |
1416 | , int previous_transnum /* or -1 if none */ | |
1417 | , bool selection | |
1418 | , bool is_last | |
1419 | , bool is_ipcomp | |
1420 | , struct state *st) /* current state object */ | |
1421 | { | |
1422 | lset_t seen_attrs = 0; | |
1423 | lset_t seen_durations = 0; | |
1424 | u_int16_t life_type = 0; | |
1425 | const struct oakley_group_desc *pfs_group = NULL; | |
1426 | ||
1427 | if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs)) | |
1428 | return FALSE; | |
1429 | ||
1430 | if (trans->isat_transnum <= previous_transnum) | |
1431 | { | |
1432 | loglog(RC_LOG_SERIOUS, "Transform Numbers in Proposal are not monotonically increasing"); | |
1433 | return FALSE; | |
1434 | } | |
1435 | ||
1436 | switch (trans->isat_np) | |
1437 | { | |
1438 | case ISAKMP_NEXT_T: | |
1439 | if (is_last) | |
1440 | { | |
1441 | loglog(RC_LOG_SERIOUS, "Proposal Payload has more Transforms than specified"); | |
1442 | return FALSE; | |
1443 | } | |
1444 | break; | |
1445 | case ISAKMP_NEXT_NONE: | |
1446 | if (!is_last) | |
1447 | { | |
1448 | loglog(RC_LOG_SERIOUS, "Proposal Payload has fewer Transforms than specified"); | |
1449 | return FALSE; | |
1450 | } | |
1451 | break; | |
1452 | default: | |
1453 | loglog(RC_LOG_SERIOUS, "expecting Transform Payload, but found %s in Proposal" | |
1454 | , enum_show(&payload_names, trans->isat_np)); | |
1455 | return FALSE; | |
1456 | } | |
1457 | ||
1458 | *attrs = null_ipsec_trans_attrs; | |
1459 | attrs->transid = trans->isat_transid; | |
1460 | ||
1461 | while (pbs_left(trans_pbs) != 0) | |
1462 | { | |
1463 | struct isakmp_attribute a; | |
1464 | pb_stream attr_pbs; | |
1465 | enum_names *vdesc; | |
1466 | u_int32_t val; /* room for larger value */ | |
1467 | bool ipcomp_inappropriate = is_ipcomp; /* will get reset if OK */ | |
1468 | ||
1469 | if (!in_struct(&a, &isakmp_ipsec_attribute_desc, trans_pbs, &attr_pbs)) | |
1470 | return FALSE; | |
1471 | ||
1472 | passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); | |
1473 | ||
1474 | if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK)) | |
1475 | { | |
1476 | loglog(RC_LOG_SERIOUS, "repeated %s attribute in IPsec Transform %u" | |
1477 | , enum_show(&ipsec_attr_names, a.isaat_af_type) | |
1478 | , trans->isat_transnum); | |
1479 | return FALSE; | |
1480 | } | |
1481 | ||
1482 | seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); | |
1483 | ||
1484 | val = a.isaat_lv; | |
1485 | ||
1486 | vdesc = ipsec_attr_val_descs[a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; | |
1487 | if (vdesc != NULL) | |
1488 | { | |
1489 | if (enum_name(vdesc, val) == NULL) | |
1490 | { | |
1491 | loglog(RC_LOG_SERIOUS, "invalid value %u for attribute %s in IPsec Transform" | |
1492 | , (unsigned)val, enum_show(&ipsec_attr_names, a.isaat_af_type)); | |
1493 | return FALSE; | |
1494 | } | |
1495 | DBG(DBG_PARSING | |
1496 | , if ((a.isaat_af_type & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) | |
1497 | DBG_log(" [%u is %s]" | |
1498 | , (unsigned)val, enum_show(vdesc, val))); | |
1499 | } | |
1500 | ||
1501 | switch (a.isaat_af_type) | |
1502 | { | |
1503 | case SA_LIFE_TYPE | ISAKMP_ATTR_AF_TV: | |
1504 | ipcomp_inappropriate = FALSE; | |
1505 | if (LHAS(seen_durations, val)) | |
1506 | { | |
1507 | loglog(RC_LOG_SERIOUS, "attribute SA_LIFE_TYPE value %s repeated in message" | |
1508 | , enum_show(&sa_lifetime_names, val)); | |
1509 | return FALSE; | |
1510 | } | |
1511 | seen_durations |= LELEM(val); | |
1512 | life_type = val; | |
1513 | break; | |
1514 | case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: | |
1515 | val = decode_long_duration(&attr_pbs); | |
1516 | /* fall through */ | |
1517 | case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TV: | |
1518 | ipcomp_inappropriate = FALSE; | |
1519 | if (!LHAS(seen_attrs, SA_LIFE_DURATION)) | |
1520 | { | |
1521 | loglog(RC_LOG_SERIOUS, "SA_LIFE_DURATION IPsec attribute not preceded by SA_LIFE_TYPE attribute"); | |
1522 | return FALSE; | |
1523 | } | |
1524 | seen_attrs &= ~(LELEM(SA_LIFE_DURATION) | LELEM(SA_LIFE_TYPE)); | |
1525 | ||
1526 | switch (life_type) | |
1527 | { | |
1528 | case SA_LIFE_TYPE_SECONDS: | |
1529 | /* silently limit duration to our maximum */ | |
1530 | attrs->life_seconds = val <= SA_LIFE_DURATION_MAXIMUM | |
1531 | ? val : SA_LIFE_DURATION_MAXIMUM; | |
1532 | break; | |
1533 | case SA_LIFE_TYPE_KBYTES: | |
1534 | attrs->life_kilobytes = val; | |
1535 | break; | |
1536 | default: | |
1537 | bad_case(life_type); | |
1538 | } | |
1539 | break; | |
1540 | case GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV: | |
1541 | if (is_ipcomp) | |
1542 | { | |
1543 | /* Accept reluctantly. Should not happen, according to | |
1544 | * draft-shacham-ippcp-rfc2393bis-05.txt 4.1. | |
1545 | */ | |
1546 | ipcomp_inappropriate = FALSE; | |
1547 | loglog(RC_COMMENT | |
1548 | , "IPCA (IPcomp SA) contains GROUP_DESCRIPTION." | |
1549 | " Ignoring inapproprate attribute."); | |
1550 | } | |
1551 | pfs_group = lookup_group(val); | |
1552 | if (pfs_group == NULL) | |
1553 | { | |
1554 | loglog(RC_LOG_SERIOUS, "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported for PFS"); | |
1555 | return FALSE; | |
1556 | } | |
1557 | break; | |
1558 | case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV: | |
1559 | ipcomp_inappropriate = FALSE; | |
1560 | #ifdef NAT_TRAVERSAL | |
1561 | switch (val) | |
1562 | { | |
1563 | case ENCAPSULATION_MODE_TUNNEL: | |
1564 | case ENCAPSULATION_MODE_TRANSPORT: | |
1565 | if (st->nat_traversal & NAT_T_DETECTED) | |
1566 | { | |
1567 | loglog(RC_LOG_SERIOUS | |
1568 | , "%s must only be used if NAT-Traversal is not detected" | |
1569 | , enum_name(&enc_mode_names, val)); | |
1570 | /* | |
1571 | * Accept it anyway because SSH-Sentinel does not | |
1572 | * use UDP_TUNNEL or UDP_TRANSPORT for the diagnostic. | |
1573 | * | |
1574 | * remove when SSH-Sentinel is fixed | |
1575 | */ | |
1576 | #ifdef I_DONT_CARE_OF_SSH_SENTINEL | |
1577 | return FALSE; | |
1578 | #endif | |
1579 | } | |
1580 | attrs->encapsulation = val; | |
1581 | break; | |
1582 | case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS: | |
1583 | #ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT | |
1584 | loglog(RC_LOG_SERIOUS | |
1585 | , "NAT-Traversal: Transport mode disabled due to security concerns"); | |
1586 | return FALSE; | |
1587 | #endif | |
1588 | case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS: | |
1589 | if (st->nat_traversal & NAT_T_WITH_RFC_VALUES) | |
1590 | { | |
1591 | loglog(RC_LOG_SERIOUS | |
1592 | , "%s must only be used with old IETF drafts" | |
1593 | , enum_name(&enc_mode_names, val)); | |
1594 | return FALSE; | |
1595 | } | |
1596 | else if (st->nat_traversal & NAT_T_DETECTED) | |
1597 | { | |
1598 | attrs->encapsulation = val | |
1599 | - ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS | |
1600 | + ENCAPSULATION_MODE_TUNNEL; | |
1601 | } | |
1602 | else | |
1603 | { | |
1604 | loglog(RC_LOG_SERIOUS | |
1605 | , "%s must only be used if NAT-Traversal is detected" | |
1606 | , enum_name(&enc_mode_names, val)); | |
1607 | return FALSE; | |
1608 | } | |
1609 | break; | |
1610 | case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC: | |
1611 | #ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT | |
1612 | loglog(RC_LOG_SERIOUS | |
1613 | , "NAT-Traversal: Transport mode disabled due " | |
1614 | "to security concerns"); | |
1615 | return FALSE; | |
1616 | #endif | |
1617 | case ENCAPSULATION_MODE_UDP_TUNNEL_RFC: | |
1618 | if ((st->nat_traversal & NAT_T_DETECTED) | |
1619 | && (st->nat_traversal & NAT_T_WITH_RFC_VALUES)) | |
1620 | { | |
1621 | attrs->encapsulation = val | |
1622 | - ENCAPSULATION_MODE_UDP_TUNNEL_RFC | |
1623 | + ENCAPSULATION_MODE_TUNNEL; | |
1624 | } | |
1625 | else if (st->nat_traversal & NAT_T_DETECTED) | |
1626 | { | |
1627 | loglog(RC_LOG_SERIOUS | |
1628 | , "%s must only be used with NAT-T RFC" | |
1629 | , enum_name(&enc_mode_names, val)); | |
1630 | return FALSE; | |
1631 | } | |
1632 | else | |
1633 | { | |
1634 | loglog(RC_LOG_SERIOUS | |
1635 | , "%s must only be used if NAT-Traversal is detected" | |
1636 | , enum_name(&enc_mode_names, val)); | |
1637 | return FALSE; | |
1638 | } | |
1639 | break; | |
1640 | default: | |
1641 | loglog(RC_LOG_SERIOUS | |
1642 | , "unknown ENCAPSULATION_MODE %d in IPSec SA", val); | |
1643 | return FALSE; | |
1644 | } | |
1645 | #else | |
1646 | attrs->encapsulation = val; | |
1647 | #endif | |
1648 | break; | |
1649 | case AUTH_ALGORITHM | ISAKMP_ATTR_AF_TV: | |
1650 | attrs->auth = val; | |
1651 | break; | |
1652 | case KEY_LENGTH | ISAKMP_ATTR_AF_TV: | |
1653 | attrs->key_len = val; | |
1654 | break; | |
1655 | case KEY_ROUNDS | ISAKMP_ATTR_AF_TV: | |
1656 | attrs->key_rounds = val; | |
1657 | break; | |
1658 | #if 0 /* not yet implemented */ | |
1659 | case COMPRESS_DICT_SIZE | ISAKMP_ATTR_AF_TV: | |
1660 | break; | |
1661 | case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TV: | |
1662 | break; | |
1663 | ||
1664 | case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: | |
1665 | break; | |
1666 | case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TLV: | |
1667 | break; | |
1668 | #endif | |
1669 | default: | |
1670 | loglog(RC_LOG_SERIOUS, "unsupported IPsec attribute %s" | |
1671 | , enum_show(&ipsec_attr_names, a.isaat_af_type)); | |
1672 | return FALSE; | |
1673 | } | |
1674 | if (ipcomp_inappropriate) | |
1675 | { | |
1676 | loglog(RC_LOG_SERIOUS, "IPsec attribute %s inappropriate for IPCOMP" | |
1677 | , enum_show(&ipsec_attr_names, a.isaat_af_type)); | |
1678 | return FALSE; | |
1679 | } | |
1680 | } | |
1681 | ||
1682 | /* Although an IPCOMP SA (IPCA) ought not to have a pfs_group, | |
1683 | * if it does, demand that it be consistent. | |
1684 | * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1. | |
1685 | */ | |
1686 | if (!is_ipcomp || pfs_group != NULL) | |
1687 | { | |
1688 | if (st->st_pfs_group == &unset_group) | |
1689 | st->st_pfs_group = pfs_group; | |
1690 | ||
1691 | if (st->st_pfs_group != pfs_group) | |
1692 | { | |
1693 | loglog(RC_LOG_SERIOUS, "GROUP_DESCRIPTION inconsistent with that of %s in IPsec SA" | |
1694 | , selection? "the Proposal" : "a previous Transform"); | |
1695 | return FALSE; | |
1696 | } | |
1697 | } | |
1698 | ||
1699 | if (LHAS(seen_attrs, SA_LIFE_DURATION)) | |
1700 | { | |
1701 | loglog(RC_LOG_SERIOUS, "SA_LIFE_TYPE IPsec attribute not followed by SA_LIFE_DURATION attribute in message"); | |
1702 | return FALSE; | |
1703 | } | |
1704 | ||
1705 | if (!LHAS(seen_attrs, ENCAPSULATION_MODE)) | |
1706 | { | |
1707 | if (is_ipcomp) | |
1708 | { | |
1709 | /* draft-shacham-ippcp-rfc2393bis-05.txt 4.1: | |
1710 | * "If the Encapsulation Mode is unspecified, | |
1711 | * the default value of Transport Mode is assumed." | |
1712 | * This contradicts/overrides the DOI (quuoted below). | |
1713 | */ | |
1714 | attrs->encapsulation = ENCAPSULATION_MODE_TRANSPORT; | |
1715 | } | |
1716 | else | |
1717 | { | |
1718 | /* ??? Technically, RFC 2407 (IPSEC DOI) 4.5 specifies that | |
1719 | * the default is "unspecified (host-dependent)". | |
1720 | * This makes little sense, so we demand that it be specified. | |
1721 | */ | |
1722 | loglog(RC_LOG_SERIOUS, "IPsec Transform must specify ENCAPSULATION_MODE"); | |
1723 | return FALSE; | |
1724 | } | |
1725 | } | |
1726 | ||
1727 | /* ??? should check for key_len and/or key_rounds if required */ | |
1728 | ||
1729 | return TRUE; | |
1730 | } | |
1731 | ||
1732 | static void | |
1733 | echo_proposal( | |
1734 | struct isakmp_proposal r_proposal, /* proposal to emit */ | |
1735 | struct isakmp_transform r_trans, /* winning transformation within it */ | |
1736 | u_int8_t np, /* Next Payload for proposal */ | |
1737 | pb_stream *r_sa_pbs, /* SA PBS into which to emit */ | |
1738 | struct ipsec_proto_info *pi, /* info about this protocol instance */ | |
1739 | struct_desc *trans_desc, /* descriptor for this transformation */ | |
1740 | pb_stream *trans_pbs, /* PBS for incoming transform */ | |
1741 | struct spd_route *sr, /* host details for the association */ | |
1742 | bool tunnel_mode) /* true for inner most tunnel SA */ | |
1743 | { | |
1744 | pb_stream r_proposal_pbs; | |
1745 | pb_stream r_trans_pbs; | |
1746 | ||
1747 | /* Proposal */ | |
1748 | r_proposal.isap_np = np; | |
1749 | r_proposal.isap_notrans = 1; | |
1750 | if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)) | |
1751 | impossible(); | |
1752 | ||
1753 | /* allocate and emit our CPI/SPI */ | |
1754 | if (r_proposal.isap_protoid == PROTO_IPCOMP) | |
1755 | { | |
1756 | /* CPI is stored in network low order end of an | |
1757 | * ipsec_spi_t. So we start a couple of bytes in. | |
1758 | * Note: we may fail to generate a satisfactory CPI, | |
1759 | * but we'll ignore that. | |
1760 | */ | |
1761 | pi->our_spi = get_my_cpi(sr, tunnel_mode); | |
1762 | out_raw((u_char *) &pi->our_spi | |
1763 | + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE | |
1764 | , IPCOMP_CPI_SIZE | |
1765 | , &r_proposal_pbs, "CPI"); | |
1766 | } | |
1767 | else | |
1768 | { | |
1769 | pi->our_spi = get_ipsec_spi(pi->attrs.spi | |
1770 | , r_proposal.isap_protoid == PROTO_IPSEC_AH ? | |
1771 | IPPROTO_AH : IPPROTO_ESP | |
1772 | , sr | |
1773 | , tunnel_mode); | |
1774 | /* XXX should check for errors */ | |
1775 | out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE | |
1776 | , &r_proposal_pbs, "SPI"); | |
1777 | } | |
1778 | ||
1779 | /* Transform */ | |
1780 | r_trans.isat_np = ISAKMP_NEXT_NONE; | |
1781 | if (!out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs)) | |
1782 | impossible(); | |
1783 | ||
1784 | /* Transform Attributes: pure echo */ | |
1785 | trans_pbs->cur = trans_pbs->start + sizeof(struct isakmp_transform); | |
1786 | if (!out_raw(trans_pbs->cur, pbs_left(trans_pbs) | |
1787 | , &r_trans_pbs, "attributes")) | |
1788 | impossible(); | |
1789 | ||
1790 | close_output_pbs(&r_trans_pbs); | |
1791 | close_output_pbs(&r_proposal_pbs); | |
1792 | } | |
1793 | ||
1794 | notification_t | |
1795 | parse_ipsec_sa_body( | |
1796 | pb_stream *sa_pbs, /* body of input SA Payload */ | |
1797 | const struct isakmp_sa *sa, /* header of input SA Payload */ | |
1798 | pb_stream *r_sa_pbs, /* if non-NULL, where to emit body of winning SA */ | |
1799 | bool selection, /* if this SA is a selection, only one transform may appear */ | |
1800 | struct state *st) /* current state object */ | |
1801 | { | |
1802 | const struct connection *c = st->st_connection; | |
1803 | u_int32_t ipsecdoisit; | |
1804 | pb_stream next_proposal_pbs; | |
1805 | ||
1806 | struct isakmp_proposal next_proposal; | |
1807 | ipsec_spi_t next_spi; | |
1808 | ||
1809 | bool next_full = TRUE; | |
1810 | ||
1811 | /* DOI */ | |
1812 | if (sa->isasa_doi != ISAKMP_DOI_IPSEC) | |
1813 | { | |
1814 | loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); | |
1815 | /* XXX Could send notification back */ | |
1816 | return DOI_NOT_SUPPORTED; | |
1817 | } | |
1818 | ||
1819 | /* Situation */ | |
1820 | if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) | |
1821 | return SITUATION_NOT_SUPPORTED; | |
1822 | ||
1823 | if (ipsecdoisit != SIT_IDENTITY_ONLY) | |
1824 | { | |
1825 | loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" | |
1826 | , bitnamesof(sit_bit_names, ipsecdoisit)); | |
1827 | /* XXX Could send notification back */ | |
1828 | return SITUATION_NOT_SUPPORTED; | |
1829 | } | |
1830 | ||
1831 | /* The rules for IPsec SAs are scattered. | |
1832 | * RFC 2408 "ISAKMP" section 4.2 gives some info. | |
1833 | * There may be multiple proposals. Those with identical proposal | |
1834 | * numbers must be considered as conjuncts. Those with different | |
1835 | * numbers are disjuncts. | |
1836 | * Each proposal may have several transforms, each considered | |
1837 | * an alternative. | |
1838 | * Each transform may have several attributes, all applying. | |
1839 | * | |
1840 | * To handle the way proposals are combined, we need to do a | |
1841 | * look-ahead. | |
1842 | */ | |
1843 | ||
1844 | if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) | |
1845 | return BAD_PROPOSAL_SYNTAX; | |
1846 | ||
1847 | /* for each conjunction of proposals... */ | |
1848 | while (next_full) | |
1849 | { | |
1850 | int propno = next_proposal.isap_proposal; | |
1851 | pb_stream ah_prop_pbs, esp_prop_pbs, ipcomp_prop_pbs; | |
1852 | struct isakmp_proposal ah_proposal, esp_proposal, ipcomp_proposal; | |
1853 | ipsec_spi_t ah_spi = 0; | |
1854 | ipsec_spi_t esp_spi = 0; | |
1855 | ipsec_spi_t ipcomp_cpi = 0; | |
1856 | bool ah_seen = FALSE; | |
1857 | bool esp_seen = FALSE; | |
1858 | bool ipcomp_seen = FALSE; | |
1859 | bool tunnel_mode = FALSE; | |
1860 | int inner_proto = 0; | |
1861 | u_int16_t well_known_cpi = 0; | |
1862 | ||
1863 | pb_stream ah_trans_pbs, esp_trans_pbs, ipcomp_trans_pbs; | |
1864 | struct isakmp_transform ah_trans, esp_trans, ipcomp_trans; | |
1865 | struct ipsec_trans_attrs ah_attrs, esp_attrs, ipcomp_attrs; | |
1866 | ||
1867 | /* for each proposal in the conjunction */ | |
1868 | do { | |
1869 | ||
1870 | if (next_proposal.isap_protoid == PROTO_IPCOMP) | |
1871 | { | |
1872 | /* IPCOMP CPI */ | |
1873 | if (next_proposal.isap_spisize == IPSEC_DOI_SPI_SIZE) | |
1874 | { | |
1875 | /* This code is to accommodate those peculiar | |
1876 | * implementations that send a CPI in the bottom of an | |
1877 | * SPI-sized field. | |
1878 | * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1 | |
1879 | */ | |
1880 | u_int8_t filler[IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE]; | |
1881 | ||
1882 | if (!in_raw(filler, sizeof(filler) | |
1883 | , &next_proposal_pbs, "CPI filler") | |
1884 | || !all_zero(filler, sizeof(filler))) | |
1885 | return INVALID_SPI; | |
1886 | } | |
1887 | else if (next_proposal.isap_spisize != IPCOMP_CPI_SIZE) | |
1888 | { | |
1889 | loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper CPI size (%u)" | |
1890 | , next_proposal.isap_spisize); | |
1891 | return INVALID_SPI; | |
1892 | } | |
1893 | ||
1894 | /* We store CPI in the low order of a network order | |
1895 | * ipsec_spi_t. So we start a couple of bytes in. | |
1896 | */ | |
1897 | zero(&next_spi); | |
1898 | if (!in_raw((u_char *)&next_spi | |
1899 | + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE | |
1900 | , IPCOMP_CPI_SIZE, &next_proposal_pbs, "CPI")) | |
1901 | return INVALID_SPI; | |
1902 | ||
1903 | /* If sanity ruled, CPIs would have to be such that | |
1904 | * the SAID (the triple (CPI, IPCOM, destination IP)) | |
1905 | * would be unique, just like for SPIs. But there is a | |
1906 | * perversion where CPIs can be well-known and consequently | |
1907 | * the triple is not unique. We hide this fact from | |
1908 | * ourselves by fudging the top 16 bits to make | |
1909 | * the property true internally! | |
1910 | */ | |
1911 | switch (ntohl(next_spi)) | |
1912 | { | |
1913 | case IPCOMP_DEFLATE: | |
1914 | well_known_cpi = ntohl(next_spi); | |
1915 | next_spi = uniquify_his_cpi(next_spi, st); | |
1916 | if (next_spi == 0) | |
1917 | { | |
1918 | loglog(RC_LOG_SERIOUS | |
1919 | , "IPsec Proposal contains well-known CPI that I cannot uniquify"); | |
1920 | return INVALID_SPI; | |
1921 | } | |
1922 | break; | |
1923 | default: | |
1924 | if (ntohl(next_spi) < IPCOMP_FIRST_NEGOTIATED | |
1925 | || ntohl(next_spi) > IPCOMP_LAST_NEGOTIATED) | |
1926 | { | |
1927 | loglog(RC_LOG_SERIOUS, "IPsec Proposal contains CPI from non-negotiated range (0x%lx)" | |
1928 | , (unsigned long) ntohl(next_spi)); | |
1929 | return INVALID_SPI; | |
1930 | } | |
1931 | break; | |
1932 | } | |
1933 | } | |
1934 | else | |
1935 | { | |
1936 | /* AH or ESP SPI */ | |
1937 | if (next_proposal.isap_spisize != IPSEC_DOI_SPI_SIZE) | |
1938 | { | |
1939 | loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper SPI size (%u)" | |
1940 | , next_proposal.isap_spisize); | |
1941 | return INVALID_SPI; | |
1942 | } | |
1943 | ||
1944 | if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI")) | |
1945 | return INVALID_SPI; | |
1946 | ||
1947 | /* SPI value 0 is invalid and values 1-255 are reserved to IANA. | |
1948 | * RFC 2402 (ESP) 2.4, RFC 2406 (AH) 2.1 | |
1949 | * IPCOMP??? | |
1950 | */ | |
1951 | if (ntohl(next_spi) < IPSEC_DOI_SPI_MIN) | |
1952 | { | |
1953 | loglog(RC_LOG_SERIOUS, "IPsec Proposal contains invalid SPI (0x%lx)" | |
1954 | , (unsigned long) ntohl(next_spi)); | |
1955 | return INVALID_SPI; | |
1956 | } | |
1957 | } | |
1958 | ||
1959 | if (next_proposal.isap_notrans == 0) | |
1960 | { | |
1961 | loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms"); | |
1962 | return BAD_PROPOSAL_SYNTAX; | |
1963 | } | |
1964 | ||
1965 | switch (next_proposal.isap_protoid) | |
1966 | { | |
1967 | case PROTO_IPSEC_AH: | |
1968 | if (ah_seen) | |
1969 | { | |
1970 | loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous AH Proposals"); | |
1971 | return BAD_PROPOSAL_SYNTAX; | |
1972 | } | |
1973 | ah_seen = TRUE; | |
1974 | ah_prop_pbs = next_proposal_pbs; | |
1975 | ah_proposal = next_proposal; | |
1976 | ah_spi = next_spi; | |
1977 | break; | |
1978 | ||
1979 | case PROTO_IPSEC_ESP: | |
1980 | if (esp_seen) | |
1981 | { | |
1982 | loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous ESP Proposals"); | |
1983 | return BAD_PROPOSAL_SYNTAX; | |
1984 | } | |
1985 | esp_seen = TRUE; | |
1986 | esp_prop_pbs = next_proposal_pbs; | |
1987 | esp_proposal = next_proposal; | |
1988 | esp_spi = next_spi; | |
1989 | break; | |
1990 | ||
1991 | case PROTO_IPCOMP: | |
1992 | if (ipcomp_seen) | |
1993 | { | |
1994 | loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous IPCOMP Proposals"); | |
1995 | return BAD_PROPOSAL_SYNTAX; | |
1996 | } | |
1997 | ipcomp_seen = TRUE; | |
1998 | ipcomp_prop_pbs = next_proposal_pbs; | |
1999 | ipcomp_proposal = next_proposal; | |
2000 | ipcomp_cpi = next_spi; | |
2001 | break; | |
2002 | ||
2003 | default: | |
2004 | loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) in IPsec Proposal" | |
2005 | , enum_show(&protocol_names, next_proposal.isap_protoid)); | |
2006 | return INVALID_PROTOCOL_ID; | |
2007 | } | |
2008 | ||
2009 | /* refill next_proposal */ | |
2010 | if (next_proposal.isap_np == ISAKMP_NEXT_NONE) | |
2011 | { | |
2012 | next_full = FALSE; | |
2013 | break; | |
2014 | } | |
2015 | else if (next_proposal.isap_np != ISAKMP_NEXT_P) | |
2016 | { | |
2017 | loglog(RC_LOG_SERIOUS, "unexpected in Proposal: %s" | |
2018 | , enum_show(&payload_names, next_proposal.isap_np)); | |
2019 | return BAD_PROPOSAL_SYNTAX; | |
2020 | } | |
2021 | ||
2022 | if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) | |
2023 | return BAD_PROPOSAL_SYNTAX; | |
2024 | } while (next_proposal.isap_proposal == propno); | |
2025 | ||
2026 | /* Now that we have all conjuncts, we should try | |
2027 | * the Cartesian product of eachs tranforms! | |
2028 | * At the moment, we take short-cuts on account of | |
2029 | * our rudimentary hard-wired policy. | |
2030 | * For now, we find an acceptable AH (if any) | |
2031 | * and then an acceptable ESP. The only interaction | |
2032 | * is that the ESP acceptance can know whether there | |
2033 | * was an acceptable AH and hence not require an AUTH. | |
2034 | */ | |
2035 | ||
2036 | if (ah_seen) | |
2037 | { | |
2038 | int previous_transnum = -1; | |
2039 | int tn; | |
2040 | ||
2041 | for (tn = 0; tn != ah_proposal.isap_notrans; tn++) | |
2042 | { | |
2043 | int ok_transid = 0; | |
2044 | bool ok_auth = FALSE; | |
2045 | ||
2046 | if (!parse_ipsec_transform(&ah_trans | |
2047 | , &ah_attrs | |
2048 | , &ah_prop_pbs | |
2049 | , &ah_trans_pbs | |
2050 | , &isakmp_ah_transform_desc | |
2051 | , previous_transnum | |
2052 | , selection | |
2053 | , tn == ah_proposal.isap_notrans - 1 | |
2054 | , FALSE | |
2055 | , st)) | |
2056 | return BAD_PROPOSAL_SYNTAX; | |
2057 | ||
2058 | previous_transnum = ah_trans.isat_transnum; | |
2059 | ||
2060 | /* we must understand ah_attrs.transid | |
2061 | * COMBINED with ah_attrs.auth. | |
2062 | * See RFC 2407 "IPsec DOI" section 4.4.3 | |
2063 | * The following combinations are legal, | |
2064 | * but we don't implement all of them: | |
2065 | * It seems as if each auth algorithm | |
2066 | * only applies to one ah transid. | |
2067 | * AH_MD5, AUTH_ALGORITHM_HMAC_MD5 | |
2068 | * AH_MD5, AUTH_ALGORITHM_KPDK (unimplemented) | |
2069 | * AH_SHA, AUTH_ALGORITHM_HMAC_SHA1 | |
2070 | * AH_DES, AUTH_ALGORITHM_DES_MAC (unimplemented) | |
2071 | */ | |
2072 | switch (ah_attrs.auth) | |
2073 | { | |
2074 | case AUTH_ALGORITHM_NONE: | |
2075 | loglog(RC_LOG_SERIOUS, "AUTH_ALGORITHM attribute missing in AH Transform"); | |
2076 | return BAD_PROPOSAL_SYNTAX; | |
2077 | ||
2078 | case AUTH_ALGORITHM_HMAC_MD5: | |
2079 | ok_auth = TRUE; | |
2080 | /* fall through */ | |
2081 | case AUTH_ALGORITHM_KPDK: | |
2082 | ok_transid = AH_MD5; | |
2083 | break; | |
2084 | ||
2085 | case AUTH_ALGORITHM_HMAC_SHA1: | |
2086 | ok_auth = TRUE; | |
2087 | ok_transid = AH_SHA; | |
2088 | break; | |
2089 | ||
2090 | case AUTH_ALGORITHM_DES_MAC: | |
2091 | ok_transid = AH_DES; | |
2092 | break; | |
2093 | } | |
2094 | if (ah_attrs.transid != ok_transid) | |
2095 | { | |
2096 | loglog(RC_LOG_SERIOUS, "%s attribute inappropriate in %s Transform" | |
2097 | , enum_name(&auth_alg_names, ah_attrs.auth) | |
2098 | , enum_show(&ah_transformid_names, ah_attrs.transid)); | |
2099 | return BAD_PROPOSAL_SYNTAX; | |
2100 | } | |
2101 | if (!ok_auth) | |
2102 | { | |
2103 | DBG(DBG_CONTROL | DBG_CRYPT | |
2104 | , DBG_log("%s attribute unsupported" | |
2105 | " in %s Transform from %s" | |
2106 | , enum_name(&auth_alg_names, ah_attrs.auth) | |
2107 | , enum_show(&ah_transformid_names, ah_attrs.transid) | |
2108 | , ip_str(&c->spd.that.host_addr))); | |
2109 | continue; /* try another */ | |
2110 | } | |
2111 | break; /* we seem to be happy */ | |
2112 | } | |
2113 | if (tn == ah_proposal.isap_notrans) | |
2114 | continue; /* we didn't find a nice one */ | |
2115 | ah_attrs.spi = ah_spi; | |
2116 | inner_proto = IPPROTO_AH; | |
2117 | if (ah_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) | |
2118 | tunnel_mode = TRUE; | |
2119 | } | |
2120 | ||
2121 | if (esp_seen) | |
2122 | { | |
2123 | int previous_transnum = -1; | |
2124 | int tn; | |
2125 | ||
2126 | for (tn = 0; tn != esp_proposal.isap_notrans; tn++) | |
2127 | { | |
2128 | if (!parse_ipsec_transform(&esp_trans | |
2129 | , &esp_attrs | |
2130 | , &esp_prop_pbs | |
2131 | , &esp_trans_pbs | |
2132 | , &isakmp_esp_transform_desc | |
2133 | , previous_transnum | |
2134 | , selection | |
2135 | , tn == esp_proposal.isap_notrans - 1 | |
2136 | , FALSE | |
2137 | , st)) | |
2138 | return BAD_PROPOSAL_SYNTAX; | |
2139 | ||
2140 | previous_transnum = esp_trans.isat_transnum; | |
2141 | ||
2142 | /* set default key length for AES encryption */ | |
2143 | if (!esp_attrs.key_len && esp_attrs.transid == ESP_AES) | |
2144 | { | |
2145 | esp_attrs.key_len = 128 / BITS_PER_BYTE; | |
2146 | } | |
2147 | ||
2148 | if (!kernel_alg_esp_enc_ok(esp_attrs.transid, esp_attrs.key_len | |
2149 | ,c->alg_info_esp)) | |
2150 | { | |
2151 | switch (esp_attrs.transid) | |
2152 | { | |
2153 | case ESP_3DES: | |
2154 | break; | |
2155 | #ifdef SUPPORT_ESP_NULL /* should be about as secure as AH-only */ | |
2156 | case ESP_NULL: | |
2157 | if (esp_attrs.auth == AUTH_ALGORITHM_NONE) | |
2158 | { | |
2159 | loglog(RC_LOG_SERIOUS, "ESP_NULL requires auth algorithm"); | |
2160 | return BAD_PROPOSAL_SYNTAX; | |
2161 | } | |
2162 | if (st->st_policy & POLICY_ENCRYPT) | |
2163 | { | |
2164 | DBG(DBG_CONTROL | DBG_CRYPT | |
2165 | , DBG_log("ESP_NULL Transform Proposal from %s" | |
2166 | " does not satisfy POLICY_ENCRYPT" | |
2167 | , ip_str(&c->spd.that.host_addr))); | |
2168 | continue; /* try another */ | |
2169 | } | |
2170 | break; | |
2171 | #endif | |
2172 | default: | |
2173 | DBG(DBG_CONTROL | DBG_CRYPT | |
2174 | , DBG_log("unsupported ESP Transform %s from %s" | |
2175 | , enum_show(&esp_transformid_names, esp_attrs.transid) | |
2176 | , ip_str(&c->spd.that.host_addr))); | |
2177 | continue; /* try another */ | |
2178 | } | |
2179 | } | |
2180 | ||
2181 | if (!kernel_alg_esp_auth_ok(esp_attrs.auth, c->alg_info_esp)) | |
2182 | { | |
2183 | switch (esp_attrs.auth) | |
2184 | { | |
2185 | case AUTH_ALGORITHM_NONE: | |
2186 | if (!ah_seen) | |
2187 | { | |
2188 | DBG(DBG_CONTROL | DBG_CRYPT | |
2189 | , DBG_log("ESP from %s must either have AUTH or be combined with AH" | |
2190 | , ip_str(&c->spd.that.host_addr))); | |
2191 | continue; /* try another */ | |
2192 | } | |
2193 | break; | |
2194 | case AUTH_ALGORITHM_HMAC_MD5: | |
2195 | case AUTH_ALGORITHM_HMAC_SHA1: | |
2196 | break; | |
2197 | default: | |
2198 | DBG(DBG_CONTROL | DBG_CRYPT | |
2199 | , DBG_log("unsupported ESP auth alg %s from %s" | |
2200 | , enum_show(&auth_alg_names, esp_attrs.auth) | |
2201 | , ip_str(&c->spd.that.host_addr))); | |
2202 | continue; /* try another */ | |
2203 | } | |
2204 | } | |
2205 | ||
2206 | /* A last check for allowed transforms in alg_info_esp | |
2207 | * (ALG_INFO_F_STRICT flag) | |
2208 | */ | |
2209 | if (!kernel_alg_esp_ok_final(esp_attrs.transid, esp_attrs.key_len | |
2210 | ,esp_attrs.auth, c->alg_info_esp)) | |
2211 | { | |
2212 | continue; | |
2213 | } | |
2214 | ||
2215 | if (ah_seen && ah_attrs.encapsulation != esp_attrs.encapsulation) | |
2216 | { | |
2217 | /* ??? This should be an error, but is it? */ | |
2218 | DBG(DBG_CONTROL | DBG_CRYPT | |
2219 | , DBG_log("AH and ESP transforms disagree about encapsulation; TUNNEL presumed")); | |
2220 | } | |
2221 | ||
2222 | break; /* we seem to be happy */ | |
2223 | } | |
2224 | if (tn == esp_proposal.isap_notrans) | |
2225 | continue; /* we didn't find a nice one */ | |
2226 | ||
2227 | esp_attrs.spi = esp_spi; | |
2228 | inner_proto = IPPROTO_ESP; | |
2229 | if (esp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) | |
2230 | tunnel_mode = TRUE; | |
2231 | } | |
2232 | else if (st->st_policy & POLICY_ENCRYPT) | |
2233 | { | |
2234 | DBG(DBG_CONTROL | DBG_CRYPT | |
2235 | , DBG_log("policy for \"%s\" requires encryption but ESP not in Proposal from %s" | |
2236 | , c->name, ip_str(&c->spd.that.host_addr))); | |
2237 | continue; /* we needed encryption, but didn't find ESP */ | |
2238 | } | |
2239 | else if ((st->st_policy & POLICY_AUTHENTICATE) && !ah_seen) | |
2240 | { | |
2241 | DBG(DBG_CONTROL | DBG_CRYPT | |
2242 | , DBG_log("policy for \"%s\" requires authentication" | |
2243 | " but none in Proposal from %s" | |
2244 | , c->name, ip_str(&c->spd.that.host_addr))); | |
2245 | continue; /* we need authentication, but we found neither ESP nor AH */ | |
2246 | } | |
2247 | ||
2248 | if (ipcomp_seen) | |
2249 | { | |
2250 | int previous_transnum = -1; | |
2251 | int tn; | |
2252 | ||
2253 | #ifdef NEVER /* we think IPcomp is working now */ | |
2254 | /**** FUDGE TO PREVENT UNREQUESTED IPCOMP: | |
2255 | **** NEEDED BECAUSE OUR IPCOMP IS EXPERIMENTAL (UNSTABLE). | |
2256 | ****/ | |
2257 | if (!(st->st_policy & POLICY_COMPRESS)) | |
2258 | { | |
2259 | plog("compression proposed by %s, but policy for \"%s\" forbids it" | |
2260 | , ip_str(&c->spd.that.host_addr), c->name); | |
2261 | continue; /* unwanted compression proposal */ | |
2262 | } | |
2263 | #endif | |
2264 | if (!can_do_IPcomp) | |
2265 | { | |
2266 | plog("compression proposed by %s, but KLIPS is not configured with IPCOMP" | |
2267 | , ip_str(&c->spd.that.host_addr)); | |
2268 | continue; | |
2269 | } | |
2270 | ||
2271 | if (well_known_cpi != 0 && !ah_seen && !esp_seen) | |
2272 | { | |
2273 | plog("illegal proposal: bare IPCOMP used with well-known CPI"); | |
2274 | return BAD_PROPOSAL_SYNTAX; | |
2275 | } | |
2276 | ||
2277 | for (tn = 0; tn != ipcomp_proposal.isap_notrans; tn++) | |
2278 | { | |
2279 | if (!parse_ipsec_transform(&ipcomp_trans | |
2280 | , &ipcomp_attrs | |
2281 | , &ipcomp_prop_pbs | |
2282 | , &ipcomp_trans_pbs | |
2283 | , &isakmp_ipcomp_transform_desc | |
2284 | , previous_transnum | |
2285 | , selection | |
2286 | , tn == ipcomp_proposal.isap_notrans - 1 | |
2287 | , TRUE | |
2288 | , st)) | |
2289 | return BAD_PROPOSAL_SYNTAX; | |
2290 | ||
2291 | previous_transnum = ipcomp_trans.isat_transnum; | |
2292 | ||
2293 | if (well_known_cpi != 0 && ipcomp_attrs.transid != well_known_cpi) | |
2294 | { | |
2295 | plog("illegal proposal: IPCOMP well-known CPI disagrees with transform"); | |
2296 | return BAD_PROPOSAL_SYNTAX; | |
2297 | } | |
2298 | ||
2299 | switch (ipcomp_attrs.transid) | |
2300 | { | |
2301 | case IPCOMP_DEFLATE: /* all we can handle! */ | |
2302 | break; | |
2303 | ||
2304 | default: | |
2305 | DBG(DBG_CONTROL | DBG_CRYPT | |
2306 | , DBG_log("unsupported IPCOMP Transform %s from %s" | |
2307 | , enum_show(&ipcomp_transformid_names, ipcomp_attrs.transid) | |
2308 | , ip_str(&c->spd.that.host_addr))); | |
2309 | continue; /* try another */ | |
2310 | } | |
2311 | ||
2312 | if (ah_seen && ah_attrs.encapsulation != ipcomp_attrs.encapsulation) | |
2313 | { | |
2314 | /* ??? This should be an error, but is it? */ | |
2315 | DBG(DBG_CONTROL | DBG_CRYPT | |
2316 | , DBG_log("AH and IPCOMP transforms disagree about encapsulation; TUNNEL presumed")); | |
2317 | } else if (esp_seen && esp_attrs.encapsulation != ipcomp_attrs.encapsulation) | |
2318 | { | |
2319 | /* ??? This should be an error, but is it? */ | |
2320 | DBG(DBG_CONTROL | DBG_CRYPT | |
2321 | , DBG_log("ESP and IPCOMP transforms disagree about encapsulation; TUNNEL presumed")); | |
2322 | } | |
2323 | ||
2324 | break; /* we seem to be happy */ | |
2325 | } | |
2326 | if (tn == ipcomp_proposal.isap_notrans) | |
2327 | continue; /* we didn't find a nice one */ | |
2328 | ipcomp_attrs.spi = ipcomp_cpi; | |
2329 | inner_proto = IPPROTO_COMP; | |
2330 | if (ipcomp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) | |
2331 | tunnel_mode = TRUE; | |
2332 | } | |
2333 | ||
2334 | /* Eureka: we liked what we saw -- accept it. */ | |
2335 | ||
2336 | if (r_sa_pbs != NULL) | |
2337 | { | |
2338 | /* emit what we've accepted */ | |
2339 | ||
2340 | /* Situation */ | |
2341 | if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)) | |
2342 | impossible(); | |
2343 | ||
2344 | /* AH proposal */ | |
2345 | if (ah_seen) | |
2346 | echo_proposal(ah_proposal | |
2347 | , ah_trans | |
2348 | , esp_seen || ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE | |
2349 | , r_sa_pbs | |
2350 | , &st->st_ah | |
2351 | , &isakmp_ah_transform_desc | |
2352 | , &ah_trans_pbs | |
2353 | , &st->st_connection->spd | |
2354 | , tunnel_mode && inner_proto == IPPROTO_AH); | |
2355 | ||
2356 | /* ESP proposal */ | |
2357 | if (esp_seen) | |
2358 | echo_proposal(esp_proposal | |
2359 | , esp_trans | |
2360 | , ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE | |
2361 | , r_sa_pbs | |
2362 | , &st->st_esp | |
2363 | , &isakmp_esp_transform_desc | |
2364 | , &esp_trans_pbs | |
2365 | , &st->st_connection->spd | |
2366 | , tunnel_mode && inner_proto == IPPROTO_ESP); | |
2367 | ||
2368 | /* IPCOMP proposal */ | |
2369 | if (ipcomp_seen) | |
2370 | echo_proposal(ipcomp_proposal | |
2371 | , ipcomp_trans | |
2372 | , ISAKMP_NEXT_NONE | |
2373 | , r_sa_pbs | |
2374 | , &st->st_ipcomp | |
2375 | , &isakmp_ipcomp_transform_desc | |
2376 | , &ipcomp_trans_pbs | |
2377 | , &st->st_connection->spd | |
2378 | , tunnel_mode && inner_proto == IPPROTO_COMP); | |
2379 | ||
2380 | close_output_pbs(r_sa_pbs); | |
2381 | } | |
2382 | ||
2383 | /* save decoded version of winning SA in state */ | |
2384 | ||
2385 | st->st_ah.present = ah_seen; | |
2386 | if (ah_seen) | |
2387 | st->st_ah.attrs = ah_attrs; | |
2388 | ||
2389 | st->st_esp.present = esp_seen; | |
2390 | if (esp_seen) | |
2391 | st->st_esp.attrs = esp_attrs; | |
2392 | ||
2393 | st->st_ipcomp.present = ipcomp_seen; | |
2394 | if (ipcomp_seen) | |
2395 | st->st_ipcomp.attrs = ipcomp_attrs; | |
2396 | ||
2397 | return NOTHING_WRONG; | |
2398 | } | |
2399 | ||
2400 | loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA"); | |
2401 | return NO_PROPOSAL_CHOSEN; | |
2402 | } |