Tech-invite3GPPspaceIETFspace
959493929190898887868584838281807978777675747372717069686766656463626160595857565554535251504948474645444342414039383736353433323130292827262524232221201918171615141312111009080706050403020100
in Index   Prev   Next

RFC 6929

Remote Authentication Dial In User Service (RADIUS) Protocol Extensions

Pages: 68
Proposed Standard
Updates:  286535756158
Part 3 of 3 – Pages 42 to 68
First   Prev   None

Top   ToC   RFC6929 - Page 42   prevText

7. Rationale for This Design

The path to extending the RADIUS protocol has been long and arduous. A number of proposals have been made and discarded by the RADEXT working group. These proposals have been judged to be either too bulky, too complex, too simple, or unworkable in practice. We do not otherwise explain here why earlier proposals did not obtain working group consensus.
Top   ToC   RFC6929 - Page 43
   The changes outlined here have the benefit of being simple, as the
   "Extended Type" format requires only a one-octet change to the
   Attribute format.  The downside is that the "Long Extended Type"
   format is awkward, and the 7 Reserved bits will likely never be used
   for anything.

7.1. Attribute Audit

An audit of almost five thousand publicly available attributes [ATTR] (2010) shows the statistics summarized below. The Attributes include over 100 Vendor dictionaries, along with the IANA-assigned attributes: Count Data Type ----- --------- 2257 integer 1762 text 273 IPv4 Address 225 string 96 other data types 35 IPv6 Address 18 date 10 integer64 4 Interface Id 3 IPv6 Prefix 4683 Total The entries in the "Data Type" column are data types recommended by [RFC6158], along with "integer64". The "other data types" row encompasses all other data types, including complex data types and data types transporting opaque data. We see that over half of the Attributes encode less than 16 octets of data. It is therefore important to have an extension mechanism that adds as little as possible to the size of these attributes. Another result is that the overwhelming majority of attributes use simple data types. Of the Attributes defined above, 177 were declared as being inside of a TLV. This is approximately 4% of the total. We did not investigate whether additional attributes were defined in a flat namespace but could have been defined as being inside of a TLV. We expect that the number could be as high as 10% of attributes.
Top   ToC   RFC6929 - Page 44
   Manual inspection of the dictionaries shows that approximately 20 (or
   0.5%) attributes have the ability to transport more than 253 octets
   of data.  These attributes are divided between VSAs and a small
   number of standard Attributes such as EAP-Message.

   The results of this audit and analysis are reflected in the design of
   the extended attributes.  The extended format has minimal overhead,
   permits TLVs, and has support for "long" attributes.

8. Diameter Considerations

The Attribute formats defined in this specification need to be transported in Diameter. While Diameter supports attributes longer than 253 octets and grouped attributes, we do not use that functionality here. Instead, we define the simplest possible encapsulation method. The new formats MUST be treated the same as traditional RADIUS attributes when converting from RADIUS to Diameter, or vice versa. That is, the new attribute space is not converted to any "extended" Diameter attribute space. Fragmented attributes are not converted to a single long Diameter attribute. The new EVS data types are not converted to Diameter attributes with the "V" bit set. In short, this document mandates no changes for existing RADIUS-to- Diameter or Diameter-to-RADIUS gateways.

9. Examples

A few examples are presented here in order to illustrate the encoding of the new Attribute formats. These examples are not intended to be exhaustive, as many others are possible. For simplicity, we do not show complete packets, but only attributes.
Top   ToC   RFC6929 - Page 45
   The examples are given using a domain-specific language implemented
   by the program given in Appendix A of this document.  The language is
   line oriented and composed of a sequence of lines matching the ABNF
   grammar ([RFC5234]) given below:

      Identifier = 1*DIGIT *( "." 1*DIGIT )

      HEXCHAR = HEXDIG HEXDIG

      STRING = DQUOTE 1*CHAR DQUOTE

      TLV = "{" SP 1*DIGIT SP DATA SP "}"

      DATA = (HEXCHAR *(SP HEXCHAR)) / (TLV *(SP TLV)) / STRING

      LINE = Identifier SP DATA

   The program has additional restrictions on its input that are not
   reflected in the above grammar.  For example, the portions of the
   identifier that refer to Type and Extended-Type are limited to values
   between 1 and 255.  We trust that the source code in Appendix A is
   clear and that these restrictions do not negatively affect the
   comprehensibility of the examples.

   The program reads the input text and interprets it as a set of
   instructions to create RADIUS attributes.  It then prints the hex
   encoding of those attributes.  It implements the minimum set of
   functionality that achieves that goal.  This minimalism means that it
   does not use attribute dictionaries; it does not implement support
   for RADIUS data types; it can be used to encode attributes with
   invalid data fields; and there is no requirement for consistency from
   one example to the next.  For example, it can be used to encode a
   User-Name attribute that contains non-UTF8 data or a
   Framed-IP-Address that contains 253 octets of ASCII data.  As a
   result, it MUST NOT be used to create RADIUS attributes for transport
   in a RADIUS message.

   However, the program correctly encodes the RADIUS attribute fields of
   "Type", "Length", "Extended-Type", "More", "Reserved", "Vendor-Id",
   "Vendor-Type", and "Vendor-Length".  It encodes RADIUS attribute data
   types "evs" and "tlv".  It can therefore be used to encode example
   attributes from inputs that are human readable.

   We do not give examples of "invalid attributes".  We also note that
   the examples show format, rather than consistent meaning.  A
   particular Attribute Type code may be used to demonstrate two
   different formats.  In real specifications, attributes have a static
   definitions based on their type code.
Top   ToC   RFC6929 - Page 46
   The examples given below are strictly for demonstration purposes only
   and do not provide a standard of any kind.

9.1. Extended Type

The following is a series of examples of the "Extended Type" format. Attribute encapsulating textual data: 241.1 "bob" -> f1 06 01 62 6f 62 Attribute encapsulating a TLV with TLV-Type of one (1): 241.2 { 1 23 45 } -> f1 07 02 01 04 23 45 Attribute encapsulating two TLVs, one after the other: 241.2 { 1 23 45 } { 2 67 89 } -> f1 0b 02 01 04 23 45 02 04 67 89 Attribute encapsulating two TLVs, where the second TLV is itself encapsulating a TLV: 241.2 { 1 23 45 } { 3 { 1 ab cd } } -> f1 0d 02 01 04 23 45 03 06 01 04 ab cd Attribute encapsulating two TLVs, where the second TLV is itself encapsulating two TLVs: 241.2 { 1 23 45 } { 3 { 1 ab cd } { 2 "foo" } } -> f1 12 02 01 04 23 45 03 0b 01 04 ab cd 02 05 66 6f 6f Attribute encapsulating a TLV, which in turn encapsulates a TLV, to a depth of 5 nestings: 241.1 { 1 { 2 { 3 { 4 { 5 cd ef } } } } } -> f1 0f 01 01 0c 02 0a 03 08 04 06 05 04 cd ef Attribute encapsulating an Extended-Vendor-Specific Attribute, with Vendor-Id of 1 and Vendor-Type of 4, which in turn encapsulates textual data: 241.26.1.4 "test" -> f1 0c 1a 00 00 00 01 04 74 65 73 74
Top   ToC   RFC6929 - Page 47
   Attribute encapsulating an Extended-Vendor-Specific Attribute, with
   Vendor-Id of 1 and Vendor-Type of 5, which in turn encapsulates a TLV
   with TLV-Type of 3, which encapsulates textual data:

     241.26.1.5 { 3 "test" }
       -> f1 0e 1a 00 00 00 01 05 03 06 74 65 73 74

9.2. Long Extended Type

The following is a series of examples of the "Long Extended Type" format. Attribute encapsulating textual data: 245.1 "bob" -> f5 07 01 00 62 6f 62 Attribute encapsulating a TLV with TLV-Type of one (1): 245.2 { 1 23 45 } -> f5 08 02 00 01 04 23 45 Attribute encapsulating two TLVs, one after the other: 245.2 { 1 23 45 } { 2 67 89 } -> f5 0c 02 00 01 04 23 45 02 04 67 89 Attribute encapsulating two TLVs, where the second TLV is itself encapsulating a TLV: 245.2 { 1 23 45 } { 3 { 1 ab cd } } -> f5 0e 02 00 01 04 23 45 03 06 01 04 ab cd Attribute encapsulating two TLVs, where the second TLV is itself encapsulating two TLVs: 245.2 { 1 23 45 } { 3 { 1 ab cd } { 2 "foo" } } -> f5 13 02 00 01 04 23 45 03 0b 01 04 ab cd 02 05 66 6f 6f Attribute encapsulating a TLV, which in turn encapsulates a TLV, to a depth of 5 nestings: 245.1 { 1 { 2 { 3 { 4 { 5 cd ef } } } } } -> f5 10 01 00 01 0c 02 0a 03 08 04 06 05 04 cd ef
Top   ToC   RFC6929 - Page 48
   Attribute encapsulating an Extended-Vendor-Specific Attribute, with
   Vendor-Id of 1 and Vendor-Type of 4, which in turn encapsulates
   textual data:

     245.26.1.4 "test"
       -> f5 0d 1a 00 00 00 00 01 04 74 65 73 74

   Attribute encapsulating an Extended-Vendor-Specific Attribute, with
   Vendor-Id of 1 and Vendor-Type of 5, which in turn encapsulates a TLV
   with TLV-Type of 3, which encapsulates textual data:

     245.26.1.5 { 3 "test" }
       -> f5 0f 1a 00 00 00 00 01 05 03 06 74 65 73 74

   Attribute encapsulating more than 251 octets of data.  The "Data"
   portions are indented for readability:

     245.4 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccc
           ccccccccccc"
       -> f5 ff 04 80 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb f5 13 04 00 cc
          cc cc cc cc cc cc cc cc cc cc cc cc cc cc
Top   ToC   RFC6929 - Page 49
   Below is an example of an attribute encapsulating an Extended-Vendor-
   Specific Attribute, with Vendor-Id of 1 and Vendor-Type of 6, which
   in turn encapsulates more than 251 octets of data.

   As the VSA encapsulates more than 251 octets of data, it is split
   into two RADIUS attributes.  The first attribute has the More field
   set, and it carries the Vendor-Id and Vendor-Type.  The second
   attribute has the More field clear and carries the rest of the data
   portion of the VSA.  Note that the second attribute does not include
   the Vendor-Id ad Vendor-Type fields.

   The "Data" portions are indented for readability:

     245.26.1.6  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
           aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
           bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccc
           ccccccccccccccccc"
       -> f5 ff 1a 80 00 00 00 01 06 aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
          aa aa aa aa aa aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
          bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb f5 18 1a 00 bb
          bb bb bb bb cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc
Top   ToC   RFC6929 - Page 50

10. IANA Considerations

This document updates [RFC3575] in that it adds new IANA considerations for RADIUS attributes. These considerations modify and extend the IANA considerations for RADIUS, rather than replacing them. The IANA considerations of this document are limited to the "RADIUS Attribute Types" registry. Some Attribute Type values that were previously marked "Reserved" are now allocated, and the registry is extended from a simple 8-bit array to a tree-like structure, up to a maximum depth of 125 nodes. Detailed instructions are given below.

10.1. Attribute Allocations

IANA has moved the following Attribute Type values from "Reserved" to "Allocated" with the corresponding names: * 241 Extended-Type-1 * 242 Extended-Type-2 * 243 Extended-Type-3 * 244 Extended-Type-4 * 245 Long-Extended-Type-1 * 246 Long-Extended-Type-2 These values serve as an encapsulation layer for the new RADIUS Attribute Type tree.

10.2. RADIUS Attribute Type Tree

Each of the Attribute Type values allocated above extends the "RADIUS Attribute Types" to an N-ary tree, via a "dotted number" notation. Allocation of an Attribute Type value "TYPE" using the new "Extended Type" format results in allocation of 255 new Attribute Type values of format "TYPE.1" through "TYPE.255". Value twenty-six (26) is assigned as "Extended-Vendor-Specific-*". Values "TYPE.241" through "TYPE.255" are marked "Reserved". All other values are "Unassigned".
Top   ToC   RFC6929 - Page 51
   The initial set of Attribute Type values and names assigned by this
   document is given below.

      * 241           Extended-Attribute-1
      * 241.{1-25}    Unassigned
      * 241.26        Extended-Vendor-Specific-1
      * 241.{27-240}  Unassigned
      * 241.{241-255} Reserved
      * 242           Extended-Attribute-2
      * 242.{1-25}    Unassigned
      * 242.26        Extended-Vendor-Specific-2
      * 242.{27-240}  Unassigned
      * 242.{241-255} Reserved
      * 243           Extended-Attribute-3
      * 243.{1-25}    Unassigned
      * 243.26        Extended-Vendor-Specific-3
      * 243.{27-240}  Unassigned
      * 243.{241-255} Reserved
      * 244           Extended-Attribute-4
      * 244.{1-25}    Unassigned
      * 244.26        Extended-Vendor-Specific-4
      * 244.{27-240}  Unassigned
      * 244.{241-255} Reserved
      * 245           Extended-Attribute-5
      * 245.{1-25}    Unassigned
      * 245.26        Extended-Vendor-Specific-5
      * 245.{27-240}  Unassigned
      * 245.{241-255} Reserved
      * 246           Extended-Attribute-6
      * 246.{1-25}    Unassigned
      * 246.26        Extended-Vendor-Specific-6
      * 246.{27-240}  Unassigned
      * 246.{241-255} Reserved

   As per [RFC5226], the values marked "Unassigned" above are available
   for assignment by IANA in future RADIUS specifications.  The values
   marked "Reserved" are reserved for future use.

   The Extended-Vendor-Specific spaces (TYPE.26) are for Private Use,
   and allocations are not managed by IANA.

   Allocation of Reserved entries in the extended space requires
   Standards Action.

   All other allocations in the extended space require IETF Review.
Top   ToC   RFC6929 - Page 52

10.3. Allocation Instructions

This section defines what actions IANA needs to take when allocating new attributes. Different actions are required when allocating attributes from the standard space, attributes of the "Extended Type" format, attributes of the "Long Extended Type" format, preferential allocations, attributes of data type TLV, attributes within a TLV, and attributes of other data types.

10.3.1. Requested Allocation from the Standard Space

Specifications can request allocation of an Attribute from within the standard space (e.g., Attribute Type Codes 1 through 255), subject to the considerations of [RFC3575] and this document.

10.3.2. Requested Allocation from the Short Extended Space

Specifications can request allocation of an Attribute that requires the format "Extended Type", by specifying the short extended space. In that case, IANA should assign the lowest Unassigned number from the Attribute Type space with the relevant format.

10.3.3. Requested Allocation from the Long Extended Space

Specifications can request allocation of an Attribute that requires the format "Long Extended Type", by specifying the extended space (long). In that case, IANA should assign the lowest Unassigned number from the Attribute Type space with the relevant format.

10.3.4. Allocation Preferences

Specifications that make no request for allocation from a specific type space should have Attributes allocated using the following criteria: * When the standard space has no more Unassigned attributes, all allocations should be performed from the extended space. * Specifications that allocate a small number of attributes (i.e., less than ten) should have all allocations made from the standard space. * Specifications that would allocate more than twenty percent of the remaining standard space attributes should have all allocations made from the extended space. * Specifications that request allocation of an attribute of data type TLV should have that attribute allocated from the extended space.
Top   ToC   RFC6929 - Page 53
   * Specifications that request allocation of an attribute that can
     transport 253 or more octets of data should have that attribute
     allocated from within the long extended space.  We note that
     Section 6.5 above makes recommendations related to this allocation.

   There is otherwise no requirement that all attributes within a
   specification be allocated from one type space or another.
   Specifications can simultaneously allocate attributes from both the
   standard space and the extended space.

10.3.5. Extending the Type Space via the TLV Data Type

When specifications request allocation of an attribute of data type TLV, that allocation extends the Attribute Type tree by one more level. Allocation of an Attribute Type value "TYPE.TLV", with data type TLV, results in allocation of 255 new Attribute Type values, of format "TYPE.TLV.1" through "TYPE.TLV.255". Values 254-255 are marked "Reserved". All other values are "Unassigned". Value 26 has no special meaning. For example, if a new attribute "Example-TLV" of data type TLV is assigned the identifier "245.1", then the extended tree will be allocated as below: * 245.1 Example-TLV * 245.1.{1-253} Unassigned * 245.1.{254-255} Reserved Note that this example does not define an "Example-TLV" attribute. The Attribute Type tree can be extended multiple levels in one specification when the specification requests allocation of nested TLVs, as discussed below.

10.3.6. Allocation within a TLV

Specifications can request allocation of Attribute Type values within an Attribute of data type TLV. The encapsulating TLV can be allocated in the same specification, or it can have been previously allocated. Specifications need to request allocation within a specific Attribute Type value (e.g., "TYPE.TLV.*"). Allocations are performed from the smallest Unassigned value, proceeding to the largest Unassigned value.
Top   ToC   RFC6929 - Page 54
   Where the Attribute being allocated is of data type TLV, the
   Attribute Type tree is extended by one level, as given in the
   previous section.  Allocations can then be made within that level.

10.3.7. Allocation of Other Data Types

Attribute Type value allocations are otherwise allocated from the smallest Unassigned value, proceeding to the largest Unassigned value, e.g., starting from 241.1, proceeding through 241.255, then to 242.1, through 242.255, etc.

11. Security Considerations

This document defines new formats for data carried inside of RADIUS but otherwise makes no changes to the security of the RADIUS protocol. Attacks on cryptographic hashes are well known and are getting better with time, as discussed in [RFC4270]. The security of the RADIUS protocol is dependent on MD5 [RFC1321], which has security issues as discussed in [RFC6151]. It is not known if the issues described in [RFC6151] apply to RADIUS. For other issues, we incorporate by reference the security considerations of [RFC6158] Section 5. As with any protocol change, code changes are required in order to implement the new features. These code changes have the potential to introduce new vulnerabilities in the software. Since the RADIUS server performs network authentication, it is an inviting target for attackers. We RECOMMEND that access to RADIUS servers be kept to a minimum.

12. References

12.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson, "Remote Authentication Dial In User Service (RADIUS)", RFC 2865, June 2000. [RFC2866] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000. [RFC3575] Aboba, B., "IANA Considerations for RADIUS (Remote Authentication Dial In User Service)", RFC 3575, July 2003.
Top   ToC   RFC6929 - Page 55
   [RFC5226]  Narten, T. and H. Alvestrand, "Guidelines for Writing an
              IANA Considerations Section in RFCs", BCP 26, RFC 5226,
              May 2008.

   [RFC6158]  DeKok, A., Ed., and G. Weber, "RADIUS Design Guidelines",
              BCP 158, RFC 6158, March 2011.

   [PEN]      IANA, "PRIVATE ENTERPRISE NUMBERS",
              <http://www.iana.org/assignments/enterprise-numbers>.

12.2. Informative References

[RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April 1992. [RFC2868] Zorn, G., Leifer, D., Rubens, A., Shriver, J., Holdrege, M., and I. Goyret, "RADIUS Attributes for Tunnel Protocol Support", RFC 2868, June 2000. [RFC4270] Hoffman, P. and B. Schneier, "Attacks on Cryptographic Hashes in Internet Protocols", RFC 4270, November 2005. [RFC5234] Crocker, D., Ed., and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, January 2008. [RFC6151] Turner, S. and L. Chen, "Updated Security Considerations for the MD5 Message-Digest and the HMAC-MD5 Algorithms", RFC 6151, March 2011. [ATTR] "alandekok/freeradius-server", available from GitHub, data retrieved September 2010, <http://github.com/alandekok/ freeradius-server/tree/master/share/>.

13. Acknowledgments

This document is the result of long discussions in the IETF RADEXT working group. The authors would like to thank all of the participants who contributed various ideas over the years. Their feedback has been invaluable and has helped to make this specification better.
Top   ToC   RFC6929 - Page 56

Appendix A. Extended Attribute Generator Program

This section contains "C" program source code that can be used for testing. It reads a line-oriented text file, parses it to create RADIUS formatted attributes, and prints the hex version of those attributes to standard output. The input accepts grammar similar to that given in Section 9, with some modifications for usability. For example, blank lines are allowed, lines beginning with a '#' character are interpreted as comments, numbers (RADIUS Types, etc.) are checked for minimum/ maximum values, and RADIUS attribute lengths are enforced. The program is included here for demonstration purposes only, and does not define a standard of any kind. ------------------------------------------------------------ /* * Copyright (c) 2013 IETF Trust and the persons identified as * authors of the code. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of Internet Society, IETF or IETF Trust, nor * the names of specific contributors, may be used to endorse or * promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Top   ToC   RFC6929 - Page 57
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    * SUCH DAMAGE.
    *
    *  Author:  Alan DeKok <aland@networkradius.com>
    */
   #include <stdlib.h>
   #include <stdio.h>
   #include <stdint.h>
   #include <string.h>
   #include <errno.h>
   #include <ctype.h>

   static int encode_tlv(char *buffer, uint8_t *output, size_t outlen);

   static const char *hextab = "0123456789abcdef";

   static int encode_data_string(char *buffer,
                        uint8_t *output, size_t outlen)
   {
        int length = 0;
        char *p;

        p = buffer + 1;

        while (*p && (outlen > 0)) {
             if (*p == '"') {
                  return length;
             }

             if (*p != '\\') {
                  *(output++) = *(p++);
                  outlen--;
                  length++;
                  continue;
             }

             switch (p[1]) {
             default:
                  *(output++) = p[1];
                  break;

             case 'n':
                  *(output++) = '\n';
                  break;
Top   ToC   RFC6929 - Page 58
             case 'r':
                  *(output++) = '\r';
                  break;

             case 't':
                  *(output++) = '\t';
                  break;
             }

             outlen--;
             length++;
        }

        fprintf(stderr, "String is not terminated\n");
        return 0;
   }

   static int encode_data_tlv(char *buffer, char **endptr,
                     uint8_t *output, size_t outlen)
   {
        int depth = 0;
        int length;
        char *p;

        for (p = buffer; *p != '\0'; p++) {
             if (*p == '{') depth++;
             if (*p == '}') {
                  depth--;
                  if (depth == 0) break;
             }
        }

        if (*p != '}') {
             fprintf(stderr, "No trailing '}' in string starting "
                  "with \"%s\"\n",
                  buffer);
             return 0;
        }

        *endptr = p + 1;
        *p = '\0';

        p = buffer + 1;
        while (isspace((int) *p)) p++;
Top   ToC   RFC6929 - Page 59
        length = encode_tlv(p, output, outlen);
        if (length == 0) return 0;

        return length;
   }

   static int encode_data(char *p, uint8_t *output, size_t outlen)
   {
        int length;

        if (!isspace((int) *p)) {
             fprintf(stderr, "Invalid character following attribute "
                  "definition\n");
             return 0;
        }

        while (isspace((int) *p)) p++;

        if (*p == '{') {
             int sublen;
             char *q;

             length = 0;

             do {
                  while (isspace((int) *p)) p++;
                  if (!*p) {
                       if (length == 0) {
                            fprintf(stderr, "No data\n");
                            return 0;
                       }

                       break;
                  }

                  sublen = encode_data_tlv(p, &q, output, outlen);
                  if (sublen == 0) return 0;

                  length += sublen;
                  output += sublen;
                  outlen -= sublen;
                  p = q;
             } while (*q);

             return length;
        }
Top   ToC   RFC6929 - Page 60
        if (*p == '"') {
             length = encode_data_string(p, output, outlen);
             return length;
        }

        length = 0;
        while (*p) {

             char *c1, *c2;

             while (isspace((int) *p)) p++;

             if (!*p) break;

             if(!(c1 = memchr(hextab, tolower((int) p[0]), 16)) ||
                !(c2 = memchr(hextab, tolower((int)  p[1]), 16))) {
                  fprintf(stderr, "Invalid data starting at "
                       "\"%s\"\n", p);
                  return 0;
             }

             *output = ((c1 - hextab) << 4) + (c2 - hextab);
             output++;
             length++;
             p += 2;

             outlen--;
             if (outlen == 0) {
                  fprintf(stderr, "Too much data\n");
                  return 0;
             }
        }

        if (length == 0) {
             fprintf(stderr, "Empty string\n");
             return 0;
        }

        return length;
   }
Top   ToC   RFC6929 - Page 61
   static int decode_attr(char *buffer, char **endptr)
   {
        long attr;

        attr = strtol(buffer, endptr, 10);
        if (*endptr == buffer) {
             fprintf(stderr, "No valid number found in string "
                  "starting with \"%s\"\n", buffer);
             return 0;
        }

        if (!**endptr) {
             fprintf(stderr, "Nothing follows attribute number\n");
             return 0;
        }

        if ((attr <= 0) || (attr > 256)) {
             fprintf(stderr, "Attribute number is out of valid "
                  "range\n");
             return 0;
        }

        return (int) attr;
   }

   static int decode_vendor(char *buffer, char **endptr)
   {
        long vendor;

        if (*buffer != '.') {
             fprintf(stderr, "Invalid separator before vendor id\n");
             return 0;
        }

        vendor = strtol(buffer + 1, endptr, 10);
        if (*endptr == (buffer + 1)) {
             fprintf(stderr, "No valid vendor number found\n");
             return 0;
        }

        if (!**endptr) {
             fprintf(stderr, "Nothing follows vendor number\n");
             return 0;
        }
Top   ToC   RFC6929 - Page 62
        if ((vendor <= 0) || (vendor > (1 << 24))) {
             fprintf(stderr, "Vendor number is out of valid range\n");
             return 0;
        }

        if (**endptr != '.') {
             fprintf(stderr, "Invalid data following vendor number\n");
             return 0;
        }
        (*endptr)++;

        return (int) vendor;
   }

   static int encode_tlv(char *buffer, uint8_t *output, size_t outlen)
   {
        int attr;
        int length;
        char *p;

        attr = decode_attr(buffer, &p);
        if (attr == 0) return 0;

        output[0] = attr;
        output[1] = 2;

        if (*p == '.') {
             p++;
             length = encode_tlv(p, output + 2, outlen - 2);

        } else {
             length = encode_data(p, output + 2, outlen - 2);
        }

        if (length == 0) return 0;
        if (length > (255 - 2)) {
             fprintf(stderr, "TLV data is too long\n");
             return 0;
        }

        output[1] += length;

        return length + 2;
   }
Top   ToC   RFC6929 - Page 63
   static int encode_vsa(char *buffer, uint8_t *output, size_t outlen)
   {
        int vendor;
        int attr;
        int length;
        char *p;

        vendor = decode_vendor(buffer, &p);
        if (vendor == 0) return 0;

        output[0] = 0;
        output[1] = (vendor >> 16) & 0xff;
        output[2] = (vendor >> 8) & 0xff;
        output[3] = vendor & 0xff;

        length = encode_tlv(p, output + 4, outlen - 4);
        if (length == 0) return 0;
        if (length > (255 - 6)) {
             fprintf(stderr, "VSA data is too long\n");
             return 0;
        }

        return length + 4;
   }

   static int encode_evs(char *buffer, uint8_t *output, size_t outlen)
   {
        int vendor;
        int attr;
        int length;
        char *p;

        vendor = decode_vendor(buffer, &p);
        if (vendor == 0) return 0;

        attr = decode_attr(p, &p);
        if (attr == 0) return 0;

        output[0] = 0;
        output[1] = (vendor >> 16) & 0xff;
        output[2] = (vendor >> 8) & 0xff;
        output[3] = vendor & 0xff;
        output[4] = attr;

        length = encode_data(p, output + 5, outlen - 5);
        if (length == 0) return 0;
Top   ToC   RFC6929 - Page 64
        return length + 5;
   }

   static int encode_extended(char *buffer,
                     uint8_t *output, size_t outlen)
   {
        int attr;
        int length;
        char *p;

        attr = decode_attr(buffer, &p);
        if (attr == 0) return 0;

        output[0] = attr;

        if (attr == 26) {
             length = encode_evs(p, output + 1, outlen - 1);
        } else {
             length = encode_data(p, output + 1, outlen - 1);
        }
        if (length == 0) return 0;
        if (length > (255 - 3)) {
             fprintf(stderr, "Extended Attr data is too long\n");

             return 0;
        }

        return length + 1;
   }

   static int encode_extended_flags(char *buffer,
                        uint8_t *output, size_t outlen)
   {
        int attr;
        int length, total;
        char *p;

        attr = decode_attr(buffer, &p);
        if (attr == 0) return 0;

        /* output[0] is the extended attribute */
        output[1] = 4;
        output[2] = attr;
        output[3] = 0;
Top   ToC   RFC6929 - Page 65
        if (attr == 26) {
             length = encode_evs(p, output + 4, outlen - 4);
             if (length == 0) return 0;

             output[1] += 5;
             length -= 5;
        } else {
             length = encode_data(p, output + 4, outlen - 4);
        }
        if (length == 0) return 0;

        total = 0;
        while (1) {
             int sublen = 255 - output[1];

             if (length <= sublen) {
                  output[1] += length;
                  total += output[1];
                  break;
             }

             length -= sublen;

             memmove(output + 255 + 4, output + 255, length);
             memcpy(output + 255, output, 4);

             output[1] = 255;

             output[3] |= 0x80;

             output += 255;
             output[1] = 4;
             total += 255;
        }

        return total;
   }

   static int encode_rfc(char *buffer, uint8_t *output, size_t outlen)
   {
        int attr;
        int length, sublen;
        char *p;

        attr = decode_attr(buffer, &p);
        if (attr == 0) return 0;
Top   ToC   RFC6929 - Page 66
        length = 2;
        output[0] = attr;
        output[1] = 2;

        if (attr == 26) {
             sublen = encode_vsa(p, output + 2, outlen - 2);

        } else if ((*p == ' ') || ((attr < 241) || (attr > 246))) {
             sublen = encode_data(p, output + 2, outlen - 2);

        } else {
             if (*p != '.') {
                  fprintf(stderr, "Invalid data following "
                       "attribute number\n");
                  return 0;
             }

             if (attr < 245) {
                  sublen = encode_extended(p + 1,
                                  output + 2, outlen - 2);
             } else {

                  /*
                   *   Not like the others!
                   */
                  return encode_extended_flags(p + 1, output, outlen);
             }
        }
        if (sublen == 0) return 0;

        if (sublen > (255 -2)) {
             fprintf(stderr, "RFC Data is too long\n");
             return 0;
        }

        output[1] += sublen;
        return length + sublen;
   }

   int main(int argc, char *argv[])
   {
        int lineno;
        size_t i, outlen;
        FILE *fp;
        char input[8192], buffer[8192];
        uint8_t output[4096];
Top   ToC   RFC6929 - Page 67
        if ((argc < 2) || (strcmp(argv[1], "-") == 0)) {
             fp = stdin;
        } else {
             fp = fopen(argv[1], "r");
             if (!fp) {
                  fprintf(stderr, "Error opening %s: %s\n",
                       argv[1], strerror(errno));
                  exit(1);
             }
        }

        lineno = 0;
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
             char *p = strchr(buffer, '\n');

             lineno++;

             if (!p) {
                  if (!feof(fp)) {
                       fprintf(stderr, "Line %d too long in %s\n",
                            lineno, argv[1]);
                       exit(1);
                  }
             } else {
                  *p = '\0';
             }

             p = strchr(buffer, '#');
             if (p) *p = '\0';

             p = buffer;

             while (isspace((int) *p)) p++;
             if (!*p) continue;

             strcpy(input, p);
             outlen = encode_rfc(input, output, sizeof(output));
             if (outlen == 0) {
                  fprintf(stderr, "Parse error in line %d of %s\n",
                       lineno, input);
                  exit(1);
             }

             printf("%s -> ", buffer);
             for (i = 0; i < outlen; i++) {
                  printf("%02x ", output[i]);
             }
Top   ToC   RFC6929 - Page 68
             printf("\n");
        }

        if (fp != stdin) fclose(fp);

        return 0;
   }
   ------------------------------------------------------------

Authors' Addresses

Alan DeKok Network RADIUS SARL 57bis blvd des Alpes 38240 Meylan France EMail: aland@networkradius.com URI: http://networkradius.com Avi Lior EMail: avi.ietf@lior.org