Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 143 additions & 31 deletions plugins/out_forward/forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,15 @@ static void secure_forward_set_ping(struct flb_forward_ping *ping,
}
}

static int secure_forward_hash_shared_key(struct flb_forward_config *fc,
struct flb_forward_ping *ping,
/*
* Compute sha512_hex(shared_key_salt + hostname + nonce + shared_key) as
* defined by the Forward protocol handshake (PING and PONG digests).
*/
static int secure_forward_hash_key_digest(struct flb_forward_config *fc,
const char *hostname,
size_t hostname_len,
const char *nonce,
size_t nonce_len,
char *buf, int buflen)
{
size_t length_entries[4];
Expand All @@ -394,11 +401,11 @@ static int secure_forward_hash_shared_key(struct flb_forward_config *fc,
data_entries[0] = (unsigned char *) fc->shared_key_salt;
length_entries[0] = 16;

data_entries[1] = (unsigned char *) fc->self_hostname;
length_entries[1] = strlen(fc->self_hostname);
data_entries[1] = (unsigned char *) hostname;
length_entries[1] = hostname_len;

data_entries[2] = (unsigned char *) ping->nonce;
length_entries[2] = ping->nonce_len;
data_entries[2] = (unsigned char *) nonce;
length_entries[2] = nonce_len;

data_entries[3] = (unsigned char *) fc->shared_key;
length_entries[3] = strlen(fc->shared_key);
Expand All @@ -419,6 +426,17 @@ static int secure_forward_hash_shared_key(struct flb_forward_config *fc,
return 0;
}

static int secure_forward_hash_shared_key(struct flb_forward_config *fc,
struct flb_forward_ping *ping,
char *buf, int buflen)
{
return secure_forward_hash_key_digest(fc,
fc->self_hostname,
strlen(fc->self_hostname),
ping->nonce, ping->nonce_len,
buf, buflen);
}

static int secure_forward_hash_password(struct flb_forward_config *fc,
struct flb_forward_ping *ping,
char *buf, int buflen)
Expand Down Expand Up @@ -458,7 +476,7 @@ static int secure_forward_hash_password(struct flb_forward_config *fc,
}

static int secure_forward_ping(struct flb_connection *u_conn,
msgpack_object map,
struct flb_forward_ping *ping,
struct flb_forward_config *fc,
struct flb_forward *ctx)
{
Expand All @@ -468,22 +486,14 @@ static int secure_forward_ping(struct flb_connection *u_conn,
char password_hexdigest[128];
msgpack_sbuffer mp_sbuf;
msgpack_packer mp_pck;
struct flb_forward_ping ping;

secure_forward_set_ping(&ping, &map);

if (ping.nonce == NULL) {
flb_plg_error(ctx->ins, "nonce not found");
return -1;
}

if (secure_forward_hash_shared_key(fc, &ping, shared_key_hexdigest, 128)) {
if (secure_forward_hash_shared_key(fc, ping, shared_key_hexdigest, 128)) {
flb_plg_error(ctx->ins, "failed to hash shared_key");
return -1;
}

if (ping.auth != NULL) {
if (secure_forward_hash_password(fc, &ping, password_hexdigest, 128)) {
if (ping->auth != NULL) {
if (secure_forward_hash_password(fc, ping, password_hexdigest, 128)) {
flb_plg_error(ctx->ins, "failed to hash password");
return -1;
}
Expand Down Expand Up @@ -512,7 +522,7 @@ static int secure_forward_ping(struct flb_connection *u_conn,
msgpack_pack_str_body(&mp_pck, shared_key_hexdigest, 128);

/* [4] Username and password (optional) */
if (ping.auth != NULL) {
if (ping->auth != NULL) {
msgpack_pack_str(&mp_pck, strlen(fc->username));
msgpack_pack_str_body(&mp_pck, fc->username, strlen(fc->username));
msgpack_pack_str(&mp_pck, 128);
Expand All @@ -537,18 +547,25 @@ static int secure_forward_ping(struct flb_connection *u_conn,
return -1;
}

static int secure_forward_pong(struct flb_forward *ctx, char *buf, int buf_size)
static int secure_forward_pong(struct flb_forward *ctx,
struct flb_forward_config *fc,
const char *nonce, size_t nonce_len,
char *buf, int buf_size)
{
int ret;
char msg[32] = {0};
char server_hexdigest[128];
size_t off = 0;
msgpack_unpacked result;
msgpack_object root;
msgpack_object o;
msgpack_object hostname;
msgpack_object digest;

msgpack_unpacked_init(&result);
ret = msgpack_unpack_next(&result, buf, buf_size, &off);
if (ret != MSGPACK_UNPACK_SUCCESS) {
msgpack_unpacked_destroy(&result);
return -1;
}

Expand All @@ -557,7 +574,14 @@ static int secure_forward_pong(struct flb_forward *ctx, char *buf, int buf_size)
goto error;
}

if (root.via.array.size < 4) {
/*
* PONG is defined as:
*
* [type, auth_result, reason, server_hostname, shared_key_hexdigest]
*/
if (root.via.array.size != 5) {
flb_plg_error(ctx->ins, "invalid PONG message: expected 5 fields, "
"got %i", root.via.array.size);
goto error;
}

Expand All @@ -575,11 +599,7 @@ static int secure_forward_pong(struct flb_forward *ctx, char *buf, int buf_size)
goto error;
}

if (o.via.boolean) {
msgpack_unpacked_destroy(&result);
return 0;
}
else {
if (!o.via.boolean) {
o = root.via.array.ptr[2];
if (o.type != MSGPACK_OBJECT_STR) {
goto error;
Expand All @@ -593,8 +613,48 @@ static int secure_forward_pong(struct flb_forward *ctx, char *buf, int buf_size)
msg[o.via.str.size] = '\0';
}
flb_plg_error(ctx->ins, "failed authorization: %s", msg);
goto error;
}

/*
* Mutual authentication: the server must prove it holds the same
* shared_key by returning
*
* sha512_hex(shared_key_salt + server_hostname + nonce + shared_key)
*/
hostname = root.via.array.ptr[3];
if (hostname.type != MSGPACK_OBJECT_STR) {
flb_plg_error(ctx->ins, "invalid PONG server_hostname type");
goto error;
}

digest = root.via.array.ptr[4];
if (digest.type != MSGPACK_OBJECT_STR || digest.via.str.size != 128) {
flb_plg_error(ctx->ins, "invalid PONG shared_key_hexdigest");
goto error;
}

ret = secure_forward_hash_key_digest(fc,
hostname.via.str.ptr,
hostname.via.str.size,
nonce, nonce_len,
server_hexdigest,
sizeof(server_hexdigest));
if (ret != 0) {
flb_plg_error(ctx->ins, "failed to hash PONG shared_key");
goto error;
}

if (memcmp(server_hexdigest, digest.via.str.ptr, 128) != 0) {
flb_plg_error(ctx->ins,
"PONG shared_key digest mismatch: "
"server does not hold the same shared_key");
goto error;
}

msgpack_unpacked_destroy(&result);
return 0;

error:
msgpack_unpacked_destroy(&result);
return -1;
Expand All @@ -606,11 +666,14 @@ static int secure_forward_handshake(struct flb_connection *u_conn,
{
int ret;
char buf[1024];
char nonce[1024];
size_t nonce_len;
size_t out_len;
size_t off;
msgpack_unpacked result;
msgpack_object root;
msgpack_object o;
struct flb_forward_ping ping;

/* Wait for server HELO */
ret = secure_forward_read(ctx, u_conn, fc, buf, sizeof(buf) - 1, &out_len);
Expand Down Expand Up @@ -665,7 +728,28 @@ static int secure_forward_handshake(struct flb_connection *u_conn,
return -1;
}

ret = secure_forward_ping(u_conn, o, fc, ctx);
secure_forward_set_ping(&ping, &o);
if (ping.nonce == NULL) {
flb_plg_error(ctx->ins, "nonce not found");
msgpack_unpacked_destroy(&result);
return -1;
}

/*
* Keep a copy of the HELO nonce: 'ping.nonce' points into 'buf' and
* the same buffer is reused below to read the PONG message. The nonce
* is required to validate the PONG shared_key digest.
*/
if (ping.nonce_len < 0 || (size_t) ping.nonce_len > sizeof(nonce)) {
flb_plg_error(ctx->ins, "HELO nonce is too large (%i bytes)",
ping.nonce_len);
msgpack_unpacked_destroy(&result);
return -1;
}
nonce_len = ping.nonce_len;
memcpy(nonce, ping.nonce, nonce_len);

ret = secure_forward_ping(u_conn, &ping, fc, ctx);
if (ret == -1) {
flb_plg_error(ctx->ins, "Failed PING");
msgpack_unpacked_destroy(&result);
Expand All @@ -675,13 +759,13 @@ static int secure_forward_handshake(struct flb_connection *u_conn,
/* Expect a PONG */
ret = secure_forward_read(ctx, u_conn, fc, buf, sizeof(buf) - 1, &out_len);
if (ret == -1) {
flb_plg_error(ctx->ins, "handshake error expecting HELO");
flb_plg_error(ctx->ins, "handshake error expecting PONG");
msgpack_unpacked_destroy(&result);
return -1;
}

/* Process PONG */
ret = secure_forward_pong(ctx, buf, out_len);
ret = secure_forward_pong(ctx, fc, nonce, nonce_len, buf, out_len);
if (ret == -1) {
msgpack_unpacked_destroy(&result);
return -1;
Expand Down Expand Up @@ -863,6 +947,20 @@ static int config_set_properties(struct flb_upstream_node *node,
fc->password = "";
}

/*
* username/password authorization is part of the secure forward
* handshake, which is only performed when a shared_key is set. Reject
* credentials that would otherwise be silently ignored.
*/
if (fc->shared_key == NULL &&
(strlen(fc->username) > 0 || strlen(fc->password) > 0)) {
flb_plg_error(ctx->ins,
"'username'/'password' is set but no 'shared_key' or "
"'empty_shared_key' is configured: username/password "
"authentication requires the secure forward handshake");
return -1;
}

/* Self Hostname */
tmp = config_get_property("self_hostname", node, ctx);
if (tmp) {
Expand Down Expand Up @@ -1027,7 +1125,11 @@ static int forward_config_ha(const char *upstream_file,
}

/* Read properties into 'fc' context */
config_set_properties(node, fc, ctx);
ret = config_set_properties(node, fc, ctx);
if (ret == -1) {
forward_config_destroy(fc);
return -1;
}

/* Initialize and validate forward_config context */
ret = forward_config_init(fc, ctx);
Expand Down Expand Up @@ -1134,7 +1236,11 @@ static int forward_config_simple(struct flb_forward *ctx,
flb_output_upstream_set(ctx->u, ins);
}
/* Read properties into 'fc' context */
config_set_properties(NULL, fc, ctx);
ret = config_set_properties(NULL, fc, ctx);
if (ret == -1) {
forward_config_destroy(fc);
return -1;
}

/* Initialize and validate forward_config context */
ret = forward_config_init(fc, ctx);
Expand Down Expand Up @@ -1628,6 +1734,12 @@ static void cb_forward_flush(struct flb_event_chunk *event_chunk,
event_chunk->tag, flb_sds_len(event_chunk->tag),
event_chunk->data, event_chunk->size,
&out_buf, &out_size);
if (mode == -1) {
flb_plg_error(ctx->ins, "failed to format outgoing payload");
msgpack_sbuffer_destroy(&mp_sbuf);
flb_free(flush_ctx);
FLB_OUTPUT_RETURN(FLB_RETRY);
}

/* Get a TCP connection instance */
if (fc->unix_path == NULL) {
Expand Down
8 changes: 7 additions & 1 deletion plugins/out_forward/forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,16 @@ struct flb_forward_ping {
int keepalive;
};

/*
* Maximum storage required for a 'chunk' ack token: Base64 representation
* of a 128 bits unique id (24 bytes) plus NUL terminator.
*/
#define FLB_FORWARD_CHUNK_TOKEN_SIZE 25

/* Flush callback context */
struct flb_forward_flush {
struct flb_forward_config *fc;
char checksum_hex[33];
char chunk_token[FLB_FORWARD_CHUNK_TOKEN_SIZE];
};

struct flb_forward_config *flb_forward_target(struct flb_forward *ctx,
Expand Down
Loading
Loading