]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add support for checkcodes
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 10 Dec 2017 18:33:44 +0000 (18:33 +0000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 10 Dec 2017 18:33:44 +0000 (18:33 +0000)
Add support for result_ind

Make signing digests flexible in preparation for EAP-AKA'

Add success notification state for result_ind

src/modules/rlm_eap/lib/sim/crypto.c
src/modules/rlm_eap/lib/sim/encode.c
src/modules/rlm_eap/lib/sim/sim_proto.h
src/modules/rlm_eap/types/rlm_eap_aka/eap_aka.h
src/modules/rlm_eap/types/rlm_eap_aka/rlm_eap_aka.c
src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c

index bb6b68520c77dc6bda8de95eb7d0c0b18a2043ac..994e44b2ddcd63f9cb14b95a7c89cf24ad7259d5 100644 (file)
@@ -35,6 +35,120 @@ RCSID("$Id$")
 #include <freeradius-devel/eap.sim.h>
 #include <openssl/evp.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)
+{
+       if (checkcode->md_ctx) EVP_MD_CTX_destroy(checkcode->md_ctx);
+       return 0;
+}
+
+/** Initialise checkcode message digest
+ *
+ * @param[in] ctx              to allocate checkcode structure in.
+ * @param[out] checkcode       a new checkcode structure.
+ * @param[in] md               to use when calculating the checkcode,
+ *                             either EVP_sha1(), or EVP_sha256().
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+int fr_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_sim_checkcode_t **checkcode, EVP_MD const *md)
+{
+       *checkcode = talloc_zero(ctx, fr_sim_checkcode_t);
+       if (!*checkcode) {
+               fr_strerror_printf("Out of memory");
+               return -1;
+       }
+
+       (*checkcode)->md_ctx = EVP_MD_CTX_create();
+       if (!(*checkcode)->md_ctx) {
+               tls_strerror_printf(true, "Failed creating MD ctx");
+       error:
+               TALLOC_FREE(*checkcode);
+               return -1;
+       }
+       if (EVP_DigestInit_ex((*checkcode)->md_ctx, md, NULL) != 1) {
+               tls_strerror_printf(true, "Failed intialising MD ctx");
+               goto error;
+       }
+
+       talloc_set_destructor(*checkcode, _fr_sim_crypto_free_checkcode);
+
+       return 0;
+}
+
+/** Digest a packet, updating the checkcode
+ *
+ * Call #fr_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
+ *                             will be initialised before the provided
+ *                             #eap_packet is fed into the digest.
+ * @param[in] eap_packet       to digest.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+int fr_sim_crypto_update_checkcode(fr_sim_checkcode_t *checkcode, eap_packet_t *eap_packet)
+{
+       uint16_t                packet_len;
+       eap_packet_raw_t        eap_hdr;
+
+       eap_hdr.code = eap_packet->code;
+       eap_hdr.id = eap_packet->id;
+       packet_len = htons((sizeof(eap_hdr) + eap_packet->type.length) & UINT16_MAX); /* EAP Header + Method + SIM data */
+       memcpy(&eap_hdr.length, &packet_len, sizeof(packet_len));
+       eap_hdr.data[0] = eap_packet->type.num;
+
+       /*
+        *      Digest the header
+        */
+       if (EVP_DigestUpdate(checkcode->md_ctx, &eap_hdr, sizeof(eap_hdr)) != 1) {
+               tls_strerror_printf(true, "Failed digesting EAP header");
+               return -1;
+       }
+
+       /*
+        *      Digest the packet
+        */
+       if (EVP_DigestUpdate(checkcode->md_ctx, eap_packet->type.data, eap_packet->type.length) != 1) {
+               tls_strerror_printf(true, "Failed digesting packet data");
+               return -1;
+       }
+
+       return 0;
+}
+
+/** Write out the final checkcode value
+ *
+ * @param[out] out             Where to write the checkcode value.  Must be at least 20
+ *                             bytes if MD was SHA1, or 32 bytes if MD was SHA256.
+ * @param[in] outlen           Length of the output buffer.
+ * @param[in,out] checkcode    structure to get final digest from and to tree.
+ * @return
+ *     - <= 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)
+{
+       unsigned int len;
+
+       if (EVP_DigestFinal_ex((*checkcode)->md_ctx, out, &len) != 1) {
+               tls_strerror_printf(true, "Failed finalising checkcode digest");
+               TALLOC_FREE(*checkcode);
+               return -1;
+       }
+
+       TALLOC_FREE(*checkcode);
+
+       return len;
+}
+
 /** Locate the start of the AT_MAC value in the buffer
  *
  * @param[in,out] data to search for the AT_MAC in.
@@ -77,29 +191,35 @@ static int fr_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
        return 1;
 }
 
-/** Append AT_MAC to the end a packet.
+/** Calculate the digest value for a packet
+ *
+ * Run a digest over a fake EAP header, the entire SIM packet and any extra HMAC data,
+ * writing a truncated (16 byte) digest value to out.
  *
- * Run SHA1 digest over a fake EAP header, the entire SIM packet and any extra HMAC data,
- * writing out the complete AT_HMAC and digest to out.
+ * @note The 16 byte digest field in the packet must have either been zeroed out before
+ *      this function is called (as it is when encoding data), or #zero_mac must be set
+ *      to true.
  *
  * @param[out] out             Where to write the digest.
  * @param[in] eap_packet       to extract header values from.
+ * @param[in] zero_mac         Assume the mac field is not zeroed (i.e. received packet)
+ *                             and skip it during mac calculation feeding in 16 zeroed
+ *                             bytes in its place.
  * @param[in] key              to use to sign the packet.
  * @param[in] key_len          Length of the key.
  * @param[in] hmac_extra       data to concatenate with the packet when calculating the HMAC
  *                             (may be NULL).
- * @param[in] hmac_extra_len   Length of hmac_extra.
+ * @param[in] hmac_extra_len   Length of hmac_extra (may be zero).
  * @return
  *     - < 0 on failure.
  *     - 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[16], eap_packet_t *eap_packet, bool zero_mac,
-                                 uint8_t const *key, size_t const key_len,
+                                 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_MD const            *md = EVP_sha1();
        EVP_PKEY                *pkey;
 
        uint8_t                 digest[SHA1_DIGEST_LENGTH];
@@ -143,13 +263,13 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, boo
 
        FR_PROTO_HEX_DUMP("hmac input eap_hdr", (uint8_t *)&eap_hdr, sizeof(eap_hdr));
        if (EVP_DigestSignUpdate(md_ctx, &eap_hdr, sizeof(eap_hdr)) != 1) {
-               tls_strerror_printf(true, "Failed digesting EAP header");
+               tls_strerror_printf(true, "Failed digesting EAP data");
                goto error;
        }
 
        /*
         *      Digest the packet up to the AT_MAC, value, then
-        *      ingest 16 bytes of zero.
+        *      digest 16 bytes of zero.
         */
        if (zero_mac) {
                switch (fr_sim_find_mac(&mac, p, end - p)) {
@@ -163,7 +283,7 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, boo
                         *      AT_MAC header and reserved bytes.
                         */
                        if (EVP_DigestSignUpdate(md_ctx, p, mac - p) != 1) {
-                               tls_strerror_printf(true, "Failed digesting header");
+                               tls_strerror_printf(true, "Failed digesting packet data (before MAC)");
                                goto error;
                        }
                        p += mac - p;
@@ -173,7 +293,7 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, boo
                         *      simulated the zeroed out Mac.
                         */
                        if (EVP_DigestSignUpdate(md_ctx, zero, sizeof(zero)) != 1) {
-                               tls_strerror_printf(true, "Failed zeroes mac");
+                               tls_strerror_printf(true, "Failed digesting zeroed MAC");
                                goto error;
                        }
                        p += sizeof(zero);
@@ -193,7 +313,7 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, boo
         *      Digest the rest of the packet.
         */
        if (EVP_DigestSignUpdate(md_ctx, p, end - p) != 1) {
-               tls_strerror_printf(true, "Failed digesting body");
+               tls_strerror_printf(true, "Failed digesting packet data");
                goto error;
        }
 
@@ -382,45 +502,6 @@ int fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys)
        return 0;
 }
 
-static int fr_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)
-{
-       uint8_t         *p = out, *end = p + outlen;
-       uint8_t         c = 0;
-       uint8_t         digest[SHA256_DIGEST_LENGTH];
-       HMAC_CTX        *hmac;
-
-       MEM(hmac = HMAC_CTX_new());
-       if (HMAC_Init_ex(hmac, key, key_len, EVP_sha256(), NULL) != 1) {
-       error:
-               tls_strerror_printf(true, "HMAC failure");
-               HMAC_CTX_free(hmac);
-               return -1;
-       }
-
-       while (p < end) {
-               unsigned int len = sizeof(digest);
-               size_t copy;
-
-               c++;
-
-               if (HMAC_Init_ex(hmac, NULL, 0, EVP_sha256(), NULL) != 1) goto error;
-               if ((p != out) && HMAC_Update(hmac, digest, sizeof(digest)) != 1) goto error;   /* Ingest last round */
-               if (HMAC_Update(hmac, in, in_len) != 1) goto error;                             /* Ingest s */
-               if (HMAC_Update(hmac, &c, sizeof(c)) != 1) goto error;                          /* Ingest round number */
-               if (HMAC_Final(hmac, digest, &len) != 1) goto error;                            /* Output T(i) */
-
-               copy = p - end;
-               if (copy > SHA256_DIGEST_LENGTH) copy = SHA256_DIGEST_LENGTH;
-
-               memcpy(p, digest, copy);
-               p += copy;
-       }
-       HMAC_CTX_free(hmac);
-
-       return 0;
-}
-
 /** EAP-AKA Prime CK Prime IK Prime derivation function
  *
  * @note expects keys to contain a SIM_VECTOR_UMTS.
@@ -507,6 +588,45 @@ int fr_sim_crypto_derive_ck_ik_prime(fr_sim_keys_t *keys)
        return 0;
 }
 
+static int fr_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)
+{
+       uint8_t         *p = out, *end = p + outlen;
+       uint8_t         c = 0;
+       uint8_t         digest[SHA256_DIGEST_LENGTH];
+       HMAC_CTX        *hmac;
+
+       MEM(hmac = HMAC_CTX_new());
+       if (HMAC_Init_ex(hmac, key, key_len, EVP_sha256(), NULL) != 1) {
+       error:
+               tls_strerror_printf(true, "HMAC failure");
+               HMAC_CTX_free(hmac);
+               return -1;
+       }
+
+       while (p < end) {
+               unsigned int len = sizeof(digest);
+               size_t copy;
+
+               c++;
+
+               if (HMAC_Init_ex(hmac, NULL, 0, EVP_sha256(), NULL) != 1) goto error;
+               if ((p != out) && HMAC_Update(hmac, digest, sizeof(digest)) != 1) goto error;   /* Ingest last round */
+               if (HMAC_Update(hmac, in, in_len) != 1) goto error;                             /* Ingest s */
+               if (HMAC_Update(hmac, &c, sizeof(c)) != 1) goto error;                          /* Ingest round number */
+               if (HMAC_Final(hmac, digest, &len) != 1) goto error;                            /* Output T(i) */
+
+               copy = p - end;
+               if (copy > SHA256_DIGEST_LENGTH) copy = SHA256_DIGEST_LENGTH;
+
+               memcpy(p, digest, copy);
+               p += copy;
+       }
+       HMAC_CTX_free(hmac);
+
+       return 0;
+}
+
 /** EAP-AKA Prime Key derivation function
  *
  * @note expects keys to contain a SIM_VECTOR_UMTS.
index 739418c10c833aea404978f3e9ea46307c93d566..d094729c4d23aee72d0c8eb5221ead5ed80eebf4 100644 (file)
@@ -965,13 +965,10 @@ ssize_t fr_sim_encode_pair(uint8_t *out, size_t outlen, vp_cursor_t *cursor, voi
        return ret;
 }
 
-ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t type,
-                     VALUE_PAIR *to_encode, eap_packet_t *eap_packet, fr_sim_keys_t const *keys)
+ssize_t fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx)
 {
        VALUE_PAIR              *vp;
 
-       unsigned int            id, eap_code;
-
        uint8_t                 *buff, *p, *end, *hmac = NULL;
        size_t                  len = 0;
        ssize_t                 slen;
@@ -980,35 +977,21 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
 
        unsigned char           subtype;
        vp_cursor_t             cursor;
-       fr_sim_encode_ctx_t     packet_ctx = {
-                                       .root = parent,
-                                       .keys = keys,
-                                       .iv_included = false
-                               };
+       fr_sim_encode_ctx_t     *packet_ctx = encode_ctx;
+       eap_packet_t            *eap_packet = packet_ctx->eap_packet;
 
        /*
         *      Encoded_msg is now an EAP-SIM message.
         *      It might be too big for putting into an
         *      EAP packet.
         */
-       vp = fr_pair_find_by_child_num(to_encode, parent, FR_SIM_SUBTYPE, TAG_ANY);
+       vp = fr_pair_find_by_child_num(to_encode, packet_ctx->root, FR_SIM_SUBTYPE, TAG_ANY);
        if (!vp) {
                REDEBUG("Missing subtype attribute");
                return -1;
        }
        subtype = vp->vp_uint16;
 
-       vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_CODE, TAG_ANY);
-       eap_code = vp ? vp->vp_uint32 : FR_EAP_CODE_REQUEST;
-
-       /*
-        *      Fill in some bits in the EAP packet
-        *
-        *      These are needed even if we're sending an almost empty packet.
-        */
-       if (eap_packet->code != FR_EAP_CODE_SUCCESS) eap_packet->code = eap_code;
-       eap_packet->type.num = type;
-
        /*
         *      Group attributes with similar lineages together
         */
@@ -1018,7 +1001,7 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
        /*
         *      Fast path...
         */
-       if (!next_encodable(&cursor, &packet_ctx)) {
+       if (!next_encodable(&cursor, packet_ctx)) {
                MEM(buff = talloc_array(eap_packet, uint8_t, 3));
 
                buff[0] = subtype;      /* SIM or AKA subtype */
@@ -1042,7 +1025,7 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
        /*
         *      Add space in the packet for AT_MAC
         */
-       vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_SIM_MAC, TAG_ANY);
+       vp = fr_pair_find_by_child_num(to_encode, packet_ctx->root, FR_EAP_SIM_MAC, TAG_ANY);
        if (vp) {
                if ((end - p) < SIM_MAC_SIZE) {
                        fr_strerror_printf("Insufficient space to store AT_MAC");
@@ -1065,7 +1048,7 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
         */
        (void)fr_pair_cursor_first(&cursor);
        while ((vp = fr_pair_cursor_current(&cursor))) {
-               slen = fr_sim_encode_pair(p, end - p, &cursor, &packet_ctx);
+               slen = fr_sim_encode_pair(p, end - p, &cursor, packet_ctx);
                if (slen < 0) {
                error:
                        talloc_free(buff);
@@ -1083,9 +1066,9 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
         */
        if (do_hmac) {
                slen = fr_sim_crypto_sign_packet(hmac, eap_packet, false,
-                                                keys->k_aut, keys->k_aut_len,
-                                                keys->vector_type == SIM_VECTOR_GSM ? keys->gsm.nonce_mt : NULL,
-                                                keys->vector_type == SIM_VECTOR_GSM ? sizeof(keys->gsm.nonce_mt) : 0);
+                                                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 attribute", hmac - 4, SIM_MAC_SIZE);
        }
index 8b3099e6ccded31248a84a3c507b46e489d692bd..73cc14881d125a3e88ba3f7c227e06e39ed3778c 100644 (file)
@@ -109,6 +109,23 @@ typedef struct {
        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 const    *md;                                    //!< Type of message digest, either EVP_Sha1() AKA
+                                                               ///< or EVP_Sha256() AKA'.
+       EVP_MD_CTX      *md_ctx;                                //!< Context to hold state of digest as we
+                                                               ///< consume packets.
+       uint8_t         checkcode[32];                          //!< Final digest value 20 bytes for SHA1,
+                                                               ///< 32 bytes for SHA-256
+} fr_sim_checkcode_t;
+
 /** Master key state struct for all SIMlike EAP protocols
  *
  */
@@ -154,8 +171,8 @@ typedef struct {
        /*
         *      Intermediates
         */
-       uint8_t         ck_prime[SIM_VECTOR_UMTS_CK_SIZE];
-       uint8_t         ik_prime[SIM_VECTOR_UMTS_IK_SIZE];
+       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'.
 
        /*
         *      Outputs
@@ -183,6 +200,15 @@ typedef struct {
        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;
 
 typedef struct _eap_session eap_session_t;
@@ -205,8 +231,7 @@ int         fr_sim_decode(REQUEST *request, vp_cursor_t *decoded,
  */
 ssize_t                fr_sim_encode_pair(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx);
 
-ssize_t                fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t type,
-                             VALUE_PAIR *to_encode, eap_packet_t *eap_packet, fr_sim_keys_t const *keys);
+ssize_t                fr_sim_encode(REQUEST *request, VALUE_PAIR *to_encode, void *encode_ctx);
 
 /*
  *     base.c
@@ -222,8 +247,14 @@ int                fr_sim_global_init(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[16], eap_packet_t *eap_packet, bool zero_mac,
-                                         uint8_t const *key, size_t const key_len,
+                                         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);
index face29eeec56aefaa6af42f42c937bc4fdfd1832..265e1fa00b1467203689b2456ecfefe7382a6bb8 100644 (file)
@@ -33,12 +33,13 @@ RCSIDH(rlm_eap_aka_eap_aka_h, "$Id$")
  * In server_start, we send a EAP-AKA Start message.
  */
 typedef enum {
-       EAP_AKA_SERVER_START            = 0,                    //!< Initial state.
-       EAP_AKA_SERVER_IDENTITY         = 5,                    //!< Attempting to discover permanent
+       EAP_AKA_SERVER_START = 0,                               //!< Initial state.
+       EAP_AKA_SERVER_IDENTITY,                                //!< Attempting to discover permanent
                                                                ///< identity of the supplicant.
-       EAP_AKA_SERVER_CHALLENGE        = 1,                    //!< We've challenged the supplicant.
-       EAP_AKA_SERVER_SUCCESS          = 2,                    //!< Authentication completed successfully.
-       EAP_AKA_SERVER_GENERAL_FAILURE,
+       EAP_AKA_SERVER_CHALLENGE,                               //!< We've challenged the supplicant.
+       EAP_AKA_SERVER_SUCCESS_NOTIFICATION,                    //!< Send success notification.
+       EAP_AKA_SERVER_SUCCESS,                                 //!< Authentication completed successfully.
+       EAP_AKA_SERVER_GENERAL_FAILURE_NOTIFICATION,            //!< Send failure notification.
        EAP_AKA_SERVER_MAX_STATES
 } eap_aka_server_state_t;
 
@@ -47,6 +48,11 @@ typedef struct {
                                                                ///< or previously requested.
        eap_aka_server_state_t          state;                  //!< Current session state.
        fr_sim_keys_t                   keys;                   //!< Various EAP-AKA keys.
+
+       fr_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.
+
        int                             aka_id;                 //!< Packet ID. (replay protection).
 } eap_aka_session_t;
 
index a70c08404b8ceb7177ebb4cb46fbed55e864aa24..8f4b760442bfaf46ecdd1f49410f157a6ab67384 100644 (file)
@@ -50,7 +50,7 @@ FR_NAME_NUMBER const aka_state_table[] = {
 static rlm_rcode_t mod_process(UNUSED void *arg, eap_session_t *eap_session);
 
 static CONF_PARSER submodule_config[] = {
-       { FR_CONF_OFFSET("request_identity", FR_TYPE_BOOL, rlm_eap_aka_t, request_identity ) },
+       { FR_CONF_OFFSET("request_identity", FR_TYPE_BOOL, rlm_eap_aka_t, request_identity ), .dflt = "yes" },
        { FR_CONF_OFFSET("virtual_server", FR_TYPE_STRING, rlm_eap_aka_t, virtual_server) },
        CONF_PARSER_TERMINATOR
 };
@@ -63,11 +63,24 @@ static int eap_aka_compose(eap_session_t *eap_session)
        VALUE_PAIR              *head = NULL, *vp;
        REQUEST                 *request = eap_session->request;
        ssize_t                 ret;
+       fr_sim_encode_ctx_t     encoder_ctx = {
+                                       .root = dict_aka_root,
+                                       .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 = EVP_sha1(),
+                                       .eap_packet = eap_session->this_round->request,
+                                       .hmac_extra = NULL,
+                                       .hmac_extra_len = 0
+                               };
 
        fr_pair_cursor_init(&cursor, &eap_session->request->reply->vps);
        fr_pair_cursor_init(&to_encode, &head);
 
-       while ((fr_pair_cursor_next_by_ancestor(&cursor, dict_sim_root, TAG_ANY))) {
+       while ((fr_pair_cursor_next_by_ancestor(&cursor, dict_aka_root, TAG_ANY))) {
                vp = fr_pair_cursor_remove(&cursor);
                fr_pair_cursor_append(&to_encode, vp);
        }
@@ -75,12 +88,11 @@ static int eap_aka_compose(eap_session_t *eap_session)
        RDEBUG2("Encoding EAP-AKA attributes");
        rdebug_pair_list(L_DBG_LVL_2, request, head, NULL);
 
+       eap_session->this_round->request->type.num = FR_EAP_AKA;
        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, dict_aka_root, FR_EAP_AKA,
-                           head, eap_session->this_round->request,
-                           &eap_aka_session->keys);
+       ret = fr_sim_encode(eap_session->request, head, &encoder_ctx);
        fr_pair_cursor_first(&to_encode);
        fr_pair_cursor_free(&to_encode);
 
@@ -124,6 +136,7 @@ static int eap_aka_send_identity_request(eap_session_t *eap_session)
        fr_cursor_t             cursor;
 
        RDEBUG2("Sending AKA-Identity (%s)", fr_int2str(sim_id_request_table, eap_aka_session->id_req, "<INVALID>"));
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
 
        packet = request->reply;
        fr_cursor_init(&cursor, &packet->vps);
@@ -157,6 +170,24 @@ static int eap_aka_send_identity_request(eap_session_t *eap_session)
        vp->vp_bool = true;
        fr_cursor_append(&cursor, vp);
 
+       /*
+        *      Encode the packet
+        */
+       if (eap_aka_compose(eap_session) < 0) 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, EVP_sha1()) < 0) {
+               RPEDEBUG("Failed initialising checkcode");
+               return -1;
+       }
+       if (fr_sim_crypto_update_checkcode(eap_aka_session->checkcode_state, eap_session->this_round->request) < 0) {
+               RPEDEBUG("Failed updating checkcode");
+               return -1;
+       }
+
        return 0;
 }
 
@@ -182,7 +213,7 @@ 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_client, *vp;
+       VALUE_PAIR              **to_peer, *vp;
        RADIUS_PACKET           *packet;
        fr_sim_vector_src_t     src = SIM_VECTOR_SRC_AUTO;
 
@@ -196,26 +227,34 @@ static int eap_aka_send_challenge(eap_session_t *eap_session)
        }
 
        RDEBUG2("Sending AKA-Challenge");
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
 
        /*
-        *      to_client is the data to the client
+        *      to_peer is the data to the client
         */
        packet = eap_session->request->reply;
-       to_client = &packet->vps;
+       to_peer = &packet->vps;
 
        /*
         *      Set the subtype to challenge
         */
-       vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_SUBTYPE);
+       MEM(vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_SUBTYPE));
        vp->vp_uint32 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_CHALLENGE;
-       fr_pair_replace(to_client, vp);
+       fr_pair_replace(to_peer, vp);
+
+       /*
+        *      Indicate we'd like to use protected success messages
+        */
+       MEM(vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_RESULT_IND));
+       vp->vp_bool = true;
+       fr_pair_replace(to_peer, vp);
 
        /*
         *      Okay, we got the challenge! Put it into an attribute.
         */
        MEM(vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_RAND));
        fr_pair_value_memcpy(vp, eap_aka_session->keys.umts.vector.rand, SIM_VECTOR_UMTS_RAND_SIZE);
-       fr_pair_add(to_client, vp);
+       fr_pair_replace(to_peer, vp);
 
        /*
         *      Send the AUTN value to the client, so it can authenticate
@@ -223,7 +262,41 @@ static int eap_aka_send_challenge(eap_session_t *eap_session)
         */
        MEM(vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_AUTN));
        fr_pair_value_memcpy(vp, eap_aka_session->keys.umts.vector.autn, SIM_VECTOR_UMTS_AUTN_SIZE);
-       fr_pair_add(to_client, vp);
+       fr_pair_replace(to_peer, vp);
+
+       /*
+        *      need to include an AT_MAC attribute so that it will get
+        *      calculated.
+        */
+       MEM(vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_MAC));
+       fr_pair_value_memcpy(vp, hmac_zero, sizeof(hmac_zero));
+       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");
+                       return -1;
+               }
+               eap_aka_session->checkcode_len = slen;
+
+               MEM(vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_CHECKCODE));
+               fr_pair_value_memcpy(vp, eap_aka_session->checkcode, slen);
+       /*
+        *      If we don't have checkcode data, then we exchanged
+        *      no identity packets, so checkcode is zero.
+        */
+       } else {
+               MEM(vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_CHECKCODE));
+               eap_aka_session->checkcode_len = 0;
+       }
+       fr_pair_replace(to_peer, vp);
 
        /*
         *      All set, calculate keys!
@@ -231,23 +304,42 @@ static int eap_aka_send_challenge(eap_session_t *eap_session)
        fr_sim_crypto_kdf_0_umts(&eap_aka_session->keys);
        if (RDEBUG_ENABLED3) fr_sim_crypto_keys_log(request, &eap_aka_session->keys);
 
+       return 1;
+}
+
+/** Send a success notification
+ *
+ */
+static void eap_aka_send_eap_success_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;
+
+       RDEBUG2("Sending AKA-Notification (Success)");
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
+       fr_cursor_init(&cursor, &packet->vps);
+
        /*
-        *      need to include an AT_MAC attribute so that it will get
-        *      calculated.
+        *      Set the subtype to notification
         */
-       vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_MAC);
-       fr_pair_value_memcpy(vp, hmac_zero, sizeof(hmac_zero));
-       fr_pair_replace(to_client, vp);
+       vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_SUBTYPE);
+       vp->vp_uint32 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_NOTIFICATION;
+       fr_cursor_append(&cursor, vp);
 
-       return 1;
+       vp = fr_pair_afrom_child_num(packet, dict_aka_root, FR_EAP_AKA_NOTIFICATION);
+       vp->vp_uint32 = FR_EAP_AKA_NOTIFICATION_VALUE_SUCCESS;
+       fr_cursor_append(&cursor, vp);
 }
 
-/** Send a success message
+/** 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 void eap_aka_send_success(eap_session_t *eap_session)
+static void eap_aka_send_eap_success(eap_session_t *eap_session)
 {
        REQUEST                 *request = eap_session->request;
        uint8_t                 *p;
@@ -259,7 +351,7 @@ static void eap_aka_send_success(eap_session_t *eap_session)
        eap_session->this_round->request->code = FR_EAP_CODE_SUCCESS;
        eap_session->finished = true;
 
-       /* to_client is the data to the client. */
+       /* to_peer is the data to the client. */
        packet = eap_session->request->reply;
        eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
 
@@ -269,10 +361,10 @@ static void eap_aka_send_success(eap_session_t *eap_session)
        eap_add_reply(eap_session->request, "MS-MPPE-Send-Key", p, EAP_TLS_MPPE_KEY_LEN);
 }
 
-/** Send a success message
+/** Send a failure message
  *
  */
-static void eap_aka_send_general_failure(eap_session_t *eap_session)
+static void eap_aka_send_eap_failure_notification(eap_session_t *eap_session)
 {
        REQUEST         *request = eap_session->request;
        RADIUS_PACKET   *packet = eap_session->request->reply;
@@ -280,11 +372,10 @@ static void eap_aka_send_general_failure(eap_session_t *eap_session)
        VALUE_PAIR      *vp;
 
        RDEBUG2("Sending AKA-Notification (General-Failure)");
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
 
        fr_cursor_init(&cursor, &packet->vps);
 
-       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
-
        /*
         *      Set the subtype to notification
         */
@@ -297,7 +388,7 @@ static void eap_aka_send_general_failure(eap_session_t *eap_session)
        fr_cursor_append(&cursor, vp);
 }
 
-static void eap_aka_send_failure(eap_session_t *eap_session)
+static void eap_aka_send_eap_failure(eap_session_t *eap_session)
 {
        eap_session->this_round->request->code = FR_EAP_CODE_FAILURE;
 }
@@ -327,7 +418,6 @@ static void eap_aka_state_enter(eap_session_t *eap_session,
         */
        case EAP_AKA_SERVER_IDENTITY:
                eap_aka_send_identity_request(eap_session);
-               eap_aka_compose(eap_session);
                break;
 
        /*
@@ -338,18 +428,26 @@ static void eap_aka_state_enter(eap_session_t *eap_session,
                eap_aka_compose(eap_session);
                break;
 
+       /*
+        *      Sent a protected success notification
+        */
+       case EAP_AKA_SERVER_SUCCESS_NOTIFICATION:
+               eap_aka_send_eap_success_notification(eap_session);
+               eap_aka_compose(eap_session);
+               break;
+
        /*
         *      Send the EAP Success message
         */
        case EAP_AKA_SERVER_SUCCESS:
-               eap_aka_send_success(eap_session);
+               eap_aka_send_eap_success(eap_session);
                return;
 
        /*
         *      Send a general failure notification
         */
-       case EAP_AKA_SERVER_GENERAL_FAILURE:
-               eap_aka_send_general_failure(eap_session);
+       case EAP_AKA_SERVER_GENERAL_FAILURE_NOTIFICATION:
+               eap_aka_send_eap_failure_notification(eap_session);
                eap_aka_compose(eap_session);
                return;
 
@@ -370,15 +468,27 @@ static int process_eap_aka_identity(eap_session_t *eap_session, VALUE_PAIR *vps)
        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_child_num(vps, dict_aka_root, FR_EAP_AKA_IDENTITY, TAG_ANY);
        if (id && fr_sim_id_type(&type, &method,
-                                eap_session->identity, talloc_array_length(eap_session->identity) - 1) < 0) {
+                                eap_session->identity, talloc_array_length(eap_session->identity) - 1) == 0) {
                RDEBUG2("Failed parsing identity: %s", fr_strerror());
        }
 
+       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));
+
        /*
         *      Negotiate the next permissive form
         *      if identity, or fail.
@@ -395,8 +505,9 @@ static int process_eap_aka_identity(eap_session_t *eap_session, VALUE_PAIR *vps)
                break;
 
        case SIM_PERMANENT_ID_REQ:
+               eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_CHALLENGE);
                REDEBUG2("Failed to negotiate a usable identity");
-               eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_GENERAL_FAILURE);
+//             eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_GENERAL_FAILURE_NOTIFICATION);
                break;
        }
 
@@ -414,7 +525,7 @@ static int process_eap_aka_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
 
        uint8_t                 calc_mac[SIM_MAC_HASH_SIZE];
        ssize_t                 slen;
-       VALUE_PAIR              *vp = NULL, *mac;
+       VALUE_PAIR              *vp = NULL, *mac, *checkcode;
 
        mac = fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_MAC, TAG_ANY);
        if (!mac) {
@@ -428,7 +539,7 @@ static int process_eap_aka_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
        }
 
        slen = fr_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true,
-                                        eap_aka_session->keys.k_aut, sizeof(eap_aka_session->keys.k_aut),
+                                        EVP_sha1(), eap_aka_session->keys.k_aut, sizeof(eap_aka_session->keys.k_aut),
                                         NULL, 0);
        if (slen < 0) {
                RPEDEBUG("Failed calculating MAC");
@@ -436,19 +547,48 @@ static int process_eap_aka_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
        }
 
        if (slen == 0) {
-               REDEBUG("Missing AT_MAC attribute in packet buffer");
+               REDEBUG("Missing EAP-AKA-MAC attribute in packet buffer");
                return -1;
        }
 
        if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
-               RDEBUG2("MAC check succeed");
+               RDEBUG2("EAP-AKA-MAC matches calculated MAC");
        } else {
-               REDEBUG("MAC checked failed");
+               REDEBUG("EAP-AKA-MAC does not match calculated MAC");
                RHEXDUMP_INLINE(L_DBG_LVL_2, mac->vp_octets, SIM_MAC_HASH_SIZE, "Received");
                RHEXDUMP_INLINE(L_DBG_LVL_2, calc_mac, SIM_MAC_HASH_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_child_num(vps, dict_aka_root, FR_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) {
+                       RDEBUG("EAP-AKA-Checkcode matches calculated checkcode");
+               } else {
+                       REDEBUG("EAP-AKA-Checkcode does not match calculated checkcode");
+                       RHEXDUMP_INLINE(L_DBG_LVL_2, checkcode->vp_octets, checkcode->vp_length, "Received");
+                       RHEXDUMP_INLINE(L_DBG_LVL_2, 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_child_num(vps, dict_aka_root, FR_EAP_AKA_RES, TAG_ANY);
        if (!vp) {
                REDEBUG("Missing EAP-AKA-RES from challenge response");
@@ -471,8 +611,16 @@ static int process_eap_aka_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
 
        RDEBUG2("EAP-AKA-RES matches XRES");
 
-       /* everything looks good, change states */
-       eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_SUCCESS);
+       /*
+        *      If the peer wants a Success notification, then
+        *      send a success notification, otherwise send a
+        *      normal EAP-Success.
+        */
+       if (fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_RESULT_IND, TAG_ANY)) {
+               eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_SUCCESS_NOTIFICATION);
+       } else {
+               eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_SUCCESS);
+       }
 
        return 0;
 }
@@ -540,7 +688,7 @@ static rlm_rcode_t mod_process(UNUSED void *arg, eap_session_t *eap_session)
                case EAP_AKA_SYNCHRONIZATION_FAILURE:
                        REDEBUG("EAP-AKA Peer synchronization failure");
                failure:
-                       eap_aka_send_failure(eap_session);
+                       eap_aka_send_eap_failure(eap_session);
                        return RLM_MODULE_REJECT;
 
                case EAP_AKA_AUTHENTICATION_REJECT:
@@ -566,7 +714,15 @@ static rlm_rcode_t mod_process(UNUSED void *arg, eap_session_t *eap_session)
                        return process_eap_aka_challenge(eap_session, vps) < 0 ? RLM_MODULE_FAIL : RLM_MODULE_HANDLED;
                }
 
-       case EAP_AKA_SERVER_GENERAL_FAILURE:
+       /*
+        *      RFC says we ignore the ACK from the peer
+        *      and always send a success.
+        */
+       case EAP_AKA_SERVER_SUCCESS_NOTIFICATION:
+               eap_aka_state_enter(eap_session, eap_aka_session, EAP_AKA_SERVER_SUCCESS);
+               break;
+
+       case EAP_AKA_SERVER_GENERAL_FAILURE_NOTIFICATION:
                if (subtype == EAP_AKA_NOTIFICATION) {
                        RDEBUG2("AKA-Notification ACKed, sending EAP-Failure");
                } else {
index 4ac0b6619781abcb67f6b5477b16e827464e3438..e1a61454b4837f37e1bc48533eeedc520d8b2805 100644 (file)
@@ -49,6 +49,20 @@ static int eap_sim_compose(eap_session_t *eap_session)
        vp_cursor_t             to_encode;
        VALUE_PAIR              *head = NULL, *vp;
        REQUEST                 *request = eap_session->request;
+       fr_sim_encode_ctx_t     encoder_ctx = {
+                                       .root = dict_sim_root,
+                                       .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 = eap_sim_session->keys.gsm.nonce_mt,
+                                       .hmac_extra_len = sizeof(eap_sim_session->keys.gsm.nonce_mt)
+                               };
+
        ssize_t                 ret;
 
        /* we will set the ID on requests, since we have to HMAC it */
@@ -65,9 +79,11 @@ static int eap_sim_compose(eap_session_t *eap_session)
        RDEBUG2("Encoding EAP-SIM attributes");
        rdebug_pair_list(L_DBG_LVL_2, request, head, NULL);
 
-       ret = fr_sim_encode(eap_session->request, dict_sim_root, FR_EAP_SIM,
-                           head, eap_session->this_round->request,
-                           &eap_sim_session->keys);
+       eap_session->this_round->request->type.num = FR_EAP_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_pair_cursor_first(&to_encode);
        fr_pair_cursor_free(&to_encode);
 
@@ -80,6 +96,7 @@ static int eap_sim_compose(eap_session_t *eap_session)
 
 static int eap_sim_send_state(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);
@@ -88,6 +105,9 @@ static int eap_sim_send_state(eap_session_t *eap_session)
        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;
+
        /* these are the outgoing attributes */
        packet = eap_session->request->reply;
        vps = &packet->vps;
@@ -145,18 +165,21 @@ static int eap_sim_send_challenge(eap_session_t *eap_session)
 
        REQUEST                 *request = eap_session->request;
        eap_sim_session_t       *eap_sim_session;
-       VALUE_PAIR              **from_client, **to_client, *vp;
+       VALUE_PAIR              **from_peer, **to_client, *vp;
        RADIUS_PACKET           *packet;
 
        eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
        rad_assert(eap_session->request != NULL);
        rad_assert(eap_session->request->reply);
 
+       RDEBUG2("Sending SIM-Challenge");
+       eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
+
        /*
-        *      from_client is the data from the client but this is for non-protocol data here.
+        *      from_peer is the data from the client but this is for non-protocol data here.
         *      We should already have consumed any client originated data.
         */
-       from_client = &eap_session->request->packet->vps;
+       from_peer = &eap_session->request->packet->vps;
 
        /*
         *      to_client is the data to the client
@@ -189,7 +212,7 @@ static int eap_sim_send_challenge(eap_session_t *eap_session)
        /*
         *      Use the SIM identity, if available
         */
-       vp = fr_pair_find_by_child_num(*from_client, dict_sim_root, FR_EAP_SIM_IDENTITY, TAG_ANY);
+       vp = fr_pair_find_by_child_num(*from_peer, dict_sim_root, FR_EAP_SIM_IDENTITY, TAG_ANY);
        if (vp) {
                MEM(eap_sim_session->keys.identity = (uint8_t *)talloc_bstrndup(eap_sim_session,
                                                                                vp->vp_strvalue, vp->vp_length));
@@ -238,10 +261,13 @@ static int eap_sim_send_challenge(eap_session_t *eap_session)
 static int eap_sim_send_success(eap_session_t *eap_session)
 {
        uint8_t                 *p;
+
+       REQUEST                 *request = eap_session->request;
        eap_sim_session_t       *eap_sim_session;
        VALUE_PAIR              *vp;
        RADIUS_PACKET           *packet;
 
+       RDEBUG2("Sending SIM-Success");
        eap_session->this_round->request->code = FR_EAP_CODE_SUCCESS;
        eap_session->finished = true;
 
@@ -393,7 +419,7 @@ static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
                return -1;
        }
 
-       slen = fr_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true,
+       slen = fr_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true, EVP_sha1(),
                                         eap_sim_session->keys.k_aut, sizeof(eap_sim_session->keys.k_aut),
                                         NULL, 0);
        if (slen < 0) {
@@ -402,14 +428,14 @@ static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
        }
 
        if (slen == 0) {
-               REDEBUG("Missing AT_MAC attribute in packet buffer");
+               REDEBUG("Missing EAP-SIM-MAC attribute in packet buffer");
                return -1;
        }
 
        if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
-               RDEBUG2("MAC check succeed");
+               RDEBUG2("EAP-SIM-MAC matches calculated MAC");
        } else {
-               REDEBUG("MAC checked failed");
+               REDEBUG("EAP-SIM-MAC does not match calculated MAC");
                RHEXDUMP_INLINE(L_DBG_LVL_2, mac->vp_octets, SIM_MAC_SIZE, "Received");
                RHEXDUMP_INLINE(L_DBG_LVL_2, calc_mac, SIM_MAC_SIZE, "Expected");
                return -1;