// Copyright 2012 Nexenta Systems, Inc. All rights reserved.
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
// OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
//
// Date - 10/08/2002
// Author - Sanj Surati
/////////////////////////////////////////////////////////////
//
// SPNEGOPARSE.C
//
// SPNEGO Token Handler Source File
//
// Contains implementation of SPNEGO Token parsing functions.
//
/////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "spnego.h"
#include "derparse.h"
#include "spnegoparse.h"
//
// Defined in DERPARSE.C
//
extern MECH_OID g_stcMechOIDList [];
/**********************************************************************/
/** **/
/** **/
/** **/
/** **/
/** Local SPNEGO Helper definitions **/
/** **/
/** **/
/** **/
/** **/
/**********************************************************************/
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// CalculateMinSpnegoInitTokenSize
//
// Parameters:
// [in] nMechTokenLength - Length of the MechToken Element
// [in] nMechListMICLength - Length of the MechListMIC Element
// (or negHints, if no MechToken)
// [in] mechOID - OID for MechList
// [in] nReqFlagsAvailable - Is ContextFlags element available
// [out] pnTokenSize - Filled out with total size of token
// [out] pnInternalTokenLength - Filled out with length minus length
// for initial token.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Calculates the required length for a SPNEGO NegTokenInit token based
// on the supplied variable length values and which elements are present.
// Note that because the lengths can be represented by an arbitrary
// number of bytes in DER encodings, we actually calculate the lengths
// backwards, so we always know how many bytes we will potentially be
// writing out.
//
////////////////////////////////////////////////////////////////////////////
int nReqFlagsAvailable, long* pnTokenSize,
long* pnInternalTokenLength )
{
// Start at 0.
long nTotalLength = 0;
long nTempLength= 0L;
// We will calculate this by walking the token backwards
// Start with MIC Element (or negHints)
if ( nMechListMICLength > 0L )
{
// Check for rollover error
if ( nTempLength < nMechListMICLength )
{
goto xEndTokenInitLength;
}
}
// Next is the MechToken
if ( nMechTokenLength > 0L )
{
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenInitLength;
}
}
// Next is the ReqFlags
if ( nReqFlagsAvailable )
{
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenInitLength;
}
}
// Next is the MechList - This is REQUIRED
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenInitLength;
}
// Following four fields are the basic header tokens
// Sequence Token
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenInitLength;
}
// Neg Token Identifier Token
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenInitLength;
}
// SPNEGO OID Token
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenInitLength;
}
// App Constructed Token
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenInitLength;
}
// The internal length doesn't include the number of bytes
// for the initial token
// We're done
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// CreateSpnegoInitToken
//
// Parameters:
// [in] pMechTypeList - OID array
// [in] MechTypeCnt - OID array length
// [in] ucContextFlags - ContextFlags value
// [in] pbMechToken - Mech Token Binary Data
// [in] ulMechTokenLen - Length of Mech Token
// [in] pbMechListMIC - MechListMIC Binary Data (or negHints)
// [in] ulMechListMICn - Length of MechListMIC
// [out] pbTokenData - Buffer to write token into.
// [in] nTokenLength - Length of pbTokenData buffer
// [in] nInternalTokenLength - Length of full token without leading
// token bytes.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token
// Note that because the lengths can be represented by an arbitrary
// number of bytes in DER encodings, we actually calculate the lengths
// backwards, so we always know how many bytes we will potentially be
// writing out.
//
// This function is also used to create an SPNEGO "hint", as described in
// [MS-SPNG] sec. 2.2.1 negTokenInit2. The "hint" looks almost identical
// to a NegTokenInit, but has a "negHints" field inserted before the MIC.
// A normal SPNEGO negTokenInit2 contains only the mech list and the
// negHints as the MIC arg, and pass NULL as the MechToken to indicate
// that we're creating a Hint rather than an Init, and use the correct
// type when writing out the MIC (or negHints) element.
//
////////////////////////////////////////////////////////////////////////////
unsigned char ucContextFlags, unsigned char* pbMechToken,
unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
unsigned long ulMechListMICLen, unsigned char* pbTokenData,
long nTokenLength, long nInternalTokenLength )
{
// Start at 0.
long nTempLength= 0L;
long nTotalBytesWritten = 0L;
long nInternalLength = 0L;
// Temporary buffer to hold the REQ Flags as BIT String Data
// We will write the token out backwards to properly handle the cases
// where the length bytes become adjustable
// Start with MIC Element (or negHints)
if ( ulMechListMICLen > 0L )
{
unsigned char ucType;
// Decrease the pbWriteTokenData, now we know the length and write it out.
// Note: When MechTokenLen == 0, we're writing a negTokenInit2 and the
// MIC arg is really negHints, written as a constructed sequence.
// Otherwise we're writing a negTokenInit, and the MIC is an OCTETSTRING.
ucType = (ulMechTokenLen == 0) ?
// Adjust Values and sanity check
{
goto xEndWriteNegTokenInit;
}
} // IF MechListMIC is present
// Next is the MechToken
if ( ulMechTokenLen > 0L )
{
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenInit;
}
} // IF MechToken Length is present
// Next is the ReqFlags
if ( ucContextFlags > 0L )
{
// We need a byte that indicates how many bits difference between the number
// of bits used in final octet (we only have one) and the max (8)
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenInit;
}
} // IF ContextFlags
// Next is the MechList - This is REQUIRED
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenInit;
}
// The next tokens we're writing out reflect the total number of bytes
// we have actually written out.
// Sequence Token
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenInit;
}
// Neg Init Token Identifier Token
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenInit;
}
// SPNEGO OID Token
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenInit;
}
// App Constructed Token
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
// Don't adjust the internal token length here, it doesn't account
// the initial bytes written out (we really don't need to keep
// a running count here, but for debugging, it helps to be able
// to see the total number of bytes written out as well as the
// number of bytes left to write).
{
}
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// CalculateMinSpnegoTargTokenSize
//
// Parameters:
// [in] MechType - Supported MechType
// [in] spnegoNegResult - Neg Result
// [in] nMechTokenLength - Length of the MechToken Element
// [in] nMechListMICLength - Length of the MechListMIC Element
// [out] pnTokenSize - Filled out with total size of token
// [out] pnInternalTokenLength - Filled out with length minus length
// for initial token.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Calculates the required length for a SPNEGO NegTokenTarg token based
// on the supplied variable length values and which elements are present.
// Note that because the lengths can be represented by an arbitrary
// number of bytes in DER encodings, we actually calculate the lengths
// backwards, so we always know how many bytes we will potentially be
// writing out.
//
////////////////////////////////////////////////////////////////////////////
long nMechListMICLen, long* pnTokenSize,
long* pnInternalTokenLength )
{
// Start at 0.
long nTotalLength = 0;
long nTempLength= 0L;
// We will calculate this by walking the token backwards
// Start with MIC Element
if ( nMechListMICLen > 0L )
{
// Check for rollover error
if ( nTempLength < nMechListMICLen )
{
goto xEndTokenTargLength;
}
}
// Next is the MechToken
if ( nMechTokenLen > 0L )
{
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenTargLength;
}
}
// Supported MechType
if ( spnego_mech_oid_NotUsed != MechType )
{
// Supported MechOID element - we use the token function since
// we already know the size of the OID token and value
NULL );
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenTargLength;
}
} // IF MechType is available
// NegResult Element
if ( spnego_negresult_NotUsed != spnegoNegResult )
{
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenTargLength;
}
} // IF negResult is available
// Following two fields are the basic header tokens
// Sequence Token
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenTargLength;
}
// Neg Token Identifier Token
// Check for rollover error
if ( nTempLength < nTotalLength )
{
goto xEndTokenTargLength;
}
// The internal length doesn't include the number of bytes
// for the initial token
// We're done
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// CreateSpnegoTargToken
//
// Parameters:
// [in] MechType - Supported MechType
// [in] eNegResult - NegResult value
// [in] pbMechToken - Mech Token Binary Data
// [in] ulMechTokenLen - Length of Mech Token
// [in] pbMechListMIC - MechListMIC Binary Data
// [in] ulMechListMICn - Length of MechListMIC
// [out] pbTokenData - Buffer to write token into.
// [in] nTokenLength - Length of pbTokenData buffer
// [in] nInternalTokenLength - Length of full token without leading
// token bytes.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token
// Note that because the lengths can be represented by an arbitrary
// number of bytes in DER encodings, we actually calculate the lengths
// backwards, so we always know how many bytes we will potentially be
// writing out.
//
////////////////////////////////////////////////////////////////////////////
unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
unsigned long ulMechListMICLen, unsigned char* pbTokenData,
long nTokenLength, long nInternalTokenLength )
{
// Start at 0.
long nTempLength= 0L;
long nTotalBytesWritten = 0L;
long nInternalLength = 0L;
unsigned char ucTemp = 0;
// We will write the token out backwards to properly handle the cases
// where the length bytes become adjustable, so the write location
// is initialized to point *just* past the end of the buffer.
// Start with MIC Element
if ( ulMechListMICLen > 0L )
{
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenTarg;
}
} // IF MechListMIC is present
// Next is the MechToken
if ( ulMechTokenLen > 0L )
{
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenTarg;
}
} // IF MechToken Length is present
// Supported Mech Type
if ( spnego_mech_oid_NotUsed != MechType )
{
&nInternalLength );
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenTarg;
}
} // IF MechType is present
// Neg Result
// NegResult Element
if ( spnego_negresult_NotUsed != eNegResult )
{
ucTemp = (unsigned char) eNegResult;
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenTarg;
}
} // If eNegResult is available
// The next tokens we're writing out reflect the total number of bytes
// we have actually written out.
// Sequence Token
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
{
goto xEndWriteNegTokenTarg;
}
// Neg Targ Token Identifier Token
// Decrease the pbWriteTokenData, now we know the length and
// write it out.
// Adjust Values and sanity check
// Don't adjust the internal token length here, it doesn't account
// the initial bytes written out (we really don't need to keep
// a running count here, but for debugging, it helps to be able
// to see the total number of bytes written out as well as the
// number of bytes left to write).
{
}
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// AllocEmptySpnegoToken
//
// Parameters:
// [in] ucCopyData - Flag to copy data or pointer.
// [in] ulFlags - Flags for SPNEGO_TOKEN data member.
// [in] pbTokenData - Binary token data.
// [in] ulTokenSize - Size of pbTokenData.
//
// Returns:
// SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct
// Failure - NULL
//
// Comments :
// Allocates a SPNEGO_TOKEN data structure and initializes it. Based on
// the value of ucCopyData, if non-zero, we copy the data into a buffer
// we allocate in this function, otherwise, we copy the data pointer
// direcly.
//
////////////////////////////////////////////////////////////////////////////
unsigned char * pbTokenData, unsigned long ulTokenSize )
{
if ( NULL != pSpnegoToken )
{
// Set the token size
// Initialize the element array
// Assign the flags value
//
// IF ucCopyData is TRUE, we will allocate a buffer and copy data into it.
// Otherwise, we will just copy the pointer and the length. This is so we
// can cut out additional allocations for performance reasons
//
{
// Alloc the internal buffer. Cleanup on failure.
{
// We must ALWAYS free this buffer
// Copy the data locally
}
else
{
free( pSpnegoToken );
pSpnegoToken = NULL;
}
} // IF ucCopyData
else
{
// Copy the pointer and the length directly - ulFlags will control whether or not
// we are allowed to free the value
}
}
return pSpnegoToken;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// FreeSpnegoToken
//
// Parameters:
// [in] pSpnegoToken - Points to SPNEGO_TOKEN to free.
//
// Returns:
// void
//
// Comments :
// If non-NULL, interprets pSpnegoToken, freeing any internal allocations
// and finally the actual structure.
//
////////////////////////////////////////////////////////////////////////////
{
if ( NULL != pSpnegoToken )
{
// Cleanup internal allocation per the flags
{
}
free ( pSpnegoToken );
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// InitSpnegoTokenElementArray
//
// Parameters:
// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
//
// Returns:
// void
//
// Comments :
// Initializes the element array data member of a SPNEGO_TOKEN data
// structure.
//
////////////////////////////////////////////////////////////////////////////
{
int nCtr;
// Set the number of elemnts
//
// Initially, all elements are unavailable
//
{
// Set the element size as well
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// InitSpnegoTokenType
//
// Parameters:
// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
// [out] pnTokenLength - Filled out with total token length
// [out] pnRemainingTokenLength - Filled out with remaining length
// after header is parsed
// [out] ppbFirstElement - Filled out with pointer to first
// element after header info.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Walks the underlying binary data for a SPNEGO_TOKEN data structure
// and determines the type of the underlying token based on token header
// information.
//
////////////////////////////////////////////////////////////////////////////
long* pnRemainingTokenLength, unsigned char** ppbFirstElement )
{
long nActualTokenLength = 0L;
//
// First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG
//
if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData )
{
// Validate the above token - this will tell us the actual length of the token
// per the encoding (minus the actual token bytes)
== SPNEGO_E_SUCCESS )
{
// Initialize the remaining token length value. This will be used
// to tell the caller how much token there is left once we've parsed
// the header (they could calculate it from the other values, but this
// is a bit friendlier)
// Make adjustments to next token
// The next token should be an OID
&nActualTokenLength ) ) == SPNEGO_E_SUCCESS )
{
// Make adjustments to next token
// The next token should specify the NegTokenInit
&nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// Make adjustments to next token
// The next token should specify the start of a sequence
&nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// NegTokenInit header is now checked out!
// Make adjustments to next token
// Store pointer to first element
} // IF Check Sequence Token
} // IF Check NegTokenInit token
} // IF Check for SPNEGO OID
} // IF check app construct token
}
else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData )
{
// The next token should specify the NegTokenInit
&nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// Initialize the remaining token length value. This will be used
// to tell the caller how much token there is left once we've parsed
// the header (they could calculate it from the other values, but this
// is a bit friendlier)
// Make adjustments to next token
// The next token should specify the start of a sequence
&nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// NegTokenInit header is now checked out!
// Make adjustments to next token
// Store pointer to first element
} // IF Check Sequence Token
} // IF Check NegTokenInit token
} // ELSE IF it's a NegTokenTarg
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// GetSpnegoInitTokenMechList
//
// Parameters:
// [in] pbTokenData - Points to binary MechList element
// in NegTokenInit.
// [in] nMechListLength - Length of the MechList
// [out] pSpnegoElement - Filled out with MechList Element
// data.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Checks that pbTokenData is pointing at something that at least
// *looks* like a MechList and then fills out the supplied
// SPNEGO_ELEMENT structure.
//
////////////////////////////////////////////////////////////////////////////
{
long nLength = 0L;
long nActualTokenLength = 0L;
// Actual MechList is prepended by a Constructed Sequence Token
&nLength, &nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// Adjust for this token
// Perform simple validation of the actual MechList (i.e. ensure that
// the OIDs in the MechList are reasonable).
{
// Initialize the element now
}
} // IF Check Token
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// InitSpnegoTokenElementFromBasicType
//
// Parameters:
// [in] pbTokenData - Points to binary element data in
// a SPNEGO token.
// [in] nElementLength - Length of the element
// [in] ucExpectedType - Expected DER type.
// [in] spnegoElementType - Which element is this?
// [out] pSpnegoElement - Filled out with element data.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Checks that pbTokenData is pointing at the specified DER type. If so,
// then we verify that lengths are proper and then fill out the
// SPNEGO_ELEMENT data structure.
//
////////////////////////////////////////////////////////////////////////////
unsigned char ucExpectedType,
{
long nLength = 0L;
long nActualTokenLength = 0L;
// The type BYTE must match our token data or something is badly wrong
if ( *pbTokenData == ucExpectedType )
{
// Check that we are pointing at the specified type
&nLength, &nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// Adjust for this token
// Initialize the element now
}
} // IF type makes sense
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// InitSpnegoTokenElementFromOID
//
// Parameters:
// [in] pbTokenData - Points to binary element data in
// a SPNEGO token.
// [in] nElementLength - Length of the element
// [in] spnegoElementType - Which element is this?
// [out] pSpnegoElement - Filled out with element data.
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Initializes a SpnegoElement from an OID - normally, this would have
// used the Basic Type function above, but since we do binary compares
// on the OIDs against the DER information as well as the OID, we need
// to account for that.
//
////////////////////////////////////////////////////////////////////////////
{
long nLength = 0L;
long nActualTokenLength = 0L;
// The type BYTE must match our token data or something is badly wrong
if ( *pbTokenData == OID )
{
// Check that we are pointing at an OID type
&nLength, &nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// Don't adjust any values for this function
// Initialize the element now
}
} // IF type makes sense
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// InitSpnegoTokenElements
//
// Parameters:
// [in] pSpnegoToken - Points to SPNEGO_TOKEN struct
// [in] pbTokenData - Points to initial binary element
// data in a SPNEGO token.
// [in] nRemainingTokenLength - Length remaining past header
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Interprets the data at pbTokenData based on the TokenType in
// pSpnegoToken. Since some elements are optional (technically all are
// but the token becomes quite useless if this is so), we check if
// an element exists before filling out the element in the array.
//
////////////////////////////////////////////////////////////////////////////
long nRemainingTokenLength )
{
//
// The following arrays contain the token identifiers for the elements
// comprising the actual token. All values are optional, and there are
// no defaults.
//
static unsigned char abNegTokenInitElements[] =
static unsigned char abNegTokenTargElements[] =
int nCtr = 0L;
long nElementLength = 0L;
long nActualTokenLength = 0L;
// Point to the correct array
switch( pSpnegoToken->ucTokenType )
{
case SPNEGO_TOKEN_INIT:
{
}
break;
case SPNEGO_TOKEN_TARG:
{
}
break;
} // SWITCH tokentype
//
// Enumerate the element arrays and look for the tokens at our current location
//
for ( nCtr = 0L;
SPNEGO_E_SUCCESS == nReturn &&
nRemainingTokenLength > 0L;
nCtr++ )
{
// Check if the token exists
&nElementLength, &nActualTokenLength ) )
== SPNEGO_E_SUCCESS )
{
// Token data should skip over the sequence token and then
// call the appropriate function to initialize the element
// Lengths in the elements should NOT go beyond the element
// length
// Different tokens mean different elements
{
// Handle each element as appropriate
switch( pbElements[nCtr] )
{
{
//
// This is a Mech List that specifies which OIDs the
// originator of the Init Token supports.
//
}
break;
{
//
// This is a BITSTRING which specifies the flags that the receiver
// pass to the gss_accept_sec_context() function.
//
}
break;
{
//
// This is an OCTETSTRING which contains a GSSAPI token corresponding
// to the first OID in the MechList.
//
}
break;
case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: // xA3
{
//
// Don't yet know if this is a negTokenInit, or negTokenInit2.
// Unfortunately, both have the same type: SPNEGO_TOKEN_INIT
// If it's negTokenInit, this element should be an OCTETSTRING
// containing the MIC. If it's a negTokenInit2, this element
// should be an SPNEGO_CONSTRUCTED_SEQUENCE containing the
// negHints (GENERALSTR, ignored)
//
if (nReturn == SPNEGO_E_UNEXPECTED_TYPE) {
// This is really a negHints element. Check the type and length,
// but otherwise just ignore it.
}
}
break;
} // SWITCH Element
}
else
{
/* pSpnegoToken->ucTokenType == SPNEGO_TOKEN_TARG */
switch( pbElements[nCtr] )
{
{
//
// This is an ENUMERATION which specifies result of the last GSS
// token negotiation call.
//
}
break;
{
//
// This is an OID which specifies a supported mechanism.
//
}
break;
{
//
// This is an OCTETSTRING which specifies results of the last GSS
// token negotiation call.
//
}
break;
{
//
// This is an OCTETSTRING, typically 16 bytes,
// which contains a message integrity BLOB.
//
}
break;
} // SWITCH Element
} // ELSE !NegTokenInit
// Account for the entire token and following data
// Token data should skip past the element length now
} // IF Token found
else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn )
{
// For now, this is a benign error (remember, all elements are optional, so
// if we don't find one, it's okay).
}
} // FOR enum elements
//
// We should always run down to 0 remaining bytes in the token. If not, we've got
// a bad token.
//
{
}
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// FindMechOIDInMechList
//
// Parameters:
// [in] pSpnegoElement - SPNEGO_ELEMENT for MechList
// [in] MechOID - OID we're looking for.
// [out] piMechTypeIndex - Index in the list where OID was
// found
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Walks the MechList for MechOID. When it is found, the index in the
// list is written to piMechTypeIndex.
//
////////////////////////////////////////////////////////////////////////////
int * piMechTypeIndex )
{
int nCtr = 0;
long nLength = 0L;
{
// Use the helper function to check the OID
== SPNEGO_E_SUCCESS )
{
*piMechTypeIndex = nCtr;
}
// Adjust for the current OID
nCtr++;
} // WHILE enuming OIDs
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// ValidateMechList
//
// Parameters:
// [in] pbMechListData - Pointer to binary MechList data
// [in] nBoundaryLength - Length we must not exceed
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Checks the data at pbMechListData to see if it looks like a MechList.
// As part of this, we walk the list and ensure that none of the OIDs
// have a length that takes us outside of nBoundaryLength.
//
////////////////////////////////////////////////////////////////////////////
{
long nLength = 0L;
long nTokenLength = 0L;
{
// Verify that we have something that at least *looks* like an OID - in other
// words it has an OID identifier and specifies a length that doesn't go beyond
// the size of the list.
&nLength, &nTokenLength );
// Adjust for the current OID
} // WHILE enuming OIDs
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// IsValidMechOid
//
// Parameters:
// [in] mechOid - mechOID id enumeration
//
// Returns:
// int Success - 1
// Failure - 0
//
// Comments :
// Checks for a valid mechOid value.
//
////////////////////////////////////////////////////////////////////////////
{
return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy &&
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// IsValidContextFlags
//
// Parameters:
// [in] ucContextFlags - ContextFlags value
//
// Returns:
// int Success - 1
// Failure - 0
//
// Comments :
// Checks for a valid ContextFlags value.
//
////////////////////////////////////////////////////////////////////////////
{
// Mask out our valid bits. If there is anything leftover, this
// is not a valid value for Context Flags
return ( ( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0 );
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// IsValidNegResult
//
// Parameters:
// [in] negResult - NegResult value
//
// Returns:
// int Success - 1
// Failure - 0
//
// Comments :
// Checks for a valid NegResult value.
//
////////////////////////////////////////////////////////////////////////////
{
return ( negResult >= spnego_negresult_success &&
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// IsValidSpnegoToken
//
// Parameters:
// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
//
// Returns:
// int Success - 1
// Failure - 0
//
// Comments :
// Performs simple heuristic on location pointed to by pSpnegoToken.
//
////////////////////////////////////////////////////////////////////////////
{
int nReturn = 0;
// Parameter should be non-NULL
if ( NULL != pSpnegoToken )
{
// Length should be at least the size defined in the header
{
// Number of elements should be >= our maximum - if it's greater, that's
// okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS
{
// Check for proper token type
{
nReturn = 1;
}
}
} // IF struct size makes sense
} // IF non-NULL spnego Token
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// IsValidSpnegoElement
//
// Parameters:
// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
// [in] spnegoElement - spnegoElement Type from enumeration
//
// Returns:
// int Success - 1
// Failure - 0
//
// Comments :
// Checks that spnegoElement has a valid value and is appropriate for
// the SPNEGO token encapsulated by pSpnegoToken.
//
////////////////////////////////////////////////////////////////////////////
{
int nReturn = 0;
// Check boundaries
if ( spnegoElement > spnego_element_min &&
{
// Check for appropriateness to token type
{
}
else
{
}
} // IF boundary conditions are met
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// CalculateElementArrayIndex
//
// Parameters:
// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
// [in] spnegoElement - spnegoElement Type from enumeration
//
// Returns:
// int index in the SPNEGO_TOKEN element array that the element can
// can be found
//
// Comments :
// Based on the Token Type, calculates the index in the element array
// at which the specified element can be found.
//
////////////////////////////////////////////////////////////////////////////
{
int nReturn = 0;
// Offset is difference between value and initial element identifier
// (these differ based on ucTokenType)
{
}
else
{
}
return nReturn;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function:
// InitTokenFromBinary
//
// Parameters:
// [in] ucCopyData - Flag indicating if data should be copied
// [in] ulFlags - Flags value for structure
// [in] pnTokenData - Binary Token Data
// [in] ulLength - Length of the data
// [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token
// data structure
//
// Returns:
// int Success - SPNEGO_E_SUCCESS
// Failure - SPNEGO API Error code
//
// Comments :
// Allocates a SPNEGO_TOKEN data structure and fills it out as
// appropriate based in the flags passed into the function.
//
////////////////////////////////////////////////////////////////////////////
// Initializes SPNEGO_TOKEN structure from DER encoded binary data
unsigned char* pbTokenData, unsigned long ulLength,
{
long nTokenLength = 0L;
long nRemainingTokenLength = 0L;
// Basic Parameter Validation
if ( NULL != pbTokenData &&
NULL != ppSpnegoToken &&
0L != ulLength )
{
//
// Allocate the empty token, then initialize the data structure.
//
if ( NULL != pSpnegoToken )
{
// Copy the binary data locally
// Initialize the token type
== SPNEGO_E_SUCCESS )
{
// Initialize the element array
== SPNEGO_E_SUCCESS )
{
}
} // IF Init Token Type
// Cleanup on error condition
if ( SPNEGO_E_SUCCESS != nReturn )
{
}
}
else
{
}
} // IF Valid parameters
return nReturn;
}