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