diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2003-07-17 08:45:38 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2003-07-17 08:45:38 +0000 |
commit | 697c978c9589b5d256576781d6e84074e4e1abb9 (patch) | |
tree | fb219b77a0531e42456144388f0da69c5e8ccaa8 /usr.sbin/tcpdump/print-ipsec.c | |
parent | 5eedaf7b34d80506fcb980c2acb3359f332b3eda (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.c | 144 |
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; |