Adding class to manage ESP context (crypto, sequence numbers)
This commit is contained in:
@@ -3,7 +3,8 @@ include $(CLEAR_VARS)
|
||||
|
||||
# copy-n-paste from Makefile.am
|
||||
LOCAL_SRC_FILES := \
|
||||
ipsec.c ipsec.h
|
||||
ipsec.c ipsec.h \
|
||||
esp_context.c esp_context.h
|
||||
|
||||
# build libipsec ---------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
ipseclib_LTLIBRARIES = libipsec.la
|
||||
|
||||
libipsec_la_SOURCES = \
|
||||
ipsec.c ipsec.h
|
||||
ipsec.c ipsec.h \
|
||||
esp_context.c esp_context.h
|
||||
|
||||
libipsec_la_LIBADD =
|
||||
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Tobias Brunner
|
||||
* Copyright (C) 2012 Giuliano Grassi
|
||||
* Copyright (C) 2012 Ralf Sager
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "esp_context.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
|
||||
/**
|
||||
* Should be a multiple of 8
|
||||
*/
|
||||
#define ESP_DEFAULT_WINDOW_SIZE 128
|
||||
|
||||
typedef struct private_esp_context_t private_esp_context_t;
|
||||
|
||||
/**
|
||||
* Private additions to esp_context_t.
|
||||
*/
|
||||
struct private_esp_context_t {
|
||||
|
||||
/**
|
||||
* Public members
|
||||
*/
|
||||
esp_context_t public;
|
||||
|
||||
/**
|
||||
* Crypter used to encrypt/decrypt ESP packets
|
||||
*/
|
||||
crypter_t *crypter;
|
||||
|
||||
/**
|
||||
* Signer to authenticate ESP packets
|
||||
*/
|
||||
signer_t *signer;
|
||||
|
||||
/**
|
||||
* The highest sequence number that was successfully verified
|
||||
* and authenticated, or assigned in an outbound context
|
||||
*/
|
||||
u_int32_t last_seqno;
|
||||
|
||||
/**
|
||||
* The bit in the window of the highest authenticated sequence number
|
||||
*/
|
||||
u_int seqno_index;
|
||||
|
||||
/**
|
||||
* The size of the anti-replay window (in bits)
|
||||
*/
|
||||
u_int window_size;
|
||||
|
||||
/**
|
||||
* The anti-replay window buffer
|
||||
*/
|
||||
chunk_t window;
|
||||
|
||||
/**
|
||||
* TRUE in case of an inbound ESP context
|
||||
*/
|
||||
bool inbound;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or unset a bit in the window.
|
||||
*/
|
||||
static inline void set_window_bit(private_esp_context_t *this,
|
||||
u_int index, bool set)
|
||||
{
|
||||
u_int i = index / CHAR_BIT;
|
||||
|
||||
if (set)
|
||||
{
|
||||
this->window.ptr[i] |= 1 << (index % CHAR_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->window.ptr[i] &= ~(1 << (index % CHAR_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bit from the window.
|
||||
*/
|
||||
static inline bool get_window_bit(private_esp_context_t *this, u_int index)
|
||||
{
|
||||
u_int i = index / CHAR_BIT;
|
||||
|
||||
return this->window.ptr[i] & (1 << index % CHAR_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the supplied seqno is not already marked in the window
|
||||
*/
|
||||
static bool check_window(private_esp_context_t *this, u_int32_t seqno)
|
||||
{
|
||||
u_int offset;
|
||||
|
||||
offset = this->last_seqno - seqno;
|
||||
offset = (this->seqno_index - offset) % this->window_size;
|
||||
return !get_window_bit(this, offset);
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, verify_seqno, bool,
|
||||
private_esp_context_t *this, u_int32_t seqno)
|
||||
{
|
||||
if (!this->inbound)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (seqno > this->last_seqno)
|
||||
{ /* |----------------------------------------|
|
||||
* <---------^ ^ or <---------^ ^
|
||||
* WIN H S WIN H S
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
else if (seqno > 0 && this->window_size > this->last_seqno - seqno)
|
||||
{ /* |----------------------------------------|
|
||||
* <---------^ or <---------^
|
||||
* WIN ^ H WIN ^ H
|
||||
* S S
|
||||
*/
|
||||
return check_window(this, seqno);
|
||||
}
|
||||
else
|
||||
{ /* |----------------------------------------|
|
||||
* ^ <---------^
|
||||
* S WIN H
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, set_authenticated_seqno, void,
|
||||
private_esp_context_t *this, u_int32_t seqno)
|
||||
{
|
||||
u_int i, shift;
|
||||
|
||||
if (!this->inbound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (seqno > this->last_seqno)
|
||||
{ /* shift the window to the new highest authenticated seqno */
|
||||
shift = seqno - this->last_seqno;
|
||||
shift = shift < this->window_size ? shift : this->window_size;
|
||||
for (i = 0; i < shift; ++i)
|
||||
{
|
||||
this->seqno_index = (this->seqno_index + 1) % this->window_size;
|
||||
set_window_bit(this, this->seqno_index, FALSE);
|
||||
}
|
||||
set_window_bit(this, this->seqno_index, TRUE);
|
||||
this->last_seqno = seqno;
|
||||
}
|
||||
else
|
||||
{ /* seqno is inside the window, set the corresponding window bit */
|
||||
i = this->last_seqno - seqno;
|
||||
set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, get_seqno, u_int32_t,
|
||||
private_esp_context_t *this)
|
||||
{
|
||||
return this->last_seqno;
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, next_seqno, bool,
|
||||
private_esp_context_t *this, u_int32_t *seqno)
|
||||
{
|
||||
if (this->inbound || this->last_seqno == UINT32_MAX)
|
||||
{ /* inbound or segno would cycle */
|
||||
return FALSE;
|
||||
}
|
||||
*seqno = ++this->last_seqno;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, get_signer, signer_t *,
|
||||
private_esp_context_t *this)
|
||||
{
|
||||
return this->signer;
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, get_crypter, crypter_t *,
|
||||
private_esp_context_t *this)
|
||||
{
|
||||
return this->crypter;
|
||||
}
|
||||
|
||||
METHOD(esp_context_t, destroy, void,
|
||||
private_esp_context_t *this)
|
||||
{
|
||||
chunk_free(&this->window);
|
||||
DESTROY_IF(this->crypter);
|
||||
DESTROY_IF(this->signer);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
|
||||
int int_alg, chunk_t int_key, bool inbound)
|
||||
{
|
||||
private_esp_context_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_crypter = _get_crypter,
|
||||
.get_signer = _get_signer,
|
||||
.get_seqno = _get_seqno,
|
||||
.next_seqno = _next_seqno,
|
||||
.verify_seqno = _verify_seqno,
|
||||
.set_authenticated_seqno = _set_authenticated_seqno,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.inbound = inbound,
|
||||
.window_size = ESP_DEFAULT_WINDOW_SIZE,
|
||||
);
|
||||
|
||||
switch(enc_alg)
|
||||
{
|
||||
case ENCR_AES_CBC:
|
||||
this->crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
|
||||
enc_key.len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!this->crypter)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
|
||||
"algorithm");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (!this->crypter->set_key(this->crypter, enc_key))
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
|
||||
"failed");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(int_alg)
|
||||
{
|
||||
case AUTH_HMAC_SHA1_96:
|
||||
case AUTH_HMAC_SHA2_256_128:
|
||||
case AUTH_HMAC_SHA2_384_192:
|
||||
case AUTH_HMAC_SHA2_512_256:
|
||||
this->signer = lib->crypto->create_signer(lib->crypto, int_alg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!this->signer)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
|
||||
"algorithm");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (!this->signer->set_key(this->signer, int_key))
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
|
||||
"failed");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inbound)
|
||||
{
|
||||
this->window = chunk_alloc(this->window_size / CHAR_BIT + 1);
|
||||
memset(this->window.ptr, 0, this->window.len);
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Tobias Brunner
|
||||
* Copyright (C) 2012 Giuliano Grassi
|
||||
* Copyright (C) 2012 Ralf Sager
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup esp_context esp_context
|
||||
* @{ @ingroup libipsec
|
||||
*/
|
||||
|
||||
#ifndef ESP_CONTEXT_H_
|
||||
#define ESP_CONTEXT_H_
|
||||
|
||||
#include <library.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
|
||||
typedef struct esp_context_t esp_context_t;
|
||||
|
||||
/**
|
||||
* ESP context, handles sequence numbers and maintains cryptographic primitives
|
||||
*/
|
||||
struct esp_context_t {
|
||||
|
||||
/**
|
||||
* Get the crypter.
|
||||
*
|
||||
* @return crypter
|
||||
*/
|
||||
crypter_t *(*get_crypter)(esp_context_t *this);
|
||||
|
||||
/**
|
||||
* Get the signer.
|
||||
*
|
||||
* @return signer
|
||||
*/
|
||||
signer_t *(*get_signer)(esp_context_t *this);
|
||||
|
||||
/**
|
||||
* Get the current outbound ESP sequence number or the highest authenticated
|
||||
* inbound sequence number.
|
||||
*
|
||||
* @return current sequence number, in host byte order
|
||||
*/
|
||||
u_int32_t (*get_seqno)(esp_context_t *this);
|
||||
|
||||
/**
|
||||
* Allocate the next outbound ESP sequence number.
|
||||
*
|
||||
* @param seqno the sequence number, in host byte order
|
||||
* @return FALSE if the sequence number cycled or inbound context
|
||||
*/
|
||||
bool (*next_seqno)(esp_context_t *this, u_int32_t *seqno);
|
||||
|
||||
/**
|
||||
* Verify an ESP sequence number. Checks whether a packet with this
|
||||
* sequence number was already received, using the anti-replay window.
|
||||
* This operation does not modify the internal state. After the sequence
|
||||
* number is successfully verified and the ESP packet is authenticated,
|
||||
* set_authenticated_seqno() should be called.
|
||||
*
|
||||
* @param seqno the sequence number to verify, in host byte order
|
||||
* @return TRUE when sequence number is valid
|
||||
*/
|
||||
bool (*verify_seqno)(esp_context_t *this, u_int32_t seqno);
|
||||
|
||||
/**
|
||||
* Adds a sequence number that was successfully verified and
|
||||
* authenticated. A user MUST call verify_seqno() immediately before
|
||||
* calling this method.
|
||||
*
|
||||
* @param seqno verified and authenticated seq number in host byte order
|
||||
*/
|
||||
void (*set_authenticated_seqno)(esp_context_t *this,
|
||||
u_int32_t seqno);
|
||||
|
||||
/**
|
||||
* Destroy an esp_context_t
|
||||
*/
|
||||
void (*destroy)(esp_context_t *this);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an esp_context_t instance
|
||||
*
|
||||
* @param enc_alg encryption algorithm
|
||||
* @param enc_key encryption key
|
||||
* @param int_alg integrity protection algorithm
|
||||
* @param int_key integrity protection key
|
||||
* @param inbound TRUE to create an inbound ESP context
|
||||
* @return ESP context instance, or NULL if creation fails
|
||||
*/
|
||||
esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key, int int_alg,
|
||||
chunk_t int_key, bool inbound);
|
||||
|
||||
#endif /** ESP_CONTEXT_H_ @}*/
|
||||
|
||||
Reference in New Issue
Block a user