The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ip/esp.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Encapsulating Security Payload for IPsec for IPv4, rfc1827.
    3  *      currently only implements tunnel mode.
    4  * TODO: update to match rfc4303.
    5  */
    6 #include        "u.h"
    7 #include        "../port/lib.h"
    8 #include        "mem.h"
    9 #include        "dat.h"
   10 #include        "fns.h"
   11 #include        "../port/error.h"
   12 
   13 #include        "ip.h"
   14 #include        "ipv6.h"
   15 #include        "libsec.h"
   16 
   17 typedef struct Esphdr Esphdr;
   18 typedef struct Esp4hdr Esp4hdr;
   19 typedef struct Esp6hdr Esp6hdr;
   20 typedef struct Esptail Esptail;
   21 typedef struct Userhdr Userhdr;
   22 typedef struct Esppriv Esppriv;
   23 typedef struct Espcb Espcb;
   24 typedef struct Algorithm Algorithm;
   25 
   26 enum
   27 {
   28         IP_ESPPROTO     = 50,   /* IP v4 and v6 protocol number */
   29         Esp4hdrlen      = IP4HDR + 8,
   30         Esp6hdrlen      = IP6HDR + 8,
   31 
   32         Esptaillen      = 2,    /* does not include pad or auth data */
   33         Userhdrlen      = 4,    /* user-visible header size - if enabled */
   34 };
   35 
   36 struct Esphdr
   37 {
   38         uchar   espspi[4];      /* Security parameter index */
   39         uchar   espseq[4];      /* Sequence number */
   40 };
   41 
   42 /*
   43  * tunnel-mode layout:          IP | ESP | TCP/UDP | user data.
   44  * transport-mode layout is:    ESP | IP | TCP/UDP | user data.
   45  */
   46 struct Esp4hdr
   47 {
   48         /* ipv4 header */
   49         uchar   vihl;           /* Version and header length */
   50         uchar   tos;            /* Type of service */
   51         uchar   length[2];      /* packet length */
   52         uchar   id[2];          /* Identification */
   53         uchar   frag[2];        /* Fragment information */
   54         uchar   Unused;
   55         uchar   espproto;       /* Protocol */
   56         uchar   espplen[2];     /* Header plus data length */
   57         uchar   espsrc[4];      /* Ip source */
   58         uchar   espdst[4];      /* Ip destination */
   59 
   60         Esphdr;
   61 };
   62 
   63 /* tunnel-mode layout */
   64 struct Esp6hdr
   65 {
   66         Ip6hdr;
   67         Esphdr;
   68 };
   69 
   70 struct Esptail
   71 {
   72         uchar   pad;
   73         uchar   nexthdr;
   74 };
   75 
   76 /* header as seen by the user */
   77 struct Userhdr
   78 {
   79         uchar   nexthdr;        /* next protocol */
   80         uchar   unused[3];
   81 };
   82 
   83 struct Esppriv
   84 {
   85         ulong   in;
   86         ulong   inerrors;
   87 };
   88 
   89 /*
   90  *  protocol specific part of Conv
   91  */
   92 struct Espcb
   93 {
   94         int     incoming;
   95         int     header;         /* user user level header */
   96         ulong   spi;
   97         ulong   seq;            /* last seq sent */
   98         ulong   window;         /* for replay attacks */
   99         char    *espalg;
  100         void    *espstate;      /* other state for esp */
  101         int     espivlen;       /* in bytes */
  102         int     espblklen;
  103         int     (*cipher)(Espcb*, uchar *buf, int len);
  104         char    *ahalg;
  105         void    *ahstate;       /* other state for esp */
  106         int     ahlen;          /* auth data length in bytes */
  107         int     ahblklen;
  108         int     (*auth)(Espcb*, uchar *buf, int len, uchar *hash);
  109 };
  110 
  111 struct Algorithm
  112 {
  113         char    *name;
  114         int     keylen;         /* in bits */
  115         void    (*init)(Espcb*, char* name, uchar *key, int keylen);
  116 };
  117 
  118 static  Conv* convlookup(Proto *esp, ulong spi);
  119 static  char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg);
  120 static  void espkick(void *x);
  121 
  122 static  void nullespinit(Espcb*, char*, uchar *key, int keylen);
  123 static  void desespinit(Espcb *ecb, char *name, uchar *k, int n);
  124 
  125 static  void nullahinit(Espcb*, char*, uchar *key, int keylen);
  126 static  void shaahinit(Espcb*, char*, uchar *key, int keylen);
  127 static  void md5ahinit(Espcb*, char*, uchar *key, int keylen);
  128 
  129 static Algorithm espalg[] =
  130 {
  131         "null",                 0,      nullespinit,
  132 //      "des3_cbc",             192,    des3espinit,    /* rfc2451 */
  133 //      "aes_128_cbc",          128,    aescbcespinit,  /* rfc3602 */
  134 //      "aes_ctr",              128,    aesctrespinit,  /* rfc3686 */
  135         "des_56_cbc",           64,     desespinit,     /* rfc2405, deprecated */
  136 //      "rc4_128",              128,    rc4espinit,     /* gone in rfc4305 */
  137         nil,                    0,      nil,
  138 };
  139 
  140 static Algorithm ahalg[] =
  141 {
  142         "null",                 0,      nullahinit,
  143         "hmac_sha1_96",         128,    shaahinit,      /* rfc2404 */
  144 //      "aes_xcbc_mac_96",      128,    aesahinit,      /* rfc3566 */
  145         "hmac_md5_96",          128,    md5ahinit,      /* rfc2403 */
  146         nil,                    0,      nil,
  147 };
  148 
  149 static char*
  150 espconnect(Conv *c, char **argv, int argc)
  151 {
  152         char *p, *pp;
  153         char *e = nil;
  154         ulong spi;
  155         Espcb *ecb = (Espcb*)c->ptcl;
  156 
  157         switch(argc) {
  158         default:
  159                 e = "bad args to connect";
  160                 break;
  161         case 2:
  162                 p = strchr(argv[1], '!');
  163                 if(p == nil){
  164                         e = "malformed address";
  165                         break;
  166                 }
  167                 *p++ = 0;
  168                 parseip(c->raddr, argv[1]);
  169                 findlocalip(c->p->f, c->laddr, c->raddr);
  170                 ecb->incoming = 0;
  171                 ecb->seq = 0;
  172                 if(strcmp(p, "*") == 0) {
  173                         qlock(c->p);
  174                         for(;;) {
  175                                 spi = nrand(1<<16) + 256;
  176                                 if(convlookup(c->p, spi) == nil)
  177                                         break;
  178                         }
  179                         qunlock(c->p);
  180                         ecb->spi = spi;
  181                         ecb->incoming = 1;
  182                         qhangup(c->wq, nil);
  183                 } else {
  184                         spi = strtoul(p, &pp, 10);
  185                         if(pp == p) {
  186                                 e = "malformed address";
  187                                 break;
  188                         }
  189                         ecb->spi = spi;
  190                         qhangup(c->rq, nil);
  191                 }
  192                 nullespinit(ecb, "null", nil, 0);
  193                 nullahinit(ecb, "null", nil, 0);
  194         }
  195         Fsconnected(c, e);
  196 
  197         return e;
  198 }
  199 
  200 
  201 static int
  202 espstate(Conv *c, char *state, int n)
  203 {
  204         return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n");
  205 }
  206 
  207 static void
  208 espcreate(Conv *c)
  209 {
  210         c->rq = qopen(64*1024, Qmsg, 0, 0);
  211         c->wq = qopen(64*1024, Qkick, espkick, c);
  212 }
  213 
  214 static void
  215 espclose(Conv *c)
  216 {
  217         Espcb *ecb;
  218 
  219         qclose(c->rq);
  220         qclose(c->wq);
  221         qclose(c->eq);
  222         ipmove(c->laddr, IPnoaddr);
  223         ipmove(c->raddr, IPnoaddr);
  224 
  225         ecb = (Espcb*)c->ptcl;
  226         free(ecb->espstate);
  227         free(ecb->ahstate);
  228         memset(ecb, 0, sizeof(Espcb));
  229 }
  230 
  231 static int
  232 ipvers(Conv *c)
  233 {
  234         if((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
  235             memcmp(c->laddr, v4prefix, IPv4off) == 0) ||
  236             ipcmp(c->raddr, IPnoaddr) == 0)
  237                 return V4;
  238         else
  239                 return V6;
  240 }
  241 
  242 static void
  243 espkick(void *x)
  244 {
  245         Conv *c = x;
  246         Esp4hdr *eh4;
  247         Esp6hdr *eh6;
  248         Esptail *et;
  249         Userhdr *uh;
  250         Espcb *ecb;
  251         Block *bp;
  252         int nexthdr, payload, pad, align, version, hdrlen, iphdrlen;
  253         uchar *auth;
  254 
  255         version = ipvers(c);
  256         iphdrlen = version == V4? IP4HDR: IP6HDR;
  257         hdrlen =   version == V4? Esp4hdrlen: Esp6hdrlen;
  258 
  259         bp = qget(c->wq);
  260         if(bp == nil)
  261                 return;
  262 
  263         qlock(c);
  264         ecb = c->ptcl;
  265 
  266         if(ecb->header) {
  267                 /* make sure the message has a User header */
  268                 bp = pullupblock(bp, Userhdrlen);
  269                 if(bp == nil) {
  270                         qunlock(c);
  271                         return;
  272                 }
  273                 uh = (Userhdr*)bp->rp;
  274                 nexthdr = uh->nexthdr;
  275                 bp->rp += Userhdrlen;
  276         } else {
  277                 nexthdr = 0;    /* what should this be? */
  278         }
  279 
  280         payload = BLEN(bp) + ecb->espivlen;
  281 
  282         /* Make space to fit ip header */
  283         bp = padblock(bp, hdrlen + ecb->espivlen);
  284 
  285         align = 4;
  286         if(ecb->espblklen > align)
  287                 align = ecb->espblklen;
  288         if(align % ecb->ahblklen != 0)
  289                 panic("espkick: ahblklen is important after all");
  290         pad = (align-1) - (payload + Esptaillen-1)%align;
  291 
  292         /*
  293          * Make space for tail
  294          * this is done by calling padblock with a negative size
  295          * Padblock does not change bp->wp!
  296          */
  297         bp = padblock(bp, -(pad+Esptaillen+ecb->ahlen));
  298         bp->wp += pad+Esptaillen+ecb->ahlen;
  299 
  300         eh4 = (Esp4hdr *)bp->rp;
  301         eh6 = (Esp6hdr *)bp->rp;
  302         et = (Esptail*)(bp->rp + hdrlen + payload + pad);
  303 
  304         /* fill in tail */
  305         et->pad = pad;
  306         et->nexthdr = nexthdr;
  307 
  308         ecb->cipher(ecb, bp->rp + hdrlen, payload + pad + Esptaillen);
  309         auth = bp->rp + hdrlen + payload + pad + Esptaillen;
  310 
  311         /* fill in head */
  312         if (version == V4) {
  313                 eh4->vihl = IP_VER4;
  314                 hnputl(eh4->espspi, ecb->spi);
  315                 hnputl(eh4->espseq, ++ecb->seq);
  316                 v6tov4(eh4->espsrc, c->laddr);
  317                 v6tov4(eh4->espdst, c->raddr);
  318                 eh4->espproto = IP_ESPPROTO;
  319                 eh4->frag[0] = 0;
  320                 eh4->frag[1] = 0;
  321         } else {
  322                 eh6->vcf[0] = IP_VER6;
  323                 hnputl(eh6->espspi, ecb->spi);
  324                 hnputl(eh6->espseq, ++ecb->seq);
  325                 ipmove(eh6->src, c->laddr);
  326                 ipmove(eh6->dst, c->raddr);
  327                 eh6->proto = IP_ESPPROTO;
  328         }
  329 
  330         ecb->auth(ecb, bp->rp + iphdrlen, (hdrlen - iphdrlen) +
  331                 payload + pad + Esptaillen, auth);
  332 
  333         qunlock(c);
  334         /* print("esp: pass down: %uld\n", BLEN(bp)); */
  335         if (version == V4)
  336                 ipoput4(c->p->f, bp, 0, c->ttl, c->tos, c);
  337         else
  338                 ipoput6(c->p->f, bp, 0, c->ttl, c->tos, c);
  339 }
  340 
  341 void
  342 espiput(Proto *esp, Ipifc*, Block *bp)
  343 {
  344         Esp4hdr *eh4;
  345         Esp6hdr *eh6;
  346         Esptail *et;
  347         Userhdr *uh;
  348         Conv *c;
  349         Espcb *ecb;
  350         uchar raddr[IPaddrlen], laddr[IPaddrlen];
  351         Fs *f;
  352         uchar *auth, *espspi;
  353         ulong spi;
  354         int payload, nexthdr, version, hdrlen;
  355 
  356         f = esp->f;
  357         if (bp == nil || BLEN(bp) == 0) {
  358                 /* get enough to identify the IP version */
  359                 bp = pullupblock(bp, IP4HDR);
  360                 if(bp == nil) {
  361                         netlog(f, Logesp, "esp: short packet\n");
  362                         return;
  363                 }
  364         }
  365         eh4 = (Esp4hdr*)bp->rp;
  366         version = ((eh4->vihl & 0xf0) == IP_VER4? V4: V6);
  367         hdrlen = version == V4? Esp4hdrlen: Esp6hdrlen;
  368 
  369         bp = pullupblock(bp, hdrlen + Esptaillen);
  370         if(bp == nil) {
  371                 netlog(f, Logesp, "esp: short packet\n");
  372                 return;
  373         }
  374 
  375         if (version == V4) {
  376                 eh4 = (Esp4hdr*)bp->rp;
  377                 spi = nhgetl(eh4->espspi);
  378                 v4tov6(raddr, eh4->espsrc);
  379                 v4tov6(laddr, eh4->espdst);
  380         } else {
  381                 eh6 = (Esp6hdr*)bp->rp;
  382                 spi = nhgetl(eh6->espspi);
  383                 ipmove(raddr, eh6->src);
  384                 ipmove(laddr, eh6->dst);
  385         }
  386 
  387         qlock(esp);
  388         /* Look for a conversation structure for this port */
  389         c = convlookup(esp, spi);
  390         if(c == nil) {
  391                 qunlock(esp);
  392                 netlog(f, Logesp, "esp: no conv %I -> %I!%d\n", raddr,
  393                         laddr, spi);
  394                 icmpnoconv(f, bp);
  395                 freeblist(bp);
  396                 return;
  397         }
  398 
  399         qlock(c);
  400         qunlock(esp);
  401 
  402         ecb = c->ptcl;
  403         /* too hard to do decryption/authentication on block lists */
  404         if(bp->next)
  405                 bp = concatblock(bp);
  406 
  407         if(BLEN(bp) < hdrlen + ecb->espivlen + Esptaillen + ecb->ahlen) {
  408                 qunlock(c);
  409                 netlog(f, Logesp, "esp: short block %I -> %I!%d\n", raddr,
  410                         laddr, spi);
  411                 freeb(bp);
  412                 return;
  413         }
  414 
  415         auth = bp->wp - ecb->ahlen;
  416         espspi = version == V4? ((Esp4hdr*)bp->rp)->espspi:
  417                                 ((Esp6hdr*)bp->rp)->espspi;
  418         if(!ecb->auth(ecb, espspi, auth - espspi, auth)) {
  419                 qunlock(c);
  420 print("esp: bad auth %I -> %I!%ld\n", raddr, laddr, spi);
  421                 netlog(f, Logesp, "esp: bad auth %I -> %I!%d\n", raddr,
  422                         laddr, spi);
  423                 freeb(bp);
  424                 return;
  425         }
  426 
  427         payload = BLEN(bp) - hdrlen - ecb->ahlen;
  428         if(payload <= 0 || payload % 4 != 0 || payload % ecb->espblklen != 0) {
  429                 qunlock(c);
  430                 netlog(f, Logesp, "esp: bad length %I -> %I!%d payload=%d BLEN=%d\n",
  431                         raddr, laddr, spi, payload, BLEN(bp));
  432                 freeb(bp);
  433                 return;
  434         }
  435         if(!ecb->cipher(ecb, bp->rp + hdrlen, payload)) {
  436                 qunlock(c);
  437 print("esp: cipher failed %I -> %I!%ld: %s\n", raddr, laddr, spi, up->errstr);
  438                 netlog(f, Logesp, "esp: cipher failed %I -> %I!%d: %s\n", raddr,
  439                         laddr, spi, up->errstr);
  440                 freeb(bp);
  441                 return;
  442         }
  443 
  444         payload -= Esptaillen;
  445         et = (Esptail*)(bp->rp + hdrlen + payload);
  446         payload -= et->pad + ecb->espivlen;
  447         nexthdr = et->nexthdr;
  448         if(payload <= 0) {
  449                 qunlock(c);
  450                 netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%d\n",
  451                         raddr, laddr, spi);
  452                 freeb(bp);
  453                 return;
  454         }
  455 
  456         /* trim packet */
  457         bp->rp += hdrlen + ecb->espivlen;
  458         bp->wp = bp->rp + payload;
  459         if(ecb->header) {
  460                 /* assume Userhdrlen < Esp4hdrlen < Esp6hdrlen */
  461                 bp->rp -= Userhdrlen;
  462                 uh = (Userhdr*)bp->rp;
  463                 memset(uh, 0, Userhdrlen);
  464                 uh->nexthdr = nexthdr;
  465         }
  466 
  467         if(qfull(c->rq)){
  468                 netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", raddr,
  469                         laddr, spi);
  470                 freeblist(bp);
  471         }else {
  472 //              print("esp: pass up: %uld\n", BLEN(bp));
  473                 qpass(c->rq, bp);
  474         }
  475 
  476         qunlock(c);
  477 }
  478 
  479 char*
  480 espctl(Conv *c, char **f, int n)
  481 {
  482         Espcb *ecb = c->ptcl;
  483         char *e = nil;
  484 
  485         if(strcmp(f[0], "esp") == 0)
  486                 e = setalg(ecb, f, n, espalg);
  487         else if(strcmp(f[0], "ah") == 0)
  488                 e = setalg(ecb, f, n, ahalg);
  489         else if(strcmp(f[0], "header") == 0)
  490                 ecb->header = 1;
  491         else if(strcmp(f[0], "noheader") == 0)
  492                 ecb->header = 0;
  493         else
  494                 e = "unknown control request";
  495         return e;
  496 }
  497 
  498 void
  499 espadvise(Proto *esp, Block *bp, char *msg)
  500 {
  501         Esp4hdr *h;
  502         Conv *c;
  503         ulong spi;
  504 
  505         h = (Esp4hdr*)(bp->rp);
  506 
  507         spi = nhgets(h->espspi);
  508         qlock(esp);
  509         c = convlookup(esp, spi);
  510         if(c != nil) {
  511                 qhangup(c->rq, msg);
  512                 qhangup(c->wq, msg);
  513         }
  514         qunlock(esp);
  515         freeblist(bp);
  516 }
  517 
  518 int
  519 espstats(Proto *esp, char *buf, int len)
  520 {
  521         Esppriv *upriv;
  522 
  523         upriv = esp->priv;
  524         return snprint(buf, len, "%lud %lud\n",
  525                 upriv->in,
  526                 upriv->inerrors);
  527 }
  528 
  529 static int
  530 esplocal(Conv *c, char *buf, int len)
  531 {
  532         Espcb *ecb = c->ptcl;
  533         int n;
  534 
  535         qlock(c);
  536         if(ecb->incoming)
  537                 n = snprint(buf, len, "%I!%uld\n", c->laddr, ecb->spi);
  538         else
  539                 n = snprint(buf, len, "%I\n", c->laddr);
  540         qunlock(c);
  541         return n;
  542 }
  543 
  544 static int
  545 espremote(Conv *c, char *buf, int len)
  546 {
  547         Espcb *ecb = c->ptcl;
  548         int n;
  549 
  550         qlock(c);
  551         if(ecb->incoming)
  552                 n = snprint(buf, len, "%I\n", c->raddr);
  553         else
  554                 n = snprint(buf, len, "%I!%uld\n", c->raddr, ecb->spi);
  555         qunlock(c);
  556         return n;
  557 }
  558 
  559 static  Conv*
  560 convlookup(Proto *esp, ulong spi)
  561 {
  562         Conv *c, **p;
  563         Espcb *ecb;
  564 
  565         for(p=esp->conv; *p; p++){
  566                 c = *p;
  567                 ecb = c->ptcl;
  568                 if(ecb->incoming && ecb->spi == spi)
  569                         return c;
  570         }
  571         return nil;
  572 }
  573 
  574 static char *
  575 setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
  576 {
  577         uchar *key;
  578         int c, i, nbyte, nchar;
  579 
  580         if(n < 2)
  581                 return "bad format";
  582         for(; alg->name; alg++)
  583                 if(strcmp(f[1], alg->name) == 0)
  584                         break;
  585         if(alg->name == nil)
  586                 return "unknown algorithm";
  587 
  588         if(n != 3)
  589                 return "bad format";
  590         nbyte = (alg->keylen + 7) >> 3;
  591         nchar = strlen(f[2]);
  592         for(i=0; i<nchar; i++) {
  593                 c = f[2][i];
  594                 if(c >= '' && c <= '9')
  595                         f[2][i] -= '';
  596                 else if(c >= 'a' && c <= 'f')
  597                         f[2][i] -= 'a'-10;
  598                 else if(c >= 'A' && c <= 'F')
  599                         f[2][i] -= 'A'-10;
  600                 else
  601                         return "bad character in key";
  602         }
  603         key = smalloc(nbyte);
  604         for(i=0; i<nchar && i*2<nbyte; i++) {
  605                 c = f[2][nchar-i-1];
  606                 if(i&1)
  607                         c <<= 4;
  608                 key[i>>1] |= c;
  609         }
  610 
  611         alg->init(ecb, alg->name, key, alg->keylen);
  612         free(key);
  613         return nil;
  614 }
  615 
  616 static int
  617 nullcipher(Espcb*, uchar*, int)
  618 {
  619         return 1;
  620 }
  621 
  622 static void
  623 nullespinit(Espcb *ecb, char *name, uchar*, int)
  624 {
  625         ecb->espalg = name;
  626         ecb->espblklen = 1;
  627         ecb->espivlen = 0;
  628         ecb->cipher = nullcipher;
  629 }
  630 
  631 static int
  632 nullauth(Espcb*, uchar*, int, uchar*)
  633 {
  634         return 1;
  635 }
  636 
  637 static void
  638 nullahinit(Espcb *ecb, char *name, uchar*, int)
  639 {
  640         ecb->ahalg = name;
  641         ecb->ahblklen = 1;
  642         ecb->ahlen = 0;
  643         ecb->auth = nullauth;
  644 }
  645 
  646 void
  647 seanq_hmac_sha1(uchar hash[SHA1dlen], uchar *t, long tlen, uchar *key, long klen)
  648 {
  649         uchar ipad[65], opad[65];
  650         int i;
  651         DigestState *digest;
  652         uchar innerhash[SHA1dlen];
  653 
  654         for(i=0; i<64; i++){
  655                 ipad[i] = 0x36;
  656                 opad[i] = 0x5c;
  657         }
  658         ipad[64] = opad[64] = 0;
  659         for(i=0; i<klen; i++){
  660                 ipad[i] ^= key[i];
  661                 opad[i] ^= key[i];
  662         }
  663         digest = sha1(ipad, 64, nil, nil);
  664         sha1(t, tlen, innerhash, digest);
  665         digest = sha1(opad, 64, nil, nil);
  666         sha1(innerhash, SHA1dlen, hash, digest);
  667 }
  668 
  669 static int
  670 shaauth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
  671 {
  672         uchar hash[SHA1dlen];
  673         int r;
  674 
  675         memset(hash, 0, SHA1dlen);
  676         seanq_hmac_sha1(hash, t, tlen, (uchar*)ecb->ahstate, 16);
  677         r = memcmp(auth, hash, ecb->ahlen) == 0;
  678         memmove(auth, hash, ecb->ahlen);
  679         return r;
  680 }
  681 
  682 static void
  683 shaahinit(Espcb *ecb, char *name, uchar *key, int klen)
  684 {
  685         if(klen != 128)
  686                 panic("shaahinit: bad keylen");
  687         klen >>= 8;             /* convert to bytes */
  688 
  689         ecb->ahalg = name;
  690         ecb->ahblklen = 1;
  691         ecb->ahlen = 12;
  692         ecb->auth = shaauth;
  693         ecb->ahstate = smalloc(klen);
  694         memmove(ecb->ahstate, key, klen);
  695 }
  696 
  697 void
  698 seanq_hmac_md5(uchar hash[MD5dlen], uchar *t, long tlen, uchar *key, long klen)
  699 {
  700         uchar ipad[65], opad[65];
  701         int i;
  702         DigestState *digest;
  703         uchar innerhash[MD5dlen];
  704 
  705         for(i=0; i<64; i++){
  706                 ipad[i] = 0x36;
  707                 opad[i] = 0x5c;
  708         }
  709         ipad[64] = opad[64] = 0;
  710         for(i=0; i<klen; i++){
  711                 ipad[i] ^= key[i];
  712                 opad[i] ^= key[i];
  713         }
  714         digest = md5(ipad, 64, nil, nil);
  715         md5(t, tlen, innerhash, digest);
  716         digest = md5(opad, 64, nil, nil);
  717         md5(innerhash, MD5dlen, hash, digest);
  718 }
  719 
  720 static int
  721 md5auth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
  722 {
  723         uchar hash[MD5dlen];
  724         int r;
  725 
  726         memset(hash, 0, MD5dlen);
  727         seanq_hmac_md5(hash, t, tlen, (uchar*)ecb->ahstate, 16);
  728         r = memcmp(auth, hash, ecb->ahlen) == 0;
  729         memmove(auth, hash, ecb->ahlen);
  730         return r;
  731 }
  732 
  733 static void
  734 md5ahinit(Espcb *ecb, char *name, uchar *key, int klen)
  735 {
  736         if(klen != 128)
  737                 panic("md5ahinit: bad keylen");
  738         klen >>= 3;             /* convert to bytes */
  739 
  740         ecb->ahalg = name;
  741         ecb->ahblklen = 1;
  742         ecb->ahlen = 12;
  743         ecb->auth = md5auth;
  744         ecb->ahstate = smalloc(klen);
  745         memmove(ecb->ahstate, key, klen);
  746 }
  747 
  748 static int
  749 descipher(Espcb *ecb, uchar *p, int n)
  750 {
  751         uchar tmp[8];
  752         uchar *pp, *tp, *ip, *eip, *ep;
  753         DESstate *ds = ecb->espstate;
  754 
  755         ep = p + n;
  756         if(ecb->incoming) {
  757                 memmove(ds->ivec, p, 8);
  758                 p += 8;
  759                 while(p < ep){
  760                         memmove(tmp, p, 8);
  761                         block_cipher(ds->expanded, p, 1);
  762                         tp = tmp;
  763                         ip = ds->ivec;
  764                         for(eip = ip+8; ip < eip; ){
  765                                 *p++ ^= *ip;
  766                                 *ip++ = *tp++;
  767                         }
  768                 }
  769         } else {
  770                 memmove(p, ds->ivec, 8);
  771                 for(p += 8; p < ep; p += 8){
  772                         pp = p;
  773                         ip = ds->ivec;
  774                         for(eip = ip+8; ip < eip; )
  775                                 *pp++ ^= *ip++;
  776                         block_cipher(ds->expanded, p, 0);
  777                         memmove(ds->ivec, p, 8);
  778                 }
  779         }
  780         return 1;
  781 }
  782 
  783 static void
  784 desespinit(Espcb *ecb, char *name, uchar *k, int n)
  785 {
  786         uchar key[8], ivec[8];
  787         int i;
  788 
  789         /* bits to bytes */
  790         n = (n+7)>>3;
  791         if(n > 8)
  792                 n = 8;
  793         memset(key, 0, sizeof(key));
  794         memmove(key, k, n);
  795         for(i=0; i<8; i++)
  796                 ivec[i] = nrand(256);
  797         ecb->espalg = name;
  798         ecb->espblklen = 8;
  799         ecb->espivlen = 8;
  800         ecb->cipher = descipher;
  801         ecb->espstate = smalloc(sizeof(DESstate));
  802         setupDESstate(ecb->espstate, key, ivec);
  803 }
  804 
  805 void
  806 espinit(Fs *fs)
  807 {
  808         Proto *esp;
  809 
  810         esp = smalloc(sizeof(Proto));
  811         esp->priv = smalloc(sizeof(Esppriv));
  812         esp->name = "esp";
  813         esp->connect = espconnect;
  814         esp->announce = nil;
  815         esp->ctl = espctl;
  816         esp->state = espstate;
  817         esp->create = espcreate;
  818         esp->close = espclose;
  819         esp->rcv = espiput;
  820         esp->advise = espadvise;
  821         esp->stats = espstats;
  822         esp->local = esplocal;
  823         esp->remote = espremote;
  824         esp->ipproto = IP_ESPPROTO;
  825         esp->nc = Nchans;
  826         esp->ptclsize = sizeof(Espcb);
  827 
  828         Fsproto(fs, esp);
  829 }
  830 
  831 
  832 #ifdef notdef
  833 enum {
  834         RC4forward= 10*1024*1024,       /* maximum skip forward */
  835         RC4back = 100*1024,     /* maximum look back */
  836 };
  837 
  838 typedef struct Esprc4 Esprc4;
  839 struct Esprc4
  840 {
  841         ulong   cseq;           /* current byte sequence number */
  842         RC4state current;
  843 
  844         int     ovalid;         /* old is valid */
  845         ulong   lgseq;          /* last good sequence */
  846         ulong   oseq;           /* old byte sequence number */
  847         RC4state old;
  848 };
  849 
  850 static void rc4espinit(Espcb *ecb, char *name, uchar *k, int n);
  851 
  852 static int
  853 rc4cipher(Espcb *ecb, uchar *p, int n)
  854 {
  855         Esprc4 *esprc4;
  856         RC4state tmpstate;
  857         ulong seq;
  858         long d, dd;
  859 
  860         if(n < 4)
  861                 return 0;
  862 
  863         esprc4 = ecb->espstate;
  864         if(ecb->incoming) {
  865                 seq = nhgetl(p);
  866                 p += 4;
  867                 n -= 4;
  868                 d = seq-esprc4->cseq;
  869                 if(d == 0) {
  870                         rc4(&esprc4->current, p, n);
  871                         esprc4->cseq += n;
  872                         if(esprc4->ovalid) {
  873                                 dd = esprc4->cseq - esprc4->lgseq;
  874                                 if(dd > RC4back)
  875                                         esprc4->ovalid = 0;
  876                         }
  877                 } else if(d > 0) {
  878 print("esp rc4cipher: missing packet: %uld %ld\n", seq, d); /* this link is hosed */
  879                         if(d > RC4forward) {
  880                                 strcpy(up->errstr, "rc4cipher: skipped too much");
  881                                 return 0;
  882                         }
  883                         esprc4->lgseq = seq;
  884                         if(!esprc4->ovalid) {
  885                                 esprc4->ovalid = 1;
  886                                 esprc4->oseq = esprc4->cseq;
  887                                 memmove(&esprc4->old, &esprc4->current,
  888                                         sizeof(RC4state));
  889                         }
  890                         rc4skip(&esprc4->current, d);
  891                         rc4(&esprc4->current, p, n);
  892                         esprc4->cseq = seq+n;
  893                 } else {
  894 print("esp rc4cipher: reordered packet: %uld %ld\n", seq, d);
  895                         dd = seq - esprc4->oseq;
  896                         if(!esprc4->ovalid || -d > RC4back || dd < 0) {
  897                                 strcpy(up->errstr, "rc4cipher: too far back");
  898                                 return 0;
  899                         }
  900                         memmove(&tmpstate, &esprc4->old, sizeof(RC4state));
  901                         rc4skip(&tmpstate, dd);
  902                         rc4(&tmpstate, p, n);
  903                         return 1;
  904                 }
  905 
  906                 /* move old state up */
  907                 if(esprc4->ovalid) {
  908                         dd = esprc4->cseq - RC4back - esprc4->oseq;
  909                         if(dd > 0) {
  910                                 rc4skip(&esprc4->old, dd);
  911                                 esprc4->oseq += dd;
  912                         }
  913                 }
  914         } else {
  915                 hnputl(p, esprc4->cseq);
  916                 p += 4;
  917                 n -= 4;
  918                 rc4(&esprc4->current, p, n);
  919                 esprc4->cseq += n;
  920         }
  921         return 1;
  922 }
  923 
  924 static void
  925 rc4espinit(Espcb *ecb, char *name, uchar *k, int n)
  926 {
  927         Esprc4 *esprc4;
  928 
  929         /* bits to bytes */
  930         n = (n+7)>>3;
  931         esprc4 = smalloc(sizeof(Esprc4));
  932         memset(esprc4, 0, sizeof(Esprc4));
  933         setupRC4state(&esprc4->current, k, n);
  934         ecb->espalg = name;
  935         ecb->espblklen = 4;
  936         ecb->espivlen = 4;
  937         ecb->cipher = rc4cipher;
  938         ecb->espstate = esprc4;
  939 }
  940 #endif

Cache object: 9b69777e37c49d33f6894ae5a166e5cc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.