From: Arran Cudbard-Bell Date: Sun, 3 Dec 2017 01:12:36 +0000 (+0000) Subject: Add all example packets from RFC4186 to tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2b0363fe3b118cdb3683d32fcb16a90febdc9cbd;p=thirdparty%2Ffreeradius-server.git Add all example packets from RFC4186 to tests Add special cases for AT_AUTS and AT_RES Add more length restrictions for some fields Remove attributes not included in SIM/AKA Fix array decoding support Add tests for SIM error cases Add support for decoding fixed length octet type attributes --- diff --git a/share/dictionary.eap.aka b/share/dictionary.eap.aka index 02187cf016a..e78976efb05 100644 --- a/share/dictionary.eap.aka +++ b/share/dictionary.eap.aka @@ -8,20 +8,19 @@ # # Non-Skippable attributes # -ATTRIBUTE EAP-AKA-Rand 1 octets -ATTRIBUTE EAP-AKA-Autn 2 octets -ATTRIBUTE EAP-AKA-Res 3 octets -ATTRIBUTE EAP-AKA-Auts 4 octets -ATTRIBUTE EAP-AKA-Nonce-MT 7 octets +ATTRIBUTE EAP-AKA-RAND 1 octets[16] # Not an array, single value +ATTRIBUTE EAP-AKA-AUTN 2 octets[16] +ATTRIBUTE EAP-AKA-RES 3 octets[16] # Special case (length field with length in bits) +ATTRIBUTE EAP-AKA-AUTS 4 octets[14] # Special case no reserved field. ATTRIBUTE EAP-AKA-Permanent-ID-Req 10 bool -ATTRIBUTE EAP-AKA-Mac 11 octets[20] +ATTRIBUTE EAP-AKA-MAC 11 octets[16] ATTRIBUTE EAP-AKA-Notification 12 short -VALUE EAP-AKA-Notification General-Failure-After-Authentication 0 -VALUE EAP-AKA-Notification Temporarily-Denied 1026 -VALUE EAP-AKA-Notification Not-Subscribed 1031 -VALUE EAP-AKA-Notification General-Failure 16384 -VALUE EAP-AKA-Notification Success 32768 +VALUE EAP-AKA-Notification General-Failure-After-Authentication 0 +VALUE EAP-AKA-Notification Temporarily-Denied 1026 +VALUE EAP-AKA-Notification Not-Subscribed 1031 +VALUE EAP-AKA-Notification General-Failure 16384 +VALUE EAP-AKA-Notification Success 32768 ATTRIBUTE EAP-AKA-Any-ID-Req 13 bool ATTRIBUTE EAP-AKA-Identity 14 string @@ -31,30 +30,30 @@ ATTRIBUTE EAP-AKA-Client-Error-Code 22 short ATTRIBUTE EAP-AKA-KDF-Input 23 string ATTRIBUTE EAP-AKA-KDF 24 short -VALUE EAP-AKA-Client-Error-Code Unable-To-Process-Packet 0 -VALUE EAP-AKA-Client-Error-Code Unsupported-Version 1 -VALUE EAP-AKA-Client-Error-Code Insufficient-Challenges 2 -VALUE EAP-AKA-Client-Error-Code RANDS-Not-Fresh 3 +VALUE EAP-AKA-Client-Error-Code Unable-To-Process-Packet 0 +VALUE EAP-AKA-Client-Error-Code Unsupported-Version 1 +VALUE EAP-AKA-Client-Error-Code Insufficient-Challenges 2 +VALUE EAP-AKA-Client-Error-Code RANDS-Not-Fresh 3 # # Skippable-Attributes # -ATTRIBUTE EAP-AKA-IV 129 octets +ATTRIBUTE EAP-AKA-IV 129 octets[16] ATTRIBUTE EAP-AKA-Encr-Data 130 tlv encrypt=4 # # These attributes are reversibly encrypted # BEGIN-TLV EAP-AKA-Encr-Data -ATTRIBUTE EAP-AKA-Padding 6 octets +ATTRIBUTE EAP-AKA-Padding 6 octets # 4, 8, 12 bytes length ATTRIBUTE EAP-AKA-Counter 19 short ATTRIBUTE EAP-AKA-Counter-Too-Small 20 bool -ATTRIBUTE EAP-AKA-Nonce-S 21 octets +ATTRIBUTE EAP-AKA-Nonce-S 21 octets[16] ATTRIBUTE EAP-AKA-Next-Pseudonym 132 string ATTRIBUTE EAP-AKA-Next-Reauth-ID 133 string END-TLV EAP-AKA-Encr-Data -ATTRIBUTE EAP-AKA-Checkcode 134 octets +ATTRIBUTE EAP-AKA-Checkcode 134 octets # Zero or Twenty bytes ATTRIBUTE EAP-AKA-Result-Ind 137 bool # @@ -63,13 +62,13 @@ ATTRIBUTE EAP-AKA-Result-Ind 137 bool FLAGS internal ATTRIBUTE EAP-AKA-Subtype 256 integer -VALUE EAP-AKA-Subtype AKA-Challenge 1 -VALUE EAP-AKA-Subtype AKA-Authentication-Reject 2 -VALUE EAP-AKA-Subtype AKA-Synchronization-Failure 4 -VALUE EAP-AKA-Subtype AKA-Identity 5 -VALUE EAP-AKA-Subtype AKA-Notification 12 -VALUE EAP-AKA-Subtype AKA-Reauthentication 13 -VALUE EAP-AKA-Subtype AKA-Client-Error 14 +VALUE EAP-AKA-Subtype AKA-Challenge 1 +VALUE EAP-AKA-Subtype AKA-Authentication-Reject 2 +VALUE EAP-AKA-Subtype AKA-Synchronization-Failure 4 +VALUE EAP-AKA-Subtype AKA-Identity 5 +VALUE EAP-AKA-Subtype AKA-Notification 12 +VALUE EAP-AKA-Subtype AKA-Reauthentication 13 +VALUE EAP-AKA-Subtype AKA-Client-Error 14 ATTRIBUTE EAP-AKA-HMAC 257 string ATTRIBUTE EAP-AKA-Key 258 octets diff --git a/share/dictionary.eap.sim b/share/dictionary.eap.sim index 1242ae99010..a32cd193eb0 100644 --- a/share/dictionary.eap.sim +++ b/share/dictionary.eap.sim @@ -8,20 +8,17 @@ # # Non-Skippable attributes # -ATTRIBUTE EAP-SIM-Rand 1 octets -ATTRIBUTE EAP-SIM-Autn 2 octets -ATTRIBUTE EAP-SIM-Res 3 octets -ATTRIBUTE EAP-SIM-Auts 4 octets +ATTRIBUTE EAP-SIM-RAND 1 octets[16] array ATTRIBUTE EAP-SIM-Nonce-MT 7 octets ATTRIBUTE EAP-SIM-Permanent-ID-Req 10 bool -ATTRIBUTE EAP-SIM-Mac 11 octets[20] +ATTRIBUTE EAP-SIM-MAC 11 octets[16] ATTRIBUTE EAP-SIM-Notification 12 short -VALUE EAP-SIM-Notification General-Failure-After-Authentication 0 -VALUE EAP-SIM-Notification Temporarily-Denied 1026 -VALUE EAP-SIM-Notification Not-Subscribed 1031 -VALUE EAP-SIM-Notification General-Failure 16384 -VALUE EAP-SIM-Notification Success 32768 +VALUE EAP-SIM-Notification General-Failure-After-Authentication 0 +VALUE EAP-SIM-Notification Temporarily-Denied 1026 +VALUE EAP-SIM-Notification Not-Subscribed 1031 +VALUE EAP-SIM-Notification General-Failure 16384 +VALUE EAP-SIM-Notification Success 32768 ATTRIBUTE EAP-SIM-Any-ID-Req 13 bool ATTRIBUTE EAP-SIM-Identity 14 string @@ -31,30 +28,29 @@ ATTRIBUTE EAP-SIM-Selected-Version 16 short ATTRIBUTE EAP-SIM-Fullauth-ID-Req 17 bool ATTRIBUTE EAP-SIM-Client-Error-Code 22 short -VALUE EAP-SIM-Client-Error-Code Unable-To-Process-Packet 0 -VALUE EAP-SIM-Client-Error-Code Unsupported-Version 1 -VALUE EAP-SIM-Client-Error-Code Insufficient-Challenges 2 -VALUE EAP-SIM-Client-Error-Code RANDS-Not-Fresh 3 +VALUE EAP-SIM-Client-Error-Code Unable-To-Process-Packet 0 +VALUE EAP-SIM-Client-Error-Code Unsupported-Version 1 +VALUE EAP-SIM-Client-Error-Code Insufficient-Challenges 2 +VALUE EAP-SIM-Client-Error-Code RANDS-Not-Fresh 3 # # Skippable-Attributes # -ATTRIBUTE EAP-SIM-IV 129 octets +ATTRIBUTE EAP-SIM-IV 129 octets[16] ATTRIBUTE EAP-SIM-Encr-Data 130 tlv encrypt=4 # # These attributes are reversibly encrypted # BEGIN-TLV EAP-SIM-Encr-Data -ATTRIBUTE EAP-SIM-Padding 6 octets +ATTRIBUTE EAP-SIM-Padding 6 octets # 4, 8, 12 bytes length ATTRIBUTE EAP-SIM-Counter 19 short ATTRIBUTE EAP-SIM-Counter-Too-Small 20 bool -ATTRIBUTE EAP-SIM-Nonce-S 21 octets +ATTRIBUTE EAP-SIM-Nonce-S 21 octets[16] ATTRIBUTE EAP-SIM-Next-Pseudonym 132 string ATTRIBUTE EAP-SIM-Next-Reauth-ID 133 string END-TLV EAP-SIM-Encr-Data -ATTRIBUTE EAP-SIM-Checkcode 134 octets ATTRIBUTE EAP-SIM-Result-Ind 137 bool # diff --git a/src/modules/rlm_eap/lib/sim/decode.c b/src/modules/rlm_eap/lib/sim/decode.c index 2fda2f84294..62a5e088ca0 100644 --- a/src/modules/rlm_eap/lib/sim/decode.c +++ b/src/modules/rlm_eap/lib/sim/decode.c @@ -56,7 +56,7 @@ RCSID("$Id$") * of 32 bits, and includes the Type/Length fields. */ -static ssize_t fr_sim_decode_pair_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, +static ssize_t sim_decode_pair_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decoder_ctx); static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, @@ -240,18 +240,19 @@ static ssize_t sim_value_decrypt(TALLOC_CTX *ctx, uint8_t **out, * - The number of elements in the array on success. * - < 0 on error (array length not a multiple of element size). */ -static int fr_sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *da) +static int sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *da) { size_t element_len; - *out = len; - /* * Could be an array of bytes, integers, etc. */ switch (da->type) { case FR_TYPE_OCTETS: - if (da->flags.length == 0) return 1; + if (da->flags.length == 0) { + fr_strerror_printf("%s: Octets array must have fixed length elements", __FUNCTION__); + return -1; + } element_len = da->flags.length; break; @@ -260,7 +261,10 @@ static int fr_sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *d break; } - if (element_len == 1) return 1; /* Fast path */ + if (element_len == 1) { + *out = 1; + return 1; /* Fast path */ + } if (!fr_cond_assert(element_len > 0)) return -1; @@ -274,13 +278,73 @@ static int fr_sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *d * Number of elements must divide exactly */ if (len % element_len) { - fr_strerror_printf("%s: Expected array value length to be multiple of %zu, got %zu", + fr_strerror_printf("%s: Expected array actual length to be multiple of %zu, got %zu", __FUNCTION__, element_len, len); return -1; } + *out = element_len; + return len / element_len; } +static ssize_t sim_decode_array(TALLOC_CTX *ctx, vp_cursor_t *cursor, + fr_dict_attr_t const *parent, + uint8_t const *data, size_t const attr_len, UNUSED size_t data_len, + void *decoder_ctx) +{ + uint8_t const *p = data, *end = p + attr_len; + uint16_t actual_len; + int elements, i; + size_t element_len; + ssize_t rcode; + + FR_PROTO_TRACE("Array attribute"); + + rad_assert(parent->flags.array); + rad_assert(attr_len >= 2); /* Should have been caught earlier */ + + /* + * Arrays with fixed length members that + * are a multiple of 4 don't need an + * actual_len value, as we can get the + * number of elements from the attribute + * length. + */ + if (!parent->flags.length || (parent->flags.length % 4)) { + actual_len = (p[0] << 8) | p[1]; + if (actual_len > (attr_len - 2)) { + fr_strerror_printf("%s: Actual length field value (%hu) > attribute value length (%zu)", + __FUNCTION__, actual_len, attr_len - 2); + return -1; + } + } else { + actual_len = attr_len - 2; /* -2 for the reserved bytes */ + } + p += 2; + + /* + * Zero length array + */ + if (!actual_len) return p - data; + + /* + * Get the number of elements + */ + elements = sim_array_members(&element_len, actual_len, parent); + if (elements < 0) return elements; + + for (i = 0; i < elements; i++) { + rcode = sim_decode_pair_value(ctx, cursor, parent, p, element_len, end - p, decoder_ctx); + if (rcode < 0) return rcode; + + p += rcode; + + if (!fr_cond_assert(p <= end)) break; + } + + return attr_len; /* Say we consumed attr_len because it may have padding */ +} + /** Break apart a TLV attribute into individual attributes * * @param[in] ctx to allocate new attributes in. @@ -292,7 +356,8 @@ static int fr_sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *d * @param[in] decoder_ctx IVs, keys etc... * @return * - Length on success. - * - -1 on failure. + * - -1 on malformed child attribute. + * - -2 on malformed TLV (this is ok > 128). */ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, @@ -305,11 +370,11 @@ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *child; VALUE_PAIR *head = NULL; vp_cursor_t tlv_cursor; - ssize_t rcode; + ssize_t rcode = -2; if (data_len < 2) { - fr_strerror_printf("Insufficient data"); - return -1; /* minimum attr size */ + fr_strerror_printf("%s: Insufficient data", __FUNCTION__); + return -2; /* minimum attr size */ } /* @@ -324,8 +389,8 @@ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, FR_PROTO_TRACE("found encrypted attribute '%s'", parent->name); decr_len = sim_value_decrypt(ctx, &decr, p + 2, - attr_len - 2, data_len - 2, decoder_ctx); /* Skip reserved */ - if (decr_len < 0) return decr_len; + attr_len - 2, data_len - 2, decoder_ctx); /* Skip reserved */ + if (decr_len < 0) return -2; p = decr; end = p + decr_len; @@ -348,7 +413,7 @@ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, error: talloc_free(decr); fr_pair_list_free(&head); - return -1; + return rcode; } /* @@ -358,18 +423,31 @@ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, * (16 in the case of AES-128-CBC). */ if (sim_at == FR_SIM_PADDING) { + uint8_t zero = 0; + uint8_t i; + if (!parent->flags.encrypt) { fr_strerror_printf("%s: Found padding attribute outside of an encrypted TLV", __FUNCTION__); - return -1; + goto error; } - if (!fr_cond_assert(data_len % 4)) return -1; + if (!fr_cond_assert(data_len % 4)) goto error; if (sim_at_len > 12) { fr_strerror_printf("%s: Expected padding attribute length <= 12 bytes, got %zu bytes", __FUNCTION__, sim_at_len); - return -1; + goto error; + } + + /* + * RFC says we MUST verify that FR_SIM_PADDING + * data is zeroed out. + */ + for (i = 2; i < sim_at_len; i++) zero |= p[i]; + if (zero) { + fr_strerror_printf("%s: Padding attribute value not zeroed", __FUNCTION__); + goto error; } p += sim_at_len; @@ -433,7 +511,6 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di { VALUE_PAIR *vp; uint8_t const *p = data; - uint8_t const *end = p + data_len; ssize_t rcode; fr_sim_decode_ctx_t *packet_ctx = decoder_ctx; @@ -444,77 +521,130 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di FR_PROTO_TRACE("Parent %s len %zu", parent->name, attr_len); FR_PROTO_HEX_DUMP(__FUNCTION__ , data, attr_len); + FR_PROTO_TRACE("Type \"%s\" (%u)", fr_int2str(dict_attr_types, parent->type, "?Unknown?"), parent->type); + /* - * It's an array type attribute with a fixed length, + * Special cases, attributes that either have odd formats, or need + * have information we need to decode the packet. + */ + switch (parent->attr) { + /* + * We need to record packet_ctx so we can decrypt AT_ENCR attributes. + * + * If we don't find it before, then that's fine, we'll try and + * find it in the rest of the packet after the encrypted + * attribute. + * + * 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_IV | Length = 5 | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Initialization Vector | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ - if (parent->flags.array) { - uint16_t actual_len; - int elements, i; - size_t element_len; + case FR_SIM_IV: + if (sim_iv_extract(&packet_ctx->iv[0], data, attr_len) < 0) return -1; + packet_ctx->have_iv = true; + break; /* Now create the attribute */ - FR_PROTO_TRACE("Array attribute"); + /* + * AT_RES - Special case (RES length is in bits) + * + * 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_RES | Length | RES Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| + * | | + * | RES | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + case FR_EAP_AKA_RES: + { + uint16_t res_len; - if (attr_len < 2) { - fr_strerror_printf("%s: Missing length field", __FUNCTION__); + if (attr_len < 2) goto raw; /* Need at least two bytes for the length field */ + + res_len = (p[0] << 8) | p[1]; + if (res_len % 8) { + fr_strerror_printf("%s: RES Length (%hu) is not a multiple of 8", + __FUNCTION__, res_len); return -1; } + res_len /= 8; - actual_len = (p[0] << 8) | p[1]; - if (actual_len > (attr_len - 2)) { - fr_strerror_printf("%s: Actual length field value (%hu) > attribute value length (%zu)", - __FUNCTION__, actual_len, attr_len - 2); + if (res_len > (attr_len - 2)) { + fr_strerror_printf("%s: RES Length field value (%hu) > attribute value length (%zu)", + __FUNCTION__, res_len, (attr_len - 2)); return -1; } - /* - * Get the number of elements - */ - elements = fr_sim_array_members(&element_len, actual_len, parent); - if (elements < 0) return elements; - - for (i = 0; i < elements; i++) { - rcode = sim_decode_pair_value(ctx, cursor, parent, p, element_len, end - p, decoder_ctx); - if (rcode < 0) return rcode; - - p += rcode; - - if (!fr_cond_assert(p <= end)) break; - } + vp = fr_pair_afrom_da(ctx, parent); + if (!vp) return -1; - return p - data; + fr_pair_value_memcpy(vp, p + 2, attr_len - 2); } + goto done; /* - * We need to record packet_ctx so we can decrypt AT_ENCR attributes. + * AT_AUTS - Octets type with no reserved field * - * If we don't find it before, then that's fine, we'll try and - * find it in the rest of the packet after the encrypted - * attribute. + * 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_AUTS | Length = 4 | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + * | | + * | AUTS | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ - if (parent->attr == FR_SIM_IV) { - if (sim_iv_extract(&packet_ctx->iv[0], data, attr_len) < 0) return -1; - packet_ctx->have_iv = true; - return attr_len; - } - - FR_PROTO_TRACE("Type \"%s\" (%u)", fr_int2str(dict_attr_types, parent->type, "?Unknown?"), parent->type); - switch (parent->type) { - case FR_TYPE_STRING: - case FR_TYPE_OCTETS: - if (parent->flags.length && (attr_len != parent->flags.length)) { + case FR_EAP_AKA_AUTS: + if (parent->flags.length != attr_len) { + wrong_len: fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, " "but value was %zu bytes", __FUNCTION__, parent->name, (size_t)parent->flags.length, attr_len); goto raw; } + vp = fr_pair_afrom_da(ctx, parent); + fr_pair_value_memcpy(vp, p, attr_len); + goto done; + + default: break; + } - case FR_TYPE_BOOL: - if (attr_len != 2) goto raw; + switch (parent->type) { + case FR_TYPE_STRING: + if (attr_len < 2) goto raw; /* Need at least two bytes for the length field */ + if (parent->flags.length && (attr_len != parent->flags.length)) goto wrong_len; + break; + + case FR_TYPE_OCTETS: + /* + * If it's not an array, then the octets fields + * have a two byte reserved prefix. + */ + if (!parent->flags.array) { + if (parent->flags.length && (attr_len != (parent->flags.length + 2))) goto wrong_len; + } else { + if (parent->flags.length && (attr_len != (parent->flags.length))) goto wrong_len; + } break; + case FR_TYPE_BOOL: + case FR_TYPE_UINT8: case FR_TYPE_UINT16: - if (attr_len != 2) goto raw; + case FR_TYPE_UINT32: + case FR_TYPE_UINT64: + if (attr_len != fr_sim_attr_sizes[parent->type][0]) goto raw; break; case FR_TYPE_TLV: @@ -525,12 +655,26 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di * attribute, OR they've already been grouped * into a contiguous memory buffer. */ - rcode = sim_decode_tlv(ctx, cursor, parent, p, attr_len, data_len, decoder_ctx); /* +2 for reserved */ - if (rcode < 0) { - FR_PROTO_TRACE("Failed decoding TLV: %s", fr_strerror()); + rcode = sim_decode_tlv(ctx, cursor, parent, p, attr_len, data_len, decoder_ctx); + switch (rcode) { + case 0: + break; + + /* + * TLV malformed (this is OK, we decode as raw) + * as required for attribute numbers > 128. + */ + case -2: + FR_PROTO_TRACE("Failed decoding TLV: %s", fr_strerror_peek()); goto raw; + + /* + * Child attribute caused error (this is fatal) + */ + default: + return rcode; } - return rcode; + default: raw: @@ -539,8 +683,8 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di * as we're prohibited from continuing by the SIM RFCs. */ if (parent->attr <= SIM_SKIPPABLE_MAX) { - fr_strerror_printf("%s: Failed parsing non-skippable attribute '%s'", - __FUNCTION__, parent->name); + fr_strerror_printf_push("%s: Failed parsing non-skippable attribute '%s'", + __FUNCTION__, parent->name); return -1; } @@ -559,28 +703,52 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di vp = fr_pair_afrom_da(ctx, parent); if (!vp) return -1; + /* + * For unknown attributes copy the entire value, not skipping + * any reserved bytes. + */ + if (parent->flags.is_unknown || parent->flags.is_raw) { + fr_pair_value_memcpy(vp, p, attr_len); + vp->vp_length = attr_len; + goto done; + } + switch (parent->type) { /* - * Strings have a two byte 'real length' field in front of the - * actual value, and that gives us the length of the string value. + * 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_ | Length | Actual Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * . String . + * . . + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ case FR_TYPE_STRING: { - uint16_t str_len = (p[0] << 8) | p[1]; + uint16_t actual_len = (p[0] << 8) | p[1]; - if (str_len > (attr_len - 2)) { - fr_strerror_printf("%s: String value length (%hu) > attribute value length (%zu)", - __FUNCTION__, str_len, attr_len - 2); + if (actual_len > (attr_len - 2)) { + fr_strerror_printf("%s: Actual length field value (%hu) > attribute value length (%zu)", + __FUNCTION__, actual_len, attr_len - 2); return -1; } - fr_pair_value_bstrncpy(vp, p + 2, str_len); + fr_pair_value_bstrncpy(vp, p + 2, actual_len); } break; case FR_TYPE_OCTETS: - fr_pair_value_memcpy(vp, p + 2, attr_len - 2); /* -2 for reserved field */ - vp->vp_length = attr_len - 2; + /* + * Non-array attributes have a 2 byte padding + */ + if (!vp->da->flags.array) { + fr_pair_value_memcpy(vp, p + 2, attr_len - 2); /* -2 for reserved field */ + } else { + fr_pair_value_memcpy(vp, p, attr_len); + } break; /* @@ -597,8 +765,35 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di vp->vp_bool = true; break; + /* + * Numbers are network byte order. + * + * In the base RFCs only short (16bit) unsigned integers are used. + * We add support for more, just for completeness. + * + * 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_ | Length = 1 | Short 1 | Short 2 | + * +---------------+---------------+-------------------------------+ + */ + case FR_TYPE_UINT8: + vp->vp_uint8 = p[0]; + break; + case FR_TYPE_UINT16: - vp->vp_uint16 = (p[0] << 8) | p[1]; + memcpy(&vp->vp_uint16, p, sizeof(vp->vp_uint16)); + vp->vp_uint16 = ntohs(vp->vp_uint32); + break; + + case FR_TYPE_UINT32: + memcpy(&vp->vp_uint32, p, sizeof(vp->vp_uint32)); + vp->vp_uint32 = ntohl(vp->vp_uint32); + break; + + case FR_TYPE_UINT64: + memcpy(&vp->vp_uint64, p, sizeof(vp->vp_uint64)); + vp->vp_uint64 = ntohll(vp->vp_uint64); break; default: @@ -607,6 +802,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di return -1; } +done: vp->type = VT_DATA; fr_pair_cursor_append(cursor, vp); @@ -627,8 +823,8 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di * - The number of bytes parsed. * - -1 on error. */ -static ssize_t fr_sim_decode_pair_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, - uint8_t const *data, size_t data_len, void *decoder_ctx) +static ssize_t sim_decode_pair_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, + uint8_t const *data, size_t data_len, void *decoder_ctx) { uint8_t sim_at; size_t sim_at_len; @@ -636,16 +832,28 @@ static ssize_t fr_sim_decode_pair_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, ssize_t rcode; fr_dict_attr_t const *da; - sim_at_len = ((size_t)data[1]) << 2; - if ((data_len < sizeof(uint32_t)) || (sim_at_len > data_len)) { - fr_strerror_printf("%s: Insufficient data", __FUNCTION__); + /* + * We need at least 2 bytes. We really need 4 but it's + * useful to print the attribute number in the errors. + */ + if (data_len < 2) { + fr_strerror_printf("%s: Insufficient data: Expected >= 2 bytes, got %zu bytes", + __FUNCTION__, data_len); return -1; } sim_at = data[0]; + + sim_at_len = ((size_t)data[1]) << 2; + if (sim_at_len > data_len) { + fr_strerror_printf("%s: Insufficient data for attribute %d: Length field %zu, remaining data %zu", + __FUNCTION__, sim_at, sim_at_len, data_len); + return -1; + } + if (sim_at_len == 0) { - fr_strerror_printf("%s: Malformed attribute %d: Length field is zero", __FUNCTION__, sim_at); + fr_strerror_printf("%s: Malformed attribute %d: Length field 0", __FUNCTION__, sim_at); return -1; } @@ -669,7 +877,11 @@ static ssize_t fr_sim_decode_pair_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, FR_PROTO_TRACE("decode context changed %s -> %s", da->parent->name, da->name); - rcode = sim_decode_pair_value(ctx, cursor, da, data + 2, sim_at_len - 2, data_len - 2, decoder_ctx); + if (da->flags.array) { + rcode = sim_decode_array(ctx, cursor, da, data + 2, sim_at_len - 2, data_len - 2, decoder_ctx); + } else { + rcode = sim_decode_pair_value(ctx, cursor, da, data + 2, sim_at_len - 2, data_len - 2, decoder_ctx); + } if (rcode < 0) return rcode; return 2 + rcode; @@ -693,7 +905,7 @@ ssize_t fr_sim_decode_pair(TALLOC_CTX *ctx, vp_cursor_t *cursor, { fr_sim_decode_ctx_t *packet_ctx = decoder_ctx; - return fr_sim_decode_pair_internal(ctx, cursor, packet_ctx->root, data, data_len, decoder_ctx); + return sim_decode_pair_internal(ctx, cursor, packet_ctx->root, data, data_len, decoder_ctx); } /** Decode SIM/AKA/AKA' specific packet data @@ -813,6 +1025,21 @@ static void *decode_test_ctx_aka(UNUSED TALLOC_CTX *ctx) return &test_ctx; } +static void *decode_test_ctx_sim_rfc4186(UNUSED TALLOC_CTX *ctx) +{ + static fr_sim_decode_ctx_t test_ctx; + static fr_sim_keys_t keys = { + .k_encr = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a, + 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 } + }; + fr_sim_global_init(); + + test_ctx.root = dict_sim_root; + test_ctx.keys = &keys; + + return &test_ctx; +} + /* * Test points */ @@ -822,6 +1049,12 @@ fr_test_point_pair_decode_t sim_tp_decode = { .func = fr_sim_decode_pair }; +extern fr_test_point_pair_decode_t sim_tp_decode_rfc4186; +fr_test_point_pair_decode_t sim_tp_decode_rfc4186 = { + .test_ctx = decode_test_ctx_sim_rfc4186, + .func = fr_sim_decode_pair +}; + extern fr_test_point_pair_decode_t aka_tp_decode; fr_test_point_pair_decode_t aka_tp_decode = { .test_ctx = decode_test_ctx_aka, diff --git a/src/modules/rlm_eap/lib/sim/encode.c b/src/modules/rlm_eap/lib/sim/encode.c index ef3bfeb187d..42bc99c19d5 100644 --- a/src/modules/rlm_eap/lib/sim/encode.c +++ b/src/modules/rlm_eap/lib/sim/encode.c @@ -298,6 +298,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, ssize_t len; VALUE_PAIR const *vp = fr_pair_cursor_current(cursor); fr_dict_attr_t const *da = tlv_stack[depth]; + fr_sim_encode_ctx_t *packet_ctx = encoder_ctx; VP_VERIFY(vp); FR_PROTO_STACK_PRINT(tlv_stack, depth); @@ -322,28 +323,141 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, break; } - switch (da->type) { - case FR_TYPE_OCTETS: + switch (da->attr) { + /* + * Allow manual override of IV - Mostly for testing or debugging + * + * 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_IV | Length = 5 | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Initialization Vector | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + case FR_SIM_IV: + if ((vp->da->flags.length && (da->flags.length != vp->vp_length)) || + (vp->vp_length != sizeof(packet_ctx->iv))) { + fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, " + "but value was %zu bytes", __FUNCTION__, + da->name, (size_t)da->flags.length, vp->vp_length); + return -1; + } + memcpy(packet_ctx->iv, vp->vp_octets, sizeof(packet_ctx->iv)); + packet_ctx->iv_included = true; + break; /* Encode IV */ + + /* + * AT_RES - Special case (RES length is in bits) + * + * 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_RES | Length | RES Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| + * | | + * | RES | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + case FR_EAP_AKA_RES: { + uint16_t res_len = htons(vp->vp_length * 8); /* Get length in bits */ size_t rounded_len = (vp->vp_length + 3) & ~3; size_t pad_len = rounded_len - vp->vp_length; uint8_t *p = out; + if ((vp->vp_length < 4) || (vp->vp_length > 16)) { + fr_strerror_printf("%s: AKA-RES Length must be between 4-16 bytes, got %zu bytes", + __FUNCTION__, vp->vp_length); + return -1; + } + if ((rounded_len + 2) > outlen) { oos: fr_strerror_printf("%s: Attribute exceeds available buffer space", __FUNCTION__); return -1; } - *p++ = 0; /* Reserved */ - *p++ = 0; /* Reserved */ + memcpy(p, &res_len, sizeof(res_len)); /* RES Length (bits, big endian) */ + p += sizeof(res_len); - if (vp->da->flags.length && (vp->vp_length != vp->da->flags.length)) { + memcpy(p, vp->vp_octets, vp->vp_length); + p += vp->vp_length; + + if (pad_len) { + memset(p, 0, pad_len); + p += pad_len; + } + + len = p - out; + } + goto done; + + /* + * AT_AUTS - Octets type with no reserved field + * + * 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_AUTS | Length = 4 | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + * | | + * | AUTS | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + case FR_EAP_AKA_AUTS: + if (vp->da->flags.length && (da->flags.length != vp->vp_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); + da->name, (size_t)da->flags.length, vp->vp_length); return -1; } + if (vp->vp_length > outlen) goto oos; + + memcpy(out, vp->vp_octets, vp->vp_length); + len = vp->vp_length; + goto done; + + default: + break; + } + + switch (da->type) { + case FR_TYPE_OCTETS: + { + size_t rounded_len; + size_t pad_len; + uint8_t *p = out; + + /* + * Autopad attributes + */ + if (vp->da->flags.length && (vp->vp_length != vp->da->flags.length)) { + rounded_len = (vp->vp_length + (vp->da->flags.length - 1)) & ~(vp->da->flags.length - 1); + pad_len = rounded_len - vp->vp_length; + } else { + rounded_len = (vp->vp_length + 3) & ~3; + pad_len = rounded_len - vp->vp_length; + } + + /* + * Non-array attributes have a 2 byte padding + */ + if (!vp->da->flags.array) { + if ((rounded_len + 2) > outlen) goto oos; + + *p++ = 0; /* Reserved */ + *p++ = 0; /* Reserved */ + /* + * Fixed length array attributes have no padding + */ + } else if (rounded_len > outlen) goto oos; memcpy(p, vp->vp_octets, vp->vp_length); p += vp->vp_length; @@ -449,6 +563,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, return -1; } +done: /* * Rebuilds the TLV stack for encoding the next attribute */ @@ -483,19 +598,30 @@ static ssize_t encode_array(uint8_t *out, size_t outlen, uint8_t *p = out, *end = p + outlen; uint8_t *value; size_t pad_len; + size_t element_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 */ + if (da->type == FR_TYPE_OCTETS) { + if (!da->flags.length) { + fr_strerror_printf("Can't encode array type attribute \"%s\" as it does not " + "have a fixed length", da->name); + return -1; + } + element_len = da->flags.length; + } else { + element_len = fr_sim_attr_sizes[da->type][0]; + } + /* * Keep encoding as long as we have space to * encode things. */ - while (fr_sim_attr_sizes[da->type][0] <= ((size_t)(end - p))) { + while (element_len <= ((size_t)(end - p))) { VALUE_PAIR *vp; ssize_t slen; @@ -508,8 +634,20 @@ static ssize_t encode_array(uint8_t *out, size_t outlen, 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)); + /* + * Arrays with an element size which is + * a multiple of 4 don't need an + * actual_length field, because the number + * of elements can be calculated from + * the attribute length. + */ + if (element_len % 4) { + actual_len = htons((p - value) & UINT16_MAX); /* Length of the elements we encoded */ + memcpy(out, &actual_len, sizeof(actual_len)); + } else { + out[0] = 0; + out[1] = 0; + } /* * Pad value a multiple of 4 @@ -966,6 +1104,21 @@ static void *encode_test_ctx_aka(UNUSED TALLOC_CTX *ctx) return &test_ctx; } +static void *encode_test_ctx_sim_rfc4186(UNUSED TALLOC_CTX *ctx) +{ + static fr_sim_encode_ctx_t test_ctx; + static fr_sim_keys_t keys = { + .k_encr = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a, + 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 } + }; + fr_sim_global_init(); + + test_ctx.root = dict_sim_root; + test_ctx.keys = &keys; + + return &test_ctx; +} + /* * Test points */ @@ -980,3 +1133,9 @@ fr_test_point_pair_encode_t aka_tp_encode = { .test_ctx = encode_test_ctx_aka, .func = fr_sim_encode_pair }; + +extern fr_test_point_pair_encode_t sim_tp_encode_rfc4186; +fr_test_point_pair_encode_t sim_tp_encode_rfc4186 = { + .test_ctx = encode_test_ctx_sim_rfc4186, + .func = fr_sim_encode_pair +}; diff --git a/src/tests/unit/all.mk b/src/tests/unit/all.mk index 3000ecf37df..2959c94c457 100644 --- a/src/tests/unit/all.mk +++ b/src/tests/unit/all.mk @@ -13,7 +13,11 @@ FILES := \ radius_lucent.txt \ radius_wimax.txt \ radius_vendor.txt \ - eap-sim.txt \ + eap_aka_encode.txt \ + eap_aka_decode.txt \ + eap_sim_encode.txt \ + eap_sim_decode.txt \ + eap_sim_error.txt \ dhcp.txt \ tlv.txt \ tunnel.txt \ diff --git a/src/tests/unit/eap_aka_decode.txt b/src/tests/unit/eap_aka_decode.txt new file mode 100644 index 00000000000..4dbfbb44fd3 --- /dev/null +++ b/src/tests/unit/eap_aka_decode.txt @@ -0,0 +1,24 @@ +# +# Tests for the EAP-SIM/AKA/AKA' decoder and decoder +# + +# Only run the tests if we have TLS support +need-feature tls + +# Load the EAP-SIM module +load eap-sim + +# +# Encode some AKA attributes with special formats +# + +# EAP-AKA-Res is an octets type attribute but with a length field containing the length +# of the value in bits. It may be between 32 - 128 bits in length. +decode-pair.aka_tp_decode 03 02 00 20 01 02 03 04 +data EAP-AKA-RES = 0x01020304 + +decode-pair.aka_tp_decode 03 05 00 80 01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08 +data EAP-AKA-RES = 0x01020304050607080102030405060708 + +decode-pair.aka_tp_decode 04 04 01 02 03 04 05 06 07 08 09 aa bb cc dd ee +data EAP-AKA-AUTS = 0x010203040506070809aabbccddee diff --git a/src/tests/unit/eap_aka_encode.txt b/src/tests/unit/eap_aka_encode.txt new file mode 100644 index 00000000000..7800214b35c --- /dev/null +++ b/src/tests/unit/eap_aka_encode.txt @@ -0,0 +1,24 @@ +# +# Tests for the EAP-SIM/AKA/AKA' encoder and decoder +# + +# Only run the tests if we have TLS support +need-feature tls + +# Load the EAP-SIM module +load eap-sim + +# +# Encode some AKA attributes with special formats +# + +# EAP-AKA-Res is an octets type attribute but with a length field containing the length +# of the value in bits. It may be between 32 - 128 bits in length. +encode-pair.aka_tp_encode EAP-AKA-RES = 0x01020304 +data 03 02 00 20 01 02 03 04 + +encode-pair.aka_tp_encode EAP-AKA-RES = 0x01020304050607080102030405060708 +data 03 05 00 80 01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08 + +encode-pair.aka_tp_encode EAP-AKA-AUTS = 0x010203040506070809aabbccddee +data 04 04 01 02 03 04 05 06 07 08 09 aa bb cc dd ee diff --git a/src/tests/unit/eap_sim_decode.txt b/src/tests/unit/eap_sim_decode.txt new file mode 100644 index 00000000000..2a0beca9d0c --- /dev/null +++ b/src/tests/unit/eap_sim_decode.txt @@ -0,0 +1,99 @@ +# +# Tests for the EAP-SIM/AKA/AKA' encoder and decoder +# + +# Encrypted attributes tested in eap_sim_encode + +# Only run the tests if we have TLS support +need-feature tls + +# Load the EAP-SIM module +load eap-sim + +# Boolean attribute +decode-pair.sim_tp_decode 0d 01 00 00 +data EAP-SIM-Any-ID-Req = yes + +# Short +decode-pair.sim_tp_decode 10 01 ff ff +data EAP-SIM-Selected-Version = 65535 + +# Octets +decode-pair.sim_tp_decode 01 05 00 00 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 +data EAP-SIM-RAND = 0x00112233445566770011223344556677 + +# Aliased (found) +decode-pair.sim_tp_decode 0c 01 04 02 +data EAP-SIM-Notification = Temporarily-Denied + +# Aliased (notfound) +decode-pair.sim_tp_decode 0c 01 ff ff +data EAP-SIM-Notification = 65535 + +# No string padding +decode-pair.sim_tp_decode 0e 05 00 10 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 69 +data EAP-SIM-Identity = "testing123@simfi" + +# Three bytes string padding +decode-pair.sim_tp_decode 0e 05 00 0d 74 65 73 74 69 6e 67 31 32 33 40 73 69 00 00 00 +data EAP-SIM-Identity = "testing123@si" + +# Two bytes string padding +decode-pair.sim_tp_decode 0e 05 00 0e 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 00 00 +data EAP-SIM-Identity = "testing123@sim" + +# One byte string padding +decode-pair.sim_tp_decode 0e 05 00 0f 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 00 +data EAP-SIM-Identity = "testing123@simf" + +# Empty string +decode-pair.sim_tp_decode 0e 01 00 00 +data EAP-SIM-Identity = "" + +# Two attributes +decode-pair.sim_tp_decode 0e 05 00 10 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 69 0d 01 00 00 +data EAP-SIM-Identity = "testing123@simfi", EAP-SIM-Any-ID-Req = yes + +# Array (one element) +decode-pair.sim_tp_decode 0f 02 00 02 00 02 00 00 +data EAP-SIM-Version-List = 2 + +# Array (multiple elements, with padding) +decode-pair.sim_tp_decode 0f 03 00 06 00 02 00 03 00 04 00 00 +data EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 3, EAP-SIM-Version-List = 4 + +# Array (multiple elements, with no padding) +decode-pair.sim_tp_decode 0f 03 00 08 00 02 ff ff 00 ff ff 00 +data EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 65535, EAP-SIM-Version-List = 255, EAP-SIM-Version-List = 65280 + +# Zero length array +decode-pair.sim_tp_decode 0f 01 00 00 +data + +# Empty TLV +decode-pair.sim_tp_decode 82 01 00 00 +data + +# RFC4186 A.3. example +decode-pair.sim_tp_decode_rfc4186 0f 02 00 02 00 01 00 00 +data EAP-SIM-Version-List = 1 + +# RFC4186 A.4. example +decode-pair.sim_tp_decode_rfc4186 07 05 00 00 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10 10 01 00 01 +data EAP-SIM-Nonce-MT = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Selected-Version = 1 + +# RFC4186 A.5. example +decode-pair.sim_tp_decode_rfc4186 01 0d 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 81 05 00 00 9e 18 b0 c2 9a 65 22 63 c0 6e fb 54 dd 00 a8 95 82 2d 00 00 55 f2 93 9b bd b1 b1 9e a1 b4 7f c0 b3 e0 be 4c ab 2c f7 37 2d 98 e3 02 3c 6b b9 24 15 72 3d 58 ba d6 6c e0 84 e1 01 b6 0f 53 58 35 4b d4 21 82 78 ae a7 bf 2c ba ce 33 10 6a ed dc 62 5b 0c 1d 5a a6 7a 41 73 9a e5 b5 79 50 97 3f c7 ff 83 01 07 3c 6f 95 31 50 fc 30 3e a1 52 d1 e1 0a 2d 1f 4f 52 26 da a1 ee 90 05 47 22 52 bd b3 b7 1d 6f 0c 3a 34 90 31 6c 46 92 98 71 bd 45 cd fd bc a6 11 2f 07 f8 be 71 79 90 d2 5f 6d d7 f2 b7 b3 20 bf 4d 5a 99 2e 88 03 31 d7 29 94 5a ec 75 ae 5d 43 c8 ed a5 fe 62 33 fc ac 49 4e e6 7a 0d 50 4d 0b 05 00 00 fe f3 24 ac 39 62 b5 9f 3b d7 82 53 ae 4d cb 6a +data EAP-SIM-RAND = 0x101112131415161718191a1b1c1d1e1f, EAP-SIM-RAND = 0x202122232425262728292a2b2c2d2e2f, EAP-SIM-RAND = 0x303132333435363738393a3b3c3d3e3f, EAP-SIM-IV = 0x9e18b0c29a652263c06efb54dd00a895, EAP-SIM-Next-Pseudonym = "w8w49PexCazWJ&xCIARmxuMKht5S1sxRDqXSEFBEg3DcZP9cIxTe5J4OyIwNGVzxeJOU1G", EAP-SIM-Next-Reauth-ID = "Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo", EAP-SIM-MAC = 0xfef324ac3962b59f3bd78253ae4dcb6a + +# RFC4186 A.6. example +decode-pair.sim_tp_decode_rfc4186 0b 05 00 00 f5 6d 64 33 e6 8e d2 97 6a c1 19 37 fc 3d 11 54 +data EAP-SIM-MAC = 0xf56d6433e68ed2976ac11937fc3d1154 + +# RFC4186 A.9. example +decode-pair.sim_tp_decode_rfc4186 81 05 00 00 d5 85 ac 77 86 b9 03 36 65 7c 77 b4 65 75 b9 c4 82 1d 00 00 68 62 91 a9 d2 ab c5 8c aa 32 94 b6 e8 5b 44 84 6c 44 e5 dc b2 de 8b 9e 80 d6 9d 49 85 8a 5d b8 4c dc 1c 9b c9 5c 01 b9 6b 6e ca 31 34 74 ae a6 d3 14 16 e1 9d aa 9d f7 0f 05 00 88 41 ca 80 14 96 4d 3b 30 a4 9b cf 43 e4 d3 f1 8e 86 29 5a 4a 2b 38 d9 6c 97 05 c2 bb b0 5c 4a ac e9 7d 5e af f5 64 04 6c 8b d3 0b c3 9b e5 e1 7a ce 2b 10 a6 0b 05 00 00 48 3a 17 99 b8 3d 7c d3 d0 a1 e4 01 d9 ee 47 70 +data EAP-SIM-IV = 0xd585ac7786b90336657c77b46575b9c4, EAP-SIM-Counter = 1, EAP-SIM-Nonce-S = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Next-Reauth-ID = "uta0M0iyIsMwWp5TTdSdnOLvg2XDVf21OYt1vnfiMcs5dnIDHOIFVavIRzMRyzW6vFzdHW@eapsim.foo", EAP-SIM-MAC = 0x483a1799b83d7cd3d0a1e401d9ee4770 + +# RFC4186 A.10. example +decode-pair.sim_tp_decode_rfc4186 81 05 00 00 cd f7 ff a6 5d e0 4c 02 6b 56 c8 6b 76 b1 02 ea 82 05 00 00 b6 ed d3 82 79 e2 a1 42 3c 1a fc 5c 45 5c 7d 56 0b 05 00 00 fa f7 6b 71 fb e2 d2 55 b9 6a 35 66 c9 15 c6 17 +data EAP-SIM-IV = 0xcdf7ffa65de04c026b56c86b76b102ea, EAP-SIM-Counter = 1, EAP-SIM-MAC = 0xfaf76b71fbe2d255b96a3566c915c617 diff --git a/src/tests/unit/eap-sim.txt b/src/tests/unit/eap_sim_encode.txt similarity index 54% rename from src/tests/unit/eap-sim.txt rename to src/tests/unit/eap_sim_encode.txt index f91dc746781..25cbdefc389 100644 --- a/src/tests/unit/eap-sim.txt +++ b/src/tests/unit/eap_sim_encode.txt @@ -17,15 +17,15 @@ encode-pair.sim_tp_encode EAP-SIM-Selected-Version = 1 data 10 01 00 01 # Octets -encode-pair.sim_tp_encode EAP-SIM-Rand = 0x00112233445566770011223344556677 +encode-pair.sim_tp_encode EAP-SIM-RAND = 0x00112233445566770011223344556677 data 01 05 00 00 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 # Octets (autopad) -encode-pair.sim_tp_encode EAP-SIM-Rand = 0x11 -data 01 02 00 00 11 00 00 00 +encode-pair.sim_tp_encode EAP-SIM-RAND = 0x11 +data 01 05 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Empty octets -encode-pair.sim_tp_encode EAP-SIM-Rand = 0x +encode-pair.sim_tp_encode EAP-SIM-RAND = 0x data 01 01 00 00 # Aliased @@ -96,3 +96,22 @@ data 0f 03 00 06 00 01 00 02 00 03 00 00 encode-pair.sim_tp_encode 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 +# RFC4186 A.3. example +encode-pair.sim_tp_encode_rfc4186 EAP-SIM-Version-List = 1 +data 0f 02 00 02 00 01 00 00 + +# RFC4186 A.4. example +encode-pair.sim_tp_encode_rfc4186 EAP-SIM-Nonce-MT = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Selected-Version = 1 +data 07 05 00 00 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10 10 01 00 01 + +# RFC4186 A.5. example +encode-pair.sim_tp_encode_rfc4186 EAP-SIM-RAND = 0x101112131415161718191a1b1c1d1e1f, EAP-SIM-RAND = 0x202122232425262728292a2b2c2d2e2f, EAP-SIM-RAND = 0x303132333435363738393a3b3c3d3e3f, EAP-SIM-IV = 0x9e18b0c29a652263c06efb54dd00a895, EAP-SIM-Next-Pseudonym = "w8w49PexCazWJ&xCIARmxuMKht5S1sxRDqXSEFBEg3DcZP9cIxTe5J4OyIwNGVzxeJOU1G", EAP-SIM-Next-Reauth-ID = "Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo" +data 01 0d 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 81 05 00 00 9e 18 b0 c2 9a 65 22 63 c0 6e fb 54 dd 00 a8 95 82 2d 00 00 55 f2 93 9b bd b1 b1 9e a1 b4 7f c0 b3 e0 be 4c ab 2c f7 37 2d 98 e3 02 3c 6b b9 24 15 72 3d 58 ba d6 6c e0 84 e1 01 b6 0f 53 58 35 4b d4 21 82 78 ae a7 bf 2c ba ce 33 10 6a ed dc 62 5b 0c 1d 5a a6 7a 41 73 9a e5 b5 79 50 97 3f c7 ff 83 01 07 3c 6f 95 31 50 fc 30 3e a1 52 d1 e1 0a 2d 1f 4f 52 26 da a1 ee 90 05 47 22 52 bd b3 b7 1d 6f 0c 3a 34 90 31 6c 46 92 98 71 bd 45 cd fd bc a6 11 2f 07 f8 be 71 79 90 d2 5f 6d d7 f2 b7 b3 20 bf 4d 5a 99 2e 88 03 31 d7 29 94 5a ec 75 ae 5d 43 c8 ed a5 fe 62 33 fc ac 49 4e e6 7a 0d 50 4d + +# RFC4186 A.9. example +encode-pair.sim_tp_encode_rfc4186 EAP-SIM-IV = 0xd585ac7786b90336657c77b46575b9c4, EAP-SIM-Counter = 1, EAP-SIM-Nonce-S = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Next-Reauth-ID = "uta0M0iyIsMwWp5TTdSdnOLvg2XDVf21OYt1vnfiMcs5dnIDHOIFVavIRzMRyzW6vFzdHW@eapsim.foo" +data 81 05 00 00 d5 85 ac 77 86 b9 03 36 65 7c 77 b4 65 75 b9 c4 82 1d 00 00 68 62 91 a9 d2 ab c5 8c aa 32 94 b6 e8 5b 44 84 6c 44 e5 dc b2 de 8b 9e 80 d6 9d 49 85 8a 5d b8 4c dc 1c 9b c9 5c 01 b9 6b 6e ca 31 34 74 ae a6 d3 14 16 e1 9d aa 9d f7 0f 05 00 88 41 ca 80 14 96 4d 3b 30 a4 9b cf 43 e4 d3 f1 8e 86 29 5a 4a 2b 38 d9 6c 97 05 c2 bb b0 5c 4a ac e9 7d 5e af f5 64 04 6c 8b d3 0b c3 9b e5 e1 7a ce 2b 10 a6 + +# RFC4186 A.10. example +encode-pair.sim_tp_encode_rfc4186 EAP-SIM-IV = 0xcdf7ffa65de04c026b56c86b76b102ea, EAP-SIM-Counter = 1 +data 81 05 00 00 cd f7 ff a6 5d e0 4c 02 6b 56 c8 6b 76 b1 02 ea 82 05 00 00 b6 ed d3 82 79 e2 a1 42 3c 1a fc 5c 45 5c 7d 56 diff --git a/src/tests/unit/eap_sim_error.txt b/src/tests/unit/eap_sim_error.txt new file mode 100644 index 00000000000..6d4cf06594b --- /dev/null +++ b/src/tests/unit/eap_sim_error.txt @@ -0,0 +1,72 @@ +# +# Tests for the EAP-SIM/AKA/AKA' encoder and decoder +# + +# Encrypted attributes tested in eap_sim_encode + +# Only run the tests if we have TLS support +need-feature tls + +# Load the EAP-SIM module +load eap-sim + +# Zero length attribute +decode-pair.sim_tp_decode 0d 00 +data sim_decode_pair_internal: Malformed attribute 13: Length field 0 + +# No length field +decode-pair.sim_tp_decode 0d +data sim_decode_pair_internal: Insufficient data: Expected >= 2 bytes, got 1 bytes + +# Boolean attribute (without reserved bytes) +decode-pair.sim_tp_decode 0d 01 +data sim_decode_pair_internal: Insufficient data for attribute 13: Length field 4, remaining data 2 + +# Boolean attribute (invalid length field) +decode-pair.sim_tp_decode 0d 00 00 00 +data sim_decode_pair_internal: Malformed attribute 13: Length field 0 + +# Boolean attribute (invalid length field) +decode-pair.sim_tp_decode 0d 02 00 00 +data sim_decode_pair_internal: Insufficient data for attribute 13: Length field 8, remaining data 4 + +# Unknown non-skippable attribute (99) +decode-pair.sim_tp_decode 63 01 00 00 +data Unknown (non-skippable) attribute 99 + +# Unknown skippable attribute (150) - Ensure the 'reserved bytes' in a normal octets +# attribute are not skipped. +decode-pair.sim_tp_decode 96 02 00 00 ff ff ff ff +data Attr-1220.150 = 0x0000ffffffff + +# Array missing length field +decode-pair.sim_tp_decode 0f 01 +data sim_decode_pair_internal: Insufficient data for attribute 15: Length field 4, remaining data 2 + +# Array actual length field > remaining data +decode-pair.sim_tp_decode 0f 01 00 01 +data sim_decode_array: Actual length field value (1) > attribute value length (0) + +# Array actual length not a multiple of the data type +decode-pair.sim_tp_decode 0f 02 00 03 00 00 00 00 +data sim_array_members: Expected array actual length to be multiple of 2, got 3 + +# Array actual length < element length +decode-pair.sim_tp_decode 0f 02 00 01 00 00 00 00 +data sim_array_members: Element length (2) > array length (1) + +# String actual length greater than value length +decode-pair.sim_tp_decode 0e 05 00 11 74 65 73 74 69 6e 67 31 32 33 40 73 69 00 00 00 +data sim_decode_pair_value: Actual length field value (17) > attribute value length (16) + +# String actual length (possible overflow) +decode-pair.sim_tp_decode 0e 05 ff ff 74 65 73 74 69 6e 67 31 32 33 40 73 69 00 00 00 +data sim_decode_pair_value: Actual length field value (65535) > attribute value length (16) + +# TLV encrypted data not a multiple of 16 (raw attribute) +decode-pair.sim_tp_decode 82 02 00 00 00 00 00 00 +data Attr-1220.130 = 0x000000000000 + +# TLV encrypted data multiple of 16, zeroed out +decode-pair.sim_tp_decode 82 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +data Attr-1220.130 = 0x000000000000000000000000000000000000