Hello,
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 :
#!/bin/sh
X509=$2
# Perform OCSP check on peer certificate
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
Regards
diff -ru openvpn/init.c openvpn-tls-export-cert/init.c
--- openvpn/init.c 2009-01-09 16:25:25.000000000 +0100
+++ openvpn-tls-export-cert/init.c 2009-01-09 16:28:34.000000000 +0100
@@ -1761,6 +1761,7 @@
#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;
diff -ru openvpn/options.c openvpn-tls-export-cert/options.c
--- openvpn/options.c 2009-01-09 16:25:25.000000000 +0100
+++ openvpn-tls-export-cert/options.c 2009-01-12 12:37:34.000000000 +0100
@@ -518,6 +518,9 @@
" 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"
@@ -1309,6 +1312,7 @@
#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);
@@ -1902,6 +1906,7 @@
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);
@@ -5424,6 +5429,11 @@
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);
diff -ru openvpn/options.h openvpn-tls-export-cert/options.h
--- openvpn/options.h 2009-01-09 16:25:25.000000000 +0100
+++ openvpn-tls-export-cert/options.h 2009-01-09 16:37:04.000000000 +0100
@@ -443,6 +443,7 @@
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;
diff -ru openvpn/ssl.c openvpn-tls-export-cert/ssl.c
--- openvpn/ssl.c 2009-01-09 16:25:25.000000000 +0100
+++ openvpn-tls-export-cert/ssl.c 2009-01-09 17:29:51.000000000 +0100
@@ -589,6 +589,49 @@
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.
@@ -777,10 +820,21 @@
/* 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,
@@ -788,6 +842,12 @@
argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
ret = openvpn_execve (&argv, opt->es, S_SCRIPT);
+ if (opt->verify_export_cert)
+ {
+ delete_file(tmp_file);
+ gc_free(&gc);
+ }
+
if (system_ok (ret))
{
msg (D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s",
diff -ru openvpn/ssl.h openvpn-tls-export-cert/ssl.h
--- openvpn/ssl.h 2009-01-09 16:25:25.000000000 +0100
+++ openvpn-tls-export-cert/ssl.h 2009-01-09 16:52:41.000000000 +0100
@@ -428,6 +428,7 @@
/* cert verification parms */
const char *verify_command;
+ const char *verify_export_cert;
const char *verify_x509name;
const char *crl_file;
int ns_cert_type;