[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openconnect-devel
Subject:    Re: [PATCH] store length of ESP encryption and HMAC keys so that they can be manipulated separately 
From:       Daniel Lenski <dlenski () gmail ! com>
Date:       2016-12-28 17:44:38
Message-ID: CAOw_LSGTYRBDkFYfTgykMUsSKnCcCOXvZzohLHE+hdpRVne2dg () mail ! gmail ! com
[Download RAW message or body]

This patch is a bit… redundant. The mapping between encryption
algorithms and encryption key length is not only stored in the vpninfo
structure, but it's also re-computed in several different places.

I would like to use the gnutls/openssl functions to determine key
length everywhere, but this would mean (a) storing backend-specific
algorithm identifiers and (b) adding a lot more #ifdef GNUTLS/OPENSSL.
Any thoughts?

Dan

On Wed, Dec 28, 2016 at 9:38 AM, Daniel Lenski <dlenski@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@gmail.com>
> ---
> esp.c                  | 13 ++++---------
> gnutls-esp.c           |  4 ++--
> gpst.c                 | 28 +++++++++++++---------------
> oncp.c                 | 42 ++++++++++++++++++++++++++++++------------
> openconnect-internal.h |  5 ++++-
> openssl-esp.c          |  2 +-
> 6 files changed, 54 insertions(+), 40 deletions(-)
> 
> diff --git a/esp.c b/esp.c
> index f6b8f27..186858a 100644
> --- a/esp.c
> +++ b/esp.c
> @@ -34,16 +34,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 ENC_AES_128_CBC:
> enctype = "AES-128-CBC (RFC3602)";
> -               enclen = 16;
> break;
> case ENC_AES_256_CBC:
> enctype = "AES-256-CBC (RFC3602)";
> -               enclen = 32;
> break;
> default:
> return -EINVAL;
> @@ -51,20 +48,18 @@ int print_esp_keys(struct openconnect_info *vpninfo, const char \
> *name, struct es switch(vpninfo->esp_hmac) {
> case HMAC_MD5:
> mactype = "HMAC-MD5-96 (RFC2403)";
> -               maclen = 16;
> break;
> case HMAC_SHA1:
> 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 14ea1da..f3ec72c 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,
> diff --git a/gpst.c b/gpst.c
> index 3346194..f89e3d3 100644
> --- a/gpst.c
> +++ b/gpst.c
> @@ -211,18 +211,18 @@ static int calculate_mtu(struct openconnect_info *vpninfo)
> static int set_esp_algo(struct openconnect_info *vpninfo, const char *s, int hmac)
> {
> if (hmac) {
> -               if (!strcmp(s, "sha1"))         { vpninfo->esp_hmac = HMAC_SHA1; \
>                 return 20; }
> -               if (!strcmp(s, "md5"))          { vpninfo->esp_hmac = HMAC_MD5; \
> return 16; } +               if (!strcmp(s, "sha1"))         { vpninfo->esp_hmac = \
> HMAC_SHA1; vpninfo->hmac_key_len = 20; return 0; } +               if (!strcmp(s, \
> "md5"))          { vpninfo->esp_hmac = HMAC_MD5;  vpninfo->hmac_key_len = 16; \
> return 0; } } else {
> if (!strcmp(s, "aes128") || !strcmp(s, "aes-128-cbc"))
> -                                               { vpninfo->esp_enc = \
>                 ENC_AES_128_CBC; return 16; }
> -               if (!strcmp(s, "aes-256-cbc"))  { vpninfo->esp_enc = \
> ENC_AES_256_CBC; return 32; } +                                               { \
> vpninfo->esp_enc = ENC_AES_128_CBC; vpninfo->enc_key_len = 16; return 0; } +        \
> if (!strcmp(s, "aes-256-cbc"))  { vpninfo->esp_enc = ENC_AES_256_CBC; \
> vpninfo->enc_key_len = 32; return 0; } }
> vpn_progress(vpninfo, PRG_ERR, _("Unknown ESP %s algorithm: %s"), hmac ? "MAC" : \
> "encryption", s); return -ENOENT;
> }
> 
> -static int get_key_bits(xmlNode *xml_node, unsigned char *dest, int keybytes)
> +static int get_key_bits(xmlNode *xml_node, unsigned char *dest)
> {
> int bits = -1;
> xmlNode *child;
> @@ -233,12 +233,12 @@ static int get_key_bits(xmlNode *xml_node, unsigned char \
> *dest, int keybytes) bits = atoi(s);
> free((void *)s);
> } else if (xmlnode_get_text(child, "val", &s) == 0) {
> -                       for (p=s; *p && *(p+1) && p<s+(keybytes<<1); p+=2)
> +                       for (p=s; *p && *(p+1) && (bits-=8)>=0; p+=2)
> *dest++ = unhex(p);
> free((void *)s);
> }
> }
> -       return (bits == (keybytes<<3)) ? 0 : -EINVAL;
> +       return (bits == 0) ? 0 : -EINVAL;
> }
> 
> /* Return value:
> @@ -288,19 +288,17 @@ static int gpst_parse_config_xml(struct openconnect_info \
> *vpninfo, xmlNode *xml_ #ifdef HAVE_ESP
> /* setup_esp_keys() will swap the active incoming key-set */
> int c = (vpninfo->current_esp_in ^ 1);
> -                       int enclen=0, maclen=0;
> for (member = xml_node->children; member; member=member->next) {
> s = NULL;
> if (!xmlnode_get_text(member, "udp-port", &s))          udp_sockaddr(vpninfo, \
>                 atoi(s));
> -                               else if (!xmlnode_get_text(member, "enc-algo", &s)) \
>                 enclen = set_esp_algo(vpninfo, s, 0);
> -                               else if (!xmlnode_get_text(member, "hmac-algo", \
> &s))    maclen = set_esp_algo(vpninfo, s, 1); +                               else \
> if (!xmlnode_get_text(member, "enc-algo", &s))     set_esp_algo(vpninfo, s, 0); +   \
> else if (!xmlnode_get_text(member, "hmac-algo", &s))    set_esp_algo(vpninfo, s, \
> 1); else if (!xmlnode_get_text(member, "c2s-spi", &s))      vpninfo->esp_out.spi = \
> htonl(strtoul(s, NULL, 16)); else if (!xmlnode_get_text(member, "s2c-spi", &s))     \
>                 vpninfo->esp_in[c].spi = htonl(strtoul(s, NULL, 16));
> -                               /* FIXME: this won't work if ekey or akey tags \
>                 appears before algo tags */
> -                               else if (xmlnode_is_named(member, "ekey-c2s"))      \
>                 get_key_bits(member, vpninfo->esp_out.secrets, enclen);
> -                               else if (xmlnode_is_named(member, "ekey-s2c"))      \
>                 get_key_bits(member, vpninfo->esp_in[c].secrets, enclen);
> -                               else if (xmlnode_is_named(member, "akey-c2s"))      \
>                 get_key_bits(member, vpninfo->esp_out.secrets+enclen, maclen);
> -                               else if (xmlnode_is_named(member, "akey-s2c"))      \
> get_key_bits(member, vpninfo->esp_in[c].secrets+enclen, maclen); +                  \
> else if (xmlnode_is_named(member, "ekey-c2s"))          get_key_bits(member, \
> vpninfo->esp_out.enc_key); +                               else if \
> (xmlnode_is_named(member, "ekey-s2c"))          get_key_bits(member, \
> vpninfo->esp_in[c].enc_key); +                               else if \
> (xmlnode_is_named(member, "akey-c2s"))          get_key_bits(member, \
> vpninfo->esp_out.hmac_key); +                               else if \
> (xmlnode_is_named(member, "akey-s2c"))          get_key_bits(member, \
> vpninfo->esp_in[c].hmac_key); free((void *)s);
> }
> if (vpninfo->dtls_state != DTLS_DISABLED) {
> diff --git a/oncp.c b/oncp.c
> index e6ff6c3..f5bcc75 100644
> --- a/oncp.c
> +++ b/oncp.c
> @@ -286,11 +286,13 @@ static int process_attr(struct openconnect_info *vpninfo, int \
> group, int attr, 
> if (attrlen != 1)
> goto badlen;
> -               if (data[0] == ENC_AES_128_CBC)
> +               if (data[0] == ENC_AES_128_CBC) {
> enctype = "AES-128";
> -               else if (data[0] == ENC_AES_256_CBC)
> +                       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);
> @@ -303,11 +305,13 @@ static int process_attr(struct openconnect_info *vpninfo, int \
> group, int attr, 
> if (attrlen != 1)
> goto badlen;
> -               if (data[0] == HMAC_MD5)
> +               if (data[0] == HMAC_MD5) {
> mactype = "MD5";
> -               else if (data[0] == HMAC_SHA1)
> +                       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);
> @@ -373,7 +377,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;
> @@ -474,6 +479,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;
> @@ -517,9 +523,17 @@ 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;
> }
> 
> @@ -531,7 +545,8 @@ static int oncp_setup_esp_keys(struct openconnect_info \
> *vpninfo) 
> #if defined(OPENCONNECT_GNUTLS)
> 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));
> @@ -539,7 +554,8 @@ static int oncp_setup_esp_keys(struct openconnect_info \
> *vpninfo) }
> #elif defined(OPENCONNECT_OPENSSL)
> 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);
> @@ -797,7 +813,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"));
> @@ -851,8 +868,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 c9f7b08..8deccca 100644
> --- a/openconnect-internal.h
> +++ b/openconnect-internal.h
> @@ -348,7 +348,8 @@ struct esp {
> uint64_t seq_backlog;
> uint64_t seq;
> uint32_t spi; /* Stored network-endian */
> -       unsigned char secrets[0x40]; /* Encryption key bytes, then HMAC key bytes \
> */ +       unsigned char enc_key[0x40]; /* Encryption key */
> +       unsigned char hmac_key[0x40]; /* HMAC key */
> };
> 
> struct openconnect_info {
> @@ -372,6 +373,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;
> diff --git a/openssl-esp.c b/openssl-esp.c
> index 106a1f9..12dd761 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"));
> --
> 2.7.4
> 

_______________________________________________
openconnect-devel mailing list
openconnect-devel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/openconnect-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic