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: 428f929758ea6842572001356568e78a2eb0345c $")
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;
164 int len = 0;
165 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
166 uint8_t *encr = NULL;
167 fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
168 EVP_CIPHER_CTX *evp_ctx;
169 EVP_CIPHER const *evp_cipher = EVP_aes_128_cbc();
170 size_t block_size = EVP_CIPHER_block_size(evp_cipher);
171 ssize_t slen;
172 /*
173 * Needs to be a multiple of 4 else we can't
174 * pad with AT_PADDING correctly as its
175 * length is specified in multiples of 4.
176 */
177 if (unlikely(inlen % 4)) {
178 fr_strerror_printf("%s: Input data length is not a multiple of 4", __FUNCTION__);
180 }
181
182 total_len = (inlen + (block_size - 1)) & ~(block_size - 1); /* Round input length to block size (16) */
183 pad_len = (total_len - inlen); /* How much we need to pad */
184
185 /*
186 * Usually in and out will be the same buffer
187 */
188 if (unlikely(fr_dbuff_start(&work_dbuff) != in)) {
189 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, in, inlen);
190 } else {
192 fr_dbuff_advance(&work_dbuff, inlen);
193 }
194
195 /*
196 * Append an AT_PADDING attribute if required
197 */
198 if (pad_len != 0) {
199 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_PADDING, (uint8_t)(pad_len >> 2));
200 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len - 2);
201 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), pad_len, "Done padding attribute");
202 }
203
204 if (unlikely(!packet_ctx->k_encr)) {
205 fr_strerror_printf("%s: No k_encr set, cannot encrypt attributes", __FUNCTION__);
207 }
208
209 evp_ctx = aka_sim_crypto_cipher_ctx();
210 if (unlikely(EVP_EncryptInit_ex(evp_ctx, evp_cipher, NULL,
211 packet_ctx->k_encr, packet_ctx->iv) != 1)) {
212 fr_tls_strerror_printf("Failed initialising AES-128-ECB context");
213 error:
214 talloc_free(encr);
216 }
217
218 encr = talloc_array(NULL, uint8_t, total_len);
219 if (!encr) {
220 fr_strerror_printf("%s: Failed allocating temporary buffer", __FUNCTION__);
221 goto error;
222 }
223
224 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), total_len, "plaintext");
225
226 /*
227 * By default OpenSSL expects 16 bytes of plaintext
228 * to produce 32 bytes of ciphertext, due to padding
229 * being added if the plaintext is a multiple of 16.
230 *
231 * There's no way for OpenSSL to determine if a
232 * 16 byte encr was padded or not, so we need to
233 * inform OpenSSL explicitly that there's no padding.
234 */
235 EVP_CIPHER_CTX_set_padding(evp_ctx, 0);
236 if (unlikely(EVP_EncryptUpdate(evp_ctx, encr, &len, fr_dbuff_start(&work_dbuff), total_len) != 1)) {
237 fr_tls_strerror_printf("%s: Failed encrypting attribute", __FUNCTION__);
238 goto error;
239 }
240 encr_len = len;
241
242 if (unlikely(EVP_EncryptFinal_ex(evp_ctx, encr + encr_len, &len) != 1)) {
243 fr_tls_strerror_printf("%s: Failed finalising encrypted attribute", __FUNCTION__);
244 goto error;
245 }
246 encr_len += len;
247
248 /*
249 * Ciphertext should be same length as plaintext.
250 */
251 if (unlikely(encr_len != total_len)) {
252 fr_strerror_printf("%s: Invalid plaintext length, expected %zu, got %zu",
253 __FUNCTION__, total_len, encr_len);
254 goto error;
255 }
256
257 FR_PROTO_HEX_DUMP(encr, encr_len, "ciphertext");
258
259 /*
260 * Overwrite the plaintext with our encrypted blob
261 */
262 fr_dbuff_set_to_start(&work_dbuff);
263
264 slen = fr_dbuff_in_memcpy(&work_dbuff, encr, encr_len);
265 talloc_free(encr);
266 if (slen <= 0) return slen;
267
268 return fr_dbuff_set(dbuff, &work_dbuff);
269}
270
271/** Encodes the data portion of an attribute
272 *
273 * @return
274 * > 0, Length of the data portion.
275 * = 0, we could not encode anything, skip this attribute (and don't encode the header)
276 * < 0, failure.
277 */
279 fr_da_stack_t *da_stack, int depth,
280 fr_dcursor_t *cursor, void *encode_ctx)
281{
282 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
283 fr_pair_t const *vp = fr_dcursor_current(cursor);
284 fr_dict_attr_t const *da = da_stack->da[depth];
285 fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
286
288 FR_PROTO_STACK_PRINT(da_stack, depth);
289
290 if (unlikely(da_stack->da[depth + 1] != NULL)) {
291 fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
293 }
294
295 if (unlikely(vp->da != da)) {
296 fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
298 }
299
300 switch (vp->vp_type) {
302 fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
303 fr_type_to_str(da_stack->da[depth]->type));
305
306 default:
307 break;
308 }
309
310 switch (da->attr) {
311 /*
312 * Allow manual override of IV - Mostly for testing or debugging
313 *
314 * 0 1 2 3
315 * 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
316 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
317 * | AT_IV | Length = 5 | Reserved |
318 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
319 * | |
320 * | Initialization Vector |
321 * | |
322 * | |
323 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 */
325 case FR_IV:
326 if ((vp->da->flags.length && (da->flags.length != vp->vp_length)) ||
327 (vp->vp_length != sizeof(packet_ctx->iv))) {
328 fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
329 "but value was %zu bytes", __FUNCTION__,
330 da->name, (size_t)da->flags.length, vp->vp_length);
332 }
333 memcpy(packet_ctx->iv, vp->vp_octets, sizeof(packet_ctx->iv));
334 packet_ctx->have_iv = true;
335 break; /* Encode IV */
336
337 /*
338 * AT_RES - Special case (RES length is in bits)
339 *
340 * 0 1 2 3
341 * 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
342 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
343 * | AT_RES | Length | RES Length |
344 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
345 * | |
346 * | RES |
347 * | |
348 * | |
349 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
350 */
351 case FR_RES:
352 if ((vp->vp_length < 4) || (vp->vp_length > 16)) {
353 fr_strerror_printf("%s: AKA-RES Length must be between 4-16 bytes, got %zu bytes",
354 __FUNCTION__, vp->vp_length);
356 }
357
358 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)(vp->vp_length * 8)); /* RES Length (bits, big endian) */
359 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, vp->vp_length);
360 goto done;
361
362 /*
363 * AT_CHECKCODE - Special case (Variable length with no length field)
364 *
365 * 0 1 2 3
366 * 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
367 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368 * | AT_CHECKCODE | Length | Reserved |
369 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370 * | |
371 * | Checkcode (0 or 20 bytes) |
372 * | |
373 * | |
374 * | |
375 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376 */
377 case FR_CHECKCODE:
378 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00); /* Reserved */
379 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, vp->vp_length);
380 goto done;
381
382 default:
383 break;
384 }
385
386 switch (vp->vp_type) {
387 /*
388 * In order to represent the string length properly we include a second
389 * 16bit length field with the real string length.
390 *
391 * The end of the string is padded buff to a multiple of 4.
392 *
393 * 0 1 2 3
394 * 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
395 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
396 * | AT_<STRING> | Length | Actual <STRING> Length |
397 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
398 * | |
399 * . String .
400 * . .
401 * | |
402 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
403 */
404 case FR_TYPE_STRING:
405 if (vp->da->flags.length && (vp->vp_length != vp->da->flags.length)) {
406 fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
407 "but value was %zu bytes", __FUNCTION__,
408 vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
410 }
411
412 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)vp->vp_length); /* Big endian real string length */
413 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)vp->vp_strvalue, vp->vp_length);
414 break;
415
416 case FR_TYPE_OCTETS:
417 /*
418 * Fixed length attribute
419 */
420 if (vp->da->flags.length) {
421 size_t prefix = fr_aka_sim_octets_prefix_len(vp->da);
422 size_t pad_len;
423 size_t value_len_rounded;
424
425 if (vp->vp_length > vp->da->flags.length) {
426 fr_strerror_printf("%s: Attribute \"%s\" needs a value of <= %zu bytes, "
427 "but value was %zu bytes", __FUNCTION__,
428 vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
430 }
431
432 /*
433 * Calculate value padding (autopad)
434 */
435 value_len_rounded = ROUND_UP(vp->vp_length, (size_t)vp->da->flags.length);
436 /*
437 * Zero out reserved bytes
438 */
439 if (prefix) FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, prefix);
440
441 /*
442 * Copy in value
443 */
444 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, vp->vp_length);
445
446 /*
447 * Pad out the value
448 */
449 pad_len = value_len_rounded - vp->vp_length;
450 if (pad_len) FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len);
451 /*
452 * Variable length attribute
453 */
454 } else {
455 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)vp->vp_length); /* Big endian real string length */
456 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)vp->vp_strvalue, vp->vp_length);
457 }
458 break;
459
460 /*
461 * In SIM/AKA/AKA' we represent truth values
462 * by either including or not including the attribute
463 * in the packet.
464 *
465 * 0 1 2 3
466 * 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
467 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
468 * | AT_<BOOL> | Length = 1 | Reserved |
469 * +---------------+---------------+-------------------------------+
470 */
471 case FR_TYPE_BOOL:
472 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00); /* reserved bytes */
473 break;
474
475 /*
476 * Numbers are network byte order.
477 *
478 * In the base RFCs only short (16bit) unsigned integers are used.
479 * We add support for more, just for completeness.
480 *
481 * 0 1 2 3
482 * 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
483 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
484 * | AT_<SHORT> | Length = 1 | Short 1 | Short 2 |
485 * +---------------+---------------+-------------------------------+
486 */
487 default:
488 {
489 ssize_t len = fr_value_box_to_network(&work_dbuff, &vp->data);
490 if (len < 0) return len;
491 break;
492 }
493 }
494done:
495 /*
496 * Rebuilds the TLV stack for encoding the next attribute
497 */
498 vp = fr_dcursor_next(cursor);
499 fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
500
501 return fr_dbuff_set(dbuff, &work_dbuff);
502}
503
504/** Encodes the data portion of an attribute
505 *
506 @verbatim
507 0 1 2 3
508 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
509 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510 | AT_VERSION_L..| Length | Actual Version List Length |
511 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
512 | Supported Version 1 | Supported Version 2 |
513 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514 . .
515 . .
516 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
517 | Supported Version N | Padding |
518 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
519 @endverbatim
520 *
521 */
523 fr_da_stack_t *da_stack, int depth,
524 fr_dcursor_t *cursor, void *encode_ctx)
525{
526 size_t pad_len;
527 size_t element_len;
528 size_t actual_len;
529 fr_dbuff_t len_dbuff = FR_DBUFF(dbuff);
530 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
531 fr_dict_attr_t const *da = da_stack->da[depth];
532 fr_assert(da->flags.array);
533
534 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 2);
535 fr_dbuff_advance(&work_dbuff, 2);
536
537 if (unlikely(da->type == FR_TYPE_OCTETS)) {
538 if (!da->flags.length) {
539 fr_strerror_printf("Can't encode array type attribute \"%s\" as it does not "
540 "have a fixed length", da->name);
542 }
543 element_len = da->flags.length;
544 } else {
545 element_len = fr_aka_sim_attr_sizes[da->type][0];
546 }
547
548 /*
549 * Keep encoding as long as we have space to
550 * encode things.
551 */
552 while (fr_dbuff_extend_lowat(NULL, &work_dbuff, element_len) >= element_len) {
553 fr_pair_t *vp;
554 ssize_t slen;
555
556 slen = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx);
557 if (slen == PAIR_ENCODE_FATAL_ERROR) return slen;
558 if (slen < 0) break;
559
560 vp = fr_dcursor_current(cursor);
561 if (!vp || (vp->da != da)) break; /* Stop if we have an attribute of a different type */
562 }
563
564 actual_len = fr_dbuff_used(&work_dbuff) - 2; /* Length of the elements we encoded */
565 /*
566 * Arrays with an element size which is
567 * a multiple of 4 don't need an
568 * actual_length field, because the number
569 * of elements can be calculated from
570 * the attribute length.
571 */
572 if (element_len % 4) {
573 FR_DBUFF_IN_RETURN(&len_dbuff, (uint16_t) actual_len);
574 } else {
575 FR_DBUFF_IN_RETURN(&len_dbuff, (uint16_t) 0);
576 }
577
578 /*
579 * Pad value to multiple of 4
580 */
581 pad_len = ROUND_UP_POW2(actual_len, 4) - actual_len;
582 if (pad_len) FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len);
583
584 return fr_dbuff_set(dbuff, &work_dbuff);
585}
586
587/** Encode an RFC format attribute header
588 *
589 * This could be a standard attribute, or a TLV data type.
590 * If it's a standard attribute, then vp->da->attr == attribute.
591 * Otherwise, attribute may be something else.
592 */
593static ssize_t encode_rfc(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth,
594 fr_dcursor_t *cursor, void *encode_ctx)
595{
596 size_t pad_len;
597 fr_dict_attr_t const *da;
598 ssize_t slen;
599 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
600 fr_dbuff_t hdr_dbuff = FR_DBUFF(dbuff);
601
602 FR_PROTO_STACK_PRINT(da_stack, depth);
603
604 switch (da_stack->da[depth]->type) {
606 fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
607 fr_type_to_str(da_stack->da[depth]->type));
609
610 default:
611 if (((fr_dict_vendor_num_by_da(da_stack->da[depth]) == 0) && (da_stack->da[depth]->attr == 0)) ||
612 (da_stack->da[depth]->attr > 255)) {
613 fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__,
614 da_stack->da[depth]->attr);
616 }
617 break;
618 }
619
620 /*
621 * Write out the value to a buffer location
622 * past the AT and Length fields.
623 *
624 * Encode value will set reserved bytes to
625 * zero and fill any subfields like actual
626 * length.
627 */
628 da = da_stack->da[depth];
629
630 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 2);
631 fr_dbuff_advance(&work_dbuff, 2);
632
633 if (da->flags.array) {
635 da_stack, depth, cursor, encode_ctx);
636 } else {
638 da_stack, depth, cursor, encode_ctx);
639 }
640 if (slen <= 0) return slen;
641
642 /*
643 * Pad value to multiple of 4
644 */
645 pad_len = ROUND_UP_POW2(fr_dbuff_used(&work_dbuff), 4) - fr_dbuff_used(&work_dbuff);
646 if (pad_len) {
647 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, pad_len);
648 }
649
650 FR_DBUFF_IN_BYTES_RETURN(&hdr_dbuff, (uint8_t)da->attr,
651 (uint8_t)(fr_dbuff_used(&work_dbuff) >> 2));
652
653 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done RFC attribute");
654
655 return fr_dbuff_set(dbuff, &work_dbuff); /* AT + Length + Data */
656}
657
659 fr_da_stack_t *da_stack, unsigned int depth,
660 fr_dcursor_t *cursor, void *encode_ctx)
661{
662 ssize_t slen;
664 fr_dbuff_t value_dbuff;
665 fr_dbuff_marker_t value_start;
666 fr_pair_t const *vp = fr_dcursor_current(cursor);
667 fr_dict_attr_t const *da = da_stack->da[depth];
668
669 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00, 0x00);
670
671 value_dbuff = FR_DBUFF(&work_dbuff);
672 fr_dbuff_marker(&value_start, &value_dbuff);
673
674 for (;;) {
675 FR_PROTO_STACK_PRINT(da_stack, depth);
676
677 /*
678 * This attribute carries sub-TLVs. The sub-TLVs
679 * can only carry SIM_MAX_ATTRIBUTE_VALUE_LEN bytes of data.
680 */
681
682 /*
683 * Determine the nested type and call the appropriate encoder
684 */
685 if (da_stack->da[depth + 1]->type == FR_TYPE_TLV) {
686 slen = encode_tlv(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
687 } else {
688 slen = encode_rfc(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
689 }
690
691 if (slen <= 0) {
692 return slen;
693 }
694
695 /*
696 * If nothing updated the attribute, stop
697 */
698 if (!fr_dcursor_current(cursor) || (vp == fr_dcursor_current(cursor))) {
699 break;
700 }
701
702 /*
703 * We can encode multiple sub TLVs, if after
704 * rebuilding the TLV Stack, the attribute
705 * at this depth is the same.
706 */
707 if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) {
708 break;
709 }
710 vp = fr_dcursor_current(cursor);
711 }
712
713 /*
714 * encrypt the contents of the TLV using AES-CBC-128
715 * or another encryption algorithm.
716 */
718 ssize_t value_len = fr_dbuff_used(&work_dbuff) - 2;
719
720 slen = encode_encrypted_value(&value_dbuff, fr_dbuff_current(&value_start),
721 value_len, encode_ctx);
722 if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
723
724#ifdef __COVERITY__
725 /*
726 * Coverity as it stands doesn't see that value_len >= 0 because
727 * work_dbuff has at least the two zero bytes in it, and thus thinks
728 * (size_t) slen - value_len will be some huge size_t value. This
729 * check should pacify it.
730 */
731 if (value_len < 0) return -1;
732#endif
733 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, (size_t)slen - value_len);
734 fr_dbuff_advance(&work_dbuff, (size_t)slen - value_len);
735 }
736
737 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV");
738
739 return fr_dbuff_set(dbuff, &work_dbuff);
740}
741
743 fr_da_stack_t *da_stack, unsigned int depth,
744 fr_dcursor_t *cursor, void *encode_ctx)
745{
746 unsigned int total_len;
747 ssize_t len;
748 fr_dict_attr_t const *da;
749 fr_dbuff_t tl_dbuff;
750 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
751 fr_dcursor_t *my_cursor = cursor;
752 fr_dcursor_t child_cursor;
753
755 FR_PROTO_STACK_PRINT(da_stack, depth);
756
757 if (da_stack->da[depth]->type != FR_TYPE_TLV) {
758 fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
759 fr_type_to_str(da_stack->da[depth]->type));
761 }
762
763 if (!da_stack->da[depth + 1]) {
764 fr_pair_t *vp;
765
766 vp = fr_dcursor_current(cursor);
767 if ((vp->vp_type != FR_TYPE_TLV) || (fr_pair_list_num_elements(&vp->vp_group) == 0)) {
768 fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
770 }
771
772 fr_assert(vp->da == da_stack->da[depth]);
773
774 vp = fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
775 my_cursor = &child_cursor;
776
777 fr_proto_da_stack_build(da_stack, vp->da);
778 }
779
780 /*
781 * Add the IV before the TLV
782 * The ASCII art in the RFCs the attributes in
783 * this order.
784 */
785 if (fr_aka_sim_flag_encrypted(da_stack->da[depth])) {
786 len = encode_iv(&work_dbuff, encode_ctx);
787 if (len < 0) return len;
788 }
789 tl_dbuff = FR_DBUFF(&work_dbuff);
790
791 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 2);
792 fr_dbuff_advance(&work_dbuff, 2);
793
794 da = da_stack->da[depth];
796 da_stack, depth, my_cursor, encode_ctx);
797 if (len <= 0) return len;
798
799 if (my_cursor != cursor) fr_dcursor_next(cursor);
800
801 /*
802 * Round attr + len + data length out to a multiple
803 * of four, and setup the attribute header and
804 * length field in the buffer.
805 */
806 total_len = ROUND_UP_POW2(len + 2, 4);
807 FR_DBUFF_IN_BYTES_RETURN(&tl_dbuff, (uint8_t)da->attr, (uint8_t)(total_len >> 2));
808
809 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV attribute");
810
811 return fr_dbuff_set(dbuff, &work_dbuff); /* AT_IV + AT_*(TLV) - Can't use total_len, doesn't include IV */
812}
813
815{
816 fr_pair_t const *vp;
817 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
819 ssize_t slen;
820
821 fr_da_stack_t da_stack;
822
823 fr_dbuff_marker(&m, &work_dbuff);
824 if (!cursor) return PAIR_ENCODE_FATAL_ERROR;
825
826 vp = fr_dcursor_current(cursor);
827 if (!vp) return 0;
828
830
831 if (vp->da->depth > FR_DICT_MAX_TLV_STACK) {
832 fr_strerror_printf("%s: Attribute depth %u exceeds maximum nesting depth %d",
833 __FUNCTION__, vp->da->depth, FR_DICT_MAX_TLV_STACK);
835 }
836
837 if (vp->da->attr == FR_MAC) {
838 fr_dcursor_next(cursor);
839 return 0;
840 }
841 /*
842 * Nested structures of attributes can't be longer than
843 * 4 * 255 bytes, so each call to an encode function can
844 * only use 4 * 255 bytes of buffer space at a time.
845 */
846
847 /*
848 * Do more work to set up the stack for the complex case.
849 */
850 fr_proto_da_stack_build(&da_stack, vp->da);
851 FR_PROTO_STACK_PRINT(&da_stack, 0);
852
853 if (da_stack.da[0]->type == FR_TYPE_TLV) {
855 &da_stack, 0, cursor, encode_ctx);
856 } else {
858 &da_stack, 0, cursor, encode_ctx);
859 }
860 if (slen < 0) return slen;
861
862 /*
863 * We couldn't do it, so we didn't do anything.
864 */
865 if (fr_dcursor_current(cursor) == vp) {
866 fr_strerror_printf("%s: Nested attribute structure too large to encode", __FUNCTION__);
868 }
869
870 return fr_dbuff_set(dbuff, &work_dbuff);
871}
872
874{
875 fr_pair_t *vp;
876
877 uint8_t *buff;
878 ssize_t slen;
879 fr_dbuff_t dbuff;
881 fr_dbuff_uctx_talloc_t tctx;
882
883 bool do_hmac = false;
884
885 unsigned char subtype;
886 fr_dcursor_t cursor;
887 fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
888 eap_packet_t *eap_packet = packet_ctx->eap_packet;
889
890 /*
891 * Encoded_msg is now an EAP-SIM message.
892 * It might be too big for putting into an
893 * EAP packet.
894 */
896 if (!vp) {
897 REDEBUG("Missing subtype attribute");
899 }
900 subtype = vp->vp_uint16;
901
902 /*
903 * Group attributes with similar lineages together
904 */
907 fr_dcursor_next(&cursor); /* Skip subtype if it came out first */
908 }
909
910 /*
911 * Will we need to generate a HMAC?
912 */
913 if (fr_pair_find_by_child_num_idx(to_encode, fr_dict_root(dict_eap_aka_sim), FR_MAC, 0)) do_hmac = true;
914
915 /*
916 * Fast path, we just need to encode a subtype
917 */
918 if (!do_hmac && !fr_dcursor_current(&cursor)) {
919 MEM(buff = talloc_array(eap_packet, uint8_t, 3));
920
921 buff[0] = subtype; /* SIM or AKA subtype */
922 buff[1] = 0; /* Reserved (0) */
923 buff[2] = 0; /* Reserved (1) */
924
925 eap_packet->type.length = 3;
926 eap_packet->type.data = buff;
927
928 FR_PROTO_HEX_DUMP(buff, eap_packet->type.length, "sim packet");
929
930 return 0;
931 }
932 fr_dcursor_head(&cursor); /* Reset */
933
934 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, 1024);
935
936 FR_DBUFF_IN_BYTES_RETURN(&dbuff, subtype, 0x00, 0x00);
937
938 /*
939 * Add space in the packet for AT_MAC
940 */
941 if (do_hmac) {
942 FR_DBUFF_IN_BYTES_RETURN(&dbuff, FR_MAC, AKA_SIM_MAC_SIZE >> 2, 0x00, 0x00);
943 fr_dbuff_marker(&hmac, &dbuff);
944 FR_DBUFF_MEMSET_RETURN(&dbuff, 0, 16);
945 }
946
947 /*
948 * Encode all the things...
949 */
950 (void)fr_dcursor_head(&cursor);
951 while (fr_dcursor_current(&cursor)) {
952 slen = fr_aka_sim_encode_pair(&dbuff, &cursor, packet_ctx);
953 if (slen < 0) {
954 error:
955 talloc_free(fr_dbuff_buff(&dbuff));
957 }
958 fr_assert(fr_dbuff_used(&dbuff) > 0); /* We messed up a check somewhere in the encoder */
959 }
960
961 eap_packet->type.length = fr_dbuff_used(&dbuff);
962 eap_packet->type.data = fr_dbuff_buff(&dbuff);
963
964 /*
965 * Calculate a SHA1-HMAC over the complete EAP packet
966 */
967 if (do_hmac) {
968 slen = fr_aka_sim_crypto_sign_packet(fr_dbuff_current(&hmac), eap_packet, false,
969 packet_ctx->hmac_md,
970 packet_ctx->k_aut, packet_ctx->k_aut_len,
971 packet_ctx->hmac_extra, packet_ctx->hmac_extra_len);
972 if (slen < 0) goto error;
973 FR_PROTO_HEX_DUMP(fr_dbuff_current(&hmac) - 4, AKA_SIM_MAC_SIZE, "hmac attribute");
974 }
975 FR_PROTO_HEX_DUMP(eap_packet->type.data, eap_packet->type.length, "sim packet");
976
977 /*
978 * Shrink buffer to the correct size
979 */
980 if (eap_packet->type.length != talloc_array_length(eap_packet->type.data)) {
981 uint8_t *realloced;
982
983 realloced = talloc_realloc(eap_packet, eap_packet->type.data, uint8_t, eap_packet->type.length);
984 if (!realloced) goto error;
985
986 eap_packet->type.data = realloced;
987 }
988
989 return fr_dbuff_used(&dbuff);
990}
991
992/*
993 * Test ctx data
994 */
996{
998
999 return 0;
1000}
1001
1002static fr_aka_sim_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
1003{
1004 fr_aka_sim_ctx_t *test_ctx;
1005
1006 test_ctx = talloc_zero(ctx, fr_aka_sim_ctx_t);
1007 test_ctx->k_encr = talloc_memdup(test_ctx, k_encr, k_encr_len);
1008 test_ctx->k_aut = talloc_zero_array(test_ctx, uint8_t, 16);
1009 test_ctx->k_aut_len = 16;
1010
1011 talloc_set_destructor(test_ctx, _test_ctx_free);
1012
1013 if (fr_aka_sim_init() < 0) {
1014 talloc_free(test_ctx);
1015 return NULL;
1016 }
1017
1018 return test_ctx;
1019}
1020
1021/*
1022 * Test ctx data
1023 */
1024static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
1025 UNUSED fr_dict_attr_t const *root_da)
1026{
1027 fr_aka_sim_ctx_t *test_ctx;
1028 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1029 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1030
1031 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1032 if (!test_ctx) return -1;
1033
1034 test_ctx->have_iv = true; /* Ensures IV is all zeros */
1035
1036 *out = test_ctx;
1037
1038 return 0;
1039}
1040
1041static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
1042 UNUSED fr_dict_attr_t const *root_da)
1043{
1044 fr_aka_sim_ctx_t *test_ctx;
1045 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1046 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1047
1048 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1049 if (!test_ctx) return -1;
1050
1051 test_ctx->have_iv = true; /* Ensures IV is all zeros */
1052
1053 *out = test_ctx;
1054
1055 return 0;
1056}
1057
1058static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
1059 UNUSED fr_dict_attr_t const *root_da)
1060{
1061 fr_aka_sim_ctx_t *test_ctx;
1062 static uint8_t k_encr[] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a,
1063 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 };
1064
1065 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1066 if (!test_ctx) return -1;
1067
1068 *out = test_ctx;
1069
1070 return 0;
1071}
1072
1073/*
1074 * Test points
1075 */
1082
1089
#define RCSID(id)
Definition build.h:487
#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:1083
#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:777
#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:683
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:83
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:921
#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:1014
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:908
#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:1166
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition dbuff.h:892
#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:1519
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:670
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:1203
#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:1393
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1361
#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:1596
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:232
#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:311
#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:328
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:421
#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:1483
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:2666
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:519
static fr_slen_t in
Definition dict.h:884
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:176
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:537
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:290
#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
talloc_free(hp)
#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:1077
ssize_t fr_aka_sim_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Definition encode.c:814
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:522
static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
Definition encode.c:1024
fr_test_point_pair_encode_t sim_tp_encode_rfc4186
Definition encode.c:1091
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:278
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:658
static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
Definition encode.c:1041
fr_test_point_pair_encode_t aka_tp_encode
Definition encode.c:1084
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:742
static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
Definition encode.c:1058
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:873
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:1002
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:593
static int _test_ctx_free(UNUSED fr_aka_sim_ctx_t *ctx)
Definition encode.c:995
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
#define ROUND_UP_POW2(_num, _mul)
Round up - Only works if _mul is a power of 2 but avoids division.
Definition math.h:202
#define ROUND_UP(_num, _mul)
Round up - Works in all cases, but is slower.
Definition math.h:206
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:1930
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:909
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
#define REDEBUG(fmt,...)
static bool done
Definition radclient.c:83
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:94
Entry point for pair encoders.
Definition test_point.h:93
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:584
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:622
#define PAIR_VERIFY(_x)
Definition pair.h:204
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:317
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
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:1525
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1030
static size_t char ** out
Definition value.h:1030