--- /dev/null
+/* * mppe.c - MPPE key implementation
+ *
+ * Copyright (c) 2020 Eivind Naess. All rights reserved.
+ * Copyright (c) 2008 Paul Mackerras. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <string.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "md4.h"
+#include "sha1.h"
+#include "ccp.h"
+#include "chap_ms.h"
+#include "mppe.h"
+
+u_char mppe_send_key[MPPE_MAX_KEY_SIZE];
+u_char mppe_recv_key[MPPE_MAX_KEY_SIZE];
+int mppe_keys_set = 0;
+
+void
+mppe_set_keys(u_char *send_key, u_char *recv_key, int keylen)
+{
+ int length = keylen;
+ if (length > MPPE_MAX_KEY_SIZE)
+ length = MPPE_MAX_KEY_SIZE;
+
+ if (send_key) {
+ BCOPY(send_key, mppe_send_key, length);
+ BZERO(send_key, keylen);
+ }
+
+ if (recv_key) {
+ BCOPY(recv_key, mppe_recv_key, length);
+ BZERO(recv_key, keylen);
+ }
+
+ mppe_keys_set = length;
+}
+
+bool
+mppe_keys_isset()
+{
+ return !!mppe_keys_set;
+}
+
+int
+mppe_get_recv_key(u_char *recv_key, int length)
+{
+ if (mppe_keys_isset()) {
+ if (length > mppe_keys_set)
+ length = mppe_keys_set;
+ BCOPY(mppe_recv_key, recv_key, length);
+ return length;
+ }
+ return 0;
+}
+
+int
+mppe_get_send_key(u_char *send_key, int length)
+{
+ if (mppe_keys_isset()) {
+ if (length > mppe_keys_set)
+ length = mppe_keys_set;
+ BCOPY(mppe_send_key, send_key, length);
+ return length;
+ }
+ return 0;
+}
+
+void
+mppe_clear_keys(void)
+{
+ mppe_keys_set = 0;
+ BZERO(mppe_send_key, sizeof(mppe_send_key));
+ BZERO(mppe_recv_key, sizeof(mppe_recv_key));
+}
+
+/*
+ * Set mppe_xxxx_key from the NTPasswordHashHash.
+ * RFC 2548 (RADIUS support) requires us to export this function (ugh).
+ */
+void
+mppe_set_chapv1(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
+{
+ SHA1_CTX sha1Context;
+ u_char Digest[SHA1_SIGNATURE_SIZE];
+
+ SHA1_Init(&sha1Context);
+ SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
+ SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
+ SHA1_Update(&sha1Context, rchallenge, 8);
+ SHA1_Final(Digest, &sha1Context);
+
+ /* Same key in both directions. */
+ mppe_set_keys(Digest, Digest, sizeof(Digest));
+}
+
+/*
+ * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
+ *
+ * This helper function used in the Winbind module, which gets the
+ * NTHashHash from the server.
+ */
+void
+mppe_set_chapv2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
+ u_char NTResponse[MS_AUTH_NTRESP_LEN], int IsServer)
+{
+ SHA1_CTX sha1Context;
+ u_char MasterKey[SHA1_SIGNATURE_SIZE];
+ u_char SendKey[SHA1_SIGNATURE_SIZE];
+ u_char RecvKey[SHA1_SIGNATURE_SIZE];
+
+ u_char SHApad1[40] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ u_char SHApad2[40] =
+ { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
+
+ /* "This is the MPPE Master Key" */
+ u_char Magic1[27] =
+ { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+ 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
+ /* "On the client side, this is the send key; "
+ "on the server side, it is the receive key." */
+ u_char Magic2[84] =
+ { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+ 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e };
+ /* "On the client side, this is the receive key; "
+ "on the server side, it is the send key." */
+ u_char Magic3[84] =
+ { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+ 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e };
+ u_char *s;
+
+ SHA1_Init(&sha1Context);
+ SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
+ SHA1_Update(&sha1Context, NTResponse, 24);
+ SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
+ SHA1_Final(MasterKey, &sha1Context);
+
+ /*
+ * generate send key
+ */
+ if (IsServer)
+ s = Magic3;
+ else
+ s = Magic2;
+ SHA1_Init(&sha1Context);
+ SHA1_Update(&sha1Context, MasterKey, 16);
+ SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
+ SHA1_Update(&sha1Context, s, 84);
+ SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
+ SHA1_Final(SendKey, &sha1Context);
+
+ /*
+ * generate recv key
+ */
+ if (IsServer)
+ s = Magic2;
+ else
+ s = Magic3;
+ SHA1_Init(&sha1Context);
+ SHA1_Update(&sha1Context, MasterKey, 16);
+ SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
+ SHA1_Update(&sha1Context, s, 84);
+ SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
+ SHA1_Final(RecvKey, &sha1Context);
+
+ mppe_set_keys(SendKey, RecvKey, SHA1_SIGNATURE_SIZE);
+}
+
+/*
+ * Set MPPE options from plugins.
+ */
+void
+mppe_set_enc_types(int policy, int types)
+{
+ /* Early exit for unknown policies. */
+ if (policy != MPPE_ENC_POL_ENC_ALLOWED &&
+ policy != MPPE_ENC_POL_ENC_REQUIRED)
+ return;
+
+ /* Don't modify MPPE if it's optional and wasn't already configured. */
+ if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
+ return;
+
+ /*
+ * Disable undesirable encryption types. Note that we don't ENABLE
+ * any encryption types, to avoid overriding manual configuration.
+ */
+ switch(types) {
+ case MPPE_ENC_TYPES_RC4_40:
+ ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
+ break;
+ case MPPE_ENC_TYPES_RC4_128:
+ ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
+ break;
+ default:
+ break;
+ }
+}
+