mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
Merge pull request #100 from emanuele-f/transop-rework
Rework transops and api
This commit is contained in:
commit
87bf4ca298
|
@ -44,7 +44,7 @@ MAN7DIR=$(MANDIR)/man7
|
|||
MAN8DIR=$(MANDIR)/man8
|
||||
|
||||
N2N_LIB=libn2n.a
|
||||
N2N_OBJS=n2n.o n2n_keyfile.o wire.o minilzo.o twofish.o \
|
||||
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o \
|
||||
edge_utils.o \
|
||||
transform_null.o transform_tf.o transform_aes.o \
|
||||
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o \
|
||||
|
@ -81,7 +81,7 @@ benchmark: benchmark.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
|
|||
example_edge_embed: example_edge_embed.c $(N2N_LIB) n2n.h
|
||||
$(CC) $(CFLAGS) example_edge_embed.c $(N2N_LIB) $(LIBS_EDGE) -o example_edge_embed
|
||||
|
||||
.c.o: n2n.h n2n_keyfile.h n2n_transforms.h n2n_wire.h twofish.h Makefile
|
||||
.c.o: n2n.h n2n_transforms.h n2n_wire.h twofish.h Makefile
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
%.gz : %
|
||||
|
|
|
@ -137,6 +137,7 @@ static int scan_address(char * ip_addr, size_t addr_size,
|
|||
|
||||
/* *************************************************** */
|
||||
|
||||
//TODO use new API
|
||||
int start_edge(const n2n_edge_cmd_t* cmd)
|
||||
{
|
||||
int keep_on_running = 0;
|
||||
|
@ -177,13 +178,7 @@ int start_edge(const n2n_edge_cmd_t* cmd)
|
|||
return 1;
|
||||
}
|
||||
eee.device.fd = cmd->vpn_fd;
|
||||
if (cmd->enc_key_file)
|
||||
{
|
||||
strncpy(eee.keyschedule, cmd->enc_key_file, N2N_PATHNAME_MAXLEN-1);
|
||||
eee.keyschedule[N2N_PATHNAME_MAXLEN-1]=0; /* strncpy does not add NULL if the source has no NULL. */
|
||||
traceEvent(TRACE_DEBUG, "keyfile = '%s'\n", eee.keyschedule);
|
||||
}
|
||||
else if (cmd->enc_key)
|
||||
if (cmd->enc_key)
|
||||
{
|
||||
encrypt_key = strdup(cmd->enc_key);
|
||||
traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", encrypt_key);
|
||||
|
@ -242,7 +237,7 @@ int start_edge(const n2n_edge_cmd_t* cmd)
|
|||
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (eee.sn_ip_array[i]));
|
||||
}
|
||||
supernode2addr(&(eee.supernode), eee.sn_ip_array[eee.sn_idx]);
|
||||
if (encrypt_key == NULL && strlen(eee.keyschedule) == 0)
|
||||
if (encrypt_key == NULL)
|
||||
{
|
||||
traceEvent(TRACE_WARNING, "Encryption is disabled in edge.");
|
||||
eee.null_transop = 1;
|
||||
|
@ -277,15 +272,6 @@ int start_edge(const n2n_edge_cmd_t* cmd)
|
|||
free(encrypt_key);
|
||||
encrypt_key = NULL;
|
||||
}
|
||||
else if (strlen(eee.keyschedule) > 0)
|
||||
{
|
||||
if (edge_init_keyschedule(&eee) != 0)
|
||||
{
|
||||
traceEvent(TRACE_ERROR, "keyschedule setup failed.\n");
|
||||
free(encrypt_key);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* else run in NULL mode */
|
||||
eee.udp_sock = open_socket(local_port, 1 /*bind ANY*/ );
|
||||
if(eee.udp_sock < 0)
|
||||
|
|
48
benchmark.c
48
benchmark.c
|
@ -70,7 +70,7 @@ uint8_t PKT_CONTENT[]={
|
|||
|
||||
/* Prototypes */
|
||||
static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c );
|
||||
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, uint8_t *pktbuf, n2n_community_t c);
|
||||
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf);
|
||||
static int perform_decryption = 0;
|
||||
|
||||
static void usage() {
|
||||
|
@ -93,34 +93,44 @@ static void parseArgs(int argc, char * argv[]) {
|
|||
|
||||
int main(int argc, char * argv[]) {
|
||||
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
|
||||
n2n_community_t c;
|
||||
n2n_trans_op_t transop_null, transop_twofish, transop_aes_cbc;
|
||||
u_char encrypt_pwd[] = "SoMEVer!S$cUREPassWORD";
|
||||
n2n_trans_op_t transop_null, transop_twofish;
|
||||
#ifdef N2N_HAVE_AES
|
||||
n2n_trans_op_t transop_aes_cbc;
|
||||
#endif
|
||||
n2n_edge_conf_t conf;
|
||||
|
||||
parseArgs(argc, argv);
|
||||
|
||||
memset(c,0,sizeof(N2N_COMMUNITY_SIZE));
|
||||
memcpy(c, "abc123def456", 12);
|
||||
/* Init configuration */
|
||||
edge_init_conf_defaults(&conf);
|
||||
strncpy((char*)conf.community_name, "abc123def456", sizeof(conf.community_name));
|
||||
conf.encrypt_key = "SoMEVer!S$cUREPassWORD";
|
||||
|
||||
/* Init transopts */
|
||||
memset(&transop_null, 0, sizeof(transop_null));
|
||||
transop_null_init(&transop_null);
|
||||
memset(&transop_twofish, 0, sizeof(transop_twofish));
|
||||
transop_twofish_init(&transop_twofish);
|
||||
transop_twofish_setup_psk(&transop_twofish, 0, encrypt_pwd, sizeof(encrypt_pwd)-1);
|
||||
memset(&transop_aes_cbc, 0, sizeof(transop_aes_cbc));
|
||||
transop_aes_init(&transop_aes_cbc);
|
||||
transop_aes_setup_psk(&transop_aes_cbc, 0, encrypt_pwd, sizeof(encrypt_pwd)-1);
|
||||
n2n_transop_null_init(&conf, &transop_null);
|
||||
n2n_transop_twofish_init(&conf, &transop_twofish);
|
||||
#ifdef N2N_HAVE_AES
|
||||
n2n_transop_aes_cbc_init(&conf, &transop_aes_cbc);
|
||||
#endif
|
||||
|
||||
/* Run the tests */
|
||||
run_transop_benchmark("transop_null", &transop_null, pktbuf, c);
|
||||
run_transop_benchmark("transop_twofish", &transop_twofish, pktbuf, c);
|
||||
run_transop_benchmark("transop_aes", &transop_aes_cbc, pktbuf, c);
|
||||
run_transop_benchmark("transop_null", &transop_null, &conf, pktbuf);
|
||||
run_transop_benchmark("transop_twofish", &transop_twofish, &conf, pktbuf);
|
||||
#ifdef N2N_HAVE_AES
|
||||
run_transop_benchmark("transop_aes", &transop_aes_cbc, &conf, pktbuf);
|
||||
#endif
|
||||
|
||||
/* Cleanup */
|
||||
transop_null.deinit(&transop_null);
|
||||
transop_twofish.deinit(&transop_twofish);
|
||||
#ifdef N2N_HAVE_AES
|
||||
transop_aes_cbc.deinit(&transop_aes_cbc);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, uint8_t *pktbuf, n2n_community_t c) {
|
||||
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf) {
|
||||
n2n_common_t cmn;
|
||||
n2n_PACKET_t pkt;
|
||||
n2n_mac_t mac_buf;
|
||||
|
@ -142,7 +152,7 @@ static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, ui
|
|||
gettimeofday( &t1, NULL );
|
||||
|
||||
while(tdiff < target_usec) {
|
||||
nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, c);
|
||||
nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, conf->community_name);
|
||||
|
||||
nw += op_fn->fwd(op_fn,
|
||||
pktbuf+nw, N2N_PKT_BUF_SIZE-nw,
|
||||
|
|
229
edge.c
229
edge.c
|
@ -35,22 +35,20 @@
|
|||
|
||||
/* ***************************************************** */
|
||||
|
||||
typedef struct {
|
||||
int local_port;
|
||||
int mgmt_port;
|
||||
char tuntap_dev_name[N2N_IFNAMSIZ];
|
||||
char ip_mode[N2N_IF_MODE_SIZE];
|
||||
char ip_addr[N2N_NETMASK_STR_SIZE];
|
||||
char netmask[N2N_NETMASK_STR_SIZE];
|
||||
int mtu;
|
||||
int got_s;
|
||||
char device_mac[N2N_MACNAMSIZ];
|
||||
char * encrypt_key;
|
||||
typedef struct n2n_priv_config {
|
||||
char tuntap_dev_name[N2N_IFNAMSIZ];
|
||||
char ip_mode[N2N_IF_MODE_SIZE];
|
||||
char ip_addr[N2N_NETMASK_STR_SIZE];
|
||||
char netmask[N2N_NETMASK_STR_SIZE];
|
||||
char device_mac[N2N_MACNAMSIZ];
|
||||
int mtu;
|
||||
uint8_t got_s;
|
||||
uint8_t daemon;
|
||||
#ifndef WIN32
|
||||
uid_t userid;
|
||||
gid_t groupid;
|
||||
uid_t userid;
|
||||
gid_t groupid;
|
||||
#endif
|
||||
} edge_conf_t;
|
||||
} n2n_priv_config_t;
|
||||
|
||||
/* ***************************************************** */
|
||||
|
||||
|
@ -144,8 +142,7 @@ static void help() {
|
|||
|
||||
printf("-a <mode:address> | Set interface address. For DHCP use '-r -a dhcp:0.0.0.0'\n");
|
||||
printf("-c <community> | n2n community name the edge belongs to.\n");
|
||||
printf("-k <encrypt key> | Encryption key (ASCII) - also N2N_KEY=<encrypt key>. Not with -K.\n");
|
||||
printf("-K <key file> | Specify a key schedule file to load. Not with -k.\n");
|
||||
printf("-k <encrypt key> | Encryption key (ASCII) - also N2N_KEY=<encrypt key>.\n");
|
||||
printf("-s <netmask> | Edge interface netmask in dotted decimal notation (255.255.255.0).\n");
|
||||
printf("-l <supernode host:port> | Supernode IP:port\n");
|
||||
printf("-b | Periodically resolve supernode IP\n");
|
||||
|
@ -163,39 +160,24 @@ static void help() {
|
|||
printf("-M <mtu> | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU);
|
||||
printf("-r | Enable packet forwarding through n2n community.\n");
|
||||
#ifdef N2N_HAVE_AES
|
||||
printf("-A | Set AES CBC as the preferred encryption mode.\n");
|
||||
printf("-A | Use AES CBC for encryption (default=use twofish).\n");
|
||||
#endif
|
||||
printf("-E | Accept multicast MAC addresses (default=drop).\n");
|
||||
printf("-v | Make more verbose. Repeat as required.\n");
|
||||
printf("-t <port> | Management UDP Port (for multiple edges on a machine).\n");
|
||||
|
||||
printf("\nEnvironment variables:\n");
|
||||
printf(" N2N_KEY | Encryption key (ASCII). Not with -K or -k.\n");
|
||||
printf(" N2N_KEY | Encryption key (ASCII). Not with -k.\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* *************************************************** */
|
||||
|
||||
static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t *eee) {
|
||||
static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_edge_conf_t *conf) {
|
||||
/* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */
|
||||
|
||||
switch(optkey) {
|
||||
case'K':
|
||||
{
|
||||
if(ec->encrypt_key) {
|
||||
traceEvent(TRACE_ERROR, "Error: -K and -k options are mutually exclusive");
|
||||
exit(1);
|
||||
} else {
|
||||
strncpy(eee->keyschedule, optargument, N2N_PATHNAME_MAXLEN-1);
|
||||
/* strncpy does not add NULL if the source has no NULL. */
|
||||
eee->keyschedule[N2N_PATHNAME_MAXLEN-1] = 0;
|
||||
|
||||
traceEvent(TRACE_NORMAL, "keyfile = '%s'\n", eee->keyschedule);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a': /* IP address and mode of TUNTAP interface */
|
||||
{
|
||||
scan_address(ec->ip_addr, N2N_NETMASK_STR_SIZE,
|
||||
|
@ -206,14 +188,14 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
|
|||
|
||||
case 'c': /* community as a string */
|
||||
{
|
||||
memset(eee->community_name, 0, N2N_COMMUNITY_SIZE);
|
||||
strncpy((char *)eee->community_name, optargument, N2N_COMMUNITY_SIZE);
|
||||
memset(conf->community_name, 0, N2N_COMMUNITY_SIZE);
|
||||
strncpy((char *)conf->community_name, optargument, N2N_COMMUNITY_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'E': /* multicast ethernet addresses accepted. */
|
||||
{
|
||||
eee->drop_multicast=0;
|
||||
conf->drop_multicast=0;
|
||||
traceEvent(TRACE_DEBUG, "Enabling ethernet multicast traffic");
|
||||
break;
|
||||
}
|
||||
|
@ -235,7 +217,7 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
|
|||
#ifndef WIN32
|
||||
case 'f' : /* do not fork as daemon */
|
||||
{
|
||||
eee->daemon=0;
|
||||
ec->daemon=0;
|
||||
break;
|
||||
}
|
||||
#endif /* #ifndef WIN32 */
|
||||
|
@ -254,37 +236,29 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
|
|||
|
||||
case 'k': /* encrypt key */
|
||||
{
|
||||
if(strlen(eee->keyschedule) > 0) {
|
||||
traceEvent(TRACE_ERROR, "-K and -k options are mutually exclusive");
|
||||
exit(1);
|
||||
} else {
|
||||
traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", ec->encrypt_key);
|
||||
ec->encrypt_key = strdup(optargument);
|
||||
}
|
||||
if(conf->encrypt_key) free(conf->encrypt_key);
|
||||
conf->encrypt_key = strdup(optargument);
|
||||
traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", conf->encrypt_key);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'r': /* enable packet routing across n2n endpoints */
|
||||
{
|
||||
eee->allow_routing = 1;
|
||||
conf->allow_routing = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef N2N_HAVE_AES
|
||||
case 'A':
|
||||
{
|
||||
eee->preferred_aes = 1;
|
||||
conf->transop_id = N2N_TRANSFORM_ID_AESCBC;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case 'l': /* supernode-list */
|
||||
if(optargument) {
|
||||
if(eee->sn_num < N2N_EDGE_NUM_SUPERNODES) {
|
||||
strncpy((eee->sn_ip_array[eee->sn_num]), optargument, N2N_EDGE_SN_HOST_SIZE);
|
||||
traceEvent(TRACE_NORMAL, "Adding supernode[%u] = %s", (unsigned int)eee->sn_num, (eee->sn_ip_array[eee->sn_num]));
|
||||
++eee->sn_num;
|
||||
} else {
|
||||
if(edge_conf_add_supernode(conf, optargument) != 0) {
|
||||
traceEvent(TRACE_WARNING, "Too many supernodes!");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -301,19 +275,19 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
|
|||
|
||||
case 'b':
|
||||
{
|
||||
eee->re_resolve_supernode_ip = 1;
|
||||
conf->re_resolve_supernode_ip = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
{
|
||||
ec->local_port = atoi(optargument);
|
||||
conf->local_port = atoi(optargument);
|
||||
break;
|
||||
}
|
||||
|
||||
case 't':
|
||||
{
|
||||
ec->mgmt_port = atoi(optargument);
|
||||
conf->mgmt_port = atoi(optargument);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -363,7 +337,7 @@ static const struct option long_options[] = {
|
|||
/* *************************************************** */
|
||||
|
||||
/* read command line options */
|
||||
static int loadFromCLI(int argc, char *argv[], edge_conf_t *ec, n2n_edge_t *eee) {
|
||||
static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_config_t *ec) {
|
||||
u_char c;
|
||||
|
||||
while((c = getopt_long(argc, argv,
|
||||
|
@ -374,7 +348,7 @@ static int loadFromCLI(int argc, char *argv[], edge_conf_t *ec, n2n_edge_t *eee)
|
|||
,
|
||||
long_options, NULL)) != '?') {
|
||||
if(c == 255) break;
|
||||
setOption(c, optarg, ec, eee);
|
||||
setOption(c, optarg, ec, conf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -400,7 +374,7 @@ static char *trim(char *s) {
|
|||
/* *************************************************** */
|
||||
|
||||
/* parse the configuration file */
|
||||
static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) {
|
||||
static int loadFromFile(const char *path, n2n_edge_conf_t *conf, n2n_priv_config_t *ec) {
|
||||
char buffer[4096], *line, *key, *value;
|
||||
u_int line_len, opt_name_len;
|
||||
FILE *fd;
|
||||
|
@ -414,7 +388,6 @@ static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) {
|
|||
}
|
||||
|
||||
while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) {
|
||||
|
||||
line = trim(line);
|
||||
value = NULL;
|
||||
|
||||
|
@ -437,7 +410,7 @@ static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) {
|
|||
if(line_len > opt_name_len + 1) value = trim(&key[opt_name_len + 1]);
|
||||
|
||||
// traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value);
|
||||
setOption(opt->val, value, ec, eee);
|
||||
setOption(opt->val, value, ec, conf);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -449,7 +422,7 @@ static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) {
|
|||
if(line_len > 2) value = trim(&key[2]);
|
||||
|
||||
// traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value);
|
||||
setOption(key[0], value, ec, eee);
|
||||
setOption(key[0], value, ec, conf);
|
||||
} else {
|
||||
traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line);
|
||||
continue;
|
||||
|
@ -565,105 +538,87 @@ static void daemonize() {
|
|||
|
||||
/** Entry point to program from kernel. */
|
||||
int main(int argc, char* argv[]) {
|
||||
int keep_on_running = 1;
|
||||
int rc;
|
||||
int i;
|
||||
n2n_edge_t eee; /* single instance for this program */
|
||||
edge_conf_t ec;
|
||||
int keep_on_running = 1;
|
||||
int rc;
|
||||
tuntap_dev tuntap; /* a tuntap device */
|
||||
n2n_edge_t *eee; /* single instance for this program */
|
||||
n2n_edge_conf_t conf; /* generic N2N edge config */
|
||||
n2n_priv_config_t ec; /* config used for standalone program execution */
|
||||
|
||||
if(argc == 1)
|
||||
help();
|
||||
|
||||
ec.local_port = 0 /* any port */;
|
||||
ec.mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
|
||||
snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), "edge0");
|
||||
snprintf(ec.ip_mode, sizeof(ec.ip_mode), "static");
|
||||
snprintf(ec.netmask, sizeof(ec.netmask), "255.255.255.0");
|
||||
ec.ip_addr[0] = '\0';
|
||||
ec.device_mac[0] = '\0';
|
||||
|
||||
/* Defaults */
|
||||
edge_init_conf_defaults(&conf);
|
||||
memset(&ec, 0, sizeof(ec));
|
||||
ec.mtu = DEFAULT_MTU;
|
||||
ec.got_s = 0;
|
||||
ec.encrypt_key = NULL;
|
||||
ec.daemon = 1; /* By default run in daemon mode. */
|
||||
#ifndef WIN32
|
||||
ec.userid = 0; /* root is the only guaranteed ID */
|
||||
ec.groupid = 0; /* root is the only guaranteed ID */
|
||||
#endif
|
||||
|
||||
if(-1 == edge_init(&eee)) {
|
||||
traceEvent(TRACE_ERROR, "Failed in edge_init");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(getenv("N2N_KEY")) {
|
||||
ec.encrypt_key = strdup(getenv("N2N_KEY"));
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
ec.tuntap_dev_name[0] = '\0';
|
||||
#else
|
||||
snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), "edge0");
|
||||
#endif
|
||||
memset(&(eee.supernode), 0, sizeof(eee.supernode));
|
||||
eee.supernode.family = AF_INET;
|
||||
snprintf(ec.ip_mode, sizeof(ec.ip_mode), "static");
|
||||
snprintf(ec.netmask, sizeof(ec.netmask), "255.255.255.0");
|
||||
|
||||
traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE);
|
||||
|
||||
#ifndef WIN32
|
||||
if((argc >= 2) && (argv[1][0] != '-')) {
|
||||
rc = loadFromFile(argv[1], &ec, &eee);
|
||||
rc = loadFromFile(argv[1], &conf, &ec);
|
||||
if(argc > 2)
|
||||
rc = loadFromCLI(argc, argv, &ec, &eee);
|
||||
rc = loadFromCLI(argc, argv, &conf, &ec);
|
||||
} else
|
||||
#endif
|
||||
rc = loadFromCLI(argc, argv, &ec, &eee);
|
||||
rc = loadFromCLI(argc, argv, &conf, &ec);
|
||||
|
||||
if((rc < 0) || (eee.sn_num == 0))
|
||||
if(rc < 0)
|
||||
help();
|
||||
|
||||
traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE);
|
||||
|
||||
for (i=0; i<eee.sn_num; ++i)
|
||||
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (eee.sn_ip_array[i]));
|
||||
if(0 == strcmp("dhcp", ec.ip_mode)) {
|
||||
traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled.");
|
||||
|
||||
supernode2addr(&(eee.supernode), eee.sn_ip_array[eee.sn_idx]);
|
||||
conf.dyn_ip_mode = 1;
|
||||
} else
|
||||
traceEvent(TRACE_NORMAL, "ip_mode='%s'", ec.ip_mode);
|
||||
|
||||
if(edge_verify_conf(&conf) != 0)
|
||||
help();
|
||||
|
||||
if(!(
|
||||
#ifdef __linux__
|
||||
(ec.tuntap_dev_name[0] != 0) &&
|
||||
#endif
|
||||
(eee.community_name[0] != 0) &&
|
||||
(ec.ip_addr[0] != 0)
|
||||
))
|
||||
{
|
||||
help();
|
||||
}
|
||||
help();
|
||||
|
||||
#ifndef WIN32
|
||||
if(eee.daemon) {
|
||||
setUseSyslog(1); /* traceEvent output now goes to syslog. */
|
||||
daemonize();
|
||||
}
|
||||
#endif /* #ifndef WIN32 */
|
||||
|
||||
if((NULL == ec.encrypt_key) && (0 == strlen(eee.keyschedule)))
|
||||
{
|
||||
traceEvent(TRACE_WARNING, "Encryption is disabled in edge.");
|
||||
|
||||
eee.null_transop = 1;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
/* If running suid root then we need to setuid before using the force. */
|
||||
setuid(0);
|
||||
/* setgid(0); */
|
||||
#endif
|
||||
|
||||
if(0 == strcmp("dhcp", ec.ip_mode)) {
|
||||
traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled.");
|
||||
|
||||
eee.dyn_ip_mode = 1;
|
||||
} else
|
||||
traceEvent(TRACE_NORMAL, "ip_mode='%s'", ec.ip_mode);
|
||||
|
||||
if(tuntap_open(&(eee.device), ec.tuntap_dev_name, ec.ip_mode, ec.ip_addr, ec.netmask, ec.device_mac, ec.mtu) < 0)
|
||||
if(tuntap_open(&tuntap, ec.tuntap_dev_name, ec.ip_mode, ec.ip_addr, ec.netmask, ec.device_mac, ec.mtu) < 0)
|
||||
return(-1);
|
||||
|
||||
if((eee = edge_init(&tuntap, &conf, &rc)) == NULL) {
|
||||
traceEvent(TRACE_ERROR, "Failed in edge_init");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if(ec.daemon) {
|
||||
setUseSyslog(1); /* traceEvent output now goes to syslog. */
|
||||
daemonize();
|
||||
}
|
||||
#endif /* #ifndef WIN32 */
|
||||
|
||||
#ifndef WIN32
|
||||
if((ec.userid != 0) || (ec.groupid != 0)) {
|
||||
traceEvent(TRACE_NORMAL, "Interface up. Dropping privileges to uid=%d, gid=%d",
|
||||
|
@ -675,30 +630,16 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if(ec.local_port > 0)
|
||||
traceEvent(TRACE_NORMAL, "Binding to local port %d", (signed int)ec.local_port);
|
||||
|
||||
if(ec.encrypt_key) {
|
||||
if(edge_init_encryption(&eee, (uint8_t *)ec.encrypt_key, strlen(ec.encrypt_key)) != 0) {
|
||||
traceEvent(TRACE_ERROR, "Error: encryption setup failed");
|
||||
return(-1);
|
||||
}
|
||||
} else if(strlen(eee.keyschedule) > 0) {
|
||||
if(edge_init_keyschedule(&eee) < 0) {
|
||||
traceEvent(TRACE_ERROR, "Error: keyschedule setup failed");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
/* else run in NULL mode */
|
||||
|
||||
if(edge_init_sockets(&eee, ec.local_port, ec.mgmt_port) < 0) {
|
||||
traceEvent(TRACE_ERROR, "Error: socket setup failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
traceEvent(TRACE_NORMAL, "edge started");
|
||||
rc = run_edge_loop(eee, &keep_on_running);
|
||||
|
||||
return run_edge_loop(&eee, &keep_on_running);
|
||||
/* Cleanup */
|
||||
edge_term(eee);
|
||||
tuntap_close(&tuntap);
|
||||
|
||||
if(conf.encrypt_key) free(conf.encrypt_key);
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
|
543
edge_utils.c
543
edge_utils.c
|
@ -46,15 +46,6 @@
|
|||
#define ARP_PERIOD_INTERVAL (10) /* sec */
|
||||
#endif
|
||||
|
||||
/** Positions in the transop array where various transforms are stored.
|
||||
*
|
||||
* Used by transop_enum_to_index(). See also the transform enumerations in
|
||||
* n2n_transforms.h */
|
||||
#define N2N_TRANSOP_NULL_IDX 0
|
||||
#define N2N_TRANSOP_TF_IDX 1
|
||||
#define N2N_TRANSOP_AESCBC_IDX 2
|
||||
/* etc. */
|
||||
|
||||
#define ETH_FRAMESIZE 14
|
||||
#define IP4_SRCOFFSET 12
|
||||
#define IP4_DSTOFFSET 16
|
||||
|
@ -67,6 +58,58 @@ static void check_peer(n2n_edge_t * eee,
|
|||
uint8_t from_supernode,
|
||||
const n2n_mac_t mac,
|
||||
const n2n_sock_t * peer);
|
||||
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port);
|
||||
static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn);
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
int edge_verify_conf(const n2n_edge_conf_t *conf) {
|
||||
if(conf->community_name[0] == 0)
|
||||
return(-1);
|
||||
|
||||
if(conf->sn_num == 0)
|
||||
return(-2);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
struct n2n_edge {
|
||||
n2n_edge_conf_t conf;
|
||||
|
||||
/* Status */
|
||||
uint8_t sn_idx; /**< Currently active supernode. */
|
||||
uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */
|
||||
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
|
||||
tuntap_dev device; /**< All about the TUNTAP device */
|
||||
n2n_trans_op_t transop; /**< The transop to use when encoding */
|
||||
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
|
||||
|
||||
/* Sockets */
|
||||
n2n_sock_t supernode;
|
||||
n2n_sock_t multicast_peer; /**< Multicast peer group (for local edges) */
|
||||
int udp_sock;
|
||||
int udp_mgmt_sock; /**< socket for status info. */
|
||||
int udp_multicast_sock; /**< socket for local multicast registrations. */
|
||||
|
||||
/* Peers */
|
||||
struct peer_info * known_peers; /**< Edges we are connected to. */
|
||||
struct peer_info * pending_peers; /**< Edges we have tried to register with. */
|
||||
|
||||
/* Timers */
|
||||
time_t last_register_req; /**< Check if time to re-register with super*/
|
||||
size_t register_lifetime; /**< Time distance after last_register_req at which to re-register. */
|
||||
time_t last_p2p; /**< Last time p2p traffic was received. */
|
||||
time_t last_sup; /**< Last time a packet arrived from supernode. */
|
||||
time_t start_time; /**< For calculating uptime */
|
||||
|
||||
/* Statistics */
|
||||
size_t tx_p2p;
|
||||
size_t rx_p2p;
|
||||
size_t tx_sup;
|
||||
size_t rx_sup;
|
||||
};
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
|
@ -74,49 +117,89 @@ static void check_peer(n2n_edge_t * eee,
|
|||
*
|
||||
* This also initialises the NULL transform operation opstruct.
|
||||
*/
|
||||
int edge_init(n2n_edge_t * eee) {
|
||||
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv) {
|
||||
n2n_transform_t transop_id = conf->transop_id;
|
||||
n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t));
|
||||
int rc = -1;
|
||||
|
||||
if((rc = edge_verify_conf(conf)) != 0) {
|
||||
traceEvent(TRACE_ERROR, "Invalid configuration");
|
||||
goto edge_init_error;
|
||||
}
|
||||
|
||||
if(!eee) {
|
||||
traceEvent(TRACE_ERROR, "Cannot allocate memory");
|
||||
goto edge_init_error;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
initWin32();
|
||||
#endif
|
||||
memset(eee, 0, sizeof(n2n_edge_t));
|
||||
memcpy(&eee->conf, conf, sizeof(*conf));
|
||||
memcpy(&eee->device, dev, sizeof(*dev));
|
||||
eee->start_time = time(NULL);
|
||||
|
||||
/* REVISIT: BbMaj7 : Should choose something with less predictability
|
||||
* particularly for embedded targets with no real-time clock. */
|
||||
srand(eee->start_time);
|
||||
|
||||
transop_null_init( &(eee->transop[N2N_TRANSOP_NULL_IDX]));
|
||||
transop_twofish_init(&(eee->transop[N2N_TRANSOP_TF_IDX] ));
|
||||
transop_aes_init(&(eee->transop[N2N_TRANSOP_AESCBC_IDX] ));
|
||||
|
||||
eee->tx_transop_idx = N2N_TRANSOP_NULL_IDX; /* No guarantee the others have been setup */
|
||||
|
||||
eee->daemon = 1; /* By default run in daemon mode. */
|
||||
eee->preferred_aes = 0; /* Disable AES by default (for compatibility) */
|
||||
eee->re_resolve_supernode_ip = 0;
|
||||
/* keyschedule set to NULLs by memset */
|
||||
/* community_name set to NULLs by memset */
|
||||
eee->null_transop = 0;
|
||||
eee->udp_sock = -1;
|
||||
eee->udp_mgmt_sock = -1;
|
||||
eee->udp_multicast_sock = -1;
|
||||
eee->dyn_ip_mode = 0;
|
||||
eee->allow_routing = 0;
|
||||
eee->drop_multicast = 1;
|
||||
eee->known_peers = NULL;
|
||||
eee->pending_peers = NULL;
|
||||
eee->last_register_req = 0;
|
||||
eee->register_lifetime = REGISTER_SUPER_INTERVAL_DFL;
|
||||
eee->last_p2p = 0;
|
||||
eee->last_sup = 0;
|
||||
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
||||
|
||||
#ifdef NOT_USED
|
||||
if(lzo_init() != LZO_E_OK) {
|
||||
traceEvent(TRACE_ERROR, "LZO compression error");
|
||||
return(-1);
|
||||
goto edge_init_error;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(int i=0; i<conf->sn_num; ++i)
|
||||
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (conf->sn_ip_array[i]));
|
||||
|
||||
/* Set the active supernode */
|
||||
supernode2addr(&(eee->supernode), conf->sn_ip_array[eee->sn_idx]);
|
||||
|
||||
/* Set active transop */
|
||||
if(conf->encrypt_key == NULL)
|
||||
transop_id = N2N_TRANSFORM_ID_NULL;
|
||||
|
||||
switch(transop_id) {
|
||||
case N2N_TRANSFORM_ID_TWOFISH:
|
||||
rc = n2n_transop_twofish_init(&eee->conf, &eee->transop);
|
||||
break;
|
||||
#ifdef N2N_HAVE_AES
|
||||
case N2N_TRANSFORM_ID_AESCBC:
|
||||
rc = n2n_transop_aes_cbc_init(&eee->conf, &eee->transop);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rc = n2n_transop_null_init(&eee->conf, &eee->transop);
|
||||
}
|
||||
|
||||
return(0);
|
||||
if((rc < 0) || (eee->transop.fwd == NULL) || (eee->transop.transform_id != transop_id)) {
|
||||
traceEvent(TRACE_ERROR, "Transop init failed");
|
||||
goto edge_init_error;
|
||||
}
|
||||
|
||||
if(eee->transop.no_encryption)
|
||||
traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
|
||||
|
||||
if(edge_init_sockets(eee, conf->local_port, conf->mgmt_port) < 0) {
|
||||
traceEvent(TRACE_ERROR, "Error: socket setup failed");
|
||||
goto edge_init_error;
|
||||
}
|
||||
|
||||
//edge_init_success:
|
||||
*rv = 0;
|
||||
return(eee);
|
||||
|
||||
edge_init_error:
|
||||
if(eee)
|
||||
free(eee);
|
||||
*rv = rc;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* ***************************************************** */
|
||||
|
@ -126,7 +209,7 @@ int edge_init(n2n_edge_t * eee) {
|
|||
* REVISIT: This is a really bad idea. The edge will block completely while the
|
||||
* hostname resolution is performed. This could take 15 seconds.
|
||||
*/
|
||||
void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
|
||||
static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
|
||||
n2n_sn_name_t addr;
|
||||
const char *supernode_host;
|
||||
|
||||
|
@ -501,7 +584,7 @@ static void send_register_super(n2n_edge_t * eee,
|
|||
cmn.ttl=N2N_DEFAULT_TTL;
|
||||
cmn.pc = n2n_register_super;
|
||||
cmn.flags = 0;
|
||||
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE);
|
||||
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
||||
|
||||
for(idx=0; idx < N2N_COOKIE_SIZE; ++idx)
|
||||
eee->last_cookie[idx] = rand() % 0xff;
|
||||
|
@ -538,7 +621,7 @@ static void send_register(n2n_edge_t * eee,
|
|||
cmn.ttl=N2N_DEFAULT_TTL;
|
||||
cmn.pc = n2n_register;
|
||||
cmn.flags = 0;
|
||||
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE);
|
||||
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
||||
|
||||
idx=0;
|
||||
encode_uint32(reg.cookie, &idx, 123456789);
|
||||
|
@ -572,7 +655,7 @@ static void send_register_ack(n2n_edge_t * eee,
|
|||
cmn.ttl=N2N_DEFAULT_TTL;
|
||||
cmn.pc = n2n_register_ack;
|
||||
cmn.flags = 0;
|
||||
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE);
|
||||
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
||||
|
||||
memset(&ack, 0, sizeof(ack));
|
||||
memcpy(ack.cookie, reg->cookie, N2N_COOKIE_SIZE);
|
||||
|
@ -608,24 +691,24 @@ static void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
|
|||
/* Give up on that supernode and try the next one. */
|
||||
++(eee->sn_idx);
|
||||
|
||||
if (eee->sn_idx >= eee->sn_num) {
|
||||
if (eee->sn_idx >= eee->conf.sn_num) {
|
||||
/* Got to end of list, go back to the start. Also works for list of one entry. */
|
||||
eee->sn_idx=0;
|
||||
}
|
||||
|
||||
traceEvent(TRACE_WARNING, "Supernode not responding - moving to %u of %u",
|
||||
(unsigned int)eee->sn_idx, (unsigned int)eee->sn_num);
|
||||
(unsigned int)eee->sn_idx, (unsigned int)eee->conf.sn_num);
|
||||
|
||||
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
|
||||
}
|
||||
else
|
||||
--(eee->sup_attempts);
|
||||
|
||||
for(sn_idx=0; sn_idx<eee->sn_num; sn_idx++) {
|
||||
supernode2addr(&(eee->supernode), eee->sn_ip_array[sn_idx]);
|
||||
for(sn_idx=0; sn_idx<eee->conf.sn_num; sn_idx++) {
|
||||
supernode2addr(&(eee->supernode), eee->conf.sn_ip_array[sn_idx]);
|
||||
|
||||
traceEvent(TRACE_INFO, "Registering with supernode [id: %u/%u][%s][attempts left %u]",
|
||||
sn_idx+1, eee->sn_num,
|
||||
sn_idx+1, eee->conf.sn_num,
|
||||
supernode_ip(eee), (unsigned int)eee->sup_attempts);
|
||||
|
||||
send_register_super(eee, &(eee->supernode));
|
||||
|
@ -657,119 +740,7 @@ static void send_deregister(n2n_edge_t * eee,
|
|||
|
||||
/** Return the IP address of the current supernode in the ring. */
|
||||
static const char * supernode_ip(const n2n_edge_t * eee) {
|
||||
return (eee->sn_ip_array)[eee->sn_idx];
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
static int edge_init_twofish_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len) {
|
||||
return transop_twofish_setup_psk(&(eee->transop[N2N_TRANSOP_TF_IDX]),
|
||||
0, encrypt_pwd, encrypt_pwd_len);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
static int edge_init_aes_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len) {
|
||||
return transop_aes_setup_psk(&(eee->transop[N2N_TRANSOP_AESCBC_IDX]),
|
||||
0, encrypt_pwd, encrypt_pwd_len);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
int edge_init_encryption(n2n_edge_t * eee, uint8_t *encrypt_pwd, uint32_t encrypt_pwd_len) {
|
||||
#ifdef N2N_HAVE_AES
|
||||
if(edge_init_aes_psk(eee, encrypt_pwd, encrypt_pwd_len) < 0) {
|
||||
traceEvent(TRACE_ERROR, "Error: AES PSK setup failed");
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(edge_init_twofish_psk(eee, encrypt_pwd, encrypt_pwd_len) < 0) {
|
||||
traceEvent(TRACE_ERROR, "Error: twofish PSK setup failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
static n2n_tostat_t n2n_tick_aes(n2n_edge_t * eee, time_t now, size_t *trop) {
|
||||
n2n_tostat_t tst = (eee->transop[N2N_TRANSOP_AESCBC_IDX].tick)(&(eee->transop[N2N_TRANSOP_AESCBC_IDX]), now);
|
||||
|
||||
if(tst.can_tx)
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "can_tx AESCBC (idx=%u)", (unsigned int)N2N_TRANSOP_AESCBC_IDX);
|
||||
*trop = N2N_TRANSOP_AESCBC_IDX;
|
||||
}
|
||||
|
||||
return tst;
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
static n2n_tostat_t n2n_tick_twofish(n2n_edge_t * eee, time_t now, size_t *trop) {
|
||||
n2n_tostat_t tst = (eee->transop[N2N_TRANSOP_TF_IDX].tick)(&(eee->transop[N2N_TRANSOP_TF_IDX]), now);
|
||||
if(tst.can_tx)
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "can_tx TF (idx=%u)", (unsigned int)N2N_TRANSOP_TF_IDX);
|
||||
*trop = N2N_TRANSOP_TF_IDX;
|
||||
}
|
||||
|
||||
return tst;
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
/** Called periodically to roll keys and do any periodic maintenance in the
|
||||
* tranform operations state machines. */
|
||||
static int n2n_tick_transop(n2n_edge_t * eee, time_t now)
|
||||
{
|
||||
size_t trop = eee->tx_transop_idx;
|
||||
|
||||
/* Tests are done in order that most preferred transform is last and causes
|
||||
* tx_transop_idx to be left at most preferred valid transform. */
|
||||
(eee->transop[N2N_TRANSOP_NULL_IDX].tick)(&(eee->transop[N2N_TRANSOP_NULL_IDX]), now);
|
||||
|
||||
if(eee->preferred_aes) {
|
||||
n2n_tick_twofish(eee, now, &trop);
|
||||
n2n_tick_aes(eee, now, &trop);
|
||||
} else {
|
||||
n2n_tick_aes(eee, now, &trop);
|
||||
n2n_tick_twofish(eee, now, &trop);
|
||||
}
|
||||
|
||||
if(trop != eee->tx_transop_idx)
|
||||
{
|
||||
eee->tx_transop_idx = trop;
|
||||
traceEvent(TRACE_INFO, "Chose new tx_transop_idx=%u", (unsigned int)(eee->tx_transop_idx));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
/** Find the transop op-struct for the transform enumeration required.
|
||||
*
|
||||
* @return - index into the transop array, or -1 on failure.
|
||||
*/
|
||||
static int transop_enum_to_index(n2n_transform_t id) {
|
||||
switch (id)
|
||||
{
|
||||
case N2N_TRANSFORM_ID_TWOFISH:
|
||||
return N2N_TRANSOP_TF_IDX;
|
||||
break;
|
||||
case N2N_TRANSFORM_ID_NULL:
|
||||
return N2N_TRANSOP_NULL_IDX;
|
||||
break;
|
||||
case N2N_TRANSFORM_ID_AESCBC:
|
||||
return N2N_TRANSOP_AESCBC_IDX;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return (eee->conf.sn_ip_array)[eee->sn_idx];
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
@ -816,20 +787,19 @@ static int handle_PACKET(n2n_edge_t * eee,
|
|||
{
|
||||
uint8_t decodebuf[N2N_PKT_BUF_SIZE];
|
||||
size_t eth_size;
|
||||
int rx_transop_idx;
|
||||
n2n_transform_t rx_transop_id;
|
||||
|
||||
rx_transop_idx = transop_enum_to_index(pkt->transform);
|
||||
rx_transop_id = (n2n_transform_t)pkt->transform;
|
||||
|
||||
if(rx_transop_idx >=0)
|
||||
{
|
||||
if(rx_transop_id == eee->conf.transop_id) {
|
||||
eth_payload = decodebuf;
|
||||
eh = (ether_hdr_t*)eth_payload;
|
||||
eth_size = eee->transop[rx_transop_idx].rev(&(eee->transop[rx_transop_idx]),
|
||||
eth_size = eee->transop.rev(&eee->transop,
|
||||
eth_payload, N2N_PKT_BUF_SIZE,
|
||||
payload, psize, pkt->srcMac);
|
||||
++(eee->transop[rx_transop_idx].rx_cnt); /* stats */
|
||||
++(eee->transop.rx_cnt); /* stats */
|
||||
|
||||
if(!(eee->allow_routing)) {
|
||||
if(!(eee->conf.allow_routing)) {
|
||||
if(ntohs(eh->type) == 0x0800) {
|
||||
uint32_t *dst = (uint32_t*)ð_payload[ETH_FRAMESIZE + IP4_DSTOFFSET];
|
||||
|
||||
|
@ -857,8 +827,8 @@ static int handle_PACKET(n2n_edge_t * eee,
|
|||
}
|
||||
else
|
||||
{
|
||||
traceEvent(TRACE_ERROR, "handle_PACKET dropped unknown transform enum %u",
|
||||
(unsigned int)pkt->transform);
|
||||
traceEvent(TRACE_ERROR, "invalid transop ID: %u, expected %u",
|
||||
rx_transop_id, eee->conf.transop_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -910,7 +880,6 @@ static void readFromMgmtSocket(n2n_edge_t * eee, int * keep_running) {
|
|||
" help This help message\n"
|
||||
" +verb Increase verbosity of logging\n"
|
||||
" -verb Decrease verbosity of logging\n"
|
||||
" reload Re-read the keyschedule\n"
|
||||
" <enter> Display statistics\n\n");
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
||||
|
@ -962,25 +931,6 @@ static void readFromMgmtSocket(n2n_edge_t * eee, int * keep_running) {
|
|||
}
|
||||
}
|
||||
|
||||
if(recvlen >= 6)
|
||||
{
|
||||
if(0 == memcmp(udp_buf, "reload", 6))
|
||||
{
|
||||
if(strlen(eee->keyschedule) > 0)
|
||||
{
|
||||
if(edge_init_keyschedule(eee) == 0)
|
||||
{
|
||||
msg_len=0;
|
||||
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
|
||||
"> OK\n");
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
||||
(struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traceEvent(TRACE_DEBUG, "mgmt status rq");
|
||||
|
||||
msg_len=0;
|
||||
|
@ -999,15 +949,9 @@ static void readFromMgmtSocket(n2n_edge_t * eee, int * keep_running) {
|
|||
(unsigned int)eee->rx_p2p);
|
||||
|
||||
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
|
||||
"trans:null |%6u|%6u|\n"
|
||||
"trans:tf |%6u|%6u|\n"
|
||||
"trans:aes |%6u|%6u|\n",
|
||||
(unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].tx_cnt,
|
||||
(unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].rx_cnt,
|
||||
(unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].tx_cnt,
|
||||
(unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].rx_cnt,
|
||||
(unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].tx_cnt,
|
||||
(unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].rx_cnt);
|
||||
"transop |%6u|%6u|\n",
|
||||
(unsigned int)eee->transop.tx_cnt,
|
||||
(unsigned int)eee->transop.rx_cnt);
|
||||
|
||||
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
|
||||
"peers pend:%u full:%u\n",
|
||||
|
@ -1071,25 +1015,6 @@ static int is_ethMulticast(const void * buf, size_t bufsize) {
|
|||
|
||||
/* ************************************** */
|
||||
|
||||
/* Choose the transop for Tx. This should be based on the newest valid
|
||||
* cipherspec in the key schedule.
|
||||
*
|
||||
* Never fall back to NULL tranform unless no key sources were specified. It is
|
||||
* better to render edge inoperative than to expose user data in the clear. In
|
||||
* the case where all SAs are expired an arbitrary transform will be chosen for
|
||||
* Tx. It will fail having no valid SAs but one must be selected.
|
||||
*/
|
||||
static size_t edge_choose_tx_transop(const n2n_edge_t * eee) {
|
||||
if(eee->null_transop)
|
||||
{
|
||||
return N2N_TRANSOP_NULL_IDX;
|
||||
}
|
||||
|
||||
return eee->tx_transop_idx;
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
/* @return 1 if destination is a peer, 0 if destination is supernode */
|
||||
static int find_peer_destination(n2n_edge_t * eee,
|
||||
n2n_mac_t mac_address,
|
||||
|
@ -1173,7 +1098,7 @@ void send_packet2net(n2n_edge_t * eee,
|
|||
|
||||
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
|
||||
size_t idx=0;
|
||||
size_t tx_transop_idx=0;
|
||||
n2n_transform_t tx_transop_idx = eee->transop.transform_id;
|
||||
|
||||
ether_hdr_t eh;
|
||||
|
||||
|
@ -1181,7 +1106,7 @@ void send_packet2net(n2n_edge_t * eee,
|
|||
memcpy(&eh, tap_pkt, sizeof(ether_hdr_t));
|
||||
|
||||
/* Discard IP packets that are not originated by this hosts */
|
||||
if(!(eee->allow_routing)) {
|
||||
if(!(eee->conf.allow_routing)) {
|
||||
if(ntohs(eh.type) == 0x0800) {
|
||||
/* This is an IP packet from the local source address - not forwarded. */
|
||||
uint32_t *src = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET];
|
||||
|
@ -1209,26 +1134,24 @@ void send_packet2net(n2n_edge_t * eee,
|
|||
cmn.ttl = N2N_DEFAULT_TTL;
|
||||
cmn.pc = n2n_packet;
|
||||
cmn.flags=0; /* no options, not from supernode, no socket */
|
||||
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE);
|
||||
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
|
||||
|
||||
memset(&pkt, 0, sizeof(pkt));
|
||||
memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE);
|
||||
memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE);
|
||||
|
||||
tx_transop_idx = edge_choose_tx_transop(eee);
|
||||
|
||||
pkt.sock.family=0; /* do not encode sock */
|
||||
pkt.transform = eee->transop[tx_transop_idx].transform_id;
|
||||
pkt.transform = tx_transop_idx;
|
||||
|
||||
idx=0;
|
||||
encode_PACKET(pktbuf, &idx, &cmn, &pkt);
|
||||
traceEvent(TRACE_DEBUG, "encoded PACKET header of size=%u transform %u (idx=%u)",
|
||||
(unsigned int)idx, (unsigned int)pkt.transform, (unsigned int)tx_transop_idx);
|
||||
traceEvent(TRACE_DEBUG, "encoded PACKET header of size=%u transform %u",
|
||||
(unsigned int)idx, tx_transop_idx);
|
||||
|
||||
idx += eee->transop[tx_transop_idx].fwd(&(eee->transop[tx_transop_idx]),
|
||||
idx += eee->transop.fwd(&eee->transop,
|
||||
pktbuf+idx, N2N_PKT_BUF_SIZE-idx,
|
||||
tap_pkt, len, pkt.dstMac);
|
||||
++(eee->transop[tx_transop_idx].tx_cnt); /* stats */
|
||||
eee->transop.tx_cnt++; /* stats */
|
||||
|
||||
send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */
|
||||
}
|
||||
|
@ -1269,7 +1192,7 @@ static void readFromTAPSocket(n2n_edge_t * eee) {
|
|||
traceEvent(TRACE_INFO, "### Rx TAP packet (%4d) for %s",
|
||||
(signed int)len, macaddr_str(mac_buf, mac));
|
||||
|
||||
if(eee->drop_multicast &&
|
||||
if(eee->conf.drop_multicast &&
|
||||
(is_ip6_discovery(eth_pkt, len) ||
|
||||
is_ethMulticast(eth_pkt, len)
|
||||
)
|
||||
|
@ -1383,7 +1306,7 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
|||
msg_type = cmn.pc; /* packet code */
|
||||
from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
if(0 == memcmp(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE)) {
|
||||
if(0 == memcmp(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE)) {
|
||||
if(msg_type == MSG_TYPE_PACKET) {
|
||||
/* process PACKET - most frequent so first in list. */
|
||||
n2n_PACKET_t pkt;
|
||||
|
@ -1560,8 +1483,8 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
|
|||
/* Make sure ciphers are updated before the packet is treated. */
|
||||
if((nowTime - lastTransop) > TRANSOP_TICK_INTERVAL) {
|
||||
lastTransop = nowTime;
|
||||
|
||||
n2n_tick_transop(eee, nowTime);
|
||||
|
||||
eee->transop.tick(&eee->transop, nowTime);
|
||||
}
|
||||
|
||||
if(rc > 0) {
|
||||
|
@ -1614,7 +1537,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
|
|||
(unsigned int)peer_list_size(eee->known_peers));
|
||||
}
|
||||
|
||||
if(eee->dyn_ip_mode &&
|
||||
if(eee->conf.dyn_ip_mode &&
|
||||
((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) {
|
||||
traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address.");
|
||||
tuntap_get_address(&(eee->device));
|
||||
|
@ -1632,75 +1555,12 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
|
|||
send_deregister(eee, &(eee->supernode));
|
||||
|
||||
closesocket(eee->udp_sock);
|
||||
tuntap_close(&(eee->device));
|
||||
|
||||
edge_term(eee);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
/** Read in a key-schedule file, parse the lines and pass each line to the
|
||||
* appropriate trans_op for parsing of key-data and adding key-schedule
|
||||
* entries. The lookup table of time->trans_op is constructed such that
|
||||
* encoding can be passed to the correct trans_op. The trans_op internal table
|
||||
* will then determine the best SA for that trans_op from the key schedule to
|
||||
* use for encoding. */
|
||||
|
||||
int edge_init_keyschedule(n2n_edge_t * eee) {
|
||||
#define N2N_NUM_CIPHERSPECS 32
|
||||
|
||||
int retval = -1;
|
||||
ssize_t numSpecs=0;
|
||||
n2n_cipherspec_t specs[N2N_NUM_CIPHERSPECS];
|
||||
size_t i;
|
||||
time_t now = time(NULL);
|
||||
|
||||
numSpecs = n2n_read_keyfile(specs, N2N_NUM_CIPHERSPECS, eee->keyschedule);
|
||||
|
||||
if(numSpecs > 0)
|
||||
{
|
||||
traceEvent(TRACE_NORMAL, "keyfile = %s read -> %d specs.\n", optarg, (signed int)numSpecs);
|
||||
|
||||
for (i=0; i < (size_t)numSpecs; ++i)
|
||||
{
|
||||
int idx;
|
||||
|
||||
idx = transop_enum_to_index(specs[i].t);
|
||||
|
||||
switch (idx)
|
||||
{
|
||||
case N2N_TRANSOP_TF_IDX:
|
||||
case N2N_TRANSOP_AESCBC_IDX:
|
||||
{
|
||||
retval = (eee->transop[idx].addspec)(&(eee->transop[idx]),
|
||||
&(specs[i]));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
if (0 != retval)
|
||||
{
|
||||
traceEvent(TRACE_ERROR, "keyschedule failed to add spec[%u] to transop[%d].\n",
|
||||
(unsigned int)i, idx);
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
n2n_tick_transop(eee, now);
|
||||
}
|
||||
else
|
||||
traceEvent(TRACE_ERROR, "Failed to process '%s'", eee->keyschedule);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
/** Deinitialise the edge and deallocate any owned memory. */
|
||||
void edge_term(n2n_edge_t * eee) {
|
||||
if(eee->udp_sock >= 0)
|
||||
|
@ -1715,38 +1575,13 @@ void edge_term(n2n_edge_t * eee) {
|
|||
clear_peer_list(&(eee->pending_peers));
|
||||
clear_peer_list(&(eee->known_peers));
|
||||
|
||||
(eee->transop[N2N_TRANSOP_TF_IDX].deinit)(&eee->transop[N2N_TRANSOP_TF_IDX]);
|
||||
(eee->transop[N2N_TRANSOP_NULL_IDX].deinit)(&eee->transop[N2N_TRANSOP_NULL_IDX]);
|
||||
eee->transop.deinit(&eee->transop);
|
||||
memset(eee, 0, sizeof(*eee));
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
const char *random_device_mac(void)
|
||||
{
|
||||
const char key[] = "0123456789abcdef";
|
||||
static char mac[18];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(mac) - 1; ++i) {
|
||||
if ((i + 1) % 3 == 0) {
|
||||
mac[i] = ':';
|
||||
continue;
|
||||
}
|
||||
#ifdef WIN32
|
||||
#define random rand
|
||||
#endif
|
||||
mac[i] = key[random() % sizeof(key)];
|
||||
#ifdef WIN32
|
||||
#undef random
|
||||
#endif
|
||||
}
|
||||
mac[sizeof(mac) - 1] = '\0';
|
||||
return mac;
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) {
|
||||
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) {
|
||||
/* Populate the multicast group for local edge */
|
||||
eee->multicast_peer.family = AF_INET;
|
||||
eee->multicast_peer.port = N2N_MULTICAST_PORT;
|
||||
|
@ -1755,6 +1590,9 @@ int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) {
|
|||
eee->multicast_peer.addr.v4[2] = 0;
|
||||
eee->multicast_peer.addr.v4[3] = 68;
|
||||
|
||||
if(udp_local_port > 0)
|
||||
traceEvent(TRACE_NORMAL, "Binding to local port %d", udp_local_port);
|
||||
|
||||
eee->udp_sock = open_socket(udp_local_port, 1 /* bind ANY */);
|
||||
if(eee->udp_sock < 0) {
|
||||
traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", udp_local_port);
|
||||
|
@ -1799,28 +1637,73 @@ int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) {
|
|||
|
||||
/* ************************************** */
|
||||
|
||||
void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
|
||||
memset(conf, 0, sizeof(*conf));
|
||||
|
||||
conf->local_port = 0 /* any port */;
|
||||
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
|
||||
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; /* use twofish for compatibility */
|
||||
conf->drop_multicast = 1;
|
||||
|
||||
if(getenv("N2N_KEY"))
|
||||
conf->encrypt_key = strdup(getenv("N2N_KEY"));
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee) {
|
||||
return(&eee->conf);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port) {
|
||||
if(conf->sn_num >= N2N_EDGE_NUM_SUPERNODES)
|
||||
return(-1);
|
||||
|
||||
strncpy((conf->sn_ip_array[conf->sn_num]), ip_and_port, N2N_EDGE_SN_HOST_SIZE);
|
||||
traceEvent(TRACE_NORMAL, "Adding supernode[%u] = %s", (unsigned int)conf->sn_num, (conf->sn_ip_array[conf->sn_num]));
|
||||
conf->sn_num++;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
int quick_edge_init(char *device_name, char *community_name,
|
||||
char *encrypt_key, char *device_mac,
|
||||
char *local_ip_address,
|
||||
char *supernode_ip_address_port,
|
||||
int *keep_on_running) {
|
||||
n2n_edge_t eee;
|
||||
tuntap_dev tuntap;
|
||||
n2n_edge_t *eee;
|
||||
n2n_edge_conf_t conf;
|
||||
int rv;
|
||||
|
||||
edge_init(&eee);
|
||||
/* Setup the configuration */
|
||||
edge_init_conf_defaults(&conf);
|
||||
conf.encrypt_key = encrypt_key;
|
||||
snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name);
|
||||
edge_conf_add_supernode(&conf, supernode_ip_address_port);
|
||||
|
||||
if(tuntap_open(&(eee.device), device_name, "static",
|
||||
local_ip_address, "255.255.255.0",
|
||||
device_mac, DEFAULT_MTU) < 0)
|
||||
/* Validate configuration */
|
||||
if(edge_verify_conf(&conf) != 0)
|
||||
return(-1);
|
||||
|
||||
if(edge_init_encryption(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key) < 0))
|
||||
/* Open the tuntap device */
|
||||
if(tuntap_open(&tuntap, device_name, "static",
|
||||
local_ip_address, "255.255.255.0",
|
||||
device_mac, DEFAULT_MTU) < 0)
|
||||
return(-2);
|
||||
|
||||
snprintf((char*)eee.community_name, sizeof(eee.community_name), "%s", community_name);
|
||||
supernode2addr(&(eee.supernode), supernode_ip_address_port);
|
||||
/* Init edge */
|
||||
if((eee = edge_init(&tuntap, &conf, &rv)) == NULL)
|
||||
goto quick_edge_init_end;
|
||||
|
||||
if(edge_init_sockets(&eee, 0 /* ANY port */, 0 /* ANY port */) < 0)
|
||||
return(-3);
|
||||
rv = run_edge_loop(eee, keep_on_running);
|
||||
edge_term(eee);
|
||||
|
||||
return(run_edge_loop(&eee, keep_on_running));
|
||||
quick_edge_init_end:
|
||||
tuntap_close(&tuntap);
|
||||
return(rv);
|
||||
}
|
||||
|
|
33
legacy/README.md
Normal file
33
legacy/README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Removed Features
|
||||
|
||||
This folder contains a list N2N legacy features which have been dropped due to
|
||||
maintainance cost versus effective use and benefits.
|
||||
|
||||
Multiple Transops
|
||||
-----------------
|
||||
|
||||
N2N used to initialize all the available transops and use the "tick" function of
|
||||
the transops to decide which transop to use before sending a packet. This however
|
||||
has the following problems:
|
||||
|
||||
- It only works with the keyfile, whereas with normal encryption we inizialize and
|
||||
keep structures that we don't need.
|
||||
- It is unfeasable as an edge node is required to implement all the transops in order
|
||||
to properly talk with other edge nodes (via keyfile).
|
||||
- It rises the complexity of the code.
|
||||
- It is not clear which transop will be used.
|
||||
- Mixing multiple encyptions together is not necessarily a good idea to improve security
|
||||
as a vulnerability in at least one encryption method will leak some information.
|
||||
|
||||
Keyfile and Key Rotation
|
||||
------------------------
|
||||
|
||||
The keyfile mechanism allowed N2N users to specify a keyfile to be used to periodically
|
||||
rotate keys and encryption methods. However, it has the following problems:
|
||||
|
||||
- This feature is obscure for most of the users and poorly documented.
|
||||
- It is tightly integrated in the core whereas it is used by only a few people (if any).
|
||||
|
||||
In conclusion the main problem is the complexity that it adds to the code. In a possible
|
||||
future rework this could be integrated as an extention (e.g. a specific trasop) without
|
||||
rising the core complexity.
|
103
legacy/edge_keyschedule.c
Normal file
103
legacy/edge_keyschedule.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
typedef struct n2n_tostat {
|
||||
uint8_t can_tx; /* Does this transop have a valid SA for encoding. */
|
||||
n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */
|
||||
} n2n_tostat_t;
|
||||
|
||||
typedef uint32_t n2n_sa_t; /* security association number */
|
||||
typedef int (*n2n_transaddspec_f)( struct n2n_trans_op * arg,
|
||||
const n2n_cipherspec_t * cspec );
|
||||
|
||||
typedef n2n_tostat_t (*n2n_transtick_f)( struct n2n_trans_op * arg,
|
||||
time_t now );
|
||||
|
||||
/** Read in a key-schedule file, parse the lines and pass each line to the
|
||||
* appropriate trans_op for parsing of key-data and adding key-schedule
|
||||
* entries. The lookup table of time->trans_op is constructed such that
|
||||
* encoding can be passed to the correct trans_op. The trans_op internal table
|
||||
* will then determine the best SA for that trans_op from the key schedule to
|
||||
* use for encoding. */
|
||||
|
||||
static int edge_init_keyschedule(n2n_edge_t *eee) {
|
||||
#define N2N_NUM_CIPHERSPECS 32
|
||||
|
||||
int retval = -1;
|
||||
ssize_t numSpecs=0;
|
||||
n2n_cipherspec_t specs[N2N_NUM_CIPHERSPECS];
|
||||
size_t i;
|
||||
time_t now = time(NULL);
|
||||
|
||||
numSpecs = n2n_read_keyfile(specs, N2N_NUM_CIPHERSPECS, eee->conf.keyschedule);
|
||||
|
||||
if(numSpecs > 0)
|
||||
{
|
||||
traceEvent(TRACE_NORMAL, "keyfile = %s read -> %d specs.\n", optarg, (signed int)numSpecs);
|
||||
|
||||
for (i=0; i < (size_t)numSpecs; ++i)
|
||||
{
|
||||
n2n_transform_t idx = (n2n_transform_t) specs[i].t;
|
||||
if(idx != eee->transop.transform_id) {
|
||||
traceEvent(TRACE_ERROR, "changing transop in keyschedule is not supported");
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
if(eee->transop.addspec != NULL)
|
||||
retval = eee->transop.addspec(&eee->transop, &(specs[i]));
|
||||
|
||||
if (0 != retval)
|
||||
{
|
||||
traceEvent(TRACE_ERROR, "keyschedule failed to add spec[%u] to transop[%d].\n",
|
||||
(unsigned int)i, idx);
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
n2n_tick_transop(eee, now);
|
||||
}
|
||||
else
|
||||
traceEvent(TRACE_ERROR, "Failed to process '%s'", eee->conf.keyschedule);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(recvlen >= 6)
|
||||
{
|
||||
if(0 == memcmp(udp_buf, "reload", 6))
|
||||
{
|
||||
if(strlen(eee->conf.keyschedule) > 0)
|
||||
{
|
||||
if(edge_init_keyschedule(eee) == 0)
|
||||
{
|
||||
msg_len=0;
|
||||
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
|
||||
"> OK\n");
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
|
||||
(struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
case'K':
|
||||
{
|
||||
if(conf->encrypt_key) {
|
||||
traceEvent(TRACE_ERROR, "Error: -K and -k options are mutually exclusive");
|
||||
exit(1);
|
||||
} else {
|
||||
strncpy(conf->keyschedule, optargument, N2N_PATHNAME_MAXLEN-1);
|
||||
/* strncpy does not add NULL if the source has no NULL. */
|
||||
conf->keyschedule[N2N_PATHNAME_MAXLEN-1] = 0;
|
||||
|
||||
traceEvent(TRACE_NORMAL, "keyfile = '%s'\n", conf->keyschedule);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printf("-K <key file> | Specify a key schedule file to load. Not with -k.\n");
|
||||
#endif
|
730
legacy/transform_aes.c
Normal file
730
legacy/transform_aes.c
Normal file
|
@ -0,0 +1,730 @@
|
|||
/**
|
||||
* (C) 2007-18 - ntop.org and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not see see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "n2n_transforms.h"
|
||||
|
||||
#if defined(N2N_HAVE_AES)
|
||||
|
||||
#include "openssl/aes.h"
|
||||
#include "openssl/sha.h"
|
||||
#ifndef _MSC_VER
|
||||
/* Not included in Visual Studio 2008 */
|
||||
#include <strings.h> /* index() */
|
||||
#endif
|
||||
|
||||
#define N2N_AES_NUM_SA 32 /* space for SAa */
|
||||
|
||||
#define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */
|
||||
#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */
|
||||
|
||||
#define AES256_KEY_BYTES (256/8)
|
||||
#define AES192_KEY_BYTES (192/8)
|
||||
#define AES128_KEY_BYTES (128/8)
|
||||
|
||||
typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
|
||||
|
||||
struct sa_aes
|
||||
{
|
||||
n2n_cipherspec_t spec; /* cipher spec parameters */
|
||||
n2n_sa_t sa_id; /* security association index */
|
||||
AES_KEY enc_key; /* tx key */
|
||||
AES_KEY dec_key; /* tx key */
|
||||
AES_KEY iv_enc_key; /* key used to encrypt the IV */
|
||||
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* key used to extend the random IV seed to full block size */
|
||||
};
|
||||
|
||||
typedef struct sa_aes sa_aes_t;
|
||||
|
||||
|
||||
/** Aes transform state data.
|
||||
*
|
||||
* With a key-schedule in place this will be populated with a number of
|
||||
* SAs. Each SA has a lifetime and some opque data. The opaque data for aes
|
||||
* consists of the SA number and key material.
|
||||
*
|
||||
*/
|
||||
struct transop_aes
|
||||
{
|
||||
ssize_t tx_sa;
|
||||
size_t num_sa;
|
||||
sa_aes_t sa[N2N_AES_NUM_SA];
|
||||
u_int8_t psk_mode;
|
||||
};
|
||||
|
||||
typedef struct transop_aes transop_aes_t;
|
||||
|
||||
static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id );
|
||||
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num);
|
||||
|
||||
static int transop_deinit_aes( n2n_trans_op_t * arg )
|
||||
{
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
size_t i;
|
||||
|
||||
if ( priv )
|
||||
{
|
||||
/* Memory was previously allocated */
|
||||
for (i=0; i<N2N_AES_NUM_SA; ++i )
|
||||
{
|
||||
sa_aes_t * sa = &(priv->sa[i]);
|
||||
|
||||
sa->sa_id=0;
|
||||
}
|
||||
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=-1;
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
||||
arg->priv=NULL; /* return to fully uninitialised state */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t aes_choose_tx_sa( transop_aes_t * priv, const u_int8_t * peer_mac ) {
|
||||
return priv->tx_sa; /* set in tick */
|
||||
}
|
||||
|
||||
static ssize_t aes_choose_rx_sa( transop_aes_t * priv, const u_int8_t * peer_mac, ssize_t sa_rx) {
|
||||
if(!priv->psk_mode)
|
||||
return aes_find_sa(priv, sa_rx);
|
||||
else
|
||||
/* NOTE the sa_rx of the packet is ignored in this case */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AES plaintext preamble */
|
||||
#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
|
||||
#define TRANSOP_AES_SA_SIZE 4
|
||||
#define TRANSOP_AES_IV_SEED_SIZE 8
|
||||
#define TRANSOP_AES_PREAMBLE_SIZE (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_IV_SEED_SIZE)
|
||||
|
||||
/* AES ciphertext preamble */
|
||||
#define TRANSOP_AES_NONCE_SIZE 4
|
||||
|
||||
/* Return the best acceptable AES key size (in bytes) given an input keysize.
|
||||
*
|
||||
* The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or
|
||||
* AES256_KEY_BYTES.
|
||||
*/
|
||||
static size_t aes_best_keysize(size_t numBytes)
|
||||
{
|
||||
if (numBytes >= AES256_KEY_BYTES )
|
||||
{
|
||||
return AES256_KEY_BYTES;
|
||||
}
|
||||
else if (numBytes >= AES192_KEY_BYTES)
|
||||
{
|
||||
return AES192_KEY_BYTES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return AES128_KEY_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_aes_cbc_iv(sa_aes_t *sa, n2n_aes_ivec_t ivec, uint64_t iv_seed) {
|
||||
uint8_t iv_full[AES_BLOCK_SIZE];
|
||||
|
||||
/* Extend the seed to full block size via the fixed ext value */
|
||||
memcpy(iv_full, sa->iv_ext_val, sizeof(iv_seed)); // note: only 64bits used of 128 available
|
||||
memcpy(iv_full + sizeof(iv_seed), &iv_seed, sizeof(iv_seed));
|
||||
|
||||
/* Encrypt the IV with secret key to make it unpredictable.
|
||||
* As discussed in https://github.com/ntop/n2n/issues/72, it's important to
|
||||
* have an unpredictable IV since the initial part of the packet plaintext
|
||||
* can be easily reconstructed from plaintext headers and used by an attacker
|
||||
* to perform differential analysis.
|
||||
*/
|
||||
AES_ecb_encrypt(iv_full, ivec, &sa->iv_enc_key, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
/** The aes packet format consists of:
|
||||
*
|
||||
* - a 8-bit aes encoding version in clear text
|
||||
* - a 32-bit SA number in clear text
|
||||
* - a 64-bit random IV seed
|
||||
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
|
||||
*
|
||||
* [V|SSSS|II|nnnnDDDDDDDDDDDDDDDDDDDDD]
|
||||
* |<------ encrypted ------>|
|
||||
*/
|
||||
static int transop_encode_aes( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len,
|
||||
const uint8_t * peer_mac)
|
||||
{
|
||||
int len2=-1;
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
uint8_t assembly[N2N_PKT_BUF_SIZE] = {0};
|
||||
uint32_t * pnonce;
|
||||
|
||||
if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
|
||||
{
|
||||
if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_PREAMBLE_SIZE) <= out_len )
|
||||
{
|
||||
int len=-1;
|
||||
size_t idx=0;
|
||||
sa_aes_t * sa;
|
||||
size_t tx_sa_num = 0;
|
||||
uint64_t iv_seed = 0;
|
||||
uint8_t padding = 0;
|
||||
n2n_aes_ivec_t enc_ivec = {0};
|
||||
|
||||
/* The transmit sa is periodically updated */
|
||||
tx_sa_num = aes_choose_tx_sa( priv, peer_mac );
|
||||
|
||||
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
|
||||
|
||||
traceEvent( TRACE_DEBUG, "encode_aes %lu with SA %lu.", in_len, sa->sa_id );
|
||||
|
||||
/* Encode the aes format version. */
|
||||
encode_uint8( outbuf, &idx, N2N_AES_TRANSFORM_VERSION );
|
||||
|
||||
/* Encode the security association (SA) number */
|
||||
encode_uint32( outbuf, &idx, sa->sa_id );
|
||||
|
||||
/* Generate and encode the IV seed.
|
||||
* Using two calls to rand() because RAND_MAX is usually < 64bit
|
||||
* (e.g. linux) and sometimes < 32bit (e.g. Windows).
|
||||
*/
|
||||
((uint32_t*)&iv_seed)[0] = rand();
|
||||
((uint32_t*)&iv_seed)[1] = rand();
|
||||
encode_buf(outbuf, &idx, &iv_seed, sizeof(iv_seed));
|
||||
|
||||
/* Encrypt the assembly contents and write the ciphertext after the SA. */
|
||||
len = in_len + TRANSOP_AES_NONCE_SIZE;
|
||||
|
||||
/* The assembly buffer is a source for encrypting data. The nonce is
|
||||
* written in first followed by the packet payload. The whole
|
||||
* contents of assembly are encrypted. */
|
||||
pnonce = (uint32_t *)assembly;
|
||||
*pnonce = rand();
|
||||
memcpy( assembly + TRANSOP_AES_NONCE_SIZE, inbuf, in_len );
|
||||
|
||||
/* Need at least one encrypted byte at the end for the padding. */
|
||||
len2 = ( (len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */
|
||||
padding = (len2-len);
|
||||
assembly[len2 - 1] = padding;
|
||||
traceEvent( TRACE_DEBUG, "padding = %u, seed = %016lx", padding, iv_seed );
|
||||
|
||||
set_aes_cbc_iv(sa, enc_ivec, iv_seed);
|
||||
|
||||
AES_cbc_encrypt( assembly, /* source */
|
||||
outbuf + TRANSOP_AES_PREAMBLE_SIZE, /* dest */
|
||||
len2, /* enc size */
|
||||
&(sa->enc_key), enc_ivec, AES_ENCRYPT );
|
||||
|
||||
len2 += TRANSOP_AES_PREAMBLE_SIZE; /* size of data carried in UDP. */
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "encode_aes outbuf too small." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "encode_aes inbuf too big to encrypt." );
|
||||
}
|
||||
|
||||
return len2;
|
||||
}
|
||||
|
||||
|
||||
/* Search through the array of SAs to find the one with the required ID.
|
||||
*
|
||||
* @return array index where found or -1 if not found
|
||||
*/
|
||||
static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id )
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < priv->num_sa; ++i)
|
||||
{
|
||||
const sa_aes_t * sa=NULL;
|
||||
|
||||
sa = &(priv->sa[i]);
|
||||
if (req_id == sa->sa_id)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* See transop_encode_aes for packet format */
|
||||
static int transop_decode_aes( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len,
|
||||
const uint8_t * peer_mac)
|
||||
{
|
||||
int len=0;
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
uint8_t assembly[N2N_PKT_BUF_SIZE];
|
||||
|
||||
if ( ( (in_len - TRANSOP_AES_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
|
||||
&& (in_len >= (TRANSOP_AES_PREAMBLE_SIZE + TRANSOP_AES_NONCE_SIZE) ) /* Has at least version, SA, iv seed and nonce */
|
||||
)
|
||||
{
|
||||
n2n_sa_t sa_rx;
|
||||
ssize_t sa_idx=-1;
|
||||
size_t rem=in_len;
|
||||
size_t idx=0;
|
||||
uint8_t aes_enc_ver=0;
|
||||
uint64_t iv_seed=0;
|
||||
|
||||
/* Get the encoding version to make sure it is supported */
|
||||
decode_uint8( &aes_enc_ver, inbuf, &rem, &idx );
|
||||
|
||||
if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver )
|
||||
{
|
||||
/* Get the SA number and make sure we are decrypting with the right one. */
|
||||
decode_uint32( &sa_rx, inbuf, &rem, &idx );
|
||||
|
||||
sa_idx = aes_choose_rx_sa(priv, peer_mac, sa_rx);
|
||||
|
||||
if ( sa_idx >= 0 )
|
||||
{
|
||||
sa_aes_t * sa = &(priv->sa[sa_idx]);
|
||||
|
||||
/* Get the IV seed */
|
||||
decode_buf((uint8_t *)&iv_seed, sizeof(iv_seed), inbuf, &rem, &idx);
|
||||
|
||||
traceEvent( TRACE_DEBUG, "decode_aes %lu with SA %lu and seed %016lx", in_len, sa->sa_id, iv_seed );
|
||||
|
||||
len = (in_len - TRANSOP_AES_PREAMBLE_SIZE);
|
||||
|
||||
if ( 0 == (len % AES_BLOCK_SIZE ) )
|
||||
{
|
||||
uint8_t padding;
|
||||
n2n_aes_ivec_t dec_ivec = {0};
|
||||
|
||||
set_aes_cbc_iv(sa, dec_ivec, iv_seed);
|
||||
|
||||
AES_cbc_encrypt( (inbuf + TRANSOP_AES_PREAMBLE_SIZE),
|
||||
assembly, /* destination */
|
||||
len,
|
||||
&(sa->dec_key),
|
||||
dec_ivec, AES_DECRYPT );
|
||||
|
||||
/* last byte is how much was padding: max value should be
|
||||
* AES_BLOCKSIZE-1 */
|
||||
padding = assembly[ len-1 ] & 0xff;
|
||||
|
||||
if ( len >= (padding + TRANSOP_AES_NONCE_SIZE))
|
||||
{
|
||||
/* strictly speaking for this to be an ethernet packet
|
||||
* it is going to need to be even bigger; but this is
|
||||
* enough to prevent segfaults. */
|
||||
traceEvent( TRACE_DEBUG, "padding = %u", padding );
|
||||
len -= padding;
|
||||
|
||||
len -= TRANSOP_AES_NONCE_SIZE; /* size of ethernet packet */
|
||||
|
||||
/* Step over 4-byte random nonce value */
|
||||
memcpy( outbuf,
|
||||
assembly + TRANSOP_AES_NONCE_SIZE,
|
||||
len );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_WARNING, "UDP payload decryption failed." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE );
|
||||
len = 0;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
traceEvent( TRACE_ERROR, "decode_aes SA number %lu not found.", sa_rx );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
traceEvent( TRACE_ERROR, "decode_aes unsupported aes version %u.", aes_enc_ver );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "decode_aes inbuf wrong size (%ul) to decrypt.", in_len );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct sha512_keybuf {
|
||||
uint8_t enc_dec_key[AES256_KEY_BYTES]; /* The key to use for AES CBC encryption/decryption */
|
||||
uint8_t iv_enc_key[AES128_KEY_BYTES]; /* The key to use to encrypt the IV with AES ECB */
|
||||
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* A value to extend the IV seed */
|
||||
}; /* size: SHA512_DIGEST_LENGTH */
|
||||
|
||||
/* NOTE: the caller should adjust priv->num_sa accordingly */
|
||||
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num) {
|
||||
sa_aes_t * sa = &(priv->sa[sa_num]);
|
||||
size_t aes_keysize_bytes;
|
||||
size_t aes_keysize_bits;
|
||||
struct sha512_keybuf keybuf;
|
||||
|
||||
/* Clear out any old possibly longer key matter. */
|
||||
memset( &(sa->enc_key), 0, sizeof(sa->enc_key) );
|
||||
memset( &(sa->dec_key), 0, sizeof(sa->dec_key) );
|
||||
memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) );
|
||||
memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) );
|
||||
|
||||
/* We still use aes_best_keysize (even not necessary since we hash the key
|
||||
* into the 256bits enc_dec_key) to let the users choose the degree of encryption.
|
||||
* Long keys will pick AES192 or AES256 with more robust but expensive encryption.
|
||||
*/
|
||||
aes_keysize_bytes = aes_best_keysize(key_size);
|
||||
aes_keysize_bits = 8 * aes_keysize_bytes;
|
||||
|
||||
/* Hash the main key to generate subkeys */
|
||||
SHA512(key, key_size, (u_char*)&keybuf);
|
||||
|
||||
/* setup of enc_key/dec_key, used for the CBC encryption */
|
||||
AES_set_encrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->enc_key));
|
||||
AES_set_decrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->dec_key));
|
||||
|
||||
/* setup of iv_enc_key and iv_ext_val, used for generating the CBC IV */
|
||||
AES_set_encrypt_key(keybuf.iv_enc_key, sizeof(keybuf.iv_enc_key) * 8, &(sa->iv_enc_key));
|
||||
memcpy(sa->iv_ext_val, keybuf.iv_ext_val, sizeof(keybuf.iv_ext_val));
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits key=%s.\n",
|
||||
priv->sa[sa_num].sa_id, aes_keysize_bits, key);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* priv: pointer to transform state
|
||||
* keybuf: buffer holding the key
|
||||
* pstat: length of keybuf
|
||||
*/
|
||||
static void add_aes_key(transop_aes_t *priv, uint8_t *keybuf, ssize_t pstat) {
|
||||
setup_aes_key(priv, keybuf, pstat, priv->num_sa);
|
||||
++(priv->num_sa);
|
||||
}
|
||||
|
||||
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
int retval = 1;
|
||||
ssize_t pstat=-1;
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
uint8_t keybuf[N2N_MAX_KEYSIZE];
|
||||
|
||||
if ( priv->num_sa < N2N_AES_NUM_SA )
|
||||
{
|
||||
const char * op = (const char *)cspec->opaque;
|
||||
const char * sep = index( op, '_' );
|
||||
|
||||
if ( sep )
|
||||
{
|
||||
char tmp[256];
|
||||
size_t s;
|
||||
|
||||
s = sep - op;
|
||||
memcpy( tmp, cspec->opaque, s );
|
||||
tmp[s]=0;
|
||||
|
||||
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
|
||||
|
||||
priv->sa[priv->num_sa].spec = *cspec;
|
||||
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
|
||||
|
||||
memset( keybuf, 0, N2N_MAX_KEYSIZE );
|
||||
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
|
||||
if ( pstat > 0 )
|
||||
{
|
||||
add_aes_key(priv, keybuf, pstat);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_aes : bad key data - missing '_'.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_aes : full.\n");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
|
||||
{
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
size_t i;
|
||||
int found=0;
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset( &r, 0, sizeof(r) );
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_aes tick num_sa=%u now=%lu", priv->num_sa, now );
|
||||
|
||||
for ( i=0; i < priv->num_sa; ++i )
|
||||
{
|
||||
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
|
||||
{
|
||||
time_t remaining = priv->sa[i].spec.valid_until - now;
|
||||
|
||||
traceEvent( TRACE_INFO, "transop_aes choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
|
||||
priv->tx_sa=i;
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_DEBUG, "transop_aes tick rejecting sa=%u %lu -> %lu",
|
||||
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0==found)
|
||||
{
|
||||
traceEvent( TRACE_INFO, "transop_aes no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.can_tx = 1;
|
||||
r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
|
||||
r.tx_spec = priv->sa[priv->tx_sa].spec;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static n2n_tostat_t transop_tick_aes_psk(n2n_trans_op_t * arg, time_t now) {
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
|
||||
// Always tx
|
||||
r.can_tx = 1;
|
||||
r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
|
||||
r.tx_spec = priv->sa[priv->tx_sa].spec;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int transop_aes_init( n2n_trans_op_t * ttt )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_aes_t * priv = NULL;
|
||||
|
||||
if ( ttt->priv )
|
||||
{
|
||||
transop_deinit_aes( ttt );
|
||||
}
|
||||
|
||||
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
|
||||
|
||||
priv = (transop_aes_t *) calloc(1, sizeof(transop_aes_t));
|
||||
|
||||
if ( NULL != priv )
|
||||
{
|
||||
size_t i;
|
||||
sa_aes_t * sa=NULL;
|
||||
|
||||
/* install the private structure. */
|
||||
ttt->priv = priv;
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=0; /* We will use this sa index for encoding. */
|
||||
priv->psk_mode = 0;
|
||||
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
|
||||
ttt->addspec = transop_addspec_aes;
|
||||
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
|
||||
ttt->deinit = transop_deinit_aes;
|
||||
ttt->fwd = transop_encode_aes;
|
||||
ttt->rev = transop_decode_aes;
|
||||
|
||||
for(i=0; i<N2N_AES_NUM_SA; ++i)
|
||||
{
|
||||
sa = &(priv->sa[i]);
|
||||
sa->sa_id=0;
|
||||
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
|
||||
memset( &(sa->enc_key), 0, sizeof(sa->enc_key) );
|
||||
memset( &(sa->dec_key), 0, sizeof(sa->dec_key) );
|
||||
memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) );
|
||||
memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) );
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Setup AES in pre-shared key mode */
|
||||
int transop_aes_setup_psk(n2n_trans_op_t *ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len) {
|
||||
int retval = 1;
|
||||
transop_aes_t *priv = (transop_aes_t *)ttt->priv;
|
||||
|
||||
if(ttt->priv) {
|
||||
/* Replace the tick function with the PSK version of it */
|
||||
ttt->tick = transop_tick_aes_psk;
|
||||
priv->psk_mode = 1;
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=0;
|
||||
|
||||
/* Setup the key to use for encryption/decryption */
|
||||
add_aes_key(priv, encrypt_pwd, encrypt_pwd_len);
|
||||
|
||||
retval = 0;
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "AES priv is not allocated");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#else /* #if defined(N2N_HAVE_AES) */
|
||||
|
||||
struct transop_aes
|
||||
{
|
||||
ssize_t tx_sa;
|
||||
};
|
||||
|
||||
typedef struct transop_aes transop_aes_t;
|
||||
|
||||
|
||||
static int transop_deinit_aes( n2n_trans_op_t * arg )
|
||||
{
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
|
||||
if ( priv )
|
||||
{
|
||||
free(priv);
|
||||
}
|
||||
|
||||
arg->priv=NULL; /* return to fully uninitialised state */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transop_encode_aes( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int transop_decode_aes( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_aes AES not built into edge.\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
|
||||
{
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset( &r, 0, sizeof(r) );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int transop_aes_init( n2n_trans_op_t * ttt )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_aes_t * priv = NULL;
|
||||
|
||||
if ( ttt->priv )
|
||||
{
|
||||
transop_deinit_aes( ttt );
|
||||
}
|
||||
|
||||
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
|
||||
|
||||
priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) );
|
||||
|
||||
if ( NULL != priv )
|
||||
{
|
||||
/* install the private structure. */
|
||||
ttt->priv = priv;
|
||||
priv->tx_sa=0; /* We will use this sa index for encoding. */
|
||||
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
|
||||
ttt->addspec = transop_addspec_aes;
|
||||
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
|
||||
ttt->deinit = transop_deinit_aes;
|
||||
ttt->fwd = transop_encode_aes;
|
||||
ttt->rev = transop_decode_aes;
|
||||
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int transop_aes_setup_psk(n2n_trans_op_t *ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if defined(N2N_HAVE_AES) */
|
||||
|
467
legacy/transform_tf.c
Normal file
467
legacy/transform_tf.c
Normal file
|
@ -0,0 +1,467 @@
|
|||
/**
|
||||
* (C) 2007-18 - ntop.org and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not see see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "n2n_transforms.h"
|
||||
#include "twofish.h"
|
||||
#ifndef _MSC_VER
|
||||
/* Not included in Visual Studio 2008 */
|
||||
#include <strings.h> /* index() */
|
||||
#endif
|
||||
|
||||
#define N2N_TWOFISH_NUM_SA 32 /* space for SAa */
|
||||
|
||||
#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding */
|
||||
|
||||
struct sa_twofish
|
||||
{
|
||||
n2n_cipherspec_t spec; /* cipher spec parameters */
|
||||
n2n_sa_t sa_id; /* security association index */
|
||||
TWOFISH * enc_tf; /* tx state */
|
||||
TWOFISH * dec_tf; /* rx state */
|
||||
};
|
||||
|
||||
typedef struct sa_twofish sa_twofish_t;
|
||||
|
||||
|
||||
/** Twofish transform state data.
|
||||
*
|
||||
* With a key-schedule in place this will be populated with a number of
|
||||
* SAs. Each SA has a lifetime and some opque data. The opaque data for twofish
|
||||
* consists of the SA number and key material.
|
||||
*
|
||||
*/
|
||||
struct transop_tf
|
||||
{
|
||||
ssize_t tx_sa;
|
||||
size_t num_sa;
|
||||
sa_twofish_t sa[N2N_TWOFISH_NUM_SA];
|
||||
};
|
||||
|
||||
typedef struct transop_tf transop_tf_t;
|
||||
|
||||
static int transop_deinit_twofish( n2n_trans_op_t * arg )
|
||||
{
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
size_t i;
|
||||
|
||||
if ( priv )
|
||||
{
|
||||
/* Memory was previously allocated */
|
||||
for (i=0; i<N2N_TWOFISH_NUM_SA; ++i )
|
||||
{
|
||||
sa_twofish_t * sa = &(priv->sa[i]);
|
||||
|
||||
TwoFishDestroy(sa->enc_tf); /* deallocate TWOFISH */
|
||||
sa->enc_tf=NULL;
|
||||
|
||||
TwoFishDestroy(sa->dec_tf); /* deallocate TWOFISH */
|
||||
sa->dec_tf=NULL;
|
||||
|
||||
sa->sa_id=0;
|
||||
}
|
||||
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=-1;
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
||||
arg->priv=NULL; /* return to fully uninitialised state */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t tf_choose_tx_sa( transop_tf_t * priv )
|
||||
{
|
||||
return priv->tx_sa; /* set in tick */
|
||||
}
|
||||
|
||||
#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in one module. */
|
||||
#define TRANSOP_TF_NONCE_SIZE 4
|
||||
#define TRANSOP_TF_SA_SIZE 4
|
||||
|
||||
/** The twofish packet format consists of:
|
||||
*
|
||||
* - a 8-bit twofish encoding version in clear text
|
||||
* - a 32-bit SA number in clear text
|
||||
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
|
||||
*
|
||||
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
|
||||
* |<------ encrypted ------>|
|
||||
*/
|
||||
static int transop_encode_twofish( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len,
|
||||
const uint8_t * peer_mac)
|
||||
{
|
||||
int len=-1;
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
uint8_t assembly[N2N_PKT_BUF_SIZE];
|
||||
uint32_t * pnonce;
|
||||
|
||||
if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
|
||||
{
|
||||
if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len )
|
||||
{
|
||||
size_t idx=0;
|
||||
sa_twofish_t * sa;
|
||||
size_t tx_sa_num = 0;
|
||||
|
||||
/* The transmit sa is periodically updated */
|
||||
tx_sa_num = tf_choose_tx_sa( priv );
|
||||
|
||||
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
|
||||
|
||||
traceEvent( TRACE_DEBUG, "encode_twofish %lu with SA %lu.", in_len, sa->sa_id );
|
||||
|
||||
/* Encode the twofish format version. */
|
||||
encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION );
|
||||
|
||||
/* Encode the security association (SA) number */
|
||||
encode_uint32( outbuf, &idx, sa->sa_id );
|
||||
|
||||
/* The assembly buffer is a source for encrypting data. The nonce is
|
||||
* written in first followed by the packet payload. The whole
|
||||
* contents of assembly are encrypted. */
|
||||
pnonce = (uint32_t *)assembly;
|
||||
*pnonce = rand();
|
||||
memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len );
|
||||
|
||||
/* Encrypt the assembly contents and write the ciphertext after the SA. */
|
||||
len = TwoFishEncryptRaw( assembly, /* source */
|
||||
outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE,
|
||||
in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */
|
||||
sa->enc_tf);
|
||||
if ( len > 0 )
|
||||
{
|
||||
len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "encode_twofish encryption failed." );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Search through the array of SAs to find the one with the required ID.
|
||||
*
|
||||
* @return array index where found or -1 if not found
|
||||
*/
|
||||
static ssize_t twofish_find_sa( const transop_tf_t * priv, const n2n_sa_t req_id )
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < priv->num_sa; ++i)
|
||||
{
|
||||
const sa_twofish_t * sa=NULL;
|
||||
|
||||
sa = &(priv->sa[i]);
|
||||
if (req_id == sa->sa_id)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/** The twofish packet format consists of:
|
||||
*
|
||||
* - a 8-bit twofish encoding version in clear text
|
||||
* - a 32-bit SA number in clear text
|
||||
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
|
||||
*
|
||||
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
|
||||
* |<------ encrypted ------>|
|
||||
*/
|
||||
static int transop_decode_twofish( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len,
|
||||
const uint8_t * peer_mac)
|
||||
{
|
||||
int len=0;
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
uint8_t assembly[N2N_PKT_BUF_SIZE];
|
||||
|
||||
if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
|
||||
&& (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */
|
||||
)
|
||||
{
|
||||
n2n_sa_t sa_rx;
|
||||
ssize_t sa_idx=-1;
|
||||
size_t rem=in_len;
|
||||
size_t idx=0;
|
||||
uint8_t tf_enc_ver=0;
|
||||
|
||||
/* Get the encoding version to make sure it is supported */
|
||||
decode_uint8( &tf_enc_ver, inbuf, &rem, &idx );
|
||||
|
||||
if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver )
|
||||
{
|
||||
/* Get the SA number and make sure we are decrypting with the right one. */
|
||||
decode_uint32( &sa_rx, inbuf, &rem, &idx );
|
||||
|
||||
sa_idx = twofish_find_sa(priv, sa_rx);
|
||||
if ( sa_idx >= 0 )
|
||||
{
|
||||
sa_twofish_t * sa = &(priv->sa[sa_idx]);
|
||||
|
||||
traceEvent( TRACE_DEBUG, "decode_twofish %lu with SA %lu.", in_len, sa_rx, sa->sa_id );
|
||||
|
||||
len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE),
|
||||
assembly, /* destination */
|
||||
(in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)),
|
||||
sa->dec_tf);
|
||||
|
||||
if ( len > 0 )
|
||||
{
|
||||
/* Step over 4-byte random nonce value */
|
||||
len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */
|
||||
|
||||
memcpy( outbuf,
|
||||
assembly + TRANSOP_TF_NONCE_SIZE,
|
||||
len );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "decode_twofish decryption failed." );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
traceEvent( TRACE_ERROR, "decode_twofish SA number %lu not found.", sa_rx );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int transop_addspec_twofish( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
int retval = 1;
|
||||
ssize_t pstat=-1;
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
uint8_t keybuf[N2N_MAX_KEYSIZE];
|
||||
|
||||
if ( priv->num_sa < N2N_TWOFISH_NUM_SA )
|
||||
{
|
||||
const char * op = (const char *)cspec->opaque;
|
||||
#ifdef __ANDROID_NDK__
|
||||
const char *sep = strchr(op, '_');
|
||||
#else
|
||||
const char * sep = index( op, '_' );
|
||||
#endif // __ANDROID_NDK__
|
||||
|
||||
if ( sep )
|
||||
{
|
||||
char tmp[256];
|
||||
size_t s;
|
||||
|
||||
s = sep - op;
|
||||
memcpy( tmp, cspec->opaque, s );
|
||||
tmp[s]=0;
|
||||
|
||||
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
|
||||
|
||||
priv->sa[priv->num_sa].spec = *cspec;
|
||||
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
|
||||
|
||||
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
|
||||
if ( pstat > 0 )
|
||||
{
|
||||
priv->sa[priv->num_sa].enc_tf = TwoFishInit( keybuf, pstat);
|
||||
priv->sa[priv->num_sa].dec_tf = TwoFishInit( keybuf, pstat);
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_twofish sa_id=%u data=%s.\n",
|
||||
priv->sa[priv->num_sa].sa_id, sep+1);
|
||||
|
||||
++(priv->num_sa);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_twofish : bad key data - missing '_'.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_twofish : full.\n");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now )
|
||||
{
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
size_t i;
|
||||
int found=0;
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset( &r, 0, sizeof(r) );
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_tf tick num_sa=%u", priv->num_sa );
|
||||
|
||||
for ( i=0; i < priv->num_sa; ++i )
|
||||
{
|
||||
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
|
||||
{
|
||||
time_t remaining = priv->sa[i].spec.valid_until - now;
|
||||
|
||||
traceEvent( TRACE_INFO, "transop_tf choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
|
||||
priv->tx_sa=i;
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_DEBUG, "transop_tf tick rejecting sa=%u %lu -> %lu",
|
||||
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0==found)
|
||||
{
|
||||
traceEvent( TRACE_INFO, "transop_tf no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.can_tx = 1;
|
||||
r.tx_spec.t = N2N_TRANSFORM_ID_TWOFISH;
|
||||
r.tx_spec = priv->sa[priv->tx_sa].spec;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int transop_twofish_setup_psk( n2n_trans_op_t * ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t * encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_tf_t * priv = (transop_tf_t *)ttt->priv;
|
||||
|
||||
if(priv) {
|
||||
sa_twofish_t *sa;
|
||||
|
||||
priv->num_sa=1; /* There is one SA in the array. */
|
||||
priv->tx_sa=0;
|
||||
sa = &(priv->sa[priv->tx_sa]);
|
||||
sa->sa_id=sa_num;
|
||||
sa->spec.valid_until = 0x7fffffff;
|
||||
|
||||
/* This is a preshared key setup. Both Tx and Rx are using the same security association. */
|
||||
|
||||
sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
|
||||
sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
|
||||
|
||||
if ( (sa->enc_tf) && (sa->dec_tf) )
|
||||
retval = 0;
|
||||
else
|
||||
traceEvent( TRACE_ERROR, "transop_twofish_setup_psk" );
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "twofish priv is not allocated" );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int transop_twofish_init( n2n_trans_op_t * ttt )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_tf_t * priv = NULL;
|
||||
|
||||
if ( ttt->priv )
|
||||
{
|
||||
transop_deinit_twofish( ttt );
|
||||
}
|
||||
|
||||
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
|
||||
|
||||
priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
|
||||
|
||||
if ( NULL != priv ) {
|
||||
size_t i;
|
||||
sa_twofish_t * sa=NULL;
|
||||
|
||||
/* install the private structure. */
|
||||
ttt->priv = priv;
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=0; /* We will use this sa index for encoding. */
|
||||
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
|
||||
ttt->addspec = transop_addspec_twofish;
|
||||
ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
|
||||
ttt->deinit = transop_deinit_twofish;
|
||||
ttt->fwd = transop_encode_twofish;
|
||||
ttt->rev = transop_decode_twofish;
|
||||
|
||||
for(i=0; i<N2N_TWOFISH_NUM_SA; ++i)
|
||||
{
|
||||
sa = &(priv->sa[i]);
|
||||
sa->sa_id=0;
|
||||
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
|
||||
sa->enc_tf=NULL;
|
||||
sa->dec_tf=NULL;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
} else {
|
||||
memset( ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
4
n2n.c
4
n2n.c
|
@ -87,8 +87,8 @@ void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) {
|
|||
va_list va_ap;
|
||||
|
||||
if(eventTraceLevel <= traceLevel) {
|
||||
char buf[2048];
|
||||
char out_buf[640];
|
||||
char buf[1024];
|
||||
char out_buf[1280];
|
||||
char theDate[N2N_TRACE_DATESIZE];
|
||||
char *extra_msg = "";
|
||||
time_t theTime = time(NULL);
|
||||
|
|
89
n2n.h
89
n2n.h
|
@ -174,64 +174,30 @@ struct peer_info {
|
|||
time_t last_seen;
|
||||
};
|
||||
|
||||
struct n2n_edge; /* defined in edge.c */
|
||||
typedef struct n2n_edge n2n_edge_t;
|
||||
|
||||
#define N2N_EDGE_SN_HOST_SIZE 48
|
||||
#define N2N_EDGE_NUM_SUPERNODES 2
|
||||
#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */
|
||||
#define N2N_PATHNAME_MAXLEN 256
|
||||
#define N2N_MAX_TRANSFORMS 16
|
||||
#define N2N_EDGE_MGMT_PORT 5644
|
||||
|
||||
|
||||
typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
|
||||
|
||||
struct n2n_edge {
|
||||
int daemon; /**< Non-zero if edge should detach and run in the background. */
|
||||
int preferred_aes; /**< Non-zero if AES is the preferred encryption meothd. */
|
||||
uint8_t re_resolve_supernode_ip;
|
||||
|
||||
n2n_sock_t supernode;
|
||||
|
||||
size_t sn_idx; /**< Currently active supernode. */
|
||||
size_t sn_num; /**< Number of supernode addresses defined. */
|
||||
typedef struct n2n_edge_conf {
|
||||
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
|
||||
int sn_wait; /**< Whether we are waiting for a supernode response. */
|
||||
|
||||
n2n_community_t community_name; /**< The community. 16 full octets. */
|
||||
char keyschedule[N2N_PATHNAME_MAXLEN];
|
||||
int null_transop; /**< Only allowed if no key sources defined. */
|
||||
n2n_transform_t transop_id; /**< The transop to use. */
|
||||
uint8_t re_resolve_supernode_ip;
|
||||
uint8_t dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
|
||||
uint8_t allow_routing; /**< Accept packet no to interface address. */
|
||||
uint8_t drop_multicast; /**< Multicast ethernet addresses. */
|
||||
uint8_t sn_num; /**< Number of supernode addresses defined. */
|
||||
char *encrypt_key;
|
||||
int local_port;
|
||||
int mgmt_port;
|
||||
} n2n_edge_conf_t;
|
||||
|
||||
int udp_sock;
|
||||
int udp_mgmt_sock; /**< socket for status info. */
|
||||
int udp_multicast_sock; /**< socket for local multicast registrations. */
|
||||
|
||||
tuntap_dev device; /**< All about the TUNTAP device */
|
||||
int dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
|
||||
int allow_routing; /**< Accept packet no to interface address. */
|
||||
int drop_multicast; /**< Multicast ethernet addresses. */
|
||||
|
||||
n2n_trans_op_t transop[N2N_MAX_TRANSFORMS]; /* one for each transform at fixed positions */
|
||||
size_t tx_transop_idx; /**< The transop to use when encoding. */
|
||||
n2n_sock_t multicast_peer; /**< Multicast peer group (for local edges) */
|
||||
struct peer_info * known_peers; /**< Edges we are connected to. */
|
||||
struct peer_info * pending_peers; /**< Edges we have tried to register with. */
|
||||
time_t last_register_req; /**< Check if time to re-register with super*/
|
||||
size_t register_lifetime; /**< Time distance after last_register_req at which to re-register. */
|
||||
time_t last_p2p; /**< Last time p2p traffic was received. */
|
||||
time_t last_sup; /**< Last time a packet arrived from supernode. */
|
||||
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
|
||||
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
|
||||
|
||||
time_t start_time; /**< For calculating uptime */
|
||||
|
||||
/* Statistics */
|
||||
size_t tx_p2p;
|
||||
size_t rx_p2p;
|
||||
size_t tx_sup;
|
||||
size_t rx_sup;
|
||||
};
|
||||
typedef struct n2n_edge n2n_edge_t; /* Opaque, see edge_utils.c */
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
|
@ -263,6 +229,13 @@ struct n2n_edge {
|
|||
|
||||
/* ************************************** */
|
||||
|
||||
/* Transop Init Functions */
|
||||
int n2n_transop_null_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
|
||||
int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
|
||||
#ifdef N2N_HAVE_AES
|
||||
int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
|
||||
#endif
|
||||
|
||||
/* Log */
|
||||
void setTraceLevel(int level);
|
||||
void setUseSyslog(int use_syslog);
|
||||
|
@ -285,9 +258,7 @@ uint8_t is_multi_broadcast(const uint8_t * dest_mac);
|
|||
char* msg_type2str(uint16_t msg_type);
|
||||
void hexdump(const uint8_t * buf, size_t len);
|
||||
void print_n2n_version();
|
||||
void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn);
|
||||
int is_empty_ip_address(const n2n_sock_t * sock);
|
||||
const char *random_device_mac(void);
|
||||
|
||||
/* Sockets */
|
||||
char* sock_to_cstr( n2n_sock_str_t out,
|
||||
|
@ -312,21 +283,21 @@ void update_peer_address(n2n_edge_t * eee,
|
|||
const n2n_sock_t * peer,
|
||||
time_t when);
|
||||
|
||||
/* Edge conf */
|
||||
void edge_init_conf_defaults(n2n_edge_conf_t *conf);
|
||||
int edge_verify_conf(const n2n_edge_conf_t *conf);
|
||||
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port);
|
||||
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee);
|
||||
|
||||
/* Public functions */
|
||||
int edge_init_keyschedule(n2n_edge_t * eee);
|
||||
void send_packet2net(n2n_edge_t * eee,
|
||||
uint8_t *tap_pkt, size_t len);
|
||||
int edge_init_encryption(n2n_edge_t * eee, uint8_t *encrypt_pwd, uint32_t encrypt_pwd_len);
|
||||
int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port);
|
||||
|
||||
int edge_init(n2n_edge_t * eee);
|
||||
void edge_term(n2n_edge_t * eee);
|
||||
int run_edge_loop(n2n_edge_t * eee, int *keep_running);
|
||||
|
||||
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv);
|
||||
void edge_term(n2n_edge_t *eee);
|
||||
int run_edge_loop(n2n_edge_t *eee, int *keep_running);
|
||||
int quick_edge_init(char *device_name, char *community_name,
|
||||
char *encrypt_key, char *device_mac,
|
||||
char *local_ip_address,
|
||||
char *supernode_ip_address_port,
|
||||
int *keep_on_running);
|
||||
|
||||
|
||||
void send_packet2net(n2n_edge_t * eee, uint8_t *tap_pkt, size_t len);
|
||||
#endif /* _N2N_H_ */
|
||||
|
|
|
@ -19,39 +19,23 @@
|
|||
#if !defined(N2N_TRANSFORMS_H_)
|
||||
#define N2N_TRANSFORMS_H_
|
||||
|
||||
#include "n2n_keyfile.h"
|
||||
#include "n2n_wire.h"
|
||||
|
||||
|
||||
#define N2N_TRANSFORM_ID_INVAL 0 /* marks uninitialised data */
|
||||
#define N2N_TRANSFORM_ID_NULL 1
|
||||
#define N2N_TRANSFORM_ID_TWOFISH 2
|
||||
#define N2N_TRANSFORM_ID_AESCBC 3
|
||||
#define N2N_TRANSFORM_ID_LZO 4
|
||||
#define N2N_TRANSFORM_ID_TWOFISH_LZO 5
|
||||
#define N2N_TRANSFORM_ID_AESCBC_LZO 6
|
||||
#define N2N_TRANSFORM_ID_USER_START 64
|
||||
#define N2N_TRANSFORM_ID_MAX 65535
|
||||
|
||||
typedef enum n2n_transform {
|
||||
N2N_TRANSFORM_ID_INVAL = 0,
|
||||
N2N_TRANSFORM_ID_NULL = 1,
|
||||
N2N_TRANSFORM_ID_TWOFISH = 2,
|
||||
N2N_TRANSFORM_ID_AESCBC = 3,
|
||||
} n2n_transform_t;
|
||||
|
||||
struct n2n_trans_op;
|
||||
typedef struct n2n_trans_op n2n_trans_op_t;
|
||||
|
||||
struct n2n_tostat {
|
||||
uint8_t can_tx; /* Does this transop have a valid SA for encoding. */
|
||||
n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */
|
||||
};
|
||||
|
||||
typedef struct n2n_tostat n2n_tostat_t;
|
||||
|
||||
|
||||
typedef int (*n2n_transdeinit_f)( n2n_trans_op_t * arg );
|
||||
typedef int (*n2n_transaddspec_f)( n2n_trans_op_t * arg,
|
||||
const n2n_cipherspec_t * cspec );
|
||||
typedef n2n_tostat_t (*n2n_transtick_f)( n2n_trans_op_t * arg,
|
||||
time_t now );
|
||||
|
||||
typedef int (*n2n_transform_f)( n2n_trans_op_t * arg,
|
||||
typedef int (*n2n_transdeinit_f)( struct n2n_trans_op * arg );
|
||||
typedef void (*n2n_transtick_f)( struct n2n_trans_op * arg, time_t now );
|
||||
typedef int (*n2n_transform_f)( struct n2n_trans_op * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
|
@ -64,35 +48,18 @@ typedef int (*n2n_transform_f)( n2n_trans_op_t * arg,
|
|||
* to use to decode the packet content. The transform code then decodes the
|
||||
* packet and consults its internal key lookup.
|
||||
*/
|
||||
struct n2n_trans_op {
|
||||
typedef struct n2n_trans_op {
|
||||
void * priv; /* opaque data. Key schedule goes here. */
|
||||
|
||||
n2n_transform_t transform_id; /* link header enum to a transform */
|
||||
uint8_t no_encryption; /* 1 if this transop does not perform encryption */
|
||||
n2n_transform_t transform_id;
|
||||
size_t tx_cnt;
|
||||
size_t rx_cnt;
|
||||
|
||||
n2n_transdeinit_f deinit; /* destructor function */
|
||||
n2n_transaddspec_f addspec; /* parse opaque data from a key schedule file. */
|
||||
n2n_transtick_f tick; /* periodic maintenance */
|
||||
n2n_transtick_f tick; /* periodic maintenance */
|
||||
n2n_transform_f fwd; /* encode a payload */
|
||||
n2n_transform_f rev; /* decode a payload */
|
||||
};
|
||||
|
||||
/* Setup a single twofish SA for single-key operation. */
|
||||
int transop_twofish_setup_psk( n2n_trans_op_t * ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t * encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len );
|
||||
/* Setup a single AES SA for single-key operation. */
|
||||
int transop_aes_setup_psk( n2n_trans_op_t * ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t * encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len );
|
||||
|
||||
/* Initialise an empty transop ready to receive cipherspec elements. */
|
||||
int transop_twofish_init( n2n_trans_op_t * ttt );
|
||||
int transop_aes_init( n2n_trans_op_t * ttt );
|
||||
void transop_null_init( n2n_trans_op_t * ttt );
|
||||
} n2n_trans_op_t;
|
||||
|
||||
#endif /* #if !defined(N2N_TRANSFORMS_H_) */
|
||||
|
||||
|
|
17
n2n_wire.h
17
n2n_wire.h
|
@ -51,7 +51,7 @@ typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE];
|
|||
|
||||
typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */
|
||||
|
||||
enum n2n_pc
|
||||
typedef enum n2n_pc
|
||||
{
|
||||
n2n_ping=0, /* Not used */
|
||||
n2n_register=1, /* Register edge to edge */
|
||||
|
@ -62,9 +62,7 @@ enum n2n_pc
|
|||
n2n_register_super_ack=6, /* ACK from supernode to edge */
|
||||
n2n_register_super_nak=7, /* NAK from supernode to edge - registration refused */
|
||||
n2n_federation=8 /* Not used by edge */
|
||||
};
|
||||
|
||||
typedef enum n2n_pc n2n_pc_t;
|
||||
} n2n_pc_t;
|
||||
|
||||
#define N2N_FLAGS_OPTIONS 0x0080
|
||||
#define N2N_FLAGS_SOCKET 0x0040
|
||||
|
@ -86,11 +84,6 @@ typedef enum n2n_pc n2n_pc_t;
|
|||
#define N2N_EINVAL -3
|
||||
#define N2N_ENOSPACE -4
|
||||
|
||||
|
||||
typedef uint16_t n2n_flags_t;
|
||||
typedef uint16_t n2n_transform_t; /* Encryption, compression type. */
|
||||
typedef uint32_t n2n_sa_t; /* security association number */
|
||||
|
||||
struct n2n_sock
|
||||
{
|
||||
uint8_t family; /* AF_INET or AF_INET6; or 0 if invalid */
|
||||
|
@ -118,8 +111,8 @@ struct n2n_common
|
|||
{
|
||||
/* int version; */
|
||||
uint8_t ttl;
|
||||
n2n_pc_t pc;
|
||||
n2n_flags_t flags;
|
||||
uint8_t pc;
|
||||
uint16_t flags;
|
||||
n2n_community_t community;
|
||||
};
|
||||
|
||||
|
@ -150,7 +143,7 @@ struct n2n_PACKET
|
|||
n2n_mac_t srcMac;
|
||||
n2n_mac_t dstMac;
|
||||
n2n_sock_t sock;
|
||||
n2n_transform_t transform;
|
||||
uint16_t transform;
|
||||
};
|
||||
|
||||
typedef struct n2n_PACKET n2n_PACKET_t;
|
||||
|
|
636
transform_aes.c
636
transform_aes.c
|
@ -19,16 +19,10 @@
|
|||
#include "n2n.h"
|
||||
#include "n2n_transforms.h"
|
||||
|
||||
#if defined(N2N_HAVE_AES)
|
||||
#ifdef N2N_HAVE_AES
|
||||
|
||||
#include "openssl/aes.h"
|
||||
#include "openssl/sha.h"
|
||||
#ifndef _MSC_VER
|
||||
/* Not included in Visual Studio 2008 */
|
||||
#include <strings.h> /* index() */
|
||||
#endif
|
||||
|
||||
#define N2N_AES_NUM_SA 32 /* space for SAa */
|
||||
|
||||
#define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */
|
||||
#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */
|
||||
|
@ -37,79 +31,6 @@
|
|||
#define AES192_KEY_BYTES (192/8)
|
||||
#define AES128_KEY_BYTES (128/8)
|
||||
|
||||
typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
|
||||
|
||||
struct sa_aes
|
||||
{
|
||||
n2n_cipherspec_t spec; /* cipher spec parameters */
|
||||
n2n_sa_t sa_id; /* security association index */
|
||||
AES_KEY enc_key; /* tx key */
|
||||
AES_KEY dec_key; /* tx key */
|
||||
AES_KEY iv_enc_key; /* key used to encrypt the IV */
|
||||
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* key used to extend the random IV seed to full block size */
|
||||
};
|
||||
|
||||
typedef struct sa_aes sa_aes_t;
|
||||
|
||||
|
||||
/** Aes transform state data.
|
||||
*
|
||||
* With a key-schedule in place this will be populated with a number of
|
||||
* SAs. Each SA has a lifetime and some opque data. The opaque data for aes
|
||||
* consists of the SA number and key material.
|
||||
*
|
||||
*/
|
||||
struct transop_aes
|
||||
{
|
||||
ssize_t tx_sa;
|
||||
size_t num_sa;
|
||||
sa_aes_t sa[N2N_AES_NUM_SA];
|
||||
u_int8_t psk_mode;
|
||||
};
|
||||
|
||||
typedef struct transop_aes transop_aes_t;
|
||||
|
||||
static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id );
|
||||
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num);
|
||||
|
||||
static int transop_deinit_aes( n2n_trans_op_t * arg )
|
||||
{
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
size_t i;
|
||||
|
||||
if ( priv )
|
||||
{
|
||||
/* Memory was previously allocated */
|
||||
for (i=0; i<N2N_AES_NUM_SA; ++i )
|
||||
{
|
||||
sa_aes_t * sa = &(priv->sa[i]);
|
||||
|
||||
sa->sa_id=0;
|
||||
}
|
||||
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=-1;
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
||||
arg->priv=NULL; /* return to fully uninitialised state */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t aes_choose_tx_sa( transop_aes_t * priv, const u_int8_t * peer_mac ) {
|
||||
return priv->tx_sa; /* set in tick */
|
||||
}
|
||||
|
||||
static ssize_t aes_choose_rx_sa( transop_aes_t * priv, const u_int8_t * peer_mac, ssize_t sa_rx) {
|
||||
if(!priv->psk_mode)
|
||||
return aes_find_sa(priv, sa_rx);
|
||||
else
|
||||
/* NOTE the sa_rx of the packet is ignored in this case */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AES plaintext preamble */
|
||||
#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
|
||||
#define TRANSOP_AES_SA_SIZE 4
|
||||
|
@ -119,6 +40,30 @@ static ssize_t aes_choose_rx_sa( transop_aes_t * priv, const u_int8_t * peer_mac
|
|||
/* AES ciphertext preamble */
|
||||
#define TRANSOP_AES_NONCE_SIZE 4
|
||||
|
||||
typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
|
||||
|
||||
typedef struct transop_aes {
|
||||
AES_KEY enc_key; /* tx key */
|
||||
AES_KEY dec_key; /* tx key */
|
||||
AES_KEY iv_enc_key; /* key used to encrypt the IV */
|
||||
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* key used to extend the random IV seed to full block size */
|
||||
} transop_aes_t;
|
||||
|
||||
struct sha512_keybuf {
|
||||
uint8_t enc_dec_key[AES256_KEY_BYTES]; /* The key to use for AES CBC encryption/decryption */
|
||||
uint8_t iv_enc_key[AES128_KEY_BYTES]; /* The key to use to encrypt the IV with AES ECB */
|
||||
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* A value to extend the IV seed */
|
||||
}; /* size: SHA512_DIGEST_LENGTH */
|
||||
|
||||
static int transop_deinit_aes(n2n_trans_op_t *arg) {
|
||||
transop_aes_t *priv = (transop_aes_t *)arg->priv;
|
||||
|
||||
if(priv)
|
||||
free(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the best acceptable AES key size (in bytes) given an input keysize.
|
||||
*
|
||||
* The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or
|
||||
|
@ -140,11 +85,11 @@ static size_t aes_best_keysize(size_t numBytes)
|
|||
}
|
||||
}
|
||||
|
||||
static void set_aes_cbc_iv(sa_aes_t *sa, n2n_aes_ivec_t ivec, uint64_t iv_seed) {
|
||||
static void set_aes_cbc_iv(transop_aes_t *priv, n2n_aes_ivec_t ivec, uint64_t iv_seed) {
|
||||
uint8_t iv_full[AES_BLOCK_SIZE];
|
||||
|
||||
/* Extend the seed to full block size via the fixed ext value */
|
||||
memcpy(iv_full, sa->iv_ext_val, sizeof(iv_seed)); // note: only 64bits used of 128 available
|
||||
memcpy(iv_full, priv->iv_ext_val, sizeof(iv_seed)); // note: only 64bits used of 128 available
|
||||
memcpy(iv_full + sizeof(iv_seed), &iv_seed, sizeof(iv_seed));
|
||||
|
||||
/* Encrypt the IV with secret key to make it unpredictable.
|
||||
|
@ -153,7 +98,7 @@ static void set_aes_cbc_iv(sa_aes_t *sa, n2n_aes_ivec_t ivec, uint64_t iv_seed)
|
|||
* can be easily reconstructed from plaintext headers and used by an attacker
|
||||
* to perform differential analysis.
|
||||
*/
|
||||
AES_ecb_encrypt(iv_full, ivec, &sa->iv_enc_key, AES_ENCRYPT);
|
||||
AES_ecb_encrypt(iv_full, ivec, &priv->iv_enc_key, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
/** The aes packet format consists of:
|
||||
|
@ -178,30 +123,22 @@ static int transop_encode_aes( n2n_trans_op_t * arg,
|
|||
uint8_t assembly[N2N_PKT_BUF_SIZE] = {0};
|
||||
uint32_t * pnonce;
|
||||
|
||||
if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
|
||||
{
|
||||
if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_PREAMBLE_SIZE) <= out_len )
|
||||
{
|
||||
if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) {
|
||||
if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_PREAMBLE_SIZE) <= out_len ) {
|
||||
int len=-1;
|
||||
size_t idx=0;
|
||||
sa_aes_t * sa;
|
||||
size_t tx_sa_num = 0;
|
||||
size_t tx_sa_num = 0; // Not used
|
||||
uint64_t iv_seed = 0;
|
||||
uint8_t padding = 0;
|
||||
n2n_aes_ivec_t enc_ivec = {0};
|
||||
|
||||
/* The transmit sa is periodically updated */
|
||||
tx_sa_num = aes_choose_tx_sa( priv, peer_mac );
|
||||
traceEvent( TRACE_DEBUG, "encode_aes %lu", in_len);
|
||||
|
||||
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
|
||||
|
||||
traceEvent( TRACE_DEBUG, "encode_aes %lu with SA %lu.", in_len, sa->sa_id );
|
||||
|
||||
/* Encode the aes format version. */
|
||||
encode_uint8( outbuf, &idx, N2N_AES_TRANSFORM_VERSION );
|
||||
|
||||
/* Encode the security association (SA) number */
|
||||
encode_uint32( outbuf, &idx, sa->sa_id );
|
||||
encode_uint32( outbuf, &idx, tx_sa_num ); // Not used
|
||||
|
||||
/* Generate and encode the IV seed.
|
||||
* Using two calls to rand() because RAND_MAX is usually < 64bit
|
||||
|
@ -227,60 +164,29 @@ static int transop_encode_aes( n2n_trans_op_t * arg,
|
|||
assembly[len2 - 1] = padding;
|
||||
traceEvent( TRACE_DEBUG, "padding = %u, seed = %016lx", padding, iv_seed );
|
||||
|
||||
set_aes_cbc_iv(sa, enc_ivec, iv_seed);
|
||||
set_aes_cbc_iv(priv, enc_ivec, iv_seed);
|
||||
|
||||
AES_cbc_encrypt( assembly, /* source */
|
||||
outbuf + TRANSOP_AES_PREAMBLE_SIZE, /* dest */
|
||||
len2, /* enc size */
|
||||
&(sa->enc_key), enc_ivec, AES_ENCRYPT );
|
||||
&(priv->enc_key), enc_ivec, AES_ENCRYPT );
|
||||
|
||||
len2 += TRANSOP_AES_PREAMBLE_SIZE; /* size of data carried in UDP. */
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "encode_aes outbuf too small." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "encode_aes inbuf too big to encrypt." );
|
||||
}
|
||||
|
||||
return len2;
|
||||
}
|
||||
|
||||
|
||||
/* Search through the array of SAs to find the one with the required ID.
|
||||
*
|
||||
* @return array index where found or -1 if not found
|
||||
*/
|
||||
static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id )
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < priv->num_sa; ++i)
|
||||
{
|
||||
const sa_aes_t * sa=NULL;
|
||||
|
||||
sa = &(priv->sa[i]);
|
||||
if (req_id == sa->sa_id)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* See transop_encode_aes for packet format */
|
||||
static int transop_decode_aes( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len,
|
||||
const uint8_t * peer_mac)
|
||||
{
|
||||
const uint8_t * peer_mac) {
|
||||
int len=0;
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
uint8_t assembly[N2N_PKT_BUF_SIZE];
|
||||
|
@ -289,8 +195,7 @@ static int transop_decode_aes( n2n_trans_op_t * arg,
|
|||
&& (in_len >= (TRANSOP_AES_PREAMBLE_SIZE + TRANSOP_AES_NONCE_SIZE) ) /* Has at least version, SA, iv seed and nonce */
|
||||
)
|
||||
{
|
||||
n2n_sa_t sa_rx;
|
||||
ssize_t sa_idx=-1;
|
||||
uint32_t sa_rx=0; // Not used
|
||||
size_t rem=in_len;
|
||||
size_t idx=0;
|
||||
uint8_t aes_enc_ver=0;
|
||||
|
@ -299,110 +204,71 @@ static int transop_decode_aes( n2n_trans_op_t * arg,
|
|||
/* Get the encoding version to make sure it is supported */
|
||||
decode_uint8( &aes_enc_ver, inbuf, &rem, &idx );
|
||||
|
||||
if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver )
|
||||
{
|
||||
/* Get the SA number and make sure we are decrypting with the right one. */
|
||||
if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver ) {
|
||||
/* Get the SA number and make sure we are decrypting with the right one. - Not used*/
|
||||
decode_uint32( &sa_rx, inbuf, &rem, &idx );
|
||||
|
||||
sa_idx = aes_choose_rx_sa(priv, peer_mac, sa_rx);
|
||||
/* Get the IV seed */
|
||||
decode_buf((uint8_t *)&iv_seed, sizeof(iv_seed), inbuf, &rem, &idx);
|
||||
|
||||
if ( sa_idx >= 0 )
|
||||
{
|
||||
sa_aes_t * sa = &(priv->sa[sa_idx]);
|
||||
traceEvent( TRACE_DEBUG, "decode_aes %lu with seed %016lx", in_len, iv_seed );
|
||||
|
||||
/* Get the IV seed */
|
||||
decode_buf((uint8_t *)&iv_seed, sizeof(iv_seed), inbuf, &rem, &idx);
|
||||
len = (in_len - TRANSOP_AES_PREAMBLE_SIZE);
|
||||
|
||||
if ( 0 == (len % AES_BLOCK_SIZE ) ) {
|
||||
uint8_t padding;
|
||||
n2n_aes_ivec_t dec_ivec = {0};
|
||||
|
||||
traceEvent( TRACE_DEBUG, "decode_aes %lu with SA %lu and seed %016lx", in_len, sa->sa_id, iv_seed );
|
||||
set_aes_cbc_iv(priv, dec_ivec, iv_seed);
|
||||
|
||||
len = (in_len - TRANSOP_AES_PREAMBLE_SIZE);
|
||||
|
||||
if ( 0 == (len % AES_BLOCK_SIZE ) )
|
||||
AES_cbc_encrypt( (inbuf + TRANSOP_AES_PREAMBLE_SIZE),
|
||||
assembly, /* destination */
|
||||
len,
|
||||
&(priv->dec_key),
|
||||
dec_ivec, AES_DECRYPT );
|
||||
|
||||
/* last byte is how much was padding: max value should be
|
||||
* AES_BLOCKSIZE-1 */
|
||||
padding = assembly[ len-1 ] & 0xff;
|
||||
|
||||
if ( len >= (padding + TRANSOP_AES_NONCE_SIZE))
|
||||
{
|
||||
uint8_t padding;
|
||||
n2n_aes_ivec_t dec_ivec = {0};
|
||||
/* strictly speaking for this to be an ethernet packet
|
||||
* it is going to need to be even bigger; but this is
|
||||
* enough to prevent segfaults. */
|
||||
traceEvent( TRACE_DEBUG, "padding = %u", padding );
|
||||
len -= padding;
|
||||
|
||||
set_aes_cbc_iv(sa, dec_ivec, iv_seed);
|
||||
|
||||
AES_cbc_encrypt( (inbuf + TRANSOP_AES_PREAMBLE_SIZE),
|
||||
assembly, /* destination */
|
||||
len,
|
||||
&(sa->dec_key),
|
||||
dec_ivec, AES_DECRYPT );
|
||||
|
||||
/* last byte is how much was padding: max value should be
|
||||
* AES_BLOCKSIZE-1 */
|
||||
padding = assembly[ len-1 ] & 0xff;
|
||||
|
||||
if ( len >= (padding + TRANSOP_AES_NONCE_SIZE))
|
||||
{
|
||||
/* strictly speaking for this to be an ethernet packet
|
||||
* it is going to need to be even bigger; but this is
|
||||
* enough to prevent segfaults. */
|
||||
traceEvent( TRACE_DEBUG, "padding = %u", padding );
|
||||
len -= padding;
|
||||
|
||||
len -= TRANSOP_AES_NONCE_SIZE; /* size of ethernet packet */
|
||||
|
||||
/* Step over 4-byte random nonce value */
|
||||
memcpy( outbuf,
|
||||
assembly + TRANSOP_AES_NONCE_SIZE,
|
||||
len );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_WARNING, "UDP payload decryption failed." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE );
|
||||
len = 0;
|
||||
}
|
||||
len -= TRANSOP_AES_NONCE_SIZE; /* size of ethernet packet */
|
||||
|
||||
/* Step over 4-byte random nonce value */
|
||||
memcpy( outbuf,
|
||||
assembly + TRANSOP_AES_NONCE_SIZE,
|
||||
len );
|
||||
} else
|
||||
traceEvent( TRACE_WARNING, "UDP payload decryption failed." );
|
||||
} else {
|
||||
traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE );
|
||||
len = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
traceEvent( TRACE_ERROR, "decode_aes SA number %lu not found.", sa_rx );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "decode_aes unsupported aes version %u.", aes_enc_ver );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "decode_aes inbuf wrong size (%ul) to decrypt.", in_len );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct sha512_keybuf {
|
||||
uint8_t enc_dec_key[AES256_KEY_BYTES]; /* The key to use for AES CBC encryption/decryption */
|
||||
uint8_t iv_enc_key[AES128_KEY_BYTES]; /* The key to use to encrypt the IV with AES ECB */
|
||||
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* A value to extend the IV seed */
|
||||
}; /* size: SHA512_DIGEST_LENGTH */
|
||||
|
||||
/* NOTE: the caller should adjust priv->num_sa accordingly */
|
||||
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num) {
|
||||
sa_aes_t * sa = &(priv->sa[sa_num]);
|
||||
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size) {
|
||||
size_t aes_keysize_bytes;
|
||||
size_t aes_keysize_bits;
|
||||
struct sha512_keybuf keybuf;
|
||||
|
||||
/* Clear out any old possibly longer key matter. */
|
||||
memset( &(sa->enc_key), 0, sizeof(sa->enc_key) );
|
||||
memset( &(sa->dec_key), 0, sizeof(sa->dec_key) );
|
||||
memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) );
|
||||
memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) );
|
||||
memset( &(priv->enc_key), 0, sizeof(priv->enc_key) );
|
||||
memset( &(priv->dec_key), 0, sizeof(priv->dec_key) );
|
||||
memset( &(priv->iv_enc_key), 0, sizeof(priv->iv_enc_key) );
|
||||
memset( &(priv->iv_ext_val), 0, sizeof(priv->iv_ext_val) );
|
||||
|
||||
/* We still use aes_best_keysize (even not necessary since we hash the key
|
||||
* into the 256bits enc_dec_key) to let the users choose the degree of encryption.
|
||||
|
@ -415,316 +281,44 @@ static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_si
|
|||
SHA512(key, key_size, (u_char*)&keybuf);
|
||||
|
||||
/* setup of enc_key/dec_key, used for the CBC encryption */
|
||||
AES_set_encrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->enc_key));
|
||||
AES_set_decrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->dec_key));
|
||||
AES_set_encrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(priv->enc_key));
|
||||
AES_set_decrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(priv->dec_key));
|
||||
|
||||
/* setup of iv_enc_key and iv_ext_val, used for generating the CBC IV */
|
||||
AES_set_encrypt_key(keybuf.iv_enc_key, sizeof(keybuf.iv_enc_key) * 8, &(sa->iv_enc_key));
|
||||
memcpy(sa->iv_ext_val, keybuf.iv_ext_val, sizeof(keybuf.iv_ext_val));
|
||||
AES_set_encrypt_key(keybuf.iv_enc_key, sizeof(keybuf.iv_enc_key) * 8, &(priv->iv_enc_key));
|
||||
memcpy(priv->iv_ext_val, keybuf.iv_ext_val, sizeof(keybuf.iv_ext_val));
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits key=%s.\n",
|
||||
priv->sa[sa_num].sa_id, aes_keysize_bits, key);
|
||||
traceEvent( TRACE_DEBUG, "AES %u bits setup completed\n",
|
||||
aes_keysize_bits, key);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* priv: pointer to transform state
|
||||
* keybuf: buffer holding the key
|
||||
* pstat: length of keybuf
|
||||
*/
|
||||
static void add_aes_key(transop_aes_t *priv, uint8_t *keybuf, ssize_t pstat) {
|
||||
setup_aes_key(priv, keybuf, pstat, priv->num_sa);
|
||||
++(priv->num_sa);
|
||||
static void transop_tick_aes(n2n_trans_op_t * arg, time_t now) {}
|
||||
|
||||
/* AES initialization function */
|
||||
int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
|
||||
transop_aes_t *priv;
|
||||
const u_char *encrypt_key = (const u_char *)conf->encrypt_key;
|
||||
size_t encrypt_key_len = strlen(conf->encrypt_key);
|
||||
|
||||
memset(ttt, 0, sizeof(*ttt));
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
|
||||
|
||||
ttt->tick = transop_tick_aes;
|
||||
ttt->deinit = transop_deinit_aes;
|
||||
ttt->fwd = transop_encode_aes;
|
||||
ttt->rev = transop_decode_aes;
|
||||
|
||||
priv = (transop_aes_t*) calloc(1, sizeof(transop_aes_t));
|
||||
if(!priv) {
|
||||
traceEvent(TRACE_ERROR, "cannot allocate transop_aes_t memory");
|
||||
return(-1);
|
||||
}
|
||||
ttt->priv = priv;
|
||||
|
||||
/* Setup the key */
|
||||
return(setup_aes_key(priv, encrypt_key, encrypt_key_len));
|
||||
}
|
||||
|
||||
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
int retval = 1;
|
||||
ssize_t pstat=-1;
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
uint8_t keybuf[N2N_MAX_KEYSIZE];
|
||||
|
||||
if ( priv->num_sa < N2N_AES_NUM_SA )
|
||||
{
|
||||
const char * op = (const char *)cspec->opaque;
|
||||
const char * sep = index( op, '_' );
|
||||
|
||||
if ( sep )
|
||||
{
|
||||
char tmp[256];
|
||||
size_t s;
|
||||
|
||||
s = sep - op;
|
||||
memcpy( tmp, cspec->opaque, s );
|
||||
tmp[s]=0;
|
||||
|
||||
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
|
||||
|
||||
priv->sa[priv->num_sa].spec = *cspec;
|
||||
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
|
||||
|
||||
memset( keybuf, 0, N2N_MAX_KEYSIZE );
|
||||
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
|
||||
if ( pstat > 0 )
|
||||
{
|
||||
add_aes_key(priv, keybuf, pstat);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_aes : bad key data - missing '_'.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_aes : full.\n");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
|
||||
{
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
size_t i;
|
||||
int found=0;
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset( &r, 0, sizeof(r) );
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_aes tick num_sa=%u now=%lu", priv->num_sa, now );
|
||||
|
||||
for ( i=0; i < priv->num_sa; ++i )
|
||||
{
|
||||
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
|
||||
{
|
||||
time_t remaining = priv->sa[i].spec.valid_until - now;
|
||||
|
||||
traceEvent( TRACE_INFO, "transop_aes choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
|
||||
priv->tx_sa=i;
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_DEBUG, "transop_aes tick rejecting sa=%u %lu -> %lu",
|
||||
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0==found)
|
||||
{
|
||||
traceEvent( TRACE_INFO, "transop_aes no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.can_tx = 1;
|
||||
r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
|
||||
r.tx_spec = priv->sa[priv->tx_sa].spec;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static n2n_tostat_t transop_tick_aes_psk(n2n_trans_op_t * arg, time_t now) {
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
|
||||
// Always tx
|
||||
r.can_tx = 1;
|
||||
r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
|
||||
r.tx_spec = priv->sa[priv->tx_sa].spec;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int transop_aes_init( n2n_trans_op_t * ttt )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_aes_t * priv = NULL;
|
||||
|
||||
if ( ttt->priv )
|
||||
{
|
||||
transop_deinit_aes( ttt );
|
||||
}
|
||||
|
||||
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
|
||||
|
||||
priv = (transop_aes_t *) calloc(1, sizeof(transop_aes_t));
|
||||
|
||||
if ( NULL != priv )
|
||||
{
|
||||
size_t i;
|
||||
sa_aes_t * sa=NULL;
|
||||
|
||||
/* install the private structure. */
|
||||
ttt->priv = priv;
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=0; /* We will use this sa index for encoding. */
|
||||
priv->psk_mode = 0;
|
||||
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
|
||||
ttt->addspec = transop_addspec_aes;
|
||||
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
|
||||
ttt->deinit = transop_deinit_aes;
|
||||
ttt->fwd = transop_encode_aes;
|
||||
ttt->rev = transop_decode_aes;
|
||||
|
||||
for(i=0; i<N2N_AES_NUM_SA; ++i)
|
||||
{
|
||||
sa = &(priv->sa[i]);
|
||||
sa->sa_id=0;
|
||||
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
|
||||
memset( &(sa->enc_key), 0, sizeof(sa->enc_key) );
|
||||
memset( &(sa->dec_key), 0, sizeof(sa->dec_key) );
|
||||
memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) );
|
||||
memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) );
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Setup AES in pre-shared key mode */
|
||||
int transop_aes_setup_psk(n2n_trans_op_t *ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len) {
|
||||
int retval = 1;
|
||||
transop_aes_t *priv = (transop_aes_t *)ttt->priv;
|
||||
|
||||
if(ttt->priv) {
|
||||
/* Replace the tick function with the PSK version of it */
|
||||
ttt->tick = transop_tick_aes_psk;
|
||||
priv->psk_mode = 1;
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=0;
|
||||
|
||||
/* Setup the key to use for encryption/decryption */
|
||||
add_aes_key(priv, encrypt_pwd, encrypt_pwd_len);
|
||||
|
||||
retval = 0;
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "AES priv is not allocated");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#else /* #if defined(N2N_HAVE_AES) */
|
||||
|
||||
struct transop_aes
|
||||
{
|
||||
ssize_t tx_sa;
|
||||
};
|
||||
|
||||
typedef struct transop_aes transop_aes_t;
|
||||
|
||||
|
||||
static int transop_deinit_aes( n2n_trans_op_t * arg )
|
||||
{
|
||||
transop_aes_t * priv = (transop_aes_t *)arg->priv;
|
||||
|
||||
if ( priv )
|
||||
{
|
||||
free(priv);
|
||||
}
|
||||
|
||||
arg->priv=NULL; /* return to fully uninitialised state */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transop_encode_aes( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int transop_decode_aes( n2n_trans_op_t * arg,
|
||||
uint8_t * outbuf,
|
||||
size_t out_len,
|
||||
const uint8_t * inbuf,
|
||||
size_t in_len )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_aes AES not built into edge.\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
|
||||
{
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset( &r, 0, sizeof(r) );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int transop_aes_init( n2n_trans_op_t * ttt )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_aes_t * priv = NULL;
|
||||
|
||||
if ( ttt->priv )
|
||||
{
|
||||
transop_deinit_aes( ttt );
|
||||
}
|
||||
|
||||
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
|
||||
|
||||
priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) );
|
||||
|
||||
if ( NULL != priv )
|
||||
{
|
||||
/* install the private structure. */
|
||||
ttt->priv = priv;
|
||||
priv->tx_sa=0; /* We will use this sa index for encoding. */
|
||||
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
|
||||
ttt->addspec = transop_addspec_aes;
|
||||
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
|
||||
ttt->deinit = transop_deinit_aes;
|
||||
ttt->fwd = transop_encode_aes;
|
||||
ttt->rev = transop_decode_aes;
|
||||
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int transop_aes_setup_psk(n2n_trans_op_t *ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if defined(N2N_HAVE_AES) */
|
||||
|
||||
#endif /* N2N_HAVE_AES */
|
||||
|
|
|
@ -71,32 +71,17 @@ static int transop_decode_null( n2n_trans_op_t * arg,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int transop_addspec_null( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static void transop_tick_null(n2n_trans_op_t * arg, time_t now) {}
|
||||
|
||||
static n2n_tostat_t transop_tick_null( n2n_trans_op_t * arg, time_t now )
|
||||
{
|
||||
n2n_tostat_t r;
|
||||
|
||||
r.can_tx=1;
|
||||
r.tx_spec.t = N2N_TRANSFORM_ID_NULL;
|
||||
r.tx_spec.valid_from = 0;
|
||||
r.tx_spec.valid_until = (time_t)(-1);
|
||||
r.tx_spec.opaque_size=0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void transop_null_init( n2n_trans_op_t * ttt )
|
||||
{
|
||||
int n2n_transop_null_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
|
||||
memset(ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_NULL;
|
||||
ttt->no_encryption = 1;
|
||||
ttt->deinit = transop_deinit_null;
|
||||
ttt->addspec = transop_addspec_null;
|
||||
ttt->tick = transop_tick_null;
|
||||
ttt->fwd = transop_encode_null;
|
||||
ttt->rev = transop_decode_null;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
|
383
transform_tf.c
383
transform_tf.c
|
@ -28,70 +28,23 @@
|
|||
|
||||
#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding */
|
||||
|
||||
struct sa_twofish
|
||||
{
|
||||
n2n_cipherspec_t spec; /* cipher spec parameters */
|
||||
n2n_sa_t sa_id; /* security association index */
|
||||
TWOFISH * enc_tf; /* tx state */
|
||||
TWOFISH * dec_tf; /* rx state */
|
||||
};
|
||||
typedef struct transop_tf {
|
||||
TWOFISH* enc_tf; /* tx state */
|
||||
TWOFISH* dec_tf; /* rx state */
|
||||
} transop_tf_t;
|
||||
|
||||
typedef struct sa_twofish sa_twofish_t;
|
||||
static int transop_deinit_twofish( n2n_trans_op_t * arg ) {
|
||||
transop_tf_t *priv = (transop_tf_t *)arg->priv;
|
||||
|
||||
|
||||
/** Twofish transform state data.
|
||||
*
|
||||
* With a key-schedule in place this will be populated with a number of
|
||||
* SAs. Each SA has a lifetime and some opque data. The opaque data for twofish
|
||||
* consists of the SA number and key material.
|
||||
*
|
||||
*/
|
||||
struct transop_tf
|
||||
{
|
||||
ssize_t tx_sa;
|
||||
size_t num_sa;
|
||||
sa_twofish_t sa[N2N_TWOFISH_NUM_SA];
|
||||
};
|
||||
|
||||
typedef struct transop_tf transop_tf_t;
|
||||
|
||||
static int transop_deinit_twofish( n2n_trans_op_t * arg )
|
||||
{
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
size_t i;
|
||||
|
||||
if ( priv )
|
||||
{
|
||||
/* Memory was previously allocated */
|
||||
for (i=0; i<N2N_TWOFISH_NUM_SA; ++i )
|
||||
{
|
||||
sa_twofish_t * sa = &(priv->sa[i]);
|
||||
|
||||
TwoFishDestroy(sa->enc_tf); /* deallocate TWOFISH */
|
||||
sa->enc_tf=NULL;
|
||||
|
||||
TwoFishDestroy(sa->dec_tf); /* deallocate TWOFISH */
|
||||
sa->dec_tf=NULL;
|
||||
|
||||
sa->sa_id=0;
|
||||
}
|
||||
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=-1;
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
||||
arg->priv=NULL; /* return to fully uninitialised state */
|
||||
if(priv) {
|
||||
TwoFishDestroy(priv->enc_tf); /* deallocate TWOFISH */
|
||||
TwoFishDestroy(priv->dec_tf); /* deallocate TWOFISH */
|
||||
free(priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t tf_choose_tx_sa( transop_tf_t * priv )
|
||||
{
|
||||
return priv->tx_sa; /* set in tick */
|
||||
}
|
||||
|
||||
#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in one module. */
|
||||
#define TRANSOP_TF_NONCE_SIZE 4
|
||||
#define TRANSOP_TF_SA_SIZE 4
|
||||
|
@ -122,21 +75,15 @@ static int transop_encode_twofish( n2n_trans_op_t * arg,
|
|||
if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len )
|
||||
{
|
||||
size_t idx=0;
|
||||
sa_twofish_t * sa;
|
||||
size_t tx_sa_num = 0;
|
||||
uint32_t sa_id=0; // Not used
|
||||
|
||||
/* The transmit sa is periodically updated */
|
||||
tx_sa_num = tf_choose_tx_sa( priv );
|
||||
|
||||
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
|
||||
|
||||
traceEvent( TRACE_DEBUG, "encode_twofish %lu with SA %lu.", in_len, sa->sa_id );
|
||||
traceEvent(TRACE_DEBUG, "encode_twofish %lu", in_len);
|
||||
|
||||
/* Encode the twofish format version. */
|
||||
encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION );
|
||||
|
||||
/* Encode the security association (SA) number */
|
||||
encode_uint32( outbuf, &idx, sa->sa_id );
|
||||
encode_uint32( outbuf, &idx, sa_id );
|
||||
|
||||
/* The assembly buffer is a source for encrypting data. The nonce is
|
||||
* written in first followed by the packet payload. The whole
|
||||
|
@ -149,7 +96,7 @@ static int transop_encode_twofish( n2n_trans_op_t * arg,
|
|||
len = TwoFishEncryptRaw( assembly, /* source */
|
||||
outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE,
|
||||
in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */
|
||||
sa->enc_tf);
|
||||
priv->enc_tf);
|
||||
if ( len > 0 )
|
||||
{
|
||||
len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */
|
||||
|
@ -173,30 +120,6 @@ static int transop_encode_twofish( n2n_trans_op_t * arg,
|
|||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Search through the array of SAs to find the one with the required ID.
|
||||
*
|
||||
* @return array index where found or -1 if not found
|
||||
*/
|
||||
static ssize_t twofish_find_sa( const transop_tf_t * priv, const n2n_sa_t req_id )
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < priv->num_sa; ++i)
|
||||
{
|
||||
const sa_twofish_t * sa=NULL;
|
||||
|
||||
sa = &(priv->sa[i]);
|
||||
if (req_id == sa->sa_id)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/** The twofish packet format consists of:
|
||||
*
|
||||
* - a 8-bit twofish encoding version in clear text
|
||||
|
@ -219,249 +142,77 @@ static int transop_decode_twofish( n2n_trans_op_t * arg,
|
|||
|
||||
if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
|
||||
&& (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */
|
||||
)
|
||||
{
|
||||
n2n_sa_t sa_rx;
|
||||
ssize_t sa_idx=-1;
|
||||
) {
|
||||
size_t rem=in_len;
|
||||
size_t idx=0;
|
||||
uint8_t tf_enc_ver=0;
|
||||
uint32_t sa_rx=0; // Not used
|
||||
|
||||
/* Get the encoding version to make sure it is supported */
|
||||
decode_uint8( &tf_enc_ver, inbuf, &rem, &idx );
|
||||
|
||||
if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver )
|
||||
{
|
||||
if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver ) {
|
||||
/* Get the SA number and make sure we are decrypting with the right one. */
|
||||
decode_uint32( &sa_rx, inbuf, &rem, &idx );
|
||||
|
||||
sa_idx = twofish_find_sa(priv, sa_rx);
|
||||
if ( sa_idx >= 0 )
|
||||
{
|
||||
sa_twofish_t * sa = &(priv->sa[sa_idx]);
|
||||
traceEvent(TRACE_DEBUG, "decode_twofish %lu", in_len);
|
||||
|
||||
traceEvent( TRACE_DEBUG, "decode_twofish %lu with SA %lu.", in_len, sa_rx, sa->sa_id );
|
||||
len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE),
|
||||
assembly, /* destination */
|
||||
(in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)),
|
||||
priv->dec_tf);
|
||||
|
||||
len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE),
|
||||
assembly, /* destination */
|
||||
(in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)),
|
||||
sa->dec_tf);
|
||||
if(len > 0) {
|
||||
/* Step over 4-byte random nonce value */
|
||||
len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */
|
||||
|
||||
if ( len > 0 )
|
||||
{
|
||||
/* Step over 4-byte random nonce value */
|
||||
len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */
|
||||
|
||||
memcpy( outbuf,
|
||||
assembly + TRANSOP_TF_NONCE_SIZE,
|
||||
len );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "decode_twofish decryption failed." );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
traceEvent( TRACE_ERROR, "decode_twofish SA number %lu not found.", sa_rx );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrong security association; drop the packet as it is undecodable. */
|
||||
traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver );
|
||||
|
||||
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len );
|
||||
}
|
||||
memcpy( outbuf,
|
||||
assembly + TRANSOP_TF_NONCE_SIZE,
|
||||
len );
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "decode_twofish decryption failed");
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver );
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int transop_addspec_twofish( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
int retval = 1;
|
||||
ssize_t pstat=-1;
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
uint8_t keybuf[N2N_MAX_KEYSIZE];
|
||||
static void transop_tick_twofish( n2n_trans_op_t * arg, time_t now ) {}
|
||||
|
||||
if ( priv->num_sa < N2N_TWOFISH_NUM_SA )
|
||||
{
|
||||
const char * op = (const char *)cspec->opaque;
|
||||
#ifdef __ANDROID_NDK__
|
||||
const char *sep = strchr(op, '_');
|
||||
#else
|
||||
const char * sep = index( op, '_' );
|
||||
#endif // __ANDROID_NDK__
|
||||
/* Twofish initialization function */
|
||||
int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
|
||||
transop_tf_t *priv;
|
||||
const u_char *encrypt_key = (const u_char *)conf->encrypt_key;
|
||||
size_t encrypt_key_len = strlen(conf->encrypt_key);
|
||||
|
||||
if ( sep )
|
||||
{
|
||||
char tmp[256];
|
||||
size_t s;
|
||||
|
||||
s = sep - op;
|
||||
memcpy( tmp, cspec->opaque, s );
|
||||
tmp[s]=0;
|
||||
|
||||
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
|
||||
memset(ttt, 0, sizeof(*ttt));
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
|
||||
|
||||
priv->sa[priv->num_sa].spec = *cspec;
|
||||
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
|
||||
ttt->tick = transop_tick_twofish;
|
||||
ttt->deinit = transop_deinit_twofish;
|
||||
ttt->fwd = transop_encode_twofish;
|
||||
ttt->rev = transop_decode_twofish;
|
||||
|
||||
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
|
||||
if ( pstat > 0 )
|
||||
{
|
||||
priv->sa[priv->num_sa].enc_tf = TwoFishInit( keybuf, pstat);
|
||||
priv->sa[priv->num_sa].dec_tf = TwoFishInit( keybuf, pstat);
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_twofish sa_id=%u data=%s.\n",
|
||||
priv->sa[priv->num_sa].sa_id, sep+1);
|
||||
|
||||
++(priv->num_sa);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_twofish : bad key data - missing '_'.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "transop_addspec_twofish : full.\n");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now )
|
||||
{
|
||||
transop_tf_t * priv = (transop_tf_t *)arg->priv;
|
||||
size_t i;
|
||||
int found=0;
|
||||
n2n_tostat_t r;
|
||||
|
||||
memset( &r, 0, sizeof(r) );
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_tf tick num_sa=%u", priv->num_sa );
|
||||
|
||||
for ( i=0; i < priv->num_sa; ++i )
|
||||
{
|
||||
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
|
||||
{
|
||||
time_t remaining = priv->sa[i].spec.valid_until - now;
|
||||
|
||||
traceEvent( TRACE_INFO, "transop_tf choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
|
||||
priv->tx_sa=i;
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_DEBUG, "transop_tf tick rejecting sa=%u %lu -> %lu",
|
||||
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0==found)
|
||||
{
|
||||
traceEvent( TRACE_INFO, "transop_tf no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.can_tx = 1;
|
||||
r.tx_spec.t = N2N_TRANSFORM_ID_TWOFISH;
|
||||
r.tx_spec = priv->sa[priv->tx_sa].spec;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int transop_twofish_setup_psk( n2n_trans_op_t * ttt,
|
||||
n2n_sa_t sa_num,
|
||||
uint8_t * encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_tf_t * priv = (transop_tf_t *)ttt->priv;
|
||||
|
||||
if(priv) {
|
||||
sa_twofish_t *sa;
|
||||
|
||||
priv->num_sa=1; /* There is one SA in the array. */
|
||||
priv->tx_sa=0;
|
||||
sa = &(priv->sa[priv->tx_sa]);
|
||||
sa->sa_id=sa_num;
|
||||
sa->spec.valid_until = 0x7fffffff;
|
||||
|
||||
/* This is a preshared key setup. Both Tx and Rx are using the same security association. */
|
||||
|
||||
sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
|
||||
sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
|
||||
|
||||
if ( (sa->enc_tf) && (sa->dec_tf) )
|
||||
retval = 0;
|
||||
else
|
||||
traceEvent( TRACE_ERROR, "transop_twofish_setup_psk" );
|
||||
} else
|
||||
traceEvent( TRACE_ERROR, "twofish priv is not allocated" );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int transop_twofish_init( n2n_trans_op_t * ttt )
|
||||
{
|
||||
int retval = 1;
|
||||
transop_tf_t * priv = NULL;
|
||||
|
||||
if ( ttt->priv )
|
||||
{
|
||||
transop_deinit_twofish( ttt );
|
||||
}
|
||||
|
||||
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
|
||||
|
||||
priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
|
||||
|
||||
if ( NULL != priv ) {
|
||||
size_t i;
|
||||
sa_twofish_t * sa=NULL;
|
||||
|
||||
/* install the private structure. */
|
||||
ttt->priv = priv;
|
||||
priv->num_sa=0;
|
||||
priv->tx_sa=0; /* We will use this sa index for encoding. */
|
||||
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
|
||||
ttt->addspec = transop_addspec_twofish;
|
||||
ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
|
||||
ttt->deinit = transop_deinit_twofish;
|
||||
ttt->fwd = transop_encode_twofish;
|
||||
ttt->rev = transop_decode_twofish;
|
||||
|
||||
for(i=0; i<N2N_TWOFISH_NUM_SA; ++i)
|
||||
{
|
||||
sa = &(priv->sa[i]);
|
||||
sa->sa_id=0;
|
||||
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
|
||||
sa->enc_tf=NULL;
|
||||
sa->dec_tf=NULL;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
} else {
|
||||
memset( ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
|
||||
}
|
||||
|
||||
return retval;
|
||||
priv = (transop_tf_t*) calloc(1, sizeof(transop_tf_t));
|
||||
if(!priv) {
|
||||
traceEvent(TRACE_ERROR, "cannot allocate transop_tf_t memory");
|
||||
return(-1);
|
||||
}
|
||||
ttt->priv = priv;
|
||||
|
||||
/* This is a preshared key setup. Both Tx and Rx are using the same security association. */
|
||||
priv->enc_tf = TwoFishInit(encrypt_key, encrypt_key_len);
|
||||
priv->dec_tf = TwoFishInit(encrypt_key, encrypt_key_len);
|
||||
|
||||
if((!priv->enc_tf) || (!priv->dec_tf)) {
|
||||
if(priv->enc_tf) TwoFishDestroy(priv->enc_tf);
|
||||
if(priv->dec_tf) TwoFishDestroy(priv->dec_tf);
|
||||
free(priv);
|
||||
traceEvent(TRACE_ERROR, "TwoFishInit failed");
|
||||
return(-2);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user