iPXE
ntlm.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 /** @file
28  *
29  * NT LAN Manager (NTLM) authentication
30  *
31  */
32 
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <byteswap.h>
38 #include <ipxe/md4.h>
39 #include <ipxe/md5.h>
40 #include <ipxe/hmac.h>
41 #include <ipxe/ntlm.h>
42 
43 /** Negotiate message
44  *
45  * This message content is fixed since there is no need to specify the
46  * calling workstation name or domain name, and the set of flags is
47  * mandated by the MS-NLMP specification.
48  */
50  .header = {
51  .magic = NTLM_MAGIC,
52  .type = cpu_to_le32 ( NTLM_NEGOTIATE ),
53  },
59 };
60 
61 /**
62  * Parse NTLM Challenge
63  *
64  * @v challenge Challenge message
65  * @v len Length of Challenge message
66  * @v info Challenge information to fill in
67  * @ret rc Return status code
68  */
69 int ntlm_challenge ( struct ntlm_challenge *challenge, size_t len,
70  struct ntlm_challenge_info *info ) {
71  size_t offset;
72 
73  DBGC ( challenge, "NTLM challenge message:\n" );
74  DBGC_HDA ( challenge, 0, challenge, len );
75 
76  /* Sanity checks */
77  if ( len < sizeof ( *challenge ) ) {
78  DBGC ( challenge, "NTLM underlength challenge (%zd bytes)\n",
79  len );
80  return -EINVAL;
81  }
82 
83  /* Extract nonce */
84  info->nonce = &challenge->nonce;
85  DBGC ( challenge, "NTLM challenge nonce:\n" );
86  DBGC_HDA ( challenge, 0, info->nonce, sizeof ( *info->nonce ) );
87 
88  /* Extract target information */
89  info->len = le16_to_cpu ( challenge->info.len );
90  offset = le32_to_cpu ( challenge->info.offset );
91  if ( ( offset > len ) ||
92  ( info->len > ( len - offset ) ) ) {
93  DBGC ( challenge, "NTLM target information outside "
94  "challenge\n" );
95  DBGC_HDA ( challenge, 0, challenge, len );
96  return -EINVAL;
97  }
98  info->target = ( ( ( void * ) challenge ) + offset );
99  DBGC ( challenge, "NTLM challenge target information:\n" );
100  DBGC_HDA ( challenge, 0, info->target, info->len );
101 
102  return 0;
103 }
104 
105 /**
106  * Calculate NTLM verification key
107  *
108  * @v domain Domain name (or NULL)
109  * @v username User name (or NULL)
110  * @v password Password (or NULL)
111  * @v key Key to fill in
112  *
113  * This is the NTOWFv2() function as defined in MS-NLMP.
114  */
115 void ntlm_key ( const char *domain, const char *username,
116  const char *password, struct ntlm_key *key ) {
117  struct digest_algorithm *md4 = &md4_algorithm;
118  struct digest_algorithm *md5 = &md5_algorithm;
119  union {
120  uint8_t md4[MD4_CTX_SIZE];
122  } ctx;
123  uint8_t digest[MD4_DIGEST_SIZE];
124  uint8_t c;
125  uint16_t wc;
126 
127  /* Use empty usernames/passwords if not specified */
128  if ( ! domain )
129  domain = "";
130  if ( ! username )
131  username = "";
132  if ( ! password )
133  password = "";
134 
135  /* Construct MD4 digest of (Unicode) password */
136  digest_init ( md4, ctx.md4 );
137  while ( ( c = *(password++) ) ) {
138  wc = cpu_to_le16 ( c );
139  digest_update ( md4, ctx.md4, &wc, sizeof ( wc ) );
140  }
141  digest_final ( md4, ctx.md4, digest );
142 
143  /* Construct HMAC-MD5 of (Unicode) upper-case username */
144  hmac_init ( md5, ctx.md5, digest, sizeof ( digest ) );
145  while ( ( c = *(username++) ) ) {
146  wc = cpu_to_le16 ( toupper ( c ) );
147  hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
148  }
149  while ( ( c = *(domain++) ) ) {
150  wc = cpu_to_le16 ( c );
151  hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
152  }
153  hmac_final ( md5, ctx.md5, key->raw );
154  DBGC ( key, "NTLM key:\n" );
155  DBGC_HDA ( key, 0, key, sizeof ( *key ) );
156 }
157 
158 /**
159  * Construct NTLM responses
160  *
161  * @v info Challenge information
162  * @v key Verification key
163  * @v nonce Nonce, or NULL to use a random nonce
164  * @v lm LAN Manager response to fill in
165  * @v nt NT response to fill in
166  */
168  struct ntlm_nonce *nonce, struct ntlm_lm_response *lm,
169  struct ntlm_nt_response *nt ) {
170  struct digest_algorithm *md5 = &md5_algorithm;
171  struct ntlm_nonce tmp_nonce;
173  unsigned int i;
174 
175  /* Generate random nonce, if needed */
176  if ( ! nonce ) {
177  for ( i = 0 ; i < sizeof ( tmp_nonce ) ; i++ )
178  tmp_nonce.raw[i] = random();
179  nonce = &tmp_nonce;
180  }
181 
182  /* Construct LAN Manager response */
183  memcpy ( &lm->nonce, nonce, sizeof ( lm->nonce ) );
184  hmac_init ( md5, ctx, key->raw, sizeof ( *key ) );
185  hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
186  hmac_update ( md5, ctx, &lm->nonce, sizeof ( lm->nonce ) );
187  hmac_final ( md5, ctx, lm->digest );
188  DBGC ( key, "NTLM LAN Manager response:\n" );
189  DBGC_HDA ( key, 0, lm, sizeof ( *lm ) );
190 
191  /* Construct NT response */
192  memset ( nt, 0, sizeof ( *nt ) );
193  nt->version = NTLM_VERSION_NTLMV2;
194  nt->high = NTLM_VERSION_NTLMV2;
195  memcpy ( &nt->nonce, nonce, sizeof ( nt->nonce ) );
196  hmac_init ( md5, ctx, key->raw, sizeof ( *key ) );
197  hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
198  hmac_update ( md5, ctx, &nt->version,
199  ( sizeof ( *nt ) -
200  offsetof ( typeof ( *nt ), version ) ) );
201  hmac_update ( md5, ctx, info->target, info->len );
202  hmac_update ( md5, ctx, &nt->zero, sizeof ( nt->zero ) );
203  hmac_final ( md5, ctx, nt->digest );
204  DBGC ( key, "NTLM NT response prefix:\n" );
205  DBGC_HDA ( key, 0, nt, sizeof ( *nt ) );
206 }
207 
208 /**
209  * Append data to NTLM message
210  *
211  * @v header Message header, or NULL to only calculate next payload
212  * @v data Data descriptor
213  * @v payload Data payload
214  * @v len Length of data
215  * @ret payload Next data payload
216  */
217 static void * ntlm_append ( struct ntlm_header *header, struct ntlm_data *data,
218  void *payload, size_t len ) {
219 
220  /* Populate data descriptor */
221  if ( header ) {
222  data->offset = cpu_to_le32 ( payload - ( ( void * ) header ) );
223  data->len = data->max_len = cpu_to_le16 ( len );
224  }
225 
226  return ( payload + len );
227 }
228 
229 /**
230  * Append Unicode string data to NTLM message
231  *
232  * @v header Message header, or NULL to only calculate next payload
233  * @v data Data descriptor
234  * @v payload Data payload
235  * @v string String to append, or NULL
236  * @ret payload Next data payload
237  */
238 static void * ntlm_append_string ( struct ntlm_header *header,
239  struct ntlm_data *data, void *payload,
240  const char *string ) {
241  uint16_t *tmp = payload;
242  uint8_t c;
243 
244  /* Convert string to Unicode */
245  for ( tmp = payload ; ( string && ( c = *(string++) ) ) ; tmp++ ) {
246  if ( header )
247  *tmp = cpu_to_le16 ( c );
248  }
249 
250  /* Append string data */
251  return ntlm_append ( header, data, payload,
252  ( ( ( void * ) tmp ) - payload ) );
253 }
254 
255 /**
256  * Construct NTLM Authenticate message
257  *
258  * @v info Challenge information
259  * @v domain Domain name, or NULL
260  * @v username User name, or NULL
261  * @v workstation Workstation name, or NULL
262  * @v lm LAN Manager response
263  * @v nt NT response
264  * @v auth Message to fill in, or NULL to only calculate length
265  * @ret len Length of message
266  */
267 size_t ntlm_authenticate ( struct ntlm_challenge_info *info, const char *domain,
268  const char *username, const char *workstation,
269  struct ntlm_lm_response *lm,
270  struct ntlm_nt_response *nt,
271  struct ntlm_authenticate *auth ) {
272  void *tmp;
273  size_t nt_len;
274  size_t len;
275 
276  /* Construct response header */
277  if ( auth ) {
278  memset ( auth, 0, sizeof ( *auth ) );
280  sizeof ( auth->header.magic ) );
282  auth->flags = ntlm_negotiate.flags;
283  }
284  tmp = ( ( ( void * ) auth ) + sizeof ( *auth ) );
285 
286  /* Construct LAN Manager response */
287  if ( auth )
288  memcpy ( tmp, lm, sizeof ( *lm ) );
289  tmp = ntlm_append ( &auth->header, &auth->lm, tmp, sizeof ( *lm ) );
290 
291  /* Construct NT response */
292  nt_len = ( sizeof ( *nt ) + info->len + sizeof ( nt->zero ) );
293  if ( auth ) {
294  memcpy ( tmp, nt, sizeof ( *nt ) );
295  memcpy ( ( tmp + sizeof ( *nt ) ), info->target, info->len );
296  memset ( ( tmp + sizeof ( *nt ) + info->len ), 0,
297  sizeof ( nt->zero ) );
298  }
299  tmp = ntlm_append ( &auth->header, &auth->nt, tmp, nt_len );
300 
301  /* Populate domain, user, and workstation names */
302  tmp = ntlm_append_string ( &auth->header, &auth->domain, tmp, domain );
303  tmp = ntlm_append_string ( &auth->header, &auth->user, tmp, username );
304  tmp = ntlm_append_string ( &auth->header, &auth->workstation, tmp,
305  workstation );
306 
307  /* Calculate length */
308  len = ( tmp - ( ( void * ) auth ) );
309  if ( auth ) {
310  DBGC ( auth, "NTLM authenticate message:\n" );
311  DBGC_HDA ( auth, 0, auth, len );
312  }
313 
314  return len;
315 }
316 
317 /**
318  * Calculate NTLM Authenticate message length
319  *
320  * @v info Challenge information
321  * @v domain Domain name, or NULL
322  * @v username User name, or NULL
323  * @v workstation Workstation name, or NULL
324  * @ret len Length of Authenticate message
325  */
327  const char *domain, const char *username,
328  const char *workstation ) {
329 
330  return ntlm_authenticate ( info, domain, username, workstation,
331  NULL, NULL, NULL );
332 }
#define MD4_DIGEST_SIZE
MD4 digest size.
Definition: md4.h:73
void hmac_init(struct digest_algorithm *digest, void *ctx, const void *key, size_t key_len)
Initialise HMAC.
Definition: hmac.c:58
#define EINVAL
Invalid argument.
Definition: errno.h:429
static wchar_t wc
Definition: wchar.h:23
static void digest_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Definition: crypto.h:224
unsigned short uint16_t
Definition: stdint.h:11
A variable-length data descriptor.
Definition: ntlm.h:75
uint8_t magic[8]
Magic signature.
Definition: ntlm.h:20
u32 info
Definition: ar9003_mac.h:24
struct ntlm_data lm
LAN Manager response.
Definition: ntlm.h:121
#define le32_to_cpu(value)
Definition: byteswap.h:114
Error codes.
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
Definition: crypto.h:230
void ntlm_response(struct ntlm_challenge_info *info, struct ntlm_key *key, struct ntlm_nonce *nonce, struct ntlm_lm_response *lm, struct ntlm_nt_response *nt)
Construct NTLM responses.
Definition: ntlm.c:167
#define DBGC(...)
Definition: compiler.h:505
Negotiate NTLM key.
Definition: ntlm.h:47
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:25
struct golan_eq_context ctx
Definition: CIB_PRM.h:28
Character types.
FILE_SECBOOT(PERMITTED)
struct ntlm_header header
Message header.
Definition: ntlm.h:119
uint16_t len
Length (in bytes)
Definition: ntlm.h:77
Authenticate message.
Definition: ntlm.h:35
size_t ntlm_authenticate(struct ntlm_challenge_info *info, const char *domain, const char *username, const char *workstation, struct ntlm_lm_response *lm, struct ntlm_nt_response *nt, struct ntlm_authenticate *auth)
Construct NTLM Authenticate message.
Definition: ntlm.c:267
static int toupper(int character)
Convert character to upper case.
Definition: ctype.h:121
unsigned long tmp
Definition: linux_pci.h:65
void * memcpy(void *dest, const void *src, size_t len) __nonnull
u32 version
Driver version.
Definition: ath9k_hw.c:1985
struct ntlm_data domain
Domain name.
Definition: ntlm.h:95
Negotiate always sign.
Definition: ntlm.h:45
Keyed-Hashing for Message Authentication.
uint8_t digest[MD5_DIGEST_SIZE]
HMAC-MD5 digest.
Definition: ntlm.h:139
#define DBGC_HDA(...)
Definition: compiler.h:506
ring len
Length.
Definition: dwmac.h:231
An Authenticate message.
Definition: ntlm.h:117
#define NTLM_MAGIC
Magic signature.
Definition: ntlm.h:26
An NTLM verification key.
Definition: ntlm.h:176
#define cpu_to_le32(value)
Definition: byteswap.h:108
uint32_t flags
Negotiation flags.
Definition: ntlm.h:93
static void digest_init(struct digest_algorithm *digest, void *ctx)
Definition: crypto.h:219
static void hmac_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Update HMAC.
Definition: hmac.h:43
struct ntlm_data workstation
Workstation name.
Definition: ntlm.h:129
A message header.
Definition: ntlm.h:18
static void * ntlm_append_string(struct ntlm_header *header, struct ntlm_data *data, void *payload, const char *string)
Append Unicode string data to NTLM message.
Definition: ntlm.c:238
#define MD5_CTX_SIZE
MD5 context size.
Definition: md5.h:67
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:32
struct ntlm_data domain
Domain name.
Definition: ntlm.h:125
static void * ntlm_append(struct ntlm_header *header, struct ntlm_data *data, void *payload, size_t len)
Append data to NTLM message.
Definition: ntlm.c:217
unsigned char uint8_t
Definition: stdint.h:10
struct ntlm_header header
Message header.
Definition: ntlm.h:91
A nonce.
Definition: ntlm.h:69
#define MD5_BLOCK_SIZE
MD5 block size.
Definition: md5.h:70
struct ntlm_nonce nonce
Client nonce.
Definition: ntlm.h:141
Negotiate extended security.
Definition: ntlm.h:43
#define le16_to_cpu(value)
Definition: byteswap.h:113
static struct dynamic_item password
Definition: login_ui.c:37
u8 nonce[32]
Nonce value.
Definition: wpa.h:52
struct ntlm_data nt
NT response.
Definition: ntlm.h:123
uint32_t flags
Negotiation flags.
Definition: ntlm.h:133
struct ntlm_data user
User name.
Definition: ntlm.h:127
#define MD4_CTX_SIZE
MD4 context size.
Definition: md4.h:67
struct ntlm_data info
Target information.
Definition: ntlm.h:113
Negotiate message type.
Definition: ntlm.h:31
A Challenge message.
Definition: ntlm.h:101
size_t ntlm_authenticate_len(struct ntlm_challenge_info *info, const char *domain, const char *username, const char *workstation)
Calculate NTLM Authenticate message length.
Definition: ntlm.c:326
#define NTLM_VERSION_NTLMV2
NTLM version.
Definition: ntlm.h:163
uint32_t offset
Offset from start of message header.
Definition: ntlm.h:85
uint32_t type
Message type.
Definition: ntlm.h:22
struct ena_llq_option header
Header locations.
Definition: ena.h:16
#define cpu_to_le16(value)
Definition: byteswap.h:107
A message digest algorithm.
Definition: crypto.h:19
int ntlm_challenge(struct ntlm_challenge *challenge, size_t len, struct ntlm_challenge_info *info)
Parse NTLM Challenge.
Definition: ntlm.c:69
uint8_t raw[8]
Raw bytes.
Definition: ntlm.h:71
uint8_t data[48]
Additional event data.
Definition: ena.h:22
static struct dynamic_item username
Definition: login_ui.c:36
void hmac_final(struct digest_algorithm *digest, void *ctx, void *hmac)
Finalise HMAC.
Definition: hmac.c:88
void ntlm_key(const char *domain, const char *username, const char *password, struct ntlm_key *key)
Calculate NTLM verification key.
Definition: ntlm.c:115
NT LAN Manager (NTLM) authentication.
struct digest_algorithm md4_algorithm
MD4 algorithm.
Definition: md4.c:262
struct ntlm_nonce nonce
Server nonce.
Definition: ntlm.h:109
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:48
NTLM challenge information.
Definition: ntlm.h:166
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
MD4 algorithm.
An NT response.
Definition: ntlm.h:145
MD5 algorithm.
Request target name and information.
Definition: ntlm.h:49
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
A LAN Manager response.
Definition: ntlm.h:137
String functions.
Negotiate Unicode character encoding.
Definition: ntlm.h:51
union @391 key
Sense key.
Definition: scsi.h:18
struct mschapv2_nt_response nt
NT response.
Definition: mschapv2.h:16
struct digest_algorithm md5_algorithm
MD5 algorithm.
Definition: md5.c:287
void * memset(void *dest, int character, size_t len) __nonnull
A Negotiate message.
Definition: ntlm.h:89