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