Use the crypto wrappers again instead of calling OpenSSL directly.

This theoretically allows other cryptographic libraries to be used,
and it improves the readability of the code.
This commit is contained in:
Guus Sliepen 2008-12-11 14:44:44 +00:00
parent 8c69f42d7d
commit 046158a216
10 changed files with 239 additions and 527 deletions

View file

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

View file

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

View file

@ -22,10 +22,8 @@
#include "system.h"
#include <openssl/err.h>
#include <openssl/evp.h>
#include "splay_tree.h"
#include "cipher.h"
#include "connection.h"
#include "logger.h"
#include "meta.h"
@ -35,8 +33,6 @@
#include "xalloc.h"
bool send_meta(connection_t *c, const char *buffer, int length) {
int outlen;
int result;
cp();
ifdebug(META) logger(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length,
@ -45,11 +41,11 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
/* Add our data to buffer */
if(c->status.encryptout) {
char outbuf[length];
size_t outlen = length;
result = EVP_EncryptUpdate(c->outctx, (unsigned char *)outbuf, &outlen, (unsigned char *)buffer, length);
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));
if(!cipher_encrypt(&c->outcipher, buffer, length, outbuf, &outlen, false) || outlen != length) {
logger(LOG_ERR, _("Error while encrypting metadata to %s (%s)"),
c->name, c->hostname);
return false;
}
@ -80,7 +76,7 @@ void broadcast_meta(connection_t *from, const char *buffer, int length) {
}
bool receive_meta(connection_t *c) {
int result, inlen, outlen;
size_t inlen;
char inbuf[MAXBUFSIZE];
char *bufp = inbuf, *endp;
@ -115,12 +111,13 @@ bool receive_meta(connection_t *c) {
inlen -= endp - bufp;
bufp = endp;
} else {
size_t outlen = inlen;
ifdebug(META) logger(LOG_DEBUG, _("Received encrypted %d bytes"), 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(!result || outlen != inlen) {
logger(LOG_ERR, _("Error while decrypting metadata from %s (%s): %s"),
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
if(!cipher_decrypt(&c->incipher, bufp, inlen, c->buffer->input->buffer + c->buffer->input->off, &outlen, false) || inlen != outlen) {
logger(LOG_ERR, _("Error while decrypting metadata from %s (%s)"),
c->name, c->hostname);
return false;
}
c->buffer->input->off += inlen;
@ -146,8 +143,10 @@ bool receive_meta(connection_t *c) {
char *request = evbuffer_readline(c->buffer->input);
if(request) {
receive_request(c, request);
bool result = receive_request(c, request);
free(request);
if(!result)
return false;
continue;
} else {
break;

View file

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

View file

@ -22,17 +22,13 @@
#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 "cipher.h"
#include "conf.h"
#include "connection.h"
#include "control.h"
#include "device.h"
#include "digest.h"
#include "graph.h"
#include "logger.h"
#include "net.h"
@ -40,6 +36,7 @@
#include "process.h"
#include "protocol.h"
#include "route.h"
#include "rsa.h"
#include "subnet.h"
#include "utils.h"
#include "xalloc.h"
@ -50,125 +47,66 @@ static struct event device_ev;
bool read_rsa_public_key(connection_t *c) {
FILE *fp;
char *fname;
char *key;
char *n;
bool result;
cp();
if(!c->rsa_key) {
c->rsa_key = RSA_new();
// RSA_blinding_on(c->rsa_key, NULL);
}
/* First, check for simple PublicKey statement */
if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) {
BN_hex2bn(&c->rsa_key->n, key);
BN_hex2bn(&c->rsa_key->e, "FFFF");
free(key);
return true;
if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) {
result = rsa_set_hex_public_key(&c->rsa, n, "FFFF");
free(n);
return result;
}
/* Else, check for PublicKeyFile statement and read it */
if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) {
fp = fopen(fname, "r");
if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname))
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
if(!fp) {
logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
fname, strerror(errno));
free(fname);
return false;
}
fp = fopen(fname, "r");
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"),
if(!fp) {
logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
fname, strerror(errno));
free(fname);
return false;
}
/* Else, check if a harnessed public key is in the config file */
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);
}
result = rsa_read_pem_public_key(&c->rsa, fp);
fclose(fp);
if(!result)
logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"), fname, strerror(errno));
free(fname);
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;
return result;
}
bool read_rsa_private_key(void) {
bool read_rsa_private_key() {
FILE *fp;
char *fname, *key, *pubkey;
struct stat s;
char *fname;
char *n, *d;
bool result;
cp();
if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) {
if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &pubkey)) {
/* First, check for simple PrivateKey statement */
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!"));
free(d);
return false;
}
myself->connection->rsa_key = RSA_new();
// RSA_blinding_on(myself->connection->rsa_key, NULL);
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);
result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d);
free(n);
free(d);
return true;
}
/* Else, check for PrivateKeyFile statement and read it */
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
asprintf(&fname, "%s/rsa_key.priv", confbase);
@ -182,9 +120,10 @@ bool read_rsa_private_key(void) {
}
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
struct stat 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);
return false;
}
@ -193,18 +132,13 @@ bool read_rsa_private_key(void) {
logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname);
#endif
myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
fclose(fp);
if(!myself->connection->rsa_key) {
logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"),
fname, strerror(errno));
free(fname);
return false;
}
if(!result)
logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"), fname, strerror(errno));
free(fname);
return true;
return result;
}
static struct event keyexpire_event;
@ -214,10 +148,14 @@ static void keyexpire_handler(int fd, short events, void *data) {
}
void regenerate_key() {
RAND_pseudo_bytes((unsigned char *)myself->key, myself->keylength);
ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key"));
if(!cipher_regenerate_key(&myself->cipher, true)) {
logger(LOG_ERR, _("Error regenerating key!"));
abort();
}
if(timeout_initialized(&keyexpire_event)) {
ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key"));
event_del(&keyexpire_event);
send_key_changed(broadcast, myself);
} else {
@ -225,16 +163,6 @@ void regenerate_key() {
}
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();
}
}
}
/*
@ -373,73 +301,44 @@ bool setup_myself(void) {
/* Generate packet encryption key */
if(get_config_string
(lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) {
if(!strcasecmp(cipher, "none")) {
myself->cipher = NULL;
} else {
myself->cipher = EVP_get_cipherbyname(cipher);
if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
cipher = xstrdup("blowfish");
if(!myself->cipher) {
logger(LOG_ERR, _("Unrecognized cipher type!"));
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(!cipher_open_by_name(&myself->cipher, cipher)) {
logger(LOG_ERR, _("Unrecognized cipher type!"));
return false;
}
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
keylifetime = 3600;
regenerate_key();
/* Check if we want to use message authentication codes... */
if(get_config_string
(lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
if(!strcasecmp(digest, "none")) {
myself->digest = NULL;
} else {
myself->digest = EVP_get_digestbyname(digest);
if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
digest = xstrdup("sha1");
if(!myself->digest) {
logger(LOG_ERR, _("Unrecognized digest type!"));
return false;
}
if(!digest_open_by_name(&myself->digest, digest)) {
logger(LOG_ERR, _("Unrecognized digest type!"));
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 */
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) {
logger(LOG_ERR, _("Bogus compression level!"));
return false;
@ -463,8 +362,8 @@ bool setup_myself(void) {
if(!setup_device())
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) {
logger(LOG_ERR, _("event_add failed: %s"), strerror(errno));
close_device();

View file

@ -74,7 +74,6 @@ node_t *new_node(void) {
n->subnet_tree = new_subnet_tree();
n->edge_tree = new_edge_tree();
n->queue = list_alloc((list_action_t) free);
EVP_CIPHER_CTX_init(&n->packet_ctx);
n->mtu = MTU;
n->maxmtu = MTU;
@ -87,9 +86,6 @@ void free_node(node_t *n) {
if(n->queue)
list_delete_list(n->queue);
if(n->key)
free(n->key);
if(n->subnet_tree)
free_subnet_tree(n->subnet_tree);
@ -98,7 +94,8 @@ void free_node(node_t *n) {
sockaddrfree(&n->address);
EVP_CIPHER_CTX_cleanup(&n->packet_ctx);
cipher_close(&n->cipher);
digest_close(&n->digest);
event_del(&n->mtuevent);
@ -169,8 +166,8 @@ int dump_nodes(struct evbuffer *out) {
for(node = node_tree->head; node; node = node->next) {
n = node->data;
if(evbuffer_add_printf(out, _(" %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"),
n->name, n->hostname, n->cipher ? n->cipher->nid : 0,
n->digest ? n->digest->type : 0, n->maclength, n->compression,
n->name, n->hostname, cipher_get_nid(&n->cipher),
digest_get_nid(&n->digest), n->maclength, n->compression,
n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu) == -1)
return errno;

View file

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

View file

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

View file

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

View file

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