These are needed for the external browser SAML support.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
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);
}
{
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;
+}
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);
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;
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);
/* 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;
+}