mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
977 lines
28 KiB
977 lines
28 KiB
/*
|
|
Key modulus's, key exponents, and issuer names were taken from the
|
|
file SSLX509.C
|
|
*/
|
|
/*Included Files------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "ssldbg.h"
|
|
//#include <assert.h>
|
|
#include "pkcs.h"
|
|
#include "guts.h"
|
|
#include "hash.h"
|
|
#include "cert.h"
|
|
|
|
/*Magic Values--------------------------------------------------------------*/
|
|
static unsigned char rgIdAlgMd2[] = {
|
|
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
|
0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00,
|
|
};
|
|
|
|
static unsigned char rgIdAlgMd5[] = {
|
|
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
|
0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00,
|
|
};
|
|
|
|
static unsigned char rgNameNetscape[] = {
|
|
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
|
|
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30,
|
|
0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07,
|
|
0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31,
|
|
0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
|
0x13, 0x1d, 0x4e, 0x65, 0x74, 0x73, 0x63, 0x61,
|
|
0x70, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75,
|
|
0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
|
0x73, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x2e,
|
|
};
|
|
|
|
static unsigned char rgKeyNetscape[] = {
|
|
0x52, 0x53, 0x41, 0x31, //magic = 'RSA1'
|
|
0x88, 0x00, 0x00, 0x00, //keylen = 136 bytes = size of data. padding at end
|
|
0x00, 0x04, 0x00, 0x00, //bitlen = 1024 bits = 16*8*8
|
|
0x7f, 0x00, 0x00, 0x00, //datalen = 127
|
|
0x03, 0x00, 0x00, 0x00, //public exponent, not sure if in right order
|
|
0x63, 0x16, 0xcc, 0xd3, 0x9c, 0x5f, 0x3e, 0x1a, //Fliped modulus
|
|
0x40, 0xd2, 0x4e, 0x77, 0xe0, 0x00, 0x09, 0xfd,
|
|
0x68, 0x15, 0x87, 0x68, 0x0b, 0x2d, 0x29, 0x2a,
|
|
0x3f, 0x40, 0xcb, 0x1f, 0x61, 0x33, 0x8e, 0xd5,
|
|
0x96, 0xb3, 0x28, 0xcf, 0x94, 0x58, 0xde, 0xfc,
|
|
0x74, 0xbd, 0x33, 0xdb, 0xb9, 0x09, 0x3e, 0x67,
|
|
0x36, 0xa7, 0xdd, 0xdd, 0x16, 0xe0, 0xbd, 0x16,
|
|
0x0e, 0x52, 0xcb, 0xb8, 0xe1, 0xb7, 0x16, 0xa0,
|
|
0x45, 0xa7, 0xff, 0x65, 0xc9, 0xb8, 0x8a, 0x59,
|
|
0x12, 0x37, 0x6b, 0x7d, 0x21, 0x4a, 0x4a, 0x48,
|
|
0x21, 0xbf, 0x4e, 0x6a, 0xa3, 0x95, 0x34, 0xa0,
|
|
0xc1, 0x32, 0xa7, 0xf0, 0xde, 0x56, 0x15, 0xad,
|
|
0x60, 0xc3, 0x14, 0xe6, 0x07, 0x51, 0x7c, 0xfe,
|
|
0x2a, 0x02, 0x50, 0x13, 0x5b, 0x82, 0xb2, 0x9b,
|
|
0xdf, 0x2d, 0x15, 0x81, 0xe9, 0xcb, 0x3c, 0xa1,
|
|
0x72, 0x7b, 0x18, 0xba, 0xec, 0x8a, 0x6c, 0xb4,
|
|
0x00, 0x00, 0x00, 0x00, //padding
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
static unsigned char rgNameRsa[] = {
|
|
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
|
|
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x20, 0x30,
|
|
0x1e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x17,
|
|
0x52, 0x53, 0x41, 0x20, 0x44, 0x61, 0x74, 0x61,
|
|
0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
|
|
0x79, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
|
|
0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b,
|
|
0x13, 0x25, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65,
|
|
0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
|
|
0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
|
|
0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
|
|
};
|
|
|
|
static unsigned char rgKeyRsa[] = {
|
|
0x52, 0x53, 0x41, 0x31, //magic = 'RSA1'
|
|
0x88, 0x00, 0x00, 0x00, //keylen = 136 bytes = size of data. padding at end
|
|
0x00, 0x04, 0x00, 0x00, //bitlen = 1024 bits = 16*8*8
|
|
0x7f, 0x00, 0x00, 0x00, //datalen = 127
|
|
0x01, 0x00, 0x01, 0x00, //public exponent, not sure if in right order
|
|
0x7b, 0x1e, 0xc8, 0xd6, 0x2d, 0xdd, 0xe5, 0x48,
|
|
0x67, 0x70, 0x6d, 0x9c, 0x39, 0x97, 0xb1, 0x82,
|
|
0x69, 0x3a, 0x73, 0x2c, 0x54, 0x49, 0xd5, 0x15,
|
|
0x1e, 0x9c, 0x59, 0x11, 0x4a, 0x2e, 0x13, 0x1a,
|
|
0x29, 0xa7, 0x1d, 0xb9, 0x48, 0x98, 0x56, 0x89,
|
|
0x50, 0xe3, 0x4c, 0x77, 0x9b, 0x3e, 0x76, 0x71,
|
|
0x13, 0x70, 0x65, 0x07, 0x84, 0x6d, 0x59, 0x81,
|
|
0xf7, 0x8f, 0x07, 0x88, 0x6c, 0x56, 0x22, 0x66,
|
|
0x25, 0x4b, 0xc9, 0x4b, 0xa2, 0x05, 0x9a, 0x81,
|
|
0x68, 0x76, 0xad, 0x02, 0x21, 0xb1, 0xe9, 0x55,
|
|
0x37, 0x86, 0x16, 0xd2, 0x08, 0x82, 0x8a, 0xe2,
|
|
0x08, 0x8f, 0xbf, 0xc9, 0x51, 0x40, 0x84, 0xe5,
|
|
0x03, 0x54, 0x64, 0x78, 0x35, 0xeb, 0xce, 0x37,
|
|
0x2c, 0x8e, 0xae, 0xad, 0x0c, 0x76, 0x01, 0x25,
|
|
0xac, 0x57, 0x83, 0x89, 0xaa, 0x5a, 0x3e, 0x83,
|
|
0xae, 0xc1, 0x7a, 0xce, 0x92,
|
|
0x00, 0x00, 0x00, 0x00, //padding
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
static unsigned char rgNameMCI[] = {
|
|
0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
|
|
0x55, 0x53, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0A,
|
|
0x13, 0x03, 0x4D, 0x43, 0x49, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03,
|
|
0x55, 0x04, 0x0B, 0x13, 0x0B, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x6E,
|
|
0x65, 0x74, 0x4D, 0x43, 0x49, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03,
|
|
0x55, 0x04, 0x0B, 0x13, 0x04, 0x4D, 0x41, 0x4C, 0x4C
|
|
};
|
|
|
|
|
|
static unsigned char rgKeyMCI[] = {
|
|
0x52, 0x53, 0x41, 0x31, //magic = 'RSA1'
|
|
0x88, 0x00, 0x00, 0x00, //keylen = 136 bytes = size of data. padding at end
|
|
0x00, 0x04, 0x00, 0x00, //bitlen = 1024 bits = 16*8*8
|
|
0x7f, 0x00, 0x00, 0x00, //datalen = 127
|
|
0x01, 0x00, 0x01, 0x00, //public exponent, not sure if in right order
|
|
0x6f, 0x51, 0x76, 0x56, 0xbb, 0x63, 0x9a, 0xed, //Fliped modulus
|
|
0x88, 0x6e, 0x81, 0x26, 0x19, 0x44, 0x1c, 0xcf,
|
|
0x5b, 0x9b, 0x5c, 0x9b, 0x21, 0x2d, 0x0f, 0xa9,
|
|
0xeb, 0x98, 0xac, 0x2b, 0xd4, 0x27, 0x95, 0x39,
|
|
0x13, 0xeb, 0xf2, 0x43, 0x8c, 0x18, 0xfe, 0xe0,
|
|
0xd5, 0x6d, 0xcc, 0x36, 0x4e, 0xdf, 0xe6, 0x49,
|
|
0xfb, 0x91, 0x31, 0x43, 0xc8, 0x1e, 0xc6, 0x25,
|
|
0xf7, 0x86, 0x49, 0x42, 0xa5, 0xa3, 0xc5, 0x6f,
|
|
0x55, 0x76, 0x98, 0xd2, 0xd4, 0xa0, 0xec, 0x41,
|
|
0xa9, 0x1f, 0x6c, 0x93, 0x5f, 0x9f, 0xc5, 0xdf,
|
|
0x88, 0x49, 0xcc, 0x27, 0x06, 0x30, 0x36, 0xd6,
|
|
0x9e, 0xe9, 0x06, 0xa5, 0xcb, 0xfb, 0xa3, 0x4d,
|
|
0x92, 0x0c, 0x08, 0xf0, 0x34, 0x1e, 0x37, 0x0d,
|
|
0x3f, 0xe4, 0xfc, 0x83, 0x88, 0x5e, 0x94, 0xf2,
|
|
0x80, 0x48, 0xce, 0x6f, 0xf0, 0x10, 0xae, 0x8f,
|
|
0xc0, 0x2d, 0xa8, 0x51, 0x5f, 0x23, 0x21, 0xe3,
|
|
0x00, 0x00, 0x00, 0x00, //padding
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
|
|
static unsigned char rgNameATTDir[] = {
|
|
0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
|
|
0x55, 0x53, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0A,
|
|
0x14, 0x04, 0x41, 0x54, 0x26, 0x54, 0x31, 0x1B, 0x30, 0x19, 0x06,
|
|
0x03, 0x55, 0x04, 0x0B, 0x14, 0x12, 0x44, 0x69, 0x72, 0x65, 0x63,
|
|
0x74, 0x6F, 0x72, 0x79, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
|
|
0x65, 0x73, 0x30, 0x81, 0x9D, 0x30, 0x0D, 0x06, 0x09
|
|
};
|
|
|
|
|
|
static unsigned char rgKeyATTDir[] = {
|
|
0x52, 0x53, 0x41, 0x31, //magic = 'RSA1'
|
|
0x88, 0x00, 0x00, 0x00, //keylen = 136 bytes = size of data. padding at end
|
|
0x00, 0x04, 0x00, 0x00, //bitlen = 1024 bits = 16*8*8
|
|
0x7f, 0x00, 0x00, 0x00, //datalen = 127
|
|
0x0F, 0x00, 0x00, 0x00, //public exponent, not sure if in right order
|
|
0x6D, 0xD5, 0x00, 0x97, 0xAC, 0x76, 0xED, 0xBA, // Flipped Modulus
|
|
0x8B, 0x08, 0x20, 0xA2, 0xDA, 0x14, 0x99, 0x3F,
|
|
0x3C, 0x16, 0x30, 0x00, 0x4E, 0xC5, 0x4F, 0x6E,
|
|
0xBA, 0x43, 0xA5, 0x6C, 0x0B, 0xAB, 0xF7, 0x97,
|
|
0xA4, 0xB8, 0xAC, 0x76, 0xA9, 0xA4, 0x6C, 0x80,
|
|
0x4D, 0xB1, 0x9E, 0x83, 0x94, 0x12, 0x32, 0x3B,
|
|
0xB8, 0x04, 0x54, 0x37, 0x16, 0xE0, 0x5A, 0x5B,
|
|
0xD5, 0x67, 0xFE, 0x51, 0x44, 0xEE, 0xC2, 0xE7,
|
|
0x22, 0xCB, 0xDE, 0x11, 0x85, 0x8C, 0x09, 0x48,
|
|
0x26, 0xBE, 0xBE, 0x4B, 0xCE, 0x7D, 0xA0, 0xA2,
|
|
0xF1, 0xFA, 0x4B, 0xDE, 0xD4, 0xB6, 0x6C, 0x07,
|
|
0x2A, 0x1F, 0xB0, 0xE3, 0xAC, 0xA2, 0xB6, 0x13,
|
|
0x92, 0x9E, 0x7E, 0x1F, 0x1A, 0x31, 0xC5, 0x11,
|
|
0xE3, 0x33, 0x23, 0xCD, 0x86, 0xC6, 0xAF, 0x48,
|
|
0x69, 0x40, 0x00, 0xFE, 0x22, 0xC6, 0xAC, 0x27,
|
|
0x87, 0x8F, 0x20, 0x0B, 0x89, 0x72, 0x64, 0x87,
|
|
0x00, 0x00, 0x00, 0x00, //padding
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
static unsigned char rgNameATT[] = {
|
|
0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
|
|
0x55, 0x53, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0A,
|
|
0x14, 0x04, 0x41, 0x54, 0x26, 0x54, 0x31, 0x1D, 0x30, 0x1B, 0x06,
|
|
0x03, 0x55, 0x04, 0x0B, 0x13, 0x14, 0x43, 0x65, 0x72, 0x74, 0x69,
|
|
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76,
|
|
0x69, 0x63, 0x65, 0x73, 0x30, 0x1E, 0x17, 0x0D, 0x39
|
|
};
|
|
|
|
static unsigned char rgKeyATT[] = {
|
|
0x52, 0x53, 0x41, 0x31, //magic = 'RSA1'
|
|
0x88, 0x00, 0x00, 0x00, //keylen = 136 bytes = size of data. padding at end
|
|
0x00, 0x04, 0x00, 0x00, //bitlen = 1024 bits = 16*8*8
|
|
0x7f, 0x00, 0x00, 0x00, //datalen = 127
|
|
0x01, 0x00, 0x01, 0x00, //public exponent, not sure if in right order
|
|
0x21, 0x68, 0xB6, 0x47, 0xAE, 0x7C, 0xD5, 0xC9,
|
|
0x46, 0x10, 0xC6, 0x3C, 0xE5, 0xBA, 0x60, 0x36,
|
|
0xC3, 0x18, 0xF0, 0x16, 0x93, 0xDB, 0x2A, 0x86,
|
|
0xD5, 0x7C, 0xFC, 0xD5, 0xE0, 0x85, 0x30, 0x61,
|
|
0x87, 0xE8, 0xDE, 0x9E, 0x4F, 0x71, 0xC2, 0x39,
|
|
0xD6, 0x08, 0xBD, 0xCC, 0x00, 0xBB, 0x58, 0x19,
|
|
0x64, 0xB6, 0x2E, 0x29, 0xB9, 0x97, 0x14, 0xEA,
|
|
0xC7, 0xF8, 0x03, 0xC3, 0x63, 0x4E, 0xD3, 0x8B,
|
|
0x15, 0xB5, 0xA0, 0xB5, 0x2A, 0x4F, 0x46, 0x47,
|
|
0x64, 0x0C, 0x44, 0x47, 0x19, 0x72, 0x9D, 0x37,
|
|
0xBE, 0x86, 0x3A, 0xA9, 0x2D, 0x75, 0x7D, 0xF9,
|
|
0x4B, 0x10, 0xCA, 0x01, 0x27, 0x05, 0xA1, 0x66,
|
|
0x13, 0xEF, 0x67, 0x51, 0x9C, 0x41, 0x66, 0xA9,
|
|
0x7E, 0xC3, 0xD9, 0x93, 0xF2, 0x9B, 0x06, 0xD6,
|
|
0x91, 0xC1, 0x09, 0xA2, 0x08, 0xE6, 0xE1, 0xFE,
|
|
0xC7, 0x14, 0xB8, 0x1B, 0x64, 0x01, 0x1E, 0xE0,
|
|
};
|
|
|
|
|
|
|
|
#define KEY_PADDING (sizeof(DWORD)*2)
|
|
#define KEY_FIELDS_SIZE ((KEY_PADDING+4)+sizeof(BSAFE_PUB_KEY))
|
|
|
|
/*Headers-------------------------------------------------------------------*/
|
|
|
|
static char* BerMagicCN2CString(unsigned char *pBuf);
|
|
static char* BerMagic2CString(unsigned char *pBuf);
|
|
|
|
|
|
/*Implementation------------------------------------------------------------*/
|
|
static LPBSAFE_PUB_KEY MakeKey(unsigned char *pMod, int nMod, unsigned char *pExp, int nExp){
|
|
LPBSAFE_PUB_KEY pKey;
|
|
|
|
/*Simple SAnity checks*/
|
|
if ( 0 == nExp
|
|
|| 0 == nMod
|
|
|| 3 < nExp
|
|
) return NULL;
|
|
|
|
|
|
/*Stupid BER integer encoding BUG fix*/
|
|
if (nMod&0x1)
|
|
{
|
|
ASSERT( (*pMod) == 0);
|
|
*pMod++;
|
|
nMod--;
|
|
ASSERT( (*pMod) & 0x80 );
|
|
}
|
|
|
|
|
|
/*create key in model of netscape one, even if too large*/
|
|
pKey = malloc(nMod+KEY_FIELDS_SIZE);//sizeof(rgKeyNetscape));
|
|
if (NULL!=pKey){
|
|
/*zero out structure*/
|
|
memset(pKey, 0, (nMod+KEY_FIELDS_SIZE));
|
|
/*copy magic value and keylen*/
|
|
memcpy(pKey, rgKeyNetscape, 8);
|
|
/*assign bitlen*/
|
|
pKey->bitlen = 8 * nMod;
|
|
/*assign datalen*/
|
|
pKey->datalen = nMod - 1;
|
|
/*make public exponent*/
|
|
pKey->pubexp = *pExp++;
|
|
while (--nExp) pKey->pubexp = (pKey->pubexp << 8) + *pExp++;
|
|
/*Copy in moduluos*/
|
|
for (nExp=0;nExp<nMod;++nExp) ((unsigned char*)pKey)[nMod+sizeof(BSAFE_PUB_KEY)-nExp-1] = pMod[nExp];
|
|
}
|
|
return pKey;
|
|
}
|
|
|
|
/*
|
|
Basic Encoding Rule Parser
|
|
Variable length field or Absoulte
|
|
pBuf - Content. Starts at size field
|
|
pLen - Length of content
|
|
pSize - Size of length identifier
|
|
RETURNS - *pLen + *pSize = total length of block
|
|
*/
|
|
static int BerGetLen(unsigned char *pBuf, int *pLen, int *pSize){
|
|
int z;
|
|
|
|
/*what type of length encoding*/
|
|
if (*pBuf & 0x80){
|
|
/*long length field*/
|
|
*pSize = 1 + (*pBuf++ ^ 0x80);
|
|
*pLen = *pBuf;
|
|
for (z = 2; z < *pSize; ++z){
|
|
*pLen <<= 8;
|
|
*pLen += *(++pBuf);
|
|
}
|
|
}
|
|
else{
|
|
/*short length encoding*/
|
|
*pSize = 1;
|
|
*pLen = *pBuf;
|
|
}
|
|
/*quick sanity check*/
|
|
ASSERT(*pSize<5);
|
|
return *pLen + *pSize;
|
|
}
|
|
|
|
/*
|
|
Basic Encoding Rule Parser
|
|
Variable length field code
|
|
pBuf - Content. Starts at field id
|
|
RETURNS - Start of next field
|
|
*/
|
|
static unsigned char* BerNextField(unsigned char *pBuf){
|
|
int a,b;
|
|
|
|
BerGetLen(++pBuf,&a,&b);
|
|
return pBuf + b;
|
|
}
|
|
|
|
/*
|
|
Basic Encoding Rule Parser
|
|
pBuf - Content. Starts at field id
|
|
RETURNS - Start of next block
|
|
*/
|
|
static unsigned char* BerNextBlock(unsigned char *pBuf){
|
|
int a,b;
|
|
a = BerGetLen(++pBuf,&a,&b);
|
|
return pBuf + a;
|
|
}
|
|
|
|
void FlipBuf(char *pBuf, int nBufLen){
|
|
int z;
|
|
unsigned char c;
|
|
|
|
for (z=0;z<nBufLen/2;++z) {
|
|
c = pBuf[nBufLen-z-1];
|
|
pBuf[nBufLen-z-1] = pBuf[z];
|
|
pBuf[z] = c;
|
|
}
|
|
}
|
|
|
|
void PKCS1Encode(char *pBuf, int nBufLen, char *pContent, int nContentLen, int nType){
|
|
int z;
|
|
|
|
/*copy in D*/
|
|
for (z=0;z<nContentLen;++z) pBuf[z]=pContent[nContentLen-z-1];
|
|
pBuf += z;
|
|
/*put in blank for designation*/
|
|
*pBuf++ = 0x00;
|
|
/*what type of block*/
|
|
if (1==nType){
|
|
/*private key operartion, fill with 0xFF's*/
|
|
z = nBufLen-3-nContentLen;
|
|
memset(pBuf, 0xFF, z);
|
|
pBuf += z;
|
|
}
|
|
else{
|
|
/*Public key operation, fill with Randoms != 0*/
|
|
#ifdef BETTER_RANDOM
|
|
GenRandom(pBuf, nBufLen-3-nContentLen);
|
|
// Crypto review needed: getting rand(256) instead of rand(255) and collapsing may
|
|
// not be cool
|
|
for (z=0;z<nBufLen-3-nContentLen;++z) {
|
|
if ( *pBuf == 0 )
|
|
(*pBuf)++;
|
|
pBuf++;
|
|
}
|
|
#else
|
|
for (z=0;z<nBufLen-3-nContentLen;++z) *pBuf++ = 1+SslRandom(255);
|
|
#endif BETTER_RANDOM
|
|
}
|
|
/*enter type of block*/
|
|
*pBuf++ = nType;
|
|
/*last bit of padding*/
|
|
*pBuf = 0;
|
|
}
|
|
|
|
/*Stuff to parse the cert. for internal use----------------------------------*/
|
|
typedef struct tagCertParsedInternal{
|
|
int nMod;
|
|
char *pMod;
|
|
|
|
int nExp;
|
|
char *pExp;
|
|
|
|
int nBody;
|
|
char *pBody;
|
|
|
|
int nSig; /*Signature Length*/
|
|
char *pSig; /*Signature*/
|
|
|
|
int nHashAlg; /*WSSA hash code*/
|
|
|
|
void *pKeyCheck; /*hardcoded BSAFE public key to check info*/
|
|
} CertParsedInternal, *PCertParsedInternal;
|
|
|
|
typedef struct _SSLTIME
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
unsigned uMins:6; //max. 60
|
|
unsigned uHrs:5; //max. 24
|
|
unsigned uDate:5; //max. 31
|
|
unsigned uMonth:4; //max. 12
|
|
unsigned uYear:12; //max. 4096
|
|
};
|
|
DWORD dwSslTime1;
|
|
};
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
unsigned uSecs:6; //max. 60
|
|
unsigned uUnused:26; //max. 24
|
|
};
|
|
DWORD dwSslTime2;
|
|
};
|
|
|
|
} SSLTIME;
|
|
|
|
static SSLTIME SslTimeFromBer(unsigned char *pCert)
|
|
{
|
|
SSLTIME sslTime;
|
|
int nBerLen, nBerSize;
|
|
|
|
BerGetLen(pCert, &nBerLen, &nBerSize);
|
|
pCert+=nBerSize;
|
|
|
|
ASSERT(nBerLen>=12);
|
|
|
|
sslTime.uYear = (*pCert++ & (~0x30)) * 10;
|
|
sslTime.uYear += (*pCert++ & (~0x30));
|
|
/* If we only have 80 or less, assume it is 21st cent. Anything
|
|
* between 81 and 99, assume it is the 20th century.
|
|
*/
|
|
if (sslTime.uYear < 100)
|
|
sslTime.uYear += (sslTime.uYear < 80 ? 2000 : 1900);
|
|
|
|
sslTime.uMonth = (*pCert++ & (~0x30)) * 10;
|
|
sslTime.uMonth += (*pCert++ & (~0x30));
|
|
sslTime.uDate = (*pCert++ & (~0x30)) * 10;
|
|
sslTime.uDate += (*pCert++ & (~0x30));
|
|
sslTime.uHrs = (*pCert++ & (~0x30)) * 10;
|
|
sslTime.uHrs += (*pCert++ & (~0x30));
|
|
sslTime.uMins = (*pCert++ & (~0x30)) * 10;
|
|
sslTime.uMins += (*pCert++ & (~0x30));
|
|
sslTime.uSecs = (*pCert++ & (~0x30)) * 10;
|
|
sslTime.uSecs += (*pCert++ & (~0x30));
|
|
sslTime.uUnused = 0;
|
|
return sslTime;
|
|
}
|
|
|
|
/* returns:
|
|
* -1 if st1 < st2 (i.e. ssl time 1 is older than ssl time 2
|
|
* 0 if st1 == st2
|
|
* 1 if st1 > st2 (i.e. ssl time 1 is newer than ssl time 2
|
|
*/
|
|
static int CompareSslTime(SSLTIME st1, SSLTIME st2)
|
|
{
|
|
if (st1.dwSslTime1 == st2.dwSslTime1)
|
|
{
|
|
if (st1.uSecs == st2.uSecs)
|
|
return 0;
|
|
else if (st1.uSecs < st2.uSecs)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
else if (st1.dwSslTime1 < st2.dwSslTime1)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
|
|
static BOOL FValidSslTimes(SSLTIME sslTimeNBefore, SSLTIME sslTimeNAfter)
|
|
{
|
|
SYSTEMTIME st;
|
|
SSLTIME sslTimeCur;
|
|
|
|
GetSystemTime(&st);
|
|
|
|
sslTimeCur.uMins = st.wMinute;
|
|
sslTimeCur.uHrs = st.wHour;
|
|
sslTimeCur.uDate = st.wDay;
|
|
sslTimeCur.uMonth = st.wMonth;
|
|
sslTimeCur.uYear = st.wYear;
|
|
sslTimeCur.uSecs = st.wSecond;
|
|
sslTimeCur.uUnused = 0;
|
|
|
|
return ( CompareSslTime(sslTimeNBefore, sslTimeCur) <= 0
|
|
&& CompareSslTime(sslTimeNAfter, sslTimeCur) >= 0);
|
|
}
|
|
|
|
//
|
|
// Compare a DNS name to a common name field value
|
|
//
|
|
// On entry:
|
|
// pDNS: pointer to string containing DNS name
|
|
// pCN: pointer to string containing common name field value
|
|
//
|
|
// On exit:
|
|
// returns: TRUE -> The two strings match
|
|
// FALSE -> The two string don't match
|
|
//
|
|
// Note:
|
|
// There are two ways for these two strings to match. The first is that
|
|
// they contain exactly the same characters. The second involved the use
|
|
// of a single wildcard character in the common name field value. This
|
|
// wildcard character ('*') can only be used once, and if used must be
|
|
// the first character of the field.
|
|
//
|
|
BOOL CompareDNStoCommonName( char *pDNS, char *pCN )
|
|
{
|
|
int nCountPeriods = 1; // start of DNS amount to virtual '.' as prefix
|
|
|
|
ASSERT( pDNS );
|
|
ASSERT( pCN );
|
|
|
|
while ( ((*pDNS == *pCN) || *pCN == '*') && *pDNS && *pCN ) {
|
|
if ( *pCN == '*' ) {
|
|
nCountPeriods = 0;
|
|
if ( *pDNS == '.' )
|
|
pCN++;
|
|
else
|
|
pDNS++;
|
|
} else {
|
|
if ( *pDNS == '.' )
|
|
nCountPeriods++;
|
|
pDNS++;
|
|
pCN++;
|
|
}
|
|
}
|
|
return (*pDNS == 0) && (*pCN == 0) && (nCountPeriods >= 2);
|
|
}
|
|
|
|
BOOL CompareDNStoMultiCommonName( char *pDNS, char *pCN )
|
|
{
|
|
char *pSpace;
|
|
BOOL retval = FALSE; // assume we won't find a match
|
|
BOOL done = FALSE; // assyme we're not done
|
|
|
|
do {
|
|
// If there is a space, turn it into a null terminator to isolate the first
|
|
// DNS name in the string
|
|
pSpace = strchr( pCN, ' ' );
|
|
if ( pSpace )
|
|
*pSpace = 0;
|
|
|
|
// See if this component is a match
|
|
retval = CompareDNStoCommonName( pDNS, pCN );
|
|
|
|
// Now restore the space (if any) that was overwritten
|
|
if ( pSpace ) {
|
|
*pSpace = ' ';
|
|
pCN = pSpace + 1;
|
|
} else {
|
|
// If there was no space, then we're done
|
|
done = TRUE;
|
|
}
|
|
} while ( !retval && !done && *pCN );
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
static void CertFreeInternal(PCertParsedInternal pcp){
|
|
}
|
|
|
|
static BOOL CertParseInternal(SSI ssi, PCertParsedInternal pcp, unsigned char *pCert, int nCert){
|
|
int nBerLen, nBerSize, nBodyLen, z;
|
|
unsigned char *pBuf;
|
|
|
|
// Assume we won't be finding a matching CN to DNS host
|
|
ssi->dwSSLUserFlags |= SO_SSL_BAD_COMMON_NAME;
|
|
|
|
/*initialize variables*/
|
|
memset(pcp,0,sizeof(*pcp));
|
|
|
|
/*weak basic integrety check*/
|
|
if (0x30 == *pCert
|
|
&&nCert == BerGetLen(++pCert, &nBerLen, &nBerSize) + 1
|
|
){
|
|
pCert += nBerSize;
|
|
/*This is the body that will be hashed later*/
|
|
pcp->pBody= pCert;
|
|
pcp->nBody= 1 + BerGetLen(pCert+1, &nBerLen, &nBerSize);
|
|
/*At Certificate Info Block-----------*/
|
|
nBodyLen = 1 + BerGetLen(pCert+1, &nBerLen, &nBerSize);
|
|
/*goto Issuer Block*/
|
|
pBuf = BerNextField(pCert);
|
|
/*at serial number*/
|
|
if (*pBuf == 0x2)
|
|
{
|
|
BerGetLen(pBuf+1, &nBerLen, &nBerSize);
|
|
/*continue towards issuer block*/
|
|
for (z=0;z<2;++z) pBuf = BerNextBlock(pBuf);
|
|
/*at issuer heading*/
|
|
BerGetLen(++pBuf, &nBerLen, &nBerSize);
|
|
pBuf += nBerSize;
|
|
/*copy issuer / key check info*/
|
|
if ((nBerLen == sizeof(rgNameNetscape))
|
|
&& (0 == memcmp(pBuf, rgNameNetscape, nBerLen))
|
|
){
|
|
pcp->pKeyCheck = (void*) &rgKeyNetscape;
|
|
}
|
|
else if ((nBerLen == sizeof(rgNameRsa))
|
|
&& (0 == memcmp(pBuf, rgNameRsa, nBerLen))
|
|
){
|
|
pcp->pKeyCheck = (void*) &rgKeyRsa;
|
|
}
|
|
else if ((nBerLen == sizeof(rgNameMCI))
|
|
&& (0 == memcmp(pBuf, rgNameMCI, nBerLen))
|
|
){
|
|
pcp->pKeyCheck = (void*) &rgKeyMCI;
|
|
}
|
|
else if ((nBerLen == sizeof(rgNameATTDir))
|
|
&& (0 == memcmp(pBuf, rgNameATTDir, nBerLen))
|
|
){
|
|
pcp->pKeyCheck = (void*) &rgKeyATTDir;
|
|
}
|
|
else if ((nBerLen == sizeof(rgNameATT))
|
|
&& (0 == memcmp(pBuf, rgNameATT, nBerLen))
|
|
){
|
|
pcp->pKeyCheck = (void*) &rgKeyATT;
|
|
}
|
|
|
|
|
|
if (pcp->pKeyCheck)
|
|
{
|
|
|
|
unsigned char *pBufNBefore, *pBufNAfter;
|
|
SSLTIME sslTimeNBefore;
|
|
SSLTIME sslTimeNAfter;
|
|
|
|
/*goto SubjectPublicKeyInfo ::= SEQUENCE*/
|
|
pBuf = BerNextField(pCert);
|
|
//pBuf points to Serial No ( *pBuf == 0x02)
|
|
// for (z=0;z<5;++z) pBuf = BerNextBlock(pBuf);
|
|
for (z=0;z<3;++z)
|
|
pBuf = BerNextBlock(pBuf);
|
|
//pBuf skipped three blocks (Serial no, signature algo, Issuer
|
|
//pBuf points into Validity
|
|
if (*(pBufNBefore = BerNextField(pBuf)) == 0x17)
|
|
sslTimeNBefore = SslTimeFromBer(pBufNBefore+1);
|
|
//pBufNBefore = Validity/Not Before
|
|
if (*(pBufNAfter = BerNextBlock(pBufNBefore)) == 0x17)
|
|
sslTimeNAfter = SslTimeFromBer(pBufNAfter+1);
|
|
|
|
// if the cert date is invalid, flag it, will chk this
|
|
// later when we're back in the UI code
|
|
if (!FValidSslTimes(sslTimeNBefore, sslTimeNAfter))
|
|
ssi->dwSSLUserFlags |= SO_SSL_CERT_EXPIRED;
|
|
|
|
// Subject ?
|
|
pBuf = BerNextBlock(pBuf);
|
|
if (0x30 == *pBuf)
|
|
{
|
|
char *szCN;
|
|
char *sz;
|
|
char *pszBuf;
|
|
int nSubject = 0;
|
|
|
|
/*at subject block*/
|
|
pszBuf = BerNextField(pBuf);
|
|
while (0x31 == *pszBuf)
|
|
{
|
|
if (nSubject) pszBuf = BerNextBlock(pszBuf);
|
|
nSubject++;
|
|
sz = BerMagic2CString(pszBuf);
|
|
szCN = BerMagicCN2CString(pszBuf);
|
|
if (sz)
|
|
{
|
|
Free(sz);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(!szCN); // if there is an szCN there is an sz
|
|
break;
|
|
}
|
|
if (szCN)
|
|
{
|
|
// wrench off a copy for common name calculations
|
|
if ( ssi->pszHostName &&
|
|
CompareDNStoMultiCommonName( ssi->pszHostName, szCN ) )
|
|
{
|
|
ssi->dwSSLUserFlags &= ~SO_SSL_BAD_COMMON_NAME;
|
|
}
|
|
Free(szCN);
|
|
}
|
|
}
|
|
|
|
} // end - if (0x30 == *pBuf)
|
|
|
|
|
|
// Subject Public Key Info
|
|
pBuf = BerNextBlock(pBuf);
|
|
|
|
/*goto subjectPublicKey BIT STRING*/
|
|
pBuf = BerNextField(pBuf);
|
|
pBuf = BerNextBlock(pBuf);
|
|
pBuf = BerNextField(pBuf);
|
|
{
|
|
int l,s;
|
|
unsigned char *pch;
|
|
/*advance for 0 as field header...*/
|
|
pBuf += 1;
|
|
pBuf = BerNextField(pBuf);
|
|
/*get modulus*/
|
|
pch = pBuf + 1;
|
|
BerGetLen(pch, &l, &s);
|
|
/*get exponent*/
|
|
pBuf = BerNextBlock(pBuf) + 1;
|
|
BerGetLen(pBuf, &nBerLen, &nBerSize);
|
|
pcp->pMod = pch + s;
|
|
pcp->nMod = l;
|
|
pcp->pExp = pBuf + nBerSize;
|
|
pcp->nExp = nBerLen;
|
|
}
|
|
|
|
/*At Algorithm Identifier Block-------*/
|
|
pCert = BerNextBlock(pCert);
|
|
/*get algorithm type*/
|
|
nBerLen = BerGetLen(pCert+1, &nBerLen, &nBerSize) + 1;
|
|
pcp->nHashAlg = WSSA_HASH_NONE;
|
|
if ((nBerLen == sizeof(rgIdAlgMd2)) && (memcmp(pCert, rgIdAlgMd2, nBerLen) == 0)){
|
|
pcp->nHashAlg = WSSA_HASH_MD2;
|
|
}
|
|
else if ((nBerLen == sizeof(rgIdAlgMd5)) && (memcmp(pCert, rgIdAlgMd5, nBerLen) == 0)){
|
|
pcp->nHashAlg = WSSA_HASH_MD5;
|
|
}
|
|
if (WSSA_HASH_NONE != pcp->nHashAlg)
|
|
{
|
|
/*At Signature Bit String Block-------*/
|
|
pCert = BerNextBlock(pCert);
|
|
BerGetLen(pCert+1, &nBerLen, &nBerSize);
|
|
pcp->nSig = nBerLen - 1;
|
|
pcp->pSig = pCert + nBerSize + 2;
|
|
return TRUE;
|
|
}
|
|
} // end - if (pcp->pKeyCheck)
|
|
} // end - if (*pBuf == 0x2)
|
|
}
|
|
CertFreeInternal(pcp);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
Checks the validity of the input certificate.
|
|
Returns 0 if a valid certificate
|
|
|
|
pCert - X.509 Certificate From packet
|
|
nCertLen - Size of the certificate
|
|
ppRsaKey - Returns pointer to spot in certificate with public key
|
|
*/
|
|
int SslCertificateX509Check(SSI ssi, unsigned char *pCert, int nCertLength, LPBSAFE_PUB_KEY *ppKeyPub){
|
|
unsigned char rgBufIn[136], rgBufOut[136];
|
|
WssaHashInfo whi;
|
|
CertParsedInternal cpi;
|
|
int q, nReturn;
|
|
|
|
#if 0
|
|
CertParsed cp;
|
|
CertParse(&cp, pCert, nCertLength);
|
|
CertFree(&cp);
|
|
#endif
|
|
nReturn = WSSA_ERROR;
|
|
if (TRUE == CertParseInternal(ssi, &cpi, pCert, nCertLength)){
|
|
*ppKeyPub = MakeKey(cpi.pMod, cpi.nMod, cpi.pExp, cpi.nExp);
|
|
if (*ppKeyPub){
|
|
/*decode their signature*/
|
|
memset(rgBufIn,0,sizeof(rgBufIn));
|
|
((LPBSAFE_PUB_KEY)cpi.pKeyCheck)->datalen=cpi.nSig;
|
|
ASSERT(((LPBSAFE_PUB_KEY)cpi.pKeyCheck)->datalen *8 <= ((LPBSAFE_PUB_KEY)cpi.pKeyCheck)->bitlen);
|
|
{
|
|
/*copy in reverse order cuz our BSAFE routiens are backwards*/
|
|
for (q=0;q<cpi.nSig;++q) rgBufIn[q]=cpi.pSig[cpi.nSig-q-1];
|
|
}
|
|
if (TRUE == BSafeEncPublic((LPBSAFE_PUB_KEY)cpi.pKeyCheck, rgBufIn, rgBufOut)
|
|
&& WSSA_OK == WssaHashInit(&whi, cpi.nHashAlg)
|
|
){
|
|
/*sig decoded and hash algorithm supported*/
|
|
WssaHashUpdate(&whi, cpi.pBody, cpi.nBody);
|
|
WssaHashFinal(&whi);
|
|
/*setup block*/
|
|
FlipBuf(rgBufOut,whi.nDigestLen);
|
|
/*compare*/
|
|
if (0==memcmp(whi.pDigest,rgBufOut,whi.nDigestLen)) nReturn = WSSA_OK;
|
|
}
|
|
}
|
|
CertFreeInternal(&cpi);
|
|
}
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define CopyString(pDest, pSrc){pDest = malloc(strlen(pSrc)+1);if (pDest) strcpy(pDest, pSrc);}
|
|
|
|
void __stdcall CertFree(PCertParsed pcp){
|
|
if (pcp){
|
|
if (pcp->szSerialNumber) Free(pcp->szSerialNumber);
|
|
if (pcp->szHashAlg) Free(pcp->szHashAlg);
|
|
if (pcp->nIssuer){
|
|
while (pcp->nIssuer--){
|
|
Free(pcp->pszIssuer[pcp->nIssuer]);
|
|
}
|
|
Free(pcp->pszIssuer);
|
|
}
|
|
if (pcp->nSubject){
|
|
while (pcp->nSubject--){
|
|
Free(pcp->pszSubject[pcp->nSubject]);
|
|
}
|
|
Free(pcp->pszSubject);
|
|
}
|
|
}
|
|
}
|
|
|
|
static char* BerField2CString(unsigned char *pCert){
|
|
int nBerLen, nBerSize;
|
|
char *szBuf;
|
|
|
|
BerGetLen(pCert, &nBerLen, &nBerSize);
|
|
szBuf = malloc(nBerLen + 1);
|
|
if (szBuf){
|
|
strncpy(szBuf, pCert+nBerSize, nBerLen);
|
|
szBuf[nBerLen]=0;
|
|
}
|
|
return szBuf;
|
|
}
|
|
|
|
static BOOL BerDate2FileTime(unsigned char *pCert){
|
|
int nBerLen, nBerSize, yy, mm, dd;
|
|
WORD wDate;
|
|
|
|
BerGetLen(pCert, &nBerLen, &nBerSize);
|
|
pCert+=nBerSize;
|
|
yy = (*pCert++ & (~0x30)) * 10;
|
|
yy += (*pCert++ & (~0x30));
|
|
mm = (*pCert++ & (~0x30)) * 10;
|
|
mm += (*pCert++ & (~0x30));
|
|
dd = (*pCert++ & (~0x30)) * 10;
|
|
dd += (*pCert++ & (~0x30));
|
|
wDate = ((yy-80) << 9) | (mm << 5) | (dd);
|
|
return wDate;
|
|
}
|
|
|
|
#ifdef ToHex
|
|
#undef ToHex
|
|
#endif
|
|
#define ToHex(z) (((z)<10)?'0'+(z):'A'+((z)-10))
|
|
|
|
static char* BerField2SerialNumber(unsigned char *pCert){
|
|
int nBerLen, nBerSize, z;
|
|
char c, *szBuf;
|
|
|
|
BerGetLen(pCert, &nBerLen, &nBerSize);
|
|
szBuf = malloc(nBerLen*3);
|
|
if (szBuf){
|
|
for (z=0;z<nBerLen*3;++z){
|
|
if (z%3==0) c = ToHex(((*(pCert+nBerSize+z/3))>>4));
|
|
if (z%3==1) c = ToHex(((*(pCert+nBerSize+z/3))&0x0f));
|
|
if (z%3==2) c = ':';
|
|
szBuf[z]=c;
|
|
}
|
|
szBuf[nBerLen*3-1]=0;
|
|
}
|
|
return szBuf;
|
|
}
|
|
|
|
|
|
static char* BerMagic2CString(unsigned char *pBuf){
|
|
if (0x31 == *pBuf){
|
|
pBuf = BerNextBlock(pBuf);
|
|
if (0x31 == *pBuf){
|
|
pBuf = BerNextField(pBuf);
|
|
if (0x30 == *pBuf){
|
|
pBuf = BerNextField(pBuf);
|
|
if (0x06 == *pBuf){
|
|
pBuf = BerNextBlock(pBuf);
|
|
if (0x13 == *pBuf || 0x14 == *pBuf ){
|
|
return BerField2CString(pBuf+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static char* BerMagicCN2CString(unsigned char *pBuf){
|
|
if (0x31 == *pBuf){
|
|
pBuf = BerNextBlock(pBuf);
|
|
if (0x31 == *pBuf){
|
|
pBuf = BerNextField(pBuf);
|
|
if (0x30 == *pBuf){
|
|
pBuf = BerNextField(pBuf);
|
|
|
|
pBuf = BerNextField(pBuf);
|
|
pBuf = BerNextField(pBuf);
|
|
if (0x03 == *pBuf) {
|
|
pBuf++;
|
|
if (0x13 == *pBuf || 0x14 == *pBuf ){
|
|
return BerField2CString(pBuf+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
BOOL __stdcall CertParse(PCertParsed pcp, unsigned char *pCert, int nCert){
|
|
int nBerLen, nBerSize, z;
|
|
unsigned char *pBuf, *sz;
|
|
BOOL fReturn;
|
|
|
|
/*initialize variables*/
|
|
memset(pcp,0,sizeof(*pcp));
|
|
fReturn = TRUE;
|
|
|
|
/*weak basic integrety check*/
|
|
if (0x30 == *pCert
|
|
&&nCert == BerGetLen(++pCert, &nBerLen, &nBerSize) + 1
|
|
){
|
|
pCert += nBerSize;
|
|
pCert = BerNextField(pCert);
|
|
if (*pCert == 0x2){
|
|
/*at serial number*/
|
|
pcp->szSerialNumber = BerField2SerialNumber(pCert+1);
|
|
}
|
|
pCert = BerNextBlock(pCert);
|
|
if (*pCert == 0x30){
|
|
/*at signature block*/
|
|
z = 1 + BerGetLen(pCert+1, &nBerLen, &nBerSize);
|
|
if ((z == sizeof(rgIdAlgMd2)) && (memcmp(pCert, rgIdAlgMd2, z) == 0)){
|
|
CopyString(pcp->szHashAlg, "MD2");
|
|
}
|
|
else if ((z == sizeof(rgIdAlgMd5)) && (memcmp(pCert, rgIdAlgMd5, z) == 0)){
|
|
CopyString(pcp->szHashAlg, "MD5");
|
|
}
|
|
}
|
|
pCert = BerNextBlock(pCert);
|
|
if (0x30 == *pCert){
|
|
/*at issuer block, get key name*/
|
|
pBuf = BerNextField(pCert);
|
|
while (0x31 == *pBuf){
|
|
if (pcp->nIssuer) pBuf = BerNextBlock(pBuf);
|
|
sz = BerMagic2CString(pBuf);
|
|
if (sz){
|
|
pcp->pszIssuer = realloc(pcp->pszIssuer, (1+pcp->nIssuer)*sizeof(*pcp->pszIssuer));
|
|
pcp->pszIssuer[pcp->nIssuer++] = sz;
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
pCert = BerNextBlock(pCert);
|
|
if (0x30 == *pCert){
|
|
/*at validity block*/
|
|
pBuf = BerNextField(pCert);
|
|
if (0x17 == *pBuf){
|
|
pcp->wDateStart = BerDate2FileTime(pBuf+1);
|
|
pBuf = BerNextBlock(pBuf);
|
|
if (0x17 == *pBuf){
|
|
pcp->wDateEnd = BerDate2FileTime(pBuf+1);
|
|
}
|
|
}
|
|
}
|
|
pCert = BerNextBlock(pCert);
|
|
if (0x30 == *pCert){
|
|
/*at subject block*/
|
|
pBuf = BerNextField(pCert);
|
|
while (0x31 == *pBuf){
|
|
if (pcp->nSubject) pBuf = BerNextBlock(pBuf);
|
|
sz = BerMagic2CString(pBuf);
|
|
if (sz){
|
|
pcp->pszSubject = realloc(pcp->pszSubject, (1+pcp->nSubject)*sizeof(*pcp->pszSubject));
|
|
pcp->pszSubject[pcp->nSubject++] = sz;
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
}
|
|
else fReturn = FALSE;
|
|
if (!fReturn) CertFree(pcp);
|
|
return fReturn;
|
|
}
|