[PATCH v3] store length of ESP encryption and HMAC keys so that they can be manipulated separately for both Juniper and GP

Daniel Lenski dlenski at gmail.com
Fri May 26 16:57:14 PDT 2017


Shame on me!!! I tested that this built and worked correctly only with
GnuTLS, not OpenSSL.

David,
Looks like you already caught and patched it yourself:
http://git.infradead.org/users/dwmw2/openconnect.git/blobdiff/b2b1dd0702239d415943cea6f821a345e0d50b63..d8b283f168c8e9574a821eef077b40984fae1026:/openssl-esp.c

A user of openconnect-gp ran into this as well. Sorry about that. :-(

-Dan

On Sun, May 14, 2017 at 9:22 PM, Daniel Lenski <dlenski at gmail.com> wrote:
> David Woodhouse wrote:
>> Daniel Lenski wrote:
>>> -       unsigned char secrets[0x40];
>>> +       unsigned char secrets[0x40]; /* Encryption key bytes, then HMAC key bytes */
>>
>> You're allowed to object to that horridness and split it into two
>> separate fields for the encryption and HMAC keys, instead of just
>> documenting it.
>>
>> In fact, one might argue that would be the better approach...
>
> Signed-off-by: Daniel Lenski <dlenski at gmail.com>
> ---
>  esp.c                  | 13 ++++---------
>  gnutls-esp.c           |  7 ++++---
>  oncp.c                 | 37 +++++++++++++++++++++++++++----------
>  openconnect-internal.h | 11 ++++++++++-
>  openssl-esp.c          |  5 +++--
>  5 files changed, 48 insertions(+), 25 deletions(-)
>
> diff --git a/esp.c b/esp.c
> index 44c9407..30ec442 100644
> --- a/esp.c
> +++ b/esp.c
> @@ -32,16 +32,13 @@ int print_esp_keys(struct openconnect_info *vpninfo, const char *name, struct es
>         int i;
>         const char *enctype, *mactype;
>         char enckey[256], mackey[256];
> -       int enclen, maclen;
>
>         switch(vpninfo->esp_enc) {
>         case 0x02:
>                 enctype = "AES-128-CBC (RFC3602)";
> -               enclen = 16;
>                 break;
>         case 0x05:
>                 enctype = "AES-256-CBC (RFC3602)";
> -               enclen = 32;
>                 break;
>         default:
>                 return -EINVAL;
> @@ -49,20 +46,18 @@ int print_esp_keys(struct openconnect_info *vpninfo, const char *name, struct es
>         switch(vpninfo->esp_hmac) {
>         case 0x01:
>                 mactype = "HMAC-MD5-96 (RFC2403)";
> -               maclen = 16;
>                 break;
>         case 0x02:
>                 mactype = "HMAC-SHA-1-96 (RFC2404)";
> -               maclen = 20;
>                 break;
>         default:
>                 return -EINVAL;
>         }
>
> -       for (i = 0; i < enclen; i++)
> -               sprintf(enckey + (2 * i), "%02x", esp->secrets[i]);
> -       for (i = 0; i < maclen; i++)
> -               sprintf(mackey + (2 * i), "%02x", esp->secrets[enclen + i]);
> +       for (i = 0; i < vpninfo->enc_key_len; i++)
> +               sprintf(enckey + (2 * i), "%02x", esp->enc_key[i]);
> +       for (i = 0; i < vpninfo->hmac_key_len; i++)
> +               sprintf(mackey + (2 * i), "%02x", esp->hmac_key[i]);
>
>         vpn_progress(vpninfo, PRG_TRACE,
>                      _("Parameters for %s ESP: SPI 0x%08x\n"),
> diff --git a/gnutls-esp.c b/gnutls-esp.c
> index 1ad4e60..f3fd499 100644
> --- a/gnutls-esp.c
> +++ b/gnutls-esp.c
> @@ -48,7 +48,7 @@ static int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp,
>         destroy_esp_ciphers(esp);
>
>         enc_key.size = gnutls_cipher_get_key_size(encalg);
> -       enc_key.data = esp->secrets;
> +       enc_key.data = esp->enc_key;
>
>         err = gnutls_cipher_init(&esp->cipher, encalg, &enc_key, NULL);
>         if (err) {
> @@ -59,7 +59,7 @@ static int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp,
>         }
>
>         err = gnutls_hmac_init(&esp->hmac, macalg,
> -                              esp->secrets + enc_key.size,
> +                              esp->hmac_key,
>                                gnutls_hmac_get_len(macalg));
>         if (err) {
>                 vpn_progress(vpninfo, PRG_ERR,
> @@ -111,7 +111,8 @@ int setup_esp_keys(struct openconnect_info *vpninfo)
>         esp_in = &vpninfo->esp_in[vpninfo->current_esp_in];
>
>         if ((ret = gnutls_rnd(GNUTLS_RND_NONCE, &esp_in->spi, sizeof(esp_in->spi))) ||
> -           (ret = gnutls_rnd(GNUTLS_RND_RANDOM, &esp_in->secrets, sizeof(esp_in->secrets)))) {
> +                   (ret = gnutls_rnd(GNUTLS_RND_RANDOM, &esp_in->enc_key, vpninfo->enc_key_len)) ||
> +                   (ret = gnutls_rnd(GNUTLS_RND_RANDOM, &esp_in->hmac_key, vpninfo->hmac_key_len)) ) {
>                 vpn_progress(vpninfo, PRG_ERR,
>                              _("Failed to generate random keys for ESP: %s\n"),
>                              gnutls_strerror(ret));
> diff --git a/oncp.c b/oncp.c
> index 3c7cfa1..45c2f15 100644
> --- a/oncp.c
> +++ b/oncp.c
> @@ -302,11 +302,13 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
>
>                 if (attrlen != 1)
>                         goto badlen;
> -               if (data[0] == 0x02)
> +               if (data[0] == ENC_AES_128_CBC) {
>                         enctype = "AES-128";
> -               else if (data[0] == 0x05)
> +                       vpninfo->enc_key_len = 16;
> +               } else if (data[0] == ENC_AES_256_CBC) {
>                         enctype = "AES-256";
> -               else
> +                       vpninfo->enc_key_len = 32;
> +               } else
>                         enctype = "unknown";
>                 vpn_progress(vpninfo, PRG_DEBUG, _("ESP encryption: 0x%02x (%s)\n"),
>                               data[0], enctype);
> @@ -319,11 +321,13 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
>
>                 if (attrlen != 1)
>                         goto badlen;
> -               if (data[0] == 0x01)
> +               if (data[0] == HMAC_MD5) {
>                         mactype = "MD5";
> -               else if (data[0] == 0x02)
> +                       vpninfo->hmac_key_len = 16;
> +               } else if (data[0] == HMAC_SHA1) {
>                         mactype = "SHA1";
> -               else
> +                       vpninfo->hmac_key_len = 20;
> +               } else
>                         mactype = "unknown";
>                 vpn_progress(vpninfo, PRG_DEBUG, _("ESP HMAC: 0x%02x (%s)\n"),
>                               data[0], mactype);
> @@ -389,7 +393,8 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
>         case GRP_ATTR(7, 2):
>                 if (attrlen != 0x40)
>                         goto badlen;
> -               memcpy(vpninfo->esp_out.secrets, data, 0x40);
> +               /* data contains enc_key and hmac_key concatenated */
> +               memcpy(vpninfo->esp_out.enc_key, data, 0x40);
>                 vpn_progress(vpninfo, PRG_DEBUG, _("%d bytes of ESP secrets\n"),
>                              attrlen);
>                 break;
> @@ -490,6 +495,7 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
>  {
>         int kmplen, kmpend, grouplen, groupend, group, attr, attrlen;
>         int ofs = 0;
> +       int split_enc_hmac_keys = 0;
>
>         kmplen = load_be16(bytes + ofs + 18);
>         kmpend = ofs + kmplen;
> @@ -533,12 +539,21 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
>                                 goto eparse;
>                         if (process_attr(vpninfo, group, attr, bytes + ofs, attrlen))
>                                 goto eparse;
> +                       if (GRP_ATTR(group, attr)==GRP_ATTR(7, 2))
> +                               split_enc_hmac_keys = 1;
>                         ofs += attrlen;
>                 }
>         }
> +
> +       /* The encryption and HMAC keys are sent concatenated together in a block of 0x40 bytes;
> +          we can't split them apart until we know how long the encryption key is. */
> +       if (split_enc_hmac_keys)
> +               memcpy(vpninfo->esp_out.hmac_key, vpninfo->esp_out.enc_key + vpninfo->enc_key_len, vpninfo->hmac_key_len);
> +
>         return 0;
>  }
>
> +
>  int oncp_connect(struct openconnect_info *vpninfo)
>  {
>         int ret, len, kmp, kmplen, group;
> @@ -786,7 +801,8 @@ int oncp_connect(struct openconnect_info *vpninfo)
>                 buf_append_bytes(reqbuf, esp_kmp_hdr, sizeof(esp_kmp_hdr));
>                 buf_append_bytes(reqbuf, &esp->spi, sizeof(esp->spi));
>                 buf_append_bytes(reqbuf, esp_kmp_part2, sizeof(esp_kmp_part2));
> -               buf_append_bytes(reqbuf, &esp->secrets, sizeof(esp->secrets));
> +               buf_append_bytes(reqbuf, &esp->enc_key, vpninfo->enc_key_len);
> +               buf_append_bytes(reqbuf, &esp->hmac_key, 0x40 - vpninfo->enc_key_len);
>                 if (buf_error(reqbuf)) {
>                         vpn_progress(vpninfo, PRG_ERR,
>                                      _("Error negotiating ESP keys\n"));
> @@ -840,8 +856,9 @@ static int oncp_receive_espkeys(struct openconnect_info *vpninfo, int len)
>                 p += sizeof(esp->spi);
>                 memcpy(p, esp_kmp_part2, sizeof(esp_kmp_part2));
>                 p += sizeof(esp_kmp_part2);
> -               memcpy(p, esp->secrets, sizeof(esp->secrets));
> -               p += sizeof(esp->secrets);
> +               memcpy(p, esp->enc_key, vpninfo->enc_key_len);
> +               memcpy(p+vpninfo->enc_key_len, esp->hmac_key, 0x40 - vpninfo->enc_key_len);
> +               p += 0x40;
>                 vpninfo->cstp_pkt->len = p - vpninfo->cstp_pkt->data;
>                 store_le16(vpninfo->cstp_pkt->oncp.rec,
>                            (p - vpninfo->cstp_pkt->oncp.kmp));
> diff --git a/openconnect-internal.h b/openconnect-internal.h
> index a24a9e4..a54761f 100644
> --- a/openconnect-internal.h
> +++ b/openconnect-internal.h
> @@ -335,7 +335,8 @@ struct esp {
>         uint64_t seq_backlog;
>         uint64_t seq;
>         uint32_t spi; /* Stored network-endian */
> -       unsigned char secrets[0x40];
> +       unsigned char enc_key[0x40]; /* Encryption key */
> +       unsigned char hmac_key[0x40]; /* HMAC key */
>  };
>
>  struct openconnect_info {
> @@ -359,6 +360,8 @@ struct openconnect_info {
>         int old_esp_maxseq;
>         struct esp esp_in[2];
>         struct esp esp_out;
> +       int enc_key_len;
> +       int hmac_key_len;
>
>         int tncc_fd; /* For Juniper TNCC */
>         const char *csd_xmltag;
> @@ -684,6 +687,12 @@ 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) */
> +#define ENC_AES_128_CBC                2
> +#define ENC_AES_256_CBC                5
> +#define HMAC_MD5               1
> +#define HMAC_SHA1              2
> +
>  #define vpn_progress(_v, lvl, ...) do {                                        \
>         if ((_v)->verbose >= (lvl))                                     \
>                 (_v)->progress((_v)->cbdata, lvl, __VA_ARGS__); \
> diff --git a/openssl-esp.c b/openssl-esp.c
> index e20bde0..faba1ff 100644
> --- a/openssl-esp.c
> +++ b/openssl-esp.c
> @@ -99,7 +99,7 @@ static int init_esp_ciphers(struct openconnect_info *vpninfo, struct esp *esp,
>                 destroy_esp_ciphers(esp);
>                 return -ENOMEM;
>         }
> -       if (!HMAC_Init_ex(esp->hmac, esp->secrets + EVP_CIPHER_key_length(encalg),
> +       if (!HMAC_Init_ex(esp->hmac, esp->hmac_key,
>                           EVP_MD_size(macalg), macalg, NULL)) {
>                 vpn_progress(vpninfo, PRG_ERR,
>                              _("Failed to initialize ESP HMAC\n"));
> @@ -151,7 +151,8 @@ int setup_esp_keys(struct openconnect_info *vpninfo)
>         esp_in = &vpninfo->esp_in[vpninfo->current_esp_in];
>
>         if (!RAND_bytes((void *)&esp_in->spi, sizeof(esp_in->spi)) ||
> -           !RAND_bytes((void *)&esp_in->secrets, sizeof(esp_in->secrets))) {
> +                   !RAND_bytes((void *)&esp_in->enc_key, vpninfo->enc_key_len)) ||
> +                   !RAND_bytes((void *)&esp_in->hmac_key, vpninfo->hmac_key_len)) ) {
>                 vpn_progress(vpninfo, PRG_ERR,
>                              _("Failed to generate random keys for ESP:\n"));
>                 openconnect_report_ssl_errors(vpninfo);
> --
> 2.7.4
>



More information about the openconnect-devel mailing list