The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
mschap.c
Go to the documentation of this file.
1 /*
2  * mschap.c
3  *
4  * Version: $Id: abe8c94beb4714bf64b7031a5a72c959c2ab3e5a $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * @copyright 2000,2001,2006,2010 The FreeRADIUS server project
21  */
22 
23 
24 /*
25  * This implements MS-CHAP, as described in RFC 2548
26  *
27  * http://www.freeradius.org/rfc/rfc2548.txt
28  *
29  */
30 
31 RCSID("$Id: abe8c94beb4714bf64b7031a5a72c959c2ab3e5a $")
32 
33 #include <freeradius-devel/server/base.h>
34 #include <freeradius-devel/server/module_rlm.h>
35 #include <freeradius-devel/util/debug.h>
36 #include <freeradius-devel/util/md5.h>
37 #include <freeradius-devel/util/sha1.h>
38 
39 #include <ctype.h>
40 
41 #include "smbdes.h"
42 #include "mschap.h"
43 
44 /** Converts Unicode password to 16-byte NT hash with MD4
45  *
46  * @param[out] out Pointer to 16 byte output buffer.
47  * @param[in] password to encode.
48  * @return
49  * - 0 on success.
50  * - -1 on failure.
51  */
52 int mschap_nt_password_hash(uint8_t out[static NT_DIGEST_LENGTH], char const *password)
53 {
54  ssize_t len;
55  uint8_t ucs2_password[512];
56 
57  len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), password, strlen(password));
58  if (len < 0) {
59  *out = '\0';
60  return -1;
61  }
62  fr_md4_calc(out, (uint8_t *) ucs2_password, len);
63 
64  return 0;
65 }
66 
67 /*
68  * challenge_hash() is used by mschap2() and auth_response()
69  * implements RFC2759 ChallengeHash()
70  * generates 64 bit challenge
71  */
73  uint8_t const peer_challenge[static MSCHAP_PEER_CHALLENGE_LENGTH],
74  uint8_t const auth_challenge[static MSCHAP_PEER_AUTHENTICATOR_CHALLENGE_LENGTH],
75  char const *user_name, size_t user_name_len)
76 {
77  fr_sha1_ctx Context;
79 
80  FR_PROTO_TRACE("RFC2759 ChallengeHash");
81  FR_PROTO_HEX_DUMP(peer_challenge, MSCHAP_PEER_CHALLENGE_LENGTH, "PeerChallenge");
82  FR_PROTO_HEX_DUMP(auth_challenge, MSCHAP_PEER_AUTHENTICATOR_CHALLENGE_LENGTH, "AuthenticatorChallenge");
83  FR_PROTO_HEX_DUMP((uint8_t const *)user_name, user_name_len, "UserName");
84 
85  fr_sha1_init(&Context);
86  fr_sha1_update(&Context, peer_challenge, MSCHAP_PEER_CHALLENGE_LENGTH);
88  fr_sha1_update(&Context, (uint8_t const *) user_name, user_name_len);
89  fr_sha1_final(hash, &Context);
90 
91  memcpy(challenge, hash, MSCHAP_CHALLENGE_LENGTH); //-V512
92 
93  FR_PROTO_HEX_DUMP(challenge, MSCHAP_CHALLENGE_LENGTH, "Challenge");
94 }
95 
96 /*
97  * auth_response() generates MS-CHAP v2 SUCCESS response
98  * according to RFC 2759 GenerateAuthenticatorResponse()
99  * returns 42-octet response string
100  */
101 void mschap_auth_response(char const *username, size_t username_len,
102  uint8_t const *nt_hash_hash,
103  uint8_t const *ntresponse,
104  uint8_t const *peer_challenge, uint8_t const *auth_challenge,
105  char *response)
106 {
107  fr_sha1_ctx Context;
108  static const uint8_t magic1[39] =
109  {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
110  0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
111  0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
112  0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
113 
114  static const uint8_t magic2[41] =
115  {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
116  0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
117  0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
118  0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
119  0x6E};
120 
121  static char const hex[] = "0123456789ABCDEF";
122 
123  size_t i;
124  uint8_t challenge[8];
125  uint8_t digest[20];
126 
127  fr_sha1_init(&Context);
128  fr_sha1_update(&Context, nt_hash_hash, 16);
129  fr_sha1_update(&Context, ntresponse, 24);
130  fr_sha1_update(&Context, magic1, 39);
131  fr_sha1_final(digest, &Context);
132  mschap_challenge_hash(challenge, peer_challenge, auth_challenge, username, username_len);
133  fr_sha1_init(&Context);
134  fr_sha1_update(&Context, digest, 20);
135  fr_sha1_update(&Context, challenge, 8);
136  fr_sha1_update(&Context, magic2, 41);
137  fr_sha1_final(digest, &Context);
138 
139  /*
140  * Encode the value of 'Digest' as "S=" followed by
141  * 40 ASCII hexadecimal digits and return it in
142  * AuthenticatorResponse.
143  * For example,
144  * "S=0123456789ABCDEF0123456789ABCDEF01234567"
145  */
146  response[0] = 'S';
147  response[1] = '=';
148 
149  /*
150  * The hexadecimal digits [A-F] MUST be uppercase.
151  */
152  for (i = 0; i < sizeof(digest); i++) {
153  response[2 + (i * 2)] = hex[(digest[i] >> 4) & 0x0f];
154  response[3 + (i * 2)] = hex[digest[i] & 0x0f];
155  }
156 }
157 
158 /*
159  * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error
160  * attribute to reply packet
161  */
162 void mschap_add_reply(request_t *request, uint8_t ident,
163  fr_dict_attr_t const *da, char const *value, size_t len)
164 {
165  fr_pair_t *vp;
166 
167  MEM(pair_update_reply(&vp, da) >= 0);
168  if (vp->vp_type == FR_TYPE_STRING) {
169  char *p;
170 
171  MEM(fr_pair_value_bstr_alloc(vp, &p, len + 1, vp->vp_tainted) == 0); /* Account for the ident byte */
172  p[0] = ident;
173  memcpy(p + 1, value, len);
174  } else {
175  uint8_t *p;
176 
177  MEM(fr_pair_value_mem_alloc(vp, &p, len + 1, vp->vp_tainted) == 0); /* Account for the ident byte */
178  p[0] = ident;
179  memcpy(p + 1, value, len);
180  }
181 }
182 
#define RCSID(id)
Definition: build.h:444
Test enumeration values.
Definition: dict_test.h:92
void fr_md4_calc(uint8_t out[static MD4_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Calculate the MD4 hash of the contents of a buffer.
Definition: md4.c:489
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen)
Convert UTF8 string to UCS2 encoding.
Definition: misc.c:306
int mschap_nt_password_hash(uint8_t out[static NT_DIGEST_LENGTH], char const *password)
Converts Unicode password to 16-byte NT hash with MD4.
Definition: mschap.c:52
void mschap_add_reply(request_t *request, uint8_t ident, fr_dict_attr_t const *da, char const *value, size_t len)
Definition: mschap.c:162
void mschap_auth_response(char const *username, size_t username_len, uint8_t const *nt_hash_hash, uint8_t const *ntresponse, uint8_t const *peer_challenge, uint8_t const *auth_challenge, char *response)
Definition: mschap.c:101
void mschap_challenge_hash(uint8_t challenge[static MSCHAP_CHALLENGE_LENGTH], uint8_t const peer_challenge[static MSCHAP_PEER_CHALLENGE_LENGTH], uint8_t const auth_challenge[static MSCHAP_PEER_AUTHENTICATOR_CHALLENGE_LENGTH], char const *user_name, size_t user_name_len)
Definition: mschap.c:72
#define MSCHAP_CHALLENGE_LENGTH
Definition: mschap.h:9
#define MSCHAP_PEER_CHALLENGE_LENGTH
Definition: mschap.h:10
#define MSCHAP_PEER_AUTHENTICATOR_CHALLENGE_LENGTH
Definition: mschap.h:11
#define NT_DIGEST_LENGTH
Definition: mschap.h:7
int fr_pair_value_bstr_alloc(fr_pair_t *vp, char **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "string" type value pair.
Definition: pair.c:2727
int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "octets" type value pair.
Definition: pair.c:2927
static const uint8_t magic1[27]
Definition: rlm_mschap.c:1272
static const uint8_t magic2[84]
Definition: rlm_mschap.c:1277
static unsigned int hash(char const *username, unsigned int tablesize)
Definition: rlm_passwd.c:132
username
Definition: rlm_securid.c:420
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition: pair.h:129
void fr_sha1_init(fr_sha1_ctx *context)
Definition: sha1.c:93
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
Definition: sha1.c:141
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
Definition: sha1.c:105
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:29
static char const hex[]
Definition: smbencrypt.c:35
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition: proto.h:41
#define FR_PROTO_TRACE(_fmt,...)
Definition: proto.h:40
static size_t char ** out
Definition: value.h:984