aboutsummaryrefslogtreecommitdiff
path: root/ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl.c')
-rw-r--r--ssl.c146
1 files changed, 120 insertions, 26 deletions
diff --git a/ssl.c b/ssl.c
index c5f2131..0a84b0d 100644
--- a/ssl.c
+++ b/ssl.c
@@ -7,6 +7,10 @@
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
*
+ * Additions for eurephia plugin done by:
+ * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009
+ *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -687,6 +691,51 @@ 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_file (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;
+}
+
+char * x509_username_field; /* GLOBAL */
+
/*
* Our verify callback function -- check
* that an incoming peer certificate is good.
@@ -697,7 +746,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
{
char *subject = NULL;
char envname[64];
- char common_name[TLS_CN_LEN];
+ char common_name[TLS_USERNAME_LEN];
SSL *ssl;
struct tls_session *session;
const struct tls_options *opt;
@@ -729,18 +778,20 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
string_mod_sslname (subject, X509_NAME_CHAR_CLASS, opt->ssl_flags);
string_replace_leading (subject, '-', '_');
- /* extract the common name */
- if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), "CN", common_name, TLS_CN_LEN))
+ /* extract the username (default is CN) */
+ if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), x509_username_field, common_name, sizeof(common_name)))
{
if (!ctx->error_depth)
- {
- msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract Common Name from X509 subject string ('%s') -- note that the Common Name length is limited to %d characters",
- subject,
- TLS_CN_LEN);
- goto err;
- }
+ {
+ msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract %s from X509 subject string ('%s') -- note that the username length is limited to %d characters",
+ x509_username_field,
+ subject,
+ TLS_USERNAME_LEN);
+ goto err;
+ }
}
+
string_mod_sslname (common_name, COMMON_NAME_CHAR_CLASS, opt->ssl_flags);
cert_hash_remember (session, ctx->error_depth, ctx->current_cert->sha1_hash);
@@ -780,6 +831,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
openvpn_snprintf (envname, sizeof(envname), "tls_id_%d", ctx->error_depth);
setenv_str (opt->es, envname, subject);
+#ifdef ENABLE_EUREPHIA
+ /* export X509 cert SHA1 fingerprint */
+ {
+ struct gc_arena gc = gc_new ();
+ openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", ctx->error_depth);
+ setenv_str (opt->es, envname,
+ format_hex_ex(ctx->current_cert->sha1_hash, SHA_DIGEST_LENGTH, 0, 1, ":", &gc));
+ gc_free(&gc);
+ }
+#endif
#if 0
/* export common name string as environmental variable */
openvpn_snprintf (envname, sizeof(envname), "tls_common_name_%d", ctx->error_depth);
@@ -906,32 +967,48 @@ 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,
subject);
argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
- ret = openvpn_execve (&argv, opt->es, S_SCRIPT);
+ ret = openvpn_run_script (&argv, opt->es, 0, "--tls-verify script");
+
+ if (opt->verify_export_cert)
+ {
+ if (tmp_file)
+ delete_file(tmp_file);
+ gc_free(&gc);
+ }
- if (system_ok (ret))
+ if (ret)
{
msg (D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s",
ctx->error_depth, subject);
}
else
{
- if (!system_executed (ret))
- argv_msg_prefix (M_ERR, &argv, "Verify command failed to execute");
msg (D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s",
ctx->error_depth, subject);
goto err; /* Reject connection */
}
}
-
+
/* check peer cert against CRL */
if (opt->crl_file)
{
@@ -1749,7 +1826,8 @@ init_ssl (const struct options *options)
}
else
#endif
- SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ x509_username_field = (char *) options->x509_username_field;
+ SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
verify_callback);
/* Connection information callback */
@@ -2288,6 +2366,7 @@ key_state_free (struct key_state *ks, bool clear)
free_buf (&ks->plaintext_read_buf);
free_buf (&ks->plaintext_write_buf);
free_buf (&ks->ack_write_buf);
+ buffer_list_free(ks->paybuf);
if (ks->send_reliable)
{
@@ -3086,6 +3165,17 @@ key_source2_read (struct key_source2 *k2,
return 1;
}
+static void
+flush_payload_buffer (struct tls_multi *multi, struct key_state *ks)
+{
+ struct buffer *b;
+ while ((b = buffer_list_peek (ks->paybuf)))
+ {
+ key_state_write_plaintext_const (multi, ks, b->data, b->len);
+ buffer_list_pop (ks->paybuf);
+ }
+}
+
/*
* Macros for key_state_soft_reset & tls_process
*/
@@ -3190,7 +3280,6 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
struct gc_arena gc = gc_new ();
struct argv argv = argv_new ();
const char *tmp_file = "";
- int retval;
bool ret = false;
/* Is username defined? */
@@ -3233,16 +3322,11 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
/* format command line */
argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
-
+
/* call command */
- retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);
+ ret = openvpn_run_script (&argv, session->opt->es, 0,
+ "--auth-user-pass-verify");
- /* test return status of command */
- if (system_ok (retval))
- ret = true;
- else if (!system_executed (retval))
- argv_msg_prefix (D_TLS_ERRORS, &argv, "TLS Auth Error: user-pass-verify script failed to execute");
-
if (!session->opt->auth_user_pass_verify_script_via_file)
setenv_del (session->opt->es, "password");
}
@@ -3688,9 +3772,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
s2 = verify_user_pass_script (session, up);
/* check sizing of username if it will become our common name */
- if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_CN_LEN)
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN)
{
- msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_CN_LEN);
+ msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN);
s1 = OPENVPN_PLUGIN_FUNC_ERROR;
}
@@ -4006,6 +4090,9 @@ tls_process (struct tls_multi *multi,
/* Set outgoing address for data channel packets */
link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es);
+ /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
+ flush_payload_buffer (multi, ks);
+
#ifdef MEASURE_TLS_HANDSHAKE_STATS
show_tls_performance_stats();
#endif
@@ -5105,6 +5192,13 @@ tls_send_payload (struct tls_multi *multi,
if (key_state_write_plaintext_const (multi, ks, data, size) == 1)
ret = true;
}
+ else
+ {
+ if (!ks->paybuf)
+ ks->paybuf = buffer_list_new (0);
+ buffer_list_push_data (ks->paybuf, data, (size_t)size);
+ ret = true;
+ }
ERR_clear_error ();