Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,32 @@ Examples
```


---------
Smartcard
---------

Smartcard support needs `openssl pkcs engine` and `opensc` to be installed.

To make use of your smartcard put at least `pkcs11:` to the user-cert config or commandline.
Takes full or partially PKCS#11 token URI. Also username and password must not be empty, but
doesn't get used. So you can type in anything.

```
user-cert = pkcs11:
user-cert = pkcs11:token=someuser
user-cert = pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=012345678;token=someuser
username = none
password = none
```

In most cases `user-cert = pkcs11:` will do it, but if needed you can get the token-URI
with `p11tool --list-token-urls`.

Multiple readers are not supported.

Tested with Yubikey, but other PIV enabled smartcards may work too.


----------
Installing
----------
Expand Down
13 changes: 13 additions & 0 deletions doc/openfortivpn.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ openfortivpn \- Client for PPP+SSL VPN tunnel services
[\fB\-\-half\-internet\-routes=<bool>\fR]
[\fB\-\-ca\-file=\fI<file>\fR]
[\fB\-\-user\-cert=\fI<file>\fR]
[\fB\-\-user-cert=\fIpkcs11:\fR]
[\fB\-\-user\-key=\fI<file>\fR]
[\fB\-\-use\-syslog\fR]
[\fB\-\-trusted\-cert=\fI<digest>\fR]
Expand Down Expand Up @@ -107,6 +108,18 @@ verify the gateway certificate.
Use specified PEM-encoded certificate if the server requires authentication
with a certificate.
.TP
\fB\-\-user-cert=\fIpkcs11:\fR
Use at least the string pkcs11: for using a smartcard. Takes also
full or partially PKCS11-URI (p11tool --list-token-urls)

--user-cert = pkcs11:

--user-cert = pkcs11:token=someuser

--user-cert = pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=012345678;token=someuser

\fBRequires openssl pkcs engine!
.TP
\fB\-\-user\-key=\fI<file>\fR
Use specified PEM-encoded key if the server requires authentication with
a certificate.
Expand Down
7 changes: 6 additions & 1 deletion src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ const struct vpn_config invalid_cfg = {
.cipher_list = NULL,
.min_tls = -1,
.seclevel_1 = -1,
.cert_whitelist = NULL
.cert_whitelist = NULL,
.use_engine = -1
};

/*
Expand Down Expand Up @@ -350,6 +351,8 @@ int load_config(struct vpn_config *cfg, const char *filename)
} else if (strcmp(key, "user-cert") == 0) {
free(cfg->user_cert);
cfg->user_cert = strdup(val);
if (strncmp(strdup(val), "pkcs11:", 7) == 0)
cfg->use_engine = 1;
} else if (strcmp(key, "user-key") == 0) {
free(cfg->user_key);
cfg->user_key = strdup(val);
Expand Down Expand Up @@ -491,6 +494,8 @@ void merge_config(struct vpn_config *dst, struct vpn_config *src)
}
if (src->user_cert) {
free(dst->user_cert);
if (strncmp(src->user_cert, "pkcs11:", 7) == 0)
dst->use_engine = 1;
dst->user_cert = src->user_cert;
}
if (src->user_key) {
Expand Down
1 change: 1 addition & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct vpn_config {
int seclevel_1;
char *cipher_list;
struct x509_digest *cert_whitelist;
int use_engine;
};

int add_trusted_cert(struct vpn_config *cfg, const char *digest);
Expand Down
17 changes: 12 additions & 5 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,12 +570,19 @@ int auth_log_in(struct tunnel *tunnel)

tunnel->cookie[0] = '\0';

snprintf(data, sizeof(data), "username=%s&credential=%s&realm=%s&ajax=1"
"&redir=%%2Fremote%%2Findex&just_logged_in=1",
username, password, realm);
if (tunnel->config->use_engine) {
snprintf(data, sizeof(data), "cert=&nup=1");
ret = http_request(tunnel, "GET", "/remote/login",
data, &res, &response_size);
} else {
snprintf(data, sizeof(data), "username=%s&credential=%s&realm=%s&ajax=1"
"&redir=%%2Fremote%%2Findex&just_logged_in=1",
username, password, realm);

ret = http_request(tunnel, "POST", "/remote/logincheck",
data, &res, &response_size);
}

ret = http_request(
tunnel, "POST", "/remote/logincheck", data, &res, &response_size);
if (ret != 1)
goto end;

Expand Down
1 change: 1 addition & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ PPPD_USAGE \
" certificate.\n" \
" --user-cert=<file> Use specified PEM-encoded certificate if the server\n" \
" requires authentication with a certificate.\n" \
" --user-cert=pkcs11: Use smartcard. Takes also partial or full PKCS11-URI.\n" \
" --user-key=<file> Use specified PEM-encoded key if the server requires\n" \
" authentication with a certificate.\n" \
" --use-syslog Log to syslog instead of terminal.\n" \
Expand Down
91 changes: 77 additions & 14 deletions src/tunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <sys/ioctl.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>
#include <openssl/engine.h>
#if HAVE_PTY_H
#include <pty.h>
#elif HAVE_UTIL_H
Expand Down Expand Up @@ -754,32 +755,94 @@ int ssl_connect(struct tunnel *tunnel)
}
}

if (tunnel->config->user_cert) {
if (!SSL_CTX_use_certificate_file(
tunnel->ssl_context, tunnel->config->user_cert,
SSL_FILETYPE_PEM)) {
log_error("SSL_CTX_use_certificate_file: %s\n",
/* Use engine for PIV if user-cert config starts with pkcs11 URI: */
if (tunnel->config->use_engine > 0) {

ENGINE *e;
ENGINE_load_builtin_engines();
e = ENGINE_by_id("pkcs11");
if (!e) {
log_error("Could not load pkcs11 Engine: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}
}
if (!ENGINE_init(e)) {
log_error("Could not init pkcs11 Engine: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
ENGINE_free(e);
return 1;
}
if (!ENGINE_set_default_RSA(e))
abort();

ENGINE_finish(e);
ENGINE_free(e);

if (tunnel->config->user_key) {
if (!SSL_CTX_use_PrivateKey_file(
tunnel->ssl_context, tunnel->config->user_key,
SSL_FILETYPE_PEM)) {
log_error("SSL_CTX_use_PrivateKey_file: %s\n",
struct token parms;
parms.uri = tunnel->config->user_cert;
parms.cert = NULL;

if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1)) {
log_error("PKCS11 ENGINE_ctrl_cmd: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}

if (!SSL_CTX_use_certificate(tunnel->ssl_context, parms.cert)) {
log_error("PKCS11 SSL_CTX_use_certificate: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}

EVP_PKEY *privkey = ENGINE_load_private_key(
e, parms.uri, UI_OpenSSL(), NULL);
if (!privkey) {
log_error("PKCS11 ENGINE_load_private_key: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}

if (!SSL_CTX_use_PrivateKey(tunnel->ssl_context, privkey)) {
log_error("PKCS11 SSL_CTX_use_PrivateKey_file: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}
}

if (tunnel->config->user_cert && tunnel->config->user_key) {
if (!SSL_CTX_check_private_key(tunnel->ssl_context)) {
log_error("SSL_CTX_check_private_key: %s\n",
log_error("PKCS11 SSL_CTX_check_private_key: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}

} else { /* end PKCS11-engine */

if (tunnel->config->user_cert) {
if (!SSL_CTX_use_certificate_file(
tunnel->ssl_context, tunnel->config->user_cert,
SSL_FILETYPE_PEM)) {
log_error("SSL_CTX_use_certificate_file: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}
}

if (tunnel->config->user_key) {
if (!SSL_CTX_use_PrivateKey_file(
tunnel->ssl_context, tunnel->config->user_key,
SSL_FILETYPE_PEM)) {
log_error("SSL_CTX_use_PrivateKey_file: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}
}

if (tunnel->config->user_cert && tunnel->config->user_key) {
if (!SSL_CTX_check_private_key(tunnel->ssl_context)) {
log_error("SSL_CTX_check_private_key: %s\n",
ERR_error_string(ERR_peek_last_error(), NULL));
return 1;
}
}
}

if (!tunnel->config->insecure_ssl) {
Expand Down
6 changes: 6 additions & 0 deletions src/tunnel.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#endif

#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <sys/types.h>

#ifdef __clang__
Expand Down Expand Up @@ -78,6 +79,11 @@ struct tunnel {
int (*on_ppp_if_down)(struct tunnel *);
};

struct token {
const char *uri;
X509 *cert;
};

int ppp_interface_is_up(struct tunnel *tunnel);

int ssl_connect(struct tunnel *tunnel);
Expand Down