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