Finish crypto wrapping. Also provide wrappers for OpenSSL.
Disable libgcrypt by default. Since it doesn't support the OFB cipher mode, we can't use it in a backwards compatible way.
This commit is contained in:
parent
f42e57f663
commit
1b8f891836
28 changed files with 951 additions and 497 deletions
12
configure.in
12
configure.in
|
@ -145,11 +145,21 @@ AC_CACHE_SAVE
|
|||
|
||||
dnl These are defined in files in m4/
|
||||
|
||||
AM_PATH_LIBGCRYPT([], [], [AC_MSG_ERROR([Libgcrypt not found.]); break])
|
||||
AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
|
||||
|
||||
AM_PATH_LIBGCRYPT([], [], [])
|
||||
tinc_OPENSSL
|
||||
tinc_ZLIB
|
||||
tinc_LZO
|
||||
|
||||
if test "$with_libgcrypt" = yes; then
|
||||
AC_MSG_ERROR([Libgcrypt support not fully implemented yet.]);
|
||||
break;
|
||||
else
|
||||
ln -sf openssl/crypto.c openssl/crypto.h openssl/cipher.c openssl/cipher.h openssl/digest.c openssl/digest.h openssl/rsa.c openssl/rsa.h src/
|
||||
fi
|
||||
|
||||
|
||||
dnl Check if support for jumbograms is requested
|
||||
AC_ARG_ENABLE(jumbograms,
|
||||
AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
|
||||
|
|
|
@ -5,7 +5,7 @@ sbin_PROGRAMS = tincd tincctl
|
|||
|
||||
EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h raw_socket/device.c uml_socket/device.c
|
||||
|
||||
tincd_SOURCES = conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
|
||||
tincd_SOURCES = cipher.c conf.c connection.c control.c crypto.c digest.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
|
||||
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c route.c rsa.c subnet.c tincd.c
|
||||
|
||||
|
@ -17,14 +17,13 @@ DEFAULT_INCLUDES =
|
|||
|
||||
INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib
|
||||
|
||||
noinst_HEADERS = conf.h connection.h control.h device.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
noinst_HEADERS = cipher.h conf.h connection.h control.h crypto.h device.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h rsa.h subnet.h
|
||||
|
||||
LIBS = @LIBS@ @LIBINTL@
|
||||
|
||||
tincd_LDADD = \
|
||||
$(top_builddir)/lib/libvpn.a \
|
||||
$(LIBGCRYPT_LIBS)
|
||||
$(top_builddir)/lib/libvpn.a
|
||||
|
||||
tincctl_LDADD = \
|
||||
$(top_builddir)/lib/libvpn.a
|
||||
|
@ -32,7 +31,6 @@ tincctl_LDADD = \
|
|||
localedir = $(datadir)/locale
|
||||
|
||||
AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\"
|
||||
tinc_CPPFLAGS = $(LIBGCRYPT_CFLAGS)
|
||||
|
||||
dist-hook:
|
||||
rm -f `find . -type l`
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -23,11 +23,10 @@
|
|||
#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"
|
||||
|
||||
|
@ -73,24 +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 */
|
||||
struct rsa_key_t 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 */
|
||||
|
|
|
@ -104,7 +104,7 @@ static bool cipher_open(cipher_t *cipher, int algo, int mode) {
|
|||
}
|
||||
|
||||
if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
|
||||
logger(LOG_DEBUG, _("Unable to intialise cipher %d mode %d!"), algo, mode);
|
||||
logger(LOG_DEBUG, _("Unable to intialise cipher %d mode %d: %s"), algo, mode, gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ void cipher_get_key(const cipher_t *cipher, void *key) {
|
|||
memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
|
||||
}
|
||||
|
||||
bool cipher_set_key(cipher_t *cipher, void *key) {
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
||||
memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
|
||||
|
||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
||||
|
@ -173,7 +173,17 @@ bool cipher_set_key(cipher_t *cipher, void *key) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool cipher_regenerate_key(cipher_t *cipher) {
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, size_t len, bool encrypt) {
|
||||
memcpy(cipher->key, key + len - cipher->keylen, cipher->keylen + cipher->blklen);
|
||||
memcpy(cipher->key + cipher->keylen, key + len - cipher->keylen - cipher->blklen, cipher->blklen);
|
||||
|
||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
|
||||
gcry_create_nonce(cipher->key, cipher->keylen + cipher->blklen);
|
||||
|
||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
||||
|
@ -182,7 +192,7 @@ bool cipher_regenerate_key(cipher_t *cipher) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool cipher_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
|
||||
static bool cipher_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
|
||||
size_t reqlen;
|
||||
|
||||
if(cipher->blklen == 1) {
|
||||
|
@ -200,7 +210,7 @@ bool cipher_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *ou
|
|||
return true;
|
||||
}
|
||||
|
||||
bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
|
||||
static bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
|
||||
size_t origlen;
|
||||
|
||||
if(cipher->blklen == 1) {
|
||||
|
@ -217,33 +227,32 @@ bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool cipher_encrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen) {
|
||||
bool cipher_encrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
gcry_error_t err;
|
||||
|
||||
// To be fixed
|
||||
|
||||
if((err = gcry_cipher_encrypt(cipher->handle, outdata, inlen, indata, inlen))) {
|
||||
logger(LOG_ERR, _("Error while encrypting"));
|
||||
logger(LOG_ERR, _("Error while encrypting: %s"), gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_decrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen) {
|
||||
bool cipher_decrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
gcry_error_t err;
|
||||
|
||||
// To be fixed
|
||||
|
||||
if((err = gcry_cipher_decrypt(cipher->handle, outdata, inlen, indata, inlen))) {
|
||||
logger(LOG_ERR, _("Error while encrypting"));
|
||||
logger(LOG_ERR, _("Error while decrypting: %s"), gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cipher_reset(cipher_t *cipher) {
|
||||
gcry_cipher_reset(cipher->handle);
|
||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
}
|
||||
|
||||
int cipher_get_nid(const cipher_t *cipher) {
|
||||
return cipher->nid;
|
||||
}
|
|
@ -37,12 +37,12 @@ extern bool cipher_open_by_nid(struct cipher *, int);
|
|||
extern bool cipher_open_blowfish_ofb(struct cipher *);
|
||||
extern void cipher_close(struct cipher *);
|
||||
extern size_t cipher_keylength(const struct cipher *);
|
||||
extern void cipher_get_key(const struct cipher *, void *);
|
||||
extern bool cipher_set_key(struct cipher *, void *);
|
||||
extern void cipher_get_key(const struct cipher *, void *, bool);
|
||||
extern bool cipher_set_key(struct cipher *, void *, bool);
|
||||
extern bool cipher_set_key_from_rsa(struct cipher *, void *, size_t, bool);
|
||||
extern bool cipher_regenerate_key(struct cipher *);
|
||||
extern void cipher_reset(struct cipher *);
|
||||
extern bool cipher_encrypt(struct cipher *, void *indata, size_t inlen, void *outdata, size_t *outlen);
|
||||
extern bool cipher_decrypt(struct cipher *, void *indata, size_t inlen, void *outdata, size_t *outlen);
|
||||
extern bool cipher_encrypt(struct cipher *, void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot);
|
||||
extern bool cipher_decrypt(struct cipher *, void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot);
|
||||
extern int cipher_get_nid(const struct cipher *);
|
||||
extern bool cipher_active(const struct cipher *);
|
||||
|
36
src/gcrypt/crypto.c
Normal file
36
src/gcrypt/crypto.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
crypto.c -- Cryptographic miscellaneous functions and initialisation
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
void crypto_init() {
|
||||
}
|
||||
|
||||
void crypto_exit() {
|
||||
}
|
||||
|
||||
void randomize(void *out, size_t outlen) {
|
||||
gcry_create_nonce(out, outlen);
|
||||
}
|
29
src/gcrypt/crypto.h
Normal file
29
src/gcrypt/crypto.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
crypto.h -- header for crypto.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __TINC_CRYPTO_H__
|
||||
#define __TINC_CRYPTO_H__
|
||||
|
||||
extern void crypto_init();
|
||||
extern void crypto_exit();
|
||||
extern void randomize(void *, size_t);
|
||||
|
||||
#endif
|
|
@ -115,16 +115,16 @@ bool digest_open_sha1(digest_t *digest) {
|
|||
void digest_close(digest_t *digest) {
|
||||
}
|
||||
|
||||
bool digest_create(digest_t *digest, void *indata, size_t inlen, void *outdata) {
|
||||
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
|
||||
gcry_md_hash_buffer(digest->algo, outdata, indata, inlen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digest_verify(digest_t *digest, void *indata, size_t inlen, void *cmpdata) {
|
||||
bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
|
||||
char outdata[digest->len];
|
||||
|
||||
gcry_md_hash_buffer(digest->algo, outdata, indata, inlen);
|
||||
return !memcmp(indata, outdata, digest->len);
|
||||
return !memcmp(cmpdata, outdata, digest->len);
|
||||
}
|
||||
|
||||
int digest_get_nid(const digest_t *digest) {
|
|
@ -30,14 +30,14 @@ typedef struct digest {
|
|||
uint16_t len;
|
||||
} digest_t;
|
||||
|
||||
bool digest_open_by_name(struct digest *, const char *);
|
||||
bool digest_open_by_nid(struct digest *, int);
|
||||
bool digest_open_sha1(struct digest *);
|
||||
void digest_close(struct digest *);
|
||||
bool digest_create(struct digest *, void *indata, size_t inlen, void *outdata);
|
||||
bool digest_verify(struct digest *, void *indata, size_t inlen, void *digestdata);
|
||||
int digest_get_nid(const struct digest *);
|
||||
size_t digest_length(const struct digest *);
|
||||
bool digest_active(const struct digest *);
|
||||
static bool digest_open_by_name(struct digest *, const char *);
|
||||
static bool digest_open_by_nid(struct digest *, int);
|
||||
static bool digest_open_sha1(struct digest *);
|
||||
static void digest_close(struct digest *);
|
||||
static bool digest_create(struct digest *, const void *indata, size_t inlen, void *outdata);
|
||||
static bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
|
||||
static int digest_get_nid(const struct digest *);
|
||||
static size_t digest_length(const struct digest *);
|
||||
static bool digest_active(const struct digest *);
|
||||
|
||||
#endif
|
|
@ -184,9 +184,34 @@ static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
|
|||
return mpi ? !err : true;
|
||||
}
|
||||
|
||||
bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
|
||||
gcry_error_t err = 0;
|
||||
|
||||
err = gcry_mpi_scan(&rsa->n, GCRY_FMT_HEX, n, 0, NULL)
|
||||
?: gcry_mpi_scan(&rsa->e, GCRY_FMT_HEX, n, 0, NULL);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_ERR, _("Error while reading RSA public key: %s"), gcry_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
|
||||
gcry_error_t err = 0;
|
||||
|
||||
err = gcry_mpi_scan(&rsa->n, GCRY_FMT_HEX, n, 0, NULL)
|
||||
?: gcry_mpi_scan(&rsa->e, GCRY_FMT_HEX, n, 0, NULL)
|
||||
?: gcry_mpi_scan(&rsa->d, GCRY_FMT_HEX, n, 0, NULL);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_ERR, _("Error while reading RSA public key: %s"), gcry_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Read PEM RSA keys
|
||||
|
||||
bool read_pem_rsa_public_key(FILE *fp, rsa_key_t *key) {
|
||||
bool read_pem_rsa_public_key(rsa_t *rsa, FILE *fp) {
|
||||
uint8_t derbuf[8096], *derp = derbuf;
|
||||
size_t derlen;
|
||||
|
||||
|
@ -196,8 +221,8 @@ bool read_pem_rsa_public_key(FILE *fp, rsa_key_t *key) {
|
|||
}
|
||||
|
||||
if(!ber_read_sequence(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, &key->n)
|
||||
|| !ber_read_mpi(&derp, &derlen, &key->e)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->n)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->e)
|
||||
|| derlen) {
|
||||
logger(LOG_ERR, _("Error while decoding RSA public key"));
|
||||
return NULL;
|
||||
|
@ -206,7 +231,7 @@ bool read_pem_rsa_public_key(FILE *fp, rsa_key_t *key) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool read_pem_rsa_private_key(FILE *fp, rsa_key_t *key) {
|
||||
bool read_pem_rsa_private_key(rsa_t *rsa, FILE *fp) {
|
||||
uint8_t derbuf[8096], *derp = derbuf;
|
||||
size_t derlen;
|
||||
|
||||
|
@ -217,9 +242,9 @@ bool read_pem_rsa_private_key(FILE *fp, rsa_key_t *key) {
|
|||
|
||||
if(!ber_read_sequence(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, &key->n)
|
||||
|| !ber_read_mpi(&derp, &derlen, &key->e)
|
||||
|| !ber_read_mpi(&derp, &derlen, &key->d)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->n)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->e)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->d)
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL) // p
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL) // q
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL)
|
||||
|
@ -233,8 +258,8 @@ bool read_pem_rsa_private_key(FILE *fp, rsa_key_t *key) {
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned int get_rsa_size(rsa_key_t *key) {
|
||||
return (gcry_mpi_get_nbits(key->n) + 7) / 8;
|
||||
size_t rsa_size(rsa_t *rsa) {
|
||||
return (gcry_mpi_get_nbits(rsa->n) + 7) / 8;
|
||||
}
|
||||
|
||||
/* Well, libgcrypt has functions to handle RSA keys, but they suck.
|
||||
|
@ -244,24 +269,24 @@ unsigned int get_rsa_size(rsa_key_t *key) {
|
|||
// TODO: get rid of this macro, properly clean up gcry_ structures after use
|
||||
#define check(foo) { gcry_error_t err = (foo); if(err) {logger(LOG_ERR, "gcrypt error %s/%s at %s:%d\n", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
|
||||
|
||||
bool rsa_public_encrypt(size_t len, void *in, void *out, rsa_key_t *key) {
|
||||
bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
||||
gcry_mpi_t inmpi;
|
||||
check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
|
||||
|
||||
gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
|
||||
gcry_mpi_powm(outmpi, inmpi, key->e, key->n);
|
||||
gcry_mpi_powm(outmpi, inmpi, rsa->e, rsa->n);
|
||||
|
||||
check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rsa_private_decrypt(size_t len, void *in, void *out, rsa_key_t *key) {
|
||||
bool rsa_public_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
||||
gcry_mpi_t inmpi;
|
||||
check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
|
||||
|
||||
gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
|
||||
gcry_mpi_powm(outmpi, inmpi, key->d, key->n);
|
||||
gcry_mpi_powm(outmpi, inmpi, rsa->d, rsa->n);
|
||||
|
||||
check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
|
||||
|
|
@ -24,17 +24,18 @@
|
|||
|
||||
#include <gcrypt.h>
|
||||
|
||||
typedef struct rsa_key_t {
|
||||
typedef struct rsa {
|
||||
gcry_mpi_t n;
|
||||
gcry_mpi_t e;
|
||||
gcry_mpi_t d;
|
||||
} rsa_key_t;
|
||||
|
||||
extern bool read_pem_rsa_public_key(FILE *fp, struct rsa_key_t *key);
|
||||
extern bool read_pem_rsa_private_key(FILE *fp, struct rsa_key_t *key);
|
||||
extern unsigned int get_rsa_size(struct rsa_key_t *key);
|
||||
extern bool rsa_public_encrypt(size_t len, void *in, void *out, struct rsa_key_t *key);
|
||||
extern bool rsa_private_decrypt(size_t len, void *in, void *out, struct rsa_key_t *key);
|
||||
} rsa_t;
|
||||
|
||||
extern bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e);
|
||||
extern bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d);
|
||||
extern bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp);
|
||||
extern bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp);
|
||||
extern size_t rsa_size(rsa_t *rsa);
|
||||
extern bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out);
|
||||
extern bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out);
|
||||
|
||||
#endif
|
39
src/meta.c
39
src/meta.c
|
@ -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,31 +33,23 @@
|
|||
#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,
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, _("Encrypted write %p %p %p %d"), c, c->buffer, outbuf, length);
|
||||
bufferevent_write(c->buffer, (void *)outbuf, length);
|
||||
logger(LOG_DEBUG, _("Done."));
|
||||
} else {
|
||||
logger(LOG_DEBUG, _("Unencrypted write %p %p %p %d"), c, c->buffer, buffer, length);
|
||||
bufferevent_write(c->buffer, (void *)buffer, length);
|
||||
logger(LOG_DEBUG, _("Done."));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -80,7 +70,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;
|
||||
|
||||
|
@ -110,23 +100,20 @@ bool receive_meta(connection_t *c) {
|
|||
else
|
||||
endp = bufp + inlen;
|
||||
|
||||
logger(LOG_DEBUG, _("Received unencrypted %ld of %d bytes"), endp - bufp, inlen);
|
||||
|
||||
evbuffer_add(c->buffer->input, bufp, endp - bufp);
|
||||
|
||||
inlen -= endp - bufp;
|
||||
bufp = endp;
|
||||
} else {
|
||||
logger(LOG_DEBUG, _("Received encrypted %d bytes"), inlen);
|
||||
size_t outlen = inlen;
|
||||
evbuffer_expand(c->buffer->input, inlen);
|
||||
result = EVP_DecryptUpdate(c->inctx, (unsigned char *)c->buffer->input->buffer, &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, &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;
|
||||
|
||||
c->buffer->input->off += inlen;
|
||||
inlen = 0;
|
||||
}
|
||||
|
||||
|
@ -148,8 +135,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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
143
src/net_setup.c
143
src/net_setup.c
|
@ -22,19 +22,13 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include <gcrypt.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"
|
||||
|
@ -53,10 +47,21 @@ static struct event device_ev;
|
|||
bool read_rsa_public_key(connection_t *c) {
|
||||
FILE *fp;
|
||||
char *fname;
|
||||
char *n;
|
||||
bool result;
|
||||
|
||||
cp();
|
||||
|
||||
/* First, check for simple PublicKey statement */
|
||||
|
||||
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))
|
||||
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
|
||||
|
||||
|
@ -69,7 +74,7 @@ bool read_rsa_public_key(connection_t *c) {
|
|||
return false;
|
||||
}
|
||||
|
||||
result = read_pem_rsa_public_key(fp, &c->rsa_key);
|
||||
result = rsa_read_pem_public_key(&c->rsa, fp);
|
||||
fclose(fp);
|
||||
|
||||
if(!result)
|
||||
|
@ -81,10 +86,27 @@ bool read_rsa_public_key(connection_t *c) {
|
|||
bool read_rsa_private_key() {
|
||||
FILE *fp;
|
||||
char *fname;
|
||||
char *n, *d;
|
||||
bool result;
|
||||
|
||||
cp();
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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);
|
||||
|
||||
|
@ -110,7 +132,7 @@ bool read_rsa_private_key() {
|
|||
logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname);
|
||||
#endif
|
||||
|
||||
result = read_pem_rsa_private_key(fp, &myself->connection->rsa_key);
|
||||
result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
|
||||
fclose(fp);
|
||||
|
||||
if(!result)
|
||||
|
@ -126,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 {
|
||||
|
@ -137,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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -285,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;
|
||||
|
@ -375,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();
|
||||
|
|
11
src/node.c
11
src/node.c
|
@ -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);
|
||||
|
||||
|
@ -171,8 +168,8 @@ void dump_nodes(void) {
|
|||
for(node = node_tree->head; node; node = node->next) {
|
||||
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)"),
|
||||
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);
|
||||
}
|
||||
|
|
12
src/node.h
12
src/node.h
|
@ -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 */
|
||||
|
||||
|
|
182
src/openssl/cipher.c
Normal file
182
src/openssl/cipher.c
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
cipher.c -- Symmetric block cipher handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "cipher.h"
|
||||
#include "logger.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static bool cipher_open(cipher_t *cipher) {
|
||||
cipher->keylen = cipher->cipher->key_len;
|
||||
cipher->blklen = cipher->cipher->iv_len;
|
||||
|
||||
cipher->key = xmalloc(cipher->keylen + cipher->blklen);
|
||||
|
||||
EVP_CIPHER_CTX_init(&cipher->ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_open_by_name(cipher_t *cipher, const char *name) {
|
||||
cipher->cipher = EVP_get_cipherbyname(name);
|
||||
|
||||
if(cipher->cipher)
|
||||
return cipher_open(cipher);
|
||||
|
||||
logger(LOG_DEBUG, _("Unknown cipher name '%s'!"), name);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_open_by_nid(cipher_t *cipher, int nid) {
|
||||
cipher->cipher = EVP_get_cipherbynid(nid);
|
||||
|
||||
if(cipher->cipher)
|
||||
return cipher_open(cipher);
|
||||
|
||||
logger(LOG_DEBUG, _("Unknown cipher nid %d!"), nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_open_blowfish_ofb(cipher_t *cipher) {
|
||||
cipher->cipher = EVP_bf_ofb();
|
||||
return cipher_open(cipher);
|
||||
}
|
||||
|
||||
void cipher_close(cipher_t *cipher) {
|
||||
EVP_CIPHER_CTX_cleanup(&cipher->ctx);
|
||||
|
||||
if(cipher->key) {
|
||||
free(cipher->key);
|
||||
cipher->key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t cipher_keylength(const cipher_t *cipher) {
|
||||
return cipher->keylen + cipher->blklen;
|
||||
}
|
||||
|
||||
void cipher_get_key(const cipher_t *cipher, void *key) {
|
||||
memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
|
||||
}
|
||||
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
||||
memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
|
||||
bool result;
|
||||
|
||||
if(encrypt)
|
||||
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
|
||||
else
|
||||
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
|
||||
|
||||
if(result)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, _("Error while setting key: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
|
||||
memcpy(cipher->key, key + len - (size_t)cipher->keylen, cipher->keylen);
|
||||
memcpy(cipher->key + cipher->keylen, key + len - (size_t)cipher->keylen - (size_t)cipher->blklen, cipher->blklen);
|
||||
bool result;
|
||||
|
||||
if(encrypt)
|
||||
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
|
||||
else
|
||||
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
|
||||
|
||||
if(result)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, _("Error while setting key: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
|
||||
bool result;
|
||||
|
||||
RAND_pseudo_bytes((unsigned char *)cipher->key, cipher->keylen + cipher->blklen);
|
||||
|
||||
if(encrypt)
|
||||
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
|
||||
else
|
||||
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
|
||||
|
||||
if(result)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, _("Error while regenerating key: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_encrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len = *outlen, pad;
|
||||
if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&&EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)
|
||||
&& EVP_EncryptFinal(&cipher->ctx, outdata + len, &pad)) {
|
||||
*outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len = *outlen;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
*outlen = len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
logger(LOG_ERR, _("Error while encrypting: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_decrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len = *outlen, pad;
|
||||
if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_DecryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)
|
||||
&& EVP_DecryptFinal(&cipher->ctx, outdata + len, &pad)) {
|
||||
*outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len = *outlen;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
*outlen = len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
logger(LOG_ERR, _("Error while encrypting: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
int cipher_get_nid(const cipher_t *cipher) {
|
||||
return cipher->cipher ? cipher->cipher->nid : 0;
|
||||
}
|
||||
|
||||
bool cipher_active(const cipher_t *cipher) {
|
||||
return cipher->cipher && cipher->cipher->nid != 0;
|
||||
}
|
49
src/openssl/cipher.h
Normal file
49
src/openssl/cipher.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
cipher.h -- header file cipher.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __TINC_CIPHER_H__
|
||||
#define __TINC_CIPHER_H__
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
typedef struct cipher {
|
||||
EVP_CIPHER_CTX ctx;
|
||||
const EVP_CIPHER *cipher;
|
||||
char *key;
|
||||
uint16_t keylen;
|
||||
uint16_t blklen;
|
||||
} cipher_t;
|
||||
|
||||
extern bool cipher_open_by_name(cipher_t *, const char *);
|
||||
extern bool cipher_open_by_nid(cipher_t *, int);
|
||||
extern bool cipher_open_blowfish_ofb(cipher_t *);
|
||||
extern void cipher_close(cipher_t *);
|
||||
extern size_t cipher_keylength(const cipher_t *);
|
||||
extern void cipher_get_key(const cipher_t *, void *);
|
||||
extern bool cipher_set_key(cipher_t *, void *, bool);
|
||||
extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool);
|
||||
extern bool cipher_regenerate_key(cipher_t *, bool);
|
||||
extern bool cipher_encrypt(cipher_t *, void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
|
||||
extern bool cipher_decrypt(cipher_t *, void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
|
||||
extern int cipher_get_nid(const cipher_t *);
|
||||
extern bool cipher_active(const cipher_t *);
|
||||
|
||||
#endif
|
45
src/openssl/crypto.c
Normal file
45
src/openssl/crypto.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
crypto.c -- Cryptographic miscellaneous functions and initialisation
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
void crypto_init() {
|
||||
RAND_load_file("/dev/urandom", 1024);
|
||||
|
||||
ENGINE_load_builtin_engines();
|
||||
ENGINE_register_all_complete();
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
}
|
||||
|
||||
void crypto_exit() {
|
||||
EVP_cleanup();
|
||||
}
|
||||
|
||||
void randomize(void *out, size_t outlen) {
|
||||
RAND_pseudo_bytes(out, outlen);
|
||||
}
|
29
src/openssl/crypto.h
Normal file
29
src/openssl/crypto.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
crypto.h -- header for crypto.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __TINC_CRYPTO_H__
|
||||
#define __TINC_CRYPTO_H__
|
||||
|
||||
extern void crypto_init();
|
||||
extern void crypto_exit();
|
||||
extern void randomize(void *, size_t);
|
||||
|
||||
#endif
|
84
src/openssl/digest.c
Normal file
84
src/openssl/digest.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
digest.c -- Digest handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "digest.h"
|
||||
#include "logger.h"
|
||||
|
||||
bool digest_open_by_name(digest_t *digest, const char *name) {
|
||||
digest->digest = EVP_get_digestbyname(name);
|
||||
if(digest->digest)
|
||||
return true;
|
||||
|
||||
logger(LOG_DEBUG, _("Unknown digest name '%s'!"), name);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool digest_open_by_nid(digest_t *digest, int nid) {
|
||||
digest->digest = EVP_get_digestbynid(nid);
|
||||
if(digest->digest)
|
||||
return true;
|
||||
|
||||
logger(LOG_DEBUG, _("Unknown digest nid %d!"), nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool digest_open_sha1(digest_t *digest) {
|
||||
digest->digest = EVP_sha1();
|
||||
return true;
|
||||
}
|
||||
|
||||
void digest_close(digest_t *digest) {
|
||||
}
|
||||
|
||||
bool digest_create(digest_t *digest, void *indata, size_t inlen, void *outdata) {
|
||||
EVP_MD_CTX ctx;
|
||||
|
||||
if(EVP_DigestInit(&ctx, digest->digest)
|
||||
&& EVP_DigestUpdate(&ctx, indata, inlen)
|
||||
&& EVP_DigestFinal(&ctx, outdata, NULL))
|
||||
return true;
|
||||
|
||||
logger(LOG_DEBUG, _("Error creating digest: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool digest_verify(digest_t *digest, void *indata, size_t inlen, void *cmpdata) {
|
||||
size_t len = EVP_MD_size(digest->digest);
|
||||
char outdata[len];
|
||||
|
||||
return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, len);
|
||||
}
|
||||
|
||||
int digest_get_nid(const digest_t *digest) {
|
||||
return digest->digest ? digest->digest->type : 0;
|
||||
}
|
||||
|
||||
size_t digest_length(const digest_t *digest) {
|
||||
return EVP_MD_size(digest->digest);
|
||||
}
|
||||
|
||||
bool digest_active(const digest_t *digest) {
|
||||
return digest->digest && digest->digest->type != 0;
|
||||
}
|
41
src/openssl/digest.h
Normal file
41
src/openssl/digest.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
digest.h -- header file digest.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __TINC_DIGEST_H__
|
||||
#define __TINC_DIGEST_H__
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
typedef struct digest {
|
||||
const EVP_MD *digest;
|
||||
} digest_t;
|
||||
|
||||
extern bool digest_open_by_name(struct digest *, const char *);
|
||||
extern bool digest_open_by_nid(struct digest *, int);
|
||||
extern bool digest_open_sha1(struct digest *);
|
||||
extern void digest_close(struct digest *);
|
||||
extern bool digest_create(struct digest *, void *indata, size_t inlen, void *outdata);
|
||||
extern bool digest_verify(struct digest *, void *indata, size_t inlen, void *digestdata);
|
||||
extern int digest_get_nid(const struct digest *);
|
||||
extern size_t digest_length(const struct digest *);
|
||||
extern bool digest_active(const struct digest *);
|
||||
|
||||
#endif
|
92
src/openssl/rsa.c
Normal file
92
src/openssl/rsa.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
rsa.c -- RSA key handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "rsa.h"
|
||||
|
||||
// Set RSA keys
|
||||
|
||||
bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
|
||||
*rsa = RSA_new();
|
||||
BN_hex2bn(&(*rsa)->n, n);
|
||||
BN_hex2bn(&(*rsa)->e, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
|
||||
*rsa = RSA_new();
|
||||
BN_hex2bn(&(*rsa)->n, n);
|
||||
BN_hex2bn(&(*rsa)->e, e);
|
||||
BN_hex2bn(&(*rsa)->d, d);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read PEM RSA keys
|
||||
|
||||
bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
|
||||
*rsa = PEM_read_RSAPublicKey(fp, rsa, NULL, NULL);
|
||||
|
||||
if(*rsa)
|
||||
return true;
|
||||
|
||||
*rsa = PEM_read_RSA_PUBKEY(fp, rsa, NULL, NULL);
|
||||
|
||||
if(*rsa)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, _("Unable to read RSA public key: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
|
||||
*rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
|
||||
|
||||
if(*rsa)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, _("Unable to read RSA private key: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t rsa_size(rsa_t *rsa) {
|
||||
return RSA_size(*rsa);
|
||||
}
|
||||
|
||||
bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
||||
if(RSA_public_encrypt(len, in, out, *rsa, RSA_NO_PADDING) == len)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, _("Unable to perform RSA encryption: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
||||
if(RSA_private_decrypt(len, in, out, *rsa, RSA_NO_PADDING) == len)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, _("Unable to perform RSA decryption: %s"), ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
37
src/openssl/rsa.h
Normal file
37
src/openssl/rsa.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
rsa.h -- RSA key handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __TINC_RSA_H__
|
||||
#define __TINC_RSA_H__
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
typedef RSA *rsa_t;
|
||||
|
||||
extern bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e);
|
||||
extern bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d);
|
||||
extern bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp);
|
||||
extern bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp);
|
||||
extern size_t rsa_size(rsa_t *rsa);
|
||||
extern bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t inlen, void *out);
|
||||
extern bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t inlen, void *out);
|
||||
|
||||
#endif
|
|
@ -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"
|
||||
|
@ -116,27 +112,22 @@ bool id_h(connection_t *c, char *request) {
|
|||
}
|
||||
|
||||
bool send_metakey(connection_t *c) {
|
||||
char *buffer;
|
||||
unsigned int len;
|
||||
bool x;
|
||||
size_t len = rsa_size(&c->rsa);
|
||||
char key[len];
|
||||
char enckey[len];
|
||||
char hexkey[2 * len + 1];
|
||||
|
||||
cp();
|
||||
|
||||
len = get_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:
|
||||
|
@ -148,13 +139,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
|
||||
|
@ -164,134 +156,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)) {
|
||||
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 = get_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)) {
|
||||
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;
|
||||
|
||||
|
@ -299,25 +235,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 = get_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 */
|
||||
|
||||
|
@ -331,72 +259,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 = get_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, get_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();
|
||||
|
||||
|
@ -408,38 +312,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, get_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;
|
||||
}
|
||||
|
||||
|
@ -447,6 +332,7 @@ bool chal_reply_h(connection_t *c, char *request) {
|
|||
Send an acknowledgement with the rest of the information needed.
|
||||
*/
|
||||
|
||||
free(c->hischallenge);
|
||||
c->allow_request = ACK;
|
||||
|
||||
return send_ack(c);
|
||||
|
|
|
@ -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];
|
||||
|
||||
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);
|
||||
|
|
18
src/tincd.c
18
src/tincd.c
|
@ -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"
|
||||
|
@ -294,12 +289,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;
|
||||
|
@ -352,7 +342,7 @@ end:
|
|||
exit_control();
|
||||
#endif
|
||||
|
||||
EVP_cleanup();
|
||||
|
||||
crypto_exit();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue