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