1 /* mppe.c - MPPE key implementation
3 * Copyright (c) 2020 Eivind Naess. All rights reserved.
4 * Copyright (c) 2008 Paul Mackerras. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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
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.
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.
38 #include "pppd-private.h"
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;
50 mppe_set_keys(u_char *send_key, u_char *recv_key, int keylen)
53 if (length > MPPE_MAX_KEY_SIZE)
54 length = MPPE_MAX_KEY_SIZE;
57 BCOPY(send_key, mppe_send_key, length);
58 BZERO(send_key, keylen);
62 BCOPY(recv_key, mppe_recv_key, length);
63 BZERO(recv_key, keylen);
66 mppe_keys_set = length;
72 return !!mppe_keys_set;
76 mppe_get_recv_key(u_char *recv_key, int length)
78 if (mppe_keys_isset()) {
79 if (length > mppe_keys_set)
80 length = mppe_keys_set;
81 BCOPY(mppe_recv_key, recv_key, length);
88 mppe_get_send_key(u_char *send_key, int length)
90 if (mppe_keys_isset()) {
91 if (length > mppe_keys_set)
92 length = mppe_keys_set;
93 BCOPY(mppe_send_key, send_key, length);
100 mppe_clear_keys(void)
103 BZERO(mppe_send_key, sizeof(mppe_send_key));
104 BZERO(mppe_recv_key, sizeof(mppe_recv_key));
108 * Set mppe_xxxx_key from the NTPasswordHashHash.
109 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
112 mppe_set_chapv1(unsigned char *rchallenge, unsigned char *PasswordHashHash)
115 u_char Digest[SHA_DIGEST_LENGTH];
118 ctx = PPP_MD_CTX_new();
121 if (PPP_DigestInit(ctx, PPP_sha1())) {
123 if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
125 if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
127 if (PPP_DigestUpdate(ctx, rchallenge, 8)) {
129 DigestLen = SHA_DIGEST_LENGTH;
130 PPP_DigestFinal(ctx, Digest, &DigestLen);
136 PPP_MD_CTX_free(ctx);
140 /* Same key in both directions. */
141 mppe_set_keys(Digest, Digest, sizeof(Digest));
145 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
147 * This helper function used in the Winbind module, which gets the
148 * NTHashHash from the server.
151 mppe_set_chapv2(unsigned char *PasswordHashHash, unsigned char *NTResponse,
156 u_char MasterKey[SHA_DIGEST_LENGTH];
157 u_char SendKey[SHA_DIGEST_LENGTH];
158 u_char RecvKey[SHA_DIGEST_LENGTH];
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 };
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 };
172 /* "This is the MPPE Master Key" */
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." */
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." */
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 };
203 ctx = PPP_MD_CTX_new();
206 if (PPP_DigestInit(ctx, PPP_sha1())) {
208 if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
210 if (PPP_DigestUpdate(ctx, NTResponse, 24)) {
212 if (PPP_DigestUpdate(ctx, Magic1, sizeof(Magic1))) {
214 KeyLen = SHA_DIGEST_LENGTH;
215 PPP_DigestFinal(ctx, MasterKey, &KeyLen);
221 PPP_MD_CTX_free(ctx);
232 ctx = PPP_MD_CTX_new();
235 if (PPP_DigestInit(ctx, PPP_sha1())) {
237 if (PPP_DigestUpdate(ctx, MasterKey, 16)) {
239 if (PPP_DigestUpdate(ctx, SHApad1, sizeof(SHApad1))) {
241 if (PPP_DigestUpdate(ctx, s, 84)) {
243 if (PPP_DigestUpdate(ctx, SHApad2, sizeof(SHApad2))) {
245 KeyLen = SHA_DIGEST_LENGTH;
246 PPP_DigestFinal(ctx, SendKey, &KeyLen);
253 PPP_MD_CTX_free(ctx);
265 ctx = PPP_MD_CTX_new();
268 if (PPP_DigestInit(ctx, PPP_sha1())) {
270 if (PPP_DigestUpdate(ctx, MasterKey, 16)) {
272 if (PPP_DigestUpdate(ctx, SHApad1, sizeof(SHApad1))) {
274 if (PPP_DigestUpdate(ctx, s, 84)) {
276 if (PPP_DigestUpdate(ctx, SHApad2, sizeof(SHApad2))) {
278 KeyLen = SHA_DIGEST_LENGTH;
279 PPP_DigestFinal(ctx, RecvKey, &KeyLen);
286 PPP_MD_CTX_free(ctx);
289 mppe_set_keys(SendKey, RecvKey, SHA_DIGEST_LENGTH);
295 * Set MPPE options from plugins.
298 mppe_set_enc_types(int policy, int types)
300 /* Early exit for unknown policies. */
301 if (policy != MPPE_ENC_POL_ENC_ALLOWED &&
302 policy != MPPE_ENC_POL_ENC_REQUIRED)
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)
310 * Disable undesirable encryption types. Note that we don't ENABLE
311 * any encryption types, to avoid overriding manual configuration.
314 case MPPE_ENC_TYPES_RC4_40:
315 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
317 case MPPE_ENC_TYPES_RC4_128:
318 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */