Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/nsNTLMAuthModule.cpp
Line
Count
Source (jump to first uncovered line)
1
/* vim:set ts=2 sw=2 et cindent: */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "nsNTLMAuthModule.h"
7
8
#include <time.h>
9
10
#include "ScopedNSSTypes.h"
11
#include "md4.h"
12
#include "mozilla/Assertions.h"
13
#include "mozilla/Base64.h"
14
#include "mozilla/Casting.h"
15
#include "mozilla/CheckedInt.h"
16
#include "mozilla/EndianUtils.h"
17
#include "mozilla/Likely.h"
18
#include "mozilla/Logging.h"
19
#include "mozilla/Preferences.h"
20
#include "mozilla/Sprintf.h"
21
#include "mozilla/Telemetry.h"
22
#include "nsCOMPtr.h"
23
#include "nsComponentManagerUtils.h"
24
#include "nsICryptoHMAC.h"
25
#include "nsICryptoHash.h"
26
#include "nsIKeyModule.h"
27
#include "nsKeyModule.h"
28
#include "nsNativeCharsetUtils.h"
29
#include "nsNetCID.h"
30
#include "nsUnicharUtils.h"
31
#include "pk11pub.h"
32
#include "prsystem.h"
33
34
static bool sNTLMv1Forced = false;
35
static mozilla::LazyLogModule sNTLMLog("NTLM");
36
37
0
#define LOG(x) MOZ_LOG(sNTLMLog, mozilla::LogLevel::Debug, x)
38
0
#define LOG_ENABLED() MOZ_LOG_TEST(sNTLMLog, mozilla::LogLevel::Debug)
39
40
static void des_makekey(const uint8_t *raw, uint8_t *key);
41
static void des_encrypt(const uint8_t *key, const uint8_t *src, uint8_t *hash);
42
43
//-----------------------------------------------------------------------------
44
// this file contains a cross-platform NTLM authentication implementation. it
45
// is based on documentation from: http://davenport.sourceforge.net/ntlm.html
46
//-----------------------------------------------------------------------------
47
48
0
#define NTLM_NegotiateUnicode               0x00000001
49
0
#define NTLM_NegotiateOEM                   0x00000002
50
0
#define NTLM_RequestTarget                  0x00000004
51
0
#define NTLM_Unknown1                       0x00000008
52
0
#define NTLM_NegotiateSign                  0x00000010
53
0
#define NTLM_NegotiateSeal                  0x00000020
54
0
#define NTLM_NegotiateDatagramStyle         0x00000040
55
0
#define NTLM_NegotiateLanManagerKey         0x00000080
56
0
#define NTLM_NegotiateNetware               0x00000100
57
0
#define NTLM_NegotiateNTLMKey               0x00000200
58
0
#define NTLM_Unknown2                       0x00000400
59
0
#define NTLM_Unknown3                       0x00000800
60
0
#define NTLM_NegotiateDomainSupplied        0x00001000
61
0
#define NTLM_NegotiateWorkstationSupplied   0x00002000
62
0
#define NTLM_NegotiateLocalCall             0x00004000
63
0
#define NTLM_NegotiateAlwaysSign            0x00008000
64
0
#define NTLM_TargetTypeDomain               0x00010000
65
0
#define NTLM_TargetTypeServer               0x00020000
66
0
#define NTLM_TargetTypeShare                0x00040000
67
0
#define NTLM_NegotiateNTLM2Key              0x00080000
68
0
#define NTLM_RequestInitResponse            0x00100000
69
0
#define NTLM_RequestAcceptResponse          0x00200000
70
0
#define NTLM_RequestNonNTSessionKey         0x00400000
71
0
#define NTLM_NegotiateTargetInfo            0x00800000
72
0
#define NTLM_Unknown4                       0x01000000
73
0
#define NTLM_Unknown5                       0x02000000
74
0
#define NTLM_Unknown6                       0x04000000
75
0
#define NTLM_Unknown7                       0x08000000
76
0
#define NTLM_Unknown8                       0x10000000
77
0
#define NTLM_Negotiate128                   0x20000000
78
0
#define NTLM_NegotiateKeyExchange           0x40000000
79
0
#define NTLM_Negotiate56                    0x80000000
80
81
// we send these flags with our type 1 message
82
#define NTLM_TYPE1_FLAGS      \
83
0
  (NTLM_NegotiateUnicode |    \
84
0
   NTLM_NegotiateOEM |        \
85
0
   NTLM_RequestTarget |       \
86
0
   NTLM_NegotiateNTLMKey |    \
87
0
   NTLM_NegotiateAlwaysSign | \
88
0
   NTLM_NegotiateNTLM2Key)
89
90
static const char NTLM_SIGNATURE[] = "NTLMSSP";
91
static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
92
static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
93
static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
94
95
0
#define NTLM_TYPE1_HEADER_LEN 32
96
0
#define NTLM_TYPE2_HEADER_LEN 48
97
0
#define NTLM_TYPE3_HEADER_LEN 64
98
99
/**
100
 * We don't actually send a LM response, but we still have to send something in this spot
101
 */
102
0
#define LM_RESP_LEN 24
103
104
0
#define NTLM_CHAL_LEN 8
105
106
0
#define NTLM_HASH_LEN 16
107
0
#define NTLMv2_HASH_LEN 16
108
0
#define NTLM_RESP_LEN 24
109
0
#define NTLMv2_RESP_LEN 16
110
0
#define NTLMv2_BLOB1_LEN 28
111
112
//-----------------------------------------------------------------------------
113
114
/**
115
 * Prints a description of flags to the NSPR Log, if enabled.
116
 */
117
static void LogFlags(uint32_t flags)
118
0
{
119
0
  if (!LOG_ENABLED())
120
0
    return;
121
0
#define TEST(_flag) \
122
0
  if (flags & NTLM_ ## _flag) \
123
0
    PR_LogPrint("    0x%08x (" # _flag ")\n", NTLM_ ## _flag)
124
0
125
0
  TEST(NegotiateUnicode);
126
0
  TEST(NegotiateOEM);
127
0
  TEST(RequestTarget);
128
0
  TEST(Unknown1);
129
0
  TEST(NegotiateSign);
130
0
  TEST(NegotiateSeal);
131
0
  TEST(NegotiateDatagramStyle);
132
0
  TEST(NegotiateLanManagerKey);
133
0
  TEST(NegotiateNetware);
134
0
  TEST(NegotiateNTLMKey);
135
0
  TEST(Unknown2);
136
0
  TEST(Unknown3);
137
0
  TEST(NegotiateDomainSupplied);
138
0
  TEST(NegotiateWorkstationSupplied);
139
0
  TEST(NegotiateLocalCall);
140
0
  TEST(NegotiateAlwaysSign);
141
0
  TEST(TargetTypeDomain);
142
0
  TEST(TargetTypeServer);
143
0
  TEST(TargetTypeShare);
144
0
  TEST(NegotiateNTLM2Key);
145
0
  TEST(RequestInitResponse);
146
0
  TEST(RequestAcceptResponse);
147
0
  TEST(RequestNonNTSessionKey);
148
0
  TEST(NegotiateTargetInfo);
149
0
  TEST(Unknown4);
150
0
  TEST(Unknown5);
151
0
  TEST(Unknown6);
152
0
  TEST(Unknown7);
153
0
  TEST(Unknown8);
154
0
  TEST(Negotiate128);
155
0
  TEST(NegotiateKeyExchange);
156
0
  TEST(Negotiate56);
157
0
158
0
#undef TEST
159
0
}
160
161
/**
162
 * Prints a hexdump of buf to the NSPR Log, if enabled.
163
 * @param tag Description of the data, will be printed in front of the data
164
 * @param buf the data to print
165
 * @param bufLen length of the data
166
 */
167
static void
168
LogBuf(const char *tag, const uint8_t *buf, uint32_t bufLen)
169
0
{
170
0
  int i;
171
0
172
0
  if (!LOG_ENABLED())
173
0
    return;
174
0
175
0
  PR_LogPrint("%s =\n", tag);
176
0
  char line[80];
177
0
  while (bufLen > 0)
178
0
  {
179
0
    int count = bufLen;
180
0
    if (count > 8)
181
0
      count = 8;
182
0
183
0
    strcpy(line, "    ");
184
0
    for (i=0; i<count; ++i)
185
0
    {
186
0
      int len = strlen(line);
187
0
      snprintf(line + len, sizeof(line) - len, "0x%02x ", int(buf[i]));
188
0
    }
189
0
    for (; i<8; ++i)
190
0
    {
191
0
      int len = strlen(line);
192
0
      snprintf(line + len, sizeof(line) - len, "     ");
193
0
    }
194
0
195
0
    int len = strlen(line);
196
0
    snprintf(line + len, sizeof(line) - len, "   ");
197
0
    for (i=0; i<count; ++i)
198
0
    {
199
0
      len = strlen(line);
200
0
      if (isprint(buf[i]))
201
0
        snprintf(line + len, sizeof(line) - len, "%c", buf[i]);
202
0
      else
203
0
        snprintf(line + len, sizeof(line) - len, ".");
204
0
    }
205
0
    PR_LogPrint("%s\n", line);
206
0
207
0
    bufLen -= count;
208
0
    buf += count;
209
0
  }
210
0
}
211
212
/**
213
 * Print base64-encoded token to the NSPR Log.
214
 * @param name Description of the token, will be printed in front
215
 * @param token The token to print
216
 * @param tokenLen length of the data in token
217
 */
218
static void
219
LogToken(const char* name, const void* token, uint32_t tokenLen)
220
0
{
221
0
  if (!LOG_ENABLED()) {
222
0
    return;
223
0
  }
224
0
225
0
  nsDependentCSubstring tokenString(static_cast<const char*>(token), tokenLen);
226
0
  nsAutoCString base64Token;
227
0
  nsresult rv = mozilla::Base64Encode(tokenString, base64Token);
228
0
  if (NS_FAILED(rv)) {
229
0
    return;
230
0
  }
231
0
232
0
  PR_LogPrint("%s: %s\n", name, base64Token.get());
233
0
}
234
235
//-----------------------------------------------------------------------------
236
237
// byte order swapping
238
#define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
239
#define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16)))
240
241
static void *
242
WriteBytes(void *buf, const void *data, uint32_t dataLen)
243
0
{
244
0
  memcpy(buf, data, dataLen);
245
0
  return (uint8_t *) buf + dataLen;
246
0
}
247
248
static void *
249
WriteDWORD(void *buf, uint32_t dword)
250
0
{
251
#ifdef IS_BIG_ENDIAN
252
  // NTLM uses little endian on the wire
253
  dword = SWAP32(dword);
254
#endif
255
  return WriteBytes(buf, &dword, sizeof(dword));
256
0
}
257
258
static void *
259
WriteSecBuf(void *buf, uint16_t length, uint32_t offset)
260
0
{
261
#ifdef IS_BIG_ENDIAN
262
  length = SWAP16(length);
263
  offset = SWAP32(offset);
264
#endif
265
  buf = WriteBytes(buf, &length, sizeof(length));
266
0
  buf = WriteBytes(buf, &length, sizeof(length));
267
0
  buf = WriteBytes(buf, &offset, sizeof(offset));
268
0
  return buf;
269
0
}
270
271
#ifdef IS_BIG_ENDIAN
272
/**
273
 * WriteUnicodeLE copies a unicode string from one buffer to another.  The
274
 * resulting unicode string is in little-endian format.  The input string is
275
 * assumed to be in the native endianness of the local machine.  It is safe
276
 * to pass the same buffer as both input and output, which is a handy way to
277
 * convert the unicode buffer to little-endian on big-endian platforms.
278
 */
279
static void *
280
WriteUnicodeLE(void *buf, const char16_t *str, uint32_t strLen)
281
{
282
  // convert input string from BE to LE
283
  uint8_t *cursor = (uint8_t *) buf,
284
          *input  = (uint8_t *) str;
285
  for (uint32_t i=0; i<strLen; ++i, input+=2, cursor+=2)
286
  {
287
    // allow for the case where |buf == str|
288
    uint8_t temp = input[0];
289
    cursor[0] = input[1];
290
    cursor[1] = temp;
291
  }
292
  return buf;
293
}
294
#endif
295
296
static uint16_t
297
ReadUint16(const uint8_t *&buf)
298
0
{
299
0
  uint16_t x = ((uint16_t) buf[0]) | ((uint16_t) buf[1] << 8);
300
0
  buf += sizeof(x);
301
0
  return x;
302
0
}
303
304
static uint32_t
305
ReadUint32(const uint8_t *&buf)
306
0
{
307
0
  uint32_t x = ( (uint32_t) buf[0])        |
308
0
               (((uint32_t) buf[1]) << 8)  |
309
0
               (((uint32_t) buf[2]) << 16) |
310
0
               (((uint32_t) buf[3]) << 24);
311
0
  buf += sizeof(x);
312
0
  return x;
313
0
}
314
315
//-----------------------------------------------------------------------------
316
317
static void
318
ZapBuf(void *buf, size_t bufLen)
319
0
{
320
0
  memset(buf, 0, bufLen);
321
0
}
322
323
static void
324
ZapString(nsString &s)
325
0
{
326
0
  ZapBuf(s.BeginWriting(), s.Length() * 2);
327
0
}
328
329
/**
330
 * NTLM_Hash computes the NTLM hash of the given password.
331
 *
332
 * @param password
333
 *        null-terminated unicode password.
334
 * @param hash
335
 *        16-byte result buffer
336
 */
337
static void
338
NTLM_Hash(const nsString &password, unsigned char *hash)
339
0
{
340
0
  uint32_t len = password.Length();
341
0
  uint8_t *passbuf;
342
0
343
#ifdef IS_BIG_ENDIAN
344
  passbuf = (uint8_t *) malloc(len * 2);
345
  WriteUnicodeLE(passbuf, password.get(), len);
346
#else
347
  passbuf = (uint8_t *) password.get();
348
0
#endif
349
0
350
0
  md4sum(passbuf, len * 2, hash);
351
0
352
#ifdef IS_BIG_ENDIAN
353
  ZapBuf(passbuf, len * 2);
354
  free(passbuf);
355
#endif
356
}
357
358
//-----------------------------------------------------------------------------
359
360
/**
361
 * LM_Response generates the LM response given a 16-byte password hash and the
362
 * challenge from the Type-2 message.
363
 *
364
 * @param hash
365
 *        16-byte password hash
366
 * @param challenge
367
 *        8-byte challenge from Type-2 message
368
 * @param response
369
 *        24-byte buffer to contain the LM response upon return
370
 */
371
static void
372
LM_Response(const uint8_t *hash, const uint8_t *challenge, uint8_t *response)
373
0
{
374
0
  uint8_t keybytes[21], k1[8], k2[8], k3[8];
375
0
376
0
  memcpy(keybytes, hash, 16);
377
0
  ZapBuf(keybytes + 16, 5);
378
0
379
0
  des_makekey(keybytes     , k1);
380
0
  des_makekey(keybytes +  7, k2);
381
0
  des_makekey(keybytes + 14, k3);
382
0
383
0
  des_encrypt(k1, challenge, response);
384
0
  des_encrypt(k2, challenge, response + 8);
385
0
  des_encrypt(k3, challenge, response + 16);
386
0
}
387
388
//-----------------------------------------------------------------------------
389
390
static nsresult
391
GenerateType1Msg(void **outBuf, uint32_t *outLen)
392
0
{
393
0
  //
394
0
  // verify that bufLen is sufficient
395
0
  //
396
0
  *outLen = NTLM_TYPE1_HEADER_LEN;
397
0
  *outBuf = moz_xmalloc(*outLen);
398
0
399
0
  //
400
0
  // write out type 1 msg
401
0
  //
402
0
  void *cursor = *outBuf;
403
0
404
0
  // 0 : signature
405
0
  cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
406
0
407
0
  // 8 : marker
408
0
  cursor = WriteBytes(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_TYPE1_MARKER));
409
0
410
0
  // 12 : flags
411
0
  cursor = WriteDWORD(cursor, NTLM_TYPE1_FLAGS);
412
0
413
0
  //
414
0
  // NOTE: it is common for the domain and workstation fields to be empty.
415
0
  //       this is true of Win2k clients, and my guess is that there is
416
0
  //       little utility to sending these strings before the charset has
417
0
  //       been negotiated.  we follow suite -- anyways, it doesn't hurt
418
0
  //       to save some bytes on the wire ;-)
419
0
  //
420
0
421
0
  // 16 : supplied domain security buffer (empty)
422
0
  cursor = WriteSecBuf(cursor, 0, 0);
423
0
424
0
  // 24 : supplied workstation security buffer (empty)
425
0
  cursor = WriteSecBuf(cursor, 0, 0);
426
0
427
0
  return NS_OK;
428
0
}
429
430
struct Type2Msg
431
{
432
  uint32_t    flags;                    // NTLM_Xxx bitwise combination
433
  uint8_t     challenge[NTLM_CHAL_LEN]; // 8 byte challenge
434
  const uint8_t *target;                // target string (type depends on flags)
435
  uint32_t    targetLen;                // target length in bytes
436
  const uint8_t *targetInfo;            // target Attribute-Value pairs (DNS domain, et al)
437
  uint32_t    targetInfoLen;            // target AV pairs length in bytes
438
};
439
440
static nsresult
441
ParseType2Msg(const void *inBuf, uint32_t inLen, Type2Msg *msg)
442
0
{
443
0
  // make sure inBuf is long enough to contain a meaningful type2 msg.
444
0
  //
445
0
  // 0  NTLMSSP Signature
446
0
  // 8  NTLM Message Type
447
0
  // 12 Target Name
448
0
  // 20 Flags
449
0
  // 24 Challenge
450
0
  // 32 targetInfo
451
0
  // 48 start of optional data blocks
452
0
  //
453
0
  if (inLen < NTLM_TYPE2_HEADER_LEN)
454
0
    return NS_ERROR_UNEXPECTED;
455
0
456
0
  auto cursor = static_cast<const uint8_t*>(inBuf);
457
0
458
0
  // verify NTLMSSP signature
459
0
  if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
460
0
    return NS_ERROR_UNEXPECTED;
461
0
462
0
  cursor += sizeof(NTLM_SIGNATURE);
463
0
464
0
  // verify Type-2 marker
465
0
  if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0)
466
0
    return NS_ERROR_UNEXPECTED;
467
0
468
0
  cursor += sizeof(NTLM_TYPE2_MARKER);
469
0
470
0
  // Read target name security buffer: ...
471
0
  // ... read target length.
472
0
  uint32_t targetLen = ReadUint16(cursor);
473
0
  // ... skip next 16-bit "allocated space" value.
474
0
  ReadUint16(cursor);
475
0
  // ... read offset from inBuf.
476
0
  uint32_t offset = ReadUint32(cursor);
477
0
  mozilla::CheckedInt<uint32_t> targetEnd = offset;
478
0
  targetEnd += targetLen;
479
0
  // Check the offset / length combo is in range of the input buffer, including
480
0
  // integer overflow checking.
481
0
  if (MOZ_LIKELY(targetEnd.isValid() && targetEnd.value() <= inLen)) {
482
0
    msg->targetLen = targetLen;
483
0
    msg->target = static_cast<const uint8_t*>(inBuf) + offset;
484
0
  } else {
485
0
    // Do not error out, for (conservative) backward compatibility.
486
0
    msg->targetLen = 0;
487
0
    msg->target = nullptr;
488
0
  }
489
0
490
0
  // read flags
491
0
  msg->flags = ReadUint32(cursor);
492
0
493
0
  // read challenge
494
0
  memcpy(msg->challenge, cursor, sizeof(msg->challenge));
495
0
  cursor += sizeof(msg->challenge);
496
0
497
0
  LOG(("NTLM type 2 message:\n"));
498
0
  LogBuf("target", msg->target, msg->targetLen);
499
0
  LogBuf("flags",
500
0
         mozilla::BitwiseCast<const uint8_t*, const uint32_t*>(&msg->flags), 4);
501
0
  LogFlags(msg->flags);
502
0
  LogBuf("challenge", msg->challenge, sizeof(msg->challenge));
503
0
504
0
  // Read (and skip) the reserved field
505
0
  ReadUint32(cursor);
506
0
  ReadUint32(cursor);
507
0
  // Read target name security buffer: ...
508
0
  // ... read target length.
509
0
  uint32_t targetInfoLen = ReadUint16(cursor);
510
0
  // ... skip next 16-bit "allocated space" value.
511
0
  ReadUint16(cursor);
512
0
  // ... read offset from inBuf.
513
0
  offset = ReadUint32(cursor);
514
0
  mozilla::CheckedInt<uint32_t> targetInfoEnd = offset;
515
0
  targetInfoEnd += targetInfoLen;
516
0
  // Check the offset / length combo is in range of the input buffer, including
517
0
  // integer overflow checking.
518
0
  if (MOZ_LIKELY(targetInfoEnd.isValid() && targetInfoEnd.value() <= inLen)) {
519
0
    msg->targetInfoLen = targetInfoLen;
520
0
    msg->targetInfo = static_cast<const uint8_t*>(inBuf) + offset;
521
0
  } else {
522
0
    NS_ERROR("failed to get NTLMv2 target info");
523
0
    return NS_ERROR_UNEXPECTED;
524
0
  }
525
0
526
0
  return NS_OK;
527
0
}
528
529
static nsresult
530
GenerateType3Msg(const nsString &domain,
531
                 const nsString &username,
532
                 const nsString &password,
533
                 const void     *inBuf,
534
                 uint32_t        inLen,
535
                 void          **outBuf,
536
                 uint32_t       *outLen)
537
0
{
538
0
  // inBuf contains Type-2 msg (the challenge) from server
539
0
  MOZ_ASSERT(NS_IsMainThread());
540
0
  nsresult rv;
541
0
  Type2Msg msg;
542
0
543
0
  rv = ParseType2Msg(inBuf, inLen, &msg);
544
0
  if (NS_FAILED(rv))
545
0
    return rv;
546
0
547
0
  bool unicode = (msg.flags & NTLM_NegotiateUnicode);
548
0
549
0
  // There is no negotiation for NTLMv2, so we just do it unless we are forced
550
0
  // by explict user configuration to use the older DES-based cryptography.
551
0
  bool ntlmv2 = (sNTLMv1Forced == false);
552
0
553
0
  // temporary buffers for unicode strings
554
#ifdef IS_BIG_ENDIAN
555
  nsAutoString ucsDomainBuf, ucsUserBuf;
556
#endif
557
  nsAutoCString hostBuf;
558
0
  nsAutoString ucsHostBuf;
559
0
  // temporary buffers for oem strings
560
0
  nsAutoCString oemDomainBuf, oemUserBuf, oemHostBuf;
561
0
  // pointers and lengths for the string buffers; encoding is unicode if
562
0
  // the "negotiate unicode" flag was set in the Type-2 message.
563
0
  const void *domainPtr, *userPtr, *hostPtr;
564
0
  uint32_t domainLen, userLen, hostLen;
565
0
566
0
  // This is for NTLM, for NTLMv2 we set the new full length once we know it
567
0
  mozilla::CheckedInt<uint16_t> ntlmRespLen = NTLM_RESP_LEN;
568
0
569
0
  //
570
0
  // get domain name
571
0
  //
572
0
  if (unicode)
573
0
  {
574
#ifdef IS_BIG_ENDIAN
575
    ucsDomainBuf = domain;
576
    domainPtr = ucsDomainBuf.get();
577
    domainLen = ucsDomainBuf.Length() * 2;
578
    WriteUnicodeLE(const_cast<void*>(domainPtr),
579
                   static_cast<const char16_t*>(domainPtr),
580
                   ucsDomainBuf.Length());
581
#else
582
    domainPtr = domain.get();
583
0
    domainLen = domain.Length() * 2;
584
0
#endif
585
0
  }
586
0
  else
587
0
  {
588
0
    NS_CopyUnicodeToNative(domain, oemDomainBuf);
589
0
    domainPtr = oemDomainBuf.get();
590
0
    domainLen = oemDomainBuf.Length();
591
0
  }
592
0
593
0
  //
594
0
  // get user name
595
0
  //
596
0
  if (unicode)
597
0
  {
598
#ifdef IS_BIG_ENDIAN
599
    ucsUserBuf = username;
600
    userPtr = ucsUserBuf.get();
601
    userLen = ucsUserBuf.Length() * 2;
602
    WriteUnicodeLE(const_cast<void*>(userPtr),
603
                   static_cast<const char16_t*>(userPtr),
604
                   ucsUserBuf.Length());
605
#else
606
    userPtr = username.get();
607
0
    userLen = username.Length() * 2;
608
0
#endif
609
0
  }
610
0
  else
611
0
  {
612
0
    NS_CopyUnicodeToNative(username, oemUserBuf);
613
0
    userPtr = oemUserBuf.get();
614
0
    userLen = oemUserBuf.Length();
615
0
  }
616
0
617
0
  //
618
0
  // get workstation name
619
0
  // (do not use local machine's hostname after bug 1046421)
620
0
  //
621
0
  rv = mozilla::Preferences::GetCString("network.generic-ntlm-auth.workstation",
622
0
                                        hostBuf);
623
0
  if (NS_FAILED(rv)) {
624
0
    return rv;
625
0
  }
626
0
627
0
  if (unicode)
628
0
  {
629
0
    ucsHostBuf = NS_ConvertUTF8toUTF16(hostBuf);
630
0
    hostPtr = ucsHostBuf.get();
631
0
    hostLen = ucsHostBuf.Length() * 2;
632
#ifdef IS_BIG_ENDIAN
633
    WriteUnicodeLE(const_cast<void*>(hostPtr),
634
                   static_cast<const char16_t*>(hostPtr),
635
                   ucsHostBuf.Length());
636
#endif
637
  }
638
0
  else
639
0
  {
640
0
    hostPtr = hostBuf.get();
641
0
    hostLen = hostBuf.Length();
642
0
  }
643
0
644
0
  //
645
0
  // now that we have generated all of the strings, we can allocate outBuf.
646
0
  //
647
0
  //
648
0
  // next, we compute the NTLM or NTLM2 responses.
649
0
  //
650
0
  uint8_t lmResp[LM_RESP_LEN];
651
0
  uint8_t ntlmResp[NTLM_RESP_LEN];
652
0
  uint8_t ntlmv2Resp[NTLMv2_RESP_LEN];
653
0
  uint8_t ntlmHash[NTLM_HASH_LEN];
654
0
  uint8_t ntlmv2_blob1[NTLMv2_BLOB1_LEN];
655
0
  if (ntlmv2) {
656
0
    // NTLMv2 mode, the default
657
0
    nsString userUpper, domainUpper;
658
0
    nsAutoCString ntlmHashStr;
659
0
    nsAutoCString ntlmv2HashStr;
660
0
    nsAutoCString lmv2ResponseStr;
661
0
    nsAutoCString ntlmv2ResponseStr;
662
0
663
0
    // temporary buffers for unicode strings
664
0
    nsAutoString ucsDomainUpperBuf;
665
0
    nsAutoString ucsUserUpperBuf;
666
0
    const void *domainUpperPtr;
667
0
    const void *userUpperPtr;
668
0
    uint32_t domainUpperLen;
669
0
    uint32_t userUpperLen;
670
0
671
0
    if (msg.targetInfoLen == 0) {
672
0
      NS_ERROR("failed to get NTLMv2 target info, can not do NTLMv2");
673
0
      return NS_ERROR_UNEXPECTED;
674
0
    }
675
0
676
0
    ToUpperCase(username, ucsUserUpperBuf);
677
0
    userUpperPtr = ucsUserUpperBuf.get();
678
0
    userUpperLen = ucsUserUpperBuf.Length() * 2;
679
#ifdef IS_BIG_ENDIAN
680
    WriteUnicodeLE(const_cast<void*>(userUpperPtr),
681
                   static_cast<const char16_t*>(userUpperPtr),
682
                   ucsUserUpperBuf.Length());
683
#endif
684
    ToUpperCase(domain, ucsDomainUpperBuf);
685
0
    domainUpperPtr = ucsDomainUpperBuf.get();
686
0
    domainUpperLen = ucsDomainUpperBuf.Length() * 2;
687
#ifdef IS_BIG_ENDIAN
688
    WriteUnicodeLE(const_cast<void*>(domainUpperPtr),
689
                   static_cast<const char16_t*>(domainUpperPtr),
690
                   ucsDomainUpperBuf.Length());
691
#endif
692
693
0
    NTLM_Hash(password, ntlmHash);
694
0
    ntlmHashStr = nsAutoCString(
695
0
      mozilla::BitwiseCast<const char*, const uint8_t*>(ntlmHash), NTLM_HASH_LEN);
696
0
697
0
    nsCOMPtr<nsIKeyObjectFactory> keyFactory =
698
0
        do_CreateInstance(NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &rv);
699
0
700
0
    if (NS_FAILED(rv)) {
701
0
      return rv;
702
0
    }
703
0
704
0
    nsCOMPtr<nsIKeyObject> ntlmKey =
705
0
        do_CreateInstance(NS_KEYMODULEOBJECT_CONTRACTID, &rv);
706
0
    if (NS_FAILED(rv)) {
707
0
      return rv;
708
0
    }
709
0
710
0
    rv = keyFactory->KeyFromString(nsIKeyObject::HMAC, ntlmHashStr, getter_AddRefs(ntlmKey));
711
0
    if (NS_FAILED(rv)) {
712
0
      return rv;
713
0
    }
714
0
715
0
    nsCOMPtr<nsICryptoHMAC> hasher =
716
0
        do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
717
0
    if (NS_FAILED(rv)) {
718
0
      return rv;
719
0
    }
720
0
    rv = hasher->Init(nsICryptoHMAC::MD5, ntlmKey);
721
0
    if (NS_FAILED(rv)) {
722
0
      return rv;
723
0
    }
724
0
    rv = hasher->Update(static_cast<const uint8_t*>(userUpperPtr), userUpperLen);
725
0
    if (NS_FAILED(rv)) {
726
0
      return rv;
727
0
    }
728
0
    rv = hasher->Update(static_cast<const uint8_t*>(domainUpperPtr),
729
0
                        domainUpperLen);
730
0
    if (NS_FAILED(rv)) {
731
0
      return rv;
732
0
    }
733
0
    rv = hasher->Finish(false, ntlmv2HashStr);
734
0
    if (NS_FAILED(rv)) {
735
0
      return rv;
736
0
    }
737
0
738
0
    uint8_t client_random[NTLM_CHAL_LEN];
739
0
    PK11_GenerateRandom(client_random, NTLM_CHAL_LEN);
740
0
741
0
    nsCOMPtr<nsIKeyObject> ntlmv2Key =
742
0
        do_CreateInstance(NS_KEYMODULEOBJECT_CONTRACTID, &rv);
743
0
    if (NS_FAILED(rv)) {
744
0
      return rv;
745
0
    }
746
0
747
0
    // Prepare the LMv2 response
748
0
    rv = keyFactory->KeyFromString(nsIKeyObject::HMAC, ntlmv2HashStr, getter_AddRefs(ntlmv2Key));
749
0
    if (NS_FAILED(rv)) {
750
0
      return rv;
751
0
    }
752
0
753
0
    rv = hasher->Init(nsICryptoHMAC::MD5, ntlmv2Key);
754
0
    if (NS_FAILED(rv)) {
755
0
      return rv;
756
0
    }
757
0
    rv = hasher->Update(msg.challenge, NTLM_CHAL_LEN);
758
0
    if (NS_FAILED(rv)) {
759
0
      return rv;
760
0
    }
761
0
    rv = hasher->Update(client_random, NTLM_CHAL_LEN);
762
0
    if (NS_FAILED(rv)) {
763
0
      return rv;
764
0
    }
765
0
    rv = hasher->Finish(false, lmv2ResponseStr);
766
0
    if (NS_FAILED(rv)) {
767
0
      return rv;
768
0
    }
769
0
770
0
    if (lmv2ResponseStr.Length() != NTLMv2_HASH_LEN) {
771
0
      return NS_ERROR_UNEXPECTED;
772
0
    }
773
0
774
0
    memcpy(lmResp, lmv2ResponseStr.get(), NTLMv2_HASH_LEN);
775
0
    memcpy(lmResp + NTLMv2_HASH_LEN, client_random, NTLM_CHAL_LEN);
776
0
777
0
    memset(ntlmv2_blob1, 0, NTLMv2_BLOB1_LEN);
778
0
779
0
    time_t unix_time;
780
0
    uint64_t nt_time = time(&unix_time);
781
0
    nt_time += 11644473600LL;    // Number of seconds betwen 1601 and 1970
782
0
    nt_time *= 1000 * 1000 * 10; // Convert seconds to 100 ns units
783
0
784
0
    ntlmv2_blob1[0] = 1;
785
0
    ntlmv2_blob1[1] = 1;
786
0
    mozilla::LittleEndian::writeUint64(&ntlmv2_blob1[8], nt_time);
787
0
    PK11_GenerateRandom(&ntlmv2_blob1[16], NTLM_CHAL_LEN);
788
0
789
0
    rv = hasher->Init(nsICryptoHMAC::MD5, ntlmv2Key);
790
0
    if (NS_FAILED(rv)) {
791
0
      return rv;
792
0
    }
793
0
    rv = hasher->Update(msg.challenge, NTLM_CHAL_LEN);
794
0
    if (NS_FAILED(rv)) {
795
0
      return rv;
796
0
    }
797
0
    rv = hasher->Update(ntlmv2_blob1, NTLMv2_BLOB1_LEN);
798
0
    if (NS_FAILED(rv)) {
799
0
      return rv;
800
0
    }
801
0
    rv = hasher->Update(msg.targetInfo, msg.targetInfoLen);
802
0
    if (NS_FAILED(rv)) {
803
0
      return rv;
804
0
    }
805
0
    rv = hasher->Finish(false, ntlmv2ResponseStr);
806
0
    if (NS_FAILED(rv)) {
807
0
      return rv;
808
0
    }
809
0
810
0
    if (ntlmv2ResponseStr.Length() != NTLMv2_RESP_LEN) {
811
0
      return NS_ERROR_UNEXPECTED;
812
0
    }
813
0
814
0
    memcpy(ntlmv2Resp, ntlmv2ResponseStr.get(), NTLMv2_RESP_LEN);
815
0
    ntlmRespLen = NTLMv2_RESP_LEN + NTLMv2_BLOB1_LEN;
816
0
    ntlmRespLen += msg.targetInfoLen;
817
0
    if (!ntlmRespLen.isValid()) {
818
0
      NS_ERROR("failed to do NTLMv2: integer overflow?!?");
819
0
      return NS_ERROR_UNEXPECTED;
820
0
    }
821
0
  } else if (msg.flags & NTLM_NegotiateNTLM2Key) {
822
0
    // compute NTLM2 session response
823
0
    nsCString sessionHashString;
824
0
825
0
    PK11_GenerateRandom(lmResp, NTLM_CHAL_LEN);
826
0
    memset(lmResp + NTLM_CHAL_LEN, 0, LM_RESP_LEN - NTLM_CHAL_LEN);
827
0
828
0
    nsCOMPtr<nsICryptoHash> hasher =
829
0
        do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
830
0
    if (NS_FAILED(rv)) {
831
0
      return rv;
832
0
    }
833
0
    rv = hasher->Init(nsICryptoHash::MD5);
834
0
    if (NS_FAILED(rv)) {
835
0
      return rv;
836
0
    }
837
0
    rv = hasher->Update(msg.challenge, NTLM_CHAL_LEN);
838
0
    if (NS_FAILED(rv)) {
839
0
      return rv;
840
0
    }
841
0
    rv = hasher->Update(lmResp, NTLM_CHAL_LEN);
842
0
    if (NS_FAILED(rv)) {
843
0
      return rv;
844
0
    }
845
0
    rv = hasher->Finish(false, sessionHashString);
846
0
    if (NS_FAILED(rv)) {
847
0
      return rv;
848
0
    }
849
0
850
0
    auto sessionHash = mozilla::BitwiseCast<const uint8_t*, const char*>(
851
0
      sessionHashString.get());
852
0
853
0
    LogBuf("NTLM2 effective key: ", sessionHash, 8);
854
0
855
0
    NTLM_Hash(password, ntlmHash);
856
0
    LM_Response(ntlmHash, sessionHash, ntlmResp);
857
0
  } else {
858
0
    NTLM_Hash(password, ntlmHash);
859
0
    LM_Response(ntlmHash, msg.challenge, ntlmResp);
860
0
861
0
    // According to http://davenport.sourceforge.net/ntlm.html#ntlmVersion2,
862
0
    // the correct way to not send the LM hash is to send the NTLM hash twice
863
0
    // in both the LM and NTLM response fields.
864
0
    LM_Response(ntlmHash, msg.challenge, lmResp);
865
0
  }
866
0
867
0
  mozilla::CheckedInt<uint32_t> totalLen = NTLM_TYPE3_HEADER_LEN + LM_RESP_LEN;
868
0
  totalLen += hostLen;
869
0
  totalLen += domainLen;
870
0
  totalLen += userLen;
871
0
  totalLen += ntlmRespLen.value();
872
0
873
0
  if (!totalLen.isValid()) {
874
0
    NS_ERROR("failed preparing to allocate NTLM response: integer overflow?!?");
875
0
    return NS_ERROR_FAILURE;
876
0
  }
877
0
  *outBuf = moz_xmalloc(totalLen.value());
878
0
  *outLen = totalLen.value();
879
0
880
0
  //
881
0
  // finally, we assemble the Type-3 msg :-)
882
0
  //
883
0
  void *cursor = *outBuf;
884
0
  mozilla::CheckedInt<uint32_t> offset;
885
0
886
0
  // 0 : signature
887
0
  cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
888
0
889
0
  // 8 : marker
890
0
  cursor = WriteBytes(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_TYPE3_MARKER));
891
0
892
0
  // 12 : LM response sec buf
893
0
  offset = NTLM_TYPE3_HEADER_LEN;
894
0
  offset += domainLen;
895
0
  offset += userLen;
896
0
  offset += hostLen;
897
0
  if (!offset.isValid()) {
898
0
    NS_ERROR("failed preparing to write NTLM response: integer overflow?!?");
899
0
    return NS_ERROR_UNEXPECTED;
900
0
  }
901
0
  cursor = WriteSecBuf(cursor, LM_RESP_LEN, offset.value());
902
0
  memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), lmResp, LM_RESP_LEN);
903
0
904
0
  // 20 : NTLM or NTLMv2 response sec buf
905
0
  offset += LM_RESP_LEN;
906
0
  if (!offset.isValid()) {
907
0
    NS_ERROR("failed preparing to write NTLM response: integer overflow?!?");
908
0
    return NS_ERROR_UNEXPECTED;
909
0
  }
910
0
  cursor = WriteSecBuf(cursor, ntlmRespLen.value(), offset.value());
911
0
  if (ntlmv2) {
912
0
    memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), ntlmv2Resp,
913
0
           NTLMv2_RESP_LEN);
914
0
    offset += NTLMv2_RESP_LEN;
915
0
    if (!offset.isValid()) {
916
0
      NS_ERROR("failed preparing to write NTLM response: integer overflow?!?");
917
0
      return NS_ERROR_UNEXPECTED;
918
0
    }
919
0
    memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), ntlmv2_blob1,
920
0
           NTLMv2_BLOB1_LEN);
921
0
    offset += NTLMv2_BLOB1_LEN;
922
0
    if (!offset.isValid()) {
923
0
      NS_ERROR("failed preparing to write NTLM response: integer overflow?!?");
924
0
      return NS_ERROR_UNEXPECTED;
925
0
    }
926
0
    memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), msg.targetInfo,
927
0
           msg.targetInfoLen);
928
0
  } else {
929
0
    memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), ntlmResp,
930
0
           NTLM_RESP_LEN);
931
0
  }
932
0
  // 28 : domain name sec buf
933
0
  offset = NTLM_TYPE3_HEADER_LEN;
934
0
  cursor = WriteSecBuf(cursor, domainLen, offset.value());
935
0
  memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), domainPtr, domainLen);
936
0
937
0
  // 36 : user name sec buf
938
0
  offset += domainLen;
939
0
  if (!offset.isValid()) {
940
0
    NS_ERROR("failed preparing to write NTLM response: integer overflow?!?");
941
0
    return NS_ERROR_UNEXPECTED;
942
0
  }
943
0
  cursor = WriteSecBuf(cursor, userLen, offset.value());
944
0
  memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), userPtr, userLen);
945
0
946
0
  // 44 : workstation (host) name sec buf
947
0
  offset += userLen;
948
0
  if (!offset.isValid()) {
949
0
    NS_ERROR("failed preparing to write NTLM response: integer overflow?!?");
950
0
    return NS_ERROR_UNEXPECTED;
951
0
  }
952
0
  cursor = WriteSecBuf(cursor, hostLen, offset.value());
953
0
  memcpy(static_cast<uint8_t*>(*outBuf) + offset.value(), hostPtr, hostLen);
954
0
955
0
  // 52 : session key sec buf (not used)
956
0
  cursor = WriteSecBuf(cursor, 0, 0);
957
0
958
0
  // 60 : negotiated flags
959
0
  cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS);
960
0
961
0
  return NS_OK;
962
0
}
963
964
//-----------------------------------------------------------------------------
965
966
NS_IMPL_ISUPPORTS(nsNTLMAuthModule, nsIAuthModule)
967
968
nsNTLMAuthModule::~nsNTLMAuthModule()
969
0
{
970
0
  ZapString(mPassword);
971
0
}
972
973
nsresult
974
nsNTLMAuthModule::InitTest()
975
0
{
976
0
  static bool prefObserved = false;
977
0
  if (!prefObserved) {
978
0
    mozilla::Preferences::AddBoolVarCache(
979
0
      &sNTLMv1Forced, "network.auth.force-generic-ntlm-v1", sNTLMv1Forced);
980
0
    prefObserved = true;
981
0
  }
982
0
983
0
  // disable NTLM authentication when FIPS mode is enabled.
984
0
  return PK11_IsFIPS() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
985
0
}
986
987
NS_IMETHODIMP
988
nsNTLMAuthModule::Init(const char* /*serviceName*/, uint32_t serviceFlags,
989
                       const char16_t* domain, const char16_t* username,
990
                       const char16_t* password)
991
0
{
992
0
  MOZ_ASSERT((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) ==
993
0
               nsIAuthModule::REQ_DEFAULT,
994
0
             "Unexpected service flags");
995
0
996
0
  mDomain = domain;
997
0
  mUsername = username;
998
0
  mPassword = password;
999
0
  mNTLMNegotiateSent = false;
1000
0
1001
0
  static bool sTelemetrySent = false;
1002
0
  if (!sTelemetrySent) {
1003
0
      mozilla::Telemetry::Accumulate(
1004
0
          mozilla::Telemetry::NTLM_MODULE_USED_2,
1005
0
          serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
1006
0
              ? NTLM_MODULE_GENERIC_PROXY
1007
0
              : NTLM_MODULE_GENERIC_DIRECT);
1008
0
      sTelemetrySent = true;
1009
0
  }
1010
0
1011
0
  return NS_OK;
1012
0
}
1013
1014
NS_IMETHODIMP
1015
nsNTLMAuthModule::GetNextToken(const void *inToken,
1016
                               uint32_t    inTokenLen,
1017
                               void      **outToken,
1018
                               uint32_t   *outTokenLen)
1019
0
{
1020
0
  nsresult rv;
1021
0
1022
0
  // disable NTLM authentication when FIPS mode is enabled.
1023
0
  if (PK11_IsFIPS()) {
1024
0
    return NS_ERROR_NOT_AVAILABLE;
1025
0
  }
1026
0
1027
0
  if (mNTLMNegotiateSent) {
1028
0
    // if inToken is non-null, and we have sent the NTLMSSP_NEGOTIATE (type 1),
1029
0
    // then the NTLMSSP_CHALLENGE (type 2) is expected
1030
0
    if (inToken) {
1031
0
      LogToken("in-token", inToken, inTokenLen);
1032
0
      // Now generate the NTLMSSP_AUTH (type 3)
1033
0
      rv = GenerateType3Msg(mDomain, mUsername, mPassword, inToken,
1034
0
          inTokenLen, outToken, outTokenLen);
1035
0
    } else {
1036
0
      LOG(("NTLMSSP_NEGOTIATE already sent and presumably "
1037
0
     "rejected by the server, refusing to send another"));
1038
0
      rv = NS_ERROR_UNEXPECTED;
1039
0
    }
1040
0
  } else {
1041
0
    if (inToken) {
1042
0
      LOG(("NTLMSSP_NEGOTIATE not sent but NTLM reply already received?!?"));
1043
0
      rv = NS_ERROR_UNEXPECTED;
1044
0
    } else {
1045
0
      rv = GenerateType1Msg(outToken, outTokenLen);
1046
0
      if (NS_SUCCEEDED(rv)) {
1047
0
  mNTLMNegotiateSent = true;
1048
0
      }
1049
0
    }
1050
0
  }
1051
0
1052
0
  if (NS_SUCCEEDED(rv))
1053
0
    LogToken("out-token", *outToken, *outTokenLen);
1054
0
1055
0
  return rv;
1056
0
}
1057
1058
NS_IMETHODIMP
1059
nsNTLMAuthModule::Unwrap(const void *inToken,
1060
                        uint32_t    inTokenLen,
1061
                        void      **outToken,
1062
                        uint32_t   *outTokenLen)
1063
0
{
1064
0
  return NS_ERROR_NOT_IMPLEMENTED;
1065
0
}
1066
1067
NS_IMETHODIMP
1068
nsNTLMAuthModule::Wrap(const void *inToken,
1069
                       uint32_t    inTokenLen,
1070
                       bool        confidential,
1071
                       void      **outToken,
1072
                       uint32_t   *outTokenLen)
1073
0
{
1074
0
  return NS_ERROR_NOT_IMPLEMENTED;
1075
0
}
1076
1077
//-----------------------------------------------------------------------------
1078
// DES support code
1079
1080
// set odd parity bit (in least significant bit position)
1081
static uint8_t
1082
des_setkeyparity(uint8_t x)
1083
0
{
1084
0
  if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
1085
0
        (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
1086
0
        (x >> 1)) & 0x01) == 0)
1087
0
    x |= 0x01;
1088
0
  else
1089
0
    x &= 0xfe;
1090
0
  return x;
1091
0
}
1092
1093
// build 64-bit des key from 56-bit raw key
1094
static void
1095
des_makekey(const uint8_t *raw, uint8_t *key)
1096
0
{
1097
0
  key[0] = des_setkeyparity(raw[0]);
1098
0
  key[1] = des_setkeyparity((raw[0] << 7) | (raw[1] >> 1));
1099
0
  key[2] = des_setkeyparity((raw[1] << 6) | (raw[2] >> 2));
1100
0
  key[3] = des_setkeyparity((raw[2] << 5) | (raw[3] >> 3));
1101
0
  key[4] = des_setkeyparity((raw[3] << 4) | (raw[4] >> 4));
1102
0
  key[5] = des_setkeyparity((raw[4] << 3) | (raw[5] >> 5));
1103
0
  key[6] = des_setkeyparity((raw[5] << 2) | (raw[6] >> 6));
1104
0
  key[7] = des_setkeyparity((raw[6] << 1));
1105
0
}
1106
1107
// run des encryption algorithm (using NSS)
1108
static void
1109
des_encrypt(const uint8_t *key, const uint8_t *src, uint8_t *hash)
1110
0
{
1111
0
  CK_MECHANISM_TYPE cipherMech = CKM_DES_ECB;
1112
0
  PK11SymKey *symkey = nullptr;
1113
0
  PK11Context *ctxt = nullptr;
1114
0
  SECItem keyItem;
1115
0
  mozilla::UniqueSECItem param;
1116
0
  SECStatus rv;
1117
0
  unsigned int n;
1118
0
1119
0
  mozilla::UniquePK11SlotInfo slot(PK11_GetBestSlot(cipherMech, nullptr));
1120
0
  if (!slot)
1121
0
  {
1122
0
    NS_ERROR("no slot");
1123
0
    goto done;
1124
0
  }
1125
0
1126
0
  keyItem.data = const_cast<uint8_t*>(key);
1127
0
  keyItem.len = 8;
1128
0
  symkey = PK11_ImportSymKey(slot.get(), cipherMech,
1129
0
                             PK11_OriginUnwrap, CKA_ENCRYPT,
1130
0
                             &keyItem, nullptr);
1131
0
  if (!symkey)
1132
0
  {
1133
0
    NS_ERROR("no symkey");
1134
0
    goto done;
1135
0
  }
1136
0
1137
0
  // no initialization vector required
1138
0
  param = mozilla::UniqueSECItem(PK11_ParamFromIV(cipherMech, nullptr));
1139
0
  if (!param)
1140
0
  {
1141
0
    NS_ERROR("no param");
1142
0
    goto done;
1143
0
  }
1144
0
1145
0
  ctxt = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
1146
0
                                    symkey, param.get());
1147
0
  if (!ctxt) {
1148
0
    NS_ERROR("no context");
1149
0
    goto done;
1150
0
  }
1151
0
1152
0
  rv = PK11_CipherOp(ctxt, hash, (int *) &n, 8, (uint8_t *) src, 8);
1153
0
  if (rv != SECSuccess) {
1154
0
    NS_ERROR("des failure");
1155
0
    goto done;
1156
0
  }
1157
0
1158
0
  rv = PK11_DigestFinal(ctxt, hash+8, &n, 0);
1159
0
  if (rv != SECSuccess) {
1160
0
    NS_ERROR("des failure");
1161
0
    goto done;
1162
0
  }
1163
0
1164
0
done:
1165
0
  if (ctxt)
1166
0
    PK11_DestroyContext(ctxt, true);
1167
0
  if (symkey)
1168
0
    PK11_FreeSymKey(symkey);
1169
0
}