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