Part of #294.
if OPENSSL
tincd_SOURCES += \
- openssl/cipher.c \
+ openssl/cipher.c openssl/cipher.h \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c \
openssl/rsa.c
tinc_SOURCES += \
- openssl/cipher.c \
+ openssl/cipher.c openssl/cipher.h \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c \
endif
endif
+if WITH_LEGACY_PROTOCOL
+tinc_SOURCES += digest.c
+tincd_SOURCES += digest.c cipher.c
+sptps_test_SOURCES += digest.c
+sptps_speed_SOURCES += digest.c
+endif
+
if MINIUPNPC
tincd_SOURCES += upnp.h upnp.c
tincd_LDADD = $(MINIUPNPC_LIBS)
--- /dev/null
+#include "cipher.h"
+#include "xalloc.h"
+
+#ifndef DISABLE_LEGACY
+
+cipher_t *cipher_alloc() {
+ return xzalloc(sizeof(cipher_t));
+}
+
+void cipher_free(cipher_t **cipher) {
+ if(cipher && *cipher) {
+ cipher_close(*cipher);
+ free(*cipher);
+ *cipher = NULL;
+ }
+}
+
+#endif // DISABLE_LEGACY
#ifndef DISABLE_LEGACY
+#ifdef HAVE_OPENSSL
+#include "openssl/cipher.h"
+#elif HAVE_LIBGCRYPT
+#include "gcrypt/cipher.h"
+#else
+#error Incorrect cryptographic library, please reconfigure.
+#endif
+
typedef struct cipher cipher_t;
-extern cipher_t *cipher_open_by_name(const char *name) __attribute__((__malloc__));
-extern cipher_t *cipher_open_by_nid(int nid) __attribute__((__malloc__));
+extern cipher_t *cipher_alloc() __attribute__((__malloc__));
+extern void cipher_free(cipher_t **cipher);
+extern bool cipher_open_by_name(cipher_t *cipher, const char *name);
+extern bool cipher_open_by_nid(cipher_t *cipher, int nid);
extern void cipher_close(cipher_t *cipher);
extern size_t cipher_keylength(const cipher_t *cipher);
extern size_t cipher_blocksize(const cipher_t *cipher);
extern int cipher_get_nid(const cipher_t *cipher);
extern bool cipher_active(const cipher_t *cipher);
-#endif
+#endif // DISABLE_LEGACY
-#endif
+#endif // TINC_CIPHER_H
}
#ifndef DISABLE_LEGACY
- cipher_close(c->incipher);
- digest_close(c->indigest);
- cipher_close(c->outcipher);
- digest_close(c->outdigest);
+ cipher_close(&c->incipher);
+ digest_close(&c->indigest);
+ cipher_close(&c->outcipher);
+ digest_close(&c->outdigest);
rsa_free(c->rsa);
#endif
#ifndef DISABLE_LEGACY
rsa_t *rsa; /* his public RSA key */
- cipher_t *incipher; /* Cipher he will use to send data to us */
- cipher_t *outcipher; /* Cipher we will use to send data to him */
- digest_t *indigest;
- digest_t *outdigest;
+ cipher_t incipher; /* Cipher he will use to send data to us */
+ cipher_t outcipher; /* Cipher we will use to send data to him */
+ digest_t indigest;
+ digest_t outdigest;
uint64_t inbudget;
uint64_t outbudget;
#endif
--- /dev/null
+#include "digest.h"
+#include "xalloc.h"
+
+#ifndef DISABLE_LEGACY
+
+digest_t *digest_alloc() {
+ return xzalloc(sizeof(digest_t));
+}
+
+void digest_free(digest_t **digest) {
+ if(digest && *digest) {
+ digest_close(*digest);
+ free(*digest);
+ *digest = NULL;
+ }
+}
+
+#endif // DISABLE_LEGACY
#ifndef DISABLE_LEGACY
+#ifdef HAVE_OPENSSL
+#include "openssl/digest.h"
+#elif HAVE_LIBGCRYPT
+#include "gcrypt/digest.h"
+#else
+#error Incorrect cryptographic library, please reconfigure.
+#endif
+
typedef struct digest digest_t;
-extern digest_t *digest_open_by_name(const char *name, size_t maclength) __attribute__((__malloc__));
-extern digest_t *digest_open_by_nid(int nid, size_t maclength) __attribute__((__malloc__));
+extern bool digest_open_by_name(digest_t *digest, const char *name, size_t maclength);
+extern bool digest_open_by_nid(digest_t *digest, int nid, size_t maclength);
+extern digest_t *digest_alloc() __attribute__((__malloc__));
+extern void digest_free(digest_t **digest);
extern void digest_close(digest_t *digest);
extern bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) __attribute__((__warn_unused_result__));
extern bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *digestdata) __attribute__((__warn_unused_result__));
}
free(cipher->key);
- cipher->key = NULL;
+
+ memset(cipher, 0, sizeof(*cipher));
}
size_t cipher_keylength(const cipher_t *cipher) {
gcry_md_close(digest->hmac);
}
- digest->hmac = NULL;
+ memset(digest, 0, sizeof(*digest));
}
bool digest_set_key(digest_t *digest, const void *key, size_t len) {
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)",
c->name, c->hostname);
return false;
size_t outlen = inlen;
- if(!cipher_decrypt(c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || (size_t)inlen != outlen) {
+ if(!cipher_decrypt(&c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || (size_t)inlen != outlen) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting metadata from %s (%s)",
c->name, c->hostname);
return false;
if(!strcasecmp(cipher, "none")) {
myself->incipher = NULL;
- } else if(!(myself->incipher = cipher_open_by_name(cipher))) {
- logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
- free(cipher);
- return false;
+ } else {
+ myself->incipher = cipher_alloc();
+
+ if(!cipher_open_by_name(myself->incipher, cipher)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
+ cipher_free(&myself->incipher);
+ free(cipher);
+ return false;
+ }
}
free(cipher);
if(!strcasecmp(digest, "none")) {
myself->indigest = NULL;
- } else if(!(myself->indigest = digest_open_by_name(digest, maclength))) {
- logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!");
- free(digest);
- return false;
+ } else {
+ myself->indigest = digest_alloc();
+
+ if(!digest_open_by_name(myself->indigest, digest, maclength)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!");
+ digest_free(&myself->indigest);
+ free(digest);
+ return false;
+ }
}
free(digest);
sockaddrfree(&n->address);
#ifndef DISABLE_LEGACY
- cipher_close(n->incipher);
- digest_close(n->indigest);
- cipher_close(n->outcipher);
- digest_close(n->outdigest);
+ cipher_free(&n->incipher);
+ digest_free(&n->indigest);
+ cipher_free(&n->outcipher);
+ digest_free(&n->outdigest);
#endif
ecdsa_free(n->ecdsa);
#include "../cipher.h"
#include "../logger.h"
-#include "../xalloc.h"
-struct cipher {
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher;
-};
-
-static cipher_t *cipher_open(const EVP_CIPHER *evp_cipher) {
- cipher_t *cipher = xzalloc(sizeof(*cipher));
+static void cipher_open(cipher_t *cipher, const EVP_CIPHER *evp_cipher) {
cipher->cipher = evp_cipher;
cipher->ctx = EVP_CIPHER_CTX_new();
if(!cipher->ctx) {
abort();
}
-
- return cipher;
}
-cipher_t *cipher_open_by_name(const char *name) {
+bool cipher_open_by_name(cipher_t *cipher, const char *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;
+ return false;
}
- return cipher_open(evp_cipher);
+ cipher_open(cipher, evp_cipher);
+ return true;
}
-cipher_t *cipher_open_by_nid(int nid) {
+bool cipher_open_by_nid(cipher_t *cipher, int 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;
+ return false;
}
- return cipher_open(evp_cipher);
+ cipher_open(cipher, evp_cipher);
+ return true;
}
void cipher_close(cipher_t *cipher) {
return;
}
- EVP_CIPHER_CTX_free(cipher->ctx);
- free(cipher);
+ if(cipher->ctx) {
+ EVP_CIPHER_CTX_free(cipher->ctx);
+ }
+
+ memset(cipher, 0, sizeof(*cipher));
}
size_t cipher_keylength(const cipher_t *cipher) {
--- /dev/null
+#ifndef TINC_OPENSSL_CIPHER_H
+#define TINC_OPENSSL_CIPHER_H
+
+#include <openssl/evp.h>
+
+struct cipher {
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *cipher;
+};
+
+#endif
*/
#include "../system.h"
-#include "../xalloc.h"
#include <openssl/err.h>
#include <openssl/hmac.h>
#include "../digest.h"
#include "../logger.h"
-static digest_t *digest_open(const EVP_MD *evp_md, size_t maclength) {
- digest_t *digest = xzalloc(sizeof(*digest));
+static void digest_open(digest_t *digest, const EVP_MD *evp_md, size_t maclength) {
digest->digest = evp_md;
size_t digestlen = EVP_MD_size(digest->digest);
} else {
digest->maclength = maclength;
}
-
- return digest;
}
-digest_t *digest_open_by_name(const char *name, size_t maclength) {
+bool digest_open_by_name(digest_t *digest, const char *name, size_t maclength) {
const EVP_MD *evp_md = EVP_get_digestbyname(name);
if(!evp_md) {
return false;
}
- return digest_open(evp_md, maclength);
+ digest_open(digest, evp_md, maclength);
+ return true;
}
-digest_t *digest_open_by_nid(int nid, size_t maclength) {
+bool digest_open_by_nid(digest_t *digest, int nid, size_t maclength) {
const EVP_MD *evp_md = EVP_get_digestbynid(nid);
if(!evp_md) {
return false;
}
- return digest_open(evp_md, maclength);
+ digest_open(digest, evp_md, maclength);
+ return true;
}
bool digest_set_key(digest_t *digest, const void *key, size_t len) {
HMAC_CTX_free(digest->hmac_ctx);
}
- free(digest);
+ memset(digest, 0, sizeof(*digest));
}
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
*/
static bool prf_xor(int nid, const uint8_t *secret, size_t secretlen, uint8_t *seed, size_t seedlen, uint8_t *out, size_t outlen) {
- digest_t *digest = digest_open_by_nid(nid, DIGEST_ALGO_SIZE);
+ digest_t digest = {0};
- if(!digest) {
+ if(!digest_open_by_nid(&digest, nid, DIGEST_ALGO_SIZE)) {
+ digest_close(&digest);
return false;
}
- if(!digest_set_key(digest, secret, secretlen)) {
- digest_close(digest);
+ if(!digest_set_key(&digest, secret, secretlen)) {
+ digest_close(&digest);
return false;
}
- size_t len = digest_length(digest);
+ size_t len = digest_length(&digest);
/* Data is what the "inner" HMAC function processes.
It consists of the previous HMAC result plus the seed.
while(outlen > 0) {
/* Inner HMAC */
- if(!digest_create(digest, data, len + seedlen, data)) {
- digest_close(digest);
+ if(!digest_create(&digest, data, len + seedlen, data)) {
+ digest_close(&digest);
return false;
}
/* Outer HMAC */
- if(!digest_create(digest, data, len + seedlen, hash)) {
- digest_close(digest);
+ if(!digest_create(&digest, data, len + seedlen, hash)) {
+ digest_close(&digest);
return false;
}
outlen -= i;
}
- digest_close(digest);
+ digest_close(&digest);
return true;
}
*/
size_t keylen = cipher_keylength(myself->incipher);
+ const char *cipher_name;
if(keylen <= 16) {
- c->outcipher = cipher_open_by_name("aes-128-cfb");
+ cipher_name = "aes-128-cfb";
} else if(keylen <= 24) {
- c->outcipher = cipher_open_by_name("aes-192-cfb");
+ cipher_name = "aes-192-cfb";
} else {
- c->outcipher = cipher_open_by_name("aes-256-cfb");
+ cipher_name = "aes-256-cfb";
}
- c->outbudget = cipher_budget(c->outcipher);
+ if(!cipher_open_by_name(&c->outcipher, cipher_name)) {
+ return false;
+ }
+
+ c->outbudget = cipher_budget(&c->outcipher);
- if(!(c->outdigest = digest_open_by_name("sha256", DIGEST_ALGO_SIZE))) {
+ if(!digest_open_by_name(&c->outdigest, "sha256", DIGEST_ALGO_SIZE)) {
+ cipher_close(&c->outcipher);
return false;
}
key[0] &= 0x7F;
- if(!cipher_set_key_from_rsa(c->outcipher, key, len, true)) {
+ if(!cipher_set_key_from_rsa(&c->outcipher, key, len, true)) {
return false;
}
/* Send the meta key */
bool result = send_request(c, "%d %d %d %d %d %s", METAKEY,
- cipher_get_nid(c->outcipher),
- digest_get_nid(c->outdigest), c->outmaclength,
+ cipher_get_nid(&c->outcipher),
+ digest_get_nid(&c->outdigest), c->outmaclength,
c->outcompression, hexkey);
c->status.encryptout = true;
/* Check and lookup cipher and digest algorithms */
if(cipher) {
- if(!(c->incipher = cipher_open_by_nid(cipher)) || !cipher_set_key_from_rsa(c->incipher, key, len, false)) {
+ if(!cipher_open_by_nid(&c->incipher, 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);
return false;
}
return false;
}
- c->inbudget = cipher_budget(c->incipher);
+ c->inbudget = cipher_budget(&c->incipher);
if(digest) {
- if(!(c->indigest = digest_open_by_nid(digest, DIGEST_ALGO_SIZE))) {
+ if(!digest_open_by_nid(&c->indigest, digest, DIGEST_ALGO_SIZE)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname);
return false;
}
bool send_chal_reply(connection_t *c) {
const 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 * 2 + 1];
/* Calculate the hash from the challenge we received */
- if(!digest_create(c->indigest, c->mychallenge, len, digest)) {
+ if(!digest_create(&c->indigest, c->mychallenge, len, digest)) {
return false;
}
/* 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");
return false;
}
/* 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");
return false;
}
randomize(key, keylen);
- cipher_close(to->incipher);
- digest_close(to->indigest);
+ cipher_free(&to->incipher);
+ digest_free(&to->indigest);
if(myself->incipher) {
- to->incipher = cipher_open_by_nid(cipher_get_nid(myself->incipher));
+ to->incipher = cipher_alloc();
- if(!to->incipher) {
+ if(!cipher_open_by_nid(to->incipher, cipher_get_nid(myself->incipher))) {
abort();
}
}
if(myself->indigest) {
- to->indigest = digest_open_by_nid(digest_get_nid(myself->indigest),
- digest_length(myself->indigest));
+ to->indigest = digest_alloc();
- if(!to->indigest) {
+ if(!digest_open_by_nid(to->indigest,
+ digest_get_nid(myself->indigest),
+ digest_length(myself->indigest))) {
abort();
}
#ifndef DISABLE_LEGACY
/* Don't use key material until every check has passed. */
- cipher_close(from->outcipher);
- digest_close(from->outdigest);
+ cipher_free(&from->outcipher);
+ digest_free(&from->outdigest);
#endif
if(!from->status.sptps) {
/* Check and lookup cipher and digest algorithms */
if(cipher) {
- if(!(from->outcipher = cipher_open_by_nid(cipher))) {
+ from->outcipher = cipher_alloc();
+
+ if(!cipher_open_by_nid(from->outcipher, cipher)) {
+ cipher_free(&from->outcipher);
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
return false;
}
}
if(digest) {
- if(!(from->outdigest = digest_open_by_nid(digest, maclength))) {
+ from->outdigest = digest_alloc();
+
+ if(!digest_open_by_nid(from->outdigest, digest, maclength)) {
+ digest_free(&from->outdigest);
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
return false;
}