From: David Woodhouse Date: Sat, 8 Jun 2019 15:20:37 +0000 (+0100) Subject: Add HMAC-SHA256-128 support for ESP X-Git-Tag: v8.04~51 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=8349cfdecdeb0b3a1d713a3ed3de109f84f1f305;p=users%2Fdwmw2%2Fopenconnect.git Add HMAC-SHA256-128 support for ESP Signed-off-by: David Woodhouse --- diff --git a/esp.c b/esp.c index 1b907435..a5cbba7f 100644 --- a/esp.c +++ b/esp.c @@ -34,22 +34,25 @@ int print_esp_keys(struct openconnect_info *vpninfo, const char *name, struct es char enckey[256], mackey[256]; switch(vpninfo->esp_enc) { - case 0x02: + case ENC_AES_128_CBC: enctype = "AES-128-CBC (RFC3602)"; break; - case 0x05: + case ENC_AES_256_CBC: enctype = "AES-256-CBC (RFC3602)"; break; default: return -EINVAL; } switch(vpninfo->esp_hmac) { - case 0x01: + case HMAC_MD5: mactype = "HMAC-MD5-96 (RFC2403)"; break; - case 0x02: + case HMAC_SHA1: mactype = "HMAC-SHA-1-96 (RFC2404)"; break; + case HMAC_SHA256: + mactype = "HMAC-SHA-256-128 (RFC4868)"; + break; default: return -EINVAL; } @@ -140,10 +143,10 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable) work_done = 1; /* both supported algos (SHA1 and MD5) have 12-byte MAC lengths (RFC2403 and RFC2404) */ - if (len <= sizeof(pkt->esp) + 12) + if (len <= sizeof(pkt->esp) + vpninfo->hmac_out_len) continue; - len -= sizeof(pkt->esp) + 12; + len -= sizeof(pkt->esp) + vpninfo->hmac_out_len; pkt->len = len; if (pkt->esp.spi == esp->spi) { @@ -358,6 +361,11 @@ int openconnect_setup_esp_keys(struct openconnect_info *vpninfo, int new_keys) if (!vpninfo->dtls_addr) return -EINVAL; + if (vpninfo->esp_hmac == HMAC_SHA256) + vpninfo->hmac_out_len = 16; + else /* MD5 and SHA1 */ + vpninfo->hmac_out_len = 12; + if (new_keys) { vpninfo->old_esp_maxseq = vpninfo->esp_in[vpninfo->current_esp_in].seq + 32; vpninfo->current_esp_in ^= 1; @@ -382,7 +390,7 @@ int openconnect_setup_esp_keys(struct openconnect_info *vpninfo, int new_keys) } /* This is the minimum; some implementations may increase it */ - vpninfo->pkt_trailer = 17 + 16 + 20; /* 17 for pad, 16 for IV, 20 for HMAC (of which we send 12) */ + vpninfo->pkt_trailer = MAX_ESP_PAD + MAX_IV_SIZE + MAX_HMAC_SIZE; vpninfo->esp_out.seq = vpninfo->esp_out.seq_backlog = 0; esp_in->seq = esp_in->seq_backlog = 0; diff --git a/gnutls-esp.c b/gnutls-esp.c index 08adc115..fbaeae2f 100644 --- a/gnutls-esp.c +++ b/gnutls-esp.c @@ -94,6 +94,9 @@ int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp_out, stru case HMAC_SHA1: macalg = GNUTLS_MAC_SHA1; break; + case HMAC_SHA256: + macalg = GNUTLS_MAC_SHA256; + break; default: return -EINVAL; } @@ -116,7 +119,7 @@ int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp_out, stru /* pkt->len shall be the *payload* length. Omitting the header and the 12-byte HMAC */ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct pkt *pkt) { - unsigned char hmac_buf[20]; + unsigned char hmac_buf[MAX_HMAC_SIZE]; int err; err = gnutls_hmac(esp->hmac, &pkt->esp, sizeof(pkt->esp) + pkt->len); @@ -127,7 +130,7 @@ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct return -EIO; } gnutls_hmac_output(esp->hmac, hmac_buf); - if (memcmp(hmac_buf, pkt->data + pkt->len, 12)) { + if (memcmp(hmac_buf, pkt->data + pkt->len, vpninfo->hmac_out_len)) { vpn_progress(vpninfo, PRG_DEBUG, _("Received ESP packet with invalid HMAC\n")); return -EINVAL; @@ -186,5 +189,5 @@ int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt) memcpy(vpninfo->esp_out.iv, pkt->data + pkt->len + padlen + 2, blksize); gnutls_cipher_encrypt(vpninfo->esp_out.cipher, vpninfo->esp_out.iv, blksize); - return sizeof(pkt->esp) + pkt->len + padlen + 2 + 12; + return sizeof(pkt->esp) + pkt->len + padlen + 2 + vpninfo->hmac_out_len; } diff --git a/openconnect-internal.h b/openconnect-internal.h index 75d93a79..a942a7ec 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -381,6 +381,7 @@ struct openconnect_info { struct esp esp_out; int enc_key_len; int hmac_key_len; + int hmac_out_len; uint32_t esp_magic; /* GlobalProtect magic ping address (network-endian) */ int tncc_fd; /* For Juniper TNCC */ @@ -713,11 +714,17 @@ struct openconnect_info { #define AC_PKT_COMPRESSED 8 /* Compressed data */ #define AC_PKT_TERM_SERVER 9 /* Server kick */ -/* Encryption and HMAC algorithms (matching Juniper's binary encoding) */ +/* Encryption and HMAC algorithms (matching Juniper/Pulse binary encoding) */ #define ENC_AES_128_CBC 2 #define ENC_AES_256_CBC 5 + #define HMAC_MD5 1 #define HMAC_SHA1 2 +#define HMAC_SHA256 3 + +#define MAX_HMAC_SIZE 32 /* SHA256 */ +#define MAX_IV_SIZE 16 +#define MAX_ESP_PAD 17 /* Including the next-header field */ #define vpn_progress(_v, lvl, ...) do { \ if ((_v)->verbose >= (lvl)) \ diff --git a/openssl-esp.c b/openssl-esp.c index 364bb283..f03a033e 100644 --- a/openssl-esp.c +++ b/openssl-esp.c @@ -130,6 +130,9 @@ int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp_out, stru case HMAC_SHA1: macalg = EVP_sha1(); break; + case HMAC_SHA256: + macalg = EVP_sha256(); + break; default: return -EINVAL; } @@ -150,7 +153,7 @@ int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp_out, stru /* pkt->len shall be the *payload* length. Omitting the header and the 12-byte HMAC */ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct pkt *pkt) { - unsigned char hmac_buf[20]; + unsigned char hmac_buf[MAX_HMAC_SIZE]; unsigned int hmac_len = sizeof(hmac_buf); int crypt_len = pkt->len; @@ -158,7 +161,7 @@ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct HMAC_Update(esp->hmac, (void *)&pkt->esp, sizeof(pkt->esp) + pkt->len); HMAC_Final(esp->hmac, hmac_buf, &hmac_len); - if (memcmp(hmac_buf, pkt->data + pkt->len, 12)) { + if (memcmp(hmac_buf, pkt->data + pkt->len, vpninfo->hmac_out_len)) { vpn_progress(vpninfo, PRG_DEBUG, _("Received ESP packet with invalid HMAC\n")); return -EINVAL; @@ -190,7 +193,7 @@ int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt) { int i, padlen; int blksize = 16; - unsigned int hmac_len = 20; + unsigned int hmac_len = vpninfo->hmac_out_len; int crypt_len; /* This gets much more fun if the IV is variable-length */ @@ -220,5 +223,5 @@ int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt) EVP_EncryptUpdate(vpninfo->esp_out.cipher, vpninfo->esp_out.iv, &blksize, pkt->data + crypt_len + hmac_len - blksize, blksize); - return sizeof(pkt->esp) + crypt_len + 12; + return sizeof(pkt->esp) + crypt_len + vpninfo->hmac_out_len; } diff --git a/pulse.c b/pulse.c index fbd351b4..8dd9cbd0 100644 --- a/pulse.c +++ b/pulse.c @@ -378,6 +378,9 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type, } else if (val == HMAC_SHA1) { mactype = "SHA1"; vpninfo->hmac_key_len = 20; + } else if (val == HMAC_SHA256) { + mactype = "SHA256"; + vpninfo->hmac_key_len = 32; } else mactype = "unknown"; vpn_progress(vpninfo, PRG_DEBUG, _("ESP HMAC: 0x%04x (%s)\n"), @@ -1049,8 +1052,10 @@ static int pulse_authenticate(struct openconnect_info *vpninfo, int connecting) /* IF-T version request. */ buf_truncate(reqbuf); buf_append_ift_hdr(reqbuf, VENDOR_TCG, IFT_VERSION_REQUEST); - /* min=1, max=1, preferred version=1 */ - buf_append_be32(reqbuf, 0x00010101); + /* Min version 1, max 2, preferred 2. Not that we actually do v2; the auth is + * still all IF-T/TLS v1. But the server won't offer us HMAC-SHA256 unless we + * advertise v2 */ + buf_append_be32(reqbuf, 0x00010202); ret = send_ift_packet(vpninfo, reqbuf); if (ret) goto out;