secur32: Implement simple MakeSignature.

This commit is contained in:
Kai Blin 2006-08-12 19:19:49 +02:00 committed by Alexandre Julliard
parent c8c7bf61ad
commit 9b480ef06e
4 changed files with 207 additions and 42 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2005 Kai Blin * Copyright 2005, 2006 Kai Blin
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -114,6 +114,8 @@ SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
helper->com_buf = NULL; helper->com_buf = NULL;
helper->com_buf_size = 0; helper->com_buf_size = 0;
helper->com_buf_offset = 0; helper->com_buf_offset = 0;
helper->session_key = NULL;
helper->neg_flags = 0;
helper->pipe_in = pipe_in[0]; helper->pipe_in = pipe_in[0];
close(pipe_in[1]); close(pipe_in[1]);
helper->pipe_out = pipe_out[1]; helper->pipe_out = pipe_out[1];
@ -262,6 +264,7 @@ void cleanup_helper(PNegoHelper helper)
HeapFree(GetProcessHeap(), 0, helper->password); HeapFree(GetProcessHeap(), 0, helper->password);
HeapFree(GetProcessHeap(), 0, helper->com_buf); HeapFree(GetProcessHeap(), 0, helper->com_buf);
HeapFree(GetProcessHeap(), 0, helper->session_key);
/* closing stdin will terminate ntlm_auth */ /* closing stdin will terminate ntlm_auth */
close(helper->pipe_out); close(helper->pipe_out);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2005 Kai Blin * Copyright 2005, 2006 Kai Blin
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -20,6 +20,7 @@
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "winnls.h" #include "winnls.h"
@ -377,7 +378,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
SECURITY_STATUS ret; SECURITY_STATUS ret;
PNegoHelper helper; PNegoHelper helper;
ULONG ctxt_attr = 0; ULONG ctxt_attr = 0;
char* buffer; char* buffer, *want_flags = NULL;
PBYTE bin; PBYTE bin;
int buffer_len, bin_len, max_len = NTLM_MAX_BUF; int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
@ -406,6 +407,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
* base64 encoded password * base64 encoded password
* AF <base64 blob> client is done, blob should be * AF <base64 blob> client is done, blob should be
* sent to server with KK prefixed * sent to server with KK prefixed
* GF <string list> A string list of negotiated flags
* GK <base64 blob> base64 encoded session key
* BH <char reason> something broke * BH <char reason> something broke
*/ */
/* The squid cache size is 2010 chars, and that's what ntlm_auth uses */ /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
@ -414,30 +417,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
{ {
TRACE("According to a MS whitepaper pszTargetName is ignored.\n"); TRACE("According to a MS whitepaper pszTargetName is ignored.\n");
} }
/* Handle all the flags */
if(fContextReq & ISC_REQ_CONFIDENTIALITY)
{
FIXME("InitializeSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n");
}
if(fContextReq & ISC_REQ_CONNECTION)
{
/* This is default, so we'll enable it */
ctxt_attr |= ISC_RET_CONNECTION;
}
if(fContextReq & ISC_REQ_EXTENDED_ERROR)
FIXME("ISC_REQ_EXTENDED_ERROR\n");
if(fContextReq & ISC_REQ_INTEGRITY)
FIXME("ISC_REQ_INTEGRITY\n");
if(fContextReq & ISC_REQ_MUTUAL_AUTH)
FIXME("ISC_REQ_MUTUAL_AUTH\n");
if(fContextReq & ISC_REQ_REPLAY_DETECT)
FIXME("ISC_REQ_REPLAY_DETECT\n");
if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
FIXME("ISC_REQ_SEQUENCE_DETECT\n");
if(fContextReq & ISC_REQ_STREAM)
FIXME("ISC_REQ_STREAM\n");
/* Done with the flags */
if(TargetDataRep == SECURITY_NETWORK_DREP){ if(TargetDataRep == SECURITY_NETWORK_DREP){
TRACE("Setting SECURITY_NETWORK_DREP\n"); TRACE("Setting SECURITY_NETWORK_DREP\n");
} }
@ -448,6 +428,38 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
if((phContext == NULL) && (pInput == NULL)) if((phContext == NULL) && (pInput == NULL))
{ {
TRACE("First time in ISC()\n"); TRACE("First time in ISC()\n");
/* Allocate space for a maximal string of
* "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL
* NTLMSSP_FEATURE_SESSION_KEY"
*/
want_flags = HeapAlloc(GetProcessHeap(), 0, 73);
if(want_flags == NULL)
{
ret = SEC_E_INSUFFICIENT_MEMORY;
goto end;
}
lstrcpyA(want_flags, "SF");
if(fContextReq & ISC_REQ_CONFIDENTIALITY)
lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL");
if(fContextReq & ISC_REQ_CONNECTION)
{
/* This is default, so we'll enable it */
ctxt_attr |= ISC_RET_CONNECTION;
lstrcatA(want_flags, " NTLMSSP_FEATURE_SESSION_KEY");
}
if(fContextReq & ISC_REQ_EXTENDED_ERROR)
FIXME("ISC_REQ_EXTENDED_ERROR\n");
if(fContextReq & ISC_REQ_INTEGRITY)
lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
if(fContextReq & ISC_REQ_MUTUAL_AUTH)
FIXME("ISC_REQ_MUTUAL_AUTH\n");
if(fContextReq & ISC_REQ_REPLAY_DETECT)
FIXME("ISC_REQ_REPLAY_DETECT\n");
if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
FIXME("ISC_REQ_SEQUENCE_DETECT\n");
if(fContextReq & ISC_REQ_STREAM)
FIXME("ISC_REQ_STREAM\n");
/* Request a challenge request from ntlm_auth */ /* Request a challenge request from ntlm_auth */
if(helper->password == NULL) if(helper->password == NULL)
{ {
@ -474,6 +486,18 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
goto end; goto end;
TRACE("Helper returned %s\n", debugstr_a(buffer)); TRACE("Helper returned %s\n", debugstr_a(buffer));
if(lstrlenA(want_flags) > 2)
{
TRACE("Want flags are '%s'\n", debugstr_a(want_flags));
lstrcpynA(buffer, want_flags, max_len-1);
if((ret = run_helper(helper, buffer, max_len, &buffer_len))
!= SEC_E_OK)
goto end;
if(!strncmp(buffer, "BH", 2))
TRACE("Helper doesn't understand new command set\n");
}
lstrcpynA(buffer, "YR", max_len-1); lstrcpynA(buffer, "YR", max_len-1);
if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
@ -542,22 +566,73 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
(strncmp(buffer, "AF ", 3) !=0)) (strncmp(buffer, "AF ", 3) !=0))
{ {
TRACE("Helper returned %c%c\n", buffer[0], buffer[1]); TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
HeapFree(GetProcessHeap(), 0, buffer); ret = SEC_E_INVALID_TOKEN;
HeapFree(GetProcessHeap(), 0, bin); goto end;
return SEC_E_INVALID_TOKEN;
} }
/* decode the blob and send it to server */ /* decode the blob and send it to server */
if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
&bin_len)) != SEC_E_OK) &bin_len)) != SEC_E_OK)
{ {
HeapFree(GetProcessHeap(), 0, buffer); goto end;
HeapFree(GetProcessHeap(), 0, bin); }
return ret;
TRACE("Getting negotiated flags\n");
lstrcpynA(buffer, "GF", max_len - 1);
if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
goto end;
if(buffer_len < 3)
{
TRACE("No flags negotiated, or helper does not support GF command\n");
}
else
{
TRACE("Negotiated %s\n", debugstr_a(buffer));
sscanf(buffer + 3, "%lx", &(helper->neg_flags));
TRACE("Stored 0x%08lx as flags\n", helper->neg_flags);
}
TRACE("Getting session key\n");
lstrcpynA(buffer, "GK", max_len - 1);
if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
goto end;
if(buffer_len < 3)
TRACE("Helper does not support GK command\n");
else
{
if(strncmp(buffer, "BH ", 3) == 0)
{
TRACE("Helper sent %s\n", debugstr_a(buffer+3));
helper->valid_session_key = FALSE;
helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16);
/*FIXME: Generate the dummy session key = MD4(MD4(password))*/
memset(helper->session_key, 0 , 16);
}
else if(strncmp(buffer, "GK ", 3) == 0)
{
if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
&bin_len)) != SEC_E_OK)
{
TRACE("Failed to decode session key\n");
}
TRACE("Session key is %s\n", debugstr_a(buffer+3));
helper->valid_session_key = TRUE;
if(!helper->session_key)
helper->session_key = HeapAlloc(GetProcessHeap(), 0, bin_len);
if(!helper->session_key)
{
TRACE("Failed to allocate memory for session key\n");
ret = SEC_E_INTERNAL_ERROR;
goto end;
}
memcpy(helper->session_key, bin, bin_len);
}
} }
phNewContext->dwUpper = ctxt_attr; phNewContext->dwUpper = ctxt_attr;
phNewContext->dwLower = ret; phNewContext->dwLower = (DWORD)helper;
ret = SEC_E_OK; ret = SEC_E_OK;
} }
@ -600,6 +675,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
HeapFree(GetProcessHeap(), 0, helper->password); HeapFree(GetProcessHeap(), 0, helper->password);
} }
end: end:
HeapFree(GetProcessHeap(), 0, want_flags);
HeapFree(GetProcessHeap(), 0, buffer); HeapFree(GetProcessHeap(), 0, buffer);
HeapFree(GetProcessHeap(), 0, bin); HeapFree(GetProcessHeap(), 0, bin);
return ret; return ret;
@ -1024,18 +1100,56 @@ static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContex
static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP, static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
PSecBufferDesc pMessage, ULONG MessageSeqNo) PSecBufferDesc pMessage, ULONG MessageSeqNo)
{ {
SECURITY_STATUS ret; PNegoHelper helper;
TRACE("%p %ld %p %ld\n", phContext, fQOP, pMessage, MessageSeqNo); TRACE("%p %ld %p %ld\n", phContext, fQOP, pMessage, MessageSeqNo);
if (phContext) if (!phContext)
return SEC_E_INVALID_HANDLE;
if(fQOP)
FIXME("Ignoring fQOP 0x%08lx", fQOP);
if(MessageSeqNo)
FIXME("Ignoring MessageSeqNo");
if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2 ||
pMessage->pBuffers[0].BufferType != SECBUFFER_TOKEN ||
!pMessage->pBuffers[0].pvBuffer)
return SEC_E_INVALID_TOKEN;
if(pMessage->pBuffers[0].cbBuffer < 16)
return SEC_E_BUFFER_TOO_SMALL;
helper = (PNegoHelper)phContext->dwLower;
TRACE("Negotiated flags are: 0x%08lx\n", helper->neg_flags);
if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
{ {
ret = SEC_E_UNSUPPORTED_FUNCTION; FIXME("Can't handle NTLMv2 signing yet. Aborting.\n");
return SEC_E_UNSUPPORTED_FUNCTION;
} }
else if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN)
{ {
ret = SEC_E_INVALID_HANDLE; FIXME("Can't handle real signing yet. Aborting.\n");
return SEC_E_UNSUPPORTED_FUNCTION;
} }
return ret;
if(helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE)
{
FIXME("Can't handle encrypted session key yet. Aborting.\n");
return SEC_E_UNSUPPORTED_FUNCTION;
}
if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
{
TRACE("Generating dummy signature\n");
/* A dummy signature is 0x01 followed by 15 bytes of 0x00 */
memset(pMessage->pBuffers[0].pvBuffer, 0, 16);
memset(pMessage->pBuffers[0].pvBuffer, 0x01, 1);
pMessage->pBuffers[0].cbBuffer = 16;
return SEC_E_OK;
}
return SEC_E_UNSUPPORTED_FUNCTION;
} }
/*********************************************************************** /***********************************************************************

View File

@ -66,6 +66,9 @@ typedef struct _NegoHelper {
char *com_buf; char *com_buf;
int com_buf_size; int com_buf_size;
int com_buf_offset; int com_buf_offset;
BYTE *session_key;
BOOL valid_session_key;
unsigned long neg_flags;
} NegoHelper, *PNegoHelper; } NegoHelper, *PNegoHelper;
/* Allocates space for and initializes a new provider. If fnTableA or fnTableW /* Allocates space for and initializes a new provider. If fnTableA or fnTableW
@ -121,4 +124,24 @@ SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf,
SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf, SECURITY_STATUS decodeBase64(char *in_buf, int in_len, BYTE *out_buf,
int max_len, int *out_len); int max_len, int *out_len);
/* NTLMSSP flags indicating the negotiated features */
#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
#define NTLMSSP_NEGOTIATE_OEM 0x00000002
#define NTLMSSP_REQUEST_TARGET 0x00000004
#define NTLMSSP_NEGOTIATE_SIGN 0x00000010
#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE 0x00000040
#define NTLMSSP_NEGOTIATE_LM_SESSION_KEY 0x00000080
#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
#define NTLMSSP_NEGOTIATE_TARGET_TYPE_DOMAIN 0x00010000
#define NTLMSSP_NEGOTIATE_TARGET_TYPE_SERVER 0x00020000
#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
#define NTLMSSP_NEGOTIATE_128 0x20000000
#define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000
#define NTLMSSP_NEGOTIATE_56 0x80000000
#endif /* ndef __SECUR32_PRIV_H__ */ #endif /* ndef __SECUR32_PRIV_H__ */

View File

@ -673,7 +673,7 @@ static void testSignSeal()
SEC_WINNT_AUTH_IDENTITY id; SEC_WINNT_AUTH_IDENTITY id;
static char sec_pkg_name[] = "NTLM"; static char sec_pkg_name[] = "NTLM";
PSecBufferDesc crypt = NULL; PSecBufferDesc crypt = NULL;
PSecBuffer data = NULL; PSecBuffer data = NULL, fake_data = NULL;
ULONG qop = 0; ULONG qop = 0;
SecPkgContext_Sizes ctxt_sizes; SecPkgContext_Sizes ctxt_sizes;
@ -739,6 +739,28 @@ static void testSignSeal()
crypt->ulVersion = SECBUFFER_VERSION; crypt->ulVersion = SECBUFFER_VERSION;
crypt->cBuffers = 2; crypt->cBuffers = 2;
if((fake_data = HeapAlloc(GetProcessHeap(), 0, sizeof(SecBuffer) * 2)) == NULL)
{
trace("Failed to allocate the fake crypto buffer, aborting test.\n");
goto end;
}
crypt->pBuffers = fake_data;
fake_data[0].BufferType = SECBUFFER_DATA;
fake_data[0].cbBuffer = ctxt_sizes.cbSecurityTrailer;
fake_data[0].pvBuffer = HeapAlloc(GetProcessHeap(), 0, fake_data[0].cbBuffer);
fake_data[1].BufferType = SECBUFFER_DATA;
fake_data[1].cbBuffer = lstrlen(message);
fake_data[1].pvBuffer = HeapAlloc(GetProcessHeap(), 0, fake_data[1].cbBuffer);
sec_status = pMakeSignature(client.ctxt, 0, crypt, 0);
ok(sec_status == SEC_E_INVALID_TOKEN,
"MakeSignature returned %s, not SEC_E_INVALID_TOKEN.\n",
getSecError(sec_status));
if((data = HeapAlloc(GetProcessHeap(), 0, sizeof(SecBuffer) * 2)) == NULL) if((data = HeapAlloc(GetProcessHeap(), 0, sizeof(SecBuffer) * 2)) == NULL)
{ {
trace("Failed to allocate the crypto buffer, aborting test.\n"); trace("Failed to allocate the crypto buffer, aborting test.\n");
@ -761,12 +783,10 @@ static void testSignSeal()
* it is sent by the client or the server * it is sent by the client or the server
*/ */
sec_status = pMakeSignature(client.ctxt, 0, crypt, 0); sec_status = pMakeSignature(client.ctxt, 0, crypt, 0);
todo_wine {
ok(sec_status == SEC_E_OK, "MakeSignature returned %s, not SEC_E_OK.\n", ok(sec_status == SEC_E_OK, "MakeSignature returned %s, not SEC_E_OK.\n",
getSecError(sec_status)); getSecError(sec_status));
ok(!memcmp(crypt->pBuffers[0].pvBuffer, message_signature, ok(!memcmp(crypt->pBuffers[0].pvBuffer, message_signature,
crypt->pBuffers[0].cbBuffer), "Signature is not as expected.\n"); crypt->pBuffers[0].cbBuffer), "Signature is not as expected.\n");
}
data[0].cbBuffer = sizeof(message_signature); data[0].cbBuffer = sizeof(message_signature);
memcpy(data[0].pvBuffer, message_signature, data[0].cbBuffer); memcpy(data[0].pvBuffer, message_signature, data[0].cbBuffer);
@ -807,6 +827,11 @@ end:
pDeleteSecurityContext(client.ctxt); pDeleteSecurityContext(client.ctxt);
pFreeCredentialsHandle(client.cred); pFreeCredentialsHandle(client.cred);
if(fake_data)
{
HeapFree(GetProcessHeap(), 0, fake_data[0].pvBuffer);
HeapFree(GetProcessHeap(), 0, fake_data[1].pvBuffer);
}
if(data) if(data)
{ {
HeapFree(GetProcessHeap(), 0, data[0].pvBuffer); HeapFree(GetProcessHeap(), 0, data[0].pvBuffer);