From 8c079e9264451529856e83f483c9c00e33e98149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zaj=C4=85czkowski?= <148013+szpak@users.noreply.github.com> Date: Tue, 5 Apr 2022 23:45:18 +0200 Subject: [PATCH] Backport patches from master for SSTP and EAP-TLS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With those changes will allow pppd to connect to an Azure VnetGWay using SSTP (or using EAP-TLS to a Windows RAS server). Backport to Fedora endorsed by Eivind Næss, their author and the author of sstp-client and network-manager-sstp. Links to git commits used to generate patches: https://github.com/ppp-project/ppp/commit/e609ed8bb62e4648568eaa49fbbc858dfda6d122 https://github.com/ppp-project/ppp/commit/d706c95906d996534f13632a747af5dc617f306e https://github.com/ppp-project/ppp/commit/d7e62a8499c4032d79e05afbd8fd3efd51c5b148 (the first one is only needed to make the second apply in the original form from Git - those changed lines are removed anyway) --- ...MPPE-keys-generated-through-an-API-2.patch | 898 ++++++++++++++++++ ...-error-in-comparing-valid-encryption.patch | 37 + ...-causing-incorrect-response-length-3.patch | 32 + ppp.spec | 8 +- 4 files changed, 974 insertions(+), 1 deletion(-) create mode 100644 ppp-2.4.9-pppd-Expose-the-MPPE-keys-generated-through-an-API-2.patch create mode 100644 ppp-2.4.9-pppd-Fix-logical-error-in-comparing-valid-encryption.patch create mode 100644 ppp-2.4.9-pppd-eap-Fix-bug-causing-incorrect-response-length-3.patch diff --git a/ppp-2.4.9-pppd-Expose-the-MPPE-keys-generated-through-an-API-2.patch b/ppp-2.4.9-pppd-Expose-the-MPPE-keys-generated-through-an-API-2.patch new file mode 100644 index 0000000..fb0bcc1 --- /dev/null +++ b/ppp-2.4.9-pppd-Expose-the-MPPE-keys-generated-through-an-API-2.patch @@ -0,0 +1,898 @@ +From d706c95906d996534f13632a747af5dc617f306e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eivind=20N=C3=A6ss?= +Date: Sat, 24 Apr 2021 03:00:34 -0700 +Subject: [PATCH] pppd: Expose the MPPE keys generated through an API (#267) + +The lengthy part of this fix is to refactor the handling of MPPE keys +by moving it into mppe.c and thus reducing the clutter in chap_ms.c. +It does so by renaming the mppe_set_keys/2 to the corresponding +mppe_set_chapv1/mppe_set_chapv2 versions and updates callers of these +functions. + +Having done so, it conveniently allows the name "mppe_set_keys" to be +re-used for this new purpose which will copy the key material up to +its size and then clear the input parameters (avoids leaving the MPPE +keys on the stack). + +Additional functiions added to the MPPE code allow plugins et al. to +access the MPPE keys, clear the keys, and check if they are set. All +plugin and CCP code has been updated to use this API. + +This fixes GitHub Issue #258 + +Signed-off-by: Eivind Naess +--- + pppd/Makefile.linux | 2 + + pppd/Makefile.sol2 | 2 +- + pppd/ccp.c | 15 +-- + pppd/chap_ms.c | 167 +---------------------- + pppd/chap_ms.h | 22 +--- + pppd/eap-tls.c | 21 +-- + pppd/eap-tls.h | 5 - + pppd/mppe.c | 248 +++++++++++++++++++++++++++++++++++ + pppd/mppe.h | 70 +++++++++- + pppd/plugins/radius/radius.c | 14 +- + pppd/plugins/winbind.c | 8 +- + 11 files changed, 348 insertions(+), 226 deletions(-) + create mode 100644 pppd/mppe.c + +diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux +index f92f7c0..852945e 100644 +--- a/pppd/Makefile.linux ++++ b/pppd/Makefile.linux +@@ -109,6 +109,8 @@ CFLAGS += -DMSLANMAN=1 + endif + ifdef MPPE + CFLAGS += -DMPPE=1 ++PPPDOBJS += mppe.o ++PPPDSRC += mppe.c + HEADERS += mppe.h + endif + endif +diff --git a/pppd/Makefile.sol2 b/pppd/Makefile.sol2 +index 809cb4b..3a8681c 100644 +--- a/pppd/Makefile.sol2 ++++ b/pppd/Makefile.sol2 +@@ -37,7 +37,7 @@ OBJS += ipv6cp.o eui64.o + + # Uncomment to enable MS-CHAP + CFLAGS += -DUSE_CRYPT -DCHAPMS -DMSLANMAN -DHAVE_CRYPT_H +-OBJS += chap_ms.o pppcrypt.o md4.o sha1.o ++OBJS += chap_ms.o pppcrypt.o md4.o sha1.o mppe.o + + # Uncomment to enable MPPE (in both CHAP and EAP-TLS) + CFLAGS += -DMPPE +diff --git a/pppd/ccp.c b/pppd/ccp.c +index 052c4c6..387b571 100644 +--- a/pppd/ccp.c ++++ b/pppd/ccp.c +@@ -38,10 +38,9 @@ + #include "ccp.h" + #include + +-#ifdef MPPE +-#include "chap_ms.h" /* mppe_xxxx_key, mppe_keys_set */ ++#include "chap_ms.h" ++#include "mppe.h" + #include "lcp.h" /* lcp_close(), lcp_fsm */ +-#endif + + + /* +@@ -574,7 +573,7 @@ ccp_resetci(fsm *f) + } + + /* A plugin (eg radius) may not have obtained key material. */ +- if (!mppe_keys_set) { ++ if (!mppe_keys_isset()) { + error("MPPE required, but keys are not available. " + "Possible plugin problem?"); + lcp_close(f->unit, "MPPE required but not available"); +@@ -705,7 +704,7 @@ static void + p[1] = opt_buf[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &p[2]); + MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); +- BCOPY(mppe_recv_key, &opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN); ++ mppe_get_recv_key(&opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN); + res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0); + if (res > 0) + p += CILEN_MPPE; +@@ -1156,8 +1155,7 @@ ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) + int mtu; + + BCOPY(p, opt_buf, CILEN_MPPE); +- BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE], +- MPPE_MAX_KEY_LEN); ++ mppe_get_send_key(&opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN); + if (ccp_test(f->unit, opt_buf, + CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) { + /* This shouldn't happen, we've already tested it! */ +@@ -1426,8 +1424,7 @@ ccp_up(fsm *f) + notice("%s transmit compression enabled", method_name(ho, NULL)); + #ifdef MPPE + if (go->mppe) { +- BZERO(mppe_recv_key, MPPE_MAX_KEY_LEN); +- BZERO(mppe_send_key, MPPE_MAX_KEY_LEN); ++ mppe_clear_keys(); + continue_networks(f->unit); /* Bring up IP et al */ + } + #endif +diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c +index df2dadd..d315ab4 100644 +--- a/pppd/chap_ms.c ++++ b/pppd/chap_ms.c +@@ -93,8 +93,7 @@ + #include "sha1.h" + #include "pppcrypt.h" + #include "magic.h" +- +- ++#include "mppe.h" + + static void ascii2unicode (char[], int, u_char[]); + static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]); +@@ -109,21 +108,12 @@ static void GenerateAuthenticatorResponsePlain + static void ChapMS_LANMan (u_char *, char *, int, u_char *); + #endif + +-#ifdef MPPE +-static void Set_Start_Key (u_char *, char *, int); +-static void SetMasterKeys (char *, int, u_char[24], int); +-#endif +- + #ifdef MSLANMAN + bool ms_lanman = 0; /* Use LanMan password instead of NT */ + /* Has meaning only with MS-CHAP challenges */ + #endif + + #ifdef MPPE +-u_char mppe_send_key[MPPE_MAX_KEY_LEN]; +-u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; +-int mppe_keys_set = 0; /* Have the MPPE keys been set? */ +- + #ifdef DEBUGMPPEKEY + /* For MPPE debug */ + /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ +@@ -719,28 +709,6 @@ GenerateAuthenticatorResponsePlain + + + #ifdef MPPE +-/* +- * Set mppe_xxxx_key from the NTPasswordHashHash. +- * RFC 2548 (RADIUS support) requires us to export this function (ugh). +- */ +-void +-mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) +-{ +- SHA1_CTX sha1Context; +- u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ +- +- 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. */ +- BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); +- BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); +- +- mppe_keys_set = 1; +-} + + /* + * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) +@@ -757,104 +725,7 @@ Set_Start_Key(u_char *rchallenge, char *secret, int secret_len) + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + +- mppe_set_keys(rchallenge, PasswordHashHash); +-} +- +-/* +- * 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_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], +- u_char NTResponse[24], int IsServer) +-{ +- SHA1_CTX sha1Context; +- u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ +- u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ +- +- 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(Digest, &sha1Context); +- +- BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); +- +- /* +- * 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(Digest, &sha1Context); +- +- BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); +- +- mppe_keys_set = 1; ++ mppe_set_chapv1(rchallenge, PasswordHashHash); + } + + /* +@@ -870,7 +741,7 @@ SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer) + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); +- mppe_set_keys2(PasswordHashHash, NTResponse, IsServer); ++ mppe_set_chapv2(PasswordHashHash, NTResponse, IsServer); + } + + #endif /* MPPE */ +@@ -945,38 +816,6 @@ ChapMS2(u_char *rchallenge, u_char *PeerChallenge, + #endif + } + +-#ifdef MPPE +-/* +- * Set MPPE options from plugins. +- */ +-void +-set_mppe_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; +- } +-} +-#endif /* MPPE */ + + static struct chap_digest_type chapms_digest = { + CHAP_MICROSOFT, /* code */ +diff --git a/pppd/chap_ms.h b/pppd/chap_ms.h +index 005eb63..4e6a621 100644 +--- a/pppd/chap_ms.h ++++ b/pppd/chap_ms.h +@@ -38,6 +38,7 @@ + #define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ + #define MS_CHAP2_RESPONSE_LEN 49 /* Response length for MS-CHAPv2 */ + #define MS_AUTH_RESPONSE_LENGTH 40 /* MS-CHAPv2 authenticator response, */ ++#define MS_AUTH_NTRESP_LEN 24 /* Length of NT-response field */ + /* as ASCII */ + + /* E=eeeeeeeeee error codes for MS-CHAP failure messages. */ +@@ -67,22 +68,6 @@ + #define MS_CHAP2_NTRESP_LEN 24 + #define MS_CHAP2_FLAGS 48 + +-#ifdef MPPE +-#include "mppe.h" /* MPPE_MAX_KEY_LEN */ +-extern u_char mppe_send_key[MPPE_MAX_KEY_LEN]; +-extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; +-extern int mppe_keys_set; +- +-/* These values are the RADIUS attribute values--see RFC 2548. */ +-#define MPPE_ENC_POL_ENC_ALLOWED 1 +-#define MPPE_ENC_POL_ENC_REQUIRED 2 +-#define MPPE_ENC_TYPES_RC4_40 2 +-#define MPPE_ENC_TYPES_RC4_128 4 +- +-/* used by plugins (using above values) */ +-extern void set_mppe_enc_types(int, int); +-#endif +- + /* Are we the authenticator or authenticatee? For MS-CHAPv2 key derivation. */ + #define MS_CHAP2_AUTHENTICATEE 0 + #define MS_CHAP2_AUTHENTICATOR 1 +@@ -90,11 +75,6 @@ extern void set_mppe_enc_types(int, int); + void ChapMS (u_char *, char *, int, u_char *); + void ChapMS2 (u_char *, u_char *, char *, char *, int, + u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int); +-#ifdef MPPE +-void mppe_set_keys (u_char *, u_char[MD4_SIGNATURE_SIZE]); +-void mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], +- u_char NTResponse[24], int IsServer); +-#endif + + void ChallengeHash (u_char[16], u_char *, char *, u_char[8]); + +diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c +index 5c202c7..bfcf199 100644 +--- a/pppd/eap-tls.c ++++ b/pppd/eap-tls.c +@@ -48,6 +48,8 @@ + #include "eap-tls.h" + #include "fsm.h" + #include "lcp.h" ++#include "chap_ms.h" ++#include "mppe.h" + #include "pathnames.h" + + typedef struct pw_cb_data +@@ -74,10 +76,6 @@ int ssl_new_session_cb(SSL *s, SSL_SESSION *sess); + X509 *get_X509_from_file(char *filename); + int ssl_cmp_certs(char *filename, X509 * a); + +-#ifdef MPPE +- +-#define EAPTLS_MPPE_KEY_LEN 32 +- + /* + * OpenSSL 1.1+ introduced a generic TLS_method() + * For older releases we substitute the appropriate method +@@ -119,6 +117,8 @@ static inline int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, long tls_ver_max) + + #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ + ++#ifdef MPPE ++#define EAPTLS_MPPE_KEY_LEN 32 + + /* + * Generate keys according to RFC 2716 and add to reply +@@ -161,24 +161,17 @@ void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client) + */ + if (client) + { +- p = out; +- BCOPY( p, mppe_send_key, sizeof(mppe_send_key) ); +- p += EAPTLS_MPPE_KEY_LEN; +- BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) ); ++ mppe_set_keys(out, out + EAPTLS_MPPE_KEY_LEN, EAPTLS_MPPE_KEY_LEN); + } + else + { +- p = out; +- BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) ); +- p += EAPTLS_MPPE_KEY_LEN; +- BCOPY( p, mppe_send_key, sizeof(mppe_send_key) ); ++ mppe_set_keys(out + EAPTLS_MPPE_KEY_LEN, out, EAPTLS_MPPE_KEY_LEN); + } +- +- mppe_keys_set = 1; + } + + #endif /* MPPE */ + ++ + void log_ssl_errors( void ) + { + unsigned long ssl_err = ERR_get_error(); +diff --git a/pppd/eap-tls.h b/pppd/eap-tls.h +index c74a831..b935ec5 100644 +--- a/pppd/eap-tls.h ++++ b/pppd/eap-tls.h +@@ -86,11 +86,6 @@ int get_eaptls_secret(int unit, char *client, char *server, + char *capath, char *pkfile, int am_server); + + #ifdef MPPE +-#include "mppe.h" /* MPPE_MAX_KEY_LEN */ +-extern u_char mppe_send_key[MPPE_MAX_KEY_LEN]; +-extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; +-extern int mppe_keys_set; +- + void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client); + #endif + +diff --git a/pppd/mppe.c b/pppd/mppe.c +new file mode 100644 +index 0000000..4f3d131 +--- /dev/null ++++ b/pppd/mppe.c +@@ -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 ++ ++#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; ++ } ++} ++ +diff --git a/pppd/mppe.h b/pppd/mppe.h +index 5eb3b37..98a89d3 100644 +--- a/pppd/mppe.h ++++ b/pppd/mppe.h +@@ -32,9 +32,12 @@ + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ ++#ifndef __MPPE_H__ ++#define __MPPE_H__ + + #define MPPE_PAD 4 /* MPPE growth per frame */ +-#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ ++#define MPPE_MAX_KEY_SIZE 32 /* Largest key length */ ++#define MPPE_MAX_KEY_LEN 16 /* Largest key size accepted by the kernel */ + + /* option bits for ccp_options.mppe */ + #define MPPE_OPT_40 0x01 /* 40 bit */ +@@ -119,3 +122,68 @@ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) ++ ++ ++#if MPPE ++ ++/* ++ * NOTE: ++ * Access to these variables directly is discuraged. Please ++ * change your code to use below accessor functions. ++ */ ++ ++/* The key material generated which is used for MPPE send key */ ++extern u_char mppe_send_key[MPPE_MAX_KEY_SIZE]; ++/* The key material generated which is used for MPPE recv key */ ++extern u_char mppe_recv_key[MPPE_MAX_KEY_SIZE]; ++/* Keys are set if value is non-zero */ ++extern int mppe_keys_set; ++ ++/* These values are the RADIUS attribute values--see RFC 2548. */ ++#define MPPE_ENC_POL_ENC_ALLOWED 1 ++#define MPPE_ENC_POL_ENC_REQUIRED 2 ++#define MPPE_ENC_TYPES_RC4_40 2 ++#define MPPE_ENC_TYPES_RC4_128 4 ++ ++/* used by plugins (using above values) */ ++void mppe_set_enc_types (int policy, int types); ++ ++/* ++ * Set the MPPE send and recv keys. NULL values for keys are ignored ++ * and input values are cleared to avoid leaving them on the stack ++ */ ++void mppe_set_keys(u_char *send_key, u_char *recv_key, int keylen); ++ ++/* ++ * Get the MPPE recv key ++ */ ++int mppe_get_recv_key(u_char *recv_key, int length); ++ ++/* ++ * Get the MPPE send key ++ */ ++int mppe_get_send_key(u_char *send_key, int length); ++ ++/* ++ * Clear the MPPE keys ++ */ ++void mppe_clear_keys(void); ++ ++/* ++ * Check if the MPPE keys are set ++ */ ++bool mppe_keys_isset(void); ++ ++/* ++ * Set mppe_xxxx_key from NT Password Hash Hash (MSCHAPv1), see RFC3079 ++ */ ++void mppe_set_chapv1(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]); ++ ++/* ++ * Set the mppe_xxxx_key from MS-CHAP-v2 credentials, see RFC3079 ++ */ ++void mppe_set_chapv2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], ++ u_char NTResponse[MS_AUTH_NTRESP_LEN], int IsServer); ++ ++#endif // #ifdef MPPE ++#endif // #ifdef __MPPE_H__ +diff --git a/pppd/plugins/radius/radius.c b/pppd/plugins/radius/radius.c +index c579831..cf4c0f2 100644 +--- a/pppd/plugins/radius/radius.c ++++ b/pppd/plugins/radius/radius.c +@@ -31,6 +31,7 @@ static char const RCSID[] = + #ifdef CHAPMS + #include "chap_ms.h" + #ifdef MPPE ++#include "mppe.h" + #include "md5.h" + #endif + #endif +@@ -743,11 +744,12 @@ radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info, + * Note that if the policy value was '0' we don't set the key! + */ + if (mppe_enc_policy && mppe_enc_keys) { +- mppe_keys_set = 1; + /* Set/modify allowed encryption types. */ + if (mppe_enc_types) +- set_mppe_enc_types(mppe_enc_policy, mppe_enc_types); ++ mppe_set_enc_types(mppe_enc_policy, mppe_enc_types); ++ return 0; + } ++ mppe_clear_keys(); + #endif + + return 0; +@@ -803,7 +805,7 @@ radius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info, + * the NAS (us) doesn't need; we only need the start key. So we have + * to generate the start key, sigh. NB: We do not support the LM-Key. + */ +- mppe_set_keys(challenge, &plain[8]); ++ mppe_set_chapv1(challenge, &plain[8]); + + return 0; + } +@@ -855,7 +857,7 @@ radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info) + for (i = 0; i < 16; i++) + plain[i] ^= buf[i]; + +- if (plain[0] != sizeof(mppe_send_key) /* 16 */) { ++ if (plain[0] != 16) { + error("RADIUS: Incorrect key length (%d) for MS-MPPE-%s-Key attribute", + (int) plain[0], type); + return -1; +@@ -869,9 +871,9 @@ radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info) + plain[16] ^= buf[0]; /* only need the first byte */ + + if (vp->attribute == PW_MS_MPPE_SEND_KEY) +- memcpy(mppe_send_key, plain + 1, 16); ++ mppe_set_keys(plain + 1, NULL, 16); + else +- memcpy(mppe_recv_key, plain + 1, 16); ++ mppe_set_keys(NULL, plain + 1, 16); + + return 0; + } +diff --git a/pppd/plugins/winbind.c b/pppd/plugins/winbind.c +index 0c395c3..67c72f6 100644 +--- a/pppd/plugins/winbind.c ++++ b/pppd/plugins/winbind.c +@@ -37,11 +37,9 @@ + #include "pppd.h" + #include "chap-new.h" + #include "chap_ms.h" +-#ifdef MPPE +-#include "md5.h" +-#endif + #include "fsm.h" + #include "ipcp.h" ++#include "mppe.h" + #include + #include + #include +@@ -583,7 +581,7 @@ winbind_chap_verify(char *user, char *ourname, int id, + nt_response, nt_response_size, + session_key, + &error_string) == AUTHENTICATED) { +- mppe_set_keys(challenge, session_key); ++ mppe_set_chapv1(challenge, session_key); + slprintf(message, message_space, "Access granted"); + return AUTHENTICATED; + +@@ -628,7 +626,7 @@ winbind_chap_verify(char *user, char *ourname, int id, + &response[MS_CHAP2_NTRESP], + &response[MS_CHAP2_PEER_CHALLENGE], + challenge, user, saresponse); +- mppe_set_keys2(session_key, &response[MS_CHAP2_NTRESP], ++ mppe_set_chapv2(session_key, &response[MS_CHAP2_NTRESP], + MS_CHAP2_AUTHENTICATOR); + if (response[MS_CHAP2_FLAGS]) { + slprintf(message, message_space, "S=%s", saresponse); +-- +2.34.1 + diff --git a/ppp-2.4.9-pppd-Fix-logical-error-in-comparing-valid-encryption.patch b/ppp-2.4.9-pppd-Fix-logical-error-in-comparing-valid-encryption.patch new file mode 100644 index 0000000..c8eb350 --- /dev/null +++ b/ppp-2.4.9-pppd-Fix-logical-error-in-comparing-valid-encryption.patch @@ -0,0 +1,37 @@ +From e609ed8bb62e4648568eaa49fbbc858dfda6d122 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eivind=20N=C3=A6ss?= +Date: Sun, 14 Mar 2021 16:20:29 -0700 +Subject: [PATCH] pppd: Fix logical error in comparing valid encryption + policies (#262) + +RFC2548 describes the proper values of the MS-MPPE-Encryption-Policy attribute. +and it can only hold 2 values: 1 (encryption allowed) and 2 (encryption required). + +See + https://tools.ietf.org/html/rfc2548, section 2.4.4 + +The correct comparison should be made with an && and not a ||. + +This fixes github issue #218 + +Signed-off-by: Eivind Naess +--- + pppd/chap_ms.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c +index e6b84f2..df2dadd 100644 +--- a/pppd/chap_ms.c ++++ b/pppd/chap_ms.c +@@ -953,7 +953,7 @@ void + set_mppe_enc_types(int policy, int types) + { + /* Early exit for unknown policies. */ +- if (policy != MPPE_ENC_POL_ENC_ALLOWED || ++ if (policy != MPPE_ENC_POL_ENC_ALLOWED && + policy != MPPE_ENC_POL_ENC_REQUIRED) + return; + +-- +2.34.1 + diff --git a/ppp-2.4.9-pppd-eap-Fix-bug-causing-incorrect-response-length-3.patch b/ppp-2.4.9-pppd-eap-Fix-bug-causing-incorrect-response-length-3.patch new file mode 100644 index 0000000..2b6f53e --- /dev/null +++ b/ppp-2.4.9-pppd-eap-Fix-bug-causing-incorrect-response-length-3.patch @@ -0,0 +1,32 @@ +From d7e62a8499c4032d79e05afbd8fd3efd51c5b148 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eivind=20N=C3=A6ss?= +Date: Thu, 3 Feb 2022 14:28:22 -0800 +Subject: [PATCH] pppd/eap: Fix bug causing incorrect response length (#334) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Need to update the esp->ea_client.ea_namelen variable. A plugin can override the +name of the user, and the variable is passed onto the eap_chap2_response generating +the wrong response length. + +Signed-off-by: Eivind Næss +--- + pppd/eap.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/pppd/eap.c b/pppd/eap.c +index 54c3d42..6cb595f 100644 +--- a/pppd/eap.c ++++ b/pppd/eap.c +@@ -2182,6 +2182,7 @@ eap_request(eap_state *esp, u_char *inp, int id, int len) + eap_send_nak(esp, id, EAPT_SRP); + break; + } ++ esp->es_client.ea_namelen = strlen(esp->es_client.ea_name); + + /* Create the MSCHAPv2 response (and add to cache) */ + unsigned char response[MS_CHAP2_RESPONSE_LEN+1]; // VLEN + VALUE +-- +2.34.1 + diff --git a/ppp.spec b/ppp.spec index 2e9c6f3..f7b0ed2 100644 --- a/ppp.spec +++ b/ppp.spec @@ -2,7 +2,7 @@ Name: ppp Version: 2.4.9 -Release: 6%{?dist} +Release: 7%{?dist} Summary: The Point-to-Point Protocol daemon License: BSD and LGPLv2+ and GPLv2+ and Public Domain URL: http://www.samba.org/ppp @@ -37,6 +37,9 @@ Patch0023: 0023-build-sys-install-rp-pppoe-plugin-files-with-standar.patch Patch0024: 0024-build-sys-install-pppoatm-plugin-files-with-standard.patch Patch0025: ppp-2.4.8-pppd-install-pppd-binary-using-standard-perms-755.patch Patch0026: ppp-2.4.9-configure-cflags-allow-commas.patch +Patch0027: ppp-2.4.9-pppd-eap-Fix-bug-causing-incorrect-response-length-3.patch +Patch0028: ppp-2.4.9-pppd-Fix-logical-error-in-comparing-valid-encryption.patch +Patch0029: ppp-2.4.9-pppd-Expose-the-MPPE-keys-generated-through-an-API-2.patch BuildRequires: make BuildRequires: gcc @@ -167,6 +170,9 @@ mkdir -p %{buildroot}%{_rundir}/ppp %doc PLUGINS %changelog +* Tue Apr 05 2022 Marcin Zajaczkowski - 2.4.9-7 +- Backport patches from master for SSTP to connect using EAP-TLS to Azure VnetGWay and Windows RAS server + * Fri Jan 21 2022 Fedora Release Engineering - 2.4.9-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild