Commit 60da8a84 authored by David Woodhouse's avatar David Woodhouse

Implement ESP encryption

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 2fea605d
......@@ -75,6 +75,7 @@ static int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp,
gnutls_strerror(err));
destroy_esp_ciphers(esp);
}
esp->seq = 0;
return 0;
}
......@@ -109,7 +110,7 @@ int setup_esp_keys(struct openconnect_info *vpninfo)
return -EINVAL;
}
ret = gnutls_rnd(GNUTLS_RND_NONCE, &vpninfo->esp_in.spi,
ret = gnutls_rnd(GNUTLS_RND_RANDOM, &vpninfo->esp_in.spi,
sizeof(vpninfo->esp_in.secrets) + sizeof(vpninfo->esp_in.spi));
if (ret) {
vpn_progress(vpninfo, PRG_ERR,
......@@ -129,6 +130,7 @@ int setup_esp_keys(struct openconnect_info *vpninfo)
}
vpninfo->dtls_state = DTLS_SECRET;
vpninfo->pkt_trailer = 16 + 20; /* 16 for pad, 20 for HMAC (of which we use 16) */
return 0;
}
......@@ -137,7 +139,7 @@ int decrypt_and_queue_esp_packet(struct openconnect_info *vpninfo, unsigned char
{
struct pkt *pkt;
unsigned char hmac_buf[20];
const int ivsize = 16; /* We don't support anything different... yet. */
const int ivsize = sizeof(pkt->esp.iv);
if (len < 20 + ivsize)
return -EINVAL;
......@@ -193,3 +195,46 @@ int decrypt_and_queue_esp_packet(struct openconnect_info *vpninfo, unsigned char
queue_packet(&vpninfo->incoming_queue, pkt);
return 0;
}
int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt)
{
int i, padlen;
const int blksize = 16;
int err;
/* This gets much more fun if the IV is variable-length */
memcpy(pkt->esp.spi, vpninfo->esp_out.spi, 4);
pkt->esp.seq = vpninfo->esp_out.seq++;
err = gnutls_rnd(GNUTLS_RND_RANDOM, pkt->esp.iv, sizeof(pkt->esp.iv));
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to generate ESP packet IV: %s\n"),
gnutls_strerror(err));
return -EIO;
}
padlen = blksize - 1 - ((pkt->len + 1) % blksize);
for (i=0; i<padlen; i++)
pkt->data[pkt->len + i] = i + 1;
pkt->data[pkt->len + padlen] = padlen;
pkt->data[pkt->len + padlen + 1] = 0x04; /* Legacy IP */
gnutls_cipher_set_iv(vpninfo->esp_out.cipher, pkt->esp.iv, sizeof(pkt->esp.iv));
err = gnutls_cipher_encrypt(vpninfo->esp_out.cipher, pkt->data, pkt->len + padlen + 2);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to encrypt ESP packet: %s\n"),
gnutls_strerror(err));
return -EIO;
}
err = gnutls_hmac(vpninfo->esp_out.hmac, pkt->data, pkt->len + padlen + 2);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to calculate HMAC for ESP packet: %s\n"),
gnutls_strerror(err));
return -EIO;
}
gnutls_hmac_output(vpninfo->esp_out.hmac, pkt->data + pkt->len + padlen + 2);
return sizeof(pkt->esp) + pkt->len + padlen + 2 + 12;
}
......@@ -59,7 +59,7 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout)
int len = vpninfo->ip_info.mtu;
if (!out_pkt) {
out_pkt = malloc(sizeof(struct pkt) + len);
out_pkt = malloc(sizeof(struct pkt) + len + vpninfo->pkt_trailer);
if (!out_pkt) {
vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
break;
......
......@@ -122,9 +122,17 @@ struct pkt {
int len;
struct pkt *next;
union {
unsigned char oncp_hdr[22];
struct {
unsigned char pad[14];
unsigned char spi[4];
uint32_t seq;
unsigned char iv[16];
} esp;
struct {
unsigned char oncp_pad[2];
unsigned char oncp_hdr[22];
};
struct {
unsigned char pad[16];
unsigned char hdr[8];
};
};
......@@ -244,6 +252,7 @@ struct esp {
#else
#error No OpenSSL support for ESP yet
#endif
uint32_t seq;
unsigned char spi[4];
unsigned char secrets[0x40];
};
......@@ -431,7 +440,8 @@ struct openconnect_info {
struct pkt *cstp_pkt;
struct pkt *dtls_pkt;
struct pkt *tun_pkt;
int pkt_trailer; /* How many bytes after payload for encryption (ESP HMAC) */
z_stream inflate_strm;
uint32_t inflate_adler32;
z_stream deflate_strm;
......@@ -752,6 +762,7 @@ int load_pkcs11_certificate(struct openconnect_info *vpninfo);
int setup_esp_keys(struct openconnect_info *vpninfo);
void destroy_esp_ciphers(struct esp *esp);
int decrypt_and_queue_esp_packet(struct openconnect_info *vpninfo, unsigned char *esp, int len);
int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt);
/* {gnutls,openssl}.c */
int ssl_nonblock_read(struct openconnect_info *vpninfo, void *buf, int maxlen);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment