771 lines
18 KiB
C++
771 lines
18 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
||
|
//
|
||
|
// File: enc.cpp
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cpp>
|
||
|
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "encode.h"
|
||
|
|
||
|
|
||
|
OIDTRANSLATE const *
|
||
|
LookupOidTranslate(
|
||
|
IN CHAR const *pszObjId)
|
||
|
{
|
||
|
DWORD i;
|
||
|
OIDTRANSLATE const *pOid = NULL;
|
||
|
|
||
|
for (i = 0; i < g_cOidTranslate; i++)
|
||
|
{
|
||
|
if (0 == strcmp(pszObjId, g_aOidTranslate[i].pszObjId))
|
||
|
{
|
||
|
pOid = &g_aOidTranslate[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
CSASSERT(NULL != pOid);
|
||
|
return(pOid);
|
||
|
}
|
||
|
|
||
|
|
||
|
long
|
||
|
EncodeObjId(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN CHAR const *pszObjId)
|
||
|
{
|
||
|
OIDTRANSLATE const *pOid;
|
||
|
long cbLength;
|
||
|
|
||
|
pOid = LookupOidTranslate(pszObjId);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_OBJECT_ID;
|
||
|
}
|
||
|
cbLength = EncodeLength(pbEncoded, pOid->cbOIDEncoded);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
CopyMemory(
|
||
|
pbEncoded + cbLength,
|
||
|
pOid->abOIDEncoded,
|
||
|
pOid->cbOIDEncoded);
|
||
|
}
|
||
|
return(1 + cbLength + pOid->cbOIDEncoded);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeLength ASN1 encodes a length field. The parameter
|
||
|
// dwLen is the length to be encoded, it is a DWORD and
|
||
|
// therefore may be no larger than 2^32. The pbEncoded
|
||
|
// parameter is the encoded result, and memory must be
|
||
|
// allocated for it by the caller. The pbEncoded parameter
|
||
|
// indicates if the result is to be written to the pbEncoded
|
||
|
// parameter. The function cannot fail and returns the
|
||
|
// number of total bytes in the encoded length.
|
||
|
// encoded length.
|
||
|
//**************************************************************************
|
||
|
|
||
|
// Notes: Encodes 0x0000 to 0x007f as <lobyte>
|
||
|
// Encodes 0x0080 to 0x00ff as <81>, <lobyte>
|
||
|
// Encodes 0x0100 to 0xffff as <82>, <hibyte>, <lobyte>
|
||
|
|
||
|
long
|
||
|
EncodeLength(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
// length is between 2^8 and 2^16 - 1
|
||
|
|
||
|
if (dwLen > 0xff)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded[0] = 0x82;
|
||
|
pbEncoded[1] = (BYTE) (dwLen >> 8);
|
||
|
pbEncoded[2] = (BYTE) dwLen;
|
||
|
}
|
||
|
return(3);
|
||
|
}
|
||
|
|
||
|
// length is between 2^7 and 2^8 - 1
|
||
|
|
||
|
if (dwLen > 0x7f)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded[0] = 0x81;
|
||
|
pbEncoded[1] = (BYTE) dwLen;
|
||
|
}
|
||
|
return(2);
|
||
|
}
|
||
|
|
||
|
// length is between 0 and 2^7 - 1
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded[0] = (BYTE) dwLen;
|
||
|
}
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
long
|
||
|
EncodeNull(
|
||
|
OPTIONAL OUT BYTE *pbEncoded)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_NULL;
|
||
|
*pbEncoded = 0;
|
||
|
}
|
||
|
return(2);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeAlgid ASN1 encodes an algorithm identifier. The
|
||
|
// parameter Algid is the algorithm identifier as an ALG_ID
|
||
|
// type. pbEncoded is the parameter used to pass back the
|
||
|
// encoded result, and memory must be allocated for it by
|
||
|
// the caller. The pbEncoded parameter indicates if the
|
||
|
// result is to be written to the pbEncoded parameter
|
||
|
// The function returns a -1 if it fails and otherwise
|
||
|
// returns the number of total bytes in the encoded
|
||
|
// algorithm identifier.
|
||
|
//**************************************************************************
|
||
|
|
||
|
long
|
||
|
EncodeAlgid(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN DWORD Algid)
|
||
|
{
|
||
|
DWORD i;
|
||
|
LONG cb = -1;
|
||
|
|
||
|
// determine the algorithm id which is to be encoded and
|
||
|
// copy the appropriate encoded algid into the destination
|
||
|
|
||
|
for (i = 0; i < g_cAlgIdTranslate; i++)
|
||
|
{
|
||
|
if (Algid == g_aAlgIdTranslate[i].AlgId)
|
||
|
{
|
||
|
cb = EncodeObjId(pbEncoded, g_aAlgIdTranslate[i].pszObjId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return(cb);
|
||
|
}
|
||
|
|
||
|
|
||
|
long
|
||
|
EncodeAlgorithm(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN DWORD AlgId)
|
||
|
{
|
||
|
BYTE abTemp[32];
|
||
|
long cbResult;
|
||
|
BYTE *pb;
|
||
|
|
||
|
pb = abTemp;
|
||
|
|
||
|
// Take a guess at the total length:
|
||
|
|
||
|
pb += EncodeHeader(pb, sizeof(abTemp));
|
||
|
|
||
|
cbResult = EncodeAlgid(pb, AlgId);
|
||
|
if (cbResult == -1)
|
||
|
{
|
||
|
return(-1);
|
||
|
}
|
||
|
pb += cbResult;
|
||
|
|
||
|
cbResult += EncodeNull(pb);
|
||
|
|
||
|
// Fix up the total length:
|
||
|
|
||
|
cbResult += EncodeHeader(abTemp, cbResult);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
CopyMemory(pbEncoded, abTemp, cbResult);
|
||
|
}
|
||
|
return(cbResult);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeInteger ASN1 encodes an integer. The pbInt parameter
|
||
|
// is the integer as an array of bytes, and dwLen is the number
|
||
|
// of bytes in the array. The least significant byte of the
|
||
|
// integer is the zeroth byte of the array. The encoded result
|
||
|
// is passed back in the pbEncoded parameter. The pbEncoded
|
||
|
// indicates if the result is to be written to the pbEncoded
|
||
|
// parameter. The function cannot fail and returns the number
|
||
|
// of total bytes in the encoded integer.
|
||
|
// This implementation will only deal with positive integers.
|
||
|
//**************************************************************************
|
||
|
|
||
|
long
|
||
|
EncodeInteger(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN BYTE const *pbInt,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
DWORD iInt;
|
||
|
long j; // Must be signed!
|
||
|
LONG cbResult;
|
||
|
LONG cbLength;
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_INTEGER;
|
||
|
}
|
||
|
cbResult = 1;
|
||
|
|
||
|
// find the most significant non-zero byte
|
||
|
|
||
|
for (iInt = dwLen - 1; pbInt[iInt] == 0; iInt--)
|
||
|
{
|
||
|
if (iInt == 0) // if the integer value is 0
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = 0x01;
|
||
|
*pbEncoded++ = 0x00;
|
||
|
}
|
||
|
return(cbResult + 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if the most significant bit of the most significant byte is set then add
|
||
|
// a 0 byte to the beginning.
|
||
|
|
||
|
if (pbInt[iInt] > 0x7f)
|
||
|
{
|
||
|
// encode the length
|
||
|
|
||
|
cbLength = EncodeLength(pbEncoded, iInt + 2);
|
||
|
|
||
|
// set the first byte of the integer to 0 and increment pointer
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded += cbLength;
|
||
|
*pbEncoded++ = 0;
|
||
|
}
|
||
|
cbResult++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// encode the length
|
||
|
|
||
|
cbLength = EncodeLength(pbEncoded, iInt + 1);
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded += cbLength;
|
||
|
}
|
||
|
}
|
||
|
cbResult += cbLength;
|
||
|
|
||
|
// copy the integer bytes into the encoded buffer
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
// copy the integer bytes into the encoded buffer
|
||
|
|
||
|
for (j = iInt; j >= 0; j--)
|
||
|
{
|
||
|
*pbEncoded++ = pbInt[j];
|
||
|
}
|
||
|
}
|
||
|
cbResult += iInt + 1;
|
||
|
return(cbResult);
|
||
|
}
|
||
|
|
||
|
|
||
|
long
|
||
|
EncodeUnicodeString(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN WCHAR const *pwsz)
|
||
|
{
|
||
|
long cbLength;
|
||
|
long cbData = wcslen(pwsz) * sizeof(WCHAR);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_UNICODE_STRING;
|
||
|
}
|
||
|
cbLength = EncodeLength(pbEncoded, cbData);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded += cbLength;
|
||
|
for ( ; L'\0' != *pwsz; pwsz++)
|
||
|
{
|
||
|
*pbEncoded++ = (BYTE) (*pwsz >> 8);
|
||
|
*pbEncoded++ = (BYTE) *pwsz;
|
||
|
}
|
||
|
}
|
||
|
return(1 + cbLength + cbData);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeIA5String ASN1 encodes a character string. The pbStr
|
||
|
// parameter is the string as an array of characters, and dwLen
|
||
|
// is the number of characters in the array. The encoded result
|
||
|
// is passed back in the pbEncoded parameter. The pbEncoded
|
||
|
// indicates if the result is to be written to the pbEncoded
|
||
|
// parameter. The function cannot fail and returns the number
|
||
|
// of total bytes in the encoded string.
|
||
|
//**************************************************************************
|
||
|
|
||
|
long
|
||
|
EncodeIA5String(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN BYTE const *pbStr,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
long cbLength;
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_IA5_STRING;
|
||
|
}
|
||
|
cbLength = EncodeLength(pbEncoded, dwLen);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
CopyMemory(pbEncoded + cbLength, pbStr, dwLen);
|
||
|
}
|
||
|
return(1 + cbLength + dwLen);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeOctetString ASN1 encodes a string of hex valued
|
||
|
// characters. The pbStr parameter is an array of characters,
|
||
|
// and dwLen is the number of characters in the array. The
|
||
|
// encoded result is passed back in the pbEncoded parameter. The
|
||
|
// pbEncoded parameter indicates if the result is to be written
|
||
|
// to the pbEncoded parameter. The function cannot fail and
|
||
|
// returns the number of total bytes in the encoded octet string
|
||
|
//**************************************************************************
|
||
|
|
||
|
long
|
||
|
EncodeOctetString(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN BYTE const *pbStr,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
long cbLength;
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_OCTET_STRING;
|
||
|
}
|
||
|
cbLength = EncodeLength(pbEncoded, dwLen);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
CopyMemory(pbEncoded + cbLength, pbStr, dwLen);
|
||
|
}
|
||
|
return(1 + cbLength + dwLen);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeBitString ASN1 encodes a string of bit characters. The
|
||
|
// pbStr parameter is an array of characters (bits), and dwLen
|
||
|
// is the number of characters in the array. The encoded result
|
||
|
// is passed back in the pbEncoded parameter. The pbEncoded
|
||
|
// indicates if the result is to be written to the pbEncoded
|
||
|
// parameter. The function cannot fail and returns the number
|
||
|
// of total bytes in the encoded string. This function uses
|
||
|
// the DER.
|
||
|
//**************************************************************************
|
||
|
|
||
|
long
|
||
|
EncodeBitString(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN BYTE const *pbStr,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
long cbLength;
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_BIT_STRING;
|
||
|
}
|
||
|
cbLength = EncodeLength(pbEncoded, dwLen + 1);
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded += cbLength;
|
||
|
|
||
|
// the next byte tells how many unused bits there are in the last byte,
|
||
|
// but this will always be zero in this implementation (DER)
|
||
|
|
||
|
*pbEncoded++ = 0;
|
||
|
CopyMemory(pbEncoded, pbStr, dwLen);
|
||
|
}
|
||
|
return(1 + cbLength + 1 + dwLen);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EncodeFileTime
|
||
|
//
|
||
|
// Synopsis: Encodes a FILETIME to a ASN.1 format time string.
|
||
|
//
|
||
|
// Arguments: [pbEncoded] --
|
||
|
// [Time] --
|
||
|
// [UTC] -- Indicate Time is UTC (true) or local (false)
|
||
|
// [WriteFlag] --
|
||
|
//
|
||
|
// History: 8-10-95 RichardW Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
long
|
||
|
EncodeFileTime(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN FILETIME Time,
|
||
|
IN BOOL UTC)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
SYSTEMTIME st;
|
||
|
FILETIME ft;
|
||
|
int count;
|
||
|
|
||
|
if (UTC)
|
||
|
{
|
||
|
ft = Time;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LocalFileTimeToFileTime(&Time, &ft);
|
||
|
}
|
||
|
|
||
|
FileTimeToSystemTime(&ft, &st);
|
||
|
|
||
|
*pbEncoded++ = BER_UTC_TIME;
|
||
|
|
||
|
count = EncodeLength(pbEncoded, 13);
|
||
|
|
||
|
// NOTE ON Y2K COMPLIANCE: This is test tool. WE WILL NOT FIX THIS
|
||
|
// CODE! It is only used to encode current dates, anyway,
|
||
|
|
||
|
pbEncoded++;
|
||
|
st.wYear %= 100;
|
||
|
|
||
|
*pbEncoded++ = (BYTE) ((st.wYear / 10) + '0');
|
||
|
*pbEncoded++ = (BYTE) ((st.wYear % 10) + '0');
|
||
|
|
||
|
*pbEncoded++ = (BYTE) ((st.wMonth / 10) + '0');
|
||
|
*pbEncoded++ = (BYTE) ((st.wMonth % 10) + '0');
|
||
|
|
||
|
*pbEncoded++ = (BYTE) ((st.wDay / 10) + '0');
|
||
|
*pbEncoded++ = (BYTE) ((st.wDay % 10) + '0');
|
||
|
|
||
|
*pbEncoded++ = (BYTE) ((st.wHour / 10) + '0');
|
||
|
*pbEncoded++ = (BYTE) ((st.wHour % 10) + '0');
|
||
|
|
||
|
*pbEncoded++ = (BYTE) ((st.wMinute / 10) + '0');
|
||
|
*pbEncoded++ = (BYTE) ((st.wMinute % 10) + '0');
|
||
|
|
||
|
*pbEncoded++ = (BYTE) ((st.wSecond / 10) + '0');
|
||
|
*pbEncoded++ = (BYTE) ((st.wSecond % 10) + '0');
|
||
|
|
||
|
*pbEncoded = 'Z';
|
||
|
}
|
||
|
|
||
|
// Tag(1) + Len(1) + Year(2) + Month(2) + Day(2) +
|
||
|
// Hour(2) + Min(2) + Sec(2) + 'Z'(1) --> 15
|
||
|
|
||
|
return(15);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeHeader ASN1 encodes a header for a sequence type. The
|
||
|
// dwLen is the length of the encoded information in the
|
||
|
// sequence. The pbEncoded indicates if the result is to be
|
||
|
// written to the pbEncoded parameter. The function cannot
|
||
|
// fail and returns the number of total bytes in the encoded
|
||
|
// header.
|
||
|
//**************************************************************************
|
||
|
|
||
|
// Notes: Encodes header as <BER_SEQUENCE>, <length>
|
||
|
|
||
|
long
|
||
|
EncodeHeader(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_SEQUENCE;
|
||
|
}
|
||
|
return(1 + EncodeLength(pbEncoded, dwLen));
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeSetOfHeader ASN1 encodes a header for a set of type.
|
||
|
// The dwLen is the length of the encoded information in the
|
||
|
// set of. The pbEncoded indicates if the result is to be
|
||
|
// written to the pbEncoded parameter. The function cannot
|
||
|
// fail and returns the number of total bytes in the encoded
|
||
|
// header.
|
||
|
//**************************************************************************
|
||
|
|
||
|
// Notes: Encodes header as <SET_OF_TAG>, <length>
|
||
|
|
||
|
long
|
||
|
EncodeSetOfHeader(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_SET_RAW;
|
||
|
}
|
||
|
return(1 + EncodeLength(pbEncoded, dwLen));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Notes: Encodes header as <BER_OPTIONAL | 0>, <length>
|
||
|
|
||
|
long
|
||
|
EncodeAttributeHeader(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_OPTIONAL | 0;
|
||
|
}
|
||
|
return(1 + EncodeLength(pbEncoded, dwLen));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Notes: Encodes header as <BER_SET>, <length>
|
||
|
|
||
|
long
|
||
|
EncodeSetHeader(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
*pbEncoded++ = BER_SET;
|
||
|
}
|
||
|
return(1 + EncodeLength(pbEncoded, dwLen));
|
||
|
}
|
||
|
|
||
|
|
||
|
//+*************************************************************************
|
||
|
// EncodeName ASN1 encodes a Name type. The pbName parameter is
|
||
|
// the name and dwLen is the length of the name in bytes.
|
||
|
// The pbEncoded indicates if the result is to be written to
|
||
|
// the pbEncoded parameter. The function cannot fail and
|
||
|
// returns the number of total bytes in the encoded name.
|
||
|
//**************************************************************************
|
||
|
|
||
|
long
|
||
|
EncodeName(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN BYTE const *pbName,
|
||
|
IN DWORD dwLen)
|
||
|
{
|
||
|
BYTE Type[MAXOBJIDLEN];
|
||
|
long TypeLen;
|
||
|
BYTE Value[MAXNAMEVALUELEN+MINHEADERLEN];
|
||
|
long ValueLen;
|
||
|
BYTE Attribute[MAXNAMELEN];
|
||
|
long AttributeLen;
|
||
|
BYTE SetHdr[MINHEADERLEN];
|
||
|
long HdrLen;
|
||
|
long NameLen;
|
||
|
|
||
|
// encode the name value
|
||
|
ValueLen = EncodeIA5String(Value, pbName, dwLen);
|
||
|
|
||
|
// encode the attribute type, this is an object identifier and here it
|
||
|
// is a fake encoding
|
||
|
Type[0] = 0x06;
|
||
|
Type[1] = 0x01;
|
||
|
Type[2] = 0x00;
|
||
|
|
||
|
TypeLen = 3;
|
||
|
|
||
|
// encode the header for the attribute
|
||
|
AttributeLen = EncodeHeader(Attribute, ValueLen + TypeLen);
|
||
|
|
||
|
// copy the attribute type and value into the attribute
|
||
|
|
||
|
CopyMemory(Attribute + AttributeLen, Type, TypeLen);
|
||
|
AttributeLen += TypeLen;
|
||
|
|
||
|
CopyMemory(Attribute + AttributeLen, Value, ValueLen);
|
||
|
AttributeLen += ValueLen;
|
||
|
|
||
|
// encode set of header
|
||
|
|
||
|
HdrLen = EncodeSetOfHeader(SetHdr, AttributeLen);
|
||
|
|
||
|
// encode Name header
|
||
|
|
||
|
NameLen = EncodeHeader(pbEncoded, HdrLen + AttributeLen);
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
CopyMemory(pbEncoded + NameLen, SetHdr, HdrLen);
|
||
|
}
|
||
|
|
||
|
NameLen += HdrLen;
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
CopyMemory(pbEncoded + NameLen, Attribute, AttributeLen);
|
||
|
}
|
||
|
|
||
|
return(NameLen + AttributeLen);
|
||
|
}
|
||
|
|
||
|
|
||
|
long
|
||
|
EncodeRDN(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN NAMEENTRY const *pNameEntry)
|
||
|
{
|
||
|
LONG cbResult;
|
||
|
LONG Length;
|
||
|
DWORD cbOIDandData;
|
||
|
DWORD cbSequence;
|
||
|
OIDTRANSLATE const *pOidName;
|
||
|
|
||
|
// Compute the size of the encoded OID and RDN string, with BER encoding
|
||
|
// tags and lengths.
|
||
|
|
||
|
pOidName = LookupOidTranslate(pNameEntry->pszObjId);
|
||
|
cbOIDandData =
|
||
|
1 +
|
||
|
EncodeLength(NULL, pOidName->cbOIDEncoded) +
|
||
|
pOidName->cbOIDEncoded +
|
||
|
1 +
|
||
|
EncodeLength(NULL, pNameEntry->cbData) +
|
||
|
pNameEntry->cbData;
|
||
|
|
||
|
cbSequence = 1 + EncodeLength(NULL, cbOIDandData) + cbOIDandData;
|
||
|
|
||
|
Length = EncodeSetHeader(pbEncoded, cbSequence);
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded += Length;
|
||
|
}
|
||
|
|
||
|
cbResult = EncodeHeader(pbEncoded, cbOIDandData);
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded += cbResult;
|
||
|
*pbEncoded++ = BER_OBJECT_ID;
|
||
|
}
|
||
|
Length += cbResult + 1;
|
||
|
|
||
|
cbResult = EncodeLength(pbEncoded, pOidName->cbOIDEncoded);
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
pbEncoded += cbResult;
|
||
|
CopyMemory(pbEncoded, pOidName->abOIDEncoded, pOidName->cbOIDEncoded);
|
||
|
pbEncoded += pOidName->cbOIDEncoded;
|
||
|
|
||
|
*pbEncoded++ = pNameEntry->BerTag;
|
||
|
}
|
||
|
Length += cbResult + pOidName->cbOIDEncoded + 1;
|
||
|
|
||
|
cbResult = EncodeLength(pbEncoded, pNameEntry->cbData);
|
||
|
Length += cbResult;
|
||
|
|
||
|
if (NULL != pbEncoded)
|
||
|
{
|
||
|
CopyMemory(pbEncoded + cbResult, pNameEntry->pbData, pNameEntry->cbData);
|
||
|
}
|
||
|
return(Length + pNameEntry->cbData);
|
||
|
}
|
||
|
|
||
|
|
||
|
long
|
||
|
EncodeDN(
|
||
|
OPTIONAL OUT BYTE *pbEncoded,
|
||
|
IN NAMETABLE const *pNameTable)
|
||
|
{
|
||
|
CHAR *pszNext;
|
||
|
CHAR *pszRDN;
|
||
|
long Result;
|
||
|
long Length;
|
||
|
long SaveResult;
|
||
|
NAMEENTRY const *pNameEntry;
|
||
|
DWORD i;
|
||
|
|
||
|
SaveResult = 0; // force one full iteration
|
||
|
pNameEntry = pNameTable->pNameEntry;
|
||
|
Length = 0;
|
||
|
for (i = 0; i < pNameTable->cnt; i++)
|
||
|
{
|
||
|
Length += 9 + pNameEntry->cbData;
|
||
|
pNameEntry++;
|
||
|
}
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
BYTE *pb;
|
||
|
|
||
|
pb = pbEncoded;
|
||
|
|
||
|
Result = EncodeHeader(pb, Length);
|
||
|
if (SaveResult == Result)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if (NULL != pb)
|
||
|
{
|
||
|
pb += Result;
|
||
|
}
|
||
|
SaveResult = Result;
|
||
|
|
||
|
Length = 0;
|
||
|
pNameEntry = pNameTable->pNameEntry;
|
||
|
for (i = 0; i < pNameTable->cnt; i++)
|
||
|
{
|
||
|
Result = EncodeRDN(pb, pNameEntry);
|
||
|
|
||
|
if (Result < 0)
|
||
|
{
|
||
|
Length = 0;
|
||
|
goto error; // return(-1)
|
||
|
}
|
||
|
if (NULL != pb)
|
||
|
{
|
||
|
pb += Result;
|
||
|
}
|
||
|
Length += Result;
|
||
|
pNameEntry++;
|
||
|
}
|
||
|
}
|
||
|
error:
|
||
|
return(Result + Length);
|
||
|
}
|