Skip to content

Commit

Permalink
protocol: update scion version and DRKey configuration (netsec-ethz#25)
Browse files Browse the repository at this point in the history
This PR updates the scion repository to the newest scionproto version.
As a consequence this includes updating a lot of configs and the DRKey
derivation scheme.

Since AS-AS keys can no longer be fetched directly from the CS an option
to configure shared keys in the LF config has been added. The fetching
of HOST-AS and HOST-HOST keys will be added at a later point.
The DRKey timestamps and especially the SPAO header will be updated in a
separate PR.

From the per peer preshared secret we derive a short term (3 day
validity) AS-AS key. The derivation is done using AES-CBC MAC keyed with
the shared secret and the input: **(type | ISD_AS1 | ISD_AS2 | start
timestamp)** where
- **type** is the 1 byte fixed constant **0**.
- **ISD_AS1** is the ISD_AS number (8 byte) in network byte order of the
fast side AS.
- **ISD_AS2** is the ISD_AS number (8 byte) in network byte order of the
slow side AS.
- **start timestamp** is the timestamp in ns (8 byte) of the start time
of the validity period for the resulting key. This can be synchronized
between peers since the initial start time is configured by both and
consequent start times can be calculated by **configured time** + **k**
* **VALIDITY_PERIOD** for some **k** such that the key is currently
valid.

It is also possible to configure multiple shared secrets with different
start time such that a shared secret can be replaced at some point.
  • Loading branch information
aaronbojarski authored Feb 7, 2024
1 parent 170478e commit 04d9345
Show file tree
Hide file tree
Showing 40 changed files with 1,764 additions and 1,474 deletions.
24 changes: 13 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ RUN apt-get update && \
&& rm -rf /var/lib/apt/lists/*

# Install Golang
RUN curl -LO https://go.dev/dl/go1.17.9.linux-amd64.tar.gz && \
echo "9dacf782028fdfc79120576c872dee488b81257b1c48e9032d122cfdb379cca6 go1.17.9.linux-amd64.tar.gz" | sha256sum -c && \
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.9.linux-amd64.tar.gz
RUN curl -LO https://golang.org/dl/go1.21.2.linux-amd64.tar.gz && \
echo "f5414a770e5e11c6e9674d4cd4dd1f4f630e176d1828d3427ea8ca4211eee90d go1.21.2.linux-amd64.tar.gz" | sha256sum -c && \
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.21.2.linux-amd64.tar.gz
ENV PATH /usr/local/go/bin:$PATH

# Install DPDK
Expand Down Expand Up @@ -52,14 +52,16 @@ RUN sudo apt-get update && \
sudo rm -rf /var/lib/apt/lists/* && \
sudo pip3 install plumbum toml supervisor-wildcards

# Require SCION NetSec binaries (contain DRKey) for SCION tests.
RUN git clone https://github.com/netsec-ethz/scion.git && cd scion && \
go build -o ./bin/ ./go/cs/ && \
go build -o ./bin/ ./go/posix-router/ && \
go build -o ./bin/ ./go/dispatcher/ && \
go build -o ./bin/ ./go/daemon/ && \
go build -o ./bin/ ./go/scion-pki/ && \
go build -o ./bin/ ./go/scion/
# Require SCION binaries for SCION tests.
RUN git clone https://github.com/scionproto/scion.git && \
cd scion && \
git checkout v0.9.1 && \
go build -o ./bin/ ./control/cmd/control && \
go build -o ./bin/ ./daemon/cmd/daemon && \
go build -o ./bin/ ./dispatcher/cmd/dispatcher && \
go build -o ./bin/ ./router/cmd/router && \
go build -o ./bin/ ./scion/cmd/scion && \
go build -o ./bin/ ./scion-pki/cmd/scion-pki
ENV SCION_DIR=/home/$USER/scion
ENV SCION_BIN=/home/$USER/scion/bin

Expand Down
30 changes: 13 additions & 17 deletions docs/SCION.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ https://go.dev/doc/install

On x86:
```
curl -LO https://go.dev/dl/go1.17.9.linux-amd64.tar.gz
echo "9dacf782028fdfc79120576c872dee488b81257b1c48e9032d122cfdb379cca6 go1.17.9.linux-amd64.tar.gz" | sha256sum -c
sudo tar -C /usr/local -xzf go1.17.9.linux-amd64.tar.gz
curl -LO https://golang.org/dl/go1.21.2.linux-amd64.tar.gz
echo "f5414a770e5e11c6e9674d4cd4dd1f4f630e176d1828d3427ea8ca4211eee90d go1.21.2.linux-amd64.tar.gz" | sha256sum -c
sudo tar -C /usr/local -xzf go1.21.2.linux-amd64.tar.gz
```

```
Expand All @@ -38,25 +38,21 @@ Don't forget to remove the PATH entry in `~/.profile`.

### Install SCION (Modules)

Besides the official SCION repository, there also exists the experimental fork from the Network Security Group at ETH Zurich:
https://github.com/netsec-ethz/scion

Currently, only the experimental fork supports DRKey.
Therefore, LightningFilter requires that version.

To obtain the source, clone the repository:
```
git clone https://github.com/netsec-ethz/scion.git
git clone https://github.com/scionproto/scion.git
cd scion
git checkout v0.9.1
```

Modules can be installed with `go build`.
E.g., the `testnet_scion` setup requires the control service (cs), border router (posix-router), dispatcher (dispatcher), daemon (daemon), the PKI (scion-pki), and SCION tools like ping (scion):
E.g., the `testnet_scion` setup requires the control service (control), border router (router), dispatcher (dispatcher), daemon (daemon), the PKI (scion-pki), and SCION tools like ping (scion):

```
go build -o ./bin/ ./go/cs/
go build -o ./bin/ ./go/posix-router/
go build -o ./bin/ ./go/dispatcher/
go build -o ./bin/ ./go/daemon/
go build -o ./bin/ ./go/scion-pki/
go build -o ./bin/ ./go/scion/
go build -o ./bin/ ./control/cmd/control
go build -o ./bin/ ./daemon/cmd/daemon
go build -o ./bin/ ./dispatcher/cmd/dispatcher
go build -o ./bin/ ./router/cmd/router
go build -o ./bin/ ./scion/cmd/scion
go build -o ./bin/ ./scion-pki/cmd/scion-pki
```
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ include(plugins/CMakePlugins.cmake)

# Add all source files
target_sources(${EXEC} PRIVATE params.c setup.c duplicate_filter.c config.c configmanager.c)
target_sources(${EXEC} PRIVATE keymanager.c ratelimiter.c statistics.c version.c)
target_sources(${EXEC} PRIVATE keyfetcher.c keymanager.c ratelimiter.c statistics.c version.c)
target_sources(${EXEC} PRIVATE worker.c worker_check.c)
target_sources(${EXEC} PRIVATE lib/crypto/crypto.c lib/hash/murmurhash.c lib/ipc/ipc.c)
target_sources(${EXEC} PRIVATE lib/mirror/mirror.c)
Expand Down
134 changes: 134 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
#define FIELD_DRKEY_PROTOCOL "drkey_protocol"
#define FIELD_DRKEY_SERVICE_ADDR "drkey_service_addr"

#define FIELD_SHARED_SECRETS "shared_secrets"
#define FIELD_NOT_BEFORE "not_before"
#define FIELD_SECRET_VALUE "sv"

#define FIELD_DST_RATELIMITER "dst_ratelimiter"

#define FIELD_WG_RATELIMITER "wg_ratelimiter"
Expand All @@ -54,6 +58,9 @@
/* potential value for the ether field of a packet modifier */
#define VALUE_ETHER_SRC_ADDR "src_addr"

/* 16 byte buffer with zero value. */
static const uint8_t zero_secret_value[16] = { 0 };

/**
* Ratelimit struct with the rate set to 0.
*
Expand Down Expand Up @@ -87,6 +94,9 @@ peer_init(struct lf_config_peer *config_peer)
.isd_as = 1,
.next = NULL,

.shared_secrets_configured_option = false,
.shared_secrets = { 0 },

/* per default no rate limit is defined for a peer */
.ratelimit_option = false,
.ratelimit = zero_ratelimit,
Expand Down Expand Up @@ -176,6 +186,120 @@ parse_ratelimit(json_value *json_val, struct lf_config_ratelimit *ratelimit)
return 0;
}

/**
* The shared_secret struct consists of a key and a timestamp.
* This should be used for preconfigured keys.
*
* @return Returns 0 on success.
*/
static int
parse_shared_secret(json_value *json_val,
struct lf_config_shared_secret *shared_secret)
{
int res, error_count = 0;
unsigned int length;
unsigned int i;
char *field_name;
json_value *field_value;
bool sv_flag = false, ts_flag = false;

/* Initialize drkey struct. Set all to 0. */
(void)memset(shared_secret, 0, sizeof *shared_secret);

if (json_val == NULL) {
return -1;
}

if (json_val->type != json_object) {
return -1;
}

length = json_val->u.object.length;

for (i = 0; i < length; ++i) {
field_name = json_val->u.object.values[i].name;
field_value = json_val->u.object.values[i].value;

if (strcmp(field_name, FIELD_SECRET_VALUE) == 0) {
res = lf_json_parse_byte_buffer(field_value, LF_CRYPTO_DRKEY_SIZE,
shared_secret->sv);
if (res != 0) {
LF_LOG(ERR, "Invalid shared secret (%d:%d)\n",
field_value->line, field_value->col);
error_count++;
}
if (memcmp(shared_secret->sv, zero_secret_value,
sizeof shared_secret->sv) == 0) {
LF_LOG(ERR,
"Invalid shared secret. "
"Secret value can not be the all zero secret value.\n");
return -1;
}
sv_flag = true;
} else if (strcmp(field_name, FIELD_NOT_BEFORE) == 0) {
res = lf_json_parse_timestamp(field_value,
&shared_secret->not_before);
if (res != 0) {
LF_LOG(ERR, "Invalid timestamp (%d:%d)\n", field_value->line,
field_value->col);
error_count++;
}
ts_flag = true;
} else {
LF_LOG(ERR, "Unknown field %s (%d:%d)\n", field_name,
field_value->line, field_value->col);
error_count++;
}
}

if (error_count > 0) {
return -1;
}

if (!sv_flag || !ts_flag) {
LF_LOG(ERR, "Invalid shared secret configuration. Need to define both "
"secret value "
"and not before timestamp.\n");
return -1;
}

return 0;
}

static int
parse_shared_secret_list(json_value *json_val,
struct lf_config_shared_secret shared_secret[LF_CONFIG_SV_MAX])
{
unsigned int length;
unsigned int i;
unsigned int res;

if (json_val == NULL) {
return -1;
}

if (json_val->type != json_array) {
return -1;
}

length = json_val->u.array.length;
if (length > LF_CONFIG_SV_MAX) {
LF_LOG(ERR, "Exceed shared secret limit (%d:%d)\n", json_val->line,
json_val->col);
return -1;
}

for (i = 0; i < length; ++i) {
res = parse_shared_secret(json_val->u.array.values[i],
&shared_secret[i]);
if (res != 0) {
return -1;
}
}

return length;
}

static int
parse_peer(json_value *json_val, struct lf_config_peer *peer)
{
Expand Down Expand Up @@ -231,6 +355,16 @@ parse_peer(json_value *json_val, struct lf_config_peer *peer)
error_count++;
}
peer->ratelimit_option = true;
} else if (strcmp(field_name, FIELD_SHARED_SECRETS) == 0) {
res = parse_shared_secret_list(field_value, peer->shared_secrets);
if (res >= 0) {
peer->shared_secrets_configured_option = true;
}
if (res < 0) {
LF_LOG(ERR, "Invalid shared secret (%d:%d)\n",
field_value->line, field_value->col);
error_count++;
}
} else {
LF_LOG(ERR, "Unknown field %s (%d:%d)\n", field_name,
field_value->line, field_value->col);
Expand Down
16 changes: 16 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <stdbool.h>
#include <stddef.h>

#include "lib/crypto/crypto.h"

/**
* This module defines the config structure and offers functionality to parse a
* JSON configuration file, check its format, and return a C struct representing
Expand All @@ -18,6 +20,11 @@

#define LF_CONFIG_PEERS_MAX 1000000 /* 1'000'000 */

/*
* Maximum number of SV that can be configured per peer
*/
#define LF_CONFIG_SV_MAX 5

/*
* Rate limits are always defined for bytes and packets.
*/
Expand All @@ -28,6 +35,11 @@ struct lf_config_ratelimit {
uint64_t packet_burst;
};

struct lf_config_shared_secret {
uint8_t sv[LF_CRYPTO_DRKEY_SIZE];
uint64_t not_before;
};

struct lf_config_peer {
/* peer identifier */
uint64_t isd_as; /* in network byte order */
Expand All @@ -37,6 +49,10 @@ struct lf_config_peer {
bool ratelimit_option; /* if a rate limit is defined */
struct lf_config_ratelimit ratelimit;

/* preconfigured shared keys */
bool shared_secrets_configured_option; /* if shared secrets are defined*/
struct lf_config_shared_secret shared_secrets[LF_CONFIG_SV_MAX];

/* LF-IP: ip -> isd_as map (TODO: move this to a separate map) */
uint32_t ip; /* in network byte order */

Expand Down
Loading

0 comments on commit 04d9345

Please sign in to comment.