]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/mppe.c
pppd: Expose the MPPE keys generated through an API (#267)
[ppp.git] / pppd / mppe.c
diff --git a/pppd/mppe.c b/pppd/mppe.c
new file mode 100644 (file)
index 0000000..4f3d131
--- /dev/null
@@ -0,0 +1,248 @@
+/* * 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;
+    }
+}
+