Test client handshake with shs1-testsuite

main
cel 8 years ago
parent 83e0bb8cd1
commit 73b7d7e544

@ -8,6 +8,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl j
.Op Fl T
.Op Fl a Ar cap
.Op Fl s Ar host
.Op Fl p Ar port
@ -22,6 +23,10 @@ standard I/O.
.Bl -tag
.It Fl j
Send stdin data as JSON.
.It Fl T
Test using shs1-testsuite protocol. Instead of connecting to a server and running
a command, connect to stdio. On successful handshake, output concatenation of
the encryption key, encryption nonce, decryption key and decryption nonce.
.It Fl c Ar cap
Capability key for secret-handshake. Default is SSB's capability key,
.Li 1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s= .

@ -95,7 +95,7 @@ static const unsigned char ssb_cap[] = {
};
static void usage() {
fputs("usage: sbotc [-j] [-a <cap>] [-s <host>] [-p <port>] [-k <key>] [-t <type>] "
fputs("usage: sbotc [-j] [-T] [-a <cap>] [-s <host>] [-p <port>] [-k <key>] [-t <type>] "
"<method> [<argument>...]\n", stderr);
exit(EXIT_FAILURE);
}
@ -153,7 +153,7 @@ static int write_all(int fd, const void *buf, size_t count) {
return 0;
}
static void shs_connect(int s, const unsigned char pubkey[32], const unsigned char seckey[64], const unsigned char appkey[32], const unsigned char server_pubkey[32], struct boxs *bs) {
static void shs_connect(int sfd, int infd, int outfd, const unsigned char pubkey[32], const unsigned char seckey[64], const unsigned char appkey[32], const unsigned char server_pubkey[32], struct boxs *bs) {
int rc;
unsigned char local_app_mac[32], remote_app_mac[32];
@ -168,12 +168,12 @@ static void shs_connect(int s, const unsigned char pubkey[32], const unsigned ch
unsigned char buf[64];
memcpy(buf, local_app_mac, 32);
memcpy(buf+32, kx_pk, 32);
rc = write_all(s, buf, sizeof(buf));
rc = write_all(outfd, buf, sizeof(buf));
if (rc < 0) err(1, "failed to send challenge");
// recv challenge
unsigned char remote_kx_pk[32];
rc = read_all(s, buf, sizeof(buf));
rc = read_all(infd, buf, sizeof(buf));
if (rc < 0) err(1, "challenge not accepted");
memcpy(remote_app_mac, buf, 32);
memcpy(remote_kx_pk, buf+32, 32);
@ -224,13 +224,13 @@ static void shs_connect(int s, const unsigned char pubkey[32], const unsigned ch
rc = crypto_secretbox_easy(boxed_auth, hello, sizeof(hello), zeros, secret2);
if (rc < 0) errx(1, "failed to box hello");
rc = write_all(s, boxed_auth, sizeof(boxed_auth));
rc = write_all(outfd, boxed_auth, sizeof(boxed_auth));
if (rc < 0) errx(1, "failed to send auth");
// verify accept
unsigned char boxed_okay[80];
rc = read_all(s, boxed_okay, sizeof(boxed_okay));
rc = read_all(infd, boxed_okay, sizeof(boxed_okay));
if (rc < 0) err(1, "hello not accepted");
unsigned char local_sk_curve[32];
@ -283,7 +283,7 @@ static void shs_connect(int s, const unsigned char pubkey[32], const unsigned ch
bs->rx_buf_pos = 0;
bs->rx_buf_len = 0;
bs->s = s;
bs->s = sfd;
}
static int pubkey_decode(const char *key_str, unsigned char key[32]) {
@ -797,7 +797,7 @@ static int args_to_json(char *out, size_t outlen, unsigned int argc, char *argv[
}
int main(int argc, char *argv[]) {
int i, s, rc;
int i, s, infd, outfd, rc;
const char *key = NULL;
const char *host = NULL;
const char *port = "8008";
@ -812,7 +812,9 @@ int main(int argc, char *argv[]) {
enum pkt_type ptype = pkt_type_buffer;
char method[256];
char app_dir[_POSIX_PATH_MAX];
char argument[argument_len];
ssize_t len;
bool test = false;
get_app_dir(app_dir, sizeof(app_dir));
@ -833,6 +835,7 @@ int main(int argc, char *argv[]) {
switch (argv[i][1]) {
case 'c': shs_cap_key_str = argv[++i]; break;
case 'j': ptype = pkt_type_json; break;
case 'T': test = true; break;
case 's': host = argv[++i]; break;
case 'k': key = argv[++i]; break;
case 'p': port = argv[++i]; break;
@ -840,7 +843,7 @@ int main(int argc, char *argv[]) {
default: usage();
}
}
if (i < argc) methodstr = argv[i++]; else usage();
if (i < argc) methodstr = argv[i++]; else if (!test) usage();
if (shs_cap_key_str) {
rc = pubkey_decode(shs_cap_key_str, shs_cap_key);
@ -849,33 +852,33 @@ int main(int argc, char *argv[]) {
memcpy(shs_cap_key, ssb_cap, 32);
}
if (!test) {
argument_len = args_to_json_length(argc-i, argv+i);
rc = args_to_json(argument, sizeof(argument), argc-i, argv+i);
if (rc < 0) errx(0, "unable to collect arguments");
argument_len = args_to_json_length(argc-i, argv+i);
char argument[argument_len];
rc = args_to_json(argument, sizeof(argument), argc-i, argv+i);
if (rc < 0) errx(0, "unable to collect arguments");
char manifest_buf[8192];
if (!typestr) {
len = read_file(manifest_buf, sizeof(manifest_buf),
"%s/manifest.json", app_dir);
if (len < 0) err(1, "failed to read manifest file");
ssize_t type_len = json_get_value(manifest_buf, methodstr, &typestr);
if (!typestr && errno == ENOMSG) errx(1,
"unable to find method '%s' in manifest", methodstr);
if (!typestr) err(1, "unable to read manifest");
((char *)typestr)[type_len] = '\0';
}
if (strcmp(typestr, "sync") == 0) type = muxrpc_type_async;
else if (strcmp(typestr, "async") == 0) type = muxrpc_type_async;
else if (strcmp(typestr, "sink") == 0) type = muxrpc_type_sink;
else if (strcmp(typestr, "source") == 0) type = muxrpc_type_source;
else if (strcmp(typestr, "duplex") == 0) type = muxrpc_type_duplex;
else errx(1, "type must be one of <async|sink|source|duplex>");
rc = method_to_json(method, sizeof(method), methodstr);
if (rc < 0) errx(0, "unable to convert method name");
char manifest_buf[8192];
if (!typestr) {
len = read_file(manifest_buf, sizeof(manifest_buf),
"%s/manifest.json", app_dir);
if (len < 0) err(1, "failed to read manifest file");
ssize_t type_len = json_get_value(manifest_buf, methodstr, &typestr);
if (!typestr && errno == ENOMSG) errx(1,
"unable to find method '%s' in manifest", methodstr);
if (!typestr) err(1, "unable to read manifest");
((char *)typestr)[type_len] = '\0';
}
if (strcmp(typestr, "sync") == 0) type = muxrpc_type_async;
else if (strcmp(typestr, "async") == 0) type = muxrpc_type_async;
else if (strcmp(typestr, "sink") == 0) type = muxrpc_type_sink;
else if (strcmp(typestr, "source") == 0) type = muxrpc_type_source;
else if (strcmp(typestr, "duplex") == 0) type = muxrpc_type_duplex;
else errx(1, "type must be one of <async|sink|source|duplex>");
rc = method_to_json(method, sizeof(method), methodstr);
if (rc < 0) errx(0, "unable to convert method name");
}
read_private_key(app_dir, private_key);
@ -887,11 +890,27 @@ int main(int argc, char *argv[]) {
memcpy(remote_key, public_key, 32);
}
s = tcp_connect(host, port);
if (s < 0) err(1, "tcp_connect");
if (test) {
infd = STDIN_FILENO;
outfd = STDOUT_FILENO;
s = -1;
} else {
s = tcp_connect(host, port);
if (s < 0) err(1, "tcp_connect");
infd = outfd = s;
}
struct boxs bs;
shs_connect(s, public_key, private_key, shs_cap_key, remote_key, &bs);
shs_connect(s, infd, outfd, public_key, private_key, shs_cap_key, remote_key, &bs);
if (test) {
rc = write_all(outfd, bs.encrypt_key, sizeof(bs.encrypt_key));
rc |= write_all(outfd, bs.nonce1, sizeof(bs.nonce1));
rc |= write_all(outfd, bs.decrypt_key, sizeof(bs.decrypt_key));
rc |= write_all(outfd, bs.rx_nonce, sizeof(bs.rx_nonce));
if (rc < 0) err(1, "failed to write handshake result");
return 0;
}
muxrpc_call(&bs, method, argument, type, typestr, 1);

@ -0,0 +1,8 @@
#!/bin/sh
cap_hex=${1?shs cap key}
pk_hex=${2?server public key}
cap_b64="$(echo -n "$cap_hex" | xxd -r -p | base64)"
pk_b64="$(echo -n "$pk_hex" | xxd -r -p | base64)"
exec sbotc -T -c "$cap_b64" -k "$pk_b64"

@ -0,0 +1,3 @@
#!/bin/sh
# test using [shs1-testsuite](%riikqU1Zc/dgjc80vABMA3DkTzTHzlxEYxGU5NYwje8=.sha256)
exec shs1testclient "$(dirname "$0")"/test-shs-inner.sh "$@"
Loading…
Cancel
Save