windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/iismap/encode.c
2020-09-26 16:20:57 +08:00

1672 lines
41 KiB
C

/*-----------------------------------------------------------------------------
* Copyright (C) Microsoft Corporation, 1995 - 1996.
* All rights reserved.
*
* This file is part of the Microsoft Private Communication Technology
* reference implementation, version 1.0
*
* The Private Communication Technology reference implementation, version 1.0
* ("PCTRef"), is being provided by Microsoft to encourage the development and
* enhancement of an open standard for secure general-purpose business and
* personal communications on open networks. Microsoft is distributing PCTRef
* at no charge irrespective of whether you use PCTRef for non-commercial or
* commercial use.
*
* Microsoft expressly disclaims any warranty for PCTRef and all derivatives of
* it. PCTRef and any related documentation is provided "as is" without
* warranty of any kind, either express or implied, including, without
* limitation, the implied warranties or merchantability, fitness for a
* particular purpose, or noninfringement. Microsoft shall have no obligation
* to provide maintenance, support, upgrades or new releases to you or to anyone
* receiving from you PCTRef or your modifications. The entire risk arising out
* of use or performance of PCTRef remains with you.
*
* Please see the file LICENSE.txt,
* or http://pct.microsoft.com/pct/pctlicen.txt
* for more information on licensing.
*
* Please see http://pct.microsoft.com/pct/pct.htm for The Private
* Communication Technology Specification version 1.0 ("PCT Specification")
*
* 1/23/96
*----------------------------------------------------------------------------*/
#include <windows.h>
#define SP_ASSERT(a)
#define DebugLog(a)
#define SP_LOG_RESULT(a) (a)
#include "ber.h"
#include "encode.h"
/************************************************************/
/* 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 Writeflag 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 length. */
/************************************************************/
typedef struct __Algorithms {
DWORD Id;
UCHAR Sequence[16];
DWORD SequenceLen;
} _Algorithms;
typedef struct __CryptAlgs {
DWORD Id;
DWORD idHash;
UCHAR Sequence[16];
DWORD SequenceLen;
} _CryptAlgs;
#define iso_member 0x2a, /* iso(1) memberbody(2) */
#define us 0x86, 0x48, /* us(840) */
#define rsadsi 0x86, 0xf7, 0x0d, /* rsadsi(113549) */
#define pkcs iso_member us rsadsi 0x01, /* pkcs */
#define pkcs_len 7
#define rsa_dsi iso_member us rsadsi
#define rsa_dsi_len 6
#define joint_iso_ccitt_ds 0x55,
#define attributetype 0x04,
#define attributeType joint_iso_ccitt_ds attributetype
#define attrtype_len 2
#if 0
_Algorithms KnownSigAlgs[] = {
{PCT_SIG_RSA_MD2, {pkcs 1, 1}, pkcs_len + 2},
{PCT_SIG_RSA_MD2, {pkcs 1, 2}, pkcs_len + 2},
{PCT_SIG_RSA_MD5, {pkcs 1, 4}, pkcs_len + 2}
};
_Algorithms KnownKeyExchAlgs[] = {{PCT_EXCH_RSA_PKCS1, {pkcs 1, 1}, pkcs_len + 2},
{PCT_EXCH_RSA_PKCS1, {pkcs 1, 2}, pkcs_len + 2},
{PCT_EXCH_RSA_PKCS1, {pkcs 1, 4}, pkcs_len + 2}
};
_CryptAlgs KnownCryptAlgs[] = {
{PCT_CIPHER_RC4 | PCT_ENC_BITS_128 | PCT_MAC_BITS_128, PCT_HASH_MD5, {rsa_dsi 3, 4}, rsa_dsi_len + 2}
};
#endif
typedef struct _NameTypes {
PSTR Prefix;
UCHAR Sequence[12];
DWORD SequenceLen;
} NameTypes;
// DO NOT change the order in this table !
NameTypes KnownNameTypes[] = { {"CN=", {attributeType 3}, attrtype_len + 1},
{"C=", {attributeType 6}, attrtype_len + 1},
{"L=", {attributeType 7}, attrtype_len + 1},
{"S=", {attributeType 8}, attrtype_len + 1},
{"O=", {attributeType 10}, attrtype_len + 1},
{"OU=", {attributeType 11}, attrtype_len + 1},
{"Email=", {pkcs 9, 1}, pkcs_len + 2},
{"Name=", {pkcs 9, 2}, pkcs_len + 2},
{"Addr=", {pkcs 9, 8}, pkcs_len + 2}
};
/************************************************************/
/* DecodeLength decodes an ASN1 encoded length field. The */
/* pbEncoded parameter is the encoded length. pdwLen is */
/* used to return the length therefore the length may be no */
/* larger than 2^32. The function returns a -1 if it fails */
/* and otherwise returns the number of total bytes in the */
/* encoded length. */
/************************************************************/
long
DecodeLength(
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded)
{
long index = 0;
BYTE count;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
if(cEncoded < 1) {
DebugLog((DEB_TRACE, "cEncode overflow %d\n", cEncoded));
return(SP_LOG_RESULT(-1));
}
/* determine what the length of the length field is */
if ((count = pbEncoded[0]) > 0x80)
{
/* if there is more than one byte in the length field then */
/* the lower seven bits tells us the number of bytes */
count = count ^ 0x80;
/* this function only allows the length field to be 3 bytes */
/* if the field is longer then the function fails */
if (count > 2)
{
DebugLog((DEB_WARN, "Length field reported to be over 3 bytes\n"));
return(SP_LOG_RESULT(-1));
}
if(count > cEncoded) {
DebugLog((DEB_TRACE, "cEncode overflow %d\n", cEncoded));
return(SP_LOG_RESULT(-1));
}
*pdwLen = 0;
/* go through the bytes of the length field */
for (index = 1; index <= count; index++)
{
*pdwLen = (*pdwLen << 8) + (DWORD) (pbEncoded[index]);
}
}
/* the length field is just one byte long */
else
{
*pdwLen = (DWORD) (pbEncoded[0]);
index = 1;
}
/* return how many bytes there were in the length field */
return index;
}
#if 0
/************************************************************/
/* DecodeSigAlgid decodes an ASN1 encoded algorithm identifier.*/
/* pbEncoded parameter is the encoded identifier. pAlgid is */
/* the parameter used to return the ALG_ID type algorithm */
/* identifier. The Writeflag parameter tells the function */
/* whether to write to pAlgid or not, if TRUE write wlse */
/* don't. The function returns a -1 if it fails and */
/* otherwise returns the number of total bytes in the */
/* encoded algorithm identifier. */
/************************************************************/
long
DecodeSigAlgid(
DWORD * pAlgid,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
DWORD i;
DWORD len;
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT(pAlgid != NULL);
SP_ASSERT((!Writeflag) || (pAlgid != NULL));
if(cEncoded < 2)
{
return(SP_LOG_RESULT(-1));
}
if (*pbEncoded++ != OBJECT_ID_TAG)
{
return(SP_LOG_RESULT(-1));
}
len = *pbEncoded++;
if(cEncoded < 2 + len) return(SP_LOG_RESULT(-1));
for (i = 0; i < sizeof(KnownSigAlgs) / sizeof(_Algorithms) ; i++ )
{
if (KnownSigAlgs[i].SequenceLen == len)
{
if (memcmp(pbEncoded, KnownSigAlgs[i].Sequence, len) == 0)
{
if (Writeflag)
{
*pAlgid = KnownSigAlgs[i].Id;
}
return(len + 2);
}
}
}
return(SP_LOG_RESULT(-1));
}
/************************************************************/
/* DecodeSigAlgid decodes an ASN1 encoded algorithm identifier.*/
/* pbEncoded parameter is the encoded identifier. pAlgid is */
/* the parameter used to return the ALG_ID type algorithm */
/* identifier. The Writeflag parameter tells the function */
/* whether to write to pAlgid or not, if TRUE write wlse */
/* don't. The function returns a -1 if it fails and */
/* otherwise returns the number of total bytes in the */
/* encoded algorithm identifier. */
/************************************************************/
long
DecodeCryptAlgid(
DWORD * pAlgid,
DWORD * pHashid,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
DWORD i;
DWORD len;
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT(pAlgid != NULL);
SP_ASSERT((!Writeflag) || (pAlgid != NULL));
if(cEncoded < 2) return(SP_LOG_RESULT(-1));
if (*pbEncoded++ != OBJECT_ID_TAG)
{
return(SP_LOG_RESULT(-1));
}
len = *pbEncoded++;
if(cEncoded < 2 + len)
{
return(SP_LOG_RESULT(-1));
}
for (i = 0; i < sizeof(KnownCryptAlgs) / sizeof(_Algorithms) ; i++ )
{
if (KnownCryptAlgs[i].SequenceLen == len)
{
if (memcmp(pbEncoded, KnownCryptAlgs[i].Sequence, len) == 0)
{
if (Writeflag)
{
*pAlgid = KnownCryptAlgs[i].Id;
*pHashid = KnownCryptAlgs[i].idHash;
}
return(len + 2);
}
}
}
return(SP_LOG_RESULT(-1));
}
/************************************************************/
/* DecodeKeyExchId decodes an ASN1 encoded algorithm identifier.*/
/* pbEncoded parameter is the encoded identifier. pAlgid is */
/* the parameter used to return the ALG_ID type algorithm */
/* identifier. The Writeflag parameter tells the function */
/* whether to write to pAlgid or not, if TRUE write wlse */
/* don't. The function returns a -1 if it fails and */
/* otherwise returns the number of total bytes in the */
/* encoded algorithm identifier. */
/************************************************************/
long
DecodeKeyExchAlgid(
DWORD * pKeyId,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
DWORD i;
DWORD len;
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!Writeflag) || (pKeyId != NULL));
if(cEncoded < 2)
{
return(SP_LOG_RESULT(-1));
}
if (*pbEncoded++ != OBJECT_ID_TAG)
{
return(SP_LOG_RESULT(-1));
}
len = *pbEncoded++;
if(cEncoded < 2 + len)
{
return(SP_LOG_RESULT(-1));
}
for (i = 0; i < sizeof(KnownCryptAlgs) / sizeof(_Algorithms) ; i++ )
{
if (KnownKeyExchAlgs[i].SequenceLen == len)
{
if (memcmp(pbEncoded, KnownKeyExchAlgs[i].Sequence, len) == 0)
{
if (Writeflag)
{
*pKeyId = KnownKeyExchAlgs[i].Id;
}
return(len + 2);
}
}
}
return(SP_LOG_RESULT(-1));
}
#endif
/************************************************************/
/* DecodeHeader decodes an ASN1 encoded sequence type header.*/
/* pbEncoded parameter is the encoded header. pdwLen is */
/* the parameter used to return the length of the encoded */
/* sequence. The function returns a -1 if it fails and */
/* otherwise returns the number of total bytes in the */
/* encoded header, not including the content. */
/************************************************************/
long
DecodeHeader(
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded)
{
long len;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
if(cEncoded < 1)
{
DebugLog((DEB_TRACE, "Buffer Overflow\n"));
return(SP_LOG_RESULT(-1));
}
/* make sure this is a sequence type */
if (pbEncoded[0] != SEQUENCE_TAG)
{
DebugLog((DEB_WARN, "Sequence Tag not found, %x instead\n", pbEncoded[0]));
return(SP_LOG_RESULT(-1));
}
/* decode the length */
if ((len = DecodeLength (pdwLen, pbEncoded + 1, cEncoded-1)) == -1)
{
DebugLog((DEB_TRACE, "Bad Length Decode\n"));
return(SP_LOG_RESULT(-1));
}
return (len + 1);
}
/************************************************************/
/* DecodeSetOfHeader decodes an ASN1 encoded set of type */
/* header. pbEncoded parameter is the encoded header. pdwLen*/
/* is the parameter used to return the length of the encoded*/
/* set of. The function returns a -1 if it fails and */
/* otherwise returns the number of total bytes in the */
/* encoded header, not including the content. */
/************************************************************/
long
DecodeSetOfHeader(
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded)
{
long len;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
/* make sure this is a sequence type */
if (*pbEncoded != SET_OF_TAG)
{
return(SP_LOG_RESULT(-1));
}
/* decode the length */
if ((len = DecodeLength (pdwLen, pbEncoded + 1, cEncoded-1)) == -1)
return(-1);
return (len + 1);
}
long
DecodeSetHeader(
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded)
{
long len;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
if (*pbEncoded != BER_SET)
{
return(SP_LOG_RESULT(-1));
}
if((len = DecodeLength(pdwLen, pbEncoded + 1, cEncoded-1)) == -1)
{
return(-1);
}
return(len + 1);
}
/****************************************************************/
/* DecodeInteger decodes an ASN1 encoded integer. The encoded */
/* integer is passed into the function with the pbEncoded */
/* parameter. The pbInt parameter is used to pass back the */
/* integer as an array of bytes, and dwLen is the number of */
/* in the array. The least significant byte of the integer */
/* is the zeroth byte of the array. The Writeflag indicates */
/* indicates if the result is to be written to the pbInt */
/* parameter. The function returns a -1 if it fails and */
/* otherwise returns the number of total bytes in the encoded */
/* integer. */
/* This implementation will only deal with positive integers. */
/****************************************************************/
long
DecodeInteger(
BYTE * pbInt,
DWORD cbBuff,
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
long count;
long i;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!Writeflag) || (pbInt != NULL));
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
/* make sure this is tagged as an integer */
if (pbEncoded[0] != INTEGER_TAG)
{
return(SP_LOG_RESULT(-1));
}
count = 1;
/* decode the length field */
if ((i = DecodeLength (pdwLen, pbEncoded + 1, cEncoded-count)) == -1)
{
return(-1);
}
count += i;
if(cEncoded < count+*pdwLen)
{
return(SP_LOG_RESULT(-1));
}
/* write the integer out if suppose to */
if (Writeflag)
{
if (pbEncoded[count] == 0)
{
count++;
(*pdwLen)--;
}
if(*pdwLen > cbBuff) return -1;
i = (*pdwLen) - 1;
while (i >= 0)
{
pbInt[i--] = pbEncoded[count++];
}
}
else
{
count += (long) *pdwLen;
}
/* return the length of the encoded integer */
return (count);
}
/****************************************************************/
/* DecodeString decodes an ASN1 encoded a character string. The*/
/* encoded string is passed into the function with the pbEncoded*/
/* parameter. The pbStr is used to pass the decoded string back*/
/* to the caller, and pdwLen is the number of characters in the */
/* decoded array. The Writeflag indicates if the result is to */
/* be written to the pbStr parameter. The function returns a */
/* -1 if it fails and otherwise returns the number of bytes in */
/* the encoded string. */
/****************************************************************/
long
DecodeString(
BYTE * pbStr,
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
long index;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!Writeflag) || (pbStr != NULL));
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
if ((*pbEncoded != BER_PRINTABLE_STRING) &&
(*pbEncoded != BER_TELETEX_STRING) &&
(*pbEncoded != BER_GRAPHIC_STRING) &&
(*pbEncoded != BER_IA5STRING))
{
return(SP_LOG_RESULT(-1));
}
/* determine how long the string is */
if ((index = DecodeLength (pdwLen, pbEncoded + 1, cEncoded-1)) == -1)
{
return(-1);
}
index++;
if(cEncoded < index + *pdwLen)
{
return(SP_LOG_RESULT(-1));
}
if (Writeflag)
{
CopyMemory(pbStr, pbEncoded + index, *pdwLen);
}
return (index + *pdwLen);
}
/****************************************************************/
/* DecodeOctetString decodes an ASN1 encoded a octet string. The*/
/* encoded string is passed into the function with the pbEncoded*/
/* parameter. The pbStr is used to pass the decoded string back*/
/* to the caller, and pdwLen is the number of characters in the */
/* decoded array. The Writeflag indicates if the result is to */
/* be written to the pbStr parameter. The function returns a */
/* -1 if it fails and otherwise returns the number of bytes in */
/* the encoded string. */
/****************************************************************/
long
DecodeOctetString(
BYTE * pbStr,
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
long index;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!Writeflag) || (pbStr != NULL));
if(cEncoded < 1)
{
DebugLog((DEB_TRACE, "cEncoded Overflow:%d\n", cEncoded));
return(SP_LOG_RESULT(-1));
}
if (pbEncoded[0] != OCTET_STRING_TAG)
{
DebugLog((DEB_TRACE, "Invalid Tag, expected OCTET_STRING, got %d\n", pbEncoded[0]));
return(SP_LOG_RESULT(-1));
}
/* determine how long the string is */
if ((index = DecodeLength (pdwLen, pbEncoded + 1, cEncoded-1)) == -1)
{
return(-1);
}
index++;
if(cEncoded < index+*pdwLen)
{
return(SP_LOG_RESULT(-1));
}
if (Writeflag)
{
CopyMemory(pbStr, pbEncoded + index, *pdwLen);
}
return (index + *pdwLen);
}
/****************************************************************/
/* DecodeBitString decodes an ASN1 encoded a bit string. The */
/* encoded string is passed into the function with the pbEncoded*/
/* parameter. The pbStr is used to pass the decoded string back*/
/* to the caller, and pdwLen is the number of characters in the */
/* decoded array. The Writeflag indicates if the result is to */
/* be written to the pbStr parameter. The function returns a */
/* -1 if it fails and otherwise returns the number of bytes in */
/* the encoded string. The DER are used in the decoding. */
/****************************************************************/
long
DecodeBitString(
BYTE * pbStr,
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
long index;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!Writeflag) || (pbStr != NULL));
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
if (pbEncoded[0] != BIT_STRING_TAG)
{
return(SP_LOG_RESULT(-1));
}
/* determine how long the string is */
if ((index = DecodeLength (pdwLen, pbEncoded + 1, cEncoded-1)) == -1)
{
return(-1);
}
/* move the index up two bytes, one for the tag and one for the byte after */
/* the length which tells the number of unused bits in the last byte, that */
/* byte is always zero in this implementation, so it is ignored */
index += 2;
/* subtract one from the length of the bit string (in bytes) since, */
/* to account for the byte after the length */
(*pdwLen)--;
if(cEncoded < index + *pdwLen)
{
return(SP_LOG_RESULT(-1));
}
if (Writeflag)
{
CopyMemory(pbStr, pbEncoded + index, *pdwLen);
}
return (index + *pdwLen);
}
#if 0
#ifdef SECURITY_LINUX
/****************************************************************/
/* DecodeUTCTime decodes an ASN1 encoded Universal time type. */
/* time type. The Time parameter is the time passed into the */
/* function as a time_t type. The encoded result is passed back*/
/* in the pbEncoded parameter. The Writeflag 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 universal time. */
/****************************************************************/
long
DecodeUTCTime(time_t *pTime, BYTE *pbEncoded, DWORD cEncoded, BOOL Writeflag)
{
long count;
struct tm tmTime;
DWORD dwLen;
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!Writeflag) || (pTime != NULL));
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
/* check to make sure this is a universal time type */
if (pbEncoded[0] != UTCTIME_TAG)
{
return(SP_LOG_RESULT(-1));
}
/* decode the length */
if ((count = DecodeLength (&dwLen, pbEncoded + 1, cEncoded-1)) == -1)
{
return -1;
}
count++;
dwLen += count;
if(cEncoded < dwLen)
{
return(SP_LOG_RESULT(-1));
}
if (Writeflag)
{
/* extract the year */
tmTime.tm_year = (int)((pbEncoded[count] - 0x30) * 0xA
+ (pbEncoded[count + 1] - 0x30));
count += 2;
/* extract the month */
tmTime.tm_mon = (int)((pbEncoded[count] - 0x30) * 0xA
+ (pbEncoded[count + 1] - 0x30));
count += 2;
/* extract the day */
tmTime.tm_mday = (int)((pbEncoded[count] - 0x30) * 0xA
+ (pbEncoded[count + 1] - 0x30));
count += 2;
/* extract the hour */
tmTime.tm_hour = (int)((pbEncoded[count] - 0x30) * 0xA
+ (pbEncoded[count + 1] - 0x30));
count += 2;
/* extract the minutes */
tmTime.tm_min = (int)((pbEncoded[count] - 0x30) * 0xA
+ (pbEncoded[count + 1] - 0x30));
count += 2;
/* extract the seconds */
tmTime.tm_sec = (int)((pbEncoded[count] - 0x30) * 0xA
+ (pbEncoded[count + 1] - 0x30));
count += 2;
/* make sure there is a Z at the end */
if (pbEncoded[count] != 'Z')
{
return(SP_LOG_RESULT(-1));
}
*pTime = mktime (&tmTime);
}
return (long)dwLen;
}
#else /* SECURITY_LINUX */
long
DecodeFileTime(
FILETIME * pTime,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL WriteFlag)
{
LONGLONG ft;
LONGLONG delta;
SYSTEMTIME st;
long count;
DWORD dwLen, dwTotalLen;
BOOL fUTC;
int Offset;
SP_ASSERT(pTime != NULL);
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!WriteFlag) || (pTime != NULL));
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
/* check to make sure this is a universal time type */
if (pbEncoded[0] != UTCTIME_TAG)
{
return(SP_LOG_RESULT(-1));
}
/* decode the length */
if ((count = DecodeLength (&dwLen, pbEncoded + 1, cEncoded-1)) == -1)
{
return(-1);
}
count++;
dwTotalLen = dwLen + count;
if(cEncoded < dwLen)
{
return(SP_LOG_RESULT(-1));
}
pbEncoded += count;
if (WriteFlag)
{
st.wYear = (WORD) ((pbEncoded[0] - '0') * 10) +
(pbEncoded[1] - '0');
if (st.wYear < 90)
{
st.wYear += 2000;
}
else
{
st.wYear += 1900;
}
pbEncoded += 2;
dwLen -= 2;
st.wMonth = (WORD) ((pbEncoded[0] - '0') * 10) +
(pbEncoded[1] - '0');
pbEncoded += 2;
dwLen -= 2;
st.wDay = (WORD) ((pbEncoded[0] - '0') * 10) +
(pbEncoded[1] - '0');
pbEncoded += 2;
dwLen -= 2;
st.wHour = (WORD) ((pbEncoded[0] - '0') * 10) +
(pbEncoded[1] - '0');
pbEncoded += 2;
dwLen -= 2;
st.wMinute = (WORD) ((pbEncoded[0] - '0') * 10) +
(pbEncoded[1] - '0');
pbEncoded += 2;
dwLen -= 2;
fUTC = FALSE;
Offset = 0;
st.wSecond = 0;
if (dwLen)
{
//
// Ok, still more to go:
//
if (*pbEncoded == 'Z')
{
DebugLog((DEB_TRACE, "FileTime: no seconds, Z term\n"));
//
// Ok, it is UTC.
//
dwLen++;
pbEncoded++;
}
else
{
if ((*pbEncoded == '+') ||
(*pbEncoded == '-') )
{
DebugLog((DEB_TRACE, "FileTime: no seconds, offset\n"));
//
// Yuck! Offset encoded!
//
if (dwLen != 5)
{
return( -1 );
}
Offset = (int) ((pbEncoded[1] - '0') * 10) +
(pbEncoded[2] - '0');
Offset *= 60;
Offset += (int) ((pbEncoded[3] - '0') * 10) +
(pbEncoded[4] - '0');
if (pbEncoded[0] == '-')
{
Offset *= -1;
}
}
else
{
st.wSecond = (WORD) ((pbEncoded[0] - '0') * 10) +
(pbEncoded[1] - '0');
if (dwLen == 3)
{
if (pbEncoded[2] != 'Z')
{
return( -1 );
}
}
else if (dwLen > 3)
{
Offset = (int) ((pbEncoded[3] - '0') * 10) +
(pbEncoded[4] - '0');
Offset *= 60;
Offset += (int) ((pbEncoded[5] - '0') * 10) +
(pbEncoded[6] - '0');
if (pbEncoded[2] == '-')
{
Offset *= -1;
}
}
}
}
}
st.wMilliseconds = 0;
SystemTimeToFileTime(&st, (FILETIME *) &ft);
if (Offset != 0)
{
delta = (LONGLONG) Offset * 10000000;
ft += delta;
}
*pTime = *((FILETIME *) &ft);
}
return(dwTotalLen);
}
#endif / * SECURITY_LINUX */
#endif
/****************************************************************/
/* DecodeName decodes an ASN1 encoded Name type. The encoded */
/* name is passed into the function with the pbEncoded parameter*/
/* The pbName parameter is used to pass the name back to the */
/* caller and pdwLen is the length of the name in bytes. */
/* The Writeflag indicates if the result is to be written to */
/* the pbName parameter. The function returns a -1 if it */
/* fails and otherwise returns the number of total bytes in the */
/* encoded name. */
/****************************************************************/
long
DecodeName(
BYTE * pbName,
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag)
{
long index;
DWORD dwLen;
SP_ASSERT(pdwLen != NULL);
SP_ASSERT(pbEncoded != NULL);
SP_ASSERT((!Writeflag) || (pbName != NULL));
/* decode the sequence header */
if ((index = DecodeHeader (&dwLen, pbEncoded, cEncoded)) == -1)
{
return(-1);
}
/* decode the set of header */
if ((index += DecodeSetOfHeader (&dwLen, pbEncoded + index, cEncoded-index)) < index)
{
return(-1);
}
/* decode the sequence header */
if ((index += DecodeHeader (&dwLen, pbEncoded + index, cEncoded-index)) < index)
{
return(-1);
}
/* decode the attribute type, in this implementation it is fake */
index += 3; /* 3 because this is the length of the fake OBJECT IDENTIFIER */
/* decode the string which is the name */
if ((index += DecodeString (pbName, pdwLen, pbEncoded + index, cEncoded-index, Writeflag)) < index)
{
return(-1);
}
return index;
}
long
DecodeNull(
BYTE * pbEncoded, DWORD cEncoded)
{
SP_ASSERT(pbEncoded != NULL);
if(cEncoded < 2) return(SP_LOG_RESULT(-1));
if (*pbEncoded != NULL_TAG)
{
return(SP_LOG_RESULT(-1));
}
return(2);
}
long
IisDecodeNameType(
int * piPrefix,
BYTE * pbEncoded,
DWORD cEncoded)
{
DWORD i;
DWORD len;
SP_ASSERT(piPrefix != NULL);
SP_ASSERT(pbEncoded != NULL);
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
if (*pbEncoded != OBJECT_ID_TAG)
{
return(SP_LOG_RESULT(-1));
}
pbEncoded++;
len = *pbEncoded++;
if(cEncoded < len+2)
{
return(SP_LOG_RESULT(-1));
}
for (i = 0; i < sizeof(KnownNameTypes) / sizeof(NameTypes) ; i++ )
{
if (KnownNameTypes[i].SequenceLen == len)
{
if (memcmp(pbEncoded, KnownNameTypes[i].Sequence, len) == 0)
{
*piPrefix = i;
return(len + 2);
}
}
}
*piPrefix = -1;
return len + 2;
}
long
IisDecodeRDN(
PSTR *pValue,
PSTR pBuf,
DWORD * pdwComponentLength,
BYTE * pbEncoded,
DWORD cEncoded
)
{
long index;
DWORD dwLen;
long CompLen = 0;
long Processed;
long RdnLen;
BOOL fTmpWrite;
PSTR pName;
int iPrefixType;
index = DecodeSetHeader(&RdnLen, pbEncoded, cEncoded);
if (index == -1)
{
return(-1);
}
Processed = RdnLen + index;
pbEncoded += index;
if (0 != RdnLen)
for (;;)
{
index = DecodeHeader(&dwLen, pbEncoded, RdnLen);
if (index < 0)
return(-1);
RdnLen -= index;
pbEncoded += index;
index = IisDecodeNameType(&iPrefixType, pbEncoded, RdnLen);
if (index < 0)
{
return(-1);
}
RdnLen -= index;
pbEncoded += index;
switch ( iPrefixType )
{
case 0: // CN
pValue[3] = pBuf;
fTmpWrite = TRUE;
break;
case 1: // C
pValue[2] = pBuf;
fTmpWrite = TRUE;
break;
case 4: // O
pValue[0] = pBuf;
fTmpWrite = TRUE;
break;
case 5: // OU
pValue[1] = pBuf;
fTmpWrite = TRUE;
break;
default:
pName = NULL;
fTmpWrite = FALSE;
}
index = DecodeString((PUCHAR)pBuf, &dwLen, pbEncoded, RdnLen, fTmpWrite);
if (index < 0)
{
return(-1);
}
pBuf[dwLen] = '\0';
CompLen += dwLen + 1;
pBuf += dwLen + 1;
RdnLen -= index;
pbEncoded += index;
if (0 < RdnLen)
{
}
else
{
break;
}
}
*pdwComponentLength = CompLen;
return Processed;
}
long
IisDecodeDN(
PSTR pValue[],
PSTR pBuf,
BYTE * pbEncoded,
DWORD cEncoded
)
{
long index;
DWORD dwLen;
long TotalNameLength;
DWORD ComponentLength;
DWORD NameLength;
long EncodedNameLength;
index = DecodeHeader(&dwLen, pbEncoded, cEncoded);
if (index == -1)
{
return(-1);
}
EncodedNameLength = index + dwLen;
TotalNameLength = dwLen;
NameLength = 0;
while (TotalNameLength > 0)
{
pbEncoded += index;
index = IisDecodeRDN( pValue,
pBuf + NameLength,
&ComponentLength,
pbEncoded,
cEncoded - index
);
if (index == -1)
return(-1);
// if (WriteFlag)
// pName += ComponentLength;
TotalNameLength -= index;
NameLength += ComponentLength;
#if 0
if ((TotalNameLength > 0) && (0 < ComponentLength))
{
if (WriteFlag)
{
*pName++ = ',';
*pName++ = ' ';
}
NameLength += 2;
}
else if ((TotalNameLength <= 0)
&& (0 == ComponentLength)
&& (0 < NameLength))
{
//
// The last RDN didn't produce any output, so we need to
// roll back that ", " we put on previously.
//
if (WriteFlag)
pName -= 2;
NameLength -= 2;
}
#endif
}
//*pdwLen = NameLength;
return(EncodedNameLength);
}
#if 0
long
DecodeSigAlg(
DWORD * pAlgId,
PBYTE pbEncoded,
DWORD cEncoded,
BOOL WriteFlag)
{
long Result;
DWORD dwLen;
long index;
index = DecodeHeader( &dwLen, pbEncoded, cEncoded);
if (index == -1)
{
return(-1);
}
Result = DecodeSigAlgid( pAlgId,
pbEncoded+index,
cEncoded - index,
WriteFlag );
if (Result == -1)
{
return(-1);
}
index += Result;
Result = DecodeNull(pbEncoded + index, cEncoded - index);
if (Result == -1)
{
return(-1);
}
return(index + Result);
}
long
DecodeCryptAlg(
DWORD * pAlgId,
DWORD * pHashid,
PBYTE pbEncoded,
DWORD cEncoded,
BOOL WriteFlag)
{
long Result;
DWORD dwLen;
long index;
index = DecodeHeader( &dwLen, pbEncoded, cEncoded);
if (index == -1)
{
return(-1);
}
Result = DecodeCryptAlgid(pAlgId, pHashid,
pbEncoded+index,
cEncoded - index,
WriteFlag );
if (Result == -1)
{
return(-1);
}
index += Result;
Result = DecodeNull(pbEncoded + index, cEncoded - index);
if (Result == -1)
{
return(-1);
}
return(index + Result);
}
long
DecodeKeyType(
DWORD * pKeyType,
PBYTE pbEncoded,
DWORD cEncoded,
BOOL WriteFlag)
{
long Result;
DWORD dwLen;
long index;
index = DecodeHeader( &dwLen, pbEncoded, cEncoded);
if (index == -1)
{
return(-1);
}
Result = DecodeKeyExchAlgid(pKeyType,
pbEncoded+index,
cEncoded - index,
WriteFlag );
if (Result == -1)
{
return(-1);
}
index += Result;
Result = DecodeNull(pbEncoded + index, cEncoded - index);
if (Result == -1)
{
return(-1);
}
return(index + Result);
}
#endif
#if 0
long
DecryptOctetString(
DWORD * pdwLen,
BYTE * pbEncoded,
DWORD cEncoded,
BOOL Writeflag,
PSTR pszPassword)
{
long index, Result;
CipherSpec CryptId;
HashSpec HashId;
SPBuffer Input, Output;
PCryptoSystem pCipher;
PCheckSumFunction pHash;
if(cEncoded < 1)
{
return(SP_LOG_RESULT(-1));
}
/* Figure out what crypto alg and pasword has we are using. */
index = DecodeCryptAlg( &CryptId, &HashId, pbEncoded, cEncoded, TRUE );
if (index == -1)
{
return(-1);
}
pCipher = CipherFromSpec(CryptId);
if(pCipher == NULL)
{
return(SP_LOG_RESULT(-1));
}
pHash = HashFromSpec(HashId);
if(pHash == NULL)
{
return(SP_LOG_RESULT(-1));
}
if (*(pbEncoded + index) != OCTET_STRING_TAG)
{
return ( -1 );
}
index++;
/* determine how long the string is */
if ((Result = DecodeLength (pdwLen, pbEncoded + index, cEncoded-index)) == -1)
if (Result == -1)
{
return(-1);
}
index += Result;
if(cEncoded < (index + *pdwLen))
{
return(SP_LOG_RESULT(-1));
}
if (Writeflag)
{
HashBuf SumBuff, Buff;
PStateBuffer pState;
PCheckSumBuffer Sum = (PCheckSumBuffer)SumBuff;
pHash->Initialize(Sum,0);
pHash->Sum(Sum, lstrlen(pszPassword), (PUCHAR)pszPassword);
pHash->Finalize(Sum, Buff);
Input.pvBuffer = Output.pvBuffer = pbEncoded+index;
Input.cbBuffer = Output.cbBuffer = *pdwLen;
Input.cbData = Output.cbData = *pdwLen;
pCipher->Initialize(Buff, pHash->cbCheckSum, &pState);
pCipher->Decrypt(pState, &Input, &Output);
pCipher->Discard(&pState);
}
return (index);
}
long
DecodePrivateKeyFile(
PctPrivateKey * * ppKey,
PBYTE pbEncoded,
DWORD cEncoded,
PSTR Password )
{
DWORD dwLen;
long Result;
long index;
DWORD KeyId;
DWORD Version;
KeyExchangeSystem *pSys = NULL;
index = 0;
SP_BEGIN("DecodePrivateKeyFile");
Result = DecodeHeader( &dwLen, pbEncoded , cEncoded);
if (Result == -1)
{
SP_RETURN(-1);
}
index += Result;
Result = DecodeOctetString( NULL, &dwLen, pbEncoded+ index, cEncoded-index, FALSE );
if (Result == -1)
{
SP_RETURN(-1);
}
index += Result;
Result = DecodeHeader( &dwLen, pbEncoded +index, cEncoded-index);
if (Result == -1)
{
SP_RETURN(-1);
}
index += Result;
/* Now, the next item should be an octet string, which is encrypted */
/* with the password above. So, we need to skip into it, decrypt it, */
/* then treat it as a constructed type: */
Result = DecryptOctetString(&dwLen,
pbEncoded+index,
cEncoded-index,
TRUE,
Password);
if (Result == -1)
{
SP_RETURN(-1);
}
index += Result;
/* The moment of truth */
Result = DecodeHeader( &dwLen, pbEncoded+index, cEncoded-index );
if (Result == -1)
{
SP_RETURN(-1);
}
index += Result;
Version = 0;
Result = DecodeInteger( (PUCHAR) &Version, sizeof(Version), &dwLen, pbEncoded+index, cEncoded-index, FALSE );
if ((Result < 0) || ( dwLen > 4 ) )
{
SP_RETURN(SP_LOG_RESULT(-1));
}
Result = DecodeInteger( (PUCHAR) &Version, sizeof(Version), &dwLen, pbEncoded+index, cEncoded-index, TRUE );
if (Result == -1 || Version != 0)
{
SP_RETURN(SP_LOG_RESULT(-1));
}
index += Result;
Result = DecodeKeyType( &KeyId, pbEncoded+index, cEncoded-index, TRUE );
if (Result == -1)
{
SP_RETURN(-1);
}
index += Result;
/* This is now the serialized rsa key. */
if (*(pbEncoded+index) != OCTET_STRING_TAG)
{
SP_RETURN(SP_LOG_RESULT(-1));
}
index ++;
Result = DecodeLength( &dwLen, pbEncoded+index, cEncoded-index );
if (Result == -1)
{
SP_RETURN(-1);
}
if(index + dwLen > cEncoded)
{
SP_RETURN(SP_LOG_RESULT(-1));
}
index += Result;
/* The sequence is the key... */
pSys = KeyExchangeFromSpec(KeyId);
if(pSys == NULL)
{
SP_RETURN(SP_LOG_RESULT(-1));
}
index += pSys->DecodePrivate(pbEncoded+index, cEncoded-index, ppKey);
SP_RETURN(index);
}
#endif