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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_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 */
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 */
69int 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 */
115void 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 {
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 */
217static 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 */
238static 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 */
267size_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 NULL
NULL pointer (VOID *)
Definition Base.h:322
union @162305117151260234136356364136041353210355154177 key
Sense key.
Definition scsi.h:3
struct golan_eq_context ctx
Definition CIB_PRM.h:0
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
u32 info
Definition ar9003_mac.h:0
unsigned short uint16_t
Definition stdint.h:11
unsigned char uint8_t
Definition stdint.h:10
u32 version
Driver version.
Definition ath9k_hw.c:1985
uint16_t offset
Offset to command line.
Definition bzimage.h:3
Character types.
static int toupper(int character)
Convert character to upper case.
Definition ctype.h:121
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
struct ena_llq_option header
Header locations.
Definition ena.h:5
Error codes.
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
void hmac_init(struct digest_algorithm *digest, void *ctx, const void *key, size_t key_len)
Initialise HMAC.
Definition hmac.c:58
void hmac_final(struct digest_algorithm *digest, void *ctx, void *hmac)
Finalise HMAC.
Definition hmac.c:88
Keyed-Hashing for Message Authentication.
static void hmac_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Update HMAC.
Definition hmac.h:43
#define le16_to_cpu(value)
Definition byteswap.h:113
#define le32_to_cpu(value)
Definition byteswap.h:114
#define cpu_to_le32(value)
Definition byteswap.h:108
#define cpu_to_le16(value)
Definition byteswap.h:107
static void digest_init(struct digest_algorithm *digest, void *ctx)
Definition crypto.h:219
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
Definition crypto.h:230
static void digest_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Definition crypto.h:224
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
unsigned long tmp
Definition linux_pci.h:65
static struct dynamic_item username
Definition login_ui.c:36
static struct dynamic_item password
Definition login_ui.c:37
struct digest_algorithm md4_algorithm
MD4 algorithm.
Definition md4.c:262
MD4 algorithm.
#define MD4_CTX_SIZE
MD4 context size.
Definition md4.h:67
#define MD4_DIGEST_SIZE
MD4 digest size.
Definition md4.h:73
struct digest_algorithm md5_algorithm
MD5 algorithm.
Definition md5.c:287
MD5 algorithm.
#define MD5_CTX_SIZE
MD5 context size.
Definition md5.h:67
#define MD5_BLOCK_SIZE
MD5 block size.
Definition md5.h:70
struct mschapv2_nt_response nt
NT response.
Definition mschapv2.h:5
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
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
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 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
int ntlm_challenge(struct ntlm_challenge *challenge, size_t len, struct ntlm_challenge_info *info)
Parse NTLM Challenge.
Definition ntlm.c:69
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
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.
@ NTLM_NEGOTIATE_NTLM
Negotiate NTLM key.
Definition ntlm.h:47
@ NTLM_REQUEST_TARGET
Request target name and information.
Definition ntlm.h:49
@ NTLM_NEGOTIATE_UNICODE
Negotiate Unicode character encoding.
Definition ntlm.h:51
@ NTLM_NEGOTIATE_ALWAYS_SIGN
Negotiate always sign.
Definition ntlm.h:45
@ NTLM_NEGOTIATE_EXTENDED_SESSIONSECURITY
Negotiate extended security.
Definition ntlm.h:43
#define NTLM_VERSION_NTLMV2
NTLM version.
Definition ntlm.h:163
@ NTLM_AUTHENTICATE
Authenticate message.
Definition ntlm.h:35
@ NTLM_NEGOTIATE
Negotiate message type.
Definition ntlm.h:31
#define NTLM_MAGIC
Magic signature.
Definition ntlm.h:26
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
A message digest algorithm.
Definition crypto.h:19
An Authenticate message.
Definition ntlm.h:117
struct ntlm_data lm
LAN Manager response.
Definition ntlm.h:121
struct ntlm_data user
User name.
Definition ntlm.h:127
struct ntlm_data domain
Domain name.
Definition ntlm.h:125
struct ntlm_data nt
NT response.
Definition ntlm.h:123
struct ntlm_header header
Message header.
Definition ntlm.h:119
struct ntlm_data workstation
Workstation name.
Definition ntlm.h:129
uint32_t flags
Negotiation flags.
Definition ntlm.h:133
NTLM challenge information.
Definition ntlm.h:166
A Challenge message.
Definition ntlm.h:101
struct ntlm_nonce nonce
Server nonce.
Definition ntlm.h:109
struct ntlm_data info
Target information.
Definition ntlm.h:113
A variable-length data descriptor.
Definition ntlm.h:75
uint16_t len
Length (in bytes)
Definition ntlm.h:77
uint32_t offset
Offset from start of message header.
Definition ntlm.h:85
A message header.
Definition ntlm.h:18
uint32_t type
Message type.
Definition ntlm.h:22
uint8_t magic[8]
Magic signature.
Definition ntlm.h:20
An NTLM verification key.
Definition ntlm.h:176
A LAN Manager response.
Definition ntlm.h:137
uint8_t digest[MD5_DIGEST_SIZE]
HMAC-MD5 digest.
Definition ntlm.h:139
struct ntlm_nonce nonce
Client nonce.
Definition ntlm.h:141
A Negotiate message.
Definition ntlm.h:89
uint32_t flags
Negotiation flags.
Definition ntlm.h:93
struct ntlm_data domain
Domain name.
Definition ntlm.h:95
struct ntlm_header header
Message header.
Definition ntlm.h:91
A nonce.
Definition ntlm.h:69
uint8_t raw[8]
Raw bytes.
Definition ntlm.h:71
An NT response.
Definition ntlm.h:145
static wchar_t wc
Definition wchar.h:23
u8 nonce[32]
Nonce value.
Definition wpa.h:25