Enforce maximum amount of bytes sent/received on meta-connections.

This is 2^{block_length_in_bits / 2 - 1}.
This commit is contained in:
Guus Sliepen 2016-10-30 15:19:12 +01:00
parent edc1efed3c
commit 979acc48ad
5 changed files with 39 additions and 0 deletions

View file

@ -33,6 +33,7 @@ extern cipher_t *cipher_open_by_nid(int) __attribute__ ((__malloc__));
extern void cipher_close(cipher_t *); extern void cipher_close(cipher_t *);
extern size_t cipher_keylength(const cipher_t *); extern size_t cipher_keylength(const cipher_t *);
extern size_t cipher_blocksize(const cipher_t *); extern size_t cipher_blocksize(const cipher_t *);
extern uint64_t cipher_budget(const cipher_t *);
extern void cipher_get_key(const cipher_t *, void *); extern void cipher_get_key(const cipher_t *, void *);
extern bool cipher_set_key(cipher_t *, void *, bool) __attribute__ ((__warn_unused_result__)); extern bool cipher_set_key(cipher_t *, void *, bool) __attribute__ ((__warn_unused_result__));
extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool) __attribute__ ((__warn_unused_result__)); extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool) __attribute__ ((__warn_unused_result__));

View file

@ -81,6 +81,8 @@ typedef struct connection_t {
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;
uint64_t inbudget;
uint64_t outbudget;
#endif #endif
ecdsa_t *ecdsa; /* his public ECDSA key */ ecdsa_t *ecdsa; /* his public ECDSA key */

View file

@ -65,6 +65,13 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
#ifdef DISABLE_LEGACY #ifdef DISABLE_LEGACY
return false; return false;
#else #else
if(length > c->outbudget) {
logger(DEBUG_META, LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname);
return false;
} else {
c->outbudget -= length;
}
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) {
@ -220,6 +227,13 @@ bool receive_meta(connection_t *c) {
#ifdef DISABLE_LEGACY #ifdef DISABLE_LEGACY
return false; return false;
#else #else
if(inlen > c->inbudget) {
logger(DEBUG_META, LOG_ERR, "yte limit exceeded for decryption from %s (%s)", c->name, c->hostname);
return false;
} else {
c->inbudget -= inlen;
}
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) {

View file

@ -77,6 +77,24 @@ size_t cipher_keylength(const cipher_t *cipher) {
return EVP_CIPHER_key_length(cipher->cipher) + EVP_CIPHER_iv_length(cipher->cipher); return EVP_CIPHER_key_length(cipher->cipher) + EVP_CIPHER_iv_length(cipher->cipher);
} }
uint64_t cipher_budget(const cipher_t *cipher) {
/* Hopefully some failsafe way to calculate the maximum amount of bytes to
send/receive with a given cipher before we might run into birthday paradox
attacks. Because we might use different modes, the block size of the mode
might be 1 byte. In that case, use the IV length. Ensure the whole thing
is limited to what can be represented with a 64 bits integer.
*/
if(!cipher || !cipher->cipher)
return UINT64_MAX; // NULL cipher
int ivlen = EVP_CIPHER_iv_length(cipher->cipher);
int blklen = EVP_CIPHER_block_size(cipher->cipher);
int len = blklen > 1 ? blklen : ivlen > 1 ? ivlen : 8;
int bits = len * 4 - 1;
return bits < 64 ? UINT64_C(1) << bits : UINT64_MAX;
}
size_t cipher_blocksize(const cipher_t *cipher) { size_t cipher_blocksize(const cipher_t *cipher) {
if(!cipher || !cipher->cipher) if(!cipher || !cipher->cipher)
return 1; return 1;

View file

@ -436,6 +436,8 @@ bool send_metakey(connection_t *c) {
if(!c) if(!c)
return false; return false;
c->outbudget = cipher_budget(c->outcipher);
if(!(c->outdigest = digest_open_by_name("sha256", -1))) if(!(c->outdigest = digest_open_by_name("sha256", -1)))
return false; return false;
@ -548,6 +550,8 @@ bool metakey_h(connection_t *c, const char *request) {
c->incipher = NULL; c->incipher = NULL;
} }
c->inbudget = cipher_budget(c->incipher);
if(digest) { if(digest) {
if(!(c->indigest = digest_open_by_nid(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);