summaryrefslogtreecommitdiff
path: root/usr.sbin/tcpdump/print-ipsec.c
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2003-07-17 08:45:38 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2003-07-17 08:45:38 +0000
commit697c978c9589b5d256576781d6e84074e4e1abb9 (patch)
treefb219b77a0531e42456144388f0da69c5e8ccaa8 /usr.sbin/tcpdump/print-ipsec.c
parent5eedaf7b34d80506fcb980c2acb3359f332b3eda (diff)
add support for ESP decryption; ok deraadt@; feedback mickey@;
many manpage fixes from jmc@
Diffstat (limited to 'usr.sbin/tcpdump/print-ipsec.c')
-rw-r--r--usr.sbin/tcpdump/print-ipsec.c144
1 files changed, 141 insertions, 3 deletions
diff --git a/usr.sbin/tcpdump/print-ipsec.c b/usr.sbin/tcpdump/print-ipsec.c
index b1a3f8d797c..fb223e21abd 100644
--- a/usr.sbin/tcpdump/print-ipsec.c
+++ b/usr.sbin/tcpdump/print-ipsec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: print-ipsec.c,v 1.7 2003/02/20 23:39:20 jason Exp $ */
+/* $OpenBSD: print-ipsec.c,v 1.8 2003/07/17 08:45:37 markus Exp $ */
/*
* Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
@@ -28,7 +28,7 @@
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/print-ipsec.c,v 1.7 2003/02/20 23:39:20 jason Exp $ (XXX)";
+ "@(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/print-ipsec.c,v 1.8 2003/07/17 08:45:37 markus Exp $ (XXX)";
#endif
#include <sys/param.h>
@@ -53,6 +53,9 @@ static const char rcsid[] =
#include "interface.h"
#include "extract.h" /* must come after interface.h */
+#include <openssl/evp.h>
+#include <ctype.h>
+
/*
* IPsec/ESP header
*/
@@ -61,6 +64,138 @@ struct esp_hdr {
u_int esp_seq;
};
+static int espinit = 0;
+static int espauthlen = 12;
+static EVP_CIPHER_CTX ctx;
+
+int
+esp_init (char *espspec)
+{
+ const EVP_CIPHER *evp;
+ char *p, *espkey, s[3], name[1024];
+ u_char *key;
+ int i, klen, len;
+
+ evp = EVP_aes_128_cbc(); /* default */
+ espkey = espspec;
+ if ((p = strchr(espspec, ':')) != NULL) {
+ len = p - espspec;
+ if (len >= sizeof(name))
+ error("espalg too long");
+ memcpy(name, espspec, len);
+ name[len] = '\0';
+ espkey = p + 1;
+
+ /* strip auth alg */
+ espauthlen = 0;
+ if ((p = strstr(name, "-hmac96")) != NULL) {
+ espauthlen = 12;
+ *p = '\0';
+ }
+ OpenSSL_add_all_algorithms();
+ if ((evp = EVP_get_cipherbyname(name)) == NULL)
+ error("espalg `%s' not supported", name);
+ }
+ klen = EVP_CIPHER_key_length(evp);
+ if (strlen(espkey) != klen * 2)
+ error("espkey size mismatch, %d bytes needed", klen);
+ if ((key = malloc(klen)) == NULL)
+ error("malloc failed");
+ for (i = 0; i < klen; i++) {
+ s[0] = espkey[2*i];
+ s[1] = espkey[2*i + 1];
+ s[2] = 0;
+ if (!isxdigit(s[0]) || !isxdigit(s[1]))
+ error("espkey must be specified in hex");
+ key[i] = strtoul(s, NULL, 16);
+ }
+ EVP_CIPHER_CTX_init(&ctx);
+ if (EVP_CipherInit(&ctx, evp, key, NULL, 0) < 0) {
+ free(key);
+ error("espkey init failed");
+ }
+ free(key);
+ espinit = 1;
+ return (0);
+}
+
+void
+esp_decrypt (const u_char *bp, u_int len, const u_char *bp2)
+{
+ const struct ip *ip;
+ u_char *data, pad, nh;
+ int blocksz;
+
+ ip = (const struct ip *)bp2;
+
+ blocksz = EVP_CIPHER_CTX_block_size(&ctx);
+
+ /* Skip fragments and short packets */
+ if (ntohs(ip->ip_off) & 0x3fff)
+ return;
+ if (snapend - bp < len) {
+ printf(" [|esp]");
+ return;
+ }
+ /*
+ * Skip ESP header and ignore authentication trailer.
+ * For decryption we need at least 2 blocks: IV and
+ * one cipher block.
+ */
+ if (len < sizeof(struct esp_hdr) + espauthlen + 2 * blocksz) {
+ printf(" [|esp]");
+ return;
+ }
+
+ data = (char *)bp;
+ data += sizeof(struct esp_hdr);
+ len -= sizeof(struct esp_hdr);
+ len -= espauthlen;
+
+ /* the first block contains the IV */
+ EVP_CipherInit(&ctx, NULL, NULL, data, 0);
+ len -= blocksz;
+ data += blocksz;
+
+ /* decrypt remaining payload */
+ EVP_Cipher(&ctx, data, data, len);
+
+ nh = data[len - 1];
+ pad = data[len - 2];
+
+ /* verify padding */
+ if (pad + 2 > len)
+ return;
+ if (data[len - 3] != pad)
+ return;
+ if (vflag > 1)
+ printf(" pad %d", pad);
+ len -= (pad + 2);
+ printf(": ");
+ switch (nh) {
+ case IPPROTO_TCP:
+ tcp_print(data, len, bp2);
+ break;
+ case IPPROTO_UDP:
+ udp_print(data, len, bp2);
+ break;
+ case IPPROTO_IPV6:
+ ip6_print(data, len);
+ break;
+ case IPPROTO_IPV4:
+ ip_print(data, len);
+ break;
+ case IPPROTO_ICMP:
+ icmp_print(data, bp2);
+ break;
+ default:
+ printf("ip-proto-%d %d", nh, len);
+ break;
+ }
+ if (vflag)
+ printf(" (esp)");
+}
+
void
esp_print (register const u_char *bp, register u_int len,
register const u_char *bp2)
@@ -82,6 +217,9 @@ esp_print (register const u_char *bp, register u_int len,
printf(" spi 0x%08X seq %d len %d",
ntohl(esp->esp_spi), ntohl(esp->esp_seq), len);
+
+ if (espinit)
+ esp_decrypt(bp, len, bp2);
}
/*
@@ -109,7 +247,7 @@ ah_print (register const u_char *bp, register u_int len,
ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst));
if (pl_len < sizeof(struct ah_hdr)) {
- printf("[|esp]");
+ printf("[|ah]");
return;
}
ah = (const struct ah_hdr *)bp;