@@ -113,6 +113,14 @@ var (
113113 nCryptAlgorithmGroupProperty = wide ("Algorithm Group" ) // NCRYPT_ALGORITHM_GROUP_PROPERTY
114114 nCryptUniqueNameProperty = wide ("Unique Name" ) // NCRYPT_UNIQUE_NAME_PROPERTY
115115 nCryptECCCurveNameProperty = wide ("ECCCurveName" ) // NCRYPT_ECC_CURVE_NAME_PROPERTY
116+ nCryptImplTypeProperty = wide ("Impl Type" ) // NCRYPT_IMPL_TYPE_PROPERTY
117+ nCryptProviderHandleProperty = wide ("Provider Handle" ) // NCRYPT_PROV_HANDLE
118+
119+ // Flags for NCRYPT_IMPL_TYPE_PROPERTY
120+ nCryptImplHardwareFlag = 0x00000001 // NCRYPT_IMPL_HARDWARE_FLAG
121+ nCryptImplSoftwareFlag = 0x00000002 // NCRYPT_IMPL_SOFTWARE_FLAG
122+ nCryptImplRemovableFlag = 0x00000008 // NCRYPT_IMPL_REMOVABLE_FLAG
123+ nCryptImplHardwareRngFlag = 0x00000010 // NCRYPT_IMPL_HARDWARE_RNG_FLAG
116124
117125 // curveIDs maps bcrypt key blob magic numbers to elliptic curves.
118126 curveIDs = map [uint32 ]elliptic.Curve {
@@ -413,15 +421,19 @@ func (w *WinCertStore) cert(issuers []string, searchRoot *uint16, store uint32)
413421 return cert , prev , nil
414422}
415423
416- // Close frees the handle to the certificate provider
417- func (w * WinCertStore ) Close () error {
418- r , _ , err := nCryptFreeObject .Call (w .Prov )
424+ func freeObject (h uintptr ) error {
425+ r , _ , err := nCryptFreeObject .Call (h )
419426 if r == 0 {
420427 return nil
421428 }
422429 return fmt .Errorf ("NCryptFreeObject returned %X: %v" , r , err )
423430}
424431
432+ // Close frees the handle to the certificate provider
433+ func (w * WinCertStore ) Close () error {
434+ return freeObject (w .Prov )
435+ }
436+
425437// Link will associate the certificate installed in the system store to the user store.
426438func (w * WinCertStore ) Link () error {
427439 cert , _ , err := w .cert (w .issuers , my , certStoreLocalMachine )
@@ -1066,21 +1078,39 @@ func (w *WinCertStore) generateRSA(keySize int) (crypto.Signer, error) {
10661078
10671079func keyMetadata (kh uintptr , store * WinCertStore ) (* Key , error ) {
10681080 // uc is used to populate the unique container name attribute of the private key
1069- uc , err := getProperty (kh , nCryptUniqueNameProperty )
1081+ uc , err := getPropertyStr (kh , nCryptUniqueNameProperty )
10701082 if err != nil {
10711083 return nil , fmt .Errorf ("unable to determine key unique name: %v" , err )
10721084 }
10731085
1086+ // get the provider handle
1087+ ph , err := getPropertyHandle (kh , nCryptProviderHandleProperty )
1088+ if err != nil {
1089+ return nil , fmt .Errorf ("unable to determine key provider: %v" , err )
1090+ }
1091+ defer freeObject (ph )
1092+
1093+ // get the provider implementation from the provider handle
1094+ impl , err := getPropertyInt (ph , nCryptImplTypeProperty )
1095+ if err != nil {
1096+ return nil , fmt .Errorf ("unable to determine provider implementation: %v" , err )
1097+ }
1098+
10741099 // Populate key storage locations for software backed keys.
10751100 var lc string
1076- if store .ProvName != ProviderMSPlatform {
1101+
1102+ // Functions like cert() pull certs from the local store *regardless*
1103+ // of the provider OpenWinCertStore was given. This means we cannot rely on
1104+ // store.Prov to tell us which provider a given key resides in. Instead, we
1105+ // lookup the provider directly from the key properties.
1106+ if impl == nCryptImplSoftwareFlag {
10771107 uc , lc , err = softwareKeyContainers (uc )
10781108 if err != nil {
10791109 return nil , err
10801110 }
10811111 }
10821112
1083- alg , err := getProperty (kh , nCryptAlgorithmGroupProperty )
1113+ alg , err := getPropertyStr (kh , nCryptAlgorithmGroupProperty )
10841114 if err != nil {
10851115 return nil , fmt .Errorf ("unable to determine key algorithm: %v" , err )
10861116 }
@@ -1109,7 +1139,7 @@ func keyMetadata(kh uintptr, store *WinCertStore) (*Key, error) {
11091139 return & Key {handle : kh , pub : pub , Container : uc , LegacyContainer : lc , AlgorithmGroup : alg }, nil
11101140}
11111141
1112- func getProperty (kh uintptr , property * uint16 ) (string , error ) {
1142+ func getProperty (kh uintptr , property * uint16 ) ([] byte , error ) {
11131143 var strSize uint32
11141144 r , _ , err := nCryptGetProperty .Call (
11151145 kh ,
@@ -1120,7 +1150,7 @@ func getProperty(kh uintptr, property *uint16) (string, error) {
11201150 0 ,
11211151 0 )
11221152 if r != 0 {
1123- return "" , fmt .Errorf ("NCryptGetProperty(%v) returned %X during size check: %v" , property , r , err )
1153+ return nil , fmt .Errorf ("NCryptGetProperty(%v) returned %X during size check: %v" , property , r , err )
11241154 }
11251155
11261156 buf := make ([]byte , strSize )
@@ -1133,9 +1163,39 @@ func getProperty(kh uintptr, property *uint16) (string, error) {
11331163 0 ,
11341164 0 )
11351165 if r != 0 {
1136- return "" , fmt .Errorf ("NCryptGetProperty %v returned %X during export: %v" , property , r , err )
1166+ return nil , fmt .Errorf ("NCryptGetProperty %v returned %X during export: %v" , property , r , err )
11371167 }
11381168
1169+ return buf , nil
1170+ }
1171+
1172+ func getPropertyHandle (kh uintptr , property * uint16 ) (uintptr , error ) {
1173+ buf , err := getProperty (kh , property )
1174+ if err != nil {
1175+ return 0 , err
1176+ }
1177+ if len (buf ) < 1 {
1178+ return 0 , fmt .Errorf ("empty result" )
1179+ }
1180+ return * * (* * uintptr )(unsafe .Pointer (& buf )), nil
1181+ }
1182+
1183+ func getPropertyInt (kh uintptr , property * uint16 ) (int , error ) {
1184+ buf , err := getProperty (kh , property )
1185+ if err != nil {
1186+ return 0 , err
1187+ }
1188+ if len (buf ) < 1 {
1189+ return 0 , fmt .Errorf ("empty result" )
1190+ }
1191+ return * * (* * int )(unsafe .Pointer (& buf )), nil
1192+ }
1193+
1194+ func getPropertyStr (kh uintptr , property * uint16 ) (string , error ) {
1195+ buf , err := getProperty (kh , property )
1196+ if err != nil {
1197+ return "" , err
1198+ }
11391199 uc := strings .Replace (string (buf ), string (0x00 ), "" , - 1 )
11401200 return uc , nil
11411201}
@@ -1257,7 +1317,7 @@ func unmarshalECC(buf []byte, kh uintptr) (*ecdsa.PublicKey, error) {
12571317
12581318// curveName reads the curve name property and returns the corresponding curve.
12591319func curveName (kh uintptr ) (elliptic.Curve , error ) {
1260- cn , err := getProperty (kh , nCryptECCCurveNameProperty )
1320+ cn , err := getPropertyStr (kh , nCryptECCCurveNameProperty )
12611321 if err != nil {
12621322 return nil , fmt .Errorf ("unable to determine the curve property name: %v" , err )
12631323 }
0 commit comments