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