tech-invite   World Map     

IETF     RFCs     Groups     SIP     ABNFs    |    3GPP     Specs     Gloss.     Arch.     IMS     UICC    |    Misc.    |    search     info

RFC 6929

 
 
 

Remote Authentication Dial In User Service (RADIUS) Protocol Extensions

Part 3 of 3, p. 42 to 68
Prev RFC Part

 


prevText      Top      Up      ToC       Page 42 
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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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      Up      ToC       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