iv_gen: Provide external sequence number (IKE, ESP)

This prevents duplicate sequential IVs in case of a HA failover.
This commit is contained in:
Tobias Brunner 2013-08-05 15:41:45 +02:00
parent d74c254dfd
commit e8229ad558
7 changed files with 18 additions and 23 deletions

View File

@ -1622,7 +1622,7 @@ METHOD(message_t, generate, status_t,
htoun32(lenpos, chunk.len + encryption->get_length(encryption)); htoun32(lenpos, chunk.len + encryption->get_length(encryption));
} }
this->payloads->insert_last(this->payloads, encryption); this->payloads->insert_last(this->payloads, encryption);
if (encryption->encrypt(encryption, chunk) != SUCCESS) if (encryption->encrypt(encryption, this->message_id, chunk) != SUCCESS)
{ {
generator->destroy(generator); generator->destroy(generator);
return INVALID_STATE; return INVALID_STATE;

View File

@ -309,7 +309,7 @@ static chunk_t append_header(private_encryption_payload_t *this, chunk_t assoc)
} }
METHOD(encryption_payload_t, encrypt, status_t, METHOD(encryption_payload_t, encrypt, status_t,
private_encryption_payload_t *this, chunk_t assoc) private_encryption_payload_t *this, u_int64_t mid, chunk_t assoc)
{ {
chunk_t iv, plain, padding, icv, crypt; chunk_t iv, plain, padding, icv, crypt;
generator_t *generator; generator_t *generator;
@ -364,7 +364,7 @@ METHOD(encryption_payload_t, encrypt, status_t,
crypt = chunk_create(plain.ptr, plain.len + padding.len); crypt = chunk_create(plain.ptr, plain.len + padding.len);
generator->destroy(generator); generator->destroy(generator);
if (!iv_gen->get_iv(iv_gen, iv.len, iv.ptr) || if (!iv_gen->get_iv(iv_gen, mid, iv.len, iv.ptr) ||
!rng->get_bytes(rng, padding.len - 1, padding.ptr)) !rng->get_bytes(rng, padding.len - 1, padding.ptr))
{ {
DBG1(DBG_ENC, "encrypting encryption payload failed, no IV or padding"); DBG1(DBG_ENC, "encrypting encryption payload failed, no IV or padding");
@ -396,7 +396,7 @@ METHOD(encryption_payload_t, encrypt, status_t,
} }
METHOD(encryption_payload_t, encrypt_v1, status_t, METHOD(encryption_payload_t, encrypt_v1, status_t,
private_encryption_payload_t *this, chunk_t iv) private_encryption_payload_t *this, u_int64_t mid, chunk_t iv)
{ {
generator_t *generator; generator_t *generator;
chunk_t plain, padding; chunk_t plain, padding;

View File

@ -71,13 +71,15 @@ struct encryption_payload_t {
/** /**
* Generate, encrypt and sign contained payloads. * Generate, encrypt and sign contained payloads.
* *
* @param mid message ID
* @param assoc associated data * @param assoc associated data
* @return * @return
* - SUCCESS if encryption successful * - SUCCESS if encryption successful
* - FAILED if encryption failed * - FAILED if encryption failed
* - INVALID_STATE if aead not supplied, but needed * - INVALID_STATE if aead not supplied, but needed
*/ */
status_t (*encrypt) (encryption_payload_t *this, chunk_t assoc); status_t (*encrypt) (encryption_payload_t *this, u_int64_t mid,
chunk_t assoc);
/** /**
* Decrypt, verify and parse contained payloads. * Decrypt, verify and parse contained payloads.

View File

@ -319,7 +319,7 @@ METHOD(esp_packet_t, encrypt, status_t,
writer->write_uint32(writer, next_seqno); writer->write_uint32(writer, next_seqno);
iv = writer->skip(writer, iv.len); iv = writer->skip(writer, iv.len);
if (!iv_gen->get_iv(iv_gen, iv.len, iv.ptr)) if (!iv_gen->get_iv(iv_gen, next_seqno, iv.len, iv.ptr))
{ {
DBG1(DBG_ESP, "ESP encryption failed: could not generate IV"); DBG1(DBG_ESP, "ESP encryption failed: could not generate IV");
writer->destroy(writer); writer->destroy(writer);

View File

@ -33,21 +33,23 @@ struct iv_gen_t {
/** /**
* Generates an IV and writes it into the buffer. * Generates an IV and writes it into the buffer.
* *
* @param seq external sequence number
* @param size size of IV in bytes * @param size size of IV in bytes
* @param buffer pointer where the generated IV will be written * @param buffer pointer where the generated IV will be written
* @return TRUE if IV allocation was successful, FALSE otherwise * @return TRUE if IV allocation was successful, FALSE otherwise
*/ */
bool (*get_iv)(iv_gen_t *this, size_t size, bool (*get_iv)(iv_gen_t *this, u_int64_t seq, size_t size,
u_int8_t *buffer) __attribute__((warn_unused_result)); u_int8_t *buffer) __attribute__((warn_unused_result));
/** /**
* Generates an IV and allocates space for it. * Generates an IV and allocates space for it.
* *
* @param seq external sequence number
* @param size size of IV in bytes * @param size size of IV in bytes
* @param chunk chunk which will hold the generated IV * @param chunk chunk which will hold the generated IV
* @return TRUE if IV allocation was successful, FALSE otherwise * @return TRUE if IV allocation was successful, FALSE otherwise
*/ */
bool (*allocate_iv)(iv_gen_t *this, size_t size, bool (*allocate_iv)(iv_gen_t *this, u_int64_t seq, size_t size,
chunk_t *chunk) __attribute__((warn_unused_result)); chunk_t *chunk) __attribute__((warn_unused_result));
/** /**

View File

@ -36,7 +36,7 @@ struct private_iv_gen_t {
}; };
METHOD(iv_gen_t, get_iv, bool, METHOD(iv_gen_t, get_iv, bool,
private_iv_gen_t *this, size_t size, u_int8_t *buffer) private_iv_gen_t *this, u_int64_t seq, size_t size, u_int8_t *buffer)
{ {
if (!this->rng) if (!this->rng)
{ {
@ -46,7 +46,7 @@ METHOD(iv_gen_t, get_iv, bool,
} }
METHOD(iv_gen_t, allocate_iv, bool, METHOD(iv_gen_t, allocate_iv, bool,
private_iv_gen_t *this, size_t size, chunk_t *chunk) private_iv_gen_t *this, u_int64_t seq, size_t size, chunk_t *chunk)
{ {
if (!this->rng) if (!this->rng)
{ {

View File

@ -26,38 +26,29 @@ struct private_iv_gen_t {
* Public iv_gen_t interface. * Public iv_gen_t interface.
*/ */
iv_gen_t public; iv_gen_t public;
/**
* sequence number
*/
u_int64_t seq;
}; };
METHOD(iv_gen_t, get_iv, bool, METHOD(iv_gen_t, get_iv, bool,
private_iv_gen_t *this, size_t size, u_int8_t *buffer) private_iv_gen_t *this, u_int64_t seq, size_t size, u_int8_t *buffer)
{ {
u_int8_t iv[sizeof(u_int64_t)]; u_int8_t iv[sizeof(u_int64_t)];
size_t len = size; size_t len = size;
if (this->seq == UINT64_MAX || len < sizeof(u_int64_t))
{
return FALSE;
}
if (len > sizeof(u_int64_t)) if (len > sizeof(u_int64_t))
{ {
len = sizeof(u_int64_t); len = sizeof(u_int64_t);
memset(buffer, 0, size - len); memset(buffer, 0, size - len);
} }
htoun64(iv, this->seq++); htoun64(iv, seq);
memcpy(buffer + size - len, iv + sizeof(u_int64_t) - len, len); memcpy(buffer + size - len, iv + sizeof(u_int64_t) - len, len);
return TRUE; return TRUE;
} }
METHOD(iv_gen_t, allocate_iv, bool, METHOD(iv_gen_t, allocate_iv, bool,
private_iv_gen_t *this, size_t size, chunk_t *chunk) private_iv_gen_t *this, u_int64_t seq, size_t size, chunk_t *chunk)
{ {
*chunk = chunk_alloc(size); *chunk = chunk_alloc(size);
if (!get_iv(this, chunk->len, chunk->ptr)) if (!get_iv(this, seq, chunk->len, chunk->ptr))
{ {
chunk_free(chunk); chunk_free(chunk);
return FALSE; return FALSE;