Platform SDK: Logon Authentication

Signing a Message

When a client and server finish setting up the security context, message support functions can be used. The client and server use the security context token created when the session was established to call MakeSignature and VerifySignature functions. The context token can be used with EncryptMessage and DecryptMessage for communications privacy.

The following example code shows the client side generating a signed message to send to the server. Before calling MakeSignature, the client calls QueryContextAttributes with a SecPkgContext_Sizes structure to determine the length of the buffer needed to hold the message signature. If the cbMaxSignature member is zero, the security package does not support signing messages. Otherwise, this member indicates the size of the buffer to allocate to receive the signature.

The example assumes that a SecHandle variable named phContext and a SOCKET structure named s are initialized. For the declarations and initiations of these variables, see Using SSPI with a Windows Sockets Client and Using SSPI with a Windows Sockets Server. This code also uses the function SendMsg and HandleError. Code for these functions can be seen in Utility Functions for Windows Sockets Client and Server.

//--------------------------------------------------------------------
//   Declare and initialize local variables.

SecPkgContext_Sizes ContextSizes;
char *MessageBuffer = "This is a sample buffer to be signed.";
DWORD MessageBufferSize = strlen(MessageBuffer);
SecBufferDesc InputBufferDescriptor;
SecBuffer InputSecurityToken[2];

ss=g_pFuncs->QueryContextAttributes(
    &phContext,
    SECPKG_ATTR_SIZES,
    &ContextSizes
    );
if(ContextSizes.cbMaxSignature == 0)
{
     HandleError("This session does not support message signing.");
}
//--------------------------------------------------------------------
// The message as a byte string is in the variable 
// MessageBuffer, and its length is in MessageBufferSize. 

//--------------------------------------------------------------------
// Build the buffer descriptor and the buffers 
// to pass to the MakeSignature call.

InputBufferDescriptor.cBuffers = 2;
InputBufferDescriptor.pBuffers = InputSecurityToken;
InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;

//--------------------------------------------------------------------
// Build a security buffer for the message itself. If 
// the SECBUFFER_READONLY attribute is set, the buffer will not be
// signed.

InputSecurityToken[0].BufferType = SECBUFFER_DATA;
InputSecurityToken[0].cbBuffer = MessageBufferSize;
InputSecurityToken[0].pvBuffer = MessageBuffer;

//--------------------------------------------------------------------
// Allocate and build a security buffer for the message
// signature.

InputSecurityToken[1].BufferType = SECBUFFER_TOKEN;
InputSecurityToken[1].cbBuffer = ContextSizes.cbMaxSignature;
InputSecurityToken[1].pvBuffer = 
        (void *)malloc(ContextSizes.cbMaxSignature);

//--------------------------------------------------------------------
// Call MakeSignature 
// For the NTLM package, the sequence number need not be specified 
// because the package provides sequencing.
// The quality of service parameter is ignored.

ss=g_pFuncs->MakeSignature(
    &phContext,
    0,                       // no quality of service
    &InputBufferDescriptor,  // input message descriptor
    0                        // no sequence number
    );
if (SEC_SUCCESS(ss))
{
     printf("Have made a signature.\n");
}
else
{ 
    HandleError("MakeSignature Failed."); 
}

//--------------------------------------------------------------------
//  Send the message.

if(!SendMsg(
    s,
    (BYTE *)InputSecurityToken[0].pvBuffer,
    InputSecurityToken[0].cbBuffer))
{
     HandleError("The message was not sent.");
}

//--------------------------------------------------------------------
//   Send the signature.

if(!SendMsg(
     s,
    (BYTE *)InputSecurityToken[1].pvBuffer,
    InputSecurityToken[1].cbBuffer ))
{
     HandleError("The signature was not sent.");
}

MakeSignature returns TRUE if the context is set up to allow signing messages and if the input buffer descriptor is correctly formatted. After the message is signed, the message and the signature with their lengths are sent to the remote computer.

Note  The data contents of the SecBuffer structures are sent, not the SecBuffer structures themselves nor the SecBufferDesc structure. New SecBuffer structures and a new SecBufferDesc structure are created by the receiving application to verify the signature.