|
|
/*-----------------------------------------------------------------------------
* 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
|