1 /* mppe.c - MPPE key implementation
2  *
3  * Copyright (c) 2020 Eivind Naess. All rights reserved.
4  * Copyright (c) 2008-2024 Paul Mackerras. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. The name(s) of the authors of this software must not be used to
19  *    endorse or promote products derived from this software without
20  *    prior written permission.
21  *
22  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include <string.h>
36 
37 
38 #include "pppd-private.h"
39 #include "fsm.h"
40 #include "ccp.h"
41 #include "chap_ms.h"
42 #include "mppe.h"
43 #include "crypto.h"
44 
45 u_char mppe_send_key[MPPE_MAX_KEY_SIZE];
46 u_char mppe_recv_key[MPPE_MAX_KEY_SIZE];
47 int mppe_keys_set = 0;
48 
49 void
mppe_set_keys(u_char * send_key,u_char * recv_key,int keylen)50 mppe_set_keys(u_char *send_key, u_char *recv_key, int keylen)
51 {
52           int length = keylen;
53           if (length > MPPE_MAX_KEY_SIZE)
54                     length = MPPE_MAX_KEY_SIZE;
55 
56           if (send_key) {
57               BCOPY(send_key, mppe_send_key, length);
58               BZERO(send_key, keylen);
59           }
60 
61           if (recv_key) {
62               BCOPY(recv_key, mppe_recv_key, length);
63               BZERO(recv_key, keylen);
64           }
65 
66           mppe_keys_set = length;
67 }
68 
69 bool
mppe_keys_isset()70 mppe_keys_isset()
71 {
72           return !!mppe_keys_set;
73 }
74 
75 int
mppe_get_recv_key(u_char * recv_key,int length)76 mppe_get_recv_key(u_char *recv_key, int length)
77 {
78           if (mppe_keys_isset()) {
79                     if (length > mppe_keys_set)
80                               length = mppe_keys_set;
81                     BCOPY(mppe_recv_key, recv_key, length);
82                     return length;
83           }
84           return 0;
85 }
86 
87 int
mppe_get_send_key(u_char * send_key,int length)88 mppe_get_send_key(u_char *send_key, int length)
89 {
90           if (mppe_keys_isset()) {
91                     if (length > mppe_keys_set)
92                               length = mppe_keys_set;
93                     BCOPY(mppe_send_key, send_key, length);
94                     return length;
95           }
96           return 0;
97 }
98 
99 void
mppe_clear_keys(void)100 mppe_clear_keys(void)
101 {
102           mppe_keys_set = 0;
103           BZERO(mppe_send_key, sizeof(mppe_send_key));
104           BZERO(mppe_recv_key, sizeof(mppe_recv_key));
105 }
106 
107 /*
108  * Set mppe_xxxx_key from the NTPasswordHashHash.
109  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
110  */
111 void
mppe_set_chapv1(unsigned char * rchallenge,unsigned char * PasswordHashHash)112 mppe_set_chapv1(unsigned char *rchallenge, unsigned char *PasswordHashHash)
113 {
114     PPP_MD_CTX *ctx;
115     u_char Digest[SHA_DIGEST_LENGTH];
116     unsigned int DigestLen;
117 
118     ctx = PPP_MD_CTX_new();
119     if (ctx != NULL) {
120 
121         if (PPP_DigestInit(ctx, PPP_sha1())) {
122 
123             if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
124 
125                 if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
126 
127                     if (PPP_DigestUpdate(ctx, rchallenge, 8)) {
128 
129                         DigestLen = SHA_DIGEST_LENGTH;
130                         PPP_DigestFinal(ctx, Digest, &DigestLen);
131                     }
132                 }
133             }
134         }
135 
136         PPP_MD_CTX_free(ctx);
137     }
138 
139 
140     /* Same key in both directions. */
141     mppe_set_keys(Digest, Digest, sizeof(Digest));
142 }
143 
144 /*
145  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
146  *
147  * This helper function used in the Winbind module, which gets the
148  * NTHashHash from the server.
149  */
150 void
mppe_set_chapv2(unsigned char * PasswordHashHash,unsigned char * NTResponse,int IsServer)151 mppe_set_chapv2(unsigned char *PasswordHashHash, unsigned char *NTResponse,
152         int IsServer)
153 {
154     PPP_MD_CTX *ctx;
155 
156     u_char          MasterKey[SHA_DIGEST_LENGTH];
157     u_char          SendKey[SHA_DIGEST_LENGTH];
158     u_char          RecvKey[SHA_DIGEST_LENGTH];
159     unsigned int KeyLen;
160 
161     u_char SHApad1[40] =
162           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
166     u_char SHApad2[40] =
167           { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
168             0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
169             0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
170             0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
171 
172     /* "This is the MPPE Master Key" */
173     u_char Magic1[27] =
174           { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
175             0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
176             0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
177     /* "On the client side, this is the send key; "
178        "on the server side, it is the receive key." */
179     u_char Magic2[84] =
180           { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
181             0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
182             0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
183             0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
184             0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
185             0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
186             0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
187             0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
188             0x6b, 0x65, 0x79, 0x2e };
189     /* "On the client side, this is the receive key; "
190        "on the server side, it is the send key." */
191     u_char Magic3[84] =
192           { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
193             0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
194             0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
195             0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
196             0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
197             0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
198             0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
199             0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
200             0x6b, 0x65, 0x79, 0x2e };
201     u_char *s;
202 
203     ctx = PPP_MD_CTX_new();
204     if (ctx != NULL) {
205 
206         if (PPP_DigestInit(ctx, PPP_sha1())) {
207 
208             if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
209 
210                 if (PPP_DigestUpdate(ctx, NTResponse, 24)) {
211 
212                     if (PPP_DigestUpdate(ctx, Magic1, sizeof(Magic1))) {
213 
214                         KeyLen = SHA_DIGEST_LENGTH;
215                         PPP_DigestFinal(ctx, MasterKey, &KeyLen);
216                     }
217                 }
218             }
219         }
220 
221         PPP_MD_CTX_free(ctx);
222     }
223 
224     /*
225      * generate send key
226      */
227     if (IsServer)
228           s = Magic3;
229     else
230           s = Magic2;
231 
232     ctx = PPP_MD_CTX_new();
233     if (ctx != NULL) {
234 
235         if (PPP_DigestInit(ctx, PPP_sha1())) {
236 
237             if (PPP_DigestUpdate(ctx, MasterKey, 16)) {
238 
239                 if (PPP_DigestUpdate(ctx, SHApad1, sizeof(SHApad1))) {
240 
241                     if (PPP_DigestUpdate(ctx, s, 84)) {
242 
243                         if (PPP_DigestUpdate(ctx, SHApad2, sizeof(SHApad2))) {
244 
245                             KeyLen = SHA_DIGEST_LENGTH;
246                             PPP_DigestFinal(ctx, SendKey, &KeyLen);
247                         }
248                     }
249                 }
250             }
251         }
252 
253         PPP_MD_CTX_free(ctx);
254     }
255 
256 
257     /*
258      * generate recv key
259      */
260     if (IsServer)
261           s = Magic2;
262     else
263           s = Magic3;
264 
265     ctx = PPP_MD_CTX_new();
266     if (ctx != NULL) {
267 
268         if (PPP_DigestInit(ctx, PPP_sha1())) {
269 
270             if (PPP_DigestUpdate(ctx, MasterKey, 16)) {
271 
272                 if (PPP_DigestUpdate(ctx, SHApad1, sizeof(SHApad1))) {
273 
274                     if (PPP_DigestUpdate(ctx, s, 84)) {
275 
276                         if (PPP_DigestUpdate(ctx, SHApad2, sizeof(SHApad2))) {
277 
278                             KeyLen = SHA_DIGEST_LENGTH;
279                             PPP_DigestFinal(ctx, RecvKey, &KeyLen);
280                         }
281                     }
282                 }
283             }
284         }
285 
286         PPP_MD_CTX_free(ctx);
287     }
288 
289     mppe_set_keys(SendKey, RecvKey, SHA_DIGEST_LENGTH);
290 }
291 
292 #ifndef UNIT_TEST
293 
294 /*
295  * Set MPPE options from plugins.
296  */
297 void
mppe_set_enc_types(int policy,int types)298 mppe_set_enc_types(int policy, int types)
299 {
300     /* Early exit for unknown policies. */
301     if (policy != MPPE_ENC_POL_ENC_ALLOWED &&
302           policy != MPPE_ENC_POL_ENC_REQUIRED)
303           return;
304 
305     /* Don't modify MPPE if it's optional and wasn't already configured. */
306     if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
307           return;
308 
309     /*
310      * Disable undesirable encryption types.  Note that we don't ENABLE
311      * any encryption types, to avoid overriding manual configuration.
312      */
313     switch(types) {
314           case MPPE_ENC_TYPES_RC4_40:
315               ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;     /* disable 128-bit */
316               break;
317           case MPPE_ENC_TYPES_RC4_128:
318               ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;      /* disable 40-bit */
319               break;
320           default:
321               break;
322     }
323 }
324 
325 #endif
326