Home | History | Annotate | Line # | Download | only in pppd
      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
     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
     70 mppe_keys_isset()
     71 {
     72 	return !!mppe_keys_set;
     73 }
     74 
     75 int
     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
     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
    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
    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
    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
    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