1
/***************************************************************************
3
* Project ___| | | | _ \| |
5
* | (__| |_| | _ <| |___
6
* \___|\___/|_| \_\_____|
8
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
10
* This software is licensed as described in the file COPYING, which
11
* you should have received as part of this distribution. The terms
12
* are also available at http://curl.haxx.se/docs/copyright.html.
14
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
* copies of the Software, and permit persons to whom the Software is
16
* furnished to do so, under the terms of the COPYING file.
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
* KIND, either express or implied.
21
* $Id: http_ntlm.c,v 1.30 2004/03/30 06:39:24 bagder Exp $
22
***************************************************************************/
27
http://davenport.sourceforge.net/ntlm.html
28
http://www.innovation.ch/java/ntlm.html
32
#ifndef CURL_DISABLE_HTTP
34
/* We need OpenSSL for the crypto lib to provide us with MD4 and DES */
36
/* -- WIN32 approved -- */
47
#include "http_ntlm.h"
49
#include "http.h" /* for Curl_http_auth_stage() */
51
#define _MPRINTF_REPLACE /* use our functions only */
52
#include <curl/mprintf.h>
54
#include <openssl/des.h>
55
#include <openssl/md4.h>
56
#include <openssl/ssl.h>
58
#if OPENSSL_VERSION_NUMBER < 0x00907001L
59
#define DES_key_schedule des_key_schedule
60
#define DES_cblock des_cblock
61
#define DES_set_odd_parity des_set_odd_parity
62
#define DES_set_key des_set_key
63
#define DES_ecb_encrypt des_ecb_encrypt
65
/* This is how things were done in the old days */
67
#define DESKEYARG(x) x
70
#define DESKEYARG(x) *x
74
/* The last #include file should be: */
79
/* Define this to make the type-3 message include the NT response message */
80
#define USE_NTRESPONSES 1
83
(*) = A "security buffer" is a triplet consisting of two shorts and one
86
1. a 'short' containing the length of the buffer in bytes
87
2. a 'short' containing the allocated space for the buffer in bytes
88
3. a 'long' containing the offset to the start of the buffer from the
89
beginning of the NTLM message, in bytes.
93
CURLntlm Curl_input_ntlm(struct connectdata *conn,
94
bool proxy, /* if proxy or not */
95
char *header) /* rest of the www-authenticate:
98
/* point to the correct struct with this */
99
struct ntlmdata *ntlm;
101
ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
103
/* skip initial whitespaces */
104
while(*header && isspace((int)*header))
107
if(checkprefix("NTLM", header)) {
108
unsigned char buffer[256];
109
header += strlen("NTLM");
111
while(*header && isspace((int)*header))
115
/* We got a type-2 message here:
117
Index Description Content
118
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
120
8 NTLM Message Type long (0x02000000)
121
12 Target Name security buffer(*)
124
(32) Context (optional) 8 bytes (two consecutive longs)
125
(40) Target Information (optional) security buffer(*)
126
32 (48) start of data block
129
size_t size = Curl_base64_decode(header, (char *)buffer);
131
ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
134
/* the nonce of interest is index [24 .. 31], 8 bytes */
135
memcpy(ntlm->nonce, &buffer[24], 8);
137
/* at index decimal 20, there's a 32bit NTLM flag field */
141
if(ntlm->state >= NTLMSTATE_TYPE1)
144
ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
147
return CURLNTLM_FINE;
151
* Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
152
* key schedule ks is also set.
154
static void setup_des_key(unsigned char *key_56,
155
DES_key_schedule DESKEYARG(ks))
160
key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
161
key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
162
key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
163
key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
164
key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
165
key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
166
key[7] = (key_56[6] << 1) & 0xFF;
168
DES_set_odd_parity(&key);
169
DES_set_key(&key, ks);
173
* takes a 21 byte array and treats it as 3 56-bit DES keys. The
174
* 8 byte plaintext is encrypted with each key and the resulting 24
175
* bytes are stored in the results array.
177
static void calc_resp(unsigned char *keys,
178
unsigned char *plaintext,
179
unsigned char *results)
183
setup_des_key(keys, DESKEY(ks));
184
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
185
DESKEY(ks), DES_ENCRYPT);
187
setup_des_key(keys+7, DESKEY(ks));
188
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
189
DESKEY(ks), DES_ENCRYPT);
191
setup_des_key(keys+14, DESKEY(ks));
192
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
193
DESKEY(ks), DES_ENCRYPT);
197
* Set up lanmanager and nt hashed passwords
199
static void mkhash(char *password,
200
unsigned char *nonce, /* 8 bytes */
201
unsigned char *lmresp /* must fit 0x18 bytes */
202
#ifdef USE_NTRESPONSES
203
, unsigned char *ntresp /* must fit 0x18 bytes */
207
unsigned char lmbuffer[21];
208
#ifdef USE_NTRESPONSES
209
unsigned char ntbuffer[21];
212
static const unsigned char magic[] = {
213
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
216
size_t len = strlen(password);
218
/* make it fit at least 14 bytes */
219
pw = malloc(len<7?14:len*2);
221
return; /* this will lead to a badly generated package */
226
for (i=0; i<len; i++)
227
pw[i] = toupper(password[i]);
233
/* create LanManager hashed password */
236
setup_des_key(pw, DESKEY(ks));
237
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
238
DESKEY(ks), DES_ENCRYPT);
240
setup_des_key(pw+7, DESKEY(ks));
241
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
242
DESKEY(ks), DES_ENCRYPT);
244
memset(lmbuffer+16, 0, 5);
246
/* create LM responses */
247
calc_resp(lmbuffer, nonce, lmresp);
249
#ifdef USE_NTRESPONSES
251
/* create NT hashed password */
254
len = strlen(password);
256
for (i=0; i<len; i++) {
257
pw[2*i] = password[i];
262
MD4_Update(&MD4, pw, 2*len);
263
MD4_Final(ntbuffer, &MD4);
265
memset(ntbuffer+16, 0, 8);
268
calc_resp(ntbuffer, nonce, ntresp);
274
#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
275
#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
276
(((x) >>16)&0xff), ((x)>>24)
278
/* this is for creating ntlm header output */
279
CURLcode Curl_output_ntlm(struct connectdata *conn,
282
const char *domain=""; /* empty */
283
const char *host=""; /* empty */
284
int domlen=(int)strlen(domain);
285
int hostlen = (int)strlen(host);
286
int hostoff; /* host name offset */
287
int domoff; /* domain name offset */
290
unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
292
/* point to the address of the pointer that holds the string to sent to the
293
server, which is for a plain host or for a HTTP proxy */
296
/* point to the name and password for this */
299
/* point to the correct struct with this */
300
struct ntlmdata *ntlm;
303
curlassert(conn->data);
304
conn->data->state.authdone = FALSE;
307
allocuserpwd = &conn->allocptr.proxyuserpwd;
308
userp = conn->proxyuser;
309
passwdp = conn->proxypasswd;
310
ntlm = &conn->proxyntlm;
313
allocuserpwd = &conn->allocptr.userpwd;
315
passwdp = conn->passwd;
319
/* not set means empty */
326
switch(ntlm->state) {
327
case NTLMSTATE_TYPE1:
328
default: /* for the weird cases we (re)start here */
330
domoff = hostoff + hostlen;
332
/* Create and send a type-1 message:
334
Index Description Content
335
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
337
8 NTLM Message Type long (0x01000000)
339
16 Supplied Domain security buffer(*)
340
24 Supplied Workstation security buffer(*)
341
32 start of data block
345
snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
346
"\x01%c%c%c" /* 32-bit type = 1 */
347
"%c%c%c%c" /* 32-bit NTLM flag field */
348
"%c%c" /* domain length */
349
"%c%c" /* domain allocated space */
350
"%c%c" /* domain name offset */
351
"%c%c" /* 2 zeroes */
352
"%c%c" /* host length */
353
"%c%c" /* host allocated space */
354
"%c%c" /* host name offset */
355
"%c%c" /* 2 zeroes */
357
"%s", /* domain string */
358
0, /* trailing zero */
359
0,0,0, /* part of type-1 long */
362
NTLMFLAG_NEGOTIATE_OEM| /* 2 */
363
NTLMFLAG_NEGOTIATE_NTLM_KEY /* 200 */
376
/* initial packet length */
377
size = 32 + hostlen + domlen;
379
/* now keeper of the base64 encoded package size */
380
size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
383
Curl_safefree(*allocuserpwd);
384
*allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
390
return CURLE_OUT_OF_MEMORY; /* FIX TODO */
394
case NTLMSTATE_TYPE2:
395
/* We received the type-2 already, create a type-3 message:
397
Index Description Content
398
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
400
8 NTLM Message Type long (0x03000000)
401
12 LM/LMv2 Response security buffer(*)
402
20 NTLM/NTLMv2 Response security buffer(*)
403
28 Domain Name security buffer(*)
404
36 User Name security buffer(*)
405
44 Workstation Name security buffer(*)
406
(52) Session Key (optional) security buffer(*)
407
(60) Flags (optional) long
408
52 (64) start of data block
416
unsigned char lmresp[0x18]; /* fixed-size */
417
#ifdef USE_NTRESPONSES
418
unsigned char ntresp[0x18]; /* fixed-size */
423
user = strchr(userp, '\\');
425
user = strchr(userp, '/');
429
domlen = user - domain;
434
userlen = strlen(user);
436
mkhash(passwdp, &ntlm->nonce[0], lmresp
437
#ifdef USE_NTRESPONSES
442
domoff = 64; /* always */
443
useroff = domoff + domlen;
444
hostoff = useroff + userlen;
445
lmrespoff = hostoff + hostlen;
446
ntrespoff = lmrespoff + 0x18;
448
/* Create the big type-3 message binary blob */
449
size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
451
"\x03%c%c%c" /* type-3, 32 bits */
453
"%c%c%c%c" /* LanManager length + allocated space */
454
"%c%c" /* LanManager offset */
455
"%c%c" /* 2 zeroes */
457
"%c%c" /* NT-response length */
458
"%c%c" /* NT-response allocated space */
459
"%c%c" /* NT-response offset */
460
"%c%c" /* 2 zeroes */
462
"%c%c" /* domain length */
463
"%c%c" /* domain allocated space */
464
"%c%c" /* domain name offset */
465
"%c%c" /* 2 zeroes */
467
"%c%c" /* user length */
468
"%c%c" /* user allocated space */
469
"%c%c" /* user offset */
470
"%c%c" /* 2 zeroes */
472
"%c%c" /* host length */
473
"%c%c" /* host allocated space */
474
"%c%c" /* host offset */
475
"%c%c%c%c%c%c" /* 6 zeroes */
477
"\xff\xff" /* message length */
478
"%c%c" /* 2 zeroes */
480
"\x01\x82" /* flags */
481
"%c%c" /* 2 zeroes */
486
/* LanManager response */
489
0, /* zero termination */
490
0,0,0, /* type-3 long, the 24 upper bits */
492
SHORTPAIR(0x18), /* LanManager response length, twice */
494
SHORTPAIR(lmrespoff),
497
#ifdef USE_NTRESPONSES
498
SHORTPAIR(0x18), /* NT-response length, twice */
504
SHORTPAIR(ntrespoff),
520
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
528
ntlmbuf[62]=ntlmbuf[63]=0;
530
memcpy(&ntlmbuf[size], domain, domlen);
533
memcpy(&ntlmbuf[size], user, userlen);
536
/* we append the binary hashes to the end of the blob */
537
if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
538
memcpy(&ntlmbuf[size], lmresp, 0x18);
542
#ifdef USE_NTRESPONSES
543
if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
544
memcpy(&ntlmbuf[size], ntresp, 0x18);
549
ntlmbuf[56] = size & 0xff;
550
ntlmbuf[57] = size >> 8;
552
/* convert the binary blob into base64 */
553
size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
556
Curl_safefree(*allocuserpwd);
557
*allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
563
return CURLE_OUT_OF_MEMORY; /* FIX TODO */
565
ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
566
conn->data->state.authdone = TRUE;
568
/* Switch to web authentication after proxy authentication is done */
570
Curl_http_auth_stage(conn->data, 401);
574
case NTLMSTATE_TYPE3:
575
/* connection is already authenticated,
576
* don't send a header in future requests */
581
conn->data->state.authdone = TRUE;
587
#endif /* USE_SSLEAY */
588
#endif /* !CURL_DISABLE_HTTP */