mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
Add -A option to enable AES CBC psk encryption
This commit is contained in:
parent
63e74ccc6a
commit
e4601590aa
19
edge.c
19
edge.c
|
@ -136,7 +136,7 @@ static void help() {
|
|||
"-l <supernode host:port>\n"
|
||||
" "
|
||||
"[-p <local port>] [-M <mtu>] "
|
||||
"[-r] [-E] [-v] [-t <mgmt port>] [-b] [-h]\n\n");
|
||||
"[-r] [-E] [-v] [-t <mgmt port>] [-b] [-A] [-h]\n\n");
|
||||
|
||||
#ifdef __linux__
|
||||
printf("-d <tun device> | tun device name\n");
|
||||
|
@ -162,6 +162,7 @@ static void help() {
|
|||
" | eg. -m 01:02:03:04:05:06\n");
|
||||
printf("-M <mtu> | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU);
|
||||
printf("-r | Enable packet forwarding through n2n community.\n");
|
||||
printf("-A | Set AES CBC as the preferred encryption mode.\n");
|
||||
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");
|
||||
|
@ -268,6 +269,12 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
|
|||
break;
|
||||
}
|
||||
|
||||
case 'A':
|
||||
{
|
||||
eee->preferred_aes = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'l': /* supernode-list */
|
||||
if(optargument) {
|
||||
if(eee->sn_num < N2N_EDGE_NUM_SUPERNODES) {
|
||||
|
@ -357,7 +364,7 @@ static int loadFromCLI(int argc, char *argv[], edge_conf_t *ec, n2n_edge_t *eee)
|
|||
u_char c;
|
||||
|
||||
while((c = getopt_long(argc, argv,
|
||||
"K:k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:",
|
||||
"K:k:a:bc:Eu:g:m:M:s:d:l:p:fvhrAt:",
|
||||
long_options, NULL)) != '?') {
|
||||
if(c == 255) break;
|
||||
setOption(c, optarg, ec, eee);
|
||||
|
@ -665,8 +672,12 @@ int main(int argc, char* argv[]) {
|
|||
traceEvent(TRACE_NORMAL, "Binding to local port %d", (signed int)ec.local_port);
|
||||
|
||||
if(ec.encrypt_key) {
|
||||
if(edge_init_twofish(&eee, (uint8_t *)(ec.encrypt_key), strlen(ec.encrypt_key)) < 0) {
|
||||
fprintf(stderr, "Error: twofish setup failed.\n");
|
||||
if(edge_init_aes_psk(&eee, (uint8_t *)(ec.encrypt_key), strlen(ec.encrypt_key)) < 0) {
|
||||
fprintf(stderr, "Error: AES PSK setup failed.\n");
|
||||
return(-1);
|
||||
}
|
||||
if(edge_init_twofish_psk(&eee, (uint8_t *)(ec.encrypt_key), strlen(ec.encrypt_key)) < 0) {
|
||||
fprintf(stderr, "Error: twofish PSK setup failed.\n");
|
||||
return(-1);
|
||||
}
|
||||
} else if(strlen(eee.keyschedule) > 0) {
|
||||
|
|
67
edge_utils.c
67
edge_utils.c
|
@ -75,6 +75,7 @@ int edge_init(n2n_edge_t * eee) {
|
|||
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 */
|
||||
|
@ -644,37 +645,65 @@ const char * supernode_ip(const n2n_edge_t * eee) {
|
|||
|
||||
/* ************************************** */
|
||||
|
||||
int edge_init_twofish(n2n_edge_t * eee, uint8_t *encrypt_pwd,
|
||||
int edge_init_twofish_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len) {
|
||||
return transop_twofish_setup(&(eee->transop[N2N_TRANSOP_TF_IDX]),
|
||||
return transop_twofish_setup_psk(&(eee->transop[N2N_TRANSOP_TF_IDX]),
|
||||
0, encrypt_pwd, encrypt_pwd_len);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* ************************************** */
|
||||
|
||||
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)
|
||||
{
|
||||
n2n_tostat_t tst;
|
||||
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. */
|
||||
tst = (eee->transop[N2N_TRANSOP_NULL_IDX].tick)(&(eee->transop[N2N_TRANSOP_NULL_IDX]), now);
|
||||
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;
|
||||
}
|
||||
(eee->transop[N2N_TRANSOP_NULL_IDX].tick)(&(eee->transop[N2N_TRANSOP_NULL_IDX]), now);
|
||||
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -1688,8 +1717,10 @@ int quick_edge_init(char *device_name, char *community_name,
|
|||
device_mac, DEFAULT_MTU) < 0)
|
||||
return(-1);
|
||||
|
||||
if(edge_init_twofish(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key)) < 0)
|
||||
return(-2);
|
||||
if(edge_init_aes_psk(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key)) < 0)
|
||||
return(-2);
|
||||
if(edge_init_twofish_psk(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key)) < 0)
|
||||
return(-2);
|
||||
|
||||
snprintf((char*)eee.community_name, sizeof(eee.community_name), "%s", community_name);
|
||||
supernode2addr(&(eee.supernode), supernode_ip_address_port);
|
||||
|
|
5
n2n.h
5
n2n.h
|
@ -186,6 +186,7 @@ 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;
|
||||
|
@ -337,7 +338,9 @@ void set_peer_operational(n2n_edge_t * eee,
|
|||
const n2n_mac_t mac,
|
||||
const n2n_sock_t * peer);
|
||||
const char * supernode_ip(const n2n_edge_t * eee);
|
||||
int edge_init_twofish(n2n_edge_t * eee, uint8_t *encrypt_pwd,
|
||||
int edge_init_twofish_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len);
|
||||
int edge_init_aes_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
|
||||
uint32_t encrypt_pwd_len);
|
||||
int run_edge_loop(n2n_edge_t * eee, int *keep_running);
|
||||
void edge_term(n2n_edge_t * eee);
|
||||
|
|
|
@ -78,7 +78,12 @@ struct n2n_trans_op {
|
|||
};
|
||||
|
||||
/* Setup a single twofish SA for single-key operation. */
|
||||
int transop_twofish_setup( n2n_trans_op_t * ttt,
|
||||
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 );
|
||||
|
|
|
@ -339,6 +339,41 @@ static int transop_decode_aes( n2n_trans_op_t * arg,
|
|||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
/* pstat is number of bytes read into keybuf. */
|
||||
sa_aes_t * sa = &(priv->sa[priv->num_sa]);
|
||||
size_t aes_keysize_bytes;
|
||||
size_t aes_keysize_bits;
|
||||
|
||||
/* Clear out any old possibly longer key matter. */
|
||||
memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
|
||||
memset( &(sa->dec_key), 0, sizeof(AES_KEY) );
|
||||
|
||||
memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
|
||||
memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
|
||||
|
||||
aes_keysize_bytes = aes_best_keysize(pstat);
|
||||
aes_keysize_bits = 8 * aes_keysize_bytes;
|
||||
|
||||
/* Use N2N_MAX_KEYSIZE because the AES key needs to be of fixed
|
||||
* size. If fewer bits specified then the rest will be
|
||||
* zeroes. AES acceptable key sizes are 128, 192 and 256
|
||||
* bits. */
|
||||
AES_set_encrypt_key( keybuf, aes_keysize_bits, &(sa->enc_key));
|
||||
AES_set_decrypt_key( keybuf, aes_keysize_bits, &(sa->dec_key));
|
||||
/* Leave ivecs set to all zeroes */
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits data=%s.\n",
|
||||
priv->sa[priv->num_sa].sa_id, aes_keysize_bits, keybuf);
|
||||
|
||||
++(priv->num_sa);
|
||||
}
|
||||
|
||||
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
|
||||
{
|
||||
int retval = 1;
|
||||
|
@ -369,33 +404,7 @@ static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * c
|
|||
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
|
||||
if ( pstat > 0 )
|
||||
{
|
||||
/* pstat is number of bytes read into keybuf. */
|
||||
sa_aes_t * sa = &(priv->sa[priv->num_sa]);
|
||||
size_t aes_keysize_bytes;
|
||||
size_t aes_keysize_bits;
|
||||
|
||||
/* Clear out any old possibly longer key matter. */
|
||||
memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
|
||||
memset( &(sa->dec_key), 0, sizeof(AES_KEY) );
|
||||
|
||||
memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
|
||||
memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
|
||||
|
||||
aes_keysize_bytes = aes_best_keysize(pstat);
|
||||
aes_keysize_bits = 8 * aes_keysize_bytes;
|
||||
|
||||
/* Use N2N_MAX_KEYSIZE because the AES key needs to be of fixed
|
||||
* size. If fewer bits specified then the rest will be
|
||||
* zeroes. AES acceptable key sizes are 128, 192 and 256
|
||||
* bits. */
|
||||
AES_set_encrypt_key( keybuf, aes_keysize_bits, &(sa->enc_key));
|
||||
AES_set_decrypt_key( keybuf, aes_keysize_bits, &(sa->dec_key));
|
||||
/* Leave ivecs set to all zeroes */
|
||||
|
||||
traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits data=%s.\n",
|
||||
priv->sa[priv->num_sa].sa_id, aes_keysize_bits, sep+1);
|
||||
|
||||
++(priv->num_sa);
|
||||
add_aes_key(priv, keybuf, pstat);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
|
@ -510,6 +519,31 @@ int transop_aes_init( n2n_trans_op_t * ttt )
|
|||
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) {
|
||||
sa_aes_t *sa;
|
||||
priv->num_sa=0;
|
||||
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. */
|
||||
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
|
||||
|
@ -606,5 +640,13 @@ int transop_aes_init( n2n_trans_op_t * ttt )
|
|||
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) */
|
||||
|
||||
|
|
|
@ -384,73 +384,34 @@ static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now )
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
int transop_twofish_setup( n2n_trans_op_t * ttt,
|
||||
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 = NULL;
|
||||
transop_tf_t * priv = (transop_tf_t *)ttt->priv;
|
||||
|
||||
if ( ttt->priv )
|
||||
{
|
||||
transop_deinit_twofish( ttt );
|
||||
}
|
||||
if(priv) {
|
||||
sa_twofish_t *sa;
|
||||
|
||||
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
|
||||
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;
|
||||
|
||||
priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
|
||||
/* This is a preshared key setup. Both Tx and Rx are using the same security association. */
|
||||
|
||||
if ( NULL != priv )
|
||||
{
|
||||
size_t i;
|
||||
sa_twofish_t * sa=NULL;
|
||||
sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
|
||||
sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
|
||||
|
||||
/* install the private structure. */
|
||||
ttt->priv = priv;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) )
|
||||
{
|
||||
ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
|
||||
ttt->deinit = transop_deinit_twofish;
|
||||
ttt->addspec = transop_addspec_twofish;
|
||||
ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
|
||||
ttt->fwd = transop_encode_twofish;
|
||||
ttt->rev = transop_decode_twofish;
|
||||
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent( TRACE_ERROR, "TwoFishInit failed" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( ttt, 0, sizeof(n2n_trans_op_t) );
|
||||
traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user