The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
encode.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * @file src/lib/eap_aka_sim/encode.c
19 * @brief Code common to EAP-SIM/AKA/AKA' clients and servers.
20 *
21 * @copyright 2017 FreeRADIUS server project
22 */
23
24RCSID("$Id: 5a9578f43179b8a96f7e5cae82a65f49f0aaee38 $")
25
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>
34
35#include <freeradius-devel/eap/types.h>
36#include "base.h"
37#include "attrs.h"
38#include "crypto_priv.h"
39
40#define SIM_MAX_ATTRIBUTE_VALUE_LEN ((255 * 4) - 2) /* max length field value less Type + Length fields */
41
42/*
43 * EAP-SIM/AKA/AKA' PACKET FORMAT
44 * ---------------- ------ ------
45 *
46 * EAP Request and Response Packet Format
47 * --- ------- --- -------- ------ ------
48 * 0 1 2 3
49 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 * | Code | Identifier | Length |
52 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 * | Type | AT-Type | AT-Length | value ... |
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 *
56 * With AT-Type/AT-Length/Value... repeating. Length is in units
57 * of 32 bits, and includes the Type/Length fields.
58 */
59
60static ssize_t encode_tlv(fr_dbuff_t *dbuff,
61 fr_da_stack_t *da_stack, unsigned int depth,
62 fr_dcursor_t *cursor, void *encode_ctx);
63
64/** Implements the iterator for EAP-AKA
65 *
66 * @param[in] cursor to iterate over.
67 * @param[in] current The fr_pair_t cursor->current. Will be advanced and checked to
68 * see if it matches the specified fr_dict_t.
69 * @param[in] uctx The fr_dict_t to search for.
70 * @return
71 * - Next matching fr_pair_t.
72 * - NULL if not more matching fr_pair_ts could be found.
73 */
74static void *fr_eap_aka_sim_next_encodable(fr_dcursor_t *cursor, void *current, UNUSED void *uctx)
75{
76 fr_pair_t *c = current;
77 fr_dict_t *dict = talloc_get_type_abort(uctx, fr_dict_t);
78
79 while ((c = fr_dlist_next(cursor->dlist, c))) {
80 PAIR_VERIFY(c);
81
82 /*
83 * Bool attribute presence is 'true' in SIM
84 * and absence is 'false'
85 */
86 if ((c->vp_type == FR_TYPE_BOOL) && (c->vp_bool == false)) continue;
87
88 if ((c->da->dict == dict) && (!c->da->flags.internal)) break;
89 }
90
91 return c;
92}
93
94/** Add an IV to a packet
95 *
96 @verbatim
97 0 1 2 3
98 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
99 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 | AT_IV | Length = 5 | Reserved |
101 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 | |
103 | Initialization Vector |
104 | |
105 | |
106 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107 @endverbatim
108 */
110{
111 fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
112 uint32_t iv[4];
113 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
114
115 /*
116 * One IV per packet
117 */
118 if (packet_ctx->have_iv) return 0;
119
120 /*
121 * Generate IV
122 */
123 iv[0] = fr_rand();
124 iv[1] = fr_rand();
125 iv[2] = fr_rand();
126 iv[3] = fr_rand();
127
128 memcpy(packet_ctx->iv, (uint8_t *)&iv[0], sizeof(packet_ctx->iv)); /* ensures alignment */
129
130 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_IV, (4 + AKA_SIM_IV_SIZE) >> 2, 0x00, 0x00);
131 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, packet_ctx->iv, sizeof(packet_ctx->iv));
132
133 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Initialisation vector");
134
135 packet_ctx->have_iv = true;
136
137 return fr_dbuff_set(dbuff, &work_dbuff);
138}
139
140/** encrypt a value with AES-CBC-128
141 *
142 * encrypts a value using AES-CBC-128, padding the value with AT_PADDING
143 * attributes until it matches the block length of the cipher (16).
144 *
145 * May also write out an AT_IV attribute if this is the first encrypted
146 * value being encoded.
147 @verbatim
148 1 2 3
149 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
150 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151 | AT_ENCR_DATA | Length | Reserved |
152 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153 | |
154 . Encrypted Data .
155 . .
156 | |
157 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
158 @endverbatim
159 */
161 uint8_t const *in, size_t inlen, void *encode_ctx)
162{
163 size_t total_len, pad_len, encr_len, len = 0;
164 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
165 uint8_t *encr = NULL;
166 fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
167 EVP_CIPHER_CTX *evp_ctx;
168 EVP_CIPHER const *evp_cipher = EVP_aes_128_cbc();
169 size_t block_size = EVP_CIPHER_block_size(evp_cipher);
170 ssize_t slen;
171 /*
172 * Needs to be a multiple of 4 else we can't
173 * pad with AT_PADDING correctly as its
174 * length is specified in multiples of 4.
175 */
176 if (unlikely(inlen % 4)) {
177 fr_strerror_printf("%s: Input data length is not a multiple of 4", __FUNCTION__);
179 }
180
181 total_len = (inlen + (block_size - 1)) & ~(block_size - 1); /* Round input length to block size (16) */
182 pad_len = (total_len - inlen); /* How much we need to pad */
183
184 /*
185 * Usually in and out will be the same buffer
186 */
187 if (unlikely(fr_dbuff_start(&work_dbuff) != in)) {
188 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, in, inlen);
189 } else {
191 fr_dbuff_advance(&work_dbuff, inlen);
192 }
193
194 /*
195 * Append an AT_PADDING attribute if required
196 */
197 if (pad_len != 0) {
198 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_PADDING, (uint8_t)(pad_len >> 2));
199 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len - 2);
200 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), pad_len, "Done padding attribute");
201 }
202
203 if (unlikely(!packet_ctx->k_encr)) {
204 fr_strerror_printf("%s: No k_encr set, cannot encrypt attributes", __FUNCTION__);
206 }
207
208 evp_ctx = aka_sim_crypto_cipher_ctx();
209 if (unlikely(EVP_EncryptInit_ex(evp_ctx, evp_cipher, NULL,
210 packet_ctx->k_encr, packet_ctx->iv) != 1)) {
211 fr_tls_strerror_printf("Failed initialising AES-128-ECB context");
212 error:
213 talloc_free(encr);
215 }
216
217 encr = talloc_array(NULL, uint8_t, total_len);
218 if (!encr) {
219 fr_strerror_printf("%s: Failed allocating temporary buffer", __FUNCTION__);
220 goto error;
221 }
222
223 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), total_len, "plaintext");
224
225 /*
226 * By default OpenSSL expects 16 bytes of plaintext
227 * to produce 32 bytes of ciphertext, due to padding
228 * being added if the plaintext is a multiple of 16.
229 *
230 * There's no way for OpenSSL to determine if a
231 * 16 byte encr was padded or not, so we need to
232 * inform OpenSSL explicitly that there's no padding.
233 */
234 EVP_CIPHER_CTX_set_padding(evp_ctx, 0);
235 if (unlikely(EVP_EncryptUpdate(evp_ctx, encr, (int *)&len, fr_dbuff_start(&work_dbuff), total_len) != 1)) {
236 fr_tls_strerror_printf("%s: Failed encrypting attribute", __FUNCTION__);
237 goto error;
238 }
239 encr_len = len;
240
241 if (unlikely(EVP_EncryptFinal_ex(evp_ctx, encr + encr_len, (int *)&len) != 1)) {
242 fr_tls_strerror_printf("%s: Failed finalising encrypted attribute", __FUNCTION__);
243 goto error;
244 }
245 encr_len += len;
246
247 /*
248 * Ciphertext should be same length as plaintext.
249 */
250 if (unlikely(encr_len != total_len)) {
251 fr_strerror_printf("%s: Invalid plaintext length, expected %zu, got %zu",
252 __FUNCTION__, total_len, encr_len);
253 goto error;
254 }
255
256 FR_PROTO_HEX_DUMP(encr, encr_len, "ciphertext");
257
258 /*
259 * Overwrite the plaintext with our encrypted blob
260 */
261 fr_dbuff_set_to_start(&work_dbuff);
262
263 slen = fr_dbuff_in_memcpy(&work_dbuff, encr, encr_len);
264 talloc_free(encr);
265 if (slen <= 0) return slen;
266
267 return fr_dbuff_set(dbuff, &work_dbuff);
268}
269
270/** Encodes the data portion of an attribute
271 *
272 * @return
273 * > 0, Length of the data portion.
274 * = 0, we could not encode anything, skip this attribute (and don't encode the header)
275 * < 0, failure.
276 */
278 fr_da_stack_t *da_stack, int depth,
279 fr_dcursor_t *cursor, void *encode_ctx)
280{
281 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
282 fr_pair_t const *vp = fr_dcursor_current(cursor);
283 fr_dict_attr_t const *da = da_stack->da[depth];
284 fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
285
287 FR_PROTO_STACK_PRINT(da_stack, depth);
288
289 if (unlikely(da_stack->da[depth + 1] != NULL)) {
290 fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
292 }
293
294 if (unlikely(vp->da != da)) {
295 fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
297 }
298
299 switch (vp->vp_type) {
301 fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
302 fr_type_to_str(da_stack->da[depth]->type));
304
305 default:
306 break;
307 }
308
309 switch (da->attr) {
310 /*
311 * Allow manual override of IV - Mostly for testing or debugging
312 *
313 * 0 1 2 3
314 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
315 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316 * | AT_IV | Length = 5 | Reserved |
317 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318 * | |
319 * | Initialization Vector |
320 * | |
321 * | |
322 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
323 */
324 case FR_IV:
325 if ((vp->da->flags.length && (da->flags.length != vp->vp_length)) ||
326 (vp->vp_length != sizeof(packet_ctx->iv))) {
327 fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
328 "but value was %zu bytes", __FUNCTION__,
329 da->name, (size_t)da->flags.length, vp->vp_length);
331 }
332 memcpy(packet_ctx->iv, vp->vp_octets, sizeof(packet_ctx->iv));
333 packet_ctx->have_iv = true;
334 break; /* Encode IV */
335
336 /*
337 * AT_RES - Special case (RES length is in bits)
338 *
339 * 0 1 2 3
340 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
341 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
342 * | AT_RES | Length | RES Length |
343 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
344 * | |
345 * | RES |
346 * | |
347 * | |
348 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
349 */
350 case FR_RES:
351 if ((vp->vp_length < 4) || (vp->vp_length > 16)) {
352 fr_strerror_printf("%s: AKA-RES Length must be between 4-16 bytes, got %zu bytes",
353 __FUNCTION__, vp->vp_length);
355 }
356
357 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)(vp->vp_length * 8)); /* RES Length (bits, big endian) */
358 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, vp->vp_length);
359 goto done;
360
361 /*
362 * AT_CHECKCODE - Special case (Variable length with no length field)
363 *
364 * 0 1 2 3
365 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
366 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367 * | AT_CHECKCODE | Length | Reserved |
368 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
369 * | |
370 * | Checkcode (0 or 20 bytes) |
371 * | |
372 * | |
373 * | |
374 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
375 */
376 case FR_CHECKCODE:
377 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00); /* Reserved */
378 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, vp->vp_length);
379 goto done;
380
381 default:
382 break;
383 }
384
385 switch (vp->vp_type) {
386 /*
387 * In order to represent the string length properly we include a second
388 * 16bit length field with the real string length.
389 *
390 * The end of the string is padded buff to a multiple of 4.
391 *
392 * 0 1 2 3
393 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
394 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
395 * | AT_<STRING> | Length | Actual <STRING> Length |
396 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 * | |
398 * . String .
399 * . .
400 * | |
401 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
402 */
403 case FR_TYPE_STRING:
404 if (vp->da->flags.length && (vp->vp_length != vp->da->flags.length)) {
405 fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
406 "but value was %zu bytes", __FUNCTION__,
407 vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
409 }
410
411 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)vp->vp_length); /* Big endian real string length */
412 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)vp->vp_strvalue, vp->vp_length);
413 break;
414
415 case FR_TYPE_OCTETS:
416 /*
417 * Fixed length attribute
418 */
419 if (vp->da->flags.length) {
420 size_t prefix = fr_aka_sim_octets_prefix_len(vp->da);
421 size_t pad_len;
422 size_t value_len_rounded;
423
424 if (vp->vp_length > vp->da->flags.length) {
425 fr_strerror_printf("%s: Attribute \"%s\" needs a value of <= %zu bytes, "
426 "but value was %zu bytes", __FUNCTION__,
427 vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
429 }
430
431 /*
432 * Calculate value padding (autopad)
433 */
434 value_len_rounded = ROUND_UP(vp->vp_length, (size_t)vp->da->flags.length);
435 /*
436 * Zero out reserved bytes
437 */
438 if (prefix) FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, prefix);
439
440 /*
441 * Copy in value
442 */
443 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, vp->vp_length);
444
445 /*
446 * Pad out the value
447 */
448 pad_len = value_len_rounded - vp->vp_length;
449 if (pad_len) FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len);
450 /*
451 * Variable length attribute
452 */
453 } else {
454 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)vp->vp_length); /* Big endian real string length */
455 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)vp->vp_strvalue, vp->vp_length);
456 }
457 break;
458
459 /*
460 * In SIM/AKA/AKA' we represent truth values
461 * by either including or not including the attribute
462 * in the packet.
463 *
464 * 0 1 2 3
465 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
466 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
467 * | AT_<BOOL> | Length = 1 | Reserved |
468 * +---------------+---------------+-------------------------------+
469 */
470 case FR_TYPE_BOOL:
471 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00); /* reserved bytes */
472 break;
473
474 /*
475 * Numbers are network byte order.
476 *
477 * In the base RFCs only short (16bit) unsigned integers are used.
478 * We add support for more, just for completeness.
479 *
480 * 0 1 2 3
481 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
482 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
483 * | AT_<SHORT> | Length = 1 | Short 1 | Short 2 |
484 * +---------------+---------------+-------------------------------+
485 */
486 default:
487 {
488 ssize_t len = fr_value_box_to_network(&work_dbuff, &vp->data);
489 if (len < 0) return len;
490 break;
491 }
492 }
493done:
494 /*
495 * Rebuilds the TLV stack for encoding the next attribute
496 */
497 vp = fr_dcursor_next(cursor);
498 fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
499
500 return fr_dbuff_set(dbuff, &work_dbuff);
501}
502
503/** Encodes the data portion of an attribute
504 *
505 @verbatim
506 0 1 2 3
507 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
508 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
509 | AT_VERSION_L..| Length | Actual Version List Length |
510 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
511 | Supported Version 1 | Supported Version 2 |
512 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513 . .
514 . .
515 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516 | Supported Version N | Padding |
517 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518 @endverbatim
519 *
520 */
522 fr_da_stack_t *da_stack, int depth,
523 fr_dcursor_t *cursor, void *encode_ctx)
524{
525 size_t pad_len;
526 size_t element_len;
527 size_t actual_len;
528 fr_dbuff_t len_dbuff = FR_DBUFF(dbuff);
529 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
530 fr_dict_attr_t const *da = da_stack->da[depth];
531 fr_assert(da->flags.array);
532
533 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 2);
534 fr_dbuff_advance(&work_dbuff, 2);
535
536 if (unlikely(da->type == FR_TYPE_OCTETS)) {
537 if (!da->flags.length) {
538 fr_strerror_printf("Can't encode array type attribute \"%s\" as it does not "
539 "have a fixed length", da->name);
541 }
542 element_len = da->flags.length;
543 } else {
544 element_len = fr_aka_sim_attr_sizes[da->type][0];
545 }
546
547 /*
548 * Keep encoding as long as we have space to
549 * encode things.
550 */
551 while (fr_dbuff_extend_lowat(NULL, &work_dbuff, element_len) >= element_len) {
552 fr_pair_t *vp;
553 ssize_t slen;
554
555 slen = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx);
556 if (slen == PAIR_ENCODE_FATAL_ERROR) return slen;
557 if (slen < 0) break;
558
559 vp = fr_dcursor_current(cursor);
560 if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */
561 }
562
563 actual_len = fr_dbuff_used(&work_dbuff) - 2; /* Length of the elements we encoded */
564 /*
565 * Arrays with an element size which is
566 * a multiple of 4 don't need an
567 * actual_length field, because the number
568 * of elements can be calculated from
569 * the attribute length.
570 */
571 if (element_len % 4) {
572 FR_DBUFF_IN_RETURN(&len_dbuff, (uint16_t) actual_len);
573 } else {
574 FR_DBUFF_IN_RETURN(&len_dbuff, (uint16_t) 0);
575 }
576
577 /*
578 * Pad value to multiple of 4
579 */
580 pad_len = ROUND_UP_POW2(actual_len, 4) - actual_len;
581 if (pad_len) FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len);
582
583 return fr_dbuff_set(dbuff, &work_dbuff);
584}
585
586/** Encode an RFC format attribute header
587 *
588 * This could be a standard attribute, or a TLV data type.
589 * If it's a standard attribute, then vp->da->attr == attribute.
590 * Otherwise, attribute may be something else.
591 */
592static ssize_t encode_rfc(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth,
593 fr_dcursor_t *cursor, void *encode_ctx)
594{
595 size_t pad_len;
596 fr_dict_attr_t const *da;
597 ssize_t slen;
598 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
599 fr_dbuff_t hdr_dbuff = FR_DBUFF(dbuff);
600
601 FR_PROTO_STACK_PRINT(da_stack, depth);
602
603 switch (da_stack->da[depth]->type) {
605 fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
606 fr_type_to_str(da_stack->da[depth]->type));
608
609 default:
610 if (((fr_dict_vendor_num_by_da(da_stack->da[depth]) == 0) && (da_stack->da[depth]->attr == 0)) ||
611 (da_stack->da[depth]->attr > 255)) {
612 fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__,
613 da_stack->da[depth]->attr);
615 }
616 break;
617 }
618
619 /*
620 * Write out the value to a buffer location
621 * past the AT and Length fields.
622 *
623 * Encode value will set reserved bytes to
624 * zero and fill any subfields like actual
625 * length.
626 */
627 da = da_stack->da[depth];
628
629 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 2);
630 fr_dbuff_advance(&work_dbuff, 2);
631
632 if (da->flags.array) {
634 da_stack, depth, cursor, encode_ctx);
635 } else {
637 da_stack, depth, cursor, encode_ctx);
638 }
639 if (slen <= 0) return slen;
640
641 /*
642 * Pad value to multiple of 4
643 */
644 pad_len = ROUND_UP_POW2(fr_dbuff_used(&work_dbuff), 4) - fr_dbuff_used(&work_dbuff);
645 if (pad_len) {
646 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len);
647 }
648
649 FR_DBUFF_IN_BYTES_RETURN(&hdr_dbuff, (uint8_t)da->attr,
650 (uint8_t)(fr_dbuff_used(&work_dbuff) >> 2));
651
652 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done RFC attribute");
653
654 return fr_dbuff_set(dbuff, &work_dbuff); /* AT + Length + Data */
655}
656
658 fr_da_stack_t *da_stack, unsigned int depth,
659 fr_dcursor_t *cursor, void *encode_ctx)
660{
661 ssize_t slen;
663 fr_dbuff_t value_dbuff;
664 fr_dbuff_marker_t value_start;
665 fr_pair_t const *vp = fr_dcursor_current(cursor);
666 fr_dict_attr_t const *da = da_stack->da[depth];
667
668 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00);
669
670 value_dbuff = FR_DBUFF(&work_dbuff);
671 fr_dbuff_marker(&value_start, &value_dbuff);
672
673 for (;;) {
674 FR_PROTO_STACK_PRINT(da_stack, depth);
675
676 /*
677 * This attribute carries sub-TLVs. The sub-TLVs
678 * can only carry SIM_MAX_ATTRIBUTE_VALUE_LEN bytes of data.
679 */
680
681 /*
682 * Determine the nested type and call the appropriate encoder
683 */
684 if (da_stack->da[depth + 1]->type == FR_TYPE_TLV) {
685 slen = encode_tlv(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
686 } else {
687 slen = encode_rfc(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
688 }
689
690 if (slen <= 0) {
691 return slen;
692 }
693
694 /*
695 * If nothing updated the attribute, stop
696 */
697 if (!fr_dcursor_current(cursor) || (vp == fr_dcursor_current(cursor))) {
698 break;
699 }
700
701 /*
702 * We can encode multiple sub TLVs, if after
703 * rebuilding the TLV Stack, the attribute
704 * at this depth is the same.
705 */
706 if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) {
707 break;
708 }
709 vp = fr_dcursor_current(cursor);
710 }
711
712 /*
713 * encrypt the contents of the TLV using AES-CBC-128
714 * or another encryption algorithm.
715 */
717 ssize_t value_len = fr_dbuff_used(&work_dbuff) - 2;
718
719 slen = encode_encrypted_value(&value_dbuff, fr_dbuff_current(&value_start),
720 value_len, encode_ctx);
721 if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
722
723#ifdef __COVERITY__
724 /*
725 * Coverity as it stands doesn't see that value_len >= 0 because
726 * work_dbuff has at least the two zero bytes in it, and thus thinks
727 * (size_t) slen - value_len will be some huge size_t value. This
728 * check should pacify it.
729 */
730 if (value_len < 0) return -1;
731#endif
732 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, (size_t)slen - value_len);
733 fr_dbuff_advance(&work_dbuff, (size_t)slen - value_len);
734 }
735
736 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV");
737
738 return fr_dbuff_set(dbuff, &work_dbuff);
739}
740
742 fr_da_stack_t *da_stack, unsigned int depth,
743 fr_dcursor_t *cursor, void *encode_ctx)
744{
745 unsigned int total_len;
746 ssize_t len;
747 fr_dict_attr_t const *da;
748 fr_dbuff_t tl_dbuff;
749 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
750 fr_dcursor_t *my_cursor = cursor;
751 fr_dcursor_t child_cursor;
752
754 FR_PROTO_STACK_PRINT(da_stack, depth);
755
756 if (da_stack->da[depth]->type != FR_TYPE_TLV) {
757 fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
758 fr_type_to_str(da_stack->da[depth]->type));
760 }
761
762 if (!da_stack->da[depth + 1]) {
763 fr_pair_t *vp;
764
765 vp = fr_dcursor_current(cursor);
766 if ((vp->vp_type != FR_TYPE_TLV) || (fr_pair_list_num_elements(&vp->vp_group) == 0)) {
767 fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
769 }
770
771 fr_assert(vp->da == da_stack->da[depth]);
772
773 vp = fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
774 my_cursor = &child_cursor;
775
776 fr_proto_da_stack_build(da_stack, vp->da);
777 }
778
779 /*
780 * Add the IV before the TLV
781 * The ASCII art in the RFCs the attributes in
782 * this order.
783 */
784 if (fr_aka_sim_flag_encrypted(da_stack->da[depth])) {
785 len = encode_iv(&work_dbuff, encode_ctx);
786 if (len < 0) return len;
787 }
788 tl_dbuff = FR_DBUFF(&work_dbuff);
789
790 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 2);
791 fr_dbuff_advance(&work_dbuff, 2);
792
793 da = da_stack->da[depth];
795 da_stack, depth, my_cursor, encode_ctx);
796 if (len <= 0) return len;
797
798 if (my_cursor != cursor) fr_dcursor_next(cursor);
799
800 /*
801 * Round attr + len + data length out to a multiple
802 * of four, and setup the attribute header and
803 * length field in the buffer.
804 */
805 total_len = ROUND_UP_POW2(len + 2, 4);
806 FR_DBUFF_IN_BYTES_RETURN(&tl_dbuff, (uint8_t)da->attr, (uint8_t)(total_len >> 2));
807
808 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV attribute");
809
810 return fr_dbuff_set(dbuff, &work_dbuff); /* AT_IV + AT_*(TLV) - Can't use total_len, doesn't include IV */
811}
812
814{
815 fr_pair_t const *vp;
816 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
818 ssize_t slen;
819
820 fr_da_stack_t da_stack;
821
822 fr_dbuff_marker(&m, &work_dbuff);
823 if (!cursor) return PAIR_ENCODE_FATAL_ERROR;
824
825 vp = fr_dcursor_current(cursor);
826 if (!vp) return 0;
827
829
830 if (vp->da->depth > FR_DICT_MAX_TLV_STACK) {
831 fr_strerror_printf("%s: Attribute depth %u exceeds maximum nesting depth %d",
832 __FUNCTION__, vp->da->depth, FR_DICT_MAX_TLV_STACK);
834 }
835
836 if (vp->da->attr == FR_MAC) {
837 fr_dcursor_next(cursor);
838 return 0;
839 }
840 /*
841 * Nested structures of attributes can't be longer than
842 * 4 * 255 bytes, so each call to an encode function can
843 * only use 4 * 255 bytes of buffer space at a time.
844 */
845
846 /*
847 * Do more work to set up the stack for the complex case.
848 */
849 fr_proto_da_stack_build(&da_stack, vp->da);
850 FR_PROTO_STACK_PRINT(&da_stack, 0);
851
852 if (da_stack.da[0]->type == FR_TYPE_TLV) {
854 &da_stack, 0, cursor, encode_ctx);
855 } else {
857 &da_stack, 0, cursor, encode_ctx);
858 }
859 if (slen < 0) return slen;
860
861 /*
862 * We couldn't do it, so we didn't do anything.
863 */
864 if (fr_dcursor_current(cursor) == vp) {
865 fr_strerror_printf("%s: Nested attribute structure too large to encode", __FUNCTION__);
867 }
868
869 return fr_dbuff_set(dbuff, &work_dbuff);
870}
871
873{
874 fr_pair_t *vp;
875
876 uint8_t *buff;
877 ssize_t slen;
878 fr_dbuff_t dbuff;
880 fr_dbuff_uctx_talloc_t tctx;
881
882 bool do_hmac = false;
883
884 unsigned char subtype;
885 fr_dcursor_t cursor;
886 fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
887 eap_packet_t *eap_packet = packet_ctx->eap_packet;
888
889 /*
890 * Encoded_msg is now an EAP-SIM message.
891 * It might be too big for putting into an
892 * EAP packet.
893 */
895 if (!vp) {
896 REDEBUG("Missing subtype attribute");
898 }
899 subtype = vp->vp_uint16;
900
901 /*
902 * Group attributes with similar lineages together
903 */
906 fr_dcursor_next(&cursor); /* Skip subtype if it came out first */
907 }
908
909 /*
910 * Will we need to generate a HMAC?
911 */
912 if (fr_pair_find_by_child_num_idx(to_encode, fr_dict_root(dict_eap_aka_sim), FR_MAC, 0)) do_hmac = true;
913
914 /*
915 * Fast path, we just need to encode a subtype
916 */
917 if (!do_hmac && !fr_dcursor_current(&cursor)) {
918 MEM(buff = talloc_array(eap_packet, uint8_t, 3));
919
920 buff[0] = subtype; /* SIM or AKA subtype */
921 buff[1] = 0; /* Reserved (0) */
922 buff[2] = 0; /* Reserved (1) */
923
924 eap_packet->type.length = 3;
925 eap_packet->type.data = buff;
926
927 FR_PROTO_HEX_DUMP(buff, eap_packet->type.length, "sim packet");
928
929 return 0;
930 }
931 fr_dcursor_head(&cursor); /* Reset */
932
933 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, 1024);
934
935 FR_DBUFF_IN_BYTES_RETURN(&dbuff, subtype, 0x00, 0x00);
936
937 /*
938 * Add space in the packet for AT_MAC
939 */
940 if (do_hmac) {
941 FR_DBUFF_IN_BYTES_RETURN(&dbuff, FR_MAC, AKA_SIM_MAC_SIZE >> 2, 0x00, 0x00);
942 fr_dbuff_marker(&hmac, &dbuff);
943 FR_DBUFF_MEMSET_RETURN(&dbuff, 0, 16);
944 }
945
946 /*
947 * Encode all the things...
948 */
949 (void)fr_dcursor_head(&cursor);
950 while (fr_dcursor_current(&cursor)) {
951 slen = fr_aka_sim_encode_pair(&dbuff, &cursor, packet_ctx);
952 if (slen < 0) {
953 error:
954 talloc_free(fr_dbuff_buff(&dbuff));
956 }
957 fr_assert(fr_dbuff_used(&dbuff) > 0); /* We messed up a check somewhere in the encoder */
958 }
959
960 eap_packet->type.length = fr_dbuff_used(&dbuff);
961 eap_packet->type.data = fr_dbuff_buff(&dbuff);
962
963 /*
964 * Calculate a SHA1-HMAC over the complete EAP packet
965 */
966 if (do_hmac) {
967 slen = fr_aka_sim_crypto_sign_packet(fr_dbuff_current(&hmac), eap_packet, false,
968 packet_ctx->hmac_md,
969 packet_ctx->k_aut, packet_ctx->k_aut_len,
970 packet_ctx->hmac_extra, packet_ctx->hmac_extra_len);
971 if (slen < 0) goto error;
972 FR_PROTO_HEX_DUMP(fr_dbuff_current(&hmac) - 4, AKA_SIM_MAC_SIZE, "hmac attribute");
973 }
974 FR_PROTO_HEX_DUMP(eap_packet->type.data, eap_packet->type.length, "sim packet");
975
976 /*
977 * Shrink buffer to the correct size
978 */
979 if (eap_packet->type.length != talloc_array_length(eap_packet->type.data)) {
980 uint8_t *realloced;
981
982 realloced = talloc_realloc(eap_packet, eap_packet->type.data, uint8_t, eap_packet->type.length);
983 if (!realloced) goto error;
984
985 eap_packet->type.data = realloced;
986 }
987
988 return fr_dbuff_used(&dbuff);
989}
990
991/*
992 * Test ctx data
993 */
995{
997
998 return 0;
999}
1000
1001static fr_aka_sim_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
1002{
1003 fr_aka_sim_ctx_t *test_ctx;
1004
1005 test_ctx = talloc_zero(ctx, fr_aka_sim_ctx_t);
1006 test_ctx->k_encr = talloc_memdup(test_ctx, k_encr, k_encr_len);
1007 test_ctx->k_aut = talloc_zero_array(test_ctx, uint8_t, 16);
1008 test_ctx->k_aut_len = 16;
1009
1010 talloc_set_destructor(test_ctx, _test_ctx_free);
1011
1012 if (fr_aka_sim_init() < 0) {
1013 talloc_free(test_ctx);
1014 return NULL;
1015 }
1016
1017 return test_ctx;
1018}
1019
1020/*
1021 * Test ctx data
1022 */
1023static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
1024{
1025 fr_aka_sim_ctx_t *test_ctx;
1026 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1027 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1028
1029 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1030 if (!test_ctx) return -1;
1031
1032 test_ctx->have_iv = true; /* Ensures IV is all zeros */
1033
1034 *out = test_ctx;
1035
1036 return 0;
1037}
1038
1039static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
1040{
1041 fr_aka_sim_ctx_t *test_ctx;
1042 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1043 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1044
1045 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1046 if (!test_ctx) return -1;
1047
1048 test_ctx->have_iv = true; /* Ensures IV is all zeros */
1049
1050 *out = test_ctx;
1051
1052 return 0;
1053}
1054
1055static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
1056{
1057 fr_aka_sim_ctx_t *test_ctx;
1058 static uint8_t k_encr[] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a,
1059 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 };
1060
1061 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1062 if (!test_ctx) return -1;
1063
1064 *out = test_ctx;
1065
1066 return 0;
1067}
1068
1069/*
1070 * Test points
1071 */
1078
1085
#define RCSID(id)
Definition build.h:485
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
eap_type_data_t type
Definition compose.h:39
Structure to hold EAP data.
Definition compose.h:35
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.
Definition dbuff.h:1072
#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...
Definition dbuff.h:767
#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.
Definition dbuff.h:673
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:81
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:911
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1004
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:898
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
Definition dbuff.h:1155
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition dbuff.h:882
#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.
Definition dbuff.h:1508
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:660
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.
Definition dbuff.h:1192
#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.
Definition dbuff.h:1382
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1350
#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.
Definition dbuff.h:1585
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:222
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
Definition dbuff.h:301
#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.
Definition dbuff.h:318
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.
Definition dbuff.h:411
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1472
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
Definition dcursor.h:234
fr_dlist_head_t * dlist
Head of the doubly linked list being iterated over.
Definition dcursor.h:94
#define MEM(x)
Definition debug.h:36
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2403
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:499
static fr_slen_t in
Definition dict.h:840
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
Definition dict_ext.h:212
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:555
size_t length
Definition types.h:111
uint8_t * data
Definition types.h:112
size_t hmac_extra_len
Definition base.h:244
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.
Definition crypto.c:284
#define AKA_SIM_IV_SIZE
Length of the IV used when processing AT_ENCR.
Definition base.h:41
bool have_iv
Whether we found the IV already.
Definition base.h:236
#define AKA_SIM_MAC_SIZE
Length of MAC used to prevent packet modification.
Definition base.h:43
uint8_t const * k_aut
The authentication key used for signing.
Definition base.h:249
EVP_MD const * hmac_md
HMAC digest algorithm, usually EVP_sha1().
Definition base.h:240
eap_packet_t * eap_packet
Needed for validating AT_MAC.
Definition base.h:238
uint8_t const * k_encr
The encryption key used for encrypting.
Definition base.h:246
uint8_t const * hmac_extra
Extra data for the HMAC function.
Definition base.h:243
uint8_t iv[AKA_SIM_IV_SIZE]
From the current packet.
Definition base.h:235
size_t k_aut_len
Definition base.h:250
#define fr_aka_sim_flag_encrypted(_da)
Definition base.h:270
Encoder/decoder ctx.
Definition base.h:234
EVP_CIPHER_CTX * aka_sim_crypto_cipher_ctx(void)
Allocate and reset a resumable EVP_CIPHER_CTX for each thread.
Definition crypto.c:70
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
Definition pair.h:36
fr_dict_t const * dict_eap_aka_sim
Definition base.c:48
void fr_aka_sim_free(void)
Definition base.c:315
int fr_aka_sim_init(void)
Definition base.c:284
size_t fr_aka_sim_octets_prefix_len(fr_dict_attr_t const *da)
Return the number of bytes before the octets value.
Definition base.c:276
size_t const fr_aka_sim_attr_sizes[FR_TYPE_MAX+1][2]
SIM AT on-the-wire format attribute sizes.
Definition base.c:210
#define SIM_MAX_ATTRIBUTE_VALUE_LEN
Definition encode.c:40
fr_test_point_pair_encode_t sim_tp_encode
Definition encode.c:1073
ssize_t fr_aka_sim_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Definition encode.c:813
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.
Definition encode.c:521
fr_test_point_pair_encode_t sim_tp_encode_rfc4186
Definition encode.c:1087
static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
Definition encode.c:1039
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.
Definition encode.c:277
static ssize_t encode_iv(fr_dbuff_t *dbuff, void *encode_ctx)
Add an IV to a packet.
Definition encode.c:109
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)
Definition encode.c:657
fr_test_point_pair_encode_t aka_tp_encode
Definition encode.c:1080
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)
Definition encode.c:741
static void * fr_eap_aka_sim_next_encodable(fr_dcursor_t *cursor, void *current, UNUSED void *uctx)
Implements the iterator for EAP-AKA.
Definition encode.c:74
ssize_t fr_aka_sim_encode(request_t *request, fr_pair_list_t *to_encode, void *encode_ctx)
Definition encode.c:872
static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
Definition encode.c:1055
static fr_aka_sim_ctx_t * test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
Definition encode.c:1001
static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
Definition encode.c:1023
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.
Definition encode.c:592
static int _test_ctx_free(UNUSED fr_aka_sim_ctx_t *ctx)
Definition encode.c:994
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
Definition encode.c:160
talloc_free(reap)
#define ROUND_UP_POW2(_num, _mul)
Round up - Only works if _mul is a power of 2 but avoids division.
Definition math.h:144
#define ROUND_UP(_num, _mul)
Round up - Works in all cases, but is slower.
Definition math.h:148
unsigned short uint16_t
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
int8_t fr_pair_cmp_by_parent_num(void const *a, void const *b)
Order attributes by their parent(s), attribute number, and tag.
Definition pair.c:1918
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.
Definition pair.c:897
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.
Definition proto.c:118
static fr_internal_encode_ctx_t encode_ctx
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
static rc_request_t * current
static bool done
Definition radclient.c:81
#define REDEBUG(fmt,...)
Definition radclient.h:52
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:93
Entry point for pair encoders.
Definition test_point.h:92
Master include file to access all functions and structures in the library.
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:567
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.
Definition pair.h:605
#define PAIR_VERIFY(_x)
Definition pair.h:191
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.
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,...)
Definition proto.h:42
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition proto.h:44
uint8_t depth
Deepest attribute in the stack.
Definition proto.h:56
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:57
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:55
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define FR_TYPE_STRUCTURAL
Definition types.h:312
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:450
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.
Definition value.c:1450
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1020
static size_t char ** out
Definition value.h:1020