// 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 // AND/OR FITNESS FOR A PARTICULAR PURPOSE. // // 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 CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength, SPNEGO_MECH_OID *mechOidLst, int mechOidCnt, int nReqFlagsAvailable, long* pnTokenSize, long* pnInternalTokenLength ) { int nReturn = SPNEGO_E_INVALID_LENGTH; // 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 ) { nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL ); // Check for rollover error if ( nTempLength < nMechListMICLength ) { goto xEndTokenInitLength; } nTotalLength += nTempLength; } // Next is the MechToken if ( nMechTokenLength > 0L ) { nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenInitLength; } nTotalLength = nTempLength; } // Next is the ReqFlags if ( nReqFlagsAvailable ) { nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenInitLength; } nTotalLength = nTempLength; } // Next is the MechList - This is REQUIRED nTempLength += ASNDerCalcMechListLength( mechOidLst, mechOidCnt, NULL ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenInitLength; } nTotalLength = nTempLength; // Following four fields are the basic header tokens // Sequence Token nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenInitLength; } nTotalLength = nTempLength; // Neg Token Identifier Token nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenInitLength; } nTotalLength = nTempLength; // SPNEGO OID Token nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenInitLength; } nTotalLength = nTempLength; // App Constructed Token nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenInitLength; } // The internal length doesn't include the number of bytes // for the initial token *pnInternalTokenLength = nTotalLength; nTotalLength = nTempLength; // We're done *pnTokenSize = nTotalLength; nReturn = SPNEGO_E_SUCCESS; xEndTokenInitLength: 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. To avoid a giant copy/paste of this function, we pass 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. // //////////////////////////////////////////////////////////////////////////// int CreateSpnegoInitToken( SPNEGO_MECH_OID *pMechTypeList, long MechTypeCnt, unsigned char ucContextFlags, unsigned char* pbMechToken, unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, unsigned long ulMechListMICLen, unsigned char* pbTokenData, long nTokenLength, long nInternalTokenLength ) { int nReturn = SPNEGO_E_INVALID_LENGTH; // Start at 0. long nTempLength= 0L; long nTotalBytesWritten = 0L; long nInternalLength = 0L; unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; // Temporary buffer to hold the REQ Flags as BIT String Data unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS]; // 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; nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); // 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) ? SPNEGO_CONSTRUCTED_SEQUENCE : OCTETSTRING; pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC, ucType, pbMechListMIC, ulMechListMICLen ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenInit; } } // IF MechListMIC is present // Next is the MechToken if ( ulMechTokenLen > 0L ) { nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, OCTETSTRING, pbMechToken, ulMechTokenLen ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenInit; } } // IF MechToken Length is present // Next is the ReqFlags if ( ucContextFlags > 0L ) { nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength ); // 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) abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF; abTempReqFlags[1] = ucContextFlags; // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenInit; } } // IF ContextFlags // Next is the MechList - This is REQUIRED nTempLength = ASNDerCalcMechListLength( pMechTypeList, MechTypeCnt, &nInternalLength ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteMechList( pbWriteTokenData, pMechTypeList, MechTypeCnt ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenInit; } // The next tokens we're writing out reflect the total number of bytes // we have actually written out. // Sequence Token nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, NULL, nTotalBytesWritten ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenInit; } // Neg Init Token Identifier Token nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, NULL, nTotalBytesWritten ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenInit; } // SPNEGO OID Token nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteOID( pbWriteTokenData, spnego_mech_oid_Spnego ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenInit; } // App Constructed Token nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, nTotalBytesWritten ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; // 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). if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && pbWriteTokenData == pbTokenData ) { nReturn = SPNEGO_E_SUCCESS; } xEndWriteNegTokenInit: 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. // //////////////////////////////////////////////////////////////////////////// int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen, long nMechListMICLen, long* pnTokenSize, long* pnInternalTokenLength ) { int nReturn = SPNEGO_E_INVALID_LENGTH; // 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 ) { nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL ); // Check for rollover error if ( nTempLength < nMechListMICLen ) { goto xEndTokenTargLength; } nTotalLength += nTempLength; } // Next is the MechToken if ( nMechTokenLen > 0L ) { nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenTargLength; } nTotalLength = nTempLength; } // 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 nTempLength += ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, NULL ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenTargLength; } nTotalLength = nTempLength; } // IF MechType is available // NegResult Element if ( spnego_negresult_NotUsed != spnegoNegResult ) { nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenTargLength; } nTotalLength = nTempLength; } // IF negResult is available // Following two fields are the basic header tokens // Sequence Token nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenTargLength; } nTotalLength = nTempLength; // Neg Token Identifier Token nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); // Check for rollover error if ( nTempLength < nTotalLength ) { goto xEndTokenTargLength; } // The internal length doesn't include the number of bytes // for the initial token *pnInternalTokenLength = nTotalLength; nTotalLength = nTempLength; // We're done *pnTokenSize = nTotalLength; nReturn = SPNEGO_E_SUCCESS; xEndTokenTargLength: 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. // //////////////////////////////////////////////////////////////////////////// int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, unsigned long ulMechListMICLen, unsigned char* pbTokenData, long nTokenLength, long nInternalTokenLength ) { int nReturn = SPNEGO_E_INVALID_LENGTH; // 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. unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; // Start with MIC Element if ( ulMechListMICLen > 0L ) { nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC, OCTETSTRING, pbMechListMIC, ulMechListMICLen ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenTarg; } } // IF MechListMIC is present // Next is the MechToken if ( ulMechTokenLen > 0L ) { nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, OCTETSTRING, pbMechToken, ulMechTokenLen ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenTarg; } } // IF MechToken Length is present // Supported Mech Type if ( spnego_mech_oid_NotUsed != MechType ) { nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, &nInternalLength ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, g_stcMechOIDList[MechType].ucOid, g_stcMechOIDList[MechType].iLen ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenTarg; } } // IF MechType is present // Neg Result // NegResult Element if ( spnego_negresult_NotUsed != eNegResult ) { ucTemp = (unsigned char) eNegResult; nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT, ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { 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 nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, NULL, nTotalBytesWritten ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; nInternalTokenLength -= nTempLength; if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) { goto xEndWriteNegTokenTarg; } // Neg Targ Token Identifier Token nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); // Decrease the pbWriteTokenData, now we know the length and // write it out. pbWriteTokenData -= nTempLength; nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, NULL, nTotalBytesWritten ); // Adjust Values and sanity check nTotalBytesWritten += nTempLength; // 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). if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && pbWriteTokenData == pbTokenData ) { nReturn = SPNEGO_E_SUCCESS; } xEndWriteNegTokenTarg: 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. // //////////////////////////////////////////////////////////////////////////// SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags, unsigned char * pbTokenData, unsigned long ulTokenSize ) { SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) ); if ( NULL != pSpnegoToken ) { // Set the token size pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE; // Initialize the element array InitSpnegoTokenElementArray( pSpnegoToken ); // Assign the flags value pSpnegoToken->ulFlags = ulFlags; // // 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 // if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData ) { // Alloc the internal buffer. Cleanup on failure. pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) ); if ( NULL != pSpnegoToken->pbBinaryData ) { // We must ALWAYS free this buffer pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA; // Copy the data locally memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize ); pSpnegoToken->ulBinaryDataLen = ulTokenSize; } 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 pSpnegoToken->pbBinaryData = pbTokenData; pSpnegoToken->ulBinaryDataLen = ulTokenSize; } } 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. // //////////////////////////////////////////////////////////////////////////// void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) { if ( NULL != pSpnegoToken ) { // Cleanup internal allocation per the flags if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA && NULL != pSpnegoToken->pbBinaryData ) { free( pSpnegoToken->pbBinaryData ); pSpnegoToken->pbBinaryData = NULL; } 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. // //////////////////////////////////////////////////////////////////////////// void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken ) { int nCtr; // Set the number of elemnts pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS; // // Initially, all elements are unavailable // for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ ) { // Set the element size as well pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE; pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE; } } ///////////////////////////////////////////////////////////////////////////// // // 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. // //////////////////////////////////////////////////////////////////////////// int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, long* pnRemainingTokenLength, unsigned char** ppbFirstElement ) { int nReturn = SPNEGO_E_INVALID_TOKEN; long nActualTokenLength = 0L; long nBoundaryLength = pSpnegoToken->ulBinaryDataLen; unsigned char* pbTokenData = pSpnegoToken->pbBinaryData; // // 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) if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength, pnTokenLength, &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) *pnRemainingTokenLength = *pnTokenLength; // Make adjustments to next token pbTokenData += nActualTokenLength; nBoundaryLength -= nActualTokenLength; // The next token should be an OID if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // Make adjustments to next token pbTokenData += nActualTokenLength; nBoundaryLength -= nActualTokenLength; *pnRemainingTokenLength -= nActualTokenLength; // The next token should specify the NegTokenInit if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // Make adjustments to next token pbTokenData += nActualTokenLength; nBoundaryLength -= nActualTokenLength; *pnRemainingTokenLength -= nActualTokenLength; // The next token should specify the start of a sequence if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // NegTokenInit header is now checked out! // Make adjustments to next token *pnRemainingTokenLength -= nActualTokenLength; // Store pointer to first element *ppbFirstElement = pbTokenData + nActualTokenLength; pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT; } // 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 if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, &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) *pnRemainingTokenLength = *pnTokenLength; // Make adjustments to next token pbTokenData += nActualTokenLength; nBoundaryLength -= nActualTokenLength; // The next token should specify the start of a sequence if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // NegTokenInit header is now checked out! // Make adjustments to next token *pnRemainingTokenLength -= nActualTokenLength; // Store pointer to first element *ppbFirstElement = pbTokenData + nActualTokenLength; pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG; } // 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. // //////////////////////////////////////////////////////////////////////////// int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength, SPNEGO_ELEMENT* pSpnegoElement ) { int nReturn = SPNEGO_E_INVALID_TOKEN; long nLength = 0L; long nActualTokenLength = 0L; // Actual MechList is prepended by a Constructed Sequence Token if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, nMechListLength, nMechListLength, &nLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // Adjust for this token nMechListLength -= nActualTokenLength; pbTokenData += nActualTokenLength; // Perform simple validation of the actual MechList (i.e. ensure that // the OIDs in the MechList are reasonable). if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS ) { // Initialize the element now pSpnegoElement->eElementType = spnego_init_mechtypes; pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; pSpnegoElement->type = SPNEGO_MECHLIST_TYPE; pSpnegoElement->nDatalength = nLength; pSpnegoElement->pbData = pbTokenData; } } // 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. // //////////////////////////////////////////////////////////////////////////// int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength, unsigned char ucExpectedType, SPNEGO_ELEMENT_TYPE spnegoElementType, SPNEGO_ELEMENT* pSpnegoElement ) { int nReturn = SPNEGO_E_UNEXPECTED_TYPE; 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 if ( ( nReturn = ASNDerCheckToken( pbTokenData, ucExpectedType, nElementLength, nElementLength, &nLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // Adjust for this token nElementLength -= nActualTokenLength; pbTokenData += nActualTokenLength; // Initialize the element now pSpnegoElement->eElementType = spnegoElementType; pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; pSpnegoElement->type = ucExpectedType; pSpnegoElement->nDatalength = nLength; pSpnegoElement->pbData = pbTokenData; } } // 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. // //////////////////////////////////////////////////////////////////////////// int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength, SPNEGO_ELEMENT_TYPE spnegoElementType, SPNEGO_ELEMENT* pSpnegoElement ) { int nReturn = SPNEGO_E_UNEXPECTED_TYPE; 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 if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, nElementLength, nElementLength, &nLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // Don't adjust any values for this function // Initialize the element now pSpnegoElement->eElementType = spnegoElementType; pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; pSpnegoElement->type = OID; pSpnegoElement->nDatalength = nElementLength; pSpnegoElement->pbData = pbTokenData; } } // 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. // //////////////////////////////////////////////////////////////////////////// int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, 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[] = { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC }; static unsigned char abNegTokenTargElements[] = { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC }; int nReturn = SPNEGO_E_SUCCESS; int nCtr = 0L; long nElementLength = 0L; long nActualTokenLength = 0L; unsigned char* pbElements = NULL; // Point to the correct array switch( pSpnegoToken->ucTokenType ) { case SPNEGO_TOKEN_INIT: { pbElements = abNegTokenInitElements; } break; case SPNEGO_TOKEN_TARG: { pbElements = abNegTokenTargElements; } break; } // SWITCH tokentype // // Enumerate the element arrays and look for the tokens at our current location // for ( nCtr = 0L; SPNEGO_E_SUCCESS == nReturn && nCtr < MAX_NUM_TOKEN_ELEMENTS && nRemainingTokenLength > 0L; nCtr++ ) { // Check if the token exists if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr], 0L, nRemainingTokenLength, &nElementLength, &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) { // Token data should skip over the sequence token and then // call the appropriate function to initialize the element pbTokenData += nActualTokenLength; // Lengths in the elements should NOT go beyond the element // length // Different tokens mean different elements if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) { // Handle each element as appropriate switch( pbElements[nCtr] ) { case SPNEGO_NEGINIT_ELEMENT_MECHTYPES: { // // This is a Mech List that specifies which OIDs the // originator of the Init Token supports. // nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength, &pSpnegoToken->aElementArray[nCtr] ); } break; case SPNEGO_NEGINIT_ELEMENT_REQFLAGS: { // // This is a BITSTRING which specifies the flags that the receiver // pass to the gss_accept_sec_context() function. // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, BITSTRING, spnego_init_reqFlags, &pSpnegoToken->aElementArray[nCtr] ); } break; case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN: { // // This is an OCTETSTRING which contains a GSSAPI token corresponding // to the first OID in the MechList. // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, OCTETSTRING, spnego_init_mechToken, &pSpnegoToken->aElementArray[nCtr] ); } 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) // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, OCTETSTRING, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr] ); if (nReturn == SPNEGO_E_UNEXPECTED_TYPE) { // This is really a negHints element. Check the type and length, // but otherwise just ignore it. long elen, tlen; nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, nElementLength, nElementLength, &elen, &tlen ); } } break; } // SWITCH Element } else { /* pSpnegoToken->ucTokenType == SPNEGO_TOKEN_TARG */ switch( pbElements[nCtr] ) { case SPNEGO_NEGTARG_ELEMENT_NEGRESULT: { // // This is an ENUMERATION which specifies result of the last GSS // token negotiation call. // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, ENUMERATED, spnego_targ_negResult, &pSpnegoToken->aElementArray[nCtr] ); } break; case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH: { // // This is an OID which specifies a supported mechanism. // nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength, spnego_targ_mechListMIC, &pSpnegoToken->aElementArray[nCtr] ); } break; case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN: { // // This is an OCTETSTRING which specifies results of the last GSS // token negotiation call. // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, OCTETSTRING, spnego_targ_responseToken, &pSpnegoToken->aElementArray[nCtr] ); } break; case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC: { // // This is an OCTETSTRING, typically 16 bytes, // which contains a message integrity BLOB. // nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, OCTETSTRING, spnego_targ_mechListMIC, &pSpnegoToken->aElementArray[nCtr] ); } break; } // SWITCH Element } // ELSE !NegTokenInit // Account for the entire token and following data nRemainingTokenLength -= ( nActualTokenLength + nElementLength ); // Token data should skip past the element length now pbTokenData += nElementLength; } // 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). nReturn = SPNEGO_E_SUCCESS; } } // FOR enum elements // // We should always run down to 0 remaining bytes in the token. If not, we've got // a bad token. // if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L ) { nReturn = SPNEGO_E_INVALID_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 FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex ) { int nReturn = SPNEGO_E_NOT_FOUND; int nCtr = 0; long nLength = 0L; long nBoundaryLength = pSpnegoElement->nDatalength; unsigned char* pbMechListData = pSpnegoElement->pbData; while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L ) { // Use the helper function to check the OID if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) ) == SPNEGO_E_SUCCESS ) { *piMechTypeIndex = nCtr; } // Adjust for the current OID pbMechListData += nLength; nBoundaryLength -= nLength; 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. // //////////////////////////////////////////////////////////////////////////// int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength ) { int nReturn = SPNEGO_E_SUCCESS; long nLength = 0L; long nTokenLength = 0L; while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 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. nReturn = ASNDerCheckToken( pbMechListData, OID, 0L, nBoundaryLength, &nLength, &nTokenLength ); // Adjust for the current OID pbMechListData += ( nLength + nTokenLength ); nBoundaryLength -= ( nLength + nTokenLength ); } // 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. // //////////////////////////////////////////////////////////////////////////// int IsValidMechOid( SPNEGO_MECH_OID mechOid ) { return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy && mechOid <= spnego_mech_oid_NTLMSSP ); } ///////////////////////////////////////////////////////////////////////////// // // Function: // IsValidContextFlags // // Parameters: // [in] ucContextFlags - ContextFlags value // // Returns: // int Success - 1 // Failure - 0 // // Comments : // Checks for a valid ContextFlags value. // //////////////////////////////////////////////////////////////////////////// int IsValidContextFlags( unsigned char ucContextFlags ) { // 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. // //////////////////////////////////////////////////////////////////////////// int IsValidNegResult( SPNEGO_NEGRESULT negResult ) { return ( negResult >= spnego_negresult_success && negResult <= spnego_negresult_rejected ); } ///////////////////////////////////////////////////////////////////////////// // // 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 IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) { int nReturn = 0; // Parameter should be non-NULL if ( NULL != pSpnegoToken ) { // Length should be at least the size defined in the header if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE ) { // 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 if ( pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS ) { // Check for proper token type if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) { 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 IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) { int nReturn = 0; // Check boundaries if ( spnegoElement > spnego_element_min && spnegoElement < spnego_element_max ) { // Check for appropriateness to token type if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) { nReturn = ( spnegoElement >= spnego_init_mechtypes && spnegoElement <= spnego_init_mechListMIC ); } else { nReturn = ( spnegoElement >= spnego_targ_negResult && spnegoElement <= spnego_targ_mechListMIC ); } } // 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 CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) { int nReturn = 0; // Offset is difference between value and initial element identifier // (these differ based on ucTokenType) if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) { nReturn = spnegoElement - spnego_init_mechtypes; } else { nReturn = spnegoElement - spnego_targ_negResult; } 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 int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags, unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN** ppSpnegoToken ) { int nReturn = SPNEGO_E_INVALID_PARAMETER; SPNEGO_TOKEN* pSpnegoToken = NULL; unsigned char* pbFirstElement = NULL; 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. // pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength ); if ( NULL != pSpnegoToken ) { // Copy the binary data locally // Initialize the token type if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength, &nRemainingTokenLength, &pbFirstElement ) ) == SPNEGO_E_SUCCESS ) { // Initialize the element array if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement, nRemainingTokenLength ) ) == SPNEGO_E_SUCCESS ) { *ppSpnegoToken = pSpnegoToken; } } // IF Init Token Type // Cleanup on error condition if ( SPNEGO_E_SUCCESS != nReturn ) { spnegoFreeData( pSpnegoToken ); } } else { nReturn = SPNEGO_E_OUT_OF_MEMORY; } } // IF Valid parameters return nReturn; }