156893Sfenner/* $NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $ */ 256893Sfenner 356893Sfenner/* 456893Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 556893Sfenner * The Regents of the University of California. All rights reserved. 656893Sfenner * 756893Sfenner * Redistribution and use in source and binary forms, with or without 856893Sfenner * modification, are permitted provided that: (1) source code distributions 956893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 1056893Sfenner * distributions including binary code include the above copyright notice and 1156893Sfenner * this paragraph in its entirety in the documentation or other materials 1256893Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1356893Sfenner * features or use of this software display the following acknowledgement: 1456893Sfenner * ``This product includes software developed by the University of California, 1556893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1656893Sfenner * the University nor the names of its contributors may be used to endorse 1756893Sfenner * or promote products derived from this software without specific prior 1856893Sfenner * written permission. 1956893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 2056893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 2156893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2256893Sfenner */ 2356893Sfenner 2456893Sfenner#ifndef lint 25127668Sbmsstatic const char rcsid[] _U_ = 26214478Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.58 2007-12-07 00:03:07 mcr Exp $ (LBL)"; 2756893Sfenner#endif 2856893Sfenner 2956893Sfenner#ifdef HAVE_CONFIG_H 3056893Sfenner#include "config.h" 3156893Sfenner#endif 3256893Sfenner 3356893Sfenner#include <string.h> 34127668Sbms 35127668Sbms#include <tcpdump-stdinc.h> 36127668Sbms 37111726Sfenner#include <stdlib.h> 3856893Sfenner 3975115Sfenner#ifdef HAVE_LIBCRYPTO 40127668Sbms#ifdef HAVE_OPENSSL_EVP_H 41127668Sbms#include <openssl/evp.h> 4256893Sfenner#endif 4356893Sfenner#endif 4456893Sfenner 4556893Sfenner#include <stdio.h> 4656893Sfenner 4775115Sfenner#include "ip.h" 4875115Sfenner#include "esp.h" 4956893Sfenner#ifdef INET6 5075115Sfenner#include "ip6.h" 5156893Sfenner#endif 5256893Sfenner 53146773Ssam#include "netdissect.h" 5456893Sfenner#include "addrtoname.h" 55127668Sbms#include "extract.h" 5656893Sfenner 57127668Sbms#ifndef HAVE_SOCKADDR_STORAGE 58127668Sbms#ifdef INET6 59127668Sbmsstruct sockaddr_storage { 60127668Sbms union { 61127668Sbms struct sockaddr_in sin; 62127668Sbms struct sockaddr_in6 sin6; 63127668Sbms } un; 64127668Sbms}; 65127668Sbms#else 66127668Sbms#define sockaddr_storage sockaddr 67127668Sbms#endif 68127668Sbms#endif /* HAVE_SOCKADDR_STORAGE */ 6998524Sfenner 70127668Sbms#ifdef HAVE_LIBCRYPTO 71127668Sbmsstruct sa_list { 72127668Sbms struct sa_list *next; 73127668Sbms struct sockaddr_storage daddr; 74214478Srpaulo u_int32_t spi; /* if == 0, then IKEv2 */ 75214478Srpaulo int initiator; 76214478Srpaulo u_char spii[8]; /* for IKEv2 */ 77214478Srpaulo u_char spir[8]; 78127668Sbms const EVP_CIPHER *evp; 79127668Sbms int ivlen; 80127668Sbms int authlen; 81214478Srpaulo u_char authsecret[256]; 82214478Srpaulo int authsecret_len; 83147899Ssam u_char secret[256]; /* is that big enough for all secrets? */ 84127668Sbms int secretlen; 85127668Sbms}; 8698524Sfenner 87214478Srpaulo/* 88214478Srpaulo * this will adjust ndo_packetp and ndo_snapend to new buffer! 89214478Srpaulo */ 90214478Srpauloint esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo, 91214478Srpaulo int initiator, 92214478Srpaulo u_char spii[8], u_char spir[8], 93214478Srpaulo u_char *buf, u_char *end) 94214478Srpaulo{ 95214478Srpaulo struct sa_list *sa; 96214478Srpaulo u_char *iv; 97214478Srpaulo int len; 98214478Srpaulo EVP_CIPHER_CTX ctx; 99214478Srpaulo 100214478Srpaulo /* initiator arg is any non-zero value */ 101214478Srpaulo if(initiator) initiator=1; 102214478Srpaulo 103214478Srpaulo /* see if we can find the SA, and if so, decode it */ 104214478Srpaulo for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) { 105214478Srpaulo if (sa->spi == 0 106214478Srpaulo && initiator == sa->initiator 107214478Srpaulo && memcmp(spii, sa->spii, 8) == 0 108214478Srpaulo && memcmp(spir, sa->spir, 8) == 0) 109214478Srpaulo break; 110214478Srpaulo } 111214478Srpaulo 112214478Srpaulo if(sa == NULL) return 0; 113214478Srpaulo if(sa->evp == NULL) return 0; 114214478Srpaulo 115214478Srpaulo /* 116214478Srpaulo * remove authenticator, and see if we still have something to 117214478Srpaulo * work with 118214478Srpaulo */ 119214478Srpaulo end = end - sa->authlen; 120214478Srpaulo iv = buf; 121214478Srpaulo buf = buf + sa->ivlen; 122214478Srpaulo len = end-buf; 123214478Srpaulo 124214478Srpaulo if(end <= buf) return 0; 125214478Srpaulo 126214478Srpaulo memset(&ctx, 0, sizeof(ctx)); 127214478Srpaulo if (EVP_CipherInit(&ctx, sa->evp, sa->secret, NULL, 0) < 0) 128214478Srpaulo (*ndo->ndo_warning)(ndo, "espkey init failed"); 129214478Srpaulo EVP_CipherInit(&ctx, NULL, NULL, iv, 0); 130214478Srpaulo EVP_Cipher(&ctx, buf, buf, len); 131214478Srpaulo EVP_CIPHER_CTX_cleanup(&ctx); 132214478Srpaulo 133214478Srpaulo ndo->ndo_packetp = buf; 134214478Srpaulo ndo->ndo_snapend = end; 135214478Srpaulo 136214478Srpaulo return 1; 137214478Srpaulo 138214478Srpaulo} 139214478Srpaulo 140146773Ssamstatic void esp_print_addsa(netdissect_options *ndo, 141146773Ssam struct sa_list *sa, int sa_def) 142127668Sbms{ 143127668Sbms /* copy the "sa" */ 14498524Sfenner 145127668Sbms struct sa_list *nsa; 14698524Sfenner 147127668Sbms nsa = (struct sa_list *)malloc(sizeof(struct sa_list)); 148127668Sbms if (nsa == NULL) 149146773Ssam (*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure"); 15098524Sfenner 151127668Sbms *nsa = *sa; 15298524Sfenner 153127668Sbms if (sa_def) 154146773Ssam ndo->ndo_sa_default = nsa; 155127668Sbms 156146773Ssam nsa->next = ndo->ndo_sa_list_head; 157146773Ssam ndo->ndo_sa_list_head = nsa; 158127668Sbms} 159127668Sbms 160127668Sbms 161147899Ssamstatic u_int hexdigit(netdissect_options *ndo, char hex) 16298524Sfenner{ 163127668Sbms if (hex >= '0' && hex <= '9') 16498524Sfenner return (hex - '0'); 165127668Sbms else if (hex >= 'A' && hex <= 'F') 16698524Sfenner return (hex - 'A' + 10); 167127668Sbms else if (hex >= 'a' && hex <= 'f') 16898524Sfenner return (hex - 'a' + 10); 169127668Sbms else { 170146773Ssam (*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex); 17198524Sfenner return 0; 17298524Sfenner } 17398524Sfenner} 17498524Sfenner 175147899Ssamstatic u_int hex2byte(netdissect_options *ndo, char *hexstring) 17698524Sfenner{ 177147899Ssam u_int byte; 17898524Sfenner 179146773Ssam byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]); 18098524Sfenner return byte; 18198524Sfenner} 18298524Sfenner 183127668Sbms/* 184214478Srpaulo * returns size of binary, 0 on failure. 185214478Srpaulo */ 186214478Srpaulostatic 187214478Srpauloint espprint_decode_hex(netdissect_options *ndo, 188214478Srpaulo u_char *binbuf, unsigned int binbuf_len, 189214478Srpaulo char *hex) 190214478Srpaulo{ 191214478Srpaulo unsigned int len; 192214478Srpaulo int i; 193214478Srpaulo 194214478Srpaulo len = strlen(hex) / 2; 195214478Srpaulo 196214478Srpaulo if (len > binbuf_len) { 197214478Srpaulo (*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len); 198214478Srpaulo return 0; 199214478Srpaulo } 200214478Srpaulo 201214478Srpaulo i = 0; 202214478Srpaulo while (hex[0] != '\0' && hex[1]!='\0') { 203214478Srpaulo binbuf[i] = hex2byte(ndo, hex); 204214478Srpaulo hex += 2; 205214478Srpaulo i++; 206214478Srpaulo } 207214478Srpaulo 208214478Srpaulo return i; 209214478Srpaulo} 210214478Srpaulo 211214478Srpaulo/* 212127668Sbms * decode the form: SPINUM@IP <tab> ALGONAME:0xsecret 213214478Srpaulo */ 214214478Srpaulo 215214478Srpaulostatic int 216214478Srpauloespprint_decode_encalgo(netdissect_options *ndo, 217214478Srpaulo char *decode, struct sa_list *sa) 218214478Srpaulo{ 219214478Srpaulo int len; 220214478Srpaulo size_t i; 221214478Srpaulo const EVP_CIPHER *evp; 222214478Srpaulo int authlen = 0; 223214478Srpaulo char *colon, *p; 224214478Srpaulo 225214478Srpaulo colon = strchr(decode, ':'); 226214478Srpaulo if (colon == NULL) { 227214478Srpaulo (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode); 228214478Srpaulo return 0; 229214478Srpaulo } 230214478Srpaulo *colon = '\0'; 231214478Srpaulo 232214478Srpaulo len = colon - decode; 233214478Srpaulo if (strlen(decode) > strlen("-hmac96") && 234214478Srpaulo !strcmp(decode + strlen(decode) - strlen("-hmac96"), 235214478Srpaulo "-hmac96")) { 236214478Srpaulo p = strstr(decode, "-hmac96"); 237214478Srpaulo *p = '\0'; 238214478Srpaulo authlen = 12; 239214478Srpaulo } 240214478Srpaulo if (strlen(decode) > strlen("-cbc") && 241214478Srpaulo !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) { 242214478Srpaulo p = strstr(decode, "-cbc"); 243214478Srpaulo *p = '\0'; 244214478Srpaulo } 245214478Srpaulo evp = EVP_get_cipherbyname(decode); 246214478Srpaulo 247214478Srpaulo if (!evp) { 248214478Srpaulo (*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode); 249214478Srpaulo sa->evp = NULL; 250214478Srpaulo sa->authlen = 0; 251214478Srpaulo sa->ivlen = 0; 252214478Srpaulo return 0; 253214478Srpaulo } 254214478Srpaulo 255214478Srpaulo sa->evp = evp; 256214478Srpaulo sa->authlen = authlen; 257214478Srpaulo sa->ivlen = EVP_CIPHER_iv_length(evp); 258214478Srpaulo 259214478Srpaulo colon++; 260214478Srpaulo if (colon[0] == '0' && colon[1] == 'x') { 261214478Srpaulo /* decode some hex! */ 262214478Srpaulo 263214478Srpaulo colon += 2; 264214478Srpaulo sa->secretlen = espprint_decode_hex(ndo, sa->secret, sizeof(sa->secret), colon); 265214478Srpaulo if(sa->secretlen == 0) return 0; 266214478Srpaulo } else { 267214478Srpaulo i = strlen(colon); 268214478Srpaulo 269214478Srpaulo if (i < sizeof(sa->secret)) { 270214478Srpaulo memcpy(sa->secret, colon, i); 271214478Srpaulo sa->secretlen = i; 272214478Srpaulo } else { 273214478Srpaulo memcpy(sa->secret, colon, sizeof(sa->secret)); 274214478Srpaulo sa->secretlen = sizeof(sa->secret); 275214478Srpaulo } 276214478Srpaulo } 277214478Srpaulo 278214478Srpaulo return 1; 279214478Srpaulo} 280214478Srpaulo 281214478Srpaulo/* 282214478Srpaulo * for the moment, ignore the auth algorith, just hard code the authenticator 283214478Srpaulo * length. Need to research how openssl looks up HMAC stuff. 284214478Srpaulo */ 285214478Srpaulostatic int 286214478Srpauloespprint_decode_authalgo(netdissect_options *ndo, 287214478Srpaulo char *decode, struct sa_list *sa) 288214478Srpaulo{ 289214478Srpaulo char *colon; 290214478Srpaulo 291214478Srpaulo colon = strchr(decode, ':'); 292214478Srpaulo if (colon == NULL) { 293214478Srpaulo (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode); 294214478Srpaulo return 0; 295214478Srpaulo } 296214478Srpaulo *colon = '\0'; 297214478Srpaulo 298214478Srpaulo if(strcasecmp(colon,"sha1") == 0 || 299214478Srpaulo strcasecmp(colon,"md5") == 0) { 300214478Srpaulo sa->authlen = 12; 301214478Srpaulo } 302214478Srpaulo return 1; 303214478Srpaulo} 304214478Srpaulo 305214478Srpaulostatic void esp_print_decode_ikeline(netdissect_options *ndo, char *line, 306214478Srpaulo const char *file, int lineno) 307214478Srpaulo{ 308214478Srpaulo /* it's an IKEv2 secret, store it instead */ 309214478Srpaulo struct sa_list sa1; 310214478Srpaulo 311214478Srpaulo char *init; 312214478Srpaulo char *icookie, *rcookie; 313214478Srpaulo int ilen, rlen; 314214478Srpaulo char *authkey; 315214478Srpaulo char *enckey; 316214478Srpaulo 317214478Srpaulo init = strsep(&line, " \t"); 318214478Srpaulo icookie = strsep(&line, " \t"); 319214478Srpaulo rcookie = strsep(&line, " \t"); 320214478Srpaulo authkey = strsep(&line, " \t"); 321214478Srpaulo enckey = strsep(&line, " \t"); 322214478Srpaulo 323214478Srpaulo /* if any fields are missing */ 324214478Srpaulo if(!init || !icookie || !rcookie || !authkey || !enckey) { 325214478Srpaulo (*ndo->ndo_warning)(ndo, "print_esp: failed to find all fields for ikev2 at %s:%u", 326214478Srpaulo file, lineno); 327214478Srpaulo 328214478Srpaulo return; 329214478Srpaulo } 330214478Srpaulo 331214478Srpaulo ilen = strlen(icookie); 332214478Srpaulo rlen = strlen(rcookie); 333214478Srpaulo 334214478Srpaulo if((init[0]!='I' && init[0]!='R') 335214478Srpaulo || icookie[0]!='0' || icookie[1]!='x' 336214478Srpaulo || rcookie[0]!='0' || rcookie[1]!='x' 337214478Srpaulo || ilen!=18 338214478Srpaulo || rlen!=18) { 339214478Srpaulo (*ndo->ndo_warning)(ndo, "print_esp: line %s:%u improperly formatted.", 340214478Srpaulo file, lineno); 341214478Srpaulo 342214478Srpaulo (*ndo->ndo_warning)(ndo, "init=%s icookie=%s(%u) rcookie=%s(%u)", 343214478Srpaulo init, icookie, ilen, rcookie, rlen); 344214478Srpaulo 345214478Srpaulo return; 346214478Srpaulo } 347214478Srpaulo 348214478Srpaulo sa1.spi = 0; 349214478Srpaulo sa1.initiator = (init[0] == 'I'); 350214478Srpaulo if(espprint_decode_hex(ndo, sa1.spii, sizeof(sa1.spii), icookie+2)!=8) 351214478Srpaulo return; 352214478Srpaulo 353214478Srpaulo if(espprint_decode_hex(ndo, sa1.spir, sizeof(sa1.spir), rcookie+2)!=8) 354214478Srpaulo return; 355214478Srpaulo 356214478Srpaulo if(!espprint_decode_encalgo(ndo, enckey, &sa1)) return; 357214478Srpaulo 358214478Srpaulo if(!espprint_decode_authalgo(ndo, authkey, &sa1)) return; 359214478Srpaulo 360214478Srpaulo esp_print_addsa(ndo, &sa1, FALSE); 361214478Srpaulo} 362214478Srpaulo 363214478Srpaulo/* 364127668Sbms * 365127668Sbms * special form: file /name 366127668Sbms * causes us to go read from this file instead. 367127668Sbms * 368127668Sbms */ 369214478Srpaulostatic void esp_print_decode_onesecret(netdissect_options *ndo, char *line, 370214478Srpaulo const char *file, int lineno) 37198524Sfenner{ 372127668Sbms struct sa_list sa1; 373127668Sbms int sa_def; 37498524Sfenner 375127668Sbms char *spikey; 376127668Sbms char *decode; 37798524Sfenner 378127668Sbms spikey = strsep(&line, " \t"); 379127668Sbms sa_def = 0; 380127668Sbms memset(&sa1, 0, sizeof(struct sa_list)); 381127668Sbms 382127668Sbms /* if there is only one token, then it is an algo:key token */ 383127668Sbms if (line == NULL) { 384127668Sbms decode = spikey; 385127668Sbms spikey = NULL; 386127668Sbms /* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */ 387127668Sbms /* sa1.spi = 0; */ 388127668Sbms sa_def = 1; 389127668Sbms } else 390127668Sbms decode = line; 391127668Sbms 392127668Sbms if (spikey && strcasecmp(spikey, "file") == 0) { 393127668Sbms /* open file and read it */ 394127668Sbms FILE *secretfile; 395127668Sbms char fileline[1024]; 396214478Srpaulo int lineno=0; 397127668Sbms char *nl; 398214478Srpaulo char *filename = line; 399127668Sbms 400214478Srpaulo secretfile = fopen(filename, FOPEN_READ_TXT); 401127668Sbms if (secretfile == NULL) { 402214478Srpaulo perror(filename); 403127668Sbms exit(3); 404127668Sbms } 405127668Sbms 406127668Sbms while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) { 407214478Srpaulo lineno++; 408127668Sbms /* remove newline from the line */ 409127668Sbms nl = strchr(fileline, '\n'); 410127668Sbms if (nl) 411127668Sbms *nl = '\0'; 412127668Sbms if (fileline[0] == '#') continue; 413127668Sbms if (fileline[0] == '\0') continue; 414127668Sbms 415214478Srpaulo esp_print_decode_onesecret(ndo, fileline, filename, lineno); 416127668Sbms } 417127668Sbms fclose(secretfile); 418127668Sbms 41998524Sfenner return; 42098524Sfenner } 42198524Sfenner 422214478Srpaulo if (spikey && strcasecmp(spikey, "ikev2") == 0) { 423214478Srpaulo esp_print_decode_ikeline(ndo, line, file, lineno); 424214478Srpaulo return; 425214478Srpaulo } 426214478Srpaulo 427127668Sbms if (spikey) { 428214478Srpaulo 429127668Sbms char *spistr, *foo; 430127668Sbms u_int32_t spino; 431127668Sbms struct sockaddr_in *sin; 432127668Sbms#ifdef INET6 433127668Sbms struct sockaddr_in6 *sin6; 434127668Sbms#endif 435214478Srpaulo 436127668Sbms spistr = strsep(&spikey, "@"); 437214478Srpaulo 438127668Sbms spino = strtoul(spistr, &foo, 0); 439127668Sbms if (spistr == foo || !spikey) { 440146773Ssam (*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo); 441127668Sbms return; 442127668Sbms } 443214478Srpaulo 444127668Sbms sa1.spi = spino; 445214478Srpaulo 446127668Sbms sin = (struct sockaddr_in *)&sa1.daddr; 447127668Sbms#ifdef INET6 448127668Sbms sin6 = (struct sockaddr_in6 *)&sa1.daddr; 449127668Sbms if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) { 450127668Sbms#ifdef HAVE_SOCKADDR_SA_LEN 451127668Sbms sin6->sin6_len = sizeof(struct sockaddr_in6); 452127668Sbms#endif 453127668Sbms sin6->sin6_family = AF_INET6; 454127668Sbms } else 455127668Sbms#endif 456214478Srpaulo if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) { 457127668Sbms#ifdef HAVE_SOCKADDR_SA_LEN 458214478Srpaulo sin->sin_len = sizeof(struct sockaddr_in); 459127668Sbms#endif 460214478Srpaulo sin->sin_family = AF_INET; 461214478Srpaulo } else { 462214478Srpaulo (*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey); 463214478Srpaulo return; 464214478Srpaulo } 46598524Sfenner } 46698524Sfenner 467127668Sbms if (decode) { 468127668Sbms /* skip any blank spaces */ 469127668Sbms while (isspace((unsigned char)*decode)) 470127668Sbms decode++; 471214478Srpaulo 472214478Srpaulo if(!espprint_decode_encalgo(ndo, decode, &sa1)) { 473127668Sbms return; 47498524Sfenner } 47598524Sfenner } 476127668Sbms 477146773Ssam esp_print_addsa(ndo, &sa1, sa_def); 47898524Sfenner} 47998524Sfenner 480214478Srpaulostatic void esp_init(netdissect_options *ndo _U_) 481127668Sbms{ 482214478Srpaulo 483214478Srpaulo OpenSSL_add_all_algorithms(); 484214478Srpaulo EVP_add_cipher_alias(SN_des_ede3_cbc, "3des"); 485214478Srpaulo} 486214478Srpaulo 487214478Srpaulovoid esp_print_decodesecret(netdissect_options *ndo) 488214478Srpaulo{ 489127668Sbms char *line; 490127668Sbms char *p; 491214478Srpaulo static int initialized = 0; 492127668Sbms 493214478Srpaulo if (!initialized) { 494214478Srpaulo esp_init(ndo); 495214478Srpaulo initialized = 1; 496214478Srpaulo } 497214478Srpaulo 498146773Ssam p = ndo->ndo_espsecret; 499127668Sbms 500214478Srpaulo while (p && p[0] != '\0') { 501127668Sbms /* pick out the first line or first thing until a comma */ 502214478Srpaulo if ((line = strsep(&p, "\n,")) == NULL) { 503214478Srpaulo line = p; 504214478Srpaulo p = NULL; 505127668Sbms } 506127668Sbms 507214478Srpaulo esp_print_decode_onesecret(ndo, line, "cmdline", 0); 508127668Sbms } 509214478Srpaulo 510214478Srpaulo ndo->ndo_espsecret = NULL; 511127668Sbms} 512127668Sbms 513127668Sbms#endif 514127668Sbms 51556893Sfennerint 516146773Ssamesp_print(netdissect_options *ndo, 517146773Ssam const u_char *bp, const int length, const u_char *bp2 518127668Sbms#ifndef HAVE_LIBCRYPTO 519127668Sbms _U_ 520127668Sbms#endif 521127668Sbms , 522127668Sbms int *nhdr 523127668Sbms#ifndef HAVE_LIBCRYPTO 524127668Sbms _U_ 525127668Sbms#endif 526127668Sbms , 527127668Sbms int *padlen 528127668Sbms#ifndef HAVE_LIBCRYPTO 529127668Sbms _U_ 530127668Sbms#endif 531127668Sbms ) 53256893Sfenner{ 533127668Sbms register const struct newesp *esp; 53456893Sfenner register const u_char *ep; 535127668Sbms#ifdef HAVE_LIBCRYPTO 536127668Sbms struct ip *ip; 537127668Sbms struct sa_list *sa = NULL; 538127668Sbms int espsecret_keylen; 53956893Sfenner#ifdef INET6 54056893Sfenner struct ip6_hdr *ip6 = NULL; 54156893Sfenner#endif 54256893Sfenner int advance; 54356893Sfenner int len; 544147899Ssam u_char *secret; 54556893Sfenner int ivlen = 0; 54656893Sfenner u_char *ivoff; 547146773Ssam u_char *p; 548127668Sbms EVP_CIPHER_CTX ctx; 549127668Sbms int blocksz; 550127668Sbms#endif 551127668Sbms 552127668Sbms esp = (struct newesp *)bp; 553127668Sbms 554127668Sbms#ifdef HAVE_LIBCRYPTO 55598524Sfenner secret = NULL; 556127668Sbms advance = 0; 557127668Sbms#endif 558127668Sbms 55998524Sfenner#if 0 56098524Sfenner /* keep secret out of a register */ 56198524Sfenner p = (u_char *)&secret; 56298524Sfenner#endif 56398524Sfenner 56475115Sfenner /* 'ep' points to the end of available data. */ 565146773Ssam ep = ndo->ndo_snapend; 56656893Sfenner 567127668Sbms if ((u_char *)(esp + 1) >= ep) { 56856893Sfenner fputs("[|ESP]", stdout); 56956893Sfenner goto fail; 57056893Sfenner } 571146773Ssam (*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi)); 572146773Ssam (*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq)); 573146773Ssam (*ndo->ndo_printf)(ndo, ", length %u", length); 57456893Sfenner 575127668Sbms#ifndef HAVE_LIBCRYPTO 576127668Sbms goto fail; 577127668Sbms#else 578127668Sbms /* initiailize SAs */ 579146773Ssam if (ndo->ndo_sa_list_head == NULL) { 580146773Ssam if (!ndo->ndo_espsecret) 581127668Sbms goto fail; 58256893Sfenner 583146773Ssam esp_print_decodesecret(ndo); 58456893Sfenner } 585127668Sbms 586146773Ssam if (ndo->ndo_sa_list_head == NULL) 58798524Sfenner goto fail; 58856893Sfenner 58956893Sfenner ip = (struct ip *)bp2; 59075115Sfenner switch (IP_V(ip)) { 59156893Sfenner#ifdef INET6 59256893Sfenner case 6: 59356893Sfenner ip6 = (struct ip6_hdr *)bp2; 59456893Sfenner /* we do not attempt to decrypt jumbograms */ 595127668Sbms if (!EXTRACT_16BITS(&ip6->ip6_plen)) 59656893Sfenner goto fail; 59756893Sfenner /* if we can't get nexthdr, we do not need to decrypt it */ 598127668Sbms len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen); 599127668Sbms 600127668Sbms /* see if we can find the SA, and if so, decode it */ 601146773Ssam for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) { 602127668Sbms struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr; 603214478Srpaulo if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) && 604127668Sbms sin6->sin6_family == AF_INET6 && 605127668Sbms memcmp(&sin6->sin6_addr, &ip6->ip6_dst, 606127668Sbms sizeof(struct in6_addr)) == 0) { 607127668Sbms break; 608127668Sbms } 609127668Sbms } 61056893Sfenner break; 61156893Sfenner#endif /*INET6*/ 61256893Sfenner case 4: 61398524Sfenner /* nexthdr & padding are in the last fragment */ 614127668Sbms if (EXTRACT_16BITS(&ip->ip_off) & IP_MF) 61598524Sfenner goto fail; 616127668Sbms len = EXTRACT_16BITS(&ip->ip_len); 617127668Sbms 618127668Sbms /* see if we can find the SA, and if so, decode it */ 619146773Ssam for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) { 620127668Sbms struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr; 621214478Srpaulo if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) && 622127668Sbms sin->sin_family == AF_INET && 623127668Sbms sin->sin_addr.s_addr == ip->ip_dst.s_addr) { 624127668Sbms break; 625127668Sbms } 626127668Sbms } 62756893Sfenner break; 62856893Sfenner default: 62956893Sfenner goto fail; 63056893Sfenner } 63156893Sfenner 632127668Sbms /* if we didn't find the specific one, then look for 633127668Sbms * an unspecified one. 634127668Sbms */ 635127668Sbms if (sa == NULL) 636146773Ssam sa = ndo->ndo_sa_default; 637127668Sbms 638127668Sbms /* if not found fail */ 639127668Sbms if (sa == NULL) 640127668Sbms goto fail; 641127668Sbms 64256893Sfenner /* if we can't get nexthdr, we do not need to decrypt it */ 64356893Sfenner if (ep - bp2 < len) 64456893Sfenner goto fail; 645127668Sbms if (ep - bp2 > len) { 646127668Sbms /* FCS included at end of frame (NetBSD 1.6 or later) */ 647127668Sbms ep = bp2 + len; 648127668Sbms } 64956893Sfenner 650127668Sbms ivoff = (u_char *)(esp + 1) + 0; 651127668Sbms ivlen = sa->ivlen; 652127668Sbms secret = sa->secret; 653127668Sbms espsecret_keylen = sa->secretlen; 654146773Ssam ep = ep - sa->authlen; 65556893Sfenner 656127668Sbms if (sa->evp) { 657127668Sbms memset(&ctx, 0, sizeof(ctx)); 658127668Sbms if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0) 659146773Ssam (*ndo->ndo_warning)(ndo, "espkey init failed"); 66056893Sfenner 661127668Sbms blocksz = EVP_CIPHER_CTX_block_size(&ctx); 66256893Sfenner 663127668Sbms p = ivoff; 664127668Sbms EVP_CipherInit(&ctx, NULL, NULL, p, 0); 665127668Sbms EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen)); 666214478Srpaulo EVP_CIPHER_CTX_cleanup(&ctx); 66756893Sfenner advance = ivoff - (u_char *)esp + ivlen; 668127668Sbms } else 669127668Sbms advance = sizeof(struct newesp); 67056893Sfenner 67156893Sfenner /* sanity check for pad length */ 67256893Sfenner if (ep - bp < *(ep - 2)) 67356893Sfenner goto fail; 67456893Sfenner 67598524Sfenner if (padlen) 67698524Sfenner *padlen = *(ep - 2) + 2; 67798524Sfenner 67856893Sfenner if (nhdr) 67956893Sfenner *nhdr = *(ep - 1); 68056893Sfenner 681146773Ssam (ndo->ndo_printf)(ndo, ": "); 68256893Sfenner return advance; 683127668Sbms#endif 68456893Sfenner 68556893Sfennerfail: 686127668Sbms return -1; 68756893Sfenner} 688146773Ssam 689146773Ssam/* 690146773Ssam * Local Variables: 691146773Ssam * c-style: whitesmith 692146773Ssam * c-basic-offset: 8 693146773Ssam * End: 694146773Ssam */ 695