724 lines
21 KiB
C
724 lines
21 KiB
C
// 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
|
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
//
|
|
// DERPARSE.C
|
|
//
|
|
// SPNEGO Token Handler Source File
|
|
//
|
|
// Contains implementation of ASN.1 DER read/write functions
|
|
// as defined in DERPARSE.H.
|
|
//
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
/*#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <memory.h>
|
|
#include "spnego.h"
|
|
#include "derparse.h"*/
|
|
|
|
#include "..\pch.h"
|
|
|
|
#define __LITTLE_ENDIAN__ 1
|
|
|
|
//
|
|
// The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in
|
|
// the array below, that a mechanism can be found.
|
|
//
|
|
MECH_OID g_stcMechOIDList[] =
|
|
{
|
|
{"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9,
|
|
spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2
|
|
{"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9,
|
|
spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2
|
|
{"\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6,
|
|
spnego_mech_oid_Spnego }, // 1.3.6.1.5.5.2
|
|
{"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a", 12, 10,
|
|
spnego_mech_oid_NTLMSSP }, // 1.3.6.1.4.1.311.2.2.10
|
|
{"", 0, 0, spnego_mech_oid_NotUsed } // Placeholder
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerGetLength
|
|
//
|
|
// Parameters:
|
|
// [in] pbLengthData - DER Length Data
|
|
// [in] nBoundaryLength - Length that value must not exceed.
|
|
// [out] pnLength - Filled out with length value
|
|
// [out] pnNumLengthBytes - Filled out with number of bytes
|
|
// consumed by DER length.
|
|
//
|
|
// Returns:
|
|
// int Success - SPNEGO_E_SUCCESS
|
|
// Failure - SPNEGO API Error code
|
|
//
|
|
// Comments :
|
|
// Interprets the data at pbLengthData as a DER length. The length must
|
|
// fit within the bounds of nBoundary length. We do not currently
|
|
// process lengths that take more than 4 bytes.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int ASNDerGetLength(unsigned char* pbLengthData, unsigned short nBoundaryLength, unsigned short* pnLength,
|
|
unsigned short* pnNumLengthBytes)
|
|
{
|
|
int nReturn = SPNEGO_E_INVALID_LENGTH;
|
|
unsigned short nNumLengthBytes = 0;
|
|
|
|
// First check if the extended length bit is set
|
|
|
|
if (*pbLengthData & LEN_XTND)
|
|
{
|
|
// Lower 7 bits contain the number of trailing bytes that describe the length
|
|
nNumLengthBytes = *pbLengthData & LEN_MASK;
|
|
|
|
// Check that the number of bytes we are about to read is within our boundary
|
|
// constraints
|
|
|
|
if (nNumLengthBytes <= nBoundaryLength - 1)
|
|
{
|
|
// For now, our handler won't deal with lengths greater than 4 bytes
|
|
if (nNumLengthBytes >= 1 && nNumLengthBytes <= 4)
|
|
{
|
|
// 0 out the initial length
|
|
*pnLength = 0L;
|
|
|
|
// Bump by 1 byte
|
|
pbLengthData++;
|
|
#ifdef __LITTLE_ENDIAN__
|
|
|
|
// There may be a cleaner way to do this, but for now, this seems to be
|
|
// an easy way to do the transformation
|
|
switch (nNumLengthBytes)
|
|
{
|
|
case 1:
|
|
{
|
|
*(((unsigned char*)pnLength)) = *pbLengthData;
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
{
|
|
*(((unsigned char*)pnLength)) = *(pbLengthData + 1);
|
|
*(((unsigned char*)pnLength) + 1) = *(pbLengthData);
|
|
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
{
|
|
*(((unsigned char*)pnLength)) = *(pbLengthData + 2);
|
|
*(((unsigned char*)pnLength) + 2) = *(pbLengthData + 1);
|
|
*(((unsigned char*)pnLength) + 3) = *(pbLengthData);
|
|
break;
|
|
}
|
|
|
|
case 4:
|
|
{
|
|
*(((unsigned char*)pnLength)) = *(pbLengthData + 3);
|
|
*(((unsigned char*)pnLength) + 1) = *(pbLengthData + 2);
|
|
*(((unsigned char*)pnLength) + 2) = *(pbLengthData + 1);
|
|
*(((unsigned char*)pnLength) + 3) = *(pbLengthData);
|
|
break;
|
|
}
|
|
|
|
} // SWITCH ( nNumLengthBytes )
|
|
|
|
#else
|
|
// We are Big-Endian, so the length can be copied in from the source
|
|
// as is. Ensure that we adjust for the number of bytes we actually
|
|
// copy.
|
|
|
|
memcpy(((unsigned char*)pnLength) + (4 - nNumLengthBytes),
|
|
pbLengthData, nNumLengthBytes);
|
|
#endif
|
|
|
|
// Account for the initial length byte
|
|
* pnNumLengthBytes = nNumLengthBytes + 1;
|
|
nReturn = SPNEGO_E_SUCCESS;
|
|
|
|
} // IF Valid Length
|
|
|
|
} // IF num bytes to read is within the boundary length
|
|
|
|
} // IF xtended length
|
|
else
|
|
{
|
|
// Extended bit is not set, so the length is in the value and the one
|
|
// byte describes the length
|
|
*pnLength = *pbLengthData & LEN_MASK;
|
|
*pnNumLengthBytes = 1;
|
|
nReturn = SPNEGO_E_SUCCESS;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerCheckToken
|
|
//
|
|
// Parameters:
|
|
// [in] pbTokenData - Token Data
|
|
// [in] nToken - Token identifier to check for
|
|
// [in] nLengthWithToken - Expected token length (with data)
|
|
// [in] nBoundaryLength - Length that value must not exceed.
|
|
// [out] pnLength - Filled out with data length
|
|
// [out] pnTokenLength - Filled out with number of bytes
|
|
// consumed by token identifier and length.
|
|
//
|
|
// Returns:
|
|
// int Success - SPNEGO_E_SUCCESS
|
|
// Failure - SPNEGO API Error code
|
|
//
|
|
// Comments :
|
|
// Checks the data pointed to by pbTokenData for the specified token
|
|
// identifier and the length that immediately follows. If
|
|
// nLengthWithToken is > 0, the calculated length must match. The
|
|
// length must also not exceed the specified boundary length .
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int ASNDerCheckToken(unsigned char* pbTokenData, unsigned char nToken,
|
|
unsigned short nLengthWithToken, unsigned short nBoundaryLength,
|
|
unsigned short* pnLength, unsigned short* pnTokenLength)
|
|
{
|
|
|
|
int nReturn = SPNEGO_E_INVALID_LENGTH;
|
|
unsigned short nNumLengthBytes = 0L;
|
|
|
|
// Make sure that we've at least got 2 bytes of room to work with
|
|
|
|
if (nBoundaryLength >= 2)
|
|
{
|
|
// The first byte of the token data MUST match the specified token
|
|
if (*pbTokenData == nToken)
|
|
{
|
|
// Next byte indicates the length
|
|
pbTokenData++;
|
|
|
|
// Get the length described by the token
|
|
if ((nReturn = ASNDerGetLength(pbTokenData, nBoundaryLength, pnLength,
|
|
&nNumLengthBytes)) == SPNEGO_E_SUCCESS)
|
|
{
|
|
// Verify that the length is LESS THAN the boundary length
|
|
// (this should prevent us walking out of our buffer)
|
|
if ((nBoundaryLength - (nNumLengthBytes + 1) < *pnLength))
|
|
{
|
|
nReturn = SPNEGO_E_INVALID_LENGTH;
|
|
}
|
|
|
|
// If we were passed a length to check, do so now
|
|
if (nLengthWithToken > 0L)
|
|
{
|
|
// Check that the expected length matches
|
|
if ((nLengthWithToken - (nNumLengthBytes + 1)) != *pnLength)
|
|
{
|
|
nReturn = SPNEGO_E_INVALID_LENGTH;
|
|
}
|
|
} // IF need to validate length
|
|
|
|
if (SPNEGO_E_SUCCESS == nReturn)
|
|
{
|
|
*pnTokenLength = nNumLengthBytes + 1;
|
|
}
|
|
|
|
} // IF ASNDerGetLength
|
|
|
|
} // IF token matches
|
|
else
|
|
{
|
|
nReturn = SPNEGO_E_TOKEN_NOT_FOUND;
|
|
}
|
|
|
|
} // IF Boundary Length is at least 2 bytes
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerCheckOID
|
|
//
|
|
// Parameters:
|
|
// [in] pbTokenData - Token Data
|
|
// [in] nMechOID - OID we are looking for
|
|
// [in] nBoundaryLength - Length that value must not exceed.
|
|
// [out] pnTokenLength - Filled out with number of bytes
|
|
// consumed by token and data.
|
|
//
|
|
// Returns:
|
|
// int Success - SPNEGO_E_SUCCESS
|
|
// Failure - SPNEGO API Error code
|
|
//
|
|
// Comments :
|
|
// Checks the data pointed to by pbTokenData for the specified OID.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int ASNDerCheckOID(unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, unsigned short nBoundaryLength,
|
|
unsigned short* pnTokenLength)
|
|
{
|
|
int nReturn = 0L;
|
|
unsigned short nLength = 0L;
|
|
|
|
// Verify that we have an OID token
|
|
if ((nReturn = ASNDerCheckToken(pbTokenData, OID, 0L, nBoundaryLength,
|
|
&nLength, pnTokenLength)) == SPNEGO_E_SUCCESS)
|
|
{
|
|
// Add the data length to the Token Length
|
|
*pnTokenLength += nLength;
|
|
|
|
// Token Lengths plus the actual length must match the length in our OID list element.
|
|
// If it doesn't, we're done
|
|
if (*pnTokenLength == g_stcMechOIDList[nMechOID].iLen)
|
|
{
|
|
// Memcompare the token and the expected field
|
|
if (memcmp(pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength) != 0)
|
|
{
|
|
nReturn = SPNEGO_E_UNEXPECTED_OID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nReturn = SPNEGO_E_UNEXPECTED_OID;
|
|
}
|
|
|
|
} // IF OID Token CHecks
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerCalcNumLengthBytes
|
|
//
|
|
// Parameters:
|
|
// [in] nLength - Length to calculate length bytes for.
|
|
//
|
|
// Returns:
|
|
// int Number of bytes necessary to represent length
|
|
//
|
|
// Comments :
|
|
// Helper function to calculate the number of length bytes necessary to
|
|
// represent a length value. For our purposes, a 32-bit value should be
|
|
// enough to describea length.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
static unsigned short ASNDerCalcNumLengthBytes(unsigned short nLength)
|
|
{
|
|
if (nLength <= 0x7F)
|
|
{
|
|
// A single byte will be sufficient for describing this length.
|
|
// The byte will simply contain the length
|
|
return 1;
|
|
}
|
|
else if (nLength <= 0xFF)
|
|
{
|
|
// Two bytes are necessary, one to say how many following bytes
|
|
// describe the length, and one to give the length
|
|
return 2;
|
|
}
|
|
else if (nLength <= 0xFFFF)
|
|
{
|
|
// Three bytes are necessary, one to say how many following bytes
|
|
// describe the length, and two to give the length
|
|
return 3;
|
|
}
|
|
else if (nLength <= 0xFFFFFF)
|
|
{
|
|
// Four bytes are necessary, one to say how many following bytes
|
|
// describe the length, and three to give the length
|
|
return 4;
|
|
}
|
|
else
|
|
{
|
|
// Five bytes are necessary, one to say how many following bytes
|
|
// describe the length, and four to give the length
|
|
return 5;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerCalcTokenLength
|
|
//
|
|
// Parameters:
|
|
// [in] nLength - Length to calculate length bytes for.
|
|
// [in] nDataLength - Actual Data length value.
|
|
//
|
|
// Returns:
|
|
// long Number of bytes necessary to represent a token, length and data
|
|
//
|
|
// Comments :
|
|
// Helper function to calculate a token and value size, based on a
|
|
// supplied length value, and any binary data that will need to be
|
|
// written out.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned short ASNDerCalcTokenLength(unsigned short nLength, unsigned short nDataLength)
|
|
{
|
|
// Add a byte to the length size to account for a single byte to
|
|
// hold the token type.
|
|
unsigned short nTotalLength = ASNDerCalcNumLengthBytes(nLength) + 1;
|
|
|
|
return nTotalLength + nDataLength;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerCalcElementLength
|
|
//
|
|
// Parameters:
|
|
// [in] nDataLength - Length of data.
|
|
// [out] pnInternalLength - Filled out with length of element
|
|
// without sequence info.
|
|
//
|
|
// Returns:
|
|
// long Number of bytes necessary to represent an element
|
|
//
|
|
// Comments :
|
|
// Helper function to calculate an element length. An element consists
|
|
// of a sequence token, a type token and then the data.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned short ASNDerCalcElementLength(unsigned short nDataLength, unsigned short* pnInternalLength)
|
|
{
|
|
// First the type token and the actual data
|
|
unsigned short nTotalLength = ASNDerCalcTokenLength(nDataLength, nDataLength);
|
|
|
|
// Internal length is the length without the element sequence token
|
|
if (NULL != pnInternalLength)
|
|
{
|
|
*pnInternalLength = nTotalLength;
|
|
}
|
|
|
|
// Next add in the element's sequence token (remember that its
|
|
// length is the total length of the type token and data)
|
|
nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L);
|
|
|
|
return nTotalLength;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerCalcMechListLength
|
|
//
|
|
// Parameters:
|
|
// [in] mechoid - Mech OID to put in list.
|
|
// [out] pnInternalLength - Filled out with length of element
|
|
// without the primary sequence token.
|
|
//
|
|
// Returns:
|
|
// long Number of bytes necessary to represent a mechList
|
|
//
|
|
// Comments :
|
|
// Helper function to calculate a MechList length. A mechlist consists
|
|
// of a NegTokenInit sequence token, a sequence token for the MechList
|
|
// and finally a list of OIDs. In our case, we only really have one
|
|
// OID.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned short ASNDerCalcMechListLength(SPNEGO_MECH_OID mechoid, unsigned short* pnInternalLength)
|
|
{
|
|
// First the OID
|
|
unsigned short nTotalLength = g_stcMechOIDList[mechoid].iLen;
|
|
|
|
// Next add in a sequence token
|
|
nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L);
|
|
|
|
// Internal length is the length without the element sequence token
|
|
if (NULL != pnInternalLength)
|
|
{
|
|
*pnInternalLength = nTotalLength;
|
|
}
|
|
|
|
// Finally add in the element's sequence token
|
|
nTotalLength += ASNDerCalcTokenLength(nTotalLength, 0L);
|
|
|
|
return nTotalLength;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerWriteLength
|
|
//
|
|
// Parameters:
|
|
// [out] pbData - Buffer to write into.
|
|
// [in] nLength - Length to write out.
|
|
//
|
|
// Returns:
|
|
// int Number of bytes written out
|
|
//
|
|
// Comments :
|
|
// Helper function to write out a length value following DER rules .
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
static unsigned short ASNDerWriteLength(unsigned char* pbData, unsigned short nLength)
|
|
{
|
|
unsigned short nNumBytesRequired = ASNDerCalcNumLengthBytes(nLength);
|
|
unsigned short nNumLengthBytes = nNumBytesRequired - 1;
|
|
|
|
if (nNumBytesRequired > 1)
|
|
{
|
|
// Write out the number of bytes following which will be used
|
|
*pbData = (unsigned char)(LEN_XTND | nNumLengthBytes);
|
|
|
|
// Point to where we'll actually write the length
|
|
pbData++;
|
|
|
|
#ifdef __LITTLE_ENDIAN__
|
|
|
|
// There may be a cleaner way to do this, but for now, this seems to be
|
|
// an easy way to do the transformation
|
|
switch (nNumLengthBytes)
|
|
{
|
|
case 1:
|
|
{
|
|
// Cast the length to a single byte, since we know that it
|
|
// is 0x7F or less (or we wouldn't only need a single byte).
|
|
|
|
*pbData = (unsigned char)nLength;
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
{
|
|
*pbData = *(((unsigned char*)&nLength) + 1);
|
|
*(pbData + 1) = *(((unsigned char*)&nLength));
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
{
|
|
*pbData = *(((unsigned char*)&nLength) + 3);
|
|
*(pbData + 1) = *(((unsigned char*)&nLength) + 2);
|
|
*(pbData + 2) = *(((unsigned char*)&nLength));
|
|
break;
|
|
}
|
|
|
|
case 4:
|
|
{
|
|
*pbData = *(((unsigned char*)&nLength) + 3);
|
|
*(pbData + 1) = *(((unsigned char*)&nLength) + 2);
|
|
*(pbData + 2) = *(((unsigned char*)&nLength) + 1);
|
|
*(pbData + 3) = *(((unsigned char*)&nLength));
|
|
break;
|
|
}
|
|
|
|
} // SWITCH ( nNumLengthBytes )
|
|
|
|
#else
|
|
// We are Big-Endian, so the length can be copied in from the source
|
|
// as is. Ensure that we adjust for the number of bytes we actually
|
|
// copy.
|
|
|
|
memcpy(pbData,
|
|
((unsigned char*)&nLength) + (4 - nNumLengthBytes), nNumLengthBytes);
|
|
#endif
|
|
|
|
} // IF > 1 byte for length
|
|
else
|
|
{
|
|
// Cast the length to a single byte, since we know that it
|
|
// is 0x7F or less (or we wouldn't only need a single byte).
|
|
|
|
*pbData = (unsigned char)nLength;
|
|
}
|
|
|
|
return nNumBytesRequired;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerWriteToken
|
|
//
|
|
// Parameters:
|
|
// [out] pbData - Buffer to write into.
|
|
// [in] ucType - Token Type
|
|
// [in] pbTokenValue - Actual Value
|
|
// [in] nLength - Length of Data.
|
|
//
|
|
// Returns:
|
|
// int Number of bytes written out
|
|
//
|
|
// Comments :
|
|
// Helper function to write out a token and any associated data. If
|
|
// pbTokenValue is non-NULL, then it is written out in addition to the
|
|
// token identifier and the length bytes.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned short ASNDerWriteToken(unsigned char* pbData, unsigned char ucType,
|
|
unsigned char* pbTokenValue, unsigned short nLength)
|
|
{
|
|
unsigned short nTotalBytesWrittenOut = 0L;
|
|
unsigned short nNumLengthBytesWritten = 0L;
|
|
|
|
// Write out the type
|
|
*pbData = ucType;
|
|
|
|
// Wrote 1 byte, and move data pointer
|
|
nTotalBytesWrittenOut++;
|
|
pbData++;
|
|
|
|
// Now write out the length and adjust the number of bytes written out
|
|
nNumLengthBytesWritten = ASNDerWriteLength(pbData, nLength);
|
|
|
|
nTotalBytesWrittenOut += nNumLengthBytesWritten;
|
|
pbData += nNumLengthBytesWritten;
|
|
|
|
// Write out the token value if we got one. The assumption is that the
|
|
// nLength value indicates how many bytes are in pbTokenValue.
|
|
|
|
if (NULL != pbTokenValue)
|
|
{
|
|
memcpy(pbData, pbTokenValue, nLength);
|
|
nTotalBytesWrittenOut += nLength;
|
|
}
|
|
|
|
return nTotalBytesWrittenOut;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerWriteOID
|
|
//
|
|
// Parameters:
|
|
// [out] pbData - Buffer to write into.
|
|
// [in] eMechOID - OID to write out.
|
|
//
|
|
// Returns:
|
|
// int Number of bytes written out
|
|
//
|
|
// Comments :
|
|
// Helper function to write out an OID. For these we have the raw bytes
|
|
// listed in a global structure. The caller simply indicates which OID
|
|
// should be written and we will splat out the data.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int ASNDerWriteOID(unsigned char* pbData, SPNEGO_MECH_OID eMechOID)
|
|
{
|
|
memcpy(pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen);
|
|
|
|
return g_stcMechOIDList[eMechOID].iLen;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerWriteMechList
|
|
//
|
|
// Parameters:
|
|
// [out] pbData - Buffer to write into.
|
|
// [in] eMechOID - OID to put in MechList.
|
|
//
|
|
// Returns:
|
|
// int Number of bytes written out
|
|
//
|
|
// Comments :
|
|
// Helper function to write out a MechList. A MechList consists of the
|
|
// Init Token Sequence, a sequence token and then the list of OIDs. In
|
|
// our case the OID is from a global array of known OIDs.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned short ASNDerWriteMechList(unsigned char* pbData, SPNEGO_MECH_OID mechoid)
|
|
{
|
|
// First get the length
|
|
unsigned short nInternalLength = 0L;
|
|
unsigned short nMechListLength = ASNDerCalcMechListLength(mechoid, &nInternalLength);
|
|
unsigned short nTempLength = 0L;
|
|
|
|
nTempLength = ASNDerWriteToken(pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
|
|
NULL, nInternalLength);
|
|
|
|
// Adjust the data pointer
|
|
pbData += nTempLength;
|
|
|
|
// Now write the Sequence token and the OID (the OID is a BLOB in the global
|
|
// structure.
|
|
|
|
nTempLength = ASNDerWriteToken(pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
|
|
g_stcMechOIDList[mechoid].ucOid,
|
|
g_stcMechOIDList[mechoid].iLen);
|
|
|
|
return nMechListLength;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function:
|
|
// ASNDerWriteElement
|
|
//
|
|
// Parameters:
|
|
// [out] pbData - Buffer to write into.
|
|
// [in] ucElementSequence - Sequence Token
|
|
// [in] ucType - Token Type
|
|
// [in] pbTokenValue - Actual Value
|
|
// [in] nLength - Length of Data.
|
|
//
|
|
// Returns:
|
|
// int Number of bytes written out
|
|
//
|
|
// Comments :
|
|
// Helper function to write out a SPNEGO Token element. An element
|
|
// consists of a sequence token, a type token and the associated data.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned short ASNDerWriteElement(unsigned char* pbData, unsigned char ucElementSequence,
|
|
unsigned char ucType, unsigned char* pbTokenValue, unsigned short nLength)
|
|
{
|
|
// First get the length
|
|
unsigned short nInternalLength = 0L;
|
|
unsigned short nElementLength = ASNDerCalcElementLength(nLength, &nInternalLength);
|
|
unsigned short nTempLength = 0L;
|
|
|
|
// Write out the sequence byte and the length of the type and data
|
|
nTempLength = ASNDerWriteToken(pbData, ucElementSequence, NULL, nInternalLength);
|
|
|
|
// Adjust the data pointer
|
|
pbData += nTempLength;
|
|
|
|
// Now write the type and the data.
|
|
nTempLength = ASNDerWriteToken(pbData, ucType, pbTokenValue, nLength);
|
|
|
|
return nElementLength;
|
|
}
|