Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'allow_multiple_servercert_arguments' into 'master'
Allow specification of multiple certificate fingerprints on command-line via --servercert

See merge request openconnect/openconnect!162
  • Loading branch information
dlenski committed Feb 5, 2021
2 parents 99bd568 + 9e60b41 commit 6279c47
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 44 deletions.
90 changes: 47 additions & 43 deletions main.c
Expand Up @@ -92,7 +92,14 @@ static int cookieonly;
static int allow_stdin_read;

static char *token_filename;
static char *server_cert = NULL;
static int allowed_fingerprints;

struct accepted_cert {
struct accepted_cert *next;
char *fingerprint;
char *host;
int port;
} *accepted_certs;

static char *username;
static char *password;
Expand Down Expand Up @@ -849,7 +856,7 @@ static void usage(void)
#endif

printf("\n%s:\n", _("Server validation"));
printf(" --servercert=FINGERPRINT %s\n", _("Server's certificate SHA1 fingerprint"));
printf(" --servercert=FINGERPRINT %s\n", _("Accept only server certificate with this fingerprint"));
printf(" --no-system-trust %s\n", _("Disable default system certificate authorities"));
printf(" --cafile=FILE %s\n", _("Cert file for server verification"));

Expand Down Expand Up @@ -1526,6 +1533,7 @@ int main(int argc, char **argv)
struct openconnect_info *vpninfo;
char *urlpath = NULL;
struct oc_vpn_option *gai;
struct accepted_cert *newcert;
char *ip;
char *proxy = getenv("https_proxy");
char *vpnc_script = NULL;
Expand Down Expand Up @@ -1696,8 +1704,19 @@ int main(int argc, char **argv)
}
break;
case OPT_SERVERCERT:
server_cert = keep_config_arg();
newcert = malloc(sizeof(*newcert));
if (!newcert) {
fprintf(stderr, _("Failed to allocate memory\n"));
exit(1);
}
newcert->next = accepted_certs;
accepted_certs = newcert;
newcert->fingerprint = keep_config_arg();
newcert->host = NULL;
newcert->port = 0;

openconnect_set_system_trust(vpninfo, 0);
allowed_fingerprints++;
break;
case OPT_RESOLVE:
ip = strchr(config_arg, ':');
Expand Down Expand Up @@ -2207,47 +2226,41 @@ static void __attribute__ ((format(printf, 3, 4)))
}
}

struct accepted_cert {
struct accepted_cert *next;
char *fingerprint;
char *host;
int port;
} *accepted_certs;

static int validate_peer_cert(void *_vpninfo, const char *reason)
{
struct openconnect_info *vpninfo = _vpninfo;
const char *fingerprint;
struct accepted_cert *this;

#ifdef INSECURE_DEBUGGING
if (server_cert && strcasecmp(server_cert, "ACCEPT")) {
#else
if (server_cert) {
#endif
int err = openconnect_check_peer_cert_hash(vpninfo, server_cert);

if (!err)
return 0;

if (err < 0)
vpn_progress(vpninfo, PRG_ERR,
_("Could not calculate hash of server's certificate\n"));
else
vpn_progress(vpninfo, PRG_ERR,
_("Server SSL certificate didn't match: %s\n"),
openconnect_get_peer_cert_hash(vpninfo));

return -EINVAL;
}

fingerprint = openconnect_get_peer_cert_hash(vpninfo);

for (this = accepted_certs; this; this = this->next) {
if (!strcasecmp(this->host, vpninfo->hostname) &&
this->port == vpninfo->port &&
!openconnect_check_peer_cert_hash(vpninfo, this->fingerprint))
#ifdef INSECURE_DEBUGGING
if (this->port == 0 && this->host == NULL && !strcasecmp(this->fingerprint, "ACCEPT")) {
fprintf(stderr, _("Insecurely accepting certificate from VPN server \"%s\" because you ran with --servercert=ACCEPT.\n"),
vpninfo->hostname);
return 0;
} else
#endif
/* XX: if set by --servercert argument (port 0 and host NULL), accept for any host/port */
if ((this->host == NULL || !strcasecmp(this->host, vpninfo->hostname)) &&
(this->port == 0 || this->port == vpninfo->port)) {
int err = openconnect_check_peer_cert_hash(vpninfo, this->fingerprint);
if (!err)
return 0;
else if (err < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Could not check server's certificate against %s\n"),
this->fingerprint);
}
}
}

if (allowed_fingerprints) {
vpn_progress(vpninfo, PRG_ERR,
_("None of the %d fingerprint(s) specified via --servercert match server's certificate: %s\n"),
allowed_fingerprints, fingerprint);
return -EINVAL;
}

while (1) {
Expand All @@ -2263,12 +2276,6 @@ static int validate_peer_cert(void *_vpninfo, const char *reason)
if (non_inter)
return -EINVAL;

#ifdef INSECURE_DEBUGGING
if (!strcasecmp(server_cert, "ACCEPT")) {
fprintf(stderr, _("Insecurely accepting because you ran with --servertcert=ACCEPT.\n"));
goto accepted;
}
#endif
fprintf(stderr, _("Enter '%s' to accept, '%s' to abort; anything else to view: "),
_("yes"), _("no"));

Expand All @@ -2278,9 +2285,6 @@ static int validate_peer_cert(void *_vpninfo, const char *reason)

if (!strcasecmp(response, _("yes"))) {
struct accepted_cert *newcert;
#ifdef INSECURE_DEBUGGING
accepted:
#endif
newcert = malloc(sizeof(*newcert));
if (newcert) {
newcert->next = accepted_certs;
Expand Down
5 changes: 4 additions & 1 deletion openconnect.8.in
Expand Up @@ -554,7 +554,10 @@ to
instead of using the normal resolver to look it up.
.TP
.B \-\-servercert=HASH
Accept server's SSL certificate only if the provided fingerprint matches.
Accept server's SSL certificate only if it matches the provided fingerprint.
This option implies \-\-no\-system\-trust, and may be specified multiple
times in order to accept multiple possible fingerprints.

The allowed fingerprint types are
.IR SHA1 ,
.IR SHA256 ,
Expand Down
1 change: 1 addition & 0 deletions www/changelog.xml
Expand Up @@ -24,6 +24,7 @@
<li>Allow protocols to delay tunnel setup and shutdown (<a href="https://gitlab.com/openconnect/openconnect/-/merge_requests/117">!117</a>)</li>
<li>Incomplete, speculative support for GlobalProtect IPv6 (<a href="https://gitlab.com/openconnect/openconnect/-/merge_requests/155">!155</a>; previous work in <a href="https://gitlab.com/openconnect/openconnect/commit/d6db0ec03394234d41fbec7ffc794ceeb486a8f0">d6db0ec</a>)</li>
<li>SIGUSR1 causes OpenConnect to log detailed connection information and statistics (<a href="https://gitlab.com/openconnect/openconnect/-/merge_requests/154">!154</a>)</li>
<li>Allow <tt>--servercert</tt> to be specified multiple times in order to accept server certificates matching more than one possible fingerprint (<a href="https://gitlab.com/openconnect/openconnect/-/merge_requests/162">!162</a>, <a href="https://gitlab.com/openconnect/openconnect/-/issues/25">#25</a>)</li>
</ul><br/>
</li>
<li><b><a href="ftp://ftp.infradead.org/pub/openconnect/openconnect-8.10.tar.gz">OpenConnect v8.10</a></b>
Expand Down

0 comments on commit 6279c47

Please sign in to comment.