source: rtems-libbsd/ipsec-tools/src/racoon/proposal.c @ ff36f5e

5-freebsd-12
Last change on this file since ff36f5e was ff36f5e, checked in by Christian Mauderer <christian.mauderer@…>, on May 30, 2018 at 12:27:35 PM

Import ipsec-tools 0.8.2.

Import unchanged ipsec-tools sources in the release version 0.8.2. The
homepage of ipsec-tools is http://ipsec-tools.sourceforge.net/. The
sources can be obtained from there.

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