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