]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
AnyConnect: Generate EC keys for X-AnyConnect-STRAP-{DH-,}Pubkey
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 7 Apr 2022 21:22:36 +0000 (22:22 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Mon, 11 Apr 2022 13:50:18 +0000 (14:50 +0100)
These are needed for the external browser SAML support.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
cstp.c
gnutls.c
library.c
openconnect-internal.h
openssl.c

diff --git a/cstp.c b/cstp.c
index d390973f3a1b949fe1da49152b45a1a46d8f800d..000b8730d9d4cf78fba1be6ff49eab15817abf78 100644 (file)
--- a/cstp.c
+++ b/cstp.c
@@ -1246,6 +1246,19 @@ void cstp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
        if (vpninfo->try_http_auth)
                buf_append(buf, "X-Support-HTTP-Auth: true\r\n");
 
+       if (!vpninfo->strap_pubkey || !vpninfo->strap_dh_pubkey) {
+               int err = generate_strap_keys(vpninfo);
+               if (err) {
+                       buf->error = err;
+                       return;
+               }
+       }
+
+       buf_append(buf, "X-AnyConnect-STRAP-Pubkey: %s\r\n",
+                  vpninfo->strap_pubkey);
+       buf_append(buf, "X-AnyConnect-STRAP-DH-Pubkey: %s\r\n",
+                  vpninfo->strap_dh_pubkey);
+
        append_mobile_headers(vpninfo, buf);
 }
 
index 91b95f3373fc5292b359fa187000a2927cd3dcc2..6d8abd79d588bd3da98d93636635b2217edb2166 100644 (file)
--- a/gnutls.c
+++ b/gnutls.c
@@ -2797,3 +2797,93 @@ void destroy_eap_ttls(struct openconnect_info *vpninfo, void *sess)
 {
        gnutls_deinit(sess);
 }
+
+static int generate_strap_key(gnutls_privkey_t *key, char **pubkey)
+{
+       int bits, pk, err;
+       gnutls_pubkey_t pkey = NULL;
+       gnutls_datum_t pdata = { };
+       struct oc_text_buf *buf = NULL;
+
+#if GNUTLS_VERSION_NUMBER >= 0x030500
+       pk = gnutls_ecc_curve_get_pk(GNUTLS_ECC_CURVE_SECP256R1);
+#else
+       pk = GNUTLS_PK_EC;
+#endif
+       bits = GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1);
+
+       err = gnutls_privkey_init(key);
+       if (err)
+               goto out;
+
+       err = gnutls_privkey_generate(*key, pk, bits, 0);
+       if (err)
+               goto out;
+
+       err = gnutls_pubkey_init(&pkey);
+       if (err)
+               goto out;
+
+       err = gnutls_pubkey_import_privkey(pkey, *key,
+                                          GNUTLS_KEY_KEY_AGREEMENT, 0);
+       if (err)
+               goto out;
+
+       err = gnutls_pubkey_export2(pkey, GNUTLS_X509_FMT_DER, &pdata);
+       if (err)
+               goto out;
+
+       buf = buf_alloc();
+       buf_append_base64(buf, pdata.data, pdata.size, 0);
+       if (buf_error(buf)) {
+               err = GNUTLS_E_MEMORY_ERROR;
+               goto out;
+       }
+
+       *pubkey = buf->data;
+       buf->data = NULL;
+ out:
+       buf_free(buf);
+       gnutls_free(pdata.data);
+       gnutls_pubkey_deinit(pkey);
+       if (err) {
+               gnutls_privkey_deinit(*key);
+               *key = NULL;
+               *pubkey = NULL;
+       }
+       return err;
+}
+
+int generate_strap_keys(struct openconnect_info *vpninfo)
+{
+       int err;
+
+       err = generate_strap_key(&vpninfo->strap_key, &vpninfo->strap_pubkey);
+       if (err) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to generate STRAP key: %s\n"),
+                            gnutls_strerror(err));
+               free_strap_keys(vpninfo);
+               return -EIO;
+       }
+
+       err = generate_strap_key(&vpninfo->strap_dh_key, &vpninfo->strap_dh_pubkey);
+       if (err) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to generate STRAP DH key: %s\n"),
+                            gnutls_strerror(err));
+               free_strap_keys(vpninfo);
+               return -EIO;
+       }
+       return 0;
+}
+
+void free_strap_keys(struct openconnect_info *vpninfo)
+{
+       if (vpninfo->strap_key)
+               gnutls_privkey_deinit(vpninfo->strap_key);
+       if (vpninfo->strap_dh_key)
+               gnutls_privkey_deinit(vpninfo->strap_dh_key);
+
+       vpninfo->strap_key = vpninfo->strap_dh_key = NULL;
+}
index 8517147607051dc61ee4551c5a4cd7a52690d63f..cd5fd9ee50b28e2c60b57d9fdff5b08b77e912db 100644 (file)
--- a/library.c
+++ b/library.c
@@ -590,11 +590,12 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
                closesocket(vpninfo->cmd_fd);
                closesocket(vpninfo->cmd_fd_write);
        }
-
+       free_strap_keys(vpninfo);
+       free(vpninfo->strap_pubkey);
+       free(vpninfo->strap_dh_pubkey);
        free(vpninfo->ppp);
        buf_free(vpninfo->ppp_tls_connect_req);
        buf_free(vpninfo->ppp_dtls_connect_req);
-
 #ifdef HAVE_ICONV
        if (vpninfo->ic_utf8_to_legacy != (iconv_t)-1)
                iconv_close(vpninfo->ic_utf8_to_legacy);
index ea7f1cad32ff0c06574aedb5dccb50bf486cc113..f066246aa091dce32bf53a262bf9b5b87b708a07 100644 (file)
@@ -573,13 +573,19 @@ struct openconnect_info {
        SSL_CTX *https_ctx;
        SSL *https_ssl;
        BIO_METHOD *ttls_bio_meth;
+       EC_KEY *strap_key;
+       EC_KEY *strap_dh_key;
 #elif defined(OPENCONNECT_GNUTLS)
        gnutls_session_t https_sess;
        gnutls_session_t eap_ttls_sess;
        gnutls_certificate_credentials_t https_cred;
        gnutls_psk_client_credentials_t psk_cred;
        char local_cert_md5[MD5_SIZE * 2 + 1]; /* For CSD */
+       gnutls_privkey_t strap_key;
+       gnutls_privkey_t strap_dh_key;
 #endif /* OPENCONNECT_GNUTLS */
+       char *strap_pubkey;
+       char *strap_dh_pubkey;
        char *ciphersuite_config;
        struct oc_text_buf *ttls_pushbuf;
        uint8_t ttls_eap_ident;
@@ -1424,6 +1430,8 @@ int hotp_hmac(struct openconnect_info *vpninfo, const void *challenge);
 int openconnect_install_ctx_verify(struct openconnect_info *vpninfo,
                                   SSL_CTX *ctx);
 #endif
+void free_strap_keys(struct openconnect_info *vpninfo);
+int generate_strap_keys(struct openconnect_info *vpninfo);
 
 /* mainloop.c */
 int tun_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable, int did_work);
index 3205dbd7d638a05e83cdc83aee0ef941bb653e10..7085429cc742a906a7c0cc3fcd2e0d83c0d8790d 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -2247,3 +2247,76 @@ void destroy_eap_ttls(struct openconnect_info *vpninfo, void *ttls)
        /* Leave the BIO_METH for now. It may get reused and we don't want to
         * have to call BIO_get_new_index() more times than is necessary */
 }
+
+static int generate_strap_key(EC_KEY **key, EC_GROUP *grp, char **pubkey)
+{
+       struct oc_text_buf *buf = NULL;
+       unsigned char *der = NULL;
+       int len;
+
+       *key = EC_KEY_new();
+       if (!*key)
+               return -EIO;
+
+       if (!EC_KEY_set_group(*key, grp))
+               return -EIO;
+
+       if (!EC_KEY_generate_key(*key))
+               return -EIO;
+
+       len = i2d_EC_PUBKEY(*key, &der);
+       buf = buf_alloc();
+       buf_append_base64(buf, der, len, 0);
+       free(der);
+       if (buf_error(buf))
+               return buf_free(buf);
+
+       *pubkey = buf->data;
+       buf->data = NULL;
+       buf_free(buf);
+       return 0;
+}
+
+int generate_strap_keys(struct openconnect_info *vpninfo)
+{
+       int err;
+       EC_GROUP *grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+
+       if (!grp) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to create prime256v1 EC group\n"));
+               return -EIO;
+       }
+
+       err = generate_strap_key(&vpninfo->strap_key, grp, &vpninfo->strap_pubkey);
+       if (err) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to generate STRAP key"));
+               openconnect_report_ssl_errors(vpninfo);
+               free_strap_keys(vpninfo);
+               EC_GROUP_free(grp);
+               return -EIO;
+       }
+
+       err = generate_strap_key(&vpninfo->strap_dh_key, grp, &vpninfo->strap_dh_pubkey);
+       if (err) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to generate STRAP DH key\n"));
+               openconnect_report_ssl_errors(vpninfo);
+               free_strap_keys(vpninfo);
+               EC_GROUP_free(grp);
+               return -EIO;
+       }
+       EC_GROUP_free(grp);
+       return 0;
+}
+
+void free_strap_keys(struct openconnect_info *vpninfo)
+{
+       if (vpninfo->strap_key)
+               EC_KEY_free(vpninfo->strap_key);
+       if (vpninfo->strap_dh_key)
+               EC_KEY_free(vpninfo->strap_dh_key);
+
+       vpninfo->strap_key = vpninfo->strap_dh_key = NULL;
+}