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