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 #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 28 29 #define NETDISSECT_REWORKED 30 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 #include <tcpdump-stdinc.h> 35 36 #include <string.h> 37 #include <stdlib.h> 38 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. 42 */ 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 50 51 #include "ip.h" 52 #ifdef INET6 53 #include "ip6.h" 54 #endif 55 56 #include "interface.h" 57 #include "extract.h" 58 59 /* 60 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 61 * All rights reserved. 62 * 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. 74 * 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. 86 */ 87 88 /* 89 * RFC1827/2406 Encapsulated Security Payload. 90 */ 91 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 */ 101 }; 102 103 #ifdef HAVE_LIBCRYPTO 104 union inaddr_u { 105 struct in_addr in4; 106 #ifdef INET6 107 struct in6_addr in6; 108 #endif 109 }; 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; 125 }; 126 127 /* 128 * this will adjust ndo_packetp and ndo_snapend to new buffer! 129 */ 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) 135 { 136 struct sa_list *sa; 137 u_char *iv; 138 int len; 139 EVP_CIPHER_CTX ctx; 140 141 /* initiator arg is any non-zero value */ 142 if(initiator) initiator=1; 143 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; 151 } 152 153 if(sa == NULL) return 0; 154 if(sa->evp == NULL) return 0; 155 156 /* 157 * remove authenticator, and see if we still have something to 158 * work with 159 */ 160 end = end - sa->authlen; 161 iv = buf; 162 buf = buf + sa->ivlen; 163 len = end-buf; 164 165 if(end <= buf) return 0; 166 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); 173 174 ndo->ndo_packetp = buf; 175 ndo->ndo_snapend = end; 176 177 return 1; 178 179 } 180 USES_APPLE_RST 181 182 static void esp_print_addsa(netdissect_options *ndo, 183 struct sa_list *sa, int sa_def) 184 { 185 /* copy the "sa" */ 186 187 struct sa_list *nsa; 188 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"); 192 193 *nsa = *sa; 194 195 if (sa_def) 196 ndo->ndo_sa_default = nsa; 197 198 nsa->next = ndo->ndo_sa_list_head; 199 ndo->ndo_sa_list_head = nsa; 200 } 201 202 203 static u_int hexdigit(netdissect_options *ndo, char hex) 204 { 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; 214 } 215 } 216 217 static u_int hex2byte(netdissect_options *ndo, char *hexstring) 218 { 219 u_int byte; 220 221 byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]); 222 return byte; 223 } 224 225 /* 226 * returns size of binary, 0 on failure. 227 */ 228 static 229 int espprint_decode_hex(netdissect_options *ndo, 230 u_char *binbuf, unsigned int binbuf_len, 231 char *hex) 232 { 233 unsigned int len; 234 int i; 235 236 len = strlen(hex) / 2; 237 238 if (len > binbuf_len) { 239 (*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len); 240 return 0; 241 } 242 243 i = 0; 244 while (hex[0] != '\0' && hex[1]!='\0') { 245 binbuf[i] = hex2byte(ndo, hex); 246 hex += 2; 247 i++; 248 } 249 250 return i; 251 } 252 253 /* 254 * decode the form: SPINUM@IP <tab> ALGONAME:0xsecret 255 */ 256 257 USES_APPLE_DEPRECATED_API 258 static int 259 espprint_decode_encalgo(netdissect_options *ndo, 260 char *decode, struct sa_list *sa) 261 { 262 size_t i; 263 const EVP_CIPHER *evp; 264 int authlen = 0; 265 char *colon, *p; 266 267 colon = strchr(decode, ':'); 268 if (colon == NULL) { 269 (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode); 270 return 0; 271 } 272 *colon = '\0'; 273 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; 280 } 281 if (strlen(decode) > strlen("-cbc") && 282 !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) { 283 p = strstr(decode, "-cbc"); 284 *p = '\0'; 285 } 286 evp = EVP_get_cipherbyname(decode); 287 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; 294 } 295 296 sa->evp = evp; 297 sa->authlen = authlen; 298 sa->ivlen = EVP_CIPHER_iv_length(evp); 299 300 colon++; 301 if (colon[0] == '0' && colon[1] == 'x') { 302 /* decode some hex! */ 303 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); 309 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); 316 } 317 } 318 319 return 1; 320 } 321 USES_APPLE_RST 322 323 /* 324 * for the moment, ignore the auth algorith, just hard code the authenticator 325 * length. Need to research how openssl looks up HMAC stuff. 326 */ 327 static int 328 espprint_decode_authalgo(netdissect_options *ndo, 329 char *decode, struct sa_list *sa) 330 { 331 char *colon; 332 333 colon = strchr(decode, ':'); 334 if (colon == NULL) { 335 (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode); 336 return 0; 337 } 338 *colon = '\0'; 339 340 if(strcasecmp(colon,"sha1") == 0 || 341 strcasecmp(colon,"md5") == 0) { 342 sa->authlen = 12; 343 } 344 return 1; 345 } 346 347 static void esp_print_decode_ikeline(netdissect_options *ndo, char *line, 348 const char *file, int lineno) 349 { 350 /* it's an IKEv2 secret, store it instead */ 351 struct sa_list sa1; 352 353 char *init; 354 char *icookie, *rcookie; 355 int ilen, rlen; 356 char *authkey; 357 char *enckey; 358 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"); 364 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); 369 370 return; 371 } 372 373 ilen = strlen(icookie); 374 rlen = strlen(rcookie); 375 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); 383 384 (*ndo->ndo_warning)(ndo, "init=%s icookie=%s(%u) rcookie=%s(%u)", 385 init, icookie, ilen, rcookie, rlen); 386 387 return; 388 } 389 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; 394 395 if(espprint_decode_hex(ndo, sa1.spir, sizeof(sa1.spir), rcookie+2)!=8) 396 return; 397 398 if(!espprint_decode_encalgo(ndo, enckey, &sa1)) return; 399 400 if(!espprint_decode_authalgo(ndo, authkey, &sa1)) return; 401 402 esp_print_addsa(ndo, &sa1, FALSE); 403 } 404 405 /* 406 * 407 * special form: file /name 408 * causes us to go read from this file instead. 409 * 410 */ 411 static void esp_print_decode_onesecret(netdissect_options *ndo, char *line, 412 const char *file, int lineno) 413 { 414 struct sa_list sa1; 415 int sa_def; 416 417 char *spikey; 418 char *decode; 419 420 spikey = strsep(&line, " \t"); 421 sa_def = 0; 422 memset(&sa1, 0, sizeof(struct sa_list)); 423 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; 434 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; 442 443 secretfile = fopen(filename, FOPEN_READ_TXT); 444 if (secretfile == NULL) { 445 perror(filename); 446 exit(3); 447 } 448 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; 457 458 esp_print_decode_onesecret(ndo, fileline, filename, lineno); 459 } 460 fclose(secretfile); 461 462 return; 463 } 464 465 if (spikey && strcasecmp(spikey, "ikev2") == 0) { 466 esp_print_decode_ikeline(ndo, line, file, lineno); 467 return; 468 } 469 470 if (spikey) { 471 472 char *spistr, *foo; 473 uint32_t spino; 474 475 spistr = strsep(&spikey, "@"); 476 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; 481 } 482 483 sa1.spi = spino; 484 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; 495 } 496 } 497 498 if (decode) { 499 /* skip any blank spaces */ 500 while (isspace((unsigned char)*decode)) 501 decode++; 502 503 if(!espprint_decode_encalgo(ndo, decode, &sa1)) { 504 return; 505 } 506 } 507 508 esp_print_addsa(ndo, &sa1, sa_def); 509 } 510 511 USES_APPLE_DEPRECATED_API 512 static void esp_init(netdissect_options *ndo _U_) 513 { 514 515 OpenSSL_add_all_algorithms(); 516 EVP_add_cipher_alias(SN_des_ede3_cbc, "3des"); 517 } 518 USES_APPLE_RST 519 520 void esp_print_decodesecret(netdissect_options *ndo) 521 { 522 char *line; 523 char *p; 524 static int initialized = 0; 525 526 if (!initialized) { 527 esp_init(ndo); 528 initialized = 1; 529 } 530 531 p = ndo->ndo_espsecret; 532 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; 538 } 539 540 esp_print_decode_onesecret(ndo, line, "cmdline", 0); 541 } 542 543 ndo->ndo_espsecret = NULL; 544 } 545 546 #endif 547 548 #ifdef HAVE_LIBCRYPTO 549 USES_APPLE_DEPRECATED_API 550 #endif 551 int 552 esp_print(netdissect_options *ndo, 553 const u_char *bp, const int length, const u_char *bp2 554 #ifndef HAVE_LIBCRYPTO 555 _U_ 556 #endif 557 , 558 int *nhdr 559 #ifndef HAVE_LIBCRYPTO 560 _U_ 561 #endif 562 , 563 int *padlen 564 #ifndef HAVE_LIBCRYPTO 565 _U_ 566 #endif 567 ) 568 { 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 585 586 esp = (struct newesp *)bp; 587 588 #ifdef HAVE_LIBCRYPTO 589 secret = NULL; 590 advance = 0; 591 #endif 592 593 #if 0 594 /* keep secret out of a register */ 595 p = (u_char *)&secret; 596 #endif 597 598 /* 'ep' points to the end of available data. */ 599 ep = ndo->ndo_snapend; 600 601 if ((u_char *)(esp + 1) >= ep) { 602 ND_PRINT((ndo, "[|ESP]")); 603 goto fail; 604 } 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)); 608 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; 616 617 esp_print_decodesecret(ndo); 618 } 619 620 if (ndo->ndo_sa_list_head == NULL) 621 goto fail; 622 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); 633 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; 641 } 642 } 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); 650 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; 658 } 659 } 660 break; 661 default: 662 goto fail; 663 } 664 665 /* if we didn't find the specific one, then look for 666 * an unspecified one. 667 */ 668 if (sa == NULL) 669 sa = ndo->ndo_sa_default; 670 671 /* if not found fail */ 672 if (sa == NULL) 673 goto fail; 674 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; 681 } 682 683 ivoff = (u_char *)(esp + 1) + 0; 684 ivlen = sa->ivlen; 685 secret = sa->secret; 686 ep = ep - sa->authlen; 687 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"); 692 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); 700 701 /* sanity check for pad length */ 702 if (ep - bp < *(ep - 2)) 703 goto fail; 704 705 if (padlen) 706 *padlen = *(ep - 2) + 2; 707 708 if (nhdr) 709 *nhdr = *(ep - 1); 710 711 ND_PRINT((ndo, ": ")); 712 return advance; 713 #endif 714 715 fail: 716 return -1; 717 } 718 #ifdef HAVE_LIBCRYPTO 719 USES_APPLE_RST 720 #endif 721 722 /* 723 * Local Variables: 724 * c-style: whitesmith 725 * c-basic-offset: 8 726 * End: 727 */ 728