/* Key modulus's, key exponents, and issuer names were taken from the file SSLX509.C */ /*Included Files------------------------------------------------------------*/ #include #include #include "ssldbg.h" //#include #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=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;qszSerialNumber) 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>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; }