#REGTEST_TYPE=devel
# This reg-test uses the "set ssl ca-file" command to update a CA file over the CLI.
+# It also tests the "abort ssl ca-file" command.
#
# It is based on two CA certificates, set_cafile_interCA1.crt and set_cafile_interCA2.crt,
# and a client certificate that was signed with set_cafile_interCA1.crt (set_cafile_client.pem)
#REQUIRE_BINARIES=socat
feature ignore_unknown_macro
-server s1 -repeat 3 {
+server s1 -repeat 4 {
rxreq
txresp
} -start
expect resp.http.X-SSL-Client-Verify == 21
} -run
+# Set a new ca-file without committing it and check that the new ca-file is not taken into account
+shell {
+ printf "set ssl ca-file ${testdir}/set_cafile_ca2.crt <<\n$(cat ${testdir}/set_cafile_ca1.crt)\n\n" | socat "${tmpdir}/h1/stats" -
+}
+
+# This connection should still fail for the same reasons as previously
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ # unable to verify the client certificate
+ expect resp.http.X-SSL-Client-Verify == 21
+} -run
+
+haproxy h1 -cli {
+ send "abort ssl ca-file ${testdir}/set_cafile_ca2.crt"
+ expect ~ "Transaction aborted for certificate '${testdir}/set_cafile_ca2.crt'!"
+ send "commit ssl ca-file ${testdir}/set_cafile_ca2.crt"
+ expect ~ "No ongoing transaction!"
+}
+
# Update the bind line's ca-file in order to accept the client certificate
shell {
return 1;
}
+
+/* parsing function of 'abort ssl ca-file' */
+static int cli_parse_abort_cafile(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ char *err = NULL;
+
+ if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+ return 1;
+
+ if (!*args[3])
+ return cli_err(appctx, "'abort ssl ca-file' expects a filename\n");
+
+ /* The operations on the CKCH architecture are locked so we can
+ * manipulate ckch_store and ckch_inst */
+ if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
+ return cli_err(appctx, "Can't abort!\nOperations on certificates are currently locked!\n");
+
+ if (!cafile_transaction.path) {
+ memprintf(&err, "No ongoing transaction!\n");
+ goto error;
+ }
+
+ if (strcmp(cafile_transaction.path, args[3]) != 0) {
+ memprintf(&err, "The ongoing transaction is about '%s' but you are trying to abort a transaction for '%s'\n", cafile_transaction.path, args[3]);
+ goto error;
+ }
+
+ /* Only free the uncommitted cafile_entry here, because the SNI and instances were not generated yet */
+ ssl_store_delete_cafile_entry(cafile_transaction.new_cafile_entry);
+ cafile_transaction.new_cafile_entry = NULL;
+ cafile_transaction.old_cafile_entry = NULL;
+ ha_free(&cafile_transaction.path);
+
+ HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
+
+ err = memprintf(&err, "Transaction aborted for certificate '%s'!\n", args[3]);
+ return cli_dynmsg(appctx, LOG_NOTICE, err);
+
+error:
+ HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
+
+ return cli_dynerr(appctx, err);
+}
+
/* release function of the `commit ssl ca-file' command, free things and unlock the spinlock */
static void cli_release_commit_cafile(struct appctx *appctx)
{
{ { "set", "ssl", "ca-file", NULL }, "set ssl ca-file <cafile> <payload> : replace a CA file", cli_parse_set_cafile, NULL, NULL },
{ { "commit", "ssl", "ca-file", NULL }, "commit ssl ca-file <cafile> : commit a CA file", cli_parse_commit_cafile, cli_io_handler_commit_cafile, cli_release_commit_cafile },
+ { { "abort", "ssl", "ca-file", NULL }, "abort ssl ca-file <cafile> : abort a transaction for a CA file", cli_parse_abort_cafile, NULL, NULL },
{ { NULL }, NULL, NULL, NULL }
}};