Added option to allow sending a cookie without the corresponding certificate.

This option is required for the cisco clients, that do not always use the
client certificate. When this option is set to false it means that the cookie
itself is sufficient for authentication. This is bad practice of smart cards
are in use.
This commit is contained in:
Nikos Mavrogiannopoulos
2013-03-01 21:52:57 +01:00
parent 394493dbcb
commit ef18851237
9 changed files with 62 additions and 10 deletions

View File

@@ -10,7 +10,13 @@ auth = "pam"
# Client config xml. The variable $GROUP will be replaced by
# the user's group name. This file must be accessible from inside
# the worker's chroot. It is not used by the openconnect client.
user-profile = ../doc/profile.xml
#user-profile = /profile.xml
# Unless set to false it is required for clients to present their
# certificate even if they are authenticating via a previously granted
# cookie. Legacy CISCO clients do not do that, and thus this option
# should be set for them.
#always-require-cert = false
# Use listen-host to limit to specific IPs or to the IPs of a provided hostname.
#listen-host = [IP|HOSTNAME]

View File

@@ -28,6 +28,7 @@
#include <fcntl.h>
#include <ocserv-args.h>
#include <autoopts/options.h>
#include <limits.h>
#include <vpn.h>
#include <tlslib.h>
@@ -124,7 +125,7 @@ unsigned j;
#endif
} else if (strcasecmp(auth[j], "certificate") == 0) {
config->auth_types |= AUTH_TYPE_CERTIFICATE;
config->cert_req = GNUTLS_CERT_REQUIRE;
config->cert_req = GNUTLS_CERT_REQUEST;
} else {
fprintf(stderr, "Unknown auth method: %s\n", auth[j]);
exit(1);
@@ -161,6 +162,7 @@ unsigned j;
READ_STRING("pid-file", pid_file, 0);
READ_STRING("banner", config->banner, 0);
READ_TF("always-require-cert", config->force_cert_auth, 0, 1);
READ_TF("use-utmp", config->use_utmp, 0, 1);
READ_TF("try-mtu-discovery", config->try_mtu, 0, 0);
@@ -237,9 +239,27 @@ static void check_cfg( struct cfg_st *config)
if (config->cert) {
config->cert_hash = calc_sha1_hash(config->cert, 1);
}
if (config->force_cert_auth)
config->cert_req = GNUTLS_CERT_REQUIRE;
if (config->xml_config_file) {
config->xml_config_hash = calc_sha1_hash(config->xml_config_file, 0);
if (config->xml_config_hash == NULL && config->chroot_dir != NULL) {
char path[_POSIX_PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", config->chroot_dir, config->xml_config_file);
config->xml_config_hash = calc_sha1_hash(path, 0);
if (config->xml_config_hash == NULL) {
fprintf(stderr, "Cannot open file '%s'\n", path);
exit(1);
}
}
if (config->xml_config_hash == NULL) {
fprintf(stderr, "Cannot open file '%s'\n", config->xml_config_file);
exit(1);
}
}
if (config->keepalive == 0)

View File

@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.c)
*
* It has been AutoGen-ed March 1, 2013 at 07:46:59 PM by AutoGen 5.16
* It has been AutoGen-ed March 1, 2013 at 09:44:33 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*

View File

@@ -87,6 +87,12 @@ auth = "pam"
# It is not used by the openconnect client.
#user-profile = /path/to/file.xml
# Unless set to false it is required for clients to present their
# certificate even if they are authenticating via a previously granted
# cookie. Legacy CISCO clients do not do that, and thus this option
# should be set for them.
#always-require-cert = false
# Use listen-host to limit to specific IPs or to the IPs of a provided hostname.
#listen-host = [IP|HOSTNAME]

View File

@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.h)
*
* It has been AutoGen-ed March 1, 2013 at 07:46:59 PM by AutoGen 5.16
* It has been AutoGen-ed March 1, 2013 at 09:44:33 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*

View File

@@ -196,13 +196,15 @@ static int verify_certificate_cb(gnutls_session_t session)
if (session == ws->dtls_session) /* no certificate is verified in DTLS */
return 0;
ws->cert_auth_ok = 0;
/* This verification function uses the trusted CAs in the credentials
* structure. So you must have installed one or more CA certificates.
*/
ret = gnutls_certificate_verify_peers2(session, &status);
if (ret < 0) {
oclog(ws, LOG_ERR, "error verifying client certificate");
return GNUTLS_E_CERTIFICATE_ERROR;
goto fail;
}
if (status != 0) {
@@ -214,7 +216,7 @@ static int verify_certificate_cb(gnutls_session_t session)
gnutls_certificate_verification_status_print(status, type,
&out, 0);
if (ret < 0)
return GNUTLS_E_CERTIFICATE_ERROR;
goto fail;
oclog(ws, LOG_INFO, "client certificate verification failed: %s", out.data);
@@ -223,13 +225,20 @@ static int verify_certificate_cb(gnutls_session_t session)
oclog(ws, LOG_INFO, "client certificate verification failed.");
#endif
return GNUTLS_E_CERTIFICATE_ERROR;
goto fail;
} else {
ws->cert_auth_ok = 1;
oclog(ws, LOG_INFO, "client certificate verification succeeded");
}
/* notify gnutls to continue handshake normally */
return 0;
fail:
if (ws->config->force_cert_auth != 0)
return GNUTLS_E_CERTIFICATE_ERROR;
else
return 0;
}
int pin_callback (void *user, int attempt, const char *token_url,
@@ -479,8 +488,7 @@ gnutls_x509_crt_t crt;
ret = gnutls_load_file(file, &data);
if (ret < 0) {
fprintf(stderr, "Cannot open file '%s': %s\n", file, gnutls_strerror(ret));
exit(1);
return NULL;
}
if (cert != 0) {

View File

@@ -83,6 +83,7 @@ struct cfg_st {
unsigned max_same_clients;
unsigned use_utmp;
unsigned try_mtu; /* MTU discovery enabled */
unsigned force_cert_auth; /* always require client certificate */
/* if gdbm is there */
char* cookie_db_name;

View File

@@ -292,6 +292,11 @@ static int auth_user(worker_st *ws, struct cmd_auth_req_st* areq)
int ret;
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if (ws->cert_auth_ok == 0) {
oclog(ws, LOG_INFO, "no certificate provided for authentication");
return -1;
}
ret = get_cert_info(ws, areq->cert_user, sizeof(areq->cert_user),
areq->cert_group, sizeof(areq->cert_group));
if (ret < 0)
@@ -322,7 +327,12 @@ struct cmd_auth_cookie_req_st areq;
if (cookie_size != sizeof(areq.cookie))
return -1;
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if ((ws->config->auth_types & AUTH_TYPE_CERTIFICATE) && ws->config->force_cert_auth != 0) {
if (ws->cert_auth_ok == 0) {
oclog(ws, LOG_INFO, "no certificate provided for cookie authentication");
return -1;
}
ret = get_cert_info(ws, areq.cert_user, sizeof(areq.cert_user),
areq.cert_group, sizeof(areq.cert_group));
if (ret < 0)

View File

@@ -87,6 +87,7 @@ typedef struct worker_st {
uint8_t master_secret[TLS_MASTER_SIZE];
uint8_t session_id[GNUTLS_MAX_SESSION_ID];
unsigned auth_ok;
unsigned cert_auth_ok;
int tun_fd;
struct http_req_st req;