From: Arran Cudbard-Bell Date: Sun, 3 Dec 2017 21:32:06 +0000 (+0000) Subject: Remove special case for AUTS X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4836683a6e6f2a698aa09b79ea75bc3c49ed9fa3;p=thirdparty%2Ffreeradius-server.git Remove special case for AUTS --- diff --git a/src/modules/rlm_eap/lib/sim/base.c b/src/modules/rlm_eap/lib/sim/base.c index 04a630e6b29..e3fe4ac78fc 100644 --- a/src/modules/rlm_eap/lib/sim/base.c +++ b/src/modules/rlm_eap/lib/sim/base.c @@ -84,6 +84,17 @@ size_t fr_sim_attr_len(VALUE_PAIR const *vp) } } +/** Return the number of bytes before the octets value + * + */ +size_t fr_sim_octets_prefix_len(fr_dict_attr_t const *da) +{ + if (da->flags.array) return 0; /* Array elements have no padding */ + if (!da->flags.length) return 2; /* Variable length attributes need length field */ + if (!(da->flags.length % 4)) return 2; /* Values that are multiples of four have 2 reserved bytes */ + return 0; /* Everything else has zero padding bytes */ +} + /* * definitions changed to take a buffer for unknowns * as this is more thread safe. diff --git a/src/modules/rlm_eap/lib/sim/decode.c b/src/modules/rlm_eap/lib/sim/decode.c index 88d6d82bb97..001ea98dbb0 100644 --- a/src/modules/rlm_eap/lib/sim/decode.c +++ b/src/modules/rlm_eap/lib/sim/decode.c @@ -523,6 +523,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di { VALUE_PAIR *vp; uint8_t const *p = data; + size_t prefix = 0; fr_sim_decode_ctx_t *packet_ctx = decoder_ctx; @@ -609,31 +610,6 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di } 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 (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; } @@ -641,19 +617,22 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di 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; + if (parent->flags.length && (attr_len != parent->flags.length)) { + 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 + prefix, attr_len); + goto raw; + } break; case FR_TYPE_OCTETS: /* - * If it's not an array, then the octets fields - * have a two byte reserved prefix. + * Get the number of bytes we expect before the value */ - 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; - } + prefix = fr_sim_octets_prefix_len(parent); + if (attr_len < prefix) goto raw; + if (parent->flags.length && (attr_len != (parent->flags.length + prefix))) goto wrong_len; break; case FR_TYPE_BOOL: @@ -740,12 +719,23 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_di case FR_TYPE_OCTETS: /* - * Non-array attributes have a 2 byte padding + * Variable length octets buffer + */ + if (!parent->flags.length) { + uint16_t actual_len = (p[0] << 8) | p[1]; + + if (actual_len > (attr_len - prefix)) { + fr_strerror_printf("%s: Actual length field value (%hu) > attribute value length (%zu)", + __FUNCTION__, actual_len, attr_len - 2); + return -1; + } + + fr_pair_value_memcpy(vp, p + prefix, actual_len); + /* + * Fixed length octets buffer */ - 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); + fr_pair_value_memcpy(vp, p + prefix, attr_len - prefix); } break; diff --git a/src/modules/rlm_eap/lib/sim/encode.c b/src/modules/rlm_eap/lib/sim/encode.c index bd6a789a47a..1e83e9aa5a5 100644 --- a/src/modules/rlm_eap/lib/sim/encode.c +++ b/src/modules/rlm_eap/lib/sim/encode.c @@ -172,7 +172,7 @@ static ssize_t encode_iv(uint8_t *out, size_t outlen, void *encoder_ctx) static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen, uint8_t const *in, size_t inlen, void *encoder_ctx) { - size_t rounded_len, pad_len, encr_len, len = 0; + size_t total_len, pad_len, encr_len, len = 0; uint8_t *p = out, *encr = NULL; fr_sim_encode_ctx_t *packet_ctx = encoder_ctx; EVP_CIPHER_CTX *evp_ctx; @@ -188,12 +188,12 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen, return -1; } - rounded_len = (inlen + (block_size - 1)) & ~(block_size - 1); /* Round input length to block size (16) */ - pad_len = (rounded_len - inlen); /* How much we need to pad */ + total_len = (inlen + (block_size - 1)) & ~(block_size - 1); /* Round input length to block size (16) */ + pad_len = (total_len - inlen); /* How much we need to pad */ - if (rounded_len > outlen) { + if (total_len > outlen) { fr_strerror_printf("%s: Insufficient buffer space, need %zu bytes, have %zu bytes", - __FUNCTION__, rounded_len, outlen); + __FUNCTION__, total_len, outlen); return -1; } @@ -228,7 +228,7 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen, return -1; } - encr = talloc_array(NULL, uint8_t, rounded_len); + encr = talloc_array(NULL, uint8_t, total_len); if (!encr) { fr_strerror_printf("%s: Failed allocating temporary buffer", __FUNCTION__); goto error; @@ -236,7 +236,7 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen, p = out; /* Because we're using out to store our plaintext (and out usually == in) */ - FR_PROTO_HEX_DUMP("plaintext", p, rounded_len); + FR_PROTO_HEX_DUMP("plaintext", p, total_len); /* * By default OpenSSL expects 16 bytes of plaintext @@ -248,7 +248,7 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen, * inform OpenSSL explicitly that there's no padding. */ EVP_CIPHER_CTX_set_padding(evp_ctx, 0); - if (unlikely(EVP_EncryptUpdate(evp_ctx, encr, (int *)&len, p, rounded_len) != 1)) { + if (unlikely(EVP_EncryptUpdate(evp_ctx, encr, (int *)&len, p, total_len) != 1)) { tls_strerror_printf(true, "%s: Failed encrypting attribute", __FUNCTION__); goto error; } @@ -263,9 +263,9 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen, /* * Plaintext should be same length as plaintext. */ - if (unlikely(encr_len != rounded_len)) { + if (unlikely(encr_len != total_len)) { fr_strerror_printf("%s: Invalid plaintext length, expected %zu, got %zu", - __FUNCTION__, rounded_len, encr_len); + __FUNCTION__, total_len, encr_len); goto error; } @@ -367,8 +367,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, 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)) { @@ -377,7 +376,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, return -1; } - if ((rounded_len + 2) > outlen) { + if ((vp->vp_length + 2) > outlen) { oos: fr_strerror_printf("%s: Attribute exceeds available buffer space", __FUNCTION__); return -1; @@ -389,88 +388,15 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, 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__, - 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; - - if (pad_len) { - memset(p, 0, pad_len); - p += pad_len; - } - - len = p - out; - } - break; - /* * In order to represent the string length properly we include a second * 16bit length field with the real string length. @@ -491,11 +417,9 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, case FR_TYPE_STRING: { uint16_t actual_len = htons((vp->vp_length & UINT16_MAX)); - size_t rounded_len = (vp->vp_length + 3) & ~3; - size_t pad_len = rounded_len - vp->vp_length; uint8_t *p = out; - if ((rounded_len + 2) > outlen) goto oos; + if ((vp->vp_length + 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, " @@ -510,9 +434,70 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, memcpy(p, vp->vp_strvalue, vp->vp_length); p += vp->vp_length; - if (pad_len) { - memset(p, 0, pad_len); - p += pad_len; + len = p - out; + } + break; + + case FR_TYPE_OCTETS: + { + uint8_t *p = out; + + /* + * Fixed length attribute + */ + if (vp->da->flags.length) { + size_t prefix = fr_sim_octets_prefix_len(vp->da); + size_t pad_len; + size_t value_len_rounded; + + if (vp->vp_length > vp->da->flags.length) { + fr_strerror_printf("%s: Attribute \"%s\" needs a value of <= %zu bytes, " + "but value was %zu bytes", __FUNCTION__, + vp->da->name, (size_t)vp->da->flags.length, vp->vp_length); + return -1; + } + + /* + * Calculate value padding (autopad) + */ + value_len_rounded = ROUND_UP(vp->vp_length, (size_t)vp->da->flags.length); + if ((value_len_rounded + prefix) > outlen) goto oos; + + /* + * Zero out reserved bytes + */ + if (prefix) { + memset(p, 0, prefix); + p += prefix; + } + + /* + * Copy in value + */ + memcpy(p, vp->vp_octets, vp->vp_length); + p += vp->vp_length; + + /* + * Pad out the value + */ + pad_len = value_len_rounded - vp->vp_length; + if (pad_len) { + memset(p, 0, pad_len); + p += pad_len; + } + /* + * Variable length attribute + */ + } else { + uint16_t actual_len = htons((vp->vp_length & UINT16_MAX)); + + if ((vp->vp_length + 2) > outlen) goto oos; /* +2 for len */ + + memcpy(p, &actual_len, sizeof(actual_len)); /* Big endian real string length */ + p += sizeof(actual_len); + + memcpy(p, vp->vp_strvalue, vp->vp_length); + p += vp->vp_length; } len = p - out; @@ -650,10 +635,15 @@ static ssize_t encode_array(uint8_t *out, size_t outlen, } /* - * Pad value a multiple of 4 + * Pad value to multiple of 4 */ - pad_len = (((p - value) + 3) & ~3) - (p - value); + pad_len = ROUND_UP_POW2(p - value, 4) - (p - value); if (pad_len) { + if (pad_len > (size_t)(end - p)) { + fr_strerror_printf("Insufficient space"); + return -1; + } + memset(p, 0, pad_len); p += pad_len; } @@ -670,7 +660,8 @@ static ssize_t encode_array(uint8_t *out, size_t outlen, static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx) { - size_t rounded_len; + size_t pad_len; + uint8_t *p = out, *end = p + outlen; fr_dict_attr_t const *da; ssize_t slen; @@ -705,24 +696,35 @@ static ssize_t encode_rfc_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const */ da = tlv_stack[depth]; + p += 2; /* Leave space for attr + len */ if (da->flags.array) { - slen = encode_array(out + 2, outlen - 2, tlv_stack, depth, cursor, encoder_ctx); + slen = encode_array(p, end - p, tlv_stack, depth, cursor, encoder_ctx); } else { - slen = encode_value(out + 2, outlen - 2, tlv_stack, depth, cursor, encoder_ctx); + slen = encode_value(p, end - p, tlv_stack, depth, cursor, encoder_ctx); } if (slen <= 0) return slen; + p += slen; + /* - * Round attr + len + data length out to a multiple - * of four, and setup the attribute header and - * length field in the buffer. + * Pad value to multiple of 4 */ - rounded_len = (slen + 2 + 3) & ~3; + pad_len = ROUND_UP_POW2(p - out, 4) - (p - out); + if (pad_len) { + if (pad_len > (size_t)(end - p)) { + fr_strerror_printf("Insufficient space"); + return -1; + } + + memset(p, 0, pad_len); + p += pad_len; + } + out[0] = da->attr & 0xff; - out[1] = rounded_len >> 2; + out[1] = (p - out) >> 2; - FR_PROTO_HEX_DUMP("Done RFC attribute", out, rounded_len); + FR_PROTO_HEX_DUMP("Done RFC attribute", out, (p - out)); - return rounded_len; /* AT + Length + Data */ + return (p - out); /* AT + Length + Data */ } static inline ssize_t encode_tlv(uint8_t *out, size_t outlen, @@ -800,7 +802,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor, void *encoder_ctx) { - unsigned int rounded_len; + unsigned int total_len; ssize_t len; uint8_t *p = out; fr_dict_attr_t const *da; @@ -844,13 +846,13 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen, * of four, and setup the attribute header and * length field in the buffer. */ - rounded_len = (len + 2 + 3) & ~3; + total_len = ROUND_UP_POW2(len + 2, 4); p[0] = da->attr & 0xff; /* Type */ - p[1] = rounded_len >> 2; /* Length */ + p[1] = total_len >> 2; /* Length */ - FR_PROTO_HEX_DUMP("Done TLV attribute", out, rounded_len); + FR_PROTO_HEX_DUMP("Done TLV attribute", out, total_len); - return rounded_len; /* AT_IV + AT_*(TLV) */ + return total_len; /* AT_IV + AT_*(TLV) */ } ssize_t fr_sim_encode_pair(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx) diff --git a/src/modules/rlm_eap/lib/sim/sim_proto.h b/src/modules/rlm_eap/lib/sim/sim_proto.h index 0adf90e6936..e918e21f2d1 100644 --- a/src/modules/rlm_eap/lib/sim/sim_proto.h +++ b/src/modules/rlm_eap/lib/sim/sim_proto.h @@ -53,6 +53,14 @@ RCSIDH(sim_h, "$Id$") #define SIM_VECTOR_UMTS_XRES_MAX_SIZE 16 #define SIM_VECTOR_UMTS_RES_MAX_SIZE 16 +/** Round up - Only works if _mul is a power of 2 but avoids division + */ +#define ROUND_UP_POW2(_num, _mul) (((_num) + ((_mul) - 1)) & ~((_mul) - 1)) + +/** Round up - Works in all cases, but is slower + */ +#define ROUND_UP(_num, _mul) (((((_num) + ((_mul) - 1))) / (_mul)) * (_mul)) + /** The type of auth vector held by a fr_sim_keys_t */ typedef enum { @@ -189,6 +197,8 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t t */ size_t fr_sim_attr_len(VALUE_PAIR const *vp); +size_t fr_sim_octets_prefix_len(fr_dict_attr_t const *da); + char const *fr_sim_session_to_name(char *out, size_t outlen, eap_sim_client_states_t state); int fr_sim_global_init(void);