Use conditional compilation for cryptographic functions.

This gets rid of the rest of the symbolic links. However, as a consequence, the
crypto header files have now moved to src/, and can no longer contain
library-specific declarations. Therefore, cipher_t, digest_t, ecdh_t, ecdsa_t
and rsa_t are now all opaque types, and only pointers to those types can be
used.
This commit is contained in:
Guus Sliepen 2013-05-01 17:17:22 +02:00
parent e70b5b5bd7
commit 9b9230a0a7
35 changed files with 595 additions and 639 deletions

View file

@ -6,7 +6,7 @@ SUBDIRS = m4 src doc gui
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = have.h system.h COPYING.README README.android EXTRA_DIST = COPYING.README README.android
ChangeLog: ChangeLog:
git log > ChangeLog git log > ChangeLog

View file

@ -192,13 +192,15 @@ tinc_ZLIB
tinc_LZO tinc_LZO
if test "$with_libgcrypt" = yes; then if test "$with_libgcrypt" = yes; then
gcrypt=true
AM_PATH_LIBGCRYPT([1.4.0], [], []) AM_PATH_LIBGCRYPT([1.4.0], [], [])
ln -sf gcrypt/cipher.c gcrypt/cipher.h gcrypt/crypto.c gcrypt/crypto.h gcrypt/digest.c gcrypt/digest.h gcrypt/ecdh.c gcrypt/ecdh.h gcrypt/ecdsa.c gcrypt/ecdsa.h gcrypt/ecdsagen.c gcrypt/ecdsagen.h gcrypt/prf.c gcrypt/prf.h gcrypt/rsa.c gcrypt/rsa.h gcrypt/rsagen.c gcrypt/rsagen.h src/
else else
openssl=true
tinc_OPENSSL tinc_OPENSSL
ln -sf openssl/cipher.c openssl/cipher.h openssl/crypto.c openssl/crypto.h openssl/digest.c openssl/digest.h openssl/ecdh.c openssl/ecdh.h openssl/ecdsa.c openssl/ecdsa.h openssl/ecdsagen.c openssl/ecdsagen.h openssl/prf.c openssl/prf.h openssl/rsa.c openssl/rsa.h openssl/rsagen.c openssl/rsagen.h src/
fi fi
AM_CONDITIONAL(OPENSSL, test "$openssl" = true)
AM_CONDITIONAL(GCRYPT, test "$grypt" = true)
dnl Check if support for jumbograms is requested dnl Check if support for jumbograms is requested
AC_ARG_ENABLE(jumbograms, AC_ARG_ENABLE(jumbograms,

View file

@ -11,6 +11,13 @@ tincd_SOURCES = \
protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c event.c tincd.c \ protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c event.c tincd.c \
dummy_device.c raw_socket_device.c multicast_device.c names.c dummy_device.c raw_socket_device.c multicast_device.c names.c
tinc_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \
info.c list.c subnet_parse.c tincctl.c top.c names.c
sptps_test_SOURCES = \
logger.c sptps.c sptps_test.c utils.c
## Conditionally compile device drivers ## Conditionally compile device drivers
if LINUX if LINUX
@ -19,6 +26,9 @@ endif
if BSD if BSD
tincd_SOURCES += bsd/device.c tincd_SOURCES += bsd/device.c
if TUNEMU
tincd_SOURCES += bsd/tunemu.c
endif
endif endif
if SOLARIS if SOLARIS
@ -41,22 +51,50 @@ if VDE
tincd_SOURCES += vde_device.c tincd_SOURCES += vde_device.c
endif endif
nodist_tincd_SOURCES = \ if OPENSSL
cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c tincd_SOURCES += \
openssl/cipher.c \
openssl/crypto.c \
openssl/ecdh.c \
openssl/ecdsa.c \
openssl/digest.c \
openssl/prf.c \
openssl/rsa.c
tinc_SOURCES += \
openssl/ecdsa.c \
openssl/ecdsagen.c \
openssl/rsa.c \
openssl/rsagen.c
sptps_test_SOURCES += \
openssl/cipher.c \
openssl/crypto.c \
openssl/ecdh.c \
openssl/ecdsa.c \
openssl/digest.c \
openssl/prf.c
endif
tinc_SOURCES = \ if GCRYPT
utils.c getopt.c getopt1.c dropin.c \ tincd_SOURCES += \
info.c list.c subnet_parse.c tincctl.c top.c names.c gcrypt/cipher.c \
gcrypt/crypto.c \
nodist_tinc_SOURCES = \ gcrypt/ecdh.c \
ecdsagen.c rsagen.c gcrypt/ecdsa.c \
gcrypt/digest.c \
sptps_test_SOURCES = \ gcrypt/prf.c \
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \ gcrypt/rsa.c
sptps.c sptps_test.c utils.c tinc_SOURCES += \
gcrypt/ecdsa.c \
if TUNEMU gcrypt/ecdsagen.c \
tincd_SOURCES += bsd/tunemu.c gcrypt/rsa.c \
gcrypt/rsagen.c
sptps_test_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/ecdh.c \
gcrypt/ecdsa.c \
gcrypt/digest.c \
gcrypt/prf.c
endif endif
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS) tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
@ -68,10 +106,7 @@ INCLUDES = @INCLUDES@
noinst_HEADERS = \ noinst_HEADERS = \
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \ xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \ buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h event.h names.h protocol.h route.h subnet.h sptps.h tincctl.h top.h hash.h event.h names.h have.h system.h
nodist_noinst_HEADERS = \
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h
LIBS = @LIBS@ @LIBGCRYPT_LIBS@ LIBS = @LIBS@ @LIBGCRYPT_LIBS@

View file

@ -1,6 +1,6 @@
/* /*
connection.c -- connection list management connection.c -- connection list management
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans 2000-2005 Ivo Timmermans
2008 Max Rijevski <maksuf@gmail.com> 2008 Max Rijevski <maksuf@gmail.com>
@ -27,6 +27,7 @@
#include "control_common.h" #include "control_common.h"
#include "list.h" #include "list.h"
#include "logger.h" #include "logger.h"
#include "rsa.h"
#include "subnet.h" #include "subnet.h"
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
@ -54,14 +55,14 @@ void free_connection(connection_t *c) {
if(!c) if(!c)
return; return;
cipher_close(&c->incipher); cipher_close(c->incipher);
digest_close(&c->indigest); digest_close(c->indigest);
cipher_close(&c->outcipher); cipher_close(c->outcipher);
digest_close(&c->outdigest); digest_close(c->outdigest);
sptps_stop(&c->sptps); sptps_stop(&c->sptps);
ecdsa_free(&c->ecdsa); ecdsa_free(c->ecdsa);
rsa_free(&c->rsa); rsa_free(c->rsa);
free(c->hischallenge); free(c->hischallenge);

View file

@ -1,6 +1,6 @@
/* /*
connection.h -- header for connection.c connection.h -- header for connection.c
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans 2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -73,12 +73,12 @@ typedef struct connection_t {
struct node_t *node; /* node associated with the other end */ struct node_t *node; /* node associated with the other end */
struct edge_t *edge; /* edge associated with this connection */ struct edge_t *edge; /* edge associated with this connection */
rsa_t rsa; /* his public RSA key */ rsa_t *rsa; /* his public RSA key */
ecdsa_t ecdsa; /* his public ECDSA key */ ecdsa_t *ecdsa; /* his public ECDSA key */
cipher_t incipher; /* Cipher he will use to send data to us */ cipher_t *incipher; /* Cipher he will use to send data to us */
cipher_t outcipher; /* Cipher we will use to send data to him */ cipher_t *outcipher; /* Cipher we will use to send data to him */
digest_t indigest; digest_t *indigest;
digest_t outdigest; digest_t *outdigest;
sptps_t sptps; sptps_t sptps;
int inmaclength; int inmaclength;

View file

@ -1,6 +1,6 @@
/* /*
ecdh.h -- header file for ecdh.c ecdh.c -- Diffie-Hellman key exchange handling
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,18 +17,21 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_ECDH_H__ #include "../system.h"
#define __TINC_ECDH_H__
#include <openssl/ecdh.h> #include "../ecdh.h"
#include "../logger.h"
#include "../utils.h"
#include "../xalloc.h"
#define ECDH_SIZE 67 ecdh_t *ecdh_generate_public(void *pubkey) {
#define ECDH_SHARED_SIZE 66 logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
typedef EC_KEY *ecdh_t; bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
return false
}
extern bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey); void ecdh_free(ecdh_t *ecdh) {
extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared); }
extern void ecdh_free(ecdh_t *ecdh);
#endif

67
src/gcrypt/ecdsa.c Normal file
View file

@ -0,0 +1,67 @@
/*
ecdsa.c -- ECDSA key handling
Copyright (C) 2011-2013 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#include "../logger.h"
#include "../ecdsa.h"
#include "../utils.h"
#include "../xalloc.h"
// Get and set ECDSA keys
//
ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
return NULL;
}
// Read PEM ECDSA keys
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
size_t ecdsa_size(ecdsa_t *ecdsa) {
return 0;
}
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
return false;
}
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
return false;
}
bool ecdsa_active(ecdsa_t *ecdsa) {
return false;
}
void ecdsa_free(ecdsa_t *ecdsa) {
}

View file

@ -1,6 +1,6 @@
/* /*
ecdsagen.h -- ECDSA key generation and export ecdsagen.c -- ECDSA key generation and export
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,14 +17,25 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_ECDSAGEN_H__ #include "../system.h"
#define __TINC_ECDSAGEN_H__
#include "ecdsa.h" #include "../ecdsagen.h"
#include "../utils.h"
#include "../xalloc.h"
extern bool ecdsa_generate(ecdsa_t *ecdsa); // Generate ECDSA key
extern bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp);
extern bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp);
extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa);
#endif ecdsa_t *ecdsa_generate(void) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
// Write PEM ECDSA keys
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
return false;
}
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
return false;
}

View file

@ -1,6 +1,6 @@
/* /*
crypto.h -- header for crypto.c prf.c -- Pseudo-Random Function for key material generation
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,11 +17,13 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_CRYPTO_H__ #include "../system.h"
#define __TINC_CRYPTO_H__
extern void crypto_init(); #include "digest.h"
extern void crypto_exit(); #include "../digest.h"
extern void randomize(void *, size_t); #include "../prf.h"
#endif bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
logger(DEBUG_ALWAYS, LOG_ERR, "PRF support using libgcrypt not implemented");
return false;
}

View file

@ -1,6 +1,6 @@
/* /*
meta.c -- handle the meta communication meta.c -- handle the meta communication
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans 2000-2005 Ivo Timmermans
2006 Scott Lamb <slamb@slamb.org> 2006 Scott Lamb <slamb@slamb.org>
@ -60,7 +60,7 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
if(c->status.encryptout) { if(c->status.encryptout) {
size_t outlen = length; size_t outlen = length;
if(!cipher_encrypt(&c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) { if(!cipher_encrypt(c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting metadata to %s (%s)", logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting metadata to %s (%s)",
c->name, c->hostname); c->name, c->hostname);
return false; return false;
@ -171,7 +171,7 @@ bool receive_meta(connection_t *c) {
} else { } else {
size_t outlen = inlen; size_t outlen = inlen;
if(!cipher_decrypt(&c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) { if(!cipher_decrypt(c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting metadata from %s (%s)", logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting metadata from %s (%s)",
c->name, c->hostname); c->name, c->hostname);
return false; return false;

View file

@ -318,10 +318,10 @@ static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
if(n->status.sptps) if(n->status.sptps)
return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len); return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) if(!digest_active(n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest))
return false; return false;
return digest_verify(&n->indigest, &inpkt->seqno, inpkt->len - n->indigest.maclength, (const char *)&inpkt->seqno + inpkt->len - n->indigest.maclength); return digest_verify(n->indigest, &inpkt->seqno, inpkt->len - digest_length(n->indigest), (const char *)&inpkt->seqno + inpkt->len - digest_length(n->indigest));
} }
static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
@ -336,7 +336,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
return; return;
} }
if(!cipher_active(&n->incipher)) { if(!cipher_active(n->incipher)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
n->name, n->hostname); n->name, n->hostname);
return; return;
@ -344,7 +344,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
/* Check packet length */ /* Check packet length */
if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) { if(inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)", logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)",
n->name, n->hostname); n->name, n->hostname);
return; return;
@ -352,20 +352,20 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
/* Check the message authentication code */ /* Check the message authentication code */
if(digest_active(&n->indigest)) { if(digest_active(n->indigest)) {
inpkt->len -= n->indigest.maclength; inpkt->len -= digest_length(n->indigest);
if(!digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) { if(!digest_verify(n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname); logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
return; return;
} }
} }
/* Decrypt the packet */ /* Decrypt the packet */
if(cipher_active(&n->incipher)) { if(cipher_active(n->incipher)) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
outlen = MAXSIZE; outlen = MAXSIZE;
if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) { if(!cipher_decrypt(n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname); logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
return; return;
} }
@ -653,11 +653,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
/* Encrypt the packet */ /* Encrypt the packet */
if(cipher_active(&n->outcipher)) { if(cipher_active(n->outcipher)) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
outlen = MAXSIZE; outlen = MAXSIZE;
if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) { if(!cipher_encrypt(n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname); logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
goto end; goto end;
} }
@ -668,9 +668,9 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
/* Add the message authentication code */ /* Add the message authentication code */
if(digest_active(&n->outdigest)) { if(digest_active(n->outdigest)) {
digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len); digest_create(n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len);
inpkt->len += digest_length(&n->outdigest); inpkt->len += digest_length(n->outdigest);
} }
/* Send the packet */ /* Send the packet */

View file

@ -58,14 +58,13 @@ char *scriptinterpreter;
char *scriptextension; char *scriptextension;
bool node_read_ecdsa_public_key(node_t *n) { bool node_read_ecdsa_public_key(node_t *n) {
if(ecdsa_active(&n->ecdsa)) if(ecdsa_active(n->ecdsa))
return true; return true;
splay_tree_t *config_tree; splay_tree_t *config_tree;
FILE *fp; FILE *fp;
char *pubname = NULL, *hcfname = NULL; char *pubname = NULL, *hcfname = NULL;
char *p; char *p;
bool result = false;
xasprintf(&hcfname, "%s" SLASH "hosts" SLASH "%s", confbase, n->name); xasprintf(&hcfname, "%s" SLASH "hosts" SLASH "%s", confbase, n->name);
@ -76,7 +75,7 @@ bool node_read_ecdsa_public_key(node_t *n) {
/* First, check for simple ECDSAPublicKey statement */ /* First, check for simple ECDSAPublicKey statement */
if(get_config_string(lookup_config(config_tree, "ECDSAPublicKey"), &p)) { if(get_config_string(lookup_config(config_tree, "ECDSAPublicKey"), &p)) {
result = ecdsa_set_base64_public_key(&n->ecdsa, p); n->ecdsa = ecdsa_set_base64_public_key(p);
free(p); free(p);
goto exit; goto exit;
} }
@ -93,28 +92,30 @@ bool node_read_ecdsa_public_key(node_t *n) {
goto exit; goto exit;
} }
result = ecdsa_read_pem_public_key(&n->ecdsa, fp); n->ecdsa = ecdsa_read_pem_public_key(fp);
fclose(fp); fclose(fp);
exit: exit:
exit_configuration(&config_tree); exit_configuration(&config_tree);
free(hcfname); free(hcfname);
free(pubname); free(pubname);
return result; return n->ecdsa;
} }
bool read_ecdsa_public_key(connection_t *c) { bool read_ecdsa_public_key(connection_t *c) {
if(ecdsa_active(c->ecdsa))
return true;
FILE *fp; FILE *fp;
char *fname; char *fname;
char *p; char *p;
bool result;
/* First, check for simple ECDSAPublicKey statement */ /* First, check for simple ECDSAPublicKey statement */
if(get_config_string(lookup_config(c->config_tree, "ECDSAPublicKey"), &p)) { if(get_config_string(lookup_config(c->config_tree, "ECDSAPublicKey"), &p)) {
result = ecdsa_set_base64_public_key(&c->ecdsa, p); c->ecdsa = ecdsa_set_base64_public_key(p);
free(p); free(p);
return result; return c->ecdsa;
} }
/* Else, check for ECDSAPublicKeyFile statement and read it */ /* Else, check for ECDSAPublicKeyFile statement and read it */
@ -131,27 +132,29 @@ bool read_ecdsa_public_key(connection_t *c) {
return false; return false;
} }
result = ecdsa_read_pem_public_key(&c->ecdsa, fp); c->ecdsa = ecdsa_read_pem_public_key(fp);
fclose(fp); fclose(fp);
if(!result) if(!c->ecdsa)
logger(DEBUG_ALWAYS, LOG_ERR, "Parsing ECDSA public key file `%s' failed.", fname); logger(DEBUG_ALWAYS, LOG_ERR, "Parsing ECDSA public key file `%s' failed.", fname);
free(fname); free(fname);
return result; return c->ecdsa;
} }
bool read_rsa_public_key(connection_t *c) { bool read_rsa_public_key(connection_t *c) {
if(ecdsa_active(c->ecdsa))
return true;
FILE *fp; FILE *fp;
char *fname; char *fname;
char *n; char *n;
bool result;
/* First, check for simple PublicKey statement */ /* First, check for simple PublicKey statement */
if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) { if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) {
result = rsa_set_hex_public_key(&c->rsa, n, "FFFF"); c->rsa = rsa_set_hex_public_key(n, "FFFF");
free(n); free(n);
return result; return c->rsa;
} }
/* Else, check for PublicKeyFile statement and read it */ /* Else, check for PublicKeyFile statement and read it */
@ -167,19 +170,18 @@ bool read_rsa_public_key(connection_t *c) {
return false; return false;
} }
result = rsa_read_pem_public_key(&c->rsa, fp); c->rsa = rsa_read_pem_public_key(fp);
fclose(fp); fclose(fp);
if(!result) if(!c->rsa)
logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno)); logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
free(fname); free(fname);
return result; return c->rsa;
} }
static bool read_ecdsa_private_key(void) { static bool read_ecdsa_private_key(void) {
FILE *fp; FILE *fp;
char *fname; char *fname;
bool result;
/* Check for PrivateKeyFile statement and read it */ /* Check for PrivateKeyFile statement and read it */
@ -207,20 +209,19 @@ static bool read_ecdsa_private_key(void) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for ECDSA private key file `%s'!", fname); logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for ECDSA private key file `%s'!", fname);
#endif #endif
result = ecdsa_read_pem_private_key(&myself->connection->ecdsa, fp); myself->connection->ecdsa = ecdsa_read_pem_private_key(fp);
fclose(fp); fclose(fp);
if(!result) if(!myself->connection->ecdsa)
logger(DEBUG_ALWAYS, LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno)); logger(DEBUG_ALWAYS, LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno));
free(fname); free(fname);
return result; return myself->connection->ecdsa;
} }
static bool read_rsa_private_key(void) { static bool read_rsa_private_key(void) {
FILE *fp; FILE *fp;
char *fname; char *fname;
char *n, *d; char *n, *d;
bool result;
/* First, check for simple PrivateKey statement */ /* First, check for simple PrivateKey statement */
@ -230,10 +231,10 @@ static bool read_rsa_private_key(void) {
free(d); free(d);
return false; return false;
} }
result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d); myself->connection->rsa = rsa_set_hex_private_key(n, "FFFF", d);
free(n); free(n);
free(d); free(d);
return result; return myself->connection->rsa;
} }
/* Else, check for PrivateKeyFile statement and read it */ /* Else, check for PrivateKeyFile statement and read it */
@ -263,13 +264,13 @@ static bool read_rsa_private_key(void) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname); logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
#endif #endif
result = rsa_read_pem_private_key(&myself->connection->rsa, fp); myself->connection->rsa = rsa_read_pem_private_key(fp);
fclose(fp); fclose(fp);
if(!result) if(!myself->connection->rsa)
logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno)); logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
free(fname); free(fname);
return result; return myself->connection->rsa;
} }
static timeout_t keyexpire_timeout; static timeout_t keyexpire_timeout;
@ -707,7 +708,7 @@ static bool setup_myself(void) {
if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher)) if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
cipher = xstrdup("blowfish"); cipher = xstrdup("blowfish");
if(!cipher_open_by_name(&myself->incipher, cipher)) { if(!(myself->incipher = cipher_open_by_name(cipher))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!"); logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
return false; return false;
} }
@ -730,7 +731,7 @@ static bool setup_myself(void) {
if(!get_config_string(lookup_config(config_tree, "Digest"), &digest)) if(!get_config_string(lookup_config(config_tree, "Digest"), &digest))
digest = xstrdup("sha1"); digest = xstrdup("sha1");
if(!digest_open_by_name(&myself->indigest, digest, maclength)) { if(!(myself->indigest = digest_open_by_name(digest, maclength))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!"); logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!");
return false; return false;
} }

View file

@ -1,6 +1,6 @@
/* /*
node.c -- node tree management node.c -- node tree management
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2001-2013 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans 2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -70,12 +70,12 @@ void free_node(node_t *n) {
sockaddrfree(&n->address); sockaddrfree(&n->address);
cipher_close(&n->incipher); cipher_close(n->incipher);
digest_close(&n->indigest); digest_close(n->indigest);
cipher_close(&n->outcipher); cipher_close(n->outcipher);
digest_close(&n->outdigest); digest_close(n->outdigest);
ecdsa_free(&n->ecdsa); ecdsa_free(n->ecdsa);
sptps_stop(&n->sptps); sptps_stop(&n->sptps);
timeout_del(&n->mtutimeout); timeout_del(&n->mtutimeout);
@ -145,8 +145,8 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
bool dump_nodes(connection_t *c) { bool dump_nodes(connection_t *c) {
for splay_each(node_t, n, node_tree) for splay_each(node_t, n, node_tree)
send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES, send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(&n->outcipher), n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(n->outcipher),
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression, digest_get_nid(n->outdigest), (int)digest_length(n->outdigest), n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-", n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change); n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);

View file

@ -52,14 +52,14 @@ typedef struct node_t {
time_t last_state_change; time_t last_state_change;
time_t last_req_key; time_t last_req_key;
ecdsa_t ecdsa; /* His public ECDSA key */ ecdsa_t *ecdsa; /* His public ECDSA key */
sptps_t sptps; sptps_t sptps;
cipher_t incipher; /* Cipher for UDP packets */ cipher_t *incipher; /* Cipher for UDP packets */
digest_t indigest; /* Digest for UDP packets */ digest_t *indigest; /* Digest for UDP packets */
cipher_t outcipher; /* Cipher for UDP packets */ cipher_t *outcipher; /* Cipher for UDP packets */
digest_t outdigest; /* Digest for UDP packets */ digest_t *outdigest; /* Digest for UDP packets */
int incompression; /* Compressionlevel, 0 = no compression */ int incompression; /* Compressionlevel, 0 = no compression */
int outcompression; /* Compressionlevel, 0 = no compression */ int outcompression; /* Compressionlevel, 0 = no compression */

View file

@ -1,6 +1,6 @@
/* /*
cipher.c -- Symmetric block cipher handling cipher.c -- Symmetric block cipher handling
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,56 +17,67 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/evp.h>
#include "cipher.h" #include "../cipher.h"
#include "logger.h" #include "../logger.h"
#include "xalloc.h" #include "../xalloc.h"
struct cipher {
EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher;
struct cipher_counter *counter;
};
typedef struct cipher_counter { typedef struct cipher_counter {
unsigned char counter[EVP_MAX_IV_LENGTH]; unsigned char counter[CIPHER_MAX_IV_SIZE];
unsigned char block[EVP_MAX_IV_LENGTH]; unsigned char block[CIPHER_MAX_IV_SIZE];
int n; int n;
} cipher_counter_t; } cipher_counter_t;
static bool cipher_open(cipher_t *cipher) { static cipher_t *cipher_open(const EVP_CIPHER *evp_cipher) {
cipher_t *cipher = xmalloc_and_zero(sizeof *cipher);
cipher->cipher = evp_cipher;
EVP_CIPHER_CTX_init(&cipher->ctx); EVP_CIPHER_CTX_init(&cipher->ctx);
return true; return cipher;
} }
bool cipher_open_by_name(cipher_t *cipher, const char *name) { cipher_t *cipher_open_by_name(const char *name) {
cipher->cipher = EVP_get_cipherbyname(name); const EVP_CIPHER *evp_cipher = EVP_get_cipherbyname(name);
if(!evp_cipher) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher name '%s'!", name);
return NULL;
}
if(cipher->cipher) return cipher_open(evp_cipher);
return cipher_open(cipher);
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher name '%s'!", name);
return false;
} }
bool cipher_open_by_nid(cipher_t *cipher, int nid) { cipher_t *cipher_open_by_nid(int nid) {
cipher->cipher = EVP_get_cipherbynid(nid); const EVP_CIPHER *evp_cipher = EVP_get_cipherbynid(nid);
if(!evp_cipher) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher nid %d!", nid);
return NULL;
}
if(cipher->cipher) return cipher_open(evp_cipher);
return cipher_open(cipher);
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher nid %d!", nid);
return false;
} }
bool cipher_open_blowfish_ofb(cipher_t *cipher) { cipher_t *cipher_open_blowfish_ofb(void) {
cipher->cipher = EVP_bf_ofb(); return cipher_open(EVP_bf_ofb());
return cipher_open(cipher);
} }
void cipher_close(cipher_t *cipher) { void cipher_close(cipher_t *cipher) {
if(!cipher)
return;
EVP_CIPHER_CTX_cleanup(&cipher->ctx); EVP_CIPHER_CTX_cleanup(&cipher->ctx);
free(cipher->counter); free(cipher->counter);
cipher->counter = NULL; free(cipher);
} }
size_t cipher_keylength(const cipher_t *cipher) { size_t cipher_keylength(const cipher_t *cipher) {
@ -214,5 +225,5 @@ int cipher_get_nid(const cipher_t *cipher) {
} }
bool cipher_active(const cipher_t *cipher) { bool cipher_active(const cipher_t *cipher) {
return cipher->cipher && cipher->cipher->nid != 0; return cipher && cipher->cipher && cipher->cipher->nid != 0;
} }

View file

@ -1,50 +0,0 @@
/*
cipher.h -- header file cipher.c
Copyright (C) 2007-2012 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __TINC_CIPHER_H__
#define __TINC_CIPHER_H__
#include <openssl/evp.h>
#define CIPHER_MAX_BLOCK_SIZE EVP_MAX_BLOCK_LENGTH
#define CIPHER_MAX_KEY_SIZE EVP_MAX_KEY_LENGTH
#define CIPHER_MAX_IV_SIZE EVP_MAX_IV_LENGTH
typedef struct cipher {
EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher;
struct cipher_counter *counter;
} 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 bool cipher_set_key(cipher_t *, void *, bool);
extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool);
extern bool cipher_set_counter(cipher_t *, const void *, size_t);
extern bool cipher_set_counter_key(cipher_t *, void *);
extern bool cipher_encrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
extern bool cipher_decrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
extern bool cipher_counter_xor(cipher_t *, const void *indata, size_t inlen, void *outdata);
extern int cipher_get_nid(const cipher_t *);
extern bool cipher_active(const cipher_t *);
#endif

View file

@ -1,6 +1,6 @@
/* /*
crypto.c -- Cryptographic miscellaneous functions and initialisation crypto.c -- Cryptographic miscellaneous functions and initialisation
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,13 +17,13 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/engine.h> #include <openssl/engine.h>
#include "crypto.h" #include "../crypto.h"
void crypto_init(void) { void crypto_init(void) {
RAND_load_file("/dev/urandom", 1024); RAND_load_file("/dev/urandom", 1024);

View file

@ -1,6 +1,6 @@
/* /*
digest.c -- Digest handling digest.c -- Digest handling
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,57 +17,55 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include "utils.h" #include "../utils.h"
#include "xalloc.h" #include "../xalloc.h"
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include "digest.h" #include "digest.h"
#include "logger.h" #include "../digest.h"
#include "../logger.h"
static digest_t *digest_open(const EVP_MD *evp_md, int maclength) {
digest_t *digest = xmalloc_and_zero(sizeof *digest);
digest->digest = evp_md;
static void set_maclength(digest_t *digest, int maclength) {
int digestlen = EVP_MD_size(digest->digest); int digestlen = EVP_MD_size(digest->digest);
if(maclength > digestlen || maclength < 0) if(maclength > digestlen || maclength < 0)
digest->maclength = digestlen; digest->maclength = digestlen;
else else
digest->maclength = maclength; digest->maclength = maclength;
return digest;
} }
bool digest_open_by_name(digest_t *digest, const char *name, int maclength) { digest_t *digest_open_by_name(const char *name, int maclength) {
digest->digest = EVP_get_digestbyname(name); const EVP_MD *evp_md = EVP_get_digestbyname(name);
digest->key = NULL;
if(!digest->digest) { if(!evp_md) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name); logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
return false; return false;
} }
set_maclength(digest, maclength); return digest_open(evp_md, maclength);
return true;
} }
bool digest_open_by_nid(digest_t *digest, int nid, int maclength) { digest_t *digest_open_by_nid(int nid, int maclength) {
digest->digest = EVP_get_digestbynid(nid); const EVP_MD *evp_md = EVP_get_digestbynid(nid);
digest->key = NULL;
if(!digest->digest) { if(!evp_md) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid); logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid);
return false; return false;
} }
set_maclength(digest, maclength); return digest_open(evp_md, maclength);
return true;
} }
bool digest_open_sha1(digest_t *digest, int maclength) { digest_t *digest_open_sha1(int maclength) {
digest->digest = EVP_sha1(); return digest_open(EVP_sha1(), maclength);
digest->key = NULL;
set_maclength(digest, maclength);
return true;
} }
bool digest_set_key(digest_t *digest, const void *key, size_t len) { bool digest_set_key(digest_t *digest, const void *key, size_t len) {
@ -78,8 +76,11 @@ bool digest_set_key(digest_t *digest, const void *key, size_t len) {
} }
void digest_close(digest_t *digest) { void digest_close(digest_t *digest) {
if(!digest)
return;
free(digest->key); free(digest->key);
digest->key = NULL; free(digest);
} }
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) { bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
@ -123,5 +124,5 @@ size_t digest_length(const digest_t *digest) {
} }
bool digest_active(const digest_t *digest) { bool digest_active(const digest_t *digest) {
return digest->digest && digest->digest->type != 0; return digest && digest->digest && digest->digest->type != 0;
} }

View file

@ -1,6 +1,6 @@
/* /*
digest.h -- header file digest.c digest.h -- header file digest.c
Copyright (C) 2007-2011 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,13 +17,11 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_DIGEST_H__ #ifndef __TINC_OPENSSL_DIGEST_H__
#define __TINC_DIGEST_H__ #define __TINC_OPENSSL_DIGEST_H__
#include <openssl/evp.h> #include <openssl/evp.h>
#define DIGEST_MAX_SIZE EVP_MAX_MD_SIZE
typedef struct digest { typedef struct digest {
const EVP_MD *digest; const EVP_MD *digest;
int maclength; int maclength;
@ -31,16 +29,4 @@ typedef struct digest {
char *key; char *key;
} digest_t; } digest_t;
extern bool digest_open_by_name(struct digest *, const char *name, int maclength);
extern bool digest_open_by_nid(struct digest *, int nid, int maclength);
extern bool digest_open_sha1(struct digest *, int maclength);
extern void digest_close(struct digest *);
extern bool digest_create(struct digest *, const void *indata, size_t inlen, void *outdata);
extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
extern bool digest_set_key(struct digest *, const void *key, size_t len);
extern int digest_get_nid(const struct digest *);
extern size_t digest_keylength(const struct digest *);
extern size_t digest_length(const struct digest *);
extern bool digest_active(const struct digest *);
#endif #endif

View file

@ -1,6 +1,6 @@
/* /*
ecdh.c -- Diffie-Hellman key exchange handling ecdh.c -- Diffie-Hellman key exchange handling
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,68 +17,70 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include "utils.h"
#include "xalloc.h"
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/ec.h> #include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/obj_mac.h> #include <openssl/obj_mac.h>
#include "ecdh.h" #define __TINC_ECDH_INTERNAL__
#include "logger.h" typedef EC_KEY ecdh_t;
bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) { #include "../ecdh.h"
*ecdh = EC_KEY_new_by_curve_name(NID_secp521r1); #include "../logger.h"
if(!*ecdh) { #include "../utils.h"
#include "../xalloc.h"
ecdh_t *ecdh_generate_public(void *pubkey) {
ecdh_t *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
if(!ecdh) {
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
if(!EC_KEY_generate_key(*ecdh)) { if(!EC_KEY_generate_key(ecdh)) {
EC_KEY_free(*ecdh); EC_KEY_free(ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return NULL;
} }
const EC_POINT *point = EC_KEY_get0_public_key(*ecdh); const EC_POINT *point = EC_KEY_get0_public_key(ecdh);
if(!point) { if(!point) {
EC_KEY_free(*ecdh); EC_KEY_free(ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return NULL;
} }
size_t result = EC_POINT_point2oct(EC_KEY_get0_group(*ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL); size_t result = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL);
if(!result) { if(!result) {
EC_KEY_free(*ecdh); EC_KEY_free(ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return NULL;
} }
return true; return ecdh;
} }
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) { bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(*ecdh)); EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(ecdh));
if(!point) { if(!point) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(ecdh);
return false; return false;
} }
int result = EC_POINT_oct2point(EC_KEY_get0_group(*ecdh), point, pubkey, ECDH_SIZE, NULL); int result = EC_POINT_oct2point(EC_KEY_get0_group(ecdh), point, pubkey, ECDH_SIZE, NULL);
if(!result) { if(!result) {
EC_POINT_free(point); EC_POINT_free(point);
EC_KEY_free(ecdh);
logger(DEBUG_ALWAYS, LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
result = ECDH_compute_key(shared, ECDH_SIZE, point, *ecdh, NULL); result = ECDH_compute_key(shared, ECDH_SIZE, point, ecdh, NULL);
EC_POINT_free(point); EC_POINT_free(point);
EC_KEY_free(*ecdh); EC_KEY_free(ecdh);
*ecdh = NULL;
if(!result) { if(!result) {
logger(DEBUG_ALWAYS, LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
@ -89,8 +91,6 @@ bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
} }
void ecdh_free(ecdh_t *ecdh) { void ecdh_free(ecdh_t *ecdh) {
if(*ecdh) { if(ecdh)
EC_KEY_free(*ecdh); EC_KEY_free(ecdh);
*ecdh = NULL;
}
} }

View file

@ -1,6 +1,6 @@
/* /*
ecdsa.c -- ECDSA key handling ecdsa.c -- ECDSA key handling
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,22 +17,26 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/err.h> #include <openssl/err.h>
#include "logger.h" #define __TINC_ECDSA_INTERNAL__
#include "ecdsa.h" typedef EC_KEY ecdsa_t;
#include "utils.h"
#include "../logger.h"
#include "../ecdsa.h"
#include "../utils.h"
#include "../xalloc.h"
// Get and set ECDSA keys // Get and set ECDSA keys
// //
bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) { ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
*ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1); ecdsa_t *ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
if(!*ecdsa) { if(!ecdsa) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "EC_KEY_new_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_DEBUG, "EC_KEY_new_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return NULL;
} }
int len = strlen(p); int len = strlen(p);
@ -40,19 +44,20 @@ bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
const unsigned char *ppubkey = pubkey; const unsigned char *ppubkey = pubkey;
len = b64decode(p, (char *)pubkey, len); len = b64decode(p, (char *)pubkey, len);
if(!o2i_ECPublicKey(ecdsa, &ppubkey, len)) { if(!o2i_ECPublicKey(&ecdsa, &ppubkey, len)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; EC_KEY_free(ecdsa);
return NULL;
} }
return true; return ecdsa;
} }
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) { char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
unsigned char *pubkey = NULL; unsigned char *pubkey = NULL;
int len = i2o_ECPublicKey(*ecdsa, &pubkey); int len = i2o_ECPublicKey(ecdsa, &pubkey);
char *base64 = malloc(len * 4 / 3 + 5); char *base64 = xmalloc(len * 4 / 3 + 5);
b64encode((char *)pubkey, base64, len); b64encode((char *)pubkey, base64, len);
free(pubkey); free(pubkey);
@ -62,41 +67,39 @@ char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
// Read PEM ECDSA keys // Read PEM ECDSA keys
bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp) { ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
*ecdsa = PEM_read_EC_PUBKEY(fp, ecdsa, NULL, NULL); ecdsa_t *ecdsa = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL);
if(*ecdsa) if(!ecdsa)
return true; logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL)); return ecdsa;
return false;
} }
bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp) { ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
*ecdsa = PEM_read_ECPrivateKey(fp, NULL, NULL, NULL); ecdsa_t *ecdsa = PEM_read_ECPrivateKey(fp, NULL, NULL, NULL);
if(*ecdsa) if(!ecdsa)
return true; logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL)); return ecdsa;
return false;
} }
size_t ecdsa_size(ecdsa_t *ecdsa) { size_t ecdsa_size(ecdsa_t *ecdsa) {
return ECDSA_size(*ecdsa); return ECDSA_size(ecdsa);
} }
// TODO: standardise output format? // TODO: standardise output format?
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) { bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa); unsigned int siglen = ECDSA_size(ecdsa);
unsigned char hash[SHA512_DIGEST_LENGTH]; unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash); SHA512(in, len, hash);
memset(sig, 0, siglen); memset(sig, 0, siglen);
if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, *ecdsa)) { if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, ecdsa)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -105,12 +108,12 @@ bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
} }
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) { bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa); unsigned int siglen = ECDSA_size(ecdsa);
unsigned char hash[SHA512_DIGEST_LENGTH]; unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash); SHA512(in, len, hash);
if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, *ecdsa)) { if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, ecdsa)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -119,12 +122,10 @@ bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
} }
bool ecdsa_active(ecdsa_t *ecdsa) { bool ecdsa_active(ecdsa_t *ecdsa) {
return *ecdsa; return ecdsa;
} }
void ecdsa_free(ecdsa_t *ecdsa) { void ecdsa_free(ecdsa_t *ecdsa) {
if(*ecdsa) { if(ecdsa)
EC_KEY_free(*ecdsa); EC_KEY_free(ecdsa);
*ecdsa = NULL;
}
} }

View file

@ -1,37 +0,0 @@
/*
ecdsa.h -- ECDSA key handling
Copyright (C) 2011 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __TINC_ECDSA_H__
#define __TINC_ECDSA_H__
#include <openssl/ec.h>
typedef EC_KEY *ecdsa_t;
extern bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p);
extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa);
extern bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp);
extern bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp);
extern size_t ecdsa_size(ecdsa_t *ecdsa);
extern bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t inlen, void *out);
extern bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t inlen, const void *out);
extern bool ecdsa_active(ecdsa_t *ecdsa);
extern void ecdsa_free(ecdsa_t *ecdsa);
#endif

View file

@ -1,6 +1,6 @@
/* /*
ecdsagen.c -- ECDSA key generation and export ecdsagen.c -- ECDSA key generation and export
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,59 +17,50 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/obj_mac.h> #include <openssl/obj_mac.h>
#include "ecdsagen.h" #define __TINC_ECDSA_INTERNAL__
#include "utils.h" typedef EC_KEY ecdsa_t;
#include "../ecdsagen.h"
#include "../utils.h"
#include "../xalloc.h"
// Generate ECDSA key // Generate ECDSA key
bool ecdsa_generate(ecdsa_t *ecdsa) { ecdsa_t *ecdsa_generate(void) {
*ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1); ecdsa_t *ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
if(!EC_KEY_generate_key(*ecdsa)) { if(!ecdsa || !EC_KEY_generate_key(ecdsa)) {
fprintf(stderr, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL)); fprintf(stderr, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
ecdsa_free(ecdsa);
return false; return false;
} }
EC_KEY_set_asn1_flag(*ecdsa, OPENSSL_EC_NAMED_CURVE); EC_KEY_set_asn1_flag(ecdsa, OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(*ecdsa, POINT_CONVERSION_COMPRESSED); EC_KEY_set_conv_form(ecdsa, POINT_CONVERSION_COMPRESSED);
return true; return ecdsa;
} }
// Write PEM ECDSA keys // Write PEM ECDSA keys
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) { bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
BIO *out = BIO_new(BIO_s_file()); BIO *out = BIO_new(BIO_s_file());
BIO_set_fp(out,fp,BIO_NOCLOSE); BIO_set_fp(out, fp, BIO_NOCLOSE);
PEM_write_bio_EC_PUBKEY(out, *ecdsa); PEM_write_bio_EC_PUBKEY(out, ecdsa);
BIO_free(out); BIO_free(out);
return true; return true;
} }
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) { bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
BIO *out = BIO_new(BIO_s_file()); BIO *out = BIO_new(BIO_s_file());
BIO_set_fp(out,fp,BIO_NOCLOSE); BIO_set_fp(out, fp, BIO_NOCLOSE);
PEM_write_bio_ECPrivateKey(out, *ecdsa, NULL, NULL, 0, NULL, NULL); PEM_write_bio_ECPrivateKey(out, ecdsa, NULL, NULL, 0, NULL, NULL);
BIO_free(out); BIO_free(out);
return true; return true;
} }
// Convert ECDSA public key to base64 format
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
unsigned char *pubkey = NULL;
int len = i2o_ECPublicKey(*ecdsa, &pubkey);
char *base64 = malloc(len * 4 / 3 + 5);
b64encode((char *)pubkey, base64, len);
free(pubkey);
return base64;
}

View file

@ -1,6 +1,6 @@
/* /*
prf.c -- Pseudo-Random Function for key material generation prf.c -- Pseudo-Random Function for key material generation
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,27 +17,30 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include <openssl/obj_mac.h> #include <openssl/obj_mac.h>
#include "digest.h" #include "digest.h"
#include "prf.h" #include "../digest.h"
#include "../prf.h"
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5. /* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
We use SHA512 instead of MD5 and SHA1. We use SHA512 instead of MD5 and SHA1.
*/ */
static bool prf_xor(int nid, const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) { static bool prf_xor(int nid, const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) {
digest_t digest; digest_t *digest = digest_open_by_nid(nid, -1);
if(!digest_open_by_nid(&digest, nid, -1)) if(!digest)
return false; return false;
if(!digest_set_key(&digest, secret, secretlen)) if(!digest_set_key(digest, secret, secretlen)) {
digest_close(digest);
return false; return false;
}
size_t len = digest_length(&digest); size_t len = digest_length(digest);
/* Data is what the "inner" HMAC function processes. /* Data is what the "inner" HMAC function processes.
It consists of the previous HMAC result plus the seed. It consists of the previous HMAC result plus the seed.
@ -51,10 +54,10 @@ static bool prf_xor(int nid, const char *secret, size_t secretlen, char *seed, s
while(outlen > 0) { while(outlen > 0) {
/* Inner HMAC */ /* Inner HMAC */
digest_create(&digest, data, len + seedlen, data); digest_create(digest, data, len + seedlen, data);
/* Outer HMAC */ /* Outer HMAC */
digest_create(&digest, data, len + seedlen, hash); digest_create(digest, data, len + seedlen, hash);
/* XOR the results of the outer HMAC into the out buffer */ /* XOR the results of the outer HMAC into the out buffer */
for(int i = 0; i < len && i < outlen; i++) for(int i = 0; i < len && i < outlen; i++)
@ -63,7 +66,7 @@ static bool prf_xor(int nid, const char *secret, size_t secretlen, char *seed, s
outlen -= len; outlen -= len;
} }
digest_close(&digest); digest_close(digest);
return true; return true;
} }

View file

@ -1,25 +0,0 @@
/*
prf.h -- header file for prf.c
Copyright (C) 2011 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __TINC_PRF_H__
#define __TINC_PRF_H__
extern bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen);
#endif

View file

@ -1,6 +1,6 @@
/* /*
rsa.c -- RSA key handling rsa.c -- RSA key handling
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,69 +17,74 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/err.h> #include <openssl/err.h>
#include "logger.h" #define __TINC_RSA_INTERNAL__
#include "rsa.h" typedef RSA rsa_t;
#include "../logger.h"
#include "../rsa.h"
// Set RSA keys // Set RSA keys
bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) { rsa_t *rsa_set_hex_public_key(char *n, char *e) {
*rsa = RSA_new(); rsa_t *rsa = RSA_new();
if(BN_hex2bn(&(*rsa)->n, n) != strlen(n)) if(!rsa)
return NULL;
if(BN_hex2bn(&rsa->n, n) != strlen(n) || BN_hex2bn(&rsa->e, e) != strlen(e)) {
RSA_free(rsa);
return false; return false;
if(BN_hex2bn(&(*rsa)->e, e) != strlen(e)) }
return false;
return true; return rsa;
} }
bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) { rsa_t *rsa_set_hex_private_key(char *n, char *e, char *d) {
*rsa = RSA_new(); rsa_t *rsa = RSA_new();
if(BN_hex2bn(&(*rsa)->n, n) != strlen(n)) if(!rsa)
return NULL;
if(BN_hex2bn(&rsa->n, n) != strlen(n) || BN_hex2bn(&rsa->e, e) != strlen(e) || BN_hex2bn(&rsa->d, d) != strlen(d)) {
RSA_free(rsa);
return false; return false;
if(BN_hex2bn(&(*rsa)->e, e) != strlen(e)) }
return false;
if(BN_hex2bn(&(*rsa)->d, d) != strlen(d)) return rsa;
return false;
return true;
} }
// Read PEM RSA keys // Read PEM RSA keys
bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) { rsa_t *rsa_read_pem_public_key(FILE *fp) {
*rsa = PEM_read_RSAPublicKey(fp, rsa, NULL, NULL); rsa_t *rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
if(*rsa) if(!rsa)
return true; rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
*rsa = PEM_read_RSA_PUBKEY(fp, rsa, NULL, NULL); if(!rsa)
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
if(*rsa) return rsa;
return true;
logger(DEBUG_ALWAYS, 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_t *rsa_read_pem_private_key(FILE *fp) {
*rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); rsa_t *rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
if(*rsa) if(!rsa)
return true; logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", ERR_error_string(ERR_get_error(), NULL)); return rsa;
return false;
} }
size_t rsa_size(rsa_t *rsa) { size_t rsa_size(rsa_t *rsa) {
return RSA_size(*rsa); return RSA_size(rsa);
} }
bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) { 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) if(RSA_public_encrypt(len, in, out, rsa, RSA_NO_PADDING) == len)
return true; return true;
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA encryption: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA encryption: %s", ERR_error_string(ERR_get_error(), NULL));
@ -87,7 +92,7 @@ bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
} }
bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) { 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) if(RSA_private_decrypt(len, in, out, rsa, RSA_NO_PADDING) == len)
return true; return true;
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA decryption: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA decryption: %s", ERR_error_string(ERR_get_error(), NULL));
@ -95,12 +100,10 @@ bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
} }
bool rsa_active(rsa_t *rsa) { bool rsa_active(rsa_t *rsa) {
return *rsa; return rsa;
} }
void rsa_free(rsa_t *rsa) { void rsa_free(rsa_t *rsa) {
if(*rsa) { if(rsa)
RSA_free(*rsa); RSA_free(rsa);
*rsa = NULL;
}
} }

View file

@ -1,38 +0,0 @@
/*
rsa.h -- RSA key handling
Copyright (C) 2007-2011 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#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);
extern bool rsa_active(rsa_t *rsa);
extern void rsa_free(rsa_t *rsa);
#endif

View file

@ -1,6 +1,6 @@
/* /*
rsagen.c -- RSA key generation and export rsagen.c -- RSA key generation and export
Copyright (C) 2008 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2008-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,13 +17,16 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "system.h" #include "../system.h"
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/err.h> #include <openssl/err.h>
#include "logger.h" #define __TINC_RSA_INTERNAL__
#include "rsagen.h" typedef RSA rsa_t;
#include "../logger.h"
#include "../rsagen.h"
/* This function prettyprints the key generation process */ /* This function prettyprints the key generation process */
@ -63,21 +66,16 @@ static void indicator(int a, int b, void *p) {
// Generate RSA key // Generate RSA key
bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent) { rsa_t *rsa_generate(size_t bits, unsigned long exponent) {
*rsa = RSA_generate_key(bits, exponent, indicator, NULL); return RSA_generate_key(bits, exponent, indicator, NULL);
return *rsa;
} }
// Write PEM RSA keys // Write PEM RSA keys
bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) { bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
PEM_write_RSAPublicKey(fp, *rsa); return PEM_write_RSAPublicKey(fp, rsa);
return true;
} }
bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) { bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
PEM_write_RSAPrivateKey(fp, *rsa, NULL, NULL, 0, NULL, NULL); return PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL);
return true;
} }

View file

@ -1,29 +0,0 @@
/*
rsagen.h -- RSA key generation and export
Copyright (C) 2008 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __TINC_RSAGEN_H__
#define __TINC_RSAGEN_H__
#include "rsa.h"
extern bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent);
extern bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp);
extern bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp);
#endif

View file

@ -1,7 +1,7 @@
/* /*
protocol_auth.c -- handle the meta-protocol, authentication protocol_auth.c -- handle the meta-protocol, authentication
Copyright (C) 1999-2005 Ivo Timmermans, Copyright (C) 1999-2005 Ivo Timmermans,
2000-2012 Guus Sliepen <guus@tinc-vpn.org> 2000-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -221,7 +221,7 @@ bool id_h(connection_t *c, const char *request) {
return false; return false;
} }
} else { } else {
if(c->protocol_minor && !ecdsa_active(&c->ecdsa)) if(c->protocol_minor && !ecdsa_active(c->ecdsa))
c->protocol_minor = 1; c->protocol_minor = 1;
} }
@ -246,13 +246,13 @@ bool send_metakey(connection_t *c) {
if(!read_rsa_public_key(c)) if(!read_rsa_public_key(c))
return false; return false;
if(!cipher_open_blowfish_ofb(&c->outcipher)) if(!(c->outcipher = cipher_open_blowfish_ofb()))
return false; return false;
if(!digest_open_sha1(&c->outdigest, -1)) if(!(c->outdigest = digest_open_sha1(-1)))
return false; return false;
size_t len = rsa_size(&c->rsa); size_t len = rsa_size(c->rsa);
char key[len]; char key[len];
char enckey[len]; char enckey[len];
char hexkey[2 * len + 1]; char hexkey[2 * len + 1];
@ -273,7 +273,7 @@ bool send_metakey(connection_t *c) {
key[0] &= 0x7F; key[0] &= 0x7F;
cipher_set_key_from_rsa(&c->outcipher, key, len, true); cipher_set_key_from_rsa(c->outcipher, key, len, true);
if(debug_level >= DEBUG_SCARY_THINGS) { if(debug_level >= DEBUG_SCARY_THINGS) {
bin2hex(key, hexkey, len); bin2hex(key, hexkey, len);
@ -287,7 +287,7 @@ bool send_metakey(connection_t *c) {
with a length equal to that of the modulus of the RSA key. with a length equal to that of the modulus of the RSA key.
*/ */
if(!rsa_public_encrypt(&c->rsa, key, len, enckey)) { if(!rsa_public_encrypt(c->rsa, key, len, enckey)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error during encryption of meta key for %s (%s)", c->name, c->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Error during encryption of meta key for %s (%s)", c->name, c->hostname);
return false; return false;
} }
@ -299,8 +299,8 @@ bool send_metakey(connection_t *c) {
/* Send the meta key */ /* Send the meta key */
bool result = send_request(c, "%d %d %d %d %d %s", METAKEY, bool result = send_request(c, "%d %d %d %d %d %s", METAKEY,
cipher_get_nid(&c->outcipher), cipher_get_nid(c->outcipher),
digest_get_nid(&c->outdigest), c->outmaclength, digest_get_nid(c->outdigest), c->outmaclength,
c->outcompression, hexkey); c->outcompression, hexkey);
c->status.encryptout = true; c->status.encryptout = true;
@ -310,7 +310,7 @@ bool send_metakey(connection_t *c) {
bool metakey_h(connection_t *c, const char *request) { bool metakey_h(connection_t *c, const char *request) {
char hexkey[MAX_STRING_SIZE]; char hexkey[MAX_STRING_SIZE];
int cipher, digest, maclength, compression; int cipher, digest, maclength, compression;
size_t len = rsa_size(&myself->connection->rsa); size_t len = rsa_size(myself->connection->rsa);
char enckey[len]; char enckey[len];
char key[len]; char key[len];
@ -332,7 +332,7 @@ bool metakey_h(connection_t *c, const char *request) {
/* Decrypt the meta key */ /* Decrypt the meta key */
if(!rsa_private_decrypt(&myself->connection->rsa, enckey, len, key)) { if(!rsa_private_decrypt(myself->connection->rsa, enckey, len, key)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error during decryption of meta key for %s (%s)", c->name, c->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Error during decryption of meta key for %s (%s)", c->name, c->hostname);
return false; return false;
} }
@ -344,12 +344,12 @@ bool metakey_h(connection_t *c, const char *request) {
/* Check and lookup cipher and digest algorithms */ /* Check and lookup cipher and digest algorithms */
if(!cipher_open_by_nid(&c->incipher, cipher) || !cipher_set_key_from_rsa(&c->incipher, key, len, false)) { if(!(c->incipher = cipher_open_by_nid(cipher)) || !cipher_set_key_from_rsa(c->incipher, key, len, false)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of cipher from %s (%s)", c->name, c->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of cipher from %s (%s)", c->name, c->hostname);
return false; return false;
} }
if(!digest_open_by_nid(&c->indigest, digest, -1)) { if(!(c->indigest = digest_open_by_nid(digest, -1))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname);
return false; return false;
} }
@ -362,7 +362,7 @@ bool metakey_h(connection_t *c, const char *request) {
} }
bool send_challenge(connection_t *c) { bool send_challenge(connection_t *c) {
size_t len = rsa_size(&c->rsa); size_t len = rsa_size(c->rsa);
char buffer[len * 2 + 1]; char buffer[len * 2 + 1];
if(!c->hischallenge) if(!c->hischallenge)
@ -383,8 +383,8 @@ bool send_challenge(connection_t *c) {
bool challenge_h(connection_t *c, const char *request) { bool challenge_h(connection_t *c, const char *request) {
char buffer[MAX_STRING_SIZE]; char buffer[MAX_STRING_SIZE];
size_t len = rsa_size(&myself->connection->rsa); size_t len = rsa_size(myself->connection->rsa);
size_t digestlen = digest_length(&c->indigest); size_t digestlen = digest_length(c->indigest);
char digest[digestlen]; char digest[digestlen];
if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) { if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) {
@ -407,7 +407,7 @@ bool challenge_h(connection_t *c, const char *request) {
/* Calculate the hash from the challenge we received */ /* Calculate the hash from the challenge we received */
digest_create(&c->indigest, buffer, len, digest); digest_create(c->indigest, buffer, len, digest);
/* Convert the hash to a hexadecimal formatted string */ /* Convert the hash to a hexadecimal formatted string */
@ -433,7 +433,7 @@ bool chal_reply_h(connection_t *c, const char *request) {
/* Check if the length of the hash is all right */ /* Check if the length of the hash is all right */
if(inlen != digest_length(&c->outdigest)) { if(inlen != digest_length(c->outdigest)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply length"); logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply length");
return false; return false;
} }
@ -441,7 +441,7 @@ bool chal_reply_h(connection_t *c, const char *request) {
/* Verify the hash */ /* Verify the hash */
if(!digest_verify(&c->outdigest, c->hischallenge, rsa_size(&c->rsa), hishash)) { if(!digest_verify(c->outdigest, c->hischallenge, rsa_size(c->rsa), hishash)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply"); logger(DEBUG_ALWAYS, LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge reply");
return false; return false;
} }
@ -461,7 +461,7 @@ static bool send_upgrade(connection_t *c) {
/* Special case when protocol_minor is 1: the other end is ECDSA capable, /* Special case when protocol_minor is 1: the other end is ECDSA capable,
* but doesn't know our key yet. So send it now. */ * but doesn't know our key yet. So send it now. */
char *pubkey = ecdsa_get_base64_public_key(&myself->connection->ecdsa); char *pubkey = ecdsa_get_base64_public_key(myself->connection->ecdsa);
if(!pubkey) if(!pubkey)
return false; return false;
@ -545,7 +545,7 @@ static bool upgrade_h(connection_t *c, const char *request) {
return false; return false;
} }
if(ecdsa_active(&c->ecdsa) || read_ecdsa_public_key(c)) { if(ecdsa_active(c->ecdsa) || read_ecdsa_public_key(c)) {
logger(DEBUG_ALWAYS, LOG_INFO, "Already have ECDSA public key from %s (%s), not upgrading.", c->name, c->hostname); logger(DEBUG_ALWAYS, LOG_INFO, "Already have ECDSA public key from %s (%s), not upgrading.", c->name, c->hostname);
return false; return false;
} }

View file

@ -124,7 +124,7 @@ bool send_req_key(node_t *to) {
static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) { static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) {
switch(reqno) { switch(reqno) {
case REQ_PUBKEY: { case REQ_PUBKEY: {
char *pubkey = ecdsa_get_base64_public_key(&myself->connection->ecdsa); char *pubkey = ecdsa_get_base64_public_key(myself->connection->ecdsa);
send_request(from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, from->name, ANS_PUBKEY, pubkey); send_request(from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, from->name, ANS_PUBKEY, pubkey);
free(pubkey); free(pubkey);
return true; return true;
@ -137,7 +137,7 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
} }
char pubkey[MAX_STRING_SIZE]; char pubkey[MAX_STRING_SIZE];
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, pubkey) != 1 || !ecdsa_set_base64_public_key(&from->ecdsa, pubkey)) { if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, pubkey) != 1 || !(from->ecdsa = ecdsa_set_base64_public_key(pubkey))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_PUBKEY", from->name, from->hostname, "invalid pubkey"); logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_PUBKEY", from->name, from->hostname, "invalid pubkey");
return true; return true;
} }
@ -259,19 +259,22 @@ bool send_ans_key(node_t *to) {
if(to->status.sptps) if(to->status.sptps)
abort(); abort();
size_t keylen = cipher_keylength(&myself->incipher); size_t keylen = cipher_keylength(myself->incipher);
char key[keylen * 2 + 1]; char key[keylen * 2 + 1];
cipher_close(&to->incipher); cipher_close(to->incipher);
digest_close(&to->indigest); digest_close(to->indigest);
cipher_open_by_nid(&to->incipher, cipher_get_nid(&myself->incipher)); to->incipher = cipher_open_by_nid(cipher_get_nid(myself->incipher));
digest_open_by_nid(&to->indigest, digest_get_nid(&myself->indigest), digest_length(&myself->indigest)); to->indigest = digest_open_by_nid(digest_get_nid(myself->indigest), digest_length(myself->indigest));
to->incompression = myself->incompression; to->incompression = myself->incompression;
if(!to->incipher || !to->indigest)
abort();
randomize(key, keylen); randomize(key, keylen);
cipher_set_key(&to->incipher, key, false); cipher_set_key(to->incipher, key, false);
digest_set_key(&to->indigest, key, keylen); digest_set_key(to->indigest, key, keylen);
bin2hex(key, key, keylen); bin2hex(key, key, keylen);
@ -283,9 +286,9 @@ bool send_ans_key(node_t *to) {
return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY, return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
myself->name, to->name, key, myself->name, to->name, key,
cipher_get_nid(&to->incipher), cipher_get_nid(to->incipher),
digest_get_nid(&to->indigest), digest_get_nid(to->indigest),
(int)digest_length(&to->indigest), (int)digest_length(to->indigest),
to->incompression); to->incompression);
} }
@ -353,8 +356,8 @@ bool ans_key_h(connection_t *c, const char *request) {
} }
/* Don't use key material until every check has passed. */ /* Don't use key material until every check has passed. */
cipher_close(&from->outcipher); cipher_close(from->outcipher);
digest_close(&from->outdigest); digest_close(from->outdigest);
from->status.validkey = false; from->status.validkey = false;
if(compression < 0 || compression > 11) { if(compression < 0 || compression > 11) {
@ -389,17 +392,17 @@ bool ans_key_h(connection_t *c, const char *request) {
/* Check and lookup cipher and digest algorithms */ /* Check and lookup cipher and digest algorithms */
if(!cipher_open_by_nid(&from->outcipher, cipher)) { if(!(from->outcipher = cipher_open_by_nid(cipher))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
return false; return false;
} }
if(!digest_open_by_nid(&from->outdigest, digest, maclength)) { if(!(from->outdigest = digest_open_by_nid(digest, maclength))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
return false; return false;
} }
if(maclength != digest_length(&from->outdigest)) { if(maclength != digest_length(from->outdigest)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname);
return false; return false;
} }
@ -408,15 +411,15 @@ bool ans_key_h(connection_t *c, const char *request) {
keylen = hex2bin(key, key, sizeof key); keylen = hex2bin(key, key, sizeof key);
if(keylen != cipher_keylength(&from->outcipher)) { if(keylen != cipher_keylength(from->outcipher)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname); logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname);
return true; return true;
} }
/* Update our copy of the origin's packet key */ /* Update our copy of the origin's packet key */
cipher_set_key(&from->outcipher, key, true); cipher_set_key(from->outcipher, key, true);
digest_set_key(&from->outdigest, key, keylen); digest_set_key(from->outdigest, key, keylen);
from->status.validkey = true; from->status.validkey = true;
from->sent_seqno = 0; from->sent_seqno = 0;

View file

@ -98,11 +98,11 @@ static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const char *data
if(s->outstate) { if(s->outstate) {
// If first handshake has finished, encrypt and HMAC // If first handshake has finished, encrypt and HMAC
cipher_set_counter(&s->outcipher, &seqno, sizeof seqno); cipher_set_counter(s->outcipher, &seqno, sizeof seqno);
if(!cipher_counter_xor(&s->outcipher, buffer + 6, len + 1UL, buffer + 6)) if(!cipher_counter_xor(s->outcipher, buffer + 6, len + 1UL, buffer + 6))
return false; return false;
if(!digest_create(&s->outdigest, buffer, len + 7UL, buffer + 7UL + len)) if(!digest_create(s->outdigest, buffer, len + 7UL, buffer + 7UL + len))
return false; return false;
return s->send_data(s->handle, type, buffer + 2, len + 21UL); return s->send_data(s->handle, type, buffer + 2, len + 21UL);
@ -131,10 +131,10 @@ static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_
if(s->outstate) { if(s->outstate) {
// If first handshake has finished, encrypt and HMAC // If first handshake has finished, encrypt and HMAC
if(!cipher_counter_xor(&s->outcipher, buffer + 4, len + 3UL, buffer + 4)) if(!cipher_counter_xor(s->outcipher, buffer + 4, len + 3UL, buffer + 4))
return false; return false;
if(!digest_create(&s->outdigest, buffer, len + 7UL, buffer + 7UL + len)) if(!digest_create(s->outdigest, buffer, len + 7UL, buffer + 7UL + len))
return false; return false;
return s->send_data(s->handle, type, buffer + 4, len + 19UL); return s->send_data(s->handle, type, buffer + 4, len + 19UL);
@ -175,7 +175,7 @@ static bool send_kex(sptps_t *s) {
randomize(s->mykex + 1, 32); randomize(s->mykex + 1, 32);
// Create a new ECDH public key. // Create a new ECDH public key.
if(!ecdh_generate_public(&s->ecdh, s->mykex + 1 + 32)) if(!(s->ecdh = ecdh_generate_public(s->mykex + 1 + 32)))
return false; return false;
return send_record_priv(s, SPTPS_HANDSHAKE, s->mykex, 1 + 32 + keylen); return send_record_priv(s, SPTPS_HANDSHAKE, s->mykex, 1 + 32 + keylen);
@ -184,7 +184,7 @@ static bool send_kex(sptps_t *s) {
// Send a SIGnature record, containing an ECDSA signature over both KEX records. // Send a SIGnature record, containing an ECDSA signature over both KEX records.
static bool send_sig(sptps_t *s) { static bool send_sig(sptps_t *s) {
size_t keylen = ECDH_SIZE; size_t keylen = ECDH_SIZE;
size_t siglen = ecdsa_size(&s->mykey); size_t siglen = ecdsa_size(s->mykey);
// Concatenate both KEX messages, plus tag indicating if it is from the connection originator, plus label // Concatenate both KEX messages, plus tag indicating if it is from the connection originator, plus label
char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen]; char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
@ -196,7 +196,7 @@ static bool send_sig(sptps_t *s) {
memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen); memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
// Sign the result. // Sign the result.
if(!ecdsa_sign(&s->mykey, msg, sizeof msg, sig)) if(!ecdsa_sign(s->mykey, msg, sizeof msg, sig))
return false; return false;
// Send the SIG exchange record. // Send the SIG exchange record.
@ -207,17 +207,16 @@ static bool send_sig(sptps_t *s) {
static bool generate_key_material(sptps_t *s, const char *shared, size_t len) { static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
// Initialise cipher and digest structures if necessary // Initialise cipher and digest structures if necessary
if(!s->outstate) { if(!s->outstate) {
bool result s->incipher = cipher_open_by_name("aes-256-ecb");
= cipher_open_by_name(&s->incipher, "aes-256-ecb") s->outcipher = cipher_open_by_name("aes-256-ecb");
&& cipher_open_by_name(&s->outcipher, "aes-256-ecb") s->indigest = digest_open_by_name("sha256", 16);
&& digest_open_by_name(&s->indigest, "sha256", 16) s->outdigest = digest_open_by_name("sha256", 16);
&& digest_open_by_name(&s->outdigest, "sha256", 16); if(!s->incipher || !s->outcipher || !s->indigest || !s->outdigest)
if(!result)
return false; return false;
} }
// Allocate memory for key material // Allocate memory for key material
size_t keylen = digest_keylength(&s->indigest) + digest_keylength(&s->outdigest) + cipher_keylength(&s->incipher) + cipher_keylength(&s->outcipher); size_t keylen = digest_keylength(s->indigest) + digest_keylength(s->outdigest) + cipher_keylength(s->incipher) + cipher_keylength(s->outcipher);
s->key = realloc(s->key, keylen); s->key = realloc(s->key, keylen);
if(!s->key) if(!s->key)
@ -254,14 +253,14 @@ static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
if(s->initiator) { if(s->initiator) {
bool result bool result
= cipher_set_counter_key(&s->incipher, s->key) = cipher_set_counter_key(s->incipher, s->key)
&& digest_set_key(&s->indigest, s->key + cipher_keylength(&s->incipher), digest_keylength(&s->indigest)); && digest_set_key(s->indigest, s->key + cipher_keylength(s->incipher), digest_keylength(s->indigest));
if(!result) if(!result)
return false; return false;
} else { } else {
bool result bool result
= cipher_set_counter_key(&s->incipher, s->key + cipher_keylength(&s->outcipher) + digest_keylength(&s->outdigest)) = cipher_set_counter_key(s->incipher, s->key + cipher_keylength(s->outcipher) + digest_keylength(s->outdigest))
&& digest_set_key(&s->indigest, s->key + cipher_keylength(&s->outcipher) + digest_keylength(&s->outdigest) + cipher_keylength(&s->incipher), digest_keylength(&s->indigest)); && digest_set_key(s->indigest, s->key + cipher_keylength(s->outcipher) + digest_keylength(s->outdigest) + cipher_keylength(s->incipher), digest_keylength(s->indigest));
if(!result) if(!result)
return false; return false;
} }
@ -296,7 +295,7 @@ static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
// Receive a SIGnature record, verify it, if it passed, compute the shared secret and calculate the session keys. // Receive a SIGnature record, verify it, if it passed, compute the shared secret and calculate the session keys.
static bool receive_sig(sptps_t *s, const char *data, uint16_t len) { static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
size_t keylen = ECDH_SIZE; size_t keylen = ECDH_SIZE;
size_t siglen = ecdsa_size(&s->hiskey); size_t siglen = ecdsa_size(s->hiskey);
// Verify length of KEX record. // Verify length of KEX record.
if(len != siglen) if(len != siglen)
@ -311,12 +310,12 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen); memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
// Verify signature. // Verify signature.
if(!ecdsa_verify(&s->hiskey, msg, sizeof msg, data)) if(!ecdsa_verify(s->hiskey, msg, sizeof msg, data))
return false; return false;
// Compute shared secret. // Compute shared secret.
char shared[ECDH_SHARED_SIZE]; char shared[ECDH_SHARED_SIZE];
if(!ecdh_compute_shared(&s->ecdh, s->hiskex + 1 + 32, shared)) if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared))
return false; return false;
// Generate key material from shared secret. // Generate key material from shared secret.
@ -336,14 +335,14 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
// TODO: only set new keys after ACK has been set/received // TODO: only set new keys after ACK has been set/received
if(s->initiator) { if(s->initiator) {
bool result bool result
= cipher_set_counter_key(&s->outcipher, s->key + cipher_keylength(&s->incipher) + digest_keylength(&s->indigest)) = cipher_set_counter_key(s->outcipher, s->key + cipher_keylength(s->incipher) + digest_keylength(s->indigest))
&& digest_set_key(&s->outdigest, s->key + cipher_keylength(&s->incipher) + digest_keylength(&s->indigest) + cipher_keylength(&s->outcipher), digest_keylength(&s->outdigest)); && digest_set_key(s->outdigest, s->key + cipher_keylength(s->incipher) + digest_keylength(s->indigest) + cipher_keylength(s->outcipher), digest_keylength(s->outdigest));
if(!result) if(!result)
return false; return false;
} else { } else {
bool result bool result
= cipher_set_counter_key(&s->outcipher, s->key) = cipher_set_counter_key(s->outcipher, s->key)
&& digest_set_key(&s->outdigest, s->key + cipher_keylength(&s->outcipher), digest_keylength(&s->outdigest)); && digest_set_key(s->outdigest, s->key + cipher_keylength(s->outcipher), digest_keylength(s->outdigest));
if(!result) if(!result)
return false; return false;
} }
@ -413,7 +412,7 @@ bool sptps_verify_datagram(sptps_t *s, const char *data, size_t len) {
memcpy(buffer, &netlen, 2); memcpy(buffer, &netlen, 2);
memcpy(buffer + 2, data, len); memcpy(buffer + 2, data, len);
return digest_verify(&s->indigest, buffer, len - 14, buffer + len - 14); return digest_verify(s->indigest, buffer, len - 14, buffer + len - 14);
} }
// Receive incoming data, datagram version. // Receive incoming data, datagram version.
@ -447,7 +446,7 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
memcpy(buffer, &netlen, 2); memcpy(buffer, &netlen, 2);
memcpy(buffer + 2, data, len); memcpy(buffer + 2, data, len);
if(!digest_verify(&s->indigest, buffer, len - 14, buffer + len - 14)) if(!digest_verify(s->indigest, buffer, len - 14, buffer + len - 14))
return error(s, EIO, "Invalid HMAC"); return error(s, EIO, "Invalid HMAC");
// Replay protection using a sliding window of configurable size. // Replay protection using a sliding window of configurable size.
@ -491,8 +490,8 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
// Decrypt. // Decrypt.
memcpy(&seqno, buffer + 2, 4); memcpy(&seqno, buffer + 2, 4);
cipher_set_counter(&s->incipher, &seqno, sizeof seqno); cipher_set_counter(s->incipher, &seqno, sizeof seqno);
if(!cipher_counter_xor(&s->incipher, buffer + 6, len - 4, buffer + 6)) if(!cipher_counter_xor(s->incipher, buffer + 6, len - 4, buffer + 6))
return false; return false;
// Append a NULL byte for safety. // Append a NULL byte for safety.
@ -540,7 +539,7 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
// Decrypt the length bytes // Decrypt the length bytes
if(s->instate) { if(s->instate) {
if(!cipher_counter_xor(&s->incipher, s->inbuf + 4, 2, &s->reclen)) if(!cipher_counter_xor(s->incipher, s->inbuf + 4, 2, &s->reclen))
return false; return false;
} else { } else {
memcpy(&s->reclen, s->inbuf + 4, 2); memcpy(&s->reclen, s->inbuf + 4, 2);
@ -578,10 +577,10 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
// Check HMAC and decrypt. // Check HMAC and decrypt.
if(s->instate) { if(s->instate) {
if(!digest_verify(&s->indigest, s->inbuf, s->reclen + 7UL, s->inbuf + s->reclen + 7UL)) if(!digest_verify(s->indigest, s->inbuf, s->reclen + 7UL, s->inbuf + s->reclen + 7UL))
return error(s, EIO, "Invalid HMAC"); return error(s, EIO, "Invalid HMAC");
if(!cipher_counter_xor(&s->incipher, s->inbuf + 6UL, s->reclen + 1UL, s->inbuf + 6UL)) if(!cipher_counter_xor(s->incipher, s->inbuf + 6UL, s->reclen + 1UL, s->inbuf + 6UL))
return false; return false;
} }
@ -609,7 +608,7 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
} }
// Start a SPTPS session. // Start a SPTPS session.
bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t mykey, ecdsa_t hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) { bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) {
// Initialise struct sptps // Initialise struct sptps
memset(s, 0, sizeof *s); memset(s, 0, sizeof *s);
@ -651,11 +650,11 @@ bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_
// Stop a SPTPS session. // Stop a SPTPS session.
bool sptps_stop(sptps_t *s) { bool sptps_stop(sptps_t *s) {
// Clean up any resources. // Clean up any resources.
cipher_close(&s->incipher); cipher_close(s->incipher);
cipher_close(&s->outcipher); cipher_close(s->outcipher);
digest_close(&s->indigest); digest_close(s->indigest);
digest_close(&s->outdigest); digest_close(s->outdigest);
ecdh_free(&s->ecdh); ecdh_free(s->ecdh);
free(s->inbuf); free(s->inbuf);
free(s->mykex); free(s->mykex);
free(s->hiskex); free(s->hiskex);

View file

@ -53,8 +53,8 @@ typedef struct sptps {
uint16_t reclen; uint16_t reclen;
bool instate; bool instate;
cipher_t incipher; cipher_t *incipher;
digest_t indigest; digest_t *indigest;
uint32_t inseqno; uint32_t inseqno;
uint32_t received; uint32_t received;
unsigned int replaywin; unsigned int replaywin;
@ -62,13 +62,13 @@ typedef struct sptps {
char *late; char *late;
bool outstate; bool outstate;
cipher_t outcipher; cipher_t *outcipher;
digest_t outdigest; digest_t *outdigest;
uint32_t outseqno; uint32_t outseqno;
ecdsa_t mykey; ecdsa_t *mykey;
ecdsa_t hiskey; ecdsa_t *hiskey;
ecdh_t ecdh; ecdh_t *ecdh;
char *mykex; char *mykex;
char *hiskex; char *hiskex;
@ -85,7 +85,7 @@ extern unsigned int sptps_replaywin;
extern void sptps_log_quiet(sptps_t *s, int s_errno, const char *format, va_list ap); extern void sptps_log_quiet(sptps_t *s, int s_errno, const char *format, va_list ap);
extern void sptps_log_stderr(sptps_t *s, int s_errno, const char *format, va_list ap); extern void sptps_log_stderr(sptps_t *s, int s_errno, const char *format, va_list ap);
extern void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap); extern void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap);
extern bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t mykey, ecdsa_t hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record); extern bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record);
extern bool sptps_stop(sptps_t *s); extern bool sptps_stop(sptps_t *s);
extern bool sptps_send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len); extern bool sptps_send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len);
extern bool sptps_receive_data(sptps_t *s, const char *data, size_t len); extern bool sptps_receive_data(sptps_t *s, const char *data, size_t len);

View file

@ -1,6 +1,6 @@
/* /*
sptps_test.c -- Simple Peer-to-Peer Security test program sptps_test.c -- Simple Peer-to-Peer Security test program
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@ bool send_meta(void *c, const char *msg , int len) { return false; }
char *logfilename = NULL; char *logfilename = NULL;
struct timeval now; struct timeval now;
ecdsa_t mykey, hiskey; ecdsa_t *mykey, *hiskey;
static bool send_data(void *handle, uint8_t type, const char *data, size_t len) { static bool send_data(void *handle, uint8_t type, const char *data, size_t len) {
char hex[len * 2 + 1]; char hex[len * 2 + 1];
@ -143,12 +143,12 @@ int main(int argc, char *argv[]) {
crypto_init(); crypto_init();
FILE *fp = fopen(argv[1], "r"); FILE *fp = fopen(argv[1], "r");
if(!ecdsa_read_pem_private_key(&mykey, fp)) if(!(mykey = ecdsa_read_pem_private_key(fp)))
return 1; return 1;
fclose(fp); fclose(fp);
fp = fopen(argv[2], "r"); fp = fopen(argv[2], "r");
if(!ecdsa_read_pem_public_key(&hiskey, fp)) if(!(hiskey = ecdsa_read_pem_public_key(fp)))
return 1; return 1;
fclose(fp); fclose(fp);

View file

@ -346,13 +346,13 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
them in. them in.
*/ */
static bool ecdsa_keygen(bool ask) { static bool ecdsa_keygen(bool ask) {
ecdsa_t key; ecdsa_t *key;
FILE *f; FILE *f;
char *pubname, *privname; char *pubname, *privname;
fprintf(stderr, "Generating ECDSA keypair:\n"); fprintf(stderr, "Generating ECDSA keypair:\n");
if(!ecdsa_generate(&key)) { if(!(key = ecdsa_generate())) {
fprintf(stderr, "Error during key generation!\n"); fprintf(stderr, "Error during key generation!\n");
return false; return false;
} else } else
@ -370,7 +370,12 @@ static bool ecdsa_keygen(bool ask) {
fchmod(fileno(f), 0600); fchmod(fileno(f), 0600);
#endif #endif
ecdsa_write_pem_private_key(&key, f); if(!ecdsa_write_pem_private_key(key, f)) {
fprintf(stderr, "Error writing private key!\n");
ecdsa_free(key);
fclose(f);
return false;
}
fclose(f); fclose(f);
@ -385,11 +390,12 @@ static bool ecdsa_keygen(bool ask) {
if(!f) if(!f)
return false; return false;
char *pubkey = ecdsa_get_base64_public_key(&key); char *pubkey = ecdsa_get_base64_public_key(key);
fprintf(f, "ECDSAPublicKey = %s\n", pubkey); fprintf(f, "ECDSAPublicKey = %s\n", pubkey);
free(pubkey); free(pubkey);
fclose(f); fclose(f);
ecdsa_free(key);
return true; return true;
} }
@ -399,13 +405,13 @@ static bool ecdsa_keygen(bool ask) {
them in. them in.
*/ */
static bool rsa_keygen(int bits, bool ask) { static bool rsa_keygen(int bits, bool ask) {
rsa_t key; rsa_t *key;
FILE *f; FILE *f;
char *pubname, *privname; char *pubname, *privname;
fprintf(stderr, "Generating %d bits keys:\n", bits); fprintf(stderr, "Generating %d bits keys:\n", bits);
if(!rsa_generate(&key, bits, 0x10001)) { if(!(key = rsa_generate(bits, 0x10001))) {
fprintf(stderr, "Error during key generation!\n"); fprintf(stderr, "Error during key generation!\n");
return false; return false;
} else } else
@ -423,7 +429,12 @@ static bool rsa_keygen(int bits, bool ask) {
fchmod(fileno(f), 0600); fchmod(fileno(f), 0600);
#endif #endif
rsa_write_pem_private_key(&key, f); if(!rsa_write_pem_private_key(key, f)) {
fprintf(stderr, "Error writing private key!\n");
fclose(f);
rsa_free(key);
return false;
}
fclose(f); fclose(f);
@ -438,9 +449,15 @@ static bool rsa_keygen(int bits, bool ask) {
if(!f) if(!f)
return false; return false;
rsa_write_pem_public_key(&key, f); if(!rsa_write_pem_public_key(key, f)) {
fprintf(stderr, "Error writing public key!\n");
fclose(f);
rsa_free(key);
return false;
}
fclose(f); fclose(f);
rsa_free(key);
return true; return true;
} }