diff options
author | Ralf Habacker <ralf.habacker@freenet.de> | 2016-07-13 00:09:15 +0200 |
---|---|---|
committer | Ralf Habacker <ralf.habacker@freenet.de> | 2016-07-13 00:09:15 +0200 |
commit | 58360164138479ac8337c0148dcbc338f1a162ef (patch) | |
tree | b1d92d0a8615f0270e1cab254d980a01b53f0c4a | |
parent | af6839be7fc3feea123c547e2046356d89236ec7 (diff) |
Add sspi client and server test app.
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=96577
-rw-r--r-- | cmake/test/CMakeLists.txt | 2 | ||||
-rw-r--r-- | test/SspiExample.h | 74 | ||||
-rw-r--r-- | test/sspi-client.cpp | 779 | ||||
-rw-r--r-- | test/sspi-server.cpp | 781 |
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); +} |