]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add support for encoding version lists
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 1 Dec 2017 15:20:38 +0000 (15:20 +0000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 1 Dec 2017 15:20:53 +0000 (15:20 +0000)
share/dictionary.eap.sim
src/modules/rlm_eap/lib/sim/base.c
src/modules/rlm_eap/lib/sim/decode.c
src/modules/rlm_eap/lib/sim/encode.c
src/modules/rlm_eap/lib/sim/sim_proto.h
src/tests/unit/eap-sim.txt

index 07e1d1e4731c260d289102e7844a3b0aef976f40..1242ae99010c00becbe5b51094b3122ffd6cb8e3 100644 (file)
@@ -14,7 +14,7 @@ ATTRIBUTE     EAP-SIM-Res                             3       octets
 ATTRIBUTE      EAP-SIM-Auts                            4       octets
 ATTRIBUTE      EAP-SIM-Nonce-MT                        7       octets
 ATTRIBUTE      EAP-SIM-Permanent-ID-Req                10      bool
-ATTRIBUTE      EAP-SIM-Mac                             11      octets
+ATTRIBUTE      EAP-SIM-Mac                             11      octets[20]
 ATTRIBUTE      EAP-SIM-Notification                    12      short
 
 VALUE  EAP-SIM-Notification            General-Failure-After-Authentication 0
index ad3955b7e9b979de7fc0d8b77c665a5217cfb37a..dea540237b33dcd22cac70fea1df6eae00b292ef 100644 (file)
@@ -40,6 +40,50 @@ RCSID("$Id$")
 fr_dict_attr_t const *dict_sim_root;
 fr_dict_attr_t const *dict_aka_root;
 
+/** SIM AT on-the-wire format attribute sizes
+ *
+ * Holds the min/max sizes of all supported SIM AT attribute values as they
+ * would be found in a SIM AT packet.
+ *
+ * These sizes may be different than the sizes of INTERNAL formats, PRESENTATION
+ * formats and generic NETWORK formats.
+ */
+size_t const fr_sim_attr_sizes[FR_TYPE_MAX + 1][2] = {
+       [FR_TYPE_INVALID]               = {~0, 0},
+
+       [FR_TYPE_STRING]                = {0, ~0},
+       [FR_TYPE_OCTETS]                = {0, ~0},
+
+       [FR_TYPE_BOOL]                  = {2, 2},
+       [FR_TYPE_UINT8]                 = {1, 1},
+       [FR_TYPE_UINT16]                = {2, 2},
+       [FR_TYPE_UINT32]                = {4, 4},
+       [FR_TYPE_UINT64]                = {8, 8},
+
+       [FR_TYPE_TLV]                   = {2, ~0},
+
+       [FR_TYPE_MAX]                   = {~0, 0}       //!< Ensure array covers all types.
+};
+
+/** Return the on-the-wire length of an attribute value
+ *
+ * @param[in] vp to return the length of.
+ * @return the length of the attribute.
+ */
+size_t fr_sim_attr_len(VALUE_PAIR const *vp)
+{
+       switch (vp->vp_type) {
+       case FR_TYPE_VARIABLE_SIZE:
+               return vp->vp_length;
+
+       default:
+               return fr_radius_attr_sizes[vp->vp_type][0];
+
+       case FR_TYPE_STRUCTURAL:
+               if (!fr_cond_assert(0)) return 0;
+       }
+}
+
 /*
  * definitions changed to take a buffer for unknowns
  * as this is more thread safe.
index 6d79d914501d9ed4068d0a78b74c346f198d009f..cf62cc201c56322678f8c81ff255d8e153981865 100644 (file)
@@ -256,7 +256,7 @@ static int fr_sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *d
                break;
 
        default:
-               element_len = dict_attr_sizes[da->type][0];
+               element_len = fr_sim_attr_sizes[da->type][0];
                break;
        }
 
index c660a29976b2a82408c887ce829a8f8b9bf6a676..8b41c2f3b6712f54b5c27dc1967f5d71fb4793bb 100644 (file)
@@ -338,6 +338,13 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
                *p++ = 0;       /* Reserved */
                *p++ = 0;       /* Reserved */
 
+               if (vp->da->flags.length && (vp->vp_length != vp->da->flags.length)) {
+                       fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
+                                          "but value was %zu bytes", __FUNCTION__,
+                                          vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
+                       return -1;
+               }
+
                memcpy(p, vp->vp_octets, vp->vp_length);
                p += vp->vp_length;
 
@@ -376,6 +383,13 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
 
                if ((rounded_len + 2) > outlen) goto oos;
 
+               if (vp->da->flags.length && (vp->vp_length != vp->da->flags.length)) {
+                       fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
+                                          "but value was %zu bytes", __FUNCTION__,
+                                          vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
+                       return -1;
+               }
+
                memcpy(p, &actual_len, sizeof(actual_len));             /* Big endian real string length */
                p += sizeof(actual_len);
 
@@ -444,6 +458,71 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
        return len;
 }
 
+/** Encodes the data portion of an attribute
+ *
+ @verbatim
+       0                   1                   2                   3
+       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
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       | AT_VERSION_L..| Length        | Actual Version List Length    |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |  Supported Version 1          |  Supported Version 2          |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       .                                                               .
+       .                                                               .
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       | Supported Version N           |     Padding                   |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ @endverbatim
+ *
+ */
+static ssize_t encode_array(uint8_t *out, size_t outlen,
+                           fr_dict_attr_t const **tlv_stack, int depth,
+                           vp_cursor_t *cursor, void *encoder_ctx)
+{
+       uint8_t                 *p = out, *end = p + outlen;
+       uint8_t                 *value;
+       size_t                  pad_len;
+       uint16_t                actual_len;
+       fr_dict_attr_t const    *da = tlv_stack[depth];
+
+       rad_assert(da->flags.array);
+
+       p += 2;
+       value = p;      /* Space for actual length */
+
+       /*
+        *      Keep encoding as long as we have space to
+        *      encode things.
+        */
+       while (fr_sim_attr_sizes[da->type][0] <= ((size_t)(end - p))) {
+               VALUE_PAIR      *vp;
+               ssize_t         slen;
+
+               slen = encode_value(p, end - p, tlv_stack, depth, cursor, encoder_ctx);
+               if (slen < 0) return slen;
+
+               p += slen;
+
+               vp = fr_pair_cursor_current(cursor);
+               if (!vp || (vp->da != da)) break;               /* Stop if we have an attribute of a different type */
+       }
+
+       actual_len = htons((p - value) & UINT16_MAX);   /* Length of the elements we encoded */
+       memcpy(out, &actual_len, sizeof(actual_len));
+
+       /*
+        *      Pad value a multiple of 4
+        */
+       pad_len = (((p - value) + 3) & ~3) - (p - value);
+       if (pad_len) {
+               memset(p, 0, pad_len);
+               p += pad_len;
+       }
+
+       return p - out;
+}
+
 /** Encode an RFC format attribute header
  *
  * This could be a standard attribute, or a TLV data type.
@@ -487,9 +566,13 @@ static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const
         *      length.
         */
        da = tlv_stack[depth];
-       slen = encode_value(out + 2, outlen - 2, tlv_stack, depth, cursor, encoder_ctx);
-       if (slen <= 0) return slen;
 
+       if (da->flags.array) {
+               slen = encode_array(out + 2, outlen - 2, tlv_stack, depth, cursor, encoder_ctx);
+       } else {
+               slen = encode_value(out + 2, outlen - 2, tlv_stack, depth, cursor, encoder_ctx);
+       }
+       if (slen <= 0) return slen;
        /*
         *      Round attr + len + data length out to a multiple
         *      of four, and setup the attribute header and
@@ -668,10 +751,11 @@ ssize_t fr_sim_encode_pair(uint8_t *out, size_t outlen, vp_cursor_t *cursor, voi
         *      Fast path for the common case.
         */
        if ((vp->da->parent == packet_ctx->root) && !vp->da->flags.concat && (vp->vp_type != FR_TYPE_TLV)) {
-               tlv_stack[0] = vp->da;
-               tlv_stack[1] = NULL;
+               tlv_stack[0] = packet_ctx->root;
+               tlv_stack[1] = vp->da;
+               tlv_stack[2] = NULL;
                FR_PROTO_STACK_PRINT(tlv_stack, 0);
-               return encode_rfc_hdr(out, attr_len, tlv_stack, 0, cursor, encoder_ctx);
+               return encode_rfc_hdr(out, attr_len, tlv_stack, 1, cursor, encoder_ctx);
        }
 
        /*
@@ -772,8 +856,8 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
                MEM(buff = talloc_array(eap_packet, uint8_t, 3));
 
                buff[0] = subtype;      /* SIM or AKA subtype */
-               buff[1] = 0;            /* Reserved */
-               buff[2] = 0;            /* Reserved */
+               buff[1] = 0;            /* Reserved (0) */
+               buff[2] = 0;            /* Reserved (1) */
 
                eap_packet->type.length = 3;
                eap_packet->type.data = buff;
@@ -786,9 +870,9 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
        end = p + talloc_array_length(p);
        if (do_hmac) end -= SIM_CALC_MAC_SIZE;
 
-       *p++ = subtype;                 /* Subtype  (1) */
-       *p++ = 0;                       /* Reserved */
-       *p++ = 0;                       /* Reserved */
+       *p++ = subtype;                 /* Subtype */
+       *p++ = 0;                       /* Reserved (0) */
+       *p++ = 0;                       /* Reserved (1) */
 
        /*
         *      Encode all the things...
index 3dd98d6b41736adfb88631230935412580071276..0adf90e69362f61189343adc9a505c96675d75d5 100644 (file)
@@ -163,6 +163,7 @@ typedef struct {
 
 typedef struct _eap_session eap_session_t;
 
+extern size_t const fr_sim_attr_sizes[FR_TYPE_MAX + 1][2];
 extern fr_dict_attr_t const *dict_sim_root;
 extern fr_dict_attr_t const *dict_aka_root;
 
@@ -186,6 +187,8 @@ ssize_t             fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t t
 /*
  *     base.c
  */
+size_t         fr_sim_attr_len(VALUE_PAIR const *vp);
+
 char const     *fr_sim_session_to_name(char *out, size_t outlen, eap_sim_client_states_t state);
 
 int            fr_sim_global_init(void);
index 4e0d16dd7086c8365fc24600acc0a4edfeb66494..28e3fdffb89a4dabe3773c238c3f9492a95c68f3 100644 (file)
@@ -78,3 +78,16 @@ data 82 05 00 00 3f b8 34 1f f8 26 e0 4d 4a f3 f9 61 3c a9 84 26 0d 01 00 00 82
 
 decode-pair.tp_decode_sim -
 data EAP-SIM-Next-Pseudonym = "testing123", EAP-SIM-Any-ID-Req = yes, EAP-SIM-Counter-Too-Small = yes
+
+# Array (one element)
+encode-pair.tp_encode_sim EAP-SIM-Version-List = 1
+data 0f 02 00 02 00 01 00 00
+
+# Array (multiple elements, with padding)
+encode-pair.tp_encode_sim EAP-SIM-Version-List = 1, EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 3
+data 0f 03 00 06 00 01 00 02 00 03 00 00
+
+# Array (multiple elements, with no padding)
+encode-pair.tp_encode_sim EAP-SIM-Version-List = 1, EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 3, EAP-SIM-Version-List = 4
+data 0f 03 00 08 00 01 00 02 00 03 00 04
+