]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Create unified library for EAP-SIM/AKA/AKA' and make those modules fully async
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 3 Sep 2019 17:42:09 +0000 (13:42 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 26 Sep 2019 18:26:21 +0000 (13:26 -0500)
74 files changed:
Makefile
raddb/mods-available/eap
raddb/sites-available/eap-aka-sim [new file with mode: 0644]
raddb/sites-available/tls-cache
share/dictionary/eap/aka-sim/dictionary [moved from share/dictionary/eap/aka/dictionary with 73% similarity]
share/dictionary/eap/aka-sim/dictionary.3gpp-ts24.139 [moved from share/dictionary/eap/aka/dictionary.3gpp-ts24.139 with 77% similarity]
share/dictionary/eap/aka-sim/dictionary.3gpp-ts24.302 [new file with mode: 0644]
share/dictionary/eap/aka-sim/dictionary.freeradius [new file with mode: 0644]
share/dictionary/eap/aka-sim/dictionary.rfc4187 [new file with mode: 0644]
share/dictionary/eap/aka-sim/dictionary.rfc5448 [moved from share/dictionary/eap/aka/dictionary.rfc5448 with 78% similarity]
share/dictionary/eap/aka-sim/dictionary.rfc7458 [new file with mode: 0644]
share/dictionary/eap/aka/dictionary.3gpp-ts24.302 [deleted file]
share/dictionary/eap/aka/dictionary.freeradius [deleted file]
share/dictionary/eap/aka/dictionary.rfc4187 [deleted file]
share/dictionary/eap/aka/dictionary.rfc7458 [deleted file]
share/dictionary/eap/sim/dictionary [deleted file]
share/dictionary/eap/sim/dictionary.3gpp-ts24.139 [deleted file]
share/dictionary/eap/sim/dictionary.3gpp-ts24.302 [deleted file]
share/dictionary/eap/sim/dictionary.freeradius [deleted file]
share/dictionary/eap/sim/dictionary.rfc4187 [deleted file]
share/dictionary/eap/sim/dictionary.rfc5448 [deleted file]
share/dictionary/eap/sim/dictionary.rfc7458 [deleted file]
share/dictionary/freeradius/dictionary.freeradius.internal
share/dictionary/freeradius/dictionary.freeradius.internal.sim
src/lib/eap_aka_sim/all.mk [new file with mode: 0644]
src/lib/eap_aka_sim/attrs.h [new file with mode: 0644]
src/lib/eap_aka_sim/base.c [new file with mode: 0644]
src/lib/eap_aka_sim/base.h [new file with mode: 0644]
src/lib/eap_aka_sim/crypto.c [moved from src/lib/sim/crypto.c with 82% similarity]
src/lib/eap_aka_sim/decode.c [moved from src/lib/sim/decode.c with 94% similarity]
src/lib/eap_aka_sim/encode.c [moved from src/lib/sim/encode.c with 93% similarity]
src/lib/eap_aka_sim/fips186prf.c [moved from src/lib/sim/fips186prf.c with 97% similarity]
src/lib/eap_aka_sim/id.c [moved from src/lib/sim/id.c with 67% similarity]
src/lib/eap_aka_sim/id.h [new file with mode: 0644]
src/lib/eap_aka_sim/state_machine.c [new file with mode: 0644]
src/lib/eap_aka_sim/state_machine.h [new file with mode: 0644]
src/lib/eap_aka_sim/vector.c [moved from src/lib/sim/vector.c with 53% similarity]
src/lib/eap_aka_sim/xlat.c [moved from src/lib/sim/xlat.c with 60% similarity]
src/lib/sim/all.mk
src/lib/sim/base.h
src/lib/sim/common.h [new file with mode: 0644]
src/lib/sim/milenage.c
src/lib/sim/milenage.h
src/lib/sim/ts_34_108.c [new file with mode: 0644]
src/lib/sim/ts_34_108.h [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_aka/all.mk
src/modules/rlm_eap/types/rlm_eap_aka/rlm_eap_aka.c
src/modules/rlm_eap/types/rlm_eap_aka_prime/README.md [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_aka_prime/all.mk [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_aka_prime/rlm_eap_aka_prime.c [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_sim/all.mk
src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c
src/modules/rlm_sigtran/attrs.h
src/modules/rlm_sigtran/client.c
src/modules/rlm_sigtran/rlm_sigtran.c
src/tests/eapol_test/config/methods-available/aka
src/tests/eapol_test/config/methods-available/aka_prime [new file with mode: 0644]
src/tests/eapol_test/config/methods-available/sim
src/tests/eapol_test/config/servers.conf
src/tests/modules/eap_aka_sim/.gitignore [moved from src/tests/modules/eap_sim/.gitignore with 100% similarity]
src/tests/modules/eap_aka_sim/all.mk [moved from src/tests/modules/eap_sim/all.mk with 100% similarity]
src/tests/modules/eap_aka_sim/module.conf [moved from src/tests/modules/eap_sim/module.conf with 52% similarity]
src/tests/modules/eap_aka_sim/sim_xlat_id_aka.attrs [moved from src/tests/modules/eap_sim/sim_xlat_id_aka.attrs with 100% similarity]
src/tests/modules/eap_aka_sim/sim_xlat_id_aka.unlang [moved from src/tests/modules/eap_sim/sim_xlat_id_aka.unlang with 84% similarity]
src/tests/modules/eap_aka_sim/sim_xlat_id_error.attrs [moved from src/tests/modules/eap_sim/sim_xlat_id_error.attrs with 100% similarity]
src/tests/modules/eap_aka_sim/sim_xlat_id_error.unlang [moved from src/tests/modules/eap_sim/sim_xlat_id_error.unlang with 69% similarity]
src/tests/modules/eap_aka_sim/sim_xlat_id_sim.attrs [moved from src/tests/modules/eap_sim/sim_xlat_id_sim.attrs with 100% similarity]
src/tests/modules/eap_aka_sim/sim_xlat_id_sim.unlang [moved from src/tests/modules/eap_sim/sim_xlat_id_sim.unlang with 73% similarity]
src/tests/unit/eap_aka_decode.txt
src/tests/unit/eap_aka_encode.txt
src/tests/unit/eap_aka_error.txt
src/tests/unit/eap_sim_decode.txt
src/tests/unit/eap_sim_encode.txt
src/tests/unit/eap_sim_error.txt

index c7af479871987ed4eed01a6f7ce063a6433feaf2..e44157f4e38d9dfb6b378ea50e8271fe50b3b599 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -59,8 +59,7 @@ PROTOCOLS    := \
        arp \
        dhcpv4 \
        dhcpv6 \
-       eap/aka \
-       eap/sim \
+       eap/aka-sim \
        ethernet \
        freeradius \
        radius \
index 9950ea23d0133d21f4b92bb99483e573eb3d60f0..80d353361f908ad2c8c28176245cbb80775bad2c 100644 (file)
@@ -77,7 +77,7 @@ eap {
        type = peap
 #      type = fast
 #      type = aka
-       type = sim
+#      type = sim
 
        #
        #  ### EAP-MD5
@@ -1379,7 +1379,7 @@ eap {
        #  * `Comp128v1`
        #  * `Comp128v2`
        #  * `Comp128v3` (default if no &control:SIM-OPc)
-       #  * `Milenage` (default if &control:SIM-OPc is available)
+       #  * `Comp128v4` (default if &control:SIM-OPc is available)
        #
        #  NOTE: In general operators will not provide the Ki (subscriber
        #  key) for their `SIM cards`, as the Ki is considered highly
@@ -1391,44 +1391,244 @@ eap {
        #
        sim {
                #
-               #  send_result_ind:: Send a protected success message.
+               #  request_identity:: Send a SIM-Start message to Requests
+               #  an additional identity to the one from the EAP-Identity-Response.
+               #
+               #  If `yes` - We send a request with AT_SUBTYPE SIM-start
+               #  with an AT_ANY_ID_REQ attribute to prompt the supplicant
+               #  to send a new identity.
+               #
+               #  The type of identity requested can be controlled by adding
+               #  one of the following attributes from the
+               #  `recv Identity-Response { ... }` section of the specified
+               #  EAP-SIM virtual_server, to the reply list:
+               #
+               #  - &reply:Any-Id-Req
+               #  - &reply:Fullauth-Id-Req
+               #  - &reply:Permanent-Id-Req
+               #
+               #  Even if this configuration item is set to 'no', additional
+               #  identities can be requested by policy.
+               #  See sites-available/eap-aka-sim for details.
+               #
+#              request_identity = no
+
+               #
+               #  ephemeral_id_length:: The length of any pseudonyms or
+               #  fastauth identities we generate (not including hint byte).
+               #
+               #  See sites-available/eap-aka-sim for details on how to trigger
+               #  the generation of pseudonym or fastauth identities.
+               #
+#              ephemeral_id_length = 14
+
+               #
+               #  strip_permanent_identity_hint:: Strip the identity hint when
+               #  copying &EAP-Identity or &Identity to &Permanent-Identity.
+               #
+               #  The stripping is only performed if this config item is set
+               #  to yes, and the hint byte matches what we'd expect for the
+               #  EAP-Method being executed.
+               #
+#              strip_permanent_identity_hint = yes
+
+               #
+               #  protected_success:: Send a protected success message.
                #
                #  If `yes` - indicate to the peer that we'd like to send
                #  a protected success message.  If the peer agrees and
                #  authentication succeeds, send a `SIM-Notification` (Success)
                #  packet protected with an `AT_MAC` attribute.
                #
-               #  After the Notification is `ACKed` by the peer, we send
+               #  After the Notification is ACKed by the peer, we send
                #  the final `EAP-Success` packet containing `MPPE` keys.
                #
-#              send_result_ind = yes
+#              protected_success = yes
+
+               #
+               #  virtual_server:: EAP-SIM virtual server containing policy
+               #  sections.  This must be set, EAP-SIM will not function
+               #  without it, as certain operations like vector gathering
+               #  require user configuration.
+               #
+               virtual_server = eap-aka-sim
        }
 
        #
        #  ### EAP-AKA
        #
-       #  This takes no configuration.
-       #
        aka {
                #
-               #  network_name:: Network ID as described by RFC 5448.
+               #  protected_success:: Send protected success messages
+               #
+#              protected_success = no
+
+               #
+               #  virtual_server:: Same as for `TTLS`, `PEAP`, etc.
+               #
+#              virtual_server = ""
+
+               #  request_identity:: Send a AKA-Identity message to request
+               #  an additional identity to the one from the EAP-Identity-Response.
+               #
+               #  If `yes` - We send a request with AT_SUBTYPE AKA-Identity
+               #  with an AT_ANY_ID_REQ attribute to prompt the supplicant
+               #  to send a new identity.
+               #
+               #  The type of identity requested can be controlled by adding
+               #  one of the following attributes from the
+               #  `recv Identity-Response { ... }` section of the specified
+               #  EAP-AKA virtual_server, to the reply list:
+               #
+               #  - &reply:Any-Id-Req
+               #  - &reply:Fullauth-Id-Req
+               #  - &reply:Permanent-Id-Req
+               #
+               #  Even if this configuration item is set to 'no', additional
+               #  identities can be requested by policy.
+               #  See sites-available/eap-aka-sim for details.
+               #
+#              request_identity = no
+
+               #
+               #  ephemeral_id_length:: The length of any pseudonyms or
+               #  fastauth identities we generate (not including hint byte).
+               #
+               #  See sites-available/eap-aka-sim for details on how to trigger
+               #  the generation of pseudonym or fastauth identities.
+               #
+#              ephemeral_id_length = 14
+
+               #
+               #  strip_permanent_identity_hint:: Strip the identity hint when
+               #  copying &EAP-Identity or &Identity to &Permanent-Identity.
+               #
+               #  The stripping is only performed if this config item is set
+               #  to yes, and the hint byte matches what we'd expect for the
+               #  EAP-Method being executed.
+               #
+#              strip_permanent_identity_hint = yes
+
+               #
+               #  protected_success:: Send a protected success message.
+               #
+               #  If `yes` - indicate to the peer that we'd like to send
+               #  a protected success message.  If the peer agrees and
+               #  authentication succeeds, send a `AKA-Notification` (Success)
+               #  packet protected with an `AT_MAC` attribute.
+               #
+               #  After the Notification is ACKed by the peer, we send
+               #  the final `EAP-Success` packet containing `MPPE` keys.
+               #
+#              protected_success = yes
+
+               #
+               #  prefer_aka_prime:: Send the AT_BIDDING attribute in
+               #  AKA-Challenge messages.
+               #
+               #  When AT_BIDDING is sent in a AKA-Challenge and the supplicant
+               #  supports EAP-AKA-Prime, RFC 5448 states the supplicant
+               #  should abort the authentication attempt as a bidding down
+               #  attack may have occurred.
+               #
+               #  If a value is not provided for this configuration item
+               #  it will be determined automatically by whether the
+               #  EAP-AKA-Prime EAP method is enabled.
+               #
+#              prefer_aka_prime = yes
+
+               #
+               #  virtual_server:: EAP-AKA virtual server containing policy
+               #  sections.  This must be set, EAP-AKA will not function
+               #  without it, as certain operations like vector gathering
+               #  require user configuration.
+               #
+               virtual_server = eap-aka-sim
+       }
+
+       #
+       #  ### EAP-AKA-Prime
+       #
+       aka-prime {
+               #
+               #  network_name:: The default value used for AT_KDF_INPUT
+               #
+               #  EAP-AKA-Prime mixes various keys with a network identifier
+               #  specifying the user's point of connection into the network
+               #  to prevent vectors being used where they were not intended
+               #  to be.
+               #
+               #  The value of the AT_KDF_INPUT can be overriden in the
+               #  eap-aka-prime virtual server with &reply:KDF-Input if
+               #  this value needs to be determined dynamically.
+               #
+               #  How this value should be created and formatted is specified
+               #  in 3GPP.24.302.
                #
 #              network_name = ""
 
                #
-               #  request_identity:: Always send an identity request before a challenge.
+               #  request_identity:: Send a AKA-Identity message to request
+               #  an additional identity to the one from the EAP-Identity-Response.
                #
-#              request_identity = ""
+               #  If `yes` - We send a request with AT_SUBTYPE AKA-Identity
+               #  with an AT_ANY_ID_REQ attribute to prompt the supplicant
+               #  to send a new identity.
+               #
+               #  The type of identity requested can be controlled by adding
+               #  one of the following attributes from the
+               #  `recv Identity-Response { ... }` section of the specified
+               #  EAP-AKA virtual_server, to the reply list:
+               #
+               #  - &reply:Any-Id-Req
+               #  - &reply:Fullauth-Id-Req
+               #  - &reply:Permanent-Id-Req
+               #
+               #  Even if this configuration item is set to 'no', additional
+               #  identities can be requested by policy.
+               #  See sites-available/eap-aka-sim for details.
+               #
+#              request_identity = no
 
                #
-               #  protected_success:: Send protected success messages
+               #  ephemeral_id_length:: The length of any pseudonyms or
+               #  fastauth identities we generate (not including hint byte).
                #
-#              protected_success = no
+               #  See sites-available/eap-aka-sim for details on how to trigger
+               #  the generation of pseudonym or fastauth identities.
+               #
+#              ephemeral_id_length = 14
 
                #
-               #  virtual_server:: Same as for `TTLS`, `PEAP`, etc.
+               #  strip_permanent_identity_hint:: Strip the identity hint when
+               #  copying &EAP-Identity or &Identity to &Permanent-Identity.
                #
-#              virtual_server = ""
+               #  The stripping is only performed if this config item is set
+               #  to yes, and the hint byte matches what we'd expect for the
+               #  EAP-Method being executed.
+               #
+#              strip_permanent_identity_hint = yes
+
+               #
+               #  protected_success:: Send a protected success message.
+               #
+               #  If `yes` - indicate to the peer that we'd like to send
+               #  a protected success message.  If the peer agrees and
+               #  authentication succeeds, send a `AKA-Notification` (Success)
+               #  packet protected with an `AT_MAC` attribute.
+               #
+               #  After the Notification is ACKed by the peer, we send
+               #  the final `EAP-Success` packet containing `MPPE` keys.
+               #
+#              protected_success = yes
+
+               #
+               #  virtual_server:: EAP-AKA virtual server containing policy
+               #  sections.  This must be set, EAP-AKA-Prime will not function
+               #  without it, as certain operations like vector gathering
+               #  require user configuration.
+               #
+               virtual_server = eap-aka-sim
        }
 }
 
diff --git a/raddb/sites-available/eap-aka-sim b/raddb/sites-available/eap-aka-sim
new file mode 100644 (file)
index 0000000..a58f8d8
--- /dev/null
@@ -0,0 +1,714 @@
+#  -*- text -*-
+#
+#  :toc:
+#
+#  $Id$
+
+#######################################################################
+#
+#  = EAP-SIM/EAP-AKA/EAP-AKA-Prime policy server
+#
+#  This server is an example of applying custom, site-specific policies
+#  to eap-aka['] based authentication.
+#  As much control is given to the user to make decisions about which
+#  AT_* attributes will be returned to the supplicant. Wherever
+#  possible the internal state of the EAP-AKA module will be updated
+#  to reflect the attributes returned from sections.
+#
+
+######################################################################
+#
+#  ## Packet Processing sections
+#
+#  Sections in this server may behave slightly differently to sections
+#  in other virtual servers, as they're being called directly by the
+#  EAP-AKA module.
+#
+#  In general, the following rcodes signify a failure to the EAP-AKA
+#  state machine:
+#
+#  - `reject`
+#  - `fail`
+#  - `invalid`
+#  - `userlock`
+#
+#  Returning failure rcodes in the majority of sections will caused the
+#  authentication to fail.
+#
+#  In some instances however, we ignore the section rcode, as the standard
+#  does not allow for an orderly rejection of the supplicant.
+#
+#  Returning failure rcodes will be ignored in the following sections, and
+#  will instead generate a warning:
+#
+#  - `send EAP-Failure`                        already rejecting the auth attempt.
+#  - `send Failure-Notification`       already rejecting the auth attempt.
+#  - `recv Failure-Notification`       already rejecting the auth attempt.
+#  - `recv Success-Notification`       sending failure after EAP-Response/
+#                                      Success Notification-ACK would
+#                                      violate the standard.
+#  - `recv Authentication-Reject`      already rejecting the auth attempt.
+#  - `recv Client-Error`               already rejecting the auth attempt.
+#  - `clear Pseudonym`                 nothing more we can do...
+#  - `clear Session`                   nothing more we can do...
+#
+#  For sections dealing with identity processing the `notfound` rcode
+#  will trigger identity negotiation. The EAP-AKA module will then request
+#  additional identity values from the supplicant.  See the `recv
+#  EAP-Identity-Response` and `recv AKA-Identity-Response` sections for more
+#  details.
+#
+#  NOTE: Setting the EAP-AKA subtype attribute is not supported, and any
+#  attempts to modify it will be ignored (you are not trusted to know how to
+#  run the EAP-AKA state machine better than the EAP-AKA module).
+#
+######################################################################
+
+server eap-aka-sim {
+       #
+       #  This is a unified configuration example for EAP-SIM, EAP-AKA
+       #  and EAP-AKA-Prime.  Many of the sections are identical between
+       #  the three EAP methods.
+       #
+       #  The main differences are between EAP-SIM and EAP-AKA['] where
+       #  additional identity processing sections are used.
+       #
+#      namespace = eap-sim
+       namespace = eap-aka
+#      namespace = eap-aka-prime
+
+       #
+       #  ### `recv Identity-Response { ... }` - Process an EAP-Identity-Response or AKA-Identity value
+       #
+       #  This is usually the first section called when starting a new EAP-AKA
+       #  session, and will be called for each round of identity negotiation.
+       #
+       #  The following request attributes are available:
+       #  - `Identity`                 the identity value received in the
+       #                               EAP-Identity-Response.
+       #  - `Permanent-Identity`       If the hint byte at the start of the
+       #                               identity string indicated it was
+       #                               permanent.
+       #
+       #  - `Identity-Type`            The type of identity the 'hint' byte
+       #                               at the start of the identity indicates.
+       #                               - `Permanent`
+       #                               - `Pseudonym`
+       #                               - `Fastauath`
+       #
+       #  - `Method-Hint`              The EAP-Method the 'hint' byte
+       #                               at the start of the identity indicates:
+       #                               - `AKA-Prime`
+       #                               - `AKA`
+       #                               - `SIM`
+       #
+       #  At the end of this section the value of `&Identity-Type` will be
+       #  checked to see if any additional identity processing steps are
+       #  required.
+       #
+       #  The following actions are associated with the various
+       #  `Identity-Type` values:
+       #  - `Permanent`::      The current `&Identity` value will be copied to
+       #                       `&session-state:Permanent-Identity`.  The hint byte
+       #                       will be stripped if the hint matches the current
+       #                       EAP-Method.  If the hint byte does not match
+       #                       the current EAP-Method the complete value of
+       #                       Identity will be copied.  In both cases the realm
+       #                       will also be stripped.  You can override the
+       #                       identity stored here in policy.
+       #  - `Pseudonym`::      `load pseudonym { ... }` will be called.
+       #  - `Fastauth`::       `load session { ... }` will be called.
+       #
+       #  #### Identity hints
+       #
+       #  In EAP-AKA['] and EAP-SIM, the first byte of the identity is used as
+       #  a hint about what type of identity has been provided by the
+       #  supplicant and which EAP method should be started.
+       #
+       #  `Identity-Type` and `Method-Hint` are added by the EAP-AKA module as
+       #  a convenience to help determine if additional identities should be
+       #  requested.
+       #
+       #  If for whatever reason the provided ID isn't not recognised or
+       #  cannot be processed, you should return `notfound` from this section
+       #  to request an additional identity from the supplicant.
+       #
+       #  Adding any of the following attributes to the reply list will also
+       #  cause an additional identity to bre request from the supplicant.
+       #
+       #  - `Permanent-Id-Req`         request the supplicants `Permanent` Id
+       #                               usually its IMSI number.
+       #  - `Fullauth-Id-Req`          request either a `Permanent` or a
+       #                               `Pseudonym` identity`.
+       #  - `Any-Id-Req`               request any identity
+       #                               (`Fastauth`, `Pseudonym`, `Permanent``).
+       #
+       #  NOTE: We do not currently support handover between the EAP-AKA/SIM
+       #  modules.  Usually this is not an issue because EAP Negotiation
+       #  allows the supplicant and server to negotiate a mutually acceptable
+       #  EAP type. If, however, you want to avoid the additional roundtrips
+       #  involved in that negotiation, you can use
+       #  `%{aka_sim_id_method:User-Name}` in the top level virtual server,
+       #  which will return the EAP method hinted by the identity, and then
+       #  set `&control:EAP-Type` to an appropriate value before calling the
+       #  EAP module.
+       #
+       #  #### Pseudonyms
+       #
+       #  When receiving a `Identity-Type = Pseudonym` request, the pseudonym
+       #  should either be decrypted or resolved to a permanent identity.
+       #  Identity resolution can be done here, or in the `load pseudonym { ... }`
+       #  section.
+       #
+       #  If for whatever reason the identity cannot be validated, you should
+       #  return `notfound` to request an additional identity.
+       #
+       #  NOTE: Setting `&Method-Hint = Pseudonym` here will cause the server
+       #  to execute the `load pseudonym { ... }` section next.  This is
+       #  sometimes useful when dealing with non-standard pseudonym identities.
+       #
+       #  #### Reauthentication
+       #
+       #  When receiving a `Identity-Type = Fastauth` request, the fastauth
+       #  identity should be resolved in a datastore of valid fastauth
+       #  identities.
+       #  Session resolution can be done here, or in the `load session { ... }`
+       #  section.
+       #
+       #  If the identity cannot be resolved, you should return `notfound` to
+       #  request an additional identity.
+       #
+       #  NOTE: Setting `&Method-Hint = Fastauth` here will cause the server
+       #  to execute the `load session { ... }` section next.  This is
+       #  sometimes useful when dealing with non-standard fastauth identities.
+       #
+       recv Identity-Response {
+               ok
+       }
+
+       #
+       #  ### `send Identity-Request { ... }` - Allow user massaging of Identity-Request
+       #
+       #  This section is called when a new Start or AKA-Identity request is
+       #  sent to the supplicant, unless `send Start { ... }` or `send
+       #  AKA-Identity { ... }` sections are provided, in which case they will
+       #  be used instead.
+       #
+       send Identity-Request {
+               ok
+       }
+
+       #
+       #  ### `send Start-Request { ... }` - Allow specific policies to be applied to SIM start requests
+       #
+       #  This section is optional, and may be used to specify EAP-SIM only
+       #  logic for sending Start requests.
+       #
+       #  If this section is not provided, `send Identity-Request { ... }`
+       #  will be executed instead.
+       #
+       #  The Identity and Start messages perform a very similar role in
+       #  EAP-SIM/EAP-AKA, the main difference being, Start messages also
+       #  allow the version of EAP-SIM to be negotiated.
+       #
+#      send Start-Request {
+#              ok
+#      }
+
+       #
+       #  ### `send Start-Request { ... }` - Allow specific policies to be applied to SIM start responses
+       #
+       #  This section is optional, and may be used to specify EAP-SIM only
+       #  logic for sending Start requests.
+       #
+       #  If this section is not provided, `send Identity-Request { ... }`
+       #  will be executed instead.
+       #
+       #  The Identity and Start messages perform a very similar role in
+       #  EAP-SIM/EAP-AKA, the main difference being, Start messages also
+       #  allow the version of EAP-SIM to be negotiated.
+       #
+#      recv Start-Response {
+#              ok
+#      }
+
+       #
+       #  ### `send AKA-Identity-Request { ... }` - Allow specific policies to be applied to AKA identity requests
+       #
+       #  This section is optional, and may be used to specify
+       #  EAP-AKA/EAP-AKA['] only logic for sending AKA-Identity requests.
+       #
+       #  If this section is not provided, `send Identity-Request { ... }`
+       #  will be executed instead.
+       #
+       #  The Identity and Start messages perform a very similar role in
+       #  EAP-SIM/EAP-AKA, the main difference being, Start messages also
+       #  allow the version of EAP-SIM to be negotiated.
+       #
+#      send AKA-Identity-Request {
+#              ok
+#      }
+
+       #
+       #  ### `send Challenge-Request { ... }` - Acquire GSM triplets or UMTS quintuplets for the Challenge-Request
+       #
+       #  NOTE: It's recommended to perform identity resolution in `recv
+       #  EAP-Identity-Response` or `recv Identity-Response` and request or
+       #  generate UMTS quintuplets in this section.
+       #
+       #  The following attributes are added by the EAP-AKA module to the
+       #  control list:
+       #
+       #  - `SIM-AMF = 0x8000` Only set when using EAP-AKA'.
+       #                       This is a hint to any modules generating or
+       #                       retrieving UMTS quintuplets that the AMF
+       #                       separation bit should be high.
+       #
+       #  The following attributes are added by the EAP-AKA module to the reply
+       #  list, to be modified by policy:
+       #
+       #  - `KDF-Input`        Only set when using EAP-AKA'
+       #                       Is initially set to the value of the
+       #                       `network_name` configuration item.  But can
+       #                       be set to anything.  If EAP is running over
+       #                       RADIUS this should usually be the SSID
+       #                       portion of Called-Station-ID.
+       #  - `Bidding`          Only set when using EAP-AKA and the
+       #                       configuration item `prefer_aka_prime` is 'yes',
+       #                       or no `prefer_aka_prime` value is provided and
+       #                       EAP-AKA' is enabled in the same EAP module.
+       #  - `Result-Ind`       Set when the configuration item
+       #                       `protected_success` is 'yes'.
+       #
+       #  Two sets of control attributes are used depending on how the
+       #  quintuplets are being acquired.
+       #
+       #  If generating triplets or quintuplets locally you should provide the
+       #  following control attributes:
+       #
+       #  - `SIM-Ki`::         Secret shared by the AuC and SIM card.
+       #  - `SIM-SQN`::        Sequence number.  Must be stored/incremented
+       #                       for each set of quintuplets generated.  Used
+       #                       for replay protection, should be a higher
+       #                       value than the counterpart SQN on the SIM.
+       #  - `SIM-OP`/`SIM-OPc`::Operator Variant Algorithm Configuration Field.
+       #                       Input to milenage.  Can provide SIM-OPc if you
+       #                       already have access to it, else the OPc will
+       #                       be derived from the OP. Must match the value
+       #                       configured on the SIM card.
+       #
+       #  If retrieving triplets from the AuC, you should should provide
+       #  three sets of the following control attributes:
+       #
+       #  - `SIM-KC`::         Authentication value from the AuC.
+       #  - `SIM-RAND`::       User authentication challenge.
+       #  - `SIM-SRES`::       Signing response.
+       #
+       #  If retrieving quintuplets from a AuC, you should provide the
+       #  following control attributes:
+       #
+       #  - `SIM-AUTN`::       Authentication value from the AuC.
+       #  - `SIM-CK`::         Ciphering Key.
+       #  - `SIM-IK`::         Integrity Key.
+       #  - `SIM-RAND`::       User authentication challenge.
+       #  - `SIM-XRES`::       Signing response.
+       #  - `SIM-SQN`::        (optional)
+       #  - `SIM-AK`::         (optional)
+       #
+       #  ### Pseudonyms
+       #
+       #  For identity privacy you may include a `&reply:Next-Pseudonym`
+       #  attribute. `&reply:Next-Pseudonym` must be a valid UTF8 string and
+       #  MUST NOT contain a realm.  The supplicant will decorate the identity
+       #  as appropriate to ensure correct routing.
+       #
+       #  The following facilitates may be useful when generating pseudonym
+       #  values:
+       #
+       #  - The encrypt expansions of the `rlm_cipher` module.
+       #  - The `%{3gpp_pseudonym_encrypt:}` expansion.
+       #  - The `%{rand:}` expansion.
+       #
+       #  NOTE: Add a `&reply:Next-Pseudonym-Id` attribute in this section to
+       #  avoid having the permanent Id of the SIM exposed during subsequent
+       #  authentication attempts.
+       #
+       #  ### Fast-Reauth
+       #
+       #  For identity privacy, to reduce load on the AuC, and to improve
+       #  authentication times/user experience, fast re-authentication may be
+       #  used.
+       #
+       #  Fast re-authentication is very similar to session-resumption in TLS
+       #  based EAP methods, where the original MK (Master Key) is stored and
+       #  then used to generate new MSKs (Master Session Keys) for subsequent
+       #  authentication attempts.
+       #
+       #  NOTE: Add a `&reply:Next-Reauth-Id` attribute in this section, to
+       #  allow session-resumption for subsequent authentication attempts.
+       #
+       #  ### Cryptographic identity overrides
+       #
+       #  The identity provided as the value of EAP-Response/Identity or in
+       #  the last processed EAP-Response/AKA-Identity or
+       #  EAP-Response/SIM-Start message is used as an input to generate the
+       #  MK (Master Key) in full authentication, and XKEY' in
+       #  re-authentication.
+       #
+       #  The identity used as inputs for these cryptographic values must be
+       #  identical on both the supplicant and the EAP server, otherwise
+       #  authentication will fail with the supplicant returning a
+       #  EAP-Response/(AKA|SIM)-Client-Error message with an
+       #  AT_CLIENT_ERROR_CODE of "unable to process packet".
+       #
+       #  Some handset manufacturers have implemented identity schemes which
+       #  require an identity not provided in the EAP-Response/Identity
+       #  message, or sent as an AT_IDENTITY value. One such identity privacy
+       #  scheme described by 3GPP S3-170116 "Privacy Protection for EAP-AKA",
+       #  where the cryptographic identity is the plaintext extracted from
+       #  the encrypted identity blob.
+       #
+       #  If you need to implement one of these identity privacy schemes, the
+       #  cryptographic identity can be specified with `&control:KDF-Identity`.
+       #
+       send Challenge-Request {
+               ok
+       }
+
+       #
+       #  ### `recv Challenge-Response { ... }` - Allow additional authorization checks and logging
+       #
+       #  The following rcodes have special meanings in this section:
+       #
+       #  - `reject`                   Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 1026
+       #                               (User has been temporarily denied access).
+       #  - `userlock`                 Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 1026
+       #                               (User has been temporarily denied access).
+       #  - `notfound`                 Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 1031
+       #                               (User has not subscribed to the requested service).
+       #  - `invalid`                  Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 0
+       #                               (General failure after authentication).
+       #  - `Fail`                     Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 0
+       #                               (General failure after authentication).
+       #  - Anything else              Continue processing the request.
+       #
+       recv Challenge-Response {
+               ok
+       }
+
+       #
+       #  ### `recv Reauthentication-Request { ... }` - Allow user massaging of a reauthentication request
+       #
+       #  There's not much to do here as the majority of the work for
+       #  session resumption is done in `load session { ... }`.
+       #
+       #  Add a `&reply:Next-Pseudonym-Id` attribute in this section if you want
+       #  to allow avoid having the permanent Id of the SIM exposed during
+       #  subsequent authentication attempts.
+       #
+       #  Add a `&reply:Next-Reauth-Id` attribute in this section, to allow
+       #  session resumption for subsequent authentication attempts.
+       #
+       #  The following rcodes have special meanings in this section:
+       #
+       #  - `reject`                   Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 16384
+       #                               (General Failure).
+       #  - `userlock`                 Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 16384
+       #                               (General Failure).
+       #  - `ok`                       Continue with reauthentication.
+       #  - `updated`                  Continue with reauthentication.
+       #  - `noop`                     Continue with reauthentication.
+       #  - Anything else              Fall back to full authentication.
+       #
+       #  NOTE: You should use fresh reauthentication ID values here, else the
+       #  supplicant may be tracked as they would if their permanent Id has been
+       #  used.
+       #
+       send Reauthentication-Request {
+               ok
+       }
+
+       #
+       #  ### `recv Reauthentication-Response { ... }` - Allow additional authorization checks and logging
+       #
+       #  Uses the same rcode mappings as `recv Challenge-Response { ... }`.
+       #
+       #  Will not allow a transition back to the challenge state, as it's
+       #  not clear that this is allowed by RFC4186/RFC4187.
+       #
+       recv Reauthentication-Response {
+               ok
+       }
+
+       #
+       #  ### `recv Client-Error { ... }` - Log the fact that the supplicant has terminated authentication
+       #
+       #  The reason for the error should be available in `&Client-Error-Code`
+       #
+       #  After this section is run authentication fails immediately with no
+       #  EAP-Response/AKA-Notification round.
+       #
+       recv Client-Error {
+               ok
+       }
+
+       #
+       #  ### `recv Authentication-Reject { ... }` - Log the fact that the supplicant failed to authenticate the AuC
+       #
+       #  NOTE: Only used for EAP-AKA and EAP-AKA'
+       #
+       #  The supplicant will respond with EAP-Response/AKA-Authentication-Reject
+       #  whenever it cannot validate the AUTN (authentication) value provided in the
+       #  EAP-Request/AKA-Challenge packet.
+       #
+       #  No additional attributes are provided by the supplicant that specify
+       #  the error.
+       #
+       #  After this section is run authentication fails immediately with no
+       #  EAP-Response/AKA-Notification round.
+       #
+       recv Authentication-Reject {
+               ok
+       }
+
+       #
+       #  ### `recv Synchronization-Failure { ... }` - Allow resynchronisation of sequence numbers
+       #
+       #  NOTE: Only used for EAP-AKA and EAP-AKA'
+       #
+       #  In some instances the SQN on the SIM card and the SQN in the AuC can
+       #  get out of sync.  When this happens the supplicant will send a
+       #  EAP-Response/Synchronization-Failure message with an AUTS attribute.
+       #
+       #  If the original UMTS quintuplets were calculated locally and you
+       #  provided Ki and OP/OPc in the Challenge-Request round, then the
+       #  EAP-AKA module will automatically calculate a new SQN for you and
+       #  place it in `&control:SIM-SQN`.  You should store this new SQN.
+       #
+       #  As a convenience, the EAP-AKA module will also repopulate
+       #  &control:SIM-Ki and &control:SIM-OPc so you do not need to retrieve
+       #  them again in the `send Challenge-Request { ... }` section.
+       #
+       #  If the UMTS quintuplets were provided by an AuC, you should submit
+       #  the AUTS value to the AuC to allow it to calculate a new SQN, then
+       #  retrieve a new UMTS quintuplet in the
+       #  `send Challenge-Request { ... }` section.
+       #
+       #  If the rcode returned from this section does not indicate failure
+       #  and a &control:SQN value is provided, we send a new challenge to
+       #  the supplicant and continue, otherwise, authentication fails.
+       #
+       #  NOTE: Only one Synchronisation attempt is permited per
+       #  authentication attempt.
+       #
+       recv Synchronization-Failure {
+               ok
+       }
+
+       #
+       #  ### `send Failure-Notification { ... }` - Allow massaging/logging of failure notifications
+       #
+       #  NOTE: The rcode returned from this section is ignored.
+       #
+       send Failure-Notification {
+               ok
+       }
+
+       #
+       #  ### `send Failure-Notification { ... }` - Allow logging of failure notification acknowledgements
+       #
+       #  NOTE: The rcode returned from this section is ignored.
+       #
+       recv Failure-Notification-ACK {
+               ok
+       }
+
+       #
+       #  ### `send Success-Notification { ... }` - Allow massaging/logging of success notifications
+       #
+       #  Uses the same rcode mappings as `recv Challenge-Response { ... }`.
+       #
+       #  NOTE: Only entered if protected result indications are used.
+       #
+       send Success-Notification {
+               ok
+       }
+
+       #
+       #  ### `send Success-Notification-Ack { ... }` - Allow logging of success notification acknowledgements
+       #
+       #  NOTE: The rcode returned from this section is ignored.
+       #
+       recv Success-Notification-ACK {
+               ok
+       }
+
+       #
+       #  ### `send EAP-Success { ... }` - Allow massaging/logging of success notifications
+       #
+       #  NOTE: The rcode returned from this section is ignored if we have already sent
+       #  a Success-Notification, otherwise the same rcode mappings as
+       #  `recv Challenge-Response { ... }` are used.
+       #
+       send EAP-Success {
+               ok
+       }
+
+       #
+       #  ### `send EAP-Failure { ... }` - Allow logging of failure notification acknowledgements
+       #
+       #  NOTE: The rcode returned from this section is ignored.
+       #
+       recv EAP-Failure {
+               ok
+       }
+
+       #
+       #  ### `store pseudonym { ... }`
+       #
+       #  If when sending a Challenge-Request Reauthentication-Request a
+       #  `&reply:Next-Pseudonym-Id` attribute is found, this section will be
+       #  called.
+       #
+       #  If `&reply:Next-Pseudonym-Id` is empty, it will be filled with a random
+       #  string of alphanumeric characters.
+       #
+       #  For consistency, &reply:Next-Pseudonym-Id will also be made available
+       #  temporarily in `&Next-Pseudonym-Id` for use as a key.
+       #
+       #  You should store the following attributes against the key
+       #  `&Next-Paeudonym-Id`:
+       #
+       #  - `&session-State:Permanent-Identity`::The permanent identity of the user.
+       #
+       #  If a failure rcode is returned authentication continues but the
+       #  Next-Pseudonym-Id will not be sent to the supplicant.
+       #
+       #  NOTE: The cache module is ideally suited for storing pseudonym
+       #  data.  If you're using multiple instances of FreeRADIUS in a
+       #  failover cluster, you may wish to use the redis or memcached drivers
+       #  to provide a unified pseudonym store.
+       #
+       #  NOTE: If you're using 3GPP style encrypted pseudonyms you do not
+       #  need populate this section.  You should however, provide a policy
+       #  for `load session { ... }`, and use that to decrypt the pseudonym.
+       #
+       store pseudonym {
+               ok
+       }
+
+       #
+       #  ### `load pseudonym { ... }`
+       #
+       #  This section will be called prior to entering the AKA-CHALLENGE state.
+       #
+       #  You should restore the contents of the following attributes using
+       #  `&Next-Pseudonym-Id` as a key:
+       #
+       #  - `&session-State:Permanent-Identity`::The permanent identity of the user.
+       #
+       #  NOTE: If you're using 3GPP style encrypted pseudonyms, you should
+       #  decrypt the pseudonym here, and store the decrypted value in
+       #  `&session-state:Permanent-Identity`.
+       #
+       load pseudonym {
+               ok
+       }
+
+       #
+       #  ### `clear pseudonym { ... }`
+       #
+       #  This section we be called if authentication or re-authentication fails.
+       #
+       #  You should remove any session information stored against
+       #  `&Next-Pseudonym-Id`.
+       #
+       clear pseudonym {
+               ok
+       }
+
+       #
+       #  ### `store session { ... }`
+       #
+       #  If when sending a Reauthentication-Request a `&reply:Next-Reauth-Id`
+       #  attribute is found, this section will be called.
+       #
+       #  You should restore the contents of the following attributes using
+       #  `&session-state:Session-ID` or `&reply:Next-Reauth-Id` as a key:
+       #
+       #  - `&session-state:Counter`::         How many times this session has
+       #                                       been resumed.
+       #  - `&session-state:Session-Data`::    The master session key.
+       #  - `&session-State:Permanent-Identity`::(optionally) the permanent
+       #                                       identity of the user.
+       #
+       #  If a failure rcode is returned, authentication continues but the
+       #  Next-Reauth-Id will not be sent to the supplicant.
+       #
+       #  NOTE: The cache module is ideally suited for storing session data.
+       #  If you're using multiple instances of FreeRADIUS in a failover
+       #  cluster, you may wish to use the redis or memcached drivers to
+       #  provide a unified session store.
+       #
+       store session {
+               ok
+       }
+
+       #
+       #  ### `load session { ... }`
+       #
+       #  This section will be called prior to attempting re-authentication.
+       #
+       #  You should restore the contents of the following attributes using
+       #  `&session-state:Session-ID` or `&reply:Next-Reauth-Id` as a key:
+       #
+       #  - `&session-state:Counter`::         How many times this session has
+       #                                       been resumed.
+       #  - `&session-state:Session-Data`::    The master session key.
+       #  - `&session-State:Permanent-Identity`::(optionally) the permanent
+       #                                       identity of the user.
+       #
+       #  The following rcodes have special meanings in this section:
+       #
+       #  - `reject`                   Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 16384
+       #                               (General Failure).
+       #  - `userlock`                 Reject the authentication attempt, send
+       #                               a Failure-Notification with an
+       #                               AT_NOTIFICATION value of 16384
+       #                               (General Failure).
+       #  - `ok`                       Continue with reauthentication.
+       #  - `updated`                  Continue with reauthentication.
+       #  - Anything else              Fall back to full authentication.
+       #
+       load session {
+               ok
+       }
+
+       #
+       #  ### `clear session { ... }`
+       #
+       #  This section we be called if authentication or re-authentication fails.
+       #
+       #  You should remove any session information stored against
+       #  `&Next-Reauth-Id`.
+       #
+       clear session {
+               ok
+       }
+}
index 4d5e6dd8120b46e9bdf693c0f4530e199a0c1f55..118cb320dd3ce1878f7a1dae8e1442a756f1ba01 100644 (file)
@@ -54,7 +54,7 @@ server tls-cache {
        #  This section is run whenever the server needs to write an
        #  entry to the TLS session cache.
        #
-       #  It should write the attribute &session-state:TLS-Session-Data
+       #  It should write the attribute &session-state:Session-Data
        #  to the cache, along with any other attributes which
        #  need to be cached.
        #
similarity index 73%
rename from share/dictionary/eap/aka/dictionary
rename to share/dictionary/eap/aka-sim/dictionary
index f9a7eb5680511b34b8d8da260f98b483e7d005ce..8261826469893571e41fe4c75fa4f21226909ae6 100644 (file)
@@ -3,11 +3,11 @@
 # This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
 # Version $Id$
 #
-#      Protocol dictionary for EAP-AKA
+#      Protocol dictionary for EAP-AKA, EAP-AKA', and EAP-SIM
 #
 #
-PROTOCOL       EAP-AKA         102
-BEGIN-PROTOCOL EAP-AKA
+PROTOCOL       EAP-AKA-SIM     102
+BEGIN-PROTOCOL EAP-AKA-SIM
 
 $INCLUDE dictionary.freeradius
 $INCLUDE dictionary.rfc4187
@@ -16,4 +16,4 @@ $INCLUDE dictionary.rfc7458
 $INCLUDE dictionary.3gpp-ts24.139
 $INCLUDE dictionary.3gpp-ts24.302
 
-END-PROTOCOL   EAP-AKA
+END-PROTOCOL   EAP-AKA-SIM
similarity index 77%
rename from share/dictionary/eap/aka/dictionary.3gpp-ts24.139
rename to share/dictionary/eap/aka-sim/dictionary.3gpp-ts24.139
index 4eca38a81c3e7c587e3692791f57c119a9524cf0..d1c599eaf7ce83c3ace8974f99dccb0792ecc655 100644 (file)
@@ -9,5 +9,5 @@
 #
 #  Skippable-Attributes
 #
-ATTRIBUTE      EAP-AKA-RQSI-Ind                        142     octets
-ATTRIBUTE      EAP-AKA-RQSI-Res                        143     octets
+ATTRIBUTE      RQSI-Ind                        142     octets
+ATTRIBUTE      RQSI-Res                        143     octets
diff --git a/share/dictionary/eap/aka-sim/dictionary.3gpp-ts24.302 b/share/dictionary/eap/aka-sim/dictionary.3gpp-ts24.302
new file mode 100644 (file)
index 0000000..4da6483
--- /dev/null
@@ -0,0 +1,18 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+#      EAP-AKA attributes defined by 3gpp-ts24.302
+#
+
+#
+#  Skippable-Attributes
+#
+ATTRIBUTE      IPMS-Ind                        137     octets
+ATTRIBUTE      IPMS-Res                        138     octets
+ATTRIBUTE      Tust-Ind                        139     octets
+ATTRIBUTE      Short-Name-For-Network          140     octets
+ATTRIBUTE      Full-Name-For-Network           141     octets
+
+ATTRIBUTE      Twan-Conn-Mode                  144     octets
diff --git a/share/dictionary/eap/aka-sim/dictionary.freeradius b/share/dictionary/eap/aka-sim/dictionary.freeradius
new file mode 100644 (file)
index 0000000..f21de62
--- /dev/null
@@ -0,0 +1,68 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+#      Attributes needed by FreeRADIUS internally
+#
+
+#
+#  Internal (Non-Protocol) attributes
+#
+FLAGS  internal
+ATTRIBUTE      Subtype                         256     integer
+
+VALUE  Subtype                 AKA-Challenge                   1
+VALUE  Subtype                 AKA-Authentication-Reject       2
+VALUE  Subtype                 AKA-Synchronization-Failure     4
+VALUE  Subtype                 AKA-Identity                    5       # EAP-SIM uses SIM-Start packets for the same purpose
+VALUE  Subtype                 SIM-Start                       10
+VALUE  Subtype                 SIM-Challenge                   11
+VALUE  Subtype                 AKA-SIM-Notification            12
+VALUE  Subtype                 AKA-SIM-Reauthentication        13
+VALUE  Subtype                 AKA-SIM-Client-Error            14
+
+ATTRIBUTE      HMAC                            257     string
+ATTRIBUTE      Key                             258     octets
+ATTRIBUTE      Extra                           259     octets
+
+#
+#  UMTS vector
+#
+ATTRIBUTE      XRES                            260     octets
+ATTRIBUTE      CK                              261     octets
+ATTRIBUTE      IK                              262     octets
+ATTRIBUTE      AUTHN                           263     octets
+
+#
+#  SIM vector
+#
+ATTRIBUTE      SRES                            270     octets
+ATTRIBUTE      KC                              271     octets
+
+#
+#  Identity negotiation
+#
+ATTRIBUTE      Method-Hint                     280     integer
+
+VALUE  Method-Hint             AKA-Prime               0
+VALUE  Method-Hint             AKA                     1
+VALUE  Method-Hint             SIM                     2
+
+ATTRIBUTE      Identity-Type                   281     integer
+
+VALUE  Identity-Type           Permanent               0
+VALUE  Identity-Type           Pseudonym               1
+VALUE  Identity-Type           Fastauth                2
+
+ATTRIBUTE      Permanent-Identity                      282     string
+ATTRIBUTE      KDF-Identity                            283     string  # Allow override of KDF Identity input
+
+#
+#  Reauthentication
+#
+ATTRIBUTE      MK                              290     octets          # Master key
+ATTRIBUTE      AK                              291     octets
+ATTRIBUTE      K-Re                            292     octets          # AKA' KDF 1 reauthentication key.
+
+
diff --git a/share/dictionary/eap/aka-sim/dictionary.rfc4187 b/share/dictionary/eap/aka-sim/dictionary.rfc4187
new file mode 100644 (file)
index 0000000..cdbbaa9
--- /dev/null
@@ -0,0 +1,70 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+##############################################################################
+#
+#      EAP-SIM and EAP-AKA attributes
+#
+##############################################################################
+#
+#  Non-Skippable attributes
+#
+ATTRIBUTE      RAND                            1       octets[16] array        # Not an array, single value
+ATTRIBUTE      AUTN                            2       octets[16]
+ATTRIBUTE      RES                             3       octets[16]              # Special case (length field with length in bits)
+ATTRIBUTE      AUTS                            4       octets[14]              # Special case no reserved field.
+ATTRIBUTE      Nonce-MT                        7       octets[16]
+ATTRIBUTE      Permanent-ID-Req                10      bool
+ATTRIBUTE      MAC                             11      octets[16]
+ATTRIBUTE      Notification                    12      short
+
+VALUE  Notification            General-Failure-After-Authentication 0
+VALUE  Notification            Temporarily-Denied      1026
+VALUE  Notification            Not-Subscribed          1031
+VALUE  Notification            General-Failure         16384
+VALUE  Notification            Success                 32768
+
+ATTRIBUTE      Any-ID-Req                      13      bool
+ATTRIBUTE      Identity                        14      string
+ATTRIBUTE      Version-List                    15      short array
+ATTRIBUTE      Selected-Version                16      short
+ATTRIBUTE      Fullauth-ID-Req                 17      bool
+ATTRIBUTE      Client-Error-Code               22      short
+
+VALUE  Client-Error-Code       Unable-To-Process-Packet 0
+VALUE  Client-Error-Code       Unsupported-Version     1
+VALUE  Client-Error-Code       Insufficient-Challenges 2
+VALUE  Client-Error-Code       RANDS-Not-Fresh         3
+
+ATTRIBUTE      KDF-Input                       23      string
+ATTRIBUTE      KDF                             24      short
+
+VALUE  KDF                     Prime-With-CK-Prime-IK-Prime 1
+
+#
+#  Skippable-Attributes
+#
+ATTRIBUTE      IV                              129     octets[16]
+ATTRIBUTE      Encr-Data                       130     tlv encrypt=4
+
+#
+#  These attributes are reversibly encrypted
+#
+BEGIN-TLV      Encr-Data
+ATTRIBUTE      Padding                         6       octets          # 4, 8, 12 bytes
+ATTRIBUTE      Counter                         19      short
+ATTRIBUTE      Counter-Too-Small               20      bool
+ATTRIBUTE      Nonce-S                         21      octets[16]
+ATTRIBUTE      Next-Pseudonym                  132     string
+ATTRIBUTE      Next-Reauth-ID                  133     string
+END-TLV                Encr-Data
+
+ATTRIBUTE      Checkcode                       134     octets          # 0, 20 or 32 bytes
+
+ATTRIBUTE      Bidding                         136     short
+
+VALUE  Bidding                 Prefer-AKA              0
+VALUE  Bidding                 Prefer-AKA-Prime        32768   # D Bit
+
+ATTRIBUTE      Result-Ind                      137     bool
similarity index 78%
rename from share/dictionary/eap/aka/dictionary.rfc5448
rename to share/dictionary/eap/aka-sim/dictionary.rfc5448
index 1d15b87941065c3510ac6c93294dbf063a19eb91..bafb32713b14166981aa53b8a315b2ce483654b7 100644 (file)
@@ -9,5 +9,5 @@
 #
 #  Non-Skippable attributes
 #
-ATTRIBUTE      EAP-AKA-KDF-Input                       23      string
-ATTRIBUTE      EAP-AKA-KDF                             24      short
+ATTRIBUTE      KDF-Input                       23      string
+ATTRIBUTE      KDF                             24      short
diff --git a/share/dictionary/eap/aka-sim/dictionary.rfc7458 b/share/dictionary/eap/aka-sim/dictionary.rfc7458
new file mode 100644 (file)
index 0000000..590bcfb
--- /dev/null
@@ -0,0 +1,17 @@
+# -*- text -*-
+# Copyright (C) 2019 The FreeRADIUS Server project and contributors
+# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
+# Version $Id$
+#
+#      EAP-AKA attributes defined by rfc7458
+#
+
+#
+#  Skippable-Attributes
+#
+ATTRIBUTE      Virtual-Network-ID              145     octets
+ATTRIBUTE      Virtual-Network-Req             146     octets
+ATTRIBUTE      Connectivity-Type               147     octets
+ATTRIBUTE      Handover-Indication             148     octets
+ATTRIBUTE      Handover-Session-ID             149     octets
+ATTRIBUTE      MN-Serial-ID                    150     octets
diff --git a/share/dictionary/eap/aka/dictionary.3gpp-ts24.302 b/share/dictionary/eap/aka/dictionary.3gpp-ts24.302
deleted file mode 100644 (file)
index 70f9099..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      EAP-AKA attributes defined by 3gpp-ts24.302
-#
-
-#
-#  Skippable-Attributes
-#
-ATTRIBUTE      EAP-AKA-IPMS-Ind                        137     octets
-ATTRIBUTE      EAP-AKA-IPMS-Res                        138     octets
-ATTRIBUTE      EAP-AKA-Tust-Ind                        139     octets
-ATTRIBUTE      EAP-AKA-Short-Name-For-Network          140     octets
-ATTRIBUTE      EAP-AKA-Full-Name-For-Network           141     octets
-
-ATTRIBUTE      EAP-AKA-Twan-Conn-Mode                  144     octets
diff --git a/share/dictionary/eap/aka/dictionary.freeradius b/share/dictionary/eap/aka/dictionary.freeradius
deleted file mode 100644 (file)
index e106d80..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      Attributes needed by FreeRADIUS internally
-#
-
-#
-#  Internal (Non-Protocol) attributes
-#
-FLAGS  internal
-ATTRIBUTE      EAP-AKA-Subtype                         256     integer
-
-VALUE  EAP-AKA-Subtype                 AKA-Challenge           1
-VALUE  EAP-AKA-Subtype                 AKA-Authentication-Reject 2
-VALUE  EAP-AKA-Subtype                 AKA-Synchronization-Failure 4
-VALUE  EAP-AKA-Subtype                 AKA-Identity            5
-VALUE  EAP-AKA-Subtype                 AKA-Notification        12
-VALUE  EAP-AKA-Subtype                 AKA-Reauthentication    13
-VALUE  EAP-AKA-Subtype                 AKA-Client-Error        14
-
-ATTRIBUTE      EAP-AKA-HMAC                            257     string
-ATTRIBUTE      EAP-AKA-Key                             258     octets
-ATTRIBUTE      EAP-AKA-Extra                           259     octets
-
-ATTRIBUTE      EAP-AKA-XRES                            260     octets
-ATTRIBUTE      EAP-AKA-CK                              261     octets
-ATTRIBUTE      EAP-AKA-IK                              262     octets
-ATTRIBUTE      EAP-AKA-AUTHN                           263     octets
-
-#
-#  Keys to store for fast-reauthentication
-#
-ATTRIBUTE      EAP-AKA-MK                              264     octets          # Master key
-ATTRIBUTE      EAP-AKA-AK                              265     octets
diff --git a/share/dictionary/eap/aka/dictionary.rfc4187 b/share/dictionary/eap/aka/dictionary.rfc4187
deleted file mode 100644 (file)
index c108383..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-##############################################################################
-#
-#      EAP-AKA and EAP-AKA' Protocol attributes
-#
-##############################################################################
-#
-#  Non-Skippable attributes
-#
-ATTRIBUTE      EAP-AKA-RAND                            1       octets[16]      # Not an array, single value
-ATTRIBUTE      EAP-AKA-AUTN                            2       octets[16]
-ATTRIBUTE      EAP-AKA-RES                             3       octets[16]      # Special case (length field with length in bits)
-ATTRIBUTE      EAP-AKA-AUTS                            4       octets[14]      # Special case no reserved field.
-ATTRIBUTE      EAP-AKA-Permanent-ID-Req                10      bool
-ATTRIBUTE      EAP-AKA-MAC                             11      octets[16]
-ATTRIBUTE      EAP-AKA-Notification                    12      short
-
-VALUE  EAP-AKA-Notification            General-Failure-After-Authentication 0
-VALUE  EAP-AKA-Notification            Temporarily-Denied      1026
-VALUE  EAP-AKA-Notification            Not-Subscribed          1031
-VALUE  EAP-AKA-Notification            General-Failure         16384
-VALUE  EAP-AKA-Notification            Success                 32768
-
-ATTRIBUTE      EAP-AKA-Any-ID-Req                      13      bool
-ATTRIBUTE      EAP-AKA-Identity                        14      string
-
-ATTRIBUTE      EAP-AKA-Fullauth-ID-Req                 17      bool
-ATTRIBUTE      EAP-AKA-Client-Error-Code               22      short
-
-VALUE  EAP-AKA-Client-Error-Code       Unable-To-Process-Packet 0
-VALUE  EAP-AKA-Client-Error-Code       Unsupported-Version     1
-VALUE  EAP-AKA-Client-Error-Code       Insufficient-Challenges 2
-VALUE  EAP-AKA-Client-Error-Code       RANDS-Not-Fresh         3
-
-ATTRIBUTE      EAP-AKA-KDF-Input                       23      string
-ATTRIBUTE      EAP-AKA-KDF                             24      short
-
-VALUE  EAP-AKA-KDF                     EAP-AKA                 0
-VALUE  EAP-AKA-KDF                     EAP-AKA-Prime-With-CK-Prime-IK-Prime 1
-
-#
-#  Skippable-Attributes
-#
-ATTRIBUTE      EAP-AKA-IV                              129     octets[16]
-ATTRIBUTE      EAP-AKA-Encr-Data                       130     tlv encrypt=4
-
-#
-#  These attributes are reversibly encrypted
-#
-BEGIN-TLV      EAP-AKA-Encr-Data
-ATTRIBUTE      EAP-AKA-Padding                         6       octets          # 4, 8, 12 bytes
-ATTRIBUTE      EAP-AKA-Counter                         19      short
-ATTRIBUTE      EAP-AKA-Counter-Too-Small               20      bool
-ATTRIBUTE      EAP-AKA-Nonce-S                         21      octets[16]
-ATTRIBUTE      EAP-AKA-Next-Pseudonym                  132     string
-ATTRIBUTE      EAP-AKA-Next-Reauth-ID                  133     string
-END-TLV                EAP-AKA-Encr-Data
-
-ATTRIBUTE      EAP-AKA-Checkcode                       134     octets          # 0, 20 or 32 bytes
-
-ATTRIBUTE      EAP-AKA-Bidding                         136     short
-
-VALUE  EAP-AKA-Bidding                 Prefer-AKA              0
-VALUE  EAP-AKA-Bidding                 Prefer-AKA-Prime        32768   # D Bit
-
-ATTRIBUTE      EAP-AKA-Result-Ind                      137     bool
diff --git a/share/dictionary/eap/aka/dictionary.rfc7458 b/share/dictionary/eap/aka/dictionary.rfc7458
deleted file mode 100644 (file)
index b305087..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      EAP-AKA attributes defined by rfc7458
-#
-
-#
-#  Skippable-Attributes
-#
-ATTRIBUTE      EAP-AKA-Virtual-Network-ID              145     octets
-ATTRIBUTE      EAP-AKA-Virtual-Network-Req             146     octets
-ATTRIBUTE      EAP-AKA-Connectivity-Type               147     octets
-ATTRIBUTE      EAP-AKA-Handover-Indication             148     octets
-ATTRIBUTE      EAP-AKA-Handover-Session-ID             149     octets
-ATTRIBUTE      EAP-AKA-MN-Serial-ID                    150     octets
diff --git a/share/dictionary/eap/sim/dictionary b/share/dictionary/eap/sim/dictionary
deleted file mode 100644 (file)
index bf3adf4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      Protocol dictionary for EAP-SIM
-#
-#
-PROTOCOL       EAP-SIM         101
-BEGIN-PROTOCOL EAP-SIM
-
-$INCLUDE dictionary.freeradius
-$INCLUDE dictionary.rfc4187
-$INCLUDE dictionary.rfc5448
-$INCLUDE dictionary.rfc7458
-$INCLUDE dictionary.3gpp-ts24.139
-$INCLUDE dictionary.3gpp-ts24.302
-
-END-PROTOCOL   EAP-SIM
diff --git a/share/dictionary/eap/sim/dictionary.3gpp-ts24.139 b/share/dictionary/eap/sim/dictionary.3gpp-ts24.139
deleted file mode 100644 (file)
index 0b30531..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      EAP-SIM attributes defined by 3gpp-ts24.139
-#
-
-#
-#  Skippable-Attributes
-#
-ATTRIBUTE      EAP-SIM-RQSI-Ind                        142     octets
-ATTRIBUTE      EAP-SIM-RQSI-Res                        143     octets
diff --git a/share/dictionary/eap/sim/dictionary.3gpp-ts24.302 b/share/dictionary/eap/sim/dictionary.3gpp-ts24.302
deleted file mode 100644 (file)
index 76a9617..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      EAP-SIM attributes defined by 3gpp-ts24.302
-#
-
-#
-#  Skippable-Attributes
-#
-ATTRIBUTE      EAP-SIM-IPMS-Ind                        137     octets
-ATTRIBUTE      EAP-SIM-IPMS-Res                        138     octets
-ATTRIBUTE      EAP-SIM-Tust-Ind                        139     octets
-ATTRIBUTE      EAP-SIM-Short-Name-For-Network          140     octets
-ATTRIBUTE      EAP-SIM-Full-Name-For-Network           141     octets
-
-ATTRIBUTE      EAP-SIM-Twan-Conn-Mode                  144     octets
diff --git a/share/dictionary/eap/sim/dictionary.freeradius b/share/dictionary/eap/sim/dictionary.freeradius
deleted file mode 100644 (file)
index dfa77aa..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      Attributes needed by FreeRADIUS internally
-#
-
-#
-#  Internal (Non-Protocol) attributes
-#
-FLAGS  internal
-ATTRIBUTE      EAP-SIM-Subtype                         256     integer
-
-VALUE  EAP-SIM-Subtype                 SIM-Start               10
-VALUE  EAP-SIM-Subtype                 SIM-Challenge           11
-VALUE  EAP-SIM-Subtype                 SIM-Notification        12
-VALUE  EAP-SIM-Subtype                 SIM-Reauthentication    13
-VALUE  EAP-SIM-Subtype                 SIM-Client-Error        14
-
-ATTRIBUTE      EAP-SIM-HMAC                            257     string
-ATTRIBUTE      EAP-SIM-Key                             258     octets
-ATTRIBUTE      EAP-SIM-Extra                           259     octets
-
-ATTRIBUTE      EAP-SIM-MK                              264     octets          # Master key
-
-ATTRIBUTE      EAP-SIM-SRES                            1222    octets
-ATTRIBUTE      EAP-SIM-KC                              1223    octets
-ATTRIBUTE      EAP-SIM-State                           1224    integer
diff --git a/share/dictionary/eap/sim/dictionary.rfc4187 b/share/dictionary/eap/sim/dictionary.rfc4187
deleted file mode 100644 (file)
index baede94..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-##############################################################################
-#
-#      EAP-SIM attributes defined by rfc4187
-#
-##############################################################################
-
-#
-#  Non-Skippable attributes
-#
-ATTRIBUTE      EAP-SIM-RAND                            1       octets[16] array
-ATTRIBUTE      EAP-SIM-Nonce-MT                        7       octets[16]
-ATTRIBUTE      EAP-SIM-Permanent-ID-Req                10      bool
-ATTRIBUTE      EAP-SIM-MAC                             11      octets[16]
-ATTRIBUTE      EAP-SIM-Notification                    12      short
-
-VALUE  EAP-SIM-Notification            General-Failure-After-Authentication 0
-VALUE  EAP-SIM-Notification            Temporarily-Denied      1026
-VALUE  EAP-SIM-Notification            Not-Subscribed          1031
-VALUE  EAP-SIM-Notification            General-Failure         16384
-VALUE  EAP-SIM-Notification            Success                 32768
-
-ATTRIBUTE      EAP-SIM-Any-ID-Req                      13      bool
-ATTRIBUTE      EAP-SIM-Identity                        14      string
-ATTRIBUTE      EAP-SIM-Version-List                    15      short array
-ATTRIBUTE      EAP-SIM-Selected-Version                16      short
-ATTRIBUTE      EAP-SIM-Fullauth-ID-Req                 17      bool
-ATTRIBUTE      EAP-SIM-Client-Error-Code               22      short
-
-VALUE  EAP-SIM-Client-Error-Code       Unable-To-Process-Packet 0
-VALUE  EAP-SIM-Client-Error-Code       Unsupported-Version     1
-VALUE  EAP-SIM-Client-Error-Code       Insufficient-Challenges 2
-VALUE  EAP-SIM-Client-Error-Code       RANDS-Not-Fresh         3
-
-#
-#  Skippable-Attributes
-#
-ATTRIBUTE      EAP-SIM-IV                              129     octets[16]
-ATTRIBUTE      EAP-SIM-Encr-Data                       130     tlv encrypt=4
-
-#
-#  These attributes are reversibly encrypted
-#
-BEGIN-TLV      EAP-SIM-Encr-Data
-ATTRIBUTE      EAP-SIM-Padding                         6       octets          # 4, 8, 12 bytes length
-ATTRIBUTE      EAP-SIM-Counter                         19      short
-ATTRIBUTE      EAP-SIM-Counter-Too-Small               20      bool
-ATTRIBUTE      EAP-SIM-Nonce-S                         21      octets[16]
-ATTRIBUTE      EAP-SIM-Next-Pseudonym                  132     string
-ATTRIBUTE      EAP-SIM-Next-Reauth-ID                  133     string
-END-TLV                EAP-SIM-Encr-Data
-
-ATTRIBUTE      EAP-SIM-Result-Ind                      137     bool
-
-#
-#  Internal attributes used by FreeRADIUS
-#
-FLAGS  internal
-ATTRIBUTE      EAP-SIM-Subtype                         256     integer
-
-VALUE  EAP-SIM-Subtype                 SIM-Start               10
-VALUE  EAP-SIM-Subtype                 SIM-Challenge           11
-VALUE  EAP-SIM-Subtype                 SIM-Notification        12
-VALUE  EAP-SIM-Subtype                 SIM-Reauthentication    13
-VALUE  EAP-SIM-Subtype                 SIM-Client-Error        14
-
-ATTRIBUTE      EAP-SIM-SRES                            1222    octets
-ATTRIBUTE      EAP-SIM-KC                              1223    octets
-ATTRIBUTE      EAP-SIM-State                           1224    integer
-
-#
-#  Keys to store for fast-reauthentication
-#
-ATTRIBUTE      EAP-AKA-MK                              264     octets          # Master key
diff --git a/share/dictionary/eap/sim/dictionary.rfc5448 b/share/dictionary/eap/sim/dictionary.rfc5448
deleted file mode 100644 (file)
index 01fdfae..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      EAP-SIM attributes defined by rfc5448
-#
-
-#
-#  Non-Skippable attributes
-#
-ATTRIBUTE      EAP-SIM-KDF-Input                       24      octets
-ATTRIBUTE      EAP-SIM-KDF                             25      octets
diff --git a/share/dictionary/eap/sim/dictionary.rfc7458 b/share/dictionary/eap/sim/dictionary.rfc7458
deleted file mode 100644 (file)
index 39950cc..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- text -*-
-# Copyright (C) 2019 The FreeRADIUS Server project and contributors
-# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
-# Version $Id$
-#
-#      EAP-SIM attributes defined by rfc7458
-#
-
-#
-#  Skippable-Attributes
-#
-ATTRIBUTE      EAP-SIM-Virtual-Network-ID              145     octets
-ATTRIBUTE      EAP-SIM-Virtual-Network-Req             146     octets
-ATTRIBUTE      EAP-SIM-Connectivity-Type               147     octets
-ATTRIBUTE      EAP-SIM-Handover-Indication             148     octets
-ATTRIBUTE      EAP-SIM-Handover-Session-ID             149     octets
-ATTRIBUTE      EAP-SIM-MN-Serial-ID                    150     octets
index 1ac9196dee702dea02d4b8e3f0395e582104d935..e7e2700cdc2735064ac61e7e50614264981c6dc8 100644 (file)
@@ -243,14 +243,6 @@ ATTRIBUTE  LDAP-Sync-Entry-DN                      7       string
 ATTRIBUTE      LDAP-Sync-Entry-UUID                    8       octets
 END-TLV                LDAP-Sync-TLV
 
-#
-#      Range:  1200-1210
-#
-#      SIM attributes.  These do not belong to either EAP-AKA or EAP-SIM
-#      they represent attributes of a SIM card.
-#
-
-
 #
 #  Server-side "listen type = foo"
 #
index e732797e87460e4e78e0a1ae158f6246cc027464..446b71f93d0df16993f276aeaa651b8d0e7c57ea 100644 (file)
@@ -27,10 +27,12 @@ ATTRIBUTE   SIM-IMSI                                5205    string
 # The algorithm the SIM card uses (Milenage for UMTS, COMP128 for others)
 
 ATTRIBUTE      SIM-Algo-Version                        5206    integer
-VALUE  SIM-Algo-Version                Comp128v1               0
-VALUE  SIM-Algo-Version                Comp128v2               1
-VALUE  SIM-Algo-Version                Comp128v3               2
-VALUE  SIM-Algo-Version                Milenage                3
+VALUE  SIM-Algo-Version                Comp128-1               1
+VALUE  SIM-Algo-Version                Comp128-2               2
+VALUE  SIM-Algo-Version                Comp128-3               3
+VALUE  SIM-Algo-Version                Comp128-4               4               # GSM Milenage TS.55.205
+VALUE  SIM-Algo-Version                Milenage                5               # UMTS Milenage
+VALUE  SIM-Algo-Version                TS-34-108-UMTS          7               # UMTS Test algorithm
 
 ATTRIBUTE      SIM-Method-Hint                         5207    integer
 
diff --git a/src/lib/eap_aka_sim/all.mk b/src/lib/eap_aka_sim/all.mk
new file mode 100644 (file)
index 0000000..94b1de4
--- /dev/null
@@ -0,0 +1,15 @@
+TARGET := libfreeradius-eap-aka-sim.a
+
+
+SOURCES        := \
+       base.c \
+       state_machine.c \
+       crypto.c \
+       decode.c \
+       encode.c \
+       fips186prf.c \
+       id.c \
+       vector.c \
+       xlat.c
+
+TGT_PREREQS    := $(LIBFREERADIUS_SERVER) libfreeradius-eap.a libfreeradius-util.a libfreeradius-sim.a
diff --git a/src/lib/eap_aka_sim/attrs.h b/src/lib/eap_aka_sim/attrs.h
new file mode 100644 (file)
index 0000000..5e9c4d3
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file src/lib/aka-sim/attrs.h
+ * @brief Attributes to EAP-SIM/AKA/AKA' clients and servers.
+ *
+ * @copyright 2003-2016 The FreeRADIUS server project
+ */
+#include <freeradius-devel/server/rad_assert.h>
+#include <freeradius-devel/util/dict.h>
+#include <freeradius-devel/protocol/eap/aka-sim/dictionary.h>
+#include <freeradius-devel/protocol/eap/aka-sim/rfc4187.h>
+#include <freeradius-devel/protocol/eap/aka-sim/dictionary.h>
+#include <freeradius-devel/protocol/eap/aka-sim/rfc4187.h>
+#include <freeradius-devel/protocol/eap/aka-sim/freeradius.h>
+
+extern fr_dict_t *dict_freeradius;
+extern fr_dict_t *dict_radius;
+extern fr_dict_t *dict_eap_aka_sim;
+
+extern fr_dict_attr_t const *attr_eap_aka_sim_ak;
+extern fr_dict_attr_t const *attr_eap_aka_sim_any_id_req;
+extern fr_dict_attr_t const *attr_eap_aka_sim_autn;
+extern fr_dict_attr_t const *attr_eap_aka_sim_auts;
+extern fr_dict_attr_t const *attr_eap_aka_sim_bidding;
+extern fr_dict_attr_t const *attr_eap_aka_sim_checkcode;
+extern fr_dict_attr_t const *attr_eap_aka_sim_ck;
+extern fr_dict_attr_t const *attr_eap_aka_sim_client_error_code;
+extern fr_dict_attr_t const *attr_eap_aka_sim_counter_too_small;
+extern fr_dict_attr_t const *attr_eap_aka_sim_counter;
+extern fr_dict_attr_t const *attr_eap_aka_sim_encr_data;
+extern fr_dict_attr_t const *attr_eap_aka_sim_fullauth_id_req;
+extern fr_dict_attr_t const *attr_eap_aka_sim_identity_type;
+extern fr_dict_attr_t const *attr_eap_aka_sim_identity;
+extern fr_dict_attr_t const *attr_eap_aka_sim_ik;
+extern fr_dict_attr_t const *attr_eap_aka_sim_iv;
+extern fr_dict_attr_t const *attr_eap_aka_sim_k_re;
+extern fr_dict_attr_t const *attr_eap_aka_sim_kc;
+extern fr_dict_attr_t const *attr_eap_aka_sim_kdf_identity;
+extern fr_dict_attr_t const *attr_eap_aka_sim_kdf_input;
+extern fr_dict_attr_t const *attr_eap_aka_sim_kdf;
+extern fr_dict_attr_t const *attr_eap_aka_sim_mac;
+extern fr_dict_attr_t const *attr_eap_aka_sim_method_hint;
+extern fr_dict_attr_t const *attr_eap_aka_sim_mk;
+extern fr_dict_attr_t const *attr_eap_aka_sim_next_pseudonym;
+extern fr_dict_attr_t const *attr_eap_aka_sim_next_reauth_id;
+extern fr_dict_attr_t const *attr_eap_aka_sim_nonce_mt;
+extern fr_dict_attr_t const *attr_eap_aka_sim_nonce_s;
+extern fr_dict_attr_t const *attr_eap_aka_sim_notification;
+extern fr_dict_attr_t const *attr_eap_aka_sim_padding;
+extern fr_dict_attr_t const *attr_eap_aka_sim_permanent_id_req;
+extern fr_dict_attr_t const *attr_eap_aka_sim_permanent_identity;
+extern fr_dict_attr_t const *attr_eap_aka_sim_rand;
+extern fr_dict_attr_t const *attr_eap_aka_sim_res;
+extern fr_dict_attr_t const *attr_eap_aka_sim_result_ind;
+extern fr_dict_attr_t const *attr_eap_aka_sim_sres;
+extern fr_dict_attr_t const *attr_eap_aka_sim_subtype;
+extern fr_dict_attr_t const *attr_eap_aka_sim_selected_version;
+extern fr_dict_attr_t const *attr_eap_aka_sim_version_list;
+extern fr_dict_attr_t const *attr_eap_aka_sim_xres;
+
+
+extern fr_dict_attr_t const *attr_ms_mppe_recv_key;
+extern fr_dict_attr_t const *attr_ms_mppe_send_key;
+
+extern fr_dict_attr_t const *attr_eap_identity;
+extern fr_dict_attr_t const *attr_eap_type;
+extern fr_dict_attr_t const *attr_session_data;
+extern fr_dict_attr_t const *attr_session_id;
+extern fr_dict_attr_t const *attr_sim_algo_version;
+extern fr_dict_attr_t const *attr_sim_amf;
+extern fr_dict_attr_t const *attr_sim_ki;
+extern fr_dict_attr_t const *attr_sim_op;
+extern fr_dict_attr_t const *attr_sim_opc;
+extern fr_dict_attr_t const *attr_sim_sqn;
diff --git a/src/lib/eap_aka_sim/base.c b/src/lib/eap_aka_sim/base.c
new file mode 100644 (file)
index 0000000..04b7997
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file src/lib/aka-sim/base.c
+ * @brief Code common to EAP-SIM/AKA/AKA' clients and servers.
+ *
+ * The development of the EAP-SIM support was funded by Internet Foundation
+ * Austria (http://www.nic.at/ipa).
+ *
+ * @copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ * @copyright 2003-2016 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/util/base.h>
+#include <freeradius-devel/util/sha1.h>
+
+#include <freeradius-devel/server/rad_assert.h>
+#include <freeradius-devel/server/module.h>
+
+#include <freeradius-devel/tls/base.h>
+
+#include <freeradius-devel/eap/types.h>
+
+#include <freeradius-devel/eap_aka_sim/base.h>
+#include <freeradius-devel/eap_aka_sim/attrs.h>
+
+static int instance_count = 0;
+
+fr_dict_t *dict_freeradius;
+fr_dict_t *dict_radius;
+fr_dict_t *dict_eap_aka_sim;
+
+extern fr_dict_autoload_t libfreeradius_aka_sim_dict[];
+fr_dict_autoload_t libfreeradius_aka_sim_dict[] = {
+       { .out = &dict_freeradius, .proto = "freeradius" },
+       { .out = &dict_radius, .proto = "radius" },
+       { .out = &dict_eap_aka_sim, .base_dir = "eap/aka-sim", .proto = "eap-aka-sim" },
+
+       { NULL }
+};
+
+fr_dict_attr_t const *attr_eap_aka_sim_ak;
+fr_dict_attr_t const *attr_eap_aka_sim_any_id_req;
+fr_dict_attr_t const *attr_eap_aka_sim_autn;
+fr_dict_attr_t const *attr_eap_aka_sim_auts;
+fr_dict_attr_t const *attr_eap_aka_sim_bidding;
+fr_dict_attr_t const *attr_eap_aka_sim_checkcode;
+fr_dict_attr_t const *attr_eap_aka_sim_ck;
+fr_dict_attr_t const *attr_eap_aka_sim_client_error_code;
+fr_dict_attr_t const *attr_eap_aka_sim_counter_too_small;
+fr_dict_attr_t const *attr_eap_aka_sim_counter;
+fr_dict_attr_t const *attr_eap_aka_sim_encr_data;
+fr_dict_attr_t const *attr_eap_aka_sim_fullauth_id_req;
+fr_dict_attr_t const *attr_eap_aka_sim_identity_type;
+fr_dict_attr_t const *attr_eap_aka_sim_identity;
+fr_dict_attr_t const *attr_eap_aka_sim_ik;
+fr_dict_attr_t const *attr_eap_aka_sim_iv;
+fr_dict_attr_t const *attr_eap_aka_sim_k_re;
+fr_dict_attr_t const *attr_eap_aka_sim_kc;
+fr_dict_attr_t const *attr_eap_aka_sim_kdf_identity;
+fr_dict_attr_t const *attr_eap_aka_sim_kdf_input;
+fr_dict_attr_t const *attr_eap_aka_sim_kdf;
+fr_dict_attr_t const *attr_eap_aka_sim_mac;
+fr_dict_attr_t const *attr_eap_aka_sim_method_hint;
+fr_dict_attr_t const *attr_eap_aka_sim_mk;
+fr_dict_attr_t const *attr_eap_aka_sim_next_pseudonym;
+fr_dict_attr_t const *attr_eap_aka_sim_next_reauth_id;
+fr_dict_attr_t const *attr_eap_aka_sim_nonce_mt;
+fr_dict_attr_t const *attr_eap_aka_sim_nonce_s;
+fr_dict_attr_t const *attr_eap_aka_sim_notification;
+fr_dict_attr_t const *attr_eap_aka_sim_padding;
+fr_dict_attr_t const *attr_eap_aka_sim_permanent_id_req;
+fr_dict_attr_t const *attr_eap_aka_sim_permanent_identity;
+fr_dict_attr_t const *attr_eap_aka_sim_rand;
+fr_dict_attr_t const *attr_eap_aka_sim_res;
+fr_dict_attr_t const *attr_eap_aka_sim_result_ind;
+fr_dict_attr_t const *attr_eap_aka_sim_sres;
+fr_dict_attr_t const *attr_eap_aka_sim_selected_version;
+fr_dict_attr_t const *attr_eap_aka_sim_subtype;
+fr_dict_attr_t const *attr_eap_aka_sim_version_list;
+fr_dict_attr_t const *attr_eap_aka_sim_xres;
+
+fr_dict_attr_t const *attr_ms_mppe_recv_key;
+fr_dict_attr_t const *attr_ms_mppe_send_key;
+
+fr_dict_attr_t const *attr_eap_identity;
+fr_dict_attr_t const *attr_eap_type;
+fr_dict_attr_t const *attr_session_data;
+fr_dict_attr_t const *attr_session_id;
+fr_dict_attr_t const *attr_sim_algo_version;
+fr_dict_attr_t const *attr_sim_amf;
+fr_dict_attr_t const *attr_sim_ki;
+fr_dict_attr_t const *attr_sim_op;
+fr_dict_attr_t const *attr_sim_opc;
+fr_dict_attr_t const *attr_sim_sqn;
+
+extern fr_dict_attr_autoload_t libfreeradius_aka_sim_dict_attr[];
+fr_dict_attr_autoload_t libfreeradius_aka_sim_dict_attr[] = {
+       { .out = &attr_eap_aka_sim_ak, .name = "AK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_any_id_req, .name = "Any-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_autn, .name = "AUTN", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_auts, .name = "AUTS", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_bidding, .name = "Bidding", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_checkcode, .name = "Checkcode", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_ck, .name = "CK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_client_error_code, .name = "Client-Error-Code", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_counter_too_small, .name = "Counter-Too-Small", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_counter, .name = "Counter", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_encr_data, .name = "Encr-Data", .type = FR_TYPE_TLV, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_fullauth_id_req, .name = "Fullauth-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_identity_type, .name = "Identity-Type", .type = FR_TYPE_UINT32, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_identity, .name = "Identity", .type = FR_TYPE_STRING, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_ik, .name = "IK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_iv, .name = "IV", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_k_re, .name = "K-Re", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_kc, .name = "KC", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_kdf_identity, .name = "KDF-Identity", .type = FR_TYPE_STRING, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_kdf_input, .name = "KDF-Input", .type = FR_TYPE_STRING, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_kdf, .name = "KDF", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_mac, .name = "MAC", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_method_hint, .name = "Method-Hint", .type = FR_TYPE_UINT32, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_mk, .name = "MK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_next_pseudonym, .name = "Next-Pseudonym", .type = FR_TYPE_STRING, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_next_reauth_id, .name = "Next-Reauth-ID", .type = FR_TYPE_STRING, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_nonce_mt, .name = "Nonce-MT", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_nonce_s, .name = "Nonce-S", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_notification, .name = "Notification", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_padding, .name = "Padding", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_permanent_id_req, .name = "Permanent-Id-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_permanent_identity, .name = "Permanent-Identity", .type = FR_TYPE_STRING, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_rand, .name = "RAND", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_res, .name = "RES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_result_ind, .name = "Result-Ind", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_sres, .name = "RES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_selected_version, .name = "Selected-Version", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_subtype, .name = "Subtype", .type = FR_TYPE_UINT32, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_version_list, .name = "Version-List", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_xres, .name = "XRES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+
+       { .out = &attr_ms_mppe_send_key, .name = "MS-MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
+       { .out = &attr_ms_mppe_recv_key, .name = "MS-MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
+
+       /*
+        *      Separate from the EAP-AKA-AND-SIM dictionary
+        *      as they're outside the notional numberspace.
+        */
+       { .out = &attr_eap_identity, .name = "EAP-Identity", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
+       { .out = &attr_eap_type, .name = "EAP-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
+
+       { .out = &attr_session_data, .name = "Session-Data", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
+       { .out = &attr_session_id, .name = "Session-Id", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
+       { .out = &attr_sim_algo_version, .name = "SIM-Algo-Version", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
+       { .out = &attr_sim_amf, .name = "SIM-AMF", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
+       { .out = &attr_sim_ki, .name = "SIM-Ki", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
+       { .out = &attr_sim_op, .name = "SIM-OP", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
+       { .out = &attr_sim_opc, .name = "SIM-OPc", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
+       { .out = &attr_sim_sqn, .name = "SIM-SQN", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
+       { NULL }
+};
+
+/** SIM AT on-the-wire format attribute sizes
+ *
+ * Holds the min/max sizes of all supported SIM AT attribute values as they
+ * would be found in a SIM AT packet.
+ *
+ * These sizes may be different than the sizes of INTERNAL formats, PRESENTATION
+ * formats and generic NETWORK formats.
+ */
+size_t const fr_aka_sim_attr_sizes[FR_TYPE_MAX + 1][2] = {
+       [FR_TYPE_INVALID]               = {~0, 0},
+
+       [FR_TYPE_STRING]                = {0, ~0},
+       [FR_TYPE_OCTETS]                = {0, ~0},
+
+       [FR_TYPE_BOOL]                  = {2, 2},
+       [FR_TYPE_UINT8]                 = {1, 1},
+       [FR_TYPE_UINT16]                = {2, 2},
+       [FR_TYPE_UINT32]                = {4, 4},
+       [FR_TYPE_UINT64]                = {8, 8},
+
+       [FR_TYPE_TLV]                   = {2, ~0},
+
+       [FR_TYPE_MAX]                   = {~0, 0}       //!< Ensure array covers all types.
+};
+
+/** Return the on-the-wire length of an attribute value
+ *
+ * @param[in] vp to return the length of.
+ * @return the length of the attribute.
+ */
+size_t fr_aka_sim_attr_len(VALUE_PAIR const *vp)
+{
+       switch (vp->vp_type) {
+       case FR_TYPE_VARIABLE_SIZE:
+               return vp->vp_length;
+
+       default:
+               return fr_aka_sim_attr_sizes[vp->vp_type][0];
+
+       case FR_TYPE_STRUCTURAL:
+               if (!fr_cond_assert(0)) return 0;
+       }
+}
+
+/** Return the number of bytes before the octets value
+ *
+ */
+size_t fr_aka_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 */
+}
+
+int fr_aka_sim_init(void)
+{
+       if (instance_count > 0) {
+               instance_count++;
+               return 0;
+       }
+
+       if (fr_dict_autoload(libfreeradius_aka_sim_dict) < 0) {
+               PERROR("Failed loading libfreeradius-eap-aka-sim dictionaries");
+               return -1;
+       }
+       if (fr_dict_attr_autoload(libfreeradius_aka_sim_dict_attr) < 0) {
+               PERROR("Failed loading libfreeradius-eap-aka-sim attributes");
+               fr_dict_autofree(libfreeradius_aka_sim_dict);
+               return -1;
+       }
+       instance_count++;
+
+       return 0;
+}
+
+void fr_aka_sim_free(void)
+{
+       if (--instance_count > 0) return;
+
+       fr_dict_autofree(libfreeradius_aka_sim_dict);
+}
+
diff --git a/src/lib/eap_aka_sim/base.h b/src/lib/eap_aka_sim/base.h
new file mode 100644 (file)
index 0000000..61dc6e7
--- /dev/null
@@ -0,0 +1,340 @@
+#pragma once
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file src/lib/aka-sim/base.h
+ * @brief Functions common to SIM protocols (EAP-SIM/EAP-AKA/EAP-AKA')
+ *
+ * The development of the EAP/SIM support was funded by Internet Foundation
+ * Austria (http://www.nic.at/ipa).
+ *
+ * @copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ * @copyright 2003-2016 The FreeRADIUS server project
+ */
+RCSIDH(sim_h, "$Id$")
+
+#include <assert.h>
+#include <openssl/evp.h>
+#include <freeradius-devel/eap/compose.h>
+#include <freeradius-devel/eap/types.h>
+
+#include "id.h"
+
+#define AKA_SIM_MAX_STRING_LENGTH              1016            //!< Maximum size of a SIM/AKA['] string ((4 * 255) - 4).
+#define AKA_SIM_IV_SIZE                                16              //!< Length of the IV used when processing AT_ENCR.
+#define AKA_SIM_MAC_DIGEST_SIZE                        16              //!< Length of MAC used to prevent packet modification.
+#define AKA_SIM_MAC_SIZE                       20              //!< Length of MAC used to prevent packet modification.
+#define AKA_SIM_AUTH_SIZE                      16
+#define AKA_SIM_SQN_AK_SIZE                    6
+#define AKA_SIM_NONCE_S_SIZE                   16              //!< Length of re-authentication nonce
+
+#define AKA_SIM_KI_SIZE                                16              //!< Length of secret data shared between SIM and AuC.
+#define AKA_SIM_OP_SIZE                                16              //!< Length of Operator Algorithm Configuration.
+#define AKA_SIM_OPC_SIZE                       16              //!< Length of modified Operator Algorithm Configuration.
+
+#define AKA_SIM_MK_SIZE                                20              //!< Master key size
+#define AKA_SIM_K_RE_SIZE                      32              //!< Reauthentication key size.
+
+#define AKA_SIM_SKIPPABLE_MAX                  127             //!< The last non-skippable attribute.
+
+#define AKA_SIM_VECTOR_GSM_RAND_SIZE           16              //!< Length of RAND in GSM triplet.
+#define AKA_SIM_VECTOR_GSM_SRES_SIZE           4               //!< Length of SRES in GSM triplet.
+#define AKA_SIM_VECTOR_GSM_KC_SIZE             8               //!< Length of Kc in GSM triplet.
+
+#define AKA_SIM_VECTOR_UMTS_AUTN_SIZE          16
+#define AKA_SIM_VECTOR_UMTS_CK_SIZE            16
+#define AKA_SIM_VECTOR_UMTS_IK_SIZE            16
+#define AKA_SIM_VECTOR_UMTS_AK_SIZE            6
+#define AKA_SIM_VECTOR_UMTS_RAND_SIZE          16
+#define AKA_SIM_VECTOR_UMTS_XRES_MAX_SIZE      16
+
+#define EAP_SIM_VERSION                                1
+#define EAP_SIM_NONCE_MT_SIZE                  16              //!< Length of challenge from SIM client.
+
+#define EAP_AKA_SIM_AUTH_SIZE                  16
+
+
+#define EAP_AKA_AUTS_SIZE                      14              //!< Server sequence number.  SIM checks this
+                                                               //!< is within the correct range.
+#define EAP_AKA_AUTH_SIZE                      16
+#define EAP_AKA_PRIME_AUTH_SIZE                        32
+
+/** The type of auth vector held by a fr_aka_sim_keys_t
+ */
+typedef enum {
+       AKA_SIM_VECTOR_NONE = 0,
+       AKA_SIM_VECTOR_GSM,                                     //!< Vector is GSM triplets.
+       AKA_SIM_VECTOR_UMTS,                                    //!< Vector is UMTS quintuplets.
+       AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH,
+       AKA_SIM_VECTOR_UMTS_REAUTH_KDF_1_REAUTH
+} fr_aka_sim_vector_type_t;
+
+/** Where to get EAP-SIM vectors from
+ */
+typedef enum {
+       AKA_SIM_VECTOR_SRC_AUTO,                                //!< Discover where to get Triplets from automatically.
+       AKA_SIM_VECTOR_SRC_TRIPLETS,                            //!< Source of triplets is EAP-SIM-* attributes.
+       AKA_SIM_VECTOR_SRC_QUINTUPLETS,                         //!< Source of triplets is derived from EAP-AKA-*
+                                                               ///< quintuplets.
+       AKA_SIM_VECTOR_SRC_KI,                                  //!< Should generate triplets locally using a Ki.
+       AKA_SIM_VECTOR_SRC_REAUTH,                              //!< Not a vector.  Result of running KDF 0 reauth
+                                                               ///< function.
+} fr_aka_sim_vector_src_t;
+
+typedef struct {
+       uint8_t         rand[AKA_SIM_VECTOR_GSM_RAND_SIZE];             //!< RAND challenge to the SIM.
+       union {
+               uint8_t         sres[AKA_SIM_VECTOR_GSM_SRES_SIZE];     //!< Signing response.
+               uint32_t        sres_uint32;
+       };
+
+       union {
+               uint8_t         kc[AKA_SIM_VECTOR_GSM_KC_SIZE];         //!< Keying response.
+               uint64_t        kc_uint64;
+       };
+} fr_aka_sim_vector_gsm_t;
+
+typedef struct {
+       uint8_t         autn[AKA_SIM_VECTOR_UMTS_AUTN_SIZE];    //!< Authentication vector from the AuC.
+       uint8_t         ck[AKA_SIM_VECTOR_UMTS_CK_SIZE];        //!< Ciphering key.
+       uint8_t         ik[AKA_SIM_VECTOR_UMTS_IK_SIZE];        //!< Integrity key.
+       uint8_t         ak[AKA_SIM_VECTOR_UMTS_AK_SIZE];        //!< Anonymity key.
+       uint8_t         rand[AKA_SIM_VECTOR_UMTS_RAND_SIZE];    //!< RAND challenge to the SIM.
+       uint8_t         xres[AKA_SIM_VECTOR_UMTS_XRES_MAX_SIZE];//!< Signing response.
+       size_t          xres_len;                               //!< Length of res (it's variable).
+} fr_aka_sim_vector_umts_t;
+
+/** Stores our checkcode state
+ *
+ * The checkcode is a hash of all identity packets exchanged
+ * up until the challenge is sent.
+ *
+ * It allows both parties to verify that they've seen the same
+ * sequence of packets.
+ */
+typedef struct {
+       EVP_MD_CTX      *md_ctx;                                //!< Context to hold state of digest as we
+                                                               ///< consume packets.
+} fr_aka_sim_checkcode_t;
+
+/** Master key state struct for all SIMlike EAP protocols
+ *
+ */
+typedef struct {
+       /*
+        *      Inputs
+        */
+       uint8_t         *identity;                              //!< Identity from AT_IDENTITY.
+       size_t          identity_len;                           //!< Length of the identity.
+
+       uint8_t         *network;                               //!< Network name (EAP-AKA-Prime only).
+       size_t          network_len;                            //!< Length of the network name (EAP-AKA-Prime only).
+
+       uint64_t        sqn;                                    //!< Sequence number
+
+       struct {
+               /*
+                *      Authentication vectors from HLR or local AuC
+                */
+               union {
+                       /** Input to kdf_0_gsm
+                        */
+                       struct {
+                               fr_aka_sim_vector_gsm_t vector[3];      //!< GSM vectors.
+                               uint32_t                num_vectors;    //!< Number of input vectors
+                                                                       //!< we're using (2 or 3).
+
+                               uint8_t nonce_mt[EAP_SIM_NONCE_MT_SIZE];//!< Nonce provided by the client.
+                               uint8_t version_list[FR_MAX_STRING_LEN];//!< Version list from negotiation.
+                               uint8_t version_list_len;               //!< Length of version list.
+                               uint8_t version_select[2];              //!< Version we agreed.
+                       } gsm;
+
+                       /** Input to kdf_*_umts
+                        */
+                       struct {
+                               fr_aka_sim_vector_umts_t        vector;         //!< UMTS vector.
+                               uint16_t                        kdf_selected;
+                       } umts;
+
+                       /** Input/output from kdf_*_reauth_*
+                        */
+                       struct {
+                               uint16_t        counter;                        //!< Re-authentication counter.
+                               uint8_t         nonce_s[AKA_SIM_NONCE_S_SIZE];  //!< Re-authentication challenge.
+                               uint8_t         xkey_prime[20];                 //!< Derived reauthentication key
+                                                                               //!< for AKA (kdf 0).
+                       } reauth;
+               };
+
+               /*
+                *      Original ki and OPc to allow AUTS validation
+                */
+               struct {
+                       uint8_t ki[AKA_SIM_KI_SIZE];            //!< Secret shared between AuC and SIM.
+                       uint8_t opc[AKA_SIM_OPC_SIZE];          //!< Operator algorithm input.
+               } auc;
+
+               fr_aka_sim_vector_type_t        vector_type;    //!< What type of authentication vector
+                                                               //!< we're using to authenticate the SIM.
+               fr_aka_sim_vector_src_t         vector_src;     //!< Where the vector came from.
+       };
+
+       /*
+        *      Inputs/outputs
+        */
+       uint8_t         mk[AKA_SIM_MK_SIZE];                    //!< Master key from session attributes.
+       size_t          mk_len;
+       uint8_t         k_re[AKA_SIM_K_RE_SIZE];                //!< Derived reauthentication key for AKA'(kdf 1).
+
+       /*
+        *      Intermediates
+        */
+       uint8_t         ck_prime[AKA_SIM_VECTOR_UMTS_CK_SIZE];  //!< Derived from CK, for AKA'.
+       uint8_t         ik_prime[AKA_SIM_VECTOR_UMTS_IK_SIZE];  //!< Derived from IK, for AKA'.
+
+       /*
+        *      Outputs
+        */
+       uint8_t         k_aut[32];                              //!< Derived authentication key.
+       size_t          k_aut_len;                              //!< Length of k_aut.  16 for AKA/SIM, 32 for AKA'.
+       uint8_t         k_encr[16];                             //!< Derived encryption key.
+       uint8_t         msk[64];                                //!< Derived master session key.
+       uint8_t         emsk[64];                               //!< Derived extended master session key.
+} fr_aka_sim_keys_t;
+
+typedef struct {
+       fr_aka_sim_keys_t const         *keys;                  //!< From the EAP session.
+       uint8_t                         iv[AKA_SIM_IV_SIZE];    //!< From the current packet.
+       bool                            have_iv;                //!< Whether we found the IV already.
+} fr_aka_sim_decode_ctx_t;
+
+typedef struct {
+       fr_dict_attr_t const            *root;                  //!< Root attribute of the dictionary.
+       fr_aka_sim_keys_t const *keys;                          //!< From the EAP session.
+       uint8_t                         iv[AKA_SIM_IV_SIZE];    //!< Generated by us using our PRNG.
+       bool                            iv_included;            //!< Whether we've already added an IV to this packet.
+
+       /*
+        *      Additional HMAC inputs
+        */
+       EVP_MD const                    *hmac_md;               //!< HMAC digest algorithm, usually EVP_sha1().
+       eap_packet_t                    *eap_packet;            //!< Needed for HMAC generation so we can construct
+                                                               ///< the EAP packet header.
+       uint8_t const                   *hmac_extra;            //!< Extra data for the HMAC function.
+       size_t                          hmac_extra_len;         //!< The length of the HMAC data.
+} fr_aka_sim_encode_ctx_t;
+
+extern size_t const fr_aka_sim_attr_sizes[FR_TYPE_MAX + 1][2];
+
+/*
+ *     decode.c
+ */
+ssize_t                fr_aka_sim_decode_pair(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+                                          uint8_t const *data, size_t data_len, void *decoder_ctx);
+
+int            fr_aka_sim_decode(REQUEST *request, fr_cursor_t *decoded, fr_dict_t const *dict,
+                                     uint8_t const *data, size_t data_len, fr_aka_sim_decode_ctx_t *ctx);
+
+/*
+ *     encode.c
+ */
+ssize_t                fr_aka_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, void *encoder_ctx);
+
+ssize_t                fr_aka_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx);
+
+/*
+ *     base.c
+ */
+size_t         fr_aka_sim_attr_len(VALUE_PAIR const *vp);
+
+size_t         fr_aka_sim_octets_prefix_len(fr_dict_attr_t const *da);
+
+int            fr_aka_sim_init(void);
+
+void           fr_aka_sim_free(void);
+
+/*
+ *     crypto.c
+ */
+int            fr_aka_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_aka_sim_checkcode_t **checkcode,
+                                                    EVP_MD const *md);
+
+int            fr_aka_sim_crypto_update_checkcode(fr_aka_sim_checkcode_t *checkcode, eap_packet_t *eap_packet);
+
+ssize_t                fr_aka_sim_crypto_finalise_checkcode(uint8_t *out, fr_aka_sim_checkcode_t **checkcode);
+
+ssize_t                fr_aka_sim_crypto_sign_packet(uint8_t out[static AKA_SIM_MAC_DIGEST_SIZE],
+                                                 eap_packet_t *eap_packet, bool zero_mac,
+                                                 EVP_MD const *md, uint8_t const *key, size_t const key_len,
+                                                 uint8_t const *hmac_extra, size_t const hmac_extra_len);
+
+int            fr_aka_sim_crypto_gsm_kdf_0(fr_aka_sim_keys_t *keys);
+
+int            fr_aka_sim_crypto_umts_kdf_0(fr_aka_sim_keys_t *keys);
+
+int            fr_aka_sim_crypto_umts_kdf_1(fr_aka_sim_keys_t *keys);
+
+void           fr_aka_sim_crypto_keys_init_kdf_0_reauth(fr_aka_sim_keys_t *keys,
+                                                        uint8_t const mk[static AKA_SIM_MK_SIZE],
+                                                        uint16_t counter);
+
+void           fr_aka_sim_crypto_keys_init_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys,
+                                                             uint8_t const k_re[static AKA_SIM_K_RE_SIZE],
+                                                             uint16_t counter);
+
+int            fr_aka_sim_crypto_kdf_0_reauth(fr_aka_sim_keys_t *keys);
+
+int            fr_aka_sim_crypto_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys);
+
+void           fr_aka_sim_crypto_keys_log(REQUEST *request, fr_aka_sim_keys_t *keys);
+
+/*
+ *     vector.c
+ */
+int            fr_aka_sim_vector_gsm_from_attrs(REQUEST *request, VALUE_PAIR *vps,
+                                                int idx,
+                                                fr_aka_sim_keys_t *keys,
+                                                fr_aka_sim_vector_src_t *src);
+
+int            fr_aka_sim_vector_umts_from_attrs(REQUEST *request, VALUE_PAIR *vps,
+                                                 fr_aka_sim_keys_t *keys,
+                                                 fr_aka_sim_vector_src_t *src);
+
+int            fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps,
+                                                                  fr_aka_sim_keys_t *keys);
+
+int            fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps,
+                                                              fr_aka_sim_keys_t *keys);
+
+void           fr_aka_sim_vector_umts_reauth_clear(fr_aka_sim_keys_t *keys);
+
+int            fr_aka_sim_umts_resync_from_attrs(uint64_t *new_sqn,
+                                                 REQUEST *request, VALUE_PAIR *auts_vp,
+                                                 fr_aka_sim_keys_t *keys);
+
+/*
+ *     fips186prf.c
+ */
+void           fr_aka_sim_fips186_2prf(uint8_t out[static 160], uint8_t mk[static 20]);
+
+/*
+ *     xlat.c
+ */
+void           fr_aka_sim_xlat_register(void);
+void           fr_aka_sim_xlat_unregister(void);
similarity index 82%
rename from src/lib/sim/crypto.c
rename to src/lib/eap_aka_sim/crypto.c
index 638310ef01cc2020887e2cf721688c431ce1eb45..951466ad1a49b4e48c314848233cf441d384aa0d 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 /**
- * @file src/lib/sim/crypto.c
+ * @file src/lib/aka-sim/crypto.c
  * @brief Calculate keys from GSM vectors.
  *
  * The development of the original EAP/SIM support was funded by Internet Foundation
@@ -33,24 +33,25 @@ RCSID("$Id$")
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <freeradius-devel/protocol/eap/sim/dictionary.h>
+#include <freeradius-devel/protocol/eap/aka-sim/dictionary.h>
 
 #include <freeradius-devel/eap/types.h>
-#include "base.h"
-#include "attrs.h"
-#include "milenage.h"
-
+#include <freeradius-devel/sim/common.h>
+#include <freeradius-devel/sim/milenage.h>
 #include <freeradius-devel/util/sha1.h>
 #include <freeradius-devel/tls/base.h>
 #include <openssl/evp.h>
 
+#include "base.h"
+#include "attrs.h"
+
 
 /** Free OpenSSL memory associated with our checkcode ctx
  *
  * @param[in] checkcode to free.
  * @return 0
  */
-static int _fr_sim_crypto_free_checkcode(fr_sim_checkcode_t *checkcode)
+static int _fr_aka_sim_crypto_free_checkcode(fr_aka_sim_checkcode_t *checkcode)
 {
        if (checkcode->md_ctx) EVP_MD_CTX_destroy(checkcode->md_ctx);
        return 0;
@@ -66,9 +67,9 @@ static int _fr_sim_crypto_free_checkcode(fr_sim_checkcode_t *checkcode)
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_sim_checkcode_t **checkcode, EVP_MD const *md)
+int fr_aka_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_aka_sim_checkcode_t **checkcode, EVP_MD const *md)
 {
-       *checkcode = talloc_zero(ctx, fr_sim_checkcode_t);
+       *checkcode = talloc_zero(ctx, fr_aka_sim_checkcode_t);
        if (!*checkcode) {
                fr_strerror_printf("Out of memory");
                return -1;
@@ -86,14 +87,14 @@ int fr_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_sim_checkcode_t **checkcode
                goto error;
        }
 
-       talloc_set_destructor(*checkcode, _fr_sim_crypto_free_checkcode);
+       talloc_set_destructor(*checkcode, _fr_aka_sim_crypto_free_checkcode);
 
        return 0;
 }
 
 /** Digest a packet, updating the checkcode
  *
- * Call #fr_sim_crypto_finalise_checkcode to obtain the final checkcode value.
+ * Call #fr_aka_sim_crypto_finalise_checkcode to obtain the final checkcode value.
  *
  * @param[in,out] checkcode    if *checkcode is NULL, a new checkcode structure
  *                             will be allocated and the message digest context
@@ -104,7 +105,7 @@ int fr_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_sim_checkcode_t **checkcode
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_crypto_update_checkcode(fr_sim_checkcode_t *checkcode, eap_packet_t *eap_packet)
+int fr_aka_sim_crypto_update_checkcode(fr_aka_sim_checkcode_t *checkcode, eap_packet_t *eap_packet)
 {
        uint16_t                packet_len;
        eap_packet_raw_t        eap_hdr;
@@ -143,7 +144,7 @@ int fr_sim_crypto_update_checkcode(fr_sim_checkcode_t *checkcode, eap_packet_t *
  *     - <= 0 on failure.
  *     - > 0 the number of bytes written to out.
  */
-ssize_t fr_sim_crypto_finalise_checkcode(uint8_t *out, fr_sim_checkcode_t **checkcode)
+ssize_t fr_aka_sim_crypto_finalise_checkcode(uint8_t *out, fr_aka_sim_checkcode_t **checkcode)
 {
        unsigned int len;
 
@@ -168,7 +169,7 @@ ssize_t fr_sim_crypto_finalise_checkcode(uint8_t *out, fr_sim_checkcode_t **chec
  *     - 0 if we found and zeroed out the mac field.
  *     - -1 if the field was malformed.
  */
-static int fr_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
+static int fr_aka_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
 {
        uint8_t *p = data, *end = p + data_len;
        size_t len;
@@ -177,16 +178,16 @@ static int fr_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
 
        p += 3; /* Skip header */
        while ((p + 2) < end) {
-               if (p[0] == FR_SIM_MAC) {
+               if (p[0] == FR_MAC) {
                        len = p[1] << 2;
                        if ((p + len) > end) {
                                fr_strerror_printf("Malformed AT_MAC: Length (%zu) exceeds buffer (%zu)", len, end - p);
                                return -1;
                        }
 
-                       if (len != SIM_MAC_SIZE) {
+                       if (len != AKA_SIM_MAC_SIZE) {
                                fr_strerror_printf("Malformed AT_MAC: Length (%zu) incorrect (%u)",
-                                                  len, SIM_MAC_SIZE);
+                                                  len, AKA_SIM_MAC_SIZE);
                                return -1;
                        }
                        *out = p + 4;
@@ -230,10 +231,10 @@ static int fr_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
  *     - 0 if there's no MAC attribute to verify.
  *     - > 0 the number of bytes written to out.
  */
-ssize_t fr_sim_crypto_sign_packet(uint8_t out[static SIM_MAC_DIGEST_SIZE],
-                                  eap_packet_t *eap_packet, bool zero_mac,
-                                 EVP_MD const *md, uint8_t const *key, size_t const key_len,
-                                 uint8_t const *hmac_extra, size_t const hmac_extra_len)
+ssize_t fr_aka_sim_crypto_sign_packet(uint8_t out[static AKA_SIM_MAC_DIGEST_SIZE],
+                                     eap_packet_t *eap_packet, bool zero_mac,
+                                     EVP_MD const *md, uint8_t const *key, size_t const key_len,
+                                     uint8_t const *hmac_extra, size_t const hmac_extra_len)
 {
        EVP_MD_CTX              *md_ctx = NULL;
        EVP_PKEY                *pkey;
@@ -304,7 +305,7 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[static SIM_MAC_DIGEST_SIZE],
         *      digest 16 bytes of zero.
         */
        if (zero_mac) {
-               switch (fr_sim_find_mac(&mac, p, end - p)) {
+               switch (fr_aka_sim_find_mac(&mac, p, end - p)) {
                case 0:
                {
                        uint8_t zero[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -400,7 +401,7 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[static SIM_MAC_DIGEST_SIZE],
        MSK    = FK[256..767]
        EMSK   = FK[768..1279]
  @endverbatim
- * @note expects keys to contain a SIM_VECTOR_GSM.
+ * @note expects keys to contain a AKA_SIM_VECTOR_GSM.
  *
  * @param[in,out] keys         Contains the authentication vectors and the buffers
  *                             to store the result of the derivation.
@@ -408,22 +409,22 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[static SIM_MAC_DIGEST_SIZE],
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys)
+int fr_aka_sim_crypto_gsm_kdf_0(fr_aka_sim_keys_t *keys)
 {
        fr_sha1_ctx     context;
        uint8_t         fk[160];
 
-       uint8_t         buf[SIM_MAX_STRING_LENGTH + sizeof(keys->gsm.nonce_mt) + 2 + sizeof(keys->gsm.version_select)];
+       uint8_t         buf[AKA_SIM_MAX_STRING_LENGTH + sizeof(keys->gsm.nonce_mt) + 2 + sizeof(keys->gsm.version_select)];
        uint8_t         *p;
 
-       if (!fr_cond_assert(keys->vector_type == SIM_VECTOR_GSM)) return -1;
+       if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_GSM)) return -1;
 
        /*
         *      Our stack buffer should be large enough in
         *      all cases.
         */
        if (!fr_cond_assert((keys->identity_len +
-                           (SIM_VECTOR_GSM_KC_SIZE * 3) +
+                           (AKA_SIM_VECTOR_GSM_KC_SIZE * 3) +
                            sizeof(keys->gsm.nonce_mt) +
                            keys->gsm.version_list_len +
                            sizeof(keys->gsm.version_select)) <= sizeof(buf))) return -1;
@@ -432,14 +433,14 @@ int fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys)
        memcpy(p, keys->identity, keys->identity_len);
        p += keys->identity_len;
 
-       memcpy(p, keys->gsm.vector[0].kc, SIM_VECTOR_GSM_KC_SIZE);
-       p += SIM_VECTOR_GSM_KC_SIZE;
+       memcpy(p, keys->gsm.vector[0].kc, AKA_SIM_VECTOR_GSM_KC_SIZE);
+       p += AKA_SIM_VECTOR_GSM_KC_SIZE;
 
-       memcpy(p, keys->gsm.vector[1].kc, SIM_VECTOR_GSM_KC_SIZE);
-       p += SIM_VECTOR_GSM_KC_SIZE;
+       memcpy(p, keys->gsm.vector[1].kc, AKA_SIM_VECTOR_GSM_KC_SIZE);
+       p += AKA_SIM_VECTOR_GSM_KC_SIZE;
 
-       memcpy(p, keys->gsm.vector[2].kc, SIM_VECTOR_GSM_KC_SIZE);
-       p += SIM_VECTOR_GSM_KC_SIZE;
+       memcpy(p, keys->gsm.vector[2].kc, AKA_SIM_VECTOR_GSM_KC_SIZE);
+       p += AKA_SIM_VECTOR_GSM_KC_SIZE;
 
        memcpy(p, keys->gsm.nonce_mt, sizeof(keys->gsm.nonce_mt));
        p += sizeof(keys->gsm.nonce_mt);
@@ -457,15 +458,15 @@ int fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys)
         */
        fr_sha1_init(&context);
        fr_sha1_update(&context, buf, p - buf);
-       fr_sha1_final(keys->master_key, &context);
+       fr_sha1_final(keys->mk, &context);
 
-       FR_PROTO_HEX_DUMP(keys->master_key, sizeof(keys->master_key), "Master key");
+       FR_PROTO_HEX_DUMP(keys->mk, sizeof(keys->mk), "Master key");
 
        /*
         *      Now use the PRF to expand it, generated
         *      k_aut, k_encr, MSK and EMSK.
         */
-       fr_sim_fips186_2prf(fk, keys->master_key);
+       fr_aka_sim_fips186_2prf(fk, keys->mk);
 
        /*
         *      Split up the result
@@ -475,9 +476,9 @@ int fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys)
        p += 16;
        FR_PROTO_HEX_DUMP(keys->k_encr, sizeof(keys->k_encr), "K_encr");
 
-       memcpy(keys->k_aut, p, EAP_SIM_AUTH_SIZE);              /* 128 bits for auth */
-       p += EAP_SIM_AUTH_SIZE;
-       keys->k_aut_len = EAP_SIM_AUTH_SIZE;
+       memcpy(keys->k_aut, p, EAP_AKA_SIM_AUTH_SIZE);          /* 128 bits for auth */
+       p += EAP_AKA_SIM_AUTH_SIZE;
+       keys->k_aut_len = EAP_AKA_SIM_AUTH_SIZE;
        FR_PROTO_HEX_DUMP(keys->k_aut, keys->k_aut_len, "K_aut");
 
        memcpy(keys->msk, p, 64);                               /* 64 bytes for Master Session Key */
@@ -492,7 +493,7 @@ int fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys)
 
 /** Key Derivation Function as described in RFC4187 (EAP-AKA) section 7
  *
- * @note expects keys to contain a SIM_VECTOR_UMTS.
+ * @note expects keys to contain a AKA_SIM_VECTOR_UMTS.
  *
  @verbatim
        MK     = SHA1(Identity|IK|CK)
@@ -509,15 +510,15 @@ int fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys)
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys)
+int fr_aka_sim_crypto_umts_kdf_0(fr_aka_sim_keys_t *keys)
 {
        fr_sha1_ctx     context;
        uint8_t         fk[160];
-       uint8_t         buf[SIM_MAX_STRING_LENGTH + sizeof(keys->umts.vector.ik) + sizeof(keys->umts.vector.ck)];
+       uint8_t         buf[AKA_SIM_MAX_STRING_LENGTH + sizeof(keys->umts.vector.ik) + sizeof(keys->umts.vector.ck)];
        uint8_t         *p;
        size_t          blen;
 
-       if (!fr_cond_assert(keys->vector_type == SIM_VECTOR_UMTS)) return - 1;
+       if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_UMTS)) return - 1;
 
        /*
         *      Our stack buffer should be large enough in
@@ -542,13 +543,13 @@ int fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys)
        /* do the master key first */
        fr_sha1_init(&context);
        fr_sha1_update(&context, buf, blen);
-       fr_sha1_final(keys->master_key, &context);
+       fr_sha1_final(keys->mk, &context);
 
        /*
         * now use the PRF to expand it, generated k_aut, k_encr,
         * MSK and EMSK.
         */
-       fr_sim_fips186_2prf(fk, keys->master_key);
+       fr_aka_sim_fips186_2prf(fk, keys->mk);
 
        /* split up the result */
        p = fk;
@@ -581,7 +582,7 @@ int fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys)
        L1 = 0x00 0x06
  @endverbatim
  *
- * @note expects keys to contain a SIM_VECTOR_UMTS.
+ * @note expects keys to contain a AKA_SIM_VECTOR_UMTS.
  *
  * @param[in,out] keys         Contains the authentication vectors and the buffers
  *                             to store the result of the derivation.
@@ -589,7 +590,7 @@ int fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys)
  *     - 0 on success.
  *     - -1 on failure.
  */
-static int sim_crypto_derive_ck_ik_prime(fr_sim_keys_t *keys)
+static int ck_ik_prime_derive(fr_aka_sim_keys_t *keys)
 {
        uint8_t         digest[sizeof(keys->ik_prime) + sizeof(keys->ck_prime)];
        size_t          len;
@@ -598,7 +599,7 @@ static int sim_crypto_derive_ck_ik_prime(fr_sim_keys_t *keys)
        uint16_t        l0, l1;
 
        uint8_t         k[sizeof(keys->umts.vector.ik) + sizeof(keys->umts.vector.ck)];
-       uint8_t         s[sizeof(uint8_t) + SIM_MAX_STRING_LENGTH + sizeof(l0) + SIM_SQN_AK_SIZE + sizeof(l1)];
+       uint8_t         s[sizeof(uint8_t) + AKA_SIM_MAX_STRING_LENGTH + sizeof(l0) + AKA_SIM_SQN_AK_SIZE + sizeof(l1)];
 
        uint8_t         *p = s;
 
@@ -606,7 +607,7 @@ static int sim_crypto_derive_ck_ik_prime(fr_sim_keys_t *keys)
        EVP_PKEY        *pkey;
        EVP_MD_CTX      *md_ctx = NULL;
 
-       if (!fr_cond_assert(keys->vector_type == SIM_VECTOR_UMTS)) return -1;
+       if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_UMTS)) return -1;
 
        uint48_to_buff(sqn_ak_buff, keys->sqn ^ uint48_from_buff(keys->umts.vector.ak));
 
@@ -617,13 +618,13 @@ static int sim_crypto_derive_ck_ik_prime(fr_sim_keys_t *keys)
        if (!fr_cond_assert((sizeof(uint8_t) +
                             keys->network_len +
                             sizeof(l0) +
-                            SIM_SQN_AK_SIZE +
+                            AKA_SIM_SQN_AK_SIZE +
                             sizeof(l1)) <= sizeof(s))) return -1;
 
        FR_PROTO_HEX_DUMP(keys->network, keys->network_len, "Network");
        FR_PROTO_HEX_DUMP(keys->umts.vector.ck, sizeof(keys->umts.vector.ck), "CK");
        FR_PROTO_HEX_DUMP(keys->umts.vector.ik, sizeof(keys->umts.vector.ik), "IK");
-       FR_PROTO_HEX_DUMP(sqn_ak_buff, SIM_SQN_AK_SIZE, "SQN âŠ• AK");
+       FR_PROTO_HEX_DUMP(sqn_ak_buff, AKA_SIM_SQN_AK_SIZE, "SQN âŠ• AK");
 
        /*
         *      FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
@@ -636,10 +637,10 @@ static int sim_crypto_derive_ck_ik_prime(fr_sim_keys_t *keys)
        memcpy(p, &l0, sizeof(l0));
        p += sizeof(l0);
 
-       memcpy(p, sqn_ak_buff, SIM_SQN_AK_SIZE);
-       p += SIM_SQN_AK_SIZE;
+       memcpy(p, sqn_ak_buff, AKA_SIM_SQN_AK_SIZE);
+       p += AKA_SIM_SQN_AK_SIZE;
 
-       l1 = htons(SIM_SQN_AK_SIZE);
+       l1 = htons(AKA_SIM_SQN_AK_SIZE);
        memcpy(p, &l1, sizeof(l1));
        p += sizeof(l1);
 
@@ -717,8 +718,8 @@ static int sim_crypto_derive_ck_ik_prime(fr_sim_keys_t *keys)
  *     - 0 on success.
  *     - -1 on failure.
  */
-static int sim_crypto_aka_prime_prf(uint8_t *out, size_t outlen,
-                                   uint8_t const *key, size_t key_len, uint8_t const *in, size_t in_len)
+static int aka_prime_prf(uint8_t *out, size_t outlen,
+                        uint8_t const *key, size_t key_len, uint8_t const *in, size_t in_len)
 {
        uint8_t         *p = out, *end = p + outlen;
        uint8_t         c = 0;
@@ -782,7 +783,7 @@ static int sim_crypto_aka_prime_prf(uint8_t *out, size_t outlen,
        EMSK   = MK[1152..1663]
  @endverbatim
  *
- * @note expects keys to contain a SIM_VECTOR_UMTS.
+ * @note expects keys to contain a AKA_SIM_VECTOR_UMTS.
  *
  * @param[in,out] keys         Contains the authentication vectors and the buffers
  *                             to store the result of the derivation.
@@ -790,19 +791,19 @@ static int sim_crypto_aka_prime_prf(uint8_t *out, size_t outlen,
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_crypto_kdf_1_umts(fr_sim_keys_t *keys)
+int fr_aka_sim_crypto_umts_kdf_1(fr_aka_sim_keys_t *keys)
 {
        uint8_t k[sizeof(keys->ck_prime) + sizeof(keys->ik_prime)];
 #define KDF_1_S_STATIC "EAP-AKA'"
-       uint8_t s[(sizeof(KDF_1_S_STATIC) - 1) + SIM_MAX_STRING_LENGTH];
+       uint8_t s[(sizeof(KDF_1_S_STATIC) - 1) + AKA_SIM_MAX_STRING_LENGTH];
        uint8_t *p = s;
 
        uint8_t mk[208];
        size_t  s_len;
 
-       sim_crypto_derive_ck_ik_prime(keys);
+       ck_ik_prime_derive(keys);
 
-       if (!fr_cond_assert(keys->vector_type == SIM_VECTOR_UMTS)) return -1;
+       if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_UMTS)) return -1;
 
        /*
         *      build s, a concatenation of EAP-AKA' and Identity
@@ -829,7 +830,7 @@ int fr_sim_crypto_kdf_1_umts(fr_sim_keys_t *keys)
        /*
         *      Feed into PRF
         */
-       if (sim_crypto_aka_prime_prf(mk, sizeof(mk), k, sizeof(k), s, s_len) < 0) return -1;
+       if (aka_prime_prf(mk, sizeof(mk), k, sizeof(k), s, s_len) < 0) return -1;
 
        /*
         *      Split the PRF output into separate keys
@@ -854,23 +855,50 @@ int fr_sim_crypto_kdf_1_umts(fr_sim_keys_t *keys)
 }
 
 
-/** Initialise fr_sim_keys_t with EAP-SIM/EAP-AKA['] reauthentication data
+/** Initialise fr_aka_sim_keys_t with EAP-SIM reauthentication data
  *
- * Generates a new nonce_s and copies the mk and counter values into the fr_sim_keys_t.
+ * Generates a new nonce_s and copies the mk and counter values into the fr_aka_sim_keys_t.
  *
- * @param[out] keys            structure to populate.
- * @param[in] master_key       from original authentication.
- * @param[in] counter          re-authentication counter.
+ * @param[out] keys    structure to populate.
+ * @param[in] mk       from original authentication.
+ * @param[in] counter  re-authentication counter.
  */
-void fr_sim_crypto_keys_init_reauth(fr_sim_keys_t *keys,
-                                   uint8_t const master_key[static SIM_MK_SIZE], uint16_t counter)
+void fr_aka_sim_crypto_keys_init_kdf_0_reauth(fr_aka_sim_keys_t *keys,
+                                             uint8_t const mk[static AKA_SIM_MK_SIZE], uint16_t counter)
 {
        uint32_t nonce_s[4];
 
        /*
         *      Copy in master key
         */
-       memcpy(keys->master_key, master_key, sizeof(keys->master_key));
+       memcpy(keys->mk, mk, sizeof(keys->mk));
+
+       keys->reauth.counter = counter;
+
+       nonce_s[0] = fr_rand();
+       nonce_s[1] = fr_rand();
+       nonce_s[2] = fr_rand();
+       nonce_s[3] = fr_rand();
+       memcpy(keys->reauth.nonce_s, (uint8_t *)&nonce_s, sizeof(keys->reauth.nonce_s));
+}
+
+/** Initialise fr_aka_sim_keys_t with EAP-AKA['] reauthentication data
+ *
+ * Generates a new nonce_s and copies the mk and counter values into the fr_aka_sim_keys_t.
+ *
+ * @param[out] keys    structure to populate.
+ * @param[in] k_re     from original authentication.
+ * @param[in] counter  re-authentication counter.
+ */
+void fr_aka_sim_crypto_keys_init_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys,
+                                                  uint8_t const k_re[static AKA_SIM_K_RE_SIZE], uint16_t counter)
+{
+       uint32_t nonce_s[4];
+
+       /*
+        *      Copy in master key
+        */
+       memcpy(keys->k_re, k_re, sizeof(keys->k_re));
 
        keys->reauth.counter = counter;
 
@@ -884,7 +912,7 @@ void fr_sim_crypto_keys_init_reauth(fr_sim_keys_t *keys,
 /** Key Derivation Function (Fast-Reauthentication) as described in RFC4186/7 (EAP-SIM/AKA) section 7
  *
  @verbatim
-       XKEY' = SHA1(Identity|counter|NONCE_S| MK)
+       XKEY' = SHA1(Identity|counter|NONCE_S|MK)
        FK    = PRF(XKEY')
        MSK   = FK[0..511]
        EMSK  = FK[512..1023]
@@ -892,9 +920,9 @@ void fr_sim_crypto_keys_init_reauth(fr_sim_keys_t *keys,
  *
  * Derives new MSK, EMSK, k_aut, k_encr
  *
- * Use #fr_sim_crypto_keys_init_reauth to populate the #fr_sim_keys_t structure.
+ * Use #fr_aka_sim_crypto_keys_init_reauth to populate the #fr_aka_sim_keys_t structure.
  *
- * @note expects keys to contain a populated master_key, none_s and counter values.
+ * @note expects keys to contain a populated mk, none_s and counter values.
  *
  * @param[in,out] keys         Contains the authentication vectors and the buffers
  *                             to store the result of the derivation.
@@ -902,11 +930,10 @@ void fr_sim_crypto_keys_init_reauth(fr_sim_keys_t *keys,
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_crypto_kdf_0_reauth(fr_sim_keys_t *keys)
+int fr_aka_sim_crypto_kdf_0_reauth(fr_aka_sim_keys_t *keys)
 {
        EVP_MD_CTX      *md_ctx;
        uint8_t         fk[160];
-       uint8_t         xkey_prime[SHA1_DIGEST_LENGTH];
 
        uint8_t         buf[384];
        uint8_t         *p;
@@ -925,7 +952,7 @@ int fr_sim_crypto_kdf_0_reauth(fr_sim_keys_t *keys)
                return -1;
        }
 
-       need = keys->identity_len + sizeof(uint16_t) + SIM_NONCE_S_SIZE + sizeof(keys->master_key);
+       need = keys->identity_len + sizeof(uint16_t) + AKA_SIM_NONCE_S_SIZE + sizeof(keys->mk);
        if (need > sizeof(buf)) {
                fr_strerror_printf("Identity too long. PRF input is %zu bytes, input buffer is %zu bytes",
                                   need, sizeof(buf));
@@ -936,16 +963,16 @@ int fr_sim_crypto_kdf_0_reauth(fr_sim_keys_t *keys)
         *      Re-derive k_aut and k_encr from the original Master Key
         *      These keys stay the same over multiple re-auth attempts.
         */
-       fr_sim_fips186_2prf(fk, keys->master_key);
+       fr_aka_sim_fips186_2prf(fk, keys->mk);
 
        p = fk;
        memcpy(keys->k_encr, p, 16);                            /* 128 bits for encryption */
        p += 16;
        FR_PROTO_HEX_DUMP(keys->k_encr, sizeof(keys->k_encr), "K_encr");
 
-       memcpy(keys->k_aut,  p, EAP_SIM_AUTH_SIZE);             /* 128 bits for auth */
+       memcpy(keys->k_aut,  p, EAP_AKA_SIM_AUTH_SIZE);         /* 128 bits for auth */
 
-       keys->k_aut_len = EAP_SIM_AUTH_SIZE;
+       keys->k_aut_len = EAP_AKA_SIM_AUTH_SIZE;
        FR_PROTO_HEX_DUMP(keys->k_aut, keys->k_aut_len, "K_aut");
 
        /*
@@ -978,8 +1005,8 @@ int fr_sim_crypto_kdf_0_reauth(fr_sim_keys_t *keys)
        /*
         *      Master key
         */
-       memcpy(p, keys->master_key, sizeof(keys->master_key));
-       p += sizeof(keys->master_key);
+       memcpy(p, keys->mk, sizeof(keys->mk));
+       p += sizeof(keys->mk);
 
        FR_PROTO_HEX_DUMP(buf, p - buf, "Identity || counter || NONCE_S || MK");
 
@@ -1004,19 +1031,19 @@ int fr_sim_crypto_kdf_0_reauth(fr_sim_keys_t *keys)
                goto error;
        }
 
-       if (EVP_DigestFinal_ex(md_ctx, xkey_prime, &len) != 1) {
+       if (EVP_DigestFinal_ex(md_ctx, keys->reauth.xkey_prime, &len) != 1) {
                tls_strerror_printf("Failed finalising digest");
                goto error;
        }
 
        EVP_MD_CTX_destroy(md_ctx);
 
-       FR_PROTO_HEX_DUMP(xkey_prime, sizeof(xkey_prime), "xkey'");
+       FR_PROTO_HEX_DUMP(keys->reauth.xkey_prime, sizeof(keys->reauth.xkey_prime), "xkey'");
 
        /*
         *      Expand XKEY' with PRF
         */
-       fr_sim_fips186_2prf(fk, xkey_prime);
+       fr_aka_sim_fips186_2prf(fk, keys->reauth.xkey_prime);
 
        /*
         *      Split up the result
@@ -1046,10 +1073,10 @@ int fr_sim_crypto_kdf_0_reauth(fr_sim_keys_t *keys)
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_crypto_kdf_1_reauth(fr_sim_keys_t *keys)
+int fr_aka_sim_crypto_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys)
 {
 #define KDF_1_S_REAUTH_STATIC  "EAP-AKA' re-auth"
-       uint8_t s[(sizeof(KDF_1_S_REAUTH_STATIC) - 1) + SIM_MAX_STRING_LENGTH + sizeof(uint16_t) + SIM_NONCE_S_SIZE];
+       uint8_t s[(sizeof(KDF_1_S_REAUTH_STATIC) - 1) + AKA_SIM_MAX_STRING_LENGTH + sizeof(uint16_t) + AKA_SIM_NONCE_S_SIZE];
        uint8_t *p = s;
 
        uint8_t mk[128];
@@ -1057,7 +1084,7 @@ int fr_sim_crypto_kdf_1_reauth(fr_sim_keys_t *keys)
        if (!fr_cond_assert(((sizeof(KDF_1_S_REAUTH_STATIC) - 1) +
                             keys->identity_len +
                             sizeof(uint16_t) +
-                            SIM_NONCE_S_SIZE) <= sizeof(s))) return -1;
+                            AKA_SIM_NONCE_S_SIZE) <= sizeof(s))) return -1;
 
        /*
         *      "EAP-AKA' re-auth"
@@ -1089,7 +1116,7 @@ int fr_sim_crypto_kdf_1_reauth(fr_sim_keys_t *keys)
        /*
         *      Feed into PRF
         */
-       if (sim_crypto_aka_prime_prf(mk, sizeof(mk), keys->k_re, sizeof(keys->k_re), s, p - s) < 0) return -1;
+       if (aka_prime_prf(mk, sizeof(mk), keys->k_re, sizeof(keys->k_re), s, p - s) < 0) return -1;
 
        FR_PROTO_HEX_DUMP(mk, sizeof(mk), "mk");
 
@@ -1109,15 +1136,15 @@ int fr_sim_crypto_kdf_1_reauth(fr_sim_keys_t *keys)
  * @param[in] request  The current request.
  * @param[in] keys     SIM keys associated with the session.
  */
-void fr_sim_crypto_keys_log(REQUEST *request, fr_sim_keys_t *keys)
+void fr_aka_sim_crypto_keys_log(REQUEST *request, fr_aka_sim_keys_t *keys)
 {
-       RDEBUG3("Cryptographic inputs");
+       RDEBUG3("KDF inputs");
 
        RINDENT();
        RHEXDUMP_INLINE3(keys->identity, keys->identity_len,
                        "Identity     :");
        switch (keys->vector_type) {
-       case SIM_VECTOR_GSM:
+       case AKA_SIM_VECTOR_GSM:
        {
                unsigned int i;
 
@@ -1128,72 +1155,89 @@ void fr_sim_crypto_keys_log(REQUEST *request, fr_sim_keys_t *keys)
                                "version_list :");
 
                for (i = 0; i < keys->gsm.num_vectors; i++) {
-                       RHEXDUMP_INLINE3(keys->gsm.vector[i].rand, SIM_VECTOR_GSM_RAND_SIZE,
-                                       "[%i] RAND    :", i);
-                       RHEXDUMP_INLINE3(keys->gsm.vector[i].sres, SIM_VECTOR_GSM_SRES_SIZE,
-                                       "[%i] SRES    :", i);
-                       RHEXDUMP_INLINE3(keys->gsm.vector[i].kc, SIM_VECTOR_GSM_KC_SIZE,
-                                       "[%i] KC      :", i);
+                       RHEXDUMP_INLINE3(keys->gsm.vector[i].rand, AKA_SIM_VECTOR_GSM_RAND_SIZE,
+                                        "[%i] RAND    :", i);
+                       RHEXDUMP_INLINE3(keys->gsm.vector[i].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE,
+                                        "[%i] SRES    :", i);
+                       RHEXDUMP_INLINE3(keys->gsm.vector[i].kc, AKA_SIM_VECTOR_GSM_KC_SIZE,
+                                        "[%i] KC      :", i);
                }
        }
                break;
 
-       case SIM_VECTOR_UMTS:
-               RHEXDUMP_INLINE3(keys->umts.vector.autn, SIM_VECTOR_UMTS_AUTN_SIZE,
-                               "AUTN         :");
+       case AKA_SIM_VECTOR_UMTS:
+               RHEXDUMP_INLINE3(keys->umts.vector.autn, AKA_SIM_VECTOR_UMTS_AUTN_SIZE,
+                                "AUTN         :");
 
-               RHEXDUMP_INLINE3(keys->umts.vector.ck, SIM_VECTOR_UMTS_CK_SIZE,
-                               "CK           :");
+               RHEXDUMP_INLINE3(keys->umts.vector.ck, AKA_SIM_VECTOR_UMTS_CK_SIZE,
+                                "CK           :");
 
-               RHEXDUMP_INLINE3(keys->umts.vector.ik, SIM_VECTOR_UMTS_IK_SIZE,
-                               "IK           :");
+               RHEXDUMP_INLINE3(keys->umts.vector.ik, AKA_SIM_VECTOR_UMTS_IK_SIZE,
+                                "IK           :");
 
-               RHEXDUMP_INLINE3(keys->umts.vector.rand, SIM_VECTOR_UMTS_RAND_SIZE,
-                               "RAND         :");
+               RHEXDUMP_INLINE3(keys->umts.vector.rand, AKA_SIM_VECTOR_UMTS_RAND_SIZE,
+                                "RAND         :");
 
                RHEXDUMP_INLINE3(keys->umts.vector.xres, keys->umts.vector.xres_len,
                                "XRES         :");
 
-               RHEXDUMP_INLINE3(keys->ck_prime, SIM_VECTOR_UMTS_CK_SIZE,
-                               "CK'          :");
+               RHEXDUMP_INLINE3(keys->ck_prime, AKA_SIM_VECTOR_UMTS_CK_SIZE,
+                                "CK'          :");
 
-               RHEXDUMP_INLINE3(keys->ik_prime, SIM_VECTOR_UMTS_IK_SIZE,
-                               "IK'          :");
+               RHEXDUMP_INLINE3(keys->ik_prime, AKA_SIM_VECTOR_UMTS_IK_SIZE,
+                                "IK'          :");
                break;
 
-       case SIM_VECTOR_UMTS_REAUTH:
-               RHEXDUMP_INLINE3(keys->master_key, sizeof(keys->master_key), "mk           :");
-               RDEBUG3("counter      : %u", keys->reauth.counter);
-               RHEXDUMP_INLINE3(keys->reauth.nonce_s, sizeof(keys->reauth.nonce_s), "nonce_s      :");
+       case AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH:
+               RHEXDUMP_INLINE3(keys->mk, sizeof(keys->mk),
+                               "MK           :");
+               RDEBUG3(
+                               "counter      : %u", keys->reauth.counter);
+               RHEXDUMP_INLINE3(keys->reauth.nonce_s, sizeof(keys->reauth.nonce_s),
+                               "nonce_s      :");
                break;
 
-       case SIM_VECTOR_NONE:
+       case AKA_SIM_VECTOR_UMTS_REAUTH_KDF_1_REAUTH:
+               RHEXDUMP_INLINE3(keys->k_re, sizeof(keys->k_re),
+                               "k_re         :");
+               RDEBUG3(
+                               "counter      : %u", keys->reauth.counter);
+               RHEXDUMP_INLINE3(keys->reauth.nonce_s, sizeof(keys->reauth.nonce_s),
+                               "nonce_s      :");
+               break;
+
+       case AKA_SIM_VECTOR_NONE:
                break;
        }
        REXDENT();
 
-       RDEBUG3("Derived keys");
+       RDEBUG3("Intermediary keys");
        RINDENT();
-
        switch (keys->vector_type) {
-       case SIM_VECTOR_UMTS_REAUTH:
+       case AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH:
+               RHEXDUMP_INLINE3(keys->reauth.xkey_prime, sizeof(keys->reauth.xkey_prime),
+                               "XKEY'        :");
                break;
 
        default:
-               RHEXDUMP_INLINE3(keys->master_key, sizeof(keys->master_key),
-                               "mk           :");
                break;
        }
+       REXDENT();
+
+       RDEBUG3("PRF output");
+       RINDENT();
+       RHEXDUMP_INLINE3(keys->mk, sizeof(keys->mk),
+                        "MK           :");
+       RHEXDUMP_INLINE3(keys->k_re, sizeof(keys->k_re),
+                        "k_re         :");
        RHEXDUMP_INLINE3(keys->k_aut, keys->k_aut_len,
-                       "k_aut        :");
+                        "k_aut        :");
        RHEXDUMP_INLINE3(keys->k_encr, sizeof(keys->k_encr),
-                       "k_encr       :");
-       RHEXDUMP_INLINE3(keys->k_re, sizeof(keys->k_re),
-                       "k_re         :");
+                        "k_encr       :");
        RHEXDUMP_INLINE3(keys->msk, sizeof(keys->msk),
-                       "msk          :");
+                        "MSK          :");
        RHEXDUMP_INLINE3(keys->emsk, sizeof(keys->emsk),
-                       "emsk         :");
+                        "EMSK         :");
        REXDENT();
 }
 
@@ -1209,7 +1253,7 @@ void fr_sim_crypto_keys_log(REQUEST *request, fr_sim_keys_t *keys)
 /*
  *     EAP-SIM (RFC4186) GSM authentication vectors
  */
-static fr_sim_keys_t const rfc4186_vector0_in = {
+static fr_aka_sim_keys_t const rfc4186_vector0_in = {
        .identity = (uint8_t const *)"1244070100000001@eapsim.foo",
        .identity_len = sizeof("1244070100000001@eapsim.foo") - 1,
 
@@ -1241,10 +1285,10 @@ static fr_sim_keys_t const rfc4186_vector0_in = {
                .version_select = { 0x00, 0x01 },
                .num_vectors = 3
        },
-       .vector_type = SIM_VECTOR_GSM
+       .vector_type = AKA_SIM_VECTOR_GSM
 };
 
-static fr_sim_keys_t const rfc4186_vector0_out = {
+static fr_aka_sim_keys_t const rfc4186_vector0_out = {
        .k_encr         = { 0x53, 0x6e, 0x5e, 0xbc, 0x44, 0x65, 0x58, 0x2a,
                            0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 },
        .k_aut          = { 0x25, 0xaf, 0x19, 0x42, 0xef, 0xcb, 0xf4, 0xbc,
@@ -1270,7 +1314,7 @@ static fr_sim_keys_t const rfc4186_vector0_out = {
 
 static void test_eap_sim_kdf_0_gsm(void)
 {
-       fr_sim_keys_t   keys;
+       fr_aka_sim_keys_t       keys;
        int             ret;
 
 /*
@@ -1280,7 +1324,7 @@ static void test_eap_sim_kdf_0_gsm(void)
 
        memcpy(&keys, &rfc4186_vector0_in, sizeof(keys));
 
-       ret = fr_sim_crypto_kdf_0_gsm(&keys);
+       ret = fr_aka_sim_crypto_gsm_kdf_0(&keys);
        TEST_CHECK(ret == 0);
 
        TEST_CHECK(memcmp(&rfc4186_vector0_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
@@ -1295,7 +1339,7 @@ static void test_eap_sim_kdf_0_gsm(void)
  *
  *     Test vector from 18 from 3GPP TS 35.208 V9 (the same used by EAP-AKA')
  */
-static fr_sim_keys_t const rfc4187_vector0_in = {
+static fr_aka_sim_keys_t const rfc4187_vector0_in = {
        .identity = (uint8_t const *)"0555444333222111",
        .identity_len = sizeof("0555444333222111") - 1,
 
@@ -1315,10 +1359,10 @@ static fr_sim_keys_t const rfc4187_vector0_in = {
                        .xres_len       = 8
                }
        },
-       .vector_type = SIM_VECTOR_UMTS
+       .vector_type = AKA_SIM_VECTOR_UMTS
 };
 
-static fr_sim_keys_t const rfc4187_vector0_out = {
+static fr_aka_sim_keys_t const rfc4187_vector0_out = {
        .k_encr         = { 0x18, 0xe8, 0xb2, 0x0b, 0xcd, 0xa7, 0x04, 0x86,
                            0xfd, 0x59, 0x59, 0x58, 0x6a, 0x9e, 0x7c, 0x3d },
        .k_aut          = { 0x18, 0xc0, 0x44, 0x07, 0x0e, 0x5e, 0x64, 0x2a,
@@ -1344,7 +1388,7 @@ static fr_sim_keys_t const rfc4187_vector0_out = {
 
 static void test_eap_aka_kdf_0_umts(void)
 {
-       fr_sim_keys_t   keys;
+       fr_aka_sim_keys_t       keys;
        int             ret;
 
 /*
@@ -1354,7 +1398,7 @@ static void test_eap_aka_kdf_0_umts(void)
 
        memcpy(&keys, &rfc4187_vector0_in, sizeof(keys));
 
-       ret = fr_sim_crypto_kdf_0_umts(&keys);
+       ret = fr_aka_sim_crypto_umts_kdf_0(&keys);
        TEST_CHECK(ret == 0);
 
        TEST_CHECK(memcmp(&rfc4187_vector0_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
@@ -1368,7 +1412,7 @@ static void test_eap_aka_kdf_0_umts(void)
 /*
  *     EAP-SIM (RFC4186) GSM re-authentication vectors
  */
-static fr_sim_keys_t const rfc4186_vector0_reauth_in = {
+static fr_aka_sim_keys_t const rfc4186_vector0_reauth_in = {
        .identity       = (uint8_t const *)"Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo",
        .identity_len   = sizeof("Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo") - 1,
 
@@ -1377,12 +1421,12 @@ static fr_sim_keys_t const rfc4186_vector0_reauth_in = {
                                .nonce_s = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
                                             0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }
                          },
-       .master_key     = { 0xe5, 0x76, 0xd5, 0xca, 0x33, 0x2e, 0x99, 0x30,
+       .mk     = { 0xe5, 0x76, 0xd5, 0xca, 0x33, 0x2e, 0x99, 0x30,
                            0x01, 0x8b, 0xf1, 0xba, 0xee, 0x27, 0x63, 0xc7,
                            0x95, 0xb3, 0xc7, 0x12 },
 };
 
-static fr_sim_keys_t const rfc4186_vector0_reauth_out = {
+static fr_aka_sim_keys_t const rfc4186_vector0_reauth_out = {
        .k_encr         = { 0x53, 0x6e, 0x5e, 0xbc, 0x44, 0x65, 0x58, 0x2a,
                            0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 },
        .k_aut          = { 0x25, 0xaf, 0x19, 0x42, 0xef, 0xcb, 0xf4, 0xbc,
@@ -1408,7 +1452,7 @@ static fr_sim_keys_t const rfc4186_vector0_reauth_out = {
 
 static void test_eap_sim_kdf_0_reauth(void)
 {
-       fr_sim_keys_t   keys;
+       fr_aka_sim_keys_t       keys;
        int             ret;
 
 /*
@@ -1418,7 +1462,7 @@ static void test_eap_sim_kdf_0_reauth(void)
 
        memcpy(&keys, &rfc4186_vector0_reauth_in, sizeof(keys));
 
-       ret = fr_sim_crypto_kdf_0_reauth(&keys);
+       ret = fr_aka_sim_crypto_kdf_0_reauth(&keys);
        TEST_CHECK(ret == 0);
 
        TEST_CHECK(memcmp(&rfc4186_vector0_reauth_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
@@ -1432,7 +1476,7 @@ static void test_eap_sim_kdf_0_reauth(void)
 /*
  *     EAP-AKA' (RFC5448) UMTS authentication vectors
  */
-static fr_sim_keys_t const rfc5448_vector0_in = {
+static fr_aka_sim_keys_t const rfc5448_vector0_in = {
        .identity = (uint8_t const *)"0555444333222111",
        .identity_len = sizeof("0555444333222111") - 1,
 
@@ -1455,10 +1499,10 @@ static fr_sim_keys_t const rfc5448_vector0_in = {
                        .xres_len       = 8
                }
        },
-       .vector_type = SIM_VECTOR_UMTS
+       .vector_type = AKA_SIM_VECTOR_UMTS
 };
 
-static fr_sim_keys_t const rfc5448_vector0_out = {
+static fr_aka_sim_keys_t const rfc5448_vector0_out = {
        .ik_prime       = { 0x00, 0x93, 0x96, 0x2d, 0x0d, 0xd8, 0x4a, 0xa5,
                            0x68, 0x4b, 0x04, 0x5c, 0x9e, 0xdf, 0xfa, 0x04 },
        .ck_prime       = { 0xcc, 0xfc, 0x23, 0x0c, 0xa7, 0x4f, 0xcc, 0x96,
@@ -1495,7 +1539,7 @@ static fr_sim_keys_t const rfc5448_vector0_out = {
 
 static void test_eap_aka_kdf_1_umts(void)
 {
-       fr_sim_keys_t   keys;
+       fr_aka_sim_keys_t       keys;
        int             ret;
 
 /*
@@ -1508,7 +1552,7 @@ static void test_eap_aka_kdf_1_umts(void)
        memcpy(keys.ck_prime, rfc5448_vector0_out.ck_prime, sizeof(keys.ck_prime));
        memcpy(keys.ik_prime, rfc5448_vector0_out.ik_prime, sizeof(keys.ik_prime));
 
-       ret = fr_sim_crypto_kdf_1_umts(&keys);
+       ret = fr_aka_sim_crypto_umts_kdf_1(&keys);
        TEST_CHECK(ret == 0);
 
        TEST_CHECK(memcmp(&rfc5448_vector0_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
@@ -1522,7 +1566,7 @@ static void test_eap_aka_kdf_1_umts(void)
 static void test_eap_aka_derive_ck_ik(void)
 {
 
-       fr_sim_keys_t   keys;
+       fr_aka_sim_keys_t       keys;
        int             ret;
 
 /*
@@ -1531,7 +1575,7 @@ static void test_eap_aka_derive_ck_ik(void)
 */
 
        memcpy(&keys, &rfc5448_vector0_in, sizeof(keys));
-       ret = sim_crypto_derive_ck_ik_prime(&keys);
+       ret = ck_ik_prime_derive(&keys);
        TEST_CHECK(ret == 0);
        TEST_CHECK(memcmp(&rfc5448_vector0_out.ck_prime, keys.ck_prime, sizeof(keys.ck_prime)) == 0);
        TEST_CHECK(memcmp(&rfc5448_vector0_out.ik_prime, keys.ik_prime, sizeof(keys.ik_prime)) == 0);
@@ -1540,7 +1584,7 @@ static void test_eap_aka_derive_ck_ik(void)
 /*
  *     EAP-AKA' (RFC5448) UMTS authentication vectors
  */
-static fr_sim_keys_t const rfc5448_vector0_reauth_in = {
+static fr_aka_sim_keys_t const rfc5448_vector0_reauth_in = {
        .identity = (uint8_t const *)"5555444333222111",
        .identity_len = sizeof("5555444333222111") - 1,
 
@@ -1568,7 +1612,7 @@ static fr_sim_keys_t const rfc5448_vector0_reauth_in = {
 /*
  *     Not tested against external source (yet)
  */
-static fr_sim_keys_t const rfc5448_vector0_reauth_out = {
+static fr_aka_sim_keys_t const rfc5448_vector0_reauth_out = {
        .k_encr         = { 0x76, 0x6f, 0xa0, 0xa6, 0xc3, 0x17, 0x17, 0x4b,
                            0x81, 0x2d, 0x52, 0xfb, 0xcd, 0x11, 0xa1, 0x79 },
        .k_aut          = { 0x08, 0x42, 0xea, 0x72, 0x2f, 0xf6, 0x83, 0x5b,
@@ -1596,7 +1640,7 @@ static fr_sim_keys_t const rfc5448_vector0_reauth_out = {
 
 static void test_eap_aka_kdf_1_reauth(void)
 {
-       fr_sim_keys_t   keys;
+       fr_aka_sim_keys_t       keys;
        int             ret;
 
 /*
@@ -1606,7 +1650,7 @@ static void test_eap_aka_kdf_1_reauth(void)
 
        memcpy(&keys, &rfc5448_vector0_reauth_in, sizeof(keys));
 
-       ret = fr_sim_crypto_kdf_1_reauth(&keys);
+       ret = fr_aka_sim_crypto_umts_kdf_1_reauth(&keys);
        TEST_CHECK(ret == 0);
 
        TEST_CHECK(memcmp(&rfc5448_vector0_reauth_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
similarity index 94%
rename from src/lib/sim/decode.c
rename to src/lib/eap_aka_sim/decode.c
index 5c77eadd7a9eb3166828434e039a6a6e4bd94133..823deef62e50b37b456cf6cf9d6ad7018204174e 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 /**
- * @file src/lib/sim/decode.c
+ * @file src/lib/aka-sim/decode.c
  * @brief Code common to EAP-SIM/AKA/AKA' clients and servers.
  *
  * The development of the EAP-SIM support was funded by Internet Foundation
@@ -35,7 +35,6 @@ RCSID("$Id$")
 #include <freeradius-devel/io/test_point.h>
 
 #include <freeradius-devel/eap/types.h>
-#include "eap_sim_common.h"
 #include "base.h"
 #include "attrs.h"
 
@@ -76,16 +75,16 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
  *     - 0 on success.
  *     - < 0 on failure (bad IV).
  */
-static inline int sim_iv_extract(uint8_t out[SIM_IV_SIZE], uint8_t const *in, size_t in_len)
+static inline int sim_iv_extract(uint8_t out[AKA_SIM_IV_SIZE], uint8_t const *in, size_t in_len)
 {
        /*
         *      Two bytes are reserved, so although
         *      the IV is actually 16 bytes, we
         *      check for 18.
         */
-       if (in_len != (SIM_IV_SIZE + 2)) {
+       if (in_len != (AKA_SIM_IV_SIZE + 2)) {
                fr_strerror_printf("%s: Invalid IV length, expected %u got %zu",
-                                  __FUNCTION__, (SIM_IV_SIZE + 2), in_len);
+                                  __FUNCTION__, (AKA_SIM_IV_SIZE + 2), in_len);
                return -1;
        }
 
@@ -95,7 +94,7 @@ static inline int sim_iv_extract(uint8_t out[SIM_IV_SIZE], uint8_t const *in, si
        }
 
        /* skip reserved bytes */
-       memcpy(out, in + 2, SIM_IV_SIZE);
+       memcpy(out, in + 2, AKA_SIM_IV_SIZE);
 
        return 0;
 }
@@ -116,7 +115,7 @@ static ssize_t sim_value_decrypt(TALLOC_CTX *ctx, uint8_t **out,
                                 uint8_t const *data, size_t const attr_len, size_t const data_len,
                                 void *decoder_ctx)
 {
-       fr_sim_decode_ctx_t     *packet_ctx = decoder_ctx;
+       fr_aka_sim_decode_ctx_t *packet_ctx = decoder_ctx;
        EVP_CIPHER_CTX          *evp_ctx;
        EVP_CIPHER const        *evp_cipher = EVP_aes_128_cbc();
        size_t                  block_size = EVP_CIPHER_block_size(evp_cipher);
@@ -160,7 +159,7 @@ static ssize_t sim_value_decrypt(TALLOC_CTX *ctx, uint8_t **out,
                                return -1;
                        }
 
-                       if (sim_at == FR_SIM_IV) {
+                       if (sim_at == FR_IV) {
                                if (sim_iv_extract(&(packet_ctx->iv[0]), p + 2, sim_at_len - 2) < 0) return -1;
                                packet_ctx->have_iv = true;
                                break;
@@ -267,7 +266,7 @@ static int sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *da)
                break;
 
        default:
-               element_len = fr_sim_attr_sizes[da->type][0];
+               element_len = fr_aka_sim_attr_sizes[da->type][0];
                break;
        }
 
@@ -439,7 +438,7 @@ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                 *      correct length for the block cipher
                 *      (16 in the case of AES-128-CBC).
                 */
-               if (sim_at == FR_SIM_PADDING) {
+               if (sim_at == FR_PADDING) {
                        uint8_t zero = 0;
                        uint8_t i;
 
@@ -458,7 +457,7 @@ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                        }
 
                        /*
-                        *      RFC says we MUST verify that FR_SIM_PADDING
+                        *      RFC says we MUST verify that FR_PADDING
                         *      data is zeroed out.
                         */
                        for (i = 2; i < sim_at_len; i++) zero |= p[i];
@@ -484,7 +483,7 @@ static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                         *      RFC says we need to die on these if we don't
                         *      understand them.  non-skippables are < 128.
                         */
-                       if (sim_at <= SIM_SKIPPABLE_MAX) {
+                       if (sim_at <= AKA_SIM_SKIPPABLE_MAX) {
                                fr_strerror_printf("%s: Unknown (non-skippable) attribute %i",
                                                   __FUNCTION__, sim_at);
                                goto error;
@@ -534,7 +533,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
        uint8_t const           *p = data;
        size_t                  prefix = 0;
 
-       fr_sim_decode_ctx_t     *packet_ctx = decoder_ctx;
+       fr_aka_sim_decode_ctx_t *packet_ctx = decoder_ctx;
 
        if (!fr_cond_assert(attr_len <= data_len)) return -1;
        if (!fr_cond_assert(parent)) return -1;
@@ -567,7 +566,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
         *      |                                                               |
         *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-       case FR_SIM_IV:
+       case FR_IV:
                if (sim_iv_extract(&packet_ctx->iv[0], data, attr_len) < 0) return -1;
                packet_ctx->have_iv = true;
                break;  /* Now create the attribute */
@@ -586,7 +585,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
         *      |                                                               |
         *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-       case FR_EAP_AKA_RES:
+       case FR_RES:
        {
                uint16_t res_len;
 
@@ -634,7 +633,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
         *      |                                                               |
         *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-       case FR_EAP_AKA_CHECKCODE:
+       case FR_CHECKCODE:
                if (attr_len < 2) goto raw;     /* Need at least two bytes for reserved field */
 
                vp = fr_pair_afrom_da(ctx, parent);
@@ -663,7 +662,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
                /*
                 *      Get the number of bytes we expect before the value
                 */
-               prefix = fr_sim_octets_prefix_len(parent);
+               prefix = fr_aka_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;
@@ -673,7 +672,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
        case FR_TYPE_UINT16:
        case FR_TYPE_UINT32:
        case FR_TYPE_UINT64:
-               if (attr_len != fr_sim_attr_sizes[parent->type][0]) goto raw;
+               if (attr_len != fr_aka_sim_attr_sizes[parent->type][0]) goto raw;
                break;
 
        case FR_TYPE_TLV:
@@ -692,7 +691,7 @@ static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_di
                 *      We can't create unknowns for non-skippable attributes
                 *      as we're prohibited from continuing by the SIM RFCs.
                 */
-               if (parent->attr <= SIM_SKIPPABLE_MAX) {
+               if (parent->attr <= AKA_SIM_SKIPPABLE_MAX) {
                        fr_strerror_printf_push("%s: Failed parsing non-skippable attribute '%s'",
                                                __FUNCTION__, parent->name);
                        return -1;
@@ -894,7 +893,7 @@ static ssize_t sim_decode_pair_internal(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr
                 *      RFC says we need to die on these if we don't
                 *      understand them.  non-skippables are < 128.
                 */
-               if (sim_at <= SIM_SKIPPABLE_MAX) {
+               if (sim_at <= AKA_SIM_SKIPPABLE_MAX) {
                        fr_strerror_printf("Unknown (non-skippable) attribute %i", sim_at);
                        return -1;
                }
@@ -928,7 +927,7 @@ static ssize_t sim_decode_pair_internal(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr
  *     - The number of bytes parsed.
  *     - -1 on error.
  */
-ssize_t fr_sim_decode_pair(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+ssize_t fr_aka_sim_decode_pair(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
                           uint8_t const *data, size_t data_len, void *decoder_ctx)
 {
        return sim_decode_pair_internal(ctx, cursor, fr_dict_root(dict), data, data_len, decoder_ctx);
@@ -961,8 +960,8 @@ ssize_t fr_sim_decode_pair(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_sim_decode(REQUEST *request, fr_cursor_t *decoded, fr_dict_t const *dict,
-                 uint8_t const *data, size_t data_len, fr_sim_decode_ctx_t *decoder_ctx)
+int fr_aka_sim_decode(REQUEST *request, fr_cursor_t *decoded, fr_dict_t const *dict,
+                 uint8_t const *data, size_t data_len, fr_aka_sim_decode_ctx_t *decoder_ctx)
 {
        ssize_t                 rcode;
        uint8_t const           *p = data;
@@ -996,7 +995,7 @@ int fr_sim_decode(REQUEST *request, fr_cursor_t *decoded, fr_dict_t const *dict,
         *      in the SIM/AKA/AKA' dict.
         */
        while (p < end) {
-               rcode = fr_sim_decode_pair(request->packet, decoded, dict, p, end - p, decoder_ctx);
+               rcode = fr_aka_sim_decode_pair(request->packet, decoded, dict, p, end - p, decoder_ctx);
                if (rcode <= 0) {
                        RPEDEBUG("Failed decoding AT");
                error:
@@ -1015,7 +1014,7 @@ int fr_sim_decode(REQUEST *request, fr_cursor_t *decoded, fr_dict_t const *dict,
        {
                VALUE_PAIR *vp;
 
-               vp = fr_pair_afrom_child_num(request->packet, fr_dict_root(dict), FR_SIM_SUBTYPE);
+               vp = fr_pair_afrom_child_num(request->packet, fr_dict_root(dict), FR_SUBTYPE);
                if (!vp) {
                        fr_strerror_printf("Failed allocating subtype attribute");
                        goto error;
@@ -1027,22 +1026,22 @@ int fr_sim_decode(REQUEST *request, fr_cursor_t *decoded, fr_dict_t const *dict,
        return 0;
 }
 
-static int _test_ctx_free(UNUSED fr_sim_decode_ctx_t *ctx)
+static int _test_ctx_free(UNUSED fr_aka_sim_decode_ctx_t *ctx)
 {
-       fr_sim_free();
+       fr_aka_sim_free();
 
        return 0;
 }
 
-static fr_sim_decode_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
+static fr_aka_sim_decode_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
 {
-       fr_sim_decode_ctx_t     *test_ctx;
-       fr_sim_keys_t           *keys;
+       fr_aka_sim_decode_ctx_t *test_ctx;
+       fr_aka_sim_keys_t               *keys;
 
-       if (fr_sim_init() < 0) return NULL;
+       if (fr_aka_sim_init() < 0) return NULL;
 
-       test_ctx = talloc_zero(ctx, fr_sim_decode_ctx_t);
-       test_ctx->keys = keys = talloc_zero(test_ctx, fr_sim_keys_t);
+       test_ctx = talloc_zero(ctx, fr_aka_sim_decode_ctx_t);
+       test_ctx->keys = keys = talloc_zero(test_ctx, fr_aka_sim_keys_t);
        memcpy(keys->k_encr, k_encr, k_encr_len);
        talloc_set_destructor(test_ctx, _test_ctx_free);
 
@@ -1053,7 +1052,7 @@ static fr_sim_decode_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr
  */
 static int decode_test_ctx_sim(void **out, TALLOC_CTX *ctx)
 {
-       fr_sim_decode_ctx_t     *test_ctx;
+       fr_aka_sim_decode_ctx_t *test_ctx;
        static uint8_t          k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
                                             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
 
@@ -1070,7 +1069,7 @@ static int decode_test_ctx_sim(void **out, TALLOC_CTX *ctx)
 
 static int decode_test_ctx_aka(void **out, TALLOC_CTX *ctx)
 {
-       fr_sim_decode_ctx_t *test_ctx;
+       fr_aka_sim_decode_ctx_t *test_ctx;
        static uint8_t          k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
                                             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
 
@@ -1086,7 +1085,7 @@ static int decode_test_ctx_aka(void **out, TALLOC_CTX *ctx)
 
 static int decode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx)
 {
-       fr_sim_decode_ctx_t *test_ctx;
+       fr_aka_sim_decode_ctx_t *test_ctx;
        static uint8_t          k_encr[] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a,
                                             0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 };
 
@@ -1104,17 +1103,17 @@ static int decode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx)
 extern fr_test_point_pair_decode_t sim_tp_decode;
 fr_test_point_pair_decode_t sim_tp_decode = {
        .test_ctx       = decode_test_ctx_sim,
-       .func           = fr_sim_decode_pair
+       .func           = fr_aka_sim_decode_pair
 };
 
 extern fr_test_point_pair_decode_t sim_tp_decode_rfc4186;
 fr_test_point_pair_decode_t sim_tp_decode_rfc4186 = {
        .test_ctx       = decode_test_ctx_sim_rfc4186,
-       .func           = fr_sim_decode_pair
+       .func           = fr_aka_sim_decode_pair
 };
 
 extern fr_test_point_pair_decode_t aka_tp_decode;
 fr_test_point_pair_decode_t aka_tp_decode = {
        .test_ctx       = decode_test_ctx_aka,
-       .func           = fr_sim_decode_pair
+       .func           = fr_aka_sim_decode_pair
 };
similarity index 93%
rename from src/lib/sim/encode.c
rename to src/lib/eap_aka_sim/encode.c
index 63fe9a12c1aed1ec24fa0cea2789f94f97606539..5f283ff2e76e8bd9bbc36844031bc6b82c30ec84 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 /**
- * @file src/lib/sim/encode.c
+ * @file src/lib/aka-sim/encode.c
  * @brief Code common to EAP-SIM/AKA/AKA' clients and servers.
  *
  * @copyright 2017 FreeRADIUS server project
@@ -31,7 +31,6 @@ RCSID("$Id$")
 #include <freeradius-devel/io/test_point.h>
 
 #include <freeradius-devel/eap/types.h>
-#include "eap_sim_common.h"
 #include "base.h"
 #include "attrs.h"
 
@@ -82,7 +81,7 @@ static inline bool is_encodable(fr_dict_attr_t const *root, VALUE_PAIR *vp)
 static inline VALUE_PAIR *next_encodable(fr_cursor_t *cursor, void *encoder_ctx)
 {
        VALUE_PAIR              *vp;
-       fr_sim_encode_ctx_t     *packet_ctx = encoder_ctx;
+       fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
 
        while ((vp = fr_cursor_next(cursor))) if (is_encodable(packet_ctx->root, vp)) break;
        return fr_cursor_current(cursor);
@@ -97,7 +96,7 @@ static inline VALUE_PAIR *next_encodable(fr_cursor_t *cursor, void *encoder_ctx)
 static inline VALUE_PAIR *first_encodable(fr_cursor_t *cursor, void *encoder_ctx)
 {
        VALUE_PAIR              *vp;
-       fr_sim_encode_ctx_t     *packet_ctx = encoder_ctx;
+       fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
 
        vp = fr_cursor_current(cursor);
        if (is_encodable(packet_ctx->root, vp)) return vp;
@@ -122,7 +121,7 @@ static inline VALUE_PAIR *first_encodable(fr_cursor_t *cursor, void *encoder_ctx
  */
 static ssize_t encode_iv(uint8_t *out, size_t outlen, void *encoder_ctx)
 {
-       fr_sim_encode_ctx_t     *packet_ctx = encoder_ctx;
+       fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
        uint8_t                 *p = out;
        uint32_t                iv[4];
 
@@ -131,7 +130,7 @@ static ssize_t encode_iv(uint8_t *out, size_t outlen, void *encoder_ctx)
         */
        if (packet_ctx->iv_included) return 0;
 
-       CHECK_FREESPACE(outlen, 4 + SIM_IV_SIZE);       /* AT_IV + Length + Reserved(2) + IV */
+       CHECK_FREESPACE(outlen, 4 + AKA_SIM_IV_SIZE);   /* AT_IV + Length + Reserved(2) + IV */
 
        /*
         *      Generate IV
@@ -143,8 +142,8 @@ static ssize_t encode_iv(uint8_t *out, size_t outlen, void *encoder_ctx)
 
        memcpy(packet_ctx->iv, (uint8_t *)&iv[0], sizeof(packet_ctx->iv));      /* ensures alignment */
 
-       *p++ = FR_SIM_IV;
-       *p++ = (4 + SIM_IV_SIZE) >> 2;
+       *p++ = FR_IV;
+       *p++ = (4 + AKA_SIM_IV_SIZE) >> 2;
        *p++ = 0;
        *p++ = 0;
        memcpy(p, packet_ctx->iv, sizeof(packet_ctx->iv));
@@ -182,7 +181,7 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen,
 {
        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;
+       fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
        EVP_CIPHER_CTX          *evp_ctx;
        EVP_CIPHER const        *evp_cipher = EVP_aes_128_cbc();
        size_t                  block_size = EVP_CIPHER_block_size(evp_cipher);
@@ -211,7 +210,7 @@ static ssize_t encode_encrypted_value(uint8_t *out, size_t outlen,
         *      Append an AT_PADDING attribute if required
         */
        if (pad_len != 0) {
-               p[0] = FR_SIM_PADDING;
+               p[0] = FR_PADDING;
                p[1] = pad_len >> 2;
                memset(p + 2, 0, pad_len - 2);  /* Ensure the rest is zeroed out */
                FR_PROTO_HEX_DUMP(p, pad_len, "Done padding attribute");
@@ -302,7 +301,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
        ssize_t                 len;
        VALUE_PAIR const        *vp = fr_cursor_current(cursor);
        fr_dict_attr_t const    *da = tlv_stack[depth];
-       fr_sim_encode_ctx_t     *packet_ctx = encoder_ctx;
+       fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
 
        VP_VERIFY(vp);
        FR_PROTO_STACK_PRINT(tlv_stack, depth);
@@ -342,7 +341,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
         *      |                                                               |
         *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-       case FR_SIM_IV:
+       case FR_IV:
                if ((vp->da->flags.length && (da->flags.length != vp->vp_length)) ||
                    (vp->vp_length != sizeof(packet_ctx->iv))) {
                        fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
@@ -368,7 +367,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
         *      |                                                               |
         *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-       case FR_EAP_AKA_RES:
+       case FR_RES:
        {
                uint16_t        res_len = htons(vp->vp_length * 8);     /* Get length in bits */
 
@@ -407,7 +406,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
         *      |                                                               |
         *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-       case FR_EAP_AKA_CHECKCODE:
+       case FR_CHECKCODE:
        {
                uint8_t *p = out;
 
@@ -477,7 +476,7 @@ static ssize_t encode_value(uint8_t *out, size_t outlen,
                 *      Fixed length attribute
                 */
                if (vp->da->flags.length) {
-                       size_t prefix = fr_sim_octets_prefix_len(vp->da);
+                       size_t prefix = fr_aka_sim_octets_prefix_len(vp->da);
                        size_t pad_len;
                        size_t value_len_rounded;
 
@@ -630,7 +629,7 @@ static ssize_t encode_array(uint8_t *out, size_t outlen,
                }
                element_len = da->flags.length;
        } else {
-               element_len = fr_sim_attr_sizes[da->type][0];
+               element_len = fr_aka_sim_attr_sizes[da->type][0];
        }
 
        /*
@@ -877,7 +876,7 @@ static ssize_t encode_tlv_hdr(uint8_t *out, size_t outlen,
        return p - out; /* AT_IV + AT_*(TLV) - Can't use total_len, doesn't include IV */
 }
 
-ssize_t fr_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, void *encoder_ctx)
+ssize_t fr_aka_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, void *encoder_ctx)
 {
        VALUE_PAIR const        *vp;
        ssize_t                 slen;
@@ -885,7 +884,7 @@ ssize_t fr_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, voi
 
        fr_dict_attr_t const    *tlv_stack[FR_DICT_MAX_TLV_STACK + 1];
        fr_dict_attr_t const    *da = NULL;
-       fr_sim_encode_ctx_t     *packet_ctx = encoder_ctx;
+       fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
 
        if (!cursor || !out) return PAIR_ENCODE_ERROR;
 
@@ -902,7 +901,7 @@ ssize_t fr_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, voi
                return PAIR_ENCODE_ERROR;
        }
 
-       if (vp->da->attr == FR_SIM_MAC) {
+       if (vp->da->attr == FR_MAC) {
                next_encodable(cursor, encoder_ctx);
                return 0;
        }
@@ -957,7 +956,7 @@ ssize_t fr_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, voi
        return slen;
 }
 
-ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
+ssize_t fr_aka_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
 {
        VALUE_PAIR              *vp;
 
@@ -969,7 +968,7 @@ ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
 
        unsigned char           subtype;
        fr_cursor_t             cursor;
-       fr_sim_encode_ctx_t     *packet_ctx = encode_ctx;
+       fr_aka_sim_encode_ctx_t *packet_ctx = encode_ctx;
        eap_packet_t            *eap_packet = packet_ctx->eap_packet;
 
        /*
@@ -977,7 +976,7 @@ ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
         *      It might be too big for putting into an
         *      EAP packet.
         */
-       vp = fr_pair_find_by_child_num(to_encode, packet_ctx->root, FR_SIM_SUBTYPE, TAG_ANY);
+       vp = fr_pair_find_by_child_num(to_encode, packet_ctx->root, FR_SUBTYPE, TAG_ANY);
        if (!vp) {
                REDEBUG("Missing subtype attribute");
                return PAIR_ENCODE_ERROR;
@@ -993,7 +992,7 @@ ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
        /*
         *      Will we need to generate a HMAC?
         */
-       if (fr_pair_find_by_child_num(to_encode, packet_ctx->root, FR_EAP_SIM_MAC, TAG_ANY)) do_hmac = true;
+       if (fr_pair_find_by_child_num(to_encode, packet_ctx->root, FR_MAC, TAG_ANY)) do_hmac = true;
 
        /*
         *      Fast path, we just need to encode a subtype
@@ -1025,10 +1024,10 @@ ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
         *      Add space in the packet for AT_MAC
         */
        if (do_hmac) {
-               CHECK_FREESPACE(end - p, SIM_MAC_SIZE);
+               CHECK_FREESPACE(end - p, AKA_SIM_MAC_SIZE);
 
-               *p++ = FR_SIM_MAC;
-               *p++ = (SIM_MAC_SIZE >> 2);
+               *p++ = FR_MAC;
+               *p++ = (AKA_SIM_MAC_SIZE >> 2);
                *p++ = 0x00;
                *p++ = 0x00;
                hmac = p;
@@ -1041,7 +1040,7 @@ ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
         */
        (void)fr_cursor_head(&cursor);
        while ((vp = fr_cursor_current(&cursor))) {
-               slen = fr_sim_encode_pair(p, end - p, &cursor, packet_ctx);
+               slen = fr_aka_sim_encode_pair(p, end - p, &cursor, packet_ctx);
                if (slen < 0) {
                error:
                        talloc_free(buff);
@@ -1058,12 +1057,12 @@ ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
         *      Calculate a SHA1-HMAC over the complete EAP packet
         */
        if (do_hmac) {
-               slen = fr_sim_crypto_sign_packet(hmac, eap_packet, false,
+               slen = fr_aka_sim_crypto_sign_packet(hmac, eap_packet, false,
                                                 packet_ctx->hmac_md,
                                                 packet_ctx->keys->k_aut, packet_ctx->keys->k_aut_len,
                                                 packet_ctx->hmac_extra, packet_ctx->hmac_extra_len);
                if (slen < 0) goto error;
-               FR_PROTO_HEX_DUMP(hmac - 4, SIM_MAC_SIZE, "hmac attribute");
+               FR_PROTO_HEX_DUMP(hmac - 4, AKA_SIM_MAC_SIZE, "hmac attribute");
        }
        FR_PROTO_HEX_DUMP(buff, eap_packet->type.length, "sim packet");
 
@@ -1085,24 +1084,24 @@ ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
 /*
  *     Test ctx data
  */
-static int _test_ctx_free(UNUSED fr_sim_encode_ctx_t *ctx)
+static int _test_ctx_free(UNUSED fr_aka_sim_encode_ctx_t *ctx)
 {
-       fr_sim_free();
+       fr_aka_sim_free();
 
        return 0;
 }
 
-static fr_sim_encode_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
+static fr_aka_sim_encode_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
 {
-       fr_sim_encode_ctx_t     *test_ctx;
-       fr_sim_keys_t           *keys;
+       fr_aka_sim_encode_ctx_t *test_ctx;
+       fr_aka_sim_keys_t               *keys;
 
-       test_ctx = talloc_zero(ctx, fr_sim_encode_ctx_t);
-       test_ctx->keys = keys = talloc_zero(test_ctx, fr_sim_keys_t);
+       test_ctx = talloc_zero(ctx, fr_aka_sim_encode_ctx_t);
+       test_ctx->keys = keys = talloc_zero(test_ctx, fr_aka_sim_keys_t);
        memcpy(keys->k_encr, k_encr, k_encr_len);
        talloc_set_destructor(test_ctx, _test_ctx_free);
 
-       if (fr_sim_init() < 0) return NULL;
+       if (fr_aka_sim_init() < 0) return NULL;
 
        return test_ctx;
 }
@@ -1112,14 +1111,14 @@ static fr_sim_encode_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr
  */
 static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx)
 {
-       fr_sim_encode_ctx_t     *test_ctx;
+       fr_aka_sim_encode_ctx_t *test_ctx;
        static uint8_t          k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
                                             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
 
        test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
        if (!test_ctx) return -1;
 
-       test_ctx->root = fr_dict_root(dict_eap_sim);
+       test_ctx->root = fr_dict_root(dict_eap_aka_sim);
        test_ctx->iv_included = true;   /* Ensures IV is all zeros */
 
        *out = test_ctx;
@@ -1129,14 +1128,14 @@ static int encode_test_ctx_sim(void **out, TALLOC_CTX *ctx)
 
 static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx)
 {
-       fr_sim_encode_ctx_t     *test_ctx;
+       fr_aka_sim_encode_ctx_t *test_ctx;
        static uint8_t          k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
                                             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
 
        test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
        if (!test_ctx) return -1;
 
-       test_ctx->root = fr_dict_root(dict_eap_aka);
+       test_ctx->root = fr_dict_root(dict_eap_aka_sim);
        test_ctx->iv_included = true;   /* Ensures IV is all zeros */
 
        *out = test_ctx;
@@ -1146,14 +1145,14 @@ static int encode_test_ctx_aka(void **out, TALLOC_CTX *ctx)
 
 static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx)
 {
-       fr_sim_encode_ctx_t     *test_ctx;
+       fr_aka_sim_encode_ctx_t *test_ctx;
        static uint8_t          k_encr[] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a,
                                             0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 };
 
        test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
        if (!test_ctx) return -1;
 
-       test_ctx->root = fr_dict_root(dict_eap_sim);
+       test_ctx->root = fr_dict_root(dict_eap_aka_sim);
 
        *out = test_ctx;
 
@@ -1166,17 +1165,17 @@ static int encode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx)
 extern fr_test_point_pair_encode_t sim_tp_encode;
 fr_test_point_pair_encode_t sim_tp_encode = {
        .test_ctx       = encode_test_ctx_sim,
-       .func           = fr_sim_encode_pair
+       .func           = fr_aka_sim_encode_pair
 };
 
 extern fr_test_point_pair_encode_t aka_tp_encode;
 fr_test_point_pair_encode_t aka_tp_encode = {
        .test_ctx       = encode_test_ctx_aka,
-       .func           = fr_sim_encode_pair
+       .func           = fr_aka_sim_encode_pair
 };
 
 extern fr_test_point_pair_encode_t sim_tp_encode_rfc4186;
 fr_test_point_pair_encode_t sim_tp_encode_rfc4186 = {
        .test_ctx       = encode_test_ctx_sim_rfc4186,
-       .func           = fr_sim_encode_pair
+       .func           = fr_aka_sim_encode_pair
 };
similarity index 97%
rename from src/lib/sim/fips186prf.c
rename to src/lib/eap_aka_sim/fips186prf.c
index c6f919b8ed1d42f0e77441a3056e5842dcbceedc..173bc461410eeb084080142ac6fa3f66d523a0a9 100644 (file)
@@ -35,7 +35,7 @@
 
 /**
  * $Id$
- * @file src/lib/sim/fips186prf.c
+ * @file src/lib/aka-sim/fips186prf.c
  * @brief EAP sim protocol encoders and decoders.
  *
  * The development of the EAP/SIM support was funded by Internet Foundation
@@ -44,7 +44,7 @@
  * This code was written from scratch by Michael Richardson, and is
  * dual licensed under both GPL and BSD.
  *
- * @copyright 2003 Michael Richardson (mcr@sandelman.ottawa.on.ca)
+ * @copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
  * @copyright 2003-2016 The FreeRADIUS server project
  */
 RCSID("$Id$")
@@ -88,7 +88,7 @@ static void onesixty_add_mod(onesixty *sum, onesixty *a, onesixty *b)
  * @param[in] mk       The master key we use to derive all other keying
  *                     data.
  */
-void fr_sim_fips186_2prf(uint8_t out[static 160], uint8_t mk[static 20])
+void fr_aka_sim_fips186_2prf(uint8_t out[static 160], uint8_t mk[static 20])
 {
        fr_sha1_ctx     context;
        int             j;
similarity index 67%
rename from src/lib/sim/id.c
rename to src/lib/eap_aka_sim/id.c
index 721e3c115fd44db0348fabcf8d6a450c37ec5cdc..798534f696736956ccfc95c87d053eea34a5ad60 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 /**
- * @file src/lib/sim/id.c
+ * @file src/lib/aka-sim/id.c
  * @brief EAP-SIM/EAP-AKA identity detection, creation, and decyption.
  *
  * @copyright 2017 The FreeRADIUS server project
 
 #define us(x) (uint8_t) x
 
-fr_table_num_sorted_t const sim_id_request_table[] = {
-       { "Any-Id-Req",         SIM_ANY_ID_REQ                  },
-       { "FullAuth-Id-Req",    SIM_FULLAUTH_ID_REQ             },
-       { "Permanent-Id-Req",   SIM_PERMANENT_ID_REQ            }
+fr_table_num_sorted_t const fr_aka_sim_id_request_table[] = {
+       { "Any-Id-Req",         AKA_SIM_ANY_ID_REQ              },
+       { "FullAuth-Id-Req",    AKA_SIM_FULLAUTH_ID_REQ         },
+       { "no",                 AKA_SIM_NO_ID_REQ               },      /* Used for config parsing */
+       { "none",               AKA_SIM_NO_ID_REQ               },
+       { "Permanent-Id-Req",   AKA_SIM_PERMANENT_ID_REQ        },
+       { NULL }
 };
-size_t sim_id_request_table_len = NUM_ELEMENTS(sim_id_request_table);
+size_t fr_aka_sim_id_request_table_len = NUM_ELEMENTS(fr_aka_sim_id_request_table);
 
-fr_table_num_sorted_t const sim_id_method_hint_table[] = {
-       { "AKA",                SIM_METHOD_HINT_AKA             },
-       { "AKA'",               SIM_METHOD_HINT_AKA_PRIME       },
-       { "SIM",                SIM_METHOD_HINT_SIM             }
+fr_table_num_sorted_t const fr_aka_sim_id_method_table[] = {
+       { "AKA'",               AKA_SIM_METHOD_HINT_AKA_PRIME   },
+       { "AKA",                AKA_SIM_METHOD_HINT_AKA         },
+       { "SIM",                AKA_SIM_METHOD_HINT_SIM         },
+       { NULL }
 };
-size_t sim_id_method_hint_table_len = NUM_ELEMENTS(sim_id_method_hint_table);
+size_t fr_aka_sim_id_method_table_len = NUM_ELEMENTS(fr_aka_sim_id_method_table);
 
 /** Find where the identity ends
  *
@@ -49,7 +53,7 @@ size_t sim_id_method_hint_table_len = NUM_ELEMENTS(sim_id_method_hint_table);
  * @return
  *     - How long the identity portion of the NAI is.
  */
-size_t fr_sim_id_user_len(char const *nai, size_t nai_len)
+size_t fr_aka_sim_id_user_len(char const *nai, size_t nai_len)
 {
        char const *p;
 
@@ -67,7 +71,7 @@ size_t fr_sim_id_user_len(char const *nai, size_t nai_len)
  *     - A pointer to where the domain portion of the domain starts.
  *     - NULL if there was no @ in the identity.
  */
-char const *fr_sim_domain(char const *nai, size_t nai_len)
+char const *fr_aka_sim_domain(char const *nai, size_t nai_len)
 {
        char const *p;
 
@@ -89,8 +93,8 @@ char const *fr_sim_domain(char const *nai, size_t nai_len)
  *     - number of bytes parsed.
  *     - <= 0 on error - The negative offset of where parsing failed.
  */
-ssize_t fr_sim_3gpp_root_nai_domain_mcc_mnc(uint16_t *mnc, uint16_t *mcc,
-                                           char const *domain, size_t domain_len)
+ssize_t fr_aka_sim_3gpp_root_nai_domain_mcc_mnc(uint16_t *mnc, uint16_t *mcc,
+                                               char const *domain, size_t domain_len)
 {
        char const *p = domain, *end = p + domain_len;
        char *q;
@@ -137,35 +141,35 @@ ssize_t fr_sim_3gpp_root_nai_domain_mcc_mnc(uint16_t *mnc, uint16_t *mcc,
        return p - domain;
 }
 
- /** Determine what type of ID was provided in the initial identity response
 *
 * @param[out] hint   Whether this is a hint to do EAP-SIM or EAP-AKA[']:
 *    - SIM_METHOD_HINT_AKA_PRIME     this ID was generated during an EAP-AKA' exchange
 *                                    or the supplicant hints it wants to perform EAP-AKA'.
 *    - SIM_METHOD_HINT_AKA           this ID was generated during an EAP-AKA exchange
 *                                    or the supplicant hints it wants to perform EAP-AKA.
 *    - SIM_METHOD_HINT_SIM           this IS was generated during an EAP-SIM exchange
 *                                    or the supplicant hints it wants to perform EAP-SIM.
 *    - SIM_METHOD_HINT_UNKNOWN       we don't know what type of authentication generated
 *                                    this ID or which one to start.
 * @param[out] type   What type of identity this is:
 *    - SIM_ID_TYPE_PERMANENT         if the ID is an IMSI.
 *    - SIM_ID_TYPE_PSEUDONYM         if the ID is a freeform pseudonym.
 *    - SIM_ID_TYPE_FASTAUTH          if the ID is a fastauth identity.
 *    - SIM_ID_TYPE_UNKNOWN           if we can't determine what sort of ID this is.
 * @param[in] id      the NAI string provided.
 * @param[in] id_len  the length of the NAI string.
 * @return
 *    - 0 on success.
 *    - -1 on failure.
 */
-int fr_sim_id_type(fr_sim_id_type_t *type, fr_sim_method_hint_t *hint, char const *id, size_t id_len)
+/** Determine what type of ID was provided in the initial identity response
+ *
* @param[out] hint    Whether this is a hint to do EAP-SIM or EAP-AKA[']:
*     - AKA_SIM_METHOD_HINT_AKA_PRIME         this ID was generated during an EAP-AKA' exchange
*                                             or the supplicant hints it wants to perform EAP-AKA'.
*     - AKA_SIM_METHOD_HINT_AKA               this ID was generated during an EAP-AKA exchange
*                                             or the supplicant hints it wants to perform EAP-AKA.
*     - AKA_SIM_METHOD_HINT_SIM               this IS was generated during an EAP-SIM exchange
*                                             or the supplicant hints it wants to perform EAP-SIM.
*     - AKA_SIM_METHOD_HINT_UNKNOWN           we don't know what type of authentication generated
*                                             this ID or which one to start.
* @param[out] type    What type of identity this is:
*     - AKA_SIM_ID_TYPE_PERMANENT             if the ID is an IMSI.
*     - AKA_SIM_ID_TYPE_PSEUDONYM             if the ID is a freeform pseudonym.
*     - AKA_SIM_ID_TYPE_FASTAUTH              if the ID is a fastauth identity.
*     - AKA_SIM_ID_TYPE_UNKNOWN               if we can't determine what sort of ID this is.
* @param[in] id       the NAI string provided.
* @param[in] id_len   the length of the NAI string.
+ * @return
    - 0 on success.
    - -1 on failure.
+ */
+int fr_aka_sim_id_type(fr_aka_sim_id_type_t *type, fr_aka_sim_method_hint_t *hint, char const *id, size_t id_len)
 {
        size_t i;
 
        if (id_len < 1) {
-               *hint = SIM_METHOD_HINT_UNKNOWN;
-               *type = SIM_ID_TYPE_UNKNOWN;
+               *hint = AKA_SIM_METHOD_HINT_UNKNOWN;
+               *type = AKA_SIM_ID_TYPE_UNKNOWN;
                fr_strerror_printf("ID length too short");
                return -1;
        }
@@ -176,15 +180,15 @@ int fr_sim_id_type(fr_sim_id_type_t *type, fr_sim_method_hint_t *hint, char cons
         *      entire string if no '@' found, so works with
         *      full NAI strings and Stripped-User-Name.
         */
-       id_len = fr_sim_id_user_len(id, id_len);
+       id_len = fr_aka_sim_id_user_len(id, id_len);
 
        /*
         *      Permanent ID format check
         */
        switch (id[0]) {
-       case SIM_ID_TAG_PERMANENT_SIM:
-       case SIM_ID_TAG_PERMANENT_AKA:
-       case SIM_ID_TAG_PERMANENT_AKA_PRIME:
+       case ID_TAG_SIM_PERMANENT:
+       case ID_TAG_AKA_PERMANENT:
+       case ID_TAG_AKA_PRIME_PERMANENT:
                if (id_len > 16) {
                        fr_strerror_printf("IMSI too long, expected <= 16 bytes got %zu bytes", id_len);
                        goto bad_format;
@@ -192,25 +196,27 @@ int fr_sim_id_type(fr_sim_id_type_t *type, fr_sim_method_hint_t *hint, char cons
 
                for (i = 1; i < id_len; i++) {
                        if (!isdigit(id[i])) {
-                               fr_strerror_printf("Invalid digit '%c' in IMSI \"%.*s\"", id[i], (int)id_len, id);
+                               fr_strerror_printf("Invalid digit '%pV' in IMSI \"%pV\"",
+                                                  fr_box_strvalue_len(&id[i], 1),
+                                                  fr_box_strvalue_len(id, id_len));
                                goto bad_format;
                        }
                }
 
                switch (id[0]) {
-               case SIM_ID_TAG_PERMANENT_SIM:
-                       *hint = SIM_METHOD_HINT_SIM;
-                       *type = SIM_ID_TYPE_PERMANENT;  /* All digits */
+               case ID_TAG_SIM_PERMANENT:
+                       *hint = AKA_SIM_METHOD_HINT_SIM;
+                       *type = AKA_SIM_ID_TYPE_PERMANENT;      /* All digits */
                        return 0;
 
-               case SIM_ID_TAG_PERMANENT_AKA:
-                       *hint = SIM_METHOD_HINT_AKA;
-                       *type = SIM_ID_TYPE_PERMANENT;  /* All digits */
+               case ID_TAG_AKA_PERMANENT:
+                       *hint = AKA_SIM_METHOD_HINT_AKA;
+                       *type = AKA_SIM_ID_TYPE_PERMANENT;      /* All digits */
                        return 0;
 
-               case SIM_ID_TAG_PERMANENT_AKA_PRIME:
-                       *hint = SIM_METHOD_HINT_AKA_PRIME;
-                       *type = SIM_ID_TYPE_PERMANENT;  /* All Digits */
+               case ID_TAG_AKA_PRIME_PERMANENT:
+                       *hint = AKA_SIM_METHOD_HINT_AKA_PRIME;
+                       *type = AKA_SIM_ID_TYPE_PERMANENT;      /* All Digits */
                        return 0;
 
                default:
@@ -226,63 +232,100 @@ bad_format:
         *      Pseudonym
         */
        switch (id[0]) {
-       case SIM_ID_TAG_PSEUDONYM_SIM:
-               *hint = SIM_METHOD_HINT_SIM;
-               *type = SIM_ID_TYPE_PSEUDONYM;
+       case ID_TAG_SIM_PSEUDONYM:
+               *hint = AKA_SIM_METHOD_HINT_SIM;
+               *type = AKA_SIM_ID_TYPE_PSEUDONYM;
                return 0;
 
-       case SIM_ID_TAG_PSEUDONYM_AKA:
-               *hint = SIM_METHOD_HINT_AKA;
-               *type = SIM_ID_TYPE_PSEUDONYM;
+       case ID_TAG_AKA_PSEUDONYM:
+               *hint = AKA_SIM_METHOD_HINT_AKA;
+               *type = AKA_SIM_ID_TYPE_PSEUDONYM;
                return 0;
 
-       case SIM_ID_TAG_PSEUDONYM_AKA_PRIME:
-               *hint = SIM_METHOD_HINT_AKA_PRIME;
-               *type = SIM_ID_TYPE_PSEUDONYM;
+       case ID_TAG_AKA_PRIME_PSEUDONYM:
+               *hint = AKA_SIM_METHOD_HINT_AKA_PRIME;
+               *type = AKA_SIM_ID_TYPE_PSEUDONYM;
                return 0;
 
        /*
         *      Fast reauth identity
         */
-       case SIM_ID_TAG_FASTAUTH_SIM:
-               *hint = SIM_METHOD_HINT_SIM;
-               *type = SIM_ID_TYPE_FASTAUTH;
+       case ID_TAG_SIM_FASTAUTH:
+               *hint = AKA_SIM_METHOD_HINT_SIM;
+               *type = AKA_SIM_ID_TYPE_FASTAUTH;
                return 0;
 
-       case SIM_ID_TAG_FASTAUTH_AKA:
-               *hint = SIM_METHOD_HINT_AKA;
-               *type = SIM_ID_TYPE_FASTAUTH;
+       case ID_TAG_AKA_FASTAUTH:
+               *hint = AKA_SIM_METHOD_HINT_AKA;
+               *type = AKA_SIM_ID_TYPE_FASTAUTH;
                return 0;
 
-       case SIM_ID_TAG_FASTAUTH_AKA_PRIME:
-               *hint = SIM_METHOD_HINT_AKA_PRIME;
-               *type = SIM_ID_TYPE_FASTAUTH;
+       case ID_TAG_AKA_PRIME_FASTAUTH:
+               *hint = AKA_SIM_METHOD_HINT_AKA_PRIME;
+               *type = AKA_SIM_ID_TYPE_FASTAUTH;
                return 0;
 
-       case SIM_ID_TAG_PERMANENT_SIM:
-               *hint = SIM_METHOD_HINT_UNKNOWN;
-               *type = SIM_ID_TYPE_UNKNOWN;
+       case ID_TAG_SIM_PERMANENT:
+               *hint = AKA_SIM_METHOD_HINT_UNKNOWN;
+               *type = AKA_SIM_ID_TYPE_UNKNOWN;
                fr_strerror_printf_push("Got SIM-Permanent-ID tag, but identity is not a permanent ID");
                return -1;
 
-       case SIM_ID_TAG_PERMANENT_AKA:
-               *hint = SIM_METHOD_HINT_UNKNOWN;
-               *type = SIM_ID_TYPE_UNKNOWN;
+       case ID_TAG_AKA_PERMANENT:
+               *hint = AKA_SIM_METHOD_HINT_UNKNOWN;
+               *type = AKA_SIM_ID_TYPE_UNKNOWN;
                fr_strerror_printf_push("Got AKA-Permanent-ID tag, but identity is not a permanent ID");
                return -1;
 
        default:
-               *hint = SIM_METHOD_HINT_UNKNOWN;
-               *type = SIM_ID_TYPE_UNKNOWN;
-               fr_strerror_printf_push("Unrecognised tag '%pV'", fr_box_strvalue_len(id, 1)); /* Have to box, may be \000 */
+               *hint = AKA_SIM_METHOD_HINT_UNKNOWN;
+               *type = AKA_SIM_ID_TYPE_UNKNOWN;
+               fr_strerror_printf_push("Unrecognised tag '%pV'", fr_box_strvalue_len(id, 1));
                return -1;
        }
 }
 
+static char hint_byte_matrix[AKA_SIM_METHOD_HINT_MAX][AKA_SIM_ID_TYPE_MAX] = {
+       [AKA_SIM_METHOD_HINT_SIM] = {
+               [AKA_SIM_ID_TYPE_PERMANENT]     = ID_TAG_SIM_PERMANENT,
+               [AKA_SIM_ID_TYPE_PSEUDONYM]     = ID_TAG_SIM_PSEUDONYM,
+               [AKA_SIM_ID_TYPE_FASTAUTH]      = ID_TAG_SIM_PERMANENT,
+               [AKA_SIM_ID_TYPE_UNKNOWN]       = '\0',
+       },
+       [AKA_SIM_METHOD_HINT_AKA] = {
+               [AKA_SIM_ID_TYPE_PERMANENT]     = ID_TAG_AKA_PERMANENT,
+               [AKA_SIM_ID_TYPE_PSEUDONYM]     = ID_TAG_AKA_PSEUDONYM,
+               [AKA_SIM_ID_TYPE_FASTAUTH]      = ID_TAG_AKA_PERMANENT,
+               [AKA_SIM_ID_TYPE_UNKNOWN]       = '\0',
+       },
+       [AKA_SIM_METHOD_HINT_AKA_PRIME] = {
+               [AKA_SIM_ID_TYPE_PERMANENT]     = ID_TAG_AKA_PRIME_PERMANENT,
+               [AKA_SIM_ID_TYPE_PSEUDONYM]     = ID_TAG_AKA_PRIME_PSEUDONYM,
+               [AKA_SIM_ID_TYPE_FASTAUTH]      = ID_TAG_AKA_PRIME_PERMANENT,
+               [AKA_SIM_ID_TYPE_UNKNOWN]       = '\0',
+       },
+       [AKA_SIM_METHOD_HINT_UNKNOWN] = {
+               '\0'    /* Should set for all elements */
+       }
+};
+
+/** Return the expected identity hint for a given type/method combination
+ *
+ * @param[in] type     Whether this is a permanent, pseudonym or fastauth ID
+ * @param[in] method   What EAP-Method the identity hints at.
+ * @return
+ *     - An IMSI tag byte [0-9] (ASCII)
+ *     - '\0' if either the method or type values are unknown.
+ */
+char fr_aka_sim_hint_byte(fr_aka_sim_id_type_t type, fr_aka_sim_method_hint_t method)
+{
+       return hint_byte_matrix[method][type];
+}
+
 /** Create a 3gpp pseudonym from a permanent ID
  *
  * @param[out] out     Where to write the resulting pseudonym, must be a buffer of
- *                     exactly SIM_3GPP_PSEUDONYM_LEN + 1 bytes.
+ *                     exactly AKA_SIM_3GPP_PSEUDONYM_LEN + 1 bytes.
  * @param[in] imsi     Permanent ID to derive pseudonym from.  Note: If the IMSI is less than
  *                     15 digits it will be rpadded with zeros.
  * @param[in] imsi_len Length of the IMSI. Must be between 1-15.
@@ -296,9 +339,9 @@ bad_format:
  *     - 0 on success.
  *     - -1 if any of the parameters were invalid.
  */
-int fr_sim_id_3gpp_pseudonym_encrypt(char out[SIM_3GPP_PSEUDONYM_LEN + 1],
-                                    char const *imsi, size_t imsi_len,
-                                    uint8_t tag, uint8_t key_ind, uint8_t const key[16])
+int fr_aka_sim_id_3gpp_pseudonym_encrypt(char out[AKA_SIM_3GPP_PSEUDONYM_LEN + 1],
+                                        char const *imsi, size_t imsi_len,
+                                        uint8_t tag, uint8_t key_ind, uint8_t const key[16])
 {
        uint8_t         padded[16];                             /* Random (8 bytes) + Compressed (8 bytes) */
        uint8_t         encr[16];                               /* aes_ecb(padded) */
@@ -326,7 +369,7 @@ int fr_sim_id_3gpp_pseudonym_encrypt(char out[SIM_3GPP_PSEUDONYM_LEN + 1],
         *      Technically the IMSI number is between 14-15, but this
         *      encryption scheme only works for 15 char IMSIs.
         */
-       if (unlikely(imsi_len != SIM_IMSI_MAX_LEN)) {
+       if (unlikely(imsi_len != AKA_SIM_IMSI_MAX_LEN)) {
                fr_strerror_printf("Invalid ID len, expected length of 15, got %zu", imsi_len);
                return -1;
        }
@@ -440,13 +483,13 @@ int fr_sim_id_3gpp_pseudonym_encrypt(char out[SIM_3GPP_PSEUDONYM_LEN + 1],
                *out_p++ = fr_base64_str[u_p[2] & 0x3f];                                        /* 6 low bits of p[2] */
                u_p += 3;
        }
-       if ((out_p - out) != SIM_3GPP_PSEUDONYM_LEN) {
+       if ((out_p - out) != AKA_SIM_3GPP_PSEUDONYM_LEN) {
                fr_strerror_printf("Base64 output length invalid, expected %i bytes, got %zu bytes",
-                                  SIM_3GPP_PSEUDONYM_LEN, out_p - out);
+                                  AKA_SIM_3GPP_PSEUDONYM_LEN, out_p - out);
                return -1;
        }
 
-       out[SIM_3GPP_PSEUDONYM_LEN] = '\0';
+       out[AKA_SIM_3GPP_PSEUDONYM_LEN] = '\0';
 
        return 0;
 }
@@ -457,7 +500,7 @@ int fr_sim_id_3gpp_pseudonym_encrypt(char out[SIM_3GPP_PSEUDONYM_LEN + 1],
  *
  * @return the tag associated with the pseudonym.
  */
-uint8_t fr_sim_id_3gpp_pseudonym_tag(char const encr_id[SIM_3GPP_PSEUDONYM_LEN])
+uint8_t fr_aka_sim_id_3gpp_pseudonym_tag(char const encr_id[AKA_SIM_3GPP_PSEUDONYM_LEN])
 {
        return fr_base64_sextet[us(encr_id[0])];
 }
@@ -468,7 +511,7 @@ uint8_t fr_sim_id_3gpp_pseudonym_tag(char const encr_id[SIM_3GPP_PSEUDONYM_LEN])
  *
  * @return the key index associated with the pseudonym.
  */
-uint8_t fr_sim_id_3gpp_pseudonym_key_index(char const encr_id[SIM_3GPP_PSEUDONYM_LEN])
+uint8_t fr_aka_sim_id_3gpp_pseudonym_key_index(char const encr_id[AKA_SIM_3GPP_PSEUDONYM_LEN])
 {
        return ((fr_base64_sextet[us(encr_id[1])] & 0x3c) >> 2);
 }
@@ -483,8 +526,8 @@ uint8_t fr_sim_id_3gpp_pseudonym_key_index(char const encr_id[SIM_3GPP_PSEUDONYM
  *     - 0 on success.
  *     - -1 if any of the parameters were invalid.
  */
-int fr_sim_id_3gpp_pseudonym_decrypt(char out[SIM_IMSI_MAX_LEN + 1],
-                                    char const encr_id[SIM_3GPP_PSEUDONYM_LEN], uint8_t const key[16])
+int fr_aka_sim_id_3gpp_pseudonym_decrypt(char out[AKA_SIM_IMSI_MAX_LEN + 1],
+                                    char const encr_id[AKA_SIM_3GPP_PSEUDONYM_LEN], uint8_t const key[16])
 {
        EVP_CIPHER_CTX  *evp_ctx;
 
@@ -497,14 +540,15 @@ int fr_sim_id_3gpp_pseudonym_decrypt(char out[SIM_IMSI_MAX_LEN + 1],
        uint8_t         *compressed = decr + 8;         /* Pointer into plaintext after the random component */
        size_t          decr_len;
 
-       char const      *p = encr_id, *end = p + SIM_3GPP_PSEUDONYM_LEN;
+       char const      *p = encr_id, *end = p + AKA_SIM_3GPP_PSEUDONYM_LEN;
 
        size_t          len = 0;
        int             i;
 
-       for (i = 0; i < SIM_3GPP_PSEUDONYM_LEN; i++) {
+       for (i = 0; i < AKA_SIM_3GPP_PSEUDONYM_LEN; i++) {
                if (!fr_is_base64(encr_id[i])) {
-                       fr_strerror_printf("Encrypted IMSI contains non-base64 char '%c'", encr_id[i]);
+                       fr_strerror_printf("Encrypted IMSI contains non-base64 char '%pV'",
+                                          fr_box_strvalue_len(&encr_id[i], 1));
                        return -1;
                }
        }
@@ -559,9 +603,9 @@ int fr_sim_id_3gpp_pseudonym_decrypt(char out[SIM_IMSI_MAX_LEN + 1],
         *      This should never happen, and probably means that
         *      some sort of memory corruption has occured.
         */
-       if (unlikely(decr_len > (SIM_IMSI_MAX_LEN + 1))) {
+       if (unlikely(decr_len > (AKA_SIM_IMSI_MAX_LEN + 1))) {
                fr_strerror_printf("Decrypted data len invalid.  Expected %i bytes, got %zu bytes",
-                                  (SIM_IMSI_MAX_LEN + 1), decr_len);
+                                  (AKA_SIM_IMSI_MAX_LEN + 1), decr_len);
                goto error;
        }
 
@@ -579,7 +623,7 @@ int fr_sim_id_3gpp_pseudonym_decrypt(char out[SIM_IMSI_MAX_LEN + 1],
 
        EVP_CIPHER_CTX_free(evp_ctx);
 
-       out[SIM_IMSI_MAX_LEN] = '\0';
+       out[AKA_SIM_IMSI_MAX_LEN] = '\0';
 
        return 0;
 }
@@ -600,18 +644,18 @@ void test_encrypt_decypt_key0(void)
        uint8_t         key_ind;
        char const      *log;
 
-       char            encrypted_id[SIM_3GPP_PSEUDONYM_LEN + 1];
+       char            encrypted_id[AKA_SIM_3GPP_PSEUDONYM_LEN + 1];
        char            decrypted_id[sizeof(id)];
 
-       TEST_CHECK(fr_sim_id_3gpp_pseudonym_encrypt(encrypted_id, id, sizeof(id) - 1, 6, 0, (uint8_t const *)key) == 0);
+       TEST_CHECK(fr_aka_sim_id_3gpp_pseudonym_encrypt(encrypted_id, id, sizeof(id) - 1, 6, 0, (uint8_t const *)key) == 0);
        while ((log = fr_strerror_pop())) printf("%s\n", log);
 
-       tag = fr_sim_id_3gpp_pseudonym_tag(encrypted_id);
+       tag = fr_aka_sim_id_3gpp_pseudonym_tag(encrypted_id);
        TEST_CHECK(tag == 6);
-       key_ind = fr_sim_id_3gpp_pseudonym_key_index(encrypted_id);
+       key_ind = fr_aka_sim_id_3gpp_pseudonym_key_index(encrypted_id);
        TEST_CHECK(key_ind == 0);
 
-       TEST_CHECK(fr_sim_id_3gpp_pseudonym_decrypt(decrypted_id, encrypted_id, (uint8_t const *)key) == 0);
+       TEST_CHECK(fr_aka_sim_id_3gpp_pseudonym_decrypt(decrypted_id, encrypted_id, (uint8_t const *)key) == 0);
        while ((log = fr_strerror_pop())) printf("%s\n", log);
 
        TEST_CHECK(memcmp(id, decrypted_id, 15) == 0);
@@ -625,18 +669,18 @@ void test_encrypt_decypt_key1(void)
        uint8_t         key_ind;
        char const      *log;
 
-       char            encrypted_id[SIM_3GPP_PSEUDONYM_LEN + 1];
+       char            encrypted_id[AKA_SIM_3GPP_PSEUDONYM_LEN + 1];
        char            decrypted_id[sizeof(id)];
 
-       TEST_CHECK(fr_sim_id_3gpp_pseudonym_encrypt(encrypted_id, id, sizeof(id) - 1, 11, 1, (uint8_t const *)key) == 0);
+       TEST_CHECK(fr_aka_sim_id_3gpp_pseudonym_encrypt(encrypted_id, id, sizeof(id) - 1, 11, 1, (uint8_t const *)key) == 0);
        while ((log = fr_strerror_pop())) printf("%s\n", log);
 
-       tag = fr_sim_id_3gpp_pseudonym_tag(encrypted_id);
+       tag = fr_aka_sim_id_3gpp_pseudonym_tag(encrypted_id);
        TEST_CHECK(tag == 11);
-       key_ind = fr_sim_id_3gpp_pseudonym_key_index(encrypted_id);
+       key_ind = fr_aka_sim_id_3gpp_pseudonym_key_index(encrypted_id);
        TEST_CHECK(key_ind == 1);
 
-       TEST_CHECK(fr_sim_id_3gpp_pseudonym_decrypt(decrypted_id, encrypted_id, (uint8_t const *)key) == 0);
+       TEST_CHECK(fr_aka_sim_id_3gpp_pseudonym_decrypt(decrypted_id, encrypted_id, (uint8_t const *)key) == 0);
        while ((log = fr_strerror_pop())) printf("%s\n", log);
 
        TEST_CHECK(memcmp(id, decrypted_id, 15) == 0);
@@ -668,19 +712,19 @@ void test_encrypt_decypt_key16(void)
        uint8_t         key_ind;
        char const      *log;
 
-       char            encrypted_id[SIM_3GPP_PSEUDONYM_LEN + 1];
+       char            encrypted_id[AKA_SIM_3GPP_PSEUDONYM_LEN + 1];
        char            decrypted_id[sizeof(id)];
 
-       TEST_CHECK(fr_sim_id_3gpp_pseudonym_encrypt(encrypted_id, id, sizeof(id) - 1,
-                                                   9, 15, (uint8_t const *)keys[15]) == 0);
+       TEST_CHECK(fr_aka_sim_id_3gpp_pseudonym_encrypt(encrypted_id, id, sizeof(id) - 1,
+                                                       9, 15, (uint8_t const *)keys[15]) == 0);
        while ((log = fr_strerror_pop())) printf("%s\n", log);
 
-       tag = fr_sim_id_3gpp_pseudonym_tag(encrypted_id);
+       tag = fr_aka_sim_id_3gpp_pseudonym_tag(encrypted_id);
        TEST_CHECK(tag == 9);
-       key_ind = fr_sim_id_3gpp_pseudonym_key_index(encrypted_id);
+       key_ind = fr_aka_sim_id_3gpp_pseudonym_key_index(encrypted_id);
        TEST_CHECK(key_ind == 15);
 
-       TEST_CHECK(fr_sim_id_3gpp_pseudonym_decrypt(decrypted_id, encrypted_id, (uint8_t const *)keys[key_ind]) == 0);
+       TEST_CHECK(fr_aka_sim_id_3gpp_pseudonym_decrypt(decrypted_id, encrypted_id, (uint8_t const *)keys[key_ind]) == 0);
        while ((log = fr_strerror_pop())) printf("%s\n", log);
 
        TEST_CHECK(memcmp(id, decrypted_id, 15) == 0);
diff --git a/src/lib/eap_aka_sim/id.h b/src/lib/eap_aka_sim/id.h
new file mode 100644 (file)
index 0000000..cfbe255
--- /dev/null
@@ -0,0 +1,111 @@
+#pragma once
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file src/lib/aka-sim/id.h
+ * @brief EAP-SIM/EAP-AKA identity detection, creation, and decyption.
+ *
+ * @copyright 2017 The FreeRADIUS server project
+ */
+#include <sys/types.h>
+#include <freeradius-devel/util/token.h>
+
+#define AKA_SIM_3GPP_PSEUDONYM_LEN             23      //!< Length of a base64 encoded 3gpp pseudonym.
+#define AKA_SIM_IMSI_MAX_LEN                   15      //!< Length of an IMSI number in ASCII.
+#define AKA_SIM_IMSI_MIN_LEN                   14      //!< Minimum length of an IMSI number in ASCII.
+
+/** SIM/AKA method hints
+ *
+ * Derived from processing the provided identity.
+ */
+typedef enum {
+       AKA_SIM_METHOD_HINT_UNKNOWN = 0,                //!< We don't know what method the identity hints at.
+       AKA_SIM_METHOD_HINT_SIM,                        //!< The identity hints the supplicant wants to use
+                                                       ///< EAP-SIM.
+       AKA_SIM_METHOD_HINT_AKA,                        //!< The identity hints the supplicant wants to use
+                                                       ///< EAP-AKA.
+       AKA_SIM_METHOD_HINT_AKA_PRIME,
+       AKA_SIM_METHOD_HINT_MAX
+} fr_aka_sim_method_hint_t;
+
+/** SIM/AKA identity type hints
+ *
+ * Derived from the processing the provided identity.
+ */
+typedef enum {
+       AKA_SIM_ID_TYPE_UNKNOWN = 0,                    //!< We don't know what type of identity this is.
+       AKA_SIM_ID_TYPE_PERMANENT,                      //!< This is a permanent identity (the IMSI of the SIM).
+       AKA_SIM_ID_TYPE_PSEUDONYM,                      //!< This is a custom pseudonym.
+       AKA_SIM_ID_TYPE_FASTAUTH,                       //!< This is a fastauth (session-resumption) id.
+       AKA_SIM_ID_TYPE_MAX
+} fr_aka_sim_id_type_t;
+
+typedef enum {
+       ID_TAG_SIM_PERMANENT                    = '1',  //!< IMSI, and hint that client wants to do EAP-SIM
+       ID_TAG_SIM_PSEUDONYM                    = '3',  //!< Pseudonym, continue EAP-SIM
+       ID_TAG_SIM_FASTAUTH                     = '5',  //!< Fastauth, continue EAP-SIM
+
+       ID_TAG_AKA_PERMANENT                    = '0',  //!< IMSI, and hint that client wants to do EAP-AKA
+       ID_TAG_AKA_PSEUDONYM                    = '2',  //!< Pseudonym, continue EAP-AKA
+       ID_TAG_AKA_FASTAUTH                     = '4',  //!< Fastauth, continue EAP-AKA
+
+       ID_TAG_AKA_PRIME_PERMANENT              = '6',  //!< IMSI, and hint that client wants to do EAP-AKA-Prime.
+       ID_TAG_AKA_PRIME_PSEUDONYM              = '7',  //!< Pseudonym, continue EAP-AKA-Prime
+       ID_TAG_AKA_PRIME_FASTAUTH               = '8'   //!< Fastuath, continue EAP-AKA-Prime
+} fr_aka_sim_id_tag_t;
+
+/** Identity request types
+ */
+typedef enum {
+       AKA_SIM_NO_ID_REQ = 0,                  //!< We're not requesting any ID.
+       AKA_SIM_ANY_ID_REQ,                     //!< Request IMSI, Pseudonym or Fast-reauth.
+       AKA_SIM_FULLAUTH_ID_REQ,                //!< Request IMSI or Pseudonym.
+       AKA_SIM_PERMANENT_ID_REQ,               //!< Request IMSI.
+} fr_aka_sim_id_req_type_t;
+
+extern fr_table_num_sorted_t const fr_aka_sim_id_request_table[];
+extern size_t fr_aka_sim_id_request_table_len;
+extern fr_table_num_sorted_t const fr_aka_sim_id_method_table[];
+extern size_t fr_aka_sim_id_method_table_len;
+
+#define ID_TAG_SIM_PSEUDONYM_B64               55
+#define ID_TAG_AKA_PSEUDONYM_B64               54
+#define ID_TAG_AKA_PRIME_PSEUDONYM_B64         59
+
+size_t         fr_aka_sim_id_user_len(char const *nai, size_t nai_len);
+
+char const     *fr_aka_sim_domain(char const *nai, size_t nai_len);
+
+ssize_t                fr_aka_sim_3gpp_root_nai_domain_mcc_mnc(uint16_t *mnc, uint16_t *mcc,
+                                                   char const *domain, size_t domain_len);
+
+int            fr_aka_sim_id_type(fr_aka_sim_id_type_t *type, fr_aka_sim_method_hint_t *hint,
+                                  char const *id, size_t id_len);
+
+char           fr_aka_sim_hint_byte(fr_aka_sim_id_type_t type, fr_aka_sim_method_hint_t method);
+
+int            fr_aka_sim_id_3gpp_pseudonym_encrypt(char out[AKA_SIM_3GPP_PSEUDONYM_LEN + 1],
+                                                    char const *imsi, size_t imsi_len,
+                                                    uint8_t tag,  uint8_t key_ind, uint8_t const key[16]);
+
+uint8_t                fr_aka_sim_id_3gpp_pseudonym_tag(char const encr_id[AKA_SIM_3GPP_PSEUDONYM_LEN]);
+
+uint8_t                fr_aka_sim_id_3gpp_pseudonym_key_index(char const encr_id[AKA_SIM_3GPP_PSEUDONYM_LEN]);
+
+int            fr_aka_sim_id_3gpp_pseudonym_decrypt(char out[AKA_SIM_IMSI_MAX_LEN],
+                                                    char const encr_id[AKA_SIM_3GPP_PSEUDONYM_LEN],
+                                                    uint8_t const key[16]);
diff --git a/src/lib/eap_aka_sim/state_machine.c b/src/lib/eap_aka_sim/state_machine.c
new file mode 100644 (file)
index 0000000..24848f0
--- /dev/null
@@ -0,0 +1,4163 @@
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file src/lib/eap_aka_sim/state_machine.c
+ * @brief Implement a common state machine for EAP-SIM, EAP-AKA, EAP-AKA'.
+ *
+ * @author Arran Cudbard-Bell \<a.cudbardb@freeradius.org\>
+ *
+ * @copyright 2019 The FreeRADIUS server project
+ * @copyright 2019 Network RADIUS \<info@networkradius.com\>
+ */
+RCSID("$Id$")
+#include <freeradius-devel/eap/base.h>
+#include <freeradius-devel/eap/types.h>
+#include <freeradius-devel/unlang/module.h>
+
+#include "base.h"
+#include "state_machine.h"
+#include "attrs.h"
+
+#ifndef EAP_TLS_MPPE_KEY_LEN
+#  define EAP_TLS_MPPE_KEY_LEN     32
+#endif
+
+/** A state transition function
+ *
+ * This is passed to sub-state machines that perform other actions, before
+ * fully transitioning to a new state.
+ *
+ * Examples of these are the sub-state machines that deal with clearing
+ * pseudonyms and reauthentication data.
+ */
+typedef rlm_rcode_t(*aka_sim_state_enter_t)(eap_aka_sim_common_conf_t *inst,
+                                           REQUEST *request, eap_session_t *eap_session);
+
+static rlm_rcode_t common_eap_failure(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t common_failure_notification(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t common_eap_success(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t common_success_notification(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t common_reauthentication(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t aka_challenge(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t sim_challenge(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t aka_identity(void *instance, void *thread, REQUEST *request);
+static rlm_rcode_t sim_start(void *instance, void *thread, REQUEST *request);
+
+static rlm_rcode_t common_failure_notification_enter(eap_aka_sim_common_conf_t *inst,
+                                                    REQUEST *request, eap_session_t *eap_session);
+static rlm_rcode_t aka_challenge_enter(eap_aka_sim_common_conf_t *inst,
+                                      REQUEST *request, eap_session_t *eap_session);
+static rlm_rcode_t sim_challenge_enter(eap_aka_sim_common_conf_t *inst,
+                                      REQUEST *request, eap_session_t *eap_session);
+static rlm_rcode_t common_challenge_enter(eap_aka_sim_common_conf_t *inst,
+                                         REQUEST *request, eap_session_t *eap_session);
+static rlm_rcode_t aka_identity_enter(eap_aka_sim_common_conf_t *inst, REQUEST *request, eap_session_t *eap_session);
+static rlm_rcode_t sim_start_enter(eap_aka_sim_common_conf_t *inst, REQUEST *request, eap_session_t *eap_session);
+static rlm_rcode_t common_identity_enter(eap_aka_sim_common_conf_t *inst,
+                                        REQUEST *request, eap_session_t *eap_session);
+
+static module_state_func_table_t const aka_sim_stable_table[] = {
+       { "FAILURE-NOTIFICATION",       common_failure_notification     },
+       { "EAP-FAILURE",                common_eap_failure              },
+       { "SUCCESS-NOTIFICATION",       common_success_notification     },
+       { "EAP-SUCCESS",                common_eap_success              },
+       { "REAUTHENTICATION",           common_reauthentication         },
+       { "AKA-CHALLENGE",              aka_challenge                   },
+       { "SIM-CHALLENGE",              sim_challenge                   },
+       { "IDENTITY",                   aka_identity                    },
+       { "SIM-START",                  sim_start                       },
+       { "EAP-IDENTITY",               aka_sim_state_machine_start     },
+
+       { NULL }
+};
+
+/** Cancel a call to a submodule
+ *
+ * @param[in] instance UNUSED.
+ * @param[in] thread   UNUSED.
+ * @param[in] request  The current request.
+ * @param[in] rctx     the eap_session_t
+ * @param[in] action   to perform.
+ */
+static void mod_signal(UNUSED void *instance, UNUSED void *thread, REQUEST *request, UNUSED void *rctx,
+                      fr_state_signal_t action)
+{
+       eap_session_t   *eap_session = eap_session_get(request->parent);
+
+       if (action != FR_SIGNAL_CANCEL) return;
+
+       RDEBUG2("Request cancelled - Destroying session");
+
+       TALLOC_FREE(eap_session->opaque);
+}
+
+/** Warn the user that the rcode they provided is being ignored in this section
+ *
+ */
+static inline void section_rcode_ignored(REQUEST *request)
+{
+       switch (request->rcode) {
+       case RLM_MODULE_USER_SECTION_REJECT:
+               RWDEBUG("Ignoring rcode (%s)",
+                       fr_table_str_by_value(mod_rcode_table, request->rcode, "<invalid>"));
+               break;
+
+       default:
+               break;
+       }
+}
+
+/** Trigger a state transition to FAILURE-NOTIFICATION if the section returned a failure code
+ *
+ */
+#define section_rcode_process(_inst, _request, _eap_session, _eap_aka_sim_session) \
+{ \
+       if (after_authentication(_eap_aka_sim_session)) { \
+               switch ((_request)->rcode) { \
+               case RLM_MODULE_REJECT:  \
+               case RLM_MODULE_USERLOCK: \
+                       eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED; \
+                       return common_failure_notification_enter(_inst, _request, _eap_session); \
+               case RLM_MODULE_NOTFOUND: \
+                       eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED; \
+                       return common_failure_notification_enter(_inst, _request, _eap_session); \
+               case RLM_MODULE_INVALID: \
+               case RLM_MODULE_FAIL: \
+                       eap_aka_sim_session->failure_type = FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION;\
+                       return common_failure_notification_enter(_inst, _request, _eap_session); \
+               default: \
+                       break; \
+               } \
+       } else { \
+               switch ((_request)->rcode) { \
+               case RLM_MODULE_USER_SECTION_REJECT: \
+                       REDEBUG("Section rcode (%s) indicates we should reject the user", \
+                               fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>")); \
+                       return common_failure_notification_enter(_inst, _request, _eap_session); \
+               default: \
+                       break; \
+               } \
+       } \
+}
+
+/** Sync up what identity we're requesting with attributes in the reply
+ *
+ */
+static bool identity_req_set_by_user(REQUEST *request, eap_aka_sim_session_t *eap_aka_sim_session)
+{
+       VALUE_PAIR      *vp;
+       fr_cursor_t     cursor;
+       bool            set_by_user = false;
+
+       /*
+        *      Check if the user included any of the
+        *      ID req attributes.  If they did, use
+        *      them to inform what we do next, and
+        *      then delete them so they don't screw
+        *      up any of the other code.
+        */
+       for (vp = fr_cursor_init(&cursor, &request->reply->vps);
+            vp;
+            vp = fr_cursor_next(&cursor)) {
+               if (vp->da == attr_eap_aka_sim_permanent_id_req) {
+                       eap_aka_sim_session->id_req = AKA_SIM_PERMANENT_ID_REQ;
+               found:
+                       set_by_user = true;
+                       RDEBUG2("Previous section added &reply:%pP, will request additional identity", vp);
+                       fr_cursor_free_item(&cursor);
+               }
+               else if (vp->da == attr_eap_aka_sim_fullauth_id_req) {
+                       eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
+                       goto found;
+               }
+               else if (vp->da == attr_eap_aka_sim_any_id_req) {
+                       eap_aka_sim_session->id_req = AKA_SIM_ANY_ID_REQ;
+                       goto found;
+               }
+       }
+
+       return set_by_user;
+}
+
+/** Based on the hint byte in the identity, add &Identity-Type and &Method-Hint attributes
+ *
+ */
+static void identity_hint_pairs_add(fr_aka_sim_id_type_t *type_p, fr_aka_sim_method_hint_t *method_p,
+                                   REQUEST *request, char const *identity)
+{
+       fr_aka_sim_id_type_t            type;
+       fr_aka_sim_method_hint_t        method;
+
+       /*
+        *      Process the identity that we received.
+        */
+       if (fr_aka_sim_id_type(&type, &method,
+                          identity, talloc_array_length(identity) - 1) < 0) {
+               RPWDEBUG2("Failed parsing identity, continuing anyway");
+       }
+
+       /*
+        *      Map the output from the generic ID parser
+        *      function to specific EAP-AKA internal
+        *      attributes in the subrequest.
+        */
+       if (type != AKA_SIM_ID_TYPE_UNKNOWN) {
+               VALUE_PAIR *vp = NULL;
+
+               MEM(pair_update_request(&vp, attr_eap_aka_sim_identity_type) >= 0);
+               switch (type) {
+               case AKA_SIM_ID_TYPE_PERMANENT:
+                       vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PERMANENT;
+                       break;
+
+               case AKA_SIM_ID_TYPE_PSEUDONYM:
+                       vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_PSEUDONYM;
+                       break;
+
+               case AKA_SIM_ID_TYPE_FASTAUTH:
+                       vp->vp_uint32 = FR_IDENTITY_TYPE_VALUE_FASTAUTH;
+                       break;
+
+               default:
+                       rad_assert(0);
+               }
+       }
+
+       /*
+        *      Map the output from the generic ID parser
+        *      function to specific EAP-AKA internal
+        *      attributes in the subrequest.
+        */
+       if (method != AKA_SIM_METHOD_HINT_UNKNOWN) {
+               VALUE_PAIR *vp = NULL;
+
+               MEM(pair_update_request(&vp, attr_eap_aka_sim_method_hint) >= 0);
+               switch (method) {
+               case AKA_SIM_METHOD_HINT_AKA_PRIME:
+                       vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA_PRIME;
+                       break;
+
+               case AKA_SIM_METHOD_HINT_AKA:
+                       vp->vp_uint32 = FR_METHOD_HINT_VALUE_AKA;
+                       break;
+
+               case AKA_SIM_METHOD_HINT_SIM:
+                       vp->vp_uint32 = FR_METHOD_HINT_VALUE_SIM;
+                       break;
+
+               default:
+                       rad_assert(0);
+               }
+       }
+
+       if (type_p) *type_p = type;
+       if (method_p) *method_p = method;
+}
+
+/** Print out the error the client returned
+ *
+ */
+static inline void client_error_debug(REQUEST *request, VALUE_PAIR *from_peer)
+{
+       VALUE_PAIR *vp;
+
+       vp = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_client_error_code, TAG_ANY);
+       if (!vp) {
+               REDEBUG("Peer has not supplied a AT_ERROR_CODE");
+       } else {
+               REDEBUG("Peer rejected request with error: %i (%pV)", vp->vp_uint16, &vp->data);
+       }
+}
+
+/** Add an Identity Request attribute to the reply
+ *
+ * Verify the progression of identity requests is valid.
+ *
+ * @param[in] request                  The current request.
+ * @param[in] eap_aka_sim_session      The current eap_aka_sim_session.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure (progression of identities was not valid).
+ */
+static int identity_req_pairs_add(REQUEST *request, eap_aka_sim_session_t *eap_aka_sim_session)
+{
+       VALUE_PAIR *vp;
+
+       switch (eap_aka_sim_session->id_req) {
+       case AKA_SIM_ANY_ID_REQ:
+               if (eap_aka_sim_session->last_id_req != AKA_SIM_NO_ID_REQ) {
+               id_out_of_order:
+                       REDEBUG("Cannot send %s, already sent %s",
+                               fr_table_str_by_value(fr_aka_sim_id_request_table, eap_aka_sim_session->id_req, "<INVALID>"),
+                               fr_table_str_by_value(fr_aka_sim_id_request_table, eap_aka_sim_session->last_id_req, "<INVALID>"));
+                       return -1;
+               }
+               MEM(pair_add_reply(&vp, attr_eap_aka_sim_any_id_req) >= 0);
+               vp->vp_bool = true;
+               break;
+
+       case AKA_SIM_FULLAUTH_ID_REQ:
+               switch (eap_aka_sim_session->last_id_req) {
+               case AKA_SIM_NO_ID_REQ:         /* Not sent anything before */
+               case AKA_SIM_ANY_ID_REQ:        /* Last request was for any ID, but the re-auth ID was bad */
+                       break;
+
+               default:
+                       goto id_out_of_order;
+               }
+               MEM(pair_add_reply(&vp, attr_eap_aka_sim_fullauth_id_req) >= 0);
+               vp->vp_bool = true;
+               break;
+
+       case AKA_SIM_PERMANENT_ID_REQ:
+               switch (eap_aka_sim_session->last_id_req) {
+               case AKA_SIM_NO_ID_REQ:         /* Not sent anything before */
+               case AKA_SIM_ANY_ID_REQ:        /* Last request was for any ID, but the re-auth ID was bad */
+               case AKA_SIM_FULLAUTH_ID_REQ:   /* ...didn't understand the pseudonym either */
+                       break;
+
+               default:
+                       goto id_out_of_order;
+               }
+               MEM(pair_add_reply(&vp, attr_eap_aka_sim_permanent_id_req) >= 0);
+               vp->vp_bool = true;
+               break;
+
+       default:
+               rad_assert(0);
+       }
+
+       return 0;
+}
+
+/** Copy the incoming identity to the permanent identity attribute
+ *
+ * If the incoming ID really looks like a permanent ID, and we were
+ * told it was a permanent ID, then (optionally) trim the first byte
+ * to form the real permanent ID.
+ *
+ * Otherwise copy the entire incoming Identity to the
+ * &session-state:Permanent-Identity attribute.
+ *
+ * @param[in] request          The current request.
+ * @param[in] in               current identity.
+ * @param[in] eap_type         The current eap_type.
+ * @param[in] strip_hint       Whether to strip the hint byte off the permanent identity
+ */
+static int identity_to_permanent_identity(REQUEST *request, VALUE_PAIR *in, eap_type_t eap_type, bool strip_hint)
+{
+       fr_aka_sim_id_type_t            our_type;
+       fr_aka_sim_method_hint_t        our_method, expected_method;
+       VALUE_PAIR                      *vp;
+
+       if (in->vp_length == 0) {
+               RDEBUG2("Not processing zero length identity");
+               return -1;
+       }
+
+       /*
+        *      Not requested to strip hint, don't do anything
+        *      fancy, just copy Identity -> Permanent-Identity.
+        */
+       if (!strip_hint) {
+               MEM(fr_pair_update_by_da(request->state_ctx, &vp,
+                                        &request->state, attr_eap_aka_sim_permanent_identity) >= 0);
+               fr_pair_value_bstrncpy(vp, in->vp_strvalue, in->vp_length);
+               return 0;
+       }
+
+       switch (eap_type) {
+       case FR_EAP_METHOD_SIM:
+               expected_method = AKA_SIM_METHOD_HINT_SIM;
+               break;
+
+       case FR_EAP_METHOD_AKA:
+               expected_method = AKA_SIM_METHOD_HINT_AKA;
+               break;
+
+       case FR_EAP_METHOD_AKA_PRIME:
+               expected_method = AKA_SIM_METHOD_HINT_AKA_PRIME;
+               break;
+
+       default:
+               return -1;
+       }
+
+       /*
+        *      First, lets see if this looks like an identity
+        *      we can process.
+        *
+        *      For now we allow all permanent identities no
+        *      matter what EAP method.
+        *
+        *      This is because we could be starting a different
+        *      EAP method to the one the identity hinted,
+        *      but we still want to strip the first byte.
+        */
+       if ((fr_aka_sim_id_type(&our_type, &our_method, in->vp_strvalue, in->vp_length) < 0) ||
+           (our_type != AKA_SIM_ID_TYPE_PERMANENT)) {
+               MEM(fr_pair_update_by_da(request->state_ctx, &vp,
+                                        &request->state, attr_eap_aka_sim_permanent_identity) >= 0);
+               fr_pair_value_bstrncpy(vp, in->vp_strvalue, in->vp_length);
+
+               RDEBUG2("%s has incorrect hint byte, expected '%c', got '%c'.  "
+                       "'hint' byte not stripped",
+                       attr_eap_aka_sim_permanent_identity->name,
+                       fr_aka_sim_hint_byte(AKA_SIM_ID_TYPE_PERMANENT, expected_method),
+                       fr_aka_sim_hint_byte(our_type, our_method));
+               RINDENT();
+               RDEBUG2("&session-state:%pP", vp);
+               REXDENT();
+       } else {
+               /*
+                *      To get here the identity must be >= 1 and must have
+                *      had the expected hint byte.
+                *
+                *      Strip off the hint byte, and then add the permanent
+                *      identity to the output list.
+                */
+               MEM(fr_pair_update_by_da(request->state_ctx, &vp,
+                                        &request->state, attr_eap_aka_sim_permanent_identity) >= 0);
+               fr_pair_value_bstrncpy(vp, in->vp_strvalue + 1, in->vp_length - 1);
+
+               RDEBUG2("Stripping 'hint' byte from %s", attr_eap_aka_sim_permanent_identity->name);
+               RINDENT();
+               RDEBUG2("&session-state:%pP", vp);
+               REXDENT();
+       }
+
+       return 0;
+}
+
+/** Set the crypto identity from a received identity
+ *
+ */
+static void identity_to_crypto_identity(REQUEST *request, eap_aka_sim_session_t *eap_aka_sim_session,
+                                       uint8_t const *identity, size_t len)
+{
+       RDEBUG3("Setting cryptographic identity to \"%pV\"", fr_box_strvalue_len((char const *)identity, len));
+
+       talloc_free(eap_aka_sim_session->keys.identity);
+       eap_aka_sim_session->keys.identity_len = len;
+       MEM(eap_aka_sim_session->keys.identity = talloc_memdup(eap_aka_sim_session, identity, len));
+}
+
+/** Determine if we're after authentication
+ *
+ */
+static inline bool after_authentication(eap_aka_sim_session_t *eap_aka_sim_session)
+{
+       return eap_aka_sim_session->challenge_success || eap_aka_sim_session->reauthentication_success;
+}
+
+/** Resume after 'store session { ... }'
+ *
+ */
+static rlm_rcode_t session_store_resume(void *instance, UNUSED void *thread, REQUEST *request, void *rctx)
+{
+       aka_sim_state_enter_t   state_enter = (aka_sim_state_enter_t)rctx;
+
+       switch (request->rcode) {
+       /*
+        *      Store failed.  Don't send fastauth id
+        */
+       case RLM_MODULE_USER_SECTION_REJECT:
+               pair_delete_reply(attr_eap_aka_sim_next_reauth_id);
+               break;
+
+       default:
+               break;
+       }
+
+       pair_delete_request(attr_eap_aka_sim_next_reauth_id);
+
+       return state_enter(instance, request, eap_session_get(request->parent));
+}
+
+/** Resume after 'store pseudonym { ... }'
+ *
+ */
+static rlm_rcode_t pseudonym_store_resume(void *instance, UNUSED void *thread, REQUEST *request, void *rctx)
+{
+       eap_aka_sim_common_conf_t *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       aka_sim_state_enter_t   state_enter = (aka_sim_state_enter_t)rctx;
+       VALUE_PAIR              *vp;
+       VALUE_PAIR              *new;
+
+       switch (request->rcode) {
+       /*
+        *      Store failed.  Don't send pseudonym
+        */
+       case RLM_MODULE_USER_SECTION_REJECT:
+               pair_delete_reply(attr_eap_aka_sim_next_pseudonym);
+               break;
+
+       default:
+               break;
+       }
+
+       request->rcode = RLM_MODULE_NOOP;       /* Needed because we may call resume functions directly */
+
+       pair_delete_request(attr_eap_aka_sim_next_pseudonym);
+
+       vp = fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_next_reauth_id, TAG_ANY);
+       if (vp) {
+               /*
+                *      Generate a random fastauth string
+                */
+               if (vp->vp_length == 0) {
+                       char *identity;
+
+                       if (!inst->ephemeral_id_length) {
+                               RWDEBUG("Found empty Next-Reauth-Id, and told not to generate one.  "
+                                       "Skipping store session { ... } section");
+
+                               goto done;
+                       }
+
+                       MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
+                       switch (eap_aka_sim_session->type) {
+                       case FR_EAP_METHOD_SIM:
+                               identity[0] = (char)ID_TAG_SIM_FASTAUTH;
+                               break;
+
+                       case FR_EAP_METHOD_AKA:
+                               identity[0] = (char)ID_TAG_AKA_FASTAUTH;
+                               break;
+
+                       case FR_EAP_METHOD_AKA_PRIME:
+                               identity[0] = (char)ID_TAG_AKA_PRIME_FASTAUTH;
+                               break;
+
+                       default:
+                               break;
+                       }
+                       fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
+                       identity[talloc_array_length(identity) - 1] = '\0';
+
+                       fr_value_box_strdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
+               }
+               pair_update_request(&new, attr_session_id);
+               fr_pair_value_memcpy(new, (uint8_t const *)vp->vp_strvalue, vp->vp_length, vp->vp_tainted);
+
+               MEM(eap_aka_sim_session->fastauth_sent = talloc_bstrndup(eap_aka_sim_session,
+                                                                        vp->vp_strvalue, vp->vp_length));
+
+               switch (eap_aka_sim_session->type) {
+               /*
+                *      AKA and SIM use the original MK for session resumption.
+                */
+               case FR_EAP_METHOD_SIM:
+               case FR_EAP_METHOD_AKA:
+                       MEM(pair_update_session_state(&vp, attr_session_data) >= 0);
+                       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.mk,
+                                            sizeof(eap_aka_sim_session->keys.mk), false);
+                       break;
+               /*
+                *      AKA' KDF 1 generates an additional key k_re
+                *      which is used for reauthentication instead
+                *      of the MK.
+                */
+               case FR_EAP_METHOD_AKA_PRIME:
+                       MEM(pair_update_session_state(&vp, attr_session_data) >= 0);
+                       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.k_re,
+                                            sizeof(eap_aka_sim_session->keys.k_re), false);
+                       break;
+
+               default:
+                       rad_assert(0);
+                       break;
+               }
+
+               /*
+                *      If the counter already exists in session
+                *      state increment by 1, otherwise, add the
+                *      attribute and set to zero.
+                */
+               vp = fr_pair_find_by_da(request->state, attr_eap_aka_sim_counter, TAG_ANY);
+               if (vp) {
+                       vp->vp_uint16++;
+               /*
+                *      Will get incremented by 1 in
+                *      reauthentication_send, so when
+                *      used, it'll be 1 (as per the standard).
+                */
+               } else {
+                       MEM(pair_add_session_state(&vp, attr_eap_aka_sim_counter) >= 0);
+                       vp->vp_uint16 = 0;
+               }
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.store_session,
+                                                     RLM_MODULE_NOOP,
+                                                     session_store_resume,
+                                                     mod_signal,
+                                                     rctx);
+       }
+
+done:
+       return state_enter(inst, request, eap_session_get(request->parent));
+}
+
+/** Implements a set of states for storing pseudonym and fastauth identities
+ *
+ * At the end of challenge or reauthentication rounds, the user may have specified
+ * a pseudonym and fastauth identity to return to the supplicant.
+ *
+ * Call the appropriate sections to persist those values.
+ *
+ * @param[in] inst             of rlm_eap_aka.
+ * @param[in] request          the current request.
+ * @param[in] state_enter      state entry function for the
+ *                             state to transition to *after* the current
+ *                             state.
+ * @return RLM_MODULE_HANDLED.
+ */
+static rlm_rcode_t session_and_pseudonym_store(eap_aka_sim_common_conf_t *inst,
+                                              REQUEST *request, eap_session_t *eap_session,
+                                              aka_sim_state_enter_t state_enter)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       VALUE_PAIR              *vp;
+       VALUE_PAIR              *new;
+
+       request->rcode = RLM_MODULE_NOOP;       /* Needed because we may call resume functions directly */
+
+       vp = fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_next_pseudonym, TAG_ANY);
+       if (vp) {
+               /*
+                *      Generate a random pseudonym string
+                */
+               if (vp->vp_length == 0) {
+                       char *identity;
+
+                       if (!inst->ephemeral_id_length) {
+                               RWDEBUG("Found empty Pseudonym-Id, and told not to generate one.  "
+                                       "Skipping store pseudonym { ... } section");
+
+                               return pseudonym_store_resume(inst,
+                                                             module_thread_by_data(inst),
+                                                             request, (void *)state_enter);
+                       }
+
+                       MEM(identity = talloc_array(vp, char, inst->ephemeral_id_length + 2));
+                       fr_rand_str((uint8_t *)identity + 1, inst->ephemeral_id_length, 'a');
+                       switch (eap_aka_sim_session->type) {
+                       case FR_EAP_METHOD_SIM:
+                               identity[0] = (char)ID_TAG_SIM_PSEUDONYM;
+                               break;
+
+                       case FR_EAP_METHOD_AKA:
+                               identity[0] = (char)ID_TAG_AKA_PSEUDONYM;
+                               break;
+
+                       case FR_EAP_METHOD_AKA_PRIME:
+                               identity[0] = (char)ID_TAG_AKA_PRIME_PSEUDONYM;
+                               break;
+
+                       default:
+                               break;
+                       }
+                       identity[talloc_array_length(identity) - 1] = '\0';
+                       fr_value_box_strdup_buffer_shallow(NULL, &vp->data, NULL, identity, false);
+               }
+               pair_update_request(&new, attr_eap_aka_sim_next_pseudonym);
+               fr_pair_value_copy(new, vp);
+
+               MEM(eap_aka_sim_session->pseudonym_sent = talloc_bstrndup(eap_aka_sim_session,
+                                                                         vp->vp_strvalue, vp->vp_length));
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.store_pseudonym,
+                                                     RLM_MODULE_NOOP,
+                                                     pseudonym_store_resume,
+                                                     mod_signal,
+                                                     (void *)state_enter);
+       }
+
+       return pseudonym_store_resume(inst, module_thread_by_data(inst), request, (void *)state_enter);
+}
+
+/** Resume after 'clear session { ... }'
+ *
+ */
+static rlm_rcode_t session_clear_resume(void *instance, UNUSED void *thread, REQUEST *request, void *rctx)
+{
+       aka_sim_state_enter_t   state_enter = (aka_sim_state_enter_t)rctx;
+
+       pair_delete_request(attr_session_id);
+
+       return state_enter(instance, request, eap_session_get(request->parent));
+}
+
+/** Resume after 'clear pseudonym { ... }'
+ *
+ */
+static rlm_rcode_t pseudonym_clear_resume(void *instance, UNUSED void *thread, REQUEST *request, void *rctx)
+{
+       eap_aka_sim_common_conf_t *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       aka_sim_state_enter_t   state_enter = (aka_sim_state_enter_t)rctx;
+
+       pair_delete_request(attr_eap_aka_sim_next_pseudonym);
+
+       /*
+        *      Clear session
+        */
+       if (eap_aka_sim_session->fastauth_sent) {
+               VALUE_PAIR *vp;
+
+               pair_delete_request(attr_session_id);
+
+               MEM(pair_update_request(&vp, attr_session_id) >= 0);
+               fr_value_box_memcpy(vp, &vp->data, NULL,
+                                   (uint8_t *)eap_aka_sim_session->fastauth_sent,
+                                   talloc_array_length(eap_aka_sim_session->fastauth_sent) - 1, true);
+               TALLOC_FREE(eap_aka_sim_session->fastauth_sent);
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.clear_session,
+                                                     RLM_MODULE_NOOP,
+                                                     session_clear_resume,
+                                                     mod_signal,
+                                                     rctx);
+       }
+
+       return state_enter(inst, request, eap_session_get(request->parent));
+}
+
+/** Implements a set of states for clearing out pseudonym and fastauth identities
+ *
+ * If either a Challenge round or Reauthentication round fail, we need to clear
+ * any identities that were provided during those rounds, as the supplicant
+ * will have discarded them.
+ *
+ * @param[in] inst             of rlm_eap_aka.
+ * @param[in] request          the current request.
+ * @param[in] state_enter      state entry function for the
+ *                             state to transition to *after* the current
+ *                             state.
+ * @return RLM_MODULE_HANDLED.
+ */
+static rlm_rcode_t session_and_pseudonym_clear(eap_aka_sim_common_conf_t *inst,
+                                              REQUEST *request, eap_session_t *eap_session,
+                                              aka_sim_state_enter_t state_enter)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       /*
+        *      Clear out pseudonyms
+        */
+       if (eap_aka_sim_session->pseudonym_sent) {
+               VALUE_PAIR *vp;
+
+               MEM(pair_update_request(&vp, attr_eap_aka_sim_next_pseudonym) >= 0);
+               fr_value_box_strdup_buffer(vp, &vp->data, NULL, eap_aka_sim_session->pseudonym_sent, true);
+               TALLOC_FREE(eap_aka_sim_session->pseudonym_sent);
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.clear_pseudonym,
+                                                     RLM_MODULE_NOOP,
+                                                     session_clear_resume,
+                                                     mod_signal,
+                                                     (void *)state_enter);
+       }
+
+       return pseudonym_clear_resume(inst, module_thread_by_data(inst), request, (void *)state_enter);
+}
+
+/** Encode EAP-SIM/AKA['] attributes
+ *
+ */
+static int common_encode(REQUEST *request, eap_session_t *eap_session, uint16_t subtype,
+                        uint8_t const *hmac_extra, size_t hmac_extra_len)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       fr_cursor_t             cursor;
+       fr_cursor_t             to_encode;
+       VALUE_PAIR              *head = NULL, *vp, *subtype_vp;
+       ssize_t                 ret;
+       fr_aka_sim_encode_ctx_t encoder_ctx = {
+                                       .root = fr_dict_root(dict_eap_aka_sim),
+                                       .keys = &eap_aka_sim_session->keys,
+
+                                       .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                                       .iv_included = false,
+
+                                       .hmac_md = eap_aka_sim_session->mac_md,
+                                       .eap_packet = eap_session->this_round->request,
+                                       .hmac_extra = hmac_extra,
+                                       .hmac_extra_len = hmac_extra_len
+                               };
+
+       /*
+        *      Set the subtype to identity request
+        */
+       MEM(pair_update_reply(&subtype_vp, attr_eap_aka_sim_subtype) >= 0);
+       subtype_vp->vp_uint16 = subtype;
+
+       /*
+        *      State what kind of request we're sending
+        */
+       if (RDEBUG_ENABLED2) {
+               switch (subtype) {
+               case FR_SUBTYPE_VALUE_SIM_START:
+               case FR_SUBTYPE_VALUE_AKA_IDENTITY:
+                       RDEBUG2("Sending EAP-Request/%pV (%s)", &subtype_vp->data,
+                               fr_table_str_by_value(fr_aka_sim_id_request_table, eap_aka_sim_session->id_req, "<INVALID>"));
+                       break;
+
+               default:
+                       RDEBUG2("Sending EAP-Request/%pV", &subtype_vp->data);
+                       break;
+               }
+       }
+
+       fr_cursor_init(&cursor, &request->reply->vps);
+       fr_cursor_init(&to_encode, &head);
+
+       /*
+        *      We have to be *SUPER* careful here not to reorder
+        *      attributes, because for EAP-SIM the RAND values
+        *      must be inserted into the packet in exactly the
+        *      same order as they appear in fr_sim_keys_t
+        *      otherwise the KDF will produce a different
+        *      result.
+        */
+       while ((vp = fr_cursor_current(&cursor))) {
+               if (!fr_dict_parent_common(encoder_ctx.root, vp->da, true)) {
+                       fr_cursor_next(&cursor);
+                       continue;
+               }
+               vp = fr_cursor_remove(&cursor);
+
+               /*
+                *      Silently discard encrypted attributes until
+                *      the peer should have k_encr.  These can be
+                *      added by policy, and seem to cause
+                *      wpa_supplicant to fail if sent before the challenge.
+                */
+               if (!eap_aka_sim_session->allow_encrypted &&
+                   fr_dict_parent_common(attr_eap_aka_sim_encr_data, vp->da, true)) {
+                       RWDEBUG("Silently discarding &reply:%s: Encrypted attributes not allowed in this round",
+                               vp->da->name);
+                       talloc_free(vp);
+                       continue;
+               }
+
+               fr_cursor_prepend(&to_encode, vp);
+       }
+
+
+       RDEBUG2("Encoding attributes");
+       log_request_pair_list(L_DBG_LVL_2, request, head, NULL);
+
+       eap_session->this_round->request->type.num = eap_aka_sim_session->type;
+       eap_session->this_round->request->id = eap_aka_sim_session->id++ & 0xff;
+       eap_session->this_round->set_request_id = true;
+
+       ret = fr_aka_sim_encode(request, head, &encoder_ctx);
+       fr_cursor_head(&to_encode);
+       fr_cursor_free_list(&to_encode);
+
+       if (ret < 0) {
+               RPEDEBUG("Failed encoding attributes");
+               return -1;
+       }
+       return 0;
+}
+
+/** Send a EAP-Failure message to the supplicant
+ *
+ */
+static rlm_rcode_t common_eap_failure_send(REQUEST *request, eap_session_t *eap_session)
+{
+       RDEBUG2("Sending EAP-Failure");
+
+       eap_session->this_round->request->code = FR_EAP_CODE_FAILURE;
+       eap_session->finished = true;
+
+       return RLM_MODULE_REJECT;
+}
+
+/** Send a EAP-Request/(AKA|SIM)-Notification (Failure) message to the supplicant
+ *
+ */
+static rlm_rcode_t common_failure_notification_send(eap_aka_sim_common_conf_t *inst,
+                                                   REQUEST *request, eap_session_t *eap_session)
+{
+       VALUE_PAIR              *vp, *notification_vp;
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       /*
+        *      Allow the user to specify specific failure notification
+        *      types.  We assume the user knows what they're doing and
+        *      only toggle success and phase bits.
+        *
+        *      This allows custom notification schemes to be implemented.
+        *
+        *      If this is prior to authentication, valid values are:
+        *      - FR_NOTIFICATION_VALUE_GENERAL_FAILURE
+        *
+        *      If this is after authentication, valid values are:
+        *      - FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION
+        *      - FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED - User has been
+        *        temporarily denied access to the requested service.
+        *      - FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED
+        *        User has not subscribed to the requested service.
+        */
+       notification_vp = fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_notification, TAG_ANY);
+
+       /*
+        *      Change the failure notification depending where
+        *      we are in the eap_aka_state machine.
+        */
+       if (after_authentication(eap_aka_sim_session)) {
+               if (!notification_vp) {
+                       pair_add_reply(&notification_vp, attr_eap_aka_sim_notification);
+                       notification_vp->vp_uint16 = eap_aka_sim_session->failure_type; /* Default will be zero */
+               }
+
+               notification_vp->vp_uint16 &= ~0x4000;  /* Unset phase bit */
+
+               /*
+                *      Include the counter attribute if we're failing
+                *      after a reauthentication success.
+                *
+                *      RFC 4187 Section #9.10
+                *
+                *      If EAP-Request/AKA-Notification is used on
+                *      a fast re-authentication exchange, and if
+                *      the P bit in AT_NOTIFICATION is set to zero,
+                *      then AT_COUNTER is used for replay protection.
+                *      In this case, the AT_ENCR_DATA and AT_IV
+                *      attributes MUST be included, and the
+                *      encapsulated plaintext attributes MUST include
+                *      the AT_COUNTER attribute.  The counter value
+                *      included in AT_COUNTER MUST be the same
+                *      as in the EAP-Request/AKA-Reauthentication
+                *      packet on the same fast re-authentication
+                *      exchange.
+                *
+                *      If the counter is used it should never be zero,
+                *      as it's incremented on first reauthentication
+                *      request.
+                */
+               if (eap_aka_sim_session->reauthentication_success) {
+                       MEM(pair_update_reply(&notification_vp, attr_eap_aka_sim_counter) >= 0);
+                       notification_vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
+               }
+
+               /*
+                *      If we're after the challenge phase
+                *      then we need to include a MAC to
+                *      protect notifications.
+                */
+               MEM(pair_update_reply(&vp, attr_eap_aka_sim_mac) >= 0);
+               fr_pair_value_memcpy(vp, NULL, 0, false);
+       } else {
+               /*
+                *      Only valid code is general failure
+                */
+               if (!notification_vp) {
+                       pair_add_reply(&notification_vp, attr_eap_aka_sim_notification);
+                       notification_vp->vp_uint16 = FR_NOTIFICATION_VALUE_GENERAL_FAILURE;
+               /*
+                *      User supplied failure code
+                */
+               } else {
+                       notification_vp->vp_uint16 |= 0x4000;   /* Set phase bit */
+               }
+       }
+       notification_vp->vp_uint16 &= ~0x8000;          /* In both cases success bit should be low */
+
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       /*
+        *      Encode the packet
+        */
+       if (common_encode(request, eap_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION, NULL, 0) < 0) {
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+
+       return RLM_MODULE_HANDLED;
+}
+
+/** Add MPPE keys to the request being sent to the supplicant
+ *
+ * The only work to be done is the add the appropriate SEND/RECV
+ * attributes derived from the MSK.
+ */
+static rlm_rcode_t common_eap_success_send(REQUEST *request, eap_session_t *eap_session)
+{
+       uint8_t                 *p;
+       eap_aka_sim_session_t   *eap_aka_sim_session;
+
+       RDEBUG2("Sending EAP-Success");
+
+       eap_session->this_round->request->code = FR_EAP_CODE_SUCCESS;
+       eap_session->finished = true;
+
+       eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque, eap_aka_sim_session_t);
+
+       RDEBUG2("Adding attributes for MSK");
+       p = eap_aka_sim_session->keys.msk;
+       eap_add_reply(request->parent, attr_ms_mppe_recv_key, p, EAP_TLS_MPPE_KEY_LEN);
+       p += EAP_TLS_MPPE_KEY_LEN;
+       eap_add_reply(request->parent, attr_ms_mppe_send_key, p, EAP_TLS_MPPE_KEY_LEN);
+
+       return RLM_MODULE_OK;
+}
+
+/** Send a EAP-Request/(AKA|SIM)-Notification (Success) message to the supplicant
+ *
+ */
+static rlm_rcode_t common_success_notification_send(eap_aka_sim_common_conf_t *inst,
+                                                   REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque, eap_aka_sim_session_t);
+       VALUE_PAIR              *vp;
+
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       if (!fr_cond_assert(after_authentication(eap_aka_sim_session))) return RLM_MODULE_FAIL;
+
+       /*
+        *      If we're in this state success bit is
+        *      high phase bit is low.
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_notification) >= 0);
+       vp->vp_uint16 = FR_NOTIFICATION_VALUE_SUCCESS;
+
+       /*
+        *      RFC 4187 section #9.10
+        *
+        *      If EAP-Request/AKA-Notification is used on
+        *      a fast re-authentication exchange, and if
+        *      the P bit in AT_NOTIFICATION is set to zero,
+        *      then AT_COUNTER is used for replay protection.
+        *      In this case, the AT_ENCR_DATA and AT_IV
+        *      attributes MUST be included, and the
+        *      encapsulated plaintext attributes MUST include
+        *      the AT_COUNTER attribute.  The counter value
+        *      included in AT_COUNTER MUST be the same
+        *      as in the EAP-Request/AKA-Reauthentication
+        *      packet on the same fast re-authentication
+        *      exchange.
+        *
+        *      If the counter is used it should never be zero,
+        *      as it's incremented on first reauthentication
+        *      request.
+        */
+       if (eap_aka_sim_session->keys.reauth.counter > 0) {
+               MEM(pair_update_reply(&vp, attr_eap_aka_sim_counter) >= 0);
+               vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
+       }
+
+       /*
+        *      Need to include an AT_MAC attribute so that
+        *      it will get calculated.
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_mac) >= 0);
+       fr_pair_value_memcpy(vp, NULL, 0, false);
+
+       /*
+        *      Encode the packet
+        */
+       if (common_encode(request, eap_session, FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION, NULL, 0) < 0) {
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+
+       return RLM_MODULE_HANDLED;
+}
+
+/** Called after 'store session { ... }' and 'store pseudonym { ... }'
+ *
+ */
+static rlm_rcode_t common_reauthentication_request_send(eap_aka_sim_common_conf_t *inst,
+                                                       REQUEST *request, eap_session_t *eap_session)
+{
+       /*
+        *      Encode the packet - AT_IV is handled automatically
+        *      by the encoder.
+        */
+       if (common_encode(request, eap_session, FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION, NULL, 0) < 0) {
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+
+       return RLM_MODULE_HANDLED;
+}
+
+/** Send a EAP-Request/(AKA|SIM)-Reauthenticate message to the supplicant
+ *
+ */
+static rlm_rcode_t common_reauthentication_request_compose(eap_aka_sim_common_conf_t *inst, REQUEST *request,
+                                                          eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       VALUE_PAIR              *to_peer = request->reply->vps, *vp;
+
+       VALUE_PAIR              *kdf_id;
+
+       /*
+        *      Allow override of KDF Identity
+        *
+        *      Because certain handset manufacturers don't
+        *      implement RFC 4187 correctly and use the
+        *      wrong identity as input the the PRF/KDF.
+        *
+        *      Not seen any doing this for re-authentication
+        *      but you never know...
+        */
+       kdf_id = fr_pair_find_by_da(request->control, attr_eap_aka_sim_kdf_identity, TAG_ANY);
+       if (kdf_id) {
+               identity_to_crypto_identity(request, eap_aka_sim_session,
+                                           (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
+               fr_pair_delete_by_da(&request->control, attr_eap_aka_sim_kdf_identity);
+       }
+
+       RDEBUG2("Generating new session keys");
+
+       switch (eap_aka_sim_session->type) {
+       /*
+        *      The GSM and UMTS KDF_0 mutate their keys using
+        *      and identical algorithm.
+        */
+       case FR_EAP_METHOD_SIM:
+       case FR_EAP_METHOD_AKA:
+               if (fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(request, request->state,
+                                                                      &eap_aka_sim_session->keys) != 0) {
+               request_new_id:
+                       switch (eap_aka_sim_session->last_id_req) {
+                       /*
+                        *      Got here processing EAP-Identity-Response
+                        *      If this is the *true* reauth ID, then
+                        *      there's no point in setting AKA_SIM_ANY_ID_REQ.
+                        */
+                       case AKA_SIM_NO_ID_REQ:
+                       case AKA_SIM_ANY_ID_REQ:
+                               RDEBUG2("Composing EAP-Request/Reauthentication failed.  Clearing reply attributes and "
+                                       "requesting additional Identity");
+                               fr_pair_list_free(&request->reply->vps);
+                               eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
+                               return common_identity_enter(inst, request, eap_session);
+
+                       case AKA_SIM_FULLAUTH_ID_REQ:
+                       case AKA_SIM_PERMANENT_ID_REQ:
+                               REDEBUG("Last requested fullauth or permanent ID, "
+                                       "but received, or were told we received (by policy), "
+                                       "a fastauth ID.  Cannot continue");
+                       failure:
+                               return common_failure_notification_enter(inst, request, eap_session);
+                       }
+               }
+               if (fr_aka_sim_crypto_kdf_0_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
+               break;
+
+       case FR_EAP_METHOD_AKA_PRIME:
+               switch (eap_aka_sim_session->kdf) {
+               case FR_KDF_VALUE_PRIME_WITH_CK_PRIME_IK_PRIME:
+                       if (fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(request, request->state,
+                                                                          &eap_aka_sim_session->keys) != 0) {
+                               goto request_new_id;
+                       }
+                       if (fr_aka_sim_crypto_umts_kdf_1_reauth(&eap_aka_sim_session->keys) < 0) goto request_new_id;
+                       break;
+
+               default:
+                       rad_assert(0);
+                       break;
+               }
+               break;
+
+       default:
+               rad_assert(0);
+               break;
+       }
+
+       if (RDEBUG_ENABLED3) fr_aka_sim_crypto_keys_log(request, &eap_aka_sim_session->keys);
+
+       /*
+        *      Add AT_IV, AT_COUNTER, AT_NONCE_S, and AT_MAC to to reply
+        *      The user may have added AT_NEXT_REAUTH_ID, in which case
+        *      we'll have sent that too.
+        */
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       /*
+        *      Indicate we'd like to use protected success messages
+        *      with AT_RESULT_IND
+        *
+        *      Use our default, but allow user override too.
+        */
+       vp = fr_pair_find_by_da(to_peer, attr_eap_aka_sim_result_ind, TAG_ANY);
+       if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
+
+       /*
+        *      RFC 5448 says AT_BIDDING is only sent in the challenge
+        *      not in reauthentication, so don't add that here.
+        */
+
+        /*
+         *     Add AT_NONCE_S
+         */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_nonce_s) >= 0);
+       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.reauth.nonce_s,
+                            sizeof(eap_aka_sim_session->keys.reauth.nonce_s), false);
+
+       /*
+        *      Add AT_COUNTER
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_counter) >= 0);
+       vp->vp_uint16 = eap_aka_sim_session->keys.reauth.counter;
+
+       /*
+        *      need to include an empty AT_MAC attribute so that
+        *      the mac will get calculated.
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_mac) >= 0);
+       fr_pair_value_memcpy(vp, NULL, 0, false);
+
+       /*
+        *      If there's no checkcode_md we're not doing
+        *      checkcodes.
+        */
+       if (eap_aka_sim_session->checkcode_md) {
+               /*
+                *      If we have checkcode data, send that to the peer
+                *      in AT_CHECKCODE for validation.
+                */
+               if (eap_aka_sim_session->checkcode_state) {
+                       ssize_t slen;
+
+                       slen = fr_aka_sim_crypto_finalise_checkcode(eap_aka_sim_session->checkcode,
+                                                                   &eap_aka_sim_session->checkcode_state);
+                       if (slen < 0) {
+                               RPEDEBUG("Failed calculating checkcode");
+                               goto failure;
+                       }
+                       eap_aka_sim_session->checkcode_len = slen;
+
+                       MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
+                       fr_pair_value_memcpy(vp, eap_aka_sim_session->checkcode, slen, false);
+               /*
+                *      If we don't have checkcode data, then we exchanged
+                *      no identity packets, so checkcode is zero.
+                */
+               } else {
+                       MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
+                       fr_pair_value_memcpy(vp, NULL, 0, false);
+                       eap_aka_sim_session->checkcode_len = 0;
+               }
+       }
+
+       /*
+        *      We've sent the challenge so the peer should now be able
+        *      to accept encrypted attributes.
+        */
+       eap_aka_sim_session->allow_encrypted = true;
+
+       return session_and_pseudonym_store(inst, request, eap_session, common_reauthentication_request_send);
+}
+
+/** Called after 'store session { ... }' and 'store pseudonym { ... }'
+ *
+ */
+static rlm_rcode_t aka_challenge_request_send(eap_aka_sim_common_conf_t *inst,
+                                             REQUEST *request, eap_session_t *eap_session)
+{
+       /*
+        *      Encode the packet - AT_IV is handled automatically
+        *      by the encoder.
+        */
+       if (common_encode(request, eap_session, FR_SUBTYPE_VALUE_AKA_CHALLENGE, NULL, 0) < 0) {
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+
+       return RLM_MODULE_HANDLED;
+}
+
+/** Send a EAP-Request/AKA-Challenge message to the supplicant
+ *
+ */
+static rlm_rcode_t aka_challenge_request_compose(eap_aka_sim_common_conf_t *inst,
+                                                REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque, eap_aka_sim_session_t);
+       VALUE_PAIR              *to_peer = request->reply->vps, *vp;
+       fr_aka_sim_vector_src_t src = AKA_SIM_VECTOR_SRC_AUTO;
+
+       VALUE_PAIR              *kdf_id;
+
+       /*
+        *      Allow override of KDF Identity
+        *
+        *      Because certain handset manufacturers don't
+        *      implement RFC 4187 correctly and use the
+        *      wrong identity as input the the PRF/KDF.
+        */
+       kdf_id = fr_pair_find_by_da(request->control, attr_eap_aka_sim_kdf_identity, TAG_ANY);
+       if (kdf_id) {
+               identity_to_crypto_identity(request, eap_aka_sim_session,
+                                           (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
+               fr_pair_delete_by_da(&request->control, attr_eap_aka_sim_kdf_identity);
+       }
+
+       RDEBUG2("Acquiring UMTS vector(s)");
+
+       if (eap_aka_sim_session->type == FR_EAP_METHOD_AKA_PRIME) {
+               /*
+                *      Copy the network name the user specified for
+                *      key derivation purposes.
+                */
+               vp = fr_pair_find_by_da(to_peer, attr_eap_aka_sim_kdf_input, TAG_ANY);
+               if (vp) {
+                       talloc_free(eap_aka_sim_session->keys.network);
+                       eap_aka_sim_session->keys.network = talloc_memdup(eap_aka_sim_session,
+                                                                         (uint8_t const *)vp->vp_strvalue,
+                                                                         vp->vp_length);
+                       eap_aka_sim_session->keys.network_len = vp->vp_length;
+               } else {
+                       REDEBUG("No network name available, can't set AT_KDF_INPUT");
+               failure:
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+
+               /*
+                *      We don't allow the user to specify
+                *      the KDF currently.
+                */
+               MEM(pair_update_reply(&vp, attr_eap_aka_sim_kdf) >= 0);
+               vp->vp_uint16 = eap_aka_sim_session->kdf;
+       }
+
+       /*
+        *      Get vectors from attribute or generate
+        *      them using COMP128-* or Milenage.
+        */
+       if (fr_aka_sim_vector_umts_from_attrs(request, request->control, &eap_aka_sim_session->keys, &src) != 0) {
+               REDEBUG("Failed retrieving UMTS vectors");
+               goto failure;
+       }
+
+       /*
+        *      Don't leave the AMF hanging around
+        */
+       if (eap_aka_sim_session->type == FR_EAP_METHOD_AKA_PRIME) pair_delete_control(attr_sim_amf);
+
+       /*
+        *      All set, calculate keys!
+        */
+       switch (eap_aka_sim_session->type) {
+       default:
+       case FR_EAP_METHOD_SIM:
+               rad_assert(0);  /* EAP-SIM has its own Challenge state */
+               break;
+
+       case FR_EAP_METHOD_AKA:
+               fr_aka_sim_crypto_umts_kdf_0(&eap_aka_sim_session->keys);
+               break;
+
+       case FR_EAP_METHOD_AKA_PRIME:
+               switch (eap_aka_sim_session->kdf) {
+               case FR_KDF_VALUE_PRIME_WITH_CK_PRIME_IK_PRIME:
+                       fr_aka_sim_crypto_umts_kdf_1(&eap_aka_sim_session->keys);
+                       break;
+
+               default:
+                       rad_assert(0);
+                       break;
+               }
+       }
+       if (RDEBUG_ENABLED3) fr_aka_sim_crypto_keys_log(request, &eap_aka_sim_session->keys);
+
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       /*
+        *      Indicate we'd like to use protected success messages
+        *      with AT_RESULT_IND
+        *
+        *      Use our default, but allow user override too.
+        */
+       vp = fr_pair_find_by_da(to_peer, attr_eap_aka_sim_result_ind, TAG_ANY);
+       if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
+
+       /*
+        *      See if we're indicating we want EAP-AKA'
+        *      If so include AT_BIDDING with the correct
+        *      value.
+        */
+       vp = fr_pair_find_by_da(to_peer, attr_eap_aka_sim_bidding, TAG_ANY);
+       if (vp) {
+               eap_aka_sim_session->send_at_bidding_prefer_prime =
+                       (vp->vp_uint16 == FR_BIDDING_VALUE_PREFER_AKA_PRIME);
+       }
+
+       /*
+        *      These attributes are only allowed with
+        *      EAP-AKA', protect users from themselves.
+        */
+       if (eap_aka_sim_session->type == FR_EAP_METHOD_AKA) {
+               pair_delete_reply(attr_eap_aka_sim_kdf_input);
+               pair_delete_reply(attr_eap_aka_sim_kdf);
+       }
+
+       /*
+        *      Okay, we got the challenge! Put it into an attribute.
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_rand) >= 0);
+       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.umts.vector.rand, AKA_SIM_VECTOR_UMTS_RAND_SIZE, false);
+
+       /*
+        *      Send the AUTN value to the client, so it can authenticate
+        *      whoever has knowledge of the Ki.
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_autn) >= 0);
+       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.umts.vector.autn, AKA_SIM_VECTOR_UMTS_AUTN_SIZE, false);
+
+       /*
+        *      need to include an AT_MAC attribute so that it will get
+        *      calculated.
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_mac) >= 0);
+       fr_pair_value_memcpy(vp, NULL, 0, false);
+
+       /*
+        *      If we have checkcode data, send that to the peer
+        *      in AT_CHECKCODE for validation.
+        */
+       if (eap_aka_sim_session->checkcode_state) {
+               ssize_t slen;
+
+               slen = fr_aka_sim_crypto_finalise_checkcode(eap_aka_sim_session->checkcode,
+                                                           &eap_aka_sim_session->checkcode_state);
+               if (slen < 0) {
+                       RPEDEBUG("Failed calculating checkcode");
+                       goto failure;
+               }
+               eap_aka_sim_session->checkcode_len = slen;
+
+               MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
+               fr_pair_value_memcpy(vp, eap_aka_sim_session->checkcode, slen, false);
+       /*
+        *      If we don't have checkcode data, then we exchanged
+        *      no identity packets, so AT_CHECKCODE is zero.
+        */
+       } else {
+               MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
+               fr_pair_value_memcpy(vp, NULL, 0, false);
+               eap_aka_sim_session->checkcode_len = 0;
+       }
+
+       /*
+        *      We've sent the challenge so the peer should now be able
+        *      to accept encrypted attributes.
+        */
+       eap_aka_sim_session->allow_encrypted = true;
+
+       return session_and_pseudonym_store(inst, request, eap_session, aka_challenge_request_send);
+}
+
+/** Called after 'store session { ... }' and 'store pseudonym { ... }'
+ *
+ */
+static rlm_rcode_t sim_challenge_request_send(eap_aka_sim_common_conf_t *inst,
+                                             REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       /*
+        *      Encode the packet - AT_IV is handled automatically
+        *      by the encoder.
+        */
+       if (common_encode(request, eap_session, FR_SUBTYPE_VALUE_SIM_CHALLENGE,
+                         eap_aka_sim_session->keys.gsm.nonce_mt, sizeof(eap_aka_sim_session->keys.gsm.nonce_mt)) < 0) {
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+
+       return RLM_MODULE_HANDLED;
+}
+
+/** Send a EAP-Request/SIM-Challenge message to the supplicant
+ *
+ */
+static rlm_rcode_t sim_challenge_request_compose(eap_aka_sim_common_conf_t *inst,
+                                                REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       VALUE_PAIR              *to_peer = request->reply->vps, *vp;
+       fr_aka_sim_vector_src_t src = AKA_SIM_VECTOR_SRC_AUTO;
+
+       VALUE_PAIR              *kdf_id;
+
+       /*
+        *      Allow override of KDF Identity
+        *
+        *      Because certain handset manufacturers don't
+        *      implement RFC 4187 correctly and use the
+        *      wrong identity as input the the PRF/KDF.
+        */
+       kdf_id = fr_pair_find_by_da(request->control, attr_eap_aka_sim_kdf_identity, TAG_ANY);
+       if (kdf_id) {
+               identity_to_crypto_identity(request, eap_aka_sim_session,
+                                           (uint8_t const *)kdf_id->vp_strvalue, kdf_id->vp_length);
+               fr_pair_delete_by_da(&request->control, attr_eap_aka_sim_kdf_identity);
+       }
+
+       RDEBUG2("Acquiring GSM vector(s)");
+       if ((fr_aka_sim_vector_gsm_from_attrs(request, request->control, 0,
+                                             &eap_aka_sim_session->keys, &src) != 0) ||
+           (fr_aka_sim_vector_gsm_from_attrs(request, request->control, 1,
+                                             &eap_aka_sim_session->keys, &src) != 0) ||
+           (fr_aka_sim_vector_gsm_from_attrs(request, request->control, 2,
+                                             &eap_aka_sim_session->keys, &src) != 0)) {
+               REDEBUG("Failed retrieving SIM vectors");
+               return RLM_MODULE_FAIL;
+       }
+
+       fr_aka_sim_crypto_gsm_kdf_0(&eap_aka_sim_session->keys);
+
+       if (RDEBUG_ENABLED3) fr_aka_sim_crypto_keys_log(request, &eap_aka_sim_session->keys);
+
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       /*
+        *      Indicate we'd like to use protected success messages
+        *      with AT_RESULT_IND
+        *
+        *      Use our default, but allow user override too.
+        */
+       vp = fr_pair_find_by_da(to_peer, attr_eap_aka_sim_result_ind, TAG_ANY);
+       if (vp) eap_aka_sim_session->send_result_ind = vp->vp_bool;
+
+       /*
+        *      Okay, we got the challenges! Put them into attributes.
+        */
+       MEM(pair_add_reply(&vp, attr_eap_aka_sim_rand) >= 0);
+       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.gsm.vector[0].rand, AKA_SIM_VECTOR_GSM_RAND_SIZE, false);
+
+       MEM(pair_add_reply(&vp, attr_eap_aka_sim_rand) >= 0);
+       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.gsm.vector[1].rand, AKA_SIM_VECTOR_GSM_RAND_SIZE, false);
+
+       MEM(pair_add_reply(&vp, attr_eap_aka_sim_rand) >= 0);
+       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.gsm.vector[2].rand, AKA_SIM_VECTOR_GSM_RAND_SIZE, false);
+
+       /*
+        *      need to include an AT_MAC attribute so that it will get
+        *      calculated.
+        */
+       MEM(pair_update_reply(&vp, attr_eap_aka_sim_mac) >= 0);
+       fr_pair_value_memcpy(vp, NULL, 0, false);
+
+       /*
+        *      We've sent the challenge so the peer should now be able
+        *      to accept encrypted attributes.
+        */
+       eap_aka_sim_session->allow_encrypted = true;
+
+       return session_and_pseudonym_store(inst, request, eap_session, sim_challenge_request_send);
+}
+
+/** Send a EAP-Request/AKA-Identity message to the supplicant
+ *
+ * There are three types of user identities that can be implemented
+ * - Permanent identities such as 0123456789098765@myoperator.com
+ *   Permanent identities can be identified by the leading zero followed by
+ *   by 15 digits (the IMSI number).
+ * - Ephemeral identities (pseudonyms).  These are identities assigned for
+ *   identity privacy so the user can't be tracked.  These can identities
+ *   can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
+ *   document section 14, where a set of up to 16 encryption keys are used
+ *   to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
+ *   randomised and stored in a datastore.
+ * - A fast resumption ID which resolves to data used for fast resumption.
+ *
+ * In order to perform full authentication the original IMSI is required for
+ * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
+ * or can't perform fast resumption, we need to request the full identity from
+ * the supplicant.
+ *
+ * @param[in] request          The current subrequest.
+ * @param[in] eap_session      to continue.
+ * @return
+ *     - RLM_MODULE_HANDLED on success.
+ *     - anything else on failure.
+ */
+static rlm_rcode_t aka_identity_request_send(eap_aka_sim_common_conf_t *inst,
+                                            REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       /*
+        *      Update eap_aka_sim_session->id_req in case the the
+        *      user set attributes in `send Identity-Request { ... }`
+        *      Also removes all existing id_req attributes
+        *      from the reply.
+        */
+       identity_req_set_by_user(request, eap_aka_sim_session);
+
+       /*
+        *      Select the right type of identity request attribute
+        *
+        *      Implement checks on identity request order described
+        *      by RFC4187 section #4.1.5.
+        *
+        *      The internal state machine should always handle this
+        *      correctly, but the user may have other ideas...
+        */
+       if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
+       failure:
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+       eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
+
+       /*
+        *      Encode the packet
+        */
+       if (common_encode(request, eap_session, FR_SUBTYPE_VALUE_AKA_IDENTITY, NULL, 0) < 0) goto failure;
+
+       /*
+        *      Digest the packet contents, updating our checkcode.
+        */
+       if (eap_aka_sim_session->checkcode_md) {
+               if (!eap_aka_sim_session->checkcode_state &&
+                   fr_aka_sim_crypto_init_checkcode(eap_aka_sim_session, &eap_aka_sim_session->checkcode_state,
+                                                    eap_aka_sim_session->checkcode_md) < 0) {
+                       RPEDEBUG("Failed initialising checkcode");
+                       goto failure;
+               }
+               if (fr_aka_sim_crypto_update_checkcode(eap_aka_sim_session->checkcode_state,
+                                                      eap_session->this_round->request) < 0) {
+                       RPEDEBUG("Failed updating checkcode");
+                       goto failure;
+               }
+       }
+
+       return RLM_MODULE_HANDLED;
+}
+
+/** Send a EAP-Request/SIM-Start message to the supplicant
+ *
+ * There are three types of user identities that can be implemented
+ * - Permanent identities such as 0123456789098765@myoperator.com
+ *   Permanent identities can be identified by the leading zero followed by
+ *   by 15 digits (the IMSI number).
+ * - Ephemeral identities (pseudonyms).  These are identities assigned for
+ *   identity privacy so the user can't be tracked.  These can identities
+ *   can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
+ *   document section 14, where a set of up to 16 encryption keys are used
+ *   to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
+ *   randomised and stored in a datastore.
+ * - A fast resumption ID which resolves to data used for fast resumption.
+ *
+ * In order to perform full authentication the original IMSI is required for
+ * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
+ * or can't perform fast resumption, we need to request the full identity from
+ * the supplicant.
+ *
+ * @param[in] request          The current subrequest.
+ * @param[in] eap_session      to continue.
+ * @return
+ *     - RLM_MODULE_HANDLED on success.
+ *     - anything else on failure.
+ */
+static rlm_rcode_t sim_start_request_send(eap_aka_sim_common_conf_t *inst,
+                                         REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       VALUE_PAIR              *vp;
+       fr_cursor_t             cursor;
+       uint8_t                 *p, *end;
+
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       p = eap_aka_sim_session->keys.gsm.version_list;
+       end = p + sizeof(eap_aka_sim_session->keys.gsm.version_list);
+       eap_aka_sim_session->keys.gsm.version_list_len = 0;
+
+       /*
+        *      If the user provided no versions, then
+        *      just add the default (1).
+        */
+       if (!(fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_version_list, TAG_ANY))) {
+               MEM(pair_add_reply(&vp, attr_eap_aka_sim_version_list) >= 0);
+               vp->vp_uint16 = EAP_SIM_VERSION;
+       }
+
+       /*
+        *      Iterate over the the versions adding them
+        *      to the version list we use for keying.
+        */
+       for (vp = fr_cursor_init(&cursor, &request->reply->vps); vp; vp = fr_cursor_next(&cursor)) {
+               if (vp->da != attr_eap_aka_sim_version_list) continue;
+
+               if ((end - p) < 2) break;
+
+               /*
+                *      Store as big endian
+                */
+               *p++ = (vp->vp_uint16 & 0xff00) >> 8;
+               *p++ = (vp->vp_uint16 & 0x00ff);
+               eap_aka_sim_session->keys.gsm.version_list_len += sizeof(uint16_t);
+       }
+
+       /*
+        *      Update eap_aka_sim_session->id_req in case the the
+        *      user set attributes in `send Identity-Request { ... }`
+        *      Also removes all existing id_req attributes
+        *      from the reply.
+        */
+       identity_req_set_by_user(request, eap_aka_sim_session);
+
+       /*
+        *      Select the right type of identity request attribute
+        *
+        *      Implement checks on identity request order described
+        *      by RFC4186 section #4.2.5.
+        *
+        *      The internal state machine should always handle this
+        *      correctly, but the user may have other ideas...
+        */
+       if (identity_req_pairs_add(request, eap_aka_sim_session) < 0) {
+       failure:
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+       eap_aka_sim_session->last_id_req = eap_aka_sim_session->id_req; /* Record what we last requested */
+
+       /*
+        *      Encode the packet
+        */
+       if (common_encode(request, eap_session, FR_SUBTYPE_VALUE_SIM_START, NULL, 0) < 0) goto failure;
+
+       return RLM_MODULE_HANDLED;
+}
+
+/** Print debugging information, and write new state to eap_session->process
+ *
+ */
+static inline void state_transition(REQUEST *request, eap_session_t *eap_session,
+                                           module_method_t new_state)
+{
+       module_method_t         old_state = eap_session->process;
+
+       if (new_state != old_state) {
+               RDEBUG2("Changed state %s -> %s",
+                       module_state_method_to_str(aka_sim_stable_table, old_state, "<unknown>"),
+                       module_state_method_to_str(aka_sim_stable_table, new_state, "<unknown>"));
+       } else {
+               RDEBUG2("Reentering state %s",
+                       module_state_method_to_str(aka_sim_stable_table, old_state, "<unknown>"));
+       }
+
+       eap_session->process = new_state;
+}
+
+/** Resume after 'send EAP-Failure { ... }'
+ *
+ */
+static rlm_rcode_t common_eap_failure_enter_resume(UNUSED void *instance, UNUSED void *thread,
+                                                  REQUEST *request, UNUSED void *rctx)
+{
+       eap_session_t   *eap_session = eap_session_get(request->parent);
+
+       section_rcode_ignored(request);
+
+       return common_eap_failure_send(request, eap_session);
+}
+
+/** Enter EAP-FAILURE state
+ *
+ */
+static rlm_rcode_t common_eap_failure_enter(eap_aka_sim_common_conf_t *inst, REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque, eap_aka_sim_session_t);
+
+       /*
+        *      Free anything we were going to send out...
+        */
+       fr_pair_list_free(&request->reply->vps);
+
+       /*
+        *      If we're failing, then any identities
+        *      we sent are now invalid.
+        */
+       if (eap_aka_sim_session->pseudonym_sent || eap_aka_sim_session->fastauth_sent) {
+               return session_and_pseudonym_clear(inst,
+                                                  request, eap_session, common_eap_failure_enter); /* come back when we're done */
+       }
+
+       state_transition(request, eap_session, common_eap_failure);
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.send_eap_failure,
+                                             RLM_MODULE_NOOP,
+                                             common_eap_failure_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Resume after 'send Failure-Notification { ... }'
+ *
+ * Ignores return code from send Failure-Notification { ... } section.
+ */
+static rlm_rcode_t common_failure_notification_enter_resume(void *instance, UNUSED void *thread,
+                                                           REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t   *eap_session = eap_session_get(request->parent);
+
+       section_rcode_ignored(request);
+
+       /*
+        *      Free anything we were going to send out...
+        */
+       fr_pair_list_free(&request->reply->vps);
+
+       /*
+        *      If there's an issue composing the failure
+        *      message just send an EAP-Failure instead.
+        */
+       return common_failure_notification_send(inst, request, eap_session);
+}
+
+/** Enter the FAILURE-NOTIFICATION state
+ *
+ */
+static rlm_rcode_t common_failure_notification_enter(eap_aka_sim_common_conf_t *inst,
+                                                    REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque, eap_aka_sim_session_t);
+
+       /*
+        *      If we're failing, then any identities
+        *      we sent are now invalid.
+        */
+       if (eap_aka_sim_session->pseudonym_sent || eap_aka_sim_session->fastauth_sent) {
+               return session_and_pseudonym_clear(inst, request, eap_session,
+                                                  common_failure_notification_enter); /* come back when we're done */
+       }
+
+       /*
+        *      We've already sent a failure notification
+        *      Now we just fail as it means something
+        *      went wrong processing the ACK or we got
+        *      garbage from the supplicant.
+        */
+       if (eap_session->process == common_failure_notification) {
+               return common_eap_failure_enter(inst, request, eap_session);
+       }
+
+       /*
+        *      Otherwise just transition as normal...
+        */
+       state_transition(request, eap_session, common_failure_notification);
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.send_failure_notification,
+                                             RLM_MODULE_NOOP,
+                                             common_failure_notification_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Resume after 'send EAP-Success { ... }'
+ *
+ */
+static rlm_rcode_t common_eap_success_enter_resume(void *instance, UNUSED void *thread,
+                                                 REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       /*
+        *      If this is true we're entering this state
+        *      after sending a AKA-Success-Notification
+        *
+        *      Is seems like a really bad idea to allow the
+        *      user to send a protected success to the
+        *      supplicant and then force a failure using
+        *      the send EAP-Success { ... } section.
+        */
+       if (eap_aka_sim_session->send_result_ind) {
+               switch (request->rcode) {
+               case RLM_MODULE_USER_SECTION_REJECT:
+                       RWDEBUG("Ignoring rcode (%s) from send EAP-Success { ... } "
+                               "as we already sent a Success-Notification",
+                               fr_table_str_by_value(mod_rcode_table, request->rcode, "<invalid>"));
+                       RWDEBUG("If you need to force a failure, return an error code from "
+                               "send Success-Notification { ... }");
+                       break;
+
+               default:
+                       break;
+               }
+
+       /*
+        *      But... if we're not working with protected
+        *      success indication, this is the only
+        *      opportunity the user has to force a failure at
+        *      the end of authentication.
+        */
+       } else {
+               section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+       }
+
+       return common_eap_success_send(request, eap_session);
+}
+
+/** Enter EAP-SUCCESS state
+ *
+ */
+static rlm_rcode_t common_eap_success_enter(eap_aka_sim_common_conf_t *inst, REQUEST *request,
+                                           eap_session_t *eap_session)
+{
+       state_transition(request, eap_session, common_eap_success);
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.send_eap_success,
+                                             RLM_MODULE_NOOP,
+                                             common_eap_success_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Resume after 'send Success-Notification { ... }'
+ *
+ */
+static rlm_rcode_t common_success_notification_enter_resume(void *instance, UNUSED void *thread,
+                                                              REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return common_success_notification_send(inst, request, eap_session);
+}
+
+/** Enter the SUCCESS-NOTIFICATION state
+ *
+ */
+static rlm_rcode_t common_success_notification_enter(eap_aka_sim_common_conf_t *inst,
+                                                       REQUEST *request, eap_session_t *eap_session)
+{
+       state_transition(request, eap_session, common_success_notification);
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.send_success_notification,
+                                             RLM_MODULE_NOOP,
+                                             common_success_notification_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Resume after 'send Reauthentication-Request { ... }'
+ *
+ */
+static rlm_rcode_t common_reauthentication_send_resume(void *instance, UNUSED void *thread,
+                                                      REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       switch (request->rcode) {
+       /*
+        *      Failed getting the values we need for resumption
+        *      Request a different identity.
+        */
+       default:
+               switch (eap_aka_sim_session->last_id_req) {
+               /*
+                *      Got here processing EAP-Identity-Response
+                *      If this is the *true* reauth ID, then
+                *      there's no point in setting AKA_SIM_ANY_ID_REQ.
+                */
+               case AKA_SIM_NO_ID_REQ:
+               case AKA_SIM_ANY_ID_REQ:
+                       RDEBUG2("Previous section returned (%s), clearing reply attributes and "
+                               "requesting additional identity",
+                               fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"));
+                       fr_pair_list_free(&request->reply->vps);
+                       eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
+
+                       return common_identity_enter(inst, request, eap_session);
+
+               case AKA_SIM_FULLAUTH_ID_REQ:
+               case AKA_SIM_PERMANENT_ID_REQ:
+                       REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
+                               "but received a Fast-Auth-Id.  Cannot continue");
+               failure:
+                       return common_failure_notification_enter(inst, request, eap_session);
+
+               }
+
+       /*
+        *      Policy rejected the user
+        */
+       case RLM_MODULE_REJECT:
+       case RLM_MODULE_USERLOCK:
+               goto failure;
+
+       /*
+        *      Everything looks ok, send the EAP-Request/reauthentication message
+        *      After storing any new pseudonyms or session information.
+        */
+       case RLM_MODULE_NOOP:
+       case RLM_MODULE_OK:
+       case RLM_MODULE_UPDATED:
+               return common_reauthentication_request_compose(inst, request, eap_session);
+       }
+}
+
+/** Resume after 'load session { ... }'
+ *
+ */
+static rlm_rcode_t session_load_resume(void *instance, UNUSED void *thread,
+                                      REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       pair_delete_request(attr_session_id);
+
+       /*
+        *      Control attributes required could have been specified
+        *      in another section.
+        */
+       if (!inst->actions.load_session) goto reauthenticate;
+
+       switch (request->rcode) {
+       /*
+        *      Failed getting the values we need for resumption
+        *      Request a different identity.
+        */
+       default:
+               switch (eap_aka_sim_session->last_id_req) {
+               /*
+                *      Got here processing EAP-Identity-Response
+                *      If this is the *true* reauth ID, then
+                *      there's no point in setting AKA_SIM_ANY_ID_REQ.
+                */
+               case AKA_SIM_NO_ID_REQ:
+               case AKA_SIM_ANY_ID_REQ:
+                       RDEBUG2("Previous section returned (%s), clearing reply attributes and "
+                               "requesting additional identity",
+                               fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"));
+                       fr_pair_list_free(&request->reply->vps);
+                       eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
+                       return common_identity_enter(inst, request, eap_session);
+
+               case AKA_SIM_FULLAUTH_ID_REQ:
+               case AKA_SIM_PERMANENT_ID_REQ:
+                       REDEBUG("Last requested Full-Auth-Id or Permanent-Identity, "
+                               "but received a Fast-Auth-Id.  Cannot continue");
+                       return common_failure_notification_enter(inst, request, eap_session);
+
+               }
+
+       /*
+        *      Policy rejected the user
+        */
+       case RLM_MODULE_REJECT:
+       case RLM_MODULE_USERLOCK:
+               return common_failure_notification_enter(inst, request, eap_session);
+
+       /*
+        *      Everything OK
+        */
+       case RLM_MODULE_OK:
+       case RLM_MODULE_UPDATED:
+       reauthenticate:
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.send_reauthentication_request,
+                                                     RLM_MODULE_NOOP,
+                                                     common_reauthentication_send_resume,
+                                                     mod_signal,
+                                                     NULL);
+       }
+}
+
+/** Resume after 'load pseudonym { ... }'
+ *
+ */
+static rlm_rcode_t pseudonym_load_resume(void *instance, UNUSED void *thread,
+                                        REQUEST *request, void *rctx)
+{
+       eap_aka_sim_common_conf_t *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       aka_sim_state_enter_t   state_enter = (aka_sim_state_enter_t)rctx;
+
+       pair_delete_request(attr_eap_aka_sim_next_reauth_id);
+
+       /*
+        *      Control attributes required could have been specified
+        *      in another section.
+        */
+       if (!inst->actions.load_pseudonym) {
+       next_state:
+               return state_enter(inst, request, eap_session);
+       }
+
+       switch (request->rcode) {
+       /*
+        *      Failed resolving the pseudonym
+        *      request a different identity.
+        */
+       default:
+               switch (eap_aka_sim_session->last_id_req) {
+               case AKA_SIM_NO_ID_REQ:
+               case AKA_SIM_ANY_ID_REQ:
+               case AKA_SIM_FULLAUTH_ID_REQ:
+                       RDEBUG2("Previous section returned (%s), clearing reply attributes and "
+                               "requesting additional identity",
+                               fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"));
+                       fr_pair_list_free(&request->reply->vps);
+                       eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
+                       return common_identity_enter(inst, request, eap_session);
+
+               case AKA_SIM_PERMANENT_ID_REQ:
+                       REDEBUG("Last requested a Permanent-Identity, but received a Pseudonym.  Cannot continue");
+               failure:
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+       /*
+        *      Policy rejected the user
+        */
+       case RLM_MODULE_REJECT:
+       case RLM_MODULE_USERLOCK:
+               goto failure;
+
+       /*
+        *      Everything OK
+        */
+       case RLM_MODULE_OK:
+       case RLM_MODULE_UPDATED:
+               goto next_state;
+       }
+}
+
+/** Enter the REAUTHENTICATION state
+ *
+ */
+static rlm_rcode_t common_reauthentication_enter(eap_aka_sim_common_conf_t *inst,
+                                                REQUEST *request, eap_session_t *eap_session)
+{
+       VALUE_PAIR              *vp = NULL;
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       state_transition(request, eap_session, common_reauthentication);
+
+       /*
+        *      Add the current identity as session_id
+        *      to make it easier to load/store things from
+        *      the cache module.
+        */
+       MEM(pair_update_request(&vp, attr_session_id) >= 0);
+       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.identity, eap_aka_sim_session->keys.identity_len, true);
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.load_session,
+                                             RLM_MODULE_NOOP,
+                                             session_load_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Resume after 'send Challenge-Request { ... }'
+ *
+ */
+static rlm_rcode_t aka_challenge_enter_resume(void *instance, UNUSED void *thread, REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return aka_challenge_request_compose(inst, request, eap_session);
+}
+
+/** Enter the AKA-CHALLENGE state
+ *
+ */
+static rlm_rcode_t aka_challenge_enter(eap_aka_sim_common_conf_t *inst,
+                                      REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque, eap_aka_sim_session_t);
+       VALUE_PAIR              *vp;
+
+       /*
+        *      If we've sent either of these identities it
+        *      means we've come here form a Reauthentication-Request
+        *      that failed.
+        */
+       if (eap_aka_sim_session->pseudonym_sent || eap_aka_sim_session->fastauth_sent) {
+               return session_and_pseudonym_clear(inst, request, eap_session, aka_challenge_enter);    /* come back when we're done */
+       }
+
+       state_transition(request, eap_session, aka_challenge);
+
+       /*
+        *      Set some default attributes, giving the user a
+        *      chance to modify them.
+        */
+       switch (eap_session->type) {
+       case FR_EAP_METHOD_AKA_PRIME:
+       {
+               uint8_t         amf_buff[2] = { 0x80, 0x00 };   /* Set the AMF separation bit high */
+
+               /*
+                *      Toggle the AMF high bit to indicate we're doing AKA'
+                */
+               MEM(pair_update_control(&vp, attr_sim_amf) >= 0);
+               fr_pair_value_memcpy(vp, amf_buff, sizeof(amf_buff), false);
+
+               /*
+                *      Use the default network name we have configured
+                *      and send it to the peer.
+                */
+               if (inst->network_name &&
+                   !fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_kdf_input, TAG_ANY)) {
+                       MEM(pair_add_reply(&vp, attr_eap_aka_sim_kdf_input) >= 0);
+                       fr_pair_value_bstrncpy(vp, inst->network_name, talloc_array_length(inst->network_name) - 1);
+               }
+       }
+               break;
+
+       default:
+               /*
+                *      Use the default bidding value we have configured
+                */
+               if (eap_aka_sim_session->send_at_bidding_prefer_prime &&
+                   !fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_bidding, TAG_ANY)) {
+                       MEM(pair_add_reply(&vp, attr_eap_aka_sim_bidding) >= 0);
+                       vp->vp_uint16 = FR_BIDDING_VALUE_PREFER_AKA_PRIME;
+               }
+               break;
+
+       }
+
+       /*
+        *      Set the defaults for protected result indicator
+        */
+       if (eap_aka_sim_session->send_result_ind &&
+           !fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+               MEM(pair_add_reply(&vp, attr_eap_aka_sim_result_ind) >= 0);
+               vp->vp_bool = true;
+       }
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.send_challenge_request,
+                                             RLM_MODULE_NOOP,
+                                             aka_challenge_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Resume after 'send Challenge-Request { ... }'
+ *
+ */
+static rlm_rcode_t sim_challenge_enter_resume(void *instance, UNUSED void *thread, REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return sim_challenge_request_compose(inst, request, eap_session);
+}
+
+/** Enter the SIM-CHALLENGE state
+ *
+ */
+static rlm_rcode_t sim_challenge_enter(eap_aka_sim_common_conf_t *inst,
+                                      REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+       VALUE_PAIR                      *vp;
+
+       /*
+        *      If we've sent either of these identities it
+        *      means we've come here form a Reauthentication-Request
+        *      that failed.
+        */
+       if (eap_aka_sim_session->pseudonym_sent || eap_aka_sim_session->fastauth_sent) {
+               return session_and_pseudonym_clear(inst, request, eap_session, sim_challenge_enter);    /* come back when we're done */
+       }
+
+       state_transition(request, eap_session, sim_challenge);
+
+       /*
+        *      Set the defaults for protected result indicator
+        */
+       if (eap_aka_sim_session->send_result_ind &&
+           !fr_pair_find_by_da(request->reply->vps, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+               MEM(pair_add_reply(&vp, attr_eap_aka_sim_result_ind) >= 0);
+               vp->vp_bool = true;
+       }
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.send_challenge_request,
+                                             RLM_MODULE_NOOP,
+                                             sim_challenge_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Enter the SIM-CHALLENGE or AKA-CHALLENGE state
+ *
+ * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
+ * to enter the correct challenge state.
+ */
+static rlm_rcode_t common_challenge_enter(eap_aka_sim_common_conf_t *inst,
+                                         REQUEST *request, eap_session_t *eap_session)
+{
+       switch (eap_session->type) {
+       case FR_EAP_METHOD_SIM:
+               return sim_challenge_enter(inst, request, eap_session);
+
+       case FR_EAP_METHOD_AKA:
+       case FR_EAP_METHOD_AKA_PRIME:
+               return aka_challenge_enter(inst, request, eap_session);
+
+       default:
+               rad_assert(0);
+       }
+}
+
+/** Resume after 'send Identity-Request { ... }'
+ *
+ */
+static rlm_rcode_t aka_identity_enter_resume(void *instance, UNUSED void *thread,
+                                                  REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return aka_identity_request_send(inst, request, eap_session);
+}
+
+/** Enter the AKA-IDENTITY state
+ *
+ */
+static rlm_rcode_t aka_identity_enter(eap_aka_sim_common_conf_t *inst, REQUEST *request, eap_session_t *eap_session)
+{
+       state_transition(request, eap_session, aka_identity);
+
+       /*
+        *      If we have an send_aka_identity_request section
+        *      then run that, otherwise just run the normal
+        *      identity request section.
+        */
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.aka.send_aka_identity_request ?
+                                                       inst->actions.aka.send_aka_identity_request:
+                                                       inst->actions.send_identity_request,
+                                             RLM_MODULE_NOOP,
+                                             aka_identity_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Resume after 'send Start { ... }'
+ *
+ */
+static rlm_rcode_t sim_start_enter_resume(void *instance, UNUSED void *thread,
+                                         REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return sim_start_request_send(inst, request, eap_session);
+}
+
+/** Enter the SIM-START state
+ *
+ */
+static rlm_rcode_t sim_start_enter(eap_aka_sim_common_conf_t *inst, REQUEST *request, eap_session_t *eap_session)
+{
+       state_transition(request, eap_session, sim_start);
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.sim.send_sim_start_request ?
+                                                       inst->actions.sim.send_sim_start_request:
+                                                       inst->actions.send_identity_request,
+                                             RLM_MODULE_NOOP,
+                                             sim_start_enter_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+/** Enter the SIM-START or AKA-IDENTITY state
+ *
+ * Called by functions which are common to both the EAP-SIM and EAP-AKA state machines
+ * to enter the correct Identity-Request state.
+ */
+static rlm_rcode_t common_identity_enter(eap_aka_sim_common_conf_t *inst,
+                                        REQUEST *request, eap_session_t *eap_session)
+{
+       switch (eap_session->type) {
+       case FR_EAP_METHOD_SIM:
+               return sim_start_enter(inst, request, eap_session);
+
+       case FR_EAP_METHOD_AKA:
+       case FR_EAP_METHOD_AKA_PRIME:
+               return aka_identity_enter(inst, request, eap_session);
+
+       default:
+               rad_assert(0);
+       }
+}
+
+/** Process a EAP-Response/(AKA|SIM)-Reauthentication message - The response to our EAP-Request/(AKA|SIM)-Reauthentication message
+ *
+ */
+static rlm_rcode_t common_reauthentication_response_process(eap_aka_sim_common_conf_t *inst, REQUEST *request,
+                                                           eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       uint8_t                 calc_mac[AKA_SIM_MAC_DIGEST_SIZE];
+       ssize_t                 slen;
+       VALUE_PAIR              *mac, *checkcode;
+       VALUE_PAIR              *from_peer = request->packet->vps;
+
+       mac = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_mac, TAG_ANY);
+       if (!mac) {
+               REDEBUG("Missing AT_MAC attribute");
+       failure:
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+       if (mac->vp_length != AKA_SIM_MAC_DIGEST_SIZE) {
+               REDEBUG("MAC has incorrect length, expected %u bytes got %zu bytes",
+                       AKA_SIM_MAC_DIGEST_SIZE, mac->vp_length);
+               goto failure;
+       }
+
+       slen = fr_aka_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true,
+                                            eap_aka_sim_session->mac_md,
+                                            eap_aka_sim_session->keys.k_aut, eap_aka_sim_session->keys.k_aut_len,
+                                            eap_aka_sim_session->keys.reauth.nonce_s,
+                                            sizeof(eap_aka_sim_session->keys.reauth.nonce_s));
+       if (slen < 0) {
+               RPEDEBUG("Failed calculating MAC");
+               goto failure;
+       } else if (slen == 0) {
+               REDEBUG("Zero length AT_MAC attribute");
+               goto failure;
+       }
+
+       if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
+               RDEBUG2("Received MAC matches calculated MAC");
+       } else {
+               REDEBUG("Received MAC does not match calculated MAC");
+               RHEXDUMP_INLINE2(mac->vp_octets, AKA_SIM_MAC_DIGEST_SIZE, "Received");
+               RHEXDUMP_INLINE2(calc_mac, AKA_SIM_MAC_DIGEST_SIZE, "Expected");
+               goto failure;
+       }
+
+       /*
+        *      If the peer doesn't include a checkcode then that
+        *      means they don't support it, and we can't validate
+        *      their view of the identity packets.
+        */
+       checkcode = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_checkcode, TAG_ANY);
+       if (checkcode) {
+               if (checkcode->vp_length != eap_aka_sim_session->checkcode_len) {
+                       REDEBUG("Received checkcode's length (%zu) does not match calculated checkcode's length (%zu)",
+                               checkcode->vp_length, eap_aka_sim_session->checkcode_len);
+                       goto failure;
+               }
+
+               if (memcmp(checkcode->vp_octets, eap_aka_sim_session->checkcode,
+                          eap_aka_sim_session->checkcode_len) == 0) {
+                       RDEBUG2("Received checkcode matches calculated checkcode");
+               } else {
+                       REDEBUG("Received checkcode does not match calculated checkcode");
+                       RHEXDUMP_INLINE2(checkcode->vp_octets, checkcode->vp_length, "Received");
+                       RHEXDUMP_INLINE2(eap_aka_sim_session->checkcode,
+                                        eap_aka_sim_session->checkcode_len, "Expected");
+                       goto failure;
+               }
+       /*
+        *      Only print something if we calculated a checkcode
+        */
+       } else if (eap_aka_sim_session->checkcode_len > 0){
+               RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
+       }
+
+       /*
+        *      Check to see if the supplicant sent
+        *      AT_COUNTER_TOO_SMALL, if they did then we
+        *      clear out reauth information and enter the
+        *      challenge state.
+        */
+       if (fr_pair_find_by_da(from_peer, attr_eap_aka_sim_counter_too_small, TAG_ANY)) {
+               RWDEBUG("Peer sent AT_COUNTER_TOO_SMALL (indicating our AT_COUNTER value (%u) wasn't fresh)",
+                       eap_aka_sim_session->keys.reauth.counter);
+
+               fr_aka_sim_vector_umts_reauth_clear(&eap_aka_sim_session->keys);
+               eap_aka_sim_session->allow_encrypted = false;
+
+               return aka_challenge_enter(inst, request, eap_session);
+       }
+
+       /*
+        *      If the peer wants a Success notification, and
+        *      we included AT_RESULT_IND then send a success
+        *      notification, otherwise send a normal EAP-Success.
+        *
+        *      RFC 4187 Section #6.2. Result Indications
+        */
+       if (eap_aka_sim_session->send_result_ind) {
+               if (!fr_pair_find_by_da(from_peer, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+                       RDEBUG("We wanted to use protected result indications, but peer does not");
+                       eap_aka_sim_session->send_result_ind = false;
+               } else {
+                       return common_success_notification_enter(inst, request, eap_session);
+               }
+       } else if (fr_pair_find_by_da(from_peer, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+               RDEBUG("Peer wanted to use protected result indications, but we do not");
+       }
+
+       eap_aka_sim_session->reauthentication_success = true;
+
+       return common_eap_success_enter(inst, request, eap_session);
+}
+
+/** Process a EAP-Response/AKA-Challenge message - The response to our EAP-Request/AKA-Challenge message
+ *
+ * Verify that MAC, and RES match what we expect.
+ */
+static rlm_rcode_t aka_challenge_response_process(eap_aka_sim_common_conf_t *inst,
+                                                 REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       uint8_t                 calc_mac[AKA_SIM_MAC_DIGEST_SIZE];
+       ssize_t                 slen;
+       VALUE_PAIR              *vp = NULL, *mac, *checkcode;
+       VALUE_PAIR              *from_peer = request->packet->vps;
+
+       mac = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_mac, TAG_ANY);
+       if (!mac) {
+               REDEBUG("Missing AT_MAC attribute");
+       failure:
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+       if (mac->vp_length != AKA_SIM_MAC_DIGEST_SIZE) {
+               REDEBUG("MAC has incorrect length, expected %u bytes got %zu bytes",
+                       AKA_SIM_MAC_DIGEST_SIZE, mac->vp_length);
+               goto failure;
+       }
+
+       slen = fr_aka_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true,
+                                            eap_aka_sim_session->mac_md,
+                                            eap_aka_sim_session->keys.k_aut, eap_aka_sim_session->keys.k_aut_len,
+                                            NULL, 0);
+       if (slen < 0) {
+               RPEDEBUG("Failed calculating MAC");
+               goto failure;
+       } else if (slen == 0) {
+               REDEBUG("Zero length AT_MAC attribute");
+               goto failure;
+       }
+
+       if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
+               RDEBUG2("Received MAC matches calculated MAC");
+       } else {
+               REDEBUG("Received MAC does not match calculated MAC");
+               RHEXDUMP_INLINE2(mac->vp_octets, AKA_SIM_MAC_DIGEST_SIZE, "Received");
+               RHEXDUMP_INLINE2(calc_mac, AKA_SIM_MAC_DIGEST_SIZE, "Expected");
+               goto failure;
+       }
+
+       /*
+        *      If the peer doesn't include a checkcode then that
+        *      means they don't support it, and we can't validate
+        *      their view of the identity packets.
+        */
+       if (eap_aka_sim_session->checkcode_md) {
+               checkcode = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_checkcode, TAG_ANY);
+               if (checkcode) {
+                       if (checkcode->vp_length != eap_aka_sim_session->checkcode_len) {
+                               REDEBUG("Received checkcode's length (%zu) does not match "
+                                       "calculated checkcode's length (%zu)",
+                                       checkcode->vp_length, eap_aka_sim_session->checkcode_len);
+                               goto failure;
+                       }
+
+                       if (memcmp(checkcode->vp_octets,
+                                  eap_aka_sim_session->checkcode, eap_aka_sim_session->checkcode_len) == 0) {
+                               RDEBUG2("Received checkcode matches calculated checkcode");
+                       } else {
+                               REDEBUG("Received checkcode does not match calculated checkcode");
+                               RHEXDUMP_INLINE2(checkcode->vp_octets, checkcode->vp_length, "Received");
+                               RHEXDUMP_INLINE2(eap_aka_sim_session->checkcode,
+                                               eap_aka_sim_session->checkcode_len, "Expected");
+                               goto failure;
+                       }
+               /*
+                *      Only print something if we calculated a checkcode
+                */
+               } else if (eap_aka_sim_session->checkcode_len > 0){
+                       RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
+               }
+       }
+
+       vp = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_res, TAG_ANY);
+       if (!vp) {
+               REDEBUG("AT_RES missing from challenge response");
+               goto failure;
+       }
+
+       if (vp->vp_length != eap_aka_sim_session->keys.umts.vector.xres_len) {
+               REDEBUG("Received RES' length (%zu) does not match calculated XRES' length (%zu)",
+                       vp->vp_length, eap_aka_sim_session->keys.umts.vector.xres_len);
+               goto failure;
+       }
+
+       if (memcmp(vp->vp_octets, eap_aka_sim_session->keys.umts.vector.xres, vp->vp_length)) {
+               REDEBUG("Received RES does not match calculated XRES");
+               RHEXDUMP_INLINE2(vp->vp_octets, vp->vp_length, "RES  :");
+               RHEXDUMP_INLINE2(eap_aka_sim_session->keys.umts.vector.xres,
+                               eap_aka_sim_session->keys.umts.vector.xres_len, "XRES :");
+               goto failure;
+       }
+
+       RDEBUG2("Received RES matches calculated XRES");
+
+       eap_aka_sim_session->challenge_success = true;
+
+       /*
+        *      If the peer wants a Success notification, and
+        *      we included AT_RESULT_IND then send a success
+        *      notification, otherwise send a normal EAP-Success.
+        *
+        *      RFC 4187 Section #6.2. Result Indications
+        */
+       if (eap_aka_sim_session->send_result_ind) {
+               if (!fr_pair_find_by_da(from_peer, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+                       RDEBUG("We wanted to use protected result indications, but peer does not");
+                       eap_aka_sim_session->send_result_ind = false;
+               } else {
+                       return common_success_notification_enter(inst, request, eap_session);
+               }
+       } else if (fr_pair_find_by_da(from_peer, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+               RDEBUG("Peer wanted to use protected result indications, but we do not");
+       }
+
+       return common_eap_success_enter(inst, request, eap_session);
+}
+
+/** Process a EAP-Response/SIM-Challenge message - The response to our EAP-Request/SIM-Challenge message
+ *
+ * Verify that MAC, and RES match what we expect.
+ */
+static rlm_rcode_t sim_challenge_response_process(eap_aka_sim_common_conf_t *inst,
+                                                 REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       uint8_t                 sres_cat[AKA_SIM_VECTOR_GSM_SRES_SIZE * 3];
+       uint8_t                 *p = sres_cat;
+
+       uint8_t                 calc_mac[AKA_SIM_MAC_DIGEST_SIZE];
+       ssize_t                 slen;
+       VALUE_PAIR              *mac;
+       VALUE_PAIR              *from_peer = request->packet->vps;
+
+       memcpy(p, eap_aka_sim_session->keys.gsm.vector[0].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
+       p += AKA_SIM_VECTOR_GSM_SRES_SIZE;
+       memcpy(p, eap_aka_sim_session->keys.gsm.vector[1].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
+       p += AKA_SIM_VECTOR_GSM_SRES_SIZE;
+       memcpy(p, eap_aka_sim_session->keys.gsm.vector[2].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE);
+
+       mac = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_mac, TAG_ANY);
+       if (!mac) {
+               REDEBUG("Missing AT_MAC attribute");
+       failure:
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+       if (mac->vp_length != AKA_SIM_MAC_DIGEST_SIZE) {
+               REDEBUG("MAC has incorrect length, expected %u bytes got %zu bytes",
+                       AKA_SIM_MAC_DIGEST_SIZE, mac->vp_length);
+               goto failure;
+       }
+
+       slen = fr_aka_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true,
+                                            eap_aka_sim_session->mac_md,
+                                            eap_aka_sim_session->keys.k_aut, eap_aka_sim_session->keys.k_aut_len,
+                                            sres_cat, sizeof(sres_cat));
+       if (slen < 0) {
+               RPEDEBUG("Failed calculating MAC");
+               goto failure;
+       } else if (slen == 0) {
+               REDEBUG("Zero length AT_MAC attribute");
+               goto failure;
+       }
+
+       if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
+               RDEBUG2("Received MAC matches calculated MAC");
+       } else {
+               REDEBUG("Received MAC does not match calculated MAC");
+               RHEXDUMP_INLINE2(mac->vp_octets, AKA_SIM_MAC_DIGEST_SIZE, "Received");
+               RHEXDUMP_INLINE2(calc_mac, AKA_SIM_MAC_DIGEST_SIZE, "Expected");
+               goto failure;
+       }
+
+       eap_aka_sim_session->challenge_success = true;
+
+       /*
+        *      If the peer wants a Success notification, and
+        *      we included AT_RESULT_IND then send a success
+        *      notification, otherwise send a normal EAP-Success.
+        */
+       if (eap_aka_sim_session->send_result_ind) {
+               if (!fr_pair_find_by_da(from_peer, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+                       RDEBUG("We wanted to use protected result indications, but peer does not");
+                       eap_aka_sim_session->send_result_ind = false;
+               } else {
+                       return common_success_notification_enter(inst, request, eap_session);
+               }
+       } else if (fr_pair_find_by_da(from_peer, attr_eap_aka_sim_result_ind, TAG_ANY)) {
+               RDEBUG("Peer wanted to use protected result indications, but we do not");
+       }
+
+       return common_eap_success_enter(inst, request, eap_session);
+}
+
+/** Process a EAP-Response/AKA-Identity message i.e. an EAP-AKA Identity-Response
+ *
+ * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
+ * - If the user requested another identity, re-enter the AKA-Identity sate.
+ * - ...or continue based on the value of &Identity-Type which was added by #aka_identity,
+ *   and possibly modified by the user.
+ *   - Fastauth - Enter the REAUTHENTICATION state.
+ *   - Pseudonym - Call 'load pseudonym { ... }'
+ *   - Permanent - Enter the CHALLENGE state.
+ */
+static rlm_rcode_t aka_identity_response_process(eap_aka_sim_common_conf_t *inst,
+                                                REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       bool                    user_set_id_req;
+       VALUE_PAIR              *identity_type;
+       VALUE_PAIR              *from_peer = request->packet->vps;
+       /*
+        *      Digest the identity response
+        */
+       if (eap_aka_sim_session->checkcode_md) {
+               if (fr_aka_sim_crypto_update_checkcode(eap_aka_sim_session->checkcode_state,
+                                                      eap_session->this_round->response) < 0) {
+                       RPEDEBUG("Failed updating checkcode");
+               failure:
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+       }
+
+       /*
+        *      See if the user wants us to request another
+        *      identity.
+        *
+        *      If they set one themselves don't override
+        *      what they set.
+        */
+       user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
+       if ((request->rcode == RLM_MODULE_NOTFOUND) || user_set_id_req) {
+               if (!user_set_id_req) {
+                       switch (eap_aka_sim_session->last_id_req) {
+                       case AKA_SIM_ANY_ID_REQ:
+                               eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
+                               break;
+
+                       case AKA_SIM_FULLAUTH_ID_REQ:
+                               eap_aka_sim_session->id_req = AKA_SIM_PERMANENT_ID_REQ;
+                               break;
+
+                       case AKA_SIM_NO_ID_REQ: /* Should not happen */
+                               rad_assert(0);
+                               /* FALL-THROUGH */
+
+                       case AKA_SIM_PERMANENT_ID_REQ:
+                               REDEBUG("Peer sent no usable identities");
+                               goto failure;
+
+                       }
+                       RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
+                               fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"),
+                               fr_table_str_by_value(fr_aka_sim_id_request_table, eap_aka_sim_session->id_req, "<INVALID>"));
+               }
+               return aka_identity_enter(inst, request, eap_session);
+       }
+
+       /*
+        *      If the identity looks like a fast re-auth id
+        *      run fast re-auth, otherwise do fullauth.
+        */
+       identity_type = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_identity_type, TAG_ANY);
+       if (identity_type) switch (identity_type->vp_uint32) {
+       case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
+               return common_reauthentication_enter(inst, request, eap_session);
+
+       /*
+        *      It's a pseudonym, which now needs resolving.
+        *      The resume function here calls aka_challenge_enter
+        *      if pseudonym resolution went ok.
+        */
+       case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.load_pseudonym,
+                                                     RLM_MODULE_NOOP,
+                                                     pseudonym_load_resume,
+                                                     mod_signal,
+                                                     (void *)aka_challenge_enter);
+       default:
+               break;
+       }
+
+       return aka_challenge_enter(inst, request, eap_session);
+}
+
+/** Helper function to check for the presence and length of AT_SELECTED_VERSION and copy its value into the keys structure
+ *
+ * Also checks the version matches one of the ones we advertised in our version list,
+ * which is a bit redundant seeing as there's only one version of EAP-SIM.
+ */
+static int sim_start_selected_version_check(REQUEST *request, VALUE_PAIR *from_peer,
+                                           eap_aka_sim_session_t *eap_aka_sim_session)
+{
+       VALUE_PAIR              *selected_version_vp;
+
+       /*
+        *      Check that we got an AT_SELECTED_VERSION
+        */
+       selected_version_vp = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_selected_version, TAG_ANY);
+       if (!selected_version_vp) {
+               REDEBUG("EAP-Response/SIM/Start does not contain AT_SELECTED_VERSION");
+               return -1;
+       }
+
+       /*
+        *      See if the selected version was in our list
+        */
+       {
+               uint8_t selected_version[2];
+               uint8_t *p, *end;
+               bool found = false;
+
+               p = eap_aka_sim_session->keys.gsm.version_list;
+               end = p + eap_aka_sim_session->keys.gsm.version_list_len;
+
+               selected_version[0] = (selected_version_vp->vp_uint16 & 0xff00) >> 8;
+               selected_version[1] = (selected_version_vp->vp_uint16 & 0x00ff);
+
+               while (p < end) {
+                       if ((p[0] == selected_version[0]) && (p[1] == selected_version[1])) {
+                               found = true;
+                               /*
+                                *      Update our keying material
+                                */
+                               eap_aka_sim_session->keys.gsm.version_select[0] = selected_version[0];
+                               eap_aka_sim_session->keys.gsm.version_select[1] = selected_version[1];
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       REDEBUG("AT_SELECTED_VERSION (%u) does not match a value in our version list",
+                               selected_version_vp->vp_uint16);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/** Helper function to check for the presence and length of AT_NONCE_MT and copy its value into the keys structure
+ *
+ * Does not actually perform cryptographic validation of AT_NONCE_MT, this is done later.
+ */
+static int sim_start_nonce_mt_check(REQUEST *request, VALUE_PAIR *from_peer,
+                                   eap_aka_sim_session_t *eap_aka_sim_session)
+{
+       VALUE_PAIR      *nonce_mt_vp;
+
+       /*
+        *      Copy nonce_mt to the keying material
+        */
+       nonce_mt_vp = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_nonce_mt, TAG_ANY);
+       if (!nonce_mt_vp) {
+               REDEBUG("EAP-Response/SIM/Start does not contain AT_NONCE_MT");
+               return -1;
+       }
+
+       if (nonce_mt_vp->vp_length != sizeof(eap_aka_sim_session->keys.gsm.nonce_mt)) {
+               REDEBUG("AT_NONCE_MT must be exactly %zu bytes, not %zu bytes",
+                       sizeof(eap_aka_sim_session->keys.gsm.nonce_mt), nonce_mt_vp->vp_length);
+               return -1;
+       }
+       memcpy(eap_aka_sim_session->keys.gsm.nonce_mt, nonce_mt_vp->vp_octets,
+              sizeof(eap_aka_sim_session->keys.gsm.nonce_mt));
+
+       return 0;
+}
+
+/** Process a EAP-Response/SIM-Start message i.e. an EAP-SIM Identity-Response
+ *
+ * - If the message does not contain AT_IDENTITY, then enter the FAILURE-NOTIFICATION state.
+ * - If the user requested another identity, re-enter the SIM-START sate.
+ * - ...or continue based on the value of &Identity-Type which was added by #sim_start,
+ *   and possibly modified by the user.
+ *   - Fastauth
+ *     - If AT_NONCE_MT or AT_SELECTED_VERSION are present, enter the FAILURE-NOTIFICATION state.
+ *     - ...or enter the REAUTHENTICATION state.
+ *   - Pseudonym - Verify selected version and AT_NONCE_MT, then call 'load pseudonym { ... }'
+ *   - Permanent - Verify selected version and AT_NONCE_MT, then enter the CHALLENGE state.
+ */
+static rlm_rcode_t sim_start_response_process(eap_aka_sim_common_conf_t *inst,
+                                             REQUEST *request, eap_session_t *eap_session)
+{
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+       bool                    user_set_id_req;
+       VALUE_PAIR              *identity_type;
+
+       VALUE_PAIR              *from_peer = request->packet->vps;
+
+       /*
+        *      See if the user wants us to request another
+        *      identity.
+        *
+        *      If they set one themselves don't override
+        *      what they set.
+        */
+       user_set_id_req = identity_req_set_by_user(request, eap_aka_sim_session);
+       if ((request->rcode == RLM_MODULE_NOTFOUND) || user_set_id_req) {
+               if (!user_set_id_req) {
+                       switch (eap_aka_sim_session->last_id_req) {
+                       case AKA_SIM_ANY_ID_REQ:
+                               eap_aka_sim_session->id_req = AKA_SIM_FULLAUTH_ID_REQ;
+                               break;
+
+                       case AKA_SIM_FULLAUTH_ID_REQ:
+                               eap_aka_sim_session->id_req = AKA_SIM_PERMANENT_ID_REQ;
+                               break;
+
+                       case AKA_SIM_NO_ID_REQ: /* Should not happen */
+                               rad_assert(0);
+                               /* FALL-THROUGH */
+
+                       case AKA_SIM_PERMANENT_ID_REQ:
+                               REDEBUG("Peer sent no usable identities");
+                       failure:
+                               return common_failure_notification_enter(inst, request, eap_session);
+                       }
+                       RDEBUG2("Previous section returned (%s), requesting next most permissive identity (%s)",
+                               fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"),
+                               fr_table_str_by_value(fr_aka_sim_id_request_table, eap_aka_sim_session->id_req, "<INVALID>"));
+               }
+               return sim_start_enter(inst, request, eap_session);
+       }
+
+       /*
+        *      If the identity looks like a fast re-auth id
+        *      run fast re-auth, otherwise do fullauth.
+        */
+       identity_type = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_identity_type, TAG_ANY);
+       if (identity_type) switch (identity_type->vp_uint32) {
+       case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
+               /*
+                *  RFC 4186 Section #9.2
+                *
+                *  The AT_NONCE_MT attribute MUST NOT be included if the AT_IDENTITY
+                *  with a fast re-authentication identity is present for fast
+                *  re-authentication
+                */
+               if (fr_pair_find_by_da(from_peer, attr_eap_aka_sim_nonce_mt, TAG_ANY)) {
+                       REDEBUG("AT_NONCE_MT is not allowed in EAP-Response/SIM-Reauthentication messages");
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+
+               /*
+                *  RFC 4186 Section #9.2
+                *
+                *  The AT_SELECTED_VERSION attribute MUST NOT be included if the
+                *  AT_IDENTITY attribute with a fast re-authentication identity is
+                *  present for fast re-authentication.
+                */
+               if (fr_pair_find_by_da(from_peer, attr_eap_aka_sim_selected_version, TAG_ANY)) {
+                       REDEBUG("AT_SELECTED_VERSION is not allowed in EAP-Response/SIM-Reauthentication messages");
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+
+               return common_reauthentication_enter(inst, request, eap_session);
+
+       /*
+        *      It's a pseudonym, which now needs resolving.
+        *      The resume function here calls aka_challenge_enter
+        *      if pseudonym resolution went ok.
+        */
+       case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
+               if (sim_start_selected_version_check(request, from_peer, eap_aka_sim_session) < 0) goto failure;
+               if (sim_start_nonce_mt_check(request, from_peer, eap_aka_sim_session) < 0) goto failure;
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.load_pseudonym,
+                                                     RLM_MODULE_NOOP,
+                                                     pseudonym_load_resume,
+                                                     mod_signal,
+                                                     (void *)sim_challenge_enter);
+
+       /*
+        *      If it's a permanent ID, copy it over to
+        *      the session state list for use in the
+        *      store pseudonym/store session sections
+        *      later.
+        */
+       case FR_IDENTITY_TYPE_VALUE_PERMANENT:
+               if (sim_start_selected_version_check(request, from_peer, eap_aka_sim_session) < 0) goto failure;
+               if (sim_start_nonce_mt_check(request, from_peer, eap_aka_sim_session) < 0) goto failure;
+
+               /* FALL-THROUGH */
+       default:
+               break;
+       }
+
+       return sim_challenge_enter(inst, request, eap_session);
+}
+
+/** Resume after 'recv Failure-Notification-Ack { ... }'
+ *
+ * - Enter the EAP-FAILURE state.
+ */
+static rlm_rcode_t common_failure_notification_recv_resume(void *instance, UNUSED void *thread,
+                                                          REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+
+       section_rcode_ignored(request);
+
+       /*
+        *      Case 2 where we're allowed to send an EAP-Failure
+        */
+       return common_eap_failure_enter(inst, request, eap_session);
+}
+
+/** Resume after 'recv Success-Notification-Ack { ... }'
+ *
+ * - Enter the EAP-SUCCESS state.
+ */
+static rlm_rcode_t common_success_notification_ack_recv_resume(void *instance, UNUSED void *thread,
+                                                              REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+
+       section_rcode_ignored(request);
+
+       /*
+        *      RFC 4187 says we ignore the contents of the
+        *      next packet after we send our success notification
+        *      and always send a success.
+        */
+       return common_eap_success_enter(inst, request, eap_session);
+}
+
+/** Resume after 'recv Challenge-Response { ... }'
+ *
+ * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
+ * - ...or call a function to process the contents of the AKA-Challenge message.
+ */
+static rlm_rcode_t aka_challenge_response_recv_resume(void *instance, UNUSED void *thread,
+                                                     REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return aka_challenge_response_process(inst, request, eap_session);
+}
+
+/** Resume after 'recv Challenge-Response { ... }'
+ *
+ * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
+ * - ...or call a function to process the contents of the SIM-Challenge message.
+ */
+static rlm_rcode_t sim_challenge_response_recv_resume(void *instance, UNUSED void *thread,
+                                                     REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return sim_challenge_response_process(inst, request, eap_session);
+}
+
+/** Resume after 'recv Identity-Response { ... }' or 'recv AKA-Identity { ... }'
+ *
+ * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
+ * - ...or call a function to process the contents of the AKA-Identity message, mainly the AT_IDENTITY value.
+ */
+static rlm_rcode_t aka_identity_response_recv_resume(void *instance, UNUSED void *thread,
+                                                    REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return aka_identity_response_process(inst, request, eap_session);
+}
+
+/** Resume after 'recv Identity-Response { ... }' or 'recv SIM-Start { ... }'
+ *
+ * - If the previous section returned a failure rcode, enter the FAILURE-NOTIFICATION state.
+ * - ...or call a function to process the contents of the SIM-Start message, mainly the AT_IDENTITY value.
+ */
+static rlm_rcode_t sim_start_response_recv_resume(void *instance, UNUSED void *thread,
+                                                 REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return sim_start_response_process(inst, request, eap_session);
+}
+
+/** Resume after 'recv Authentication-Reject { ... }'
+ *
+ * - Enter the FAILURE-NOTIFICATION state.
+ */
+static rlm_rcode_t aka_authentication_reject_recv_resume(void *instance, UNUSED void *thread,
+                                                        REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+
+       section_rcode_ignored(request);
+
+       /*
+        *      Case 2 where we're allowed to send an EAP-Failure
+        */
+       return common_eap_failure_enter(inst, request, eap_session);
+}
+
+/** Resume after 'recv Synchronization-Failure { ... }'
+ *
+ * - If 'recv Synchronization-Failure { ... }' returned a failure
+ *   rcode, enter the FAILURE-NOTIFICATION state.
+ * - ...or if no 'recv Syncronization-Failure { ... }' section was
+ *   defined, then enter the FAILURE-NOTIFICATION state.
+ * - ...or if the user didn't provide a new SQN value in &control:SQN
+ *   then enter the FAILURE-NOTIFICATION state.
+ * - ...or enter the AKA-CHALLENGE state.
+ */
+static rlm_rcode_t aka_synchronization_failure_recv_resume(void *instance, UNUSED void *thread,
+                                                          REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+       VALUE_PAIR                      *vp;
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       /*
+        *      If there's no section to handle this, then no resynchronisation
+        *      can't have occurred and we just send a reject.
+        *
+        *      Similarly, if we've already received one synchronisation failure
+        *      then it's highly likely whatever user configured action was
+        *      configured was unsuccessful, and we should just give up.
+        */
+       if (!inst->actions.aka.recv_syncronization_failure || eap_aka_sim_session->prev_recv_sync_failure) {
+       failure:
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+
+       /*
+        *      We couldn't generate an SQN and the user didn't provide one,
+        *      so we need to fail.
+        */
+       vp = fr_pair_find_by_da(request->control, attr_sim_sqn, TAG_ANY);
+       if (!vp) {
+               REDEBUG("No &control:SQN value provided after resynchronisation, cannot continue");
+               goto failure;
+       }
+
+       /*
+        *      RFC 4187 Section #6.3.1
+        *
+        *      "if the peer detects that the
+        *      sequence number in AUTN is not correct, the peer responds with
+        *      EAP-Response/AKA-Synchronization-Failure (Section 9.6), and the
+        *      server proceeds with a new EAP-Request/AKA-Challenge."
+        */
+       return aka_challenge_enter(inst, request, eap_session);
+}
+
+/** Resume after 'recv Client-Error { ... }'
+ *
+ * - Enter the EAP-FAILURE state.
+ */
+static rlm_rcode_t common_client_error_recv_resume(void *instance, UNUSED void *thread,
+                                                  REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+
+       section_rcode_ignored(request);
+
+       return common_eap_failure_enter(inst, request, eap_session);
+}
+
+/** Resume after 'recv Reauthentication-Response { ... }'
+ *
+ * - If 'recv Reauthentication-Response { ... }' returned a failure
+ *   rcode, enter the FAILURE-NOTIFICATION state.
+ * - ...or call the EAP-Request/Reauthentication-Response function to act on the
+ *   contents of the response.
+ */
+static rlm_rcode_t common_reauthentication_response_recv_resume(void *instance, UNUSED void *thread,
+                                                               REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t               *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t                   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                            eap_aka_sim_session_t);
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       return common_reauthentication_response_process(inst, request, eap_session);
+}
+
+/** Decode the peer's response
+ *
+ * This is called by the state_* functions to decode the peer's response.
+ */
+static rlm_rcode_t common_decode(VALUE_PAIR **subtype_vp, VALUE_PAIR **vps,
+                                eap_aka_sim_common_conf_t *inst, REQUEST *request)
+{
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       fr_aka_sim_decode_ctx_t ctx = {
+                                       .keys = &eap_aka_sim_session->keys,
+                               };
+       VALUE_PAIR              *aka_vps;
+       fr_cursor_t             cursor;
+
+       int                     ret;
+
+       fr_cursor_init(&cursor, &request->packet->vps);
+       fr_cursor_tail(&cursor);
+
+       ret = fr_aka_sim_decode(request,
+                               &cursor,
+                               dict_eap_aka_sim,
+                               eap_session->this_round->response->type.data,
+                               eap_session->this_round->response->type.length,
+                               &ctx);
+       /*
+        *      RFC 4187 says we *MUST* notify, not just
+        *      send an EAP-Failure in this case where
+        *      we cannot decode an EAP-AKA packet.
+        */
+       if (ret < 0) {
+               RPEDEBUG2("Failed decoding attributes");
+       failure:
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+       /* vps is the data from the client */
+       aka_vps = fr_cursor_next(&cursor);
+       if (aka_vps && RDEBUG_ENABLED2) {
+               RDEBUG2("Decoded attributes");
+               log_request_pair_list(L_DBG_LVL_2, request, aka_vps, NULL);
+       }
+
+       *subtype_vp = fr_pair_find_by_da(aka_vps, attr_eap_aka_sim_subtype, TAG_ANY);
+       if (!*subtype_vp) {
+               REDEBUG("Missing AT_SUBTYPE");
+               goto failure;
+       }
+       *vps = aka_vps;
+
+       RDEBUG2("Received EAP-Response/%pV", &(*subtype_vp)->data);
+
+       return RLM_MODULE_OK;
+}
+
+/** FAILURE state - State machine exit point after sending EAP-Failure
+ *
+ * Should never actually be called. Is just a placeholder function to represent the FAILURE
+ * termination state.  Could equally be a NULL pointer, but then on a logic error
+ * we'd get a SEGV instead of a more friendly assert/failure rcode.
+ */
+static rlm_rcode_t common_eap_failure(UNUSED void *instance, UNUSED void *thread, UNUSED REQUEST *request)
+{
+       rad_assert(0);  /* Should never actually be called */
+       return RLM_MODULE_FAIL;
+}
+
+/** FAILURE-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
+ *
+ * - Continue based on received AT_SUBTYPE value:
+ *   - EAP-Response/SIM-Client-Error - Call 'recv Failure-Notification-Ack { ... }'
+ *   - Anything else, enter the FAILURE-NOTIFICATION state.
+ */
+static rlm_rcode_t common_failure_notification(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       rlm_rcode_t                     rcode;
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+
+       VALUE_PAIR                      *subtype_vp = NULL;
+       VALUE_PAIR                      *vps;
+
+       rcode = common_decode(&subtype_vp, &vps, inst, request);
+       if (rcode != RLM_MODULE_OK) return rcode;
+
+#ifdef __clang_analyzer__
+       rad_assert(subtype_vp);
+#endif
+       switch (subtype_vp->vp_uint16) {
+       case FR_SUBTYPE_VALUE_AKA_SIM_NOTIFICATION:
+               RDEBUG2("Failure-Notification ACKed, sending EAP-Failure");
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_failure_notification_ack,
+                                                     RLM_MODULE_NOOP,
+                                                     common_failure_notification_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       default:
+               RWDEBUG("Failure-Notification not ACKed correctly, sending EAP-Failure anyway");
+               return common_eap_failure_enter(inst, request, eap_session);
+       }
+}
+
+/** SUCCESS state - State machine exit point after sending EAP-Success
+ *
+ * Should never actually be called. Is just a placeholder function to represent the FAILURE
+ * termination state.  Could equally be a NULL pointer, but then on a logic error
+ * we'd get a SEGV instead of a more friendly assert/failure rcode.
+ */
+static rlm_rcode_t common_eap_success(UNUSED void *instance, UNUSED void *thread, UNUSED REQUEST *request)
+{
+       rad_assert(0);
+       return RLM_MODULE_FAIL;
+}
+
+/** SUCCESS-NOTIFICATION state - Continue the state machine after receiving a response to our EAP-Request/(AKA|SIM)-Notification
+ *
+ * - Call 'recv Success-Notification-Ack { ... }'
+ */
+static rlm_rcode_t common_success_notification(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.recv_success_notification_ack,
+                                             RLM_MODULE_NOOP,
+                                             common_success_notification_ack_recv_resume,
+                                             mod_signal,
+                                             NULL);
+}
+
+
+/** REAUTHENTICATION state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
+ *
+ * - Continue based on received AT_SUBTYPE value:
+ *   - EAP-Response/(SIM|AKA)-Reauthentication - call 'recv Reauthentication-Response { ... }'
+ *   - EAP-Response/(SIM|AKA)-Client-Error - call 'recv Client-Error { ... }' and after that
+ *     send a EAP-Request/(SIM|AKA)-Notification indicating a General Failure.
+ *   - Anything else, enter the FAILURE-NOTIFICATION state.
+ */
+static rlm_rcode_t common_reauthentication(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       rlm_rcode_t                     rcode;
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       VALUE_PAIR                      *subtype_vp = NULL;
+       VALUE_PAIR                      *from_peer;
+
+       rcode = common_decode(&subtype_vp, &from_peer, inst, request);
+       if (rcode != RLM_MODULE_OK) return rcode;
+
+#ifdef __clang_analyzer__
+       rad_assert(subtype_vp);
+#endif
+       /*
+        *      These aren't allowed in Reauthentication responses as they don't apply:
+        *
+        *      EAP_AKA_AUTHENTICATION_REJECT   - We didn't provide an AUTN value
+        *      EAP_AKA_SYNCHRONIZATION_FAILURE - We didn't use new vectors.
+        */
+       switch (subtype_vp->vp_uint16) {
+       case FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION:
+               /*
+                *      AT_COUNTER_TOO_SMALL is handled
+                *      in common_reauthentication_response_process.
+                */
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_reauthentication_response,
+                                                     RLM_MODULE_NOOP,
+                                                     common_reauthentication_response_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       /*
+        *      Case 1 where we're allowed to send an EAP-Failure
+        */
+       case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
+               client_error_debug(request, from_peer);
+
+               eap_aka_sim_session->allow_encrypted = false;
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_client_error,
+                                                     RLM_MODULE_NOOP,
+                                                     common_client_error_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       /*
+        *      RFC 4187 says we *MUST* notify, not just
+        *      send an EAP-Failure in this case.
+        */
+       default:
+               REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
+               eap_aka_sim_session->allow_encrypted = false;
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+}
+
+/** AKA-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
+ *
+ * - Continue based on received AT_SUBTYPE value:
+ *   - EAP-Response/AKA-Challenge - call 'recv Challenge-Response { ... }'.
+ *   - EAP-Response/AKA-Authentication-Reject - call 'recv Authentication-Reject { ... }'  and after that
+ *     send a EAP-Request/SIM-Notification indicating a General Failure.
+ *   - EAP-Response/AKA-Syncronization-Failure - call 'recv Syncronization-Failure { ... }'.
+ *   - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
+ *     send a EAP-Request/AKA-Notification indicating a General Failure.
+ *   - Anything else, enter the FAILURE-NOTIFICATION state.
+ */
+static rlm_rcode_t aka_challenge(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       rlm_rcode_t             rcode;
+       eap_aka_sim_common_conf_t               *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque, eap_aka_sim_session_t);
+
+       VALUE_PAIR              *subtype_vp = NULL;
+       VALUE_PAIR              *vp;
+       VALUE_PAIR              *from_peer;
+
+       rcode = common_decode(&subtype_vp, &from_peer, inst, request);
+       if (rcode != RLM_MODULE_OK) return rcode;
+
+#ifdef __clang_analyzer__
+       rad_assert(subtype_vp);
+#endif
+       switch (subtype_vp->vp_uint16) {
+       case FR_SUBTYPE_VALUE_AKA_CHALLENGE:
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_challenge_response,
+                                                     RLM_MODULE_NOOP,
+                                                     aka_challenge_response_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       /*
+        *      Case 2 where we're allowed to send an EAP-Failure
+        */
+       case FR_SUBTYPE_VALUE_AKA_AUTHENTICATION_REJECT:
+               eap_aka_sim_session->allow_encrypted = false;
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.aka.recv_authentication_reject,
+                                                     RLM_MODULE_NOOP,
+                                                     aka_authentication_reject_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       case FR_SUBTYPE_VALUE_AKA_SYNCHRONIZATION_FAILURE:
+       {
+               uint64_t        new_sqn;
+
+               eap_aka_sim_session->allow_encrypted = false;
+
+               vp = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_auts, TAG_ANY);
+               if (!vp) {
+                       REDEBUG("EAP-Response/AKA-Synchronisation-Failure missing AT_AUTS");
+               failure:
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+
+               switch (fr_aka_sim_umts_resync_from_attrs(&new_sqn,
+                                                         request, vp, &eap_aka_sim_session->keys)) {
+               /*
+                *      Add everything back that we'll need in the
+                *      next challenge round.
+                */
+               case 0:
+                       MEM(pair_add_control(&vp, attr_sim_sqn) >= 0);
+                       vp->vp_uint64 = new_sqn;
+
+                       MEM(pair_add_control(&vp, attr_sim_ki) >= 0);
+                       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.auc.ki,
+                                            sizeof(eap_aka_sim_session->keys.auc.ki), false);
+
+                       MEM(pair_add_control(&vp, attr_sim_opc) >= 0);
+                       fr_pair_value_memcpy(vp, eap_aka_sim_session->keys.auc.opc,
+                                            sizeof(eap_aka_sim_session->keys.auc.opc), false);
+                       break;
+
+               case 1: /* Don't have Ki or OPc so something else will need to deal with this */
+                       break;
+
+               default:
+               case -1:
+                       goto failure;
+               }
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.aka.recv_syncronization_failure,
+                                                     RLM_MODULE_NOOP,
+                                                     aka_synchronization_failure_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+       }
+
+       /*
+        *      Case 1 where we're allowed to send an EAP-Failure
+        */
+       case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
+               client_error_debug(request, from_peer);
+
+               eap_aka_sim_session->allow_encrypted = false;
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_client_error,
+                                                     RLM_MODULE_NOOP,
+                                                     common_client_error_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       /*
+        *      RFC 4187 says we *MUST* notify, not just
+        *      send an EAP-Failure in this case.
+        */
+       default:
+               REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
+               eap_aka_sim_session->allow_encrypted = false;
+               goto failure;
+       }
+}
+
+/** SIM-CHALLENGE state - Continue the state machine after receiving a response to our EAP-Request/SIM-Challenge
+ *
+ * - Continue based on received AT_SUBTYPE value:
+ *   - EAP-Response/SIM-Challenge - call 'recv Challenge-Response { ... }'.
+ *   - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
+ *     send a EAP-Request/SIM-Notification indicating a General Failure.
+ *   - Anything else, enter the FAILURE-NOTIFICATION state.
+ */
+static rlm_rcode_t sim_challenge(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       rlm_rcode_t             rcode;
+       eap_aka_sim_common_conf_t *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t           *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t   *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                            eap_aka_sim_session_t);
+
+       VALUE_PAIR              *subtype_vp = NULL;
+       VALUE_PAIR              *from_peer;
+
+       rcode = common_decode(&subtype_vp, &from_peer, inst, request);
+       if (rcode != RLM_MODULE_OK) return rcode;
+
+#ifdef __clang_analyzer__
+       rad_assert(subtype_vp);
+#endif
+       switch (subtype_vp->vp_uint16) {
+       case FR_SUBTYPE_VALUE_SIM_CHALLENGE:
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_challenge_response,
+                                                     RLM_MODULE_NOOP,
+                                                     sim_challenge_response_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       /*
+        *      Case 1 where we're allowed to send an EAP-Failure
+        */
+       case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
+               client_error_debug(request, from_peer);
+
+               eap_aka_sim_session->allow_encrypted = false;
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_client_error,
+                                                     RLM_MODULE_NOOP,
+                                                     common_client_error_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       /*
+        *      RFC 4186 says we *MUST* notify, not just
+        *      send an EAP-Failure in this case.
+        */
+       default:
+               REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
+
+               eap_aka_sim_session->allow_encrypted = false;
+
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+}
+
+/** AKA-IDENTITY state - Continue the state machine after receiving a response to our EAP-Request/AKA-Identity
+ *
+ * - Continue based on received AT_SUBTYPE value:
+ *   - EAP-Response/AKA-Identity - call either 'recv Identity-Response { ... }' or if
+ *     provided 'recv AKA-Identity-Response { ... }'. The idea here is that the
+ *     EAP-Identity-Response is really the first round in identity negotiation and
+ *     there's no real value distinguishing between the first round and subsequent
+ *     rounds, but if users do want to run different logic, then give them a way of
+ *     doing that.
+ *   - EAP-Response/AKA-Client-Error - call 'recv Client-Error { ... }' and after that
+ *     send a EAP-Request/SIM-Notification indicating a General Failure.
+ *   - Anything else, enter the FAILURE-NOTIFICATION state.
+ */
+static rlm_rcode_t aka_identity(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       rlm_rcode_t                     rcode;
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+       VALUE_PAIR                      *subtype_vp = NULL;
+       VALUE_PAIR                      *from_peer;
+
+       rcode = common_decode(&subtype_vp, &from_peer, inst, request);
+       if (rcode != RLM_MODULE_OK) return rcode;
+
+#ifdef __clang_analyzer__
+       rad_assert(subtype_vp);
+#endif
+
+       switch (subtype_vp->vp_uint16) {
+       /*
+        *      This is the subtype we expect
+        */
+       case FR_SUBTYPE_VALUE_AKA_IDENTITY:
+       {
+               VALUE_PAIR              *id;
+               fr_aka_sim_id_type_t    type;
+
+               id = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_identity, TAG_ANY);
+               if (!id) {
+                       /*
+                        *  9.2.  EAP-Response/Identity
+                        *
+                        *  The peer sends EAP-Response/Identity in response to a valid
+                        *  EAP-Request/Identity from the server.
+                        *  The peer MUST include the AT_IDENTITY attribute.  The usage of
+                        *  AT_IDENTITY is defined in Section 4.1.
+                        */
+                       REDEBUG("EAP-Response/Identity does not contain AT_IDENTITY");
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+
+               /*
+                *      Add ID hint attributes to the request to help
+                *      the user make policy decisions.
+                */
+               identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
+               if (type == AKA_SIM_ID_TYPE_PERMANENT) {
+                       identity_to_permanent_identity(request, id,
+                                                      eap_aka_sim_session->type,
+                                                      inst->strip_permanent_identity_hint);
+               }
+
+               /*
+                *      Update cryptographic identity
+                */
+               identity_to_crypto_identity(request, eap_aka_sim_session,
+                                           (uint8_t const *)id->vp_strvalue, id->vp_length);
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.aka.recv_aka_identity_response?
+                                                               inst->actions.aka.recv_aka_identity_response:
+                                                               inst->actions.recv_identity_response,
+                                                     RLM_MODULE_NOOP,
+                                                     aka_identity_response_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+       }
+
+       /*
+        *      Case 1 where we're allowed to send an EAP-Failure
+        *
+        *      This can happen in the case of a conservative
+        *      peer, where it refuses to provide the permanent
+        *      identity.
+        */
+       case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
+               client_error_debug(request, from_peer);
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_client_error,
+                                                     RLM_MODULE_NOOP,
+                                                     common_client_error_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       default:
+               /*
+                *      RFC 4187 says we *MUST* notify, not just
+                *      send an EAP-Failure in this case.
+                */
+               REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+}
+
+/** SIM-START state - Continue the state machine after receiving a response to our EAP-Request/SIM-Start
+ *
+ * - Continue based on received AT_SUBTYPE value:
+ *   - EAP-Response/SIM-Start - call either 'recv Identity-Response { ... }' or if
+ *     provided 'recv SIM-Start-Response { ... }'. The idea here is that the
+ *     EAP-Identity-Response is really the first round in identity negotiation and
+ *     there's no real value distinguishing between the first round and subsequent
+ *     rounds, but if users do want to run different logic, then give them a way of
+ *     doing that.
+ *   - EAP-Response/SIM-Client-Error - call 'recv Client-Error { ... }' and after that
+ *     send a EAP-Request/SIM-Notification indicating a General Failure.
+ *   - Anything else, enter the FAILURE-NOTIFICATION state.
+ */
+static rlm_rcode_t sim_start(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       rlm_rcode_t                     rcode;
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+
+       VALUE_PAIR                      *subtype_vp = NULL;
+       VALUE_PAIR                      *from_peer;
+
+       rcode = common_decode(&subtype_vp, &from_peer, inst, request);
+       if (rcode != RLM_MODULE_OK) return rcode;
+
+#ifdef __clang_analyzer__
+       rad_assert(subtype_vp);
+#endif
+
+       switch (subtype_vp->vp_uint16) {
+       case FR_SUBTYPE_VALUE_SIM_START:
+       {
+               VALUE_PAIR              *id;
+               fr_aka_sim_id_type_t    type;
+
+               id = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_identity, TAG_ANY);
+               if (!id) {
+                       /*
+                        *  RFC 4186 Section #9.2
+                        *
+                        *  The peer sends EAP-Response/SIM/Start in response to a valid
+                        *  EAP-Request/SIM/Start from the server.
+                        *  The peer MUST include the AT_IDENTITY attribute.  The usage of
+                        *  AT_IDENTITY is defined in Section 4.1.
+                        */
+                       REDEBUG("EAP-Response/SIM/Start does not contain AT_IDENTITY");
+                       return common_failure_notification_enter(inst, request, eap_session);
+               }
+
+               /*
+                *      Add ID hint attributes to the request to help
+                *      the user make policy decisions.
+                */
+               identity_hint_pairs_add(&type, NULL, request, id->vp_strvalue);
+               if (type == AKA_SIM_ID_TYPE_PERMANENT) {
+                       identity_to_permanent_identity(request, id,
+                                                      eap_aka_sim_session->type,
+                                                      inst->strip_permanent_identity_hint);
+               }
+
+               /*
+                *      Update cryptographic identity
+                */
+               identity_to_crypto_identity(request, eap_aka_sim_session,
+                                           (uint8_t const *)id->vp_strvalue, id->vp_length);
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.sim.recv_sim_start_response?
+                                                               inst->actions.sim.recv_sim_start_response:
+                                                               inst->actions.recv_identity_response,
+                                                     RLM_MODULE_NOOP,
+                                                     sim_start_response_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+       }
+
+       /*
+        *      Case 1 where we're allowed to send an EAP-Failure
+        *
+        *      This can happen in the case of a conservative
+        *      peer, where it refuses to provide the permanent
+        *      identity.
+        */
+       case FR_SUBTYPE_VALUE_AKA_SIM_CLIENT_ERROR:
+               client_error_debug(request, from_peer);
+
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.recv_client_error,
+                                                     RLM_MODULE_NOOP,
+                                                     common_client_error_recv_resume,
+                                                     mod_signal,
+                                                     NULL);
+
+       default:
+               /*
+                *      RFC 4187 says we *MUST* notify, not just
+                *      send an EAP-Failure in this case.
+                */
+               REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+}
+
+
+/** Resume after 'recv Identity-Response { ... }'
+ *
+ * - Perform the majority of eap_aka_sim_session_t initialisation.
+ * - If 'recv Identity-Response { ... }' returned a failure rcode, enter the FAILURE-NOTIFICATION state.
+ * - ...or continue based on the identity hint byte in the AT_IDENTITY value or EAP-Identity-Response value:
+ *   - If identity is a pseudonym, call load pseudonym { ... }.
+ *   - If identity is a fastauth identity, enter the REAUTHENTICATE state.
+ *   - If identity is a permanent identity, enter the CHALLENGE state.
+ */
+static rlm_rcode_t common_eap_identity_resume(void *instance, UNUSED void *thread, REQUEST *request, UNUSED void *rctx)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session = talloc_get_type_abort(eap_session->opaque,
+                                                                                    eap_aka_sim_session_t);
+       VALUE_PAIR                      *eap_type, *method, *identity_type;
+       fr_aka_sim_method_hint_t        running, hinted;
+       VALUE_PAIR                      *from_peer = request->packet->vps;
+
+       section_rcode_process(inst, request, eap_session, eap_aka_sim_session);
+
+       /*
+        *      Ignore attempts to change the EAP-Type
+        *      This must be done before we enter
+        *      the submodule.
+        */
+       eap_type = fr_pair_find_by_da(request->control, attr_eap_type, TAG_ANY);
+       if (eap_type) RWDEBUG("Ignoring &control:EAP-Type, this must be set *before* the EAP module is called");
+
+       method = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_method_hint, TAG_ANY);
+
+       /*
+        *      Set default configuration, we may allow these
+        *      to be toggled by attributes later.
+        */
+       eap_aka_sim_session->send_result_ind = inst->protected_success;
+       eap_aka_sim_session->id_req = AKA_SIM_NO_ID_REQ;        /* Set the default */
+
+       /*
+        *      Unless AKA-Prime is explicitly disabled,
+        *      use it... It has stronger keying, and
+        *      binds authentication to the network.
+        */
+       switch (eap_session->type) {
+       case FR_EAP_METHOD_SIM:
+               RDEBUG2("New EAP-SIM session");
+
+               running = AKA_SIM_METHOD_HINT_SIM;
+
+               eap_aka_sim_session->type = FR_EAP_METHOD_SIM;
+               eap_aka_sim_session->mac_md = EVP_sha1();       /* no checkcode support, so no checkcode_md */
+
+               /*
+                *      RFC 5448 makes no mention of being
+                *      able to use this with EAP-SIM, so it's
+                *      permanently disabled for that EAP method.
+                */
+               eap_aka_sim_session->send_at_bidding_prefer_prime = false;
+               break;
+
+       case FR_EAP_METHOD_AKA:
+               RDEBUG2("New EAP-AKA session");
+
+               running = AKA_SIM_METHOD_HINT_AKA;
+
+               eap_aka_sim_session->type = FR_EAP_METHOD_AKA;
+               eap_aka_sim_session->checkcode_md = eap_aka_sim_session->mac_md = EVP_sha1();
+               eap_aka_sim_session->send_at_bidding_prefer_prime = inst->send_at_bidding_prefer_prime;
+               break;
+
+       case FR_EAP_METHOD_AKA_PRIME:
+               RDEBUG2("New EAP-AKA' session");
+
+               running = AKA_SIM_METHOD_HINT_AKA_PRIME;
+
+               eap_aka_sim_session->type = FR_EAP_METHOD_AKA_PRIME;
+               eap_aka_sim_session->kdf = FR_KDF_VALUE_PRIME_WITH_CK_PRIME_IK_PRIME;
+               eap_aka_sim_session->checkcode_md = eap_aka_sim_session->mac_md = EVP_sha256();
+               break;
+
+       default:
+               rad_assert(0);
+       }
+
+       /*
+        *      Warn the user if the selected identity
+        *      does not match what's hinted.
+        */
+       if (method) {
+               switch (method->vp_uint32) {
+               case FR_METHOD_HINT_VALUE_AKA_PRIME:
+                       hinted = AKA_SIM_METHOD_HINT_AKA_PRIME;
+                       break;
+
+               case FR_METHOD_HINT_VALUE_AKA:
+                       hinted = AKA_SIM_METHOD_HINT_AKA;
+                       break;
+
+               case FR_METHOD_HINT_VALUE_SIM:
+                       hinted = AKA_SIM_METHOD_HINT_SIM;
+                       break;
+
+               default:
+                       hinted = running;
+                       break;
+               }
+
+               if (hinted != running) {
+                       RWDEBUG("EAP-Identity hints that EAP-%s should be started, but we're attempting EAP-%s",
+                               fr_table_str_by_value(fr_aka_sim_id_method_table, hinted, "<INVALID>"),
+                               fr_table_str_by_value(fr_aka_sim_id_method_table, running, "<INVALID>"));
+               }
+       }
+
+       /*
+        *      We always start by requesting any ID
+        *      initially as we can always negotiate down.
+        */
+       if (!identity_req_set_by_user(request, eap_aka_sim_session)) {
+               if (request->rcode == RLM_MODULE_NOTFOUND) {
+                       eap_aka_sim_session->id_req = AKA_SIM_ANY_ID_REQ;
+                       RDEBUG2("Previous section returned (%s), requesting additional identity (%s)",
+                               fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"),
+                               fr_table_str_by_value(fr_aka_sim_id_request_table, eap_aka_sim_session->id_req, "<INVALID>"));
+               } else if (inst->request_identity != AKA_SIM_NO_ID_REQ) {
+                       eap_aka_sim_session->id_req = inst->request_identity;
+                       RDEBUG2("Requesting additional identity (%s)",
+                               fr_table_str_by_value(fr_aka_sim_id_request_table, eap_aka_sim_session->id_req, "<INVALID>"));
+               }
+       }
+
+       /*
+        *      User may want us to always request an identity
+        *      initially.  The RFCs says this is also the
+        *      better way to operate, as the supplicant
+        *      can 'decorate' the identity in the identity
+        *      response.
+        */
+       if (eap_aka_sim_session->id_req != AKA_SIM_NO_ID_REQ) return common_identity_enter(inst, request, eap_session);
+
+       /*
+        *      If the identity looks like a fast re-auth id
+        *      run fast re-auth, otherwise do a fullauth.
+        */
+       identity_type = fr_pair_find_by_da(from_peer, attr_eap_aka_sim_identity_type, TAG_ANY);
+       if (identity_type) switch (identity_type->vp_uint32) {
+       case FR_IDENTITY_TYPE_VALUE_FASTAUTH:
+               return common_reauthentication_enter(inst, request, eap_session);
+
+       /*
+        *      It's a pseudonym, which now needs resolving.
+        *      The resume function here calls aka_challenge_enter
+        *      if pseudonym resolution went ok.
+        */
+       case FR_IDENTITY_TYPE_VALUE_PSEUDONYM:
+               return unlang_module_yield_to_section(request,
+                                                     inst->actions.load_pseudonym,
+                                                     RLM_MODULE_NOOP,
+                                                     pseudonym_load_resume,
+                                                     mod_signal,
+                                                     (void *)common_challenge_enter);
+
+       case FR_IDENTITY_TYPE_VALUE_PERMANENT:
+               /* FALL-THROUGH */
+
+       default:
+               break;
+       }
+
+       return common_challenge_enter(inst, request, eap_session);
+}
+
+/** Zero out the eap_aka_sim_session when we free it to clear knowledge of secret keys
+ *
+ * @param[in] eap_aka_sim_session      to free.
+ * @return 0
+ */
+static int _eap_aka_sim_session_free(eap_aka_sim_session_t *eap_aka_sim_session)
+{
+       memset(eap_aka_sim_session, 0, sizeof(*eap_aka_sim_session));
+       return 0;
+}
+
+/** Enter the EAP-IDENTITY state - State machine entry point
+ *
+ * - Process the incoming EAP-Identity-Response
+ * - Start EAP-SIM/EAP-AKA/EAP-AKA' state machine optionally calling 'recv Identity-Response { ... }'
+ */
+rlm_rcode_t aka_sim_state_machine_start(void *instance, UNUSED void *thread, REQUEST *request)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+       eap_session_t                   *eap_session = eap_session_get(request->parent);
+       eap_aka_sim_session_t           *eap_aka_sim_session;
+       VALUE_PAIR                      *vp;
+       fr_aka_sim_id_type_t            type;
+
+
+       MEM(eap_aka_sim_session = talloc_zero(eap_session, eap_aka_sim_session_t));
+       talloc_set_destructor(eap_aka_sim_session, _eap_aka_sim_session_free);
+
+       eap_session->opaque = eap_aka_sim_session;
+
+       /*
+        *      This value doesn't have be strong, but it is
+        *      good if it is different now and then.
+        */
+       eap_aka_sim_session->id = (fr_rand() & 0xff);
+
+       /*
+        *      Verify we received an EAP-Response/Identity
+        *      message before the supplicant started sending
+        *      EAP-SIM/AKA/AKA' packets.
+        */
+       if (!eap_session->identity) {
+               REDEBUG("All SIM or AKA exchanges must begin with a EAP-Response/Identity message");
+               return common_failure_notification_enter(inst, request, eap_session);
+       }
+
+       /*
+        *      Add ID hint attributes to the request to help
+        *      the user make policy decisions.
+        */
+
+       /*
+        *      Copy the EAP-Identity into and Identity
+        *      attribute to make policies easier.
+        */
+       MEM(pair_add_request(&vp, attr_eap_aka_sim_identity) >= 0);
+       fr_pair_value_bstrncpy(vp, eap_session->identity, talloc_array_length(eap_session->identity) - 1);
+
+       /*
+        *      Add ID hint attributes to the request to help
+        *      the user make policy decisions.
+        */
+       identity_hint_pairs_add(&type, NULL, request, eap_session->identity);
+       if (type == AKA_SIM_ID_TYPE_PERMANENT) {
+               identity_to_permanent_identity(request, vp, eap_session->type,
+                                              inst->strip_permanent_identity_hint);
+       }
+
+       identity_to_crypto_identity(request, eap_aka_sim_session,
+                                   (uint8_t const *)eap_session->identity,
+                                   talloc_array_length(eap_session->identity) - 1);
+
+       /*
+        *      Running the same section as Identity-Response
+        *      makes policies significantly easier.
+        */
+       return unlang_module_yield_to_section(request,
+                                             inst->actions.recv_identity_response,
+                                             RLM_MODULE_NOOP,
+                                             common_eap_identity_resume,
+                                             mod_signal,
+                                             NULL);
+}
diff --git a/src/lib/eap_aka_sim/state_machine.h b/src/lib/eap_aka_sim/state_machine.h
new file mode 100644 (file)
index 0000000..0f3fc23
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file lib/eap_aka_sim/state_machine.h
+ * @brief Declarations for EAP-AKA
+ *
+ * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ *
+ * @copyright 2016-2019 The FreeRADIUS server project
+ * @copyright 2016-2019 Network RADIUS SARL <sales@networkradius.com>
+ */
+RCSIDH(lib_eap_aka_sim_state_machine_h, "$Id$")
+
+#include <freeradius-devel/eap_aka_sim/base.h>
+
+/** Cache sections to call on various protocol events
+ *
+ */
+typedef struct {
+       union {
+               struct {
+                       CONF_SECTION    *send_aka_identity_request;     //!< Called when we're about to request a
+                                                                       ///< different identity.
+                       CONF_SECTION    *recv_aka_identity_response;    //!< Called when we receive a new identity.
+
+                       CONF_SECTION    *recv_authentication_reject;    //!< Called if the supplicant rejects the
+                                                                       ///< authentication attempt.
+                       CONF_SECTION    *recv_syncronization_failure;   //!< Called if the supplicant determines
+                                                                       ///< the AUTN value is invalid.
+                                                                       ///< Usually used for resyncing with the HLR.
+               } aka;
+
+               struct {
+                       CONF_SECTION    *send_sim_start_request;        //!< Called when we're about to request a
+                                                                       ///< different identity.
+                       CONF_SECTION    *recv_sim_start_response;       //!< Called when we receive a new identity.
+
+               } sim;
+       };
+
+       CONF_SECTION    *send_identity_request;         //!< Called when we're about to request a
+                                                       ///< different identity.
+       CONF_SECTION    *recv_identity_response;        //!< Called when we receive a new identity.
+
+       CONF_SECTION    *send_challenge_request;        //!< Called when we're about to send a
+                                                       ///< a challenge.
+       CONF_SECTION    *recv_challenge_response;       //!< Called when we receive a response
+                                                       ///< to a previous challenge.
+
+       CONF_SECTION    *send_fast_reauth_request;      //!< Called when we're about to send a
+                                                       ///< Fast-Reauth-Request.
+       CONF_SECTION    *recv_fast_reauth_response;     //!< Called when we receive a response
+                                                       ///< to a previous Fast-Reauth-Request.
+
+       CONF_SECTION    *recv_client_error;             //!< Called if the supplicant experiences
+                                                       ///< an error of some kind.
+
+       CONF_SECTION    *send_reauthentication_request; //!< Challenge the supplicant with an MK
+                                                       ///< from an existing session.
+
+       CONF_SECTION    *recv_reauthentication_response; //!< Process the reauthentication response
+                                                       ///< from the supplicant.
+
+       CONF_SECTION    *send_failure_notification;     //!< Called when we're about to send a
+                                                       ///< failure notification.
+       CONF_SECTION    *send_success_notification;     //!< Called when we're about to send a
+                                                       ///< success notification.
+       CONF_SECTION    *recv_failure_notification_ack; //!< Called when the supplicant ACKs our
+                                                       ///< failure notification.
+       CONF_SECTION    *recv_success_notification_ack; //!< Called when the supplicant ACKs our
+                                                       ///< success notification.
+
+       CONF_SECTION    *send_eap_success;              //!< Called when we send an EAP-Success message.
+       CONF_SECTION    *send_eap_failure;              //!< Called when we send an EAP-Failure message.
+
+       CONF_SECTION    *load_pseudonym;                //!< Resolve a pseudonym to a permanent ID.
+       CONF_SECTION    *store_pseudonym;               //!< Store a permanent ID to pseudonym mapping.
+       CONF_SECTION    *clear_pseudonym;               //!< Clear pseudonym to permanent ID mapping.
+
+       CONF_SECTION    *load_session;                  //!< Load cached authentication vectors.
+       CONF_SECTION    *store_session;                 //!< Store authentication vectors.
+       CONF_SECTION    *clear_session;                 //!< Clear authentication vectors.
+} eap_aka_sim_actions_t;
+
+typedef struct {
+       eap_type_t                      type;                           //!< Either FR_TYPE_AKA, or FR_TYPE_AKA_PRIME.
+
+       bool                            challenge_success;              //!< Whether we received the correct
+                                                                       ///< challenge response.
+       bool                            reauthentication_success;       //!< Whether we got a valid reauthentication
+                                                                       ///< response.
+
+       bool                            allow_encrypted;                //!< Whether we can send encrypted
+                                                                       ///< attributes at this phase of the attempt.
+
+       uint16_t                        failure_type;                   //!< One of the following values:
+                                                                       ///< - FR_NOTIFICATION_VALUE_GENERAL_FAILURE_AFTER_AUTHENTICATION
+                                                                       ///< - FR_NOTIFICATION_VALUE_TEMPORARILY_DENIED
+                                                                       ///< - FR_NOTIFICATION_VALUE_NOT_SUBSCRIBED
+                                                                       ///< - FR_NOTIFICATION_VALUE_GENERAL_FAILURE
+
+       /*
+        *      Identity management
+        */
+       char                            *pseudonym_sent;                //!< Pseudonym value we sent.
+       char                            *fastauth_sent;                 //!< Fastauth value we sent.
+
+       fr_aka_sim_id_req_type_t        id_req;                         //!< The type of identity we're requesting
+       fr_aka_sim_id_req_type_t        last_id_req;                    //!< The last identity request we sent.
+
+       /*
+        *      Per-session configuration
+        */
+
+       bool                            send_result_ind;                //!< Say that we would like to use protected
+                                                                       ///< result indications
+                                                                       ///< (AKA-Notification-Success).
+       bool                            send_at_bidding_prefer_prime;   //!< Indicate that we prefer EAP-AKA' and
+                                                                       ///< include an AT_BIDDING attribute.
+
+       bool                            prev_recv_sync_failure;         //!< We only allow one sync failure per
+                                                                       ///< session for sanity.
+
+
+       fr_aka_sim_keys_t               keys;                           //!< Various EAP-AKA/AKA'/SIMkeys.
+
+       EVP_MD const                    *checkcode_md;                  //!< Message digest we use to generate the
+                                                                       ///< checkcode. EVP_sha1() for EAP-AKA/SIM,
+                                                                       ///< EVP_sha256() for EAP-AKA'.
+       fr_aka_sim_checkcode_t          *checkcode_state;               //!< Digest of all identity packets we've seen.
+       uint8_t                         checkcode[32];                  //!< Checkcode we calculated.
+       size_t                          checkcode_len;                  //!< 0, 20 or 32 bytes.
+
+
+       uint16_t                        kdf;                            //!< The key derivation function used to derive
+                                                                       ///< session keys.
+
+       EVP_MD const                    *mac_md;                        //!< HMAC-MD we use to generate the MAC.
+                                                                       ///< EVP_sha1() for EAP-AKA, EVP_sha256()
+                                                                       ///< for EAP-AKA'.
+
+       int                             id;                             //!< Packet ID. (replay protection).
+} eap_aka_sim_session_t;
+
+typedef struct {
+       char const                      *network_name;                  //!< Network ID as described by RFC 5448.
+       fr_aka_sim_id_req_type_t        request_identity;               //!< Whether we always request the identity of
+                                                                       ///< the subscriber.
+       size_t                          ephemeral_id_length;            //!< The length of any identities we're
+                                                                       ///< generating.
+       CONF_SECTION                    *virtual_server;                //!< Virtual server.
+       bool                            protected_success;              //!< Send a success notification as well as
+                                                                       ///< and EAP-Success packet.
+       bool                            send_at_bidding_prefer_prime;   //!< Include the AT bidding attribute in
+                                                                       ///< challenge requests.
+       bool                            send_at_bidding_prefer_prime_is_set;    //!< Whether the user specified a value.
+
+       bool                            strip_permanent_identity_hint;  //!< Control whether the hint byte is stripped
+                                                                       ///< when populating Permanent-Identity.
+
+       eap_aka_sim_actions_t           actions;                        //!< Pre-compiled virtual server sections.
+} eap_aka_sim_common_conf_t;
+
+/*
+ *     The main entry point
+ */
+rlm_rcode_t aka_sim_state_machine_start(void *instance, UNUSED void *thread, REQUEST *request);
similarity index 53%
rename from src/lib/sim/vector.c
rename to src/lib/eap_aka_sim/vector.c
index 821cbb07406a2bdefe7708032ef6e97da17f39d9..a77201b31b13483586afcfdf6a33f5d8b3c18cee 100644 (file)
@@ -16,7 +16,7 @@
 
 /**
  * $Id$
- * @file src/lib/sim/vector.c
+ * @file src/lib/aka-sim/vector.c
  * @brief Retrieve or derive vectors for EAP-SIM.
  *
  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
@@ -28,10 +28,14 @@ RCSID("$Id$")
 
 #include <freeradius-devel/eap/base.h>
 #include <freeradius-devel/eap/types.h>
+#include <freeradius-devel/sim/common.h>
+#include <freeradius-devel/sim/milenage.h>
+#include <freeradius-devel/sim/ts_34_108.h>
+#include <freeradius-devel/sim/comp128.h>
+#include <freeradius-devel/protocol/freeradius/freeradius.internal.sim.h>
+
 #include "base.h"
 #include "attrs.h"
-#include "comp128.h"
-#include "milenage.h"
 
 #include <freeradius-devel/server/rad_assert.h>
 
@@ -71,9 +75,8 @@ static int vector_opc_from_op(REQUEST *request, uint8_t const **out, uint8_t opc
        return 1;
 }
 
-static int vector_gsm_from_ki(eap_session_t *eap_session, VALUE_PAIR *vps, int idx, fr_sim_keys_t *keys)
+static int vector_gsm_from_ki(REQUEST *request, VALUE_PAIR *vps, int idx, fr_aka_sim_keys_t *keys)
 {
-       REQUEST         *request = eap_session->request;
        VALUE_PAIR      *ki_vp, *version_vp;
        uint8_t         opc_buff[MILENAGE_OPC_SIZE];
        uint8_t const   *opc_p;
@@ -100,14 +103,14 @@ static int vector_gsm_from_ki(eap_session_t *eap_session, VALUE_PAIR *vps, int i
        version_vp = fr_pair_find_by_da(vps, attr_sim_algo_version, TAG_ANY);
        if (!version_vp) {
                if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
-               version = opc_p ? 4 : 3;
+               version = opc_p ? FR_SIM_ALGO_VERSION_VALUE_COMP128_4 : FR_SIM_ALGO_VERSION_VALUE_COMP128_3;
        /*
-        *      Version we explicitly specified, see if we can find the prerequisite
+        *      Version was explicitly specified, see if we can find the prerequisite
         *      attributes.
         */
        } else {
                version = version_vp->vp_uint32;
-               if (version == 4) {
+               if (version == FR_SIM_ALGO_VERSION_VALUE_COMP128_4) {
                        if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
                        if (!opc_p) {
                                RPEDEBUG2("No &control:%s or &control:%s found, "
@@ -117,34 +120,34 @@ static int vector_gsm_from_ki(eap_session_t *eap_session, VALUE_PAIR *vps, int i
                }
        }
 
-       for (i = 0; i < SIM_VECTOR_GSM_RAND_SIZE; i += sizeof(uint32_t)) {
+       for (i = 0; i < AKA_SIM_VECTOR_GSM_RAND_SIZE; i += sizeof(uint32_t)) {
                uint32_t rand = fr_rand();
                memcpy(&keys->gsm.vector[idx].rand[i], &rand, sizeof(rand));
        }
 
        switch (version) {
-       case 1:
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_1:
                comp128v1(keys->gsm.vector[idx].sres,
                          keys->gsm.vector[idx].kc,
                          ki_vp->vp_octets,
                          keys->gsm.vector[idx].rand);
                break;
 
-       case 2:
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_2:
                comp128v23(keys->gsm.vector[idx].sres,
                           keys->gsm.vector[idx].kc,
                           ki_vp->vp_octets,
                           keys->gsm.vector[idx].rand, true);
                break;
 
-       case 3:
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_3:
                comp128v23(keys->gsm.vector[idx].sres,
                           keys->gsm.vector[idx].kc,
                           ki_vp->vp_octets,
                           keys->gsm.vector[idx].rand, false);
                break;
 
-       case 4:
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_4:
                if (milenage_gsm_generate(keys->gsm.vector[idx].sres,
                                          keys->gsm.vector[idx].kc,
                                          opc_p,
@@ -165,65 +168,64 @@ static int vector_gsm_from_ki(eap_session_t *eap_session, VALUE_PAIR *vps, int i
         */
        memcpy(keys->auc.ki, ki_vp->vp_octets, sizeof(keys->auc.ki));
        memcpy(keys->auc.opc, opc_p, sizeof(keys->auc.opc));
-       keys->vector_src = SIM_VECTOR_SRC_KI;
+       keys->vector_src = AKA_SIM_VECTOR_SRC_KI;
 
        return 0;
 }
 
-static int vector_gsm_from_triplets(eap_session_t *eap_session, VALUE_PAIR *vps,
-                                   int idx, fr_sim_keys_t *keys)
+static int vector_gsm_from_triplets(REQUEST *request, VALUE_PAIR *vps,
+                                   int idx, fr_aka_sim_keys_t *keys)
 {
-       REQUEST         *request = eap_session->request;
        VALUE_PAIR      *rand = NULL, *sres = NULL, *kc = NULL;
        fr_cursor_t     cursor;
        int             i;
 
-       for (i = 0, (kc = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_sim_kc));
+       for (i = 0, (kc = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_sim_kc));
             (i < idx) && (kc = fr_cursor_next(&cursor));
             i++);
        if (!kc) {
                RDEBUG3("No &control:%s[%i] attribute found, not using GSM triplets",
-                       attr_eap_sim_kc->name, idx);
+                       attr_eap_aka_sim_kc->name, idx);
                return 1;
        }
-       if (kc->vp_length != SIM_VECTOR_GSM_KC_SIZE) {
-               REDEBUG("&control:%s[%i] is not " STRINGIFY(SIM_VECTOR_GSM_KC_SIZE) " bytes, got %zu bytes",
-                       attr_eap_sim_kc->name, idx, kc->vp_length);
+       if (kc->vp_length != AKA_SIM_VECTOR_GSM_KC_SIZE) {
+               REDEBUG("&control:%s[%i] is not " STRINGIFY(AKA_SIM_VECTOR_GSM_KC_SIZE) " bytes, got %zu bytes",
+                       attr_eap_aka_sim_kc->name, idx, kc->vp_length);
                return -1;
        }
 
-       for (i = 0, (rand = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_sim_rand));
+       for (i = 0, (rand = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_sim_rand));
             (i < idx) && (rand = fr_cursor_next(&cursor));
             i++);
        if (!rand) {
                RDEBUG3("No &control:%s[%i] attribute found, not using GSM triplets",
-                       attr_eap_sim_rand->name, idx);
+                       attr_eap_aka_sim_rand->name, idx);
                return 1;
        }
-       if (rand->vp_length != SIM_VECTOR_GSM_RAND_SIZE) {
+       if (rand->vp_length != AKA_SIM_VECTOR_GSM_RAND_SIZE) {
                REDEBUG("&control:EAP-SIM-Rand[%i] is not " STRINGIFY(SIM_RAND_SIZE) " bytes, got %zu bytes",
                        idx, rand->vp_length);
                return -1;
        }
 
-       for (i = 0, (sres = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_sim_sres));
+       for (i = 0, (sres = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_sim_sres));
             (i < idx) && (sres = fr_cursor_next(&cursor));
             i++);
        if (!sres) {
                RDEBUG3("No &control:%s[%i] attribute found, not using GSM triplets",
-                       attr_eap_sim_sres->name, idx);
+                       attr_eap_aka_sim_sres->name, idx);
                return 1;
        }
-       if (sres->vp_length != SIM_VECTOR_GSM_SRES_SIZE) {
-               REDEBUG("&control:%s[%i] is not " STRINGIFY(SIM_VECTOR_GSM_SRES_SIZE) " bytes, got %zu bytes",
-                       attr_eap_sim_sres->name, idx, sres->vp_length);
+       if (sres->vp_length != AKA_SIM_VECTOR_GSM_SRES_SIZE) {
+               REDEBUG("&control:%s[%i] is not " STRINGIFY(AKA_SIM_VECTOR_GSM_SRES_SIZE) " bytes, got %zu bytes",
+                       attr_eap_aka_sim_sres->name, idx, sres->vp_length);
                return -1;
        }
 
-       memcpy(keys->gsm.vector[idx].kc, kc->vp_strvalue, SIM_VECTOR_GSM_KC_SIZE);
-       memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, SIM_VECTOR_GSM_RAND_SIZE);
-       memcpy(keys->gsm.vector[idx].sres, sres->vp_octets, SIM_VECTOR_GSM_SRES_SIZE);
-       keys->vector_src = SIM_VECTOR_SRC_TRIPLETS;
+       memcpy(keys->gsm.vector[idx].kc, kc->vp_strvalue, AKA_SIM_VECTOR_GSM_KC_SIZE);
+       memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, AKA_SIM_VECTOR_GSM_RAND_SIZE);
+       memcpy(keys->gsm.vector[idx].sres, sres->vp_octets, AKA_SIM_VECTOR_GSM_SRES_SIZE);
+       keys->vector_src = AKA_SIM_VECTOR_SRC_TRIPLETS;
 
        return 0;
 }
@@ -231,10 +233,9 @@ static int vector_gsm_from_triplets(eap_session_t *eap_session, VALUE_PAIR *vps,
 /** Derive triplets from quintuplets
  *
  */
-static int vector_gsm_from_quintuplets(eap_session_t *eap_session, VALUE_PAIR *vps,
-                                      int idx, fr_sim_keys_t *keys)
+static int vector_gsm_from_quintuplets(REQUEST *request, VALUE_PAIR *vps,
+                                      int idx, fr_aka_sim_keys_t *keys)
 {
-       REQUEST         *request = eap_session->request;
        fr_cursor_t     cursor;
 
        VALUE_PAIR      *ck = NULL, *ik = NULL, *rand = NULL, *xres = NULL;
@@ -244,59 +245,59 @@ static int vector_gsm_from_quintuplets(eap_session_t *eap_session, VALUE_PAIR *v
        /*
         *      Fetch CK
         */
-       for (i = 0, (ck = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_ck));
+       for (i = 0, (ck = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_sim_ck));
             (i < idx) && (ck = fr_cursor_next(&cursor));
             i++);
        if (!ck) {
                RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation",
-                       attr_eap_aka_ck->name, idx);
+                       attr_eap_aka_sim_ck->name, idx);
                return 1;
        }
 
        /*
         *      Fetch IK
         */
-       for (i = 0, (ik = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_ik));
+       for (i = 0, (ik = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_sim_ik));
             (i < idx) && (ik = fr_cursor_next(&cursor));
             i++);
        if (!ik) {
                RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation",
-                       attr_eap_aka_ik->name, idx);
+                       attr_eap_aka_sim_ik->name, idx);
                return 1;
        }
 
        /*
         *      Fetch RAND
         */
-       for (i = 0, (rand = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_rand));
+       for (i = 0, (rand = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_sim_rand));
             (i < idx) && (rand = fr_cursor_next(&cursor));
             i++);
        if (!rand) {
                RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation",
-                       attr_eap_aka_rand->name, idx);
+                       attr_eap_aka_sim_rand->name, idx);
                return 1;
        }
 
-       if (rand->vp_length != SIM_VECTOR_UMTS_RAND_SIZE) {
+       if (rand->vp_length != AKA_SIM_VECTOR_UMTS_RAND_SIZE) {
                REDEBUG("&control:%s[%i] incorrect length.  Expected "
-                       STRINGIFY(SIM_VECTOR_UMTS_RAND_SIZE) " bytes, "
-                       "got %zu bytes", attr_eap_aka_rand->name, idx, rand->vp_length);
+                       STRINGIFY(AKA_SIM_VECTOR_UMTS_RAND_SIZE) " bytes, "
+                       "got %zu bytes", attr_eap_aka_sim_rand->name, idx, rand->vp_length);
                return -1;
        }
 
        /*
         *      Fetch XRES
         */
-       for (i = 0, (xres = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_xres));
+       for (i = 0, (xres = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_sim_xres));
             (i < idx) && (xres = fr_cursor_next(&cursor));
             i++);
        if (!xres) {
                RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation",
-                       attr_eap_aka_xres->name, idx);
+                       attr_eap_aka_sim_xres->name, idx);
                return 1;
        }
 
-       memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, SIM_VECTOR_GSM_RAND_SIZE);
+       memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, AKA_SIM_VECTOR_GSM_RAND_SIZE);
 
        milenage_gsm_from_umts(keys->gsm.vector[idx].sres,
                               keys->gsm.vector[idx].kc,
@@ -304,7 +305,7 @@ static int vector_gsm_from_quintuplets(eap_session_t *eap_session, VALUE_PAIR *v
                               ck->vp_octets,
                               xres->vp_octets);
 
-       keys->vector_src = SIM_VECTOR_SRC_QUINTUPLETS;
+       keys->vector_src = AKA_SIM_VECTOR_SRC_QUINTUPLETS;
 
        return 0;
 }
@@ -313,11 +314,11 @@ static int vector_gsm_from_quintuplets(eap_session_t *eap_session, VALUE_PAIR *v
  *
  * Hunt for a source of SIM triplets
  *
- * @param eap_session          The current eap_session.
- * @param vps                  List to hunt for triplets in.
- * @param idx                  To write EAP-SIM triplets to.
- * @param keys                 EAP session keys.
- * @param src                  Forces triplets to be retrieved from a particular src
+ * @param[in] request          The current subrequest.
+ * @param[in] vps              List to hunt for triplets in.
+ * @param[in] idx              To write EAP-SIM triplets to.
+ * @param[in] keys             EAP session keys.
+ * @param[in] src              Forces triplets to be retrieved from a particular src
  *                             and ensures if multiple triplets are being retrieved
  *                             that they all come from the same src.
  * @return
@@ -325,41 +326,40 @@ static int vector_gsm_from_quintuplets(eap_session_t *eap_session, VALUE_PAIR *v
  *     - 0     Vector was retrieved OK and written to the specified index.
  *     - -1    Error retrieving vector from the specified src.
  */
-int fr_sim_vector_gsm_from_attrs(eap_session_t *eap_session, VALUE_PAIR *vps,
-                                int idx, fr_sim_keys_t *keys, fr_sim_vector_src_t *src)
+int fr_aka_sim_vector_gsm_from_attrs(REQUEST *request, VALUE_PAIR *vps,
+                                    int idx, fr_aka_sim_keys_t *keys, fr_aka_sim_vector_src_t *src)
 {
-       REQUEST         *request = eap_session->request;
        int             ret;
 
        rad_assert(idx >= 0 && idx < 3);
-       rad_assert((keys->vector_type == SIM_VECTOR_NONE) || (keys->vector_type == SIM_VECTOR_GSM));
+       rad_assert((keys->vector_type == AKA_SIM_VECTOR_NONE) || (keys->vector_type == AKA_SIM_VECTOR_GSM));
 
        switch (*src) {
        default:
-       case SIM_VECTOR_SRC_KI:
-               ret = vector_gsm_from_ki(eap_session, vps, idx, keys);
+       case AKA_SIM_VECTOR_SRC_KI:
+               ret = vector_gsm_from_ki(request, vps, idx, keys);
                if (ret == 0) {
-                       *src = SIM_VECTOR_SRC_KI;
+                       *src = AKA_SIM_VECTOR_SRC_KI;
                        break;
                }
                if (ret < 0) return -1;
-               if (*src != SIM_VECTOR_SRC_AUTO) return 1;
+               if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
                /* FALL-THROUGH */
 
-       case SIM_VECTOR_SRC_TRIPLETS:
-               ret = vector_gsm_from_triplets(eap_session, vps, idx, keys);
+       case AKA_SIM_VECTOR_SRC_TRIPLETS:
+               ret = vector_gsm_from_triplets(request, vps, idx, keys);
                if (ret == 0) {
-                       *src = SIM_VECTOR_SRC_TRIPLETS;
+                       *src = AKA_SIM_VECTOR_SRC_TRIPLETS;
                        break;
                }
                if (ret < 0) return -1;
-               if (*src != SIM_VECTOR_SRC_AUTO) return 1;
+               if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
                /* FALL-THROUGH */
 
-       case SIM_VECTOR_SRC_QUINTUPLETS:
-               ret = vector_gsm_from_quintuplets(eap_session, vps, idx, keys);
+       case AKA_SIM_VECTOR_SRC_QUINTUPLETS:
+               ret = vector_gsm_from_quintuplets(request, vps, idx, keys);
                if (ret == 0) {
-                       *src = SIM_VECTOR_SRC_QUINTUPLETS;
+                       *src = AKA_SIM_VECTOR_SRC_QUINTUPLETS;
                        break;
                }
                if (ret < 0) return -1;
@@ -378,90 +378,127 @@ int fr_sim_vector_gsm_from_attrs(eap_session_t *eap_session, VALUE_PAIR *vps,
                /*
                 *      Don't change colon indent, matches other messages later...
                 */
-               RHEXDUMP_INLINE2(
-                               keys->gsm.vector[idx].kc, SIM_VECTOR_GSM_KC_SIZE,
-                               "KC           :");
-               RHEXDUMP_INLINE2(
-                               keys->gsm.vector[idx].rand, SIM_VECTOR_GSM_RAND_SIZE,
-                               "RAND         :");
-               RHEXDUMP_INLINE2(
-                               keys->gsm.vector[idx].sres, SIM_VECTOR_GSM_SRES_SIZE,
-                               "SRES         :");
+               RHEXDUMP_INLINE2(keys->gsm.vector[idx].kc, AKA_SIM_VECTOR_GSM_KC_SIZE,
+                                "KC           :");
+               RHEXDUMP_INLINE2(keys->gsm.vector[idx].rand, AKA_SIM_VECTOR_GSM_RAND_SIZE,
+                                "RAND         :");
+               RHEXDUMP_INLINE2(keys->gsm.vector[idx].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE,
+                                "SRES         :");
                REXDENT();
        }
 
-       keys->vector_type = SIM_VECTOR_GSM;
+       keys->vector_type = AKA_SIM_VECTOR_GSM;
 
        return 0;
 }
 
-static int vector_umts_from_ki(REQUEST *request, VALUE_PAIR *vps, fr_sim_keys_t *keys)
+static int vector_umts_from_ki(REQUEST *request, VALUE_PAIR *vps, fr_aka_sim_keys_t *keys)
 {
        VALUE_PAIR      *ki_vp, *amf_vp, *sqn_vp, *version_vp;
 
-       uint64_t        sqn;
-       uint8_t         amf_buff[MILENAGE_AMF_SIZE] = { 0x00, 0x00 };
-       uint8_t         opc_buff[MILENAGE_OPC_SIZE];
-       uint8_t const   *opc_p;
-       uint32_t        version = 4;
+       size_t          ki_size, amf_size;
+       uint32_t        version = FR_SIM_ALGO_VERSION_VALUE_MILENAGE;
        int             i;
 
+       /*
+        *      Select the algorithm (default to Milenage)
+        */
+       version_vp = fr_pair_find_by_da(vps, attr_sim_algo_version, TAG_ANY);
+       if (version_vp) version = version_vp->vp_uint32;
+
+       /*
+        *      Get expected input sizes
+        */
+       switch (version) {
+       case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
+               ki_size = MILENAGE_KI_SIZE;
+               amf_size = MILENAGE_AMF_SIZE;
+               break;
+
+       case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
+               ki_size = TS_34_108_KI_SIZE;
+               amf_size = TS_34_108_AMF_SIZE;
+               break;
+
+       /*
+        *      GSM algos
+        */
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_1:
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_2:
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_3:
+       case FR_SIM_ALGO_VERSION_VALUE_COMP128_4:
+               REDEBUG("COMP128-* algorithms cannot generate UMTS vectors");
+               return -1;
+
+       default:
+               REDEBUG("Unknown/unsupported algorithm %i", version);
+               return -1;
+       }
+
+       /*
+        *      Find the Ki VP and check its length
+        */
        ki_vp = fr_pair_find_by_da(vps, attr_sim_ki, TAG_ANY);
        if (!ki_vp) {
                RDEBUG3("No &control:%s found, not generating quintuplets locally", attr_sim_ki->name);
                return 1;
-       } else if (ki_vp->vp_length != MILENAGE_KI_SIZE) {
-               REDEBUG("&control:%s has incorrect length, expected %u bytes got %zu bytes",
-                       attr_sim_ki->name, MILENAGE_KI_SIZE, ki_vp->vp_length);
+       } else if (ki_vp->vp_length != ki_size) {
+               REDEBUG("&control:%s has incorrect length, expected %zu bytes got %zu bytes",
+                       attr_sim_ki->name, ki_size, ki_vp->vp_length);
                return -1;
        }
 
-       if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
+       /*
+        *      Find the Sequence Number VP or default to SQN = 2
+        */
+       sqn_vp = fr_pair_find_by_da(vps, attr_sim_sqn, TAG_ANY);
+       keys->sqn = sqn_vp ? sqn_vp->vp_uint64 : 2;     /* 2 is the lowest valid SQN on our side */
 
+       /*
+        *      Check if we have an AMF value
+        */
        amf_vp = fr_pair_find_by_da(vps, attr_sim_amf, TAG_ANY);
        if (amf_vp) {
-               if (amf_vp->vp_length != sizeof(amf_buff)) {
-                       REDEBUG("&control:%s has incorrect length, expected %u bytes got %zu bytes",
-                               attr_sim_amf->name, MILENAGE_AMF_SIZE, amf_vp->vp_length);
+               if (amf_vp->vp_length != amf_size) {
+                       REDEBUG("&control:%s has incorrect length, expected %zu bytes got %zu bytes",
+                               attr_sim_amf->name, amf_size, amf_vp->vp_length);
                        return -1;
                }
-               memcpy(amf_buff, amf_vp->vp_octets, sizeof(amf_buff));
        }
 
-       sqn_vp = fr_pair_find_by_da(vps, attr_sim_sqn, TAG_ANY);
-       sqn = sqn_vp ? sqn_vp->vp_uint64 : 2;
-
        /*
-        *      We default to milenage
+        *      Generate rand
         */
-       version_vp = fr_pair_find_by_da(vps, attr_sim_algo_version, TAG_ANY);
-       if (version_vp) version = version_vp->vp_uint32;
-
-       for (i = 0; i < SIM_VECTOR_UMTS_RAND_SIZE; i += sizeof(uint32_t)) {
+       for (i = 0; i < AKA_SIM_VECTOR_UMTS_RAND_SIZE; i += sizeof(uint32_t)) {
                uint32_t rand = fr_rand();
                memcpy(&keys->umts.vector.rand[i], &rand, sizeof(rand));
        }
 
        switch (version) {
-       case 4:
+       case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
        {
-               uint8_t sqn_buff[MILENAGE_SQN_SIZE];
+               uint8_t         amf_buff[MILENAGE_AMF_SIZE] = { 0x00, 0x00 };
+               uint8_t         sqn_buff[MILENAGE_SQN_SIZE];
+               uint8_t         opc_buff[MILENAGE_OPC_SIZE];
+               uint8_t const   *opc_p;
+
+               if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
 
-               keys->sqn = sqn_vp ? sqn_vp->vp_uint64 : 0;
                uint48_to_buff(sqn_buff, keys->sqn);
+               if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
 
                RDEBUG3("Milenage inputs");
                RINDENT();
                /*
                 *      Don't change colon indent, matches other messages later...
                 */
-               RHEXDUMP_INLINE3(ki_vp->vp_octets, MILENAGE_KI_SIZE,
+               RHEXDUMP_INLINE3(ki_vp->vp_octets, ki_size,
                                 "Ki           :");
-               RHEXDUMP_INLINE3(opc_p, MILENAGE_OPC_SIZE,
+               RHEXDUMP_INLINE3(opc_p, sizeof(opc_buff),
                                 "OPc          :");
-               RHEXDUMP_INLINE3(sqn_buff, MILENAGE_SQN_SIZE,
+               RHEXDUMP_INLINE3(sqn_buff, sizeof(sqn_buff),
                                 "SQN          :");
-               RHEXDUMP_INLINE3(amf_buff, MILENAGE_AMF_SIZE,
+               RHEXDUMP_INLINE3(amf_buff, sizeof(amf_buff),
                                 "AMF          :");
                REXDENT();
 
@@ -473,12 +510,12 @@ static int vector_umts_from_ki(REQUEST *request, VALUE_PAIR *vps, fr_sim_keys_t
                                           opc_p,
                                           amf_buff,
                                           ki_vp->vp_octets,
-                                          sqn,
+                                          keys->sqn,
                                           keys->umts.vector.rand) < 0) {
                        RPEDEBUG2("Failed deriving UMTS Quintuplet");
                        return -1;
                }
-               keys->umts.vector.xres_len = 8;
+               keys->umts.vector.xres_len = MILENAGE_RES_SIZE;
 
                /*
                 *      Store the keys we used for possible AUTS
@@ -486,18 +523,65 @@ static int vector_umts_from_ki(REQUEST *request, VALUE_PAIR *vps, fr_sim_keys_t
                 */
                memcpy(keys->auc.ki, ki_vp->vp_octets, sizeof(keys->auc.ki));
                memcpy(keys->auc.opc, opc_p, sizeof(keys->auc.opc));
-               keys->vector_src = SIM_VECTOR_SRC_KI;
+               keys->vector_src = AKA_SIM_VECTOR_SRC_KI;
        }
                return 0;
 
-       case 1:
-       case 2:
-       case 3:
-               REDEBUG("Only Milenage can be used to generate quintuplets");
-               return -1;
+       /*
+        *      This is a dummy algorithm and should be used for testing
+        *      purposes only.  It offers no security and can be trivially
+        *      broken and the original Ki retrieved.
+        */
+       case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
+       {
+               uint8_t         amf_buff[TS_34_108_AMF_SIZE] = { 0x00, 0x00 };
+               uint8_t         sqn_buff[TS_34_108_SQN_SIZE];
+
+               uint48_to_buff(sqn_buff, keys->sqn);
+
+               if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
+
+               RDEBUG3("TS-34-108-UMTS inputs");
+               RINDENT();
+               /*
+                *      Don't change colon indent, matches other messages later...
+                */
+               RHEXDUMP_INLINE3(
+                               ki_vp->vp_octets, ki_size,
+                               "Ki           :");
+               RHEXDUMP_INLINE3(
+                               sqn_buff, sizeof(sqn_buff),
+                               "SQN          :");
+               RHEXDUMP_INLINE3(
+                               amf_buff, sizeof(amf_buff),
+                               "AMF          :");
+               REXDENT();
+
+               if (ts_34_108_umts_generate(keys->umts.vector.autn,
+                                           keys->umts.vector.ik,
+                                           keys->umts.vector.ck,
+                                           keys->umts.vector.ak,
+                                           keys->umts.vector.xres,
+                                           amf_buff,
+                                           ki_vp->vp_octets,
+                                           keys->sqn,
+                                           keys->umts.vector.rand) < 0) {
+                       RPEDEBUG2("Failed deriving UMTS Quintuplet");
+                       return -1;
+               }
+               keys->umts.vector.xres_len = TS_34_108_RES_SIZE;
+
+               /*
+                *      Store the keys we used for possible AUTS
+                *      validation later.
+                */
+               memcpy(keys->auc.ki, ki_vp->vp_octets, sizeof(keys->auc.ki));
+               keys->vector_src = AKA_SIM_VECTOR_SRC_KI;
+       }
+               return 0;
 
        default:
-               REDEBUG("Unknown/unsupported algorithm %i", version);
+               rad_assert(0);
                return -1;
        }
 }
@@ -505,7 +589,7 @@ static int vector_umts_from_ki(REQUEST *request, VALUE_PAIR *vps, fr_sim_keys_t
 /** Get one set of quintuplets from the request
  *
  */
-static int vector_umts_from_quintuplets(REQUEST *request, VALUE_PAIR *vps, fr_sim_keys_t *keys)
+static int vector_umts_from_quintuplets(REQUEST *request, VALUE_PAIR *vps, fr_aka_sim_keys_t *keys)
 {
        VALUE_PAIR      *rand_vp = NULL, *xres_vp = NULL, *ck_vp = NULL, *ik_vp = NULL;
        VALUE_PAIR      *autn_vp = NULL, *sqn_vp = NULL, *ak_vp = NULL;
@@ -513,90 +597,90 @@ static int vector_umts_from_quintuplets(REQUEST *request, VALUE_PAIR *vps, fr_si
        /*
         *      Fetch AUTN
         */
-       autn_vp = fr_pair_find_by_da(vps, attr_eap_aka_autn, TAG_ANY);
+       autn_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_autn, TAG_ANY);
        if (!autn_vp) {
-               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_autn->name);
+               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_autn->name);
                return 1;
        }
 
-       if (autn_vp->vp_length > SIM_VECTOR_UMTS_AUTN_SIZE) {
+       if (autn_vp->vp_length > AKA_SIM_VECTOR_UMTS_AUTN_SIZE) {
                REDEBUG("&control:%s incorrect length.  Expected "
-                       STRINGIFY(SIM_VECTOR_UMTS_AUTN_SIZE) " bytes, got %zu bytes",
-                       attr_eap_aka_autn->name, autn_vp->vp_length);
+                       STRINGIFY(AKA_SIM_VECTOR_UMTS_AUTN_SIZE) " bytes, got %zu bytes",
+                       attr_eap_aka_sim_autn->name, autn_vp->vp_length);
                return -1;
        }
 
        /*
         *      Fetch CK
         */
-       ck_vp = fr_pair_find_by_da(vps, attr_eap_aka_ck, TAG_ANY);
+       ck_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_ck, TAG_ANY);
        if (!ck_vp) {
-               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_ck->name);
+               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_ck->name);
                return 1;
        }
 
-       if (ck_vp->vp_length > SIM_VECTOR_UMTS_CK_SIZE) {
+       if (ck_vp->vp_length > AKA_SIM_VECTOR_UMTS_CK_SIZE) {
                REDEBUG("&control:%s incorrect length.  Expected "
                        STRINGIFY(EAP_AKA_XRES_MAX_SIZE) " bytes, got %zu bytes",
-                       attr_eap_aka_ck->name, ck_vp->vp_length);
+                       attr_eap_aka_sim_ck->name, ck_vp->vp_length);
                return -1;
        }
 
        /*
         *      Fetch IK
         */
-       ik_vp = fr_pair_find_by_da(vps, attr_eap_aka_ik, TAG_ANY);
+       ik_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_ik, TAG_ANY);
        if (!ik_vp) {
-               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_ik->name);
+               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_ik->name);
                return 1;
        }
 
-       if (ik_vp->vp_length > SIM_VECTOR_UMTS_IK_SIZE) {
+       if (ik_vp->vp_length > AKA_SIM_VECTOR_UMTS_IK_SIZE) {
                REDEBUG("&control:%s incorrect length.  Expected "
-                       STRINGIFY(SIM_VECTOR_UMTS_IK_SIZE) " bytes, got %zu bytes",
-                       attr_eap_aka_ik->name, ik_vp->vp_length);
+                       STRINGIFY(AKA_SIM_VECTOR_UMTS_IK_SIZE) " bytes, got %zu bytes",
+                       attr_eap_aka_sim_ik->name, ik_vp->vp_length);
                return -1;
        }
 
        /*
         *      Fetch RAND
         */
-       rand_vp = fr_pair_find_by_da(vps, attr_eap_aka_rand, TAG_ANY);
+       rand_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_rand, TAG_ANY);
        if (!rand_vp) {
-               RDEBUG3("No &control:%s attribute found, not using quintuplet derivation", attr_eap_aka_rand->name);
+               RDEBUG3("No &control:%s attribute found, not using quintuplet derivation", attr_eap_aka_sim_rand->name);
                return 1;
        }
 
-       if (rand_vp->vp_length != SIM_VECTOR_UMTS_RAND_SIZE) {
-               REDEBUG("&control:%s incorrect length.  Expected " STRINGIFY(SIM_VECTOR_UMTS_RAND_SIZE) " bytes, "
-                       "got %zu bytes", attr_eap_aka_rand->name, rand_vp->vp_length);
+       if (rand_vp->vp_length != AKA_SIM_VECTOR_UMTS_RAND_SIZE) {
+               REDEBUG("&control:%s incorrect length.  Expected " STRINGIFY(AKA_SIM_VECTOR_UMTS_RAND_SIZE) " bytes, "
+                       "got %zu bytes", attr_eap_aka_sim_rand->name, rand_vp->vp_length);
                return -1;
        }
 
        /*
         *      Fetch XRES
         */
-       xres_vp = fr_pair_find_by_da(vps, attr_eap_aka_xres, TAG_ANY);
+       xres_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_xres, TAG_ANY);
        if (!xres_vp) {
-               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_xres->name);
+               RDEBUG3("No &control:%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_xres->name);
                return 1;
        }
 
-       if (xres_vp->vp_length > SIM_VECTOR_UMTS_XRES_MAX_SIZE) {
+       if (xres_vp->vp_length > AKA_SIM_VECTOR_UMTS_XRES_MAX_SIZE) {
                REDEBUG("&control:%s incorrect length.  Expected < "
                        STRINGIFY(EAP_AKA_XRES_MAX_SIZE) " bytes, got %zu bytes",
-                       attr_eap_aka_xres->name, xres_vp->vp_length);
+                       attr_eap_aka_sim_xres->name, xres_vp->vp_length);
                return -1;
        }
 
        /*
         *      Fetch (optional) AK
         */
-       ak_vp = fr_pair_find_by_da(vps, attr_eap_aka_ak, TAG_ANY);
+       ak_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_ak, TAG_ANY);
        if (ak_vp && (ak_vp->vp_length != MILENAGE_AK_SIZE)) {
                REDEBUG("&control:%s incorrect length.  Expected "
                        STRINGIFY(MILENAGE_AK_SIZE) " bytes, got %zu bytes",
-                       attr_eap_aka_ak->name, ak_vp->vp_length);
+                       attr_eap_aka_sim_ak->name, ak_vp->vp_length);
                return -1;
        }
 
@@ -641,14 +725,14 @@ static int vector_umts_from_quintuplets(REQUEST *request, VALUE_PAIR *vps, fr_si
                memset(keys->umts.vector.ak, 0, sizeof(keys->umts.vector.ak));
        }
 
-       memcpy(keys->umts.vector.autn, autn_vp->vp_octets, SIM_VECTOR_UMTS_AUTN_SIZE);
-       memcpy(keys->umts.vector.ck, ck_vp->vp_octets, SIM_VECTOR_UMTS_CK_SIZE);
-       memcpy(keys->umts.vector.ik, ik_vp->vp_octets, SIM_VECTOR_UMTS_IK_SIZE);
-       memcpy(keys->umts.vector.rand, rand_vp->vp_octets, SIM_VECTOR_UMTS_RAND_SIZE);
+       memcpy(keys->umts.vector.autn, autn_vp->vp_octets, AKA_SIM_VECTOR_UMTS_AUTN_SIZE);
+       memcpy(keys->umts.vector.ck, ck_vp->vp_octets, AKA_SIM_VECTOR_UMTS_CK_SIZE);
+       memcpy(keys->umts.vector.ik, ik_vp->vp_octets, AKA_SIM_VECTOR_UMTS_IK_SIZE);
+       memcpy(keys->umts.vector.rand, rand_vp->vp_octets, AKA_SIM_VECTOR_UMTS_RAND_SIZE);
        memcpy(keys->umts.vector.xres, xres_vp->vp_octets, xres_vp->vp_length);
        keys->umts.vector.xres_len = xres_vp->vp_length;        /* xres is variable length */
 
-       keys->vector_src = SIM_VECTOR_SRC_QUINTUPLETS;
+       keys->vector_src = AKA_SIM_VECTOR_SRC_QUINTUPLETS;
 
        return 0;
 }
@@ -667,29 +751,29 @@ static int vector_umts_from_quintuplets(REQUEST *request, VALUE_PAIR *vps, fr_si
  *     - 0     Vector was retrieved OK and written to the specified index.
  *     - -1    Error retrieving vector from the specified src.
  */
-int fr_sim_vector_umts_from_attrs(REQUEST *request, VALUE_PAIR *vps,
-                                 fr_sim_keys_t *keys, fr_sim_vector_src_t *src)
+int fr_aka_sim_vector_umts_from_attrs(REQUEST *request, VALUE_PAIR *vps,
+                                     fr_aka_sim_keys_t *keys, fr_aka_sim_vector_src_t *src)
 {
        int             ret;
 
-       rad_assert((keys->vector_type == SIM_VECTOR_NONE) || (keys->vector_type == SIM_VECTOR_UMTS));
+       rad_assert((keys->vector_type == AKA_SIM_VECTOR_NONE) || (keys->vector_type == AKA_SIM_VECTOR_UMTS));
 
        switch (*src) {
        default:
-       case SIM_VECTOR_SRC_KI:
+       case AKA_SIM_VECTOR_SRC_KI:
                ret = vector_umts_from_ki(request, vps, keys);
                if (ret == 0) {
-                       *src = SIM_VECTOR_SRC_KI;
+                       *src = AKA_SIM_VECTOR_SRC_KI;
                        break;
                }
                if (ret < 0) return -1;
-               if (*src != SIM_VECTOR_SRC_AUTO) return 1;
+               if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
                /* FALL-THROUGH */
 
-       case SIM_VECTOR_SRC_QUINTUPLETS:
+       case AKA_SIM_VECTOR_SRC_QUINTUPLETS:
                ret = vector_umts_from_quintuplets(request, vps, keys);
                if (ret == 0) {
-                       *src = SIM_VECTOR_SRC_QUINTUPLETS;
+                       *src = AKA_SIM_VECTOR_SRC_QUINTUPLETS;
                        break;;
                }
                if (ret < 0) return -1;
@@ -708,30 +792,25 @@ int fr_sim_vector_umts_from_attrs(REQUEST *request, VALUE_PAIR *vps,
                /*
                 *      Don't change colon indent, matches other messages later...
                 */
-               RHEXDUMP_INLINE2(
-                               keys->umts.vector.autn, SIM_VECTOR_UMTS_AUTN_SIZE,
-                               "AUTN         :");
-               RHEXDUMP_INLINE2(
-                               keys->umts.vector.ck, SIM_VECTOR_UMTS_CK_SIZE,
-                               "CK           :");
-               RHEXDUMP_INLINE2(
-                               keys->umts.vector.ik, SIM_VECTOR_UMTS_IK_SIZE,
-                               "IK           :");
-               RHEXDUMP_INLINE2(
-                               keys->umts.vector.rand, SIM_VECTOR_UMTS_RAND_SIZE,
-                               "RAND         :");
-               RHEXDUMP_INLINE2(
-                               keys->umts.vector.xres, keys->umts.vector.xres_len,
-                               "XRES         :");
+               RHEXDUMP_INLINE2(keys->umts.vector.autn, AKA_SIM_VECTOR_UMTS_AUTN_SIZE,
+                                "AUTN         :");
+               RHEXDUMP_INLINE2(keys->umts.vector.ck, AKA_SIM_VECTOR_UMTS_CK_SIZE,
+                                "CK           :");
+               RHEXDUMP_INLINE2(keys->umts.vector.ik, AKA_SIM_VECTOR_UMTS_IK_SIZE,
+                                "IK           :");
+               RHEXDUMP_INLINE2(keys->umts.vector.rand, AKA_SIM_VECTOR_UMTS_RAND_SIZE,
+                                "RAND         :");
+               RHEXDUMP_INLINE2(keys->umts.vector.xres, keys->umts.vector.xres_len,
+                                "XRES         :");
                REXDENT();
        }
 
-       keys->vector_type = SIM_VECTOR_UMTS;
+       keys->vector_type = AKA_SIM_VECTOR_UMTS;
 
        return 0;
 }
 
-/** Populate a fr_sim_keys_t structure from attributes in the session-state list
+/** Populate a fr_aka_sim_keys_t structure from attributes in the session-state list
  *
  * @param[in] request  The current request.
  * @param[in] vps      Session-state list
@@ -741,7 +820,7 @@ int fr_sim_vector_umts_from_attrs(REQUEST *request, VALUE_PAIR *vps,
  *     - 0 on success.
  *     - -1 on validation failure.
  */
-int fr_sim_vector_umts_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps, fr_sim_keys_t *keys)
+int fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps, fr_aka_sim_keys_t *keys)
 {
        VALUE_PAIR *counter_vp;
        VALUE_PAIR *mk_vp;
@@ -750,32 +829,83 @@ int fr_sim_vector_umts_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps, fr_s
         *      This is the *old* counter value increment
         *      by 1 to get the *new* counter value
         */
-       counter_vp = fr_pair_find_by_da(vps, attr_eap_aka_counter, TAG_ANY);
+       counter_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_counter, TAG_ANY);
        if (!counter_vp) {
                RDEBUG2("No &session-state:%s attribute found, can't calculate re-auth keys",
-                       attr_eap_aka_counter->name);
+                       attr_eap_aka_sim_counter->name);
                return 1;
        }
        counter_vp->vp_uint16++;
 
-       mk_vp = fr_pair_find_by_da(vps, attr_eap_aka_mk, TAG_ANY);
+       mk_vp = fr_pair_find_by_da(vps, attr_session_data, TAG_ANY);
+       if (!mk_vp) mk_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_mk, TAG_ANY);
        if (!mk_vp) {
+               RDEBUG2("Neither &session-state:%s or &session-state:%s attributes found, "
+                       "can't calculate re-auth keys", attr_session_data->name, attr_eap_aka_sim_mk->name);
+               return 1;
+       }
+
+       if (mk_vp->vp_length != AKA_SIM_MK_SIZE) {
+               REDEBUG("&session-state:%s incorrect length.  Expected "
+                       STRINGIFY(AKA_SIM_MK_SIZE) " bytes, got %zu bytes",
+                       attr_eap_aka_sim_mk->name, mk_vp->vp_length);
+               return -1;
+       }
+
+       fr_aka_sim_crypto_keys_init_kdf_0_reauth(keys, mk_vp->vp_octets, counter_vp->vp_uint16);
+
+       keys->vector_type = AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH;    /* Didn't come from a vector */
+       keys->vector_src = AKA_SIM_VECTOR_SRC_REAUTH;
+
+       return 0;
+}
+
+/** Populate a fr_aka_sim_keys_t structure from attributes in the session-state list
+ *
+ * @param[in] request  The current request.
+ * @param[in] vps      Session-state list
+ * @param[in] keys     key structure to populate.
+ * @return
+ *     - 1 if we do not have sufficient data.
+ *     - 0 on success.
+ *     - -1 on validation failure.
+ */
+int fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps, fr_aka_sim_keys_t *keys)
+{
+       VALUE_PAIR *counter_vp;
+       VALUE_PAIR *k_re_vp;
+
+       /*
+        *      This is the *old* counter value increment
+        *      by 1 to get the *new* counter value
+        */
+       counter_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_counter, TAG_ANY);
+       if (!counter_vp) {
                RDEBUG2("No &session-state:%s attribute found, can't calculate re-auth keys",
-                       attr_eap_aka_mk->name);
+                       attr_eap_aka_sim_counter->name);
                return 1;
        }
+       counter_vp->vp_uint16++;
 
-       if (mk_vp->vp_length != SIM_MK_SIZE) {
-               REDEBUG("&control:%s incorrect length.  Expected "
-                       STRINGIFY(SIM_MK_SIZE) " bytes, got %zu bytes",
-                       attr_eap_aka_mk->name, mk_vp->vp_length);
+       k_re_vp = fr_pair_find_by_da(vps, attr_session_data, TAG_ANY);
+       if (!k_re_vp) k_re_vp = fr_pair_find_by_da(vps, attr_eap_aka_sim_k_re, TAG_ANY);
+       if (!k_re_vp) {
+               RDEBUG2("Neither &session-state:%s or &session-sate:%s attributes found, "
+                       "can't calculate re-auth keys", attr_session_data->name, attr_eap_aka_sim_k_re->name);
+               return 1;
+       }
+
+       if (k_re_vp->vp_length != AKA_SIM_K_RE_SIZE) {
+               REDEBUG("&session-state:%s incorrect length.  Expected "
+                       STRINGIFY(AKA_SIM_K_RE_SIZE) " bytes, got %zu bytes",
+                       attr_eap_aka_sim_mk->name, k_re_vp->vp_length);
                return -1;
        }
 
-       fr_sim_crypto_keys_init_reauth(keys, mk_vp->vp_octets, counter_vp->vp_uint16);
+       fr_aka_sim_crypto_keys_init_umts_kdf_1_reauth(keys, k_re_vp->vp_octets, counter_vp->vp_uint16);
 
-       keys->vector_type = SIM_VECTOR_UMTS_REAUTH;     /* Didn't come from a vector */
-       keys->vector_src = SIM_VECTOR_SRC_REAUTH;
+       keys->vector_type = AKA_SIM_VECTOR_UMTS_REAUTH_KDF_1_REAUTH;    /* Didn't come from a vector */
+       keys->vector_src = AKA_SIM_VECTOR_SRC_REAUTH;
 
        return 0;
 }
@@ -784,7 +914,7 @@ int fr_sim_vector_umts_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps, fr_s
  *
  * @param[in] keys     key structure to clear.
  */
-void fr_sim_vector_umts_reauth_clear(fr_sim_keys_t *keys)
+void fr_aka_sim_vector_umts_reauth_clear(fr_aka_sim_keys_t *keys)
 {
        memset(&keys->reauth, 0, sizeof(keys->reauth));
        keys->vector_src = 0;
@@ -802,10 +932,10 @@ void fr_sim_vector_umts_reauth_clear(fr_sim_keys_t *keys)
  *     - 0 on success.
  *     - -1 on validation failure.
  */
-int fr_sim_umts_resync_from_attrs(uint64_t *new_sqn,
-                                 REQUEST *request, VALUE_PAIR *auts_vp, fr_sim_keys_t *keys)
+int fr_aka_sim_umts_resync_from_attrs(uint64_t *new_sqn,
+                                     REQUEST *request, VALUE_PAIR *auts_vp, fr_aka_sim_keys_t *keys)
 {
-       if (keys->vector_src != SIM_VECTOR_SRC_KI) {
+       if (keys->vector_src != AKA_SIM_VECTOR_SRC_KI) {
                RDEBUG2("Original vectors were not generated locally, cannot perform AUTS validation");
                return 1;
        }
@@ -813,7 +943,7 @@ int fr_sim_umts_resync_from_attrs(uint64_t *new_sqn,
        if (auts_vp->vp_length != MILENAGE_AUTS_SIZE) {
                REDEBUG("&control:%s incorrect length.  Expected "
                        STRINGIFY(MILENAGE_AUTS_SIZE) " bytes, got %zu bytes",
-                       attr_eap_aka_auts->name, auts_vp->vp_length);
+                       attr_eap_aka_sim_auts->name, auts_vp->vp_length);
                return -1;
        }
 
similarity index 60%
rename from src/lib/sim/xlat.c
rename to src/lib/eap_aka_sim/xlat.c
index 04fe102d05b017d48df706fcfe3f2ae47183b90a..c376d6d0101a5ad718e2bd8333a550a1a583d58b 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 /**
- * @file src/lib/sim/xlat.c
+ * @file src/lib/aka-sim/xlat.c
  * @brief EAP-SIM/EAP-AKA identity detection, creation, and decyption.
  *
  * @copyright 2017 The FreeRADIUS server project
 #include "base.h"
 #include "attrs.h"
 
-static int sim_xlat_refs = 0;
+static int aka_sim_xlat_refs = 0;
 
 
 /** Returns the SIM method EAP-SIM or EAP-AKA hinted at by the user identifier
  *
- *     %{sim_id_method:&id_attr}
+ *     %{aka_sim_id_method:&id_attr}
  */
-static ssize_t sim_xlat_id_method(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
-                                 UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
-                                 REQUEST *request, char const *fmt)
+static ssize_t aka_sim_xlat_id_method_xlat(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
+                                          UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
+                                          REQUEST *request, char const *fmt)
 {
-       vp_tmpl_t               *vpt;
-       TALLOC_CTX              *our_ctx = talloc_init("sim_xlat");
-       ssize_t                 slen, id_len;
-       char const              *p = fmt, *id, *method;
-       fr_sim_id_type_t        type_hint;
-       fr_sim_method_hint_t    method_hint;
+       vp_tmpl_t                       *vpt;
+       TALLOC_CTX                      *our_ctx = talloc_init("aka_sim_xlat");
+       ssize_t                         slen, id_len;
+       char const                      *p = fmt, *id, *method;
+       fr_aka_sim_id_type_t            type_hint;
+       fr_aka_sim_method_hint_t        method_hint;
 
        /*
         *  Trim whitespace
@@ -67,16 +67,33 @@ static ssize_t sim_xlat_id_method(TALLOC_CTX *ctx, char **out, UNUSED size_t out
        }
 
        id_len = talloc_array_length(id) - 1;
-       if (fr_sim_id_type(&type_hint, &method_hint, id, id_len) < 0) {
-               RPEDEBUG2("SIM ID \"%pV\" has unrecognised format", fr_box_strvalue_len(id, id_len));
+       if (fr_aka_sim_id_type(&type_hint, &method_hint, id, id_len) < 0) {
+               RPEDEBUG2("AKA/SIM Id \"%pV\" has unrecognised format", fr_box_strvalue_len(id, id_len));
                goto error;
        }
 
-       method = fr_dict_enum_alias_by_value(attr_sim_method_hint, fr_box_uint32(method_hint));
-       if (!method) {
-               REDEBUG("Missing Sim-Method-Hint value");
-               goto error;
+       switch (method_hint) {
+       default:
+       case AKA_SIM_METHOD_HINT_UNKNOWN:
+               *out = NULL;
+               return 0;
+
+       case AKA_SIM_METHOD_HINT_SIM:
+               method = fr_dict_enum_alias_by_value(attr_eap_aka_sim_method_hint,
+                                                    fr_box_uint32(FR_METHOD_HINT_VALUE_SIM));
+               break;
+
+       case AKA_SIM_METHOD_HINT_AKA:
+               method = fr_dict_enum_alias_by_value(attr_eap_aka_sim_method_hint,
+                                                    fr_box_uint32(FR_METHOD_HINT_VALUE_AKA));
+               break;
+
+       case AKA_SIM_METHOD_HINT_AKA_PRIME:
+               method = fr_dict_enum_alias_by_value(attr_eap_aka_sim_method_hint,
+                                                    fr_box_uint32(FR_METHOD_HINT_VALUE_AKA_PRIME));
+               break;
        }
+
        *out = talloc_typed_strdup(ctx, method);
        talloc_free(our_ctx);
 
@@ -85,18 +102,18 @@ static ssize_t sim_xlat_id_method(TALLOC_CTX *ctx, char **out, UNUSED size_t out
 
 /** Returns the type of identity used
  *
- *     %{sim_id_type:&id_attr}
+ *     %{aka_sim_id_type:&id_attr}
  */
-static ssize_t sim_xlat_id_type(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
+static ssize_t aka_sim_xlat_id_type_xlat(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
                                UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
                                REQUEST *request, char const *fmt)
 {
-       vp_tmpl_t               *vpt;
-       TALLOC_CTX              *our_ctx = talloc_init("sim_xlat");
-       ssize_t                 slen, id_len;
-       char const              *p = fmt, *id, *method;
-       fr_sim_id_type_t        type_hint;
-       fr_sim_method_hint_t    method_hint;
+       vp_tmpl_t                       *vpt;
+       TALLOC_CTX                      *our_ctx = talloc_init("aka_sim_xlat");
+       ssize_t                         slen, id_len;
+       char const                      *p = fmt, *id, *type;
+       fr_aka_sim_id_type_t            type_hint;
+       fr_aka_sim_method_hint_t        method_hint;
 
        /*
         *  Trim whitespace
@@ -121,17 +138,34 @@ static ssize_t sim_xlat_id_type(TALLOC_CTX *ctx, char **out, UNUSED size_t outle
        }
 
        id_len = talloc_array_length(id) - 1;
-       if (fr_sim_id_type(&type_hint, &method_hint, id, id_len) < 0) {
-               RPEDEBUG2("SIM ID \"%pV\" has unrecognised format", fr_box_strvalue_len(id, id_len));
+       if (fr_aka_sim_id_type(&type_hint, &method_hint, id, id_len) < 0) {
+               RPEDEBUG2("AKA/AKA/SIM Id \"%pV\" has unrecognised format", fr_box_strvalue_len(id, id_len));
                goto error;
        }
 
-       method = fr_dict_enum_alias_by_value(attr_sim_identity_type, fr_box_uint32(type_hint));
-       if (!method) {
-               REDEBUG("Missing Sim-Method-Hint value");
-               goto error;
+       switch (type_hint) {
+       default:
+       case AKA_SIM_ID_TYPE_UNKNOWN:
+               *out = NULL;
+               return 0;
+
+       case AKA_SIM_ID_TYPE_PERMANENT:
+               type = fr_dict_enum_alias_by_value(attr_eap_aka_sim_identity_type,
+                                                  fr_box_uint32(FR_IDENTITY_TYPE_VALUE_PERMANENT));
+               break;
+
+       case AKA_SIM_ID_TYPE_PSEUDONYM:
+               type = fr_dict_enum_alias_by_value(attr_eap_aka_sim_identity_type,
+                                                  fr_box_uint32(FR_IDENTITY_TYPE_VALUE_PSEUDONYM));
+               break;
+
+       case AKA_SIM_ID_TYPE_FASTAUTH:
+               type = fr_dict_enum_alias_by_value(attr_eap_aka_sim_identity_type,
+                                                  fr_box_uint32(FR_IDENTITY_TYPE_VALUE_FASTAUTH));
+               break;
        }
-       *out = talloc_typed_strdup(ctx, method);
+
+       *out = talloc_typed_strdup(ctx, type);
        talloc_free(our_ctx);
 
        return talloc_array_length(*out) - 1;
@@ -139,15 +173,15 @@ static ssize_t sim_xlat_id_type(TALLOC_CTX *ctx, char **out, UNUSED size_t outle
 
 /** Returns the key index from a 3gpp pseudonym
  *
- *     %{sim_id_3gpp_pseudonym_key_index:&id_attr}
+ *     %{3gpp_pseudonym_key_index:&id_attr}
  *
  */
-static ssize_t sim_xlat_3gpp_pseudonym_key_index(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
+static ssize_t aka_sim_3gpp_pseudonym_key_index_xlat(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
                                                 UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
                                                 REQUEST *request, char const *fmt)
 {
        vp_tmpl_t       *vpt;
-       TALLOC_CTX      *our_ctx = talloc_init("sim_xlat");
+       TALLOC_CTX      *our_ctx = talloc_init("aka_sim_xlat");
        ssize_t         slen, id_len;
        char const      *p = fmt, *id;
 
@@ -174,29 +208,29 @@ static ssize_t sim_xlat_3gpp_pseudonym_key_index(TALLOC_CTX *ctx, char **out, UN
        }
 
        id_len = talloc_array_length(id) - 1;
-       if (id_len != SIM_3GPP_PSEUDONYM_LEN) {
+       if (id_len != AKA_SIM_3GPP_PSEUDONYM_LEN) {
                REDEBUG2("3gpp pseudonym incorrect length, expected %i bytes, got %zu bytes",
-                        SIM_3GPP_PSEUDONYM_LEN, id_len);
+                        AKA_SIM_3GPP_PSEUDONYM_LEN, id_len);
                goto error;
        }
 
-       MEM(*out = talloc_typed_asprintf(ctx, "%i", fr_sim_id_3gpp_pseudonym_tag(id)));
+       MEM(*out = talloc_typed_asprintf(ctx, "%i", fr_aka_sim_id_3gpp_pseudonym_tag(id)));
        talloc_free(our_ctx);
 
        return talloc_array_length(*out) - 1;
 }
 
-static ssize_t sim_xlat_3gpp_pseudonym_decrypt(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
+static ssize_t aka_sim_3gpp_pseudonym_decrypt_xlat(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
                                               UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
                                               REQUEST *request, char const *fmt)
 {
        vp_tmpl_t       *id_vpt, *key_vpt;
-       TALLOC_CTX      *our_ctx = talloc_init("sim_xlat");
+       TALLOC_CTX      *our_ctx = talloc_init("aka_sim_xlat");
        ssize_t         slen, id_len, key_len;
        uint8_t         tag;
        char            out_tag;
        uint8_t         *key;
-       char            decrypted[SIM_IMSI_MAX_LEN + 1];
+       char            decrypted[AKA_SIM_IMSI_MAX_LEN + 1];
        char const      *p = fmt, *id;
 
        /*
@@ -245,9 +279,9 @@ static ssize_t sim_xlat_3gpp_pseudonym_decrypt(TALLOC_CTX *ctx, char **out, UNUS
        }
 
        id_len = talloc_array_length(id);
-       if (id_len != (SIM_3GPP_PSEUDONYM_LEN + 1)) {
+       if (id_len != (AKA_SIM_3GPP_PSEUDONYM_LEN + 1)) {
                REDEBUG2("3gpp pseudonym incorrect length, expected %i bytes, got %zu bytes",
-                        SIM_3GPP_PSEUDONYM_LEN + 1, id_len);
+                        AKA_SIM_3GPP_PSEUDONYM_LEN + 1, id_len);
                goto error;
        }
 
@@ -257,28 +291,28 @@ static ssize_t sim_xlat_3gpp_pseudonym_decrypt(TALLOC_CTX *ctx, char **out, UNUS
                goto error;
        }
 
-       tag = fr_sim_id_3gpp_pseudonym_tag(id);
+       tag = fr_aka_sim_id_3gpp_pseudonym_tag(id);
        switch (tag) {
-       case SIM_ID_TAG_PSEUDONYM_SIM_B64:
-               out_tag = SIM_ID_TAG_PERMANENT_SIM;
+       case ID_TAG_SIM_PSEUDONYM_B64:
+               out_tag = ID_TAG_SIM_PERMANENT;
                break;
 
-       case SIM_ID_TAG_PSEUDONYM_AKA_B64:
-               out_tag = SIM_ID_TAG_PERMANENT_AKA;
+       case ID_TAG_AKA_PSEUDONYM_B64:
+               out_tag = ID_TAG_AKA_PERMANENT;
                break;
 
-       case SIM_ID_TAG_PSEUDONYM_AKA_PRIME_B64:
-               out_tag = SIM_ID_TAG_PERMANENT_AKA_PRIME;
+       case ID_TAG_AKA_PRIME_PSEUDONYM_B64:
+               out_tag = ID_TAG_AKA_PRIME_PERMANENT;
                break;
 
        default:
-               REDEBUG2("Unexpected tag value (%u) in SIM ID \"%pV\"", tag, fr_box_strvalue_len(id, id_len));
+               REDEBUG2("Unexpected tag value (%u) in AKA/SIM Id \"%pV\"", tag, fr_box_strvalue_len(id, id_len));
                goto error;
        }
 
        RDEBUG2("Decrypting \"%pV\"", fr_box_strvalue_len(id, id_len));
-       if (fr_sim_id_3gpp_pseudonym_decrypt(decrypted, id, key) < 0) {
-               RPEDEBUG2("Failed decrypting SIM ID");
+       if (fr_aka_sim_id_3gpp_pseudonym_decrypt(decrypted, id, key) < 0) {
+               RPEDEBUG2("Failed decrypting AKA/SIM Id");
                goto error;
        }
 
@@ -293,23 +327,23 @@ static ssize_t sim_xlat_3gpp_pseudonym_decrypt(TALLOC_CTX *ctx, char **out, UNUS
 
 /** Encrypts a 3gpp pseudonym
  *
- *     %{sim_id_3gpp_pseudonym_encrypt:&id_attr &key_attr key_index}
+ *     %{3gpp_pseudonym_encrypt:&id_attr &key_attr key_index}
  *
  */
-static ssize_t sim_xlat_3gpp_pseudonym_encrypt(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
+static ssize_t aka_sim_3gpp_pseudonym_encrypt_xlat(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen,
                                               UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
                                               REQUEST *request, char const *fmt)
 {
-       vp_tmpl_t               *id_vpt, *key_vpt;
-       TALLOC_CTX              *our_ctx = talloc_init("sim_xlat");
-       ssize_t                 slen, id_len, key_len;
-       uint8_t                 *key, tag = 0;
-       unsigned long           key_index;
-       char                    encrypted[SIM_3GPP_PSEUDONYM_LEN + 1];
-       char const              *p = fmt, *id;
+       vp_tmpl_t                       *id_vpt, *key_vpt;
+       TALLOC_CTX                      *our_ctx = talloc_init("aka_sim_xlat");
+       ssize_t                         slen, id_len, key_len;
+       uint8_t                         *key, tag = 0;
+       unsigned long                   key_index;
+       char                            encrypted[AKA_SIM_3GPP_PSEUDONYM_LEN + 1];
+       char const                      *p = fmt, *id;
        char const              *id_p, *id_end;
-       fr_sim_id_type_t        type_hint;
-       fr_sim_method_hint_t    method_hint;
+       fr_aka_sim_id_type_t            type_hint;
+       fr_aka_sim_method_hint_t        method_hint;
 
        /*
         *  Trim whitespace
@@ -387,32 +421,33 @@ static ssize_t sim_xlat_3gpp_pseudonym_encrypt(TALLOC_CTX *ctx, char **out, UNUS
         *      Determine what type/method hints are in the current ID.
         */
        id_len = talloc_array_length(id) - 1;
-       if (id_len == (SIM_IMSI_MAX_LEN + 1)) { /* +1 for ID tag */
-               if (fr_sim_id_type(&type_hint, &method_hint, id, id_len) < 0) {
+       if (id_len == (AKA_SIM_IMSI_MAX_LEN + 1)) {     /* +1 for ID tag */
+               if (fr_aka_sim_id_type(&type_hint, &method_hint, id, id_len) < 0) {
                        RPEDEBUG2("SIM ID \"%pV\" has unrecognised format", fr_box_strvalue_len(id, id_len));
                        goto error;
                }
 
-               if (type_hint != SIM_ID_TYPE_PERMANENT) {
+               if (type_hint != AKA_SIM_ID_TYPE_PERMANENT) {
                        REDEBUG2("SIM ID \"%pV\" is not a permanent identity (IMSI)", fr_box_strvalue_len(id, id_len));
                        goto error;
                }
 
                switch (method_hint) {
-               case SIM_METHOD_HINT_SIM:
-                       tag = SIM_ID_TAG_PSEUDONYM_SIM_B64;
+               case AKA_SIM_METHOD_HINT_SIM:
+                       tag = ID_TAG_SIM_PSEUDONYM_B64;
                        break;
 
-               case SIM_METHOD_HINT_AKA:
-                       tag = SIM_ID_TAG_PSEUDONYM_AKA_B64;
+               case AKA_SIM_METHOD_HINT_AKA:
+                       tag = ID_TAG_AKA_PSEUDONYM_B64;
                        break;
 
-               case SIM_METHOD_HINT_AKA_PRIME:
-                       tag = SIM_ID_TAG_PSEUDONYM_AKA_PRIME_B64;
+               case AKA_SIM_METHOD_HINT_AKA_PRIME:
+                       tag = ID_TAG_AKA_PRIME_PSEUDONYM_B64;
                        break;
 
-               case SIM_METHOD_HINT_UNKNOWN:
-                       REDEBUG2("SIM ID \"%pV\" does not contain a method hint", fr_box_strvalue_len(id, id_len));
+               case AKA_SIM_METHOD_HINT_UNKNOWN:
+               case AKA_SIM_METHOD_HINT_MAX:
+                       REDEBUG2("AKA/SIM ID \"%pV\" does not contain a method hint", fr_box_strvalue_len(id, id_len));
                        goto error;
                }
 
@@ -421,10 +456,10 @@ static ssize_t sim_xlat_3gpp_pseudonym_encrypt(TALLOC_CTX *ctx, char **out, UNUS
        /*
         *      ID lacks a hint byte, figure it out from &control:EAP-Type
         */
-       } else if ((id_len >= SIM_IMSI_MIN_LEN) && (id_len <= SIM_IMSI_MAX_LEN)) {
+       } else if ((id_len >= AKA_SIM_IMSI_MIN_LEN) && (id_len <= AKA_SIM_IMSI_MAX_LEN)) {
                VALUE_PAIR *eap_type;
 
-               eap_type = fr_pair_find_by_da(request->control, attr_eap_type, TAG_ANY);
+               eap_type = fr_pair_find_by_da(request->packet->vps, attr_eap_type, TAG_ANY);
                if (!eap_type) {
                        REDEBUG("SIM ID does not contain method hint, and no &control:EAP-Type found.  "
                                "Don't know what tag to prepend to encrypted identity");
@@ -433,15 +468,15 @@ static ssize_t sim_xlat_3gpp_pseudonym_encrypt(TALLOC_CTX *ctx, char **out, UNUS
 
                switch (eap_type->vp_uint32) {
                case FR_EAP_TYPE_VALUE_SIM:
-                       tag = SIM_ID_TAG_PSEUDONYM_SIM_B64;
+                       tag = ID_TAG_SIM_PSEUDONYM_B64;
                        break;
 
                case FR_EAP_TYPE_VALUE_AKA:
-                       tag = SIM_ID_TAG_PSEUDONYM_AKA_B64;
+                       tag = ID_TAG_AKA_PSEUDONYM_B64;
                        break;
 
                case FR_EAP_TYPE_VALUE_AKA_PRIME:
-                       tag = SIM_ID_TAG_PSEUDONYM_AKA_PRIME_B64;
+                       tag = ID_TAG_AKA_PRIME_PSEUDONYM_B64;
                        break;
 
                default:
@@ -452,7 +487,7 @@ static ssize_t sim_xlat_3gpp_pseudonym_encrypt(TALLOC_CTX *ctx, char **out, UNUS
                id_p = id;
                id_end = id_p + id_len;
        } else {
-               REDEBUG2("IMSI incorrect length, expected %i bytes, got %zu bytes", SIM_IMSI_MAX_LEN + 1,
+               REDEBUG2("IMSI incorrect length, expected %i bytes, got %zu bytes", AKA_SIM_IMSI_MAX_LEN + 1,
                         id_len);
                goto error;
 
@@ -463,7 +498,7 @@ static ssize_t sim_xlat_3gpp_pseudonym_encrypt(TALLOC_CTX *ctx, char **out, UNUS
         *
         *      Strip existing tag from the permanent id
         */
-       if (fr_sim_id_3gpp_pseudonym_encrypt(encrypted, id_p, id_end - id_p, tag, (uint8_t)key_index, key) < 0) {
+       if (fr_aka_sim_id_3gpp_pseudonym_encrypt(encrypted, id_p, id_end - id_p, tag, (uint8_t)key_index, key) < 0) {
                RPEDEBUG2("Failed encrypting SIM ID \"%pV\"", fr_box_strvalue_len(id, id_len));
                return -1;
        }
@@ -474,35 +509,35 @@ static ssize_t sim_xlat_3gpp_pseudonym_encrypt(TALLOC_CTX *ctx, char **out, UNUS
        return talloc_array_length(*out) - 1;
 }
 
-void sim_xlat_register(void)
+void fr_aka_sim_xlat_register(void)
 {
-       if (sim_xlat_refs) {
-               sim_xlat_refs++;
+       if (aka_sim_xlat_refs) {
+               aka_sim_xlat_refs++;
                return;
        }
 
-       xlat_register(NULL, "sim_id_method", sim_xlat_id_method, NULL, NULL, 0, 0, true);
-       xlat_register(NULL, "sim_id_type", sim_xlat_id_type, NULL, NULL, 0, 0, true);
+       xlat_register(NULL, "aka_sim_id_method", aka_sim_xlat_id_method_xlat, NULL, NULL, 0, 0, true);
+       xlat_register(NULL, "aka_sim_id_type", aka_sim_xlat_id_type_xlat, NULL, NULL, 0, 0, true);
        xlat_register(NULL, "3gpp_pseudonym_key_index",
-                     sim_xlat_3gpp_pseudonym_key_index, NULL, NULL, 0, 0, true);
+                     aka_sim_3gpp_pseudonym_key_index_xlat, NULL, NULL, 0, 0, true);
        xlat_register(NULL, "3gpp_pseudonym_decrypt",
-                     sim_xlat_3gpp_pseudonym_decrypt, NULL, NULL, 0, 0, true);
+                     aka_sim_3gpp_pseudonym_decrypt_xlat, NULL, NULL, 0, 0, true);
        xlat_register(NULL, "3gpp_pseudonym_encrypt",
-                     sim_xlat_3gpp_pseudonym_encrypt, NULL, NULL, 0, 0, true);
-       sim_xlat_refs = 1;
+                     aka_sim_3gpp_pseudonym_encrypt_xlat, NULL, NULL, 0, 0, true);
+       aka_sim_xlat_refs = 1;
 }
 
-void sim_xlat_unregister(void)
+void fr_aka_sim_xlat_unregister(void)
 {
-       if (sim_xlat_refs > 1) {
-               sim_xlat_refs--;
+       if (aka_sim_xlat_refs > 1) {
+               aka_sim_xlat_refs--;
                return;
        }
 
-       xlat_unregister("sim_id_method");
-       xlat_unregister("sim_id_type");
+       xlat_unregister("aka_sim_id_method");
+       xlat_unregister("aka_sim_id_type");
        xlat_unregister("3gpp_pseudonym_key_index");
        xlat_unregister("3gpp_pseudonym_decrypt");
        xlat_unregister("3gpp_pseudonym_encrypt");
-       sim_xlat_refs = 0;
+       aka_sim_xlat_refs = 0;
 }
index 2aaa1113ca6bc03677a1b770181cb10d8a4073db..3ebe9a2f7f9f98b0a597d3d1ba76901f4a2bccf1 100644 (file)
@@ -1,18 +1,10 @@
 ifneq "$(OPENSSL_LIBS)" ""
-TARGET := libfreeradius-eap-sim.a
+TARGET := libfreeradius-sim.a
 endif
 
 SOURCES        := \
-       base.c \
        comp128.c \
-       crypto.c \
-       decode.c \
-       encode.c \
-       fips186prf.c \
-       id.c \
        milenage.c \
-       vector.c \
-       xlat.c
+       ts_34_108.c
 
-SRC_INCDIRS    := . ${top_srcdir}/src/modules/rlm_eap/lib/base ${top_srcdir}/src/modules/rlm_eap/
-TGT_PREREQS    := $(LIBFREERADIUS_SERVER) libfreeradius-util.a
+TGT_PREREQS    := libfreeradius-util.a
index d1fd262de6855a98003a7540ef3b6d9acd13998b..7e8e72424739ae3095ca765fb9ebaeb1e83ca813 100644 (file)
 #pragma once
 /*
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or (at
- *   your option) any later version.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
  *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
  *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 /**
  * $Id$
- * @file src/lib/sim/base.h
- * @brief Functions common to SIM protocols (EAP-SIM/EAP-AKA/EAP-AKA')
  *
- * The development of the EAP/SIM support was funded by Internet Foundation
- * Austria (http://www.nic.at/ipa).
+ * @file src/lib/base.h
+ * @brief Master include file for all lib/sim functions.
  *
- * @copyright 2003 Michael Richardson (mcr@sandelman.ottawa.on.ca)
- * @copyright 2003-2016 The FreeRADIUS server project
+ * @copyright 2019 The FreeRADIUS server project
  */
-RCSIDH(sim_h, "$Id$")
+RCSIDH(sim_base_h, "$Id$")
 
-#include <assert.h>
-#include <openssl/evp.h>
-#include <freeradius-devel/eap/compose.h>
-#include <freeradius-devel/eap/types.h>
-
-#include "id.h"
-#include "eap_sim_common.h"
-#include "eap_aka_common.h"
-
-#define SIM_MAX_STRING_LENGTH          1016            //!< Maximum size of a SIM/AKA['] string ((4 * 255) - 4).
-#define SIM_IV_SIZE                    16              //!< Length of the IV used when processing AT_ENCR.
-#define SIM_MAC_DIGEST_SIZE            16              //!< Length of MAC used to prevent packet modification.
-#define SIM_MAC_SIZE                   20              //!< Length of MAC used to prevent packet modification.
-#define SIM_AUTH_SIZE                  16
-#define SIM_SQN_AK_SIZE                        6
-#define SIM_NONCE_S_SIZE               16              //!< Length of re-authentication nonce
-
-#define SIM_KI_SIZE                    16              //!< Length of secret data shared between SIM and AuC.
-#define SIM_OP_SIZE                    16              //!< Length of Operator Algorithm Configuration.
-#define SIM_OPC_SIZE                   16              //!< Length of modified Operator Algorithm Configuration.
-
-#define SIM_MK_SIZE                    20              //!< Master key size
-
-#define SIM_SKIPPABLE_MAX              127             //!< The last non-skippable attribute.
-
-#define SIM_VECTOR_GSM_RAND_SIZE       16              //!< Length of RAND in GSM triplet.
-#define SIM_VECTOR_GSM_SRES_SIZE       4               //!< Length of SRES in GSM triplet.
-#define SIM_VECTOR_GSM_KC_SIZE         8               //!< Length of Kc in GSM triplet.
-
-#define SIM_VECTOR_UMTS_AUTN_SIZE      16
-#define SIM_VECTOR_UMTS_CK_SIZE                16
-#define SIM_VECTOR_UMTS_IK_SIZE                16
-#define SIM_VECTOR_UMTS_AK_SIZE                6
-#define SIM_VECTOR_UMTS_RAND_SIZE      16
-#define SIM_VECTOR_UMTS_XRES_MAX_SIZE  16
-#define SIM_VECTOR_UMTS_RES_MAX_SIZE   16
-
-/** The type of auth vector held by a fr_sim_keys_t
- */
-typedef enum {
-       SIM_VECTOR_NONE = 0,
-       SIM_VECTOR_GSM,                                         //!< Vector is GSM triplets.
-       SIM_VECTOR_UMTS,                                        //!< Vector is UMTS quintuplets.
-       SIM_VECTOR_UMTS_REAUTH
-} fr_sim_vector_type_t;
-
-/** Where to get EAP-SIM vectors from
- */
-typedef enum {
-       SIM_VECTOR_SRC_AUTO,                                    //!< Discover where to get Triplets from automatically.
-       SIM_VECTOR_SRC_TRIPLETS,                                //!< Source of triplets is EAP-SIM-* attributes.
-       SIM_VECTOR_SRC_QUINTUPLETS,                             //!< Source of triplets is derived from EAP-AKA-*
-                                                               ///< quintuplets.
-       SIM_VECTOR_SRC_KI,                                      //!< Should generate triplets locally using a Ki.
-       SIM_VECTOR_SRC_REAUTH
-} fr_sim_vector_src_t;
-
-typedef struct {
-       uint8_t         rand[SIM_VECTOR_GSM_RAND_SIZE];         //!< RAND challenge to the SIM.
-       union {
-               uint8_t         sres[SIM_VECTOR_GSM_SRES_SIZE];         //!< Signing response.
-               uint32_t        sres_uint32;
-       };
-
-       union {
-               uint8_t         kc[SIM_VECTOR_GSM_KC_SIZE];             //!< Keying response.
-               uint64_t        kc_uint64;
-       };
-} fr_sim_vector_gsm_t;
-
-typedef struct {
-       uint8_t         autn[SIM_VECTOR_UMTS_AUTN_SIZE];        //!< Authentication vector from the AuC.
-       uint8_t         ck[SIM_VECTOR_UMTS_CK_SIZE];            //!< Ciphering key.
-       uint8_t         ik[SIM_VECTOR_UMTS_IK_SIZE];            //!< Integrity key.
-       uint8_t         ak[SIM_VECTOR_UMTS_AK_SIZE];            //!< Anonymity key.
-       uint8_t         rand[SIM_VECTOR_UMTS_RAND_SIZE];        //!< RAND challenge to the SIM.
-       uint8_t         xres[SIM_VECTOR_UMTS_RES_MAX_SIZE];     //!< Signing response.
-       size_t          xres_len;                               //!< Length of res (it's variable).
-} fr_sim_vector_umts_t;
-
-/** Stores our checkcode state
- *
- * The checkcode is a hash of all identity packets exchanged
- * up until the challenge is sent.
- *
- * It allows both parties to verify that they've seen the same
- * sequence of packets.
- */
-typedef struct {
-       EVP_MD_CTX      *md_ctx;                                //!< Context to hold state of digest as we
-                                                               ///< consume packets.
-} fr_sim_checkcode_t;
-
-/** Master key state struct for all SIMlike EAP protocols
- *
- */
-typedef struct {
-       /*
-        *      Inputs
-        */
-       uint8_t         *identity;                              //!< Identity from AT_IDENTITY.
-       size_t          identity_len;                           //!< Length of the identity.
-
-       uint8_t         *network;                               //!< Network name (EAP-AKA-Prime only).
-       size_t          network_len;                            //!< Length of the network name (EAP-AKA-Prime only).
-
-       uint64_t        sqn;                                    //!< Sequence number
-
-       struct {
-               /*
-                *      Authentication vectors from HLR or local AuC
-                */
-               union {
-                       /** Input to kdf_0_gsm
-                        */
-                       struct {
-                               fr_sim_vector_gsm_t     vector[3];      //!< GSM vectors.
-                               uint32_t                num_vectors;    //!< Number of input vectors
-                                                                       //!< we're using (2 or 3).
-
-                               uint8_t nonce_mt[EAP_SIM_NONCE_MT_SIZE];//!< Nonce provided by the client.
-                               uint8_t version_list[FR_MAX_STRING_LEN];//!< Version list from negotiation.
-                               uint8_t version_list_len;               //!< Length of version list.
-                               uint8_t version_select[2];              //!< Version we agreed.
-                       } gsm;
-
-                       /** Input to kdf_*_umts
-                        */
-                       struct {
-                               fr_sim_vector_umts_t    vector;         //!< UMTS vector.
-                               uint16_t                kdf_selected;
-                       } umts;
-               };
-
-               /*
-                *      Original ki and OPc to allow AUTS validation
-                */
-               struct {
-                       uint8_t ki[SIM_KI_SIZE];                //!< Secret shared between AuC and SIM.
-                       uint8_t opc[SIM_OPC_SIZE];              //!< Operator algorithm input.
-               } auc;
-
-               /*
-                *      Re-authentication data
-                */
-               struct {
-                       uint16_t        counter;                        //!< Re-authentication counter.
-                       uint8_t         nonce_s[SIM_NONCE_S_SIZE];      //!< Re-authentication challenge.
-               } reauth;
-
-
-               fr_sim_vector_type_t    vector_type;            //!< What type of authentication vector
-                                                               //!< we're using to authenticate the SIM.
-               fr_sim_vector_src_t     vector_src;             //!< Where the vector came from.
-       };
-
-       /*
-        *      Intermediates
-        */
-       uint8_t         ck_prime[SIM_VECTOR_UMTS_CK_SIZE];      //!< Derived from CK, for AKA'.
-       uint8_t         ik_prime[SIM_VECTOR_UMTS_IK_SIZE];      //!< Derived from IK, for AKA'.
-
-       /*
-        *      Inputs/outputs
-        */
-       uint8_t         master_key[SIM_MK_SIZE];                //!< Master key from session attributes.
-
-       /*
-        *      Outputs
-        */
-       uint8_t         k_aut[32];                              //!< Derived authentication key.
-       size_t          k_aut_len;                              //!< Length of k_aut.  16 for AKA/SIM, 32 for AKA'.
-       uint8_t         k_re[32];                               //!< Derived reauthentication key.
-       uint8_t         k_encr[16];                             //!< Derived encryption key.
-
-       uint8_t         msk[64];                                //!< Derived master session key.
-       uint8_t         emsk[64];                               //!< Derived extended master session key.
-} fr_sim_keys_t;
-
-typedef struct {
-       fr_sim_keys_t const     *keys;                          //!< From the EAP session.
-       uint8_t                 iv[SIM_IV_SIZE];                //!< From the current packet.
-       bool                    have_iv;                        //!< Whether we found the IV already.
-} fr_sim_decode_ctx_t;
-
-typedef struct {
-       fr_dict_attr_t const    *root;                          //!< Root attribute of the dictionary.
-       fr_sim_keys_t const     *keys;                          //!< From the EAP session.
-       uint8_t                 iv[SIM_IV_SIZE];                //!< Generated by us using our PRNG.
-       bool                    iv_included;                    //!< Whether we've already added an IV to this packet.
-
-       /*
-        *      Additional HMAC inputs
-        */
-       EVP_MD const            *hmac_md;                       //!< HMAC digest algorithm, usually EVP_sha1().
-       eap_packet_t            *eap_packet;                    //!< Needed for HMAC generation so we can construct
-                                                               ///< the EAP packet header.
-       uint8_t const           *hmac_extra;                    //!< Extra data for the HMAC function.
-       size_t                  hmac_extra_len;                 //!< The length of the HMAC data.
-} fr_sim_encode_ctx_t;
-
-extern size_t const fr_sim_attr_sizes[FR_TYPE_MAX + 1][2];
-
-/*
- *     decode.c
- */
-ssize_t                fr_sim_decode_pair(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
-                                  uint8_t const *data, size_t data_len, void *decoder_ctx);
-
-int            fr_sim_decode(REQUEST *request, fr_cursor_t *decoded, fr_dict_t const *dict,
-                             uint8_t const *data, size_t data_len, fr_sim_decode_ctx_t *ctx);
-
-/*
- *     encode.c
- */
-ssize_t                fr_sim_encode_pair(uint8_t *out, size_t outlen, fr_cursor_t *cursor, void *encoder_ctx);
-
-ssize_t                fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx);
-
-/*
- *     base.c
- */
-size_t         fr_sim_attr_len(VALUE_PAIR const *vp);
-
-size_t         fr_sim_octets_prefix_len(fr_dict_attr_t const *da);
-
-int            fr_sim_init(void);
-
-void           fr_sim_free(void);
-
-/*
- *     crypto.c
- */
-int            fr_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_sim_checkcode_t **checkcode, EVP_MD const *md);
-
-int            fr_sim_crypto_update_checkcode(fr_sim_checkcode_t *checkcode, eap_packet_t *eap_packet);
-
-ssize_t                fr_sim_crypto_finalise_checkcode(uint8_t *out, fr_sim_checkcode_t **checkcode);
-
-ssize_t                fr_sim_crypto_sign_packet(uint8_t out[static SIM_MAC_DIGEST_SIZE],
-                                         eap_packet_t *eap_packet, bool zero_mac,
-                                         EVP_MD const *md, uint8_t const *key, size_t const key_len,
-                                         uint8_t const *hmac_extra, size_t const hmac_extra_len);
-
-int            fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys);
-
-int            fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys);
-
-int            fr_sim_crypto_kdf_1_umts(fr_sim_keys_t *keys);
-
-void           fr_sim_crypto_keys_init_reauth(fr_sim_keys_t *keys,
-                                              uint8_t const master_key[static SIM_MK_SIZE], uint16_t counter);
-
-int            fr_sim_crypto_kdf_0_reauth(fr_sim_keys_t *keys);
-
-int            fr_sim_crypto_kdf_1_reauth(fr_sim_keys_t *keys);
-
-void           fr_sim_crypto_keys_log(REQUEST *request, fr_sim_keys_t *keys);
-
-/*
- *     vector.c
- */
-int            fr_sim_vector_gsm_from_attrs(eap_session_t *eap_session, VALUE_PAIR *vps,
-                                            int idx, fr_sim_keys_t *keys, fr_sim_vector_src_t *src);
-
-int            fr_sim_vector_umts_from_attrs(REQUEST *request, VALUE_PAIR *vps,
-                                             fr_sim_keys_t *keys, fr_sim_vector_src_t *src);
-
-int            fr_sim_vector_umts_reauth_from_attrs(REQUEST *request, VALUE_PAIR *vps,
-                                                    fr_sim_keys_t *keys);
-
-void           fr_sim_vector_umts_reauth_clear(fr_sim_keys_t *keys);
-
-int            fr_sim_umts_resync_from_attrs(uint64_t *new_sqn,
-                                             REQUEST *request, VALUE_PAIR *auts_vp, fr_sim_keys_t *keys);
-
-/*
- *     fips186prf.c
- */
-void           fr_sim_fips186_2prf(uint8_t out[static 160], uint8_t mk[static 20]);
-
-/*
- *     xlat.c
- */
-void           sim_xlat_register(void);
-void           sim_xlat_unregister(void);
+#include <freeradius-devel/sim/common.h>
+#include <freeradius-devel/sim/comp128.h
+#include <freeradius-devel/sim/milenage.h>
+#include <freeradius-devel/sim/ts_34_108.h>
diff --git a/src/lib/sim/common.h b/src/lib/sim/common.h
new file mode 100644 (file)
index 0000000..ea94dad
--- /dev/null
@@ -0,0 +1,64 @@
+#pragma once
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file lib/sim/common.h
+ * @brief Common code used by multiple SIM algorithms
+ *
+ * @copyright 2019 The FreeRADIUS server project
+ * @copyright 2019 Arran Cudbard-Bell \<a.cudbardb@freeradius.org\>
+ */
+
+/** Copy a 48bit value from a 64bit integer into a uint8_t buff in big endian byte order
+ *
+ * There may be fast ways of doing this, but this is the *correct*
+ * way, and does not make assumptions about how integers are laid
+ * out in memory.
+ *
+ * @param[out] out     6 byte butter to store value.
+ * @param[in] i                integer value.
+ * @return pointer to out.
+ */
+static inline uint8_t *uint48_to_buff(uint8_t out[static 6], uint64_t i)
+{
+       out[0] = (i & 0xff0000000000) >> 40;
+       out[1] = (i & 0x00ff00000000) >> 32;
+       out[2] = (i & 0x0000ff000000) >> 24;
+       out[3] = (i & 0x000000ff0000) >> 16;
+       out[4] = (i & 0x00000000ff00) >> 8;
+       out[5] = (i & 0x0000000000ff);
+
+       return out;
+}
+
+/** Convert a 48bit big endian value into a unsigned 64bit integer
+ *
+ */
+static inline uint64_t uint48_from_buff(uint8_t const in[6])
+{
+       uint64_t i = 0;
+
+       i |= ((uint64_t)in[0]) << 40;
+       i |= ((uint64_t)in[1]) << 32;
+       i |= ((uint32_t)in[2]) << 24;
+       i |= ((uint32_t)in[3]) << 16;
+       i |= ((uint16_t)in[4]) << 8;
+       i |= in[5];
+
+       return i;
+}
index 2d664473e2fe0934c8f318e01422410f01190e36..d89941479f86cce69e0d97816f2069c4c69985f3 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * @file src/lib/sim/milenage.c
+ * @file src/lib/aka-sim/milenage.c
  * @brief 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
  *
  * This file implements an example authentication algorithm defined for 3GPP
@@ -23,6 +23,7 @@
 #include <freeradius-devel/tls/log.h>
 #include <freeradius-devel/util/proto.h>
 #include <openssl/evp.h>
+#include "common.h"
 #include "milenage.h"
 
 #define MILENAGE_MAC_A_SIZE    8
index 551ecbd5c569adfd94dbd665413a551faeb9e061..809aec1fc444b5288d6b629f2d5ffbab19fc1625 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 /**
- * @file src/lib/sim/milenage.h
+ * @file src/lib/aka-sim/milenage.h
  * @brief 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
  *
  * This file implements an example authentication algorithm defined for 3GPP
 #define MILENAGE_SRES_SIZE     4
 #define MILENAGE_KC_SIZE       8
 
-/** Copy a 48bit value from a 64bit integer into a uint8_t buff in big endian byte order
- *
- * There may be fast ways of doing this, but this is the *correct*
- * way, and does not make assumptions about how integers are laid
- * out in memory.
- *
- * @param[out] out     6 byte butter to store value.
- * @param[in] i                integer value.
- * @return pointer to out.
- */
-static inline uint8_t *uint48_to_buff(uint8_t out[static 6], uint64_t i)
-{
-       out[0] = (i & 0xff0000000000) >> 40;
-       out[1] = (i & 0x00ff00000000) >> 32;
-       out[2] = (i & 0x0000ff000000) >> 24;
-       out[3] = (i & 0x000000ff0000) >> 16;
-       out[4] = (i & 0x00000000ff00) >> 8;
-       out[5] = (i & 0x0000000000ff);
-
-       return out;
-}
-
-/** Convert a 48bit big endian value into a unsigned 64bit integer
- *
- */
-static inline uint64_t uint48_from_buff(uint8_t const in[6])
-{
-       uint64_t i = 0;
-
-       i |= ((uint64_t)in[0]) << 40;
-       i |= ((uint64_t)in[1]) << 32;
-       i |= ((uint32_t)in[2]) << 24;
-       i |= ((uint32_t)in[3]) << 16;
-       i |= ((uint16_t)in[4]) << 8;
-       i |= in[5];
-
-       return i;
-}
-
 int    milenage_opc_generate(uint8_t opc[MILENAGE_OPC_SIZE],
                              uint8_t const op[MILENAGE_OP_SIZE],
                              uint8_t const ki[MILENAGE_KI_SIZE]);
diff --git a/src/lib/sim/ts_34_108.c b/src/lib/sim/ts_34_108.c
new file mode 100644 (file)
index 0000000..f43c7c1
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file ts_34_108.h
+ * @brief Implementation of the TS.34.108 dummy USMI algorithm
+ *
+ * @copyright 2019 The FreeRADIUS server project
+ * @copyright 2019 Arran Cudbard-Bell \<a.cudbardb@freeradius.org\>
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include <freeradius-devel/util/proto.h>
+#include "common.h"
+#include "ts_34_108.h"
+
+static_assert(TS_34_108_KI_SIZE == TS_34_108_RAND_SIZE,
+             "TS.34.108 Ki and RAND sizes must be identical");
+
+#define TS_34_108_XDOUT_SIZE   TS_34_108_RAND_SIZE
+#define TS_34_108_CDOUT_SIZE   8
+#define TS_34_108_XMAC_SIZE    8
+
+int ts_34_108_umts_generate(uint8_t autn[TS_34_108_AUTN_SIZE],
+                           uint8_t ik[TS_34_108_IK_SIZE],
+                           uint8_t ck[TS_34_108_CK_SIZE],
+                           uint8_t ak[TS_34_108_AK_SIZE],
+                           uint8_t res[TS_34_108_RES_SIZE],
+                           uint8_t const amf[TS_34_108_AMF_SIZE],
+                           uint8_t const ki[TS_34_108_KI_SIZE],
+                           uint64_t sqn,
+                           uint8_t const rand[TS_34_108_RAND_SIZE])
+{
+       size_t          i;
+       uint8_t         xdout[TS_34_108_XDOUT_SIZE];
+       uint8_t         cdout[TS_34_108_CDOUT_SIZE];
+       uint8_t         xmac[TS_34_108_XMAC_SIZE];
+       uint8_t         sqn_buff[TS_34_108_SQN_SIZE];
+       uint8_t         *p;
+
+       /*
+        *  Step 1:
+        *      XOR to the challenge RAND, a predefined number K (in which at least
+        *      one bit is not zero, see clause 8.2), having the same bit length
+        *      (128 * bits) as RAND.
+        */
+       for (i = 0; i < sizeof(xdout); i++) xdout[i] = ki[i] ^ rand[i];
+
+       /*
+        *  Step 2:
+        *      RES (test USIM), XRES (SS), CK, IK and AK are extracted from
+        *      XDOUT.
+        */
+
+       /*
+        *      RES[bits 0,1, ...n-1,n] = f2(XDOUT,n) = XDOUT[bits 0,1, . . .n-1,n]
+        */
+       memcpy(res, xdout, TS_34_108_RES_SIZE);
+
+       /*
+        *      CK[bits 0,1, ...126,127] = f3(XDOUT) = XDOUT[bits 8,9, ...126,127,0,1, ...6,7]
+        */
+       memcpy(ck, xdout + 1, TS_34_108_CK_SIZE - 1);
+       ck[TS_34_108_CK_SIZE - 1] = xdout[0];
+
+       /*
+        *      IK[bits0,1, ...126,127] = f4(XDOUT) = XDOUT[bits16,17, ...126,127,0,1, ...14,15]
+        */
+       p = ik;
+       memcpy(ik, xdout + 2, TS_34_108_CK_SIZE - 2);
+       ik[TS_34_108_CK_SIZE - 2] = xdout[0];
+       ik[TS_34_108_CK_SIZE - 1] = xdout[1];
+
+       /*
+        *      AK[bits0,1, ...46,47] = f5(XDOUT) = XDOUT[bits24,25, ...70,71]
+        */
+       memcpy(ak, xdout + 3, TS_34_108_AK_SIZE);
+
+       /*
+        *  Step 3:
+        *      Concatenate SQN with AMF to obtain CDOUT
+        */
+       uint48_to_buff(sqn_buff, sqn);
+       p = cdout;
+       memcpy(p, sqn_buff, TS_34_108_SQN_SIZE);
+       p += TS_34_108_SQN_SIZE;
+       memcpy(p, amf, TS_34_108_AMF_SIZE);
+
+       /*
+        *  Step 4:
+        *      XMAC (test USIM) and MAC (SS) are calculated from XDOUT and CDOUT.
+        */
+       for (i = 0; i < sizeof(xmac); i++) xmac[i] = xdout[i] ^ cdout[i];
+
+       /*
+        *  Step 5:
+        *      The SS calculates the authentication token AUTN.
+        */
+       p = autn;
+       for (i = 0; i < sizeof(sqn_buff); i++) p[i] = sqn_buff[i] ^ ak[i];
+       p += sizeof(sqn_buff);
+       memcpy(p, amf, TS_34_108_AMF_SIZE);
+       p += TS_34_108_AMF_SIZE;
+       memcpy(p, xmac, TS_34_108_XMAC_SIZE);
+
+       return 0;
+}
diff --git a/src/lib/sim/ts_34_108.h b/src/lib/sim/ts_34_108.h
new file mode 100644 (file)
index 0000000..338038f
--- /dev/null
@@ -0,0 +1,54 @@
+#pragma once
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file ts_34_108.h
+ * @brief Implementation of the TS.34.108 dummy USMI algorithm
+ *
+ * @copyright 2019 The FreeRADIUS server project
+ * @copyright 2019 Arran Cudbard-Bell \<a.cudbardb@freeradius.org\>
+ */
+
+/*
+ *     Inputs
+ */
+#define TS_34_108_KI_SIZE      16              //!< Subscriber key.
+#define TS_34_108_OP_SIZE      16              //!< Operator code (unique to the operator)
+#define TS_34_108_AMF_SIZE     2               //!< Authentication management field.
+#define TS_34_108_SQN_SIZE     6               //!< Sequence number.
+#define TS_34_108_RAND_SIZE    16              //!< Random challenge.
+
+/*
+ *     UMTS Outputs
+ */
+#define TS_34_108_AK_SIZE      6               //!< Anonymisation key.
+#define TS_34_108_AUTN_SIZE    16              //!< Network authentication key.
+#define TS_34_108_IK_SIZE      16              //!< Integrity key.
+#define        TS_34_108_CK_SIZE       16              //!< Ciphering key.
+#define TS_34_108_RES_SIZE     16
+#define TS_34_108_AUTS_SIZE    14
+
+int    ts_34_108_umts_generate(uint8_t autn[TS_34_108_AUTN_SIZE],
+                               uint8_t ik[TS_34_108_IK_SIZE],
+                               uint8_t ck[TS_34_108_CK_SIZE],
+                               uint8_t ak[TS_34_108_AK_SIZE],
+                               uint8_t res[TS_34_108_RES_SIZE],
+                               uint8_t const amf[TS_34_108_AMF_SIZE],
+                               uint8_t const ki[TS_34_108_KI_SIZE],
+                               uint64_t sqn,
+                               uint8_t const rand[TS_34_108_RAND_SIZE]);
index 3df5fe40de717da1e53df08b8194bc238af25cf7..72524c0cf26e3df181091dc80123dabde0c20441 100644 (file)
@@ -6,8 +6,4 @@ endif
 
 SOURCES                := $(TARGETNAME).c
 
-SRC_CFLAGS     :=
-TGT_LDLIBS     :=
-SRC_INCDIRS    := ${top_srcdir}/src/modules/rlm_eap/ ${top_srcdir}/src/modules/rlm_eap/lib/base/ ${top_srcdir}/src/modules/rlm_eap/lib/sim/
-
-TGT_PREREQS    := $(LIBFREERADIUS_SERVER) libfreeradius-radius.a libfreeradius-util.a libfreeradius-eap.a libfreeradius-eap-sim.a
+TGT_PREREQS    := $(LIBFREERADIUS_SERVER) libfreeradius-radius.a libfreeradius-util.a libfreeradius-eap.a libfreeradius-sim.a libfreeradius-eap-aka-sim.a
index 917d7e00453150d18c29bd975f5dfdc99bb6f3ea..a057dbfab54a2008fe7b4ea72f8ee8d5ce79da4a 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * $Id$
  * @file rlm_eap_aka.c
- * @brief Implements the AKA part of EAP-AKA
+ * @brief Implements EAP-AKA
  *
  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
  *
 RCSID("$Id$")
 
 #include <freeradius-devel/eap/base.h>
-#include <freeradius-devel/eap/types.h>
+#include <freeradius-devel/eap_aka_sim/state_machine.h>
 #include <freeradius-devel/server/rad_assert.h>
-#include <freeradius-devel/sim/base.h>
 #include <freeradius-devel/unlang/compile.h>
-
-#include <freeradius-devel/protocol/eap/aka/freeradius.h>
-#include <freeradius-devel/protocol/eap/aka/rfc4187.h>
-
-#include "eap_aka.h"
-
-#ifndef EAP_TLS_MPPE_KEY_LEN
-#  define EAP_TLS_MPPE_KEY_LEN     32
-#endif
-
-static fr_table_num_ordered_t const aka_state_table[] = {
-       { "IDENTITY",                           EAP_AKA_SERVER_IDENTITY                         },
-       { "CHALLENGE",                          EAP_AKA_SERVER_CHALLENGE                        },
-       { "SUCCESS-NOTIFICATION",               EAP_AKA_SERVER_SUCCESS_NOTIFICATION             },
-       { "SUCCESS",                            EAP_AKA_SERVER_SUCCESS                          },
-       { "FAILURE-NOTIFICATION",               EAP_AKA_SERVER_FAILURE_NOTIFICATION             },
-       { "FAILURE",                            EAP_AKA_SERVER_FAILURE                          },
-};
-static size_t aka_state_table_len = NUM_ELEMENTS(aka_state_table);
-
-static int mod_section_compile(eap_aka_actions_t *actions, CONF_SECTION *server_cs);
-static int virtual_server_parse(TALLOC_CTX *ctx, void *out, void *parent,
-                               CONF_ITEM *ci, UNUSED CONF_PARSER const *rule);
+#include <freeradius-devel/unlang/module.h>
 
 static CONF_PARSER submodule_config[] = {
-       { FR_CONF_OFFSET("network_name", FR_TYPE_STRING | FR_TYPE_REQUIRED, rlm_eap_aka_t, network_name ) },
-       { FR_CONF_OFFSET("request_identity", FR_TYPE_BOOL, rlm_eap_aka_t, request_identity ), .dflt = "no" },
-       { FR_CONF_OFFSET("protected_success", FR_TYPE_BOOL, rlm_eap_aka_t, protected_success ), .dflt = "no" },
-       { FR_CONF_OFFSET("virtual_server", FR_TYPE_VOID, rlm_eap_aka_t, actions), .func = virtual_server_parse },
+       { FR_CONF_OFFSET("request_identity", FR_TYPE_BOOL, eap_aka_sim_common_conf_t, request_identity ),
+         .func = cf_table_parse_uint32, .uctx = &(cf_table_parse_ctx_t){ .table = fr_aka_sim_id_request_table, .len = &fr_aka_sim_id_request_table_len }},
+       { FR_CONF_OFFSET("strip_permanent_identity_hint", FR_TYPE_BOOL, eap_aka_sim_common_conf_t,
+                        strip_permanent_identity_hint ), .dflt = "yes" },
+       { FR_CONF_OFFSET("ephemeral_id_length", FR_TYPE_UINT8, eap_aka_sim_common_conf_t, ephemeral_id_length ), .dflt = "14" },        /* 14 for compatibility */
+       { FR_CONF_OFFSET("protected_success", FR_TYPE_BOOL, eap_aka_sim_common_conf_t, protected_success ), .dflt = "no" },
+       { FR_CONF_OFFSET_IS_SET("prefer_aka_prime", FR_TYPE_BOOL, eap_aka_sim_common_conf_t, send_at_bidding_prefer_prime ), .dflt = "no" },
+       { FR_CONF_OFFSET("virtual_server", FR_TYPE_VOID, eap_aka_sim_common_conf_t, virtual_server), .func = virtual_server_cf_parse },
        CONF_PARSER_TERMINATOR
 };
 
-static fr_dict_t *dict_freeradius;
-static fr_dict_t *dict_radius;
-static fr_dict_t *dict_eap_aka;
+static fr_dict_t *dict_eap_aka_sim;
 
 extern fr_dict_autoload_t rlm_eap_aka_dict[];
 fr_dict_autoload_t rlm_eap_aka_dict[] = {
-       { .out = &dict_freeradius, .proto = "freeradius" },
-       { .out = &dict_radius, .proto = "radius" },
-       { .out = &dict_eap_aka, .proto = "eap-aka", .base_dir = "eap/aka" },
+       { .out = &dict_eap_aka_sim, .base_dir="eap/aka-sim", .proto = "eap-aka-sim"  },
        { NULL }
 };
 
-static fr_dict_attr_t const *attr_eap_aka_subtype;
-static fr_dict_attr_t const *attr_sim_amf;
-
-static fr_dict_attr_t const *attr_ms_mppe_send_key;
-static fr_dict_attr_t const *attr_ms_mppe_recv_key;
-
-static fr_dict_attr_t const *attr_eap_aka_any_id_req;
-static fr_dict_attr_t const *attr_eap_aka_autn;
-static fr_dict_attr_t const *attr_eap_aka_bidding;
-static fr_dict_attr_t const *attr_eap_aka_checkcode;
-static fr_dict_attr_t const *attr_eap_aka_client_error_code;
-static fr_dict_attr_t const *attr_eap_aka_encr_data;
-static fr_dict_attr_t const *attr_eap_aka_fullauth_id_req;
-static fr_dict_attr_t const *attr_eap_aka_identity;
-static fr_dict_attr_t const *attr_eap_aka_kdf;
-static fr_dict_attr_t const *attr_eap_aka_kdf_input;
-static fr_dict_attr_t const *attr_eap_aka_mac;
-static fr_dict_attr_t const *attr_eap_aka_notification;
-static fr_dict_attr_t const *attr_eap_aka_permanent_id_req;
-static fr_dict_attr_t const *attr_eap_aka_rand;
-static fr_dict_attr_t const *attr_eap_aka_res;
-static fr_dict_attr_t const *attr_eap_aka_result_ind;
-
-extern fr_dict_attr_autoload_t rlm_eap_aka_dict_attr[];
-fr_dict_attr_autoload_t rlm_eap_aka_dict_attr[] = {
-
-       { .out = &attr_sim_amf, .name = "SIM-AMF", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
-
-       { .out = &attr_ms_mppe_send_key, .name = "MS-MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
-       { .out = &attr_ms_mppe_recv_key, .name = "MS-MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
-
-       { .out = &attr_eap_aka_any_id_req, .name = "EAP-AKA-Any-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_autn, .name = "EAP-AKA-AUTN", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_bidding, .name = "EAP-AKA-Bidding", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_checkcode, .name = "EAP-AKA-Checkcode", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_client_error_code, .name = "EAP-AKA-Client-Error-Code", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_encr_data, .name = "EAP-AKA-Encr-Data", .type = FR_TYPE_TLV, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_fullauth_id_req, .name = "EAP-AKA-Fullauth-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_identity, .name = "EAP-AKA-Identity", .type = FR_TYPE_STRING, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_kdf_input, .name = "EAP-AKA-KDF-Input", .type = FR_TYPE_STRING, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_kdf, .name = "EAP-AKA-KDF", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_mac, .name = "EAP-AKA-MAC", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_notification, .name = "EAP-AKA-Notification", .type = FR_TYPE_UINT16, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_permanent_id_req, .name = "EAP-AKA-Permanent-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_rand, .name = "EAP-AKA-RAND", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_res, .name = "EAP-AKA-RES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_result_ind, .name = "EAP-AKA-Result-Ind", .type = FR_TYPE_BOOL, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_subtype, .name = "EAP-AKA-Subtype", .type = FR_TYPE_UINT32, .dict = &dict_eap_aka },
-       { NULL }
-};
-
-static int virtual_server_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
-                               CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
-{
-       CONF_SECTION    *server_cs;
-
-       if (virtual_server_has_namespace(&server_cs, cf_pair_value(cf_item_to_pair(ci)),
-                                        dict_eap_aka, ci) < 0) return -1;
-
-       if (mod_section_compile(out, server_cs) < 0) return -1;
-
-       return 0;
-}
-
-static int eap_aka_compose(eap_session_t *eap_session)
-{
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-       fr_cursor_t             cursor;
-       fr_cursor_t             to_encode;
-       VALUE_PAIR              *head = NULL, *vp;
-       REQUEST                 *request = eap_session->request;
-       ssize_t                 ret;
-       fr_sim_encode_ctx_t     encoder_ctx = {
-                                       .root = fr_dict_root(dict_eap_aka),
-                                       .keys = &eap_aka_session->keys,
-
-                                       .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
-                                       .iv_included = false,
-
-                                       .hmac_md = eap_aka_session->mac_md,
-                                       .eap_packet = eap_session->this_round->request,
-                                       .hmac_extra = NULL,
-                                       .hmac_extra_len = 0
-                               };
-
-       fr_cursor_init(&cursor, &eap_session->request->reply->vps);
-       fr_cursor_init(&to_encode, &head);
-
-       while ((vp = fr_cursor_current(&cursor))) {
-               if (!fr_dict_parent_common(encoder_ctx.root, vp->da, true)) {
-                       fr_cursor_next(&cursor);
-                       continue;
-               }
-               vp = fr_cursor_remove(&cursor);
-
-               /*
-                *      Silently discard encrypted attributes until
-                *      the peer should have k_encr.  These can be
-                *      added by policy, and seem to cause
-                *      wpa_supplicant to fail if sent before the challenge.
-                */
-               if (!eap_aka_session->allow_encrypted && fr_dict_parent_common(attr_eap_aka_encr_data, vp->da, true)) {
-                       RWDEBUG("Silently discarding &reply:%s: Encrypted attributes not allowed in this round",
-                               vp->da->name);
-                       talloc_free(vp);
-                       continue;
-               }
-
-               fr_cursor_append(&to_encode, vp);
-       }
-
-       RDEBUG2("Encoding EAP-AKA attributes");
-       log_request_pair_list(L_DBG_LVL_2, request, head, NULL);
-
-       eap_session->this_round->request->type.num = eap_aka_session->type;
-       eap_session->this_round->request->id = eap_aka_session->aka_id++ & 0xff;
-       eap_session->this_round->set_request_id = true;
-
-       ret = fr_sim_encode(eap_session->request, head, &encoder_ctx);
-       fr_cursor_head(&to_encode);
-       fr_cursor_free_list(&to_encode);
-
-       if (ret < 0) {
-               RPEDEBUG("Failed encoding EAP-AKA data");
-               return -1;
-       }
-       return 0;
-}
-
-/** Send an EAP-AKA identity request to the supplicant
- *
- * There are three types of user identities that can be implemented
- * - Permanent identities such as 0123456789098765@myoperator.com
- *   Permanent identities can be identified by the leading zero followed by
- *   by 15 digits (the IMSI number).
- * - Ephemeral identities (pseudonyms).  These are identities assigned for
- *   identity privacy so the user can't be tracked.  These can identities
- *   can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
- *   document section 14, where a set of up to 16 encryption keys are used
- *   to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
- *   randomised and stored in a datastore.
- * - A fast resumption ID which resolves to data used for fast resumption.
- *
- * In order to perform full authentication the original IMSI is required for
- * forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
- * or can't perform fast resumption, we need to request the full identity from
- * the supplicant.
- *
- * @param[in] eap_session      to continue.
- * @return
- *     - 0 on success.
- *     - <0 on failure.
- */
-static int eap_aka_send_identity_request(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-       VALUE_PAIR              *vp;
-       RADIUS_PACKET           *packet;
-       fr_cursor_t             cursor;
-
-       RDEBUG2("Sending AKA-Identity (%s)", fr_table_str_by_value(sim_id_request_table, eap_aka_session->id_req, "<INVALID>"));
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-       eap_aka_session->allow_encrypted = false;       /* In case this is after failed fast-resumption */
-
-       packet = request->reply;
-       fr_cursor_init(&cursor, &packet->vps);
-
-       /*
-        *      Set the subtype to identity request
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_aka_subtype);
-       vp->vp_uint16 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_IDENTITY;
-       fr_cursor_append(&cursor, vp);
-
-       /*
-        *      Select the right type of identity request attribute
-        */
-       switch (eap_aka_session->id_req) {
-       case SIM_ANY_ID_REQ:
-               vp = fr_pair_afrom_da(packet, attr_eap_aka_any_id_req);
-               break;
-
-       case SIM_PERMANENT_ID_REQ:
-               vp = fr_pair_afrom_da(packet, attr_eap_aka_permanent_id_req);
-               break;
-
-       case SIM_FULLAUTH_ID_REQ:
-               vp = fr_pair_afrom_da(packet, attr_eap_aka_fullauth_id_req);
-               break;
-
-       default:
-               rad_assert(0);
-       }
-       vp->vp_bool = true;
-       fr_cursor_append(&cursor, vp);
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_aka_compose(eap_session) < 0) {
-       failure:
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       /*
-        *      Digest the packet contents, updating our checkcode.
-        */
-       if (!eap_aka_session->checkcode_state &&
-           fr_sim_crypto_init_checkcode(eap_aka_session, &eap_aka_session->checkcode_state,
-                                        eap_aka_session->checkcode_md) < 0) {
-               RPEDEBUG("Failed initialising checkcode");
-               goto failure;
-       }
-       if (fr_sim_crypto_update_checkcode(eap_aka_session->checkcode_state, eap_session->this_round->request) < 0) {
-               RPEDEBUG("Failed updating checkcode");
-               goto failure;
-       }
-
-       return 0;
-}
-
-/** Send the challenge itself
- *
- * Challenges will come from one of three places eventually:
- *
- * 1  from attributes like FR_EAP_AKA_RANDx
- *         (these might be retrieved from a database)
- *
- * 2  from internally implemented SIM authenticators
- *         (a simple one based upon XOR will be provided)
- *
- * 3  from some kind of SS7 interface.
- *
- * For now, they only come from attributes.
- * It might be that the best way to do 2/3 will be with a different
- * module to generate/calculate things.
- */
-static int eap_aka_send_challenge(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-       VALUE_PAIR              **to_peer, *vp;
-       RADIUS_PACKET           *packet;
-       fr_sim_vector_src_t     src = SIM_VECTOR_SRC_AUTO;
-
-       rad_assert(request);
-       rad_assert(request->reply);
-
-       /*
-        *      to_peer is the data to the client
-        */
-       packet = eap_session->request->reply;
-       to_peer = &packet->vps;
-
-       RDEBUG2("Acquiring UMTS vector(s)");
-
-       /*
-        *      Toggle the AMF high bit to indicate we're doing AKA'
-        */
-       if (eap_aka_session->type == FR_EAP_METHOD_AKA_PRIME) {
-               uint8_t amf_buff[2] = { 0x80, 0x00 };   /* Set the AMF separation bit high */
-
-               MEM(pair_update_control(&vp, attr_sim_amf) >= 0);
-               fr_pair_value_memcpy(vp, amf_buff, sizeof(amf_buff), false);
-       }
-
-       /*
-        *      Get vectors from attribute or generate
-        *      them using COMP128-* or Milenage.
-        */
-       if (fr_sim_vector_umts_from_attrs(request, request->control, &eap_aka_session->keys, &src) != 0) {
-               REDEBUG("Failed retrieving UMTS vectors");
-               return RLM_MODULE_FAIL;
-       }
-
-       /*
-        *      Don't leave the AMF hanging around
-        */
-       if (eap_aka_session->type == FR_EAP_METHOD_AKA_PRIME) pair_delete_control(attr_sim_amf);
-
-       /*
-        *      All set, calculate keys!
-        */
-       switch (eap_aka_session->kdf) {
-       case FR_EAP_AKA_KDF_VALUE_EAP_AKA_PRIME_WITH_CK_PRIME_IK_PRIME:
-               fr_sim_crypto_kdf_1_umts(&eap_aka_session->keys);
-               break;
-
-       default:
-               fr_sim_crypto_kdf_0_umts(&eap_aka_session->keys);
-               break;
-       }
-       if (RDEBUG_ENABLED3) fr_sim_crypto_keys_log(request, &eap_aka_session->keys);
-
-       RDEBUG2("Sending AKA-Challenge");
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
-       /*
-        *      Set the subtype to challenge
-        */
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_subtype));
-       vp->vp_uint16 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_CHALLENGE;
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      Indicate we'd like to use protected success messages
-        */
-       if (eap_aka_session->send_result_ind) {
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_result_ind));
-               vp->vp_bool = true;
-               fr_pair_replace(to_peer, vp);
-       }
-
-       /*
-        *      We support EAP-AKA' and the peer should use that
-        *      if it's able to...
-        */
-       if (eap_aka_session->send_at_bidding) {
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_bidding));
-               vp->vp_uint16 = FR_EAP_AKA_BIDDING_VALUE_PREFER_AKA_PRIME;
-               fr_pair_replace(to_peer, vp);
-       }
-
-       /*
-        *      Send the network name and KDF to the peer
-        */
-       if (eap_aka_session->type == FR_EAP_METHOD_AKA_PRIME) {
-               if (!eap_aka_session->keys.network_len) {
-                       REDEBUG2("No network name available, can't set EAP-AKA-KDF-Input");
-               failure:
-                       fr_pair_list_free(&packet->vps);
-                       return -1;
-               }
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_kdf_input));
-               fr_pair_value_bstrncpy(vp, eap_aka_session->keys.network, eap_aka_session->keys.network_len);
-               fr_pair_replace(to_peer, vp);
-
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_kdf));
-               vp->vp_uint16 = eap_aka_session->kdf;
-               fr_pair_replace(to_peer, vp);
-       }
-
-       /*
-        *      Okay, we got the challenge! Put it into an attribute.
-        */
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_rand));
-       fr_pair_value_memcpy(vp, eap_aka_session->keys.umts.vector.rand, SIM_VECTOR_UMTS_RAND_SIZE, false);
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      Send the AUTN value to the client, so it can authenticate
-        *      whoever has knowledge of the Ki.
-        */
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_autn));
-       fr_pair_value_memcpy(vp, eap_aka_session->keys.umts.vector.autn, SIM_VECTOR_UMTS_AUTN_SIZE, false);
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      need to include an AT_MAC attribute so that it will get
-        *      calculated.
-        */
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_mac));
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      If we have checkcode data, send that to the peer
-        *      for validation.
-        */
-       if (eap_aka_session->checkcode_state) {
-               ssize_t slen;
-
-               slen = fr_sim_crypto_finalise_checkcode(eap_aka_session->checkcode, &eap_aka_session->checkcode_state);
-               if (slen < 0) {
-                       RPEDEBUG("Failed calculating checkcode");
-                       goto failure;
-               }
-               eap_aka_session->checkcode_len = slen;
-
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_checkcode));
-               fr_pair_value_memcpy(vp, eap_aka_session->checkcode, slen, false);
-       /*
-        *      If we don't have checkcode data, then we exchanged
-        *      no identity packets, so checkcode is zero.
-        */
-       } else {
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_checkcode));
-               eap_aka_session->checkcode_len = 0;
-       }
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      We've sent the challenge so the peer should now be able
-        *      to accept encrypted attributes.
-        */
-       eap_aka_session->allow_encrypted = true;
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_aka_compose(eap_session) < 0) goto failure;
-
-       return 0;
-}
-
-/** Send a success notification
- *
- */
-static int eap_aka_send_eap_success_notification(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       RADIUS_PACKET           *packet = eap_session->request->reply;
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-       fr_cursor_t             cursor;
-       VALUE_PAIR              *vp;
-
-       RDEBUG2("Sending AKA-Notification (Success)");
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
-       if (!fr_cond_assert(eap_aka_session->challenge_success)) return -1;
-
-       fr_cursor_init(&cursor, &packet->vps);
-
-       /*
-        *      Set the subtype to notification
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_aka_subtype);
-       vp->vp_uint16 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_NOTIFICATION;
-       fr_cursor_append(&cursor, vp);
-
-       vp = fr_pair_afrom_da(packet, attr_eap_aka_notification);
-       vp->vp_uint16 = FR_EAP_AKA_NOTIFICATION_VALUE_SUCCESS;
-       fr_cursor_append(&cursor, vp);
-
-       /*
-        *      Need to include an AT_MAC attribute so that it will get
-        *      calculated.
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_aka_mac);
-       fr_pair_replace(&packet->vps, vp);
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_aka_compose(eap_session) < 0) {
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       return 0;
-}
-
-/** Send a success message with MPPE-keys
- *
- * The only work to be done is the add the appropriate SEND/RECV
- * attributes derived from the MSK.
- */
-static int eap_aka_send_eap_success(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       uint8_t                 *p;
-       eap_aka_session_t       *eap_aka_session;
-
-       RDEBUG2("Sending EAP-Success");
-
-       eap_session->this_round->request->code = FR_EAP_CODE_SUCCESS;
-       eap_session->finished = true;
-
-       eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-
-       p = eap_aka_session->keys.msk;
-       eap_add_reply(eap_session->request, attr_ms_mppe_recv_key, p, EAP_TLS_MPPE_KEY_LEN);
-       p += EAP_TLS_MPPE_KEY_LEN;
-       eap_add_reply(eap_session->request, attr_ms_mppe_send_key, p, EAP_TLS_MPPE_KEY_LEN);
-
-       return 0;
-}
-
-/** Send a failure message
- *
- */
-static int eap_aka_send_eap_failure_notification(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       RADIUS_PACKET           *packet = eap_session->request->reply;
-       fr_cursor_t             cursor;
-       VALUE_PAIR              *vp;
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-
-       fr_cursor_init(&cursor, &packet->vps);
-
-       vp = fr_pair_find_by_da(packet->vps, attr_eap_aka_notification, TAG_ANY);
-       if (!vp) {
-               vp = fr_pair_afrom_da(packet, attr_eap_aka_notification);
-               vp->vp_uint16 = FR_EAP_AKA_NOTIFICATION_VALUE_GENERAL_FAILURE;
-               fr_cursor_append(&cursor, vp);
-       }
-
-       /*
-        *      Change the failure notification depending where
-        *      we are in the state machine.
-        */
-       if (eap_aka_session->challenge_success) {
-               vp->vp_uint16 &= ~0x4000;       /* Unset phase bit */
-       } else {
-               vp->vp_uint16 |= 0x4000;        /* Set phase bit */
-       }
-       vp->vp_uint16 &= ~0x8000;               /* In both cases success bit should be low */
-
-       RDEBUG2("Sending AKA-Notification (%pV)", &vp->data);
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
-       /*
-        *      Set the subtype to notification
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_aka_subtype);
-       vp->vp_uint16 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_NOTIFICATION;
-       fr_cursor_append(&cursor, vp);
-
-       /*
-        *      If we're after the challenge phase
-        *      then we need to include a MAC to
-        *      protect notifications.
-        */
-       if (eap_aka_session->challenge_success) {
-               vp = fr_pair_afrom_da(packet, attr_eap_aka_mac);
-               fr_pair_replace(&packet->vps, vp);
-       }
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_aka_compose(eap_session) < 0) {
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int eap_aka_send_eap_failure(eap_session_t *eap_session)
-{
-       REQUEST         *request = eap_session->request;
-
-       RDEBUG2("Sending EAP-Failure");
-
-       eap_session->this_round->request->code = FR_EAP_CODE_FAILURE;
-       eap_session->finished = true;
-
-       return 0;
-}
-
-/** Run the server state machine
- *
- */
-static void eap_aka_state_enter(eap_session_t *eap_session, eap_aka_server_state_t new_state)
-{
-       REQUEST                 *request = eap_session->request;
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-
-       if (new_state != eap_aka_session->state) {
-               RDEBUG2("Changed state %s -> %s",
-                       fr_table_str_by_value(aka_state_table, eap_aka_session->state, "<unknown>"),
-                       fr_table_str_by_value(aka_state_table, new_state, "<unknown>"));
-               eap_aka_session->state = new_state;
-       } else {
-               RDEBUG2("Reentering state %s",
-                       fr_table_str_by_value(aka_state_table, eap_aka_session->state, "<unknown>"));
-       }
-
-       switch (new_state) {
-       /*
-        *      Send an EAP-AKA Identity request
-        */
-       case EAP_AKA_SERVER_IDENTITY:
-               if (eap_aka_send_identity_request(eap_session) < 0) {
-               notify_failure:
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-                       return;
-               }
-               break;
-
-       /*
-        *      Send the EAP-AKA Challenge message.
-        */
-       case EAP_AKA_SERVER_CHALLENGE:
-               if (eap_aka_send_challenge(eap_session) < 0) goto notify_failure;
-               break;
-
-       /*
-        *      Sent a protected success notification
-        */
-       case EAP_AKA_SERVER_SUCCESS_NOTIFICATION:
-               if (eap_aka_send_eap_success_notification(eap_session) < 0) goto notify_failure;
-               break;
-
-       /*
-        *      Send the EAP Success message (we're done)
-        */
-       case EAP_AKA_SERVER_SUCCESS:
-               if (eap_aka_send_eap_success(eap_session) < 0) goto notify_failure;
-               return;
-
-       /*
-        *      Send a general failure notification
-        */
-       case EAP_AKA_SERVER_FAILURE_NOTIFICATION:
-               if (eap_aka_send_eap_failure_notification(eap_session) < 0) {   /* Fallback to EAP-Failure */
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE);
-               }
-               return;
-
-       /*
-        *      Send an EAP-Failure (we're done)
-        */
-       case EAP_AKA_SERVER_FAILURE:
-               eap_aka_send_eap_failure(eap_session);
-               return;
-
-       default:
-               rad_assert(0);  /* Invalid transition */
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-               return;
-       }
-}
-
-static int process_eap_aka_identity(eap_session_t *eap_session, VALUE_PAIR *vps)
-{
-       REQUEST                 *request = eap_session->request;
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-       VALUE_PAIR              *id;
-       fr_sim_id_type_t        type = SIM_ID_TYPE_UNKNOWN;
-       fr_sim_method_hint_t    method = SIM_METHOD_HINT_UNKNOWN;
-
-       /*
-        *      Digest the identity response
-        */
-       if (fr_sim_crypto_update_checkcode(eap_aka_session->checkcode_state, eap_session->this_round->response) < 0) {
-               RPEDEBUG("Failed updating checkcode");
-               return -1;
-       }
-
-       /*
-        *      See if we got an AT_IDENTITY
-        */
-       id = fr_pair_find_by_da(vps, attr_eap_aka_identity, TAG_ANY);
-       if (id) {
-               if (fr_sim_id_type(&type, &method,
-                                  eap_session->identity, talloc_array_length(eap_session->identity) - 1) < 0) {
-                       RPWDEBUG2("Failed parsing identity");
-               }
-               /*
-                *      Update cryptographic identity
-                */
-               talloc_const_free(eap_aka_session->keys.identity);
-               eap_aka_session->keys.identity_len = id->vp_length;
-               MEM(eap_aka_session->keys.identity = talloc_memdup(eap_aka_session, id->vp_strvalue, id->vp_length));
-       }
-
-       /*
-        *      @TODO Run a virtual server to see if we can use the
-        *      identity we just acquired, or whether we need to
-        *      negotiate the next permissive ID.
-        */
-
-       /*
-        *      Negotiate the next permissive form
-        *      if identity, or fail.
-        */
-       switch (eap_aka_session->id_req) {
-       case SIM_ANY_ID_REQ:
-               eap_aka_session->id_req = SIM_FULLAUTH_ID_REQ;
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_IDENTITY);
-               break;
-
-       case SIM_FULLAUTH_ID_REQ:
-               eap_aka_session->id_req = SIM_PERMANENT_ID_REQ;
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_IDENTITY);
-               break;
-
-       case SIM_PERMANENT_ID_REQ:
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_CHALLENGE);
-//             REDEBUG2("Failed to negotiate a usable identity");
-//             eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-               break;
-
-       case SIM_NO_ID_REQ:
-               rad_assert(0);
-               return -1;
-       }
-
-       return 0;
-}
-
-/**  Process an EAP-AKA/Response/Challenge
- *
- * Verify that MAC, and RES match what we expect.
- */
-static int process_eap_aka_challenge(eap_session_t *eap_session, VALUE_PAIR *vps)
-{
-       REQUEST                 *request = eap_session->request;
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-
-       uint8_t                 calc_mac[SIM_MAC_DIGEST_SIZE];
-       ssize_t                 slen;
-       VALUE_PAIR              *vp = NULL, *mac, *checkcode;
-
-       mac = fr_pair_find_by_da(vps, attr_eap_aka_mac, TAG_ANY);
-       if (!mac) {
-               REDEBUG("Missing AT_MAC attribute");
-               return -1;
-       }
-       if (mac->vp_length != SIM_MAC_DIGEST_SIZE) {
-               REDEBUG("EAP-AKA-MAC has incorrect length, expected %u bytes got %zu bytes",
-                       SIM_MAC_DIGEST_SIZE, mac->vp_length);
-               return -1;
-       }
-
-       slen = fr_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true,
-                                        eap_aka_session->mac_md,
-                                        eap_aka_session->keys.k_aut, eap_aka_session->keys.k_aut_len,
-                                        NULL, 0);
-       if (slen < 0) {
-               RPEDEBUG("Failed calculating MAC");
-               return -1;
-       } else if (slen == 0) {
-               REDEBUG("Missing EAP-AKA-MAC attribute in packet buffer");
-               return -1;
-       }
-
-       if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
-               RDEBUG2("EAP-AKA-MAC matches calculated MAC");
-       } else {
-               REDEBUG("EAP-AKA-MAC does not match calculated MAC");
-               RHEXDUMP_INLINE2(mac->vp_octets, SIM_MAC_DIGEST_SIZE, "Received");
-               RHEXDUMP_INLINE2(calc_mac, SIM_MAC_DIGEST_SIZE, "Expected");
-               return -1;
-       }
-
-       /*
-        *      If the peer doesn't include a checkcode then that
-        *      means they don't support it, and we can't validate
-        *      their view of the identity packets.
-        */
-       checkcode = fr_pair_find_by_da(vps, attr_eap_aka_checkcode, TAG_ANY);
-       if (checkcode) {
-               if (checkcode->vp_length != eap_aka_session->checkcode_len) {
-                       REDEBUG("Checkcode length (%zu) does not match calculated checkcode length (%zu)",
-                               checkcode->vp_length, eap_aka_session->checkcode_len);
-                       return -1;
-               }
-
-               if (memcmp(checkcode->vp_octets, eap_aka_session->checkcode, eap_aka_session->checkcode_len) == 0) {
-                       RDEBUG2("EAP-AKA-Checkcode matches calculated checkcode");
-               } else {
-                       REDEBUG("EAP-AKA-Checkcode does not match calculated checkcode");
-                       RHEXDUMP_INLINE2(checkcode->vp_octets, checkcode->vp_length, "Received");
-                       RHEXDUMP_INLINE2(eap_aka_session->checkcode,
-                                       eap_aka_session->checkcode_len, "Expected");
-                       return -1;
-               }
-       /*
-        *      Only print something if we calculated a checkcode
-        */
-       } else if (eap_aka_session->checkcode_len > 0){
-               RDEBUG2("Peer didn't include EAP-AKA-Checkcode, skipping checkcode validation");
-       }
-
-       vp = fr_pair_find_by_da(vps, attr_eap_aka_res, TAG_ANY);
-       if (!vp) {
-               REDEBUG("Missing EAP-AKA-RES from challenge response");
-               return -1;
-       }
-
-       if (vp->vp_length != eap_aka_session->keys.umts.vector.xres_len) {
-               REDEBUG("EAP-AKA-RES length (%zu) does not match XRES length (%zu)",
-                       vp->vp_length, eap_aka_session->keys.umts.vector.xres_len);
-               return -1;
-       }
-
-       if (memcmp(vp->vp_octets, eap_aka_session->keys.umts.vector.xres, vp->vp_length)) {
-               REDEBUG("EAP-AKA-RES from client does match XRES");
-               RHEXDUMP_INLINE2(vp->vp_octets, vp->vp_length, "RES  :");
-               RHEXDUMP_INLINE2(eap_aka_session->keys.umts.vector.xres,
-                               eap_aka_session->keys.umts.vector.xres_len, "XRES :");
-               return -1;
-       }
-
-       RDEBUG2("EAP-AKA-RES matches XRES");
-
-       eap_aka_session->challenge_success = true;
-
-       /*
-        *      If the peer wants a Success notification, then
-        *      send a success notification, otherwise send a
-        *      normal EAP-Success.
-        */
-       if (fr_pair_find_by_da(vps, attr_eap_aka_result_ind, TAG_ANY)) {
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_SUCCESS_NOTIFICATION);
-               return 1;
-       }
-
-       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_SUCCESS);
-       return 0;
-}
-
-/** Process the Peer's response and advantage the state machine
- *
- */
-static rlm_rcode_t mod_process(UNUSED void *instance, UNUSED void *thread, REQUEST *request)
-{
-       eap_session_t           *eap_session = eap_session_get(request);
-       eap_aka_session_t       *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
-
-       fr_sim_decode_ctx_t     ctx = {
-                                       .keys = &eap_aka_session->keys,
-                               };
-       VALUE_PAIR              *vp, *vps, *subtype_vp;
-       fr_cursor_t             cursor;
-
-       eap_aka_subtype_t       subtype;
-
-       int                     ret;
-
-       /*
-        *      RFC 4187 says we ignore the contents of the
-        *      next packet after we send our success notification
-        *      and always send a success.
-        */
-       if (eap_aka_session->state == EAP_AKA_SERVER_SUCCESS_NOTIFICATION) {
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_SUCCESS);
-               return RLM_MODULE_HANDLED;
-       }
-
-       /* vps is the data from the client */
-       vps = request->packet->vps;
-
-       fr_cursor_init(&cursor, &request->packet->vps);
-       fr_cursor_tail(&cursor);
-
-       ret = fr_sim_decode(eap_session->request,
-                           &cursor,
-                           dict_eap_aka,
-                           eap_session->this_round->response->type.data,
-                           eap_session->this_round->response->type.length,
-                           &ctx);
-       /*
-        *      RFC 4187 says we *MUST* notify, not just
-        *      send an EAP-Failure in this case where
-        *      we cannot decode an EAP-AKA packet.
-        */
-       if (ret < 0) {
-               RPEDEBUG2("Failed decoding EAP-AKA attributes");
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-               return RLM_MODULE_HANDLED;      /* We need to process more packets */
-       }
-
-       vp = fr_cursor_current(&cursor);
-       if (vp && RDEBUG_ENABLED2) {
-               RDEBUG2("EAP-AKA decoded attributes");
-               log_request_pair_list(L_DBG_LVL_2, request, vp, NULL);
-       }
-
-       subtype_vp = fr_pair_find_by_da(vps, attr_eap_aka_subtype, TAG_ANY);
-       if (!subtype_vp) {
-               REDEBUG("Missing EAP-AKA-Subtype");
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-               return RLM_MODULE_HANDLED;                              /* We need to process more packets */
-       }
-       subtype = subtype_vp->vp_uint16;
-
-       switch (eap_aka_session->state) {
-       /*
-        *      Here we expected the peer to send
-        *      us identities for validation.
-        */
-       case EAP_AKA_SERVER_IDENTITY:
-               switch (subtype) {
-               case EAP_AKA_IDENTITY:
-                       if (process_eap_aka_identity(eap_session, vps) == 0) return RLM_MODULE_HANDLED;
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-                       return RLM_MODULE_HANDLED;      /* We need to process more packets */
-
-               /*
-                *      Case 1 where we're allowed to send an EAP-Failure
-                *
-                *      This can happen in the case of a conservative
-                *      peer, where it refuses to provide the permanent
-                *      identity.
-                */
-               case EAP_AKA_CLIENT_ERROR:
-               {
-                       char buff[20];
-
-                       vp = fr_pair_find_by_da(vps, attr_eap_aka_client_error_code, TAG_ANY);
-                       if (!vp) {
-                               REDEBUG("EAP-AKA Peer rejected AKA-Identity (%s) with client-error message but "
-                                       "has not supplied a client error code",
-                                       fr_table_str_by_value(sim_id_request_table, eap_aka_session->id_req, "<INVALID>"));
-                       } else {
-                               REDEBUG("Client rejected AKA-Identity (%s) with error: %s (%i)",
-                                       fr_table_str_by_value(sim_id_request_table, eap_aka_session->id_req, "<INVALID>"),
-                                       fr_pair_value_enum(vp, buff), vp->vp_uint16);
-                       }
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE);
-                       return RLM_MODULE_REJECT;
-               }
-
-               case EAP_AKA_NOTIFICATION:
-               notification:
-               {
-                       char buff[20];
-
-                       vp = fr_pair_afrom_da(vps, attr_eap_aka_notification);
-                       if (!vp) {
-                               REDEBUG2("Received AKA-Notification with no notification code");
-                               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-                               return RLM_MODULE_HANDLED;                      /* We need to process more packets */
-                       }
-
-                       /*
-                        *      Case 3 where we're allowed to send an EAP-Failure
-                        */
-                       if (!(vp->vp_uint16 & 0x8000)) {
-                               REDEBUG2("AKA-Notification %s (%i) indicates failure", fr_pair_value_enum(vp, buff),
-                                        vp->vp_uint16);
-                               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE);
-                               return RLM_MODULE_REJECT;
-                       }
-
-                       /*
-                        *      ...if it's not a failure, then re-enter the
-                        *      current state.
-                        */
-                       REDEBUG2("Got AKA-Notification %s (%i)", fr_pair_value_enum(vp, buff), vp->vp_uint16);
-                       eap_aka_state_enter(eap_session, eap_aka_session->state);
-                       return RLM_MODULE_HANDLED;
-               }
-
-               default:
-               unexpected_subtype:
-                       /*
-                        *      RFC 4187 says we *MUST* notify, not just
-                        *      send an EAP-Failure in this case.
-                        */
-                       REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-                       return RLM_MODULE_HANDLED;                              /* We need to process more packets */
-               }
-
-       /*
-        *      Process the response to our previous challenge.
-        */
-       case EAP_AKA_SERVER_CHALLENGE:
-               switch (subtype) {
-               case EAP_AKA_CHALLENGE:
-                       switch (process_eap_aka_challenge(eap_session, vps)) {
-                       case 1:
-                               return RLM_MODULE_HANDLED;
-
-                       case 0:
-                               return RLM_MODULE_OK;
-
-                       case -1:
-                               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-                               return RLM_MODULE_HANDLED;                      /* We need to process more packets */
-                       }
-
-
-               case EAP_AKA_SYNCHRONIZATION_FAILURE:
-                       REDEBUG("EAP-AKA Peer synchronization failure");        /* We can't handle these yet */
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-                       return RLM_MODULE_HANDLED;                              /* We need to process more packets */
-
-               /*
-                *      Case 1 where we're allowed to send an EAP-Failure
-                */
-               case EAP_AKA_CLIENT_ERROR:
-               {
-                       char buff[20];
-
-                       vp = fr_pair_find_by_da(vps, attr_eap_aka_client_error_code, TAG_ANY);
-                       if (!vp) {
-                               REDEBUG("EAP-AKA Peer rejected AKA-Challenge with client-error message but "
-                                       "has not supplied a client error code");
-                       } else {
-                               REDEBUG("Client rejected AKA-Challenge with error: %s (%i)",
-                                       fr_pair_value_enum(vp, buff), vp->vp_uint16);
-                       }
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE);
-                       return RLM_MODULE_REJECT;
-               }
-
-               /*
-                *      Case 2 where we're allowed to send an EAP-Failure
-                */
-               case EAP_AKA_AUTHENTICATION_REJECT:
-                       REDEBUG("EAP-AKA Peer Rejected AUTN");
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE);
-                       return RLM_MODULE_REJECT;
-
-               case EAP_AKA_NOTIFICATION:
-                       goto notification;
-
-               default:
-                       goto unexpected_subtype;
-               }
-
-       /*
-        *      Peer acked our failure
-        */
-       case EAP_AKA_SERVER_FAILURE_NOTIFICATION:
-               switch (subtype) {
-               case EAP_AKA_NOTIFICATION:
-                       RDEBUG2("AKA-Notification ACKed, sending EAP-Failure");
-                       eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE);
-                       return RLM_MODULE_REJECT;
-
-               default:
-                       goto unexpected_subtype;
-               }
-
-       /*
-        *      Something bad happened...
-        */
-       default:
-               rad_assert(0);
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
-               return RLM_MODULE_HANDLED;                              /* We need to process more packets */
-       }
-}
-
-/** Initiate the EAP-SIM session by starting the state machine
- *
- */
-static rlm_rcode_t mod_session_init(void *instance, UNUSED void *thread, REQUEST *request)
-{
-       rlm_eap_aka_t                   *inst = talloc_get_type_abort(instance, rlm_eap_aka_t);
-       eap_session_t                   *eap_session = eap_session_get(request);
-       eap_aka_session_t               *eap_aka_session;
-
-       fr_sim_id_type_t                type;
-       fr_sim_method_hint_t            method;
-
-       MEM(eap_aka_session = talloc_zero(eap_session, eap_aka_session_t));
-
-       eap_session->opaque = eap_aka_session;
-
-       /*
-        *      Set default configuration, we may allow these
-        *      to be toggled by attributes later.
-        */
-       eap_aka_session->request_identity = inst->request_identity;
-       eap_aka_session->send_result_ind = inst->protected_success;
-       eap_aka_session->id_req = SIM_NO_ID_REQ;        /* Set the default */
-
-       /*
-        *      This value doesn't have be strong, but it is
-        *      good if it is different now and then.
-        */
-       eap_aka_session->aka_id = (fr_rand() & 0xff);
-
-       /*
-        *      Process the identity that we received in the
-        *      EAP-Identity-Response and use it to determine
-        *      the initial request we send to the Supplicant.
-        */
-       if (fr_sim_id_type(&type, &method,
-                          eap_session->identity, talloc_array_length(eap_session->identity) - 1) < 0) {
-               RPWDEBUG2("Failed parsing identity, continuing anyway");
-       }
-
-       /*
-        *      Unless AKA-Prime is explicitly disabled,
-        *      use it... It has stronger keying, and
-        *      binds authentication to the network.
-        */
-       switch (eap_session->type) {
-       case FR_EAP_METHOD_AKA_PRIME:
-       default:
-               RDEBUG2("New EAP-AKA' session");
-               eap_aka_session->type = FR_EAP_METHOD_AKA_PRIME;
-               eap_aka_session->kdf = FR_EAP_AKA_KDF_VALUE_EAP_AKA_PRIME_WITH_CK_PRIME_IK_PRIME;
-               eap_aka_session->checkcode_md = eap_aka_session->mac_md = EVP_sha256();
-               eap_aka_session->keys.network = (uint8_t *)talloc_bstrndup(eap_aka_session, inst->network_name,
-                                                                          talloc_array_length(inst->network_name) - 1);
-               eap_aka_session->keys.network_len = talloc_array_length(eap_aka_session->keys.network) - 1;
-               switch (method) {
-               default:
-                       RWDEBUG("EAP-Identity-Response hints that EAP-%s should be started, but we're "
-                               "attempting EAP-AKA'", fr_table_str_by_value(sim_id_method_hint_table, method, "<INVALID>"));
-                       break;
-
-               case SIM_METHOD_HINT_AKA_PRIME:
-               case SIM_METHOD_HINT_UNKNOWN:
-                       break;
-               }
-               break;
-
-       case FR_EAP_METHOD_AKA:
-               RDEBUG2("New EAP-AKA session");
-               eap_aka_session->type = FR_EAP_METHOD_AKA;
-               eap_aka_session->kdf = FR_EAP_AKA_KDF_VALUE_EAP_AKA;    /* Not actually sent */
-               eap_aka_session->checkcode_md = eap_aka_session->mac_md = EVP_sha1();
-               eap_aka_session->send_at_bidding = true;
-               switch (method) {
-               default:
-                       RWDEBUG("EAP-Identity-Response hints that EAP-%s should be started, but we're "
-                               "attempting EAP-AKA", fr_table_str_by_value(sim_id_method_hint_table, method, "<INVALID>"));
-                       break;
-
-               case SIM_METHOD_HINT_AKA:
-               case SIM_METHOD_HINT_UNKNOWN:
-                       break;
-               }
-               break;
-       }
-       eap_session->process = mod_process;
-
-       /*
-        *      Admin wants us to always request an identity
-        *      initially.  The RFC says this is also the
-        *      better way to operate, as the supplicant
-        *      can 'decorate' the identity in the identity
-        *      response.
-        */
-       if (inst->request_identity) {
-       request_id:
-               /*
-                *      We always start by requesting
-                *      any ID initially as we can
-                *      always negotiate down.
-                */
-               eap_aka_session->id_req = SIM_ANY_ID_REQ;
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_IDENTITY);
-               return RLM_MODULE_HANDLED;
-       }
-       /*
-        *      Figure out what type of identity we have
-        *      and use it to determine the initial
-        *      request we send.
-        */
-       switch (type) {
-       /*
-        *      If there's no valid tag on the identity
-        *      then it's probably been decorated by the
-        *      supplicant.
-        *
-        *      Request the unmolested identity
-        */
-       case SIM_ID_TYPE_UNKNOWN:
-               RWDEBUG("Identity format unknown, sending Identity request");
-               goto request_id;
-
-       /*
-        *      These types need to be transformed into something
-        *      usable before we can do anything.
-        */
-       case SIM_ID_TYPE_PSEUDONYM:
-       case SIM_ID_TYPE_FASTAUTH:
-
-       /*
-        *      Permanent ID means we can just send the challenge
-        */
-       case SIM_ID_TYPE_PERMANENT:
-               eap_aka_session->keys.identity_len = talloc_array_length(eap_session->identity) - 1;
-               MEM(eap_aka_session->keys.identity = talloc_memdup(eap_aka_session, eap_session->identity,
-                                                                  eap_aka_session->keys.identity_len));
-               eap_aka_state_enter(eap_session, EAP_AKA_SERVER_CHALLENGE);
-               return RLM_MODULE_HANDLED;
-       }
-
-       return RLM_MODULE_HANDLED;
-}
-
-#define ACTION_SECTION(_out, _field, _verb, _name) \
-do { \
-       CONF_SECTION *_tmp; \
-       _tmp = cf_section_find(server_cs, _verb, _name); \
-       if (_tmp) { \
-               if (unlang_compile(_tmp, MOD_AUTHORIZE, NULL) < 0) return -1; \
-               found = true; \
-       } \
-       if (_out) _out->_field = _tmp; \
-} while (0)
-
 /** Compile virtual server sections
  *
  * Called twice, once when a server with an eap-aka namespace is found, and once
@@ -1274,72 +63,76 @@ do { \
  * EAP-AKA module will use to execute unlang code.
  *
  */
-static int mod_section_compile(eap_aka_actions_t *actions, CONF_SECTION *server_cs)
+static int mod_section_compile(eap_aka_sim_actions_t *actions, CONF_SECTION *server_cs)
 {
        bool found = false;
 
        if (!fr_cond_assert(server_cs)) return -1;
 
        /*
-        *      Initial Identity-Response
-        *
-        *      We then either:
-        *      - Request a new identity
-        *      - Start full authentication
-        *      - Start fast re-authentication
-        *      - Fail...
+        *      Identity negotiation
         */
-       ACTION_SECTION(actions, recv_eap_identity_response, "recv", "EAP-Identity-Response");
+       EAP_SECTION_COMPILE(actions, send_identity_request, "send", "Identity-Request");
+       EAP_SECTION_COMPILE(actions, recv_identity_response, "recv", "Identity-Response");
 
        /*
-        *      Identity negotiation
+        *      Optional override sections if the user *really*
+        *      wants to apply special policies for subsequent
+        *      request/response rounds.
         */
-       ACTION_SECTION(actions, send_identity_request, "send", "Identity-Request");
-       ACTION_SECTION(actions, recv_identity_response, "recv", "Identity-Response");
+       EAP_SECTION_COMPILE(actions, aka.send_aka_identity_request, "send", "AKA-Identity-Request");
+       EAP_SECTION_COMPILE(actions, aka.recv_aka_identity_response, "recv", "AKA-Identity-Response");
 
        /*
         *      Full-Authentication
         */
-       ACTION_SECTION(actions, send_challenge_request, "send", "Challenge-Request");
-       ACTION_SECTION(actions, recv_challenge_response, "recv", "Challenge-Response");
+       EAP_SECTION_COMPILE(actions, send_challenge_request, "send", "Challenge-Request");
+       EAP_SECTION_COMPILE(actions, recv_challenge_response, "recv", "Challenge-Response");
 
        /*
-        *      Fast-Re-Authentication
+        *      Fast-Reauthentication
         */
-       ACTION_SECTION(actions, send_fast_reauth_request, "send", "Fast-Reauth-Request");
-       ACTION_SECTION(actions, recv_fast_reauth_response, "recv", "Fast-Reauth-Response");
+       EAP_SECTION_COMPILE(actions, send_reauthentication_request, "send", "Reauthentication-Request");
+       EAP_SECTION_COMPILE(actions, recv_reauthentication_response, "recv", "Reauthentication-Response");
 
        /*
         *      Failures originating from the supplicant
         */
-       ACTION_SECTION(actions, recv_client_error, "recv", "Client-Error");
-       ACTION_SECTION(actions, recv_authentication_reject, "recv", "Authentication-Reject");
-       ACTION_SECTION(actions, recv_syncronization_failure, "recv", "Syncronization-Failure");
+       EAP_SECTION_COMPILE(actions, recv_client_error, "recv", "Client-Error");
+       EAP_SECTION_COMPILE(actions, aka.recv_authentication_reject, "recv", "Authentication-Reject");
+       EAP_SECTION_COMPILE(actions, aka.recv_syncronization_failure, "recv", "Syncronization-Failure");
 
        /*
         *      Failure originating from the server
         */
-       ACTION_SECTION(actions, send_failure_notification, "send", "Failure-Notification");
-       ACTION_SECTION(actions, recv_failure_notification_ack, "recv", "Failure-Notification-ACK");
+       EAP_SECTION_COMPILE(actions, send_failure_notification, "send", "Failure-Notification");
+       EAP_SECTION_COMPILE(actions, recv_failure_notification_ack, "recv", "Failure-Notification-ACK");
 
        /*
         *      Protected success indication
         */
-       ACTION_SECTION(actions, send_success_notification, "send", "Success-Notification");
-       ACTION_SECTION(actions, recv_success_notification_ack, "recv", "Success-Notification-ACK");
+       EAP_SECTION_COMPILE(actions, send_success_notification, "send", "Success-Notification");
+       EAP_SECTION_COMPILE(actions, recv_success_notification_ack, "recv", "Success-Notification-ACK");
 
        /*
         *      Final EAP-Success and EAP-Failure messages
         */
-       ACTION_SECTION(actions, send_eap_success, "send", "EAP-Success");
-       ACTION_SECTION(actions, send_eap_failure, "send", "EAP-Failure");
+       EAP_SECTION_COMPILE(actions, send_eap_success, "send", "EAP-Success");
+       EAP_SECTION_COMPILE(actions, send_eap_failure, "send", "EAP-Failure");
 
        /*
         *      Fast-Reauth vectors
         */
-       ACTION_SECTION(actions, load_session, "load", "session");
-       ACTION_SECTION(actions, store_session, "store", "session");
-       ACTION_SECTION(actions, clear_session, "clear", "session");
+       EAP_SECTION_COMPILE(actions, store_session, "store", "session");
+       EAP_SECTION_COMPILE(actions, load_session, "load", "session");
+       EAP_SECTION_COMPILE(actions, clear_session, "clear", "session");
+
+       /*
+        *      Pseudonym processing
+        */
+       EAP_SECTION_COMPILE(actions, store_pseudonym, "store", "pseudonym");
+       EAP_SECTION_COMPILE(actions, load_pseudonym, "load", "pseudonym");
+       EAP_SECTION_COMPILE(actions, clear_pseudonym, "clear", "pseudonym");
 
        /*
         *      Warn if we couldn't find any actions.
@@ -1352,6 +145,34 @@ static int mod_section_compile(eap_aka_actions_t *actions, CONF_SECTION *server_
        return 0;
 }
 
+static int mod_instantiate(void *instance, CONF_SECTION *conf)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+
+       if (mod_section_compile(&inst->actions, inst->virtual_server) < 0) return -1;
+
+       /*
+        *      If the user didn't specify a bidding value
+        *      infer whether we need to send the bidding
+        *      attribute, by whether the EAP module has
+        *      has the AKA-Prime module enabled.
+        */
+       if (!inst->send_at_bidding_prefer_prime_is_set) {
+               CONF_SECTION    *parent = cf_item_to_section(cf_parent(conf));
+               CONF_PAIR       *cp = NULL;
+
+               while ((cp = cf_pair_find_next(parent, cp, "type"))) {
+                       if (strcmp(cf_pair_value(cp), "aka-prime") == 0) {
+                               cf_log_debug(conf, "Setting 'prefer_aka_prime = yes', as EAP-AKA-Prime is enabled");
+                               inst->send_at_bidding_prefer_prime = true;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /** Compile any virtual servers with the "eap-aka" namespace
  *
  */
@@ -1362,20 +183,20 @@ static int mod_namespace_load(CONF_SECTION *server_cs)
 
 static int mod_load(void)
 {
-       if (virtual_namespace_register("eap-aka", "eap-aka", "eap/aka", mod_namespace_load) < 0) return -1;
+       if (virtual_namespace_register("eap-aka", "eap-aka-sim", "eap/aka-sim", mod_namespace_load) < 0) return -1;
 
-       if (fr_sim_init() < 0) return -1;
+       if (fr_aka_sim_init() < 0) return -1;
 
-       sim_xlat_register();
+       fr_aka_sim_xlat_register();
 
        return 0;
 }
 
 static void mod_unload(void)
 {
-       sim_xlat_unregister();
+       fr_aka_sim_xlat_unregister();
 
-       fr_sim_free();
+       fr_aka_sim_free();
 }
 
 /*
@@ -1387,13 +208,17 @@ rlm_eap_submodule_t rlm_eap_aka = {
        .name           = "eap_aka",
        .magic          = RLM_MODULE_INIT,
 
-       .provides       = { FR_EAP_METHOD_AKA, FR_EAP_METHOD_AKA_PRIME },
-       .inst_size      = sizeof(rlm_eap_aka_t),
-       .inst_type      = "rlm_eap_aka_t",
+       .provides       = { FR_EAP_METHOD_AKA },
+
+       .inst_size      = sizeof(eap_aka_sim_common_conf_t),
+       .inst_type      = "eap_aka_sim_common_conf_t",
        .config         = submodule_config,
 
        .onload         = mod_load,
        .unload         = mod_unload,
-       .session_init   = mod_session_init,     /* Initialise a new EAP session */
-       .entry_point    = mod_process,          /* Process next round of EAP method */
+
+       .instantiate    = mod_instantiate,
+
+       .session_init   = aka_sim_state_machine_start,  /* Initialise a new EAP session */
+       .namespace      = &dict_eap_aka_sim
 };
diff --git a/src/modules/rlm_eap/types/rlm_eap_aka_prime/README.md b/src/modules/rlm_eap/types/rlm_eap_aka_prime/README.md
new file mode 100644 (file)
index 0000000..b268d29
--- /dev/null
@@ -0,0 +1,9 @@
+# rlm_eap_aka_prime
+## Metadata
+<dl>
+  <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements [RFC 5448](https://tools.ietf.org/html/rfc5448) EAP-AKA authentication.  EAP-AKA provides authentication
+and session keying material for 802.11i (WPA/2 Enterprise) using UMTS quintuplets.
diff --git a/src/modules/rlm_eap/types/rlm_eap_aka_prime/all.mk b/src/modules/rlm_eap/types/rlm_eap_aka_prime/all.mk
new file mode 100644 (file)
index 0000000..c9d92f3
--- /dev/null
@@ -0,0 +1,9 @@
+TARGETNAME     := rlm_eap_aka_prime
+
+ifneq "$(OPENSSL_LIBS)" ""
+TARGET         := $(TARGETNAME).a
+endif
+
+SOURCES                := $(TARGETNAME).c
+
+TGT_PREREQS    := $(LIBFREERADIUS_SERVER) libfreeradius-radius.a libfreeradius-util.a libfreeradius-eap.a libfreeradius-sim.a libfreeradius-eap-aka-sim.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_aka_prime/rlm_eap_aka_prime.c b/src/modules/rlm_eap/types/rlm_eap_aka_prime/rlm_eap_aka_prime.c
new file mode 100644 (file)
index 0000000..a7d156f
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *   This program is is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or (at
+ *   your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file rlm_eap_aka_prime.c
+ * @brief Implements EAP-AKA'
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ *
+ * @copyright 2019 The FreeRADIUS server project
+ * @copyright 2019 Network RADIUS SARL <sales@networkradius.com>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/eap/base.h>
+#include <freeradius-devel/eap_aka_sim/state_machine.h>
+#include <freeradius-devel/server/rad_assert.h>
+#include <freeradius-devel/unlang/compile.h>
+#include <freeradius-devel/unlang/module.h>
+
+static CONF_PARSER submodule_config[] = {
+       { FR_CONF_OFFSET("network_name", FR_TYPE_STRING, eap_aka_sim_common_conf_t, network_name ) },
+       { FR_CONF_OFFSET("request_identity", FR_TYPE_BOOL, eap_aka_sim_common_conf_t, request_identity ),
+         .func = cf_table_parse_uint32, .uctx = &(cf_table_parse_ctx_t){ .table = fr_aka_sim_id_request_table, .len = &fr_aka_sim_id_request_table_len }},
+       { FR_CONF_OFFSET("strip_permanent_identity_hint", FR_TYPE_BOOL, eap_aka_sim_common_conf_t,
+                        strip_permanent_identity_hint ), .dflt = "yes" },
+       { FR_CONF_OFFSET("ephemeral_id_length", FR_TYPE_UINT8, eap_aka_sim_common_conf_t, ephemeral_id_length ), .dflt = "14" },        /* 14 for compatibility */
+       { FR_CONF_OFFSET("protected_success", FR_TYPE_BOOL, eap_aka_sim_common_conf_t, protected_success ), .dflt = "no" },
+       { FR_CONF_OFFSET("virtual_server", FR_TYPE_VOID, eap_aka_sim_common_conf_t, virtual_server), .func = virtual_server_cf_parse },
+       CONF_PARSER_TERMINATOR
+};
+
+static fr_dict_t *dict_eap_aka_sim;
+
+extern fr_dict_autoload_t rlm_eap_aka_dict[];
+fr_dict_autoload_t rlm_eap_aka_dict[] = {
+       { .out = &dict_eap_aka_sim, .base_dir="eap/aka-sim", .proto = "eap-aka-sim"  },
+       { NULL }
+};
+
+/** Compile virtual server sections
+ *
+ * Called twice, once when a server with an eap-aka namespace is found, and once
+ * when an EAP-AKA module is instantiated.
+ *
+ * The first time is with actions == NULL and is to compile the sections and
+ * perform validation.
+ * The second time is to write out pointers to the compiled sections which the
+ * EAP-AKA module will use to execute unlang code.
+ *
+ */
+static int mod_section_compile(eap_aka_sim_actions_t *actions, CONF_SECTION *server_cs)
+{
+       bool found = false;
+
+       if (!fr_cond_assert(server_cs)) return -1;
+
+       /*
+        *      Identity negotiation
+        */
+       EAP_SECTION_COMPILE(actions, send_identity_request, "send", "Identity-Request");
+       EAP_SECTION_COMPILE(actions, recv_identity_response, "recv", "Identity-Response");
+
+       /*
+        *      Optional override sections if the user *really*
+        *      wants to apply special policies for subsequent
+        *      request/response rounds.
+        */
+       EAP_SECTION_COMPILE(actions, aka.send_aka_identity_request, "send", "AKA-Identity-Request");
+       EAP_SECTION_COMPILE(actions, aka.recv_aka_identity_response, "recv", "AKA-Identity-Response");
+
+       /*
+        *      Full-Authentication
+        */
+       EAP_SECTION_COMPILE(actions, send_challenge_request, "send", "Challenge-Request");
+       EAP_SECTION_COMPILE(actions, recv_challenge_response, "recv", "Challenge-Response");
+
+       /*
+        *      Fast-Re-Authentication
+        */
+       EAP_SECTION_COMPILE(actions, send_reauthentication_request, "send", "Reauthentication-Request");
+       EAP_SECTION_COMPILE(actions, recv_reauthentication_response, "recv", "Reauthentication-Response");
+
+       /*
+        *      Failures originating from the supplicant
+        */
+       EAP_SECTION_COMPILE(actions, recv_client_error, "recv", "Client-Error");
+       EAP_SECTION_COMPILE(actions, aka.recv_authentication_reject, "recv", "Authentication-Reject");
+       EAP_SECTION_COMPILE(actions, aka.recv_syncronization_failure, "recv", "Syncronization-Failure");
+
+       /*
+        *      Failure originating from the server
+        */
+       EAP_SECTION_COMPILE(actions, send_failure_notification, "send", "Failure-Notification");
+       EAP_SECTION_COMPILE(actions, recv_failure_notification_ack, "recv", "Failure-Notification-ACK");
+
+       /*
+        *      Protected success indication
+        */
+       EAP_SECTION_COMPILE(actions, send_success_notification, "send", "Success-Notification");
+       EAP_SECTION_COMPILE(actions, recv_success_notification_ack, "recv", "Success-Notification-ACK");
+
+       /*
+        *      Final EAP-Success and EAP-Failure messages
+        */
+       EAP_SECTION_COMPILE(actions, send_eap_success, "send", "EAP-Success");
+       EAP_SECTION_COMPILE(actions, send_eap_failure, "send", "EAP-Failure");
+
+       /*
+        *      Fast-Reauth vectors
+        */
+       EAP_SECTION_COMPILE(actions, store_session, "store", "session");
+       EAP_SECTION_COMPILE(actions, load_session, "load", "session");
+       EAP_SECTION_COMPILE(actions, clear_session, "clear", "session");
+
+       /*
+        *      Pseudonym processing
+        */
+       EAP_SECTION_COMPILE(actions, store_pseudonym, "store", "pseudonym");
+       EAP_SECTION_COMPILE(actions, load_pseudonym, "load", "pseudonym");
+       EAP_SECTION_COMPILE(actions, clear_pseudonym, "clear", "pseudonym");
+
+       /*
+        *      Warn if we couldn't find any actions.
+        */
+       if (!found) {
+               cf_log_warn(server_cs, "No \"eap-aka-prime\" actions found in virtual server \"%s\"",
+                           cf_section_name2(server_cs));
+       }
+
+       return 0;
+}
+
+static int mod_instantiate(void *instance, UNUSED CONF_SECTION *conf)
+{
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
+
+       if (mod_section_compile(&inst->actions, inst->virtual_server) < 0) return -1;
+
+       return 0;
+}
+
+/** Compile any virtual servers with the "eap-aka" namespace
+ *
+ */
+static int mod_namespace_load(CONF_SECTION *server_cs)
+{
+       return mod_section_compile(NULL, server_cs);
+}
+
+static int mod_load(void)
+{
+       if (virtual_namespace_register("eap-aka-prime", "eap-aka-sim", "eap/aka-sim", mod_namespace_load) < 0) return -1;
+
+       if (fr_aka_sim_init() < 0) return -1;
+
+       fr_aka_sim_xlat_register();
+
+       return 0;
+}
+
+static void mod_unload(void)
+{
+       fr_aka_sim_xlat_unregister();
+
+       fr_aka_sim_free();
+}
+
+/*
+ *     The module name should be the only globally exported symbol.
+ *     That is, everything else should be 'static'.
+ */
+extern rlm_eap_submodule_t rlm_eap_aka_prime;
+rlm_eap_submodule_t rlm_eap_aka_prime = {
+       .name           = "eap_aka_prime",
+       .magic          = RLM_MODULE_INIT,
+
+       .provides       = { FR_EAP_METHOD_AKA_PRIME },
+
+       .inst_size      = sizeof(eap_aka_sim_common_conf_t),
+       .inst_type      = "eap_aka_sim_common_conf_t",
+       .config         = submodule_config,
+
+       .onload         = mod_load,
+       .unload         = mod_unload,
+
+       .instantiate    = mod_instantiate,
+
+       .session_init   = aka_sim_state_machine_start,  /* Initialise a new EAP session */
+       .namespace      = &dict_eap_aka_sim
+};
index e4e3acdb5eb2c58401c8a61cc27402fb8be43759..1fb9cead506819d3b686d1facf91a2be0cef3903 100644 (file)
@@ -6,8 +6,4 @@ endif
 
 SOURCES                := $(TARGETNAME).c
 
-SRC_CFLAGS     :=
-TGT_LDLIBS     :=
-SRC_INCDIRS    := ${top_srcdir}/src/modules/rlm_eap/ ${top_srcdir}/src/modules/rlm_eap/lib/base/ ${top_srcdir}/src/modules/rlm_eap/lib/sim/
-
-TGT_PREREQS    := $(LIBFREERADIUS_SERVER) libfreeradius-radius.a libfreeradius-util.a libfreeradius-eap.a libfreeradius-eap-sim.a
+TGT_PREREQS    := $(LIBFREERADIUS_SERVER) libfreeradius-radius.a libfreeradius-util.a libfreeradius-eap.a libfreeradius-sim.a libfreeradius-eap-aka-sim.a
index 928c0210aab855757adf195df81c1d8164e2627e..7f724e0947fbd3ff32058dafa8c5ab5f435d9caa 100644 (file)
 
 /**
  * $Id$
- * @file rlm_eap_sim.c
- * @brief Implements the SIM part of EAP-SIM
+ * @file rlm_eap_aka.c
+ * @brief Implements EAP-AKA
  *
- * The development of the EAP/SIM support was funded by Internet Foundation
- * Austria (http://www.nic.at/ipa).
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
  *
- * @copyright 2003 Michael Richardson (mcr@sandelman.ottawa.on.ca)
- * @copyright 2003-2016 The FreeRADIUS server project
- * @copyright 2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2016 The FreeRADIUS server project
+ * @copyright 2016 Network RADIUS SARL <sales@networkradius.com>
  */
 RCSID("$Id$")
 
 #include <freeradius-devel/eap/base.h>
-#include <freeradius-devel/eap/types.h>
+#include <freeradius-devel/eap_aka_sim/state_machine.h>
 #include <freeradius-devel/server/rad_assert.h>
-#include <freeradius-devel/sim/base.h>
-
-#include <freeradius-devel/protocol/eap/sim/rfc4187.h>
-
-#include "eap_sim.h"
-
-#ifndef EAP_TLS_MPPE_KEY_LEN
-#  define EAP_TLS_MPPE_KEY_LEN     32
-#endif
-
-static fr_table_num_ordered_t const sim_state_table[] = {
-       { "START",                              EAP_SIM_SERVER_START                            },
-       { "CHALLENGE",                          EAP_SIM_SERVER_CHALLENGE                        },
-       { "REAUTHENTICATE",                     EAP_SIM_SERVER_REAUTHENTICATE                   },
-       { "SUCCESS-NOTIFICATION",               EAP_SIM_SERVER_SUCCESS_NOTIFICATION             },
-       { "SUCCESS",                            EAP_SIM_SERVER_SUCCESS                          },
-       { "FAILURE-NOTIFICATION",               EAP_SIM_SERVER_FAILURE_NOTIFICATION             },
-       { "FAILURE",                            EAP_SIM_SERVER_FAILURE                          },
-};
-static size_t sim_state_table_len = NUM_ELEMENTS(sim_state_table);
+#include <freeradius-devel/unlang/compile.h>
+#include <freeradius-devel/unlang/module.h>
 
 static CONF_PARSER submodule_config[] = {
-       { FR_CONF_OFFSET("virtual_server", FR_TYPE_STRING, rlm_eap_sim_t, virtual_server) },
-       { FR_CONF_OFFSET("protected_success", FR_TYPE_BOOL, rlm_eap_sim_t, protected_success ), .dflt = "no" },
+       { FR_CONF_OFFSET("request_identity", FR_TYPE_BOOL, eap_aka_sim_common_conf_t, request_identity ),
+         .func = cf_table_parse_uint32, .uctx = &(cf_table_parse_ctx_t){ .table = fr_aka_sim_id_request_table, .len = &fr_aka_sim_id_request_table_len }},
+       { FR_CONF_OFFSET("strip_permanent_identity_hint", FR_TYPE_BOOL, eap_aka_sim_common_conf_t,
+                        strip_permanent_identity_hint ), .dflt = "yes" },
+       { FR_CONF_OFFSET("ephemeral_id_length", FR_TYPE_UINT8, eap_aka_sim_common_conf_t, ephemeral_id_length ), .dflt = "14" },        /* 14 for compatibility */
+       { FR_CONF_OFFSET("protected_success", FR_TYPE_BOOL, eap_aka_sim_common_conf_t, protected_success ), .dflt = "no" },
+       { FR_CONF_OFFSET("virtual_server", FR_TYPE_VOID | FR_TYPE_REQUIRED, eap_aka_sim_common_conf_t, virtual_server), .func = virtual_server_cf_parse },
        CONF_PARSER_TERMINATOR
 };
 
-static fr_dict_t *dict_freeradius;
-static fr_dict_t *dict_radius;
-static fr_dict_t *dict_eap_sim;
-
-extern fr_dict_autoload_t rlm_eap_sim_dict[];
-fr_dict_autoload_t rlm_eap_sim_dict[] = {
-       { .out = &dict_freeradius, .proto = "freeradius" },
-       { .out = &dict_radius, .proto = "radius" },
-       { .out = &dict_eap_sim, .proto = "eap-sim", .base_dir = "eap/sim" },
-       { NULL }
-};
-
-static fr_dict_attr_t const *attr_eap_sim_mk;
-static fr_dict_attr_t const *attr_eap_sim_subtype;
-
-static fr_dict_attr_t const *attr_ms_mppe_send_key;
-static fr_dict_attr_t const *attr_ms_mppe_recv_key;
+static fr_dict_t *dict_eap_aka_sim;
 
-static fr_dict_attr_t const *attr_eap_sim_any_id_req;
-static fr_dict_attr_t const *attr_eap_sim_client_error_code;
-static fr_dict_attr_t const *attr_eap_sim_counter;
-static fr_dict_attr_t const *attr_eap_sim_encr_data;
-static fr_dict_attr_t const *attr_eap_sim_fullauth_id_req;
-static fr_dict_attr_t const *attr_eap_sim_identity;
-static fr_dict_attr_t const *attr_eap_sim_mac;
-static fr_dict_attr_t const *attr_eap_sim_nonce_mt;
-static fr_dict_attr_t const *attr_eap_sim_nonce_s;
-static fr_dict_attr_t const *attr_eap_sim_notification;
-static fr_dict_attr_t const *attr_eap_sim_permanent_id_req;
-static fr_dict_attr_t const *attr_eap_sim_rand;
-static fr_dict_attr_t const *attr_eap_sim_result_ind;
-static fr_dict_attr_t const *attr_eap_sim_selected_version;
-static fr_dict_attr_t const *attr_eap_sim_version_list;
-
-extern fr_dict_attr_autoload_t rlm_eap_sim_dict_attr[];
-fr_dict_attr_autoload_t rlm_eap_sim_dict_attr[] = {
-       { .out = &attr_eap_sim_mk, .name = "EAP-SIM-MK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
-
-       { .out = &attr_ms_mppe_send_key, .name = "MS-MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
-       { .out = &attr_ms_mppe_recv_key, .name = "MS-MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
-
-       { .out = &attr_eap_sim_any_id_req, .name = "EAP-SIM-Any-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_client_error_code, .name = "EAP-SIM-Client-Error-Code", .type = FR_TYPE_UINT16, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_counter, .name = "EAP-SIM-Counter", .type = FR_TYPE_UINT16, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_encr_data, .name = "EAP-SIM-Encr-Data", .type = FR_TYPE_TLV, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_fullauth_id_req, .name = "EAP-SIM-Fullauth-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_identity, .name = "EAP-SIM-Identity", .type = FR_TYPE_STRING, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_mac, .name = "EAP-SIM-MAC", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_nonce_mt, .name = "EAP-SIM-Nonce-MT", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_nonce_s, .name = "EAP-SIM-Nonce-S", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_notification, .name = "EAP-SIM-Notification", .type = FR_TYPE_UINT16, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_permanent_id_req, .name = "EAP-SIM-Permanent-ID-Req", .type = FR_TYPE_BOOL, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_rand, .name = "EAP-SIM-RAND", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_result_ind, .name = "EAP-SIM-Result-Ind", .type = FR_TYPE_BOOL, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_selected_version, .name = "EAP-SIM-Selected-Version", .type = FR_TYPE_UINT16, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_subtype, .name = "EAP-SIM-Subtype", .type = FR_TYPE_UINT32, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_version_list, .name = "EAP-SIM-Version-List", .type = FR_TYPE_UINT16, .dict = &dict_eap_sim },
+extern fr_dict_autoload_t rlm_eap_aka_dict[];
+fr_dict_autoload_t rlm_eap_aka_dict[] = {
+       { .out = &dict_eap_aka_sim, .base_dir="eap/aka-sim", .proto = "eap-aka-sim"  },
        { NULL }
 };
 
-/*
- *     build a reply to be sent.
- */
-static int eap_sim_compose(eap_session_t *eap_session, uint8_t const *hmac_extra, size_t hmac_extra_len)
-{
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-       fr_cursor_t             cursor;
-       fr_cursor_t             to_encode;
-       VALUE_PAIR              *head = NULL, *vp;
-       REQUEST                 *request = eap_session->request;
-       fr_sim_encode_ctx_t     encoder_ctx = {
-                                       .root = fr_dict_root(dict_eap_sim),
-                                       .keys = &eap_sim_session->keys,
-
-                                       .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
-                                       .iv_included = false,
-
-                                       .hmac_md = EVP_sha1(),
-                                       .eap_packet = eap_session->this_round->request,
-                                       .hmac_extra = hmac_extra,
-                                       .hmac_extra_len = hmac_extra_len
-                               };
-
-       ssize_t                 ret;
-
-       /* we will set the ID on requests, since we have to HMAC it */
-       eap_session->this_round->set_request_id = true;
-
-       fr_cursor_init(&cursor, &eap_session->request->reply->vps);
-       fr_cursor_init(&to_encode, &head);
-
-       while ((vp = fr_cursor_current(&cursor))) {
-               if (!fr_dict_parent_common(fr_dict_root(dict_eap_sim), vp->da, true)) {
-                       fr_cursor_next(&cursor);
-                       continue;
-               }
-               vp = fr_cursor_remove(&cursor);
-
-               /*
-                *      Silently discard encrypted attributes until
-                *      the peer should have k_encr.  These can be
-                *      added by policy, and seem to cause
-                *      wpa_supplicant to fail if sent before the challenge.
-                */
-               if (!eap_sim_session->allow_encrypted && fr_dict_parent_common(attr_eap_sim_encr_data, vp->da, true)) {
-                       RWDEBUG("Silently discarding &reply:%s: Encrypted attributes not allowed in this round",
-                               vp->da->name);
-                       talloc_free(vp);
-                       continue;
-               }
-
-               fr_cursor_append(&to_encode, vp);
-       }
-
-       RDEBUG2("Encoding EAP-SIM attributes");
-       log_request_pair_list(L_DBG_LVL_2, request, head, NULL);
-
-       eap_session->this_round->request->type.num = FR_EAP_METHOD_SIM;
-       eap_session->this_round->request->id = eap_sim_session->sim_id++ & 0xff;
-       eap_session->this_round->set_request_id = true;
-
-       ret = fr_sim_encode(eap_session->request, head, &encoder_ctx);
-       fr_cursor_head(&to_encode);
-       fr_cursor_free_list(&to_encode);
-
-       if (ret < 0) {
-               RPEDEBUG("Failed encoding EAP-SIM data");
-               return -1;
-       }
-       return 0;
-}
-
-static int eap_sim_send_start(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       VALUE_PAIR              **vps, *vp;
-       uint16_t                version;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-       RADIUS_PACKET           *packet;
-
-       rad_assert(eap_session->request != NULL);
-       rad_assert(eap_session->request->reply);
-
-       RDEBUG2("Sending SIM-State");
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-       eap_sim_session->allow_encrypted = false;       /* In case this is after failed fast-resumption */
-
-       /* these are the outgoing attributes */
-       packet = eap_session->request->reply;
-       vps = &packet->vps;
-       rad_assert(vps != NULL);
-
-       /*
-        *      Add appropriate TLVs for the EAP things we wish to send.
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_version_list);
-       vp->vp_uint16 = EAP_SIM_VERSION;
-       fr_pair_add(vps, vp);
-
-       /* record it in the ess */
-       version = htons(EAP_SIM_VERSION);
-       memcpy(eap_sim_session->keys.gsm.version_list, &version, sizeof(version));
-       eap_sim_session->keys.gsm.version_list_len = 2;
-
-       /*
-        *      Select the right type of identity request attribute
-        */
-       switch (eap_sim_session->id_req) {
-       case SIM_ANY_ID_REQ:
-               vp = fr_pair_afrom_da(packet, attr_eap_sim_any_id_req);
-               break;
-
-       case SIM_PERMANENT_ID_REQ:
-               vp = fr_pair_afrom_da(packet, attr_eap_sim_permanent_id_req);
-               break;
-
-       case SIM_FULLAUTH_ID_REQ:
-               vp = fr_pair_afrom_da(packet, attr_eap_sim_fullauth_id_req);
-               break;
-
-       default:
-               rad_assert(0);
-       }
-       vp->vp_bool = true;
-       fr_pair_replace(vps, vp);
-
-       /* the SUBTYPE, set to start. */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_subtype);
-       vp->vp_uint16 = EAP_SIM_START;
-       fr_pair_replace(vps, vp);
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_sim_compose(eap_session, NULL, 0) < 0) {
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       return 0;
-}
-
-/** Send the challenge itself
- *
- * Challenges will come from one of three places eventually:
- *
- * 1  from attributes like FR_EAP_SIM_RANDx
- *         (these might be retrieved from a database)
- *
- * 2  from internally implemented SIM authenticators
- *         (a simple one based upon XOR will be provided)
- *
- * 3  from some kind of SS7 interface.
- *
- * For now, they only come from attributes.
- * It might be that the best way to do 2/3 will be with a different
- * module to generate/calculate things.
- */
-static int eap_sim_send_challenge(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-       VALUE_PAIR              **to_peer, *vp;
-       RADIUS_PACKET           *packet;
-       fr_sim_vector_src_t     src = SIM_VECTOR_SRC_AUTO;
-
-       rad_assert(eap_session->request != NULL);
-       rad_assert(eap_session->request->reply);
-
-       RDEBUG2("Acquiring GSM vector(s)");
-       if ((fr_sim_vector_gsm_from_attrs(eap_session, request->control, 0, &eap_sim_session->keys, &src) != 0) ||
-           (fr_sim_vector_gsm_from_attrs(eap_session, request->control, 1, &eap_sim_session->keys, &src) != 0) ||
-           (fr_sim_vector_gsm_from_attrs(eap_session, request->control, 2, &eap_sim_session->keys, &src) != 0)) {
-               REDEBUG("Failed retrieving SIM vectors");
-               return RLM_MODULE_FAIL;
-       }
-
-       /*
-        *      All set, calculate keys!
-        */
-       fr_sim_crypto_kdf_0_gsm(&eap_sim_session->keys);
-       if (RDEBUG_ENABLED3) fr_sim_crypto_keys_log(request, &eap_sim_session->keys);
-
-       RDEBUG2("Sending SIM-Challenge");
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
-       /*
-        *      to_peer is the data to the client
-        */
-       packet = eap_session->request->reply;
-       to_peer = &packet->vps;
-
-       /*
-        *      Okay, we got the challenges! Put them into attributes.
-        */
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_sim_rand));
-       fr_pair_value_memcpy(vp, eap_sim_session->keys.gsm.vector[0].rand, SIM_VECTOR_GSM_RAND_SIZE, false);
-       fr_pair_add(to_peer, vp);
-
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_sim_rand));
-       fr_pair_value_memcpy(vp, eap_sim_session->keys.gsm.vector[1].rand, SIM_VECTOR_GSM_RAND_SIZE, false);
-       fr_pair_add(to_peer, vp);
-
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_sim_rand));
-       fr_pair_value_memcpy(vp, eap_sim_session->keys.gsm.vector[2].rand, SIM_VECTOR_GSM_RAND_SIZE, false);
-       fr_pair_add(to_peer, vp);
-
-       /*
-        *      Set subtype to challenge.
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_subtype);
-       vp->vp_uint16 = EAP_SIM_CHALLENGE;
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      Indicate we'd like to use protected success messages
-        */
-       if (eap_sim_session->send_result_ind) {
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_sim_result_ind));
-               vp->vp_bool = true;
-               fr_pair_replace(to_peer, vp);
-       }
-
-       /*
-        *      Need to include an AT_MAC attribute so that it will get
-        *      calculated.
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_mac);
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      We've sent the challenge so the peer should now be able
-        *      to accept encrypted attributes.
-        */
-       eap_sim_session->allow_encrypted = true;
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_sim_compose(eap_session,
-                           eap_sim_session->keys.gsm.nonce_mt, sizeof(eap_sim_session->keys.gsm.nonce_mt)) < 0) {
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       return 0;
-}
-
-/** Send NONCE_S and re-key
- *
- */
-static int eap_sim_send_reauthentication(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-       VALUE_PAIR              **to_peer, *vp, *mk, *counter;
-       RADIUS_PACKET           *packet;
-
-       rad_assert(eap_session->request != NULL);
-       rad_assert(eap_session->request->reply);
-
-       /*
-        *      to_peer is the data to the client
-        */
-       packet = eap_session->request->reply;
-       to_peer = &packet->vps;
-
-       /*
-        *      If any of the session resumption inputs (on our side)
-        *      are missing or malformed, return an error code
-        *      and the state machine will jump to the start state.
-        */
-       mk = fr_pair_find_by_da(request->control, attr_eap_sim_mk, TAG_ANY);
-       if (!mk) {
-               RWDEBUG2("Missing &control:EAP-SIM-MK, skipping session resumption");
-               return -1;
-       }
-       if (mk->vp_length != SIM_MK_SIZE) {
-               RWDEBUG("&control:EAP-SIM-MK has incorrect length, expected %u bytes got %zu bytes",
-                       SIM_MK_SIZE, mk->vp_length);
-               return -1;
-       }
-       counter = fr_pair_find_by_da(request->control, attr_eap_sim_counter, TAG_ANY);
-       if (!counter) {
-               RWDEBUG2("Missing &control:EAP-SIM-Counter, skipping session resumption");
-               return -1;
-       }
-
-       /*
-        *      All set, calculate keys!
-        */
-       fr_sim_crypto_keys_init_reauth(&eap_sim_session->keys, mk->vp_octets, counter->vp_uint16);
-       fr_sim_crypto_kdf_0_reauth(&eap_sim_session->keys);
-       if (RDEBUG_ENABLED3) fr_sim_crypto_keys_log(request, &eap_sim_session->keys);
-
-       RDEBUG2("Sending SIM-Reauthentication");
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
-       /*
-        *      Set subtype to challenge.
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_subtype);
-       vp->vp_uint16 = EAP_SIM_REAUTH;
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      Add nonce_s
-        */
-       MEM(vp = fr_pair_afrom_da(packet, attr_eap_sim_nonce_s));
-       fr_pair_value_memcpy(vp, eap_sim_session->keys.reauth.nonce_s,
-                            sizeof(eap_sim_session->keys.reauth.nonce_s), false);
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      Indicate we'd like to use protected success messages
-        */
-       if (eap_sim_session->send_result_ind) {
-               MEM(vp = fr_pair_afrom_da(packet, attr_eap_sim_result_ind));
-               vp->vp_bool = true;
-               fr_pair_replace(to_peer, vp);
-       }
-
-       /*
-        *      Need to include an AT_MAC attribute so that it will get
-        *      calculated.
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_mac);
-       fr_pair_replace(to_peer, vp);
-
-       /*
-        *      We've sent the challenge so the peer should now be able
-        *      to accept encrypted attributes.
-        */
-       eap_sim_session->allow_encrypted = true;
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_sim_compose(eap_session, NULL, 0) < 0) {
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       return 0;
-}
-
-/** Send a success notification
- *
- */
-static int eap_sim_send_eap_success_notification(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       RADIUS_PACKET           *packet = eap_session->request->reply;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-       fr_cursor_t             cursor;
-       VALUE_PAIR              *vp;
-
-       RDEBUG2("Sending SIM-Notification (Success)");
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
-       if (!fr_cond_assert(eap_sim_session->challenge_success)) return -1;
-
-       fr_cursor_init(&cursor, &packet->vps);
-
-       /*
-        *      Set the subtype to notification
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_subtype);
-       vp->vp_uint16 = FR_EAP_SIM_SUBTYPE_VALUE_SIM_NOTIFICATION;
-       fr_cursor_append(&cursor, vp);
-
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_notification);
-       vp->vp_uint16 = FR_EAP_SIM_NOTIFICATION_VALUE_SUCCESS;
-       fr_cursor_append(&cursor, vp);
-
-       /*
-        *      Need to include an AT_MAC attribute so that it will get
-        *      calculated.
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_mac);
-       fr_pair_replace(&packet->vps, vp);
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_sim_compose(eap_session, NULL, 0) < 0) {
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       return 0;
-}
-
-/** Send a success message
+/** Compile virtual server sections
  *
- * The only work to be done is the add the appropriate SEND/RECV
- * radius attributes derived from the MSK.
- */
-static int eap_sim_send_eap_success(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       uint8_t                 *p;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-
-       RDEBUG2("Sending SIM-Success");
-       eap_session->this_round->request->code = FR_EAP_CODE_SUCCESS;
-       eap_session->finished = true;
-
-       p = eap_sim_session->keys.msk;
-       eap_add_reply(eap_session->request, attr_ms_mppe_recv_key, p, EAP_TLS_MPPE_KEY_LEN);
-       p += EAP_TLS_MPPE_KEY_LEN;
-       eap_add_reply(eap_session->request, attr_ms_mppe_send_key, p, EAP_TLS_MPPE_KEY_LEN);
-
-       return 0;
-}
-
-/** Send a failure message
+ * Called twice, once when a server with an eap-aka namespace is found, and once
+ * when an EAP-AKA module is instantiated.
  *
- */
-static int eap_sim_send_eap_failure_notification(eap_session_t *eap_session)
-{
-       REQUEST                 *request = eap_session->request;
-       RADIUS_PACKET           *packet = eap_session->request->reply;
-       fr_cursor_t             cursor;
-       VALUE_PAIR              *vp;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-
-       fr_cursor_init(&cursor, &packet->vps);
-
-       vp = fr_pair_find_by_da(packet->vps, attr_eap_sim_notification, TAG_ANY);
-       if (!vp) {
-               vp = fr_pair_afrom_da(packet, attr_eap_sim_notification);
-               vp->vp_uint16 = FR_EAP_SIM_NOTIFICATION_VALUE_GENERAL_FAILURE;
-               fr_cursor_append(&cursor, vp);
-       }
-
-       /*
-        *      Change the failure notification depending where
-        *      we are in the state machine.
-        */
-       if (eap_sim_session->challenge_success) {
-               vp->vp_uint16 &= ~0x4000;       /* Unset phase bit */
-       } else {
-               vp->vp_uint16 |= 0x4000;        /* Set phase bit */
-       }
-       vp->vp_uint16 &= ~0x8000;               /* In both cases success bit should be low */
-
-       RDEBUG2("Sending SIM-Notification (%pV)", &vp->data);
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
-       /*
-        *      Set the subtype to notification
-        */
-       vp = fr_pair_afrom_da(packet, attr_eap_sim_subtype);
-       vp->vp_uint16 = FR_EAP_SIM_SUBTYPE_VALUE_SIM_NOTIFICATION;
-       fr_cursor_append(&cursor, vp);
-
-       /*
-        *      If we're after the challenge phase
-        *      then we need to include a MAC to
-        *      protect notifications.
-        */
-       if (eap_sim_session->challenge_success) {
-               vp = fr_pair_afrom_da(packet, attr_eap_sim_mac);
-               fr_pair_replace(&packet->vps, vp);
-       }
-
-       /*
-        *      Encode the packet
-        */
-       if (eap_sim_compose(eap_session, NULL, 0) < 0) {
-               fr_pair_list_free(&packet->vps);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int eap_sim_send_eap_failure(eap_session_t *eap_session)
-{
-       REQUEST         *request = eap_session->request;
-
-       RDEBUG2("Sending EAP-Failure");
-
-       eap_session->this_round->request->code = FR_EAP_CODE_FAILURE;
-       eap_session->finished = true;
-
-       return 0;
-}
-
-/** Run the server state machine
+ * The first time is with actions == NULL and is to compile the sections and
+ * perform validation.
+ * The second time is to write out pointers to the compiled sections which the
+ * EAP-AKA module will use to execute unlang code.
  *
  */
-static void eap_sim_state_enter(eap_session_t *eap_session, eap_sim_server_state_t new_state)
+static int mod_section_compile(eap_aka_sim_actions_t *actions, CONF_SECTION *server_cs)
 {
-       REQUEST                 *request = eap_session->request;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
+       bool found = false;
 
-       if (new_state != eap_sim_session->state) {
-               RDEBUG2("Changed state %s -> %s",
-                       fr_table_str_by_value(sim_state_table, eap_sim_session->state, "<unknown>"),
-                       fr_table_str_by_value(sim_state_table, new_state, "<unknown>"));
-               eap_sim_session->state = new_state;
-       } else {
-               RDEBUG2("Reentering state %s",
-                       fr_table_str_by_value(sim_state_table, eap_sim_session->state, "<unknown>"));
-       }
-
-       switch (new_state) {
-       /*
-        *      Send our version list
-        */
-       case EAP_SIM_SERVER_START:
-       start:
-               if (eap_sim_send_start(eap_session) < 0) {
-               notify_failure:
-                       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-                       return;
-               }
-               break;
+       if (!fr_cond_assert(server_cs)) return -1;
 
        /*
-        *      Send the EAP-SIM Challenge message.
+        *      Identity negotiation
         */
-       case EAP_SIM_SERVER_CHALLENGE:
-               if (eap_sim_send_challenge(eap_session) < 0) goto notify_failure;
-               break;
-
-       case EAP_SIM_SERVER_REAUTHENTICATE:
-               if (eap_sim_send_reauthentication(eap_session) < 0) goto start;
-               break;
+       EAP_SECTION_COMPILE(actions, send_identity_request, "send", "Identity-Request");
+       EAP_SECTION_COMPILE(actions, recv_identity_response, "recv", "Identity-Response");
 
        /*
-        *      Sent a protected success notification
+        *      Optional override sections if the user *really*
+        *      wants to apply special policies for subsequent
+        *      request/response rounds.
         */
-       case EAP_SIM_SERVER_SUCCESS_NOTIFICATION:
-               if (eap_sim_send_eap_success_notification(eap_session) < 0) goto notify_failure;
-               break;
+       EAP_SECTION_COMPILE(actions, sim.send_sim_start_request, "send", "Start");
+       EAP_SECTION_COMPILE(actions, sim.recv_sim_start_response, "recv", "Start");
 
        /*
-        *      Send the EAP Success message (we're done)
+        *      Full-Authentication
         */
-       case EAP_SIM_SERVER_SUCCESS:
-               if (eap_sim_send_eap_success(eap_session) < 0) goto notify_failure;
-               return;
+       EAP_SECTION_COMPILE(actions, send_challenge_request, "send", "Challenge-Request");
+       EAP_SECTION_COMPILE(actions, recv_challenge_response, "recv", "Challenge-Response");
 
        /*
-        *      Send a general failure notification
+        *      Fast-Re-Authentication
         */
-       case EAP_SIM_SERVER_FAILURE_NOTIFICATION:
-               if (eap_sim_send_eap_failure_notification(eap_session) < 0) {   /* Fallback to EAP-Failure */
-                       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
-               }
-               return;
+       EAP_SECTION_COMPILE(actions, send_reauthentication_request, "send", "Reauthentication-Request");
+       EAP_SECTION_COMPILE(actions, recv_reauthentication_response, "recv", "Reauthentication-Response");
 
        /*
-        *      Send an EAP-Failure (we're done)
+        *      Failures originating from the supplicant
         */
-       case EAP_SIM_SERVER_FAILURE:
-               eap_sim_send_eap_failure(eap_session);
-               return;
-
-       default:
-               rad_assert(0);  /* Invalid transition */
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-               return;
-       }
-}
-
-/** Process an EAP-Sim/Response/Start
- *
- * Verify that client chose a version, and provided a NONCE_MT,
- * and if so, then change states to challenge, and send the new
- * challenge, else, resend the Request/Start.
- */
-static int process_eap_sim_start(eap_session_t *eap_session, VALUE_PAIR *vps)
-{
-       REQUEST                 *request = eap_session->request;
-       VALUE_PAIR              *nonce_vp, *selected_version_vp;
-       eap_sim_session_t       *eap_sim_session;
-       uint16_t                eap_sim_version;
-       VALUE_PAIR              *id;
-       fr_sim_id_type_t        type = SIM_ID_TYPE_UNKNOWN;
-       fr_sim_method_hint_t    method = SIM_METHOD_HINT_UNKNOWN;
-
-       eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
+       EAP_SECTION_COMPILE(actions, recv_client_error, "recv", "Client-Error");
 
        /*
-        *      For fullauth We require both the NONCE_MT
-        *      and SELECTED_VERSION from the peer, else
-        *      the packet is invalid.
+        *      Failure originating from the server
         */
-       nonce_vp = fr_pair_find_by_da(vps, attr_eap_sim_nonce_mt, TAG_ANY);
-       selected_version_vp = fr_pair_find_by_da(vps, attr_eap_sim_selected_version, TAG_ANY);
-       if (!nonce_vp || !selected_version_vp) {
-               REDEBUG2("Client did not select a version and send a NONCE");
-               return -1;
-       }
-
-       eap_sim_version = selected_version_vp->vp_uint16;
-       if (eap_sim_version != EAP_SIM_VERSION) {
-               REDEBUG2("EAP-SIM-Version %i is unknown", eap_sim_version);
-               return -1;
-       }
+       EAP_SECTION_COMPILE(actions, send_failure_notification, "send", "Failure-Notification");
+       EAP_SECTION_COMPILE(actions, recv_failure_notification_ack, "recv", "Failure-Notification-ACK");
 
        /*
-        *      Record it for later keying
+        *      Protected success indication
         */
-       eap_sim_version = htons(eap_sim_version);
-       memcpy(eap_sim_session->keys.gsm.version_select,
-              &eap_sim_version, sizeof(eap_sim_session->keys.gsm.version_select));
+       EAP_SECTION_COMPILE(actions, send_success_notification, "send", "Success-Notification");
+       EAP_SECTION_COMPILE(actions, recv_success_notification_ack, "recv", "Success-Notification-ACK");
 
        /*
-        *      Double check the nonce size.
+        *      Final EAP-Success and EAP-Failure messages
         */
-       if (nonce_vp->vp_length != 16) {
-               REDEBUG("EAP-SIM nonce_mt must be 16 bytes, not %zu bytes", nonce_vp->vp_length);
-               return -1;
-       }
-       memcpy(eap_sim_session->keys.gsm.nonce_mt, nonce_vp->vp_octets, 16);
+       EAP_SECTION_COMPILE(actions, send_eap_success, "send", "EAP-Success");
+       EAP_SECTION_COMPILE(actions, send_eap_failure, "send", "EAP-Failure");
 
        /*
-        *      See if we got an AT_IDENTITY
+        *      Fast-Reauth vectors
         */
-       id = fr_pair_find_by_da(vps, attr_eap_sim_identity, TAG_ANY);
-       if (id) {
-               if (fr_sim_id_type(&type, &method,
-                                  eap_session->identity, talloc_array_length(eap_session->identity) - 1) < 0) {
-                       RPWDEBUG2("Failed parsing identity");
-               }
-
-               /*
-                *      Update cryptographic identity
-                */
-               talloc_const_free(eap_sim_session->keys.identity);
-               eap_sim_session->keys.identity_len = id->vp_length;
-               MEM(eap_sim_session->keys.identity = talloc_memdup(eap_sim_session, id->vp_strvalue, id->vp_length));
-       }
+       EAP_SECTION_COMPILE(actions, store_session, "store", "session");
+       EAP_SECTION_COMPILE(actions, load_session, "load", "session");
+       EAP_SECTION_COMPILE(actions, clear_session, "clear", "session");
 
        /*
-        *      @TODO Run a virtual server to see if we can use the
-        *      identity we just acquired, or whether we need to
-        *      negotiate the next permissive ID.
+        *      Pseudonym processing
         */
+       EAP_SECTION_COMPILE(actions, store_pseudonym, "store", "pseudonym");
+       EAP_SECTION_COMPILE(actions, load_pseudonym, "load", "pseudonym");
+       EAP_SECTION_COMPILE(actions, clear_pseudonym, "clear", "pseudonym");
 
        /*
-        *      Negotiate the next permissive form
-        *      if identity, or fail.
+        *      Warn if we couldn't find any actions.
         */
-       switch (eap_sim_session->id_req) {
-       case SIM_ANY_ID_REQ:
-               eap_sim_session->id_req = SIM_FULLAUTH_ID_REQ;
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_START);
-               break;
-
-       case SIM_FULLAUTH_ID_REQ:
-               eap_sim_session->id_req = SIM_PERMANENT_ID_REQ;
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_START);
-               break;
-
-       case SIM_NO_ID_REQ:
-       case SIM_PERMANENT_ID_REQ:
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_CHALLENGE);
-//             REDEBUG2("Failed to negotiate a usable identity");
-//             eap_sim_state_enter(eap_session, eap_sim_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-               break;
+       if (!found) {
+               cf_log_warn(server_cs, "No \"eap-aka\" actions found in virtual server \"%s\"",
+                           cf_section_name2(server_cs));
        }
 
        return 0;
 }
 
-
-/** Process an EAP-Sim/Response/Challenge
- *
- * Verify that MAC that we received matches what we would have
- * calculated from the packet with the SRESx appended.
- */
-static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps)
+static int mod_instantiate(void *instance, UNUSED CONF_SECTION *conf)
 {
-       REQUEST                 *request = eap_session->request;
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-
-       uint8_t                 sres_cat[SIM_VECTOR_GSM_SRES_SIZE * 3];
-       uint8_t                 *p = sres_cat;
-
-       uint8_t                 calc_mac[SIM_MAC_DIGEST_SIZE];
-       ssize_t                 slen;
-       VALUE_PAIR              *mac;
-
-       memcpy(p, eap_sim_session->keys.gsm.vector[0].sres, SIM_VECTOR_GSM_SRES_SIZE);
-       p += SIM_VECTOR_GSM_SRES_SIZE;
-       memcpy(p, eap_sim_session->keys.gsm.vector[1].sres, SIM_VECTOR_GSM_SRES_SIZE);
-       p += SIM_VECTOR_GSM_SRES_SIZE;
-       memcpy(p, eap_sim_session->keys.gsm.vector[2].sres, SIM_VECTOR_GSM_SRES_SIZE);
-
-       mac = fr_pair_find_by_da(vps, attr_eap_sim_mac, TAG_ANY);
-       if (!mac) {
-               REDEBUG("Missing AT_MAC attribute");
-               return -1;
-       }
-       if (mac->vp_length != SIM_MAC_DIGEST_SIZE) {
-               REDEBUG("EAP-SIM-MAC has incorrect length, expected %u bytes got %zu bytes",
-                       SIM_MAC_DIGEST_SIZE, mac->vp_length);
-               return -1;
-       }
-
-       slen = fr_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true, EVP_sha1(),
-                                        eap_sim_session->keys.k_aut, eap_sim_session->keys.k_aut_len,
-                                        sres_cat, sizeof(sres_cat));
-       if (slen < 0) {
-               RPEDEBUG("Failed calculating MAC");
-               return -1;
-       } else if (slen == 0) {
-               REDEBUG("Missing EAP-SIM-MAC attribute in packet buffer");
-               return -1;
-       }
-
-       if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
-               RDEBUG2("EAP-SIM-MAC matches calculated MAC");
-       } else {
-               REDEBUG("EAP-SIM-MAC does not match calculated MAC");
-               RHEXDUMP_INLINE2(mac->vp_octets, SIM_MAC_DIGEST_SIZE, "Received");
-               RHEXDUMP_INLINE2(calc_mac, SIM_MAC_DIGEST_SIZE, "Expected");
-               return -1;
-       }
-
-       eap_sim_session->challenge_success = true;
+       eap_aka_sim_common_conf_t       *inst = talloc_get_type_abort(instance, eap_aka_sim_common_conf_t);
 
-       /*
-        *      If the peer wants a Success notification, then
-        *      send a success notification, otherwise send a
-        *      normal EAP-Success.
-        */
-       if (fr_pair_find_by_da(vps, attr_eap_sim_result_ind, TAG_ANY)) {
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_SUCCESS_NOTIFICATION);
-               return 1;
-       }
+       if (mod_section_compile(&inst->actions, inst->virtual_server) < 0) return -1;
 
-       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_SUCCESS);
        return 0;
 }
 
-
-/** Authenticate a previously sent challenge
+/** Compile any virtual servers with the "eap-aka" namespace
  *
  */
-static rlm_rcode_t mod_process(UNUSED void *instance, UNUSED void *thread, REQUEST *request)
-{
-       eap_session_t           *eap_session = eap_session_get(request);
-       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
-
-       fr_sim_decode_ctx_t     ctx = { .keys = &eap_sim_session->keys };
-       VALUE_PAIR              *subtype_vp, *from_peer, *vp;
-       fr_cursor_t             cursor;
-
-       eap_sim_subtype_t       subtype;
-
-       int                     ret;
-
-       /*
-        *      VPS is the data from the client
-        */
-       from_peer = eap_session->request->packet->vps;
-
-       fr_cursor_init(&cursor, &request->packet->vps);
-       fr_cursor_tail(&cursor);
-
-       ret = fr_sim_decode(eap_session->request,
-                           &cursor,
-                           dict_eap_sim,
-                           eap_session->this_round->response->type.data,
-                           eap_session->this_round->response->type.length,
-                           &ctx);
-       /*
-        *      RFC 4186 says we *MUST* notify, not just
-        *      send an EAP-Failure in this case where
-        *      we cannot decode an EAP-AKA packet.
-        */
-       if (ret < 0) {
-               RPEDEBUG2("Failed decoding EAP-SIM attributes");
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-               return RLM_MODULE_HANDLED;      /* We need to process more packets */
-       }
-
-       vp = fr_cursor_current(&cursor);
-       if (vp && RDEBUG_ENABLED2) {
-               RDEBUG2("Decoded EAP-SIM attributes");
-               log_request_pair_list(L_DBG_LVL_2, request, vp, NULL);
-       }
-
-       subtype_vp = fr_pair_find_by_da(from_peer, attr_eap_sim_subtype, TAG_ANY);
-       if (!subtype_vp) {
-               REDEBUG("Missing EAP-SIM-Subtype");
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-               return RLM_MODULE_HANDLED;                              /* We need to process more packets */
-       }
-       subtype = subtype_vp->vp_uint16;
-
-       switch (eap_sim_session->state) {
-       /*
-        *      Response to our advertised versions and request for an ID
-        *      This is very similar to Identity negotiation in EAP-AKA[']
-        */
-       case EAP_SIM_SERVER_START:
-               switch (subtype) {
-               case EAP_SIM_START:
-                       if (process_eap_sim_start(eap_session, from_peer) == 0) return RLM_MODULE_HANDLED;
-                       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-                       return RLM_MODULE_HANDLED;      /* We need to process more packets */
-
-               /*
-                *      Case 1 where we're allowed to send an EAP-Failure
-                *
-                *      This can happen in the case of a conservative
-                *      peer, where it refuses to provide the permanent
-                *      identity.
-                */
-               case EAP_SIM_CLIENT_ERROR:
-               {
-                       char buff[20];
-
-                       vp = fr_pair_find_by_da(from_peer, attr_eap_sim_client_error_code, TAG_ANY);
-                       if (!vp) {
-                               REDEBUG("EAP-SIM Peer rejected SIM-Start (%s) with client-error message but "
-                                       "has not supplied a client error code",
-                                       fr_table_str_by_value(sim_id_request_table, eap_sim_session->id_req, "<INVALID>"));
-                       } else {
-                               REDEBUG("Client rejected SIM-Start (%s) with error: %s (%i)",
-                                       fr_table_str_by_value(sim_id_request_table, eap_sim_session->id_req, "<INVALID>"),
-                                       fr_pair_value_enum(vp, buff), vp->vp_uint16);
-                       }
-                       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
-                       return RLM_MODULE_REJECT;
-               }
-
-               case EAP_SIM_NOTIFICATION:
-               notification:
-               {
-                       char buff[20];
-
-                       vp = fr_pair_afrom_da(from_peer, attr_eap_sim_notification);
-                       if (!vp) {
-                               REDEBUG2("Received SIM-Notification with no notification code");
-                               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-                               return RLM_MODULE_HANDLED;                      /* We need to process more packets */
-                       }
-
-                       /*
-                        *      Case 2 where we're allowed to send an EAP-Failure
-                        */
-                       if (!(vp->vp_uint16 & 0x8000)) {
-                               REDEBUG2("SIM-Notification %s (%i) indicates failure", fr_pair_value_enum(vp, buff),
-                                        vp->vp_uint16);
-                               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
-                               return RLM_MODULE_REJECT;
-                       }
-
-                       /*
-                        *      ...if it's not a failure, then re-enter the
-                        *      current state.
-                        */
-                       REDEBUG2("Got SIM-Notification %s (%i)", fr_pair_value_enum(vp, buff), vp->vp_uint16);
-                       eap_sim_state_enter(eap_session, eap_sim_session->state);
-                       return RLM_MODULE_HANDLED;
-
-               default:
-               unexpected_subtype:
-                       /*
-                        *      RFC 4186 says we *MUST* notify, not just
-                        *      send an EAP-Failure in this case.
-                        */
-                       REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
-                       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-                       return RLM_MODULE_HANDLED;                              /* We need to process more packets */
-               }
-               }
-
-       /*
-        *      Process the response to our previous challenge.
-        */
-       case EAP_SIM_SERVER_CHALLENGE:
-               switch (subtype) {
-               /*
-                *      A response to our EAP-Sim/Request/Challenge!
-                */
-               case EAP_SIM_CHALLENGE:
-                       switch (process_eap_sim_challenge(eap_session, from_peer)) {
-                       case 1:
-                               return RLM_MODULE_HANDLED;
-
-                       case 0:
-                               return RLM_MODULE_OK;
-
-                       case -1:
-                       default:
-                               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-                               return RLM_MODULE_HANDLED;                      /* We need to process more packets */
-                       }
-
-               case EAP_SIM_CLIENT_ERROR:
-               {
-                       char buff[20];
-
-                       vp = fr_pair_find_by_da(from_peer, attr_eap_sim_client_error_code, TAG_ANY);
-                       if (!vp) {
-                               REDEBUG("EAP-SIM Peer rejected SIM-Challenge with client-error message but "
-                                       "has not supplied a client error code");
-                       } else {
-                               REDEBUG("Client rejected SIM-Challenge with error: %s (%i)",
-                                       fr_pair_value_enum(vp, buff), vp->vp_uint16);
-                       }
-                       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
-                       return RLM_MODULE_REJECT;
-               }
-
-               case EAP_SIM_NOTIFICATION:
-                       goto notification;
-
-               default:
-                       goto unexpected_subtype;
-               }
-
-       /*
-        *      Peer acked our failure
-        */
-       case EAP_SIM_SERVER_FAILURE_NOTIFICATION:
-               switch (subtype) {
-               case EAP_SIM_NOTIFICATION:
-                       RDEBUG2("SIM-Notification ACKed, sending EAP-Failure");
-                       eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
-                       return RLM_MODULE_REJECT;
-
-               default:
-                       goto unexpected_subtype;
-               }
-
-       /*
-        *      Something bad happened...
-        */
-       default:
-               rad_assert(0);
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
-               return RLM_MODULE_HANDLED;                              /* We need to process more packets */
-       }
-}
-
-/*
- *     Initiate the EAP-SIM session by starting the state machine
- *      and initiating the state.
- */
-static rlm_rcode_t mod_session_init(void *instance, UNUSED void *thread, REQUEST *request)
+static int mod_namespace_load(CONF_SECTION *server_cs)
 {
-       rlm_eap_sim_t                   *inst = talloc_get_type_abort(instance, rlm_eap_sim_t);
-       eap_session_t                   *eap_session = eap_session_get(request);
-       eap_sim_session_t               *eap_sim_session;
-
-       fr_sim_id_type_t                type;
-       fr_sim_method_hint_t            method;
-
-       MEM(eap_sim_session = talloc_zero(eap_session, eap_sim_session_t));
-
-       eap_session->opaque = eap_sim_session;
-
-       /*
-        *      Set default configuration, we may allow these
-        *      to be toggled by attributes later.
-        */
-       eap_sim_session->send_result_ind = inst->protected_success;
-       eap_sim_session->id_req = SIM_ANY_ID_REQ;       /* Set the default */
-
-       /*
-        *      This value doesn't have be strong, but it is
-        *      good if it is different now and then.
-        */
-       eap_sim_session->sim_id = (fr_rand() & 0xff);
-
-       /*
-        *      Save the keying material, because it could change on a subsequent retrieval.
-        */
-       RDEBUG2("New EAP-SIM session");
-
-       /*
-        *      Process the identity that we received in the
-        *      EAP-Identity-Response and use it to determine
-        *      the initial request we send to the Supplicant.
-        */
-       if (fr_sim_id_type(&type, &method,
-                          eap_session->identity, talloc_array_length(eap_session->identity) - 1) < 0) {
-               RPWDEBUG2("Failed parsing identity, continuing anyway");
-       }
-
-       switch (method) {
-       default:
-               RWDEBUG("EAP-Identity-Response hints that EAP-%s should be started, but we're attempting EAP-SIM",
-                       fr_table_str_by_value(sim_id_method_hint_table, method, "<INVALID>"));
-               break;
-
-       case SIM_METHOD_HINT_SIM:
-       case SIM_METHOD_HINT_UNKNOWN:
-               break;
-       }
-       eap_session->process = mod_process;
-
-       /*
-        *      Figure out what type of identity we have
-        *      and use it to determine the initial
-        *      request we send.
-        */
-       switch (type) {
-       /*
-        *      These types need to be transformed into something
-        *      usable before we can do anything.
-        */
-       case SIM_ID_TYPE_UNKNOWN:
-       case SIM_ID_TYPE_PSEUDONYM:
-       case SIM_ID_TYPE_FASTAUTH:
-       /*
-        *      Permanent ID means we can just send the challenge
-        */
-       case SIM_ID_TYPE_PERMANENT:
-               eap_sim_session->keys.identity_len = talloc_array_length(eap_session->identity) - 1;
-               MEM(eap_sim_session->keys.identity = talloc_memdup(eap_sim_session, eap_session->identity,
-                                                                  eap_sim_session->keys.identity_len));
-               eap_sim_state_enter(eap_session, EAP_SIM_SERVER_START);
-               return RLM_MODULE_HANDLED;
-       }
-
-       return RLM_MODULE_HANDLED;
+       return mod_section_compile(NULL, server_cs);
 }
 
 static int mod_load(void)
 {
-       if (fr_sim_init() < 0) return -1;
+       if (virtual_namespace_register("eap-sim", "eap-aka-sim", "eap/aka-sim", mod_namespace_load) < 0) return -1;
+
+       if (fr_aka_sim_init() < 0) return -1;
 
-       sim_xlat_register();
+       fr_aka_sim_xlat_register();
 
        return 0;
 }
 
 static void mod_unload(void)
 {
-       sim_xlat_unregister();
+       fr_aka_sim_xlat_unregister();
 
-       fr_sim_free();
+       fr_aka_sim_free();
 }
 
 /*
@@ -1175,11 +187,16 @@ rlm_eap_submodule_t rlm_eap_sim = {
        .magic          = RLM_MODULE_INIT,
 
        .provides       = { FR_EAP_METHOD_SIM },
-       .inst_size      = sizeof(rlm_eap_sim_t),
+
+       .inst_size      = sizeof(eap_aka_sim_common_conf_t),
+       .inst_type      = "eap_aka_sim_common_conf_t",
        .config         = submodule_config,
 
        .onload         = mod_load,
        .unload         = mod_unload,
-       .session_init   = mod_session_init,     /* Initialise a new EAP session */
-       .entry_point    = mod_process,          /* Process next round of EAP method */
+
+       .instantiate    = mod_instantiate,
+
+       .session_init   = aka_sim_state_machine_start,  /* Initialise a new EAP session */
+       .namespace      = &dict_eap_aka_sim
 };
index 0a6448be8f2fa34d4956c682c1d4ac3a2a3d9caa..b0d5da976c8b1a95646562abd970b832fe61fd23 100644 (file)
@@ -26,15 +26,14 @@ RCSIDH(rlm_sigtran_attrs_h, "$Id$")
 
 #include <freeradius-devel/util/dict.h>
 
-extern fr_dict_t *dict_eap_sim;
-extern fr_dict_t *dict_eap_aka;
+extern fr_dict_t *dict_eap_aka_sim;
 
-extern fr_dict_attr_t const *attr_eap_aka_autn;
-extern fr_dict_attr_t const *attr_eap_aka_ck;
-extern fr_dict_attr_t const *attr_eap_aka_ik;
-extern fr_dict_attr_t const *attr_eap_aka_rand;
-extern fr_dict_attr_t const *attr_eap_aka_xres;
+extern fr_dict_attr_t const *attr_eap_aka_sim_autn;
+extern fr_dict_attr_t const *attr_eap_aka_sim_ck;
+extern fr_dict_attr_t const *attr_eap_aka_sim_ik;
+extern fr_dict_attr_t const *attr_eap_aka_sim_rand;
+extern fr_dict_attr_t const *attr_eap_aka_sim_xres;
 
-extern fr_dict_attr_t const *attr_eap_sim_kc;
-extern fr_dict_attr_t const *attr_eap_sim_sres;
-extern fr_dict_attr_t const *attr_eap_sim_rand;
+extern fr_dict_attr_t const *attr_eap_aka_sim_kc;
+extern fr_dict_attr_t const *attr_eap_aka_sim_sres;
+extern fr_dict_attr_t const *attr_eap_aka_sim_rand;
index c7a873e68d41e053708691c34fdd19dce7f57e0d..d780e365fffbbcf2f94c5c9f6ed7c150538d22b9 100644 (file)
@@ -28,8 +28,8 @@
 
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/rad_assert.h>
-#include <freeradius-devel/protocol/eap/aka/dictionary.h>
-#include <freeradius-devel/protocol/eap/sim/dictionary.h>
+#include <freeradius-devel/protocol/eap/aka-sim/dictionary.h>
+#include <freeradius-devel/protocol/eap/aka-sim/dictionary.h>
 #include <freeradius-devel/unlang/base.h>
 #include <freeradius-devel/server/module.h>
 
@@ -270,8 +270,8 @@ int sigtran_client_link_down(sigtran_conn_t const **conn)
        return 0;
 }
 
-static void sigtran_client_signal(UNUSED REQUEST *request, UNUSED void *instance,
-                                 UNUSED void *thread, void *rctx, fr_state_signal_t action)
+static void sigtran_client_signal(UNUSED void *instance, UNUSED void *thread, UNUSED REQUEST *request,
+                                 void *rctx, fr_state_signal_t action)
 {
        sigtran_transaction_t   *txn = talloc_get_type_abort(rctx, sigtran_transaction_t);
 
@@ -284,7 +284,7 @@ static void sigtran_client_signal(UNUSED REQUEST *request, UNUSED void *instance
        txn->ctx.request = NULL;        /* remove the link to the (now dead) request */
 }
 
-static rlm_rcode_t sigtran_client_map_resume(REQUEST *request, UNUSED void *instance, UNUSED void *thread, void *rctx)
+static rlm_rcode_t sigtran_client_map_resume(UNUSED void *instance, UNUSED void *thread, REQUEST *request, void *rctx)
 {
        sigtran_transaction_t                   *txn = talloc_get_type_abort(rctx, sigtran_transaction_t);
        rlm_rcode_t                             rcode;
@@ -313,18 +313,18 @@ static rlm_rcode_t sigtran_client_map_resume(REQUEST *request, UNUSED void *inst
 
                                RDEBUG2("SIM auth vector %i", i);
                                RINDENT();
-                               vp = fr_pair_afrom_da(request, attr_eap_sim_rand);
-                               fr_pair_value_memsteal(vp, vec->sim.rand, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_rand);
+                               fr_pair_value_memsteal(vp, vec->sim.rand, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
 
-                               vp = fr_pair_afrom_da(request, attr_eap_sim_sres);
-                               fr_pair_value_memsteal(vp, vec->sim.sres, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_sres);
+                               fr_pair_value_memsteal(vp, vec->sim.sres, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
 
-                               vp = fr_pair_afrom_da(request, attr_eap_sim_kc);
-                               fr_pair_value_memsteal(vp, vec->sim.kc, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_kc);
+                               fr_pair_value_memsteal(vp, vec->sim.kc, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
                                REXDENT();
@@ -341,28 +341,28 @@ static rlm_rcode_t sigtran_client_map_resume(REQUEST *request, UNUSED void *inst
 
                                RDEBUG2("UMTS auth vector %i", i);
                                RINDENT();
-                               vp = fr_pair_afrom_da(request, attr_eap_aka_rand);
-                               fr_pair_value_memsteal(vp, vec->umts.rand, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_rand);
+                               fr_pair_value_memsteal(vp, vec->umts.rand, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
 
-                               vp = fr_pair_afrom_da(request, attr_eap_aka_xres);
-                               fr_pair_value_memsteal(vp, vec->umts.xres, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_xres);
+                               fr_pair_value_memsteal(vp, vec->umts.xres, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
 
-                               vp = fr_pair_afrom_da(request, attr_eap_aka_ck);
-                               fr_pair_value_memsteal(vp, vec->umts.ck, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_ck);
+                               fr_pair_value_memsteal(vp, vec->umts.ck, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
 
-                               vp = fr_pair_afrom_da(request, attr_eap_aka_ik);
-                               fr_pair_value_memsteal(vp, vec->umts.ik, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_ik);
+                               fr_pair_value_memsteal(vp, vec->umts.ik, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
 
-                               vp = fr_pair_afrom_da(request, attr_eap_aka_autn);
-                               fr_pair_value_memsteal(vp, vec->umts.authn, false);
+                               vp = fr_pair_afrom_da(request, attr_eap_aka_sim_autn);
+                               fr_pair_value_memsteal(vp, vec->umts.authn, true);
                                RDEBUG2("&control:%pP", vp);
                                fr_cursor_append(&cursor, vp);
                                REXDENT();
@@ -435,7 +435,7 @@ rlm_rcode_t sigtran_client_map_send_auth_info(rlm_sigtran_t const *inst, REQUEST
                break;
 
        default:
-               ERROR("%i is not a valid version", req->version);
+               REDEBUG("%i is not a valid version", req->version);
                goto error;
        }
 
@@ -443,26 +443,33 @@ rlm_rcode_t sigtran_client_map_send_auth_info(rlm_sigtran_t const *inst, REQUEST
        txn->ctx.request = request;
 
        if (tmpl_aexpand(req, &imsi, request, inst->imsi, NULL, NULL) < 0) {
-               ERROR("Failed retrieving IMSI");
+               REDEBUG("Failed retrieving IMSI");
                goto error;
        }
 
        len = talloc_array_length(imsi) - 1;
        if ((len != 16) && (len != 15)) {
-               ERROR("IMSI must be 15 or 16 digits got %zu digits", len);
+               REDEBUG("IMSI must be 15 or 16 digits got %zu digits", len);
                goto error;
        }
 
        if (sigtran_ascii_to_tbcd(req, &req->imsi, imsi) < 0) {
-               ERROR("Failed converting ASCII to BCD");
+               REDEBUG("Failed converting ASCII to BCD");
                goto error;
        }
 
+       if (RDEBUG_ENABLED2) {
+               RDEBUG2("Sending MAPv%u request with IMSI \"%pV\"", req->version, fr_box_strvalue_buffer(imsi));
+       } else if (RDEBUG_ENABLED3){
+               RDEBUG3("Sending MAPv%u request with IMSI \"%pV\" (TBCD %pV)",
+                       req->version, fr_box_strvalue_buffer(imsi), fr_box_octets_buffer(req->imsi));
+       }
+
        /*
         *      FIXME - We shouldn't assume the pipe is always writable
         */
        if (write(fd, &txn, sizeof(txn)) < 0) {
-               ERROR("worker - ctrl_pipe (%i) write failed: %s", fd, fr_syserror(errno));
+               REDEBUG("worker - ctrl_pipe (%i) write failed: %s", fd, fr_syserror(errno));
                goto error;
        }
 
index 1e78dd210414920183c96894cd8f3b44c099e756..c6f29afe3685e713284669047ff9d1484d400957 100644 (file)
@@ -156,23 +156,30 @@ static const CONF_PARSER module_config[] = {
        CONF_PARSER_TERMINATOR
 };
 
-fr_dict_t *dict_eap_sim;
-fr_dict_t *dict_eap_aka;
+fr_dict_t *dict_eap_aka_sim;
 
-fr_dict_attr_t const *attr_eap_aka_autn;
-fr_dict_attr_t const *attr_eap_aka_ck;
-fr_dict_attr_t const *attr_eap_aka_ik;
-fr_dict_attr_t const *attr_eap_aka_rand;
-fr_dict_attr_t const *attr_eap_aka_xres;
+/*
+ *     UMTS vector
+ */
+fr_dict_attr_t const *attr_eap_aka_sim_autn;
+fr_dict_attr_t const *attr_eap_aka_sim_ck;
+fr_dict_attr_t const *attr_eap_aka_sim_ik;
+fr_dict_attr_t const *attr_eap_aka_sim_xres;
 
-fr_dict_attr_t const *attr_eap_sim_kc;
-fr_dict_attr_t const *attr_eap_sim_sres;
-fr_dict_attr_t const *attr_eap_sim_rand;
+/*
+ *     GSM vector
+ */
+fr_dict_attr_t const *attr_eap_aka_sim_kc;
+fr_dict_attr_t const *attr_eap_aka_sim_sres;
+
+/*
+ *     Shared
+ */
+fr_dict_attr_t const *attr_eap_aka_sim_rand;
 
 extern fr_dict_autoload_t rlm_sigtran_dict[];
 fr_dict_autoload_t rlm_sigtran_dict[] = {
-       { .out = &dict_eap_sim, .proto = "eap-sim" },
-       { .out = &dict_eap_aka, .proto = "eap-aka" },
+       { .out = &dict_eap_aka_sim, .base_dir = "eap/aka-sim", .proto = "eap-aka-sim" },
        { NULL }
 };
 
@@ -180,15 +187,13 @@ fr_dict_attr_t const *attr_auth_type;
 
 extern fr_dict_attr_autoload_t rlm_sigtran_dict_attr[];
 fr_dict_attr_autoload_t rlm_sigtran_dict_attr[] = {
-       { .out = &attr_eap_aka_autn, .name = "EAP-AKA-AUTN", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_ck, .name = "EAP-AKA-CK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_ik, .name = "EAP-AKA-IK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_rand, .name = "EAP-AKA-RAND", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-       { .out = &attr_eap_aka_xres, .name = "EAP-AKA-XRES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka },
-
-       { .out = &attr_eap_sim_kc, .name = "EAP-SIM-KC", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_rand, .name = "EAP-SIM-RAND", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
-       { .out = &attr_eap_sim_sres, .name = "EAP-SIM-SRES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_sim },
+       { .out = &attr_eap_aka_sim_autn, .name = "AUTN", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_ck, .name = "CK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_ik, .name = "IK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_kc, .name = "KC", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_rand, .name = "RAND", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_sres, .name = "SRES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
+       { .out = &attr_eap_aka_sim_xres, .name = "XRES", .type = FR_TYPE_OCTETS, .dict = &dict_eap_aka_sim },
 
        { NULL }
 };
index 846809cbeae88b5e5cd82d328ed9c2913e9af5e8..796894973eeef65877e6b32c17c60da097c45e54 100644 (file)
@@ -2,4 +2,5 @@ type = aka
 
 aka {
        network_name = "testing123"
+       virtual_server = "eap-aka"
 }
diff --git a/src/tests/eapol_test/config/methods-available/aka_prime b/src/tests/eapol_test/config/methods-available/aka_prime
new file mode 100644 (file)
index 0000000..c51d140
--- /dev/null
@@ -0,0 +1,6 @@
+type = aka_prime
+
+aka_prime {
+       network_name = "testing123"
+       virtual_server = "eap-aka"
+}
index 3a74bebadd8e71a00207ca0abb709d18feb53645..57f5e2c82458256be647826178c5257cc86cac8b 100644 (file)
@@ -1,4 +1,5 @@
 type = sim
 
 sim {
+       virtual_server = "eap-sim"
 }
index a74a95b4865e95c1a7278385d2c53b1cfe34f0a9..4938820b9af7fb6f30a21beb66b6c70ce8df9a16 100644 (file)
@@ -38,6 +38,26 @@ modules {
        $INCLUDE ${maindir}/mods-available/pap
        $INCLUDE ${maindir}/mods-available/mschap
 
+       cache eap_aka_sim_cache {
+               #
+               #  key:: Cache key.
+               #
+               key = "%{Session-ID}"
+
+               #
+               #  ttl:: TTL for cache entries.
+               #
+               ttl = 15
+
+               #
+               #  update <section> { ... }::
+               #
+               update {
+                       &session-state:Session-Data     := &session-state:Session-Data
+                       &session-state:Counter          := &session-state:Counter
+               }
+       }
+
        eap {
                default_eap_type = md5
                ignore_unknown_eap_types = no
@@ -74,6 +94,7 @@ modules {
                }
                $INCLUDE ${testdir}/methods-enabled/
        }
+
 }
 
 policy {
@@ -110,13 +131,6 @@ server test {
                                &EAP-TLS-Require-Client-Cert := yes
                        }
                }
-
-               # Test credentials for EAP-SIM, EAP-AKA, EAP-AKA'
-                update control {
-                        &Sim-Ki  := 0x465b5ce8b199b49faa5f0a2ee238a6bc
-                        &Sim-Opc := 0xcd63cb71954a9f4e48a5994e37a02baf
-                        &Sim-SQN := 3
-                }
                files
                eap
        }
@@ -149,6 +163,9 @@ server inner-tunnel {
        }
 
        recv Access-Request {
+               update request {
+                       &User-Name := &outer.User-Name
+               }
                files
                pap
                chap
@@ -181,3 +198,147 @@ server inner-tunnel {
        send Access-Challenge {
        }
 }
+
+server eap-aka-prime {
+       namespace = eap-aka-prime
+
+       recv Identity-Response {
+               "%{debug_attr:&session-state:}"
+               if (!&session-state:Tmp-String-0) {
+                       update reply {
+                               &Any-ID-Req := yes
+                       }
+                       update session-state {
+                               &Tmp-String-0 := yes
+                       }
+               }
+               ok
+       }
+
+       send Identity-Request {
+               ok
+       }
+
+       send Challenge-Request {
+                update control {
+                        &Sim-Ki  := 0x465b5ce8b199b49faa5f0a2ee238a6bc
+                        &Sim-Opc := 0xcd63cb71954a9f4e48a5994e37a02baf
+                        &Sim-SQN := 3
+                }
+               update reply {
+                       &Next-Reauth-Id := ""
+                       &Next-Pseudonym := ""
+               }
+       }
+
+       store session {
+               eap_aka_sim_cache
+       }
+
+       load session {
+               eap_aka_sim_cache
+       }
+
+       clear session {
+               eap_aka_sim_cache
+       }
+}
+
+server eap-aka {
+       namespace = eap-aka
+
+       recv Identity-Response {
+               "%{debug_attr:&session-state:}"
+               if (!&session-state:Tmp-String-0) {
+                       update reply {
+                               &Any-ID-Req := yes
+                       }
+                       update session-state {
+                               &Tmp-String-0 := yes
+                       }
+               }
+               ok
+       }
+
+       send Identity-Request {
+               ok
+       }
+
+       send Challenge-Request {
+                update control {
+                        &Sim-Ki  := 0x465b5ce8b199b49faa5f0a2ee238a6bc
+                        &Sim-Opc := 0xcd63cb71954a9f4e48a5994e37a02baf
+                        &Sim-SQN := 3
+                }
+               update reply {
+                       &Next-Reauth-Id := ""
+                       &Next-Pseudonym := ""
+               }
+       }
+
+       store session {
+               eap_aka_sim_cache
+       }
+
+       load session {
+               eap_aka_sim_cache
+       }
+
+       clear session {
+               eap_aka_sim_cache
+       }
+}
+
+server eap-sim {
+       namespace = eap-sim
+
+       recv Identity-Response {
+               "%{debug_attr:&session-state:}"
+               if (!&session-state:Tmp-String-0) {
+                       update reply {
+                               &Any-ID-Req := yes
+                       }
+                       update session-state {
+                               &Tmp-String-0 := yes
+                       }
+               }
+               ok
+       }
+
+       send Identity-Request {
+               ok
+       }
+
+       send Challenge-Request {
+                update control {
+                        &Sim-Ki  := 0x465b5ce8b199b49faa5f0a2ee238a6bc
+                        &Sim-Opc := 0xcd63cb71954a9f4e48a5994e37a02baf
+                        &Sim-SQN := 3
+                }
+               update reply {
+                       &Next-Reauth-Id := ""
+                       &Next-Pseudonym := ""
+               }
+               ok
+       }
+
+       send Reauthentication-Request {
+               update reply {
+                       &Next-Reauth-Id := ""
+                       &Next-Pseudonym := ""
+               }
+               ok
+       }
+
+       store session {
+               eap_aka_sim_cache
+       }
+
+       load session {
+               eap_aka_sim_cache
+       }
+
+       clear session {
+               eap_aka_sim_cache
+       }
+}
similarity index 52%
rename from src/tests/modules/eap_sim/module.conf
rename to src/tests/modules/eap_aka_sim/module.conf
index f6b1e689de4e06afcad4c8be83a6b60342cbe706..3740491b23eb61e70159bd8902222f8e3d9c0fb6 100644 (file)
@@ -1,6 +1,6 @@
 eap {
        type = sim
        sim {
-
+               virtual_server = default
        }
 }
similarity index 84%
rename from src/tests/modules/eap_sim/sim_xlat_id_aka.unlang
rename to src/tests/modules/eap_aka_sim/sim_xlat_id_aka.unlang
index 5cb43468d9647c46566a8346e2fc24e07db2daf8..9e4d188a9ea032766124819c8be4b8d630def494 100644 (file)
@@ -1,17 +1,17 @@
-if ("%{sim_id_method:&User-Name}" != 'AKA') {
+if ("%{aka_sim_id_method:User-Name}" != 'AKA') {
        test_fail
 } else {
        test_pass
 }
 
-if ("%{sim_id_type:&User-Name}" != 'Permanent') {
+if ("%{aka_sim_id_type:User-Name}" != 'Permanent') {
        test_fail
 } else {
        test_pass
 }
 
 #
-#  0.1 - Encrypt the permanent ID
+#  Encrypt the permanent ID
 #
 update control {
        &Tmp-String-0 := '1420032219455258'
@@ -23,7 +23,7 @@ update control {
 #
 #  0.2 - Can we get the EAP method from the encrypted blob correctly?
 #
-if ("%{sim_id_method:&control:User-Name}" != 'AKA') {
+if ("%{aka_sim_id_method:control:User-Name}" != 'AKA') {
        test_fail
 } else {
        test_pass
@@ -32,7 +32,7 @@ if ("%{sim_id_method:&control:User-Name}" != 'AKA') {
 #
 #  0.3 - Can we identify the encrypted blob correctly?
 #
-if ("%{sim_id_type:&control:User-Name}" != 'Pseudonym') {
+if ("%{aka_sim_id_type:control:User-Name}" != 'Pseudonym') {
        test_fail
 } else {
        test_pass
@@ -85,7 +85,7 @@ update control {
 #
 #  1.2 - Can we identify the encrypted blob correctly?
 #
-if ("%{sim_id_type:&control:User-Name[1]}" != 'Pseudonym') {
+if ("%{aka_sim_id_type:&control:User-Name[1]}" != 'Pseudonym') {
        test_fail
 } else {
        test_pass
similarity index 69%
rename from src/tests/modules/eap_sim/sim_xlat_id_error.unlang
rename to src/tests/modules/eap_aka_sim/sim_xlat_id_error.unlang
index 31f10880a6a88233964c856f467f836bcba83fd6..45caa5e3db64787da0c991a15dfc8e13e6fcc944 100644 (file)
@@ -5,7 +5,7 @@ update request {
        &User-Name := '14200322194552581'
 }
 
-if ("%{sim_id_method:User-Name}" != '') {
+if ("%{aka_sim_id_method:User-Name}" != '') {
        test_fail
 } else {
        test_pass
@@ -18,7 +18,7 @@ update request {
        &User-Name := ''
 }
 
-if ("%{sim_id_method:User-Name}" != '') {
+if ("%{aka_sim_id_method:User-Name}" != '') {
        test_fail
 } else {
        test_pass
similarity index 73%
rename from src/tests/modules/eap_sim/sim_xlat_id_sim.unlang
rename to src/tests/modules/eap_aka_sim/sim_xlat_id_sim.unlang
index 3167af2e5a908f4d1e7264df3ea5d15a673b0913..76c90186e999a8d345bc8754b66607efdd7778d6 100644 (file)
@@ -1,10 +1,10 @@
-if ("%{sim_id_method:User-Name}" != 'SIM') {
+if ("%{aka_sim_id_method:User-Name}" != 'SIM') {
        test_fail
 } else {
        test_pass
 }
 
-if ("%{sim_id_type:User-Name}" != 'Permanent') {
+if ("%{aka_sim_id_type:User-Name}" != 'Permanent') {
        test_fail
 } else {
        test_pass
@@ -23,7 +23,7 @@ update control {
 #
 #  Can we get the EAP method from the encrypted blob correctly?
 #
-if ("%{sim_id_method:control:User-Name}" != 'SIM') {
+if ("%{aka_sim_id_method:control:User-Name}" != 'SIM') {
        test_fail
 } else {
        test_pass
@@ -32,7 +32,7 @@ if ("%{sim_id_method:control:User-Name}" != 'SIM') {
 #
 #  Can we identify the encrypted blob correctly?
 #
-if ("%{sim_id_type:control:User-Name}" != 'Pseudonym') {
+if ("%{aka_sim_id_type:control:User-Name}" != 'Pseudonym') {
        test_fail
 } else {
        test_pass
index 2eaef519901fb2784f7bc8d476814ca5d867f52d..9502bf66f126b59a32ac6294c8bd51d4564b8157 100644 (file)
@@ -6,32 +6,32 @@
 need-feature tls
 
 # Load the EAP-SIM module
-load eap-sim
-load-dictionary eap-aka eap/aka
+load eap-aka-sim
+load-dictionary eap-aka-sim eap/aka-sim
 
 #
 # Encode some AKA attributes with special formats
 #
 
-# EAP-AKA-Res is an octets type attribute but with a length field containing the length
+# Res is an octets type attribute but with a length field containing the length
 # of the value in bits.  It may be between 32 - 128 bits in length.
 decode-pair.aka_tp_decode 03 02 00 20 01 02 03 04
-data EAP-AKA-RES = 0x01020304
+data RES = 0x01020304
 
 decode-pair.aka_tp_decode 03 05 00 80 01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08
-data EAP-AKA-RES = 0x01020304050607080102030405060708
+data RES = 0x01020304050607080102030405060708
 
 decode-pair.aka_tp_decode 03 05 00 78 01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08
-data EAP-AKA-RES = 0x010203040506070801020304050607
+data RES = 0x010203040506070801020304050607
 
 decode-pair.aka_tp_decode 04 04 01 02 03 04 05 06 07 08 09 aa bb cc dd ee
-data EAP-AKA-AUTS = 0x010203040506070809aabbccddee
+data AUTS = 0x010203040506070809aabbccddee
 
 decode-pair.aka_tp_decode 86 01 00 00
-data EAP-AKA-Checkcode = 0x
+data Checkcode = 0x
 
 decode-pair.aka_tp_decode 86 06 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 a0 b0 c0 d0
-data EAP-AKA-Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0
+data Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0
 
 decode-pair.aka_tp_decode 86 09 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 a0 b0 c0 d0 a0 b0 c0 d0 a0 b0 c0 d0 a0 b0 c0 d0
-data EAP-AKA-Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0a0b0c0d0a0b0c0d0a0b0c0d0
+data Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0a0b0c0d0a0b0c0d0a0b0c0d0
index 9c13b478fcc06461d7dc2512be481f8604dde9bc..242cdce705543a06f5d19a297ba7d536f23d2528 100644 (file)
@@ -5,30 +5,30 @@
 # Only run the tests if we have TLS support
 need-feature tls
 
-# Load the EAP-SIM module
-load eap-sim
-load-dictionary eap-aka eap/aka
+# Load the EAP-AKA/SIM encoder/decoder
+load eap-aka-sim
+load-dictionary eap-aka-sim eap/aka-sim
 
 #
 # Encode some AKA attributes with special formats
 #
 
-# EAP-AKA-Res is an octets type attribute but with a length field containing the length
+# Res is an octets type attribute but with a length field containing the length
 # of the value in bits.  It may be between 32 - 128 bits in length.
-encode-pair.aka_tp_encode EAP-AKA-RES = 0x01020304
+encode-pair.aka_tp_encode RES = 0x01020304
 data 03 02 00 20 01 02 03 04
 
-encode-pair.aka_tp_encode EAP-AKA-RES = 0x01020304050607080102030405060708
+encode-pair.aka_tp_encode RES = 0x01020304050607080102030405060708
 data 03 05 00 80 01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08
 
-encode-pair.aka_tp_encode EAP-AKA-AUTS = 0x010203040506070809aabbccddee
+encode-pair.aka_tp_encode AUTS = 0x010203040506070809aabbccddee
 data 04 04 01 02 03 04 05 06 07 08 09 aa bb cc dd ee
 
-encode-pair.aka_tp_encode EAP-AKA-Checkcode = 0x
+encode-pair.aka_tp_encode Checkcode = 0x
 data 86 01 00 00
 
-encode-pair.aka_tp_encode EAP-AKA-Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0
+encode-pair.aka_tp_encode Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0
 data 86 06 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 a0 b0 c0 d0
 
-encode-pair.aka_tp_encode EAP-AKA-Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0a0b0c0d0a0b0c0d0a0b0c0d0
+encode-pair.aka_tp_encode Checkcode = 0x0102030405060708090a0b0c0d0e0f00a0b0c0d0a0b0c0d0a0b0c0d0a0b0c0d0
 data 86 09 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 a0 b0 c0 d0 a0 b0 c0 d0 a0 b0 c0 d0 a0 b0 c0 d0
index 0795f2180039deafa03c9e6e543fff1ee4da9c36..49e688af04b4856f72910c9959b0f1323a075b39 100644 (file)
@@ -7,17 +7,17 @@
 # Only run the tests if we have TLS support
 need-feature tls
 
-# Load the EAP-SIM module
-load eap-sim
-load-dictionary eap-aka eap/aka
+# Load the EAP-AKA/SIM encoder/decoder
+load eap-aka-sim
+load-dictionary eap-aka-sim eap/aka-sim
 
 # AKA_RES with invalid length (too small)
 decode-pair.aka_tp_decode 04 03 aa bb aa aa aa aa bb bb bb bb
-data sim_decode_pair_value: Failed parsing non-skippable attribute 'EAP-AKA-AUTS': sim_decode_pair_value: Attribute "EAP-AKA-AUTS" needs a value of exactly 14 bytes, but value was 10 bytes
+data sim_decode_pair_value: Failed parsing non-skippable attribute 'AUTS': sim_decode_pair_value: Attribute "AUTS" needs a value of exactly 14 bytes, but value was 10 bytes
 
 # AKA_RES with invalid length (too big)
 decode-pair.aka_tp_decode 04 05 aa bb aa aa aa aa bb bb bb bb cc cc cc cc dd dd dd dd
-data sim_decode_pair_value: Failed parsing non-skippable attribute 'EAP-AKA-AUTS': sim_decode_pair_value: Attribute "EAP-AKA-AUTS" needs a value of exactly 14 bytes, but value was 18 bytes
+data sim_decode_pair_value: Failed parsing non-skippable attribute 'AUTS': sim_decode_pair_value: Attribute "AUTS" needs a value of exactly 14 bytes, but value was 18 bytes
 
 # AKA_RES with invalid number of bits (too small)
 decode-pair.aka_tp_decode 03 02 00 18 aa bb cc dd
@@ -33,8 +33,4 @@ data sim_decode_pair_value: RES Length field value must be between 32-128 bits,
 
 # AKA_RES with invalid number of bits (too big - exceed limit)
 decode-pair.aka_tp_decode 03 05 00 7f aa bb cc dd aa bb cc dd aa bb cc dd aa bb cc dd
-data sim_decode_pair_value: RES Length (127) is not a multiple of 8
-
-# AKA Rand only contains a single attribute
-decode-pair.aka_tp_decode 01 09 00 00 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 78
-data sim_decode_pair_value: Failed parsing non-skippable attribute 'EAP-AKA-RAND': sim_decode_pair_value: Attribute "EAP-AKA-RAND" needs a value of exactly 16 bytes, but value was 34 bytes
+data sim_decode_pair_value: RES Length (127) is not a multiple of 8
\ No newline at end of file
index 71e55752278bc73d0bfa97482ad91fe807c13d55..643aac83d3f572c1d6f8f7b40f6f4a08b316544f 100644 (file)
@@ -7,68 +7,68 @@
 # Only run the tests if we have TLS support
 need-feature tls
 
-# Load the EAP-SIM module
-load eap-sim
-load-dictionary eap-sim eap/sim
+# Load the EAP-AKA/SIM encoder/decoder
+load eap-aka-sim
+load-dictionary eap-aka-sim eap/aka-sim
 
 # Boolean attribute
 decode-pair.sim_tp_decode 0d 01 00 00
-data EAP-SIM-Any-ID-Req = yes
+data Any-ID-Req = yes
 
 # Short
 decode-pair.sim_tp_decode 10 01 ff ff
-data EAP-SIM-Selected-Version = 65535
+data Selected-Version = 65535
 
 # Octets
 decode-pair.sim_tp_decode 01 05 00 00 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77
-data EAP-SIM-RAND = 0x00112233445566770011223344556677
+data RAND = 0x00112233445566770011223344556677
 
 decode-pair.sim_tp_decode 01 09 00 00 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 78
-data EAP-SIM-RAND = 0x00112233445566770011223344556677, EAP-SIM-RAND = 0x00112233445566770011223344556678
+data RAND = 0x00112233445566770011223344556677, RAND = 0x00112233445566770011223344556678
 
 # Aliased (found)
 decode-pair.sim_tp_decode 0c 01 04 02
-data EAP-SIM-Notification = Temporarily-Denied
+data Notification = Temporarily-Denied
 
 # Aliased (notfound)
 decode-pair.sim_tp_decode 0c 01 ff ff
-data EAP-SIM-Notification = 65535
+data Notification = 65535
 
 # No string padding
 decode-pair.sim_tp_decode 0e 05 00 10 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 69
-data EAP-SIM-Identity = "testing123@simfi"
+data Identity = "testing123@simfi"
 
 # Three bytes string padding
 decode-pair.sim_tp_decode 0e 05 00 0d 74 65 73 74 69 6e 67 31 32 33 40 73 69 00 00 00
-data EAP-SIM-Identity = "testing123@si"
+data Identity = "testing123@si"
 
 # Two bytes string padding
 decode-pair.sim_tp_decode 0e 05 00 0e 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 00 00
-data EAP-SIM-Identity = "testing123@sim"
+data Identity = "testing123@sim"
 
 # One byte string padding
 decode-pair.sim_tp_decode 0e 05 00 0f 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 00
-data EAP-SIM-Identity = "testing123@simf"
+data Identity = "testing123@simf"
 
 # Empty string
 decode-pair.sim_tp_decode 0e 01 00 00
-data EAP-SIM-Identity = ""
+data Identity = ""
 
 # Two attributes
 decode-pair.sim_tp_decode 0e 05 00 10 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 69 0d 01 00 00
-data EAP-SIM-Identity = "testing123@simfi", EAP-SIM-Any-ID-Req = yes
+data Identity = "testing123@simfi", Any-ID-Req = yes
 
 # Array (one element)
 decode-pair.sim_tp_decode 0f 02 00 02 00 02 00 00
-data EAP-SIM-Version-List = 2
+data Version-List = 2
 
 # Array (multiple elements, with padding)
 decode-pair.sim_tp_decode 0f 03 00 06 00 02 00 03 00 04 00 00
-data EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 3, EAP-SIM-Version-List = 4
+data Version-List = 2, Version-List = 3, Version-List = 4
 
 # Array (multiple elements, with no padding)
 decode-pair.sim_tp_decode 0f 03 00 08 00 02 ff ff 00 ff ff 00
-data EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 65535, EAP-SIM-Version-List = 255, EAP-SIM-Version-List = 65280
+data Version-List = 2, Version-List = 65535, Version-List = 255, Version-List = 65280
 
 # Zero length array
 decode-pair.sim_tp_decode 0f 01 00 00
@@ -84,35 +84,35 @@ data Attr-130.255 = 0x0000000000000000000000000000
 
 # Mixture of known and than skippable unknown
 decode-pair.sim_tp_decode 82 05 00 00 47 bd f4 5e 3d c5 69 da e8 fa 73 2a 69 44 a8 78
-data EAP-SIM-Counter = 0, Attr-130.255 = 0x00000000000000000000
+data Counter = 0, Attr-130.255 = 0x00000000000000000000
 
 decode-pair.sim_tp_decode 82 05 00 00 b2 dd 1d a3 e1 fc 91 3d 94 6b 3f a1 ba 5d 73 e2
-data Attr-130.255 = 0x00000000000000000000, EAP-SIM-Counter = 0
+data Attr-130.255 = 0x00000000000000000000, Counter = 0
 
 # RFC4186 A.3. example
 decode-pair.sim_tp_decode_rfc4186 0f 02 00 02 00 01 00 00
-data EAP-SIM-Version-List = 1
+data Version-List = 1
 
 # RFC4186 A.4. example
 decode-pair.sim_tp_decode_rfc4186 07 05 00 00 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10 10 01 00 01
-data EAP-SIM-Nonce-MT = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Selected-Version = 1
+data Nonce-MT = 0x0123456789abcdeffedcba9876543210, Selected-Version = 1
 
 # RFC4186 A.5. example
 decode-pair.sim_tp_decode_rfc4186 01 0d 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 81 05 00 00 9e 18 b0 c2 9a 65 22 63 c0 6e fb 54 dd 00 a8 95 82 2d 00 00 55 f2 93 9b bd b1 b1 9e a1 b4 7f c0 b3 e0 be 4c ab 2c f7 37 2d 98 e3 02 3c 6b b9 24 15 72 3d 58 ba d6 6c e0 84 e1 01 b6 0f 53 58 35 4b d4 21 82 78 ae a7 bf 2c ba ce 33 10 6a ed dc 62 5b 0c 1d 5a a6 7a 41 73 9a e5 b5 79 50 97 3f c7 ff 83 01 07 3c 6f 95 31 50 fc 30 3e a1 52 d1 e1 0a 2d 1f 4f 52 26 da a1 ee 90 05 47 22 52 bd b3 b7 1d 6f 0c 3a 34 90 31 6c 46 92 98 71 bd 45 cd fd bc a6 11 2f 07 f8 be 71 79 90 d2 5f 6d d7 f2 b7 b3 20 bf 4d 5a 99 2e 88 03 31 d7 29 94 5a ec 75 ae 5d 43 c8 ed a5 fe 62 33 fc ac 49 4e e6 7a 0d 50 4d 0b 05 00 00 fe f3 24 ac 39 62 b5 9f 3b d7 82 53 ae 4d cb 6a
-data EAP-SIM-RAND = 0x101112131415161718191a1b1c1d1e1f, EAP-SIM-RAND = 0x202122232425262728292a2b2c2d2e2f, EAP-SIM-RAND = 0x303132333435363738393a3b3c3d3e3f, EAP-SIM-IV = 0x9e18b0c29a652263c06efb54dd00a895, EAP-SIM-Next-Pseudonym = "w8w49PexCazWJ&xCIARmxuMKht5S1sxRDqXSEFBEg3DcZP9cIxTe5J4OyIwNGVzxeJOU1G", EAP-SIM-Next-Reauth-ID = "Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo", EAP-SIM-MAC = 0xfef324ac3962b59f3bd78253ae4dcb6a
+data RAND = 0x101112131415161718191a1b1c1d1e1f, RAND = 0x202122232425262728292a2b2c2d2e2f, RAND = 0x303132333435363738393a3b3c3d3e3f, IV = 0x9e18b0c29a652263c06efb54dd00a895, Next-Pseudonym = "w8w49PexCazWJ&xCIARmxuMKht5S1sxRDqXSEFBEg3DcZP9cIxTe5J4OyIwNGVzxeJOU1G", Next-Reauth-ID = "Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo", MAC = 0xfef324ac3962b59f3bd78253ae4dcb6a
 
 # RFC4186 A.6. example
 decode-pair.sim_tp_decode_rfc4186 0b 05 00 00 f5 6d 64 33 e6 8e d2 97 6a c1 19 37 fc 3d 11 54
-data EAP-SIM-MAC = 0xf56d6433e68ed2976ac11937fc3d1154
+data MAC = 0xf56d6433e68ed2976ac11937fc3d1154
 
 # RFC4186 A.9. example
 decode-pair.sim_tp_decode_rfc4186 81 05 00 00 d5 85 ac 77 86 b9 03 36 65 7c 77 b4 65 75 b9 c4 82 1d 00 00 68 62 91 a9 d2 ab c5 8c aa 32 94 b6 e8 5b 44 84 6c 44 e5 dc b2 de 8b 9e 80 d6 9d 49 85 8a 5d b8 4c dc 1c 9b c9 5c 01 b9 6b 6e ca 31 34 74 ae a6 d3 14 16 e1 9d aa 9d f7 0f 05 00 88 41 ca 80 14 96 4d 3b 30 a4 9b cf 43 e4 d3 f1 8e 86 29 5a 4a 2b 38 d9 6c 97 05 c2 bb b0 5c 4a ac e9 7d 5e af f5 64 04 6c 8b d3 0b c3 9b e5 e1 7a ce 2b 10 a6 0b 05 00 00 48 3a 17 99 b8 3d 7c d3 d0 a1 e4 01 d9 ee 47 70
-data EAP-SIM-IV = 0xd585ac7786b90336657c77b46575b9c4, EAP-SIM-Counter = 1, EAP-SIM-Nonce-S = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Next-Reauth-ID = "uta0M0iyIsMwWp5TTdSdnOLvg2XDVf21OYt1vnfiMcs5dnIDHOIFVavIRzMRyzW6vFzdHW@eapsim.foo", EAP-SIM-MAC = 0x483a1799b83d7cd3d0a1e401d9ee4770
+data IV = 0xd585ac7786b90336657c77b46575b9c4, Counter = 1, Nonce-S = 0x0123456789abcdeffedcba9876543210, Next-Reauth-ID = "uta0M0iyIsMwWp5TTdSdnOLvg2XDVf21OYt1vnfiMcs5dnIDHOIFVavIRzMRyzW6vFzdHW@eapsim.foo", MAC = 0x483a1799b83d7cd3d0a1e401d9ee4770
 
 # RFC4186 A.10. example
 decode-pair.sim_tp_decode_rfc4186 81 05 00 00 cd f7 ff a6 5d e0 4c 02 6b 56 c8 6b 76 b1 02 ea 82 05 00 00 b6 ed d3 82 79 e2 a1 42 3c 1a fc 5c 45 5c 7d 56 0b 05 00 00 fa f7 6b 71 fb e2 d2 55 b9 6a 35 66 c9 15 c6 17
-data EAP-SIM-IV = 0xcdf7ffa65de04c026b56c86b76b102ea, EAP-SIM-Counter = 1, EAP-SIM-MAC = 0xfaf76b71fbe2d255b96a3566c915c617
+data IV = 0xcdf7ffa65de04c026b56c86b76b102ea, Counter = 1, MAC = 0xfaf76b71fbe2d255b96a3566c915c617
 
 # RFC4186 A.10. example - With IV at the end of the packet
 decode-pair.sim_tp_decode_rfc4186 82 05 00 00 b6 ed d3 82 79 e2 a1 42 3c 1a fc 5c 45 5c 7d 56 0b 05 00 00 fa f7 6b 71 fb e2 d2 55 b9 6a 35 66 c9 15 c6 17 81 05 00 00 cd f7 ff a6 5d e0 4c 02 6b 56 c8 6b 76 b1 02 ea
-data EAP-SIM-Counter = 1, EAP-SIM-MAC = 0xfaf76b71fbe2d255b96a3566c915c617, EAP-SIM-IV = 0xcdf7ffa65de04c026b56c86b76b102ea
+data Counter = 1, MAC = 0xfaf76b71fbe2d255b96a3566c915c617, IV = 0xcdf7ffa65de04c026b56c86b76b102ea
index a027d09b58517d8cfae328bb27ac5b2e6f9e1d85..cf49b108bb868abe6511f9186ff40cd29952aa14 100644 (file)
 # Only run the tests if we have TLS support
 need-feature tls
 
-# Load the EAP-SIM module
-load eap-sim
-load-dictionary eap-sim eap/sim
+# Load the EAP-AKA/SIM encoder/decoder
+load eap-aka-sim
+load-dictionary eap-aka-sim eap/aka-sim
 
 # Boolean attribute
-encode-pair.sim_tp_encode EAP-SIM-Any-ID-Req = yes
+encode-pair.sim_tp_encode Any-ID-Req = yes
 data 0d 01 00 00
 
 # False Boolean attribute (should produce no data)
-encode-pair.sim_tp_encode EAP-SIM-Any-ID-Req = no
+encode-pair.sim_tp_encode Any-ID-Req = no
 data
 
 # Short
-encode-pair.sim_tp_encode EAP-SIM-Selected-Version = 1
+encode-pair.sim_tp_encode Selected-Version = 1
 data 10 01 00 01
 
 # Octets
-encode-pair.sim_tp_encode EAP-SIM-RAND = 0x00112233445566770011223344556677
+encode-pair.sim_tp_encode RAND = 0x00112233445566770011223344556677
 data 01 05 00 00 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77
 
-encode-pair.sim_tp_encode EAP-SIM-RAND = 0x00112233445566770011223344556677, EAP-SIM-RAND = 0x00112233445566770011223344556678
+encode-pair.sim_tp_encode RAND = 0x00112233445566770011223344556677, RAND = 0x00112233445566770011223344556678
 data 01 09 00 00 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 77 00 11 22 33 44 55 66 78
 
 # Octets (autopad)
-encode-pair.sim_tp_encode EAP-SIM-RAND = 0x11
+encode-pair.sim_tp_encode RAND = 0x11
 data 01 05 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 
 # Empty octets
-encode-pair.sim_tp_encode EAP-SIM-RAND = 0x
+encode-pair.sim_tp_encode RAND = 0x
 data 01 01 00 00
 
 # Aliased
-encode-pair.sim_tp_encode EAP-SIM-Notification = Temporarily-Denied
+encode-pair.sim_tp_encode Notification = Temporarily-Denied
 data 0c 01 04 02
 
 # No string padding
-encode-pair.sim_tp_encode EAP-SIM-Identity = "testing123@simfi"
+encode-pair.sim_tp_encode Identity = "testing123@simfi"
 data 0e 05 00 10 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 69
 
 # Three bytes string padding
-encode-pair.sim_tp_encode EAP-SIM-Identity = "testing123@si"
+encode-pair.sim_tp_encode Identity = "testing123@si"
 data 0e 05 00 0d 74 65 73 74 69 6e 67 31 32 33 40 73 69 00 00 00
 
 # Two bytes string padding
-encode-pair.sim_tp_encode EAP-SIM-Identity = "testing123@sim"
+encode-pair.sim_tp_encode Identity = "testing123@sim"
 data 0e 05 00 0e 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 00 00
 
 # One byte string padding
-encode-pair.sim_tp_encode EAP-SIM-Identity = "testing123@simf"
+encode-pair.sim_tp_encode Identity = "testing123@simf"
 data 0e 05 00 0f 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 00
 
 # Empty string
-encode-pair.sim_tp_encode EAP-SIM-Identity = ""
+encode-pair.sim_tp_encode Identity = ""
 data 0e 01 00 00
 
 # Two attributes
-encode-pair.sim_tp_encode EAP-SIM-Identity = "testing123@simfi", EAP-SIM-Any-ID-Req = yes
+encode-pair.sim_tp_encode Identity = "testing123@simfi", Any-ID-Req = yes
 data 0e 05 00 10 74 65 73 74 69 6e 67 31 32 33 40 73 69 6d 66 69 0d 01 00 00
 
 # A single encrypted attribute
-encode-pair.sim_tp_encode EAP-SIM-Next-Pseudonym = "testing123"
+encode-pair.sim_tp_encode Next-Pseudonym = "testing123"
 data 82 05 00 00 3f b8 34 1f f8 26 e0 4d 4a f3 f9 61 3c a9 84 26
 
 decode-pair.sim_tp_decode -
-data EAP-SIM-Next-Pseudonym = "testing123"
+data Next-Pseudonym = "testing123"
 
 # Encrypt attribute requiring padding
-encode-pair.sim_tp_encode EAP-SIM-Counter-Too-Small = yes
+encode-pair.sim_tp_encode Counter-Too-Small = yes
 data 82 05 00 00 5a f8 99 3c 02 f5 6c 04 b8 6e bb 54 3a af 74 32
 
 decode-pair.sim_tp_decode -
-data EAP-SIM-Counter-Too-Small = yes
+data Counter-Too-Small = yes
 
 # Two encrypted attributes, one bool to extend plaintext so it's not a multiple block of block length
-encode-pair.sim_tp_encode EAP-SIM-Next-Pseudonym = "testing123", EAP-SIM-Counter-Too-Small = yes
+encode-pair.sim_tp_encode Next-Pseudonym = "testing123", Counter-Too-Small = yes
 data 82 09 00 00 3f b8 34 1f f8 26 e0 4d 4a f3 f9 61 3c a9 84 26 0f 4a 53 ce 33 99 9e 4f 29 df a4 79 18 a9 57 dd
 
 decode-pair.sim_tp_decode -
-data EAP-SIM-Next-Pseudonym = "testing123", EAP-SIM-Counter-Too-Small = yes
+data Next-Pseudonym = "testing123", Counter-Too-Small = yes
 
 # Plaintext and encrypted attributes interleaved (this shouldn't happen usually, due to sorting)
-encode-pair.sim_tp_encode EAP-SIM-Next-Pseudonym = "testing123", EAP-SIM-Any-ID-Req = yes, EAP-SIM-Counter-Too-Small = yes
+encode-pair.sim_tp_encode Next-Pseudonym = "testing123", Any-ID-Req = yes, Counter-Too-Small = yes
 data 82 05 00 00 3f b8 34 1f f8 26 e0 4d 4a f3 f9 61 3c a9 84 26 0d 01 00 00 82 05 00 00 5a f8 99 3c 02 f5 6c 04 b8 6e bb 54 3a af 74 32
 
 decode-pair.sim_tp_decode -
-data EAP-SIM-Next-Pseudonym = "testing123", EAP-SIM-Any-ID-Req = yes, EAP-SIM-Counter-Too-Small = yes
+data Next-Pseudonym = "testing123", Any-ID-Req = yes, Counter-Too-Small = yes
 
 # Array (one element)
-encode-pair.sim_tp_encode EAP-SIM-Version-List = 1
+encode-pair.sim_tp_encode Version-List = 1
 data 0f 02 00 02 00 01 00 00
 
 # Array (multiple elements, with padding)
-encode-pair.sim_tp_encode EAP-SIM-Version-List = 1, EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 3
+encode-pair.sim_tp_encode Version-List = 1, Version-List = 2, Version-List = 3
 data 0f 03 00 06 00 01 00 02 00 03 00 00
 
 # Array (multiple elements, with no padding)
-encode-pair.sim_tp_encode EAP-SIM-Version-List = 1, EAP-SIM-Version-List = 2, EAP-SIM-Version-List = 3, EAP-SIM-Version-List = 4
+encode-pair.sim_tp_encode Version-List = 1, Version-List = 2, Version-List = 3, Version-List = 4
 data 0f 03 00 08 00 01 00 02 00 03 00 04
 
 # RFC4186 A.3. example
-encode-pair.sim_tp_encode_rfc4186 EAP-SIM-Version-List = 1
+encode-pair.sim_tp_encode_rfc4186 Version-List = 1
 data 0f 02 00 02 00 01 00 00
 
 # RFC4186 A.4. example
-encode-pair.sim_tp_encode_rfc4186 EAP-SIM-Nonce-MT = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Selected-Version = 1
+encode-pair.sim_tp_encode_rfc4186 Nonce-MT = 0x0123456789abcdeffedcba9876543210, Selected-Version = 1
 data 07 05 00 00 01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10 10 01 00 01
 
 # RFC4186 A.5. example
-encode-pair.sim_tp_encode_rfc4186 EAP-SIM-RAND = 0x101112131415161718191a1b1c1d1e1f, EAP-SIM-RAND = 0x202122232425262728292a2b2c2d2e2f, EAP-SIM-RAND = 0x303132333435363738393a3b3c3d3e3f, EAP-SIM-IV = 0x9e18b0c29a652263c06efb54dd00a895, EAP-SIM-Next-Pseudonym = "w8w49PexCazWJ&xCIARmxuMKht5S1sxRDqXSEFBEg3DcZP9cIxTe5J4OyIwNGVzxeJOU1G", EAP-SIM-Next-Reauth-ID = "Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo"
+encode-pair.sim_tp_encode_rfc4186 RAND = 0x101112131415161718191a1b1c1d1e1f, RAND = 0x202122232425262728292a2b2c2d2e2f, RAND = 0x303132333435363738393a3b3c3d3e3f, IV = 0x9e18b0c29a652263c06efb54dd00a895, Next-Pseudonym = "w8w49PexCazWJ&xCIARmxuMKht5S1sxRDqXSEFBEg3DcZP9cIxTe5J4OyIwNGVzxeJOU1G", Next-Reauth-ID = "Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo"
 data 01 0d 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 81 05 00 00 9e 18 b0 c2 9a 65 22 63 c0 6e fb 54 dd 00 a8 95 82 2d 00 00 55 f2 93 9b bd b1 b1 9e a1 b4 7f c0 b3 e0 be 4c ab 2c f7 37 2d 98 e3 02 3c 6b b9 24 15 72 3d 58 ba d6 6c e0 84 e1 01 b6 0f 53 58 35 4b d4 21 82 78 ae a7 bf 2c ba ce 33 10 6a ed dc 62 5b 0c 1d 5a a6 7a 41 73 9a e5 b5 79 50 97 3f c7 ff 83 01 07 3c 6f 95 31 50 fc 30 3e a1 52 d1 e1 0a 2d 1f 4f 52 26 da a1 ee 90 05 47 22 52 bd b3 b7 1d 6f 0c 3a 34 90 31 6c 46 92 98 71 bd 45 cd fd bc a6 11 2f 07 f8 be 71 79 90 d2 5f 6d d7 f2 b7 b3 20 bf 4d 5a 99 2e 88 03 31 d7 29 94 5a ec 75 ae 5d 43 c8 ed a5 fe 62 33 fc ac 49 4e e6 7a 0d 50 4d
 
 # RFC4186 A.9. example
-encode-pair.sim_tp_encode_rfc4186 EAP-SIM-IV = 0xd585ac7786b90336657c77b46575b9c4, EAP-SIM-Counter = 1, EAP-SIM-Nonce-S = 0x0123456789abcdeffedcba9876543210, EAP-SIM-Next-Reauth-ID = "uta0M0iyIsMwWp5TTdSdnOLvg2XDVf21OYt1vnfiMcs5dnIDHOIFVavIRzMRyzW6vFzdHW@eapsim.foo"
+encode-pair.sim_tp_encode_rfc4186 IV = 0xd585ac7786b90336657c77b46575b9c4, Counter = 1, Nonce-S = 0x0123456789abcdeffedcba9876543210, Next-Reauth-ID = "uta0M0iyIsMwWp5TTdSdnOLvg2XDVf21OYt1vnfiMcs5dnIDHOIFVavIRzMRyzW6vFzdHW@eapsim.foo"
 data 81 05 00 00 d5 85 ac 77 86 b9 03 36 65 7c 77 b4 65 75 b9 c4 82 1d 00 00 68 62 91 a9 d2 ab c5 8c aa 32 94 b6 e8 5b 44 84 6c 44 e5 dc b2 de 8b 9e 80 d6 9d 49 85 8a 5d b8 4c dc 1c 9b c9 5c 01 b9 6b 6e ca 31 34 74 ae a6 d3 14 16 e1 9d aa 9d f7 0f 05 00 88 41 ca 80 14 96 4d 3b 30 a4 9b cf 43 e4 d3 f1 8e 86 29 5a 4a 2b 38 d9 6c 97 05 c2 bb b0 5c 4a ac e9 7d 5e af f5 64 04 6c 8b d3 0b c3 9b e5 e1 7a ce 2b 10 a6
 
 # RFC4186 A.10. example
-encode-pair.sim_tp_encode_rfc4186 EAP-SIM-IV = 0xcdf7ffa65de04c026b56c86b76b102ea, EAP-SIM-Counter = 1
+encode-pair.sim_tp_encode_rfc4186 IV = 0xcdf7ffa65de04c026b56c86b76b102ea, Counter = 1
 data 81 05 00 00 cd f7 ff a6 5d e0 4c 02 6b 56 c8 6b 76 b1 02 ea 82 05 00 00 b6 ed d3 82 79 e2 a1 42 3c 1a fc 5c 45 5c 7d 56
index c7410c774ac9b6fcd62fb54a166c8f92494ae6ef..c46903367fda830c41fe76be0342041913e37660 100644 (file)
@@ -7,9 +7,9 @@
 # Only run the tests if we have TLS support
 need-feature tls
 
-# Load the EAP-SIM module
-load eap-sim
-load-dictionary eap-sim eap/sim
+# Load the EAP-AKA/SIM encoder/decoder
+load eap-aka-sim
+load-dictionary eap-aka-sim eap/aka-sim
 
 # Zero length attribute
 decode-pair.sim_tp_decode 0d 00