0
0
mirror of https://github.com/OpenVPN/openvpn.git synced 2024-09-20 20:03:13 +02:00

enhance tls-verify possibility

It should be nice to enhance tls-verify check possibilities against peer
cert during a pending TLS connection like :
- OCSP verification
- check any X509 extensions of the peer certificate
- delta CRL verification
- ...

This patch add a new "tls-export-cert" option which allow to get peer
certificate in PEM format and to store it in an openvpn temporary file.
Peer certificate is stored before tls-script execution and deleted after.
The name of the related temporary file is available under tls-verify
script by an environment variable "peer_cert".

The patch was made from OpenVPN svn Beta21 branches.

Here is a very simple exemple of Tls-verify script which provide OCSP
support to OpenVPN (with tls-export-cert option) without any OpenVPN
"core" modification :

X509=$2

openssl ocsp \
      -issuer /etc/openvpn/ssl.crt/RootCA.pem \
      -CAfile /etc/openvpn/ssl.capath/OpenVPNServeur-cafile.pem \
      -cert $peer_cert \
      -url http://your-ocsp-url
      if [ $? -ne 0 ]
      then
          echo "error : OCSP check failed for ${X509}" | logger -t
"tls-verify"
          exit 1
       fi

This has been discussed here:
<http://thread.gmane.org/gmane.network.openvpn.devel/2492>
<http://thread.gmane.org/gmane.network.openvpn.devel/3150>
<http://thread.gmane.org/gmane.network.openvpn.devel/3217>

This patch has been modified by David Sommerseth, by fixing a few issues
which came up to during the code review process.  The man page has been
updated and tmp_file in ssl.c is checked for not being NULL before calling
delete_file().

Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
This commit is contained in:
Mathieu GIANNECCHINI 2010-03-02 00:26:57 +01:00 committed by David Sommerseth
parent 9bd1cd1b00
commit a3982181e2
6 changed files with 87 additions and 0 deletions

1
init.c
View File

@ -1805,6 +1805,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
#endif
to.verify_command = options->tls_verify;
to.verify_export_cert = options->tls_export_cert;
to.verify_x509name = options->tls_remote;
to.crl_file = options->crl_file;
to.ns_cert_type = options->ns_cert_type;

View File

@ -4258,6 +4258,14 @@ to
to build a command line which will be passed to the script.
.\"*********************************************************
.TP
.B --tls-export-cert directory
Store the certificates the clients uses upon connection to this
directory. This will be done before --tls-verify is called. The
certificates will use a temporary name and will be deleted when
the tls-verify script returns. The file name used for the certificate
is available via the peer_cert environment variable.
.\"*********************************************************
.TP
.B --tls-remote name
Accept connections only from a host with X509 name
or common name equal to
@ -5242,6 +5250,11 @@ than their names as denoted on the command line
or configuration file.
.\"*********************************************************
.TP
.B peer_cert
Temporary file name containing the client certificate upon
connection. Useful in conjunction with --tls-verify
.\"*********************************************************
.TP
.B script_context
Set to "init" or "restart" prior to up/down script execution.
For more information, see

View File

@ -529,6 +529,9 @@ static const char usage_message[] =
" tests of certification. cmd should return 0 to allow\n"
" TLS handshake to proceed, or 1 to fail. (cmd is\n"
" executed as 'cmd certificate_depth X509_NAME_oneline')\n"
"--tls-export-cert [directory] : Get peer cert in PEM format and store it \n"
" in an openvpn temporary file in [directory]. Peer cert is \n"
" stored before tls-verify script execution and deleted after.\n"
"--tls-remote x509name: Accept connections only from a host with X509 name\n"
" x509name. The remote host must also pass all other tests\n"
" of verification.\n"
@ -1325,6 +1328,7 @@ show_settings (const struct options *o)
#endif
SHOW_STR (cipher_list);
SHOW_STR (tls_verify);
SHOW_STR (tls_export_cert);
SHOW_STR (tls_remote);
SHOW_STR (crl_file);
SHOW_INT (ns_cert_type);
@ -1914,6 +1918,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (pkcs12_file);
MUST_BE_UNDEF (cipher_list);
MUST_BE_UNDEF (tls_verify);
MUST_BE_UNDEF (tls_export_cert);
MUST_BE_UNDEF (tls_remote);
MUST_BE_UNDEF (tls_timeout);
MUST_BE_UNDEF (renegotiate_bytes);
@ -5525,6 +5530,11 @@ add_option (struct options *options,
goto err;
options->tls_verify = string_substitute (p[1], ',', ' ', &options->gc);
}
else if (streq (p[0], "tls-export-cert") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->tls_export_cert = p[1];
}
else if (streq (p[0], "tls-remote") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);

View File

@ -440,6 +440,7 @@ struct options
const char *pkcs12_file;
const char *cipher_list;
const char *tls_verify;
const char *tls_export_cert;
const char *tls_remote;
const char *crl_file;

61
ssl.c
View File

@ -687,6 +687,49 @@ string_mod_sslname (char *str, const unsigned int restrictive_flags, const unsig
string_mod (str, restrictive_flags, 0, '_');
}
/* Get peer cert and store it in pem format in a temporary file
* in tmp_dir
*/
const char *
get_peer_cert(X509_STORE_CTX *ctx, const char *tmp_dir, struct gc_arena *gc)
{
X509 *peercert;
FILE *peercert_file;
const char *peercert_filename="";
if(!tmp_dir)
return NULL;
/* get peer cert */
peercert = X509_STORE_CTX_get_current_cert(ctx);
if(!peercert)
{
msg (M_ERR, "Unable to get peer certificate from current context");
return NULL;
}
/* create tmp file to store peer cert */
peercert_filename = create_temp_filename (tmp_dir, "pcf", gc);
/* write peer-cert in tmp-file */
peercert_file = fopen(peercert_filename, "w+");
if(!peercert_file)
{
msg (M_ERR, "Failed to open temporary file : %s", peercert_filename);
return NULL;
}
if(PEM_write_X509(peercert_file,peercert)<0)
{
msg (M_ERR, "Failed to write peer certificate in PEM format");
fclose(peercert_file);
return NULL;
}
fclose(peercert_file);
return peercert_filename;
}
/*
* Our verify callback function -- check
* that an incoming peer certificate is good.
@ -885,10 +928,21 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
/* run --tls-verify script */
if (opt->verify_command)
{
const char *tmp_file;
struct gc_arena gc;
int ret;
setenv_str (opt->es, "script_type", "tls-verify");
if (opt->verify_export_cert)
{
gc = gc_new();
if (tmp_file=get_peer_cert(ctx, opt->verify_export_cert,&gc))
{
setenv_str(opt->es, "peer_cert", tmp_file);
}
}
argv_printf (&argv, "%sc %d %s",
opt->verify_command,
ctx->error_depth,
@ -896,6 +950,13 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
ret = openvpn_execve (&argv, opt->es, S_SCRIPT);
if (opt->verify_export_cert)
{
if (tmp_file)
delete_file(tmp_file);
gc_free(&gc);
}
if (system_ok (ret))
{
msg (D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s",

1
ssl.h
View File

@ -441,6 +441,7 @@ struct tls_options
/* cert verification parms */
const char *verify_command;
const char *verify_export_cert;
const char *verify_x509name;
const char *crl_file;
int ns_cert_type;