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.28 2004/03/08 16:20:51 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 #undef USE_NTRESPONSES
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,
283 const char *domain=""; /* empty */
284 const char *host=""; /* empty */
285 int domlen=(int)strlen(domain);
286 int hostlen = (int)strlen(host);
287 int hostoff; /* host name offset */
288 int domoff; /* domain name offset */
291 unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
293 /* point to the address of the pointer that holds the string to sent to the
294 server, which is for a plain host or for a HTTP proxy */
297 /* point to the name and password for this */
300 /* point to the correct struct with this */
301 struct ntlmdata *ntlm;
306 allocuserpwd = &conn->allocptr.proxyuserpwd;
307 userp = conn->proxyuser;
308 passwdp = conn->proxypasswd;
309 ntlm = &conn->proxyntlm;
312 allocuserpwd = &conn->allocptr.userpwd;
314 passwdp = conn->passwd;
318 /* not set means empty */
325 switch(ntlm->state) {
326 case NTLMSTATE_TYPE1:
327 default: /* for the weird cases we (re)start here */
329 domoff = hostoff + hostlen;
331 /* Create and send a type-1 message:
333 Index Description Content
334 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
336 8 NTLM Message Type long (0x01000000)
338 16 Supplied Domain security buffer(*)
339 24 Supplied Workstation security buffer(*)
340 32 start of data block
344 snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
345 "\x01%c%c%c" /* 32-bit type = 1 */
346 "%c%c%c%c" /* 32-bit NTLM flag field */
347 "%c%c" /* domain length */
348 "%c%c" /* domain allocated space */
349 "%c%c" /* domain name offset */
350 "%c%c" /* 2 zeroes */
351 "%c%c" /* host length */
352 "%c%c" /* host allocated space */
353 "%c%c" /* host name offset */
354 "%c%c" /* 2 zeroes */
356 "%s", /* domain string */
357 0, /* trailing zero */
358 0,0,0, /* part of type-1 long */
361 NTLMFLAG_NEGOTIATE_OEM| /* 2 */
362 NTLMFLAG_NEGOTIATE_NTLM_KEY /* 200 */
375 /* initial packet length */
376 size = 32 + hostlen + domlen;
378 /* now keeper of the base64 encoded package size */
379 size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
382 Curl_safefree(*allocuserpwd);
383 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
389 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
393 case NTLMSTATE_TYPE2:
394 /* We received the type-2 already, create a type-3 message:
396 Index Description Content
397 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
399 8 NTLM Message Type long (0x03000000)
400 12 LM/LMv2 Response security buffer(*)
401 20 NTLM/NTLMv2 Response security buffer(*)
402 28 Domain Name security buffer(*)
403 36 User Name security buffer(*)
404 44 Workstation Name security buffer(*)
405 (52) Session Key (optional) security buffer(*)
406 (60) Flags (optional) long
407 52 (64) start of data block
415 unsigned char lmresp[0x18]; /* fixed-size */
416 #ifdef USE_NTRESPONSES
417 unsigned char ntresp[0x18]; /* fixed-size */
422 user = strchr(userp, '\\');
424 user = strchr(userp, '/');
428 domlen = user - domain;
433 userlen = strlen(user);
435 mkhash(passwdp, &ntlm->nonce[0], lmresp
436 #ifdef USE_NTRESPONSES
441 domoff = 64; /* always */
442 useroff = domoff + domlen;
443 hostoff = useroff + userlen;
444 lmrespoff = hostoff + hostlen;
445 ntrespoff = lmrespoff + 0x18;
447 /* Create the big type-3 message binary blob */
448 size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
450 "\x03%c%c%c" /* type-3, 32 bits */
452 "%c%c%c%c" /* LanManager length + allocated space */
453 "%c%c" /* LanManager offset */
454 "%c%c" /* 2 zeroes */
456 "%c%c" /* NT-response length */
457 "%c%c" /* NT-response allocated space */
458 "%c%c" /* NT-response offset */
459 "%c%c" /* 2 zeroes */
461 "%c%c" /* domain length */
462 "%c%c" /* domain allocated space */
463 "%c%c" /* domain name offset */
464 "%c%c" /* 2 zeroes */
466 "%c%c" /* user length */
467 "%c%c" /* user allocated space */
468 "%c%c" /* user offset */
469 "%c%c" /* 2 zeroes */
471 "%c%c" /* host length */
472 "%c%c" /* host allocated space */
473 "%c%c" /* host offset */
474 "%c%c%c%c%c%c" /* 6 zeroes */
476 "\xff\xff" /* message length */
477 "%c%c" /* 2 zeroes */
479 "\x01\x82" /* flags */
480 "%c%c" /* 2 zeroes */
485 /* LanManager response */
488 0, /* zero termination */
489 0,0,0, /* type-3 long, the 24 upper bits */
491 SHORTPAIR(0x18), /* LanManager response length, twice */
493 SHORTPAIR(lmrespoff),
496 #ifdef USE_NTRESPONSES
497 SHORTPAIR(0x18), /* NT-response length, twice */
503 SHORTPAIR(ntrespoff),
519 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
527 ntlmbuf[62]=ntlmbuf[63]=0;
529 memcpy(&ntlmbuf[size], domain, domlen);
532 memcpy(&ntlmbuf[size], user, userlen);
535 /* we append the binary hashes to the end of the blob */
536 if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
537 memcpy(&ntlmbuf[size], lmresp, 0x18);
541 #ifdef USE_NTRESPONSES
542 if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
543 memcpy(&ntlmbuf[size], ntresp, 0x18);
548 ntlmbuf[56] = size & 0xff;
549 ntlmbuf[57] = size >> 8;
551 /* convert the binary blob into base64 */
552 size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
555 Curl_safefree(*allocuserpwd);
556 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
562 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
564 ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
567 /* Switch to web authentication after proxy authentication is done */
569 Curl_http_auth_stage(conn->data, 401);
573 case NTLMSTATE_TYPE3:
574 /* connection is already authenticated,
575 * don't send a header in future requests */
586 #endif /* USE_SSLEAY */
587 #endif /* !CURL_DISABLE_HTTP */