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