Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Pass only the signature of the server's cert from NetworkManager.
Since we run openconnect as an unprivileged user, it may not be able to
read the original trust chain and validate the certificate for itself.
But since the auth-dialog has already connected to the server and done
the authentication, it can just give us the known signature for the
certificate the server is using today...

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed May 26, 2009
1 parent 07aa3bc commit aa76199
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 0 deletions.
1 change: 1 addition & 0 deletions auth-dlg-settings.h
Expand Up @@ -30,6 +30,7 @@

#define NM_OPENCONNECT_KEY_GATEWAY "gateway"
#define NM_OPENCONNECT_KEY_COOKIE "cookie"
#define NM_OPENCONNECT_KEY_GWCERT "gwcert"
#define NM_OPENCONNECT_KEY_AUTHTYPE "authtype"
#define NM_OPENCONNECT_KEY_USERCERT "usercert"
#define NM_OPENCONNECT_KEY_CACERT "cacert"
Expand Down
5 changes: 5 additions & 0 deletions main.c
Expand Up @@ -81,6 +81,7 @@ static struct option long_options[] = {
{"reconnect-timeout", 1, 0, '7'},
{"dtls-ciphers", 1, 0, '8'},
{"authgroup", 1, 0, '9'},
{"servercert", 1, 0, 0x01},
{NULL, 0, 0, 0},
};

Expand Down Expand Up @@ -120,6 +121,7 @@ void usage(void)
printf(" --no-passwd Disable password/SecurID authentication\n");
printf(" --passwd-on-stdin Read password from standard input\n");
printf(" --reconnect-timeout Connection retry timeout in seconds\n");
printf(" --servercert Server's SSL certificate signature\n");
exit(1);
}

Expand Down Expand Up @@ -188,6 +190,9 @@ int main(int argc, char **argv)
case '0':
vpninfo->cafile = optarg;
break;
case 0x01:
vpninfo->servercert = optarg;
break;
case '1':
vpninfo->dtls_attempt_period = 0;
break;
Expand Down
24 changes: 24 additions & 0 deletions nm-auth-dialog.c
Expand Up @@ -1055,6 +1055,29 @@ void write_progress(struct openconnect_info *info, int level, const char *fmt, .
g_free(msg);
}

static void print_peer_cert(struct openconnect_info *vpninfo)
{
X509 *cert = SSL_get_peer_certificate(vpninfo->https_ssl);
BIO *bp = BIO_new(BIO_s_mem());
char zero = 0;
char *tmp1, *tmp2;
BUF_MEM *sig;

i2a_ASN1_STRING(bp, cert->signature, V_ASN1_OCTET_STRING);
BIO_write(bp, &zero, 1);
BIO_get_mem_ptr(bp, &sig);
tmp1 = sig->data;
while ((tmp2 = strchr(tmp1, '\\'))) {
tmp1 = tmp2++;
while (isspace(*tmp2))
tmp2++;
memmove(tmp1, tmp2, strlen(tmp2) + 1);
}

printf("gwcert\n%s\n", sig->data);
BIO_free(bp);
}

static gboolean cookie_obtained(auth_ui_data *ui_data)
{
ui_data->getting_cookie = FALSE;
Expand Down Expand Up @@ -1099,6 +1122,7 @@ static gboolean cookie_obtained(auth_ui_data *ui_data)

printf("%s\n%s\n", NM_OPENCONNECT_KEY_GATEWAY, ui_data->vpninfo->hostname);
printf("%s\n%s\n", NM_OPENCONNECT_KEY_COOKIE, ui_data->vpninfo->cookie);
print_peer_cert(ui_data->vpninfo);
memset((void *)ui_data->vpninfo->cookie, 0, strlen(ui_data->vpninfo->cookie));
printf("\n\n");
fflush(stdout);
Expand Down
7 changes: 7 additions & 0 deletions openconnect.8
Expand Up @@ -117,6 +117,10 @@ openconnect \- Connect to Cisco AnyConnect VPN
[
.B --reconnect-timeout
]
[
.B --servercert
.I SIGNATURE
]
\fIserver\fR

.SH DESCRIPTION
Expand Down Expand Up @@ -255,6 +259,9 @@ Read password from standard input
Keep reconnect attempts until so much seconds are elapsed. The default
timeout is 300 seconds, which means that openconnect can recover
VPN connection after a temporary network down time of 300 seconds.
.TP
.B --servercert
Accept server's SSL certificate only if its signature matches.

.SH LIMITATIONS
The
Expand Down
1 change: 1 addition & 0 deletions openconnect.h
Expand Up @@ -138,6 +138,7 @@ struct openconnect_info {
int tpm;
char *tpmpass;
const char *cafile;
const char *servercert;
const char *xmlconfig;
char xmlsha1[(SHA_DIGEST_LENGTH * 2) + 1];
char *username;
Expand Down
32 changes: 32 additions & 0 deletions ssl.c
Expand Up @@ -160,6 +160,35 @@ static int verify_callback(X509_STORE_CTX *ctx, void *arg)
return X509_verify_cert(ctx);
}

static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
{
BIO *bp = BIO_new(BIO_s_mem());
char zero = 0;
char *tmp1, *tmp2;
BUF_MEM *sig;
int result = 0;

i2a_ASN1_STRING(bp, cert->signature, V_ASN1_OCTET_STRING);
BIO_write(bp, &zero, 1);
BIO_get_mem_ptr(bp, &sig);
tmp1 = sig->data;
while ((tmp2 = strchr(tmp1, '\\'))) {
tmp1 = tmp2++;
while (isspace(*tmp2))
tmp2++;
memmove(tmp1, tmp2, strlen(tmp2) + 1);
}

if (strcmp(vpninfo->servercert, sig->data)) {
vpninfo->progress(vpninfo, PRG_ERR,
"Server SSL certificate didn't match\n");
result = -EINVAL;
}

BIO_free(bp);
return result;
}

static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
{
X509 *peer_cert;
Expand All @@ -177,6 +206,9 @@ static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)

peer_cert = SSL_get_peer_certificate(https_ssl);

if (vpninfo->servercert)
return check_server_cert(vpninfo, peer_cert);

if (vpninfo->validate_peer_cert)
return vpninfo->validate_peer_cert(vpninfo, peer_cert);

Expand Down

0 comments on commit aa76199

Please sign in to comment.