|
|
/*-----------------------------------------------------------------------------
* 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 <spbase.h>
#include <ber.h>
typedef struct __EncAlgs { DWORD Id; UCHAR Sequence[16]; DWORD SequenceLen; } _EncAlgs;
#define iso_member 0x2a, /* iso(1) memberbody(2) */
#define us 0x86, 0x48, /* us(840) */
#define rsadsi 0x86, 0xf7, 0x0d, /* rsadsi(113549) */
#define pkcs 0x01, /* pkcs(1) */
#define pkcs_1 iso_member us rsadsi 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
_EncAlgs EncKnownAlgs[] = { {ALGTYPE_SIG_RSA_MD5, {pkcs_1 1, 4}, pkcs_len + 2}, {ALGTYPE_KEYEXCH_RSA_MD5, {pkcs_1 1, 1}, pkcs_len + 2}, {ALGTYPE_CIPHER_RC4_MD5, {rsa_dsi 3, 4}, rsa_dsi_len + 2}, {ALGTYPE_KEYEXCH_DH, {pkcs_1 3, 1}, pkcs_len + 2}, };
typedef struct _NameTypes { PSTR Prefix; DWORD PrefixLen; UCHAR Sequence[8]; DWORD SequenceLen; } NameTypes;
#define CNTYPE_INDEX 0
NameTypes EncKnownNameTypes[] = { {"CN=", 3, {attributeType 3}, attrtype_len + 1}, {"C=", 2, {attributeType 6}, attrtype_len + 1}, {"L=", 2, {attributeType 7}, attrtype_len + 1}, {"S=", 2, {attributeType 8}, attrtype_len + 1}, {"O=", 2, {attributeType 10}, attrtype_len + 1}, {"OU=", 3, {attributeType 11}, attrtype_len + 1} };
/************************************************************/ /* 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 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( BYTE * pbEncoded, DWORD dwLen, BOOL Writeflag) { // length is between 2^8 and 2^16 - 1
if (dwLen > 0xFF) { if (Writeflag) { 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 (Writeflag) { pbEncoded[0] = 0x81; pbEncoded[1] = (BYTE) dwLen; } return (2); }
// length is between 0 and 2^7 - 1
if (Writeflag) { pbEncoded[0] = (BYTE) dwLen; } return (1); }
/****************************************************************/ /* 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 Writeflag */ /* 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( BYTE *pbEncoded, BYTE *pbInt, DWORD dwLen, BOOL Writeflag) { DWORD i; long j; // Must be signed!
BYTE *pb = pbEncoded;
if (Writeflag) { *pb = INTEGER_TAG; } pb++;
/* find the most significant non-zero byte */
for (i = dwLen - 1; pbInt[i] == 0; i--) { if (i == 0) /* if the integer value is 0 */ { if (Writeflag) { pb[0] = 0x01; pb[1] = 0x00; } return(3); } }
/* if the most significant bit of the most sig byte is set */ /* then need to add a 0 byte to the beginning. */
if (pbInt[i] > 0x7F) { /* encode the length */ pb += EncodeLength(pb, i + 2, Writeflag);
if (Writeflag) { /* set the first byte of the integer to 0 and increment pointer */ *pb = 0; } pb++; } else { /* encode the length */ pb += EncodeLength(pb, i + 1, Writeflag); }
/* copy the integer bytes into the encoded buffer */ if (Writeflag) { /* copy the integer bytes into the encoded buffer */ for (j = i; j >= 0; j--) { *pb++ = pbInt[j]; } } else { pb += i; } return (long)(pb - pbEncoded); }
/****************************************************************/ /* EncodeString 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 Writeflag */ /* 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 EncodeString( BYTE * pbEncoded, BYTE * pbStr, DWORD dwLen, BOOL Writeflag) { long lengthlen;
if (Writeflag) { *pbEncoded++ = CHAR_STRING_TAG; } lengthlen = EncodeLength(pbEncoded, dwLen, Writeflag);
if (Writeflag) { CopyMemory(pbEncoded + lengthlen, pbStr, dwLen); } return(1 + lengthlen + 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*/ /* Writeflag 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( BYTE * pbEncoded, BYTE * pbStr, DWORD dwLen, BOOL Writeflag) { long lengthlen;
if (Writeflag) { *pbEncoded++ = OCTET_STRING_TAG; } lengthlen = EncodeLength(pbEncoded, dwLen, Writeflag);
if (Writeflag) { CopyMemory(pbEncoded + lengthlen, pbStr, dwLen); } return(1 + lengthlen + 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 Writeflag */ /* 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( BYTE * pbEncoded, BYTE * pbStr, DWORD dwLen, BOOL Writeflag) { long lengthlen;
if (Writeflag) { *pbEncoded++ = BIT_STRING_TAG; }
lengthlen = EncodeLength(pbEncoded, dwLen + 1, Writeflag);
if (Writeflag) { pbEncoded += lengthlen;
// 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 + lengthlen + 1 + (long) dwLen); }
/****************************************************************/ /* EncodeHeader ASN1 encodes a header for a sequence type. The */ /* dwLen is the length of the encoded information in the */ /* sequence. The Writeflag 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 <SEQUENCE_TAG>, <length>
long EncodeHeader( BYTE * pbEncoded, DWORD dwLen, BOOL Writeflag) { if (Writeflag) { *pbEncoded++ = SEQUENCE_TAG; } return(1 + EncodeLength(pbEncoded, dwLen, Writeflag)); }
/****************************************************************/ /* EncodeSetOfHeader ASN1 encodes a header for a set of type. */ /* The dwLen is the length of the encoded information in the */ /* set of. The Writeflag 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( BYTE * pbEncoded, DWORD dwLen, BOOL Writeflag) { if (Writeflag) { *pbEncoded++ = SET_OF_TAG; } return(1 + EncodeLength(pbEncoded, dwLen, Writeflag)); }
// Notes: Encodes header as <ATTRIBUTE_TAG>, <length>
long EncodeAttributeHeader( BYTE * pbEncoded, DWORD dwLen, BOOL Writeflag) { if (Writeflag) { *pbEncoded++ = ATTRIBUTE_TAG; } return(1 + EncodeLength(pbEncoded, dwLen, Writeflag)); }
// Notes: Encodes header as <BER_SET>, <length>
long EncodeSetHeader( BYTE * pbEncoded, DWORD dwLen, BOOL WriteFlag) { if (WriteFlag) { *pbEncoded++ = BER_SET; } return(1 + EncodeLength(pbEncoded, dwLen, WriteFlag)); }
/****************************************************************/ /* EncodeName ASN1 encodes a Name type. The pbName parameter is */ /* the name and dwLen is the length of the name in bytes. */ /* The Writeflag 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( BYTE * pbEncoded, BYTE * pbName, DWORD dwLen, BOOL Writeflag) { 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 = EncodeString(Value, pbName, dwLen, Writeflag); SP_ASSERT(ValueLen > 0 && ValueLen <= sizeof(Value));
/* 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;
/* enocde the header for the attribute */ AttributeLen = EncodeHeader( Attribute, (DWORD) (ValueLen + TypeLen), Writeflag); SP_ASSERT(AttributeLen > 0); SP_ASSERT(AttributeLen + TypeLen + ValueLen <= sizeof(Attribute));
/* copy the attribute type and value into the attribute */ CopyMemory(Attribute + AttributeLen, Type, (size_t) TypeLen); AttributeLen += TypeLen; CopyMemory(Attribute + AttributeLen, Value, (size_t) ValueLen); AttributeLen += ValueLen;
/* encode set of header */ HdrLen = EncodeSetOfHeader(SetHdr, (DWORD) AttributeLen, Writeflag); SP_ASSERT(HdrLen > 0 && HdrLen <= sizeof(SetHdr));
/* encode Name header */ NameLen = EncodeHeader( pbEncoded, (DWORD) (HdrLen + AttributeLen), Writeflag); SP_ASSERT(NameLen > 0);
CopyMemory(pbEncoded + NameLen, SetHdr, (size_t) HdrLen); NameLen += HdrLen; CopyMemory(pbEncoded + NameLen, Attribute, (size_t) AttributeLen);
return(NameLen + AttributeLen); }
long EncodeRDN( BYTE * pbEncoded, PSTR pszRDN, BOOL WriteFlag) { LONG Result; DWORD RelLength; long Length; NameTypes *pNameType; char ach[4];
SP_ASSERT(pszRDN != NULL); if (pszRDN[0] == '\0' || pszRDN[1] == '\0' || pszRDN[2] == '\0' || (pszRDN[1] != '=' && pszRDN[2] != '=')) { return(-1); } ach[0] = pszRDN[0]; ach[1] = pszRDN[1]; if (ach[1] == '=') { ach[2] = '\0'; } else { ach[2] = pszRDN[2]; ach[3] = '\0'; }
for (pNameType = EncKnownNameTypes; ; pNameType++) { if (pNameType == &EncKnownNameTypes[sizeof(EncKnownNameTypes) / sizeof(EncKnownNameTypes[0])]) { return(-1); } SP_ASSERT(lstrlen(pNameType->Prefix) < sizeof(ach)); if (lstrcmpi(ach, pNameType->Prefix) == 0) { break; } }
RelLength = lstrlen(&pszRDN[pNameType->PrefixLen]);
// Prefix data takes up 9 bytes
Length = EncodeSetHeader(pbEncoded, RelLength + 9, WriteFlag); pbEncoded += Length;
Result = EncodeHeader(pbEncoded, RelLength + 7, WriteFlag); pbEncoded += Result; Length += Result + 2 + pNameType->SequenceLen;
if (WriteFlag) { *pbEncoded++ = OBJECT_ID_TAG; *pbEncoded++ = (BYTE) pNameType->SequenceLen;
CopyMemory(pbEncoded, pNameType->Sequence, pNameType->SequenceLen); pbEncoded += pNameType->SequenceLen;
*pbEncoded++ = pNameType == &EncKnownNameTypes[CNTYPE_INDEX]? TELETEX_STRING_TAG : PRINTABLE_STRING_TAG;
} Length++;
Result = EncodeLength(pbEncoded, RelLength, WriteFlag); Length += Result;
if (WriteFlag) { CopyMemory( pbEncoded + Result, &pszRDN[pNameType->PrefixLen], RelLength); } return(Length + RelLength); }
long EncodeDN( BYTE * pbEncoded, PSTR pszDN, BOOL WriteFlag) { PSTR pszRDN; long Result = 0; long Length; long SaveResult;
SP_ASSERT(pszDN != NULL);
SaveResult = 0; // force one full iteration
Length = 2 * lstrlen(pszDN); // your guess is as good as mine
while (TRUE) { PSTR pszNext; BYTE *pb;
pb = pbEncoded;
Result = EncodeHeader(pb, Length, WriteFlag); if (SaveResult == Result) { break; } pb += Result; SaveResult = Result;
Length = 0; pszRDN = pszDN; while (*pszRDN != '\0') { for (pszNext = pszRDN; ; pszNext++) { if (*pszNext == ',') { *pszNext = '\0'; break; } if (*pszNext == '\0') { pszNext = NULL; break; } }
Result = EncodeRDN(pb, pszRDN, WriteFlag);
// Restore the comma before checking for error
if (NULL != pszNext) { *pszNext = ','; } if (Result < 0) { DebugLog((DEB_TRACE, "EncodeDN: Error: %s\n", pszRDN)); Length = 0; goto error; // return(-1)
}
pb += Result; Length += Result;
if (NULL == pszNext) { break; }
pszRDN = pszNext + 1; while (*pszRDN == ' ') { pszRDN++; } DebugLog((DEB_TRACE, "EncodeDN: Length = %d\n", Length)); } } SP_ASSERT(0 != SaveResult); error: return(Result + Length); }
|