/////////////////////////////////////////////////////////////////////////////
//  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 <windows.h>
#include <windef.h>
#include <wincrypt.h>
#include <sgccheck.h>

#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,     // ..p<n...
    0x4b, 0xf7, 0x40, 0x93, 0xd3, 0x35, 0x1d, 0x17,     // K.@..5..
    0x6c, 0xe8, 0x1d, 0x62, 0xec, 0x74, 0x96, 0x48,     // l..b.t.H
    0x4f, 0x1e, 0xcf, 0xf0, 0x54, 0x2b, 0x30, 0x0b,     // O...T+0.
    0x66, 0x3a, 0x83, 0x1c, 0x32, 0xda, 0x3d, 0x02,     // f:..2.=.
    0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x8d, 0x30,     // .......0
    0x81, 0x8a, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x1d,     // ..0...U.
    0x0a, 0x04, 0x06, 0x30, 0x04, 0x03, 0x02, 0x07,     // ...0....
    0x80, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d, 0x25,     // .0 ..U.%
    0x04, 0x19, 0x30, 0x17, 0x06, 0x0a, 0x2b, 0x06,     // ..0...+.
    0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x03,     // ....7...
    0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,     // ..`.H...
    0x42, 0x04, 0x01, 0x30, 0x57, 0x06, 0x03, 0x55,     // B..0W..U
    0x1d, 0x01, 0x04, 0x50, 0x30, 0x4e, 0x80, 0x10,     // ...P0N..
    0x35, 0x2f, 0x90, 0xa8, 0x13, 0xd6, 0x82, 0x32,     // 5......2
    0x85, 0x1a, 0x5d, 0x0f, 0xdc, 0x83, 0xe3, 0x28,     // ..]....(
    0xa1, 0x28, 0x30, 0x26, 0x31, 0x24, 0x30, 0x22,     // .(0&1$0"
    0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1b, 0x53,     // ..U....S
    0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x20,     // channel
    0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x47, 0x43,     // Test SGC
    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,     //  Authori
    0x74, 0x79, 0x82, 0x10, 0x46, 0xeb, 0x72, 0x4f,     // ty..F.rO
    0xc0, 0x00, 0x78, 0xab, 0x11, 0xd2, 0x84, 0xb0,     // ..x.....
    0x35, 0xb8, 0xe0, 0xb1, 0x30, 0x0d, 0x06, 0x09,     // 5...0...
    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,     // *.H.....
    0x04, 0x05, 0x00, 0x03, 0x41, 0x00, 0x65, 0x35,     // ....A.e5
    0x80, 0xaf, 0xa3, 0xba, 0x5d, 0x13, 0xcd, 0x86,     // ....]...
    0xad, 0xda, 0x06, 0xb6, 0xb3, 0x51, 0xf4, 0x71,     // .....Q.q
    0x4a, 0x0b, 0xd2, 0xc1, 0x91, 0x13, 0xc3, 0x0c,     // J.......
    0xd7, 0xb7, 0x9f, 0xa6, 0x3c, 0x04, 0xfa, 0xb7,     // ....<...
    0x97, 0x94, 0x64, 0xf0, 0x5b, 0xab, 0x65, 0x3b,     // ..d.[.e;
    0x88, 0x95, 0x59, 0x4c, 0x18, 0x11, 0xc4, 0xac,     // ..YL....
    0x5c, 0x6e, 0x31, 0xf0, 0xdd, 0x74, 0xc1, 0x55,     // .n1..t.U
    0x7e, 0x7f, 0x66, 0xf4, 0x8a, 0x57 };               // ~.f..W
#endif // SGC_TEST_KEY


typedef struct SGC_ROOT
{
    CONST BYTE *    pbCert;
    DWORD           cbCert;
    PCCERT_CONTEXT  pCertContext;
} SGC_ROOT, *PSGC_ROOT;


static SGC_ROOT SGCRoots[] = {
    { GenevaSGCRoot,    sizeof(GenevaSGCRoot),  NULL },
    { VSCLASS3ROOT,     sizeof(VSCLASS3ROOT),   NULL },
#ifdef SGC_TEST_KEY
    { TestSGCRoot,      sizeof(TestSGCRoot),    NULL }
#endif // SGC_TEST_KEY
};

static CONST DWORD SGCRootCount = sizeof(SGCRoots) / sizeof(SGC_ROOT);

static CONST LPCSTR rgSGCExtensions[]
    = { szOID_SGC_NETSCAPE,
        szOID_SERVER_GATED_CRYPTO };

static CONST CERT_ENHKEY_USAGE SGCExtensions
    = { sizeof(rgSGCExtensions)/sizeof(LPSTR),
        (LPSTR *)rgSGCExtensions };


//
// Load root certs
//

DWORD
LoadSGCRoots(
    IN CRITICAL_SECTION *pCritSec)  // must be initialized
{
    DWORD   dwReturn = ERROR_INTERNAL_ERROR;
    BOOL    fInCritSec = FALSE;
    BOOL    fLoadRoots = FALSE;
    DWORD   i;

    // check if the Roots are already loaded
    for (i = 0; i < SGCRootCount; i++)
    {
        if (SGCRoots[i].pCertContext == NULL)
        {
            fLoadRoots = TRUE;
            break;
        }
    }
    if (!fLoadRoots)
    {
        dwReturn = ERROR_SUCCESS;
        goto ErrorExit;
    }

    // wrap with a try since there is a critical sections in here
    __try
    {
        // take the critical section
        EnterCriticalSection(pCritSec);
        fInCritSec = TRUE;

        for (i = 0; i < SGCRootCount; i++)
        {
            if (SGCRoots[i].pCertContext == NULL)
            {

                SGCRoots[i].pCertContext = CertCreateCertificateContext(
                                                X509_ASN_ENCODING,
                                                SGCRoots[i].pbCert,
                                                SGCRoots[i].cbCert);
                if (NULL == SGCRoots[i].pCertContext)
                {
                    dwReturn = GetLastError();
                    goto ErrorExit;
                }
            }
        }

    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        // ?BUGBUG? Could be resource exhaustion
        dwReturn = ERROR_INVALID_PARAMETER;
        goto ErrorExit;
    }

    dwReturn = ERROR_SUCCESS;

ErrorExit:
    if (fInCritSec)
        LeaveCriticalSection(pCritSec);
    return dwReturn;
}


//
// delete the public key values
//

void
SGCDeletePubKeyValues(
    IN OUT BYTE **ppbKeyMod,
    IN OUT DWORD *pcbKeyMod,
    IN OUT DWORD *pdwKeyExpo)
{
    if (*ppbKeyMod)
        SGCFree(*ppbKeyMod);
    *ppbKeyMod = NULL;
    *pcbKeyMod = 0;
    *pdwKeyExpo = 0;
}


//
// get the public key form the cert context and assign it to the
// passed in parameters
//

DWORD
SGCAssignPubKey(
    IN PCCERT_CONTEXT pCertContext,
    IN OUT BYTE **ppbKeyMod,
    IN OUT DWORD *pcbKeyMod,
    IN OUT DWORD *pdwKeyExpo)
{
    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));

    // 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;
}