///////////////////////////////////////////////////////////////////////////// // FILE : sgccheck.c // // DESCRIPTION : Code to check if SGC is enabled // // AUTHOR : jeffspel // // HISTORY : // // Jun 16 1998 jeffspel Create // // Nov 16 1998 jbanes Pluggable SGC roots. // // // // Copyright (C) 1998 Microsoft Corporation All Rights Reserved // ///////////////////////////////////////////////////////////////////////////// #include #include #include #include #define SGCAlloc(cb) LocalAlloc(LMEM_ZEROINIT, cb) #define SGCFree(pb) LocalFree(pb) //#define SGC_TEST_KEY // COMMENT OUT THIS LINE BEFORE CHECKING IN!!! #ifdef SGC_TEST_KEY #pragma message ("WARNING -- Building with SGC Test Key enabled.") #endif #define SGC_VERIFICATION_FLAGS (CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG) // Geneva SGC Root static CONST BYTE GenevaSGCRoot[] = { 0x30, 0x82, 0x03, 0x0a, 0x30, 0x82, 0x01, 0xf2, // 0...0... 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x20, // ....... 0x9d, 0x11, 0xd1, 0x0e, 0x7f, 0x7b, 0x85, 0x74, // .....{.t 0x80, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, // .0...*.H 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, // ........ 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, // 0.1.0... 0x55, 0x04, 0x03, 0x13, 0x12, 0x52, 0x6f, 0x6f, // U....Roo 0x74, 0x20, 0x53, 0x47, 0x43, 0x20, 0x41, 0x75, // t SGC Au 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, // thority0 0x1e, 0x17, 0x0d, 0x39, 0x37, 0x30, 0x38, 0x30, // ...97080 0x36, 0x31, 0x37, 0x31, 0x34, 0x34, 0x37, 0x5a, // 6171447Z 0x17, 0x0d, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, // ..100101 0x30, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, // 070000Z0 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, // .1.0...U 0x04, 0x03, 0x13, 0x12, 0x52, 0x6f, 0x6f, 0x74, // ....Root 0x20, 0x53, 0x47, 0x43, 0x20, 0x41, 0x75, 0x74, // SGC Aut 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, // hority0. 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, // ."0...*. 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, // H....... 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, // ......0. 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xec, // ........ 0x55, 0x5d, 0x0f, 0xaf, 0x6c, 0x5b, 0xa5, 0x21, // U]..l[.! 0xe5, 0x81, 0xbc, 0x0d, 0x96, 0xee, 0xb4, 0x63, // .......c 0xbc, 0x4c, 0x14, 0x68, 0x6d, 0xfe, 0xd7, 0x64, // .L.hm..d 0x2d, 0xe7, 0x59, 0x9d, 0x8e, 0x20, 0x9c, 0x1c, // -.Y.. .. 0xb1, 0x18, 0x39, 0x38, 0x80, 0xc6, 0x08, 0xa6, // ..98.... 0x65, 0x39, 0x6c, 0x0a, 0x86, 0x6c, 0x8b, 0x6a, // e9l..l.j 0xaa, 0x4a, 0x7a, 0xb4, 0xe5, 0x23, 0x7b, 0x9c, // .Jz..#{. 0xa2, 0x88, 0x81, 0xa5, 0x2c, 0x9f, 0x2e, 0xce, // ....,... 0x56, 0xd8, 0x69, 0xc7, 0xd7, 0x54, 0xf8, 0xdd, // V.i..T.. 0xab, 0x9b, 0xc7, 0xba, 0x8e, 0xe7, 0x60, 0x1c, // ......`. 0x45, 0x20, 0x09, 0x9d, 0x00, 0x25, 0x16, 0x15, // E ...%.. 0xe0, 0x40, 0x2c, 0xf2, 0xac, 0xfa, 0x1f, 0xf8, // .@,..... 0x6d, 0x5e, 0xda, 0xbb, 0x14, 0xaf, 0x4c, 0x82, // m^....L. 0xf3, 0x5d, 0x81, 0xcb, 0xef, 0xcd, 0xa8, 0x0f, // .]...... 0xf1, 0xec, 0xa5, 0xa3, 0x44, 0x94, 0x69, 0x7a, // ....D.iz 0x88, 0xec, 0xa9, 0x18, 0xf3, 0xac, 0x38, 0xe6, // ......8. 0xe7, 0xe0, 0xe1, 0x11, 0xa8, 0xa5, 0x5f, 0x18, // ......_. 0x00, 0x72, 0xd0, 0x00, 0x9e, 0x12, 0x89, 0x50, // .r.....P 0x96, 0x20, 0xdb, 0xcd, 0x63, 0xe7, 0xb3, 0xc0, // . ..c... 0xfa, 0x54, 0xa1, 0xe7, 0x4a, 0x74, 0x5d, 0xcd, // .T..Jt]. 0x4a, 0x2f, 0x4c, 0x44, 0xa3, 0xdc, 0x40, 0xad, // J/LD..@. 0xe7, 0xdc, 0x4d, 0x9b, 0x2a, 0x55, 0x13, 0x0b, // ..M.*U.. 0x4d, 0x4f, 0x3d, 0xc3, 0x02, 0xac, 0xd2, 0x03, // MO=..... 0x70, 0x0a, 0x48, 0xa9, 0x96, 0x5b, 0x04, 0x57, // p.H..[.W 0xb9, 0xe2, 0x5a, 0x04, 0x5e, 0xcf, 0x6f, 0x4e, // ..Z.^.oN 0x4c, 0xf3, 0x8e, 0xa2, 0xd0, 0xd9, 0xcb, 0x01, // L....... 0xbc, 0x8c, 0x14, 0xd5, 0x08, 0xfc, 0x18, 0x08, // ........ 0xc1, 0x65, 0x83, 0x3f, 0x0e, 0xa4, 0x17, 0x1c, // .e.?.... 0x6e, 0x45, 0x0a, 0xef, 0x1d, 0x40, 0xc4, 0x7b, // nE...@.{ 0x6a, 0x7e, 0x5d, 0xa6, 0xde, 0x97, 0x22, 0x7b, // j~]..."{ 0x67, 0xbf, 0xc0, 0xa2, 0x83, 0x39, 0xb6, 0xf6, // g....9.. 0x15, 0x16, 0xc6, 0x6f, 0x09, 0x61, 0xb1, 0x02, // ...o.a.. 0x03, 0x01, 0x00, 0x01, 0xa3, 0x4c, 0x30, 0x4a, // .....L0J 0x30, 0x48, 0x06, 0x03, 0x55, 0x1d, 0x01, 0x04, // 0H..U... 0x41, 0x30, 0x3f, 0x80, 0x10, 0x0d, 0x27, 0x29, // A0?...') 0xe4, 0x05, 0x2a, 0x97, 0xb4, 0x77, 0x58, 0x35, // ..*..wX5 0x47, 0x93, 0x2d, 0x06, 0xb8, 0xa1, 0x1f, 0x30, // G.-....0 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, // .1.0...U 0x04, 0x03, 0x13, 0x12, 0x52, 0x6f, 0x6f, 0x74, // ....Root 0x20, 0x53, 0x47, 0x43, 0x20, 0x41, 0x75, 0x74, // SGC Aut 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x82, 0x0a, // hority.. 0x20, 0x9d, 0x11, 0xd1, 0x0e, 0x7f, 0x7b, 0x85, // .....{. 0x74, 0x80, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, // t.0...*. 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, // H....... 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x2b, 0x02, // ......+. 0x2b, 0x37, 0x66, 0xa5, 0xd1, 0x8c, 0x3e, 0x20, // +7f...> 0x08, 0x1a, 0x0c, 0xb7, 0xf5, 0x63, 0xcb, 0xc6, // .....c.. 0xdd, 0x9b, 0x62, 0x52, 0x32, 0xbc, 0x33, 0x74, // ..bR2.3t 0x7a, 0xde, 0xb0, 0x80, 0x05, 0xfa, 0xe5, 0xb5, // z....... 0xe4, 0xf7, 0xf1, 0xd7, 0xa0, 0x95, 0x5c, 0x6c, // .......l 0x05, 0x9b, 0x2f, 0x03, 0x4b, 0xb7, 0x8a, 0x95, // ../.K... 0x0e, 0xb0, 0x06, 0x80, 0xa0, 0x2a, 0x1b, 0xa4, // .....*.. 0x09, 0x58, 0xbd, 0x87, 0xd4, 0x38, 0x44, 0xb4, // .X...8D. 0x71, 0x7b, 0xfb, 0x74, 0xa2, 0x89, 0x48, 0xe6, // q{.t..H. 0x5f, 0xab, 0x9a, 0xa4, 0x0a, 0x38, 0xcc, 0x57, // _....8.W 0xa1, 0x14, 0x2c, 0x5c, 0xee, 0xc2, 0x13, 0x81, // ..,..... 0x00, 0xc3, 0x2d, 0xb1, 0x70, 0xde, 0x9f, 0xb1, // ..-.p... 0x70, 0x43, 0x7e, 0x22, 0xa0, 0x77, 0x96, 0xc8, // pC~".w.. 0xdf, 0x99, 0xdc, 0xa6, 0x4e, 0xb3, 0xb5, 0x74, // ....N..t 0x34, 0x13, 0x12, 0x24, 0xa2, 0x6b, 0x95, 0x80, // 4..$.k.. 0xcf, 0xaa, 0x4a, 0x68, 0xb1, 0x77, 0x27, 0x98, // ..Jh.w'. 0xef, 0xaa, 0x62, 0xd3, 0x22, 0x81, 0x33, 0x2b, // ..b.".3+ 0x12, 0x50, 0xef, 0x16, 0x86, 0xe6, 0x9a, 0x5a, // .P.....Z 0x73, 0x89, 0x6d, 0x83, 0xf2, 0x08, 0xa3, 0x13, // s.m..... 0xab, 0x05, 0xd5, 0x6e, 0x68, 0xf6, 0x90, 0xa4, // ...nh... 0x4a, 0x9f, 0x7c, 0x4c, 0x5d, 0x8f, 0x58, 0xf3, // J.|L].X. 0x11, 0x4c, 0xc7, 0x08, 0x51, 0xea, 0x76, 0xd1, // .L..Q.v. 0xb5, 0x55, 0x32, 0x3f, 0xff, 0x67, 0xef, 0x35, // .U2?.g.5 0x8c, 0x89, 0xd3, 0xc6, 0x75, 0x15, 0x68, 0x9f, // ....u.h. 0x67, 0x46, 0x9c, 0x94, 0x41, 0xf5, 0x76, 0x51, // gF..A.vQ 0x86, 0xac, 0x91, 0x75, 0xec, 0xb6, 0xf7, 0x00, // ...u.... 0x40, 0x5b, 0xfe, 0x61, 0xd8, 0x33, 0x2d, 0x37, // @[.a.3-7 0x65, 0x8b, 0x94, 0xd9, 0x97, 0x21, 0x15, 0x2c, // e....!., 0x13, 0x49, 0xff, 0xde, 0xb7, 0x83, 0xd9, 0xae, // .I...... 0xc4, 0xce, 0x24, 0xb2, 0x50, 0xdf, 0x75, 0x14, // ..$.P.u. 0x12, 0x8c, 0x46, 0xa4, 0xac, 0xef, 0x4c, 0x72, // ..F...Lr 0x00, 0x00, 0xe1, 0x4c, 0x8e, 0xee }; // ...L.. // Versign Class 3 SGC Root static CONST BYTE VSCLASS3ROOT[] = { 0x30, 0x82, 0x02, 0x31, 0x30, 0x82, 0x01, 0x9a, 0x02, 0x05, 0x02, 0xa1, 0x00, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x36, 0x30, 0x31, 0x32, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc9, 0x5c, 0x59, 0x9e, 0xf2, 0x1b, 0x8a, 0x01, 0x14, 0xb4, 0x10, 0xdf, 0x04, 0x40, 0xdb, 0xe3, 0x57, 0xaf, 0x6a, 0x45, 0x40, 0x8f, 0x84, 0x0c, 0x0b, 0xd1, 0x33, 0xd9, 0xd9, 0x11, 0xcf, 0xee, 0x02, 0x58, 0x1f, 0x25, 0xf7, 0x2a, 0xa8, 0x44, 0x05, 0xaa, 0xec, 0x03, 0x1f, 0x78, 0x7f, 0x9e, 0x93, 0xb9, 0x9a, 0x00, 0xaa, 0x23, 0x7d, 0xd6, 0xac, 0x85, 0xa2, 0x63, 0x45, 0xc7, 0x72, 0x27, 0xcc, 0xf4, 0x4c, 0xc6, 0x75, 0x71, 0xd2, 0x39, 0xef, 0x4f, 0x42, 0xf0, 0x75, 0xdf, 0x0a, 0x90, 0xc6, 0x8e, 0x20, 0x6f, 0x98, 0x0f, 0xf8, 0xac, 0x23, 0x5f, 0x70, 0x29, 0x36, 0xa4, 0xc9, 0x86, 0xe7, 0xb1, 0x9a, 0x20, 0xcb, 0x53, 0xa5, 0x85, 0xe7, 0x3d, 0xbe, 0x7d, 0x9a, 0xfe, 0x24, 0x45, 0x33, 0xdc, 0x76, 0x15, 0xed, 0x0f, 0xa2, 0x71, 0x64, 0x4c, 0x65, 0x2e, 0x81, 0x68, 0x45, 0xa7, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x75, 0x66, 0x6c, 0x3e, 0xd1, 0xcd, 0x81, 0xdb, 0xb5, 0xf8, 0x2f, 0x36, 0x51, 0xb6, 0xf7, 0x42, 0xbc, 0xcd, 0x42, 0xaf, 0xdc, 0x0e, 0xfa, 0x15, 0x6c, 0xf8, 0x67, 0x93, 0x57, 0x3a, 0xeb, 0xb6, 0x92, 0xe8, 0xb6, 0x01, 0xca, 0x8c, 0xb7, 0x8e, 0x43, 0xb4, 0x49, 0x65, 0xf9, 0x3e, 0xee, 0xbd, 0x75, 0x46, 0x2e, 0xc9, 0xfc, 0x25, 0x5d, 0xa8, 0xc7, 0x2f, 0x8b, 0x9b, 0x8f, 0x68, 0xcf, 0xb4, 0x9c, 0x97, 0x18, 0xc0, 0x4d, 0xef, 0x1f, 0xd9, 0xaf, 0x82, 0xb3, 0xe6, 0x64, 0xb8, 0x84, 0x5c, 0x8a, 0x9a, 0x07, 0x52, 0x43, 0x61, 0xfb, 0x74, 0x9e, 0x5b, 0x3a, 0x36, 0xfc, 0x4c, 0xb2, 0xfc, 0x1a, 0x3f, 0x15, 0x2e, 0xa5, 0x5b, 0x3c, 0x1b, 0x90, 0xec, 0x88, 0x29, 0xe4, 0x59, 0x16, 0xf9, 0xce, 0x07, 0xad, 0xec, 0xe9, 0xdd, 0xda, 0xd2, 0x31, 0x8a, 0x4f, 0xd6, 0xd8, 0xef, 0x17, 0x8d }; // SGC Test Root #ifdef SGC_TEST_KEY static CONST BYTE TestSGCRoot[] = { 0x30, 0x82, 0x01, 0xda, 0x30, 0x82, 0x01, 0x84, // 0...0... 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x46, // .......F 0xeb, 0x72, 0x4f, 0xc0, 0x00, 0x78, 0xab, 0x11, // .rO..x.. 0xd2, 0x84, 0xb0, 0x35, 0xb8, 0xe0, 0xb1, 0x30, // ...5...0 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, // ...*.H.. 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x26, // ......0& 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, // 1$0"..U. 0x03, 0x13, 0x1b, 0x53, 0x63, 0x68, 0x61, 0x6e, // ...Schan 0x6e, 0x65, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, // nel Test 0x20, 0x53, 0x47, 0x43, 0x20, 0x41, 0x75, 0x74, // SGC Aut 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, // hority0. 0x17, 0x0d, 0x39, 0x38, 0x31, 0x31, 0x32, 0x35, // ..981125 0x32, 0x31, 0x34, 0x35, 0x35, 0x34, 0x5a, 0x17, // 214554Z. 0x0d, 0x33, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, // .3912312 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x26, // 35959Z0& 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, // 1$0"..U. 0x03, 0x13, 0x1b, 0x53, 0x63, 0x68, 0x61, 0x6e, // ...Schan 0x6e, 0x65, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, // nel Test 0x20, 0x53, 0x47, 0x43, 0x20, 0x41, 0x75, 0x74, // SGC Aut 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x5c, // hority0. 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, // 0...*.H. 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, // ........ 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xd1, // K.0H.A.. 0x95, 0x8e, 0x14, 0xc9, 0x8b, 0x28, 0x00, 0xd4, // .....(.. 0xed, 0x40, 0xb5, 0xd4, 0xec, 0x1f, 0x67, 0xb1, // .@....g. 0xa2, 0xb3, 0x18, 0xca, 0x6b, 0x48, 0x6c, 0x54, // ....kHlT 0xaf, 0xc4, 0x70, 0x3c, 0x6e, 0xee, 0x15, 0xba, // ..ppCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, 0, NULL, &cbBlob)) { dwReturn = (DWORD)NTE_BAD_DATA; // ?BUGBUG? Always? goto ErrorExit; } pBlob = (BLOBHEADER*)SGCAlloc(cbBlob); if (NULL == pBlob) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } if (!CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, 0, pBlob, &cbBlob)) { dwReturn = (DWORD)NTE_BAD_DATA; // ?BUGBUG? Always? goto ErrorExit; } pRSAPubKey = (RSAPUBKEY*)((BYTE*)pBlob + sizeof(BLOBHEADER)); // delete any old public key info SGCDeletePubKeyValues(ppbKeyMod, pcbKeyMod, pdwKeyExpo); // assign public key values *pdwKeyExpo = pRSAPubKey->pubexp; *pcbKeyMod = pRSAPubKey->bitlen / 8; *ppbKeyMod = (BYTE*)SGCAlloc(*pcbKeyMod); if (NULL == *ppbKeyMod) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } pb = (BYTE*)pRSAPubKey + sizeof(RSAPUBKEY); memcpy(*ppbKeyMod, pb, *pcbKeyMod); dwReturn = ERROR_SUCCESS; ErrorExit: if (pBlob) SGCFree(pBlob); return dwReturn; } // // check if the passed in public key matches the one in the cert // static DWORD SamePublicKey( IN PCCERT_CONTEXT pCertContext, IN BYTE *pbExchKeyMod, IN DWORD cbExchKeyMod, IN DWORD dwExchKeyExpo) { DWORD dwReturn = ERROR_INTERNAL_ERROR; BLOBHEADER *pBlob = NULL; DWORD cbBlob = 0; RSAPUBKEY *pRSAPubKey; BYTE *pb; // decode the public key from the cert into a PUBLICKEYBLOB if (!CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, 0, NULL, &cbBlob)) { dwReturn = (DWORD)NTE_BAD_DATA; // ?BUGBUG? Always? goto ErrorExit; } pBlob = (BLOBHEADER*)SGCAlloc(cbBlob); if (NULL == pBlob) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; goto ErrorExit; } if (!CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, 0, pBlob, &cbBlob)) { dwReturn = (DWORD)NTE_BAD_DATA; // ?BUGBUG? Always? goto ErrorExit; } pRSAPubKey = (RSAPUBKEY*)((BYTE*)pBlob + sizeof(BLOBHEADER)); // check the length of the modulus and the exponent if (((pRSAPubKey->bitlen / 8) != cbExchKeyMod) || (pRSAPubKey->pubexp != dwExchKeyExpo)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } // check that the modulus values match pb = (BYTE*)pRSAPubKey + sizeof(RSAPUBKEY); if (0 != memcmp(pbExchKeyMod, pb, cbExchKeyMod)) { dwReturn = (DWORD)NTE_BAD_DATA; goto ErrorExit; } dwReturn = ERROR_SUCCESS; ErrorExit: if (pBlob) SGCFree(pBlob); return dwReturn; } static DWORD ReadSgcExtensions( PCCERT_CONTEXT pCertContext) { PCERT_EXTENSION pExt; PCTL_USAGE pUsage = NULL; DWORD cbUsage; DWORD dwSGCFlags = 0; DWORD i; pExt = CertFindExtension(szOID_ENHANCED_KEY_USAGE, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension); if (pExt == NULL) goto cleanup; if (!CryptDecodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, pExt->Value.pbData, pExt->Value.cbData, 0, NULL, &cbUsage)) { goto cleanup; } pUsage = (PCTL_USAGE)SGCAlloc(cbUsage); if (pUsage == NULL) goto cleanup; if (!CryptDecodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, pExt->Value.pbData, pExt->Value.cbData, 0, pUsage, &cbUsage)) { goto cleanup; } for (i = 0; i < pUsage->cUsageIdentifier; i++) { if (0 == strcmp(pUsage->rgpszUsageIdentifier[i], szOID_SGC_NETSCAPE)) { dwSGCFlags |= CRYPT_SGC; } else if (0 == strcmp(pUsage->rgpszUsageIdentifier[i], szOID_SERVER_GATED_CRYPTO)) { dwSGCFlags |= CRYPT_FASTSGC | CRYPT_SGC; } } cleanup: if (pUsage) SGCFree(pUsage); return dwSGCFlags; } //+--------------------------------------------------------------------------- // // Function: FindBridgeCertificate // // Synopsis: Search the specified certificate store for a valid SGC // bridge certificate. // // Arguments: [hCAStore] -- Certificate store to search. This is // typically the CA store. // // [pChainContext] -- Certificate chain for which we are finding // a bridge certificate. The bridge cert // may branch off of any certificate in the // chain. // // [pRootContext] -- Handle to baked-in SGC root certificate // (typically Geneva). // // History: 11-16-98 jbanes Created // // Notes: An SGC bridge certificate is defined as a certificate with a // SUBJECT equal to the ISSUER in one of the 'pChainContext' // certificates. To be valid, the bridge certificate must // contain at least one SGC EKU and it must chain up to a // baked-in SGC root certificate. // // Returns: TRUE if a valid SGC bridge cert was found, and FALSE // otherwise. // //---------------------------------------------------------------------------- static BOOL FindBridgeCertificate( IN HCERTSTORE hCAStore, IN PCCERT_CHAIN_CONTEXT pChainContext, IN PCCERT_CONTEXT pRootContext) { PCERT_SIMPLE_CHAIN pSimpleChain; PCCERT_CONTEXT pCurrent = NULL; PCCERT_CONTEXT pCurrentCA = NULL; PCCERT_CHAIN_CONTEXT pCAChainContext = NULL; CERT_CHAIN_PARA ChainPara; CERT_TRUST_STATUS TrustStatus; BOOL fFound; DWORD i; BOOL fRet = FALSE; DWORD dwFlags; // // Enumerate all of the certificates in the CA store that contain // one of the SGC extensions. // pCurrent = NULL; for (;;) { // Find an SGC intermediate certificate. pCurrentCA = CertFindCertificateInStore( hCAStore, X509_ASN_ENCODING, CERT_FIND_OR_ENHKEY_USAGE_FLAG, CERT_COMPARE_ENHKEY_USAGE, &SGCExtensions, pCurrentCA); if (pCurrentCA == NULL) break; // // Is this CA certificate a bridge for any of the certificates in the // passed in certificate chain? // fFound = FALSE; pSimpleChain = pChainContext->rgpChain[0]; for (i = 0; i < pSimpleChain->cElement; i++) { pCurrent = pSimpleChain->rgpElement[i]->pCertContext; if (ReadSgcExtensions(pCurrent) == 0) { // This certificate doesn't contain any SGC certificate // extensions, so skip the rest of this chain. break; } if (CertCompareCertificateName(X509_ASN_ENCODING, &pCurrentCA->pCertInfo->Subject, &pCurrent->pCertInfo->Issuer)) { // The names match. Now check the signature. dwFlags = SGC_VERIFICATION_FLAGS; if (!CertVerifySubjectCertificateContext(pCurrent, pCurrentCA, &dwFlags)) { // Error checking signature. continue; } if (dwFlags & SGC_VERIFICATION_FLAGS) { // Signature did not verify or certificate expired. continue; } fFound = TRUE; break; } } if (!fFound) continue; // // Does this CA certificate chain up to Geneva? // ZeroMemory(&ChainPara, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); if (!CertGetCertificateChain(NULL, pCurrentCA, NULL, hCAStore, &ChainPara, 0, NULL, &pCAChainContext)) { // Error building chain. continue; } pSimpleChain = pCAChainContext->rgpChain[0]; for (i = 0; i < pSimpleChain->cElement; i++) { pCurrent = pSimpleChain->rgpElement[i]->pCertContext; // Determine if certificate is signed correctly. TrustStatus = pSimpleChain->rgpElement[i]->TrustStatus; if (0 != (TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)) { break; } // Is issuer Geneva? if (CertCompareCertificateName(pCurrent->dwCertEncodingType, &pCurrent->pCertInfo->Issuer, &pRootContext->pCertInfo->Subject)) { // Verify the signature of the current certificate using the // validated root certificate from the schannel resource. dwFlags = SGC_VERIFICATION_FLAGS; if (!CertVerifySubjectCertificateContext(pCurrent, pRootContext, &dwFlags)) { break; } if (dwFlags & SGC_VERIFICATION_FLAGS) break; fRet = TRUE; goto ErrorExit; } } } ErrorExit: if (pCurrentCA) CertFreeCertificateContext(pCurrentCA); if (pCAChainContext) CertFreeCertificateChain(pCAChainContext); return fRet; } // // check if the context may be SGC enabled // DWORD SPQueryCFLevel( IN PCCERT_CONTEXT pCertContext, IN BYTE *pbExchKeyMod, IN DWORD cbExchKeyMod, IN DWORD dwExchKeyExpo, OUT DWORD *pdwSGCFlags) { DWORD dwReturn = ERROR_INTERNAL_ERROR; DWORD i, j; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_CHAIN_PARA ChainPara; PCERT_SIMPLE_CHAIN pSimpleChain; CERT_TRUST_STATUS TrustStatus; HCERTSTORE hCAStore = NULL; PCCERT_CONTEXT pCurrent = NULL; PCCERT_CONTEXT pIssuer = NULL; DWORD dwFlags; DWORD dwSgcFlags; DWORD dwSts; *pdwSGCFlags = 0; // // check if the passed in public key matches the one in the cert // if (pbExchKeyMod) { dwSts = SamePublicKey(pCertContext, pbExchKeyMod, cbExchKeyMod, dwExchKeyExpo); if (ERROR_SUCCESS != dwSts) { dwReturn = dwSts; goto ErrorExit; } } // // Does the leaf certificate contain any SGC extensions? // dwSgcFlags = ReadSgcExtensions(pCertContext); if (dwSgcFlags == 0) { // No SGC extensions found. dwReturn = ERROR_SUCCESS; goto ErrorExit; } // // Build a certificate chain. // ZeroMemory(&ChainPara, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); *pdwSGCFlags = 0; if (!CertGetCertificateChain( NULL, pCertContext, NULL, pCertContext->hCertStore, &ChainPara, 0, NULL, &pChainContext)) { dwReturn = GetLastError(); goto ErrorExit; } // // Does the leaf chain directly up to the Geneva root? // pSimpleChain = pChainContext->rgpChain[0]; for (i = 0; i < pSimpleChain->cElement; i++) { pCurrent = pSimpleChain->rgpElement[i]->pCertContext; if (ReadSgcExtensions(pCurrent) == 0) { // This certificate doesn't contain any SGC certificate // extensions, so skip the rest of this chain. break; } TrustStatus = pSimpleChain->rgpElement[i]->TrustStatus; if (0 != (TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)) { // Certificate is not signed correctly. dwReturn = (DWORD)NTE_BAD_SIGNATURE; goto ErrorExit; } // Is Geneva issuer of "pCurrent"? for (j = 0; j < SGCRootCount; j++) { dwFlags = SGC_VERIFICATION_FLAGS; if (!CertVerifySubjectCertificateContext( pCurrent, SGCRoots[j].pCertContext, &dwFlags)) { continue; } if (dwFlags & SGC_VERIFICATION_FLAGS) { continue; } // We made it, so set the SGC flags as appropriate. *pdwSGCFlags |= dwSgcFlags; dwReturn = ERROR_SUCCESS; goto ErrorExit; } } // // Search for bridge certificate. // hCAStore = CertOpenSystemStore(0, "CA"); if (NULL == hCAStore) { dwReturn = GetLastError(); goto ErrorExit; } for (i = 0; i < SGCRootCount; i++) { if (SGCRoots[i].pCertContext != NULL) { if (FindBridgeCertificate(hCAStore, pChainContext, SGCRoots[i].pCertContext)) { // We made it, so set the SGC flags as appropriate. *pdwSGCFlags |= dwSgcFlags; dwReturn = ERROR_SUCCESS; goto ErrorExit; } } } dwReturn = (DWORD)NTE_FAIL; ErrorExit: if (pIssuer) CertFreeCertificateContext(pIssuer); if (pChainContext) CertFreeCertificateChain(pChainContext); if (hCAStore) CertCloseStore(hCAStore, 0); return dwReturn; }