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