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.
1482 lines
49 KiB
1482 lines
49 KiB
//+-------------------------------------------------------------------------
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1996
|
|
//
|
|
// File: tstore3.cpp
|
|
//
|
|
// Contents: Cert Store API Tests:
|
|
// - CertGetSubjectCertificateFromStore: serial numbers with
|
|
// leading 0's or 0xFF's
|
|
// - Open two system stores. Ensure certs and CRLs are
|
|
// written through
|
|
// - CertStoreSave: test SaveToMemory for serialized and PKCS7
|
|
// - Call CertOpenSystemStoreW
|
|
// - Get hash property for a created context
|
|
// - Do a CertVerifySubjectCertificateContext for a
|
|
// certificate in a store and a certificate context.
|
|
// Should pass for both a store certificate and
|
|
// a certificate context. The certificate context
|
|
// uses the default hCryptProv.
|
|
// - Close a store with a not freed certificate context.
|
|
// Should get a warning at closing.
|
|
// - Delete and recalculate the hash property for a
|
|
// certificate context after the store has been closed.
|
|
// - Delete the certificate context after the store has
|
|
// been closed
|
|
// - Duplicate a certificate. Delete it from the store.
|
|
// Also delete its duplicate. Close the store.
|
|
// - Check that CertCloseStore preserves last error
|
|
// - Win95 test (Win95 has following registry limitations:
|
|
// Max single key value of 16K, max total value length
|
|
// per key of 64K)
|
|
//
|
|
// - Write 8 certificates > 10k to same system store
|
|
// - Write same certificate to two system stores
|
|
// - Set large property > 16K to force certificates to
|
|
// be saved to a file.
|
|
// - Verify written properties.
|
|
// - Delete large property. File should be deleted and
|
|
// certificate stored in registry.
|
|
// - Rewrite large property. Delete certificate.
|
|
// - Check CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG
|
|
//
|
|
// Functions: main
|
|
//
|
|
// History: 11-Jan-97 philh created
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include "wincrypt.h"
|
|
#include "certtest.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <time.h>
|
|
|
|
#define SIGNATURE_ALG_OBJID szOID_RSA_MD5RSA
|
|
#define TEST_ISSUER_NAME "TestIssuer"
|
|
static HCRYPTPROV hCryptProv = 0;
|
|
|
|
static void PrintExpectedError(LPCSTR pszMsg)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
printf("%s got expected error => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
|
|
}
|
|
|
|
void PrintNoError(LPCSTR pszMsg)
|
|
{
|
|
printf("%s failed => expected error\n", pszMsg);
|
|
}
|
|
|
|
static BOOL EncodeIssuer(
|
|
OUT BYTE **ppbIssuerEncoded,
|
|
OUT DWORD *pcbIssuerEncoded
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbIssuerEncoded = NULL;
|
|
DWORD cbIssuerEncoded;
|
|
|
|
CERT_RDN_ATTR rgAttr[1];
|
|
CERT_RDN rgRDN[1];
|
|
CERT_NAME_INFO Name;
|
|
|
|
Name.cRDN = 1;
|
|
Name.rgRDN = rgRDN;
|
|
rgRDN[0].cRDNAttr = 1;
|
|
rgRDN[0].rgRDNAttr = rgAttr;
|
|
|
|
rgAttr[0].pszObjId = szOID_COMMON_NAME;
|
|
rgAttr[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
|
|
rgAttr[0].Value.pbData = (BYTE *) TEST_ISSUER_NAME;
|
|
rgAttr[0].Value.cbData = strlen(TEST_ISSUER_NAME);
|
|
|
|
CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
NULL, // pbEncoded
|
|
&cbIssuerEncoded
|
|
);
|
|
if (cbIssuerEncoded == 0) {
|
|
PrintLastError("EncodeIssuer::CryptEncodeObject(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbIssuerEncoded = (BYTE *) TestAlloc(cbIssuerEncoded);
|
|
if (pbIssuerEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
dwCertEncodingType,
|
|
X509_NAME,
|
|
&Name,
|
|
pbIssuerEncoded,
|
|
&cbIssuerEncoded
|
|
)) {
|
|
PrintLastError("EncodeIssuer::CryptEncodeObject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
*ppbIssuerEncoded = pbIssuerEncoded;
|
|
*pcbIssuerEncoded = cbIssuerEncoded;
|
|
return fResult;
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
if (pbIssuerEncoded) {
|
|
TestFree(pbIssuerEncoded);
|
|
pbIssuerEncoded = 0;
|
|
}
|
|
cbIssuerEncoded = 0;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
static BOOL GetPublicKey(
|
|
PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
|
|
DWORD cbPubKeyInfo;
|
|
DWORD dwKeySpec;
|
|
|
|
dwKeySpec = AT_SIGNATURE;
|
|
CryptExportPublicKeyInfo(
|
|
hCryptProv,
|
|
dwKeySpec,
|
|
dwCertEncodingType,
|
|
NULL, // pPubKeyInfo
|
|
&cbPubKeyInfo
|
|
);
|
|
if (cbPubKeyInfo == 0) {
|
|
PrintLastError("GetPublicKey::CryptExportPublicKeyInfo(cb == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) TestAlloc(cbPubKeyInfo);
|
|
if (pPubKeyInfo == NULL) goto ErrorReturn;
|
|
if (!CryptExportPublicKeyInfo(
|
|
hCryptProv,
|
|
dwKeySpec,
|
|
dwCertEncodingType,
|
|
pPubKeyInfo,
|
|
&cbPubKeyInfo
|
|
)) {
|
|
PrintLastError("GetPublicKey::CryptExportPublicKeyInfo");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
*ppPubKeyInfo = pPubKeyInfo;
|
|
return fResult;
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
if (pPubKeyInfo) {
|
|
TestFree(pPubKeyInfo);
|
|
pPubKeyInfo = NULL;
|
|
}
|
|
goto CommonReturn;
|
|
}
|
|
|
|
static BOOL EncodeCert(
|
|
IN PCRYPT_INTEGER_BLOB pSerialNumber,
|
|
OUT BYTE **ppbCertEncoded,
|
|
OUT DWORD *pcbCertEncoded
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbIssuerEncoded = NULL;
|
|
DWORD cbIssuerEncoded;
|
|
PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
|
|
BYTE *pbCertEncoded = NULL;
|
|
DWORD cbCertEncoded;
|
|
CERT_INFO Cert;
|
|
|
|
if (!EncodeIssuer(&pbIssuerEncoded, &cbIssuerEncoded)) goto ErrorReturn;
|
|
|
|
// PUBLIC KEY
|
|
if (!GetPublicKey(&pPubKeyInfo)) goto ErrorReturn;
|
|
|
|
// CERT
|
|
memset(&Cert, 0, sizeof(Cert));
|
|
Cert.dwVersion = CERT_V3;
|
|
Cert.SerialNumber = *pSerialNumber;
|
|
Cert.SignatureAlgorithm.pszObjId = SIGNATURE_ALG_OBJID;
|
|
Cert.Issuer.pbData = pbIssuerEncoded;
|
|
Cert.Issuer.cbData = cbIssuerEncoded;
|
|
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
GetSystemTime(&SystemTime);
|
|
|
|
SystemTimeToFileTime(&SystemTime, &Cert.NotBefore);
|
|
SystemTime.wYear++;
|
|
if (!SystemTimeToFileTime(&SystemTime, &Cert.NotAfter)) {
|
|
SystemTime.wDay = 1;
|
|
SystemTimeToFileTime(&SystemTime, &Cert.NotAfter);
|
|
}
|
|
}
|
|
|
|
Cert.Subject.pbData = pbIssuerEncoded;
|
|
Cert.Subject.cbData = cbIssuerEncoded;
|
|
Cert.SubjectPublicKeyInfo = *pPubKeyInfo;
|
|
|
|
CryptSignAndEncodeCertificate(
|
|
hCryptProv,
|
|
AT_SIGNATURE,
|
|
dwCertEncodingType,
|
|
X509_CERT_TO_BE_SIGNED,
|
|
&Cert,
|
|
&Cert.SignatureAlgorithm,
|
|
NULL, // pvHashAuxInfo
|
|
NULL, // pbEncoded
|
|
&cbCertEncoded
|
|
);
|
|
if (cbCertEncoded == 0) {
|
|
PrintLastError("CryptSignAndEncodeCertificate(cbEncoded == 0)");
|
|
goto ErrorReturn;
|
|
}
|
|
pbCertEncoded = (BYTE *) TestAlloc(cbCertEncoded);
|
|
if (pbCertEncoded == NULL) goto ErrorReturn;
|
|
if (!CryptSignAndEncodeCertificate(
|
|
hCryptProv,
|
|
AT_SIGNATURE,
|
|
dwCertEncodingType,
|
|
X509_CERT_TO_BE_SIGNED,
|
|
&Cert,
|
|
&Cert.SignatureAlgorithm,
|
|
NULL, // pvHashAuxInfo
|
|
pbCertEncoded,
|
|
&cbCertEncoded
|
|
)) {
|
|
PrintLastError("CryptSignAndEncodeCertificate");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
if (pbIssuerEncoded)
|
|
TestFree(pbIssuerEncoded);
|
|
if (pPubKeyInfo)
|
|
TestFree(pPubKeyInfo);
|
|
*ppbCertEncoded = pbCertEncoded;
|
|
*pcbCertEncoded = cbCertEncoded;
|
|
return fResult;
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
if (pbCertEncoded) {
|
|
TestFree(pbCertEncoded);
|
|
pbCertEncoded = 0;
|
|
}
|
|
cbCertEncoded = 0;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
static PCCERT_CONTEXT GetSubject(
|
|
IN HCERTSTORE hStore,
|
|
IN PCRYPT_INTEGER_BLOB pSerialNumber
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
PCCERT_CONTEXT pCert;
|
|
CERT_INFO CertInfo;
|
|
|
|
memset(&CertInfo, 0, sizeof(CertInfo));
|
|
if (!EncodeIssuer(&CertInfo.Issuer.pbData, &CertInfo.Issuer.cbData))
|
|
return NULL;
|
|
|
|
CertInfo.SerialNumber = *pSerialNumber;
|
|
pCert = CertGetSubjectCertificateFromStore(hStore, dwCertEncodingType,
|
|
&CertInfo);
|
|
if (NULL == pCert)
|
|
PrintLastError("GetSubject");
|
|
TestFree(CertInfo.Issuer.pbData);
|
|
return pCert;
|
|
}
|
|
|
|
static BOOL TestGetSubject(
|
|
IN LPSTR pszMsg,
|
|
IN HCERTSTORE hStore,
|
|
IN DWORD cSerialNumber,
|
|
IN CRYPT_INTEGER_BLOB rgSerialNumber[],
|
|
IN BOOL rgfExpectedGet[]
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
DWORD i;
|
|
CERT_INFO CertInfo;
|
|
memset(&CertInfo, 0, sizeof(CertInfo));
|
|
|
|
if (!EncodeIssuer(&CertInfo.Issuer.pbData, &CertInfo.Issuer.cbData))
|
|
return FALSE;
|
|
|
|
for (i = 0; i < cSerialNumber; i++) {
|
|
PCCERT_CONTEXT pCert;
|
|
|
|
CertInfo.SerialNumber = rgSerialNumber[i];
|
|
pCert = CertGetSubjectCertificateFromStore(hStore, dwCertEncodingType,
|
|
&CertInfo);
|
|
if (pCert) {
|
|
if (!rgfExpectedGet[i]) {
|
|
fResult = FALSE;
|
|
printf("%s SerialNumber[%d] failed => expected error\n",
|
|
pszMsg, i);
|
|
}
|
|
CertFreeCertificateContext(pCert);
|
|
} else if (rgfExpectedGet[i]) {
|
|
DWORD dwErr = GetLastError();
|
|
fResult = FALSE;
|
|
printf("%s SerialNumber[%d] failed => 0x%x (%d) \n", pszMsg, i,
|
|
dwErr, dwErr);
|
|
}
|
|
|
|
}
|
|
TestFree(CertInfo.Issuer.pbData);
|
|
return fResult;
|
|
}
|
|
|
|
static DWORD WINAPI VerifyCertSignThreadProc(
|
|
LPVOID lpThreadParameter
|
|
)
|
|
{
|
|
PCCERT_CONTEXT pCert0 = (PCCERT_CONTEXT) lpThreadParameter;
|
|
DWORD dwFlags = CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
|
|
|
|
if (!CertVerifySubjectCertificateContext(pCert0, pCert0, &dwFlags))
|
|
PrintLastError("CertVerifySubjectCertificateContext(Thread, SIGNATURE)");
|
|
else if (dwFlags != 0) {
|
|
printf("CertVerifySubjectCertificateContext(Thread, SIGNATURE) failed =>");
|
|
printf("dwFlags = 0x%x\n", dwFlags);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static BOOL DoTest()
|
|
{
|
|
BOOL fResult;
|
|
DWORD dwErr;
|
|
BYTE *pbCertEncoded = NULL;
|
|
DWORD cbCertEncoded;
|
|
CERT_INFO CertInfo;
|
|
memset(&CertInfo, 0, sizeof(CertInfo));
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
PCCERT_CONTEXT pCert0 = NULL;
|
|
PCCERT_CONTEXT pCertDup = NULL;
|
|
|
|
HCERTSTORE hStore1 = NULL;
|
|
HCERTSTORE hStore2 = NULL;
|
|
HCERTSTORE hStore3 = NULL;
|
|
|
|
CRYPT_DATA_BLOB SerializeStore;
|
|
memset(&SerializeStore, 0, sizeof(SerializeStore));
|
|
HCERTSTORE hSerializeStore = NULL;
|
|
|
|
CRYPT_DATA_BLOB PKCS7Store;
|
|
memset(&PKCS7Store, 0, sizeof(PKCS7Store));
|
|
HCERTSTORE hPKCS7Store = NULL;
|
|
DWORD i;
|
|
DWORD dwFlags;
|
|
|
|
CRYPT_DATA_BLOB SmallStore;
|
|
#define DELTA_LESS_LENGTH 8
|
|
|
|
BYTE rgbSerial0[] = {0x7f, 0x7e, 0x7d, 0x7c, 0x7b};
|
|
BYTE rgbSerial1[] = {0x81, 0x82, 0x83};
|
|
BYTE rgbSerial2[] = {0x00, 0x00, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b};
|
|
BYTE rgbSerial3[] = {0xFF, 0xFF, 0xFF, 0x81, 0x82, 0x83};
|
|
BYTE rgbSerial4[] = {0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x00, 0x00};
|
|
BYTE rgbSerial5[] = {0x81, 0x82, 0x83, 0xFF, 0xFF, 0xFF};
|
|
BYTE rgbSerial6[] = {0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0xFF};
|
|
BYTE rgbSerial7[] = {0x81, 0x82, 0x83, 0x00};
|
|
|
|
CRYPT_INTEGER_BLOB rgSerialNumber[] = {
|
|
sizeof(rgbSerial0), rgbSerial0,
|
|
sizeof(rgbSerial1), rgbSerial1,
|
|
sizeof(rgbSerial2), rgbSerial2,
|
|
sizeof(rgbSerial3), rgbSerial3,
|
|
sizeof(rgbSerial4), rgbSerial4,
|
|
sizeof(rgbSerial5), rgbSerial5,
|
|
sizeof(rgbSerial6), rgbSerial6,
|
|
sizeof(rgbSerial7), rgbSerial7,
|
|
};
|
|
|
|
BOOL rgfExpectedGet[] = {
|
|
TRUE,
|
|
TRUE,
|
|
FALSE,
|
|
FALSE,
|
|
TRUE,
|
|
TRUE,
|
|
FALSE,
|
|
FALSE
|
|
};
|
|
|
|
BOOL rgfDeleteExpectedGet[] = {
|
|
TRUE,
|
|
FALSE
|
|
};
|
|
|
|
BYTE rgbAux0[] = {0x00};
|
|
BYTE rgbAux1[] = {0x11, 0x11};
|
|
BYTE rgbAux2[] = {0x22, 0x22, 0x22};
|
|
BYTE rgbAux[8];
|
|
CRYPT_DATA_BLOB AuxData;
|
|
|
|
BYTE rgbStoreHash[MAX_HASH_LEN];
|
|
DWORD cbStoreHash;
|
|
BYTE rgbStoreHash2[MAX_HASH_LEN];
|
|
DWORD cbStoreHash2;
|
|
BYTE rgbContextHash[MAX_HASH_LEN];
|
|
DWORD cbContextHash;
|
|
|
|
if (!EncodeIssuer(&CertInfo.Issuer.pbData, &CertInfo.Issuer.cbData))
|
|
goto ErrorReturn;
|
|
|
|
if (NULL == (hStore1 = CertOpenSystemStoreW(hCryptProv, L"Test"))) {
|
|
PrintLastError("CertOpenSystemStoreW(Test)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// Delete all certs in the store
|
|
pCert = NULL;
|
|
while (pCert = CertEnumCertificatesInStore(hStore1, pCert)) {
|
|
PCCERT_CONTEXT pDeleteCert = CertDuplicateCertificateContext(pCert);
|
|
CertDeleteCertificateFromStore(pDeleteCert);
|
|
}
|
|
|
|
// Add two certs to the store
|
|
for (i = 0; i < 2; i++) {
|
|
if (!EncodeCert(&rgSerialNumber[i], &pbCertEncoded, &cbCertEncoded))
|
|
goto ErrorReturn;
|
|
if (!CertAddEncodedCertificateToStore(
|
|
hStore1,
|
|
dwCertEncodingType,
|
|
pbCertEncoded,
|
|
cbCertEncoded,
|
|
CERT_STORE_ADD_NEW,
|
|
NULL)) { // ppCertContext
|
|
PrintLastError("CertAddEncodedCertificateToStore");
|
|
goto ErrorReturn;
|
|
}
|
|
if (0 == i) {
|
|
// Create certificate context for future use
|
|
if (NULL == (pCert0 = CertCreateCertificateContext(
|
|
dwCertEncodingType,
|
|
pbCertEncoded,
|
|
cbCertEncoded))) {
|
|
PrintLastError("CertCreateCertificateContext");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
TestFree(pbCertEncoded);
|
|
pbCertEncoded = NULL;
|
|
}
|
|
|
|
TestGetSubject(
|
|
"Store1",
|
|
hStore1,
|
|
sizeof(rgSerialNumber)/sizeof(rgSerialNumber[0]),
|
|
rgSerialNumber,
|
|
rgfExpectedGet
|
|
);
|
|
|
|
// All the certificates should have been pushed through to the
|
|
// registry
|
|
if (NULL == (hStore2 = CertOpenSystemStoreA(0, "Test"))) {
|
|
PrintLastError("CertOpenSystemStoreA(Test)");
|
|
goto ErrorReturn;
|
|
}
|
|
TestGetSubject(
|
|
"Store2",
|
|
hStore2,
|
|
sizeof(rgSerialNumber)/sizeof(rgSerialNumber[0]),
|
|
rgSerialNumber,
|
|
rgfExpectedGet
|
|
);
|
|
|
|
CertInfo.SerialNumber = rgSerialNumber[4];
|
|
// Update different properties on the same certificate via different
|
|
// stores
|
|
if (NULL == (pCert = CertGetSubjectCertificateFromStore(
|
|
hStore1, dwCertEncodingType, &CertInfo))) {
|
|
PrintLastError("CertGetSubjectCertificateFromStore");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
AuxData.pbData = rgbAux0;
|
|
AuxData.cbData = sizeof(rgbAux0);
|
|
if (!CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID + 0,
|
|
0, // dwFlags
|
|
&AuxData
|
|
)) {
|
|
PrintLastError("CertSetCertificateContextProperty");
|
|
goto ErrorReturn;
|
|
}
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
|
|
if (NULL == (pCert = CertGetSubjectCertificateFromStore(
|
|
hStore2, dwCertEncodingType, &CertInfo))) {
|
|
PrintLastError("CertGetSubjectCertificateFromStore");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
AuxData.pbData = rgbAux1;
|
|
AuxData.cbData = sizeof(rgbAux1);
|
|
if (!CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID + 1,
|
|
0, // dwFlags
|
|
&AuxData
|
|
)) {
|
|
PrintLastError("CertSetCertificateContextProperty");
|
|
goto ErrorReturn;
|
|
}
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
|
|
// Reopen store. The properties should have been pushed through
|
|
// to the registry.
|
|
if (NULL == (hStore3 = CertOpenSystemStoreA(0, "Test"))) {
|
|
PrintLastError("CertOpenSystemStoreA(Test)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
TestGetSubject(
|
|
"Store3",
|
|
hStore3,
|
|
sizeof(rgSerialNumber)/sizeof(rgSerialNumber[0]),
|
|
rgSerialNumber,
|
|
rgfExpectedGet
|
|
);
|
|
|
|
// Display certs in the store
|
|
pCert = NULL;
|
|
i = 0;
|
|
printf("###### Test Store Certificates Before Delete ######\n");
|
|
while (pCert = CertEnumCertificatesInStore(hStore3, pCert)) {
|
|
printf("===== %d =====\n", i);
|
|
DisplayCert(pCert, DISPLAY_BRIEF_FLAG);
|
|
i++;
|
|
}
|
|
|
|
// Save certificates to in memory serialized store and in memory
|
|
// PKCS #7 store
|
|
if (!CertSaveStore(
|
|
hStore3,
|
|
0, // dwCertEncodingType,
|
|
CERT_STORE_SAVE_AS_STORE,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&SerializeStore,
|
|
0)) { // dwFlags
|
|
PrintLastError("CertSaveStore(CERT_STORE_SAVE_AS_STORE)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (NULL == (SerializeStore.pbData = (BYTE *) TestAlloc(
|
|
SerializeStore.cbData)))
|
|
goto ErrorReturn;
|
|
if (!CertSaveStore(
|
|
hStore3,
|
|
0, // dwCertEncodingType,
|
|
CERT_STORE_SAVE_AS_STORE,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&SerializeStore,
|
|
0)) { // dwFlags
|
|
PrintLastError("CertSaveStore(CERT_STORE_SAVE_AS_STORE)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// The following should fail with ERROR_MORE_DATA
|
|
SmallStore = SerializeStore;
|
|
SmallStore.cbData -= DELTA_LESS_LENGTH;
|
|
if (CertSaveStore(
|
|
hStore3,
|
|
0, // dwCertEncodingType,
|
|
CERT_STORE_SAVE_AS_STORE,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&SmallStore,
|
|
0)) // dwFlags
|
|
PrintNoError("CertSaveStore(CERT_STORE_SAVE_AS_STORE, insufficient length)");
|
|
else {
|
|
DWORD dwErr = GetLastError();
|
|
PrintExpectedError("CertSaveStore(CERT_STORE_SAVE_AS_STORE, insufficient length)");
|
|
if (ERROR_MORE_DATA != dwErr) {
|
|
printf("CertSaveStore(CERT_STORE_SAVE_AS_STORE) failed => ");
|
|
printf("LastError = %d, expected = %d\n", dwErr, ERROR_MORE_DATA);
|
|
}
|
|
}
|
|
|
|
if (SmallStore.cbData != SerializeStore.cbData) {
|
|
printf("CertSaveStore(CERT_STORE_SAVE_AS_STORE) failed => ");
|
|
printf("cbData = %d, expected = %d\n",
|
|
SmallStore.cbData, SerializeStore.cbData);
|
|
} else {
|
|
printf("cbData = %d, expected = %d\n",
|
|
SmallStore.cbData, SerializeStore.cbData);
|
|
}
|
|
|
|
|
|
if (!CertSaveStore(
|
|
hStore3,
|
|
0, // dwCertEncodingType,
|
|
CERT_STORE_SAVE_AS_STORE,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&SerializeStore,
|
|
0)) { // dwFlags
|
|
PrintLastError("CertSaveStore(CERT_STORE_SAVE_AS_STORE)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!CertSaveStore(
|
|
hStore3,
|
|
dwCertEncodingType | dwMsgEncodingType,
|
|
CERT_STORE_SAVE_AS_PKCS7,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&PKCS7Store,
|
|
0)) { // dwFlags
|
|
PrintLastError("CertSaveStore(CERT_STORE_SAVE_AS_PKCS7)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (NULL == (PKCS7Store.pbData = (BYTE *) TestAlloc(
|
|
PKCS7Store.cbData)))
|
|
goto ErrorReturn;
|
|
if (!CertSaveStore(
|
|
hStore3,
|
|
dwCertEncodingType | dwMsgEncodingType,
|
|
CERT_STORE_SAVE_AS_PKCS7,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&PKCS7Store,
|
|
0)) { // dwFlags
|
|
PrintLastError("CertSaveStore(CERT_STORE_SAVE_AS_PKCS7)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// The following should fail with ERROR_MORE_DATA
|
|
SmallStore = PKCS7Store;
|
|
SmallStore.cbData -= DELTA_LESS_LENGTH;
|
|
if (CertSaveStore(
|
|
hStore3,
|
|
dwCertEncodingType | dwMsgEncodingType,
|
|
CERT_STORE_SAVE_AS_PKCS7,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&SmallStore,
|
|
0))
|
|
PrintNoError("CertSaveStore(CERT_STORE_SAVE_AS_PKCS7, insufficient length)");
|
|
else {
|
|
DWORD dwErr = GetLastError();
|
|
PrintExpectedError("CertSaveStore(CERT_STORE_SAVE_AS_PKCS7, insufficient length)");
|
|
if (ERROR_MORE_DATA != dwErr) {
|
|
printf("CertSaveStore(CERT_STORE_SAVE_AS_PKCS7) failed => ");
|
|
printf("LastError = %d, expected = %d\n", dwErr, ERROR_MORE_DATA);
|
|
}
|
|
}
|
|
|
|
if (SmallStore.cbData != PKCS7Store.cbData) {
|
|
printf("CertSaveStore(CERT_STORE_SAVE_AS_PKCS7) failed => ");
|
|
printf("cbData = %d, expected = %d\n",
|
|
SmallStore.cbData, PKCS7Store.cbData);
|
|
} else {
|
|
printf("cbData = %d, expected = %d\n",
|
|
SmallStore.cbData, PKCS7Store.cbData);
|
|
}
|
|
|
|
if (!CertSaveStore(
|
|
hStore3,
|
|
dwCertEncodingType | dwMsgEncodingType,
|
|
CERT_STORE_SAVE_AS_PKCS7,
|
|
CERT_STORE_SAVE_TO_MEMORY,
|
|
&PKCS7Store,
|
|
0)) { // dwFlags
|
|
PrintLastError("CertSaveStore(CERT_STORE_SAVE_AS_PKCS7)");
|
|
goto ErrorReturn;
|
|
}
|
|
CertCloseStore(hStore3, 0);
|
|
hStore3 = NULL;
|
|
|
|
// Open in memory serialized store.
|
|
if (NULL == (hSerializeStore = CertOpenStore(
|
|
CERT_STORE_PROV_SERIALIZED,
|
|
0, // dwEncodingType
|
|
0, // hCryptProv
|
|
0, // dwFlags
|
|
(const void *) &SerializeStore))) {
|
|
PrintLastError("CertOpenStore(SERIALIZED)");
|
|
goto ErrorReturn;
|
|
}
|
|
TestGetSubject(
|
|
"SerializeStore",
|
|
hSerializeStore,
|
|
sizeof(rgSerialNumber)/sizeof(rgSerialNumber[0]),
|
|
rgSerialNumber,
|
|
rgfExpectedGet
|
|
);
|
|
|
|
// Display certs in the store
|
|
pCert = NULL;
|
|
i = 0;
|
|
printf("###### Serialized Store Certificates ######\n");
|
|
while (pCert = CertEnumCertificatesInStore(hSerializeStore, pCert)) {
|
|
printf("===== %d =====\n", i);
|
|
DisplayCert(pCert, DISPLAY_VERBOSE_FLAG);
|
|
i++;
|
|
}
|
|
|
|
// Open in memory PKCS7 store.
|
|
if (NULL == (hPKCS7Store = CertOpenStore(
|
|
CERT_STORE_PROV_PKCS7,
|
|
dwCertEncodingType | dwMsgEncodingType,
|
|
0, // hCryptProv
|
|
0, // dwFlags
|
|
(const void *) &PKCS7Store))) {
|
|
PrintLastError("CertOpenStore(SERIALIZED)");
|
|
goto ErrorReturn;
|
|
}
|
|
TestGetSubject(
|
|
"PKCS7Store",
|
|
hPKCS7Store,
|
|
sizeof(rgSerialNumber)/sizeof(rgSerialNumber[0]),
|
|
rgSerialNumber,
|
|
rgfExpectedGet
|
|
);
|
|
|
|
// Display certs in the store
|
|
pCert = NULL;
|
|
i = 0;
|
|
printf("###### PKCS7 Store Certificates ######\n");
|
|
while (pCert = CertEnumCertificatesInStore(hPKCS7Store, pCert)) {
|
|
printf("===== %d =====\n", i);
|
|
DisplayCert(pCert, DISPLAY_VERBOSE_FLAG);
|
|
i++;
|
|
}
|
|
|
|
// Delete the certificate in one store and update its property
|
|
// in the other store. Should get an error.
|
|
CertInfo.SerialNumber = rgSerialNumber[1];
|
|
if (NULL == (pCert = CertGetSubjectCertificateFromStore(
|
|
hStore1, dwCertEncodingType, &CertInfo))) {
|
|
PrintLastError("CertGetSubjectCertificateFromStore");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!CertDeleteCertificateFromStore(pCert)) {
|
|
PrintLastError("CertDeleteCertificateFromStore");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (NULL == (pCert = CertGetSubjectCertificateFromStore(
|
|
hStore2, dwCertEncodingType, &CertInfo))) {
|
|
PrintLastError("CertGetSubjectCertificateFromStore");
|
|
goto ErrorReturn;
|
|
}
|
|
AuxData.pbData = rgbAux2;
|
|
AuxData.cbData = sizeof(rgbAux2);
|
|
if (!CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID + 2,
|
|
0, // dwFlags
|
|
&AuxData
|
|
))
|
|
PrintExpectedError("CertSetCertificateContextProperty(deleted in other store)");
|
|
else
|
|
PrintNoError("CertSetCertificateContextProperty(deleted in other store)");
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
|
|
|
|
// Reopen store. The certificate delete should have pushed through
|
|
// to the registry.
|
|
if (NULL == (hStore3 = CertOpenSystemStoreA(0, "Test"))) {
|
|
PrintLastError("CertOpenSystemStoreA(Test)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
TestGetSubject(
|
|
"After Delete Store3",
|
|
hStore3,
|
|
sizeof(rgfDeleteExpectedGet)/sizeof(rgfDeleteExpectedGet[0]),
|
|
rgSerialNumber,
|
|
rgfDeleteExpectedGet
|
|
);
|
|
|
|
// Display certs in the store
|
|
pCert = NULL;
|
|
i = 0;
|
|
printf("###### Test Store Certificates After Delete ######\n");
|
|
while (pCert = CertEnumCertificatesInStore(hStore3, pCert)) {
|
|
printf("===== %d =====\n", i);
|
|
DisplayCert(pCert, DISPLAY_VERBOSE_FLAG);
|
|
i++;
|
|
}
|
|
|
|
// Check that we can get the hash property for a created context.
|
|
// Compare with the hash of the same certificate in a store.
|
|
CertInfo.SerialNumber = rgSerialNumber[0];
|
|
if (NULL == (pCert = CertGetSubjectCertificateFromStore(
|
|
hSerializeStore, dwCertEncodingType, &CertInfo))) {
|
|
PrintLastError("CertGetSubjectCertificateFromStore(SerializeStore)");
|
|
goto ErrorReturn;
|
|
}
|
|
cbStoreHash = MAX_HASH_LEN;
|
|
if (!CertGetCertificateContextProperty(pCert, CERT_SHA1_HASH_PROP_ID,
|
|
rgbStoreHash, &cbStoreHash)) {
|
|
PrintLastError("CertGetCertificateContextProperty(SerializeStore)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbContextHash = MAX_HASH_LEN;
|
|
if (!CertGetCertificateContextProperty(pCert0, CERT_SHA1_HASH_PROP_ID,
|
|
rgbContextHash, &cbContextHash))
|
|
PrintLastError("CertGetCertificateContextProperty(created context)");
|
|
else if (cbContextHash != cbStoreHash ||
|
|
0 != memcmp(rgbContextHash, rgbStoreHash, cbContextHash)) {
|
|
printf("CertGetCertificateContextProperty(created context) failed => ");
|
|
printf("hash didn't compare with store's hash\n");
|
|
}
|
|
|
|
|
|
// Do a CertVerifySubjectCertificateContext for a
|
|
// certificate in a store and a certificate context.
|
|
// Should pass for both a store certificate and
|
|
// a certificate context. The certificate context
|
|
// uses the default provider.
|
|
dwFlags = CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
|
|
if (!CertVerifySubjectCertificateContext(pCert, pCert, &dwFlags))
|
|
PrintLastError("CertVerifySubjectCertificateContext(in store)");
|
|
else if (dwFlags != 0) {
|
|
printf("CertVerifySubjectCertificateContext(in store) failed =>");
|
|
printf("dwFlags = 0x%x\n", dwFlags);
|
|
}
|
|
|
|
dwFlags = CERT_STORE_TIME_VALIDITY_FLAG;
|
|
if (!CertVerifySubjectCertificateContext(pCert0, pCert0, &dwFlags))
|
|
PrintLastError("CertVerifySubjectCertificateContext(context, TIME_VALIDITY)");
|
|
else if (dwFlags != 0) {
|
|
printf("CertVerifySubjectCertificateContext(context, TIME_VALIDITY) failed =>");
|
|
printf("dwFlags = 0x%x\n", dwFlags);
|
|
}
|
|
|
|
dwFlags = CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
|
|
if (!CertVerifySubjectCertificateContext(pCert0, pCert0, &dwFlags))
|
|
PrintLastError("CertVerifySubjectCertificateContext(context, SIGNATURE)");
|
|
else if (dwFlags != 0) {
|
|
printf("CertVerifySubjectCertificateContext(context, SIGNATURE) failed =>");
|
|
printf("dwFlags = 0x%x\n", dwFlags);
|
|
}
|
|
|
|
|
|
{
|
|
// Install DefaultContext applicable to all threads in process.
|
|
// Create another thread that does the verify. For testing purposes,
|
|
// will modify the CryptVerifyCertificateSignature to sleep while
|
|
// holding a refCount on the DefaultContext. Will do an Uninstall
|
|
// that should cause us to wait until the Verify returns.
|
|
|
|
HCRYPTPROV hProv = 0;
|
|
|
|
if (!CryptAcquireContext(
|
|
&hProv,
|
|
NULL, // pszContainer
|
|
NULL, // pszProvider,
|
|
PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT // dwFlags
|
|
)) {
|
|
PrintLastError(
|
|
"CryptAcquireContext(PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)");
|
|
} else {
|
|
HCRYPTDEFAULTCONTEXT hDefaultContext;
|
|
|
|
if (!CryptInstallDefaultContext(
|
|
hProv,
|
|
CRYPT_DEFAULT_CONTEXT_CERT_SIGN_OID,
|
|
(const void *) szOID_RSA_MD5RSA,
|
|
CRYPT_DEFAULT_CONTEXT_PROCESS_FLAG,
|
|
NULL, // pvReserved
|
|
&hDefaultContext
|
|
)) {
|
|
PrintLastError("CryptInstallDefaultContext");
|
|
} else {
|
|
HANDLE hThread;
|
|
DWORD dwThreadId;
|
|
|
|
if (NULL == (hThread = CreateThread(
|
|
NULL, // lpThreadAttributes
|
|
0, // dwStackSize
|
|
VerifyCertSignThreadProc,
|
|
(void *) pCert0,
|
|
0, // dwCreationFlags
|
|
&dwThreadId
|
|
)))
|
|
PrintLastError("CreateThread");
|
|
else
|
|
CloseHandle(hThread);
|
|
|
|
Sleep(500);
|
|
if (!CryptUninstallDefaultContext(
|
|
hDefaultContext,
|
|
0, // dwFlags
|
|
NULL // pvReserved
|
|
))
|
|
PrintLastError("CryptUninstallDefaultContext");
|
|
}
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
}
|
|
|
|
// Close a store with a not freed certificate context. Should get a warning
|
|
// at closing.
|
|
fResult = CertCloseStore(hSerializeStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
hSerializeStore = NULL;
|
|
if (fResult)
|
|
PrintNoError("CertCloseStore(with not freed certificate)");
|
|
else
|
|
PrintExpectedError("CertCloseStore(with not freed certificate)");
|
|
|
|
// Delete and recalculate the hash property for a certificate context
|
|
// after the store has been closed.
|
|
if (!CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_SHA1_HASH_PROP_ID,
|
|
0, // dwFlags
|
|
NULL // pvData
|
|
))
|
|
PrintLastError("CertSetCertificateContextProperty(SHA1, delete after close store)");
|
|
cbStoreHash2 = MAX_HASH_LEN;
|
|
if (!CertGetCertificateContextProperty(pCert, CERT_SHA1_HASH_PROP_ID,
|
|
rgbStoreHash2, &cbStoreHash2))
|
|
PrintLastError("CertGetCertificateContextProperty(SHA1, after close store)");
|
|
else if (cbStoreHash2 != cbStoreHash ||
|
|
0 != memcmp(rgbStoreHash2, rgbStoreHash, cbStoreHash2)) {
|
|
printf("CertGetCertificateContextProperty(SHA1, after close store) failed => ");
|
|
printf("hash didn't compare with store's hash\n");
|
|
}
|
|
|
|
// Delete the certificate context after the store has been closed
|
|
if (!CertDeleteCertificateFromStore(pCert))
|
|
PrintLastError("CertDeleteCertificateFromStore(after close store)");
|
|
pCert = NULL;
|
|
|
|
// Duplicate a certificate. Delete it from the store. Also delete its
|
|
// duplicate. Close the store.
|
|
if (NULL == (pCert = CertGetSubjectCertificateFromStore(
|
|
hPKCS7Store, dwCertEncodingType, &CertInfo))) {
|
|
PrintLastError("CertGetSubjectCertificateFromStore(PKCS7)");
|
|
goto ErrorReturn;
|
|
}
|
|
pCertDup = CertDuplicateCertificateContext(pCert);
|
|
if (!CertDeleteCertificateFromStore(pCert))
|
|
PrintLastError("CertDeleteCertificateFromStore(PKCS7)");
|
|
pCert = NULL;
|
|
if (!CertDeleteCertificateFromStore(pCertDup))
|
|
PrintLastError("CertDeleteCertificateFromStore(PKCS7, duplicated cert)");
|
|
pCertDup = NULL;
|
|
|
|
// Also check that last error is preserved for no errors
|
|
#define EXPECTED_LAST_ERROR 0x11223344
|
|
SetLastError(EXPECTED_LAST_ERROR);
|
|
fResult = CertCloseStore(hPKCS7Store, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
hPKCS7Store = NULL;
|
|
if (!fResult)
|
|
PrintError("CertCloseStore(PKCS7, after two deletes)");
|
|
else if (EXPECTED_LAST_ERROR != (dwErr = GetLastError())) {
|
|
printf("CertCloseStore failed => globbered last error.");
|
|
printf(" Expected 0x%x (%d), got 0x%x (%d)\n",
|
|
EXPECTED_LAST_ERROR, EXPECTED_LAST_ERROR, dwErr, dwErr);
|
|
}
|
|
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
if (pbCertEncoded)
|
|
TestFree(pbCertEncoded);
|
|
if (CertInfo.Issuer.pbData)
|
|
TestFree(CertInfo.Issuer.pbData);
|
|
if (SerializeStore.pbData)
|
|
TestFree(SerializeStore.pbData);
|
|
if (PKCS7Store.pbData)
|
|
TestFree(PKCS7Store.pbData);
|
|
|
|
if (hStore1)
|
|
CertCloseStore(hStore1, 0);
|
|
if (hStore2)
|
|
CertCloseStore(hStore2, 0);
|
|
if (hStore3)
|
|
CertCloseStore(hStore3, 0);
|
|
if (hSerializeStore)
|
|
CertCloseStore(hSerializeStore, 0);
|
|
if (hPKCS7Store)
|
|
CertCloseStore(hPKCS7Store, 0);
|
|
|
|
if (pCert)
|
|
CertFreeCertificateContext(pCert);
|
|
if (pCert0)
|
|
CertFreeCertificateContext(pCert0);
|
|
if (pCertDup)
|
|
CertFreeCertificateContext(pCertDup);
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
static BOOL DoWin95Test()
|
|
{
|
|
|
|
#define WIN95_ADD_CERT_CNT 8
|
|
#define WIN95_ADD_CB_PROP 10000
|
|
|
|
#define WIN95_STORE_CNT 2
|
|
LPWSTR rgpwszStore[WIN95_STORE_CNT] = {
|
|
L"Test0",
|
|
L"Test1"
|
|
};
|
|
|
|
#define WIN95_PROP_CNT 5
|
|
DWORD rgcbProp[WIN95_PROP_CNT][WIN95_STORE_CNT] = {
|
|
100, 200, // 0
|
|
0x5000, 0x6000, // 1
|
|
0x1000, 0x6300, // 2
|
|
0x30, 0x300, // 3
|
|
0x4300, 0x4200 // 4
|
|
};
|
|
|
|
DWORD dwSerialNumber;
|
|
CRYPT_INTEGER_BLOB SerialNumber = {
|
|
sizeof(dwSerialNumber), (BYTE *) &dwSerialNumber
|
|
};
|
|
|
|
BOOL fResult;
|
|
BYTE *pbCertEncoded = NULL;
|
|
DWORD cbCertEncoded;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
HCERTSTORE hStore = NULL;
|
|
CRYPT_DATA_BLOB Prop;
|
|
BYTE *pbProp = NULL;
|
|
DWORD cbProp;
|
|
DWORD cb;
|
|
DWORD i, j, k;
|
|
DWORD cAdd;
|
|
|
|
if (NULL == (hStore = CertOpenSystemStoreW(NULL, L"Test"))) {
|
|
PrintLastError("CertOpenSystemStoreW");
|
|
goto ErrorReturn;
|
|
}
|
|
// Delete all certs in the store
|
|
pCert = NULL;
|
|
while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
|
|
PCCERT_CONTEXT pDeleteCert = CertDuplicateCertificateContext(pCert);
|
|
CertDeleteCertificateFromStore(pDeleteCert);
|
|
}
|
|
|
|
if (NULL == (pbProp = (BYTE *) TestAlloc(
|
|
WIN95_ADD_CB_PROP + WIN95_ADD_CERT_CNT)))
|
|
goto ErrorReturn;
|
|
// Add certs each having a property of 10,000 + cAdd bytes in length
|
|
for (cAdd = 0; cAdd < WIN95_ADD_CERT_CNT; cAdd++) {
|
|
dwSerialNumber = cAdd;
|
|
|
|
if (!EncodeCert(&SerialNumber, &pbCertEncoded, &cbCertEncoded))
|
|
goto ErrorReturn;
|
|
|
|
// Add encoded certificate to store.
|
|
fResult = CertAddEncodedCertificateToStore(
|
|
hStore,
|
|
dwCertEncodingType,
|
|
pbCertEncoded,
|
|
cbCertEncoded,
|
|
CERT_STORE_ADD_NEW,
|
|
&pCert);
|
|
TestFree(pbCertEncoded);
|
|
pbCertEncoded = NULL;
|
|
if (!fResult) {
|
|
printf("AddEncodedCertificate[%d]", cAdd);
|
|
PrintLastError("");
|
|
break;
|
|
}
|
|
|
|
Prop.pbData = pbProp;
|
|
Prop.cbData = WIN95_ADD_CB_PROP + cAdd;
|
|
for (k = 0; k < WIN95_ADD_CB_PROP + cAdd; k++)
|
|
pbProp[k] = (BYTE) cAdd;
|
|
fResult = CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID,
|
|
0, // dwFlags
|
|
&Prop
|
|
);
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
|
|
if (!fResult) {
|
|
printf("SetProperty for AddedCertificate[%d]", cAdd);
|
|
PrintLastError("");
|
|
break;
|
|
}
|
|
}
|
|
|
|
CertCloseStore(hStore, 0);
|
|
hStore = NULL;
|
|
|
|
// Verify that we can successfully read the added certs.
|
|
if (NULL == (hStore = CertOpenSystemStoreW(NULL, L"Test"))) {
|
|
PrintLastError("CertOpenSystemStoreW");
|
|
goto ErrorReturn;
|
|
}
|
|
while (cAdd--) {
|
|
dwSerialNumber = cAdd;
|
|
pCert = GetSubject(hStore, &SerialNumber);
|
|
if (NULL == pCert) {
|
|
printf("GetAddedCertificate[%d]\n", cAdd);
|
|
PrintLastError("");
|
|
} else {
|
|
cbProp = WIN95_ADD_CB_PROP + WIN95_ADD_CERT_CNT;
|
|
|
|
if (!CertGetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID,
|
|
pbProp,
|
|
&cbProp)) {
|
|
printf("GetProperty for AddedCertificate[%d]", cAdd);
|
|
PrintLastError("");
|
|
} else if (cbProp != WIN95_ADD_CB_PROP + cAdd) {
|
|
printf("GetProperty for AddedCertificate[%d] failed => ", cAdd);
|
|
printf("cbProp = %d, not expected = %d\n",
|
|
cbProp, WIN95_ADD_CB_PROP + cAdd);
|
|
} else {
|
|
for (k = 0; k < cbProp; k++) {
|
|
if (pbProp[k] != (BYTE) cAdd) {
|
|
printf("GetProperty for AddedCertificate[%d] failed => ", cAdd);
|
|
printf("not expected value\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
}
|
|
}
|
|
|
|
CertCloseStore(hStore, 0);
|
|
hStore = NULL;
|
|
TestFree(pbProp);
|
|
pbProp = NULL;
|
|
|
|
dwSerialNumber = 0x12345678;
|
|
if (!EncodeCert(&SerialNumber, &pbCertEncoded, &cbCertEncoded))
|
|
goto ErrorReturn;
|
|
|
|
for (j = 0; j < WIN95_STORE_CNT; j++) {
|
|
if (NULL == (hStore = CertOpenSystemStoreW(
|
|
NULL, rgpwszStore[j]))) {
|
|
printf("%s => ", rgpwszStore[j]);
|
|
PrintLastError("CertOpenSystemStoreW");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// Delete all certs in the store
|
|
pCert = NULL;
|
|
while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
|
|
PCCERT_CONTEXT pDeleteCert = CertDuplicateCertificateContext(pCert);
|
|
CertDeleteCertificateFromStore(pDeleteCert);
|
|
}
|
|
|
|
// Add encoded certificate to store.
|
|
if (!CertAddEncodedCertificateToStore(
|
|
hStore,
|
|
dwCertEncodingType,
|
|
pbCertEncoded,
|
|
cbCertEncoded,
|
|
CERT_STORE_ADD_NEW,
|
|
&pCert)) { // ppCertContext
|
|
printf("%s => ", rgpwszStore[j]);
|
|
PrintLastError("CertAddEncodedCertificateToStore");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cb = rgcbProp[0][j];
|
|
if (NULL == (pbProp = (BYTE *) TestAlloc(cb)))
|
|
goto ErrorReturn;
|
|
Prop.pbData = pbProp;
|
|
Prop.cbData = cb;
|
|
for (k = 0; k < cb; k++)
|
|
pbProp[k] = (BYTE) (j + 1);
|
|
if (!CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID,
|
|
0, // dwFlags
|
|
&Prop
|
|
)) {
|
|
printf("%s => ", rgpwszStore[j]);
|
|
PrintLastError("CertSetCertificateContextProperty");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
TestFree(pbProp);
|
|
pbProp = NULL;
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
CertCloseStore(hStore, 0);
|
|
hStore = NULL;
|
|
}
|
|
|
|
TestFree(pbCertEncoded);
|
|
pbCertEncoded = NULL;
|
|
|
|
// Loop and read previous property. compare. write new property.
|
|
for (i = 1; i < WIN95_PROP_CNT; i++) {
|
|
for (j = 0; j < WIN95_STORE_CNT; j++) {
|
|
|
|
if (NULL == (hStore = CertOpenSystemStoreW(
|
|
NULL, rgpwszStore[j]))) {
|
|
printf("Prop[%d] Store[%d] ", i, j);
|
|
PrintLastError("CertOpenSystemStoreW");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pCert = GetSubject(hStore, &SerialNumber);
|
|
if (NULL == pCert) {
|
|
printf("Prop[%d] Store[%d] ", i, j);
|
|
PrintLastError("GetSubject");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!CertGetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID,
|
|
NULL, // pbProp
|
|
&cbProp)) {
|
|
printf("Prop[%d] Store[%d] ", i, j);
|
|
PrintLastError("CertGetCertificateContextProperty");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cb = rgcbProp[i-1][j];
|
|
if (cbProp != cb) {
|
|
printf("Prop[%d] Store[%d] ", i, j);
|
|
printf("GetProperty failed => ");
|
|
printf("cbProp = %d, not expected = %d\n", cbProp, cb);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (NULL == (pbProp = (BYTE *) TestAlloc(cbProp)))
|
|
goto ErrorReturn;
|
|
if (!CertGetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID,
|
|
pbProp,
|
|
&cbProp)) {
|
|
printf("Prop[%d] Store[%d] ", i, j);
|
|
PrintLastError("CertGetCertificateContextProperty");
|
|
goto ErrorReturn;
|
|
}
|
|
for (k = 0; k < cbProp; k++) {
|
|
if (pbProp[k] != (BYTE) (j + 1)) {
|
|
printf("Prop[%d] Store[%d] ", i, j);
|
|
printf("GetProperty failed => ");
|
|
printf("not expected value\n");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
TestFree(pbProp);
|
|
pbProp = NULL;
|
|
|
|
cb = rgcbProp[i][j];
|
|
if (NULL == (pbProp = (BYTE *) TestAlloc(cb)))
|
|
goto ErrorReturn;
|
|
Prop.pbData = pbProp;
|
|
Prop.cbData = cb;
|
|
for (k = 0; k < cb; k++)
|
|
pbProp[k] = (BYTE) (j + 1);
|
|
if (!CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_FIRST_USER_PROP_ID,
|
|
0, // dwFlags
|
|
&Prop
|
|
)) {
|
|
printf("Prop[%d] Store[%d] cb=%d ", i, j, cb);
|
|
PrintLastError("CertSetCertificateContextProperty");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
TestFree(pbProp);
|
|
pbProp = NULL;
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
CertCloseStore(hStore, 0);
|
|
hStore = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
TestFree(pbProp);
|
|
TestFree(pbCertEncoded);
|
|
if (hStore)
|
|
CertCloseStore(hStore, 0);
|
|
if (pCert)
|
|
CertFreeCertificateContext(pCert);
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
static BOOL DoDeferCloseTest()
|
|
{
|
|
BOOL fResult;
|
|
|
|
BYTE rgbSerial[] = {0x7f, 0x7e, 0x7d, 0x7c, 0x7b};
|
|
CRYPT_INTEGER_BLOB SerialNumber = {
|
|
sizeof(rgbSerial), rgbSerial
|
|
};
|
|
|
|
HCERTSTORE hStore = NULL;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
BYTE *pbCertEncoded = NULL;
|
|
DWORD cbCertEncoded;
|
|
|
|
if (!EncodeCert(&SerialNumber, &pbCertEncoded, &cbCertEncoded))
|
|
goto ErrorReturn;
|
|
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Do defer close with no duplicated contexts
|
|
// ---------------------------------------------------------------------
|
|
if (NULL == (hStore = CertOpenStore(
|
|
CERT_STORE_PROV_MEMORY,
|
|
0, // dwEncodingType
|
|
0, // hCryptProv
|
|
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
|
|
NULL))) { // pvPara
|
|
PrintLastError("CertOpenStore(MEMORY, DEFER)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!CertAddEncodedCertificateToStore(
|
|
hStore,
|
|
dwCertEncodingType,
|
|
pbCertEncoded,
|
|
cbCertEncoded,
|
|
CERT_STORE_ADD_NEW,
|
|
NULL)) { // ppCertContext
|
|
PrintLastError("CertAddEncodedCertificateToStore");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
hStore = NULL;
|
|
if (fResult)
|
|
printf("Defer close with no duplicated contexts\n");
|
|
else
|
|
PrintLastError("CertCloseStore(DEFER, no duplicated contexts");
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Do defer close with duplicated contexts
|
|
// ---------------------------------------------------------------------
|
|
if (NULL == (hStore = CertOpenStore(
|
|
CERT_STORE_PROV_MEMORY,
|
|
0, // dwEncodingType
|
|
0, // hCryptProv
|
|
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
|
|
NULL))) { // pvPara
|
|
PrintLastError("CertOpenStore(MEMORY, DEFER)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!CertAddEncodedCertificateToStore(
|
|
hStore,
|
|
dwCertEncodingType,
|
|
pbCertEncoded,
|
|
cbCertEncoded,
|
|
CERT_STORE_ADD_NEW,
|
|
&pCert)) { // ppCertContext
|
|
PrintLastError("CertAddEncodedCertificateToStore");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
hStore = NULL;
|
|
if (fResult)
|
|
PrintExpectedError("CertCloseStore(DEFER, with duplicated certificate)");
|
|
else
|
|
printf("Defer close with duplicated contexts\n");
|
|
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Do context delete after a defer close
|
|
// ---------------------------------------------------------------------
|
|
if (NULL == (hStore = CertOpenStore(
|
|
CERT_STORE_PROV_MEMORY,
|
|
0, // dwEncodingType
|
|
0, // hCryptProv
|
|
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
|
|
NULL))) { // pvPara
|
|
PrintLastError("CertOpenStore(MEMORY, DEFER)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!CertAddEncodedCertificateToStore(
|
|
hStore,
|
|
dwCertEncodingType,
|
|
pbCertEncoded,
|
|
cbCertEncoded,
|
|
CERT_STORE_ADD_NEW,
|
|
&pCert)) { // ppCertContext
|
|
PrintLastError("CertAddEncodedCertificateToStore");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
hStore = NULL;
|
|
if (fResult)
|
|
PrintExpectedError("CertCloseStore(DEFER, with duplicated certificate)");
|
|
else
|
|
printf("Defer close with context to be deleted after\n");
|
|
|
|
CertDeleteCertificateFromStore(pCert);
|
|
pCert = NULL;
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
TestFree(pbCertEncoded);
|
|
if (hStore)
|
|
CertCloseStore(hStore, 0);
|
|
if (pCert)
|
|
CertFreeCertificateContext(pCert);
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
int _cdecl main(int argc, char * argv[])
|
|
{
|
|
printf("command line: %s\n", GetCommandLine());
|
|
|
|
hCryptProv = GetCryptProv();
|
|
if (hCryptProv == 0)
|
|
return -1;
|
|
|
|
DoTest();
|
|
DoWin95Test();
|
|
DoDeferCloseTest();
|
|
|
|
CryptReleaseContext(hCryptProv, 0);
|
|
printf("Done.\n");
|
|
return 0;
|
|
}
|