~rcr/rirc

5bcae8f2fdd873b0b792b650b8fb66568787d221 — Richard Robbins 10 days ago 62bd337
add --tls-ca-file, rename --tls-ca-path, --tls-cert
10 files changed, 214 insertions(+), 145 deletions(-)

M README.md
M config.def.h
M docs/rirc.1
M src/io.c
M src/io.h
M src/rirc.c
M src/rirc.h
M src/state.c
M test/io.mock.c
M test/state.c
M README.md => README.md +3 -2
@@ 82,9 82,10 @@ Server connection options:
   --ipv4                   Connect to server using only ipv4 addresses
   --ipv6                   Connect to server using only ipv6 addresses
   --tls-disable            Set server TLS disabled
   --tls-ca-file=PATH       Set server TLS CA cert file path
   --tls-ca-path=PATH       Set server TLS CA cert directory path
   --tls-cert=PATH          Set server TLS client cert file path
   --tls-verify=MODE        Set server TLS peer certificate verification mode
   --tls-cert-ca=PATH       Set server TLS ca cert file path
   --tls-cert-client=PATH   Set server TLS client cert file path
```

Commands:

M config.def.h => config.def.h +5 -1
@@ 110,7 110,11 @@

/* [NETWORK] */

/* Default CA certifate file path
/* Default CA certificate file path
 *   ("": a list of known paths is checked) */
#define CA_CERT_FILE ""

/* Default CA certificate directory path
 *   ("": a list of known paths is checked) */
#define CA_CERT_PATH ""


M docs/rirc.1 => docs/rirc.1 +9 -6
@@ 52,6 52,15 @@ Connect to \fIserver\fP using only ipv6 addresses
.B --tls-disable
Set \fIserver\fP TLS disabled, default port to 6667
.TP
.BI --tls-ca-file= path
Set \fIserver\fP TLS CA cert file \fIpath\fP
.TP
.BI --tls-ca-path= path
Set \fIserver\fP TLS CA cert directory \fIpath\fP
.TP
.BI --tls-cert= path
Set \fIserver\fP TLS client cert file \fIpath\fP
.TP
.BI --tls-verify= mode
Set \fIserver\fP TLS peer certificate verification \fImode\fP:
.EX


@@ 59,12 68,6 @@ Set \fIserver\fP TLS peer certificate verification \fImode\fP:
\(bu \fIoptional\fP - cert is verified, handshake continues on error
\(bu \fIrequired\fP - cert is verified, handshake is aborted on error (default)
.EE
.TP
.BI --tls-cert-ca= path
Set \fIserver\fP TLS ca cert file \fIpath\fP
.TP
.BI --tls-cert-client= path
Set \fIserver\fP TLS client cert file \fIpath\fP
.SH USAGE
.TS
l .

M src/io.c => src/io.c +59 -36
@@ 105,8 105,9 @@ struct connection
	const void *obj;
	const char *host;
	const char *port;
	const char *tls_cert_ca;
	const char *tls_cert_client;
	const char *tls_ca_file;
	const char *tls_ca_path;
	const char *tls_cert;
	enum io_state {
		IO_ST_INVALID,
		IO_ST_DXED, /* Socket disconnected, passive */


@@ 158,7 159,7 @@ static const char* io_tls_err(int);
static int io_tls_establish(struct connection*);
static int io_tls_x509_vrfy(struct connection*);

const char *ca_cert_paths[] = {
const char *default_ca_certs[] = {
	"/etc/ssl/ca-bundle.pem",
	"/etc/ssl/cert.pem",
	"/etc/ssl/certs/ca-certificates.crt",


@@ 172,8 173,9 @@ connection(
	const void *obj,
	const char *host,
	const char *port,
	const char *tls_cert_ca,
	const char *tls_cert_client,
	const char *tls_ca_file,
	const char *tls_ca_path,
	const char *tls_cert,
	uint32_t flags)
{
	struct connection *cx;


@@ 185,8 187,9 @@ connection(
	cx->flags = flags;
	cx->host = strdup(host);
	cx->port = strdup(port);
	cx->tls_cert_ca = (tls_cert_ca ? strdup(tls_cert_ca) : NULL);
	cx->tls_cert_client = (tls_cert_client ? strdup(tls_cert_client) : NULL);
	cx->tls_ca_file = (tls_ca_file ? strdup(tls_ca_file) : NULL);
	cx->tls_ca_path = (tls_ca_path ? strdup(tls_ca_path) : NULL);
	cx->tls_cert = (tls_cert ? strdup(tls_cert) : NULL);
	cx->st_cur = IO_ST_DXED;
	cx->st_new = IO_ST_INVALID;
	PT_CF(pthread_mutex_init(&(cx->mtx), NULL));


@@ 200,8 203,9 @@ connection_free(struct connection *cx)
	PT_CF(pthread_mutex_destroy(&(cx->mtx)));
	free((void*)cx->host);
	free((void*)cx->port);
	free((void*)cx->tls_cert_ca);
	free((void*)cx->tls_cert_client);
	free((void*)cx->tls_ca_file);
	free((void*)cx->tls_ca_path);
	free((void*)cx->tls_cert);
	free(cx);
}



@@ 841,53 845,72 @@ io_tls_establish(struct connection *cx)
		goto err;
	}

	if (cx->tls_cert_client) {
	ret = -1;

		if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_client), cx->tls_cert_client)) < 0) {
			io_error(cx, "  .. Failed to load client cert: '%s': %s", cx->tls_cert_client, io_tls_err(ret));
	if (ret < 0 && cx->tls_ca_file) {
		if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_ca), cx->tls_ca_file)) < 0) {
			io_error(cx, "  .. Failed to load ca cert file: '%s': %s", cx->tls_ca_file, io_tls_err(ret));
			goto err;
		}
	}

		if ((ret = mbedtls_pk_parse_keyfile(
				&(cx->tls_pk_ctx),
				cx->tls_cert_client,
				NULL,
				mbedtls_ctr_drbg_random,
				&(cx->tls_ctr_drbg))))
		{
			io_error(cx, "  .. Failed to load client cert key: '%s': %s", cx->tls_cert_client, io_tls_err(ret));
	if (ret < 0 && cx->tls_ca_path) {
		if ((ret = mbedtls_x509_crt_parse_path(&(cx->tls_x509_crt_ca), cx->tls_ca_path)) < 0) {
			io_error(cx, "  .. Failed to load ca cert path: '%s': %s", cx->tls_ca_path, io_tls_err(ret));
			goto err;
		}
	}

		if ((ret = mbedtls_ssl_conf_own_cert(&(cx->tls_conf), &(cx->tls_x509_crt_client), &(cx->tls_pk_ctx)))) {
			io_error(cx, "  .. Failed to configure client cert: '%s': %s", cx->tls_cert_client, io_tls_err(ret));
	if (ret < 0 && default_ca_file && *default_ca_file) {
		if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_ca), default_ca_file)) < 0) {
			io_error(cx, "  .. Failed to load ca cert file: '%s': %s", default_ca_file, io_tls_err(ret));
			goto err;
		}
	}

	if (ret < 0 && default_ca_path && *default_ca_path) {
		if ((ret = mbedtls_x509_crt_parse_path(&(cx->tls_x509_crt_ca), default_ca_path)) < 0) {
			io_error(cx, "  .. Failed to load ca cert path: '%s': %s", default_ca_path, io_tls_err(ret));
			goto err;
		}
	}

	if (cx->tls_cert_ca) {
	if (ret < 0) {

		size_t i;

		for (i = 0; i < ARR_LEN(default_ca_certs); i++) {
			if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_ca), default_ca_certs[i])) >= 0)
				break;
		}

		if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_ca), cx->tls_cert_ca)) < 0) {
			io_error(cx, "  .. Failed to load ca cert: '%s': %s", cx->tls_cert_ca, io_tls_err(ret));
		if (i == ARR_LEN(default_ca_certs)) {
			io_error(cx, "  .. Failed to load default ca certs: %s", io_tls_err(ret));
			goto err;
		}
	}

	} else if (ca_cert_path && *ca_cert_path) {
	if (cx->tls_cert) {

		if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_ca), ca_cert_path)) < 0) {
			io_error(cx, "  .. Failed to load ca cert: '%s': %s", ca_cert_path, io_tls_err(ret));
		if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_client), cx->tls_cert)) < 0) {
			io_error(cx, "  .. Failed to load client cert: '%s': %s", cx->tls_cert, io_tls_err(ret));
			goto err;
		}

	} else {
		if ((ret = mbedtls_pk_parse_keyfile(
				&(cx->tls_pk_ctx),
				cx->tls_cert,
				NULL,
				mbedtls_ctr_drbg_random,
				&(cx->tls_ctr_drbg))))
		{
			io_error(cx, "  .. Failed to load client cert key: '%s': %s", cx->tls_cert, io_tls_err(ret));
			goto err;
		}

		for (size_t i = 0; i < ARR_LEN(ca_cert_paths); i++) {
			if ((ret = mbedtls_x509_crt_parse_file(&(cx->tls_x509_crt_ca), ca_cert_paths[i])) >= 0) {
				break;
			} else if (i == ARR_LEN(ca_cert_paths)) {
				io_error(cx, "  .. Failed to load ca cert: %s", io_tls_err(ret));
				goto err;
			}
		if ((ret = mbedtls_ssl_conf_own_cert(&(cx->tls_conf), &(cx->tls_x509_crt_client), &(cx->tls_pk_ctx)))) {
			io_error(cx, "  .. Failed to configure client cert: '%s': %s", cx->tls_cert, io_tls_err(ret));
			goto err;
		}
	}


M src/io.h => src/io.h +3 -2
@@ 89,8 89,9 @@ struct connection* connection(
	const void*, /* callback object */
	const char*, /* host */
	const char*, /* port */
	const char*, /* tls_cert_ca */
	const char*, /* tls_cert_client */
	const char*, /* tls_ca_file */
	const char*, /* tls_ca_path */
	const char*, /* tls_cert */
	uint32_t);   /* flags */

void connection_free(struct connection*);

M src/rirc.c => src/rirc.c +77 -62
@@ 25,10 25,16 @@ static const char* rirc_opt_str(char);
static const char* rirc_pw_name(void);
static int rirc_parse_args(int, char**);

#ifdef CA_CERT_FILE
const char *default_ca_file = CA_CERT_FILE;
#else
const char *default_ca_file;
#endif

#ifdef CA_CERT_PATH
const char *ca_cert_path = CA_CERT_PATH;
const char *default_ca_path = CA_CERT_PATH;
#else
const char *ca_cert_path;
const char *default_ca_path;
#endif

#ifdef DEFAULT_NICKS


@@ 79,9 85,10 @@ static const char *const rirc_help =
"\n   --ipv4                   Connect to server using only ipv4 addresses"
"\n   --ipv6                   Connect to server using only ipv6 addresses"
"\n   --tls-disable            Set server TLS disabled"
"\n   --tls-ca-file=PATH       Set server TLS CA cert file path"
"\n   --tls-ca-path=PATH       Set server TLS CA cert directory path"
"\n   --tls-cert=PATH          Set server TLS client cert file path"
"\n   --tls-verify=MODE        Set server TLS peer certificate verification mode"
"\n   --tls-cert-ca=PATH       Set server TLS ca cert file path"
"\n   --tls-cert-client=PATH   Set server TLS client cert file path"
"\n";

static const char *const rirc_version =


@@ 103,12 110,13 @@ rirc_opt_str(char c)
		case 'u': return "-u/--username";
		case 'r': return "-r/--realname";
		case 'm': return "-m/--mode";
		case '4': return "--ipv4";
		case '6': return "--ipv6";
		case 'x': return "--tls-disable";
		case 'y': return "--tls-verify";
		case 'z': return "--tls-cert-ca";
		case '0': return "--tls-cert-client";
		case '0': return "--ipv4";
		case '1': return "--ipv6";
		case '2': return "--tls-disable";
		case '3': return "--tls-ca-file";
		case '4': return "--tls-ca-path";
		case '5': return "--tls-cert";
		case '6': return "--tls-verify";
		default:
			fatal("unknown option flag '%c'", c);
	}


@@ 145,8 153,9 @@ rirc_parse_args(int argc, char **argv)
		const char *mode;
		const char *nicks;
		const char *chans;
		const char *tls_cert_ca;
		const char *tls_cert_client;
		const char *tls_ca_file;
		const char *tls_ca_path;
		const char *tls_cert;
		int ipv;
		int tls;
		int tls_vrfy;


@@ 154,22 163,23 @@ rirc_parse_args(int argc, char **argv)
	} cli_servers[MAX_CLI_SERVERS];

	struct option long_opts[] = {
		{"server",          required_argument, 0, 's'},
		{"port",            required_argument, 0, 'p'},
		{"pass",            required_argument, 0, 'w'},
		{"username",        required_argument, 0, 'u'},
		{"realname",        required_argument, 0, 'r'},
		{"mode",            required_argument, 0, 'm'},
		{"nicks",           required_argument, 0, 'n'},
		{"chans",           required_argument, 0, 'c'},
		{"help",            no_argument,       0, 'h'},
		{"version",         no_argument,       0, 'v'},
		{"ipv4",            no_argument,       0, '4'},
		{"ipv6",            no_argument,       0, '6'},
		{"tls-disable",     no_argument,       0, 'x'},
		{"tls-verify",      required_argument, 0, 'y'},
		{"tls-cert-ca",     required_argument, 0, 'z'},
		{"tls-cert-client", required_argument, 0, '0'},
		{"server",      required_argument, 0, 's'},
		{"port",        required_argument, 0, 'p'},
		{"pass",        required_argument, 0, 'w'},
		{"username",    required_argument, 0, 'u'},
		{"realname",    required_argument, 0, 'r'},
		{"mode",        required_argument, 0, 'm'},
		{"nicks",       required_argument, 0, 'n'},
		{"chans",       required_argument, 0, 'c'},
		{"help",        no_argument,       0, 'h'},
		{"version",     no_argument,       0, 'v'},
		{"ipv4",        no_argument,       0, '0'},
		{"ipv6",        no_argument,       0, '1'},
		{"tls-disable", no_argument,       0, '2'},
		{"tls-ca-file", required_argument, 0, '3'},
		{"tls-ca-path", required_argument, 0, '4'},
		{"tls-cert",    required_argument, 0, '5'},
		{"tls-verify",  required_argument, 0, '6'},
		{0, 0, 0, 0}
	};



@@ 191,19 201,20 @@ rirc_parse_args(int argc, char **argv)
					return -1;
				}

				cli_servers[n_servers - 1].host            = optarg;
				cli_servers[n_servers - 1].port            = NULL;
				cli_servers[n_servers - 1].pass            = NULL;
				cli_servers[n_servers - 1].username        = default_username;
				cli_servers[n_servers - 1].realname        = default_realname;
				cli_servers[n_servers - 1].mode            = NULL;
				cli_servers[n_servers - 1].nicks           = default_nicks;
				cli_servers[n_servers - 1].chans           = NULL;
				cli_servers[n_servers - 1].tls_cert_ca     = NULL;
				cli_servers[n_servers - 1].tls_cert_client = NULL;
				cli_servers[n_servers - 1].ipv             = IO_IPV_UNSPEC;
				cli_servers[n_servers - 1].tls             = IO_TLS_ENABLED;
				cli_servers[n_servers - 1].tls_vrfy        = IO_TLS_VRFY_REQUIRED;
				cli_servers[n_servers - 1].host        = optarg;
				cli_servers[n_servers - 1].port        = NULL;
				cli_servers[n_servers - 1].pass        = NULL;
				cli_servers[n_servers - 1].username    = default_username;
				cli_servers[n_servers - 1].realname    = default_realname;
				cli_servers[n_servers - 1].mode        = NULL;
				cli_servers[n_servers - 1].nicks       = default_nicks;
				cli_servers[n_servers - 1].chans       = NULL;
				cli_servers[n_servers - 1].tls_ca_file = NULL;
				cli_servers[n_servers - 1].tls_ca_path = NULL;
				cli_servers[n_servers - 1].tls_cert    = NULL;
				cli_servers[n_servers - 1].ipv         = IO_IPV_UNSPEC;
				cli_servers[n_servers - 1].tls         = IO_TLS_ENABLED;
				cli_servers[n_servers - 1].tls_vrfy    = IO_TLS_VRFY_REQUIRED;
				break;

			#define CHECK_SERVER_OPTARG(OPT_C, REQ) \


@@ 251,22 262,37 @@ rirc_parse_args(int argc, char **argv)
				cli_servers[n_servers - 1].chans = optarg;
				break;

			case '4': /* Connect using ipv4 only */
			case '0': /* Connect using ipv4 only */
				CHECK_SERVER_OPTARG(opt_c, 0);
				cli_servers[n_servers -1].ipv = IO_IPV_4;
				break;

			case '6': /* Connect using ipv6 only */
			case '1': /* Connect using ipv6 only */
				CHECK_SERVER_OPTARG(opt_c, 0);
				cli_servers[n_servers -1].ipv = IO_IPV_6;
				break;

			case 'x': /* Set server TLS disabled */
			case '2': /* Set server TLS disabled */
				CHECK_SERVER_OPTARG(opt_c, 0);
				cli_servers[n_servers -1].tls = IO_TLS_DISABLED;
				break;

			case 'y': /* Set server TLS peer certificate verification mode */
			case '3': /* Set server TLS CA cert file path */
				CHECK_SERVER_OPTARG(opt_c, 1);
				cli_servers[n_servers - 1].tls_ca_file = optarg;
				break;

			case '4': /* Set server TLS CA cert directory path */
				CHECK_SERVER_OPTARG(opt_c, 1);
				cli_servers[n_servers - 1].tls_ca_path = optarg;
				break;

			case '5': /* Set server TLS client cert file path */
				CHECK_SERVER_OPTARG(opt_c, 1);
				cli_servers[n_servers - 1].tls_cert = optarg;
				break;

			case '6': /* Set server TLS peer certificate verification mode */
				CHECK_SERVER_OPTARG(opt_c, 1);
				if (!strcmp(optarg, "0") || !strcmp(optarg, "disabled")) {
					cli_servers[n_servers -1].tls_vrfy = IO_TLS_VRFY_DISABLED;


@@ 283,15 309,6 @@ rirc_parse_args(int argc, char **argv)
				arg_error("invalid option for '--tls-verify' '%s'", optarg);
				return -1;

			case 'z': /* Set server TLS ca cert file path */
				CHECK_SERVER_OPTARG(opt_c, 1);
				cli_servers[n_servers - 1].tls_cert_ca = optarg;
				break;

			case '0': /* Set server TLS client cert file path */
				CHECK_SERVER_OPTARG(opt_c, 1);
				cli_servers[n_servers - 1].tls_cert_client = optarg;
				break;

			#undef CHECK_SERVER_OPTARG



@@ 324,11 341,6 @@ rirc_parse_args(int argc, char **argv)

	for (size_t i = 0; i < n_servers; i++) {

		uint32_t flags =
			cli_servers[i].ipv |
			cli_servers[i].tls |
			cli_servers[i].tls_vrfy;

		if (cli_servers[i].port == NULL)
			cli_servers[i].port = (cli_servers[i].tls == IO_TLS_ENABLED) ? "6697" : "6667";



@@ 345,9 357,12 @@ rirc_parse_args(int argc, char **argv)
			cli_servers[i].s,
			cli_servers[i].host,
			cli_servers[i].port,
			cli_servers[i].tls_cert_ca,
			cli_servers[i].tls_cert_client,
			flags);
			cli_servers[i].tls_ca_file,
			cli_servers[i].tls_ca_path,
			cli_servers[i].tls_cert,
			(cli_servers[i].ipv |
			 cli_servers[i].tls |
			 cli_servers[i].tls_vrfy));

		if (server_list_add(state_server_list(), cli_servers[i].s)) {
			arg_error("duplicate server: %s:%s", cli_servers[i].host, cli_servers[i].port);

M src/rirc.h => src/rirc.h +2 -1
@@ 3,7 3,8 @@

/* Default config values obtained at runtime */

extern const char *ca_cert_path;
extern const char *default_ca_file;
extern const char *default_ca_path;
extern const char *default_nicks;
extern const char *default_username;
extern const char *default_realname;

M src/state.c => src/state.c +32 -25
@@ 630,19 630,20 @@ command(struct channel *c, char *buf)
			int ret;
			struct server *s;

			const char *host            = str;
			const char *port            = NULL;
			const char *pass            = NULL;
			const char *username        = default_username;
			const char *realname        = default_realname;
			const char *mode            = NULL;
			const char *nicks           = default_nicks;
			const char *chans           = NULL;
			const char *tls_cert_ca     = NULL;
			const char *tls_cert_client = NULL;
			int ipv      = IO_IPV_UNSPEC;
			int tls      = IO_TLS_ENABLED;
			int tls_vrfy = IO_TLS_VRFY_REQUIRED;
			const char *host        = str;
			const char *port        = NULL;
			const char *pass        = NULL;
			const char *username    = default_username;
			const char *realname    = default_realname;
			const char *mode        = NULL;
			const char *nicks       = default_nicks;
			const char *chans       = NULL;
			const char *tls_ca_file = NULL;
			const char *tls_ca_path = NULL;
			const char *tls_cert    = NULL;
			int ipv                 = IO_IPV_UNSPEC;
			int tls                 = IO_TLS_ENABLED;
			int tls_vrfy            = IO_TLS_VRFY_REQUIRED;

			while ((str = irc_strsep(&buf))) {



@@ 690,6 691,21 @@ command(struct channel *c, char *buf)
					ipv = IO_IPV_6;
				} else if (!strcmp(str, "--tls-disable")) {
					tls = IO_TLS_DISABLED;
				} else if (!strcmp(str, "--tls-ca-file")) {
					if (!(tls_ca_file = irc_strsep(&buf))) {
						action(action_error, "connect: '--tls-ca-file' requires an argument");
						return;
					}
				} else if (!strcmp(str, "--tls-ca-path")) {
					if (!(tls_ca_path = irc_strsep(&buf))) {
						action(action_error, "connect: '--tls-ca-path' requires an argument");
						return;
					}
				} else if (!strcmp(str, "--tls-cert")) {
					if (!(tls_cert = irc_strsep(&buf))) {
						action(action_error, "connect: '--tls-cert' requires an argument");
						return;
					}
				} else if (!strcmp(str, "--tls-verify")) {
					if (!(str = irc_strsep(&buf))) {
						action(action_error, "connect: '--tls-verify' requires an argument");


@@ 704,16 720,6 @@ command(struct channel *c, char *buf)
						action(action_error, "connect: invalid option for '--tls-verify' '%s'", str);
						return;
					}
				} else if (!strcmp(str, "--tls-cert-ca")) {
					if (!(tls_cert_ca = irc_strsep(&buf))) {
						action(action_error, "connect: '--tls-cert-ca' requires an argument");
						return;
					}
				} else if (!strcmp(str, "--tls-cert-client")) {
					if (!(tls_cert_client = irc_strsep(&buf))) {
						action(action_error, "connect: '--tls-cert-client' requires an argument");
						return;
					}
				} else {
					action(action_error, "connect: unknown option '%s'", str);
					return;


@@ 747,8 753,9 @@ command(struct channel *c, char *buf)
				s,
				host,
				port,
				tls_cert_ca,
				tls_cert_client,
				tls_ca_file,
				tls_ca_path,
				tls_cert,
				(ipv | tls | tls_vrfy));

			if ((ret = io_cx(s->connection)))

M test/io.mock.c => test/io.mock.c +10 -2
@@ 37,12 37,20 @@ io_sendf(struct connection *c, const char *fmt, ...)
}

struct connection*
connection(const void *o, const char *h, const char *p, const char *ca, const char *cl, uint32_t f)
connection(
	const void *o,
	const char *h,
	const char *p,
	const char *caf,
	const char *cap,
	const char *cl,
	uint32_t f)
{
	UNUSED(o);
	UNUSED(h);
	UNUSED(p);
	UNUSED(ca);
	UNUSED(caf);
	UNUSED(cap);
	UNUSED(cl);
	UNUSED(f);
	return NULL;

M test/state.c => test/state.c +14 -8
@@ 241,18 241,23 @@ test_command_connect(void)
	assert_strcmp(current_channel()->name, "host-1");
	INP_C(0x0A);

	INP_COMMAND(":connect host --tls-verify");
	assert_strcmp(action_message(), "connect: '--tls-verify' requires an argument");
	INP_COMMAND(":connect host --tls-ca-file");
	assert_strcmp(action_message(), "connect: '--tls-ca-file' requires an argument");
	assert_strcmp(current_channel()->name, "host-1");
	INP_C(0x0A);

	INP_COMMAND(":connect host --tls-cert-ca");
	assert_strcmp(action_message(), "connect: '--tls-cert-ca' requires an argument");
	INP_COMMAND(":connect host --tls-ca-path");
	assert_strcmp(action_message(), "connect: '--tls-ca-path' requires an argument");
	assert_strcmp(current_channel()->name, "host-1");
	INP_C(0x0A);

	INP_COMMAND(":connect host --tls-cert-client");
	assert_strcmp(action_message(), "connect: '--tls-cert-client' requires an argument");
	INP_COMMAND(":connect host --tls-cert");
	assert_strcmp(action_message(), "connect: '--tls-cert' requires an argument");
	assert_strcmp(current_channel()->name, "host-1");
	INP_C(0x0A);

	INP_COMMAND(":connect host --tls-verify");
	assert_strcmp(action_message(), "connect: '--tls-verify' requires an argument");
	assert_strcmp(current_channel()->name, "host-1");
	INP_C(0x0A);



@@ 314,14 319,15 @@ test_command_connect(void)
		" --ipv4"
		" --ipv6"
		" --tls-disable"
		" --tls-ca-file path"
		" --tls-ca-path path"
		" --tls-cert path"
		" --tls-verify 0"
		" --tls-verify 1"
		" --tls-verify 2"
		" --tls-verify disabled"
		" --tls-verify optional"
		" --tls-verify required"
		" --tls-cert-ca path"
		" --tls-cert-client path"
	);

	s = current_channel()->server;