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