411 lines
8.8 KiB
C
411 lines
8.8 KiB
C
/* $NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that: (1) source code distributions
|
|
* retain the above copyright notice and this paragraph in its entirety, (2)
|
|
* distributions including binary code include the above copyright notice and
|
|
* this paragraph in its entirety in the documentation or other materials
|
|
* provided with the distribution, and (3) all advertising materials mentioning
|
|
* features or use of this software display the following acknowledgement:
|
|
* ``This product includes software developed by the University of California,
|
|
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
|
|
* the University nor the names of its contributors may be used to endorse
|
|
* or promote products derived from this software without specific prior
|
|
* written permission.
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static const char rcsid[] =
|
|
"@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.20.4.2 2002/02/22 09:26:27 guy Exp $ (LBL)";
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#ifdef HAVE_LIBCRYPTO
|
|
#include <openssl/des.h>
|
|
#include <openssl/blowfish.h>
|
|
#ifdef HAVE_RC5_H
|
|
#include <openssl/rc5.h>
|
|
#endif
|
|
#ifdef HAVE_CAST_H
|
|
#include <openssl/cast.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "ip.h"
|
|
#include "esp.h"
|
|
#ifdef INET6
|
|
#include "ip6.h"
|
|
#endif
|
|
|
|
#define AVOID_CHURN 1
|
|
#include "interface.h"
|
|
#include "addrtoname.h"
|
|
|
|
static struct esp_algorithm *espsecret_xform=NULL; /* cache of decoded alg. */
|
|
static char *espsecret_key=NULL;
|
|
|
|
|
|
enum cipher { NONE,
|
|
DESCBC,
|
|
BLOWFISH,
|
|
RC5,
|
|
CAST128,
|
|
DES3CBC};
|
|
|
|
|
|
|
|
struct esp_algorithm {
|
|
char *name;
|
|
enum cipher algo;
|
|
int ivlen;
|
|
int authlen;
|
|
int replaysize;
|
|
};
|
|
|
|
struct esp_algorithm esp_xforms[]={
|
|
{"none", NONE, 0, 0, 0},
|
|
{"des-cbc", DESCBC, 8, 0, 0},
|
|
{"des-cbc-hmac96", DESCBC, 8, 12, 4},
|
|
{"blowfish-cbc", BLOWFISH,8, 0, 0},
|
|
{"blowfish-cbc-hmac96", BLOWFISH,8, 12, 4},
|
|
{"rc5-cbc", RC5, 8, 0, 0},
|
|
{"rc5-cbc-hmac96", RC5, 8, 12, 4},
|
|
{"cast128-cbc", CAST128, 8, 0, 0},
|
|
{"cast128-cbc-hmac96", CAST128, 8, 12, 4},
|
|
{"3des-cbc-hmac96", DES3CBC, 8, 12, 4},
|
|
};
|
|
|
|
static int hexdigit(char hex)
|
|
{
|
|
if(hex >= '0' && hex <= '9') {
|
|
return (hex - '0');
|
|
} else if(hex >= 'A' && hex <= 'F') {
|
|
return (hex - 'A' + 10);
|
|
} else if(hex >= 'a' && hex <= 'f') {
|
|
return (hex - 'a' + 10);
|
|
} else {
|
|
printf("invalid hex digit %c in espsecret\n", hex);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int hex2byte(char *hexstring)
|
|
{
|
|
int byte;
|
|
|
|
byte = (hexdigit(hexstring[0]) << 4) +
|
|
hexdigit(hexstring[1]);
|
|
return byte;
|
|
}
|
|
|
|
|
|
static void esp_print_decodesecret(void)
|
|
{
|
|
char *colon;
|
|
int len, i;
|
|
struct esp_algorithm *xf;
|
|
|
|
if(espsecret == NULL) {
|
|
/* set to NONE transform */
|
|
espsecret_xform = esp_xforms;
|
|
return;
|
|
}
|
|
|
|
if(espsecret_key != NULL) {
|
|
return;
|
|
}
|
|
|
|
colon = strchr(espsecret, ':');
|
|
if(colon == NULL) {
|
|
printf("failed to decode espsecret: %s\n",
|
|
espsecret);
|
|
/* set to NONE transform */
|
|
espsecret_xform = esp_xforms;
|
|
}
|
|
|
|
len = colon - espsecret;
|
|
xf = esp_xforms;
|
|
while(xf->name && strncasecmp(espsecret, xf->name, len)!=0) {
|
|
xf++;
|
|
}
|
|
if(xf->name == NULL) {
|
|
printf("failed to find cipher algo %s\n",
|
|
espsecret);
|
|
espsecret_xform = esp_xforms;
|
|
return;
|
|
}
|
|
espsecret_xform = xf;
|
|
|
|
colon++;
|
|
if(colon[0]=='0' && colon[1]=='x') {
|
|
/* decode some hex! */
|
|
colon+=2;
|
|
len = strlen(colon) / 2;
|
|
espsecret_key = (char *)malloc(len);
|
|
if(espsecret_key == NULL) {
|
|
fprintf(stderr, "%s: ran out of memory (%d) to allocate secret key\n",
|
|
program_name, len);
|
|
exit(2);
|
|
}
|
|
i = 0;
|
|
while(colon[0] != '\0' && colon[1]!='\0') {
|
|
espsecret_key[i]=hex2byte(colon);
|
|
colon+=2;
|
|
i++;
|
|
}
|
|
} else {
|
|
espsecret_key = colon;
|
|
}
|
|
}
|
|
|
|
int
|
|
esp_print(register const u_char *bp, register const u_char *bp2,
|
|
int *nhdr, int *padlen)
|
|
{
|
|
register const struct esp *esp;
|
|
register const u_char *ep;
|
|
u_int32_t spi;
|
|
struct ip *ip = NULL;
|
|
#ifdef INET6
|
|
struct ip6_hdr *ip6 = NULL;
|
|
#endif
|
|
int advance;
|
|
int len;
|
|
char *secret;
|
|
int ivlen = 0;
|
|
u_char *ivoff;
|
|
u_char *p;
|
|
|
|
esp = (struct esp *)bp;
|
|
spi = (u_int32_t)ntohl(esp->esp_spi);
|
|
secret = NULL;
|
|
|
|
#if 0
|
|
/* keep secret out of a register */
|
|
p = (u_char *)&secret;
|
|
#endif
|
|
|
|
/* 'ep' points to the end of available data. */
|
|
ep = snapend;
|
|
|
|
if ((u_char *)(esp + 1) >= ep - sizeof(struct esp)) {
|
|
fputs("[|ESP]", stdout);
|
|
goto fail;
|
|
}
|
|
printf("ESP(spi=0x%08x", spi);
|
|
printf(",seq=0x%x", (u_int32_t)ntohl(*(u_int32_t *)(esp + 1)));
|
|
printf(")");
|
|
|
|
/* if we don't have decryption key, we can't decrypt this packet. */
|
|
if (!espsecret)
|
|
goto fail;
|
|
|
|
if(!espsecret_xform) {
|
|
esp_print_decodesecret();
|
|
}
|
|
if(espsecret_xform->algo == NONE) {
|
|
goto fail;
|
|
}
|
|
|
|
ip = (struct ip *)bp2;
|
|
switch (IP_V(ip)) {
|
|
#ifdef INET6
|
|
case 6:
|
|
ip6 = (struct ip6_hdr *)bp2;
|
|
ip = NULL;
|
|
/* we do not attempt to decrypt jumbograms */
|
|
if (!ntohs(ip6->ip6_plen))
|
|
goto fail;
|
|
/* if we can't get nexthdr, we do not need to decrypt it */
|
|
len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
|
|
break;
|
|
#endif /*INET6*/
|
|
case 4:
|
|
/* nexthdr & padding are in the last fragment */
|
|
if (ntohs(ip->ip_off) & IP_MF)
|
|
goto fail;
|
|
#ifdef INET6
|
|
ip6 = NULL;
|
|
#endif
|
|
len = ntohs(ip->ip_len);
|
|
break;
|
|
default:
|
|
goto fail;
|
|
}
|
|
|
|
/* if we can't get nexthdr, we do not need to decrypt it */
|
|
if (ep - bp2 < len)
|
|
goto fail;
|
|
|
|
ivoff = (u_char *)(esp + 1) + espsecret_xform->replaysize;
|
|
ivlen = espsecret_xform->ivlen;
|
|
secret = espsecret_key;
|
|
|
|
switch (espsecret_xform->algo) {
|
|
case DESCBC:
|
|
#ifdef HAVE_LIBCRYPTO
|
|
{
|
|
u_char iv[8];
|
|
des_key_schedule schedule;
|
|
|
|
switch (ivlen) {
|
|
case 4:
|
|
memcpy(iv, ivoff, 4);
|
|
memcpy(&iv[4], ivoff, 4);
|
|
p = &iv[4];
|
|
*p++ ^= 0xff;
|
|
*p++ ^= 0xff;
|
|
*p++ ^= 0xff;
|
|
*p++ ^= 0xff;
|
|
break;
|
|
case 8:
|
|
memcpy(iv, ivoff, 8);
|
|
break;
|
|
default:
|
|
goto fail;
|
|
}
|
|
|
|
des_check_key = 0;
|
|
des_set_key((void *)secret, schedule);
|
|
|
|
p = ivoff + ivlen;
|
|
des_cbc_encrypt((void *)p, (void *)p,
|
|
(long)(ep - p), schedule, (void *)iv,
|
|
DES_DECRYPT);
|
|
advance = ivoff - (u_char *)esp + ivlen;
|
|
break;
|
|
}
|
|
#else
|
|
goto fail;
|
|
#endif /*HAVE_LIBCRYPTO*/
|
|
|
|
case BLOWFISH:
|
|
#ifdef HAVE_LIBCRYPTO
|
|
{
|
|
BF_KEY schedule;
|
|
|
|
BF_set_key(&schedule, strlen(secret), secret);
|
|
|
|
p = ivoff + ivlen;
|
|
BF_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
|
|
BF_DECRYPT);
|
|
advance = ivoff - (u_char *)esp + ivlen;
|
|
break;
|
|
}
|
|
#else
|
|
goto fail;
|
|
#endif /*HAVE_LIBCRYPTO*/
|
|
|
|
case RC5:
|
|
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_RC5_H)
|
|
{
|
|
RC5_32_KEY schedule;
|
|
|
|
RC5_32_set_key(&schedule, strlen(secret), secret,
|
|
RC5_16_ROUNDS);
|
|
|
|
p = ivoff + ivlen;
|
|
RC5_32_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
|
|
RC5_DECRYPT);
|
|
advance = ivoff - (u_char *)esp + ivlen;
|
|
break;
|
|
}
|
|
#else
|
|
goto fail;
|
|
#endif /*HAVE_LIBCRYPTO*/
|
|
|
|
case CAST128:
|
|
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_CAST_H) && !defined(HAVE_BUGGY_CAST128)
|
|
{
|
|
CAST_KEY schedule;
|
|
|
|
CAST_set_key(&schedule, strlen(secret), secret);
|
|
|
|
p = ivoff + ivlen;
|
|
CAST_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
|
|
CAST_DECRYPT);
|
|
advance = ivoff - (u_char *)esp + ivlen;
|
|
break;
|
|
}
|
|
#else
|
|
goto fail;
|
|
#endif /*HAVE_LIBCRYPTO*/
|
|
|
|
case DES3CBC:
|
|
#if defined(HAVE_LIBCRYPTO)
|
|
{
|
|
des_key_schedule s1, s2, s3;
|
|
|
|
des_check_key = 1;
|
|
des_set_odd_parity((void *)secret);
|
|
des_set_odd_parity((void *)(secret + 8));
|
|
des_set_odd_parity((void *)(secret + 16));
|
|
if(des_set_key((void *)secret, s1) != 0) {
|
|
printf("failed to schedule key 1\n");
|
|
}
|
|
if(des_set_key((void *)(secret + 8), s2)!=0) {
|
|
printf("failed to schedule key 2\n");
|
|
}
|
|
if(des_set_key((void *)(secret + 16), s3)!=0) {
|
|
printf("failed to schedule key 3\n");
|
|
}
|
|
|
|
p = ivoff + ivlen;
|
|
des_ede3_cbc_encrypt((void *)p, (void *)p,
|
|
(long)(ep - p),
|
|
s1, s2, s3,
|
|
(void *)ivoff, DES_DECRYPT);
|
|
advance = ivoff - (u_char *)esp + ivlen;
|
|
break;
|
|
}
|
|
#else
|
|
goto fail;
|
|
#endif /*HAVE_LIBCRYPTO*/
|
|
|
|
case NONE:
|
|
default:
|
|
advance = sizeof(struct esp) + espsecret_xform->replaysize;
|
|
break;
|
|
}
|
|
|
|
ep = ep - espsecret_xform->authlen;
|
|
/* sanity check for pad length */
|
|
if (ep - bp < *(ep - 2))
|
|
goto fail;
|
|
|
|
if (padlen)
|
|
*padlen = *(ep - 2) + 2;
|
|
|
|
if (nhdr)
|
|
*nhdr = *(ep - 1);
|
|
|
|
printf(": ");
|
|
return advance;
|
|
|
|
fail:
|
|
if (nhdr)
|
|
*nhdr = -1;
|
|
return 65536;
|
|
}
|