Temporarily revert to old crypto code

(The new code is still segfaulting for me, and I'd like to proceed with other
work.)

This largely rolls back to the revision 1545 state of the existing code
(new crypto layer is still there with no callers), though I reintroduced
the segfault fix of revision 1562.
This commit is contained in:
Scott Lamb 2007-11-07 02:47:05 +00:00
parent 269892f70b
commit 40731d030f
10 changed files with 535 additions and 239 deletions

View file

@ -23,7 +23,6 @@
#include "system.h" #include "system.h"
#include "splay_tree.h" #include "splay_tree.h"
#include "cipher.h"
#include "conf.h" #include "conf.h"
#include "list.h" #include "list.h"
#include "logger.h" #include "logger.h"
@ -74,8 +73,14 @@ void free_connection(connection_t *c) {
if(c->hostname) if(c->hostname)
free(c->hostname); free(c->hostname);
cipher_close(&c->incipher); if(c->inkey)
cipher_close(&c->outcipher); free(c->inkey);
if(c->outkey)
free(c->outkey);
if(c->mychallenge)
free(c->mychallenge);
if(c->hischallenge) if(c->hischallenge)
free(c->hischallenge); free(c->hischallenge);

View file

@ -23,11 +23,11 @@
#ifndef __TINC_CONNECTION_H__ #ifndef __TINC_CONNECTION_H__
#define __TINC_CONNECTION_H__ #define __TINC_CONNECTION_H__
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <event.h> #include <event.h>
#include "cipher.h"
#include "digest.h"
#include "rsa.h"
#include "splay_tree.h" #include "splay_tree.h"
#define OPTION_INDIRECT 0x0001 #define OPTION_INDIRECT 0x0001
@ -72,18 +72,23 @@ typedef struct connection_t {
struct node_t *node; /* node associated with the other end */ struct node_t *node; /* node associated with the other end */
struct edge_t *edge; /* edge associated with this connection */ struct edge_t *edge; /* edge associated with this connection */
rsa_t rsa; /* his public/private key */ RSA *rsa_key; /* his public/private key */
cipher_t incipher; /* Cipher he will use to send data to us */ const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */
cipher_t outcipher; /* Cipher we will use to send data to him */ const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */
digest_t indigest; EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */
digest_t outdigest; EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */
char *inkey; /* His symmetric meta key + iv */
char *outkey; /* Our symmetric meta key + iv */
int inkeylength; /* Length of his key + iv */
int outkeylength; /* Length of our key + iv */
const EVP_MD *indigest;
const EVP_MD *outdigest;
int inmaclength; int inmaclength;
int outmaclength; int outmaclength;
int incompression; int incompression;
int outcompression; int outcompression;
char *mychallenge; /* challenge we received from him */
char *hischallenge; /* The challenge we sent to him */ char *hischallenge; /* challenge we sent to him */
struct bufferevent *buffer; /* buffer events on this metadata connection */ struct bufferevent *buffer; /* buffer events on this metadata connection */
struct event inevent; /* input event on this metadata connection */ struct event inevent; /* input event on this metadata connection */

View file

@ -22,8 +22,10 @@
#include "system.h" #include "system.h"
#include <openssl/err.h>
#include <openssl/evp.h>
#include "splay_tree.h" #include "splay_tree.h"
#include "cipher.h"
#include "connection.h" #include "connection.h"
#include "logger.h" #include "logger.h"
#include "meta.h" #include "meta.h"
@ -33,23 +35,31 @@
#include "xalloc.h" #include "xalloc.h"
bool send_meta(connection_t *c, const char *buffer, int length) { bool send_meta(connection_t *c, const char *buffer, int length) {
int outlen;
int result;
cp(); cp();
ifdebug(META) logger(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length, c->name, c->hostname); ifdebug(META) logger(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length,
c->name, c->hostname);
/* Add our data to buffer */ /* Add our data to buffer */
if(c->status.encryptout) { if(c->status.encryptout) {
char outbuf[length]; char outbuf[length];
size_t outlen = length;
if(!cipher_encrypt(&c->outcipher, buffer, length, outbuf, &outlen, false) || outlen != length) { result = EVP_EncryptUpdate(c->outctx, (unsigned char *)outbuf, &outlen, (unsigned char *)buffer, length);
logger(LOG_ERR, _("Error while encrypting metadata to %s (%s)"), c->name, c->hostname); if(!result || outlen != length) {
logger(LOG_ERR, _("Error while encrypting metadata to %s (%s): %s"),
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
logger(LOG_DEBUG, _("Encrypted write %p %p %p %d"), c, c->buffer, outbuf, length);
bufferevent_write(c->buffer, (void *)outbuf, length); bufferevent_write(c->buffer, (void *)outbuf, length);
logger(LOG_DEBUG, _("Done."));
} else { } else {
logger(LOG_DEBUG, _("Unencrypted write %p %p %p %d"), c, c->buffer, buffer, length);
bufferevent_write(c->buffer, (void *)buffer, length); bufferevent_write(c->buffer, (void *)buffer, length);
logger(LOG_DEBUG, _("Done."));
} }
return true; return true;
@ -70,7 +80,7 @@ void broadcast_meta(connection_t *from, const char *buffer, int length) {
} }
bool receive_meta(connection_t *c) { bool receive_meta(connection_t *c) {
size_t inlen; int result, inlen, outlen;
char inbuf[MAXBUFSIZE]; char inbuf[MAXBUFSIZE];
char *bufp = inbuf, *endp; char *bufp = inbuf, *endp;
@ -105,15 +115,16 @@ bool receive_meta(connection_t *c) {
inlen -= endp - bufp; inlen -= endp - bufp;
bufp = endp; bufp = endp;
} else { } else {
size_t outlen = inlen; logger(LOG_DEBUG, _("Received encrypted %d bytes"), inlen);
evbuffer_expand(c->buffer->input, c->buffer->input->off + inlen); evbuffer_expand(c->buffer->input, c->buffer->input->off + inlen);
result = EVP_DecryptUpdate(c->inctx, (unsigned char *)c->buffer->input->buffer + c->buffer->input->off, &outlen, (unsigned char *)bufp, inlen);
if(!cipher_decrypt(&c->incipher, bufp, inlen, c->buffer->input->buffer + c->buffer->input->off, &outlen, false) || inlen != outlen) { if(!result || outlen != inlen) {
logger(LOG_ERR, _("Error while decrypting metadata from %s (%s)"), c->name, c->hostname); logger(LOG_ERR, _("Error while decrypting metadata from %s (%s): %s"),
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
c->buffer->input->off += inlen; c->buffer->input->off += inlen;
inlen = 0; inlen = 0;
} }
@ -135,10 +146,8 @@ bool receive_meta(connection_t *c) {
char *request = evbuffer_readline(c->buffer->input); char *request = evbuffer_readline(c->buffer->input);
if(request) { if(request) {
bool result = receive_request(c, request); receive_request(c, request);
free(request); free(request);
if(!result)
return false;
continue; continue;
} else { } else {
break; break;

View file

@ -22,15 +22,18 @@
#include "system.h" #include "system.h"
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/hmac.h>
#include <zlib.h> #include <zlib.h>
#include LZO1X_H #include LZO1X_H
#include "splay_tree.h" #include "splay_tree.h"
#include "cipher.h"
#include "conf.h" #include "conf.h"
#include "connection.h" #include "connection.h"
#include "crypto.h"
#include "digest.h"
#include "device.h" #include "device.h"
#include "ethernet.h" #include "ethernet.h"
#include "graph.h" #include "graph.h"
@ -49,6 +52,7 @@
#endif #endif
int keylifetime = 0; int keylifetime = 0;
EVP_CIPHER_CTX packet_ctx;
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS]; static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
static void send_udppacket(node_t *, vpn_packet_t *); static void send_udppacket(node_t *, vpn_packet_t *);
@ -81,7 +85,7 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
len = 64; len = 64;
memset(packet.data, 0, 14); memset(packet.data, 0, 14);
randomize(packet.data + 14, len - 14); RAND_pseudo_bytes(packet.data + 14, len - 14);
packet.len = len; packet.len = len;
ifdebug(TRAFFIC) logger(LOG_INFO, _("Sending MTU probe length %d to %s (%s)"), len, n->name, n->hostname); ifdebug(TRAFFIC) logger(LOG_INFO, _("Sending MTU probe length %d to %s (%s)"), len, n->name, n->hostname);
@ -164,14 +168,15 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 }; vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
int nextpkt = 0; int nextpkt = 0;
vpn_packet_t *outpkt = pkt[0]; vpn_packet_t *outpkt = pkt[0];
size_t outlen; int outlen, outpad;
unsigned char hmac[EVP_MAX_MD_SIZE];
int i; int i;
cp(); cp();
/* Check packet length */ /* Check packet length */
if(inpkt->len < sizeof(inpkt->seqno) + digest_length(&myself->digest)) { if(inpkt->len < sizeof(inpkt->seqno) + myself->maclength) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"), ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
n->name, n->hostname); n->name, n->hostname);
return; return;
@ -179,23 +184,33 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
/* Check the message authentication code */ /* Check the message authentication code */
if(digest_active(&myself->digest) && !digest_verify(&myself->digest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len)) { if(myself->digest && myself->maclength) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname); inpkt->len -= myself->maclength;
return; HMAC(myself->digest, myself->key, myself->keylength,
(unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len, myself->maclength)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"),
n->name, n->hostname);
return;
}
} }
/* Decrypt the packet */ /* Decrypt the packet */
if(cipher_active(&myself->cipher)) { if(myself->cipher) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
if(!cipher_decrypt(&myself->cipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) { if(!EVP_DecryptInit_ex(&packet_ctx, NULL, NULL, NULL, NULL)
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s)"), n->name, n->hostname); || !EVP_DecryptUpdate(&packet_ctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_DecryptFinal_ex(&packet_ctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s): %s"),
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
return; return;
} }
outpkt->len = outlen; outpkt->len = outlen + outpad;
inpkt = outpkt; inpkt = outpkt;
} }
@ -268,7 +283,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
int nextpkt = 0; int nextpkt = 0;
vpn_packet_t *outpkt; vpn_packet_t *outpkt;
int origlen; int origlen;
size_t outlen; int outlen, outpad;
vpn_packet_t *copy; vpn_packet_t *copy;
static int priority = 0; static int priority = 0;
int origpriority; int origpriority;
@ -324,24 +339,28 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
/* Encrypt the packet */ /* Encrypt the packet */
if(cipher_active(&n->cipher)) { if(n->cipher) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
if(!cipher_encrypt(&n->cipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) { if(!EVP_EncryptInit_ex(&n->packet_ctx, NULL, NULL, NULL, NULL)
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s)"), n->name, n->hostname); || !EVP_EncryptUpdate(&n->packet_ctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_EncryptFinal_ex(&n->packet_ctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s): %s"),
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
goto end; goto end;
} }
outpkt->len = outlen; outpkt->len = outlen + outpad;
inpkt = outpkt; inpkt = outpkt;
} }
/* Add the message authentication code */ /* Add the message authentication code */
if(digest_active(&n->digest)) { if(n->digest && n->maclength) {
digest_create(&n->digest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len); HMAC(n->digest, n->key, n->keylength, (unsigned char *) &inpkt->seqno,
inpkt->len += digest_length(&n->digest); inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
inpkt->len += n->maclength;
} }
/* Determine which socket we have to use */ /* Determine which socket we have to use */

View file

@ -22,13 +22,17 @@
#include "system.h" #include "system.h"
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include "splay_tree.h" #include "splay_tree.h"
#include "cipher.h"
#include "conf.h" #include "conf.h"
#include "connection.h" #include "connection.h"
#include "control.h" #include "control.h"
#include "device.h" #include "device.h"
#include "digest.h"
#include "graph.h" #include "graph.h"
#include "logger.h" #include "logger.h"
#include "net.h" #include "net.h"
@ -36,7 +40,6 @@
#include "process.h" #include "process.h"
#include "protocol.h" #include "protocol.h"
#include "route.h" #include "route.h"
#include "rsa.h"
#include "subnet.h" #include "subnet.h"
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
@ -47,66 +50,125 @@ static struct event device_ev;
bool read_rsa_public_key(connection_t *c) { bool read_rsa_public_key(connection_t *c) {
FILE *fp; FILE *fp;
char *fname; char *fname;
char *n; char *key;
bool result;
cp(); cp();
if(!c->rsa_key) {
c->rsa_key = RSA_new();
// RSA_blinding_on(c->rsa_key, NULL);
}
/* First, check for simple PublicKey statement */ /* First, check for simple PublicKey statement */
if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) { if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) {
result = rsa_set_hex_public_key(&c->rsa, n, "FFFF"); BN_hex2bn(&c->rsa_key->n, key);
free(n); BN_hex2bn(&c->rsa_key->e, "FFFF");
return result; free(key);
return true;
} }
/* Else, check for PublicKeyFile statement and read it */ /* Else, check for PublicKeyFile statement and read it */
if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) {
asprintf(&fname, "%s/hosts/%s", confbase, c->name); fp = fopen(fname, "r");
fp = fopen(fname, "r"); if(!fp) {
logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
fname, strerror(errno));
free(fname);
return false;
}
if(!fp) {
logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
fname, strerror(errno));
free(fname); free(fname);
c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
fclose(fp);
if(c->rsa_key)
return true; /* Woohoo. */
/* If it fails, try PEM_read_RSA_PUBKEY. */
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
fname, strerror(errno));
free(fname);
return false;
}
free(fname);
c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL);
fclose(fp);
if(c->rsa_key) {
// RSA_blinding_on(c->rsa_key, NULL);
return true;
}
logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"),
fname, strerror(errno));
return false; return false;
} }
result = rsa_read_pem_public_key(&c->rsa, fp); /* Else, check if a harnessed public key is in the config file */
fclose(fp);
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
fp = fopen(fname, "r");
if(fp) {
c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
fclose(fp);
}
if(!result)
logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"), fname, strerror(errno));
free(fname); free(fname);
return result;
if(c->rsa_key)
return true;
/* Try again with PEM_read_RSA_PUBKEY. */
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
fp = fopen(fname, "r");
if(fp) {
c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL);
// RSA_blinding_on(c->rsa_key, NULL);
fclose(fp);
}
free(fname);
if(c->rsa_key)
return true;
logger(LOG_ERR, _("No public key for %s specified!"), c->name);
return false;
} }
bool read_rsa_private_key() { bool read_rsa_private_key(void) {
FILE *fp; FILE *fp;
char *fname; char *fname, *key, *pubkey;
char *n, *d; struct stat s;
bool result;
cp(); cp();
/* First, check for simple PrivateKey statement */ if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) {
if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &pubkey)) {
if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) {
if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &n)) {
logger(LOG_ERR, _("PrivateKey used but no PublicKey found!")); logger(LOG_ERR, _("PrivateKey used but no PublicKey found!"));
free(d);
return false; return false;
} }
result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d); myself->connection->rsa_key = RSA_new();
free(n); // RSA_blinding_on(myself->connection->rsa_key, NULL);
free(d); BN_hex2bn(&myself->connection->rsa_key->d, key);
BN_hex2bn(&myself->connection->rsa_key->n, pubkey);
BN_hex2bn(&myself->connection->rsa_key->e, "FFFF");
free(key);
free(pubkey);
return true; return true;
} }
/* Else, check for PrivateKeyFile statement and read it */
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
asprintf(&fname, "%s/rsa_key.priv", confbase); asprintf(&fname, "%s/rsa_key.priv", confbase);
@ -120,10 +182,9 @@ bool read_rsa_private_key() {
} }
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN) #if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
struct stat s;
if(fstat(fileno(fp), &s)) { if(fstat(fileno(fp), &s)) {
logger(LOG_ERR, _("Could not stat RSA private key file `%s': %s'"), fname, strerror(errno)); logger(LOG_ERR, _("Could not stat RSA private key file `%s': %s'"),
fname, strerror(errno));
free(fname); free(fname);
return false; return false;
} }
@ -132,13 +193,18 @@ bool read_rsa_private_key() {
logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname); logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname);
#endif #endif
result = rsa_read_pem_private_key(&myself->connection->rsa, fp); myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
fclose(fp); fclose(fp);
if(!result) if(!myself->connection->rsa_key) {
logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"), fname, strerror(errno)); logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"),
fname, strerror(errno));
free(fname);
return false;
}
free(fname); free(fname);
return result; return true;
} }
static struct event keyexpire_event; static struct event keyexpire_event;
@ -148,14 +214,10 @@ static void keyexpire_handler(int fd, short events, void *data) {
} }
void regenerate_key() { void regenerate_key() {
ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key")); RAND_pseudo_bytes((unsigned char *)myself->key, myself->keylength);
if(!cipher_regenerate_key(&myself->cipher, true)) {
logger(LOG_ERR, _("Error regenerating key!"));
abort();
}
if(timeout_initialized(&keyexpire_event)) { if(timeout_initialized(&keyexpire_event)) {
ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key"));
event_del(&keyexpire_event); event_del(&keyexpire_event);
send_key_changed(broadcast, myself); send_key_changed(broadcast, myself);
} else { } else {
@ -163,6 +225,16 @@ void regenerate_key() {
} }
event_add(&keyexpire_event, &(struct timeval){keylifetime, 0}); event_add(&keyexpire_event, &(struct timeval){keylifetime, 0});
if(myself->cipher) {
EVP_CIPHER_CTX_init(&packet_ctx);
if(!EVP_DecryptInit_ex(&packet_ctx, myself->cipher, NULL, (unsigned char *)myself->key, (unsigned char *)myself->key + myself->cipher->key_len)) {
logger(LOG_ERR, _("Error during initialisation of cipher for %s (%s): %s"),
myself->name, myself->hostname, ERR_error_string(ERR_get_error(), NULL));
abort();
}
}
} }
/* /*
@ -301,44 +373,73 @@ bool setup_myself(void) {
/* Generate packet encryption key */ /* Generate packet encryption key */
if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) if(get_config_string
cipher = xstrdup("blowfish"); (lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) {
if(!strcasecmp(cipher, "none")) {
myself->cipher = NULL;
} else {
myself->cipher = EVP_get_cipherbyname(cipher);
if(!cipher_open_by_name(&myself->cipher, cipher)) { if(!myself->cipher) {
logger(LOG_ERR, _("Unrecognized cipher type!")); logger(LOG_ERR, _("Unrecognized cipher type!"));
return false; return false;
} }
}
} else
myself->cipher = EVP_bf_cbc();
if(myself->cipher)
myself->keylength = myself->cipher->key_len + myself->cipher->iv_len;
else
myself->keylength = 1;
myself->connection->outcipher = EVP_bf_ofb();
myself->key = xmalloc(myself->keylength);
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
keylifetime = 3600; keylifetime = 3600;
regenerate_key(); regenerate_key();
/* Check if we want to use message authentication codes... */ /* Check if we want to use message authentication codes... */
if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) if(get_config_string
digest = xstrdup("sha1"); (lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
if(!strcasecmp(digest, "none")) {
myself->digest = NULL;
} else {
myself->digest = EVP_get_digestbyname(digest);
if(!digest_open_by_name(&myself->digest, digest)) { if(!myself->digest) {
logger(LOG_ERR, _("Unrecognized digest type!")); logger(LOG_ERR, _("Unrecognized digest type!"));
return false; return false;
} }
if(!get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->maclength))
if(digest_active(&myself->digest)) {
if(myself->maclength > digest_length(&myself->digest)) {
logger(LOG_ERR, _("MAC length exceeds size of digest!"));
return false;
} else if(myself->maclength < 0) {
logger(LOG_ERR, _("Bogus MAC length!"));
return false;
} }
} } else
myself->digest = EVP_sha1();
myself->connection->outdigest = EVP_sha1();
if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"),
&myself->maclength)) {
if(myself->digest) {
if(myself->maclength > myself->digest->md_size) {
logger(LOG_ERR, _("MAC length exceeds size of digest!"));
return false;
} else if(myself->maclength < 0) {
logger(LOG_ERR, _("Bogus MAC length!"));
return false;
}
}
} else
myself->maclength = 4;
myself->connection->outmaclength = 0;
/* Compression */ /* Compression */
if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->compression)) { if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"),
&myself->compression)) {
if(myself->compression < 0 || myself->compression > 11) { if(myself->compression < 0 || myself->compression > 11) {
logger(LOG_ERR, _("Bogus compression level!")); logger(LOG_ERR, _("Bogus compression level!"));
return false; return false;
@ -362,8 +463,8 @@ bool setup_myself(void) {
if(!setup_device()) if(!setup_device())
return false; return false;
event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL); event_set(&device_ev, device_fd, EV_READ|EV_PERSIST,
handle_device_data, NULL);
if (event_add(&device_ev, NULL) < 0) { if (event_add(&device_ev, NULL) < 0) {
logger(LOG_ERR, _("event_add failed: %s"), strerror(errno)); logger(LOG_ERR, _("event_add failed: %s"), strerror(errno));
close_device(); close_device();

View file

@ -74,6 +74,7 @@ node_t *new_node(void) {
n->subnet_tree = new_subnet_tree(); n->subnet_tree = new_subnet_tree();
n->edge_tree = new_edge_tree(); n->edge_tree = new_edge_tree();
n->queue = list_alloc((list_action_t) free); n->queue = list_alloc((list_action_t) free);
EVP_CIPHER_CTX_init(&n->packet_ctx);
n->mtu = MTU; n->mtu = MTU;
n->maxmtu = MTU; n->maxmtu = MTU;
@ -86,6 +87,9 @@ void free_node(node_t *n) {
if(n->queue) if(n->queue)
list_delete_list(n->queue); list_delete_list(n->queue);
if(n->key)
free(n->key);
if(n->subnet_tree) if(n->subnet_tree)
free_subnet_tree(n->subnet_tree); free_subnet_tree(n->subnet_tree);
@ -94,8 +98,7 @@ void free_node(node_t *n) {
sockaddrfree(&n->address); sockaddrfree(&n->address);
cipher_close(&n->cipher); EVP_CIPHER_CTX_cleanup(&n->packet_ctx);
digest_close(&n->digest);
event_del(&n->mtuevent); event_del(&n->mtuevent);
@ -168,8 +171,8 @@ void dump_nodes(void) {
for(node = node_tree->head; node; node = node->next) { for(node = node_tree->head; node; node = node->next) {
n = node->data; n = node->data;
logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)"), logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)"),
n->name, n->hostname, cipher_get_nid(&n->cipher), n->name, n->hostname, n->cipher ? n->cipher->nid : 0,
digest_get_nid(&n->digest), n->maclength, n->compression, n->digest ? n->digest->type : 0, n->maclength, n->compression,
n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-", n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu); n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
} }

View file

@ -24,9 +24,7 @@
#define __TINC_NODE_H__ #define __TINC_NODE_H__
#include "splay_tree.h" #include "splay_tree.h"
#include "cipher.h"
#include "connection.h" #include "connection.h"
#include "digest.h"
#include "list.h" #include "list.h"
#include "subnet.h" #include "subnet.h"
@ -52,9 +50,13 @@ typedef struct node_t {
node_status_t status; node_status_t status;
cipher_t cipher; /* Cipher for UDP packets */ const EVP_CIPHER *cipher; /* Cipher type for UDP packets */
digest_t digest; /* Digest for UDP packets */ char *key; /* Cipher key and iv */
int maclength; /* Portion of digest to use */ int keylength; /* Cipher key and iv length */
EVP_CIPHER_CTX packet_ctx; /* Cipher context */
const EVP_MD *digest; /* Digest type for MAC */
int maclength; /* Length of MAC */
int compression; /* Compressionlevel, 0 = no compression */ int compression; /* Compressionlevel, 0 = no compression */

View file

@ -22,10 +22,14 @@
#include "system.h" #include "system.h"
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include "splay_tree.h" #include "splay_tree.h"
#include "conf.h" #include "conf.h"
#include "connection.h" #include "connection.h"
#include "crypto.h"
#include "edge.h" #include "edge.h"
#include "graph.h" #include "graph.h"
#include "logger.h" #include "logger.h"
@ -33,7 +37,6 @@
#include "netutl.h" #include "netutl.h"
#include "node.h" #include "node.h"
#include "protocol.h" #include "protocol.h"
#include "rsa.h"
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
@ -114,22 +117,27 @@ bool id_h(connection_t *c, char *request) {
} }
bool send_metakey(connection_t *c) { bool send_metakey(connection_t *c) {
size_t len = rsa_size(&c->rsa); char *buffer;
char key[len]; int len;
char enckey[len]; bool x;
char hexkey[2 * len + 1];
cp(); cp();
if(!cipher_open_blowfish_ofb(&c->outcipher)) len = RSA_size(c->rsa_key);
return false;
/* Allocate buffers for the meta key */
buffer = alloca(2 * len + 1);
if(!digest_open_sha1(&c->outdigest)) if(!c->outkey)
return false; c->outkey = xmalloc(len);
/* Create a random key */ if(!c->outctx)
c->outctx = xmalloc_and_zero(sizeof(*c->outctx));
cp();
/* Copy random data to the buffer */
randomize(key, len); RAND_pseudo_bytes((unsigned char *)c->outkey, len);
/* The message we send must be smaller than the modulus of the RSA key. /* The message we send must be smaller than the modulus of the RSA key.
By definition, for a key of k bits, the following formula holds: By definition, for a key of k bits, the following formula holds:
@ -141,14 +149,13 @@ bool send_metakey(connection_t *c) {
This can be done by setting the most significant bit to zero. This can be done by setting the most significant bit to zero.
*/ */
key[0] &= 0x7F; c->outkey[0] &= 0x7F;
cipher_set_key_from_rsa(&c->outcipher, key, len, true);
ifdebug(SCARY_THINGS) { ifdebug(SCARY_THINGS) {
bin2hex(key, hexkey, len); bin2hex(c->outkey, buffer, len);
hexkey[len * 2] = '\0'; buffer[len * 2] = '\0';
logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), hexkey); logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"),
buffer);
} }
/* Encrypt the random data /* Encrypt the random data
@ -158,78 +165,135 @@ bool send_metakey(connection_t *c) {
with a length equal to that of the modulus of the RSA key. with a length equal to that of the modulus of the RSA key.
*/ */
if(!rsa_public_encrypt(&c->rsa, key, len, enckey)) { if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) {
logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"),
c->name, c->hostname);
return false; return false;
} }
/* Convert the encrypted random data to a hexadecimal formatted string */ /* Convert the encrypted random data to a hexadecimal formatted string */
bin2hex(enckey, hexkey, len); bin2hex(buffer, buffer, len);
hexkey[len * 2] = '\0'; buffer[len * 2] = '\0';
/* Send the meta key */ /* Send the meta key */
bool result = send_request(c, "%d %d %d %d %d %s", METAKEY, x = send_request(c, "%d %d %d %d %d %s", METAKEY,
cipher_get_nid(&c->outcipher), c->outcipher ? c->outcipher->nid : 0,
digest_get_nid(&c->outdigest), c->outmaclength, c->outdigest ? c->outdigest->type : 0, c->outmaclength,
c->outcompression, hexkey); c->outcompression, buffer);
c->status.encryptout = true; /* Further outgoing requests are encrypted with the key we just generated */
return result;
if(c->outcipher) {
if(!EVP_EncryptInit(c->outctx, c->outcipher,
(unsigned char *)c->outkey + len - c->outcipher->key_len,
(unsigned char *)c->outkey + len - c->outcipher->key_len -
c->outcipher->iv_len)) {
logger(LOG_ERR, _("Error during initialisation of cipher for %s (%s): %s"),
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
c->status.encryptout = true;
}
return x;
} }
bool metakey_h(connection_t *c, char *request) { bool metakey_h(connection_t *c, char *request) {
char hexkey[MAX_STRING_SIZE]; char buffer[MAX_STRING_SIZE];
int cipher, digest, maclength, compression; int cipher, digest, maclength, compression;
size_t len = rsa_size(&myself->connection->rsa); int len;
char enckey[len];
char key[len];
cp(); cp();
if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, hexkey) != 5) { if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname); logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name,
c->hostname);
return false; return false;
} }
len = RSA_size(myself->connection->rsa_key);
/* Check if the length of the meta key is all right */ /* Check if the length of the meta key is all right */
if(strlen(hexkey) != len * 2) { if(strlen(buffer) != len * 2) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength"); logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength");
return false; return false;
} }
/* Allocate buffers for the meta key */
if(!c->inkey)
c->inkey = xmalloc(len);
if(!c->inctx)
c->inctx = xmalloc_and_zero(sizeof(*c->inctx));
/* Convert the challenge from hexadecimal back to binary */ /* Convert the challenge from hexadecimal back to binary */
hex2bin(hexkey, enckey, len); hex2bin(buffer, buffer, len);
/* Decrypt the meta key */ /* Decrypt the meta key */
if(!rsa_private_decrypt(&myself->connection->rsa, enckey, len, key)) { if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */
logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"),
c->name, c->hostname);
return false; return false;
} }
ifdebug(SCARY_THINGS) { ifdebug(SCARY_THINGS) {
bin2hex(key, hexkey, len); bin2hex(c->inkey, buffer, len);
hexkey[len * 2] = '\0'; buffer[len * 2] = '\0';
logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), hexkey); logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
} }
/* All incoming requests will now be encrypted. */
/* Check and lookup cipher and digest algorithms */ /* Check and lookup cipher and digest algorithms */
if(!cipher_open_by_nid(&c->incipher, cipher) || !cipher_set_key_from_rsa(&c->incipher, key, len, false)) { if(cipher) {
logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s)"), c->name, c->hostname); c->incipher = EVP_get_cipherbynid(cipher);
return false;
if(!c->incipher) {
logger(LOG_ERR, _("%s (%s) uses unknown cipher!"), c->name, c->hostname);
return false;
}
if(!EVP_DecryptInit(c->inctx, c->incipher,
(unsigned char *)c->inkey + len - c->incipher->key_len,
(unsigned char *)c->inkey + len - c->incipher->key_len -
c->incipher->iv_len)) {
logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s): %s"),
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
c->status.decryptin = true;
} else {
c->incipher = NULL;
} }
if(!digest_open_by_nid(&c->indigest, digest)) { c->inmaclength = maclength;
logger(LOG_ERR, _("Error during initialisation of digest from %s (%s)"), c->name, c->hostname);
return false; if(digest) {
c->indigest = EVP_get_digestbynid(digest);
if(!c->indigest) {
logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), c->name, c->hostname);
return false;
}
if(c->inmaclength > c->indigest->md_size || c->inmaclength < 0) {
logger(LOG_ERR, _("%s (%s) uses bogus MAC length!"), c->name, c->hostname);
return false;
}
} else {
c->indigest = NULL;
} }
c->status.decryptin = true; c->incompression = compression;
c->allow_request = CHALLENGE; c->allow_request = CHALLENGE;
@ -237,17 +301,25 @@ bool metakey_h(connection_t *c, char *request) {
} }
bool send_challenge(connection_t *c) { bool send_challenge(connection_t *c) {
size_t len = rsa_size(&c->rsa); char *buffer;
char buffer[len * 2 + 1]; int len;
cp(); cp();
/* CHECKME: what is most reasonable value for len? */
len = RSA_size(c->rsa_key);
/* Allocate buffers for the challenge */
buffer = alloca(2 * len + 1);
if(!c->hischallenge) if(!c->hischallenge)
c->hischallenge = xmalloc(len); c->hischallenge = xmalloc(len);
/* Copy random data to the buffer */ /* Copy random data to the buffer */
randomize(c->hischallenge, len); RAND_pseudo_bytes((unsigned char *)c->hischallenge, len);
/* Convert to hex */ /* Convert to hex */
@ -261,48 +333,72 @@ bool send_challenge(connection_t *c) {
bool challenge_h(connection_t *c, char *request) { bool challenge_h(connection_t *c, char *request) {
char buffer[MAX_STRING_SIZE]; char buffer[MAX_STRING_SIZE];
size_t len = rsa_size(&myself->connection->rsa); int len;
size_t digestlen = digest_length(&c->outdigest);
char digest[digestlen];
cp(); cp();
if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) { if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name, c->hostname); logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name,
c->hostname);
return false; return false;
} }
len = RSA_size(myself->connection->rsa_key);
/* Check if the length of the challenge is all right */ /* Check if the length of the challenge is all right */
if(strlen(buffer) != len * 2) { if(strlen(buffer) != len * 2) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong challenge length"); logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
c->hostname, "wrong challenge length");
return false; return false;
} }
/* Allocate buffers for the challenge */
if(!c->mychallenge)
c->mychallenge = xmalloc(len);
/* Convert the challenge from hexadecimal back to binary */ /* Convert the challenge from hexadecimal back to binary */
hex2bin(buffer, buffer, len); hex2bin(buffer, c->mychallenge, len);
c->allow_request = CHAL_REPLY; c->allow_request = CHAL_REPLY;
/* Rest is done by send_chal_reply() */
return send_chal_reply(c);
}
bool send_chal_reply(connection_t *c) {
char hash[EVP_MAX_MD_SIZE * 2 + 1];
EVP_MD_CTX ctx;
cp(); cp();
/* Calculate the hash from the challenge we received */ /* Calculate the hash from the challenge we received */
digest_create(&c->indigest, buffer, len, digest); if(!EVP_DigestInit(&ctx, c->indigest)
|| !EVP_DigestUpdate(&ctx, c->mychallenge, RSA_size(myself->connection->rsa_key))
|| !EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL)) {
logger(LOG_ERR, _("Error during calculation of response for %s (%s): %s"),
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
/* Convert the hash to a hexadecimal formatted string */ /* Convert the hash to a hexadecimal formatted string */
bin2hex(digest, buffer, digestlen); bin2hex(hash, hash, c->indigest->md_size);
buffer[digestlen * 2] = '\0'; hash[c->indigest->md_size * 2] = '\0';
/* Send the reply */ /* Send the reply */
return send_request(c, "%d %s", CHAL_REPLY, buffer); return send_request(c, "%d %s", CHAL_REPLY, hash);
} }
bool chal_reply_h(connection_t *c, char *request) { bool chal_reply_h(connection_t *c, char *request) {
char hishash[MAX_STRING_SIZE]; char hishash[MAX_STRING_SIZE];
char myhash[EVP_MAX_MD_SIZE];
EVP_MD_CTX ctx;
cp(); cp();
@ -314,19 +410,38 @@ bool chal_reply_h(connection_t *c, char *request) {
/* Check if the length of the hash is all right */ /* Check if the length of the hash is all right */
if(strlen(hishash) != digest_length(&c->outdigest) * 2) { if(strlen(hishash) != c->outdigest->md_size * 2) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length")); logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
c->hostname, _("wrong challenge reply length"));
return false; return false;
} }
/* Convert the hash to binary format */ /* Convert the hash to binary format */
hex2bin(hishash, hishash, digest_length(&c->outdigest)); hex2bin(hishash, hishash, c->outdigest->md_size);
/* Verify the hash */ /* Calculate the hash from the challenge we sent */
if(!EVP_DigestInit(&ctx, c->outdigest)
|| !EVP_DigestUpdate(&ctx, c->hischallenge, RSA_size(c->rsa_key))
|| !EVP_DigestFinal(&ctx, (unsigned char *)myhash, NULL)) {
logger(LOG_ERR, _("Error during calculation of response from %s (%s): %s"),
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
/* Verify the incoming hash with the calculated hash */
if(memcmp(hishash, myhash, c->outdigest->md_size)) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
c->hostname, _("wrong challenge reply"));
ifdebug(SCARY_THINGS) {
bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
hishash[SHA_DIGEST_LENGTH * 2] = '\0';
logger(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
}
if(!digest_verify(&c->outdigest, c->hischallenge, rsa_size(&c->rsa), hishash)) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply"));
return false; return false;
} }
@ -334,8 +449,6 @@ bool chal_reply_h(connection_t *c, char *request) {
Send an acknowledgement with the rest of the information needed. Send an acknowledgement with the rest of the information needed.
*/ */
free(c->hischallenge);
c->hischallenge = NULL;
c->allow_request = ACK; c->allow_request = ACK;
return send_ack(c); return send_ack(c);

View file

@ -22,8 +22,10 @@
#include "system.h" #include "system.h"
#include <openssl/evp.h>
#include <openssl/err.h>
#include "splay_tree.h" #include "splay_tree.h"
#include "cipher.h"
#include "connection.h" #include "connection.h"
#include "logger.h" #include "logger.h"
#include "net.h" #include "net.h"
@ -33,7 +35,7 @@
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
static bool mykeyused = false; bool mykeyused = false;
bool send_key_changed(connection_t *c, const node_t *n) { bool send_key_changed(connection_t *c, const node_t *n) {
cp(); cp();
@ -135,19 +137,18 @@ bool req_key_h(connection_t *c, char *request) {
} }
bool send_ans_key(connection_t *c, const node_t *from, const node_t *to) { bool send_ans_key(connection_t *c, const node_t *from, const node_t *to) {
size_t keylen = cipher_keylength(&from->cipher); char *key;
char key[keylen];
cp(); cp();
cipher_get_key(&from->cipher, key); key = alloca(2 * from->keylength + 1);
bin2hex(key, key, keylen); bin2hex(from->key, key, from->keylength);
key[keylen * 2] = '\0'; key[from->keylength * 2] = '\0';
return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY, return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY,
from->name, to->name, key, from->name, to->name, key,
cipher_get_nid(&from->cipher), from->cipher ? from->cipher->nid : 0,
digest_get_nid(&from->digest), from->maclength, from->digest ? from->digest->type : 0, from->maclength,
from->compression); from->compression);
} }
@ -193,28 +194,58 @@ bool ans_key_h(connection_t *c, char *request) {
return send_request(to->nexthop->connection, "%s", request); return send_request(to->nexthop->connection, "%s", request);
} }
/* Update our copy of the origin's packet key */
if(from->key)
free(from->key);
from->key = xstrdup(key);
from->keylength = strlen(key) / 2;
hex2bin(from->key, from->key, from->keylength);
from->key[from->keylength] = '\0';
from->status.validkey = true;
from->status.waitingforkey = false;
from->sent_seqno = 0;
/* Check and lookup cipher and digest algorithms */ /* Check and lookup cipher and digest algorithms */
if(!cipher_open_by_nid(&from->cipher, cipher)) { if(cipher) {
logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname); from->cipher = EVP_get_cipherbynid(cipher);
return false;
}
if(strlen(key) / 2 != cipher_keylength(&from->cipher)) { if(!from->cipher) {
logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname); logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name,
return false; from->hostname);
return false;
}
if(from->keylength != from->cipher->key_len + from->cipher->iv_len) {
logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name,
from->hostname);
return false;
}
} else {
from->cipher = NULL;
} }
from->maclength = maclength; from->maclength = maclength;
if(!digest_open_by_nid(&from->digest, digest)) { if(digest) {
logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname); from->digest = EVP_get_digestbynid(digest);
return false;
}
if(from->maclength > digest_length(&from->digest) || from->maclength < 0) { if(!from->digest) {
logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname); logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name,
return false; from->hostname);
return false;
}
if(from->maclength > from->digest->md_size || from->maclength < 0) {
logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"),
from->name, from->hostname);
return false;
}
} else {
from->digest = NULL;
} }
if(compression < 0 || compression > 11) { if(compression < 0 || compression > 11) {
@ -224,14 +255,12 @@ bool ans_key_h(connection_t *c, char *request) {
from->compression = compression; from->compression = compression;
/* Update our copy of the origin's packet key */ if(from->cipher)
if(!EVP_EncryptInit_ex(&from->packet_ctx, from->cipher, NULL, (unsigned char *)from->key, (unsigned char *)from->key + from->cipher->key_len)) {
hex2bin(key, key, cipher_keylength(&from->cipher)); logger(LOG_ERR, _("Error during initialisation of key from %s (%s): %s"),
cipher_set_key(&from->cipher, key, false); from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
from->status.validkey = true; }
from->status.waitingforkey = false;
from->sent_seqno = 0;
if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes) if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes)
send_mtu_probe(from); send_mtu_probe(from);

View file

@ -31,13 +31,18 @@
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
#include LZO1X_H #include LZO1X_H
#include <getopt.h> #include <getopt.h>
#include "conf.h" #include "conf.h"
#include "control.h" #include "control.h"
#include "crypto.h"
#include "device.h" #include "device.h"
#include "logger.h" #include "logger.h"
#include "net.h" #include "net.h"
@ -290,7 +295,12 @@ int main(int argc, char **argv)
/* Slllluuuuuuurrrrp! */ /* Slllluuuuuuurrrrp! */
srand(time(NULL)); srand(time(NULL));
crypto_init(); RAND_load_file("/dev/urandom", 1024);
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
OpenSSL_add_all_algorithms();
if(!read_server_config()) if(!read_server_config())
return 1; return 1;
@ -343,7 +353,7 @@ end:
exit_control(); exit_control();
#endif #endif
crypto_exit(); EVP_cleanup();
return status; return status;
} }