]> git.meshlink.io Git - meshlink/commitdiff
Finish crypto wrapping. Also provide wrappers for OpenSSL.
authorGuus Sliepen <guus@tinc-vpn.org>
Wed, 23 May 2007 13:45:49 +0000 (13:45 +0000)
committerGuus Sliepen <guus@tinc-vpn.org>
Wed, 23 May 2007 13:45:49 +0000 (13:45 +0000)
Disable libgcrypt by default. Since it doesn't support the OFB cipher mode,
we can't use it in a backwards compatible way.

34 files changed:
configure.in
src/Makefile.am
src/cipher.c [deleted file]
src/cipher.h [deleted file]
src/connection.c
src/connection.h
src/digest.c [deleted file]
src/digest.h [deleted file]
src/gcrypt/cipher.c [new file with mode: 0644]
src/gcrypt/cipher.h [new file with mode: 0644]
src/gcrypt/crypto.c [new file with mode: 0644]
src/gcrypt/crypto.h [new file with mode: 0644]
src/gcrypt/digest.c [new file with mode: 0644]
src/gcrypt/digest.h [new file with mode: 0644]
src/gcrypt/rsa.c [new file with mode: 0644]
src/gcrypt/rsa.h [new file with mode: 0644]
src/meta.c
src/net_packet.c
src/net_setup.c
src/node.c
src/node.h
src/openssl/cipher.c [new file with mode: 0644]
src/openssl/cipher.h [new file with mode: 0644]
src/openssl/crypto.c [new file with mode: 0644]
src/openssl/crypto.h [new file with mode: 0644]
src/openssl/digest.c [new file with mode: 0644]
src/openssl/digest.h [new file with mode: 0644]
src/openssl/rsa.c [new file with mode: 0644]
src/openssl/rsa.h [new file with mode: 0644]
src/protocol_auth.c
src/protocol_key.c
src/rsa.c [deleted file]
src/rsa.h [deleted file]
src/tincd.c

index cbf6bf2381c6f35fbbdfe721ed1b166012914449..f6a163b7fa88849255c12261bccc37796711c030 100644 (file)
@@ -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)]),
index 5259ff7a51b06bb10fdde1681b0b9acd4d0361c6..a318dcd5b906131b8cf31dcb3a9b36183d393fd0 100644 (file)
@@ -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`
diff --git a/src/cipher.c b/src/cipher.c
deleted file mode 100644 (file)
index 6117907..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
-    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 "cipher.h"
-#include "logger.h"
-#include "xalloc.h"
-
-static struct {
-       const char *name;
-       int algo;
-       int mode;
-       int nid;
-} ciphertable[] = {
-       {"none", GCRY_CIPHER_NONE, GCRY_CIPHER_MODE_NONE, 0},
-
-       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 92},
-       {"blowfish", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 91},
-       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB, 93},
-       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, 94},
-
-       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 418},
-       {"aes", GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 419},
-       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, 421},
-       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OFB, 420},
-
-       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, 422},
-       {"aes192", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, 423},
-       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB, 425},
-       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB, 424},
-
-       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 426},
-       {"aes256", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 427},
-       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 429},
-       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, 428},
-};
-
-static bool nametocipher(const char *name, int *algo, int *mode) {
-       int i;
-
-       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
-               if(ciphertable[i].name && !strcasecmp(name, ciphertable[i].name)) {
-                       *algo = ciphertable[i].algo;
-                       *mode = ciphertable[i].mode;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static bool nidtocipher(int nid, int *algo, int *mode) {
-       int i;
-
-       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
-               if(nid == ciphertable[i].nid) {
-                       *algo = ciphertable[i].algo;
-                       *mode = ciphertable[i].mode;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static bool ciphertonid(int algo, int mode, int *nid) {
-       int i;
-
-       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
-               if(algo == ciphertable[i].algo && mode == ciphertable[i].mode) {
-                       *nid = ciphertable[i].nid;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static bool cipher_open(cipher_t *cipher, int algo, int mode) {
-       gcry_error_t err;
-
-       if(!ciphertonid(algo, mode, &cipher->nid)) {
-               logger(LOG_DEBUG, _("Cipher %d mode %d has no corresponding nid!"), algo, mode);
-               return false;
-       }
-
-       if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
-               logger(LOG_DEBUG, _("Unable to intialise cipher %d mode %d!"), algo, mode);
-               return false;
-       }
-
-       cipher->keylen = gcry_cipher_get_algo_keylen(algo);
-       if(mode == GCRY_CIPHER_MODE_ECB || mode == GCRY_CIPHER_MODE_CBC)
-               cipher->blklen = gcry_cipher_get_algo_blklen(algo);
-       else
-               cipher->blklen = 0;
-       cipher->key = xmalloc(cipher->keylen + cipher->blklen);
-
-       return true;
-}
-
-bool cipher_open_by_name(cipher_t *cipher, const char *name) {
-       int algo, mode;
-
-       if(!nametocipher(name, &algo, &mode)) {
-               logger(LOG_DEBUG, _("Unknown cipher name '%s'!"), name);
-               return false;
-       }
-
-       return cipher_open(cipher, algo, mode);
-}
-
-bool cipher_open_by_nid(cipher_t *cipher, int nid) {
-       int algo, mode;
-
-       if(!nidtocipher(nid, &algo, &mode)) {
-               logger(LOG_DEBUG, _("Unknown cipher ID %d!"), nid);
-               return false;
-       }
-
-       return cipher_open(cipher, algo, mode);
-}
-
-bool cipher_open_blowfish_ofb(cipher_t *cipher) {
-       return cipher_open(cipher, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB);
-}
-
-void cipher_close(cipher_t *cipher) {
-       if(cipher->handle) {
-               gcry_cipher_close(cipher->handle);
-               cipher->handle = NULL;
-       }
-
-       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) {
-       memcpy(cipher->key, key, cipher->keylen + 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) {
-       gcry_create_nonce(cipher->key, cipher->keylen + 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_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
-       size_t reqlen;
-
-       if(cipher->blklen == 1) {
-               *outlen = inlen;
-               return true;
-       }
-
-       reqlen = ((inlen + 1) / cipher->blklen) * cipher->blklen;
-       if(reqlen > *outlen)
-               return false;
-
-       // add padding
-
-       *outlen = reqlen;
-       return true;
-}
-
-bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
-       size_t origlen;
-
-       if(cipher->blklen == 1) {
-               *outlen = inlen;
-               return true;
-       }
-
-       if(inlen % cipher->blklen)
-               return false;
-
-       // check and remove padding
-
-       *outlen = origlen;
-       return true;
-}
-
-bool cipher_encrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen) {
-       gcry_error_t err;
-
-       if((err = gcry_cipher_encrypt(cipher->handle, outdata, inlen, indata, inlen))) {
-               logger(LOG_ERR, _("Error while encrypting"));
-               return false;
-       }
-
-       return true;
-}
-
-bool cipher_decrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen) {
-       gcry_error_t err;
-
-       if((err = gcry_cipher_decrypt(cipher->handle, outdata, inlen, indata, inlen))) {
-               logger(LOG_ERR, _("Error while encrypting"));
-               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;
-}
-
-bool cipher_active(const cipher_t *cipher) {
-       return cipher->nid != 0;
-}
diff --git a/src/cipher.h b/src/cipher.h
deleted file mode 100644 (file)
index 45a4fc5..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-    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 <gcrypt.h>
-
-typedef struct cipher {
-       gcry_cipher_hd_t handle;
-       char *key;
-       int nid;
-       uint16_t keylen;
-       uint16_t blklen;
-} cipher_t;
-
-extern bool cipher_open_by_name(struct cipher *, const char *);
-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 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 int cipher_get_nid(const struct cipher *);
-extern bool cipher_active(const struct cipher *);
-
-#endif
index 21cb6aa93398229ad9bb848134d23557104c6ac9..a369cb83d900827a5741c77343de39bc64c5dafe 100644 (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);
index e5cd68950de4eb3d49ac9b2602647f280c9808a1..54caa2610a81f93124180a658d1642f7085918a5 100644 (file)
 #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 */
diff --git a/src/digest.c b/src/digest.c
deleted file mode 100644 (file)
index 50b0f23..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
-    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 "digest.h"
-#include "logger.h"
-
-static struct {
-       const char *name;
-       int algo;
-       int nid;
-} digesttable[] = {
-       {"none", GCRY_MD_NONE, 0},
-       {"sha1", GCRY_MD_SHA1, 64},
-       {"sha256", GCRY_MD_SHA256, 672},
-       {"sha384", GCRY_MD_SHA384, 673},
-       {"sha512", GCRY_MD_SHA512, 674},
-};
-
-static bool nametodigest(const char *name, int *algo) {
-       int i;
-
-       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
-               if(digesttable[i].name && !strcasecmp(name, digesttable[i].name)) {
-                       *algo = digesttable[i].algo;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static bool nidtodigest(int nid, int *algo) {
-       int i;
-
-       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
-               if(nid == digesttable[i].nid) {
-                       *algo = digesttable[i].algo;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static bool digesttonid(int algo, int *nid) {
-       int i;
-
-       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
-               if(algo == digesttable[i].algo) {
-                       *nid = digesttable[i].nid;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static bool digest_open(digest_t *digest, int algo) {
-       if(!digesttonid(algo, &digest->nid)) {
-               logger(LOG_DEBUG, _("Digest %d has no corresponding nid!"), algo);
-               return false;
-       }
-
-       digest->len = gcry_md_get_algo_dlen(algo);
-
-       return true;
-}
-
-bool digest_open_by_name(digest_t *digest, const char *name) {
-       int algo;
-
-       if(!nametodigest(name, &algo)) {
-               logger(LOG_DEBUG, _("Unknown digest name '%s'!"), name);
-               return false;
-       }
-
-       return digest_open(digest, algo);
-}
-
-bool digest_open_by_nid(digest_t *digest, int nid) {
-       int algo;
-
-       if(!nidtodigest(nid, &algo)) {
-               logger(LOG_DEBUG, _("Unknown digest ID %d!"), nid);
-               return false;
-       }
-
-       return digest_open(digest, algo);
-}
-
-bool digest_open_sha1(digest_t *digest) {
-       return digest_open(digest, GCRY_MD_SHA1);
-}
-
-void digest_close(digest_t *digest) {
-}
-
-bool digest_create(digest_t *digest, 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) {
-       char outdata[digest->len];
-
-       gcry_md_hash_buffer(digest->algo, outdata, indata, inlen);
-       return !memcmp(indata, outdata, digest->len);
-}
-
-int digest_get_nid(const digest_t *digest) {
-       return digest->nid;
-}
-
-size_t digest_length(const digest_t *digest) {
-       return digest->len;
-}
-
-bool digest_active(const digest_t *digest) {
-       return digest->algo != GCRY_MD_NONE;
-}
diff --git a/src/digest.h b/src/digest.h
deleted file mode 100644 (file)
index dd9029e..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-    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 <gcrypt.h>
-
-typedef struct digest {
-       int algo;
-       int nid;
-       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 *);
-
-#endif
diff --git a/src/gcrypt/cipher.c b/src/gcrypt/cipher.c
new file mode 100644 (file)
index 0000000..e1f1e05
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+    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 "cipher.h"
+#include "logger.h"
+#include "xalloc.h"
+
+static struct {
+       const char *name;
+       int algo;
+       int mode;
+       int nid;
+} ciphertable[] = {
+       {"none", GCRY_CIPHER_NONE, GCRY_CIPHER_MODE_NONE, 0},
+
+       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 92},
+       {"blowfish", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 91},
+       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB, 93},
+       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, 94},
+
+       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 418},
+       {"aes", GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 419},
+       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, 421},
+       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OFB, 420},
+
+       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, 422},
+       {"aes192", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, 423},
+       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB, 425},
+       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB, 424},
+
+       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 426},
+       {"aes256", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 427},
+       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 429},
+       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, 428},
+};
+
+static bool nametocipher(const char *name, int *algo, int *mode) {
+       int i;
+
+       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
+               if(ciphertable[i].name && !strcasecmp(name, ciphertable[i].name)) {
+                       *algo = ciphertable[i].algo;
+                       *mode = ciphertable[i].mode;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool nidtocipher(int nid, int *algo, int *mode) {
+       int i;
+
+       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
+               if(nid == ciphertable[i].nid) {
+                       *algo = ciphertable[i].algo;
+                       *mode = ciphertable[i].mode;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool ciphertonid(int algo, int mode, int *nid) {
+       int i;
+
+       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
+               if(algo == ciphertable[i].algo && mode == ciphertable[i].mode) {
+                       *nid = ciphertable[i].nid;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool cipher_open(cipher_t *cipher, int algo, int mode) {
+       gcry_error_t err;
+
+       if(!ciphertonid(algo, mode, &cipher->nid)) {
+               logger(LOG_DEBUG, _("Cipher %d mode %d has no corresponding nid!"), algo, mode);
+               return false;
+       }
+
+       if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
+               logger(LOG_DEBUG, _("Unable to intialise cipher %d mode %d: %s"), algo, mode, gcry_strerror(err));
+               return false;
+       }
+
+       cipher->keylen = gcry_cipher_get_algo_keylen(algo);
+       if(mode == GCRY_CIPHER_MODE_ECB || mode == GCRY_CIPHER_MODE_CBC)
+               cipher->blklen = gcry_cipher_get_algo_blklen(algo);
+       else
+               cipher->blklen = 0;
+       cipher->key = xmalloc(cipher->keylen + cipher->blklen);
+
+       return true;
+}
+
+bool cipher_open_by_name(cipher_t *cipher, const char *name) {
+       int algo, mode;
+
+       if(!nametocipher(name, &algo, &mode)) {
+               logger(LOG_DEBUG, _("Unknown cipher name '%s'!"), name);
+               return false;
+       }
+
+       return cipher_open(cipher, algo, mode);
+}
+
+bool cipher_open_by_nid(cipher_t *cipher, int nid) {
+       int algo, mode;
+
+       if(!nidtocipher(nid, &algo, &mode)) {
+               logger(LOG_DEBUG, _("Unknown cipher ID %d!"), nid);
+               return false;
+       }
+
+       return cipher_open(cipher, algo, mode);
+}
+
+bool cipher_open_blowfish_ofb(cipher_t *cipher) {
+       return cipher_open(cipher, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB);
+}
+
+void cipher_close(cipher_t *cipher) {
+       if(cipher->handle) {
+               gcry_cipher_close(cipher->handle);
+               cipher->handle = NULL;
+       }
+
+       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);
+
+       gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
+       gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
+
+       return true;
+}
+
+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);
+       gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
+
+       return true;
+}
+
+static bool cipher_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
+       size_t reqlen;
+
+       if(cipher->blklen == 1) {
+               *outlen = inlen;
+               return true;
+       }
+
+       reqlen = ((inlen + 1) / cipher->blklen) * cipher->blklen;
+       if(reqlen > *outlen)
+               return false;
+
+       // add padding
+
+       *outlen = reqlen;
+       return true;
+}
+
+static bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
+       size_t origlen;
+
+       if(cipher->blklen == 1) {
+               *outlen = inlen;
+               return true;
+       }
+
+       if(inlen % cipher->blklen)
+               return false;
+
+       // check and remove padding
+
+       *outlen = origlen;
+       return true;
+}
+
+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: %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 oneshot) {
+       gcry_error_t err;
+
+       // To be fixed
+
+       if((err = gcry_cipher_decrypt(cipher->handle, outdata, inlen, indata, inlen))) {
+               logger(LOG_ERR, _("Error while decrypting: %s"), gcry_strerror(err));
+               return false;
+       }
+
+       return true;
+}
+
+int cipher_get_nid(const cipher_t *cipher) {
+       return cipher->nid;
+}
+
+bool cipher_active(const cipher_t *cipher) {
+       return cipher->nid != 0;
+}
diff --git a/src/gcrypt/cipher.h b/src/gcrypt/cipher.h
new file mode 100644 (file)
index 0000000..759a523
--- /dev/null
@@ -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 <gcrypt.h>
+
+typedef struct cipher {
+       gcry_cipher_hd_t handle;
+       char *key;
+       int nid;
+       uint16_t keylen;
+       uint16_t blklen;
+} cipher_t;
+
+extern bool cipher_open_by_name(struct cipher *, const char *);
+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 *, 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 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 *);
+
+#endif
diff --git a/src/gcrypt/crypto.c b/src/gcrypt/crypto.c
new file mode 100644 (file)
index 0000000..9465606
--- /dev/null
@@ -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);
+}
diff --git a/src/gcrypt/crypto.h b/src/gcrypt/crypto.h
new file mode 100644 (file)
index 0000000..3999251
--- /dev/null
@@ -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
diff --git a/src/gcrypt/digest.c b/src/gcrypt/digest.c
new file mode 100644 (file)
index 0000000..639fa67
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+    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 "digest.h"
+#include "logger.h"
+
+static struct {
+       const char *name;
+       int algo;
+       int nid;
+} digesttable[] = {
+       {"none", GCRY_MD_NONE, 0},
+       {"sha1", GCRY_MD_SHA1, 64},
+       {"sha256", GCRY_MD_SHA256, 672},
+       {"sha384", GCRY_MD_SHA384, 673},
+       {"sha512", GCRY_MD_SHA512, 674},
+};
+
+static bool nametodigest(const char *name, int *algo) {
+       int i;
+
+       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
+               if(digesttable[i].name && !strcasecmp(name, digesttable[i].name)) {
+                       *algo = digesttable[i].algo;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool nidtodigest(int nid, int *algo) {
+       int i;
+
+       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
+               if(nid == digesttable[i].nid) {
+                       *algo = digesttable[i].algo;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool digesttonid(int algo, int *nid) {
+       int i;
+
+       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
+               if(algo == digesttable[i].algo) {
+                       *nid = digesttable[i].nid;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool digest_open(digest_t *digest, int algo) {
+       if(!digesttonid(algo, &digest->nid)) {
+               logger(LOG_DEBUG, _("Digest %d has no corresponding nid!"), algo);
+               return false;
+       }
+
+       digest->len = gcry_md_get_algo_dlen(algo);
+
+       return true;
+}
+
+bool digest_open_by_name(digest_t *digest, const char *name) {
+       int algo;
+
+       if(!nametodigest(name, &algo)) {
+               logger(LOG_DEBUG, _("Unknown digest name '%s'!"), name);
+               return false;
+       }
+
+       return digest_open(digest, algo);
+}
+
+bool digest_open_by_nid(digest_t *digest, int nid) {
+       int algo;
+
+       if(!nidtodigest(nid, &algo)) {
+               logger(LOG_DEBUG, _("Unknown digest ID %d!"), nid);
+               return false;
+       }
+
+       return digest_open(digest, algo);
+}
+
+bool digest_open_sha1(digest_t *digest) {
+       return digest_open(digest, GCRY_MD_SHA1);
+}
+
+void digest_close(digest_t *digest) {
+}
+
+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, const void *indata, size_t inlen, const void *cmpdata) {
+       char outdata[digest->len];
+
+       gcry_md_hash_buffer(digest->algo, outdata, indata, inlen);
+       return !memcmp(cmpdata, outdata, digest->len);
+}
+
+int digest_get_nid(const digest_t *digest) {
+       return digest->nid;
+}
+
+size_t digest_length(const digest_t *digest) {
+       return digest->len;
+}
+
+bool digest_active(const digest_t *digest) {
+       return digest->algo != GCRY_MD_NONE;
+}
diff --git a/src/gcrypt/digest.h b/src/gcrypt/digest.h
new file mode 100644 (file)
index 0000000..6a644c7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    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 <gcrypt.h>
+
+typedef struct digest {
+       int algo;
+       int nid;
+       uint16_t len;
+} digest_t;
+
+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
diff --git a/src/gcrypt/rsa.c b/src/gcrypt/rsa.c
new file mode 100644 (file)
index 0000000..99ee11b
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+    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 <gcrypt.h>
+
+#include "logger.h"
+#include "rsa.h"
+
+// Base64 encoding/decoding tables
+
+static const uint8_t b64d[128] = {
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+  0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+  0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+  0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+  0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+  0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+  0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+  0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+  0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+  0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
+  0xff, 0xff
+};
+
+static const char b64e[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// PEM encoding/decoding functions
+
+static bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize) {
+       bool decode = false;
+       char line[1024];
+       uint16_t word = 0;
+       int shift = 10;
+       size_t i, j = 0;
+
+       while(!feof(fp)) {
+               if(!fgets(line, sizeof line, fp))
+                       return false;
+
+               if(!decode && !strncmp(line, "-----BEGIN ", 11)) {
+                       if(!strncmp(line + 11, header, strlen(header)))
+                               decode = true;
+                       continue;
+               }
+
+               if(decode && !strncmp(line, "-----END", 8)) {
+                       break;
+               }
+
+               if(!decode)
+                       continue;
+
+               for(i = 0; line[i] >= ' '; i++) {
+                       if(line[i] >= 128 || line[i] < 0 || b64d[(int)line[i]] == 0xff)
+                               break;
+                       word |= b64d[(int)line[i]] << shift;
+                       shift -= 6;
+                       if(shift <= 2) {
+                               if(j > size) {
+                                       errno = ENOMEM;
+                                       return false;
+                               }
+
+                               buf[j++] = word >> 8;
+                               word <<= 8;
+                               shift += 8;
+                       }
+               }
+       }
+
+       if(outsize)
+               *outsize = j;
+       return true;
+}
+
+
+// BER decoding functions
+
+static int ber_read_id(unsigned char **p, size_t *buflen) {
+       if(*buflen <= 0)
+               return -1;
+
+       if((**p & 0x1f) == 0x1f) {
+               int id = 0;
+               bool more;
+               while(*buflen > 0) {
+                       id <<= 7;
+                       id |= **p & 0x7f;
+                       more = *(*p)++ & 0x80;
+                       (*buflen)--;
+                       if(!more)
+                               break;
+               }
+               return id;
+       } else {
+               (*buflen)--;
+               return *(*p)++ & 0x1f;
+       }
+}
+
+static size_t ber_read_len(unsigned char **p, size_t *buflen) {
+       if(*buflen <= 0)
+               return -1;
+
+       if(**p & 0x80) {
+               size_t result = 0;
+               int len = *(*p)++ & 0x7f;
+               (*buflen)--;
+               if(len > *buflen)
+                       return 0;
+
+               while(len--) {
+                       result <<= 8;
+                       result |= *(*p)++;
+                       (*buflen)--;
+               }
+
+               return result;
+       } else {
+               (*buflen)--;
+               return *(*p)++;
+       }
+}
+       
+
+static bool ber_read_sequence(unsigned char **p, size_t *buflen, size_t *result) {
+       int tag = ber_read_id(p, buflen);
+       size_t len = ber_read_len(p, buflen);
+
+       if(tag == 0x10) {
+               if(result)
+                       *result = len;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
+       int tag = ber_read_id(p, buflen);
+       size_t len = ber_read_len(p, buflen);
+       gcry_error_t err = 0;
+
+       if(tag != 0x02 || len > *buflen)
+               return false;
+
+       if(mpi)
+               err = gcry_mpi_scan(mpi, GCRYMPI_FMT_USG, *p, len, NULL);
+       
+       *p += len;
+       *buflen -= len;
+
+       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(rsa_t *rsa, FILE *fp) {
+       uint8_t derbuf[8096], *derp = derbuf;
+       size_t derlen;
+
+       if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof derbuf, &derlen)) {
+               logger(LOG_ERR, _("Unable to read RSA public key: %s"), strerror(errno));
+               return NULL;
+       }
+
+       if(!ber_read_sequence(&derp, &derlen, NULL)
+                       || !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;
+       }
+
+       return true;
+}
+
+bool read_pem_rsa_private_key(rsa_t *rsa, FILE *fp) {
+       uint8_t derbuf[8096], *derp = derbuf;
+       size_t derlen;
+
+       if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof derbuf, &derlen)) {
+               logger(LOG_ERR, _("Unable to read RSA private key: %s"), strerror(errno));
+               return NULL;
+       }
+
+       if(!ber_read_sequence(&derp, &derlen, NULL)
+                       || !ber_read_mpi(&derp, &derlen, NULL)
+                       || !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)
+                       || !ber_read_mpi(&derp, &derlen, NULL)
+                       || !ber_read_mpi(&derp, &derlen, NULL) // u
+                       || derlen) {
+               logger(LOG_ERR, _("Error while decoding RSA private key"));
+               return NULL;
+       }
+
+       return true;
+}
+
+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.
+ * So we just use libgcrypt's mpi functions, and do the math ourselves.
+ */
+
+// 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(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, rsa->e, rsa->n);
+
+       check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
+
+       return true;
+}
+
+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, rsa->d, rsa->n);
+
+       check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
+
+       return true;
+}
diff --git a/src/gcrypt/rsa.h b/src/gcrypt/rsa.h
new file mode 100644 (file)
index 0000000..0b3937a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    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 <gcrypt.h>
+
+typedef struct rsa {
+       gcry_mpi_t n;
+       gcry_mpi_t e;
+       gcry_mpi_t d;
+} 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
index 795141123e7abda5fa7274cb39925f4a824c83b5..2791ea198c2b4e4471f7e0734a613cff686cc9bf 100644 (file)
 
 #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"
 #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;
index 2a86d657e35e783b827f3e927829fb528ce67aa4..eee3972e16135a54bb0fcc72f89ac29b971d167c 100644 (file)
 
 #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 */
index 94e3987287a47e20852ce6e08adbf107f2a5dc8c..033bf3761eb773bd728e4827cf30de6ec72de723 100644 (file)
 
 #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(!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();
+       if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
+               cipher = xstrdup("blowfish");
 
-       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(!myself->digest) {
-                               logger(LOG_ERR, _("Unrecognized digest type!"));
-                               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;
+       if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
+               digest = xstrdup("sha1");
 
-       myself->connection->outmaclength = 0;
+       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;
+               }
+       }
 
        /* 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();
index cbafe712c9840d62b3c59ca726a740e5e4acee47..280a70cbb28252c77e8887f4e4e6085a5dcf540f 100644 (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);
        
@@ -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);
        }
index 83af5e3ccc7523de03b8c569f500566500f6aa34..4186d06193ecd31d1695142ed1813f720a50a96d 100644 (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 */
 
diff --git a/src/openssl/cipher.c b/src/openssl/cipher.c
new file mode 100644 (file)
index 0000000..bf999a2
--- /dev/null
@@ -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;
+}
diff --git a/src/openssl/cipher.h b/src/openssl/cipher.h
new file mode 100644 (file)
index 0000000..68acb41
--- /dev/null
@@ -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
diff --git a/src/openssl/crypto.c b/src/openssl/crypto.c
new file mode 100644 (file)
index 0000000..7e6e9f6
--- /dev/null
@@ -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);
+}
diff --git a/src/openssl/crypto.h b/src/openssl/crypto.h
new file mode 100644 (file)
index 0000000..3999251
--- /dev/null
@@ -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
diff --git a/src/openssl/digest.c b/src/openssl/digest.c
new file mode 100644 (file)
index 0000000..7c4dfc2
--- /dev/null
@@ -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;
+}
diff --git a/src/openssl/digest.h b/src/openssl/digest.h
new file mode 100644 (file)
index 0000000..28ee9d0
--- /dev/null
@@ -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
diff --git a/src/openssl/rsa.c b/src/openssl/rsa.c
new file mode 100644 (file)
index 0000000..5e923f1
--- /dev/null
@@ -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;   
+}
diff --git a/src/openssl/rsa.h b/src/openssl/rsa.h
new file mode 100644 (file)
index 0000000..dade1f3
--- /dev/null
@@ -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
index 499e6869ed38c69076dc67b9a4ffd065711b4271..291c4b0176f02a25978924551f9c0d66fb98e0b7 100644 (file)
 
 #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);
-
-       /* 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 */
+       hex2bin(hishash, hishash, digest_length(&c->outdigest));
 
-       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);
index 05bc97ba0dbcecc33f10c72b519ef6a35f045dda..66ffb115f1e7f207aeef8032fd164092f7ca27a5 100644 (file)
 
 #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(!from->cipher) {
-                       logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name,
-                                  from->hostname);
-                       return false;
-               }
+       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->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(!from->digest) {
-                       logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name,
-                                  from->hostname);
-                       return false;
-               }
+       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->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);
diff --git a/src/rsa.c b/src/rsa.c
deleted file mode 100644 (file)
index 486f354..0000000
--- a/src/rsa.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
-    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 <gcrypt.h>
-
-#include "logger.h"
-#include "rsa.h"
-
-// Base64 encoding/decoding tables
-
-static const uint8_t b64d[128] = {
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
-  0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
-  0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
-  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
-  0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
-  0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-  0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
-  0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
-  0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
-  0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
-  0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
-  0xff, 0xff
-};
-
-static const char b64e[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-// PEM encoding/decoding functions
-
-static bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize) {
-       bool decode = false;
-       char line[1024];
-       uint16_t word = 0;
-       int shift = 10;
-       size_t i, j = 0;
-
-       while(!feof(fp)) {
-               if(!fgets(line, sizeof line, fp))
-                       return false;
-
-               if(!decode && !strncmp(line, "-----BEGIN ", 11)) {
-                       if(!strncmp(line + 11, header, strlen(header)))
-                               decode = true;
-                       continue;
-               }
-
-               if(decode && !strncmp(line, "-----END", 8)) {
-                       break;
-               }
-
-               if(!decode)
-                       continue;
-
-               for(i = 0; line[i] >= ' '; i++) {
-                       if(line[i] >= 128 || line[i] < 0 || b64d[(int)line[i]] == 0xff)
-                               break;
-                       word |= b64d[(int)line[i]] << shift;
-                       shift -= 6;
-                       if(shift <= 2) {
-                               if(j > size) {
-                                       errno = ENOMEM;
-                                       return false;
-                               }
-
-                               buf[j++] = word >> 8;
-                               word <<= 8;
-                               shift += 8;
-                       }
-               }
-       }
-
-       if(outsize)
-               *outsize = j;
-       return true;
-}
-
-
-// BER decoding functions
-
-static int ber_read_id(unsigned char **p, size_t *buflen) {
-       if(*buflen <= 0)
-               return -1;
-
-       if((**p & 0x1f) == 0x1f) {
-               int id = 0;
-               bool more;
-               while(*buflen > 0) {
-                       id <<= 7;
-                       id |= **p & 0x7f;
-                       more = *(*p)++ & 0x80;
-                       (*buflen)--;
-                       if(!more)
-                               break;
-               }
-               return id;
-       } else {
-               (*buflen)--;
-               return *(*p)++ & 0x1f;
-       }
-}
-
-static size_t ber_read_len(unsigned char **p, size_t *buflen) {
-       if(*buflen <= 0)
-               return -1;
-
-       if(**p & 0x80) {
-               size_t result = 0;
-               int len = *(*p)++ & 0x7f;
-               (*buflen)--;
-               if(len > *buflen)
-                       return 0;
-
-               while(len--) {
-                       result <<= 8;
-                       result |= *(*p)++;
-                       (*buflen)--;
-               }
-
-               return result;
-       } else {
-               (*buflen)--;
-               return *(*p)++;
-       }
-}
-       
-
-static bool ber_read_sequence(unsigned char **p, size_t *buflen, size_t *result) {
-       int tag = ber_read_id(p, buflen);
-       size_t len = ber_read_len(p, buflen);
-
-       if(tag == 0x10) {
-               if(result)
-                       *result = len;
-               return true;
-       } else {
-               return false;
-       }
-}
-
-static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
-       int tag = ber_read_id(p, buflen);
-       size_t len = ber_read_len(p, buflen);
-       gcry_error_t err = 0;
-
-       if(tag != 0x02 || len > *buflen)
-               return false;
-
-       if(mpi)
-               err = gcry_mpi_scan(mpi, GCRYMPI_FMT_USG, *p, len, NULL);
-       
-       *p += len;
-       *buflen -= len;
-
-       return mpi ? !err : true;
-}
-
-// Read PEM RSA keys
-
-bool read_pem_rsa_public_key(FILE *fp, rsa_key_t *key) {
-       uint8_t derbuf[8096], *derp = derbuf;
-       size_t derlen;
-
-       if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof derbuf, &derlen)) {
-               logger(LOG_ERR, _("Unable to read RSA public key: %s"), strerror(errno));
-               return NULL;
-       }
-
-       if(!ber_read_sequence(&derp, &derlen, NULL)
-                       || !ber_read_mpi(&derp, &derlen, &key->n)
-                       || !ber_read_mpi(&derp, &derlen, &key->e)
-                       || derlen) {
-               logger(LOG_ERR, _("Error while decoding RSA public key"));
-               return NULL;
-       }
-
-       return true;
-}
-
-bool read_pem_rsa_private_key(FILE *fp, rsa_key_t *key) {
-       uint8_t derbuf[8096], *derp = derbuf;
-       size_t derlen;
-
-       if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof derbuf, &derlen)) {
-               logger(LOG_ERR, _("Unable to read RSA private key: %s"), strerror(errno));
-               return NULL;
-       }
-
-       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, NULL) // p
-                       || !ber_read_mpi(&derp, &derlen, NULL) // q
-                       || !ber_read_mpi(&derp, &derlen, NULL)
-                       || !ber_read_mpi(&derp, &derlen, NULL)
-                       || !ber_read_mpi(&derp, &derlen, NULL) // u
-                       || derlen) {
-               logger(LOG_ERR, _("Error while decoding RSA private key"));
-               return NULL;
-       }
-
-       return true;
-}
-
-unsigned int get_rsa_size(rsa_key_t *key) {
-       return (gcry_mpi_get_nbits(key->n) + 7) / 8;
-}
-
-/* Well, libgcrypt has functions to handle RSA keys, but they suck.
- * So we just use libgcrypt's mpi functions, and do the math ourselves.
- */
-
-// 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) {
-       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);
-
-       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) {
-       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);
-
-       check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
-
-       return true;
-}
diff --git a/src/rsa.h b/src/rsa.h
deleted file mode 100644 (file)
index bcb795e..0000000
--- a/src/rsa.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-    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 <gcrypt.h>
-
-typedef struct rsa_key_t {
-       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);
-
-
-#endif
index 95c45d3b7e579ae5a8d1728cb489a1e7be4db828..d5942ce0c2f396ba7c5b20566d31452487390090 100644 (file)
 #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;
 }