summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf Habacker <ralf.habacker@freenet.de>2016-07-13 00:09:15 +0200
committerRalf Habacker <ralf.habacker@freenet.de>2016-07-13 00:09:15 +0200
commit58360164138479ac8337c0148dcbc338f1a162ef (patch)
treeb1d92d0a8615f0270e1cab254d980a01b53f0c4a
parentaf6839be7fc3feea123c547e2046356d89236ec7 (diff)
Add sspi client and server test app.
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=96577
-rw-r--r--cmake/test/CMakeLists.txt2
-rw-r--r--test/SspiExample.h74
-rw-r--r--test/sspi-client.cpp779
-rw-r--r--test/sspi-server.cpp781
4 files changed, 1636 insertions, 0 deletions
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 58eed0901..28e599c24 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -76,6 +76,8 @@ add_helper_executable(manual-tcp ${manual-tcp_SOURCES} ${DBUS_INTERNAL_LIBRARIES
add_helper_executable(manual-backtrace ${CMAKE_SOURCE_DIR}/../test/manual-backtrace.c dbus-1)
if(WIN32)
add_helper_executable(manual-paths ${manual-paths_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
+ add_helper_executable(sspi-client ${CMAKE_SOURCE_DIR}/../test/sspi-client.cpp ws2_32 secur32)
+ add_helper_executable(sspi-server ${CMAKE_SOURCE_DIR}/../test/sspi-server.cpp ws2_32 secur32)
endif()
if(DBUS_WITH_GLIB)
diff --git a/test/SspiExample.h b/test/SspiExample.h
new file mode 100644
index 000000000..b0126dc94
--- /dev/null
+++ b/test/SspiExample.h
@@ -0,0 +1,74 @@
+
+// SspiExample.h
+#include <sspi.h>
+#include <windows.h>
+
+BOOL SendMsg (SOCKET s, PBYTE pBuf, DWORD cbBuf);
+BOOL ReceiveMsg (SOCKET s, PBYTE pBuf, DWORD cbBuf, DWORD *pcbRead);
+BOOL SendBytes (SOCKET s, PBYTE pBuf, DWORD cbBuf);
+BOOL ReceiveBytes (SOCKET s, PBYTE pBuf, DWORD cbBuf, DWORD *pcbRead);
+void cleanup();
+
+BOOL GenClientContext (
+ BYTE *pIn,
+ DWORD cbIn,
+ BYTE *pOut,
+ DWORD *pcbOut,
+ BOOL *pfDone,
+ CHAR *pszTarget,
+ CredHandle *hCred,
+ struct _SecHandle *hcText
+);
+
+BOOL GenServerContext (
+ BYTE *pIn,
+ DWORD cbIn,
+ BYTE *pOut,
+ DWORD *pcbOut,
+ BOOL *pfDone,
+ BOOL fNewCredential
+);
+
+BOOL EncryptThis (
+ PBYTE pMessage,
+ ULONG cbMessage,
+ BYTE ** ppOutput,
+ LPDWORD pcbOutput,
+ ULONG securityTrailer
+ );
+
+PBYTE DecryptThis(
+ PBYTE achData,
+ LPDWORD pcbMessage,
+ struct _SecHandle *hCtxt,
+ ULONG cbSecurityTrailer
+);
+
+BOOL
+SignThis (
+ PBYTE pMessage,
+ ULONG cbMessage,
+ BYTE ** ppOutput,
+ LPDWORD pcbOutput
+);
+
+PBYTE VerifyThis(
+ PBYTE pBuffer,
+ LPDWORD pcbMessage,
+ struct _SecHandle *hCtxt,
+ ULONG cbMaxSignature
+);
+
+void PrintHexDump(DWORD length, PBYTE buffer);
+
+BOOL ConnectAuthSocket (
+ SOCKET *s,
+ CredHandle *hCred,
+ struct _SecHandle *hcText,
+ char *ServerName,
+ char *TargetName
+);
+
+BOOL CloseAuthSocket (SOCKET s);
+
+void MyHandleError(char *s, SECURITY_STATUS ss = 0);
diff --git a/test/sspi-client.cpp b/test/sspi-client.cpp
new file mode 100644
index 000000000..ee6c28bcc
--- /dev/null
+++ b/test/sspi-client.cpp
@@ -0,0 +1,779 @@
+
+//--------------------------------------------------------------------
+// Client-side program to establish an SSPI socket connection
+// with a server and exchange messages.
+
+//--------------------------------------------------------------------
+// Define macros and constants.
+
+#define SECURITY_WIN32
+#define BIG_BUFF 2048
+#define SEC_SUCCESS(Status) ((Status) >= 0)
+#define g_usPort 2000
+
+#define cbMaxMessage 12000
+#define MessageAttribute ISC_REQ_CONFIDENTIALITY
+
+#include <windows.h>
+#include <winsock.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "SspiExample.h"
+
+BOOL DoAuthentication (
+ SOCKET s,
+ CredHandle *hCred,
+ struct _SecHandle *hcText,
+ char *TargetName);
+
+int main(int argc, char **argv)
+{
+ SOCKET Client_Socket;
+ BYTE Data[BIG_BUFF];
+ PCHAR pMessage;
+ WSADATA wsaData;
+ CredHandle hCred;
+ struct _SecHandle hCtxt;
+ SECURITY_STATUS ss;
+ DWORD cbRead;
+ ULONG cbMaxSignature;
+ ULONG cbSecurityTrailer;
+ SecPkgContext_Sizes SecPkgContextSizes;
+ SecPkgContext_NegotiationInfo SecPkgNegInfo;
+ char *ServerName = "";
+ char *TargetName = "";
+
+ if (argc == 1)
+ {
+ fprintf(stderr, "sspi-client <hostname> <user>\n");
+ exit(1);
+ }
+
+ if (argc > 1)
+ ServerName = argv[1];
+
+ if (argc > 2)
+ TargetName = argv[2];
+
+ //-------------------------------------------------------------------
+ // Initialize the socket and the SSP security package.
+
+ if(WSAStartup (0x0101, &wsaData))
+ {
+ MyHandleError("Could not initialize winsock ");
+ }
+
+ //--------------------------------------------------------------------
+ // Connect to a server.
+
+ if (!ConnectAuthSocket (
+ &Client_Socket,
+ &hCred,
+ &hCtxt,
+ ServerName,
+ TargetName))
+ {
+ MyHandleError("Authenticated server connection ");
+ }
+
+ //--------------------------------------------------------------------
+ // An authenticated session with a server has been established.
+ // Receive and manage a message from the server.
+ // First, find and display the name of the negotiated
+ // SSP and the size of the signature and the encryption
+ // trailer blocks for this SSP.
+ ss = QueryContextAttributes(
+ &hCtxt,
+ SECPKG_ATTR_NEGOTIATION_INFO,
+ &SecPkgNegInfo );
+ if (!SEC_SUCCESS(ss))
+ {
+ MyHandleError("QueryContextAttributes failed ", ss);
+ }
+ else
+ {
+ printf("Package Name: %s\n", SecPkgNegInfo.PackageInfo->Name);
+ }
+
+ ss = QueryContextAttributes(
+ &hCtxt,
+ SECPKG_ATTR_SIZES,
+ &SecPkgContextSizes );
+
+ if (!SEC_SUCCESS(ss))
+ {
+ MyHandleError("Query context ", ss);
+ }
+
+ cbMaxSignature = SecPkgContextSizes.cbMaxSignature;
+ cbSecurityTrailer = SecPkgContextSizes.cbSecurityTrailer;
+
+ printf("InitializeSecurityContext result = 0x%08x\n", ss);
+
+ //--------------------------------------------------------------------
+ // Decrypt and display the message from the server.
+
+ if (!ReceiveBytes(
+ Client_Socket,
+ Data,
+ BIG_BUFF,
+ &cbRead))
+ {
+ MyHandleError("No response from server ");
+ }
+
+ if (0 == cbRead)
+ {
+ MyHandleError("Zero bytes received ");
+ }
+
+ pMessage = (PCHAR) DecryptThis(
+ Data,
+ &cbRead,
+ &hCtxt,
+ cbSecurityTrailer);
+
+ printf ("The message from the server is \n -> %.*s \n",
+ cbRead, pMessage);
+
+ //--------------------------------------------------------------------
+ // Terminate socket and security package.
+
+ DeleteSecurityContext (&hCtxt);
+ FreeCredentialHandle (&hCred);
+ shutdown (Client_Socket, 2);
+ closesocket (Client_Socket);
+ if (SOCKET_ERROR == WSACleanup ())
+ {
+ MyHandleError("Problem with socket cleanup ");
+ }
+
+ exit (EXIT_SUCCESS);
+} // end main
+
+//--------------------------------------------------------------------
+// ConnectAuthSocket establishes an authenticated socket connection
+// with a server and initializes needed security package resources.
+
+BOOL ConnectAuthSocket (
+ SOCKET *s,
+ CredHandle *hCred,
+ struct _SecHandle *hcText,
+ char *ServerName,
+ char *TargetName)
+{
+ unsigned long ulAddress;
+ struct hostent *pHost;
+ SOCKADDR_IN sin;
+
+ //--------------------------------------------------------------------
+ // Lookup the server's address.
+
+ ulAddress = inet_addr (ServerName);
+
+ if (INADDR_NONE == ulAddress)
+ {
+ pHost = gethostbyname (ServerName);
+ if (NULL == pHost)
+ {
+ MyHandleError("Unable to resolve host name ");
+ }
+ memcpy((char FAR *)&ulAddress, pHost->h_addr, pHost->h_length);
+ }
+
+ //--------------------------------------------------------------------
+ // Create the socket.
+
+ *s = socket (
+ PF_INET,
+ SOCK_STREAM,
+ 0);
+
+ if (INVALID_SOCKET == *s)
+ {
+ MyHandleError("Unable to create socket");
+ }
+ else
+ {
+ printf("Socket created.\n");
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ulAddress;
+ sin.sin_port = htons (g_usPort);
+
+ //--------------------------------------------------------------------
+ // Connect to the server.
+
+ if (connect (*s, (LPSOCKADDR) &sin, sizeof (sin)))
+ {
+ closesocket (*s);
+ MyHandleError( "Connect failed ");
+ }
+
+ //--------------------------------------------------------------------
+ // Authenticate the connection.
+
+ if (!DoAuthentication (*s, hCred, hcText, TargetName))
+ {
+ closesocket (*s);
+ MyHandleError("Authentication ");
+ }
+
+ return(TRUE);
+} // end ConnectAuthSocket
+
+BOOL DoAuthentication (
+ SOCKET s,
+ CredHandle *hCred,
+ struct _SecHandle *hcText,
+ char *TargetName)
+{
+ BOOL fDone = FALSE;
+ DWORD cbOut = 0;
+ DWORD cbIn = 0;
+ PBYTE pInBuf;
+ PBYTE pOutBuf;
+
+
+ if(!(pInBuf = (PBYTE) malloc(cbMaxMessage)))
+ {
+ MyHandleError("Memory allocation ");
+ }
+
+ if(!(pOutBuf = (PBYTE) malloc(cbMaxMessage)))
+ {
+ MyHandleError("Memory allocation ");
+ }
+
+ cbOut = cbMaxMessage;
+ if (!GenClientContext (
+ NULL,
+ 0,
+ pOutBuf,
+ &cbOut,
+ &fDone,
+ TargetName,
+ hCred,
+ hcText
+ ))
+ {
+ return(FALSE);
+ }
+
+ if (!SendMsg (s, pOutBuf, cbOut ))
+ {
+ MyHandleError("Send message failed ");
+ }
+
+ while (!fDone)
+ {
+ if (!ReceiveMsg (
+ s,
+ pInBuf,
+ cbMaxMessage,
+ &cbIn))
+ {
+ MyHandleError("Receive message failed ");
+ }
+
+ cbOut = cbMaxMessage;
+
+ if (!GenClientContext (
+ pInBuf,
+ cbIn,
+ pOutBuf,
+ &cbOut,
+ &fDone,
+ TargetName,
+ hCred,
+ hcText))
+ {
+ MyHandleError("GenClientContext failed");
+ }
+ if (!SendMsg (
+ s,
+ pOutBuf,
+ cbOut))
+ {
+ MyHandleError("Send message 2 failed ");
+ }
+ }
+
+ free(pInBuf);
+ free(pOutBuf);
+ return(TRUE);
+}
+
+BOOL GenClientContext (
+ BYTE *pIn,
+ DWORD cbIn,
+ BYTE *pOut,
+ DWORD *pcbOut,
+ BOOL *pfDone,
+ CHAR *pszTarget,
+ CredHandle *hCred,
+struct _SecHandle *hcText)
+{
+ SECURITY_STATUS ss;
+ TimeStamp Lifetime;
+ SecBufferDesc OutBuffDesc;
+ SecBuffer OutSecBuff;
+ SecBufferDesc InBuffDesc;
+ SecBuffer InSecBuff;
+ ULONG ContextAttributes;
+ static TCHAR lpPackageName[1024];
+
+ if( NULL == pIn )
+ {
+ strcpy_s(lpPackageName, 1024 * sizeof(TCHAR), "Negotiate");
+ ss = AcquireCredentialsHandle (
+ NULL,
+ lpPackageName,
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ hCred,
+ &Lifetime);
+
+ if (!(SEC_SUCCESS (ss)))
+ {
+ MyHandleError("AcquireCreds failed ");
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // Prepare the buffers.
+
+ OutBuffDesc.ulVersion = 0;
+ OutBuffDesc.cBuffers = 1;
+ OutBuffDesc.pBuffers = &OutSecBuff;
+
+ OutSecBuff.cbBuffer = *pcbOut;
+ OutSecBuff.BufferType = SECBUFFER_TOKEN;
+ OutSecBuff.pvBuffer = pOut;
+
+ //-------------------------------------------------------------------
+ // The input buffer is created only if a message has been received
+ // from the server.
+
+ if (pIn)
+ {
+ InBuffDesc.ulVersion = 0;
+ InBuffDesc.cBuffers = 1;
+ InBuffDesc.pBuffers = &InSecBuff;
+
+ InSecBuff.cbBuffer = cbIn;
+ InSecBuff.BufferType = SECBUFFER_TOKEN;
+ InSecBuff.pvBuffer = pIn;
+
+ ss = InitializeSecurityContext (
+ hCred,
+ hcText,
+ pszTarget,
+ MessageAttribute,
+ 0,
+ SECURITY_NATIVE_DREP,
+ &InBuffDesc,
+ 0,
+ hcText,
+ &OutBuffDesc,
+ &ContextAttributes,
+ &Lifetime);
+ }
+ else
+ {
+ ss = InitializeSecurityContext (
+ hCred,
+ NULL,
+ pszTarget,
+ MessageAttribute,
+ 0,
+ SECURITY_NATIVE_DREP,
+ NULL,
+ 0,
+ hcText,
+ &OutBuffDesc,
+ &ContextAttributes,
+ &Lifetime);
+ }
+
+ if (!SEC_SUCCESS (ss))
+ {
+ MyHandleError ("InitializeSecurityContext failed " );
+ }
+
+ //-------------------------------------------------------------------
+ // If necessary, complete the token.
+
+ if ((SEC_I_COMPLETE_NEEDED == ss)
+ || (SEC_I_COMPLETE_AND_CONTINUE == ss))
+ {
+ ss = CompleteAuthToken (hcText, &OutBuffDesc);
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf (stderr, "complete failed: 0x%08x\n", ss);
+ return FALSE;
+ }
+ }
+
+ *pcbOut = OutSecBuff.cbBuffer;
+
+ *pfDone = !((SEC_I_CONTINUE_NEEDED == ss) ||
+ (SEC_I_COMPLETE_AND_CONTINUE == ss));
+
+ printf ("Token buffer generated (%lu bytes):\n", OutSecBuff.cbBuffer);
+ PrintHexDump (OutSecBuff.cbBuffer, (PBYTE)OutSecBuff.pvBuffer);
+ return TRUE;
+
+}
+
+PBYTE DecryptThis(
+ PBYTE pBuffer,
+ LPDWORD pcbMessage,
+struct _SecHandle *hCtxt,
+ ULONG cbSecurityTrailer)
+{
+ SECURITY_STATUS ss;
+ SecBufferDesc BuffDesc;
+ SecBuffer SecBuff[2];
+ ULONG ulQop = 0;
+ PBYTE pSigBuffer;
+ PBYTE pDataBuffer;
+ DWORD SigBufferSize;
+
+ //-------------------------------------------------------------------
+ // By agreement, the server encrypted the message and set the size
+ // of the trailer block to be just what it needed. DecryptMessage
+ // needs the size of the trailer block.
+ // The size of the trailer is in the first DWORD of the
+ // message received.
+
+ SigBufferSize = *((DWORD *) pBuffer);
+ printf ("data before decryption including trailer (%lu bytes):\n",
+ *pcbMessage);
+ PrintHexDump (*pcbMessage, (PBYTE) pBuffer);
+
+ //--------------------------------------------------------------------
+ // By agreement, the server placed the trailer at the beginning
+ // of the message that was sent immediately following the trailer
+ // size DWORD.
+
+ pSigBuffer = pBuffer + sizeof(DWORD);
+
+ //--------------------------------------------------------------------
+ // The data comes after the trailer.
+
+ pDataBuffer = pSigBuffer + SigBufferSize;
+
+ //--------------------------------------------------------------------
+ // *pcbMessage is reset to the size of just the encrypted bytes.
+
+ *pcbMessage = *pcbMessage - SigBufferSize - sizeof(DWORD);
+
+ //--------------------------------------------------------------------
+ // Prepare the buffers to be passed to the DecryptMessage function.
+
+ BuffDesc.ulVersion = 0;
+ BuffDesc.cBuffers = 2;
+ BuffDesc.pBuffers = SecBuff;
+
+ SecBuff[0].cbBuffer = SigBufferSize;
+ SecBuff[0].BufferType = SECBUFFER_TOKEN;
+ SecBuff[0].pvBuffer = pSigBuffer;
+
+ SecBuff[1].cbBuffer = *pcbMessage;
+ SecBuff[1].BufferType = SECBUFFER_DATA;
+ SecBuff[1].pvBuffer = pDataBuffer;
+
+ ss = DecryptMessage(
+ hCtxt,
+ &BuffDesc,
+ 0,
+ &ulQop);
+
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf(stderr, "DecryptMessage failed");
+ }
+
+ //-------------------------------------------------------------------
+ // Return a pointer to the decrypted data. The trailer data
+ // is discarded.
+
+ return pDataBuffer;
+
+}
+
+PBYTE VerifyThis(
+ PBYTE pBuffer,
+ LPDWORD pcbMessage,
+struct _SecHandle *hCtxt,
+ ULONG cbMaxSignature)
+{
+
+ SECURITY_STATUS ss;
+ SecBufferDesc BuffDesc;
+ SecBuffer SecBuff[2];
+ ULONG ulQop = 0;
+ PBYTE pSigBuffer;
+ PBYTE pDataBuffer;
+
+ //-------------------------------------------------------------------
+ // The global cbMaxSignature is the size of the signature
+ // in the message received.
+
+ printf ("data before verifying (including signature):\n");
+ PrintHexDump (*pcbMessage, pBuffer);
+
+ //--------------------------------------------------------------------
+ // By agreement with the server,
+ // the signature is at the beginning of the message received,
+ // and the data that was signed comes after the signature.
+
+ pSigBuffer = pBuffer;
+ pDataBuffer = pBuffer + cbMaxSignature;
+
+ //-------------------------------------------------------------------
+ // The size of the message is reset to the size of the data only.
+
+ *pcbMessage = *pcbMessage - (cbMaxSignature);
+
+ //--------------------------------------------------------------------
+ // Prepare the buffers to be passed to the signature verification
+ // function.
+
+ BuffDesc.ulVersion = 0;
+ BuffDesc.cBuffers = 2;
+ BuffDesc.pBuffers = SecBuff;
+
+ SecBuff[0].cbBuffer = cbMaxSignature;
+ SecBuff[0].BufferType = SECBUFFER_TOKEN;
+ SecBuff[0].pvBuffer = pSigBuffer;
+
+ SecBuff[1].cbBuffer = *pcbMessage;
+ SecBuff[1].BufferType = SECBUFFER_DATA;
+ SecBuff[1].pvBuffer = pDataBuffer;
+
+ ss = VerifySignature(
+ hCtxt,
+ &BuffDesc,
+ 0,
+ &ulQop
+ );
+
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf(stderr, "VerifyMessage failed");
+ }
+ else
+ {
+ printf("Message was properly signed.\n");
+ }
+
+ return pDataBuffer;
+
+} // end VerifyThis
+
+
+void PrintHexDump(
+ DWORD length,
+ PBYTE buffer)
+{
+ DWORD i,count,index;
+ CHAR rgbDigits[]="0123456789abcdef";
+ CHAR rgbLine[100];
+ char cbLine;
+
+ for(index = 0; length;
+ length -= count, buffer += count, index += count)
+ {
+ count = (length > 16) ? 16:length;
+
+ sprintf_s(rgbLine, 100, "%4.4x ",index);
+ cbLine = 6;
+
+ for(i=0;i<count;i++)
+ {
+ rgbLine[cbLine++] = rgbDigits[buffer[i] >> 4];
+ rgbLine[cbLine++] = rgbDigits[buffer[i] & 0x0f];
+ if(i == 7)
+ {
+ rgbLine[cbLine++] = ':';
+ }
+ else
+ {
+ rgbLine[cbLine++] = ' ';
+ }
+ }
+ for(; i < 16; i++)
+ {
+ rgbLine[cbLine++] = ' ';
+ rgbLine[cbLine++] = ' ';
+ rgbLine[cbLine++] = ' ';
+ }
+
+ rgbLine[cbLine++] = ' ';
+
+ for(i = 0; i < count; i++)
+ {
+ if(buffer[i] < 32 || buffer[i] > 126)
+ {
+ rgbLine[cbLine++] = '.';
+ }
+ else
+ {
+ rgbLine[cbLine++] = buffer[i];
+ }
+ }
+
+ rgbLine[cbLine++] = 0;
+ printf("%s\n", rgbLine);
+ }
+}
+
+BOOL SendMsg (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf)
+{
+ if (0 == cbBuf)
+ return(TRUE);
+
+ //----------------------------------------------------------
+ // Send the size of the message.
+
+ if (!SendBytes (s, (PBYTE)&cbBuf, sizeof (cbBuf)))
+ return(FALSE);
+
+ //----------------------------------------------------------
+ // Send the body of the message.
+
+ if (!SendBytes (
+ s,
+ pBuf,
+ cbBuf))
+ {
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+BOOL ReceiveMsg (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf,
+ DWORD *pcbRead)
+
+{
+ DWORD cbRead;
+ DWORD cbData;
+
+ //----------------------------------------------------------
+ // Receive the number of bytes in the message.
+
+ if (!ReceiveBytes (
+ s,
+ (PBYTE)&cbData,
+ sizeof (cbData),
+ &cbRead))
+ {
+ return(FALSE);
+ }
+
+ if (sizeof (cbData) != cbRead)
+ return(FALSE);
+ //----------------------------------------------------------
+ // Read the full message.
+
+ if (!ReceiveBytes (
+ s,
+ pBuf,
+ cbData,
+ &cbRead))
+ {
+ return(FALSE);
+ }
+
+ if (cbRead != cbData)
+ return(FALSE);
+
+ *pcbRead = cbRead;
+ return(TRUE);
+} // end ReceiveMessage
+
+BOOL SendBytes (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf)
+{
+ PBYTE pTemp = pBuf;
+ int cbSent;
+ int cbRemaining = cbBuf;
+
+ if (0 == cbBuf)
+ return(TRUE);
+
+ while (cbRemaining)
+ {
+ cbSent = send (
+ s,
+ (const char *)pTemp,
+ cbRemaining,
+ 0);
+ if (SOCKET_ERROR == cbSent)
+ {
+ fprintf (stderr, "send failed: %u\n", GetLastError ());
+ return FALSE;
+ }
+
+ pTemp += cbSent;
+ cbRemaining -= cbSent;
+ }
+
+ return TRUE;
+}
+
+BOOL ReceiveBytes (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf,
+ DWORD *pcbRead)
+{
+ PBYTE pTemp = pBuf;
+ int cbRead, cbRemaining = cbBuf;
+
+ while (cbRemaining)
+ {
+ cbRead = recv (
+ s,
+ (char *)pTemp,
+ cbRemaining,
+ 0);
+ if (0 == cbRead)
+ break;
+ if (SOCKET_ERROR == cbRead)
+ {
+ fprintf (stderr, "recv failed: %u\n", GetLastError ());
+ return FALSE;
+ }
+
+ cbRemaining -= cbRead;
+ pTemp += cbRead;
+ }
+
+ *pcbRead = cbBuf - cbRemaining;
+
+ return TRUE;
+} // end ReceiveBytes
+
+
+void MyHandleError(char *s, SECURITY_STATUS ss)
+{
+
+ fprintf(stderr,"%s error - code %08x Exiting.\n",s, ss);
+ exit (EXIT_FAILURE);
+}
diff --git a/test/sspi-server.cpp b/test/sspi-server.cpp
new file mode 100644
index 000000000..60df7cc67
--- /dev/null
+++ b/test/sspi-server.cpp
@@ -0,0 +1,781 @@
+
+//--------------------------------------------------------------------
+// This is a server-side SSPI Windows Sockets program.
+
+#define usPort 2000
+#define SECURITY_WIN32
+#define SEC_SUCCESS(Status) ((Status) >= 0)
+
+#include <windows.h>
+#include <winsock.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "SspiExample.h"
+
+CredHandle hcred;
+struct _SecHandle hctxt;
+
+static PBYTE g_pInBuf = NULL;
+static PBYTE g_pOutBuf = NULL;
+static DWORD g_cbMaxMessage;
+static TCHAR g_lpPackageName[1024];
+
+BOOL DoAuthentication (SOCKET AuthSocket, char *TargetName);
+BOOL AcceptAuthSocket (SOCKET *ServerSocket, char *TargetName);
+
+int main (int argc, char **argv)
+{
+ CHAR pMessage[200];
+ DWORD cbMessage;
+ PBYTE pDataToClient = NULL;
+ DWORD cbDataToClient = 0;
+ PCHAR pUserName = NULL;
+ DWORD cbUserName = 0;
+ SOCKET Server_Socket;
+ WSADATA wsaData;
+ SECURITY_STATUS ss;
+ PSecPkgInfo pkgInfo;
+ SecPkgContext_Sizes SecPkgContextSizes;
+ SecPkgContext_NegotiationInfo SecPkgNegInfo;
+ ULONG cbMaxSignature;
+ ULONG cbSecurityTrailer;
+ char *TargetName = "";
+
+ if (argc == 1)
+ {
+ fprintf(stderr, "sspi-server <user>\n");
+ exit(1);
+ }
+
+ if (argc > 1)
+ TargetName = argv[1];
+
+ //-----------------------------------------------------------------
+ // Set the default package to negotiate.
+
+ strcpy_s(g_lpPackageName, 1024 * sizeof(TCHAR), "Negotiate");
+
+ //-----------------------------------------------------------------
+ // Initialize the socket interface and the security package.
+
+ if( WSAStartup (0x0101, &wsaData))
+ {
+ fprintf (stderr, "Could not initialize winsock: \n");
+ cleanup();
+ }
+
+ ss = QuerySecurityPackageInfo (
+ g_lpPackageName,
+ &pkgInfo);
+
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf (stderr,
+ "Could not query package info for %s, error 0x%08x\n",
+ g_lpPackageName, ss);
+ cleanup();
+ }
+
+ g_cbMaxMessage = pkgInfo->cbMaxToken;
+
+ FreeContextBuffer(pkgInfo);
+
+ g_pInBuf = (PBYTE) malloc (g_cbMaxMessage);
+ g_pOutBuf = (PBYTE) malloc (g_cbMaxMessage);
+
+ if (NULL == g_pInBuf || NULL == g_pOutBuf)
+ {
+ fprintf (stderr, "Memory allocation error.\n");
+ cleanup();
+ }
+
+ //-----------------------------------------------------------------
+ // Start looping for clients.
+
+ while(TRUE)
+ {
+ printf("Waiting for client to connect...\n");
+
+ //-----------------------------------------------------------------
+ // Make an authenticated connection with client.
+
+ if (!AcceptAuthSocket (&Server_Socket, TargetName))
+ {
+ fprintf (stderr, "Could not authenticate the socket.\n");
+ cleanup();
+ }
+
+ ss = QueryContextAttributes(
+ &hctxt,
+ SECPKG_ATTR_SIZES,
+ &SecPkgContextSizes );
+
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf (stderr, "QueryContextAttributes failed: 0x%08x\n", ss);
+ exit(1);
+ }
+
+ //----------------------------------------------------------------
+ // The following values are used for encryption and signing.
+
+ cbMaxSignature = SecPkgContextSizes.cbMaxSignature;
+ cbSecurityTrailer = SecPkgContextSizes.cbSecurityTrailer;
+
+ ss = QueryContextAttributes(
+ &hctxt,
+ SECPKG_ATTR_NEGOTIATION_INFO,
+ &SecPkgNegInfo );
+
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf (stderr, "QueryContextAttributes failed: 0x%08x\n", ss);
+ exit(1);
+ }
+ else
+ {
+ printf("Package Name: %s\n", SecPkgNegInfo.PackageInfo->Name);
+ }
+
+ //----------------------------------------------------------------
+ // Free the allocated buffer.
+
+ FreeContextBuffer(SecPkgNegInfo.PackageInfo);
+
+ //-----------------------------------------------------------------
+ // Impersonate the client.
+
+ ss = ImpersonateSecurityContext (&hctxt);
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf (stderr, "Impersonate failed: 0x%08x\n", ss);
+ cleanup();
+ }
+ else
+ {
+ printf("Impersonation worked. \n");
+ }
+
+ GetUserName (NULL, &cbUserName);
+ pUserName = (PCHAR) malloc (cbUserName);
+
+ if (!pUserName)
+ {
+ fprintf (stderr, "Memory allocation error. \n");
+ cleanup();
+ }
+
+ if (!GetUserName (
+ pUserName,
+ &cbUserName))
+ {
+ fprintf (stderr, "Could not get the client name. \n");
+ cleanup();
+ }
+ else
+ {
+ printf ("Client connected as : %s\n", pUserName);
+ }
+
+ //-----------------------------------------------------------------
+ // Revert to self.
+
+ ss = RevertSecurityContext (&hctxt);
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf (stderr, "Revert failed: 0x%08x\n", ss);
+ cleanup();
+ }
+ else
+ {
+ printf("Reverted to self.\n");
+ }
+
+ //-----------------------------------------------------------------
+ // Send the client an encrypted message.
+
+ strcpy_s(pMessage, sizeof(pMessage),
+ "This is your server speaking");
+ cbMessage = strlen(pMessage);
+
+ EncryptThis (
+ (PBYTE) pMessage,
+ cbMessage,
+ &pDataToClient,
+ &cbDataToClient,
+ cbSecurityTrailer);
+
+ //-----------------------------------------------------------------
+ // Send the encrypted data to client.
+
+
+ if (!SendBytes(
+ Server_Socket,
+ pDataToClient,
+ cbDataToClient))
+ {
+ printf("send message failed. \n");
+ cleanup();
+ }
+
+ printf(" %d encrypted bytes sent. \n", cbDataToClient);
+
+ if (Server_Socket)
+ {
+ DeleteSecurityContext (&hctxt);
+ FreeCredentialHandle (&hcred);
+ shutdown (Server_Socket, 2) ;
+ closesocket (Server_Socket);
+ Server_Socket = 0;
+ }
+
+ if (pUserName)
+ {
+ free (pUserName);
+ pUserName = NULL;
+ cbUserName = 0;
+ }
+ if(pDataToClient)
+ {
+ free (pDataToClient);
+ pDataToClient = NULL;
+ cbDataToClient = 0;
+ }
+ } // end while loop
+
+ printf("Server ran to completion without error.\n");
+ cleanup();
+} // end main
+
+BOOL AcceptAuthSocket (SOCKET *ServerSocket, char *TargetName)
+{
+ SOCKET sockListen;
+ SOCKET sockClient;
+ SOCKADDR_IN sockIn;
+
+ //-----------------------------------------------------------------
+ // Create listening socket.
+
+ sockListen = socket (
+ PF_INET,
+ SOCK_STREAM,
+ 0);
+
+ if (INVALID_SOCKET == sockListen)
+ {
+ fprintf (stderr, "Failed to create socket: %u\n", GetLastError ());
+ return(FALSE);
+ }
+
+ //-----------------------------------------------------------------
+ // Bind to local port.
+
+ sockIn.sin_family = AF_INET;
+ sockIn.sin_addr.s_addr = 0;
+ sockIn.sin_port = htons(usPort);
+
+ if (SOCKET_ERROR == bind (
+ sockListen,
+ (LPSOCKADDR) &sockIn,
+ sizeof (sockIn)))
+ {
+ fprintf (stderr, "bind failed: %u\n", GetLastError ());
+ return(FALSE);
+ }
+
+ //-----------------------------------------------------------------
+ // Listen for client.
+
+ if (SOCKET_ERROR == listen (sockListen, 1))
+ {
+ fprintf (stderr, "Listen failed: %u\n", GetLastError ());
+ return(FALSE);
+ }
+ else
+ {
+ printf("Listening ! \n");
+ }
+
+ //-----------------------------------------------------------------
+ // Accept client.
+
+ sockClient = accept (
+ sockListen,
+ NULL,
+ NULL);
+
+ if (INVALID_SOCKET == sockClient)
+ {
+ fprintf (stderr, "accept failed: %u\n", GetLastError ());
+ return(FALSE);
+ }
+
+ closesocket (sockListen);
+
+ *ServerSocket = sockClient;
+
+
+ return(DoAuthentication (sockClient, TargetName));
+
+} // end AcceptAuthSocket
+
+BOOL DoAuthentication (SOCKET AuthSocket, char *TargetName)
+{
+SECURITY_STATUS ss;
+DWORD cbIn, cbOut;
+BOOL done = FALSE;
+TimeStamp Lifetime;
+BOOL fNewConversation;
+
+fNewConversation = TRUE;
+
+ss = AcquireCredentialsHandle (
+ NULL,
+ g_lpPackageName,
+ SECPKG_CRED_INBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &hcred,
+ &Lifetime);
+
+if (!SEC_SUCCESS (ss))
+{
+ fprintf (stderr, "AcquireCreds failed: 0x%08x\n", ss);
+ return(FALSE);
+}
+
+while(!done)
+{
+ if (!ReceiveMsg (
+ AuthSocket,
+ g_pInBuf,
+ g_cbMaxMessage,
+ &cbIn))
+ {
+ return(FALSE);
+ }
+
+ cbOut = g_cbMaxMessage;
+
+ if (!GenServerContext (
+ g_pInBuf,
+ cbIn,
+ g_pOutBuf,
+ &cbOut,
+ &done,
+ fNewConversation))
+ {
+ fprintf(stderr,"GenServerContext failed.\n");
+ return(FALSE);
+ }
+ fNewConversation = FALSE;
+ if (!SendMsg (
+ AuthSocket,
+ g_pOutBuf,
+ cbOut))
+ {
+ fprintf(stderr,"Sending message failed.\n");
+ return(FALSE);
+ }
+}
+
+return(TRUE);
+} // end DoAuthentication
+
+BOOL GenServerContext (
+ BYTE *pIn,
+ DWORD cbIn,
+ BYTE *pOut,
+ DWORD *pcbOut,
+ BOOL *pfDone,
+ BOOL fNewConversation)
+{
+SECURITY_STATUS ss;
+TimeStamp Lifetime;
+SecBufferDesc OutBuffDesc;
+SecBuffer OutSecBuff;
+SecBufferDesc InBuffDesc;
+SecBuffer InSecBuff;
+ULONG Attribs = 0;
+
+//----------------------------------------------------------------
+// Prepare output buffers.
+
+OutBuffDesc.ulVersion = 0;
+OutBuffDesc.cBuffers = 1;
+OutBuffDesc.pBuffers = &OutSecBuff;
+
+OutSecBuff.cbBuffer = *pcbOut;
+OutSecBuff.BufferType = SECBUFFER_TOKEN;
+OutSecBuff.pvBuffer = pOut;
+
+//----------------------------------------------------------------
+// Prepare input buffers.
+
+InBuffDesc.ulVersion = 0;
+InBuffDesc.cBuffers = 1;
+InBuffDesc.pBuffers = &InSecBuff;
+
+InSecBuff.cbBuffer = cbIn;
+InSecBuff.BufferType = SECBUFFER_TOKEN;
+InSecBuff.pvBuffer = pIn;
+
+printf ("Token buffer received (%lu bytes):\n", InSecBuff.cbBuffer);
+PrintHexDump (InSecBuff.cbBuffer, (PBYTE)InSecBuff.pvBuffer);
+
+ss = AcceptSecurityContext (
+ &hcred,
+ fNewConversation ? NULL : &hctxt,
+ &InBuffDesc,
+ Attribs,
+ SECURITY_NATIVE_DREP,
+ &hctxt,
+ &OutBuffDesc,
+ &Attribs,
+ &Lifetime);
+
+if (!SEC_SUCCESS (ss))
+{
+ fprintf (stderr, "AcceptSecurityContext failed: 0x%08x\n", ss);
+ return FALSE;
+}
+
+//----------------------------------------------------------------
+// Complete token if applicable.
+
+if ((SEC_I_COMPLETE_NEEDED == ss)
+ || (SEC_I_COMPLETE_AND_CONTINUE == ss))
+{
+ ss = CompleteAuthToken (&hctxt, &OutBuffDesc);
+ if (!SEC_SUCCESS(ss))
+ {
+ fprintf (stderr, "complete failed: 0x%08x\n", ss);
+ return FALSE;
+ }
+}
+
+*pcbOut = OutSecBuff.cbBuffer;
+
+// fNewConversation equals FALSE.
+
+printf ("Token buffer generated (%lu bytes):\n",
+ OutSecBuff.cbBuffer);
+PrintHexDump (
+ OutSecBuff.cbBuffer,
+ (PBYTE)OutSecBuff.pvBuffer);
+
+*pfDone = !((SEC_I_CONTINUE_NEEDED == ss)
+ || (SEC_I_COMPLETE_AND_CONTINUE == ss));
+
+printf("AcceptSecurityContext result = 0x%08x\n", ss);
+
+return TRUE;
+
+} // end GenServerContext
+
+
+BOOL EncryptThis (
+ PBYTE pMessage,
+ ULONG cbMessage,
+ BYTE ** ppOutput,
+ ULONG * pcbOutput,
+ ULONG cbSecurityTrailer)
+{
+SECURITY_STATUS ss;
+SecBufferDesc BuffDesc;
+SecBuffer SecBuff[2];
+ULONG ulQop = 0;
+ULONG SigBufferSize;
+
+//-----------------------------------------------------------------
+// The size of the trailer (signature + padding) block is
+// determined from the global cbSecurityTrailer.
+
+SigBufferSize = cbSecurityTrailer;
+
+printf ("Data before encryption: %s\n", pMessage);
+printf ("Length of data before encryption: %d \n",cbMessage);
+
+//-----------------------------------------------------------------
+// Allocate a buffer to hold the signature,
+// encrypted data, and a DWORD
+// that specifies the size of the trailer block.
+
+* ppOutput = (PBYTE) malloc (
+ SigBufferSize + cbMessage + sizeof(DWORD));
+
+//------------------------------------------------------------------
+// Prepare buffers.
+
+BuffDesc.ulVersion = 0;
+BuffDesc.cBuffers = 2;
+BuffDesc.pBuffers = SecBuff;
+
+SecBuff[0].cbBuffer = SigBufferSize;
+SecBuff[0].BufferType = SECBUFFER_TOKEN;
+SecBuff[0].pvBuffer = *ppOutput + sizeof(DWORD);
+
+SecBuff[1].cbBuffer = cbMessage;
+SecBuff[1].BufferType = SECBUFFER_DATA;
+SecBuff[1].pvBuffer = pMessage;
+
+ss = EncryptMessage(
+ &hctxt,
+ ulQop,
+ &BuffDesc,
+ 0);
+
+if (!SEC_SUCCESS(ss))
+{
+ fprintf (stderr, "EncryptMessage failed: 0x%08x\n", ss);
+ return(FALSE);
+}
+else
+{
+ printf("The message has been encrypted. \n");
+}
+
+//------------------------------------------------------------------
+// Indicate the size of the buffer in the first DWORD.
+
+*((DWORD *) *ppOutput) = SecBuff[0].cbBuffer;
+
+//-----------------------------------------------------------------
+// Append the encrypted data to our trailer block
+// to form a single block.
+// Putting trailer at the beginning of the buffer works out
+// better.
+
+memcpy (*ppOutput+SecBuff[0].cbBuffer+sizeof(DWORD), pMessage,
+ cbMessage);
+
+*pcbOutput = cbMessage + SecBuff[0].cbBuffer + sizeof(DWORD);
+
+printf ("data after encryption including trailer (%lu bytes):\n",
+ *pcbOutput);
+PrintHexDump (*pcbOutput, *ppOutput);
+
+return TRUE;
+
+} // end EncryptThis
+
+
+
+void PrintHexDump(DWORD length, PBYTE buffer)
+{
+DWORD i,count,index;
+CHAR rgbDigits[]="0123456789abcdef";
+CHAR rgbLine[100];
+char cbLine;
+
+for(index = 0; length;
+ length -= count, buffer += count, index += count)
+{
+ count = (length > 16) ? 16:length;
+
+ sprintf_s(rgbLine, 100, "%4.4x ",index);
+ cbLine = 6;
+
+ for(i=0;i<count;i++)
+ {
+ rgbLine[cbLine++] = rgbDigits[buffer[i] >> 4];
+ rgbLine[cbLine++] = rgbDigits[buffer[i] & 0x0f];
+ if(i == 7)
+ {
+ rgbLine[cbLine++] = ':';
+ }
+ else
+ {
+ rgbLine[cbLine++] = ' ';
+ }
+ }
+ for(; i < 16; i++)
+ {
+ rgbLine[cbLine++] = ' ';
+ rgbLine[cbLine++] = ' ';
+ rgbLine[cbLine++] = ' ';
+ }
+
+ rgbLine[cbLine++] = ' ';
+
+ for(i = 0; i < count; i++)
+ {
+ if(buffer[i] < 32 || buffer[i] > 126)
+ {
+ rgbLine[cbLine++] = '.';
+ }
+ else
+ {
+ rgbLine[cbLine++] = buffer[i];
+ }
+ }
+
+ rgbLine[cbLine++] = 0;
+ printf("%s\n", rgbLine);
+}
+} // end PrintHexDump
+
+
+BOOL SendMsg (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf)
+{
+if (0 == cbBuf)
+ return(TRUE);
+
+//----------------------------------------------------------------
+// Send the size of the message.
+
+if (!SendBytes (
+ s,
+ (PBYTE)&cbBuf,
+ sizeof (cbBuf)))
+{
+ return(FALSE);
+}
+
+//----------------------------------------------------------------
+// Send the body of the message.
+
+if (!SendBytes (
+ s,
+ pBuf,
+ cbBuf))
+{
+ return(FALSE);
+}
+
+return(TRUE);
+} // end SendMsg
+
+BOOL ReceiveMsg (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf,
+ DWORD *pcbRead)
+{
+DWORD cbRead;
+DWORD cbData;
+
+//-----------------------------------------------------------------
+// Retrieve the number of bytes in the message.
+
+if (!ReceiveBytes (
+ s,
+ (PBYTE)&cbData,
+ sizeof (cbData),
+ &cbRead))
+{
+ return(FALSE);
+}
+
+if (sizeof (cbData) != cbRead)
+{
+ return(FALSE);
+}
+
+//----------------------------------------------------------------
+// Read the full message.
+
+if (!ReceiveBytes (
+ s,
+ pBuf,
+ cbData,
+ &cbRead))
+{
+ return(FALSE);
+}
+
+if (cbRead != cbData)
+{
+ return(FALSE);
+}
+
+*pcbRead = cbRead;
+
+return(TRUE);
+} // end ReceiveMsg
+
+BOOL SendBytes (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf)
+{
+PBYTE pTemp = pBuf;
+int cbSent, cbRemaining = cbBuf;
+
+if (0 == cbBuf)
+{
+ return(TRUE);
+}
+
+while (cbRemaining)
+{
+ cbSent = send (
+ s,
+ (const char *)pTemp,
+ cbRemaining,
+ 0);
+ if (SOCKET_ERROR == cbSent)
+{
+ fprintf (stderr, "send failed: %u\n", GetLastError ());
+ return FALSE;
+}
+
+pTemp += cbSent;
+cbRemaining -= cbSent;
+}
+
+return TRUE;
+} // end SendBytes
+
+BOOL ReceiveBytes (
+ SOCKET s,
+ PBYTE pBuf,
+ DWORD cbBuf,
+ DWORD *pcbRead)
+{
+PBYTE pTemp = pBuf;
+int cbRead, cbRemaining = cbBuf;
+
+while (cbRemaining)
+{
+ cbRead = recv (
+ s,
+ (char *)pTemp,
+ cbRemaining,
+ 0);
+ if (0 == cbRead)
+ {
+ break;
+ }
+
+ if (SOCKET_ERROR == cbRead)
+ {
+ fprintf (stderr, "recv failed: %u\n", GetLastError ());
+ return FALSE;
+ }
+
+cbRemaining -= cbRead;
+pTemp += cbRead;
+}
+
+*pcbRead = cbBuf - cbRemaining;
+
+return TRUE;
+} // end ReceivesBytes
+
+void cleanup()
+{
+ if (g_pInBuf)
+ free (g_pInBuf);
+
+ if (g_pOutBuf)
+ free (g_pOutBuf);
+
+ WSACleanup ();
+ exit(0);
+}