1 /* $NetBSD: proposal.c,v 1.18 2025/03/07 15:55:29 christos Exp $ */
2
3 /* $Id: proposal.c,v 1.18 2025/03/07 15:55:29 christos Exp $ */
4
5 /*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * 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 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "config.h"
35
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
40
41 #include <netinet/in.h>
42 #include PATH_IPSEC_H
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <errno.h>
48
49 #include "var.h"
50 #include "misc.h"
51 #include "vmbuf.h"
52 #include "plog.h"
53 #include "sockmisc.h"
54 #include "debug.h"
55
56 #include "policy.h"
57 #include "pfkey.h"
58 #include "isakmp_var.h"
59 #include "isakmp.h"
60 #include "ipsec_doi.h"
61 #include "algorithm.h"
62 #include "proposal.h"
63 #include "sainfo.h"
64 #include "localconf.h"
65 #include "remoteconf.h"
66 #include "oakley.h"
67 #include "handler.h"
68 #include "strnames.h"
69 #include "gcmalloc.h"
70 #ifdef ENABLE_NATT
71 #include "nattraversal.h"
72 #endif
73
74 static uint g_nextreqid = 1;
75
76 /* %%%
77 * modules for ipsec sa spec
78 */
79 struct saprop *
newsaprop()80 newsaprop()
81 {
82 struct saprop *new;
83
84 new = racoon_calloc(1, sizeof(*new));
85 if (new == NULL)
86 return NULL;
87
88 return new;
89 }
90
91 struct saproto *
newsaproto()92 newsaproto()
93 {
94 struct saproto *new;
95
96 new = racoon_calloc(1, sizeof(*new));
97 if (new == NULL)
98 return NULL;
99
100 return new;
101 }
102
103 /* set saprop to last part of the prop tree */
104 void
inssaprop(struct saprop ** head,struct saprop * new)105 inssaprop(struct saprop **head, struct saprop *new)
106 {
107 struct saprop *p;
108
109 if (*head == NULL) {
110 *head = new;
111 return;
112 }
113
114 for (p = *head; p->next; p = p->next)
115 ;
116 p->next = new;
117
118 return;
119 }
120
121 /* set saproto to the end of the proto tree in saprop */
122 void
inssaproto(struct saprop * pp,struct saproto * new)123 inssaproto(struct saprop *pp, struct saproto *new)
124 {
125 struct saproto *p;
126
127 for (p = pp->head; p && p->next; p = p->next)
128 ;
129 if (p == NULL)
130 pp->head = new;
131 else
132 p->next = new;
133
134 return;
135 }
136
137 /* set saproto to the top of the proto tree in saprop */
138 void
inssaprotorev(struct saprop * pp,struct saproto * new)139 inssaprotorev(struct saprop *pp, struct saproto *new)
140 {
141 new->next = pp->head;
142 pp->head = new;
143
144 return;
145 }
146
147 struct satrns *
newsatrns(void)148 newsatrns(void)
149 {
150 struct satrns *new;
151
152 new = racoon_calloc(1, sizeof(*new));
153 if (new == NULL)
154 return NULL;
155
156 return new;
157 }
158
159 /* set saproto to last part of the proto tree in saprop */
160 void
inssatrns(struct saproto * pr,struct satrns * new)161 inssatrns(struct saproto *pr, struct satrns *new)
162 {
163 struct satrns *tr;
164
165 for (tr = pr->head; tr && tr->next; tr = tr->next)
166 ;
167 if (tr == NULL)
168 pr->head = new;
169 else
170 tr->next = new;
171
172 return;
173 }
174
175 /*
176 * take a single match between saprop. allocate a new proposal and return it
177 * for future use (like picking single proposal from a bundle).
178 * pp1: peer's proposal.
179 * pp2: my proposal.
180 * NOTE: In the case of initiator, must be ensured that there is no
181 * modification of the proposal by calling cmp_aproppair_i() before
182 * this function.
183 * XXX cannot understand the comment!
184 */
185 struct saprop *
cmpsaprop_alloc(struct ph1handle * ph1,const struct saprop * pp1,const struct saprop * pp2,int side)186 cmpsaprop_alloc(struct ph1handle *ph1,
187 const struct saprop *pp1,
188 const struct saprop *pp2,
189 int side)
190 {
191 struct saprop *newpp = NULL;
192 struct saproto *pr1, *pr2, *newpr = NULL;
193 struct satrns *tr1, *tr2, *newtr;
194 const int ordermatters = 0;
195 int npr1, npr2;
196 int spisizematch;
197
198 newpp = newsaprop();
199 if (newpp == NULL) {
200 plog(LLV_ERROR, LOCATION, NULL,
201 "failed to allocate saprop.\n");
202 return NULL;
203 }
204 newpp->prop_no = pp1->prop_no;
205
206 /* see proposal.h about lifetime/key length and PFS selection. */
207
208 /* check time/bytes lifetime and PFS */
209 switch (ph1->rmconf->pcheck_level) {
210 case PROP_CHECK_OBEY:
211 newpp->lifetime = pp1->lifetime;
212 newpp->lifebyte = pp1->lifebyte;
213 newpp->pfs_group = pp1->pfs_group;
214 break;
215
216 case PROP_CHECK_STRICT:
217 if (pp1->lifetime > pp2->lifetime) {
218 plog(LLV_ERROR, LOCATION, NULL,
219 "long lifetime proposed: "
220 "my:%d peer:%d\n",
221 (int)pp2->lifetime, (int)pp1->lifetime);
222 goto err;
223 }
224 if (pp1->lifebyte > pp2->lifebyte) {
225 plog(LLV_ERROR, LOCATION, NULL,
226 "long lifebyte proposed: "
227 "my:%d peer:%d\n",
228 pp2->lifebyte, pp1->lifebyte);
229 goto err;
230 }
231 newpp->lifetime = pp1->lifetime;
232 newpp->lifebyte = pp1->lifebyte;
233
234 prop_pfs_check:
235 if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) {
236 plog(LLV_ERROR, LOCATION, NULL,
237 "pfs group mismatched: "
238 "my:%d peer:%d\n",
239 pp2->pfs_group, pp1->pfs_group);
240 goto err;
241 }
242 newpp->pfs_group = pp1->pfs_group;
243 break;
244
245 case PROP_CHECK_CLAIM:
246 /* lifetime */
247 if (pp1->lifetime <= pp2->lifetime) {
248 newpp->lifetime = pp1->lifetime;
249 } else {
250 newpp->lifetime = pp2->lifetime;
251 newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
252 plog(LLV_NOTIFY, LOCATION, NULL,
253 "use own lifetime: "
254 "my:%d peer:%d\n",
255 (int)pp2->lifetime, (int)pp1->lifetime);
256 }
257
258 /* lifebyte */
259 if (pp1->lifebyte > pp2->lifebyte) {
260 newpp->lifebyte = pp2->lifebyte;
261 newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
262 plog(LLV_NOTIFY, LOCATION, NULL,
263 "use own lifebyte: "
264 "my:%d peer:%d\n",
265 pp2->lifebyte, pp1->lifebyte);
266 }
267 newpp->lifebyte = pp1->lifebyte;
268
269 goto prop_pfs_check;
270
271 case PROP_CHECK_EXACT:
272 if (pp1->lifetime != pp2->lifetime) {
273 plog(LLV_ERROR, LOCATION, NULL,
274 "lifetime mismatched: "
275 "my:%d peer:%d\n",
276 (int)pp2->lifetime, (int)pp1->lifetime);
277 goto err;
278 }
279
280 if (pp1->lifebyte != pp2->lifebyte) {
281 plog(LLV_ERROR, LOCATION, NULL,
282 "lifebyte mismatched: "
283 "my:%d peer:%d\n",
284 pp2->lifebyte, pp1->lifebyte);
285 goto err;
286 }
287 if (pp1->pfs_group != pp2->pfs_group) {
288 plog(LLV_ERROR, LOCATION, NULL,
289 "pfs group mismatched: "
290 "my:%d peer:%d\n",
291 pp2->pfs_group, pp1->pfs_group);
292 goto err;
293 }
294 newpp->lifetime = pp1->lifetime;
295 newpp->lifebyte = pp1->lifebyte;
296 newpp->pfs_group = pp1->pfs_group;
297 break;
298
299 default:
300 plog(LLV_ERROR, LOCATION, NULL,
301 "invalid pcheck_level why?.\n");
302 goto err;
303 }
304
305 #ifdef HAVE_SECCTX
306 /* check the security_context properties.
307 * It is possible for one side to have a security context
308 * and the other side doesn't. If so, this is an error.
309 */
310
311 if (*pp1->sctx.ctx_str && !(*pp2->sctx.ctx_str)) {
312 plog(LLV_ERROR, LOCATION, NULL,
313 "My proposal missing security context\n");
314 goto err;
315 }
316 if (!(*pp1->sctx.ctx_str) && *pp2->sctx.ctx_str) {
317 plog(LLV_ERROR, LOCATION, NULL,
318 "Peer is missing security context\n");
319 goto err;
320 }
321
322 if (*pp1->sctx.ctx_str && *pp2->sctx.ctx_str) {
323 if (pp1->sctx.ctx_doi == pp2->sctx.ctx_doi)
324 newpp->sctx.ctx_doi = pp1->sctx.ctx_doi;
325 else {
326 plog(LLV_ERROR, LOCATION, NULL,
327 "sec doi mismatched: my:%d peer:%d\n",
328 pp2->sctx.ctx_doi, pp1->sctx.ctx_doi);
329 goto err;
330 }
331
332 if (pp1->sctx.ctx_alg == pp2->sctx.ctx_alg)
333 newpp->sctx.ctx_alg = pp1->sctx.ctx_alg;
334 else {
335 plog(LLV_ERROR, LOCATION, NULL,
336 "sec alg mismatched: my:%d peer:%d\n",
337 pp2->sctx.ctx_alg, pp1->sctx.ctx_alg);
338 goto err;
339 }
340
341 if ((pp1->sctx.ctx_strlen != pp2->sctx.ctx_strlen) ||
342 memcmp(pp1->sctx.ctx_str, pp2->sctx.ctx_str,
343 pp1->sctx.ctx_strlen) != 0) {
344 plog(LLV_ERROR, LOCATION, NULL,
345 "sec ctx string mismatched: my:%s peer:%s\n",
346 pp2->sctx.ctx_str, pp1->sctx.ctx_str);
347 goto err;
348 } else {
349 newpp->sctx.ctx_strlen = pp1->sctx.ctx_strlen;
350 memcpy(newpp->sctx.ctx_str, pp1->sctx.ctx_str,
351 pp1->sctx.ctx_strlen);
352 }
353 }
354 #endif /* HAVE_SECCTX */
355
356 npr1 = npr2 = 0;
357 for (pr1 = pp1->head; pr1; pr1 = pr1->next)
358 npr1++;
359 for (pr2 = pp2->head; pr2; pr2 = pr2->next)
360 npr2++;
361 if (npr1 != npr2)
362 goto err;
363
364 /* check protocol order */
365 pr1 = pp1->head;
366 pr2 = pp2->head;
367
368 for (;;) {
369 if (!ordermatters) {
370 /*
371 * XXX does not work if we have multiple proposals
372 * with the same proto_id
373 */
374 switch (side) {
375 case RESPONDER:
376 if (!pr2)
377 break;
378 for (pr1 = pp1->head; pr1; pr1 = pr1->next) {
379 if (pr1->proto_id == pr2->proto_id)
380 break;
381 }
382 break;
383 case INITIATOR:
384 if (!pr1)
385 break;
386 for (pr2 = pp2->head; pr2; pr2 = pr2->next) {
387 if (pr2->proto_id == pr1->proto_id)
388 break;
389 }
390 break;
391 }
392 }
393 if (!pr1 || !pr2)
394 break;
395
396 if (pr1->proto_id != pr2->proto_id) {
397 plog(LLV_ERROR, LOCATION, NULL,
398 "proto_id mismatched: "
399 "my:%s peer:%s\n",
400 s_ipsecdoi_proto(pr2->proto_id),
401 s_ipsecdoi_proto(pr1->proto_id));
402 goto err;
403 }
404 spisizematch = 0;
405 if (pr1->spisize == pr2->spisize)
406 spisizematch = 1;
407 else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) {
408 /*
409 * draft-shacham-ippcp-rfc2393bis-05.txt:
410 * need to accept 16bit and 32bit SPI (CPI) for IPComp.
411 */
412 if (pr1->spisize == sizeof(uint16_t) &&
413 pr2->spisize == sizeof(uint32_t)) {
414 spisizematch = 1;
415 } else if (pr2->spisize == sizeof(uint16_t) &&
416 pr1->spisize == sizeof(uint32_t)) {
417 spisizematch = 1;
418 }
419 if (spisizematch) {
420 plog(LLV_ERROR, LOCATION, NULL,
421 "IPComp SPI size promoted "
422 "from 16bit to 32bit\n");
423 }
424 }
425 if (!spisizematch) {
426 plog(LLV_ERROR, LOCATION, NULL,
427 "spisize mismatched: "
428 "my:%d peer:%d\n",
429 (int)pr2->spisize, (int)pr1->spisize);
430 goto err;
431 }
432
433 #ifdef ENABLE_NATT
434 if ((ph1->natt_flags & NAT_DETECTED) &&
435 natt_udp_encap (pr2->encmode))
436 {
437 plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n",
438 s_ipsecdoi_encmode(pr2->encmode),
439 s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff));
440 pr2->encmode -= ph1->natt_options->mode_udp_diff;
441 pr2->udp_encap = 1;
442 }
443
444 if ((ph1->natt_flags & NAT_DETECTED) &&
445 natt_udp_encap (pr1->encmode))
446 {
447 plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
448 s_ipsecdoi_encmode(pr1->encmode),
449 pr1->encmode,
450 s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff),
451 pr1->encmode - ph1->natt_options->mode_udp_diff);
452 pr1->encmode -= ph1->natt_options->mode_udp_diff;
453 pr1->udp_encap = 1;
454 }
455 #endif
456
457 if (pr1->encmode != pr2->encmode) {
458 plog(LLV_ERROR, LOCATION, NULL,
459 "encmode mismatched: "
460 "my:%s peer:%s\n",
461 s_ipsecdoi_encmode(pr2->encmode),
462 s_ipsecdoi_encmode(pr1->encmode));
463 goto err;
464 }
465
466 for (tr1 = pr1->head; tr1; tr1 = tr1->next) {
467 for (tr2 = pr2->head; tr2; tr2 = tr2->next) {
468 if (cmpsatrns(pr1->proto_id, tr1, tr2, ph1->rmconf->pcheck_level) == 0)
469 goto found;
470 }
471 }
472
473 goto err;
474
475 found:
476 newpr = newsaproto();
477 if (newpr == NULL) {
478 plog(LLV_ERROR, LOCATION, NULL,
479 "failed to allocate saproto.\n");
480 goto err;
481 }
482 newpr->proto_id = pr1->proto_id;
483 newpr->spisize = pr1->spisize;
484 newpr->encmode = pr1->encmode;
485 newpr->spi = pr2->spi; /* copy my SPI */
486 newpr->spi_p = pr1->spi; /* copy peer's SPI */
487 newpr->reqid_in = pr2->reqid_in;
488 newpr->reqid_out = pr2->reqid_out;
489 #ifdef ENABLE_NATT
490 newpr->udp_encap = pr1->udp_encap | pr2->udp_encap;
491 #endif
492
493 newtr = newsatrns();
494 if (newtr == NULL) {
495 plog(LLV_ERROR, LOCATION, NULL,
496 "failed to allocate satrns.\n");
497 racoon_free(newpr);
498 goto err;
499 }
500 newtr->trns_no = tr1->trns_no;
501 newtr->trns_id = tr1->trns_id;
502 newtr->encklen = tr1->encklen;
503 newtr->authtype = tr1->authtype;
504
505 inssatrns(newpr, newtr);
506 inssaproto(newpp, newpr);
507
508 pr1 = pr1->next;
509 pr2 = pr2->next;
510 }
511
512 /* XXX should check if we have visited all items or not */
513 if (!ordermatters) {
514 switch (side) {
515 case RESPONDER:
516 if (!pr2)
517 pr1 = NULL;
518 break;
519 case INITIATOR:
520 if (!pr1)
521 pr2 = NULL;
522 break;
523 }
524 }
525
526 /* should be matched all protocols in a proposal */
527 if (pr1 != NULL || pr2 != NULL)
528 goto err;
529
530 return newpp;
531
532 err:
533 flushsaprop(newpp);
534 return NULL;
535 }
536
537 /* take a single match between saprop. returns 0 if pp1 equals to pp2. */
538 int
cmpsaprop(const struct saprop * pp1,const struct saprop * pp2)539 cmpsaprop(const struct saprop *pp1, const struct saprop *pp2)
540 {
541 if (pp1->pfs_group != pp2->pfs_group) {
542 plog(LLV_WARNING, LOCATION, NULL,
543 "pfs_group mismatch. mine:%d peer:%d\n",
544 pp1->pfs_group, pp2->pfs_group);
545 /* FALLTHRU */
546 }
547
548 if (pp1->lifetime > pp2->lifetime) {
549 plog(LLV_WARNING, LOCATION, NULL,
550 "less lifetime proposed. mine:%d peer:%d\n",
551 (int)pp1->lifetime, (int)pp2->lifetime);
552 /* FALLTHRU */
553 }
554 if (pp1->lifebyte > pp2->lifebyte) {
555 plog(LLV_WARNING, LOCATION, NULL,
556 "less lifebyte proposed. mine:%d peer:%d\n",
557 pp1->lifebyte, pp2->lifebyte);
558 /* FALLTHRU */
559 }
560
561 return 0;
562 }
563
564 /*
565 * take a single match between satrns. returns 0 if tr1 equals to tr2.
566 * tr1: peer's satrns
567 * tr2: my satrns
568 */
569 int
cmpsatrns(int proto_id,const struct satrns * tr1,const struct satrns * tr2,int check_level)570 cmpsatrns(
571 int proto_id,
572 const struct satrns *tr1,
573 const struct satrns *tr2,
574 int check_level)
575 {
576 if (tr1->trns_id != tr2->trns_id) {
577 plog(LLV_WARNING, LOCATION, NULL,
578 "trns_id mismatched: "
579 "my:%s peer:%s\n",
580 s_ipsecdoi_trns(proto_id, tr2->trns_id),
581 s_ipsecdoi_trns(proto_id, tr1->trns_id));
582 return 1;
583 }
584
585 if (tr1->authtype != tr2->authtype) {
586 plog(LLV_WARNING, LOCATION, NULL,
587 "authtype mismatched: "
588 "my:%s peer:%s\n",
589 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype),
590 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype));
591 return 1;
592 }
593
594 /* Check key length regarding checkmode
595 * XXX Shall we send some kind of notify message when key length rejected ?
596 */
597 switch(check_level){
598 case PROP_CHECK_OBEY:
599 return 0;
600
601 case PROP_CHECK_STRICT:
602 /* FALLTHROUGH */
603 case PROP_CHECK_CLAIM:
604 if (tr1->encklen < tr2->encklen) {
605 plog(LLV_WARNING, LOCATION, NULL,
606 "low key length proposed, "
607 "mine:%d peer:%d.\n",
608 tr2->encklen, tr1->encklen);
609 return 1;
610 }
611 break;
612 case PROP_CHECK_EXACT:
613 if (tr1->encklen != tr2->encklen) {
614 plog(LLV_WARNING, LOCATION, NULL,
615 "key length mismatched, "
616 "mine:%d peer:%d.\n",
617 tr2->encklen, tr1->encklen);
618 return 1;
619 }
620 break;
621 }
622
623 return 0;
624 }
625
626 int
set_satrnsbysainfo(struct saproto * pr,struct sainfo * sainfo)627 set_satrnsbysainfo(struct saproto *pr, struct sainfo *sainfo)
628 {
629 struct sainfoalg *a, *b;
630 struct satrns *newtr;
631 int t;
632
633 switch (pr->proto_id) {
634 case IPSECDOI_PROTO_IPSEC_AH:
635 if (sainfo->algs[algclass_ipsec_auth] == NULL) {
636 plog(LLV_ERROR, LOCATION, NULL,
637 "no auth algorithm found\n");
638 goto err;
639 }
640 t = 1;
641 for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) {
642
643 if (a->alg == IPSECDOI_ATTR_AUTH_NONE)
644 continue;
645
646 /* allocate satrns */
647 newtr = newsatrns();
648 if (newtr == NULL) {
649 plog(LLV_ERROR, LOCATION, NULL,
650 "failed to allocate satrns.\n");
651 goto err;
652 }
653
654 newtr->trns_no = t++;
655 newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg);
656 newtr->authtype = a->alg;
657
658 inssatrns(pr, newtr);
659 }
660 break;
661 case IPSECDOI_PROTO_IPSEC_ESP:
662 if (sainfo->algs[algclass_ipsec_enc] == NULL) {
663 plog(LLV_ERROR, LOCATION, NULL,
664 "no encryption algorithm found\n");
665 goto err;
666 }
667 t = 1;
668 for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) {
669 for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) {
670 /* allocate satrns */
671 newtr = newsatrns();
672 if (newtr == NULL) {
673 plog(LLV_ERROR, LOCATION, NULL,
674 "failed to allocate satrns.\n");
675 goto err;
676 }
677
678 newtr->trns_no = t++;
679 newtr->trns_id = a->alg;
680 newtr->encklen = a->encklen;
681 newtr->authtype = b->alg;
682
683 inssatrns(pr, newtr);
684 }
685 }
686 break;
687 case IPSECDOI_PROTO_IPCOMP:
688 if (sainfo->algs[algclass_ipsec_comp] == NULL) {
689 plog(LLV_ERROR, LOCATION, NULL,
690 "no ipcomp algorithm found\n");
691 goto err;
692 }
693 t = 1;
694 for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) {
695
696 /* allocate satrns */
697 newtr = newsatrns();
698 if (newtr == NULL) {
699 plog(LLV_ERROR, LOCATION, NULL,
700 "failed to allocate satrns.\n");
701 goto err;
702 }
703
704 newtr->trns_no = t++;
705 newtr->trns_id = a->alg;
706 newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/
707
708 inssatrns(pr, newtr);
709 }
710 break;
711 default:
712 plog(LLV_ERROR, LOCATION, NULL,
713 "unknown proto_id (%d).\n", pr->proto_id);
714 goto err;
715 }
716
717 /* no proposal found */
718 if (pr->head == NULL) {
719 plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n");
720 return -1;
721 }
722
723 return 0;
724
725 err:
726 flushsatrns(pr->head);
727 return -1;
728 }
729
730 struct saprop *
aproppair2saprop(struct prop_pair * p0)731 aproppair2saprop(struct prop_pair *p0)
732 {
733 struct prop_pair *p, *t;
734 struct saprop *newpp;
735 struct saproto *newpr;
736 struct satrns *newtr;
737 uint8_t *spi;
738
739 if (p0 == NULL)
740 return NULL;
741
742 /* allocate ipsec a sa proposal */
743 newpp = newsaprop();
744 if (newpp == NULL) {
745 plog(LLV_ERROR, LOCATION, NULL,
746 "failed to allocate saprop.\n");
747 return NULL;
748 }
749 newpp->prop_no = p0->prop->p_no;
750 /* lifetime & lifebyte must be updated later */
751
752 for (p = p0; p; p = p->next) {
753
754 /* allocate ipsec sa protocol */
755 newpr = newsaproto();
756 if (newpr == NULL) {
757 plog(LLV_ERROR, LOCATION, NULL,
758 "failed to allocate saproto.\n");
759 goto err;
760 }
761
762 /* check spi size */
763 /* XXX should be handled isakmp cookie */
764 if (sizeof(newpr->spi) < p->prop->spi_size) {
765 plog(LLV_ERROR, LOCATION, NULL,
766 "invalid spi size %d.\n", p->prop->spi_size);
767 racoon_free(newpr);
768 goto err;
769 }
770
771 /*
772 * XXX SPI bits are left-filled, for use with IPComp.
773 * we should be switching to variable-length spi field...
774 */
775 newpr->proto_id = p->prop->proto_id;
776 newpr->spisize = p->prop->spi_size;
777 memset(&newpr->spi, 0, sizeof(newpr->spi));
778 spi = (uint8_t *)&newpr->spi;
779 spi += sizeof(newpr->spi);
780 spi -= p->prop->spi_size;
781 memcpy(spi, p->prop + 1, p->prop->spi_size);
782 newpr->reqid_in = 0;
783 newpr->reqid_out = 0;
784
785 for (t = p; t; t = t->tnext) {
786
787 plog(LLV_DEBUG, LOCATION, NULL,
788 "prop#=%d prot-id=%s spi-size=%d "
789 "#trns=%d trns#=%d trns-id=%s\n",
790 t->prop->p_no,
791 s_ipsecdoi_proto(t->prop->proto_id),
792 t->prop->spi_size, t->prop->num_t,
793 t->trns->t_no,
794 s_ipsecdoi_trns(t->prop->proto_id,
795 t->trns->t_id));
796
797 /* allocate ipsec sa transform */
798 newtr = newsatrns();
799 if (newtr == NULL) {
800 plog(LLV_ERROR, LOCATION, NULL,
801 "failed to allocate satrns.\n");
802 racoon_free(newpr);
803 goto err;
804 }
805
806 if (ipsecdoi_t2satrns(t->trns,
807 newpp, newpr, newtr) < 0) {
808 flushsaprop(newpp);
809 racoon_free(newtr);
810 racoon_free(newpr);
811 return NULL;
812 }
813
814 inssatrns(newpr, newtr);
815 }
816
817 /*
818 * If the peer does not specify encryption mode, use
819 * transport mode by default. This is to conform to
820 * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies
821 * that unspecified == transport), as well as RFC2407
822 * (unspecified == implementation dependent default).
823 */
824 if (newpr->encmode == 0)
825 newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
826
827 inssaproto(newpp, newpr);
828 }
829
830 return newpp;
831
832 err:
833 flushsaprop(newpp);
834 return NULL;
835 }
836
837 void
flushsaprop(struct saprop * head)838 flushsaprop(struct saprop *head)
839 {
840 struct saprop *p, *save;
841
842 for (p = head; p != NULL; p = save) {
843 save = p->next;
844 flushsaproto(p->head);
845 racoon_free(p);
846 }
847
848 return;
849 }
850
851 void
flushsaproto(struct saproto * head)852 flushsaproto(struct saproto *head)
853 {
854 struct saproto *p, *save;
855
856 for (p = head; p != NULL; p = save) {
857 save = p->next;
858 flushsatrns(p->head);
859 vfree(p->keymat);
860 vfree(p->keymat_p);
861 racoon_free(p);
862 }
863
864 return;
865 }
866
867 void
flushsatrns(struct satrns * head)868 flushsatrns(struct satrns *head)
869 {
870 struct satrns *p, *save;
871
872 for (p = head; p != NULL; p = save) {
873 save = p->next;
874 racoon_free(p);
875 }
876
877 return;
878 }
879
880 /*
881 * print multiple proposals
882 */
883 void
printsaprop(const int pri,const struct saprop * pp)884 printsaprop(const int pri, const struct saprop *pp)
885 {
886 const struct saprop *p;
887
888 if (pp == NULL) {
889 plog(pri, LOCATION, NULL, "(null)");
890 return;
891 }
892
893 for (p = pp; p; p = p->next) {
894 printsaprop0(pri, p);
895 }
896
897 return;
898 }
899
900 /*
901 * print one proposal.
902 */
903 void
printsaprop0(int pri,const struct saprop * pp)904 printsaprop0(int pri, const struct saprop *pp)
905 {
906 const struct saproto *p;
907
908 if (pp == NULL)
909 return;
910
911 for (p = pp->head; p; p = p->next) {
912 printsaproto(pri, p);
913 }
914
915 return;
916 }
917
918 void
printsaproto(const int pri,const struct saproto * pr)919 printsaproto(const int pri, const struct saproto *pr)
920 {
921 struct satrns *tr;
922
923 if (pr == NULL)
924 return;
925
926 plog(pri, LOCATION, NULL,
927 " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx "
928 "encmode=%s reqid=%d:%d)\n",
929 s_ipsecdoi_proto(pr->proto_id),
930 (int)pr->spisize,
931 (unsigned long)ntohl(pr->spi),
932 (unsigned long)ntohl(pr->spi_p),
933 s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode),
934 (int)pr->reqid_in, (int)pr->reqid_out);
935
936 for (tr = pr->head; tr; tr = tr->next) {
937 printsatrns(pri, pr->proto_id, tr);
938 }
939
940 return;
941 }
942
943 void
printsatrns(const int pri,const int proto_id,const struct satrns * tr)944 printsatrns(const int pri, const int proto_id, const struct satrns *tr)
945 {
946 if (tr == NULL)
947 return;
948
949 switch (proto_id) {
950 case IPSECDOI_PROTO_IPSEC_AH:
951 plog(pri, LOCATION, NULL,
952 " (trns_id=%s authtype=%s)\n",
953 s_ipsecdoi_trns(proto_id, tr->trns_id),
954 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
955 break;
956 case IPSECDOI_PROTO_IPSEC_ESP:
957 plog(pri, LOCATION, NULL,
958 " (trns_id=%s encklen=%d authtype=%s)\n",
959 s_ipsecdoi_trns(proto_id, tr->trns_id),
960 tr->encklen,
961 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
962 break;
963 case IPSECDOI_PROTO_IPCOMP:
964 plog(pri, LOCATION, NULL,
965 " (trns_id=%s)\n",
966 s_ipsecdoi_trns(proto_id, tr->trns_id));
967 break;
968 default:
969 plog(pri, LOCATION, NULL,
970 "(unknown proto_id %d)\n", proto_id);
971 }
972
973 return;
974 }
975
976 void
print_proppair0(int pri,struct prop_pair * p,int level)977 print_proppair0(int pri, struct prop_pair *p, int level)
978 {
979 char spc[21];
980
981 memset(spc, ' ', sizeof(spc));
982 spc[sizeof(spc) - 1] = '\0';
983 if (level < 20) {
984 spc[level] = '\0';
985 }
986
987 plog(pri, LOCATION, NULL,
988 "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext);
989 if (p->next)
990 print_proppair0(pri, p->next, level + 1);
991 if (p->tnext)
992 print_proppair0(pri, p->tnext, level + 1);
993 }
994
995 void
print_proppair(int pri,struct prop_pair * p)996 print_proppair(int pri, struct prop_pair *p)
997 {
998 print_proppair0(pri, p, 1);
999 }
1000
1001 int
set_proposal_from_policy(struct ph2handle * iph2,struct secpolicy * sp_main,struct secpolicy * sp_sub)1002 set_proposal_from_policy(struct ph2handle *iph2,
1003 struct secpolicy *sp_main,
1004 struct secpolicy *sp_sub)
1005 {
1006 struct saprop *newpp;
1007 struct ipsecrequest *req;
1008 int encmodesv = IPSECDOI_ATTR_ENC_MODE_TRNS; /* use only when complex_bundle */
1009
1010 newpp = newsaprop();
1011 if (newpp == NULL) {
1012 plog(LLV_ERROR, LOCATION, NULL,
1013 "failed to allocate saprop.\n");
1014 goto err;
1015 }
1016 newpp->prop_no = 1;
1017 newpp->lifetime = iph2->sainfo->lifetime;
1018 newpp->lifebyte = iph2->sainfo->lifebyte;
1019 newpp->pfs_group = iph2->sainfo->pfs_group;
1020
1021 if (lcconf->complex_bundle)
1022 goto skip1;
1023
1024 /*
1025 * decide the encryption mode of this SA bundle.
1026 * the mode becomes tunnel mode when there is even one policy
1027 * of tunnel mode in the SPD. otherwise the mode becomes
1028 * transport mode.
1029 */
1030 for (req = sp_main->req; req; req = req->next) {
1031 if (req->saidx.mode == IPSEC_MODE_TUNNEL) {
1032 encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode);
1033 #ifdef ENABLE_NATT
1034 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1035 encmodesv += iph2->ph1->natt_options->mode_udp_diff;
1036 #endif
1037 break;
1038 }
1039 }
1040
1041 skip1:
1042 for (req = sp_main->req; req; req = req->next) {
1043 struct saproto *newpr;
1044
1045 /*
1046 * check if SA bundle ?
1047 * nested SAs negotiation is NOT supported.
1048 * me +--- SA1 ---+ peer1
1049 * me +--- SA2 --------------+ peer2
1050 */
1051 /* allocate ipsec sa protocol */
1052 newpr = newsaproto();
1053 if (newpr == NULL) {
1054 plog(LLV_ERROR, LOCATION, NULL,
1055 "failed to allocate saproto.\n");
1056 goto err;
1057 }
1058
1059 newpr->proto_id = ipproto2doi(req->saidx.proto);
1060 if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP)
1061 newpr->spisize = 2;
1062 else
1063 newpr->spisize = 4;
1064 if (lcconf->complex_bundle) {
1065 newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
1066 #ifdef ENABLE_NATT
1067 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1068 newpr->encmode +=
1069 iph2->ph1->natt_options->mode_udp_diff;
1070 #endif
1071 }
1072 else
1073 newpr->encmode = encmodesv;
1074
1075 if (iph2->side == INITIATOR)
1076 newpr->reqid_out = req->saidx.reqid;
1077 else
1078 newpr->reqid_in = req->saidx.reqid;
1079
1080 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
1081 plog(LLV_ERROR, LOCATION, NULL,
1082 "failed to get algorithms.\n");
1083 racoon_free(newpr);
1084 goto err;
1085 }
1086
1087 /* set new saproto */
1088 inssaprotorev(newpp, newpr);
1089 }
1090
1091 /* get reqid_in from inbound policy */
1092 if (sp_sub) {
1093 struct saproto *pr;
1094
1095 req = sp_sub->req;
1096 pr = newpp->head;
1097 while (req && pr) {
1098 if (iph2->side == INITIATOR)
1099 pr->reqid_in = req->saidx.reqid;
1100 else
1101 pr->reqid_out = req->saidx.reqid;
1102 pr = pr->next;
1103 req = req->next;
1104 }
1105 if (pr || req) {
1106 plog(LLV_NOTIFY, LOCATION, NULL,
1107 "There is a difference "
1108 "between the in/out bound policies in SPD.\n");
1109 }
1110 }
1111
1112 iph2->proposal = newpp;
1113
1114 printsaprop0(LLV_DEBUG, newpp);
1115
1116 return 0;
1117 err:
1118 flushsaprop(newpp);
1119 return -1;
1120 }
1121
1122 /*
1123 * generate a policy from peer's proposal.
1124 * this function unconditionally choices first proposal in SA payload
1125 * passed by peer.
1126 */
1127 int
set_proposal_from_proposal(struct ph2handle * iph2)1128 set_proposal_from_proposal(struct ph2handle *iph2)
1129 {
1130 struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
1131 struct saproto *newpr = NULL, *pr;
1132 struct prop_pair **pair;
1133 int error = -1;
1134 int i;
1135
1136 /* get proposal pair */
1137 pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
1138 if (pair == NULL)
1139 goto end;
1140
1141 /*
1142 * make my proposal according as the client proposal.
1143 * XXX assumed there is only one proposal even if it's the SA bundle.
1144 */
1145 for (i = 0; i < MAXPROPPAIRLEN; i++) {
1146 if (pair[i] == NULL)
1147 continue;
1148
1149 if (pp_peer != NULL)
1150 flushsaprop(pp_peer);
1151
1152 pp_peer = aproppair2saprop(pair[i]);
1153 if (pp_peer == NULL)
1154 goto end;
1155
1156 pp0 = newsaprop();
1157 if (pp0 == NULL) {
1158 plog(LLV_ERROR, LOCATION, NULL,
1159 "failed to allocate saprop.\n");
1160 goto end;
1161 }
1162 pp0->prop_no = 1;
1163 pp0->lifetime = iph2->sainfo->lifetime;
1164 pp0->lifebyte = iph2->sainfo->lifebyte;
1165 pp0->pfs_group = iph2->sainfo->pfs_group;
1166
1167 #ifdef HAVE_SECCTX
1168 if (*pp_peer->sctx.ctx_str) {
1169 pp0->sctx.ctx_doi = pp_peer->sctx.ctx_doi;
1170 pp0->sctx.ctx_alg = pp_peer->sctx.ctx_alg;
1171 pp0->sctx.ctx_strlen = pp_peer->sctx.ctx_strlen;
1172 memcpy(pp0->sctx.ctx_str, pp_peer->sctx.ctx_str,
1173 pp_peer->sctx.ctx_strlen);
1174 }
1175 #endif /* HAVE_SECCTX */
1176
1177 if (pp_peer->next != NULL) {
1178 plog(LLV_ERROR, LOCATION, NULL,
1179 "pp_peer is inconsistency, ignore it.\n");
1180 /*FALLTHROUGH*/
1181 }
1182
1183 for (pr = pp_peer->head; pr; pr = pr->next)
1184 {
1185 newpr = newsaproto();
1186 if (newpr == NULL)
1187 {
1188 plog(LLV_ERROR, LOCATION, NULL,
1189 "failed to allocate saproto.\n");
1190 racoon_free(pp0);
1191 goto end;
1192 }
1193 newpr->proto_id = pr->proto_id;
1194 newpr->spisize = pr->spisize;
1195 newpr->encmode = pr->encmode;
1196 newpr->spi = 0;
1197 newpr->spi_p = pr->spi; /* copy peer's SPI */
1198 newpr->reqid_in = 0;
1199 newpr->reqid_out = 0;
1200
1201 if (iph2->ph1->rmconf->gen_policy == GENERATE_POLICY_UNIQUE){
1202 newpr->reqid_in = g_nextreqid ;
1203 newpr->reqid_out = g_nextreqid ++;
1204 /*
1205 * XXX there is a (very limited)
1206 * risk of reusing the same reqid
1207 * as another SP entry for the same peer
1208 */
1209 if(g_nextreqid >= IPSEC_MANUAL_REQID_MAX)
1210 g_nextreqid = 1;
1211 }else{
1212 newpr->reqid_in = 0;
1213 newpr->reqid_out = 0;
1214 }
1215
1216 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0)
1217 {
1218 plog(LLV_ERROR, LOCATION, NULL,
1219 "failed to get algorithms.\n");
1220 racoon_free(newpr);
1221 racoon_free(pp0);
1222 goto end;
1223 }
1224 inssaproto(pp0, newpr);
1225 }
1226
1227 inssaprop(&newpp, pp0);
1228 }
1229
1230 plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n");
1231 printsaprop0(LLV_DEBUG, newpp);
1232
1233 iph2->proposal = newpp;
1234
1235 error = 0;
1236
1237 end:
1238 if (error && newpp)
1239 flushsaprop(newpp);
1240
1241 if (pp_peer)
1242 flushsaprop(pp_peer);
1243 if (pair)
1244 free_proppair(pair);
1245 return error;
1246 }
1247