OpenConnect client extended to support Palo Alto Networks' GlobalProtect VPN
dlenski Fix GlobalProtect authgroup handling
When connecting to a GlobalProtect server via the portal interface, then
`vpninfo->authgroup` needs to be set to the URL of one of the allowed

The problem here is that if the user actually wanted to select the _first_
gateway in the dropdown list, it was already pre-selected, and thus clicking
"continue"/"login" on the form wouldn't trigger `OC_FORM_RESULT_NEWGROUP`.

This would prevent `vpninfo->authgroup` from getting set correctly, and the
gateway redirect would be skipped entirely.  Thus it was effectively
impossible to select the first option in the gateway dropdown.

Signed-off-by: Daniel Lenski <>
Latest commit e5fe063 Oct 8, 2018
Failed to load latest commit information.
android android: Enable arm64 and x86_64 builds Feb 12, 2018
java allow overriding User-Agent in Java library Aug 15, 2018
m4 Use AX_CHECK_VSCRIPT to test for version script support Dec 7, 2014
po Update translations from GNOME Sep 17, 2018
tests Save latest ESP sequence number even if replay protection isn't in use Feb 27, 2018
www Update TPM documentation to mention TPMv2 Oct 3, 2018
.gitignore Add a basic test suite Jul 8, 2016
.gitlab-ci.yml Update yum/dnf cache before package installation Jul 12, 2018
.travis.yml make `master` the main branch of the repo Oct 3, 2018
AUTHORS Provide a list of authors and contributors Aug 21, 2009
COPYING.LGPL Whitespace cleanups Apr 9, 2009
Dockerfile make `master` the main branch of the repo Oct 3, 2018 Add shell of TPM2 support Oct 3, 2018 make `master` the main branch of the repo Oct 3, 2018
README.DTLS Update README.DTLS to reflect current OpenSSL versions May 9, 2010
README.TESTS Add a basic test suite Jul 8, 2016 Update Oct 3, 2018
TODO stoken: Update documentation, manpage with libstoken information Oct 15, 2012
acinclude.m4 acinclude: Add AX_JNI_INCLUDE_DIR macro Jan 15, 2014
auth-common.c simplify gpst_xml_or_error handling and config parsing Sep 30, 2018
auth-globalprotect.c Fix GlobalProtect authgroup handling Oct 8, 2018
auth-juniper.c Revert "Don't treat Juniper 'realm' field as authgroup" Aug 9, 2018
auth.c Merge branch 'master' of into HEAD Oct 3, 2018 Check whether glibtoolize is available in addition to libtoolize Aug 9, 2018
compat.c Fix format warning in openconnect_win32__strerror() Sep 3, 2016
config.rpath Import AM_ICONV implementation Oct 30, 2014 Add shell of TPM2 support Oct 3, 2018 Add alternative CSD script to post results directly Aug 9, 2018 Clean up Aug 9, 2018
cstp.c add protocol-agnostic idle_timeout and openconnect_get_idle_timeout()… Aug 6, 2018
digest.c Introduced buf_append_hex() Dec 13, 2016
dtls.c Fix crash on DTLS resumption Feb 12, 2018
esp-seqno.c Fix translation of ESP warning messages Mar 13, 2018
esp.c Clarify a few uncommented corners of the ESP support Aug 2, 2018
gnutls-dtls.c Fix crash on DTLS resumption Feb 12, 2018
gnutls-esp.c Save latest ESP sequence number even if replay protection isn't in use Feb 27, 2018
gnutls.c Add shell of TPM2 support Oct 3, 2018
gnutls.h Add shell of TPM2 support Oct 3, 2018
gnutls_tpm.c Shift TSS context out of generic vpninfo Oct 3, 2018
gnutls_tpm2.c Add shell of TPM2 support Oct 3, 2018
gpst.c fix segfault when search domain list in empty (fixes #129) Oct 6, 2018
gssapi.c Fix some more proxy assumptions in HTTP auth Feb 24, 2015 include computer name in the GP cookie Aug 4, 2018
http-auth.c openconnect_base64_decode: fix sign of error return value Sep 8, 2018
http.c add PAN GlobalProtect protocol support (HTTPS tunnel only) May 31, 2018
iconv.c Update copyright year Jan 26, 2015
jni.c add protocol-agnostic idle_timeout and openconnect_get_idle_timeout()… Aug 6, 2018 add protocol-agnostic idle_timeout and openconnect_get_idle_timeout()… Aug 6, 2018
library.c Fix issue causing front-ends/GUIs to be insensitive to changes in the… Oct 8, 2018
lzo.c Add LZO decompression support Jan 27, 2015
lzo.h Add LZO decompression support Jan 27, 2015
lzs.c Stop using 1ULL as the base value to be shifted in LZS GET_BITS() Feb 28, 2015
main.c command-line client should fill in any password field with value supp… Sep 21, 2018
mainloop.c Add support for GlobalProtect ESP tunnel May 31, 2018
ntlm.c Kill auth_is_proxy() abomination in ntlm.c Oct 6, 2015
oath.c Introduced buf_append_hex() Dec 13, 2016
oncp.c Remove first oNCP negotiation request (only second is necessary) Aug 2, 2018
openconnect-internal.h Add shell of TPM2 support Oct 3, 2018 openconnect.8: reference ocserv(8) Jun 26, 2018
openconnect.h add protocol-agnostic idle_timeout and openconnect_get_idle_timeout()… Aug 6, 2018
openconnect.ico Windows application icon Feb 26, 2018 Fix openssl dependency in openssl.pc Sep 25, 2016
openconnect.rc Windows application icon Feb 26, 2018
openssl-dtls.c Fix build with LibreSSL 2.5.1 and higher. May 12, 2017
openssl-esp.c Save latest ESP sequence number even if replay protection isn't in use Feb 27, 2018
openssl-pkcs11.c Fix OpenSSL 1.1 build of EC workaround Sep 6, 2016
openssl.c Add support for files from the *other* OpenSSL TPM2 engine. FFS. Oct 3, 2018
script.c fix a bug leading to incorrect split-include netmasks Feb 27, 2018
ssl.c Simplify DTLS conditionals Sep 10, 2016
sspi.c Don't always send Proxy-Authenticate: for SSPI auth Mar 26, 2015
stoken.c Move protocol-specific decisions about when to use tokencodes into pr… Jan 30, 2015 Add TNCC support Jan 26, 2015
tun-win32.c Toggle TAP status to force Windows to re-run NLA. Sep 2, 2018
tun.c Fix IPv6 setup on Solaris Sep 22, 2016 Tag version 7.08 Dec 13, 2016
win32-ipicmp.h Add support for GlobalProtect ESP tunnel May 31, 2018
xml.c Fix leak of xmlfile on error path Feb 28, 2015
yubikey.c Shift PC/SC context out of generic vpninfo Oct 3, 2018

OpenConnect with PAN GlobalProtect support

Build Status

Table of Contents

What is this?

This is a modified version of the fantastic open-source VPN client OpenConnect which supports the PAN GlobalProtect VPN in its native modes (SSL and ESP)—with no assistance or cooperation needed from your VPN administrators.

I began developing it in October 2016, and started using it for "real work" almost immediately. It has become increasingly polished since then.

GlobalProtect support will be merged into the mainline OpenConnect v8.0. Since I began working on it, I've started working on other pieces of openconnect, so I'll probably leave this repository in place to continue work on it. This repository contains two main branches:

  • globalprotect: a very messy branch with my piece-by-piece work on implementing the GlobalProtect protocol. Retained mainly for historical reasons.
  • master: a "cleaned-up" mainline integration branch. I squash commits and rebase it on the upstream master branch fairly frequently.

Feedback and troubleshooting

Please report problems with GlobalProtect connectivity as Github issues. If you are having trouble authenticating to your GlobalProtect server, please run OpenConnect with the --dump -vvv flags to dump the authentication flow; please compare the back-and-forth configuration requests to this anonymized transcript and include information about relevant differences in your issue report.

Bonus points: If your VPN uses a weird authentication flow, please check out the Gist where I wrote a quick-and-dirty "GlobalProtect server simulator" in Python. It's fairly straightforward to understand, and if you can modify it to reproduce the authentication flow used by your VPN, it'll make it a whole lot easier to add support.


Please refer to the build requirements for the official releases of OpenConnect. This version has the exact same build dependencies as OpenConnect v7.06; modern versions of autoconf, automake, gcc, libxml, etc.

Building from source on Linux

Under Debian-based or Ubuntu-based distributions, this should install the requirements:

$ sudo apt-get install \
    build-essential gettext autoconf automake libproxy-dev \
    libxml2-dev libtool vpnc-scripts pkg-config \
    libgnutls-dev # may be named libgnutls28-dev on some recent Debian/Ubuntu-based distros

Once you have all the build dependencies installed, checkout and build from this repository.

$ git clone //
$ cd openconnect
$ ./
$ ./configure
$ make
$ sudo make install && sudo ldconfig

Building on the Mac

Homebrew is required. To build and install into /usr/local:

$ brew install pkg-config gettext gnutls lz4 automake
$ export LIBTOOLIZE=glibtoolize
$ ./
$ ./configure --prefix=/usr/local --with-vpnc-script=/usr/local/etc/vpnc-script --disable-nls
$ make
$ make install

Please see this Gist on how to set up and use OpenConnect on the Mac. Don't forget to install vpnc-script into /usr/local/etc.


Building an openconnect Docker image is as easy as:

$ docker build -t openconnect .

Then, you can run that docker image as a container:

$ docker run -ti openconnect
/openconnect# ./openconnect --protocol=gp

But that'll restrict the use of the tunnel to inside the container, and maybe you want to use it system-wide. For that, you'll need a privileged container making use of the host (you computer) network:

$ docker run -ti --rm --privileged --net=host openconnect
/openconnect# ./openconnect --protocol=gp

Leave that container running, open another terminal, and you'll see a newly created tun connection for your whole system to use.

Connecting to a GlobalProtect VPN

Run openconnect like this to test it with your GlobalProtect VPN provider.

$ ./openconnect --protocol=gp --dump -vvv
Please enter your username and password.

It currently supports the following authentication mechanisms:

  • Username and password
  • "Challenge"-based multi-factor authentication, wherein the server requests a secondary username and password after the first one
  • TLS/SSL client certificate (include --certificate cert_with_privkey.pem if your VPN requires a client certificate and private key)

I'd welcome feedback on how to support other authentication methods in use with GlobalProtect.

HIP report submission

The HIP ("Host Integrity Protection") mechanism is a security scanner for PAN GlobalProtect VPNs, in the same vein as Cisco's CSD and Juniper's Host Checker.

The server requests a "HIP report" upon client connection, then the client generates a "HIP report" XML file, and then the client uploads it to the server.

If all goes well, the client should have the expected level of access to resources on the network after these steps are complete. At least two things can go wrong:

  • Many GlobalProtect servers report that they require HIP reports, but don't actually enforce this requirement. (For this reason, OpenConnect does not currently fail if a HIP report is required but no HIP report script is provided.)
  • Many GlobalProtect servers will claim that the HIP report was accepted successfully but silently fail to enable the expected network access, presumably because some aspect of the HIP report contents were not approved.

OpenConnect supports HIP report generation and submission by passing the --csd-wrapper=SCRIPT argument with a shell script to generate a HIP report in the format expected by the server. This shell script must output the HIP report to standard output and exit successfully (status code 0).

An example script is included in the repository. Depending on how picky your GlobalProtect VPN is, it may be necessary to spoof or alter some of the parameters of the HIP report to match your GlobalProtect VPN's expectations as to its contents.

Portal vs. gateway servers

For some GlobalProtect VPNs, there is a distinction between "portal" and "gateway" servers, although in many GlobalProtect VPNs they run on the same server. "Portal" application URLs are found under /global-protect, while "gateway" application URLs are under /ssl-vpn.

Try using both the "Portal address" and the "GlobalProtect Gateway IP" shown in the Windows client with OpenConnect:

GlobalProtect Windows client

The official GlobalProtect VPN clients always connect first via the portal. The portal then sends a choice of one or more gateways. However, this behavior is unnecessary, and adds an additional delay in establishing a connection.

Recent versions of openconnect can connect via either the portal endpoint or the gateway endpoint:

  • If unspecified, the gateway endpoint is tried first, then the portal endpoint.
  • For the gateway, include a URL-path starting with /ssl-vpn or specify --usergroup=gateway
  • For the portal, include a URL-path starting with /global-protect or specify --usergroup=portal
    • To choose a specific gateway from the portal without further prompting, add --authgroup $GATEWAYNAME

Example of connecting via the portal interface and getting a choice of gateway servers:

$ openconnect --protocol=gp --usergroup=portal
Please enter your username and password.
Connected to HTTPS on
3 gateway servers available:
  NorthAmerica (
  Europe (
  Asia (
Please select GlobalProtect gateway.
GATEWAY: [NorthAmerica|Europe|Asia]:


  • Support web-based/SAML-based authentication flows (see pull #98 for preliminary work, and issue #116 for more discussion regarding Okta)
  • Configure multi-stage build into the Dockerfile, to get a smaller Docker image