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;
}
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) {
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;
}
/* 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;
case HMAC_SHA1:
macalg = GNUTLS_MAC_SHA1;
break;
+ case HMAC_SHA256:
+ macalg = GNUTLS_MAC_SHA256;
+ break;
default:
return -EINVAL;
}
/* 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);
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;
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;
}
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 */
#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)) \
case HMAC_SHA1:
macalg = EVP_sha1();
break;
+ case HMAC_SHA256:
+ macalg = EVP_sha256();
+ break;
default:
return -EINVAL;
}
/* 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;
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;
{
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 */
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;
}
} 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"),
/* 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;