Merge remote-tracking branch 'origin/vendor/LIBRESSL'
[dragonfly.git] / contrib / tcpdump / print-esp.c
1 /*      $NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $        */
2
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23
24 #ifndef lint
25 static const char rcsid[] _U_ =
26     "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.58 2007-12-07 00:03:07 mcr Exp $ (LBL)";
27 #endif
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <string.h>
34
35 #include <tcpdump-stdinc.h>
36
37 #include <stdlib.h>
38
39 #ifdef HAVE_LIBCRYPTO
40 #ifdef HAVE_OPENSSL_EVP_H
41 #include <openssl/evp.h>
42 #endif
43 #endif
44
45 #include <stdio.h>
46
47 #include "ip.h"
48 #include "esp.h"
49 #ifdef INET6
50 #include "ip6.h"
51 #endif
52
53 #include "netdissect.h"
54 #include "addrtoname.h"
55 #include "extract.h"
56
57 #ifndef HAVE_SOCKADDR_STORAGE
58 #ifdef INET6
59 struct sockaddr_storage {
60         union {
61                 struct sockaddr_in sin;
62                 struct sockaddr_in6 sin6;
63         } un;
64 };
65 #else
66 #define sockaddr_storage sockaddr
67 #endif
68 #endif /* HAVE_SOCKADDR_STORAGE */
69
70 #ifdef HAVE_LIBCRYPTO
71 struct sa_list {
72         struct sa_list  *next;
73         struct sockaddr_storage daddr;
74         u_int32_t       spi;          /* if == 0, then IKEv2 */
75         int             initiator;
76         u_char          spii[8];      /* for IKEv2 */
77         u_char          spir[8];
78         const EVP_CIPHER *evp;
79         int             ivlen;
80         int             authlen;
81         u_char          authsecret[256];
82         int             authsecret_len;
83         u_char          secret[256];  /* is that big enough for all secrets? */
84         int             secretlen;
85 };
86
87 /*
88  * this will adjust ndo_packetp and ndo_snapend to new buffer!
89  */
90 int esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo,
91                                       int initiator,
92                                       u_char spii[8], u_char spir[8],
93                                       u_char *buf, u_char *end)
94 {
95         struct sa_list *sa;
96         u_char *iv;
97         int len;
98         EVP_CIPHER_CTX ctx;
99
100         /* initiator arg is any non-zero value */
101         if(initiator) initiator=1;
102                                        
103         /* see if we can find the SA, and if so, decode it */
104         for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
105                 if (sa->spi == 0
106                     && initiator == sa->initiator
107                     && memcmp(spii, sa->spii, 8) == 0
108                     && memcmp(spir, sa->spir, 8) == 0)
109                         break;
110         }
111
112         if(sa == NULL) return 0;
113         if(sa->evp == NULL) return 0;
114
115         /*
116          * remove authenticator, and see if we still have something to
117          * work with
118          */
119         end = end - sa->authlen;
120         iv  = buf;
121         buf = buf + sa->ivlen;
122         len = end-buf;
123
124         if(end <= buf) return 0;
125
126         memset(&ctx, 0, sizeof(ctx));
127         if (EVP_CipherInit(&ctx, sa->evp, sa->secret, NULL, 0) < 0)
128                 (*ndo->ndo_warning)(ndo, "espkey init failed");
129         EVP_CipherInit(&ctx, NULL, NULL, iv, 0);
130         EVP_Cipher(&ctx, buf, buf, len);
131         EVP_CIPHER_CTX_cleanup(&ctx);
132
133         ndo->ndo_packetp = buf;
134         ndo->ndo_snapend = end;
135
136         return 1;
137         
138 }
139
140 static void esp_print_addsa(netdissect_options *ndo,
141                             struct sa_list *sa, int sa_def)
142 {
143         /* copy the "sa" */
144
145         struct sa_list *nsa;
146
147         nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
148         if (nsa == NULL)
149                 (*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure");
150
151         *nsa = *sa;
152
153         if (sa_def)
154                 ndo->ndo_sa_default = nsa;
155
156         nsa->next = ndo->ndo_sa_list_head;
157         ndo->ndo_sa_list_head = nsa;
158 }
159
160
161 static u_int hexdigit(netdissect_options *ndo, char hex)
162 {
163         if (hex >= '0' && hex <= '9')
164                 return (hex - '0');
165         else if (hex >= 'A' && hex <= 'F')
166                 return (hex - 'A' + 10);
167         else if (hex >= 'a' && hex <= 'f')
168                 return (hex - 'a' + 10);
169         else {
170                 (*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex);
171                 return 0;
172         }
173 }
174
175 static u_int hex2byte(netdissect_options *ndo, char *hexstring)
176 {
177         u_int byte;
178
179         byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]);
180         return byte;
181 }
182
183 /*
184  * returns size of binary, 0 on failure.
185  */
186 static
187 int espprint_decode_hex(netdissect_options *ndo,
188                         u_char *binbuf, unsigned int binbuf_len,
189                         char *hex)
190 {
191         unsigned int len;
192         int i;
193
194         len = strlen(hex) / 2;
195                 
196         if (len > binbuf_len) {
197                 (*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len);
198                 return 0;
199         }
200                 
201         i = 0;
202         while (hex[0] != '\0' && hex[1]!='\0') {
203                 binbuf[i] = hex2byte(ndo, hex);
204                 hex += 2;
205                 i++;
206         }
207
208         return i;
209 }
210
211 /*
212  * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
213  */
214
215 static int
216 espprint_decode_encalgo(netdissect_options *ndo,
217                         char *decode, struct sa_list *sa)
218 {
219         int len;
220         size_t i;
221         const EVP_CIPHER *evp;
222         int authlen = 0;
223         char *colon, *p;
224         
225         colon = strchr(decode, ':');
226         if (colon == NULL) {
227                 (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
228                 return 0;
229         }
230         *colon = '\0';
231         
232         len = colon - decode;
233         if (strlen(decode) > strlen("-hmac96") &&
234             !strcmp(decode + strlen(decode) - strlen("-hmac96"),
235                     "-hmac96")) {
236                 p = strstr(decode, "-hmac96");
237                 *p = '\0';
238                 authlen = 12;
239         }
240         if (strlen(decode) > strlen("-cbc") &&
241             !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
242                 p = strstr(decode, "-cbc");
243                 *p = '\0';
244         }
245         evp = EVP_get_cipherbyname(decode);
246
247         if (!evp) {
248                 (*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode);
249                 sa->evp = NULL;
250                 sa->authlen = 0;
251                 sa->ivlen = 0;
252                 return 0;
253         }
254         
255         sa->evp = evp;
256         sa->authlen = authlen;
257         sa->ivlen = EVP_CIPHER_iv_length(evp);
258         
259         colon++;
260         if (colon[0] == '0' && colon[1] == 'x') {
261                 /* decode some hex! */
262
263                 colon += 2;
264                 sa->secretlen = espprint_decode_hex(ndo, sa->secret, sizeof(sa->secret), colon);
265                 if(sa->secretlen == 0) return 0;
266         } else {
267                 i = strlen(colon);
268                 
269                 if (i < sizeof(sa->secret)) {
270                         memcpy(sa->secret, colon, i);
271                         sa->secretlen = i;
272                 } else {
273                         memcpy(sa->secret, colon, sizeof(sa->secret));
274                         sa->secretlen = sizeof(sa->secret);
275                 }
276         }
277
278         return 1;
279 }
280
281 /*
282  * for the moment, ignore the auth algorith, just hard code the authenticator
283  * length. Need to research how openssl looks up HMAC stuff.
284  */
285 static int
286 espprint_decode_authalgo(netdissect_options *ndo,
287                          char *decode, struct sa_list *sa)
288 {
289         char *colon;
290
291         colon = strchr(decode, ':');
292         if (colon == NULL) {
293                 (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
294                 return 0;
295         }
296         *colon = '\0';
297         
298         if(strcasecmp(colon,"sha1") == 0 ||
299            strcasecmp(colon,"md5") == 0) {
300                 sa->authlen = 12;
301         }
302         return 1;
303 }
304
305 static void esp_print_decode_ikeline(netdissect_options *ndo, char *line,
306                                      const char *file, int lineno)
307 {
308         /* it's an IKEv2 secret, store it instead */
309         struct sa_list sa1;
310
311         char *init;
312         char *icookie, *rcookie;
313         int   ilen, rlen;
314         char *authkey;
315         char *enckey;
316         
317         init = strsep(&line, " \t");
318         icookie = strsep(&line, " \t");
319         rcookie = strsep(&line, " \t");
320         authkey = strsep(&line, " \t");
321         enckey  = strsep(&line, " \t");
322         
323         /* if any fields are missing */
324         if(!init || !icookie || !rcookie || !authkey || !enckey) {
325                 (*ndo->ndo_warning)(ndo, "print_esp: failed to find all fields for ikev2 at %s:%u",
326                                     file, lineno);
327                 
328                 return;
329         }
330         
331         ilen = strlen(icookie);
332         rlen = strlen(rcookie);
333
334         if((init[0]!='I' && init[0]!='R')
335            || icookie[0]!='0' || icookie[1]!='x'
336            || rcookie[0]!='0' || rcookie[1]!='x'
337            || ilen!=18
338            || rlen!=18) {
339                 (*ndo->ndo_warning)(ndo, "print_esp: line %s:%u improperly formatted.",
340                                     file, lineno);
341
342                 (*ndo->ndo_warning)(ndo, "init=%s icookie=%s(%u) rcookie=%s(%u)",
343                                     init, icookie, ilen, rcookie, rlen);
344                 
345                 return;
346         }
347
348         sa1.spi = 0;
349         sa1.initiator = (init[0] == 'I');
350         if(espprint_decode_hex(ndo, sa1.spii, sizeof(sa1.spii), icookie+2)!=8)
351                 return;
352
353         if(espprint_decode_hex(ndo, sa1.spir, sizeof(sa1.spir), rcookie+2)!=8)
354                 return;
355
356         if(!espprint_decode_encalgo(ndo, enckey, &sa1)) return;
357
358         if(!espprint_decode_authalgo(ndo, authkey, &sa1)) return;
359         
360         esp_print_addsa(ndo, &sa1, FALSE);
361 }
362
363 /*
364  *
365  * special form: file /name
366  * causes us to go read from this file instead.
367  *
368  */
369 static void esp_print_decode_onesecret(netdissect_options *ndo, char *line,
370                                        const char *file, int lineno)
371 {
372         struct sa_list sa1;
373         int sa_def;
374
375         char *spikey;
376         char *decode;
377
378         spikey = strsep(&line, " \t");
379         sa_def = 0;
380         memset(&sa1, 0, sizeof(struct sa_list));
381
382         /* if there is only one token, then it is an algo:key token */
383         if (line == NULL) {
384                 decode = spikey;
385                 spikey = NULL;
386                 /* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
387                 /* sa1.spi = 0; */
388                 sa_def    = 1;
389         } else
390                 decode = line;
391
392         if (spikey && strcasecmp(spikey, "file") == 0) {
393                 /* open file and read it */
394                 FILE *secretfile;
395                 char  fileline[1024];
396                 int   lineno=0;
397                 char  *nl;
398                 char *filename = line;
399
400                 secretfile = fopen(filename, FOPEN_READ_TXT);
401                 if (secretfile == NULL) {
402                         perror(filename);
403                         exit(3);
404                 }
405
406                 while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
407                         lineno++;
408                         /* remove newline from the line */
409                         nl = strchr(fileline, '\n');
410                         if (nl)
411                                 *nl = '\0';
412                         if (fileline[0] == '#') continue;
413                         if (fileline[0] == '\0') continue;
414
415                         esp_print_decode_onesecret(ndo, fileline, filename, lineno);
416                 }
417                 fclose(secretfile);
418
419                 return;
420         }
421
422         if (spikey && strcasecmp(spikey, "ikev2") == 0) {
423                 esp_print_decode_ikeline(ndo, line, file, lineno);
424                 return;
425         } 
426
427         if (spikey) {
428                 
429                 char *spistr, *foo;
430                 u_int32_t spino;
431                 struct sockaddr_in *sin;
432 #ifdef INET6
433                 struct sockaddr_in6 *sin6;
434 #endif
435                 
436                 spistr = strsep(&spikey, "@");
437                 
438                 spino = strtoul(spistr, &foo, 0);
439                 if (spistr == foo || !spikey) {
440                         (*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo);
441                         return;
442                 }
443                 
444                 sa1.spi = spino;
445                 
446                 sin = (struct sockaddr_in *)&sa1.daddr;
447 #ifdef INET6
448                 sin6 = (struct sockaddr_in6 *)&sa1.daddr;
449                 if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {
450 #ifdef HAVE_SOCKADDR_SA_LEN
451                         sin6->sin6_len = sizeof(struct sockaddr_in6);
452 #endif
453                         sin6->sin6_family = AF_INET6;
454                 } else
455 #endif
456                         if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {
457 #ifdef HAVE_SOCKADDR_SA_LEN
458                                 sin->sin_len = sizeof(struct sockaddr_in);
459 #endif
460                                 sin->sin_family = AF_INET;
461                         } else {
462                                 (*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey);
463                                 return;
464                         }
465         }
466
467         if (decode) {
468                 /* skip any blank spaces */
469                 while (isspace((unsigned char)*decode))
470                         decode++;
471                 
472                 if(!espprint_decode_encalgo(ndo, decode, &sa1)) {
473                         return;
474                 }
475         }
476
477         esp_print_addsa(ndo, &sa1, sa_def);
478 }
479
480 static void esp_init(netdissect_options *ndo _U_)
481 {
482
483         OpenSSL_add_all_algorithms();
484         EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
485 }
486
487 void esp_print_decodesecret(netdissect_options *ndo)
488 {
489         char *line;
490         char *p;
491         static int initialized = 0;
492
493         if (!initialized) {
494                 esp_init(ndo);
495                 initialized = 1;
496         }
497
498         p = ndo->ndo_espsecret;
499
500         while (p && p[0] != '\0') {
501                 /* pick out the first line or first thing until a comma */
502                 if ((line = strsep(&p, "\n,")) == NULL) {
503                         line = p;
504                         p = NULL;
505                 }
506
507                 esp_print_decode_onesecret(ndo, line, "cmdline", 0);
508         }
509
510         ndo->ndo_espsecret = NULL;
511 }
512
513 #endif
514
515 int
516 esp_print(netdissect_options *ndo,
517           const u_char *bp, const int length, const u_char *bp2
518 #ifndef HAVE_LIBCRYPTO
519         _U_
520 #endif
521         ,
522         int *nhdr
523 #ifndef HAVE_LIBCRYPTO
524         _U_
525 #endif
526         ,
527         int *padlen
528 #ifndef HAVE_LIBCRYPTO
529         _U_
530 #endif
531         )
532 {
533         register const struct newesp *esp;
534         register const u_char *ep;
535 #ifdef HAVE_LIBCRYPTO
536         struct ip *ip;
537         struct sa_list *sa = NULL;
538         int espsecret_keylen;
539 #ifdef INET6
540         struct ip6_hdr *ip6 = NULL;
541 #endif
542         int advance;
543         int len;
544         u_char *secret;
545         int ivlen = 0;
546         u_char *ivoff;
547         u_char *p;
548         EVP_CIPHER_CTX ctx;
549         int blocksz;
550 #endif
551
552         esp = (struct newesp *)bp;
553
554 #ifdef HAVE_LIBCRYPTO
555         secret = NULL;
556         advance = 0;
557 #endif
558
559 #if 0
560         /* keep secret out of a register */
561         p = (u_char *)&secret;
562 #endif
563
564         /* 'ep' points to the end of available data. */
565         ep = ndo->ndo_snapend;
566
567         if ((u_char *)(esp + 1) >= ep) {
568                 fputs("[|ESP]", stdout);
569                 goto fail;
570         }
571         (*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));
572         (*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq));
573         (*ndo->ndo_printf)(ndo, ", length %u", length);
574
575 #ifndef HAVE_LIBCRYPTO
576         goto fail;
577 #else
578         /* initiailize SAs */
579         if (ndo->ndo_sa_list_head == NULL) {
580                 if (!ndo->ndo_espsecret)
581                         goto fail;
582
583                 esp_print_decodesecret(ndo);
584         }
585
586         if (ndo->ndo_sa_list_head == NULL)
587                 goto fail;
588
589         ip = (struct ip *)bp2;
590         switch (IP_V(ip)) {
591 #ifdef INET6
592         case 6:
593                 ip6 = (struct ip6_hdr *)bp2;
594                 /* we do not attempt to decrypt jumbograms */
595                 if (!EXTRACT_16BITS(&ip6->ip6_plen))
596                         goto fail;
597                 /* if we can't get nexthdr, we do not need to decrypt it */
598                 len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
599
600                 /* see if we can find the SA, and if so, decode it */
601                 for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
602                         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;
603                         if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
604                             sin6->sin6_family == AF_INET6 &&
605                             memcmp(&sin6->sin6_addr, &ip6->ip6_dst,
606                                    sizeof(struct in6_addr)) == 0) {
607                                 break;
608                         }
609                 }
610                 break;
611 #endif /*INET6*/
612         case 4:
613                 /* nexthdr & padding are in the last fragment */
614                 if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
615                         goto fail;
616                 len = EXTRACT_16BITS(&ip->ip_len);
617
618                 /* see if we can find the SA, and if so, decode it */
619                 for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
620                         struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;
621                         if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
622                             sin->sin_family == AF_INET &&
623                             sin->sin_addr.s_addr == ip->ip_dst.s_addr) {
624                                 break;
625                         }
626                 }
627                 break;
628         default:
629                 goto fail;
630         }
631
632         /* if we didn't find the specific one, then look for
633          * an unspecified one.
634          */
635         if (sa == NULL)
636                 sa = ndo->ndo_sa_default;
637         
638         /* if not found fail */
639         if (sa == NULL)
640                 goto fail;
641
642         /* if we can't get nexthdr, we do not need to decrypt it */
643         if (ep - bp2 < len)
644                 goto fail;
645         if (ep - bp2 > len) {
646                 /* FCS included at end of frame (NetBSD 1.6 or later) */
647                 ep = bp2 + len;
648         }
649
650         ivoff = (u_char *)(esp + 1) + 0;
651         ivlen = sa->ivlen;
652         secret = sa->secret;
653         espsecret_keylen = sa->secretlen;
654         ep = ep - sa->authlen;
655
656         if (sa->evp) {
657                 memset(&ctx, 0, sizeof(ctx));
658                 if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
659                         (*ndo->ndo_warning)(ndo, "espkey init failed");
660
661                 blocksz = EVP_CIPHER_CTX_block_size(&ctx);
662
663                 p = ivoff;
664                 EVP_CipherInit(&ctx, NULL, NULL, p, 0);
665                 EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
666                 EVP_CIPHER_CTX_cleanup(&ctx);
667                 advance = ivoff - (u_char *)esp + ivlen;
668         } else
669                 advance = sizeof(struct newesp);
670
671         /* sanity check for pad length */
672         if (ep - bp < *(ep - 2))
673                 goto fail;
674
675         if (padlen)
676                 *padlen = *(ep - 2) + 2;
677
678         if (nhdr)
679                 *nhdr = *(ep - 1);
680
681         (ndo->ndo_printf)(ndo, ": ");
682         return advance;
683 #endif
684
685 fail:
686         return -1;
687 }
688
689 /*
690  * Local Variables:
691  * c-style: whitesmith
692  * c-basic-offset: 8
693  * End:
694  */