Use the crypto wrappers again instead of calling OpenSSL directly.
This theoretically allows other cryptographic libraries to be used, and it improves the readability of the code.
This commit is contained in:
parent
8c69f42d7d
commit
046158a216
10 changed files with 239 additions and 527 deletions
|
|
@ -22,14 +22,10 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "crypto.h"
|
||||
#include "edge.h"
|
||||
#include "graph.h"
|
||||
#include "logger.h"
|
||||
|
|
@ -37,6 +33,7 @@
|
|||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
#include "protocol.h"
|
||||
#include "rsa.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
|
|
@ -117,27 +114,22 @@ bool id_h(connection_t *c, char *request) {
|
|||
}
|
||||
|
||||
bool send_metakey(connection_t *c) {
|
||||
char *buffer;
|
||||
int len;
|
||||
bool x;
|
||||
size_t len = rsa_size(&c->rsa);
|
||||
char key[len];
|
||||
char enckey[len];
|
||||
char hexkey[2 * len + 1];
|
||||
|
||||
cp();
|
||||
|
||||
len = RSA_size(c->rsa_key);
|
||||
|
||||
/* Allocate buffers for the meta key */
|
||||
|
||||
buffer = alloca(2 * len + 1);
|
||||
if(!cipher_open_blowfish_ofb(&c->outcipher))
|
||||
return false;
|
||||
|
||||
if(!c->outkey)
|
||||
c->outkey = xmalloc(len);
|
||||
if(!digest_open_sha1(&c->outdigest))
|
||||
return false;
|
||||
|
||||
if(!c->outctx)
|
||||
c->outctx = xmalloc_and_zero(sizeof(*c->outctx));
|
||||
cp();
|
||||
/* Copy random data to the buffer */
|
||||
/* Create a random key */
|
||||
|
||||
RAND_pseudo_bytes((unsigned char *)c->outkey, len);
|
||||
randomize(key, len);
|
||||
|
||||
/* The message we send must be smaller than the modulus of the RSA key.
|
||||
By definition, for a key of k bits, the following formula holds:
|
||||
|
|
@ -149,13 +141,14 @@ bool send_metakey(connection_t *c) {
|
|||
This can be done by setting the most significant bit to zero.
|
||||
*/
|
||||
|
||||
c->outkey[0] &= 0x7F;
|
||||
key[0] &= 0x7F;
|
||||
|
||||
cipher_set_key_from_rsa(&c->outcipher, key, len, true);
|
||||
|
||||
ifdebug(SCARY_THINGS) {
|
||||
bin2hex(c->outkey, buffer, len);
|
||||
buffer[len * 2] = '\0';
|
||||
logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"),
|
||||
buffer);
|
||||
bin2hex(key, hexkey, len);
|
||||
hexkey[len * 2] = '\0';
|
||||
logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), hexkey);
|
||||
}
|
||||
|
||||
/* Encrypt the random data
|
||||
|
|
@ -165,135 +158,78 @@ bool send_metakey(connection_t *c) {
|
|||
with a length equal to that of the modulus of the RSA key.
|
||||
*/
|
||||
|
||||
if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) {
|
||||
logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"),
|
||||
c->name, c->hostname);
|
||||
if(!rsa_public_encrypt(&c->rsa, key, len, enckey)) {
|
||||
logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Convert the encrypted random data to a hexadecimal formatted string */
|
||||
|
||||
bin2hex(buffer, buffer, len);
|
||||
buffer[len * 2] = '\0';
|
||||
bin2hex(enckey, hexkey, len);
|
||||
hexkey[len * 2] = '\0';
|
||||
|
||||
/* Send the meta key */
|
||||
|
||||
x = send_request(c, "%d %d %d %d %d %s", METAKEY,
|
||||
c->outcipher ? c->outcipher->nid : 0,
|
||||
c->outdigest ? c->outdigest->type : 0, c->outmaclength,
|
||||
c->outcompression, buffer);
|
||||
|
||||
/* Further outgoing requests are encrypted with the key we just generated */
|
||||
|
||||
if(c->outcipher) {
|
||||
if(!EVP_EncryptInit(c->outctx, c->outcipher,
|
||||
(unsigned char *)c->outkey + len - c->outcipher->key_len,
|
||||
(unsigned char *)c->outkey + len - c->outcipher->key_len -
|
||||
c->outcipher->iv_len)) {
|
||||
logger(LOG_ERR, _("Error during initialisation of cipher for %s (%s): %s"),
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
c->status.encryptout = true;
|
||||
}
|
||||
|
||||
return x;
|
||||
bool result = send_request(c, "%d %d %d %d %d %s", METAKEY,
|
||||
cipher_get_nid(&c->outcipher),
|
||||
digest_get_nid(&c->outdigest), c->outmaclength,
|
||||
c->outcompression, hexkey);
|
||||
|
||||
c->status.encryptout = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool metakey_h(connection_t *c, char *request) {
|
||||
char buffer[MAX_STRING_SIZE];
|
||||
char hexkey[MAX_STRING_SIZE];
|
||||
int cipher, digest, maclength, compression;
|
||||
int len;
|
||||
size_t len = rsa_size(&myself->connection->rsa);
|
||||
char enckey[len];
|
||||
char key[len];
|
||||
|
||||
cp();
|
||||
|
||||
if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) {
|
||||
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name,
|
||||
c->hostname);
|
||||
if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, hexkey) != 5) {
|
||||
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
len = RSA_size(myself->connection->rsa_key);
|
||||
|
||||
/* Check if the length of the meta key is all right */
|
||||
|
||||
if(strlen(buffer) != len * 2) {
|
||||
if(strlen(hexkey) != len * 2) {
|
||||
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Allocate buffers for the meta key */
|
||||
|
||||
if(!c->inkey)
|
||||
c->inkey = xmalloc(len);
|
||||
|
||||
if(!c->inctx)
|
||||
c->inctx = xmalloc_and_zero(sizeof(*c->inctx));
|
||||
|
||||
/* Convert the challenge from hexadecimal back to binary */
|
||||
|
||||
hex2bin(buffer, buffer, len);
|
||||
hex2bin(hexkey, enckey, len);
|
||||
|
||||
/* Decrypt the meta key */
|
||||
|
||||
if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */
|
||||
logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"),
|
||||
c->name, c->hostname);
|
||||
if(!rsa_private_decrypt(&myself->connection->rsa, enckey, len, key)) {
|
||||
logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
ifdebug(SCARY_THINGS) {
|
||||
bin2hex(c->inkey, buffer, len);
|
||||
buffer[len * 2] = '\0';
|
||||
logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
|
||||
bin2hex(key, hexkey, len);
|
||||
hexkey[len * 2] = '\0';
|
||||
logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), hexkey);
|
||||
}
|
||||
|
||||
/* All incoming requests will now be encrypted. */
|
||||
|
||||
/* Check and lookup cipher and digest algorithms */
|
||||
|
||||
if(cipher) {
|
||||
c->incipher = EVP_get_cipherbynid(cipher);
|
||||
|
||||
if(!c->incipher) {
|
||||
logger(LOG_ERR, _("%s (%s) uses unknown cipher!"), c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!EVP_DecryptInit(c->inctx, c->incipher,
|
||||
(unsigned char *)c->inkey + len - c->incipher->key_len,
|
||||
(unsigned char *)c->inkey + len - c->incipher->key_len -
|
||||
c->incipher->iv_len)) {
|
||||
logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s): %s"),
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
c->status.decryptin = true;
|
||||
} else {
|
||||
c->incipher = NULL;
|
||||
if(!cipher_open_by_nid(&c->incipher, cipher) || !cipher_set_key_from_rsa(&c->incipher, key, len, false)) {
|
||||
logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s)"), c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
c->inmaclength = maclength;
|
||||
|
||||
if(digest) {
|
||||
c->indigest = EVP_get_digestbynid(digest);
|
||||
|
||||
if(!c->indigest) {
|
||||
logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(c->inmaclength > c->indigest->md_size || c->inmaclength < 0) {
|
||||
logger(LOG_ERR, _("%s (%s) uses bogus MAC length!"), c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
c->indigest = NULL;
|
||||
if(!digest_open_by_nid(&c->indigest, digest)) {
|
||||
logger(LOG_ERR, _("Error during initialisation of digest from %s (%s)"), c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
c->incompression = compression;
|
||||
c->status.decryptin = true;
|
||||
|
||||
c->allow_request = CHALLENGE;
|
||||
|
||||
|
|
@ -301,25 +237,17 @@ bool metakey_h(connection_t *c, char *request) {
|
|||
}
|
||||
|
||||
bool send_challenge(connection_t *c) {
|
||||
char *buffer;
|
||||
int len;
|
||||
size_t len = rsa_size(&c->rsa);
|
||||
char buffer[len * 2 + 1];
|
||||
|
||||
cp();
|
||||
|
||||
/* CHECKME: what is most reasonable value for len? */
|
||||
|
||||
len = RSA_size(c->rsa_key);
|
||||
|
||||
/* Allocate buffers for the challenge */
|
||||
|
||||
buffer = alloca(2 * len + 1);
|
||||
|
||||
if(!c->hischallenge)
|
||||
c->hischallenge = xmalloc(len);
|
||||
|
||||
/* Copy random data to the buffer */
|
||||
|
||||
RAND_pseudo_bytes((unsigned char *)c->hischallenge, len);
|
||||
randomize(c->hischallenge, len);
|
||||
|
||||
/* Convert to hex */
|
||||
|
||||
|
|
@ -333,72 +261,48 @@ bool send_challenge(connection_t *c) {
|
|||
|
||||
bool challenge_h(connection_t *c, char *request) {
|
||||
char buffer[MAX_STRING_SIZE];
|
||||
int len;
|
||||
size_t len = rsa_size(&myself->connection->rsa);
|
||||
size_t digestlen = digest_length(&c->outdigest);
|
||||
char digest[digestlen];
|
||||
|
||||
cp();
|
||||
|
||||
if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) {
|
||||
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name,
|
||||
c->hostname);
|
||||
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
len = RSA_size(myself->connection->rsa_key);
|
||||
|
||||
/* Check if the length of the challenge is all right */
|
||||
|
||||
if(strlen(buffer) != len * 2) {
|
||||
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
|
||||
c->hostname, "wrong challenge length");
|
||||
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong challenge length");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Allocate buffers for the challenge */
|
||||
|
||||
if(!c->mychallenge)
|
||||
c->mychallenge = xmalloc(len);
|
||||
|
||||
/* Convert the challenge from hexadecimal back to binary */
|
||||
|
||||
hex2bin(buffer, c->mychallenge, len);
|
||||
hex2bin(buffer, buffer, len);
|
||||
|
||||
c->allow_request = CHAL_REPLY;
|
||||
|
||||
/* Rest is done by send_chal_reply() */
|
||||
|
||||
return send_chal_reply(c);
|
||||
}
|
||||
|
||||
bool send_chal_reply(connection_t *c) {
|
||||
char hash[EVP_MAX_MD_SIZE * 2 + 1];
|
||||
EVP_MD_CTX ctx;
|
||||
|
||||
cp();
|
||||
|
||||
/* Calculate the hash from the challenge we received */
|
||||
|
||||
if(!EVP_DigestInit(&ctx, c->indigest)
|
||||
|| !EVP_DigestUpdate(&ctx, c->mychallenge, RSA_size(myself->connection->rsa_key))
|
||||
|| !EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL)) {
|
||||
logger(LOG_ERR, _("Error during calculation of response for %s (%s): %s"),
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
digest_create(&c->indigest, buffer, len, digest);
|
||||
|
||||
/* Convert the hash to a hexadecimal formatted string */
|
||||
|
||||
bin2hex(hash, hash, c->indigest->md_size);
|
||||
hash[c->indigest->md_size * 2] = '\0';
|
||||
bin2hex(digest, buffer, digestlen);
|
||||
buffer[digestlen * 2] = '\0';
|
||||
|
||||
/* Send the reply */
|
||||
|
||||
return send_request(c, "%d %s", CHAL_REPLY, hash);
|
||||
return send_request(c, "%d %s", CHAL_REPLY, buffer);
|
||||
}
|
||||
|
||||
bool chal_reply_h(connection_t *c, char *request) {
|
||||
char hishash[MAX_STRING_SIZE];
|
||||
char myhash[EVP_MAX_MD_SIZE];
|
||||
EVP_MD_CTX ctx;
|
||||
|
||||
cp();
|
||||
|
||||
|
|
@ -410,38 +314,19 @@ bool chal_reply_h(connection_t *c, char *request) {
|
|||
|
||||
/* Check if the length of the hash is all right */
|
||||
|
||||
if(strlen(hishash) != c->outdigest->md_size * 2) {
|
||||
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
|
||||
c->hostname, _("wrong challenge reply length"));
|
||||
if(strlen(hishash) != digest_length(&c->outdigest) * 2) {
|
||||
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Convert the hash to binary format */
|
||||
|
||||
hex2bin(hishash, hishash, c->outdigest->md_size);
|
||||
hex2bin(hishash, hishash, digest_length(&c->outdigest));
|
||||
|
||||
/* Calculate the hash from the challenge we sent */
|
||||
|
||||
if(!EVP_DigestInit(&ctx, c->outdigest)
|
||||
|| !EVP_DigestUpdate(&ctx, c->hischallenge, RSA_size(c->rsa_key))
|
||||
|| !EVP_DigestFinal(&ctx, (unsigned char *)myhash, NULL)) {
|
||||
logger(LOG_ERR, _("Error during calculation of response from %s (%s): %s"),
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Verify the incoming hash with the calculated hash */
|
||||
|
||||
if(memcmp(hishash, myhash, c->outdigest->md_size)) {
|
||||
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
|
||||
c->hostname, _("wrong challenge reply"));
|
||||
|
||||
ifdebug(SCARY_THINGS) {
|
||||
bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
|
||||
hishash[SHA_DIGEST_LENGTH * 2] = '\0';
|
||||
logger(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
|
||||
}
|
||||
/* Verify the hash */
|
||||
|
||||
if(!digest_verify(&c->outdigest, c->hischallenge, rsa_size(&c->rsa), hishash)) {
|
||||
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -449,6 +334,8 @@ bool chal_reply_h(connection_t *c, char *request) {
|
|||
Send an acknowledgement with the rest of the information needed.
|
||||
*/
|
||||
|
||||
free(c->hischallenge);
|
||||
c->hischallenge = NULL;
|
||||
c->allow_request = ACK;
|
||||
|
||||
return send_ack(c);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue