Coverage Report

Created: 2023-03-26 07:33

/src/wget/src/http-ntlm.c
Line
Count
Source (jump to first uncovered line)
1
/* NTLM code.
2
   Copyright (C) 2005-2011, 2015, 2018-2023 Free Software Foundation,
3
   Inc.
4
   Contributed by Daniel Stenberg.
5
6
This file is part of GNU Wget.
7
8
GNU Wget is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
 (at your option) any later version.
12
13
GNU Wget is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
18
You should have received a copy of the GNU General Public License
19
along with Wget.  If not, see <http://www.gnu.org/licenses/>.
20
21
Additional permission under GNU GPL version 3 section 7
22
23
If you modify this program, or any covered work, by linking or
24
combining it with the OpenSSL project's OpenSSL library (or a
25
modified version of that library), containing parts covered by the
26
terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
27
grants you additional permission to convey the resulting work.
28
Corresponding Source for a non-source form of such a combination
29
shall include the source code for the parts of OpenSSL used as well
30
as that of the covered work.  */
31
32
#include "wget.h"
33
34
/* NTLM details:
35
36
   http://davenport.sourceforge.net/ntlm.html
37
   http://www.innovation.ch/java/ntlm.html
38
39
*/
40
41
#include <stdio.h>
42
#include <string.h>
43
#include <stdlib.h>
44
45
#include "utils.h"
46
#include "http-ntlm.h"
47
48
#ifdef HAVE_NETTLE
49
# include <nettle/md4.h>
50
# include <nettle/des.h>
51
#else
52
# include <openssl/des.h>
53
# include <openssl/md4.h>
54
# include <openssl/opensslv.h>
55
56
# if OPENSSL_VERSION_NUMBER < 0x00907001L
57
#  define DES_key_schedule des_key_schedule
58
#  define DES_cblock des_cblock
59
#  define DES_set_odd_parity des_set_odd_parity
60
#  define DES_set_key des_set_key
61
#  define DES_ecb_encrypt des_ecb_encrypt
62
63
/* This is how things were done in the old days */
64
#  define DESKEY(x) x
65
#  define DESKEYARG(x) x
66
# else
67
/* Modern version */
68
#  define DESKEYARG(x) *x
69
#  define DESKEY(x) &x
70
# endif
71
72
#endif
73
74
/* Define this to make the type-3 message include the NT response message */
75
#define USE_NTRESPONSES 1
76
77
78
/* Flag bits definitions available at on
79
   http://davenport.sourceforge.net/ntlm.html */
80
81
#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
82
#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
83
84
/*
85
  (*) = A "security buffer" is a triplet consisting of two shorts and one
86
  long:
87
88
  1. a 'short' containing the length of the buffer in bytes
89
  2. a 'short' containing the allocated space for the buffer in bytes
90
  3. a 'long' containing the offset to the start of the buffer from the
91
     beginning of the NTLM message, in bytes.
92
*/
93
94
/* return true on success, false otherwise */
95
bool
96
ntlm_input (struct ntlmdata *ntlm, const char *header)
97
0
{
98
0
  if (0 != strncmp (header, "NTLM", 4))
99
0
    return false;
100
101
0
  header += 4;
102
0
  while (*header && c_isspace(*header))
103
0
    header++;
104
105
0
  if (*header)
106
0
    {
107
      /* We got a type-2 message here:
108
109
         Index   Description         Content
110
         0       NTLMSSP Signature   Null-terminated ASCII "NTLMSSP"
111
                                     (0x4e544c4d53535000)
112
         8       NTLM Message Type   long (0x02000000)
113
         12      Target Name         security buffer(*)
114
         20      Flags               long
115
         24      Challenge           8 bytes
116
         (32)    Context (optional)  8 bytes (two consecutive longs)
117
         (40)    Target Information  (optional) security buffer(*)
118
         32 (48) start of data block
119
      */
120
0
      ssize_t size;
121
0
      char buffer[48]; // decode 48 bytes needs ((48 + 2) / 3) * 4 + 1 bytes
122
123
0
      DEBUGP (("Received a type-2 NTLM message.\n"));
124
125
0
      size = wget_base64_decode (header, buffer, sizeof (buffer));
126
0
      if (size < 0)
127
0
        return false;           /* malformed base64 from server */
128
129
0
      ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
130
131
0
      if ((size_t) size >= sizeof (buffer))
132
        /* the nonce of interest is index [24 .. 31], 8 bytes */
133
0
        memcpy (ntlm->nonce, &buffer[24], 8);
134
135
      /* at index decimal 20, there's a 32bit NTLM flag field */
136
0
    }
137
0
  else
138
0
    {
139
0
      if (ntlm->state == NTLMSTATE_LAST)
140
0
        {
141
0
          DEBUGP (("NTLM auth restarted.\n"));
142
          /* no return, continue */
143
0
        }
144
0
      else if (ntlm->state == NTLMSTATE_TYPE3)
145
0
        {
146
0
          DEBUGP (("NTLM handshake rejected.\n"));
147
0
          ntlm->state = NTLMSTATE_NONE;
148
0
          return false;
149
0
        }
150
0
      else if (ntlm->state >= NTLMSTATE_TYPE1)
151
0
        {
152
0
          DEBUGP (("Unexpected empty NTLM message.\n"));
153
0
          return false; /* this is an error */
154
0
        }
155
156
0
      DEBUGP (("Empty NTLM message, (re)starting transaction.\n"));
157
0
      ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
158
0
    }
159
160
0
  return true;
161
0
}
162
163
/*
164
 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
165
 * key schedule ks is also set.
166
 */
167
#ifdef HAVE_NETTLE
168
static void
169
setup_des_key(unsigned char *key_56,
170
              struct des_ctx *des)
171
0
{
172
0
  unsigned char key[8];
173
174
0
  key[0] = key_56[0];
175
0
  key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
176
0
  key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
177
0
  key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
178
0
  key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
179
0
  key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
180
0
  key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
181
0
  key[7] =  (key_56[6] << 1) & 0xFF;
182
183
0
  nettle_des_set_key(des, key);
184
0
}
185
#else
186
static void
187
setup_des_key(unsigned char *key_56,
188
              DES_key_schedule DESKEYARG(ks))
189
{
190
  DES_cblock key;
191
192
  key[0] = key_56[0];
193
  key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
194
  key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
195
  key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
196
  key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
197
  key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
198
  key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
199
  key[7] =  (key_56[6] << 1) & 0xFF;
200
201
  DES_set_odd_parity(&key);
202
  DES_set_key(&key, ks);
203
}
204
#endif
205
206
 /*
207
  * takes a 21 byte array and treats it as 3 56-bit DES keys. The
208
  * 8 byte plaintext is encrypted with each key and the resulting 24
209
  * bytes are stored in the results array.
210
  */
211
static void
212
calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results)
213
0
{
214
0
#ifdef HAVE_NETTLE
215
0
  struct des_ctx des;
216
217
0
  setup_des_key(keys, &des);
218
0
  nettle_des_encrypt(&des, 8, results, plaintext);
219
220
0
  setup_des_key(keys + 7, &des);
221
0
  nettle_des_encrypt(&des, 8, results + 8, plaintext);
222
223
0
  setup_des_key(keys + 14, &des);
224
0
  nettle_des_encrypt(&des, 8, results + 16, plaintext);
225
#else
226
  DES_key_schedule ks;
227
228
  setup_des_key(keys, DESKEY(ks));
229
  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
230
                  DESKEY(ks), DES_ENCRYPT);
231
232
  setup_des_key(keys+7, DESKEY(ks));
233
  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
234
                  DESKEY(ks), DES_ENCRYPT);
235
236
  setup_des_key(keys+14, DESKEY(ks));
237
  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
238
                  DESKEY(ks), DES_ENCRYPT);
239
#endif
240
0
}
241
242
/*
243
 * Set up lanmanager and nt hashed passwords
244
 */
245
static void
246
mkhash(const char *password,
247
       unsigned char *nonce,    /* 8 bytes */
248
       unsigned char *lmresp    /* must fit 0x18 bytes */
249
#ifdef USE_NTRESPONSES
250
       , unsigned char *ntresp  /* must fit 0x18 bytes */
251
#endif
252
  )
253
0
{
254
0
  unsigned char lmbuffer[21];
255
0
#ifdef USE_NTRESPONSES
256
0
  unsigned char ntbuffer[21];
257
0
#endif
258
0
  unsigned char pw[14];
259
0
  static const unsigned char magic[] = {
260
0
    0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
261
0
  };
262
0
  size_t i, len = strlen(password);
263
264
  /* make it fit at least 14 bytes */
265
266
0
  if (len > sizeof (pw))
267
0
    len = sizeof (pw);
268
269
0
  for (i = 0; i < len; i++)
270
0
    pw[i] = (unsigned char) c_toupper (password[i]);
271
272
0
  for (; i < sizeof (pw); i++)
273
0
    pw[i] = 0;
274
275
0
  {
276
    /* create LanManager hashed password */
277
0
#ifdef HAVE_NETTLE
278
0
    struct des_ctx des;
279
280
0
    setup_des_key(pw, &des);
281
0
    nettle_des_encrypt(&des, 8, lmbuffer, magic);
282
283
0
    setup_des_key(pw + 7, &des);
284
0
    nettle_des_encrypt(&des, 8, lmbuffer + 8, magic);
285
#else
286
    DES_key_schedule ks;
287
288
    setup_des_key(pw, DESKEY (ks));
289
    DES_ecb_encrypt((DES_cblock *) magic, (DES_cblock *) lmbuffer,
290
                    DESKEY (ks), DES_ENCRYPT);
291
292
    setup_des_key(pw+7, DESKEY (ks));
293
    DES_ecb_encrypt((DES_cblock *) magic, (DES_cblock *) (lmbuffer + 8),
294
                    DESKEY (ks), DES_ENCRYPT);
295
#endif
296
297
0
    memset(lmbuffer + 16, 0, 5);
298
0
  }
299
  /* create LM responses */
300
0
  calc_resp(lmbuffer, nonce, lmresp);
301
302
0
#ifdef USE_NTRESPONSES
303
0
  {
304
0
#ifdef HAVE_NETTLE
305
0
    struct md4_ctx MD4;
306
#else
307
    MD4_CTX MD4;
308
#endif
309
310
0
    unsigned char pw4[64];
311
312
0
    len = strlen (password);
313
314
0
    if (len > sizeof (pw4) / 2)
315
0
      len = sizeof (pw4) / 2;
316
317
0
    for (i = 0; i < len; i++) {
318
0
      pw4[2 * i]     = (unsigned char) password[i];
319
0
      pw4[2 * i + 1] = 0;
320
0
    }
321
322
0
#ifdef HAVE_NETTLE
323
0
    nettle_md4_init(&MD4);
324
0
    nettle_md4_update(&MD4, (unsigned) (2 * len), pw4);
325
0
    nettle_md4_digest(&MD4, MD4_DIGEST_SIZE, ntbuffer);
326
#else
327
    /* create NT hashed password */
328
    MD4_Init(&MD4);
329
    MD4_Update(&MD4, pw4, 2 * len);
330
    MD4_Final(ntbuffer, &MD4);
331
#endif
332
333
0
    memset(ntbuffer + 16, 0, 5);
334
0
  }
335
336
0
  calc_resp(ntbuffer, nonce, ntresp);
337
0
#endif
338
0
}
339
340
0
#define SHORTPAIR(x) (char) ((x) & 0xff), (char) ((x) >> 8)
341
0
#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
342
0
  (((x) >>16)&0xff), ((x)>>24)
343
344
/* this is for creating ntlm header output */
345
char *
346
ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
347
             bool *ready)
348
0
{
349
0
  const char *domain = ""; /* empty */
350
0
  const char *host = ""; /* empty */
351
0
  size_t domlen = strlen(domain);
352
0
  size_t hostlen = strlen(host);
353
0
  size_t hostoff; /* host name offset */
354
0
  size_t domoff;  /* domain name offset */
355
0
  size_t size;
356
0
  char ntlmbuf[256]; /* enough, unless the host/domain is very long */
357
358
  /* point to the address of the pointer that holds the string to sent to the
359
     server, which is for a plain host or for a HTTP proxy */
360
0
  char *output = NULL;
361
362
0
  *ready = false;
363
364
  /* not set means empty */
365
0
  if(!user)
366
0
    user="";
367
368
0
  if(!passwd)
369
0
    passwd="";
370
371
0
  switch(ntlm->state) {
372
0
  case NTLMSTATE_TYPE1:
373
0
  case NTLMSTATE_NONE:
374
0
  case NTLMSTATE_LAST:
375
0
    hostoff = 32;
376
0
    domoff = hostoff + hostlen;
377
378
0
    DEBUGP (("Creating a type-1 NTLM message.\n"));
379
380
    /* Create and send a type-1 message:
381
382
    Index Description          Content
383
    0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
384
                               (0x4e544c4d53535000)
385
    8     NTLM Message Type    long (0x01000000)
386
    12    Flags                long
387
    16    Supplied Domain      security buffer(*)
388
    24    Supplied Workstation security buffer(*)
389
    32    start of data block
390
391
    */
392
393
0
    snprintf (ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
394
0
              "\x01%c%c%c" /* 32-bit type = 1 */
395
0
              "%c%c%c%c"   /* 32-bit NTLM flag field */
396
0
              "%c%c"  /* domain length */
397
0
              "%c%c"  /* domain allocated space */
398
0
              "%c%c"  /* domain name offset */
399
0
              "%c%c"  /* 2 zeroes */
400
0
              "%c%c"  /* host length */
401
0
              "%c%c"  /* host allocated space */
402
0
              "%c%c"  /* host name offset */
403
0
              "%c%c"  /* 2 zeroes */
404
0
              "%s"   /* host name */
405
0
              "%s",  /* domain string */
406
0
              0,     /* trailing zero */
407
0
              0,0,0, /* part of type-1 long */
408
409
0
              LONGQUARTET(
410
0
                NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
411
0
                NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
412
                /* equals 0x0202 */
413
0
                ),
414
0
              SHORTPAIR(domlen),
415
0
              SHORTPAIR(domlen),
416
0
              SHORTPAIR(domoff),
417
0
              0,0,
418
0
              SHORTPAIR(hostlen),
419
0
              SHORTPAIR(hostlen),
420
0
              SHORTPAIR(hostoff),
421
0
              0,0,
422
0
              host, domain);
423
424
    /* initial packet length */
425
0
    size = 32 + hostlen + domlen;
426
427
0
    output = xmalloc(5 + BASE64_LENGTH (size) + 1);
428
0
    memcpy(output, "NTLM ", 5);
429
0
    wget_base64_encode (ntlmbuf, size, output + 5);
430
431
0
    break;
432
433
0
  case NTLMSTATE_TYPE2:
434
    /* We received the type-2 already, create a type-3 message:
435
436
    Index   Description            Content
437
    0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
438
                                   (0x4e544c4d53535000)
439
    8       NTLM Message Type      long (0x03000000)
440
    12      LM/LMv2 Response       security buffer(*)
441
    20      NTLM/NTLMv2 Response   security buffer(*)
442
    28      Domain Name            security buffer(*)
443
    36      User Name              security buffer(*)
444
    44      Workstation Name       security buffer(*)
445
    (52)    Session Key (optional) security buffer(*)
446
    (60)    Flags (optional)       long
447
    52 (64) start of data block
448
449
    */
450
451
0
  {
452
0
    size_t lmrespoff;
453
0
    size_t ntrespoff;
454
0
    size_t useroff;
455
0
    unsigned char lmresp[0x18]; /* fixed-size */
456
0
#ifdef USE_NTRESPONSES
457
0
    unsigned char ntresp[0x18]; /* fixed-size */
458
0
#endif
459
0
    const char *usr;
460
0
    size_t userlen;
461
462
0
    DEBUGP (("Creating a type-3 NTLM message.\n"));
463
464
0
    usr = strchr(user, '\\');
465
0
    if(!usr)
466
0
      usr = strchr(user, '/');
467
468
0
    if (usr) {
469
0
      domain = user;
470
0
      domlen = (size_t) (usr - domain);
471
0
      usr++;
472
0
    }
473
0
    else
474
0
      usr = user;
475
0
    userlen = strlen(usr);
476
477
0
    mkhash(passwd, &ntlm->nonce[0], lmresp
478
0
#ifdef USE_NTRESPONSES
479
0
           , ntresp
480
0
#endif
481
0
      );
482
483
0
    domoff = 64; /* always */
484
0
    useroff = domoff + domlen;
485
0
    hostoff = useroff + userlen;
486
0
    lmrespoff = hostoff + hostlen;
487
0
    ntrespoff = lmrespoff + 0x18;
488
489
    /* Create the big type-3 message binary blob */
490
491
0
    snprintf (ntlmbuf, sizeof (ntlmbuf),
492
0
              "NTLMSSP%c"
493
0
              "\x03%c%c%c" /* type-3, 32 bits */
494
495
0
              "%c%c%c%c" /* LanManager length + allocated space */
496
0
              "%c%c" /* LanManager offset */
497
0
              "%c%c" /* 2 zeroes */
498
499
0
              "%c%c" /* NT-response length */
500
0
              "%c%c" /* NT-response allocated space */
501
0
              "%c%c" /* NT-response offset */
502
0
              "%c%c" /* 2 zeroes */
503
504
0
              "%c%c" /* domain length */
505
0
              "%c%c" /* domain allocated space */
506
0
              "%c%c" /* domain name offset */
507
0
              "%c%c" /* 2 zeroes */
508
509
0
              "%c%c" /* user length */
510
0
              "%c%c" /* user allocated space */
511
0
              "%c%c" /* user offset */
512
0
              "%c%c" /* 2 zeroes */
513
514
0
              "%c%c" /* host length */
515
0
              "%c%c" /* host allocated space */
516
0
              "%c%c" /* host offset */
517
0
              "%c%c%c%c%c%c" /* 6 zeroes */
518
519
0
              "\xff\xff" /* message length */
520
0
              "%c%c" /* 2 zeroes */
521
522
0
              "\x01\x82" /* flags */
523
0
              "%c%c" /* 2 zeroes */
524
525
              /* domain string */
526
              /* user string */
527
              /* host string */
528
              /* LanManager response */
529
              /* NT response */
530
0
              ,
531
0
              0, /* zero termination */
532
0
              0, 0, 0, /* type-3 long, the 24 upper bits */
533
534
0
              SHORTPAIR (0x18), /* LanManager response length, twice */
535
0
              SHORTPAIR (0x18),
536
0
              SHORTPAIR (lmrespoff),
537
0
              0x0, 0x0,
538
539
0
#ifdef USE_NTRESPONSES
540
0
              SHORTPAIR (0x18), /* NT-response length, twice */
541
0
              SHORTPAIR (0x18),
542
#else
543
              0x0, 0x0,
544
              0x0, 0x0,
545
#endif
546
0
              SHORTPAIR (ntrespoff),
547
0
              0x0, 0x0,
548
549
0
              SHORTPAIR (domlen),
550
0
              SHORTPAIR (domlen),
551
0
              SHORTPAIR (domoff),
552
0
              0x0, 0x0,
553
554
0
              SHORTPAIR (userlen),
555
0
              SHORTPAIR (userlen),
556
0
              SHORTPAIR (useroff),
557
0
              0x0, 0x0,
558
559
0
              SHORTPAIR (hostlen),
560
0
              SHORTPAIR (hostlen),
561
0
              SHORTPAIR (hostoff),
562
0
              0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
563
564
0
              0x0, 0x0,
565
566
0
              0x0, 0x0);
567
568
    /* size is now 64 */
569
0
    size=64;
570
0
    ntlmbuf[62]=ntlmbuf[63]=0;
571
572
    /* Make sure that the user and domain strings fit in the target buffer
573
       before we copy them there. */
574
0
    if((size + userlen + domlen) >= sizeof(ntlmbuf))
575
0
      return NULL;
576
577
0
    memcpy(&ntlmbuf[size], domain, domlen);
578
0
    size += domlen;
579
580
0
    memcpy(&ntlmbuf[size], usr, userlen);
581
0
    size += userlen;
582
583
    /* we append the binary hashes to the end of the blob */
584
0
    if(size < (sizeof(ntlmbuf) - 0x18)) {
585
0
      memcpy(&ntlmbuf[size], lmresp, 0x18);
586
0
      size += 0x18;
587
0
    }
588
589
0
#ifdef USE_NTRESPONSES
590
0
    if(size < (sizeof(ntlmbuf) - 0x18)) {
591
0
      memcpy(&ntlmbuf[size], ntresp, 0x18);
592
0
      size += 0x18;
593
0
    }
594
0
#endif
595
596
0
    ntlmbuf[56] = (char) (size & 0xff);
597
0
    ntlmbuf[57] = (char) (size >> 8);
598
599
    /* convert the binary blob into base64 */
600
0
    output = xmalloc(5 + BASE64_LENGTH (size) + 1);
601
0
    memcpy(output, "NTLM ", 5);
602
0
    wget_base64_encode (ntlmbuf, size, output + 5);
603
604
0
    ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
605
0
    *ready = true;
606
0
  }
607
0
  break;
608
609
0
  case NTLMSTATE_TYPE3:
610
    /* connection is already authenticated,
611
     * don't send a header in future requests */
612
0
    *ready = true;
613
0
    output = NULL;
614
0
    break;
615
0
  }
616
617
0
  return output;
618
0
}