Computing MS-MPPE-Recv-Key and MS-MPPE-Send-Key in MS-CHAPv2 auth
Hello there, I'm trying to figure out how MS-MPPE-Send-Key and MS-MPPE-Recv-Key are getting generated by freeradius-server. Here, it is the sample captured traffic I've for a MS-CHAPv2 (Access-Accept) auth between a radius client and server: MS-MPPE-Recv-Key: a660ce53f31ef08ed6cf209ece137a1dee40aeae5d8e5b9de0f1592324bc92569fc1 MS-MPPE-Send-Key: a81579eb58f0bd25636599778c8689516129db8b25ec2d1e4c15797862efedabb3c So, the first thing I noticed here is that the length of the values for both AVPs are 34 bytes. I read rfc2548 and rfc3079 for this matter and then tried to find corresponding implementations in the code-base (src/modules/rlm_mschap/rlm_mschap.c), and found "mppe_chap2_gen_keys128" function. The function is being called by "mod_authenticate_resume" : /* now create MPPE attributes */ if (inst->use_mppe) { fr_pair_t *vp; uint8_t mppe_sendkey[34]; uint8_t mppe_recvkey[34]; switch (mschap_version) { case 1: RDEBUG2("Generating MS-CHAPv1 MPPE keys"); memset(mppe_sendkey, 0, 32); /* * According to RFC 2548 we * should send NT hash. But in * practice it doesn't work. * Instead, we should send nthashhash * * This is an error in RFC 2548. */ /* * do_mschap cares to zero nthashhash if NT hash * is not available. */ memcpy(mppe_sendkey + 8, nthashhash, NT_DIGEST_LENGTH); mppe_add_reply(inst, request, tmpl_attr_tail_da(env_data->chap_mppe_keys), mppe_sendkey, 24); //-V666 break; case 2: RDEBUG2("Generating MS-CHAPv2 MPPE keys"); mppe_chap2_gen_keys128(nthashhash, response->vp_octets + 26, mppe_sendkey, mppe_recvkey); mppe_add_reply(inst, request, tmpl_attr_tail_da(env_data->mppe_recv_key), mppe_recvkey, 16); mppe_add_reply(inst, request, tmpl_attr_tail_da(env_data->mppe_send_key), mppe_sendkey, 16); break; default: fr_assert(0); break; } MEM(pair_update_reply(&vp, tmpl_attr_tail_da(env_data->mppe_encryption_policy)) >= 0); vp->vp_uint32 = inst->require_encryption ? 2 : 1; MEM(pair_update_reply(&vp, tmpl_attr_tail_da(env_data->mppe_encryption_types)) >= 0); vp->vp_uint32 = inst->require_strong ? 4 : 6; } /* else we weren't asked to use MPPE */ Correct me if I'm wrong but here I read " mppe_sendkey" and " mppe_recvkey" variables are initialized with 34 bytes (as i expected!), but later by calling mppe_chap2_gen_keys128 only 16 bytes are copied. I was expecting other items (such as 'Salt') to be taken into account too .. Thanks.
On Jan 5, 2025, at 2:37 PM, Hadi Rezaee <rezaee.hadi@gmail.com> wrote:
I'm trying to figure out how MS-MPPE-Send-Key and MS-MPPE-Recv-Key are getting generated by freeradius-server.
The short answer is "read the RFCs and the code"
Here, it is the sample captured traffic I've for a MS-CHAPv2 (Access-Accept) auth between a radius client and server: MS-MPPE-Recv-Key: a660ce53f31ef08ed6cf209ece137a1dee40aeae5d8e5b9de0f1592324bc92569fc1 MS-MPPE-Send-Key: a81579eb58f0bd25636599778c8689516129db8b25ec2d1e4c15797862efedabb3c
Those are just random values. They don't mean anything.
Correct me if I'm wrong but here I read " mppe_sendkey" and " mppe_recvkey" variables are initialized with 34 bytes (as i expected!), but later by calling mppe_chap2_gen_keys128 only 16 bytes are copied. I was expecting other items (such as 'Salt') to be taken into account too ..
To be honest, I haven't looked at that code in a long time. If it's generating 34-byte keys, then it works. Which means that your reading of the code is wrong. If you want to know what the code is doing, use a debugger like gdb to step through it. Alan DeKok.
Hello Alan and thanks for your response. You're absolutely right, I need to go back for more research and code review :) Regards, Hadi On Mon, Jan 6, 2025 at 5:34 PM Alan DeKok <aland@deployingradius.com> wrote:
On Jan 5, 2025, at 2:37 PM, Hadi Rezaee <rezaee.hadi@gmail.com> wrote:
I'm trying to figure out how MS-MPPE-Send-Key and MS-MPPE-Recv-Key are getting generated by freeradius-server.
The short answer is "read the RFCs and the code"
Here, it is the sample captured traffic I've for a MS-CHAPv2 (Access-Accept) auth between a radius client and server: MS-MPPE-Recv-Key: a660ce53f31ef08ed6cf209ece137a1dee40aeae5d8e5b9de0f1592324bc92569fc1 MS-MPPE-Send-Key: a81579eb58f0bd25636599778c8689516129db8b25ec2d1e4c15797862efedabb3c
Those are just random values. They don't mean anything.
Correct me if I'm wrong but here I read " mppe_sendkey" and " mppe_recvkey" variables are initialized with 34 bytes (as i expected!), but later by calling mppe_chap2_gen_keys128 only 16 bytes are copied. I was expecting other items (such as 'Salt') to be taken into account too ..
To be honest, I haven't looked at that code in a long time. If it's generating 34-byte keys, then it works. Which means that your reading of the code is wrong.
If you want to know what the code is doing, use a debugger like gdb to step through it.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
Hi Hadi! Feel free to drop me an email directly if you get really stuck (I've no experience with MS-CHAP, but I can just about make sense of RFCs), but in regards to mppe_add_reply - MS-CHAPv2 uses 128 bit send/receive session keys (16 bytes). When calling mppe_add_reply, Alan is adding a keypair to the VP list that is 16 bytes long for each. See this [https://datatracker.ietf.org/doc/html/draft-ietf-pppext-mschapv2-keys] IETF Draft from 1998 for session key reference, and RFC 2759 [https://datatracker.ietf.org/doc/html/rfc2759] for more info about the whole MS-CHAPv2 auth process. Cheers! Jacob [bitNew2.png] On 06/01/2025 14:54:07, Hadi Rezaee <rezaee.hadi@gmail.com> wrote: Hello Alan and thanks for your response. You're absolutely right, I need to go back for more research and code review :) Regards, Hadi On Mon, Jan 6, 2025 at 5:34 PM Alan DeKok wrote:
On Jan 5, 2025, at 2:37 PM, Hadi Rezaee wrote:
I'm trying to figure out how MS-MPPE-Send-Key and MS-MPPE-Recv-Key are getting generated by freeradius-server.
The short answer is "read the RFCs and the code"
Here, it is the sample captured traffic I've for a MS-CHAPv2 (Access-Accept) auth between a radius client and server: MS-MPPE-Recv-Key: a660ce53f31ef08ed6cf209ece137a1dee40aeae5d8e5b9de0f1592324bc92569fc1 MS-MPPE-Send-Key: a81579eb58f0bd25636599778c8689516129db8b25ec2d1e4c15797862efedabb3c
Those are just random values. They don't mean anything.
Correct me if I'm wrong but here I read " mppe_sendkey" and " mppe_recvkey" variables are initialized with 34 bytes (as i expected!), but later by calling mppe_chap2_gen_keys128 only 16 bytes are copied. I was expecting other items (such as 'Salt') to be taken into account too ..
To be honest, I haven't looked at that code in a long time. If it's generating 34-byte keys, then it works. Which means that your reading of the code is wrong.
If you want to know what the code is doing, use a debugger like gdb to step through it.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
Hello Jacob, Thanks for your kind reply, your hints helped me a lot. Finally I've found the missing piece (encrypting the generated mppe keys based on rfc2548) in the code-base. There was a good comment for "mppe_chap2_gen_keys128" function (src/modules/rlm_mschap/rlm_mschap.c) that I didn't paid attention to, which says: /* * dictionary.microsoft defines these attributes as * 'encrypt=Tunnel-Password'. The functions in src/lib/radius.c will * take care of encrypting/decrypting them as appropriate, * so that we don't have to. */ So, just like you said after the mppe send/recv keys (16 bytes) generated, "encode_tunnel_password" function (src/protocols/radius/encode.c) then encrypt them based on (rfc2548 section 2.4.2 and 2.4.3). Thanks again to you and Alan for guidance, I appreciate it. Regards, Hadi On Tue, Jan 7, 2025 at 7:04 AM Jacob Lane <admin@bitcomputing.io> wrote:
Hi Hadi! Feel free to drop me an email directly if you get really stuck (I've no experience with MS-CHAP, but I can just about make sense of RFCs), but in regards to mppe_add_reply - MS-CHAPv2 uses 128 bit send/receive session keys (16 bytes). When calling mppe_add_reply, Alan is adding a keypair to the VP list that is 16 bytes long for each. See this [ https://datatracker.ietf.org/doc/html/draft-ietf-pppext-mschapv2-keys] IETF Draft from 1998 for session key reference, and RFC 2759 [ https://datatracker.ietf.org/doc/html/rfc2759] for more info about the whole MS-CHAPv2 auth process.
Cheers!
Jacob [bitNew2.png] On 06/01/2025 14:54:07, Hadi Rezaee <rezaee.hadi@gmail.com> wrote: Hello Alan and thanks for your response. You're absolutely right, I need to go back for more research and code review :)
Regards, Hadi
On Mon, Jan 6, 2025 at 5:34 PM Alan DeKok wrote:
On Jan 5, 2025, at 2:37 PM, Hadi Rezaee wrote:
I'm trying to figure out how MS-MPPE-Send-Key and MS-MPPE-Recv-Key are getting generated by freeradius-server.
The short answer is "read the RFCs and the code"
Here, it is the sample captured traffic I've for a MS-CHAPv2 (Access-Accept) auth between a radius client and server: MS-MPPE-Recv-Key: a660ce53f31ef08ed6cf209ece137a1dee40aeae5d8e5b9de0f1592324bc92569fc1 MS-MPPE-Send-Key: a81579eb58f0bd25636599778c8689516129db8b25ec2d1e4c15797862efedabb3c
Those are just random values. They don't mean anything.
Correct me if I'm wrong but here I read " mppe_sendkey" and " mppe_recvkey" variables are initialized with 34 bytes (as i expected!), but later by calling mppe_chap2_gen_keys128 only 16 bytes are copied. I was expecting other items (such as 'Salt') to be taken into account too ..
To be honest, I haven't looked at that code in a long time. If it's generating 34-byte keys, then it works. Which means that your reading of the code is wrong.
If you want to know what the code is doing, use a debugger like gdb to step through it.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
Hi Hadi! No worries at all! Really glad you were able to find what you were looking for - if you want to make life much easier for yourself, I would highly recommend generating the Doxygen documentation included with the source. It makes hunting down functions and structure definitions infinitely easier!! Cheers and all the very best, Jacob [bitNew2.png] On 07/01/2025 19:55:37, Hadi Rezaee <rezaee.hadi@gmail.com> wrote: Hello Jacob, Thanks for your kind reply, your hints helped me a lot. Finally I've found the missing piece (encrypting the generated mppe keys based on rfc2548) in the code-base. There was a good comment for "mppe_chap2_gen_keys128" function (src/modules/rlm_mschap/rlm_mschap.c) that I didn't paid attention to, which says: /* * dictionary.microsoft defines these attributes as * 'encrypt=Tunnel-Password'. The functions in src/lib/radius.c will * take care of encrypting/decrypting them as appropriate, * so that we don't have to. */ So, just like you said after the mppe send/recv keys (16 bytes) generated, "encode_tunnel_password" function (src/protocols/radius/encode.c) then encrypt them based on (rfc2548 section 2.4.2 and 2.4.3). Thanks again to you and Alan for guidance, I appreciate it. Regards, Hadi On Tue, Jan 7, 2025 at 7:04 AM Jacob Lane wrote:
Hi Hadi! Feel free to drop me an email directly if you get really stuck (I've no experience with MS-CHAP, but I can just about make sense of RFCs), but in regards to mppe_add_reply - MS-CHAPv2 uses 128 bit send/receive session keys (16 bytes). When calling mppe_add_reply, Alan is adding a keypair to the VP list that is 16 bytes long for each. See this [ https://datatracker.ietf.org/doc/html/draft-ietf-pppext-mschapv2-keys] IETF Draft from 1998 for session key reference, and RFC 2759 [ https://datatracker.ietf.org/doc/html/rfc2759] for more info about the whole MS-CHAPv2 auth process.
Cheers!
Jacob [bitNew2.png] On 06/01/2025 14:54:07, Hadi Rezaee wrote: Hello Alan and thanks for your response. You're absolutely right, I need to go back for more research and code review :)
Regards, Hadi
On Mon, Jan 6, 2025 at 5:34 PM Alan DeKok wrote:
On Jan 5, 2025, at 2:37 PM, Hadi Rezaee wrote:
I'm trying to figure out how MS-MPPE-Send-Key and MS-MPPE-Recv-Key are getting generated by freeradius-server.
The short answer is "read the RFCs and the code"
Here, it is the sample captured traffic I've for a MS-CHAPv2 (Access-Accept) auth between a radius client and server: MS-MPPE-Recv-Key: a660ce53f31ef08ed6cf209ece137a1dee40aeae5d8e5b9de0f1592324bc92569fc1 MS-MPPE-Send-Key: a81579eb58f0bd25636599778c8689516129db8b25ec2d1e4c15797862efedabb3c
Those are just random values. They don't mean anything.
Correct me if I'm wrong but here I read " mppe_sendkey" and " mppe_recvkey" variables are initialized with 34 bytes (as i expected!), but later by calling mppe_chap2_gen_keys128 only 16 bytes are copied. I was expecting other items (such as 'Salt') to be taken into account too ..
To be honest, I haven't looked at that code in a long time. If it's generating 34-byte keys, then it works. Which means that your reading of the code is wrong.
If you want to know what the code is doing, use a debugger like gdb to step through it.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
participants (3)
-
Alan DeKok -
Hadi Rezaee -
Jacob Lane