]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Use RFC9266 'tls-exporter' channel bindings for Cisco STRAP with TLSv1.3
authorDavid Woodhouse <dwmw2@infradead.org>
Fri, 15 Nov 2024 15:46:05 +0000 (15:46 +0000)
committerDavid Woodhouse <dwmw2@infradead.org>
Fri, 15 Nov 2024 17:14:33 +0000 (17:14 +0000)
Fixes #659

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
gnutls.c
openconnect-internal.h
openssl.c
www/changelog.xml

index 9fc010b984b71fb1ae2a021d0100eb17d085d768..6c2e3aec29c1c0db60509ed7893de7d603043719 100644 (file)
--- a/gnutls.c
+++ b/gnutls.c
@@ -3176,7 +3176,25 @@ void append_strap_verify(struct openconnect_info *vpninfo,
 
        /* Concatenate our Finished message with our pubkey to be signed */
        struct oc_text_buf *nonce = buf_alloc();
-       buf_append_bytes(nonce, vpninfo->finished, vpninfo->finished_len);
+       if (gnutls_protocol_get_version(vpninfo->https_sess) <= GNUTLS_TLS1_2) {
+               /* For TLSv1.2 and earlier, use RFC5929 'tls-unique' channel binding */
+               buf_append_bytes(nonce, vpninfo->finished, vpninfo->finished_len);
+       } else {
+               /* For TLSv1.3 use RFC9266 'tls-exporter' channel binding */
+               char channel_binding_buf[TLS_EXPORTER_KEY_SIZE];
+               err = gnutls_prf(vpninfo->https_sess, TLS_EXPORTER_LABEL_SIZE, TLS_EXPORTER_LABEL,
+                                0, 0, 0, TLS_EXPORTER_KEY_SIZE, channel_binding_buf);
+               if (err) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Failed to generate channel bindings for STRAP key: %s\n"),
+                                    gnutls_strerror(err));
+                       if (!buf_error(buf))
+                               buf->error = -EIO;
+                       buf_free(nonce);
+                       return;
+               }
+               buf_append_bytes(nonce, channel_binding_buf, TLS_EXPORTER_KEY_SIZE);
+       }
 
        if (rekey) {
                /* We have a copy and we don't want it freed just yet */
index 5abfe98d79c5e242d18df5f411f4eaac2da45d15..600b43b31ec8468790cea8d1d4bd860904c2dd6f 100644 (file)
@@ -1060,6 +1060,11 @@ static inline void __monitor_fd_new(struct openconnect_info *vpninfo,
 #define PSK_LABEL_SIZE (sizeof(PSK_LABEL) - 1)
 #define PSK_KEY_SIZE 32
 
+/* Key material for RFC9266 tls-exporter channel binding */
+#define TLS_EXPORTER_LABEL "EXPORTER-Channel-Binding"
+#define TLS_EXPORTER_LABEL_SIZE (sizeof(TLS_EXPORTER_LABEL) - 1)
+#define TLS_EXPORTER_KEY_SIZE 32
+
 /* Packet types */
 
 #define AC_PKT_DATA            0       /* Uncompressed data */
index 3f204d0f19af255a2d3df6a1ae6c08771dfcb5b6..b354cf7466e66da794933ea230cc86eecd1e19e5 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -2518,14 +2518,30 @@ void append_strap_verify(struct openconnect_info *vpninfo,
                         struct oc_text_buf *buf, int rekey)
 {
        unsigned char finished[64];
-       size_t flen = SSL_get_finished(vpninfo->https_ssl, finished, sizeof(finished));
+       size_t flen;
 
-       if (flen > sizeof(finished)) {
-               vpn_progress(vpninfo, PRG_ERR,
-                            _("SSL Finished message too large (%zu bytes)\n"), flen);
-               if (!buf_error(buf))
-                       buf->error = -EIO;
-               return;
+       if (SSL_SESSION_get_protocol_version(SSL_get_session(vpninfo->https_ssl)) <= TLS1_2_VERSION) {
+               /* For TLSv1.2 and earlier, use RFC5929 'tls-unique' channel binding */
+               flen = SSL_get_finished(vpninfo->https_ssl, finished, sizeof(finished));
+               if (flen > sizeof(finished)) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("SSL Finished message too large (%zu bytes)\n"), flen);
+                       if (!buf_error(buf))
+                               buf->error = -EIO;
+                       return;
+               }
+       } else {
+               /* For TLSv1.3 use RFC9266 'tls-exporter' channel binding */
+               if (!SSL_export_keying_material(vpninfo->https_ssl,
+                                               finished, TLS_EXPORTER_KEY_SIZE,
+                                               TLS_EXPORTER_LABEL, TLS_EXPORTER_LABEL_SIZE,
+                                               NULL, 0, 0)) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Failed to generate channel bindings for STRAP key\n"));
+                       openconnect_report_ssl_errors(vpninfo);
+                       return;
+               }
+               flen = TLS_EXPORTER_KEY_SIZE;
        }
 
        /* If we're rekeying, we need to sign the Verify header with the *old* key. */
index 04b088f262c292d9910ba691b5a51e87ef37afb7..f4f463634977a9285955d84ac5b95800efa77fb7 100644 (file)
@@ -15,6 +15,7 @@
 <ul>
    <li><b>OpenConnect HEAD</b>
      <ul>
+       <li>Fix Cisco Anyconnect STRAP channel bindings with TLSv1.3 (<a href="https://gitlab.com/openconnect/openconnect/-/issues/659">#659</a>).</li>
        <li>Fix ASN.1 encoding of TPMv2 ECDSA signatures with GnuTLS &amp;lt; 3.6.0</li>
        <li>Handle Pulse configuration packets that cannot fit in a single TLS frame (<a href="https://gitlab.com/openconnect/openconnect/-/issues/617">#617</a>, <a href="https://gitlab.com/openconnect/openconnect/-/merge_requests/480">!480</a>).</li>
        <li>Send operating system information to Pulse servers (<a href="https://gitlab.com/openconnect/openconnect/-/merge_requests/481">!481</a>).</li>