fixes bug 224653 "provide cross-platform NTLM auth implementation" r=kaie sr=bryner

This commit is contained in:
darin%meer.net 2003-11-18 02:20:34 +00:00
Родитель a579ee29b7
Коммит 5fb0075b24
15 изменённых файлов: 1831 добавлений и 371 удалений

Просмотреть файл

@ -88,6 +88,7 @@ XPIDLSRCS = \
nsIByteRangeRequest.idl \
nsIMultiPartChannel.idl \
nsIExternalProtocolHandler.idl \
nsIAuthModule.idl \
$(NULL)
EXPORTS = \

Просмотреть файл

@ -0,0 +1,88 @@
/* vim:set ts=4 sw=4 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by IBM Corporation are Copyright (C) 2003
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
[uuid(991eff7c-a8ba-441a-b71b-753bd8e6d6be)]
interface nsIAuthModule : nsISupports
{
/**
* Called to initialize an auth module. The other methods cannot be called
* unless this method succeeds.
*
* @param aDomain
* the authentication domain, which may be null if not applicable.
* @param aUsername
* the user's login name
* @param aPassword
* the user's password
*/
void init(in wstring aDomain,
in wstring aUsername,
in wstring aPassword);
/**
* Called to get the next token in a sequence of authentication steps.
*
* @param aInToken
* A buffer containing the input token (e.g., a challenge from a
* server). This may be null.
* @param aInTokenLength
* The length of the input token.
* @param aOutToken
* If getNextToken succeeds, then aOutToken will point to a buffer
* to be sent in response to the server challenge. The length of
* this buffer is given by aOutTokenLength. The buffer at aOutToken
* must be recycled with a call to nsMemory::Free.
* @param aOutTokenLength
* If getNextToken succeeds, then aOutTokenLength contains the
* length of the buffer (number of bytes) pointed to by aOutToken.
*/
void getNextToken([const] in voidPtr aInToken,
in unsigned long aInTokenLength,
out voidPtr aOutToken,
out unsigned long aOutTokenLength);
};
%{C++
/**
* nsIAuthModule implementations are registered under the following contract
* ID prefix:
*/
#define NS_AUTH_MODULE_CONTRACTID_PREFIX \
"@mozilla.org/network/auth-module;1?name="
%}

Просмотреть файл

@ -181,10 +181,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFtpProtocolHandler, Init)
#include "nsHttpAuthManager.h"
#include "nsHttpBasicAuth.h"
#include "nsHttpDigestAuth.h"
#ifdef XP_WIN
#include "nsHttpNTLMAuth.h"
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpNTLMAuth, Init)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpNTLMAuth)
#undef LOG
#undef LOG_ENABLED
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpHandler, Init)
@ -888,12 +886,10 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "digest",
nsHttpDigestAuthConstructor },
#ifdef XP_WIN
{ "HTTP NTLM Auth Encoder",
NS_HTTPNTLMAUTH_CID,
NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "ntlm",
nsHttpNTLMAuthConstructor },
#endif
{ NS_HTTPAUTHMANAGER_CLASSNAME,
NS_HTTPAUTHMANAGER_CID,

Просмотреть файл

@ -53,18 +53,13 @@ CPPSRCS = \
nsHttpAuthManager.cpp \
nsHttpBasicAuth.cpp \
nsHttpDigestAuth.cpp \
nsHttpNTLMAuth.cpp \
nsHttpTransaction.cpp \
nsHttpHandler.cpp \
nsHttpChannel.cpp \
nsHttpPipeline.cpp \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
CPPSRCS += \
nsHttpNTLMAuth.cpp \
$(NULL)
endif
LOCAL_INCLUDES=-I$(srcdir)/../../../base/src
# we don't want the shared lib, but we want to force the creation of a

Просмотреть файл

@ -19,7 +19,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com>
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,197 +35,16 @@
*
* ***** END LICENSE BLOCK ***** */
#include <windows.h>
#include <stdlib.h>
#define SECURITY_WIN32 1
#include <security.h>
#include <rpc.h>
#include "nsHttp.h"
#include "nsHttpNTLMAuth.h"
#include "plbase64.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsNativeCharsetUtils.h"
static HINSTANCE gLib = NULL;
static PSecurityFunctionTable gFT = NULL;
static ULONG gMaxTokenLen = 0;
#ifdef DEBUG
#define CASE_(_x) case _x: return # _x;
static const char *MapErrorCode(int rc)
{
switch (rc) {
CASE_(SEC_E_OK)
CASE_(SEC_I_CONTINUE_NEEDED)
CASE_(SEC_I_COMPLETE_NEEDED)
CASE_(SEC_I_COMPLETE_AND_CONTINUE)
CASE_(SEC_E_INCOMPLETE_MESSAGE)
CASE_(SEC_I_INCOMPLETE_CREDENTIALS)
CASE_(SEC_E_INVALID_HANDLE)
CASE_(SEC_E_TARGET_UNKNOWN)
CASE_(SEC_E_LOGON_DENIED)
CASE_(SEC_E_INTERNAL_ERROR)
CASE_(SEC_E_NO_CREDENTIALS)
CASE_(SEC_E_NO_AUTHENTICATING_AUTHORITY)
CASE_(SEC_E_INSUFFICIENT_MEMORY)
CASE_(SEC_E_INVALID_TOKEN)
}
return "<unknown>";
}
#else
#define MapErrorCode(_rc) ""
#endif
//-----------------------------------------------------------------------------
#include "nsICryptoFIPSInfo.h"
#include "nsIServiceManager.h"
#include "nsIComponentManager.h"
#include "nsIAuthModule.h"
#include "nsCOMPtr.h"
// test for FIPS mode. if set, then NTLM cannot be supported. if PSM is not
// present, assume FIPS mode to be consistent with DIGEST auth. i.e., if user
// did not install PSM, then we should assume that the user doesn't want any
// crypto activity.
static PRBool
IsNTLMDisabled()
{
nsresult rv;
nsCOMPtr<nsICryptoFIPSInfo> fipsInfo =
do_GetService(NS_CRYPTO_FIPSINFO_SERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return PR_TRUE;
PRBool result;
rv = fipsInfo->GetIsFIPSModeActive(&result);
if (NS_FAILED(rv)) return PR_TRUE;
return result;
}
#include "plbase64.h"
//-----------------------------------------------------------------------------
static PRBool
IsWin9x()
{
static PRInt32 result = -1;
if (result == -1) {
OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
if (GetVersionEx(&info)) {
result = (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
info.dwMajorVersion == 4);
}
else {
NS_WARNING("GetVersionEx failed");
result = PR_FALSE;
}
}
return (PRBool) result;
}
//-----------------------------------------------------------------------------
// IE6 will automatically send out the user's default identity when challenged.
// this is rather risky given NTLM's use of the MD4 hash and the fact that any
// webserver can issue a NTLM challenge. this macro defines whether or not
// mozilla will automatically send out the user's default identity.
#define TRY_DEFAULT_LOGON_AUTOMATICALLY PR_FALSE
class nsNTLMSessionState : public nsISupports
{
public:
NS_DECL_ISUPPORTS
nsNTLMSessionState()
: mDefaultLogonFailed(!TRY_DEFAULT_LOGON_AUTOMATICALLY)
{}
virtual ~nsNTLMSessionState() {}
PRBool mDefaultLogonFailed;
};
NS_IMPL_ISUPPORTS0(nsNTLMSessionState)
//-----------------------------------------------------------------------------
class nsNTLMContinuationState : public nsISupports
{
public:
NS_DECL_ISUPPORTS
virtual ~nsNTLMContinuationState()
{
(gFT->DeleteSecurityContext)(&mCtx);
#ifdef __MINGW32__
(gFT->FreeCredentialsHandle)(&mCred);
#else
(gFT->FreeCredentialHandle)(&mCred);
#endif
}
CredHandle mCred;
CtxtHandle mCtx;
};
NS_IMPL_ISUPPORTS0(nsNTLMContinuationState)
//-----------------------------------------------------------------------------
nsHttpNTLMAuth::nsHttpNTLMAuth()
{
}
nsHttpNTLMAuth::~nsHttpNTLMAuth()
{
if (gLib) {
FreeLibrary(gLib);
gLib = NULL;
}
}
nsresult
nsHttpNTLMAuth::Init()
{
if (IsNTLMDisabled())
return NS_ERROR_FAILURE;
PSecurityFunctionTable (*initFun)(void);
// Win9x provides SECUR32.DLL, but WinNT4.0 (and likely older versions)
// only provide SECURITY.DLL. Newer versions of Windows provide both.
gLib = LoadLibrary("secur32.dll");
if (!gLib) {
gLib = LoadLibrary("security.dll");
if (!gLib) {
NS_ERROR("failed to load secur32.dll");
return NS_ERROR_UNEXPECTED;
}
}
initFun = (PSecurityFunctionTable (*)(void)) GetProcAddress(gLib, "InitSecurityInterfaceA");
if (!initFun) {
NS_ERROR("failed to locate DLL entry point");
return NS_ERROR_UNEXPECTED;
}
gFT = initFun();
if (!gFT) {
NS_ERROR("no function table");
return NS_ERROR_UNEXPECTED;
}
PSecPkgInfo pkgInfo;
int rc = (gFT->QuerySecurityPackageInfo)("NTLM", &pkgInfo);
if (rc != SEC_E_OK) {
NS_ERROR("NTLM security package not found");
return NS_ERROR_UNEXPECTED;
}
gMaxTokenLen = pkgInfo->cbMaxToken;
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsHttpNTLMAuth, nsIHttpAuthenticator)
NS_IMETHODIMP
@ -238,24 +57,25 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpChannel *channel,
{
LOG(("nsHttpNTLMAuth::ChallengeReceived\n"));
// NOTE: we don't define any session state
*identityInvalid = PR_FALSE;
// only request new identity if challenge is exactly "NTLM" and if we
// have determined that the default logon is not accepted.
// only request new identity if challenge is exactly "NTLM"
if (PL_strcasecmp(challenge, "NTLM") == 0) {
nsNTLMSessionState *session = (nsNTLMSessionState *) *sessionState;
if (session) {
// existance of continuation state implies default logon was
// attempted and must have failed.
if (*continuationState)
session->mDefaultLogonFailed = PR_TRUE;
}
else {
session = new nsNTLMSessionState();
if (!session)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*sessionState = session);
}
*identityInvalid = session->mDefaultLogonFailed;
nsCOMPtr<nsIAuthModule> module =
do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "ntlm");
// if this fails, then it means that we cannot do NTLM auth.
if (!module)
return NS_ERROR_UNEXPECTED;
// non-null continuation state implies that we failed to authenticate.
// blow away the old authentication state, and use the new one.
NS_IF_RELEASE(*continuationState);
NS_ADDREF(*continuationState = module);
// prompt user for domain, username, and password...
*identityInvalid = PR_TRUE;
}
return NS_OK;
}
@ -274,103 +94,25 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpChannel *httpChannel,
{
LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));
// NOTE: the FIPS setting can change dynamically, so we need to check it
// here as well. this isn't a very costly check, and moreover we aren't
// going to execute this code that frequently since NTLM performs the
// handshake once per connection.
if (IsNTLMDisabled())
return NS_ERROR_FAILURE;
*creds = nsnull;
NS_ENSURE_TRUE(gFT, NS_ERROR_NOT_INITIALIZED);
nsresult rv;
nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
NS_ENSURE_SUCCESS(rv, rv);
*creds = NULL;
nsNTLMSessionState *session = (nsNTLMSessionState *) *sessionState;
NS_ASSERTION(session, "ChallengeReceived not called");
nsNTLMContinuationState *state = (nsNTLMContinuationState *) *continuationState;
CtxtHandle *ctxIn;
SecBufferDesc obd, ibd;
SecBuffer ob, ib;
PRBool ibSet;
int rc;
void *inBuf, *outBuf;
PRUint32 inBufLen, outBufLen;
// initial challenge
if (PL_strcasecmp(challenge, "NTLM") == 0) {
SEC_WINNT_AUTH_IDENTITY_W identW;
SEC_WINNT_AUTH_IDENTITY_A identA;
nsCString domainBuf, userBuf, passBuf;
void *pIdent = NULL;
TimeStamp useBefore;
PRUnichar *buf = nsnull;
// initialize auth module
rv = module->Init(domain, user, pass);
if (NS_FAILED(rv))
return rv;
if (user && pass && domain) {
//
// The version of SECUR32.DLL that ships with many versions of Win9x will
// crash and burn if given a unicode user identity. See bug 212336.
//
if (IsWin9x()) {
NS_CopyUnicodeToNative(nsDependentString(user), userBuf);
NS_CopyUnicodeToNative(nsDependentString(domain), domainBuf);
NS_CopyUnicodeToNative(nsDependentString(pass), passBuf);
identA.User = (unsigned char *) userBuf.get();
identA.UserLength = userBuf.Length();
identA.Domain = (unsigned char *) domainBuf.get();
identA.DomainLength = domainBuf.Length();
identA.Password = (unsigned char *) passBuf.get();
identA.PasswordLength = passBuf.Length();
identA.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
pIdent = &identA;
}
else {
identW.User = (unsigned short *) user;
identW.UserLength = nsCRT::strlen(user);
identW.Domain = (unsigned short *) domain;
identW.DomainLength = nsCRT::strlen(domain);
identW.Password = (unsigned short *) pass;
identW.PasswordLength = nsCRT::strlen(pass);
identW.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
pIdent = &identW;
}
#ifdef DEBUG_darinf
LOG((" using supplied logon [domain=%s user=%s pass=%s]\n",
NS_LossyConvertUCS2toASCII(domain).get(),
NS_LossyConvertUCS2toASCII(user).get(),
NS_LossyConvertUCS2toASCII(pass).get()));
#endif
}
else
LOG((" using default windows logon\n"));
// clear out any old state (in case user identity was wrong)
if (state) {
NS_RELEASE(state);
*continuationState = nsnull;
if (session)
session->mDefaultLogonFailed = PR_TRUE;
}
state = new nsNTLMContinuationState(); // no addref yet
rc = (gFT->AcquireCredentialsHandle)(NULL, // pszPrincipal
"NTLM", // pszPackage
SECPKG_CRED_OUTBOUND, // fCredentialUse
NULL, // pvLogonID
pIdent, // pAuthData
NULL, // pGetKeyFn
NULL, // pvGetKeyArgument
&state->mCred, // phCredential
&useBefore); // ptsExpiry
LOG((" AcquireCredentialsHandle returned [rc=%d]\n", rc));
CRTFREEIF(buf);
ctxIn = NULL;
ibSet = PR_FALSE;
inBuf = nsnull;
}
else {
NS_ENSURE_TRUE(state, NS_ERROR_UNEXPECTED);
// decode challenge; skip past "NTLM " to the start of the base64
// encoded data.
int len = strlen(challenge);
@ -380,80 +122,37 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpChannel *httpChannel,
len -= 5;
// decode into the input secbuffer
ib.BufferType = SECBUFFER_TOKEN;
ib.cbBuffer = (len * 3)/4; // sufficient size (see plbase64.h)
ib.pvBuffer = malloc(ib.cbBuffer);
if (!ib.pvBuffer)
inBufLen = (len * 3)/4; // sufficient size (see plbase64.h)
inBuf = nsMemory::Alloc(inBufLen);
if (!inBuf)
return NS_ERROR_OUT_OF_MEMORY;
if (PL_Base64Decode(challenge, len, (char *) ib.pvBuffer) == NULL) {
free(ib.pvBuffer);
if (PL_Base64Decode(challenge, len, (char *) inBuf) == nsnull) {
nsMemory::Free(inBuf);
return NS_ERROR_UNEXPECTED; // improper base64 encoding
}
ctxIn = &state->mCtx;
ibSet = PR_TRUE;
}
DWORD ctxReq = ISC_REQ_REPLAY_DETECT |
ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_REQ_DELEGATE;
DWORD ctxAttr;
if (ibSet) {
ibd.ulVersion = SECBUFFER_VERSION;
ibd.cBuffers = 1;
ibd.pBuffers = &ib;
}
obd.ulVersion = SECBUFFER_VERSION;
obd.cBuffers = 1;
obd.pBuffers = &ob; // just one buffer
ob.BufferType = SECBUFFER_TOKEN; // preping a token here
ob.cbBuffer = gMaxTokenLen;
ob.pvBuffer = calloc(ob.cbBuffer, 1);
rc = (gFT->InitializeSecurityContext)(&state->mCred, // phCredential
ctxIn, // phContext
NULL, // pszTargetName
ctxReq, // fContextReq
0, // Reserved1
SECURITY_NATIVE_DREP, // TargetDataRep
ibSet ? &ibd : NULL, // pInput
0, // Reserved2
&state->mCtx, // phNewContext
&obd, // pOutput
&ctxAttr, // pfContextAttr
NULL); // ptsExpiry
LOG((" InitializeSecurityContext returned [rc=%d:%s]\n", rc, MapErrorCode(rc)));
if (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_OK) {
rv = module->GetNextToken(inBuf, inBufLen, &outBuf, &outBufLen);
if (NS_SUCCEEDED(rv)) {
// base64 encode data in output buffer and prepend "NTLM "
int credsLen = 5 + ((ob.cbBuffer + 2)/3)*4;
*creds = (char *) malloc(credsLen + 1);
if (*creds) {
int credsLen = 5 + ((outBufLen + 2)/3)*4;
*creds = (char *) nsMemory::Alloc(credsLen + 1);
if (!*creds)
rv = NS_ERROR_OUT_OF_MEMORY;
else {
memcpy(*creds, "NTLM ", 5);
PL_Base64Encode((char *) ob.pvBuffer, ob.cbBuffer, *creds + 5);
PL_Base64Encode((char *) outBuf, outBufLen, *creds + 5);
(*creds)[credsLen] = '\0'; // null terminate
}
// OK, we are done with |outBuf|
nsMemory::Free(outBuf);
}
if (ibSet)
free(ib.pvBuffer);
free(ob.pvBuffer);
if (inBuf)
nsMemory::Free(inBuf);
if (!*creds) {
// destroy newly allocated state
if (state && !*continuationState)
delete state;
return NS_ERROR_FAILURE;
}
// save newly allocated state
if (state && !*continuationState)
NS_ADDREF(*continuationState = state);
return NS_OK;
return rv;
}
NS_IMETHODIMP

Просмотреть файл

@ -46,10 +46,8 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIHTTPAUTHENTICATOR
nsHttpNTLMAuth();
virtual ~nsHttpNTLMAuth();
nsresult Init();
nsHttpNTLMAuth() {}
virtual ~nsHttpNTLMAuth() {}
};
#endif // !nsHttpNTLMAuth_h__

Просмотреть файл

@ -55,7 +55,7 @@ CPPSRCS = \
TestIOThreads.cpp \
TestOpen.cpp \
TestCookie.cpp \
TestServ.cpp \
ReadNTLM.cpp \
$(NULL)
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))

358
netwerk/test/ReadNTLM.cpp Normal file
Просмотреть файл

@ -0,0 +1,358 @@
/* vim: set ts=2 sw=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by IBM Corporation are Copyright (C) 2003
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include <stdio.h>
#include "plbase64.h"
#include "nsString.h"
#include "nsString2.h"
#include "nsNativeCharsetUtils.h"
#include "nsReadableUtils.h"
#include "prmem.h"
/*
* ReadNTLM : reads NTLM messages.
*
* based on http://davenport.sourceforge.net/ntlm.html
*/
#define kNegotiateUnicode 0x00000001
#define kNegotiateOEM 0x00000002
#define kRequestTarget 0x00000004
#define kUnknown1 0x00000008
#define kNegotiateSign 0x00000010
#define kNegotiateSeal 0x00000020
#define kNegotiateDatagramStyle 0x00000040
#define kNegotiateLanManagerKey 0x00000080
#define kNegotiateNetware 0x00000100
#define kNegotiateNTLMKey 0x00000200
#define kUnknown2 0x00000400
#define kUnknown3 0x00000800
#define kNegotiateDomainSupplied 0x00001000
#define kNegotiateWorkstationSupplied 0x00002000
#define kNegotiateLocalCall 0x00004000
#define kNegotiateAlwaysSign 0x00008000
#define kTargetTypeDomain 0x00010000
#define kTargetTypeServer 0x00020000
#define kTargetTypeShare 0x00040000
#define kNegotiateNTLM2Key 0x00080000
#define kRequestInitResponse 0x00100000
#define kRequestAcceptResponse 0x00200000
#define kRequestNonNTSessionKey 0x00400000
#define kNegotiateTargetInfo 0x00800000
#define kUnknown4 0x01000000
#define kUnknown5 0x02000000
#define kUnknown6 0x04000000
#define kUnknown7 0x08000000
#define kUnknown8 0x10000000
#define kNegotiate128 0x20000000
#define kNegotiateKeyExchange 0x40000000
#define kNegotiate56 0x80000000
static const char NTLM_SIGNATURE[] = "NTLMSSP";
static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
#define NTLM_MARKER_LEN 4
#define NTLM_TYPE1_HEADER_LEN 32
#define NTLM_TYPE2_HEADER_LEN 32
#define NTLM_TYPE3_HEADER_LEN 64
#define LM_HASH_LEN 16
#define LM_RESP_LEN 24
#define NTLM_HASH_LEN 16
#define NTLM_RESP_LEN 24
static void PrintFlags(PRUint32 flags)
{
#define TEST(_flag) \
if (flags & k ## _flag) \
printf(" 0x%08x (" # _flag ")\n", k ## _flag)
TEST(NegotiateUnicode);
TEST(NegotiateOEM);
TEST(RequestTarget);
TEST(Unknown1);
TEST(NegotiateSign);
TEST(NegotiateSeal);
TEST(NegotiateDatagramStyle);
TEST(NegotiateLanManagerKey);
TEST(NegotiateNetware);
TEST(NegotiateNTLMKey);
TEST(Unknown2);
TEST(Unknown3);
TEST(NegotiateDomainSupplied);
TEST(NegotiateWorkstationSupplied);
TEST(NegotiateLocalCall);
TEST(NegotiateAlwaysSign);
TEST(TargetTypeDomain);
TEST(TargetTypeServer);
TEST(TargetTypeShare);
TEST(NegotiateNTLM2Key);
TEST(RequestInitResponse);
TEST(RequestAcceptResponse);
TEST(RequestNonNTSessionKey);
TEST(NegotiateTargetInfo);
TEST(Unknown4);
TEST(Unknown5);
TEST(Unknown6);
TEST(Unknown7);
TEST(Unknown8);
TEST(Negotiate128);
TEST(NegotiateKeyExchange);
TEST(Negotiate56);
#undef TEST
}
static void
PrintBuf(const char *tag, const PRUint8 *buf, PRUint32 bufLen)
{
int i;
printf("%s =\n", tag);
while (bufLen > 0)
{
int count = bufLen;
if (count > 8)
count = 8;
printf(" ");
for (i=0; i<count; ++i)
{
printf("0x%02x ", int(buf[i]));
}
for (; i<8; ++i)
{
printf(" ");
}
printf(" ");
for (i=0; i<count; ++i)
{
if (isprint(buf[i]))
printf("%c", buf[i]);
else
printf(".");
}
printf("\n");
bufLen -= count;
buf += count;
}
}
static PRUint16
ReadUint16(const PRUint8 *&buf)
{
PRUint16 x;
#ifdef IS_BIG_ENDIAN
x = ((PRUint16) buf[1]) | ((PRUint16) buf[0] << 8);
#else
x = ((PRUint16) buf[0]) | ((PRUint16) buf[1] << 8);
#endif
buf += sizeof(x);
return x;
}
static PRUint32
ReadUint32(const PRUint8 *&buf)
{
PRUint32 x;
#ifdef IS_BIG_ENDIAN
x = ( (PRUint32) buf[3]) |
(((PRUint32) buf[2]) << 8) |
(((PRUint32) buf[1]) << 16) |
(((PRUint32) buf[0]) << 24);
#else
x = ( (PRUint32) buf[0]) |
(((PRUint32) buf[1]) << 8) |
(((PRUint32) buf[2]) << 16) |
(((PRUint32) buf[3]) << 24);
#endif
buf += sizeof(x);
return x;
}
typedef struct {
PRUint16 length;
PRUint16 capacity;
PRUint32 offset;
} SecBuf;
static void
ReadSecBuf(SecBuf *s, const PRUint8 *&buf)
{
s->length = ReadUint16(buf);
s->capacity = ReadUint16(buf);
s->offset = ReadUint32(buf);
}
static void
ReadType1MsgBody(const PRUint8 *inBuf, PRUint32 start)
{
const PRUint8 *cursor = inBuf + start;
PRUint32 flags;
PrintBuf("flags", cursor, 4);
// read flags
flags = ReadUint32(cursor);
PrintFlags(flags);
// type 1 message may not include trailing security buffers
if ((flags & kNegotiateDomainSupplied) |
(flags & kNegotiateWorkstationSupplied))
{
SecBuf secbuf;
ReadSecBuf(&secbuf, cursor);
PrintBuf("supplied domain", inBuf + secbuf.offset, secbuf.length);
ReadSecBuf(&secbuf, cursor);
PrintBuf("supplied workstation", inBuf + secbuf.offset, secbuf.length);
}
}
static void
ReadType2MsgBody(const PRUint8 *inBuf, PRUint32 start)
{
PRUint16 targetLen, offset;
PRUint32 flags;
const PRUint8 *target;
const PRUint8 *cursor = inBuf + start;
// read target name security buffer
targetLen = ReadUint16(cursor);
ReadUint16(cursor); // discard next 16-bit value
offset = ReadUint32(cursor); // get offset from inBuf
target = inBuf + offset;
PrintBuf("target", target, targetLen);
PrintBuf("flags", cursor, 4);
// read flags
flags = ReadUint32(cursor);
PrintFlags(flags);
// read challenge
PrintBuf("challenge", cursor, 8);
cursor += 8;
PrintBuf("context", cursor, 8);
cursor += 8;
SecBuf secbuf;
ReadSecBuf(&secbuf, cursor);
PrintBuf("target information", inBuf + secbuf.offset, secbuf.length);
}
static void
ReadType3MsgBody(const PRUint8 *inBuf, PRUint32 start)
{
const PRUint8 *cursor = inBuf + start;
SecBuf secbuf;
ReadSecBuf(&secbuf, cursor); // LM response
PrintBuf("LM response", inBuf + secbuf.offset, secbuf.length);
ReadSecBuf(&secbuf, cursor); // NTLM response
PrintBuf("NTLM response", inBuf + secbuf.offset, secbuf.length);
ReadSecBuf(&secbuf, cursor); // domain name
PrintBuf("domain name", inBuf + secbuf.offset, secbuf.length);
ReadSecBuf(&secbuf, cursor); // user name
PrintBuf("user name", inBuf + secbuf.offset, secbuf.length);
ReadSecBuf(&secbuf, cursor); // workstation name
PrintBuf("workstation name", inBuf + secbuf.offset, secbuf.length);
ReadSecBuf(&secbuf, cursor); // session key
PrintBuf("session key", inBuf + secbuf.offset, secbuf.length);
PRUint32 flags = ReadUint32(cursor);
PrintBuf("flags", (const PRUint8 *) &flags, sizeof(flags));
PrintFlags(flags);
}
static void
ReadMsg(const char *base64buf, PRUint32 bufLen)
{
PRUint8 *inBuf = (PRUint8 *) PL_Base64Decode(base64buf, bufLen, NULL);
if (!inBuf)
{
printf("PL_Base64Decode failed\n");
return;
}
const PRUint8 *cursor = inBuf;
PrintBuf("signature", cursor, 8);
// verify NTLMSSP signature
if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
{
printf("### invalid or corrupt NTLM signature\n");
}
cursor += sizeof(NTLM_SIGNATURE);
PrintBuf("message type", cursor, 4);
if (memcmp(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
ReadType1MsgBody(inBuf, 12);
else if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
ReadType2MsgBody(inBuf, 12);
else if (memcmp(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
ReadType3MsgBody(inBuf, 12);
else
printf("### invalid or unknown message type\n");
PR_Free(inBuf);
}
int main(int argc, char **argv)
{
if (argc == 1)
{
printf("usage: ntlmread <msg>\n");
return -1;
}
ReadMsg(argv[1], (PRUint32) strlen(argv[1]));
return 0;
}

Просмотреть файл

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=2 sw=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@ -47,6 +48,9 @@
#ifdef WIN32
#include <windows.h>
#endif
#ifdef XP_UNIX
#include <unistd.h>
#endif
#include "nspr.h"
#include "nscore.h"
#include "nsCOMPtr.h"
@ -67,6 +71,9 @@
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIDNSService.h"
#include "nsIAuthPrompt.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsISimpleEnumerator.h"
#include "nsXPIDLString.h"
@ -92,6 +99,39 @@ static PRBool gAskUserForInput = PR_FALSE;
static PRBool gResume = PR_FALSE;
static PRUint32 gStartAt = 0;
//-----------------------------------------------------------------------------
// Set proxy preferences for testing
//-----------------------------------------------------------------------------
static nsresult
SetHttpProxy(const char *proxy)
{
const char *colon = strchr(proxy, ':');
if (!colon)
{
NS_WARNING("invalid proxy token; use host:port");
return NS_ERROR_UNEXPECTED;
}
int port = atoi(colon + 1);
if (port == 0)
{
NS_WARNING("invalid proxy port; must be an integer");
return NS_ERROR_UNEXPECTED;
}
nsCAutoString proxyHost;
proxyHost = Substring(proxy, colon);
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs)
{
prefs->SetCharPref("network.proxy.http", proxyHost.get());
prefs->SetIntPref("network.proxy.http_port", port);
prefs->SetIntPref("network.proxy.type", 1); // manual proxy config
}
LOG(("connecting via proxy=%s:%d\n", proxyHost.get(), port));
return NS_OK;
}
//-----------------------------------------------------------------------------
// HeaderVisitor
//-----------------------------------------------------------------------------
@ -182,6 +222,97 @@ TestHttpEventSink::OnRedirect(nsIHttpChannel *channel, nsIChannel *newChannel)
return NS_OK;
}
//-----------------------------------------------------------------------------
// TestAuthPrompt
//-----------------------------------------------------------------------------
class TestAuthPrompt : public nsIAuthPrompt
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIAUTHPROMPT
TestAuthPrompt();
virtual ~TestAuthPrompt();
};
NS_IMPL_ISUPPORTS1(TestAuthPrompt, nsIAuthPrompt)
TestAuthPrompt::TestAuthPrompt()
{
}
TestAuthPrompt::~TestAuthPrompt()
{
}
NS_IMETHODIMP
TestAuthPrompt::Prompt(const PRUnichar *dialogTitle,
const PRUnichar *text,
const PRUnichar *passwordRealm,
PRUint32 savePassword,
const PRUnichar *defaultText,
PRUnichar **result,
PRBool *_retval)
{
*_retval = PR_FALSE;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
TestAuthPrompt::PromptUsernameAndPassword(const PRUnichar *dialogTitle,
const PRUnichar *dialogText,
const PRUnichar *passwordRealm,
PRUint32 savePassword,
PRUnichar **user,
PRUnichar **pwd,
PRBool *_retval)
{
NS_ConvertUTF16toUTF8 text(passwordRealm);
printf("* --------------------------------------------------------------------------- *\n");
printf("* Authentication Required [%s]\n", text.get());
printf("* --------------------------------------------------------------------------- *\n");
char buf[256];
int n;
printf("Enter username: ");
fgets(buf, sizeof(buf), stdin);
n = strlen(buf);
buf[n-1] = '\0'; // trim trailing newline
*user = ToNewUnicode(nsDependentCString(buf));
const char *p;
#ifdef XP_UNIX
p = getpass("Enter password: ");
#else
printf("Enter password: ");
fgets(buf, sizeof(buf), stdin);
n = strlen(buf);
buf[n-1] = '\0'; // trim trailing newline
p = buf;
#endif
*pwd = ToNewUnicode(nsDependentCString(p));
// zap buf
memset(buf, 0, sizeof(buf));
*_retval = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
TestAuthPrompt::PromptPassword(const PRUnichar *dialogTitle,
const PRUnichar *text,
const PRUnichar *passwordRealm,
PRUint32 savePassword,
PRUnichar **pwd,
PRBool *_retval)
{
*_retval = PR_FALSE;
return NS_ERROR_NOT_IMPLEMENTED;
}
//-----------------------------------------------------------------------------
// InputTestConsumer
//-----------------------------------------------------------------------------
@ -413,19 +544,30 @@ public:
NotificationCallbacks() {
}
NS_IMETHOD GetInterface(const nsIID& eventSinkIID, void* *result) {
NS_IMETHOD GetInterface(const nsIID& iid, void* *result) {
nsresult rv = NS_ERROR_FAILURE;
if (eventSinkIID.Equals(NS_GET_IID(nsIHttpEventSink))) {
if (iid.Equals(NS_GET_IID(nsIHttpEventSink))) {
TestHttpEventSink *sink;
sink = new TestHttpEventSink();
if (sink == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(sink);
rv = sink->QueryInterface(eventSinkIID, result);
rv = sink->QueryInterface(iid, result);
NS_RELEASE(sink);
}
if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) {
TestAuthPrompt *prompt;
prompt = new TestAuthPrompt();
if (prompt == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(prompt);
rv = prompt->QueryInterface(iid, result);
NS_RELEASE(prompt);
}
return rv;
}
};
@ -595,7 +737,7 @@ main(int argc, char* argv[])
}
#if defined(PR_LOGGING)
gTestLog = PR_NewLogModule("Test");
gTestLog = PR_NewLogModule("Test");
#endif
/*
@ -640,6 +782,11 @@ main(int argc, char* argv[])
continue;
}
if (PL_strcasecmp(argv[i], "-proxy") == 0) {
SetHttpProxy(argv[++i]);
continue;
}
LOG(("\t%s\n", argv[i]));
rv = StartLoadingURL(argv[i]);
}

Просмотреть файл

@ -79,12 +79,15 @@ CPPSRCS = \
nsUsageArrayHelper.cpp \
nsCRLManager.cpp \
nsNSSShutDown.cpp \
nsNTLMAuthModule.cpp \
$(NULL)
ifdef MOZ_XUL
CPPSRCS += nsCertTree.cpp
endif
CSRCS += md4.c
REQUIRES = nspr \
xpcom \
string \

Просмотреть файл

@ -0,0 +1,171 @@
/* vim:set ts=2 sw=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by IBM Corporation are Copyright (C) 2003
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* "clean room" MD4 implementation (see RFC 1320)
*/
#include <string.h>
#include "md4.h"
typedef PRUint32 Uint32;
typedef PRUint8 Uint8;
/* the "conditional" function */
#define F(x,y,z) (((x) & (y)) | (~(x) & (z)))
/* the "majority" function */
#define G(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
/* the "parity" function */
#define H(x,y,z) ((x) ^ (y) ^ (z))
/* rotate n-bits to the left */
#define ROTL(x,n) (((x) << (n)) | ((x) >> (0x20 - n)))
/* round 1: [abcd k s]: a = (a + F(b,c,d) + X[k]) <<< s */
#define RD1(a,b,c,d,k,s) a += F(b,c,d) + X[k]; a = ROTL(a,s)
/* round 2: [abcd k s]: a = (a + G(b,c,d) + X[k] + MAGIC) <<< s */
#define RD2(a,b,c,d,k,s) a += G(b,c,d) + X[k] + 0x5A827999; a = ROTL(a,s)
/* round 3: [abcd k s]: a = (a + H(b,c,d) + X[k] + MAGIC) <<< s */
#define RD3(a,b,c,d,k,s) a += H(b,c,d) + X[k] + 0x6ED9EBA1; a = ROTL(a,s)
/* converts from word array to byte array, len is number of bytes */
static void w2b(Uint8 *out, const Uint32 *in, Uint32 len)
{
Uint8 *bp; const Uint32 *wp, *wpend;
bp = out;
wp = in;
wpend = wp + (len >> 2);
for (; wp != wpend; ++wp, bp += 4)
{
bp[0] = (Uint8) ((*wp ) & 0xFF);
bp[1] = (Uint8) ((*wp >> 8) & 0xFF);
bp[2] = (Uint8) ((*wp >> 16) & 0xFF);
bp[3] = (Uint8) ((*wp >> 24) & 0xFF);
}
}
/* converts from byte array to word array, len is number of bytes */
static void b2w(Uint32 *out, const Uint8 *in, Uint32 len)
{
Uint32 *wp; const Uint8 *bp, *bpend;
wp = out;
bp = in;
bpend = in + len;
for (; bp != bpend; bp += 4, ++wp)
{
*wp = (Uint32) (bp[0] ) |
(Uint32) (bp[1] << 8) |
(Uint32) (bp[2] << 16) |
(Uint32) (bp[3] << 24);
}
}
/* update state: data is 64 bytes in length */
static void md4step(Uint32 state[4], const Uint8 *data)
{
Uint32 A, B, C, D, X[16];
b2w(X, data, 64);
A = state[0];
B = state[1];
C = state[2];
D = state[3];
RD1(A,B,C,D, 0,3); RD1(D,A,B,C, 1,7); RD1(C,D,A,B, 2,11); RD1(B,C,D,A, 3,19);
RD1(A,B,C,D, 4,3); RD1(D,A,B,C, 5,7); RD1(C,D,A,B, 6,11); RD1(B,C,D,A, 7,19);
RD1(A,B,C,D, 8,3); RD1(D,A,B,C, 9,7); RD1(C,D,A,B,10,11); RD1(B,C,D,A,11,19);
RD1(A,B,C,D,12,3); RD1(D,A,B,C,13,7); RD1(C,D,A,B,14,11); RD1(B,C,D,A,15,19);
RD2(A,B,C,D, 0,3); RD2(D,A,B,C, 4,5); RD2(C,D,A,B, 8, 9); RD2(B,C,D,A,12,13);
RD2(A,B,C,D, 1,3); RD2(D,A,B,C, 5,5); RD2(C,D,A,B, 9, 9); RD2(B,C,D,A,13,13);
RD2(A,B,C,D, 2,3); RD2(D,A,B,C, 6,5); RD2(C,D,A,B,10, 9); RD2(B,C,D,A,14,13);
RD2(A,B,C,D, 3,3); RD2(D,A,B,C, 7,5); RD2(C,D,A,B,11, 9); RD2(B,C,D,A,15,13);
RD3(A,B,C,D, 0,3); RD3(D,A,B,C, 8,9); RD3(C,D,A,B, 4,11); RD3(B,C,D,A,12,15);
RD3(A,B,C,D, 2,3); RD3(D,A,B,C,10,9); RD3(C,D,A,B, 6,11); RD3(B,C,D,A,14,15);
RD3(A,B,C,D, 1,3); RD3(D,A,B,C, 9,9); RD3(C,D,A,B, 5,11); RD3(B,C,D,A,13,15);
RD3(A,B,C,D, 3,3); RD3(D,A,B,C,11,9); RD3(C,D,A,B, 7,11); RD3(B,C,D,A,15,15);
state[0] += A;
state[1] += B;
state[2] += C;
state[3] += D;
}
void md4sum(const Uint8 *input, Uint32 inputLen, Uint8 *result)
{
Uint8 final[128];
Uint32 i, n, m, state[4];
/* magic initial states */
state[0] = 0x67452301;
state[1] = 0xEFCDAB89;
state[2] = 0x98BADCFE;
state[3] = 0x10325476;
/* compute number of complete 64-byte segments contained in input */
m = inputLen >> 6;
/* digest first m segments */
for (i=0; i<m; ++i)
md4step(state, (input + (i << 6)));
/* build final buffer */
n = inputLen % 64;
memcpy(final, input + (m << 6), n);
final[n] = 0x80;
memset(final + n + 1, 0, 120 - (n + 1));
inputLen = inputLen << 3;
w2b(final + (n >= 56 ? 120 : 56), &inputLen, 4);
md4step(state, final);
if (n >= 56)
md4step(state, final + 64);
/* copy state to result */
w2b(result, state, 16);
}

Просмотреть файл

@ -0,0 +1,70 @@
/* vim:set ts=2 sw=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by IBM Corporation are Copyright (C) 2003
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef md4_h__
#define md4_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "prtypes.h"
/**
* md4sum - computes the MD4 sum over the input buffer per RFC 1320
*
* @param input
* buffer containing input data
* @param inputLen
* length of input buffer (number of bytes)
* @param result
* 16-byte buffer that will contain the MD4 sum upon return
*
* NOTE: MD4 is superceded by MD5. do not use MD4 unless required by the
* protocol you are implementing (e.g., NTLM requires MD4).
*
* NOTE: this interface is designed for relatively small buffers. A streaming
* interface would make more sense if that were a requirement. Currently, this
* is good enough for the applications we care about.
*/
void md4sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result);
#ifdef __cplusplus
}
#endif
#endif /* md4_h__ */

Просмотреть файл

@ -52,6 +52,7 @@
#include "nsICategoryManager.h"
#include "nsCRLManager.h"
#include "nsCipherInfo.h"
#include "nsNTLMAuthModule.h"
// We must ensure that the nsNSSComponent has been loaded before
// creating any other components.
@ -166,6 +167,7 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsHash)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsCertPicker)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsCRLManager)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsCipherInfoService)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(PR_FALSE, nsNTLMAuthModule, InitTest)
static NS_METHOD RegisterPSMContentListeners(
nsIComponentManager *aCompMgr,
@ -379,6 +381,13 @@ static const nsModuleComponentInfo components[] =
NS_PKCS11MODULEDB_CID,
NS_CRYPTO_FIPSINFO_SERVICE_CONTRACTID,
nsPKCS11ModuleDBConstructor
},
{
NS_NTLMAUTHMODULE_CLASSNAME,
NS_NTLMAUTHMODULE_CID,
NS_NTLMAUTHMODULE_CONTRACTID,
nsNTLMAuthModuleConstructor
}
};

Просмотреть файл

@ -0,0 +1,852 @@
/* vim:set ts=2 sw=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by IBM Corporation are Copyright (C) 2003
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include "nsNSSShutDown.h"
#include "nsNTLMAuthModule.h"
#include "nsNativeCharsetUtils.h"
#include "nsReadableUtils.h"
#include "nsString.h"
#include "prsystem.h"
#include "nss.h"
#include "pk11func.h"
#include "md4.h"
static void des_makekey(const PRUint8 *raw, PRUint8 *key);
static void des_encrypt(const PRUint8 *key, const PRUint8 *src, PRUint8 *hash);
static void md5sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result);
//-----------------------------------------------------------------------------
// this file contains a cross-platform NTLM authentication implementation. it
// is based on documentation from: http://davenport.sourceforge.net/ntlm.html
//-----------------------------------------------------------------------------
#define NTLM_NegotiateUnicode 0x00000001
#define NTLM_NegotiateOEM 0x00000002
#define NTLM_RequestTarget 0x00000004
#define NTLM_Unknown1 0x00000008
#define NTLM_NegotiateSign 0x00000010
#define NTLM_NegotiateSeal 0x00000020
#define NTLM_NegotiateDatagramStyle 0x00000040
#define NTLM_NegotiateLanManagerKey 0x00000080
#define NTLM_NegotiateNetware 0x00000100
#define NTLM_NegotiateNTLMKey 0x00000200
#define NTLM_Unknown2 0x00000400
#define NTLM_Unknown3 0x00000800
#define NTLM_NegotiateDomainSupplied 0x00001000
#define NTLM_NegotiateWorkstationSupplied 0x00002000
#define NTLM_NegotiateLocalCall 0x00004000
#define NTLM_NegotiateAlwaysSign 0x00008000
#define NTLM_TargetTypeDomain 0x00010000
#define NTLM_TargetTypeServer 0x00020000
#define NTLM_TargetTypeShare 0x00040000
#define NTLM_NegotiateNTLM2Key 0x00080000
#define NTLM_RequestInitResponse 0x00100000
#define NTLM_RequestAcceptResponse 0x00200000
#define NTLM_RequestNonNTSessionKey 0x00400000
#define NTLM_NegotiateTargetInfo 0x00800000
#define NTLM_Unknown4 0x01000000
#define NTLM_Unknown5 0x02000000
#define NTLM_Unknown6 0x04000000
#define NTLM_Unknown7 0x08000000
#define NTLM_Unknown8 0x10000000
#define NTLM_Negotiate128 0x20000000
#define NTLM_NegotiateKeyExchange 0x40000000
#define NTLM_Negotiate56 0x80000000
// we send these flags with our type 1 message
#define NTLM_TYPE1_FLAGS \
(NTLM_NegotiateUnicode | \
NTLM_NegotiateOEM | \
NTLM_RequestTarget | \
NTLM_NegotiateNTLMKey | \
NTLM_NegotiateNTLM2Key)
static const char NTLM_SIGNATURE[] = "NTLMSSP";
static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
#define NTLM_TYPE1_HEADER_LEN 32
#define NTLM_TYPE2_HEADER_LEN 32
#define NTLM_TYPE3_HEADER_LEN 64
#define LM_HASH_LEN 16
#define LM_RESP_LEN 24
#define NTLM_HASH_LEN 16
#define NTLM_RESP_LEN 24
//-----------------------------------------------------------------------------
#ifdef DEBUG
static void PrintFlags(PRUint32 flags)
{
#define TEST(_flag) \
if (flags & NTLM_ ## _flag) \
printf(" 0x%08x (" # _flag ")\n", NTLM_ ## _flag)
TEST(NegotiateUnicode);
TEST(NegotiateOEM);
TEST(RequestTarget);
TEST(Unknown1);
TEST(NegotiateSign);
TEST(NegotiateSeal);
TEST(NegotiateDatagramStyle);
TEST(NegotiateLanManagerKey);
TEST(NegotiateNetware);
TEST(NegotiateNTLMKey);
TEST(Unknown2);
TEST(Unknown3);
TEST(NegotiateDomainSupplied);
TEST(NegotiateWorkstationSupplied);
TEST(NegotiateLocalCall);
TEST(NegotiateAlwaysSign);
TEST(TargetTypeDomain);
TEST(TargetTypeServer);
TEST(TargetTypeShare);
TEST(NegotiateNTLM2Key);
TEST(RequestInitResponse);
TEST(RequestAcceptResponse);
TEST(RequestNonNTSessionKey);
TEST(NegotiateTargetInfo);
TEST(Unknown4);
TEST(Unknown5);
TEST(Unknown6);
TEST(Unknown7);
TEST(Unknown8);
TEST(Negotiate128);
TEST(NegotiateKeyExchange);
TEST(Negotiate56);
#undef TEST
}
static void
PrintBuf(const char *tag, const PRUint8 *buf, PRUint32 bufLen)
{
int i;
printf("%s =\n", tag);
while (bufLen > 0)
{
int count = bufLen;
if (count > 8)
count = 8;
printf(" ");
for (i=0; i<count; ++i)
{
printf("0x%02x ", int(buf[i]));
}
for (; i<8; ++i)
{
printf(" ");
}
printf(" ");
for (i=0; i<count; ++i)
{
if (isprint(buf[i]))
printf("%c", buf[i]);
else
printf(".");
}
printf("\n");
bufLen -= count;
buf += count;
}
}
#endif // DEBUG
//-----------------------------------------------------------------------------
// byte order swapping
#define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
#define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16)))
static void *
WriteBytes(void *buf, const void *data, PRUint32 dataLen)
{
memcpy(buf, data, dataLen);
return (PRUint8 *) buf + dataLen;
}
static void *
WriteDWORD(void *buf, PRUint32 dword)
{
#ifdef IS_BIG_ENDIAN
// NTLM uses little endian on the wire
dword = SWAP32(dword);
#endif
return WriteBytes(buf, &dword, sizeof(dword));
}
static void *
WriteSecBuf(void *buf, PRUint16 length, PRUint32 offset)
{
#ifdef IS_BIG_ENDIAN
length = SWAP16(length);
offset = SWAP32(offset);
#endif
buf = WriteBytes(buf, &length, sizeof(length));
buf = WriteBytes(buf, &length, sizeof(length));
buf = WriteBytes(buf, &offset, sizeof(offset));
return buf;
}
#ifdef IS_BIG_ENDIAN
/**
* WriteUnicodeLE copies a unicode string from one buffer to another. The
* resulting unicode string is in little-endian format. The input string is
* assumed to be in the native endianness of the local machine. It is safe
* to pass the same buffer as both input and output, which is a handy way to
* convert the unicode buffer to little-endian on big-endian platforms.
*/
static void *
WriteUnicodeLE(void *buf, const PRUnichar *str, PRUint32 strLen)
{
// convert input string from BE to LE
PRUint8 *cursor = (PRUint8 *) buf,
*input = (PRUint8 *) str;
for (PRUint32 i=0; i<strLen; ++i, input+=2, cursor+=2)
{
// allow for the case where |buf == str|
PRUint8 temp = input[0];
cursor[0] = input[1];
cursor[1] = temp;
}
return buf;
}
#endif
static PRUint16
ReadUint16(const PRUint8 *&buf)
{
PRUint16 x = ((PRUint16) buf[0]) | ((PRUint16) buf[1] << 8);
buf += sizeof(x);
return x;
}
static PRUint32
ReadUint32(const PRUint8 *&buf)
{
PRUint32 x = ( (PRUint32) buf[0]) |
(((PRUint32) buf[1]) << 8) |
(((PRUint32) buf[2]) << 16) |
(((PRUint32) buf[3]) << 24);
buf += sizeof(x);
return x;
}
//-----------------------------------------------------------------------------
static void
ZapBuf(void *buf, size_t bufLen)
{
memset(buf, 0, bufLen);
}
static void
ZapString(nsCString &s)
{
ZapBuf(NS_CONST_CAST(char *, s.get()), s.Length());
}
static void
ZapString(nsString &s)
{
ZapBuf(NS_CONST_CAST(PRUnichar *, s.get()), s.Length() * 2);
}
static const unsigned char LM_MAGIC[] = "KGS!@#$%";
/**
* LM_Hash computes the LM hash of the given password.
*
* @param password
* null-terminated unicode password.
* @param hash
* 16-byte result buffer
*/
static void
LM_Hash(const nsString &password, unsigned char *hash)
{
// convert password to OEM character set. we'll just use the native
// filesystem charset.
nsCAutoString passbuf;
NS_CopyUnicodeToNative(password, passbuf);
ToUpperCase(passbuf);
PRUint32 n = passbuf.Length();
passbuf.SetLength(14);
for (PRUint32 i=n; i<14; ++i)
passbuf.SetCharAt('\0', i);
unsigned char k1[8], k2[8];
des_makekey((const unsigned char *) passbuf.get() , k1);
des_makekey((const unsigned char *) passbuf.get() + 7, k2);
ZapString(passbuf);
// use password keys to hash LM magic string twice.
des_encrypt(k1, LM_MAGIC, hash);
des_encrypt(k2, LM_MAGIC, hash + 8);
}
/**
* NTLM_Hash computes the NTLM hash of the given password.
*
* @param password
* null-terminated unicode password.
* @param hash
* 16-byte result buffer
*/
static void
NTLM_Hash(const nsString &password, unsigned char *hash)
{
PRUint32 len = password.Length();
PRUint8 *passbuf;
#ifdef IS_BIG_ENDIAN
passbuf = (PRUint8 *) malloc(len * 2);
WriteUnicodeLE(passbuf, password.get(), len);
#else
passbuf = (PRUint8 *) password.get();
#endif
md4sum(passbuf, len * 2, hash);
#ifdef IS_BIG_ENDIAN
ZapBuf(passbuf, len * 2);
free(passbuf);
#endif
}
//-----------------------------------------------------------------------------
/**
* LM_Response generates the LM response given a 16-byte password hash and the
* challenge from the Type-2 message.
*
* @param hash
* 16-byte password hash
* @param challenge
* 8-byte challenge from Type-2 message
* @param response
* 24-byte buffer to contain the LM response upon return
*/
static void
LM_Response(const PRUint8 *hash, const PRUint8 *challenge, PRUint8 *response)
{
PRUint8 keybytes[21], k1[8], k2[8], k3[8];
memcpy(keybytes, hash, 16);
ZapBuf(keybytes + 16, 5);
des_makekey(keybytes , k1);
des_makekey(keybytes + 7, k2);
des_makekey(keybytes + 14, k3);
des_encrypt(k1, challenge, response);
des_encrypt(k2, challenge, response + 8);
des_encrypt(k3, challenge, response + 16);
}
//-----------------------------------------------------------------------------
static nsresult
GenerateType1Msg(void **outBuf, PRUint32 *outLen)
{
//
// verify that bufLen is sufficient
//
*outLen = NTLM_TYPE1_HEADER_LEN;
*outBuf = nsMemory::Alloc(*outLen);
if (!*outBuf)
return NS_ERROR_OUT_OF_MEMORY;
//
// write out type 1 msg
//
void *cursor = *outBuf;
// 0 : signature
cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
// 8 : marker
cursor = WriteBytes(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_TYPE1_MARKER));
// 12 : flags
cursor = WriteDWORD(cursor, NTLM_TYPE1_FLAGS);
//
// NOTE: it is common for the domain and workstation fields to be empty.
// this is true of Win2k clients, and my guess is that there is
// little utility to sending these strings before the charset has
// been negotiated. we follow suite -- anyways, it doesn't hurt
// to save some bytes on the wire ;-)
//
// 16 : supplied domain security buffer (empty)
cursor = WriteSecBuf(cursor, 0, NTLM_TYPE1_HEADER_LEN);
// 24 : supplied workstation security buffer (empty)
cursor = WriteSecBuf(cursor, 0, NTLM_TYPE1_HEADER_LEN);
return NS_OK;
}
struct Type2Msg
{
PRUint32 flags; // NTLM_Xxx bitwise combination
PRUint8 challenge[8]; // 8 byte challenge
const void *target; // target string (type depends on flags)
PRUint32 targetLen; // target length in bytes
};
static nsresult
ParseType2Msg(const void *inBuf, PRUint32 inLen, Type2Msg *msg)
{
// make sure inBuf is long enough to contain a meaningful type2 msg.
//
// 0 NTLMSSP Signature
// 8 NTLM Message Type
// 12 Target Name
// 20 Flags
// 24 Challenge
// 32 end of header, start of optional data blocks
//
if (inLen < NTLM_TYPE2_HEADER_LEN)
return NS_ERROR_UNEXPECTED;
const PRUint8 *cursor = (const PRUint8 *) inBuf;
// verify NTLMSSP signature
if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
return NS_ERROR_UNEXPECTED;
cursor += sizeof(NTLM_SIGNATURE);
// verify Type-2 marker
if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0)
return NS_ERROR_UNEXPECTED;
cursor += sizeof(NTLM_TYPE2_MARKER);
// read target name security buffer
msg->targetLen = ReadUint16(cursor);
ReadUint16(cursor); // discard next 16-bit value
PRUint32 offset = ReadUint32(cursor); // get offset from inBuf
msg->target = ((const PRUint8 *) inBuf) + offset;
// read flags
msg->flags = ReadUint32(cursor);
// read challenge
memcpy(msg->challenge, cursor, sizeof(msg->challenge));
cursor += sizeof(msg->challenge);
#ifdef DEBUG
printf("NTLM type 2 message:\n");
PrintBuf("target", (const PRUint8 *) msg->target, msg->targetLen);
PrintBuf("flags", (const PRUint8 *) &msg->flags, 4);
PrintFlags(msg->flags);
PrintBuf("challenge", msg->challenge, sizeof(msg->challenge));
#endif
// we currently do not implement LMv2/NTLMv2 or NTLM2 responses,
// so we can ignore target information. we may want to enable
// support for these alternate mechanisms in the future.
return NS_OK;
}
static nsresult
GenerateType3Msg(const nsString &domain,
const nsString &username,
const nsString &password,
const void *inBuf,
PRUint32 inLen,
void **outBuf,
PRUint32 *outLen)
{
// inBuf contains Type-2 msg (the challenge) from server
nsresult rv;
Type2Msg msg;
rv = ParseType2Msg(inBuf, inLen, &msg);
if (NS_FAILED(rv))
return rv;
PRBool unicode = (msg.flags & NTLM_NegotiateUnicode);
// temporary buffers for unicode strings
#ifdef IS_BIG_ENDIAN
nsAutoString ucsDomainBuf, ucsUserBuf;
#endif
nsAutoString ucsHostBuf;
// temporary buffers for oem strings
nsCAutoString oemDomainBuf, oemUserBuf, oemHostBuf;
// pointers and lengths for the string buffers; encoding is unicode if
// the "negotiate unicode" flag was set in the Type-2 message.
const void *domainPtr, *userPtr, *hostPtr;
PRUint32 domainLen, userLen, hostLen;
//
// get domain name
//
if (unicode)
{
#ifdef IS_BIG_ENDIAN
ucsDomainBuf = domain;
domainPtr = ucsDomainBuf.get();
domainLen = ucsDomainBuf.Length() * 2;
WriteUnicodeLE((void *) domainPtr, domainPtr, domainLen);
#else
domainPtr = domain.get();
domainLen = domain.Length() * 2;
#endif
}
else
{
NS_CopyUnicodeToNative(domain, oemDomainBuf);
domainPtr = oemDomainBuf.get();
domainLen = oemDomainBuf.Length();
}
//
// get user name
//
if (unicode)
{
#ifdef IS_BIG_ENDIAN
ucsUserBuf = username;
userPtr = ucsUserBuf.get();
userLen = ucsUserBuf.Length() * 2;
WriteUnicodeLE((void *) userPtr, userPtr, userLen);
#else
userPtr = username.get();
userLen = username.Length() * 2;
#endif
}
else
{
NS_CopyUnicodeToNative(username, oemUserBuf);
userPtr = oemUserBuf.get();
userLen = oemUserBuf.Length();
}
//
// get workstation name (use local machine's hostname)
//
char hostBuf[SYS_INFO_BUFFER_LENGTH];
if (PR_GetSystemInfo(PR_SI_HOSTNAME, hostBuf, sizeof(hostBuf)) == PR_FAILURE)
return NS_ERROR_UNEXPECTED;
hostLen = strlen(hostBuf);
if (unicode)
{
// hostname is ASCII, so we can do a simple zero-pad expansion:
CopyASCIItoUCS2(nsDependentCString(hostBuf, hostLen), ucsHostBuf);
hostPtr = ucsHostBuf.get();
hostLen = ucsHostBuf.Length() * 2;
#ifdef IS_BIG_ENDIAN
WriteUnicodeLE((void *) hostPtr, hostPtr, hostLen);
#endif
}
else
hostPtr = hostBuf;
//
// now that we have generated all of the strings, we can allocate outBuf.
//
*outLen = NTLM_TYPE3_HEADER_LEN + hostLen + domainLen + userLen +
LM_RESP_LEN + NTLM_RESP_LEN;
*outBuf = nsMemory::Alloc(*outLen);
if (!*outBuf)
return NS_ERROR_OUT_OF_MEMORY;
//
// next, we compute the LM and NTLM responses.
//
PRUint8 lmResp[LM_RESP_LEN], ntlmResp[NTLM_RESP_LEN], ntlmHash[NTLM_HASH_LEN];
if (msg.flags & NTLM_NegotiateNTLM2Key)
{
// compute NTLM2 session response
PRUint8 sessionHash[16], temp[16];
PK11_GenerateRandom(lmResp, 8);
memset(lmResp + 8, 0, LM_RESP_LEN - 8);
memcpy(temp, msg.challenge, 8);
memcpy(temp + 8, lmResp, 8);
md5sum(temp, 16, sessionHash);
NTLM_Hash(password, ntlmHash);
LM_Response(ntlmHash, sessionHash, ntlmResp);
}
else
{
PRUint8 lmHash[LM_HASH_LEN];
LM_Hash(password, lmHash);
LM_Response(lmHash, msg.challenge, lmResp);
NTLM_Hash(password, ntlmHash);
LM_Response(ntlmHash, msg.challenge, ntlmResp);
}
//
// finally, we assemble the Type-3 msg :-)
//
void *cursor = *outBuf;
PRUint32 offset;
// 0 : signature
cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
// 8 : marker
cursor = WriteBytes(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_TYPE3_MARKER));
// 12 : LM response sec buf
offset = NTLM_TYPE3_HEADER_LEN + domainLen + userLen + hostLen;
cursor = WriteSecBuf(cursor, LM_RESP_LEN, offset);
memcpy((PRUint8 *) *outBuf + offset, lmResp, LM_RESP_LEN);
// 20 : NTLM response sec buf
offset += LM_RESP_LEN;
cursor = WriteSecBuf(cursor, NTLM_RESP_LEN, offset);
memcpy((PRUint8 *) *outBuf + offset, ntlmResp, NTLM_RESP_LEN);
// 28 : domain name sec buf
offset = NTLM_TYPE3_HEADER_LEN;
cursor = WriteSecBuf(cursor, domainLen, offset);
memcpy((PRUint8 *) *outBuf + offset, domainPtr, domainLen);
// 36 : user name sec buf
offset += domainLen;
cursor = WriteSecBuf(cursor, userLen, offset);
memcpy((PRUint8 *) *outBuf + offset, userPtr, userLen);
// 44 : workstation (host) name sec buf
offset += userLen;
cursor = WriteSecBuf(cursor, hostLen, offset);
memcpy((PRUint8 *) *outBuf + offset, hostPtr, hostLen);
// 52 : session key sec buf (not used)
offset += (hostLen + LM_RESP_LEN + NTLM_RESP_LEN);
cursor = WriteSecBuf(cursor, 0, offset);
// 60 : negotiated flags
cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS);
return NS_OK;
}
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS1(nsNTLMAuthModule, nsIAuthModule)
nsNTLMAuthModule::~nsNTLMAuthModule()
{
ZapString(mPassword);
}
nsresult
nsNTLMAuthModule::InitTest()
{
nsNSSShutDownPreventionLock locker;
//
// disable NTLM authentication when FIPS mode is enabled.
//
return PK11_IsFIPS() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
}
NS_IMETHODIMP
nsNTLMAuthModule::Init(const PRUnichar *domain,
const PRUnichar *username,
const PRUnichar *password)
{
mDomain = domain;
mUsername = username;
mPassword = password;
return NS_OK;
}
NS_IMETHODIMP
nsNTLMAuthModule::GetNextToken(const void *inToken,
PRUint32 inTokenLen,
void **outToken,
PRUint32 *outTokenLen)
{
nsresult rv;
nsNSSShutDownPreventionLock locker;
//
// disable NTLM authentication when FIPS mode is enabled.
//
if (PK11_IsFIPS())
return NS_ERROR_NOT_AVAILABLE;
// if inToken is non-null, then assume it contains a type 2 message...
if (inToken)
rv = GenerateType3Msg(mDomain, mUsername, mPassword, inToken,
inTokenLen, outToken, outTokenLen);
else
rv = GenerateType1Msg(outToken, outTokenLen);
return rv;
}
//-----------------------------------------------------------------------------
// DES support code
// set odd parity bit (in least significant bit position)
static PRUint8
des_setkeyparity(PRUint8 x)
{
if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
(x >> 4) ^ (x >> 3) ^ (x >> 2) ^
(x >> 1)) & 0x01) == 0)
x |= 0x01;
else
x &= 0xfe;
return x;
}
// build 64-bit des key from 56-bit raw key
static void
des_makekey(const PRUint8 *raw, PRUint8 *key)
{
key[0] = des_setkeyparity(raw[0]);
key[1] = des_setkeyparity((raw[0] << 7) | (raw[1] >> 1));
key[2] = des_setkeyparity((raw[1] << 6) | (raw[2] >> 2));
key[3] = des_setkeyparity((raw[2] << 5) | (raw[3] >> 3));
key[4] = des_setkeyparity((raw[3] << 4) | (raw[4] >> 4));
key[5] = des_setkeyparity((raw[4] << 3) | (raw[5] >> 5));
key[6] = des_setkeyparity((raw[5] << 2) | (raw[6] >> 6));
key[7] = des_setkeyparity((raw[6] << 1));
}
// run des encryption algorithm (using NSS)
static void
des_encrypt(const PRUint8 *key, const PRUint8 *src, PRUint8 *hash)
{
CK_MECHANISM_TYPE cipherMech = CKM_DES_ECB;
PK11SlotInfo *slot = nsnull;
PK11SymKey *symkey = nsnull;
PK11Context *ctxt = nsnull;
SECItem keyItem, *param;
SECStatus rv;
unsigned int n;
slot = PK11_GetBestSlot(cipherMech, nsnull);
if (!slot)
{
NS_ERROR("no slot");
goto done;
}
keyItem.data = (PRUint8 *) key;
keyItem.len = 8;
symkey = PK11_ImportSymKey(slot, cipherMech,
PK11_OriginUnwrap, CKA_ENCRYPT,
&keyItem, nsnull);
if (!symkey)
{
NS_ERROR("no symkey");
goto done;
}
// no initialization vector required
param = PK11_ParamFromIV(cipherMech, nsnull);
if (!param)
{
NS_ERROR("no param");
goto done;
}
ctxt = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
symkey, param);
if (!ctxt)
{
NS_ERROR("no context");
goto done;
}
rv = PK11_CipherOp(ctxt, hash, (int *) &n, 8, (PRUint8 *) src, 8);
if (rv != SECSuccess)
{
NS_ERROR("des failure");
goto done;
}
rv = PK11_DigestFinal(ctxt, hash+8, &n, 0);
if (rv != SECSuccess)
{
NS_ERROR("des failure");
goto done;
}
done:
if (ctxt)
PK11_DestroyContext(ctxt, PR_TRUE);
if (symkey)
PK11_FreeSymKey(symkey);
if (param)
SECITEM_FreeItem(param, PR_TRUE);
if (slot)
PK11_FreeSlot(slot);
}
//-----------------------------------------------------------------------------
// MD5 support code
static void md5sum(const PRUint8 *input, PRUint32 inputLen, PRUint8 *result)
{
PK11Context *ctxt = PK11_CreateDigestContext(SEC_OID_MD5);
if (ctxt)
{
if (PK11_DigestBegin(ctxt) == SECSuccess)
{
if (PK11_DigestOp(ctxt, input, inputLen) == SECSuccess)
{
PRUint32 resultLen = 16;
PK11_DigestFinal(ctxt, result, &resultLen, resultLen);
}
}
}
PK11_DestroyContext(ctxt, PR_TRUE);
}

Просмотреть файл

@ -0,0 +1,73 @@
/* vim:set ts=2 sw=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by IBM Corporation are Copyright (C) 2003
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsNTLMAuthModule_h__
#define nsNTLMAuthModule_h__
#include "nsIAuthModule.h"
#include "nsString2.h"
class nsNTLMAuthModule : public nsIAuthModule
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIAUTHMODULE
nsNTLMAuthModule() {}
virtual ~nsNTLMAuthModule();
nsresult InitTest();
private:
nsString mDomain;
nsString mUsername;
nsString mPassword;
};
#define NS_NTLMAUTHMODULE_CLASSNAME \
"nsNTLMAuthModule"
#define NS_NTLMAUTHMODULE_CONTRACTID \
NS_AUTH_MODULE_CONTRACTID_PREFIX "ntlm"
#define NS_NTLMAUTHMODULE_CID \
{ /* a4e5888f-4fe4-4632-8e7e-745196ea7c70 */ \
0xa4e5888f, \
0x4fe4, \
0x4632, \
{0x8e, 0x7e, 0x74, 0x51, 0x96, 0xea, 0x7c, 0x70} \
}
#endif // nsNTLMAuthModule_h__