24 RCSID(
"$Id: 9bc8c82b8a7d178e54b5c7def44b0cf83f50591b $")
26 #include <freeradius-devel/io/test_point.h>
27 #include <freeradius-devel/server/module.h>
28 #include <freeradius-devel/tls/base.h>
29 #include <freeradius-devel/tls/strerror.h>
30 #include <freeradius-devel/util/dbuff.h>
31 #include <freeradius-devel/util/rand.h>
32 #include <freeradius-devel/util/debug.h>
33 #include <freeradius-devel/util/sha1.h>
35 #include <freeradius-devel/eap/types.h>
40 #define SIM_MAX_ATTRIBUTE_VALUE_LEN ((255 * 4) - 2)
75 if (!
vp)
return false;
76 if (
vp->
da->flags.internal)
return false;
113 if (packet_ctx->
have_iv)
return 0;
123 memcpy(packet_ctx->
iv, (
uint8_t *)&iv[0],
sizeof(packet_ctx->
iv));
158 size_t total_len, pad_len, encr_len, len = 0;
162 EVP_CIPHER_CTX *evp_ctx;
163 EVP_CIPHER
const *evp_cipher = EVP_aes_128_cbc();
164 size_t block_size = EVP_CIPHER_block_size(evp_cipher);
176 total_len = (
inlen + (block_size - 1)) & ~(block_size - 1);
177 pad_len = (total_len -
inlen);
204 if (
unlikely(EVP_EncryptInit_ex(evp_ctx, evp_cipher, NULL,
205 packet_ctx->
k_encr, packet_ctx->
iv) != 1)) {
206 fr_tls_strerror_printf(
"Failed initialising AES-128-ECB context");
212 encr = talloc_array(NULL,
uint8_t, total_len);
229 EVP_CIPHER_CTX_set_padding(evp_ctx, 0);
230 if (
unlikely(EVP_EncryptUpdate(evp_ctx, encr, (
int *)&len,
fr_dbuff_start(&work_dbuff), total_len) != 1)) {
231 fr_tls_strerror_printf(
"%s: Failed encrypting attribute", __FUNCTION__);
236 if (
unlikely(EVP_EncryptFinal_ex(evp_ctx, encr + encr_len, (
int *)&len) != 1)) {
237 fr_tls_strerror_printf(
"%s: Failed finalising encrypted attribute", __FUNCTION__);
245 if (
unlikely(encr_len != total_len)) {
247 __FUNCTION__, total_len, encr_len);
260 if (slen <= 0)
return slen;
294 switch (
vp->vp_type) {
320 if ((
vp->
da->flags.length && (da->flags.length !=
vp->vp_length)) ||
321 (
vp->vp_length !=
sizeof(packet_ctx->
iv))) {
323 "but value was %zu bytes", __FUNCTION__,
324 da->name, (
size_t)da->flags.length,
vp->vp_length);
327 memcpy(packet_ctx->
iv,
vp->vp_octets,
sizeof(packet_ctx->
iv));
346 if ((
vp->vp_length < 4) || (
vp->vp_length > 16)) {
348 __FUNCTION__,
vp->vp_length);
380 switch (
vp->vp_type) {
399 if (
vp->
da->flags.length && (
vp->vp_length !=
vp->
da->flags.length)) {
401 "but value was %zu bytes", __FUNCTION__,
402 vp->
da->name, (
size_t)
vp->
da->flags.length,
vp->vp_length);
414 if (
vp->
da->flags.length) {
417 size_t value_len_rounded;
419 if (
vp->vp_length >
vp->
da->flags.length) {
421 "but value was %zu bytes", __FUNCTION__,
422 vp->
da->name, (
size_t)
vp->
da->flags.length,
vp->vp_length);
429 value_len_rounded =
ROUND_UP(
vp->vp_length, (
size_t)
vp->
da->flags.length);
443 pad_len = value_len_rounded -
vp->vp_length;
484 if (len < 0)
return len;
532 if (!da->flags.length) {
534 "have a fixed length", da->name);
537 element_len = da->flags.length;
555 if (!
vp || (
vp->
da != da))
break;
566 if (element_len % 4) {
598 switch (da_stack->
da[
depth]->type) {
606 (da_stack->
da[
depth]->attr > 255)) {
627 if (da->flags.array) {
634 if (slen <= 0)
return slen;
665 value_dbuff =
FR_DBUFF(&work_dbuff);
701 if ((da != da_stack->
da[
depth]) || (da_stack->
depth < da->depth)) {
725 if (value_len < 0)
return -1;
740 unsigned int total_len;
757 if (!da_stack->
da[
depth + 1]) {
769 my_cursor = &child_cursor;
781 if (len < 0)
return len;
791 if (len <= 0)
return len;
831 if (
vp->
da->attr == FR_MAC) {
854 if (slen < 0)
return slen;
860 fr_strerror_printf(
"%s: Nested attribute structure too large to encode", __FUNCTION__);
875 fr_dbuff_uctx_talloc_t tctx;
877 bool do_hmac =
false;
879 unsigned char subtype;
891 REDEBUG(
"Missing subtype attribute");
894 subtype =
vp->vp_uint16;
966 if (slen < 0)
goto error;
978 if (!realloced)
goto error;
1001 test_ctx->
k_encr = talloc_memdup(test_ctx, k_encr, k_encr_len);
1002 test_ctx->
k_aut = talloc_zero_array(test_ctx,
uint8_t, 16);
1021 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1022 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1025 if (!test_ctx)
return -1;
1037 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1038 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1041 if (!test_ctx)
return -1;
1053 static uint8_t k_encr[] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a,
1054 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 };
1057 if (!test_ctx)
return -1;
Structure to hold EAP data.
EAP-SIM/EAP-AKA Private crypto functions.
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat)
Extend if we're below _lowat and return if we can't extend above _lowat.
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
#define FR_DBUFF_MAX_BIND_CURRENT(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
return fr_dcursor_filter_next(cursor, eval, uctx)
fr_dcursor_eval_t void const * uctx
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
ssize_t fr_aka_sim_crypto_sign_packet(uint8_t out[static AKA_SIM_MAC_DIGEST_SIZE], eap_packet_t *eap_packet, bool zero_mac, EVP_MD const *md, uint8_t const *key, size_t const key_len, uint8_t const *hmac_extra, size_t const hmac_extra_len)
Calculate the digest value for a packet.
#define AKA_SIM_IV_SIZE
Length of the IV used when processing AT_ENCR.
bool have_iv
Whether we found the IV already.
#define AKA_SIM_MAC_SIZE
Length of MAC used to prevent packet modification.
uint8_t const * k_aut
The authentication key used for signing.
EVP_MD const * hmac_md
HMAC digest algorithm, usually EVP_sha1().
eap_packet_t * eap_packet
Needed for validating AT_MAC.
uint8_t const * k_encr
The encryption key used for encrypting.
uint8_t const * hmac_extra
Extra data for the HMAC function.
uint8_t iv[AKA_SIM_IV_SIZE]
From the current packet.
#define fr_aka_sim_flag_encrypted(_da)
EVP_CIPHER_CTX * aka_sim_crypto_cipher_ctx(void)
Allocate and reset a resumable EVP_CIPHER_CTX for each thread.
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
fr_dict_t const * dict_eap_aka_sim
void fr_aka_sim_free(void)
int fr_aka_sim_init(void)
size_t fr_aka_sim_octets_prefix_len(fr_dict_attr_t const *da)
Return the number of bytes before the octets value.
size_t const fr_aka_sim_attr_sizes[FR_TYPE_MAX+1][2]
SIM AT on-the-wire format attribute sizes.
#define SIM_MAX_ATTRIBUTE_VALUE_LEN
fr_test_point_pair_encode_t sim_tp_encode
ssize_t fr_aka_sim_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
static ssize_t encode_array(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encodes the data portion of an attribute.
fr_test_point_pair_encode_t sim_tp_encode_rfc4186
static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encodes the data portion of an attribute.
static ssize_t encode_iv(fr_dbuff_t *dbuff, void *encode_ctx)
Add an IV to a packet.
static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx)
static ssize_t encode_tlv_internal(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
fr_test_point_pair_encode_t aka_tp_encode
static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx)
ssize_t fr_aka_sim_encode(request_t *request, fr_pair_list_t *to_encode, void *encode_ctx)
static fr_aka_sim_ctx_t * test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
static ssize_t encode_rfc(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode an RFC format attribute header.
static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx)
static int _test_ctx_free(UNUSED fr_aka_sim_ctx_t *ctx)
static bool is_eap_aka_encodable(void const *item, UNUSED void const *uctx)
Evaluation function for EAP-AKA-encodability.
static ssize_t encode_encrypted_value(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen, void *encode_ctx)
encrypt a value with AES-CBC-128
#define ROUND_UP_POW2(_num, _mul)
Round up - Only works if _mul is a power of 2 but avoids division.
#define ROUND_UP(_num, _mul)
Round up - Works in all cases, but is slower.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
static uint8_t depth(fr_minmax_heap_index_t i)
fr_pair_t * fr_pair_find_by_child_num_idx(fr_pair_list_t const *list, fr_dict_attr_t const *parent, unsigned int attr, unsigned int idx)
Find the pair with the matching child attribute at a given index.
int8_t fr_pair_cmp_by_parent_num(void const *a, void const *b)
Order attributes by their parent(s), attribute number, and tag.
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
static fr_internal_encode_ctx_t encode_ctx
uint32_t fr_rand(void)
Return a 32-bit random number.
static char buff[sizeof("18446744073709551615")+3]
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Entry point for pair encoders.
Master include file to access all functions and structures in the library.
static fr_pair_t * fr_pair_dcursor_child_iter_init(fr_dcursor_t *cursor, fr_pair_list_t const *list, fr_dcursor_t const *parent)
Initializes a child dcursor from a parent cursor, with an iteration function.
void fr_pair_list_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
#define FR_PROTO_STACK_PRINT(_stack, _depth)
uint8_t depth
Deepest attribute in the stack.
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Structure for holding the stack of dictionary attributes being encoded.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
#define FR_TYPE_STRUCTURAL
return fr_dbuff_set(dbuff, &our_dbuff)
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out