This commit adds the option --tls-crypt-v2-max-age n. When a client key
is older than n days or has no timestamp, the server rejects it.
Based on work by Rein van Baaren for Sentyron.
Co-authored-by: Rein van Baaren <revaban04@proton.me>
Change-Id: I0579d18c784e2ac16973d5553992c28f281a0900
Signed-off-by: Max Fillinger <max@max-fillinger.net>
Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1304
Message-Id: <
20251119140149.31867-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg34545.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
The command can reject the connection by exiting with a non-zero exit
code.
+--tls-crypt-v2-max-age n
+ Reject tls-crypt-v2 client keys that are older than n days or have
+ no timestamp.
+
--tls-exit
Exit on TLS negotiation failure. This option can be useful when you only
want to make one attempt at connecting, e.g. in a test or monitoring script.
The message is dropped and no error response is sent when either 3.1, 3.2 or
3.3 fails (DoS protection).
-4. Server optionally checks metadata using a --tls-crypt-v2-verify script
+4. The server optionally checks if the client key contains a timestamp that is
+ below a maximum age configured with the --tls-crypt-v2-max-age option.
+
+5. Server optionally checks metadata using a --tls-crypt-v2-verify script
This allows early abort of connection, *before* we expose any of the
notoriously dangerous TLS, X.509 and ASN.1 parsers and thereby reduces the
{
to.tls_wrap.tls_crypt_v2_server_key = c->c1.ks.tls_crypt_v2_server_key;
to.tls_crypt_v2_verify_script = c->options.tls_crypt_v2_verify_script;
+ to.tls_crypt_v2_max_age = c->options.tls_crypt_v2_max_age;
if (options->ce.tls_crypt_v2_force_cookie)
{
to.tls_wrap.opt.flags |= CO_FORCE_TLSCRYPTV2_COOKIE;
" fresh tls-crypt-v2 server key, and store to keyfile\n"
"--tls-crypt-v2-verify cmd : Run command cmd to verify the metadata of the\n"
" client-supplied tls-crypt-v2 client key\n"
+ "--tls-crypt-v2-max-age n : Only accept tls-crypt-v2 client keys that have a\n"
+ " timestamp which is at most n days old.\n"
"--askpass [file]: Get PEM password from controlling tty before we daemonize.\n"
"--auth-nocache : Don't cache --askpass or --auth-user-pass passwords.\n"
"--crl-verify crl ['dir']: Check peer certificate against a CRL.\n"
VERIFY_PERMISSION(OPT_P_GENERAL);
options->tls_crypt_v2_verify_script = p[1];
}
+ else if (streq(p[0], "tls-crypt-v2-max-age") && p[1])
+ {
+ VERIFY_PERMISSION(OPT_P_GENERAL);
+ if (!atoi_constrained(p[1], &options->tls_crypt_v2_max_age, "tls-crypt-v2-max-age", 1, INT_MAX, msglevel))
+ {
+ goto err;
+ }
+ }
else if (streq(p[0], "x509-track") && p[1] && !p[2])
{
VERIFY_PERMISSION(OPT_P_GENERAL);
const char *tls_crypt_v2_verify_script;
+ int tls_crypt_v2_max_age;
+
/* Allow only one session */
bool single_session;
bool tls_crypt_v2;
const char *tls_crypt_v2_verify_script;
+ int tls_crypt_v2_max_age;
/** TLS handshake wrapping state */
struct tls_wrap_ctx tls_wrap;
#include "argv.h"
#include "base64.h"
#include "crypto.h"
+#include "integer.h"
#include "platform.h"
#include "run_command.h"
#include "session_id.h"
return ret;
}
+static bool
+tls_crypt_v2_check_client_key_age(const struct tls_wrap_ctx *ctx, int max_days)
+{
+ if (ctx->tls_crypt_v2_metadata.len < 1 + sizeof(int64_t))
+ {
+ msg(M_WARN, "ERROR: Client key metadata is too small to contain a timestamp.");
+ return false;
+ }
+
+ const uint8_t *metadata = ctx->tls_crypt_v2_metadata.data;
+ if (*metadata != TLS_CRYPT_METADATA_TYPE_TIMESTAMP)
+ {
+ msg(M_WARN, "ERROR: Client key does not have a timestamp.");
+ return false;
+ }
+
+ int64_t timestamp;
+ memcpy(×tamp, metadata + 1, sizeof(int64_t));
+ timestamp = (int64_t)ntohll((uint64_t)timestamp);
+ int64_t max_age_in_seconds = max_days * 24 * 60 * 60;
+ if (now - timestamp > max_age_in_seconds)
+ {
+ msg(M_WARN, "ERROR: Client key is too old.");
+ return false;
+ }
+ return true;
+}
+
static bool
tls_crypt_v2_verify_metadata(const struct tls_wrap_ctx *ctx, const struct tls_options *opt)
{
return false;
}
+ if (opt && opt->tls_crypt_v2_max_age > 0 && !tls_crypt_v2_check_client_key_age(ctx, opt->tls_crypt_v2_max_age))
+ {
+ secure_memzero(&ctx->original_wrap_keydata, sizeof(ctx->original_wrap_keydata));
+ return false;
+ }
+
if (opt && opt->tls_crypt_v2_verify_script && !tls_crypt_v2_verify_metadata(ctx, opt))
{
secure_memzero(&ctx->original_wrap_keydata, sizeof(ctx->original_wrap_keydata));