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