curl_ntlm_msgs.c: Corrected small spelling mistake in comments
[platform/upstream/curl.git] / lib / curl_ntlm_msgs.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "setup.h"
24
25 #ifdef USE_NTLM
26
27 /*
28  * NTLM details:
29  *
30  * http://davenport.sourceforge.net/ntlm.html
31  * http://www.innovation.ch/java/ntlm.html
32  */
33
34 #define DEBUG_ME 0
35
36 #ifdef USE_SSLEAY
37
38 #  ifdef USE_OPENSSL
39 #    include <openssl/des.h>
40 #    ifndef OPENSSL_NO_MD4
41 #      include <openssl/md4.h>
42 #    endif
43 #    include <openssl/md5.h>
44 #    include <openssl/ssl.h>
45 #    include <openssl/rand.h>
46 #  else
47 #    include <des.h>
48 #    ifndef OPENSSL_NO_MD4
49 #      include <md4.h>
50 #    endif
51 #    include <md5.h>
52 #    include <ssl.h>
53 #    include <rand.h>
54 #  endif
55 #  include "ssluse.h"
56
57 #elif defined(USE_GNUTLS_NETTLE)
58
59 #  include <nettle/md5.h>
60 #  include <gnutls/gnutls.h>
61 #  include <gnutls/crypto.h>
62 #  define MD5_DIGEST_LENGTH 16
63
64 #elif defined(USE_GNUTLS)
65
66 #  include <gcrypt.h>
67 #  include "gtls.h"
68 #  define MD5_DIGEST_LENGTH 16
69 #  define MD4_DIGEST_LENGTH 16
70
71 #elif defined(USE_NSS)
72
73 #  include <nss.h>
74 #  include <pk11pub.h>
75 #  include <hasht.h>
76 #  include "nssg.h"
77 #  include "curl_md4.h"
78 #  define MD5_DIGEST_LENGTH MD5_LENGTH
79
80 #elif defined(USE_WINDOWS_SSPI)
81 #  include "curl_sspi.h"
82 #else
83 #  error "Can't compile NTLM support without a crypto library."
84 #endif
85
86 #include "urldata.h"
87 #include "non-ascii.h"
88 #include "sendf.h"
89 #include "curl_base64.h"
90 #include "curl_ntlm_core.h"
91 #include "curl_gethostname.h"
92 #include "curl_memory.h"
93
94 #define BUILDING_CURL_NTLM_MSGS_C
95 #include "curl_ntlm_msgs.h"
96
97 #define _MPRINTF_REPLACE /* use our functions only */
98 #include <curl/mprintf.h>
99
100 /* The last #include file should be: */
101 #include "memdebug.h"
102
103 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
104 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
105
106 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
107 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
108   (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
109
110 #if DEBUG_ME
111 # define DEBUG_OUT(x) x
112 static void ntlm_print_flags(FILE *handle, unsigned long flags)
113 {
114   if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
115     fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
116   if(flags & NTLMFLAG_NEGOTIATE_OEM)
117     fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
118   if(flags & NTLMFLAG_REQUEST_TARGET)
119     fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
120   if(flags & (1<<3))
121     fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
122   if(flags & NTLMFLAG_NEGOTIATE_SIGN)
123     fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
124   if(flags & NTLMFLAG_NEGOTIATE_SEAL)
125     fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
126   if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
127     fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
128   if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
129     fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
130   if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
131     fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
132   if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
133     fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
134   if(flags & (1<<10))
135     fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
136   if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
137     fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
138   if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
139     fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
140   if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
141     fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
142   if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
143     fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
144   if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
145     fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
146   if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
147     fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
148   if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
149     fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
150   if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
151     fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
152   if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
153     fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
154   if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
155     fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
156   if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
157     fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
158   if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
159     fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
160   if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
161     fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
162   if(flags & (1<<24))
163     fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
164   if(flags & (1<<25))
165     fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
166   if(flags & (1<<26))
167     fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
168   if(flags & (1<<27))
169     fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
170   if(flags & (1<<28))
171     fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
172   if(flags & NTLMFLAG_NEGOTIATE_128)
173     fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
174   if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
175     fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
176   if(flags & NTLMFLAG_NEGOTIATE_56)
177     fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
178 }
179
180 static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
181 {
182   const char *p = buf;
183   (void)handle;
184   fprintf(stderr, "0x");
185   while(len-- > 0)
186     fprintf(stderr, "%02.2x", (unsigned int)*p++);
187 }
188 #else
189 # define DEBUG_OUT(x) Curl_nop_stmt
190 #endif
191
192 #ifndef USE_WINDOWS_SSPI
193 /*
194  * This function converts from the little endian format used in the
195  * incoming package to whatever endian format we're using natively.
196  * Argument is a pointer to a 4 byte buffer.
197  */
198 static unsigned int readint_le(unsigned char *buf)
199 {
200   return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
201     ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
202 }
203 #endif
204
205 /*
206   NTLM message structure notes:
207
208   A 'short' is a 'network short', a little-endian 16-bit unsigned value.
209
210   A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
211
212   A 'security buffer' represents a triplet used to point to a buffer,
213   consisting of two shorts and one long:
214
215     1. A 'short' containing the length of the buffer content in bytes.
216     2. A 'short' containing the allocated space for the buffer in bytes.
217     3. A 'long' containing the offset to the start of the buffer in bytes,
218        from the beginning of the NTLM message.
219 */
220
221 /*
222  * Curl_ntlm_decode_type2_message()
223  *
224  * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP
225  * or POP3 server. The message is first decoded from a base64 string into a
226  * raw ntlm message and checked for validity before the appropriate data for
227  * creating a type-3 message is written to the given ntlm data structure.
228  *
229  * Parameters:
230  *
231  * data    [in]     - Pointer to session handle.
232  * header  [in]     - Pointer to the input buffer.
233  * ntlm    [in]     - Pointer to ntlm data struct being used and modified.
234  *
235  * Returns CURLE_OK on success.
236  */
237 CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
238                                         const char* header,
239                                         struct ntlmdata* ntlm)
240 {
241 #ifndef USE_WINDOWS_SSPI
242   static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
243 #endif
244
245   /* NTLM type-2 message structure:
246
247           Index  Description            Content
248             0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
249                                         (0x4e544c4d53535000)
250             8    NTLM Message Type      long (0x02000000)
251            12    Target Name            security buffer
252            20    Flags                  long
253            24    Challenge              8 bytes
254           (32)   Context                8 bytes (two consecutive longs) (*)
255           (40)   Target Information     security buffer (*)
256           (48)   OS Version Structure   8 bytes (*)
257   32 (48) (56)   Start of data block    (*)
258                                         (*) -> Optional
259   */
260
261   size_t size = 0;
262   unsigned char *buffer = NULL;
263   CURLcode error;
264
265 #if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
266   (void)data;
267 #endif
268
269   error = Curl_base64_decode(header, &buffer, &size);
270   if(error)
271     return error;
272
273   if(!buffer) {
274     infof(data, "NTLM handshake failure (unhandled condition)\n");
275     return CURLE_REMOTE_ACCESS_DENIED;
276   }
277
278 #ifdef USE_WINDOWS_SSPI
279   ntlm->type_2 = malloc(size + 1);
280   if(ntlm->type_2 == NULL) {
281     free(buffer);
282     return CURLE_OUT_OF_MEMORY;
283   }
284   ntlm->n_type_2 = (unsigned long)size;
285   memcpy(ntlm->type_2, buffer, size);
286 #else
287   ntlm->flags = 0;
288
289   if((size < 32) ||
290      (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
291      (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
292     /* This was not a good enough type-2 message */
293     free(buffer);
294     infof(data, "NTLM handshake failure (bad type-2 message)\n");
295     return CURLE_REMOTE_ACCESS_DENIED;
296   }
297
298   ntlm->flags = readint_le(&buffer[20]);
299   memcpy(ntlm->nonce, &buffer[24], 8);
300
301   DEBUG_OUT({
302     fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
303     ntlm_print_flags(stderr, ntlm->flags);
304     fprintf(stderr, "\n                  nonce=");
305     ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
306     fprintf(stderr, "\n****\n");
307     fprintf(stderr, "**** Header %s\n ", header);
308   });
309 #endif
310   free(buffer);
311
312   return CURLE_OK;
313 }
314
315 #ifdef USE_WINDOWS_SSPI
316 void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
317 {
318   if(ntlm->type_2) {
319     free(ntlm->type_2);
320     ntlm->type_2 = NULL;
321   }
322   if(ntlm->has_handles) {
323     s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
324     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
325     ntlm->has_handles = 0;
326   }
327   if(ntlm->p_identity) {
328     if(ntlm->identity.User) free(ntlm->identity.User);
329     if(ntlm->identity.Password) free(ntlm->identity.Password);
330     if(ntlm->identity.Domain) free(ntlm->identity.Domain);
331     ntlm->p_identity = NULL;
332   }
333 }
334 #endif
335
336 #ifndef USE_WINDOWS_SSPI
337 /* copy the source to the destination and fill in zeroes in every
338    other destination byte! */
339 static void unicodecpy(unsigned char *dest,
340                        const char *src, size_t length)
341 {
342   size_t i;
343   for(i = 0; i < length; i++) {
344     dest[2 * i] = (unsigned char)src[i];
345     dest[2 * i + 1] = '\0';
346   }
347 }
348 #endif
349
350 /*
351  * Curl_ntlm_create_type1_message()
352  *
353  * This is used to generate an already encoded NTLM type-1 message ready
354  * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
355  * using the appropriate compile time crypo API.
356  *
357  * Parameters:
358  *
359  * userp   [in]     - The user name in the format User or Domain\User.
360  * passdwp [in]     - The user's password.
361  * ntlm    [in/out] - The ntlm data struct being used and modified.
362  * outptr  [in/out] - The address where a pointer to newly allocated memory
363  *                    holding the result will be stored upon completion.
364  * outlen  [out]    - The length of the output message.
365  *
366  * Returns CURLE_OK on success.
367  */
368 CURLcode Curl_ntlm_create_type1_message(const char *userp,
369                                         const char *passwdp,
370                                         struct ntlmdata *ntlm,
371                                         char **outptr,
372                                         size_t *outlen)
373 {
374   /* NTLM type-1 message structure:
375
376        Index  Description            Content
377          0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
378                                      (0x4e544c4d53535000)
379          8    NTLM Message Type      long (0x01000000)
380         12    Flags                  long
381        (16)   Supplied Domain        security buffer (*)
382        (24)   Supplied Workstation   security buffer (*)
383        (32)   OS Version Structure   8 bytes (*)
384   (32) (40)   Start of data block    (*)
385                                      (*) -> Optional
386   */
387
388   unsigned char ntlmbuf[NTLM_BUFSIZE];
389   size_t size;
390
391 #ifdef USE_WINDOWS_SSPI
392
393   SecBuffer buf;
394   SecBufferDesc desc;
395   SECURITY_STATUS status;
396   ULONG attrs;
397   const char *dest = "";
398   const char *user;
399   const char *domain = "";
400   size_t userlen = 0;
401   size_t domlen = 0;
402   size_t passwdlen = 0;
403   TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
404
405   Curl_ntlm_sspi_cleanup(ntlm);
406
407   user = strchr(userp, '\\');
408   if(!user)
409     user = strchr(userp, '/');
410
411   if(user) {
412     domain = userp;
413     domlen = user - userp;
414     user++;
415   }
416   else {
417     user = userp;
418     domain = "";
419     domlen = 0;
420   }
421
422   if(user)
423     userlen = strlen(user);
424
425   if(passwdp)
426     passwdlen = strlen(passwdp);
427
428   if(userlen > 0) {
429     /* note: initialize all of this before doing the mallocs so that
430      * it can be cleaned up later without leaking memory.
431      */
432     ntlm->p_identity = &ntlm->identity;
433     memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
434     if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
435       return CURLE_OUT_OF_MEMORY;
436
437     ntlm->identity.UserLength = (unsigned long)userlen;
438     if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
439       return CURLE_OUT_OF_MEMORY;
440
441     ntlm->identity.PasswordLength = (unsigned long)strlen(passwdp);
442     if((ntlm->identity.Domain = malloc(domlen + 1)) == NULL)
443       return CURLE_OUT_OF_MEMORY;
444
445     strncpy((char *)ntlm->identity.Domain, domain, domlen);
446     ntlm->identity.Domain[domlen] = '\0';
447     ntlm->identity.DomainLength = (unsigned long)domlen;
448     ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
449   }
450   else
451     ntlm->p_identity = NULL;
452
453   status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM",
454                                                SECPKG_CRED_OUTBOUND, NULL,
455                                                ntlm->p_identity, NULL, NULL,
456                                                &ntlm->handle, &tsDummy);
457   if(status != SEC_E_OK)
458     return CURLE_OUT_OF_MEMORY;
459
460   desc.ulVersion = SECBUFFER_VERSION;
461   desc.cBuffers  = 1;
462   desc.pBuffers  = &buf;
463   buf.cbBuffer   = NTLM_BUFSIZE;
464   buf.BufferType = SECBUFFER_TOKEN;
465   buf.pvBuffer   = ntlmbuf;
466
467   status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
468                                                 (void *)dest,
469                                                 ISC_REQ_CONFIDENTIALITY |
470                                                 ISC_REQ_REPLAY_DETECT |
471                                                 ISC_REQ_CONNECTION,
472                                                 0, SECURITY_NETWORK_DREP,
473                                                 NULL, 0,
474                                                 &ntlm->c_handle, &desc,
475                                                 &attrs, &tsDummy);
476
477   if(status == SEC_I_COMPLETE_AND_CONTINUE ||
478      status == SEC_I_CONTINUE_NEEDED)
479     s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
480   else if(status != SEC_E_OK) {
481     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
482     return CURLE_RECV_ERROR;
483   }
484
485   ntlm->has_handles = 1;
486   size = buf.cbBuffer;
487
488 #else
489
490   const char *host = "";              /* empty */
491   const char *domain = "";            /* empty */
492   size_t hostlen = 0;
493   size_t domlen = 0;
494   size_t hostoff = 0;
495   size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
496                                          domain are empty */
497   (void)userp;
498   (void)passwdp;
499   (void)ntlm;
500
501 #if USE_NTLM2SESSION
502 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
503 #else
504 #define NTLM2FLAG 0
505 #endif
506   snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
507            NTLMSSP_SIGNATURE "%c"
508            "\x01%c%c%c" /* 32-bit type = 1 */
509            "%c%c%c%c"   /* 32-bit NTLM flag field */
510            "%c%c"       /* domain length */
511            "%c%c"       /* domain allocated space */
512            "%c%c"       /* domain name offset */
513            "%c%c"       /* 2 zeroes */
514            "%c%c"       /* host length */
515            "%c%c"       /* host allocated space */
516            "%c%c"       /* host name offset */
517            "%c%c"       /* 2 zeroes */
518            "%s"         /* host name */
519            "%s",        /* domain string */
520            0,           /* trailing zero */
521            0, 0, 0,     /* part of type-1 long */
522
523            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
524                        NTLMFLAG_REQUEST_TARGET |
525                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
526                        NTLM2FLAG |
527                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
528            SHORTPAIR(domlen),
529            SHORTPAIR(domlen),
530            SHORTPAIR(domoff),
531            0, 0,
532            SHORTPAIR(hostlen),
533            SHORTPAIR(hostlen),
534            SHORTPAIR(hostoff),
535            0, 0,
536            host,  /* this is empty */
537            domain /* this is empty */);
538
539   /* Initial packet length */
540   size = 32 + hostlen + domlen;
541
542 #endif
543
544   DEBUG_OUT({
545     fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
546             "0x%08.8x ",
547             LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
548                         NTLMFLAG_REQUEST_TARGET |
549                         NTLMFLAG_NEGOTIATE_NTLM_KEY |
550                         NTLM2FLAG |
551                         NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
552             NTLMFLAG_NEGOTIATE_OEM |
553             NTLMFLAG_REQUEST_TARGET |
554             NTLMFLAG_NEGOTIATE_NTLM_KEY |
555             NTLM2FLAG |
556             NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
557     ntlm_print_flags(stderr,
558                      NTLMFLAG_NEGOTIATE_OEM |
559                      NTLMFLAG_REQUEST_TARGET |
560                      NTLMFLAG_NEGOTIATE_NTLM_KEY |
561                      NTLM2FLAG |
562                      NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
563     fprintf(stderr, "\n****\n");
564   });
565
566   /* Return with binary blob encoded into base64 */
567   return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
568 }
569
570 /*
571  * Curl_ntlm_create_type3_message()
572  *
573  * This is used to generate an already encoded NTLM type-3 message ready
574  * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
575  * using the appropriate compile time crypo API.
576  *
577  * Parameters:
578  *
579  * data    [in]     - The session handle.
580  * userp   [in]     - The user name in the format User or Domain\User.
581  * passdwp [in]     - The user's password.
582  * ntlm    [in/out] - The ntlm data struct being used and modified.
583  * outptr  [in/out] - The address where a pointer to newly allocated memory
584  *                    holding the result will be stored upon completion.
585  * outlen  [out]    - The length of the output message.
586  *
587  * Returns CURLE_OK on success.
588  */
589 CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
590                                         const char *userp,
591                                         const char *passwdp,
592                                         struct ntlmdata *ntlm,
593                                         char **outptr,
594                                         size_t *outlen)
595 {
596   /* NTLM type-3 message structure:
597
598           Index  Description            Content
599             0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
600                                         (0x4e544c4d53535000)
601             8    NTLM Message Type      long (0x03000000)
602            12    LM/LMv2 Response       security buffer
603            20    NTLM/NTLMv2 Response   security buffer
604            28    Target Name            security buffer
605            36    User Name              security buffer
606            44    Workstation Name       security buffer
607           (52)   Session Key            security buffer (*)
608           (60)   Flags                  long (*)
609           (64)   OS Version Structure   8 bytes (*)
610   52 (64) (72)   Start of data block
611                                           (*) -> Optional
612   */
613
614   unsigned char ntlmbuf[NTLM_BUFSIZE];
615   size_t size;
616
617 #ifdef USE_WINDOWS_SSPI
618   const char *dest = "";
619   SecBuffer type_2;
620   SecBuffer type_3;
621   SecBufferDesc type_2_desc;
622   SecBufferDesc type_3_desc;
623   SECURITY_STATUS status;
624   ULONG attrs;
625   TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
626
627   (void)passwdp;
628   (void)userp;
629   (void)data;
630
631   type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
632   type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
633   type_2_desc.pBuffers  = &type_2;
634   type_3_desc.pBuffers  = &type_3;
635
636   type_2.BufferType = SECBUFFER_TOKEN;
637   type_2.pvBuffer   = ntlm->type_2;
638   type_2.cbBuffer   = ntlm->n_type_2;
639   type_3.BufferType = SECBUFFER_TOKEN;
640   type_3.pvBuffer   = ntlmbuf;
641   type_3.cbBuffer   = NTLM_BUFSIZE;
642
643   status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle,
644                                                 &ntlm->c_handle,
645                                                 (void *)dest,
646                                                 ISC_REQ_CONFIDENTIALITY |
647                                                 ISC_REQ_REPLAY_DETECT |
648                                                 ISC_REQ_CONNECTION,
649                                                 0, SECURITY_NETWORK_DREP,
650                                                 &type_2_desc,
651                                                 0, &ntlm->c_handle,
652                                                 &type_3_desc,
653                                                 &attrs, &tsDummy);
654   if(status != SEC_E_OK)
655     return CURLE_RECV_ERROR;
656
657   size = type_3.cbBuffer;
658
659   Curl_ntlm_sspi_cleanup(ntlm);
660
661 #else
662   int lmrespoff;
663   unsigned char lmresp[24]; /* fixed-size */
664 #if USE_NTRESPONSES
665   int ntrespoff;
666   unsigned char ntresp[24]; /* fixed-size */
667 #endif
668   bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
669   char host[HOSTNAME_MAX + 1] = "";
670   const char *user;
671   const char *domain = "";
672   size_t hostoff = 0;
673   size_t useroff = 0;
674   size_t domoff = 0;
675   size_t hostlen = 0;
676   size_t userlen = 0;
677   size_t domlen = 0;
678   CURLcode res;
679
680   user = strchr(userp, '\\');
681   if(!user)
682     user = strchr(userp, '/');
683
684   if(user) {
685     domain = userp;
686     domlen = (user - domain);
687     user++;
688   }
689   else
690     user = userp;
691
692   if(user)
693     userlen = strlen(user);
694
695   /* Get the machine's un-qualified host name as NTLM doesn't like the fully
696      qualified domain name */
697   if(Curl_gethostname(host, sizeof(host))) {
698     infof(data, "gethostname() failed, continuing without!\n");
699     hostlen = 0;
700   }
701   else {
702     hostlen = strlen(host);
703   }
704
705   if(unicode) {
706     domlen = domlen * 2;
707     userlen = userlen * 2;
708     hostlen = hostlen * 2;
709   }
710
711 #if USE_NTLM2SESSION
712   /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
713   if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
714     unsigned char ntbuffer[0x18];
715     unsigned char tmp[0x18];
716     unsigned char md5sum[MD5_DIGEST_LENGTH];
717     unsigned char entropy[8];
718
719     /* Need to create 8 bytes random data */
720 #ifdef USE_SSLEAY
721     MD5_CTX MD5pw;
722     Curl_ossl_seed(data); /* Initiate the seed if not already done */
723     RAND_bytes(entropy, 8);
724 #elif defined(USE_GNUTLS_NETTLE)
725     struct md5_ctx MD5pw;
726     gnutls_rnd(GNUTLS_RND_RANDOM, entropy, 8);
727 #elif defined(USE_GNUTLS)
728     gcry_md_hd_t MD5pw;
729     Curl_gtls_seed(data); /* Initiate the seed if not already done */
730     gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
731 #elif defined(USE_NSS)
732     PK11Context *MD5pw;
733     unsigned int MD5len;
734     Curl_nss_seed(data);  /* Initiate the seed if not already done */
735     PK11_GenerateRandom(entropy, 8);
736 #endif
737
738     /* 8 bytes random data as challenge in lmresp */
739     memcpy(lmresp, entropy, 8);
740
741     /* Pad with zeros */
742     memset(lmresp + 8, 0, 0x10);
743
744     /* Fill tmp with challenge(nonce?) + entropy */
745     memcpy(tmp, &ntlm->nonce[0], 8);
746     memcpy(tmp + 8, entropy, 8);
747
748 #ifdef USE_SSLEAY
749     MD5_Init(&MD5pw);
750     MD5_Update(&MD5pw, tmp, 16);
751     MD5_Final(md5sum, &MD5pw);
752 #elif defined(USE_GNUTLS_NETTLE)
753     md5_init(&MD5pw);
754     md5_update(&MD5pw, 16, tmp);
755     md5_digest(&MD5pw, 16, md5sum);
756 #elif defined(USE_GNUTLS)
757     gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
758     gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
759     memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
760     gcry_md_close(MD5pw);
761 #elif defined(USE_NSS)
762     MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
763     PK11_DigestOp(MD5pw, tmp, 16);
764     PK11_DigestFinal(MD5pw, md5sum, &MD5len, MD5_DIGEST_LENGTH);
765     PK11_DestroyContext(MD5pw, PR_TRUE);
766 #endif
767
768     /* We shall only use the first 8 bytes of md5sum, but the des
769        code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
770     if(CURLE_OUT_OF_MEMORY ==
771        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
772       return CURLE_OUT_OF_MEMORY;
773     Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
774
775     /* End of NTLM2 Session code */
776   }
777   else
778 #endif
779   {
780
781 #if USE_NTRESPONSES
782     unsigned char ntbuffer[0x18];
783 #endif
784     unsigned char lmbuffer[0x18];
785
786 #if USE_NTRESPONSES
787     if(CURLE_OUT_OF_MEMORY ==
788        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
789       return CURLE_OUT_OF_MEMORY;
790     Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
791 #endif
792
793     Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
794     Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
795     /* A safer but less compatible alternative is:
796      *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
797      * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
798   }
799
800   lmrespoff = 64; /* size of the message header */
801 #if USE_NTRESPONSES
802   ntrespoff = lmrespoff + 0x18;
803   domoff = ntrespoff + 0x18;
804 #else
805   domoff = lmrespoff + 0x18;
806 #endif
807   useroff = domoff + domlen;
808   hostoff = useroff + userlen;
809
810   /* Create the big type-3 message binary blob */
811   size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
812                   NTLMSSP_SIGNATURE "%c"
813                   "\x03%c%c%c"  /* 32-bit type = 3 */
814
815                   "%c%c"  /* LanManager length */
816                   "%c%c"  /* LanManager allocated space */
817                   "%c%c"  /* LanManager offset */
818                   "%c%c"  /* 2 zeroes */
819
820                   "%c%c"  /* NT-response length */
821                   "%c%c"  /* NT-response allocated space */
822                   "%c%c"  /* NT-response offset */
823                   "%c%c"  /* 2 zeroes */
824
825                   "%c%c"  /* domain length */
826                   "%c%c"  /* domain allocated space */
827                   "%c%c"  /* domain name offset */
828                   "%c%c"  /* 2 zeroes */
829
830                   "%c%c"  /* user length */
831                   "%c%c"  /* user allocated space */
832                   "%c%c"  /* user offset */
833                   "%c%c"  /* 2 zeroes */
834
835                   "%c%c"  /* host length */
836                   "%c%c"  /* host allocated space */
837                   "%c%c"  /* host offset */
838                   "%c%c"  /* 2 zeroes */
839
840                   "%c%c"  /* session key length (unknown purpose) */
841                   "%c%c"  /* session key allocated space (unknown purpose) */
842                   "%c%c"  /* session key offset (unknown purpose) */
843                   "%c%c"  /* 2 zeroes */
844
845                   "%c%c%c%c",  /* flags */
846
847                   /* domain string */
848                   /* user string */
849                   /* host string */
850                   /* LanManager response */
851                   /* NT response */
852
853                   0,                /* zero termination */
854                   0, 0, 0,          /* type-3 long, the 24 upper bits */
855
856                   SHORTPAIR(0x18),  /* LanManager response length, twice */
857                   SHORTPAIR(0x18),
858                   SHORTPAIR(lmrespoff),
859                   0x0, 0x0,
860
861 #if USE_NTRESPONSES
862                   SHORTPAIR(0x18),  /* NT-response length, twice */
863                   SHORTPAIR(0x18),
864                   SHORTPAIR(ntrespoff),
865                   0x0, 0x0,
866 #else
867                   0x0, 0x0,
868                   0x0, 0x0,
869                   0x0, 0x0,
870                   0x0, 0x0,
871 #endif
872                   SHORTPAIR(domlen),
873                   SHORTPAIR(domlen),
874                   SHORTPAIR(domoff),
875                   0x0, 0x0,
876
877                   SHORTPAIR(userlen),
878                   SHORTPAIR(userlen),
879                   SHORTPAIR(useroff),
880                   0x0, 0x0,
881
882                   SHORTPAIR(hostlen),
883                   SHORTPAIR(hostlen),
884                   SHORTPAIR(hostoff),
885                   0x0, 0x0,
886
887                   0x0, 0x0,
888                   0x0, 0x0,
889                   0x0, 0x0,
890                   0x0, 0x0,
891
892                   LONGQUARTET(ntlm->flags));
893
894   DEBUGASSERT(size == 64);
895   DEBUGASSERT(size == (size_t)lmrespoff);
896
897   /* We append the binary hashes */
898   if(size < (NTLM_BUFSIZE - 0x18)) {
899     memcpy(&ntlmbuf[size], lmresp, 0x18);
900     size += 0x18;
901   }
902
903   DEBUG_OUT({
904     fprintf(stderr, "**** TYPE3 header lmresp=");
905     ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
906   });
907
908 #if USE_NTRESPONSES
909   if(size < (NTLM_BUFSIZE - 0x18)) {
910     DEBUGASSERT(size == (size_t)ntrespoff);
911     memcpy(&ntlmbuf[size], ntresp, 0x18);
912     size += 0x18;
913   }
914
915   DEBUG_OUT({
916     fprintf(stderr, "\n   ntresp=");
917     ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
918   });
919
920 #endif
921
922   DEBUG_OUT({
923     fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
924             LONGQUARTET(ntlm->flags), ntlm->flags);
925     ntlm_print_flags(stderr, ntlm->flags);
926     fprintf(stderr, "\n****\n");
927   });
928
929   /* Make sure that the domain, user and host strings fit in the
930      buffer before we copy them there. */
931   if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
932     failf(data, "user + domain + host name too big");
933     return CURLE_OUT_OF_MEMORY;
934   }
935
936   DEBUGASSERT(size == domoff);
937   if(unicode)
938     unicodecpy(&ntlmbuf[size], domain, domlen / 2);
939   else
940     memcpy(&ntlmbuf[size], domain, domlen);
941
942   size += domlen;
943
944   DEBUGASSERT(size == useroff);
945   if(unicode)
946     unicodecpy(&ntlmbuf[size], user, userlen / 2);
947   else
948     memcpy(&ntlmbuf[size], user, userlen);
949
950   size += userlen;
951
952   DEBUGASSERT(size == hostoff);
953   if(unicode)
954     unicodecpy(&ntlmbuf[size], host, hostlen / 2);
955   else
956     memcpy(&ntlmbuf[size], host, hostlen);
957
958   size += hostlen;
959
960   /* Convert domain, user, and host to ASCII but leave the rest as-is */
961   res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
962                                 size - domoff);
963   if(res)
964     return CURLE_CONV_FAILED;
965
966 #endif
967
968   /* Return with binary blob encoded into base64 */
969   return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
970 }
971
972 #endif /* USE_NTLM */