Skip to content

Commit

Permalink
Implement ESP encryption
Browse files Browse the repository at this point in the history
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Jan 26, 2015
1 parent 2fea605 commit 60da8a8
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
49 changes: 47 additions & 2 deletions gnutls-esp.c
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand All @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
2 changes: 1 addition & 1 deletion mainloop.c
Expand Up @@ -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;
Expand Down
17 changes: 14 additions & 3 deletions openconnect-internal.h
Expand Up @@ -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];
};
};
Expand Down Expand Up @@ -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];
};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 60da8a8

Please sign in to comment.