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.56 2005-04-21 06:44:40 guy 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 #ifdef HAVE_LIBCRYPTO 40 #ifdef HAVE_OPENSSL_EVP_H 41 #include <openssl/evp.h> 42 #endif 43 #endif 44 45 #include <stdio.h> 46 47 #include "ip.h" 48 #include "esp.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 #ifndef HAVE_SOCKADDR_STORAGE 58 #ifdef INET6 59 struct sockaddr_storage { 60 union { 61 struct sockaddr_in sin; 62 struct sockaddr_in6 sin6; 63 } un; 64 }; 65 #else 66 #define sockaddr_storage sockaddr 67 #endif 68 #endif /* HAVE_SOCKADDR_STORAGE */ 69 70 #ifdef HAVE_LIBCRYPTO 71 struct sa_list { 72 struct sa_list *next; 73 struct sockaddr_storage daddr; 74 u_int32_t spi; 75 const EVP_CIPHER *evp; 76 int ivlen; 77 int authlen; 78 u_char secret[256]; /* is that big enough for all secrets? */ 79 int secretlen; 80 }; 81 82 static void esp_print_addsa(netdissect_options *ndo, 83 struct sa_list *sa, int sa_def) 84 { 85 /* copy the "sa" */ 86 87 struct sa_list *nsa; 88 89 nsa = (struct sa_list *)malloc(sizeof(struct sa_list)); 90 if (nsa == NULL) 91 (*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure"); 92 93 *nsa = *sa; 94 95 if (sa_def) 96 ndo->ndo_sa_default = nsa; 97 98 nsa->next = ndo->ndo_sa_list_head; 99 ndo->ndo_sa_list_head = nsa; 100 } 101 102 103 static u_int hexdigit(netdissect_options *ndo, char hex) 104 { 105 if (hex >= '0' && hex <= '9') 106 return (hex - '0'); 107 else if (hex >= 'A' && hex <= 'F') 108 return (hex - 'A' + 10); 109 else if (hex >= 'a' && hex <= 'f') 110 return (hex - 'a' + 10); 111 else { 112 (*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex); 113 return 0; 114 } 115 } 116 117 static u_int hex2byte(netdissect_options *ndo, char *hexstring) 118 { 119 u_int byte; 120 121 byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]); 122 return byte; 123 } 124 125 /* 126 * decode the form: SPINUM@IP <tab> ALGONAME:0xsecret 127 * 128 * special form: file /name 129 * causes us to go read from this file instead. 130 * 131 */ 132 static void esp_print_decode_onesecret(netdissect_options *ndo, char *line) 133 { 134 struct sa_list sa1; 135 int sa_def; 136 137 char *spikey; 138 char *decode; 139 140 spikey = strsep(&line, " \t"); 141 sa_def = 0; 142 memset(&sa1, 0, sizeof(struct sa_list)); 143 144 /* if there is only one token, then it is an algo:key token */ 145 if (line == NULL) { 146 decode = spikey; 147 spikey = NULL; 148 /* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */ 149 /* sa1.spi = 0; */ 150 sa_def = 1; 151 } else 152 decode = line; 153 154 if (spikey && strcasecmp(spikey, "file") == 0) { 155 /* open file and read it */ 156 FILE *secretfile; 157 char fileline[1024]; 158 char *nl; 159 160 secretfile = fopen(line, FOPEN_READ_TXT); 161 if (secretfile == NULL) { 162 perror(line); 163 exit(3); 164 } 165 166 while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) { 167 /* remove newline from the line */ 168 nl = strchr(fileline, '\n'); 169 if (nl) 170 *nl = '\0'; 171 if (fileline[0] == '#') continue; 172 if (fileline[0] == '\0') continue; 173 174 esp_print_decode_onesecret(ndo, fileline); 175 } 176 fclose(secretfile); 177 178 return; 179 } 180 181 if (spikey) { 182 char *spistr, *foo; 183 u_int32_t spino; 184 struct sockaddr_in *sin; 185 #ifdef INET6 186 struct sockaddr_in6 *sin6; 187 #endif 188 189 spistr = strsep(&spikey, "@"); 190 191 spino = strtoul(spistr, &foo, 0); 192 if (spistr == foo || !spikey) { 193 (*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo); 194 return; 195 } 196 197 sa1.spi = spino; 198 199 sin = (struct sockaddr_in *)&sa1.daddr; 200 #ifdef INET6 201 sin6 = (struct sockaddr_in6 *)&sa1.daddr; 202 if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) { 203 #ifdef HAVE_SOCKADDR_SA_LEN 204 sin6->sin6_len = sizeof(struct sockaddr_in6); 205 #endif 206 sin6->sin6_family = AF_INET6; 207 } else 208 #endif 209 if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) { 210 #ifdef HAVE_SOCKADDR_SA_LEN 211 sin->sin_len = sizeof(struct sockaddr_in); 212 #endif 213 sin->sin_family = AF_INET; 214 } else { 215 (*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey); 216 return; 217 } 218 } 219 220 if (decode) { 221 char *colon, *p; 222 u_char espsecret_key[256]; 223 int len; 224 size_t i; 225 const EVP_CIPHER *evp; 226 int authlen = 0; 227 228 /* skip any blank spaces */ 229 while (isspace((unsigned char)*decode)) 230 decode++; 231 232 colon = strchr(decode, ':'); 233 if (colon == NULL) { 234 (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode); 235 return; 236 } 237 *colon = '\0'; 238 239 len = colon - decode; 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 if (!evp) { 254 (*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode); 255 sa1.evp = NULL; 256 sa1.authlen = 0; 257 sa1.ivlen = 0; 258 return; 259 } 260 261 sa1.evp = evp; 262 sa1.authlen = authlen; 263 sa1.ivlen = EVP_CIPHER_iv_length(evp); 264 265 colon++; 266 if (colon[0] == '0' && colon[1] == 'x') { 267 /* decode some hex! */ 268 colon += 2; 269 len = strlen(colon) / 2; 270 271 if (len > 256) { 272 (*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len); 273 return; 274 } 275 276 i = 0; 277 while (colon[0] != '\0' && colon[1]!='\0') { 278 espsecret_key[i] = hex2byte(ndo, colon); 279 colon += 2; 280 i++; 281 } 282 283 memcpy(sa1.secret, espsecret_key, i); 284 sa1.secretlen = i; 285 } else { 286 i = strlen(colon); 287 288 if (i < sizeof(sa1.secret)) { 289 memcpy(sa1.secret, colon, i); 290 sa1.secretlen = i; 291 } else { 292 memcpy(sa1.secret, colon, sizeof(sa1.secret)); 293 sa1.secretlen = sizeof(sa1.secret); 294 } 295 } 296 } 297 298 esp_print_addsa(ndo, &sa1, sa_def); 299 } 300 301 static void esp_print_decodesecret(netdissect_options *ndo) 302 { 303 char *line; 304 char *p; 305 306 p = ndo->ndo_espsecret; 307 308 while (ndo->ndo_espsecret && ndo->ndo_espsecret[0] != '\0') { 309 /* pick out the first line or first thing until a comma */ 310 if ((line = strsep(&ndo->ndo_espsecret, "\n,")) == NULL) { 311 line = ndo->ndo_espsecret; 312 ndo->ndo_espsecret = NULL; 313 } 314 315 esp_print_decode_onesecret(ndo, line); 316 } 317 } 318 319 static void esp_init(netdissect_options *ndo _U_) 320 { 321 322 OpenSSL_add_all_algorithms(); 323 EVP_add_cipher_alias(SN_des_ede3_cbc, "3des"); 324 } 325 #endif 326 327 int 328 esp_print(netdissect_options *ndo, 329 const u_char *bp, const int length, const u_char *bp2 330 #ifndef HAVE_LIBCRYPTO 331 _U_ 332 #endif 333 , 334 int *nhdr 335 #ifndef HAVE_LIBCRYPTO 336 _U_ 337 #endif 338 , 339 int *padlen 340 #ifndef HAVE_LIBCRYPTO 341 _U_ 342 #endif 343 ) 344 { 345 register const struct newesp *esp; 346 register const u_char *ep; 347 #ifdef HAVE_LIBCRYPTO 348 struct ip *ip; 349 struct sa_list *sa = NULL; 350 int espsecret_keylen; 351 #ifdef INET6 352 struct ip6_hdr *ip6 = NULL; 353 #endif 354 int advance; 355 int len; 356 u_char *secret; 357 int ivlen = 0; 358 u_char *ivoff; 359 u_char *p; 360 EVP_CIPHER_CTX ctx; 361 int blocksz; 362 static int initialized = 0; 363 #endif 364 365 esp = (struct newesp *)bp; 366 367 #ifdef HAVE_LIBCRYPTO 368 secret = NULL; 369 advance = 0; 370 371 if (!initialized) { 372 esp_init(ndo); 373 initialized = 1; 374 } 375 #endif 376 377 #if 0 378 /* keep secret out of a register */ 379 p = (u_char *)&secret; 380 #endif 381 382 /* 'ep' points to the end of available data. */ 383 ep = ndo->ndo_snapend; 384 385 if ((u_char *)(esp + 1) >= ep) { 386 fputs("[|ESP]", stdout); 387 goto fail; 388 } 389 (*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi)); 390 (*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq)); 391 (*ndo->ndo_printf)(ndo, ", length %u", length); 392 393 #ifndef HAVE_LIBCRYPTO 394 goto fail; 395 #else 396 /* initiailize SAs */ 397 if (ndo->ndo_sa_list_head == NULL) { 398 if (!ndo->ndo_espsecret) 399 goto fail; 400 401 esp_print_decodesecret(ndo); 402 } 403 404 if (ndo->ndo_sa_list_head == NULL) 405 goto fail; 406 407 ip = (struct ip *)bp2; 408 switch (IP_V(ip)) { 409 #ifdef INET6 410 case 6: 411 ip6 = (struct ip6_hdr *)bp2; 412 /* we do not attempt to decrypt jumbograms */ 413 if (!EXTRACT_16BITS(&ip6->ip6_plen)) 414 goto fail; 415 /* if we can't get nexthdr, we do not need to decrypt it */ 416 len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen); 417 418 /* see if we can find the SA, and if so, decode it */ 419 for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) { 420 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr; 421 if (sa->spi == ntohl(esp->esp_spi) && 422 sin6->sin6_family == AF_INET6 && 423 memcmp(&sin6->sin6_addr, &ip6->ip6_dst, 424 sizeof(struct in6_addr)) == 0) { 425 break; 426 } 427 } 428 break; 429 #endif /*INET6*/ 430 case 4: 431 /* nexthdr & padding are in the last fragment */ 432 if (EXTRACT_16BITS(&ip->ip_off) & IP_MF) 433 goto fail; 434 len = EXTRACT_16BITS(&ip->ip_len); 435 436 /* see if we can find the SA, and if so, decode it */ 437 for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) { 438 struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr; 439 if (sa->spi == ntohl(esp->esp_spi) && 440 sin->sin_family == AF_INET && 441 sin->sin_addr.s_addr == ip->ip_dst.s_addr) { 442 break; 443 } 444 } 445 break; 446 default: 447 goto fail; 448 } 449 450 /* if we didn't find the specific one, then look for 451 * an unspecified one. 452 */ 453 if (sa == NULL) 454 sa = ndo->ndo_sa_default; 455 456 /* if not found fail */ 457 if (sa == NULL) 458 goto fail; 459 460 /* if we can't get nexthdr, we do not need to decrypt it */ 461 if (ep - bp2 < len) 462 goto fail; 463 if (ep - bp2 > len) { 464 /* FCS included at end of frame (NetBSD 1.6 or later) */ 465 ep = bp2 + len; 466 } 467 468 ivoff = (u_char *)(esp + 1) + 0; 469 ivlen = sa->ivlen; 470 secret = sa->secret; 471 espsecret_keylen = sa->secretlen; 472 ep = ep - sa->authlen; 473 474 if (sa->evp) { 475 memset(&ctx, 0, sizeof(ctx)); 476 if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0) 477 (*ndo->ndo_warning)(ndo, "espkey init failed"); 478 479 blocksz = EVP_CIPHER_CTX_block_size(&ctx); 480 481 p = ivoff; 482 EVP_CipherInit(&ctx, NULL, NULL, p, 0); 483 EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen)); 484 advance = ivoff - (u_char *)esp + ivlen; 485 } else 486 advance = sizeof(struct newesp); 487 488 /* sanity check for pad length */ 489 if (ep - bp < *(ep - 2)) 490 goto fail; 491 492 if (padlen) 493 *padlen = *(ep - 2) + 2; 494 495 if (nhdr) 496 *nhdr = *(ep - 1); 497 498 (ndo->ndo_printf)(ndo, ": "); 499 return advance; 500 #endif 501 502 fail: 503 return -1; 504 } 505 506 /* 507 * Local Variables: 508 * c-style: whitesmith 509 * c-basic-offset: 8 510 * End: 511 */ 512