The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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 
24 RCSID("$Id: 084ef1dbab8618c6e3d242bbbda7950c6c036849 $")
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 
60 static 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  */
71 static 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  */
104 static ssize_t encode_iv(fr_dbuff_t *dbuff, void *encode_ctx)
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 
281  PAIR_VERIFY(vp);
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) {
295  case FR_TYPE_STRUCTURAL:
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  }
488 done:
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  */
587 static 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) {
599  case FR_TYPE_STRUCTURAL:
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  */
711  if (!da->flags.extra && da->flags.subtype) {
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  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, (size_t)slen - value_len);
719  fr_dbuff_advance(&work_dbuff, (size_t)slen - value_len);
720  }
721 
722  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV");
723 
724  return fr_dbuff_set(dbuff, &work_dbuff);
725 }
726 
728  fr_da_stack_t *da_stack, unsigned int depth,
729  fr_dcursor_t *cursor, void *encode_ctx)
730 {
731  unsigned int total_len;
732  ssize_t len;
733  fr_dict_attr_t const *da;
734  fr_dbuff_t tl_dbuff;
735  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
736  fr_dcursor_t *my_cursor = cursor;
737  fr_dcursor_t child_cursor;
738 
740  FR_PROTO_STACK_PRINT(da_stack, depth);
741 
742  if (da_stack->da[depth]->type != FR_TYPE_TLV) {
743  fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
744  fr_type_to_str(da_stack->da[depth]->type));
746  }
747 
748  if (!da_stack->da[depth + 1]) {
749  fr_pair_t *vp;
750 
751  vp = fr_dcursor_current(cursor);
752  if ((vp->vp_type != FR_TYPE_TLV) || (fr_pair_list_num_elements(&vp->vp_group) == 0)) {
753  fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
755  }
756 
757  fr_assert(vp->da == da_stack->da[depth]);
758 
759  vp = fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
760  my_cursor = &child_cursor;
761 
762  fr_proto_da_stack_build(da_stack, vp->da);
763  }
764 
765  /*
766  * Add the IV before the TLV
767  * The ASCII art in the RFCs the attributes in
768  * this order.
769  */
770  if (!da_stack->da[depth]->flags.extra && da_stack->da[depth]->flags.subtype) {
771  len = encode_iv(&work_dbuff, encode_ctx);
772  if (len < 0) return len;
773  }
774  tl_dbuff = FR_DBUFF(&work_dbuff);
775 
776  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 2);
777  fr_dbuff_advance(&work_dbuff, 2);
778 
779  da = da_stack->da[depth];
781  da_stack, depth, my_cursor, encode_ctx);
782  if (len <= 0) return len;
783 
784  if (my_cursor != cursor) fr_dcursor_next(cursor);
785 
786  /*
787  * Round attr + len + data length out to a multiple
788  * of four, and setup the attribute header and
789  * length field in the buffer.
790  */
791  total_len = ROUND_UP_POW2(len + 2, 4);
792  FR_DBUFF_IN_BYTES_RETURN(&tl_dbuff, (uint8_t)da->attr, (uint8_t)(total_len >> 2));
793 
794  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV attribute");
795 
796  return fr_dbuff_set(dbuff, &work_dbuff); /* AT_IV + AT_*(TLV) - Can't use total_len, doesn't include IV */
797 }
798 
800 {
801  fr_pair_t const *vp;
802  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
804  ssize_t slen;
805 
806  fr_da_stack_t da_stack;
807 
808  fr_dbuff_marker(&m, &work_dbuff);
809  if (!cursor) return PAIR_ENCODE_FATAL_ERROR;
810 
812  if (!vp) return 0;
813 
814  PAIR_VERIFY(vp);
815 
816  if (vp->da->depth > FR_DICT_MAX_TLV_STACK) {
817  fr_strerror_printf("%s: Attribute depth %i exceeds maximum nesting depth %i",
818  __FUNCTION__, vp->da->depth, FR_DICT_MAX_TLV_STACK);
820  }
821 
822  if (vp->da->attr == FR_MAC) {
824  return 0;
825  }
826  /*
827  * Nested structures of attributes can't be longer than
828  * 4 * 255 bytes, so each call to an encode function can
829  * only use 4 * 255 bytes of buffer space at a time.
830  */
831 
832  /*
833  * Do more work to set up the stack for the complex case.
834  */
835  fr_proto_da_stack_build(&da_stack, vp->da);
836  FR_PROTO_STACK_PRINT(&da_stack, 0);
837 
838  if (da_stack.da[0]->type == FR_TYPE_TLV) {
840  &da_stack, 0, cursor, encode_ctx);
841  } else {
843  &da_stack, 0, cursor, encode_ctx);
844  }
845  if (slen < 0) return slen;
846 
847  /*
848  * We couldn't do it, so we didn't do anything.
849  */
850  if (fr_dcursor_current(cursor) == vp) {
851  fr_strerror_printf("%s: Nested attribute structure too large to encode", __FUNCTION__);
853  }
854 
855  return fr_dbuff_set(dbuff, &work_dbuff);
856 }
857 
859 {
860  fr_pair_t *vp;
861 
862  uint8_t *buff;
863  ssize_t slen;
864  fr_dbuff_t dbuff;
865  fr_dbuff_marker_t hmac;
866  fr_dbuff_uctx_talloc_t tctx;
867 
868  bool do_hmac = false;
869 
870  unsigned char subtype;
871  fr_dcursor_t cursor;
872  fr_aka_sim_ctx_t *packet_ctx = encode_ctx;
873  eap_packet_t *eap_packet = packet_ctx->eap_packet;
874 
875  /*
876  * Encoded_msg is now an EAP-SIM message.
877  * It might be too big for putting into an
878  * EAP packet.
879  */
880  vp = fr_pair_find_by_child_num_idx(to_encode, fr_dict_root(dict_eap_aka_sim), FR_SUBTYPE, 0);
881  if (!vp) {
882  REDEBUG("Missing subtype attribute");
884  }
885  subtype = vp->vp_uint16;
886 
887  /*
888  * Group attributes with similar lineages together
889  */
891  if (fr_pair_dcursor_init(&cursor, to_encode) == vp) {
892  fr_dcursor_next(&cursor); /* Skip subtype if it came out first */
893  }
894 
895  /*
896  * Will we need to generate a HMAC?
897  */
898  if (fr_pair_find_by_child_num_idx(to_encode, fr_dict_root(dict_eap_aka_sim), FR_MAC, 0)) do_hmac = true;
899 
900  /*
901  * Fast path, we just need to encode a subtype
902  */
903  if (!do_hmac && !fr_dcursor_filter_current(&cursor, is_eap_aka_encodable, packet_ctx)) {
904  MEM(buff = talloc_array(eap_packet, uint8_t, 3));
905 
906  buff[0] = subtype; /* SIM or AKA subtype */
907  buff[1] = 0; /* Reserved (0) */
908  buff[2] = 0; /* Reserved (1) */
909 
910  eap_packet->type.length = 3;
911  eap_packet->type.data = buff;
912 
913  FR_PROTO_HEX_DUMP(buff, eap_packet->type.length, "sim packet");
914 
915  return 0;
916  }
917  fr_dcursor_head(&cursor); /* Reset */
918 
919  fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, 1024);
920 
921  FR_DBUFF_IN_BYTES_RETURN(&dbuff, subtype, 0x00, 0x00);
922 
923  /*
924  * Add space in the packet for AT_MAC
925  */
926  if (do_hmac) {
927  FR_DBUFF_IN_BYTES_RETURN(&dbuff, FR_MAC, AKA_SIM_MAC_SIZE >> 2, 0x00, 0x00);
928  fr_dbuff_marker(&hmac, &dbuff);
929  FR_DBUFF_MEMSET_RETURN(&dbuff, 0, 16);
930  }
931 
932  /*
933  * Encode all the things...
934  */
935  (void)fr_dcursor_head(&cursor);
936  while (fr_dcursor_current(&cursor)) {
937  slen = fr_aka_sim_encode_pair(&dbuff, &cursor, packet_ctx);
938  if (slen < 0) {
939  error:
940  talloc_free(fr_dbuff_buff(&dbuff));
942  }
943  fr_assert(fr_dbuff_used(&dbuff) > 0); /* We messed up a check somewhere in the encoder */
944  }
945 
946  eap_packet->type.length = fr_dbuff_used(&dbuff);
947  eap_packet->type.data = fr_dbuff_buff(&dbuff);
948 
949  /*
950  * Calculate a SHA1-HMAC over the complete EAP packet
951  */
952  if (do_hmac) {
953  slen = fr_aka_sim_crypto_sign_packet(fr_dbuff_current(&hmac), eap_packet, false,
954  packet_ctx->hmac_md,
955  packet_ctx->k_aut, packet_ctx->k_aut_len,
956  packet_ctx->hmac_extra, packet_ctx->hmac_extra_len);
957  if (slen < 0) goto error;
958  FR_PROTO_HEX_DUMP(fr_dbuff_current(&hmac) - 4, AKA_SIM_MAC_SIZE, "hmac attribute");
959  }
960  FR_PROTO_HEX_DUMP(eap_packet->type.data, eap_packet->type.length, "sim packet");
961 
962  /*
963  * Shrink buffer to the correct size
964  */
965  if (eap_packet->type.length != talloc_array_length(eap_packet->type.data)) {
966  uint8_t *realloced;
967 
968  realloced = talloc_realloc(eap_packet, eap_packet->type.data, uint8_t, eap_packet->type.length);
969  if (!realloced) goto error;
970 
971  eap_packet->type.data = realloced;
972  }
973 
974  return fr_dbuff_used(&dbuff);
975 }
976 
977 /*
978  * Test ctx data
979  */
981 {
982  fr_aka_sim_free();
983 
984  return 0;
985 }
986 
987 static fr_aka_sim_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
988 {
989  fr_aka_sim_ctx_t *test_ctx;
990 
991  test_ctx = talloc_zero(ctx, fr_aka_sim_ctx_t);
992  test_ctx->k_encr = talloc_memdup(test_ctx, k_encr, k_encr_len);
993  test_ctx->k_aut = talloc_zero_array(test_ctx, uint8_t, 16);
994  test_ctx->k_aut_len = 16;
995 
996  talloc_set_destructor(test_ctx, _test_ctx_free);
997 
998  if (fr_aka_sim_init() < 0) {
999  talloc_free(test_ctx);
1000  return NULL;
1001  }
1002 
1003  return test_ctx;
1004 }
1005 
1006 /*
1007  * Test ctx data
1008  */
1009 static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx)
1010 {
1011  fr_aka_sim_ctx_t *test_ctx;
1012  static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1013  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1014 
1015  test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1016  if (!test_ctx) return -1;
1017 
1018  test_ctx->have_iv = true; /* Ensures IV is all zeros */
1019 
1020  *out = test_ctx;
1021 
1022  return 0;
1023 }
1024 
1025 static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx)
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 
1041 static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx)
1042 {
1043  fr_aka_sim_ctx_t *test_ctx;
1044  static uint8_t k_encr[] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a,
1045  0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 };
1046 
1047  test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1048  if (!test_ctx) return -1;
1049 
1050  *out = test_ctx;
1051 
1052  return 0;
1053 }
1054 
1055 /*
1056  * Test points
1057  */
1061  .func = fr_aka_sim_encode_pair
1062 };
1063 
1067  .func = fr_aka_sim_encode_pair
1068 };
1069 
1073  .func = fr_aka_sim_encode_pair
1074 };
#define RCSID(id)
Definition: build.h:444
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
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:1067
#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:762
#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:668
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:906
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition: dbuff.h:893
#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:1150
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition: dbuff.h:877
#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:1503
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition: dbuff.h:655
#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:1377
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition: dbuff.h:1345
#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:1580
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:406
#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
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:1187
#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
#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:1467
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:543
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:582
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
Definition: dcursor.h:233
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition: dict.h:384
static fr_slen_t in
Definition: dict.h:645
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:182
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
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:37
fr_dict_t const * dict_eap_aka_sim
Definition: base.c:48
void fr_aka_sim_free(void)
Definition: base.c:285
int fr_aka_sim_init(void)
Definition: base.c:254
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:246
size_t const fr_aka_sim_attr_sizes[FR_TYPE_MAX+1][2]
SIM AT on-the-wire format attribute sizes.
Definition: base.c:205
#define SIM_MAX_ATTRIBUTE_VALUE_LEN
Definition: encode.c:40
fr_test_point_pair_encode_t sim_tp_encode
Definition: encode.c:1059
ssize_t fr_aka_sim_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Definition: encode.c:799
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:1071
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 int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx)
Definition: encode.c:1009
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:1065
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:727
static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx)
Definition: encode.c:1041
ssize_t fr_aka_sim_encode(request_t *request, fr_pair_list_t *to_encode, void *encode_ctx)
Definition: encode.c:858
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:987
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 encode_test_ctx_aka(void **out, TALLOC_CTX *ctx)
Definition: encode.c:1025
static int _test_ctx_free(UNUSED fr_aka_sim_ctx_t *ctx)
Definition: encode.c:980
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
Definition: merged_model.c:31
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
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:888
int8_t fr_pair_cmp_by_parent_num(void const *a, void const *b)
Order attributes by their parent(s), attribute number, and tag.
Definition: pair.c:1918
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.
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:106
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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:92
Entry point for pair encoders.
Definition: test_point.h:91
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:610
#define PAIR_VERIFY(_x)
Definition: pair.h:190
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.
Definition: pair_inline.c:140
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:590
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
Definition: pair_inline.c:151
#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
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
return fr_dbuff_set(dbuff, &our_dbuff)
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
Definition: value.c:1359
static size_t char fr_sbuff_t size_t inlen
Definition: value.h:984
static size_t char ** out
Definition: value.h:984