1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2009, 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 ***************************************************************************/
26 http://davenport.sourceforge.net/ntlm.html
27 http://www.innovation.ch/java/ntlm.html
29 Another implementation:
30 http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp
34 #ifndef CURL_DISABLE_HTTP
39 /* -- WIN32 approved -- */
50 #if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
55 #include "easyif.h" /* for Curl_convert_... prototypes */
58 #include "curl_base64.h"
59 #include "http_ntlm.h"
61 #include "curl_gethostname.h"
62 #include "curl_memory.h"
64 #define _MPRINTF_REPLACE /* use our functions only */
65 #include <curl/mprintf.h>
67 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
68 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
73 # include <openssl/des.h>
74 # ifndef OPENSSL_NO_MD4
75 # include <openssl/md4.h>
77 # include <openssl/md5.h>
78 # include <openssl/ssl.h>
79 # include <openssl/rand.h>
82 # ifndef OPENSSL_NO_MD4
90 #if OPENSSL_VERSION_NUMBER < 0x00907001L
91 #define DES_key_schedule des_key_schedule
92 #define DES_cblock des_cblock
93 #define DES_set_odd_parity des_set_odd_parity
94 #define DES_set_key des_set_key
95 #define DES_ecb_encrypt des_ecb_encrypt
97 /* This is how things were done in the old days */
99 #define DESKEYARG(x) x
102 #define DESKEYARG(x) *x
106 #ifdef OPENSSL_NO_MD4
107 /* This requires MD4, but OpenSSL was compiled without it */
108 #define USE_NTRESPONSES 0
109 #define USE_NTLM2SESSION 0
112 #elif defined(USE_GNUTLS)
117 #define MD5_DIGEST_LENGTH 16
118 #define MD4_DIGEST_LENGTH 16
120 #elif defined(USE_NSS)
122 #include "curl_md4.h"
127 #define MD5_DIGEST_LENGTH MD5_LENGTH
129 #elif defined(USE_WINDOWS_SSPI)
131 #include "curl_sspi.h"
134 # error "Can't compile NTLM support without a crypto library."
137 /* The last #include file should be: */
138 #include "memdebug.h"
140 #ifndef USE_NTRESPONSES
141 /* Define this to make the type-3 message include the NT response message */
142 #define USE_NTRESPONSES 1
144 /* Define this to make the type-3 message include the NTLM2Session response
145 message, requires USE_NTRESPONSES. */
146 #define USE_NTLM2SESSION 1
149 #ifndef USE_WINDOWS_SSPI
150 /* this function converts from the little endian format used in the incoming
151 package to whatever endian format we're using natively */
152 static unsigned int readint_le(unsigned char *buf) /* must point to a
155 return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
156 ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
161 # define DEBUG_OUT(x) x
162 static void print_flags(FILE *handle, unsigned long flags)
164 if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
165 fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
166 if(flags & NTLMFLAG_NEGOTIATE_OEM)
167 fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
168 if(flags & NTLMFLAG_REQUEST_TARGET)
169 fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
171 fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
172 if(flags & NTLMFLAG_NEGOTIATE_SIGN)
173 fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
174 if(flags & NTLMFLAG_NEGOTIATE_SEAL)
175 fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
176 if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
177 fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
178 if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
179 fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
180 if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
181 fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
182 if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
183 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
185 fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
186 if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
187 fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
188 if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
189 fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
190 if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
191 fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
192 if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
193 fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
194 if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
195 fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
196 if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
197 fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
198 if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
199 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
200 if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
201 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
202 if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
203 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
204 if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
205 fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
206 if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
207 fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
208 if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
209 fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
210 if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
211 fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
213 fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
215 fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
217 fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
219 fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
221 fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
222 if(flags & NTLMFLAG_NEGOTIATE_128)
223 fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
224 if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
225 fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
226 if(flags & NTLMFLAG_NEGOTIATE_56)
227 fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
230 static void print_hex(FILE *handle, const char *buf, size_t len)
233 fprintf(stderr, "0x");
235 fprintf(stderr, "%02.2x", (unsigned int)*p++);
238 # define DEBUG_OUT(x)
242 (*) = A "security buffer" is a triplet consisting of two shorts and one
245 1. a 'short' containing the length of the buffer in bytes
246 2. a 'short' containing the allocated space for the buffer in bytes
247 3. a 'long' containing the offset to the start of the buffer from the
248 beginning of the NTLM message, in bytes.
252 CURLntlm Curl_input_ntlm(struct connectdata *conn,
253 bool proxy, /* if proxy or not */
254 const char *header) /* rest of the www-authenticate:
257 /* point to the correct struct with this */
258 struct ntlmdata *ntlm;
259 #ifndef USE_WINDOWS_SSPI
260 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
264 if(CURLE_OK != Curl_nss_force_init(conn->data))
268 ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
270 /* skip initial whitespaces */
271 while(*header && ISSPACE(*header))
274 if(checkprefix("NTLM", header)) {
275 header += strlen("NTLM");
277 while(*header && ISSPACE(*header))
281 /* We got a type-2 message here:
283 Index Description Content
284 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
286 8 NTLM Message Type long (0x02000000)
287 12 Target Name security buffer(*)
290 (32) Context (optional) 8 bytes (two consecutive longs)
291 (40) Target Information (optional) security buffer(*)
292 32 (48) start of data block
295 unsigned char *buffer;
296 size = Curl_base64_decode(header, &buffer);
300 ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
302 #ifdef USE_WINDOWS_SSPI
303 ntlm->type_2 = malloc(size+1);
304 if(ntlm->type_2 == NULL) {
306 return CURLE_OUT_OF_MEMORY;
308 ntlm->n_type_2 = size;
309 memcpy(ntlm->type_2, buffer, size);
314 (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
315 (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) {
316 /* This was not a good enough type-2 message */
321 ntlm->flags = readint_le(&buffer[20]);
322 memcpy(ntlm->nonce, &buffer[24], 8);
325 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
326 print_flags(stderr, ntlm->flags);
327 fprintf(stderr, "\n nonce=");
328 print_hex(stderr, (char *)ntlm->nonce, 8);
329 fprintf(stderr, "\n****\n");
330 fprintf(stderr, "**** Header %s\n ", header);
336 if(ntlm->state >= NTLMSTATE_TYPE1)
339 ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
342 return CURLNTLM_FINE;
345 #ifndef USE_WINDOWS_SSPI
349 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
350 * key schedule ks is also set.
352 static void setup_des_key(const unsigned char *key_56,
353 DES_key_schedule DESKEYARG(ks))
358 key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
359 key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
360 key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
361 key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
362 key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
363 key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
364 key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
366 DES_set_odd_parity(&key);
367 DES_set_key(&key, ks);
370 #else /* defined(USE_SSLEAY) */
373 * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS.
375 static void extend_key_56_to_64(const unsigned char *key_56, char *key)
378 key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
379 key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
380 key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
381 key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
382 key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
383 key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
384 key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
387 #if defined(USE_GNUTLS)
390 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
392 static void setup_des_key(const unsigned char *key_56,
393 gcry_cipher_hd_t *des)
396 extend_key_56_to_64(key_56, key);
397 gcry_cipher_setkey(*des, key, 8);
400 #elif defined(USE_NSS)
403 * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using
404 * the expanded key. The caller is responsible for giving 64 bit of valid
405 * data is IN and (at least) 64 bit large buffer as OUT.
407 static bool encrypt_des(const unsigned char *in, unsigned char *out,
408 const unsigned char *key_56)
410 const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */
411 PK11SlotInfo *slot = NULL;
412 char key[8]; /* expanded 64 bit key */
414 PK11SymKey *symkey = NULL;
415 SECItem *param = NULL;
416 PK11Context *ctx = NULL;
417 int out_len; /* not used, required by NSS */
420 /* use internal slot for DES encryption (requires NSS to be initialized) */
421 slot = PK11_GetInternalKeySlot();
425 /* expand the 56 bit key to 64 bit and wrap by NSS */
426 extend_key_56_to_64(key_56, key);
427 key_item.data = (unsigned char *)key;
428 key_item.len = /* hard-wired */ 8;
429 symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT,
434 /* create DES encryption context */
435 param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL);
438 ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param);
442 /* perform the encryption */
443 if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8,
444 (unsigned char *)in, /* inbuflen */ 8)
445 && SECSuccess == PK11_Finalize(ctx))
446 rv = /* all OK */ TRUE;
451 PK11_DestroyContext(ctx, PR_TRUE);
453 PK11_FreeSymKey(symkey);
455 SECITEM_FreeItem(param, PR_TRUE);
460 #endif /* defined(USE_NSS) */
462 #endif /* defined(USE_SSLEAY) */
465 * takes a 21 byte array and treats it as 3 56-bit DES keys. The
466 * 8 byte plaintext is encrypted with each key and the resulting 24
467 * bytes are stored in the results array.
469 static void lm_resp(const unsigned char *keys,
470 const unsigned char *plaintext,
471 unsigned char *results)
476 setup_des_key(keys, DESKEY(ks));
477 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
478 DESKEY(ks), DES_ENCRYPT);
480 setup_des_key(keys+7, DESKEY(ks));
481 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
482 DESKEY(ks), DES_ENCRYPT);
484 setup_des_key(keys+14, DESKEY(ks));
485 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
486 DESKEY(ks), DES_ENCRYPT);
487 #elif defined(USE_GNUTLS)
488 gcry_cipher_hd_t des;
490 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
491 setup_des_key(keys, &des);
492 gcry_cipher_encrypt(des, results, 8, plaintext, 8);
493 gcry_cipher_close(des);
495 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
496 setup_des_key(keys+7, &des);
497 gcry_cipher_encrypt(des, results+8, 8, plaintext, 8);
498 gcry_cipher_close(des);
500 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
501 setup_des_key(keys+14, &des);
502 gcry_cipher_encrypt(des, results+16, 8, plaintext, 8);
503 gcry_cipher_close(des);
504 #elif defined(USE_NSS)
505 encrypt_des(plaintext, results, keys);
506 encrypt_des(plaintext, results+8, keys+7);
507 encrypt_des(plaintext, results+16, keys+14);
513 * Set up lanmanager hashed password
515 static void mk_lm_hash(struct SessionHandle *data,
516 const char *password,
517 unsigned char *lmbuffer /* 21 bytes */)
519 unsigned char pw[14];
520 static const unsigned char magic[] = {
521 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
523 size_t len = CURLMIN(strlen(password), 14);
525 Curl_strntoupper((char *)pw, password, len);
526 memset(&pw[len], 0, 14-len);
528 #ifdef CURL_DOES_CONVERSIONS
530 * The LanManager hashed password needs to be created using the
531 * password in the network encoding not the host encoding.
534 Curl_convert_to_network(data, (char *)pw, 14);
540 /* Create LanManager hashed password. */
545 setup_des_key(pw, DESKEY(ks));
546 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
547 DESKEY(ks), DES_ENCRYPT);
549 setup_des_key(pw+7, DESKEY(ks));
550 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
551 DESKEY(ks), DES_ENCRYPT);
552 #elif defined(USE_GNUTLS)
553 gcry_cipher_hd_t des;
555 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
556 setup_des_key(pw, &des);
557 gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
558 gcry_cipher_close(des);
560 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
561 setup_des_key(pw+7, &des);
562 gcry_cipher_encrypt(des, lmbuffer+8, 8, magic, 8);
563 gcry_cipher_close(des);
564 #elif defined(USE_NSS)
565 encrypt_des(magic, lmbuffer, pw);
566 encrypt_des(magic, lmbuffer+8, pw+7);
569 memset(lmbuffer + 16, 0, 21 - 16);
574 static void ascii_to_unicode_le(unsigned char *dest, const char *src,
578 for (i=0; i<srclen; i++) {
579 dest[2*i] = (unsigned char)src[i];
585 * Set up nt hashed passwords
587 static CURLcode mk_nt_hash(struct SessionHandle *data,
588 const char *password,
589 unsigned char *ntbuffer /* 21 bytes */)
591 size_t len = strlen(password);
592 unsigned char *pw = malloc(len*2);
594 return CURLE_OUT_OF_MEMORY;
596 ascii_to_unicode_le(pw, password, len);
598 #ifdef CURL_DOES_CONVERSIONS
600 * The NT hashed password needs to be created using the
601 * password in the network encoding not the host encoding.
604 Curl_convert_to_network(data, (char *)pw, len*2);
610 /* Create NT hashed password. */
614 MD4_Update(&MD4pw, pw, 2*len);
615 MD4_Final(ntbuffer, &MD4pw);
616 #elif defined(USE_GNUTLS)
618 gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
619 gcry_md_write(MD4pw, pw, 2*len);
620 memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH);
621 gcry_md_close(MD4pw);
622 #elif defined(USE_NSS)
623 Curl_md4it(ntbuffer, pw, 2*len);
626 memset(ntbuffer + 16, 0, 21 - 16);
637 #ifdef USE_WINDOWS_SSPI
640 ntlm_sspi_cleanup(struct ntlmdata *ntlm)
646 if(ntlm->has_handles) {
647 s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
648 s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
649 ntlm->has_handles = 0;
651 if(ntlm->p_identity) {
652 if(ntlm->identity.User) free(ntlm->identity.User);
653 if(ntlm->identity.Password) free(ntlm->identity.Password);
654 if(ntlm->identity.Domain) free(ntlm->identity.Domain);
655 ntlm->p_identity = NULL;
661 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
662 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
663 (((x) >>16)&0xff), (((x)>>24) & 0xff)
665 #define HOSTNAME_MAX 1024
667 /* this is for creating ntlm header output */
668 CURLcode Curl_output_ntlm(struct connectdata *conn,
671 const char *domain=""; /* empty */
672 char host [HOSTNAME_MAX+ 1] = ""; /* empty */
673 #ifndef USE_WINDOWS_SSPI
674 size_t domlen = strlen(domain);
675 size_t hostlen = strlen(host);
676 size_t hostoff; /* host name offset */
677 size_t domoff; /* domain name offset */
681 unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very
684 /* point to the address of the pointer that holds the string to sent to the
685 server, which is for a plain host or for a HTTP proxy */
688 /* point to the name and password for this */
691 /* point to the correct struct with this */
692 struct ntlmdata *ntlm;
696 DEBUGASSERT(conn->data);
699 if(CURLE_OK != Curl_nss_force_init(conn->data))
700 return CURLE_OUT_OF_MEMORY;
704 allocuserpwd = &conn->allocptr.proxyuserpwd;
705 userp = conn->proxyuser;
706 passwdp = conn->proxypasswd;
707 ntlm = &conn->proxyntlm;
708 authp = &conn->data->state.authproxy;
711 allocuserpwd = &conn->allocptr.userpwd;
713 passwdp = conn->passwd;
715 authp = &conn->data->state.authhost;
719 /* not set means empty */
726 #ifdef USE_WINDOWS_SSPI
727 if (s_hSecDll == NULL) {
728 /* not thread safe and leaks - use curl_global_init() to avoid */
729 CURLcode err = Curl_sspi_global_init();
730 if (s_hSecDll == NULL)
735 switch(ntlm->state) {
736 case NTLMSTATE_TYPE1:
737 default: /* for the weird cases we (re)start here */
738 #ifdef USE_WINDOWS_SSPI
742 SECURITY_STATUS status;
746 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
748 ntlm_sspi_cleanup(ntlm);
750 user = strchr(userp, '\\');
752 user = strchr(userp, '/');
756 domlen = user - userp;
766 /* note: initialize all of this before doing the mallocs so that
767 * it can be cleaned up later without leaking memory.
769 ntlm->p_identity = &ntlm->identity;
770 memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
771 if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
772 return CURLE_OUT_OF_MEMORY;
773 ntlm->identity.UserLength = strlen(user);
774 if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
775 return CURLE_OUT_OF_MEMORY;
776 ntlm->identity.PasswordLength = strlen(passwdp);
777 if((ntlm->identity.Domain = malloc(domlen+1)) == NULL)
778 return CURLE_OUT_OF_MEMORY;
779 strncpy((char *)ntlm->identity.Domain, domain, domlen);
780 ntlm->identity.Domain[domlen] = '\0';
781 ntlm->identity.DomainLength = domlen;
782 ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
785 ntlm->p_identity = NULL;
788 if(s_pSecFn->AcquireCredentialsHandleA(
789 NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity,
790 NULL, NULL, &ntlm->handle, &tsDummy
792 return CURLE_OUT_OF_MEMORY;
795 desc.ulVersion = SECBUFFER_VERSION;
797 desc.pBuffers = &buf;
798 buf.cbBuffer = sizeof(ntlmbuf);
799 buf.BufferType = SECBUFFER_TOKEN;
800 buf.pvBuffer = ntlmbuf;
802 status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
804 ISC_REQ_CONFIDENTIALITY |
805 ISC_REQ_REPLAY_DETECT |
807 0, SECURITY_NETWORK_DREP,
809 &ntlm->c_handle, &desc,
812 if(status == SEC_I_COMPLETE_AND_CONTINUE ||
813 status == SEC_I_CONTINUE_NEEDED) {
814 s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
816 else if(status != SEC_E_OK) {
817 s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
818 return CURLE_RECV_ERROR;
821 ntlm->has_handles = 1;
826 domoff = hostoff + hostlen; /* This is 0: remember that host and domain
829 /* Create and send a type-1 message:
831 Index Description Content
832 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
834 8 NTLM Message Type long (0x01000000)
836 16 Supplied Domain security buffer(*)
837 24 Supplied Workstation security buffer(*)
838 32 start of data block
842 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
846 snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c"
847 "\x01%c%c%c" /* 32-bit type = 1 */
848 "%c%c%c%c" /* 32-bit NTLM flag field */
849 "%c%c" /* domain length */
850 "%c%c" /* domain allocated space */
851 "%c%c" /* domain name offset */
852 "%c%c" /* 2 zeroes */
853 "%c%c" /* host length */
854 "%c%c" /* host allocated space */
855 "%c%c" /* host name offset */
856 "%c%c" /* 2 zeroes */
858 "%s", /* domain string */
859 0, /* trailing zero */
860 0,0,0, /* part of type-1 long */
863 NTLMFLAG_NEGOTIATE_OEM|
864 NTLMFLAG_REQUEST_TARGET|
865 NTLMFLAG_NEGOTIATE_NTLM_KEY|
867 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
877 host /* this is empty */, domain /* this is empty */);
879 /* initial packet length */
880 size = 32 + hostlen + domlen;
884 fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
885 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM|
886 NTLMFLAG_REQUEST_TARGET|
887 NTLMFLAG_NEGOTIATE_NTLM_KEY|
889 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
890 NTLMFLAG_NEGOTIATE_OEM|
891 NTLMFLAG_REQUEST_TARGET|
892 NTLMFLAG_NEGOTIATE_NTLM_KEY|
894 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
896 NTLMFLAG_NEGOTIATE_OEM|
897 NTLMFLAG_REQUEST_TARGET|
898 NTLMFLAG_NEGOTIATE_NTLM_KEY|
900 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
901 fprintf(stderr, "\n****\n");
904 /* now size is the size of the base64 encoded package size */
905 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
908 Curl_safefree(*allocuserpwd);
909 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
912 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
916 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
920 case NTLMSTATE_TYPE2:
921 /* We received the type-2 message already, create a type-3 message:
923 Index Description Content
924 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
926 8 NTLM Message Type long (0x03000000)
927 12 LM/LMv2 Response security buffer(*)
928 20 NTLM/NTLMv2 Response security buffer(*)
929 28 Domain Name security buffer(*)
930 36 User Name security buffer(*)
931 44 Workstation Name security buffer(*)
932 (52) Session Key (optional) security buffer(*)
933 (60) Flags (optional) long
934 52 (64) start of data block
939 #ifdef USE_WINDOWS_SSPI
940 SecBuffer type_2, type_3;
941 SecBufferDesc type_2_desc, type_3_desc;
942 SECURITY_STATUS status;
944 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
946 type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION;
947 type_2_desc.cBuffers = type_3_desc.cBuffers = 1;
948 type_2_desc.pBuffers = &type_2;
949 type_3_desc.pBuffers = &type_3;
951 type_2.BufferType = SECBUFFER_TOKEN;
952 type_2.pvBuffer = ntlm->type_2;
953 type_2.cbBuffer = ntlm->n_type_2;
954 type_3.BufferType = SECBUFFER_TOKEN;
955 type_3.pvBuffer = ntlmbuf;
956 type_3.cbBuffer = sizeof(ntlmbuf);
958 status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, &ntlm->c_handle,
960 ISC_REQ_CONFIDENTIALITY |
961 ISC_REQ_REPLAY_DETECT |
963 0, SECURITY_NETWORK_DREP, &type_2_desc,
964 0, &ntlm->c_handle, &type_3_desc,
967 if(status != SEC_E_OK)
968 return CURLE_RECV_ERROR;
970 size = type_3.cbBuffer;
972 ntlm_sspi_cleanup(ntlm);
976 unsigned char lmresp[24]; /* fixed-size */
979 unsigned char ntresp[24]; /* fixed-size */
985 user = strchr(userp, '\\');
987 user = strchr(userp, '/');
991 domlen = (user - domain);
996 userlen = strlen(user);
998 if(Curl_gethostname(host, HOSTNAME_MAX)) {
999 infof(conn->data, "gethostname() failed, continuing without!");
1003 /* If the workstation if configured with a full DNS name (i.e.
1004 * workstation.somewhere.net) gethostname() returns the fully qualified
1005 * name, which NTLM doesn't like.
1007 char *dot = strchr(host, '.');
1010 hostlen = strlen(host);
1013 #if USE_NTLM2SESSION
1014 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
1015 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
1016 unsigned char ntbuffer[0x18];
1017 unsigned char tmp[0x18];
1018 unsigned char md5sum[MD5_DIGEST_LENGTH];
1019 unsigned char entropy[8];
1021 /* Need to create 8 bytes random data */
1024 Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
1025 RAND_bytes(entropy,8);
1026 #elif defined(USE_GNUTLS)
1028 Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
1029 gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
1030 #elif defined(USE_NSS)
1032 unsigned int outlen;
1033 Curl_nss_seed(conn->data); /* Initiate the seed if not already done */
1034 PK11_GenerateRandom(entropy, 8);
1037 /* 8 bytes random data as challenge in lmresp */
1038 memcpy(lmresp,entropy,8);
1039 /* Pad with zeros */
1040 memset(lmresp+8,0,0x10);
1042 /* Fill tmp with challenge(nonce?) + entropy */
1043 memcpy(tmp,&ntlm->nonce[0],8);
1044 memcpy(tmp+8,entropy,8);
1048 MD5_Update(&MD5pw, tmp, 16);
1049 MD5_Final(md5sum, &MD5pw);
1050 #elif defined(USE_GNUTLS)
1051 gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
1052 gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
1053 memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
1054 gcry_md_close(MD5pw);
1055 #elif defined(USE_NSS)
1056 MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
1057 PK11_DigestOp(MD5pw, tmp, 16);
1058 PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH);
1059 PK11_DestroyContext(MD5pw, PR_TRUE);
1062 /* We shall only use the first 8 bytes of md5sum,
1063 but the des code in lm_resp only encrypt the first 8 bytes */
1064 if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
1065 return CURLE_OUT_OF_MEMORY;
1066 lm_resp(ntbuffer, md5sum, ntresp);
1068 /* End of NTLM2 Session code */
1075 unsigned char ntbuffer[0x18];
1077 unsigned char lmbuffer[0x18];
1080 if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
1081 return CURLE_OUT_OF_MEMORY;
1082 lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
1085 mk_lm_hash(conn->data, passwdp, lmbuffer);
1086 lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
1087 /* A safer but less compatible alternative is:
1088 * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
1089 * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
1092 lmrespoff = 64; /* size of the message header */
1094 ntrespoff = lmrespoff + 0x18;
1095 domoff = ntrespoff + 0x18;
1097 domoff = lmrespoff + 0x18;
1099 useroff = domoff + domlen;
1100 hostoff = useroff + userlen;
1103 * In the case the server sets the flag NTLMFLAG_NEGOTIATE_UNICODE, we
1104 * need to filter it off because libcurl doesn't UNICODE encode the
1105 * strings it packs into the NTLM authenticate packet.
1107 ntlm->flags &= ~NTLMFLAG_NEGOTIATE_UNICODE;
1109 /* Create the big type-3 message binary blob */
1110 size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
1111 NTLMSSP_SIGNATURE "%c"
1112 "\x03%c%c%c" /* type-3, 32 bits */
1114 "%c%c" /* LanManager length */
1115 "%c%c" /* LanManager allocated space */
1116 "%c%c" /* LanManager offset */
1117 "%c%c" /* 2 zeroes */
1119 "%c%c" /* NT-response length */
1120 "%c%c" /* NT-response allocated space */
1121 "%c%c" /* NT-response offset */
1122 "%c%c" /* 2 zeroes */
1124 "%c%c" /* domain length */
1125 "%c%c" /* domain allocated space */
1126 "%c%c" /* domain name offset */
1127 "%c%c" /* 2 zeroes */
1129 "%c%c" /* user length */
1130 "%c%c" /* user allocated space */
1131 "%c%c" /* user offset */
1132 "%c%c" /* 2 zeroes */
1134 "%c%c" /* host length */
1135 "%c%c" /* host allocated space */
1136 "%c%c" /* host offset */
1137 "%c%c" /* 2 zeroes */
1139 "%c%c" /* session key length (unknown purpose) */
1140 "%c%c" /* session key allocated space (unknown purpose) */
1141 "%c%c" /* session key offset (unknown purpose) */
1142 "%c%c" /* 2 zeroes */
1144 "%c%c%c%c" /* flags */
1149 /* LanManager response */
1152 0, /* zero termination */
1153 0,0,0, /* type-3 long, the 24 upper bits */
1155 SHORTPAIR(0x18), /* LanManager response length, twice */
1157 SHORTPAIR(lmrespoff),
1161 SHORTPAIR(0x18), /* NT-response length, twice */
1163 SHORTPAIR(ntrespoff),
1191 LONGQUARTET(ntlm->flags));
1192 DEBUGASSERT(size==64);
1194 DEBUGASSERT(size == (size_t)lmrespoff);
1195 /* We append the binary hashes */
1196 if(size < (sizeof(ntlmbuf) - 0x18)) {
1197 memcpy(&ntlmbuf[size], lmresp, 0x18);
1202 fprintf(stderr, "**** TYPE3 header lmresp=");
1203 print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
1207 if(size < (sizeof(ntlmbuf) - 0x18)) {
1208 DEBUGASSERT(size == (size_t)ntrespoff);
1209 memcpy(&ntlmbuf[size], ntresp, 0x18);
1214 fprintf(stderr, "\n ntresp=");
1215 print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
1221 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
1222 LONGQUARTET(ntlm->flags), ntlm->flags);
1223 print_flags(stderr, ntlm->flags);
1224 fprintf(stderr, "\n****\n");
1228 /* Make sure that the domain, user and host strings fit in the target
1229 buffer before we copy them there. */
1230 if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) {
1231 failf(conn->data, "user + domain + host name too big");
1232 return CURLE_OUT_OF_MEMORY;
1235 DEBUGASSERT(size == domoff);
1236 memcpy(&ntlmbuf[size], domain, domlen);
1239 DEBUGASSERT(size == useroff);
1240 memcpy(&ntlmbuf[size], user, userlen);
1243 DEBUGASSERT(size == hostoff);
1244 memcpy(&ntlmbuf[size], host, hostlen);
1247 #ifdef CURL_DOES_CONVERSIONS
1248 /* convert domain, user, and host to ASCII but leave the rest as-is */
1249 if(CURLE_OK != Curl_convert_to_network(conn->data,
1250 (char *)&ntlmbuf[domoff],
1252 return CURLE_CONV_FAILED;
1254 #endif /* CURL_DOES_CONVERSIONS */
1258 /* convert the binary blob into base64 */
1259 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
1262 Curl_safefree(*allocuserpwd);
1263 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
1266 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
1270 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
1272 ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
1277 case NTLMSTATE_TYPE3:
1278 /* connection is already authenticated,
1279 * don't send a header in future requests */
1281 free(*allocuserpwd);
1293 Curl_ntlm_cleanup(struct connectdata *conn)
1295 #ifdef USE_WINDOWS_SSPI
1296 ntlm_sspi_cleanup(&conn->ntlm);
1297 ntlm_sspi_cleanup(&conn->proxyntlm);
1304 #endif /* USE_NTLM */
1305 #endif /* !CURL_DISABLE_HTTP */