Commit 9e8c0bbd authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

Implement collection stores.

parent a18042e7
...@@ -161,6 +161,35 @@ typedef struct _WINE_MEMSTORE ...@@ -161,6 +161,35 @@ typedef struct _WINE_MEMSTORE
struct list certs; struct list certs;
} WINE_MEMSTORE, *PWINE_MEMSTORE; } WINE_MEMSTORE, *PWINE_MEMSTORE;
typedef struct _WINE_STORE_LIST_ENTRY
{
PWINECRYPT_CERTSTORE store;
DWORD dwUpdateFlags;
DWORD dwPriority;
struct list entry;
} WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
/* Returned by a collection store during enumeration.
* Note: relies on the list entry being valid after use, which a number of
* conditions might make untrue (reentrancy, closing a collection store before
* continuing an enumeration on it, ...). The tests seem to indicate this
* sort of unsafety is okay, since Windows isn't well-behaved in these
* scenarios either.
*/
typedef struct _WINE_COLLECTION_CERT_CONTEXT
{
WINE_CERT_CONTEXT_REF cert;
PWINE_STORE_LIST_ENTRY entry;
PWINE_CERT_CONTEXT_REF childContext;
} WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
typedef struct _WINE_COLLECTIONSTORE
{
WINECRYPT_CERTSTORE hdr;
CRITICAL_SECTION cs;
struct list stores;
} WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
/* Like CertGetCertificateContextProperty, but operates directly on the /* Like CertGetCertificateContextProperty, but operates directly on the
* WINE_CERT_CONTEXT. Doesn't support special-case properties, since they * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
* are handled by CertGetCertificateContextProperty, and are particular to the * are handled by CertGetCertificateContextProperty, and are particular to the
...@@ -444,6 +473,249 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, ...@@ -444,6 +473,249 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
return (PWINECRYPT_CERTSTORE)store; return (PWINECRYPT_CERTSTORE)store;
} }
static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
{
PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
PWINE_STORE_LIST_ENTRY entry, next;
BOOL ret;
TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
ret = FALSE;
EnterCriticalSection(&cs->cs);
LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
entry)
{
if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
{
ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
break;
}
}
LeaveCriticalSection(&cs->cs);
SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
return ret;
}
static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
PWINE_CERT_CONTEXT context, HCERTSTORE store)
{
PWINE_COLLECTION_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
sizeof(WINE_COLLECTION_CERT_CONTEXT));
if (ret)
{
/* Initialize to empty for now, just make sure the size is right */
CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
ret->entry = NULL;
ret->childContext = NULL;
}
return (PWINE_CERT_CONTEXT_REF)ret;
}
static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
{
PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
PWINE_STORE_LIST_ENTRY entry, next;
TRACE("(%p, %08lx)\n", store, dwFlags);
LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
entry)
{
TRACE("closing %p\n", entry);
CertCloseStore((HCERTSTORE)entry->store, dwFlags);
HeapFree(GetProcessHeap(), 0, entry);
}
DeleteCriticalSection(&cs->cs);
HeapFree(GetProcessHeap(), 0, cs);
}
/* Advances a collection enumeration by one cert, if possible, where advancing
* means:
* - calling the current store's enumeration function once, and returning
* the enumerated cert if one is returned
* - moving to the next store if the current store has no more items, and
* recursively calling itself to get the next item.
* Returns NULL if the collection contains no more items or on error.
* Assumes the collection store's lock is held.
*/
static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
PWINE_COLLECTION_CERT_CONTEXT pPrev)
{
PWINE_COLLECTION_CERT_CONTEXT ret;
PWINE_CERT_CONTEXT_REF child;
TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
if (pPrev)
{
child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
pPrev->childContext);
if (child)
{
ret = pPrev;
memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
ret->cert.cert.hCertStore = (HCERTSTORE)store;
InterlockedIncrement(&ret->cert.context->ref);
ret->childContext = child;
}
else
{
struct list *storeNext = list_next(&store->stores,
&storeEntry->entry);
pPrev->childContext = NULL;
CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
if (storeNext)
{
storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
entry);
ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
}
else
{
SetLastError(CRYPT_E_NOT_FOUND);
ret = NULL;
}
}
}
else
{
child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
NULL);
if (child)
{
ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
child->context, store);
if (ret)
{
ret->entry = storeEntry;
ret->childContext = child;
}
else
CertFreeCertificateContext((PCCERT_CONTEXT)child);
}
else
{
struct list *storeNext = list_next(&store->stores,
&storeEntry->entry);
if (storeNext)
{
storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
entry);
ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
}
else
{
SetLastError(CRYPT_E_NOT_FOUND);
ret = NULL;
}
}
}
TRACE("returning %p\n", ret);
return ret;
}
static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
{
PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
PWINE_COLLECTION_CERT_CONTEXT prevEntry =
(PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
TRACE("(%p, %p)\n", store, pPrev);
if (prevEntry)
{
EnterCriticalSection(&cs->cs);
ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
LeaveCriticalSection(&cs->cs);
}
else
{
EnterCriticalSection(&cs->cs);
if (!list_empty(&cs->stores))
{
PWINE_STORE_LIST_ENTRY storeEntry;
storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
entry);
ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
}
else
{
SetLastError(CRYPT_E_NOT_FOUND);
ret = NULL;
}
LeaveCriticalSection(&cs->cs);
}
TRACE("returning %p\n", ret);
return (PWINE_CERT_CONTEXT_REF)ret;
}
static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
PCCERT_CONTEXT pCertContext, DWORD dwFlags)
{
PWINE_COLLECTION_CERT_CONTEXT context =
(PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
BOOL ret;
TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
if (ret)
{
context->childContext = NULL;
CertFreeCertificateContext((PCCERT_CONTEXT)context);
}
return ret;
}
static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
{
PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
TRACE("(%p)\n", ref);
if (context->childContext)
CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
}
static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
DWORD dwFlags, const void *pvPara)
{
PWINE_COLLECTIONSTORE store;
if (dwFlags & CERT_STORE_DELETE_FLAG)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
store = NULL;
}
else
{
store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(WINE_COLLECTIONSTORE));
if (store)
{
CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
StoreTypeCollection);
store->hdr.closeStore = CRYPT_CollectionCloseStore;
store->hdr.addCert = CRYPT_CollectionAddCert;
store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
store->hdr.enumCert = CRYPT_CollectionEnumCert;
store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
store->hdr.freeCert = CRYPT_CollectionFreeCert;
InitializeCriticalSection(&store->cs);
list_init(&store->stores);
}
}
return (PWINECRYPT_CERTSTORE)store;
}
static void WINAPI CRYPT_DummyCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) static void WINAPI CRYPT_DummyCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
{ {
HeapFree(GetProcessHeap(), 0, (PWINECRYPT_CERTSTORE)hCertStore); HeapFree(GetProcessHeap(), 0, (PWINECRYPT_CERTSTORE)hCertStore);
...@@ -515,10 +787,12 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, ...@@ -515,10 +787,12 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
case (int)CERT_STORE_PROV_MEMORY: case (int)CERT_STORE_PROV_MEMORY:
openFunc = CRYPT_MemOpenStore; openFunc = CRYPT_MemOpenStore;
break; break;
case (int)CERT_STORE_PROV_COLLECTION:
openFunc = CRYPT_CollectionOpenStore;
break;
case (int)CERT_STORE_PROV_REG: case (int)CERT_STORE_PROV_REG:
case (int)CERT_STORE_PROV_SYSTEM_A: case (int)CERT_STORE_PROV_SYSTEM_A:
case (int)CERT_STORE_PROV_SYSTEM_W: case (int)CERT_STORE_PROV_SYSTEM_W:
case (int)CERT_STORE_PROV_COLLECTION:
openFunc = CRYPT_DummyOpenStore; openFunc = CRYPT_DummyOpenStore;
break; break;
default: default:
...@@ -531,7 +805,7 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, ...@@ -531,7 +805,7 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM)) else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
openFunc = CRYPT_DummyOpenStore; openFunc = CRYPT_DummyOpenStore;
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION)) else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
openFunc = CRYPT_DummyOpenStore; openFunc = CRYPT_CollectionOpenStore;
else else
{ {
FIXME("unimplemented type %s\n", lpszStoreProvider); FIXME("unimplemented type %s\n", lpszStoreProvider);
...@@ -1429,15 +1703,107 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, ...@@ -1429,15 +1703,107 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority) HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
{ {
FIXME("(%p, %p, %08lx, %ld): stub\n", hCollectionStore, hSiblingStore, PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
PWINE_STORE_LIST_ENTRY entry;
BOOL ret;
TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
dwUpdateFlags, dwPriority); dwUpdateFlags, dwPriority);
if (!collection || !sibling)
return TRUE; return TRUE;
if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
{
SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
return FALSE;
}
if (collection->hdr.type != StoreTypeCollection)
{
SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
return FALSE;
}
if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
{
SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
return FALSE;
}
entry = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_ENTRY));
if (entry)
{
InterlockedIncrement(&sibling->ref);
TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
entry->store = sibling;
entry->dwUpdateFlags = dwUpdateFlags;
entry->dwPriority = dwPriority;
list_init(&entry->entry);
TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
EnterCriticalSection(&collection->cs);
if (dwPriority)
{
PWINE_STORE_LIST_ENTRY cursor;
BOOL added = FALSE;
LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
WINE_STORE_LIST_ENTRY, entry)
{
if (cursor->dwPriority < dwPriority)
{
list_add_before(&cursor->entry, &entry->entry);
added = TRUE;
break;
}
}
if (!added)
list_add_tail(&collection->stores, &entry->entry);
}
else
list_add_tail(&collection->stores, &entry->entry);
LeaveCriticalSection(&collection->cs);
ret = TRUE;
}
else
ret = FALSE;
return ret;
} }
void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore, void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
HCERTSTORE hSiblingStore) HCERTSTORE hSiblingStore)
{ {
FIXME("(%p, %p): stub\n", hCollectionStore, hSiblingStore); PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
PWINE_STORE_LIST_ENTRY store, next;
TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
if (!collection || !sibling)
return;
if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
{
SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
return;
}
if (collection->hdr.type != StoreTypeCollection)
return;
if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
{
SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
return;
}
EnterCriticalSection(&collection->cs);
LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
WINE_STORE_LIST_ENTRY, entry)
{
if (store->store == sibling)
{
list_remove(&store->entry);
CertCloseStore(store->store, 0);
HeapFree(GetProcessHeap(), 0, store);
break;
}
}
LeaveCriticalSection(&collection->cs);
} }
PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr, PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
......
...@@ -254,6 +254,312 @@ static void testMemStore(void) ...@@ -254,6 +254,312 @@ static void testMemStore(void)
CertCloseStore(store1, 0); CertCloseStore(store1, 0);
} }
static const BYTE bigCert2[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
"\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x41\x6c\x65\x78\x20\x4c"
"\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
"\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
"\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x41\x6c\x65\x78"
"\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
"\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
"\x01";
static void testCollectionStore(void)
{
HCERTSTORE store1, store2, collection, collection2;
PCCERT_CONTEXT context;
BOOL ret;
collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
/* Try adding a cert to any empty collection */
ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
"Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
GetLastError());
/* Create and add a cert to a memory store */
store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
/* Add the memory store to the collection, without allowing adding */
ret = CertAddStoreToCollection(collection, store1, 0, 0);
ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
/* Verify the cert is in the collection */
context = CertEnumCertificatesInStore(collection, NULL);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
CertFreeCertificateContext(context);
}
/* Check that adding to the collection isn't allowed */
ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
"Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
GetLastError());
/* Create a new memory store */
store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
/* Try adding a store to a non-collection store */
ret = CertAddStoreToCollection(store1, store2,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
"Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
GetLastError());
/* Try adding some bogus stores */
/* This crashes in Windows
ret = CertAddStoreToCollection(0, store2,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
*/
/* This "succeeds"... */
ret = CertAddStoreToCollection(collection, 0,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
/* while this crashes.
ret = CertAddStoreToCollection(collection, 1,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
*/
/* Add it to the collection, this time allowing adding */
ret = CertAddStoreToCollection(collection, store2,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
/* Check that adding to the collection is allowed */
ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
/* Now check that it was actually added to store2 */
context = CertEnumCertificatesInStore(store2, NULL);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == store2, "Unexpected store\n");
CertFreeCertificateContext(context);
}
/* Check that the collection has both bigCert and bigCert2. bigCert comes
* first because store1 was added first.
*/
context = CertEnumCertificatesInStore(collection, NULL);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
"Unexpected cert\n");
context = CertEnumCertificatesInStore(collection, context);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert2,
context->cbCertEncoded), "Unexpected cert\n");
context = CertEnumCertificatesInStore(collection, context);
ok(!context, "Unexpected cert\n");
}
}
/* close store2, and check that the collection is unmodified */
CertCloseStore(store2, 0);
context = CertEnumCertificatesInStore(collection, NULL);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
"Unexpected cert\n");
context = CertEnumCertificatesInStore(collection, context);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert2,
context->cbCertEncoded), "Unexpected cert\n");
context = CertEnumCertificatesInStore(collection, context);
ok(!context, "Unexpected cert\n");
}
}
/* Adding a collection to a collection is legal */
collection2 = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
ret = CertAddStoreToCollection(collection2, collection,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
/* check the contents of collection2 */
context = CertEnumCertificatesInStore(collection2, NULL);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection2, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
"Unexpected cert\n");
context = CertEnumCertificatesInStore(collection2, context);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection2, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert2,
context->cbCertEncoded), "Unexpected cert\n");
context = CertEnumCertificatesInStore(collection2, context);
ok(!context, "Unexpected cert\n");
}
}
/* I'd like to test closing the collection in the middle of enumeration,
* but my tests have been inconsistent. The first time calling
* CertEnumCertificatesInStore on a closed collection succeeded, while the
* second crashed. So anything appears to be fair game.
* I'd also like to test removing a store from a collection in the middle
* of an enumeration, but my tests in Windows have been inconclusive.
* In one scenario it worked. In another scenario, about a third of the
* time this leads to "random" crashes elsewhere in the code. This
* probably means this is not allowed.
*/
CertCloseStore(store1, 0);
CertCloseStore(collection, 0);
CertCloseStore(collection2, 0);
/* Add the same cert to two memory stores, then put them in a collection */
store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
ok(store1 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
ok(store2 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
ret = CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING,
bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
ok(collection != 0, "CertOpenStore failed: %08lx\n", GetLastError());
ret = CertAddStoreToCollection(collection, store1,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
ret = CertAddStoreToCollection(collection, store2,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
/* Check that the collection has two copies of the same cert */
context = CertEnumCertificatesInStore(collection, NULL);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
"Unexpected cert\n");
context = CertEnumCertificatesInStore(collection, context);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
"Unexpected cert\n");
context = CertEnumCertificatesInStore(collection, context);
ok(context == NULL, "Unexpected cert\n");
}
}
/* The following would check whether I can delete an identical cert, rather
* than one enumerated from the store. It crashes, so that means I must
* only call CertDeleteCertificateFromStore with contexts enumerated from
* the store.
context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
sizeof(bigCert) - 1);
ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
GetLastError());
if (context)
{
ret = CertDeleteCertificateFromStore(collection, context);
printf("ret is %d, GetLastError is %08lx\n", ret, GetLastError());
CertFreeCertificateContext(context);
}
*/
/* Now check deleting from the collection. */
context = CertEnumCertificatesInStore(collection, NULL);
ok(context != NULL, "Expected a valid context\n");
if (context)
{
CertDeleteCertificateFromStore(context);
/* store1 should now be empty */
context = CertEnumCertificatesInStore(store1, NULL);
ok(!context, "Unexpected cert\n");
/* and there should be one certificate in the collection */
context = CertEnumCertificatesInStore(collection, NULL);
ok(context != NULL, "Expected a valid cert\n");
if (context)
{
ok(context->hCertStore == collection, "Unexpected store\n");
ok(context->cbCertEncoded == sizeof(bigCert) - 1,
"Expected size %d, got %ld\n", sizeof(bigCert) - 1,
context->cbCertEncoded);
ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
"Unexpected cert\n");
}
context = CertEnumCertificatesInStore(collection, context);
ok(context == NULL, "Unexpected cert\n");
}
/* Finally, test removing stores from the collection. No return value, so
* it's a bit funny to test.
*/
/* This crashes
CertRemoveStoreFromCollection(NULL, NULL);
*/
/* This "succeeds," no crash, no last error set */
SetLastError(0xdeadbeef);
CertRemoveStoreFromCollection(store2, collection);
ok(GetLastError() == 0xdeadbeef,
"Didn't expect an error to be set: %08lx\n", GetLastError());
/* After removing store2, the collection should be empty */
SetLastError(0xdeadbeef);
CertRemoveStoreFromCollection(collection, store2);
ok(GetLastError() == 0xdeadbeef,
"Didn't expect an error to be set: %08lx\n", GetLastError());
context = CertEnumCertificatesInStore(collection, NULL);
ok(!context, "Unexpected cert\n");
CertCloseStore(collection, 0);
CertCloseStore(store2, 0);
CertCloseStore(store1, 0);
}
static void testCertProperties(void) static void testCertProperties(void)
{ {
PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING, PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
...@@ -367,6 +673,7 @@ START_TEST(cert) ...@@ -367,6 +673,7 @@ START_TEST(cert)
/* various combinations of CertOpenStore */ /* various combinations of CertOpenStore */
testMemStore(); testMemStore();
testCollectionStore();
testCertProperties(); testCertProperties();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment