crypt32: Fix certificate adding
- Implement add disposition in CertAddCertificateContextToStore, rather than in each store. - Add a few more tests.
This commit is contained in:
parent
ef9038c761
commit
5eadd8c791
|
@ -126,11 +126,14 @@ struct _WINE_CERT_CONTEXT;
|
|||
typedef struct _WINE_CERT_CONTEXT * (*EnumCertFunc)
|
||||
(struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT *pPrev);
|
||||
|
||||
/* Called to add a new certificate context to a store. If ppStoreContext is
|
||||
* not NULL, the added context should be returned in *ppStoreContext.
|
||||
/* Called to add a certificate context to a store. If toReplace is not NULL,
|
||||
* context replaces toReplace in the store, and access checks should not be
|
||||
* performed. Otherwise context is a new context, and it should only be
|
||||
* added if the store allows it. If ppStoreContext is not NULL, the added
|
||||
* context should be returned in *ppStoreContext.
|
||||
*/
|
||||
typedef BOOL (*AddCertFunc)(struct WINE_CRYPTCERTSTORE *store,
|
||||
struct _WINE_CERT_CONTEXT *context, DWORD dwAddDisposition,
|
||||
struct _WINE_CERT_CONTEXT *context, struct _WINE_CERT_CONTEXT *toReplace,
|
||||
PCCERT_CONTEXT *ppStoreContext);
|
||||
|
||||
typedef enum _CertStoreType {
|
||||
|
@ -174,7 +177,7 @@ typedef struct _WINE_CERT_CONTEXT
|
|||
LONG ref;
|
||||
ContextType type;
|
||||
} WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
|
||||
typedef const struct _WINE_CERT_CONTEXT PCWINE_CERT_CONTEXT;
|
||||
typedef const struct _WINE_CERT_CONTEXT *PCWINE_CERT_CONTEXT;
|
||||
|
||||
typedef struct _WINE_CERT_CONTEXT_DATA
|
||||
{
|
||||
|
@ -317,83 +320,38 @@ static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_LINK ref,
|
|||
}
|
||||
|
||||
static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store,
|
||||
PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition,
|
||||
PWINE_CERT_CONTEXT cert, PWINE_CERT_CONTEXT toReplace,
|
||||
PCCERT_CONTEXT *ppStoreContext)
|
||||
{
|
||||
WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
|
||||
BOOL add = FALSE, ret;
|
||||
PCCERT_CONTEXT existing = NULL;
|
||||
PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
|
||||
BOOL ret;
|
||||
|
||||
TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext);
|
||||
TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
|
||||
|
||||
if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
|
||||
if (entry)
|
||||
{
|
||||
BYTE hashToAdd[20];
|
||||
DWORD size = sizeof(hashToAdd);
|
||||
PWINE_CERT_LIST_ENTRY existing = (PWINE_CERT_LIST_ENTRY)toReplace;
|
||||
|
||||
ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)cert,
|
||||
CERT_HASH_PROP_ID, hashToAdd, &size);
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
|
||||
|
||||
existing = CertFindCertificateInStore(store,
|
||||
cert->cert.dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
switch (dwAddDisposition)
|
||||
{
|
||||
case CERT_STORE_ADD_ALWAYS:
|
||||
add = TRUE;
|
||||
break;
|
||||
case CERT_STORE_ADD_NEW:
|
||||
{
|
||||
TRACE("adding %p\n", entry);
|
||||
CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)cert, store);
|
||||
EnterCriticalSection(&ms->cs);
|
||||
if (existing)
|
||||
{
|
||||
TRACE("found matching certificate, not adding\n");
|
||||
SetLastError(CRYPT_E_EXISTS);
|
||||
add = FALSE;
|
||||
entry->entry.prev = existing->entry.prev;
|
||||
entry->entry.next = existing->entry.next;
|
||||
entry->entry.prev->next = &entry->entry;
|
||||
entry->entry.next->prev = &entry->entry;
|
||||
existing->entry.prev = existing->entry.next = &existing->entry;
|
||||
CertFreeCertificateContext((PCCERT_CONTEXT)existing);
|
||||
}
|
||||
else
|
||||
add = TRUE;
|
||||
break;
|
||||
}
|
||||
case CERT_STORE_ADD_REPLACE_EXISTING:
|
||||
{
|
||||
add = TRUE;
|
||||
if (existing)
|
||||
{
|
||||
TRACE("found matching certificate, replacing\n");
|
||||
CertDeleteCertificateFromStore(existing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
|
||||
add = FALSE;
|
||||
}
|
||||
if (existing)
|
||||
CertFreeCertificateContext(existing);
|
||||
if (add)
|
||||
{
|
||||
PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(
|
||||
sizeof(WINE_CERT_LIST_ENTRY));
|
||||
|
||||
if (entry)
|
||||
{
|
||||
TRACE("adding %p\n", entry);
|
||||
CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)cert, store);
|
||||
EnterCriticalSection(&ms->cs);
|
||||
list_add_tail(&ms->certs, &entry->entry);
|
||||
LeaveCriticalSection(&ms->cs);
|
||||
if (ppStoreContext)
|
||||
*ppStoreContext =
|
||||
CertDuplicateCertificateContext((PCCERT_CONTEXT)entry);
|
||||
ret = TRUE;
|
||||
}
|
||||
else
|
||||
ret = FALSE;
|
||||
LeaveCriticalSection(&ms->cs);
|
||||
if (ppStoreContext)
|
||||
*ppStoreContext =
|
||||
CertDuplicateCertificateContext((PCCERT_CONTEXT)entry);
|
||||
ret = TRUE;
|
||||
}
|
||||
else
|
||||
ret = FALSE;
|
||||
|
@ -506,30 +464,78 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
|
|||
return (PWINECRYPT_CERTSTORE)store;
|
||||
}
|
||||
|
||||
static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionCreateContextFromChild(
|
||||
PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
|
||||
PWINE_CERT_CONTEXT child)
|
||||
{
|
||||
PWINE_COLLECTION_CERT_CONTEXT ret =
|
||||
CryptMemAlloc(sizeof(WINE_COLLECTION_CERT_CONTEXT));
|
||||
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_InitCertRef((PWINE_CERT_CONTEXT_LINK)ret, child, store);
|
||||
/* The child has already been addref'd, and CRYPT_InitCertRef does
|
||||
* again, so free child once to get the ref count right. (Not doing so
|
||||
* will leak memory if the caller calls CertFreeCertificateContext
|
||||
* rather than CertEnumCertificatesInStore.)
|
||||
*/
|
||||
CertFreeCertificateContext((PCCERT_CONTEXT)child);
|
||||
ret->storeEntry = storeEntry;
|
||||
}
|
||||
else
|
||||
CertFreeCertificateContext((PCCERT_CONTEXT)child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store,
|
||||
PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition,
|
||||
PWINE_CERT_CONTEXT cert, PWINE_CERT_CONTEXT toReplace,
|
||||
PCCERT_CONTEXT *ppStoreContext)
|
||||
{
|
||||
PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
|
||||
PWINE_STORE_LIST_ENTRY entry, next;
|
||||
BOOL ret;
|
||||
PCCERT_CONTEXT childContext = NULL;
|
||||
PWINE_STORE_LIST_ENTRY storeEntry = NULL;
|
||||
|
||||
TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext);
|
||||
TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
|
||||
|
||||
ret = FALSE;
|
||||
EnterCriticalSection(&cs->cs);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
|
||||
entry)
|
||||
if (toReplace)
|
||||
{
|
||||
if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
|
||||
{
|
||||
ret = entry->store->addCert(entry->store, cert, dwAddDisposition,
|
||||
ppStoreContext);
|
||||
break;
|
||||
}
|
||||
PWINE_COLLECTION_CERT_CONTEXT existing =
|
||||
(PWINE_COLLECTION_CERT_CONTEXT)toReplace;
|
||||
|
||||
storeEntry = existing->storeEntry;
|
||||
ret = storeEntry->store->addCert(storeEntry->store, cert,
|
||||
existing->cert.linked, &childContext);
|
||||
}
|
||||
LeaveCriticalSection(&cs->cs);
|
||||
SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
|
||||
else
|
||||
{
|
||||
PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
|
||||
PWINE_STORE_LIST_ENTRY entry, next;
|
||||
|
||||
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)
|
||||
{
|
||||
storeEntry = entry;
|
||||
ret = entry->store->addCert(entry->store, cert, NULL,
|
||||
&childContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&cs->cs);
|
||||
if (!storeEntry)
|
||||
SetLastError(HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
|
||||
}
|
||||
if (ppStoreContext && childContext)
|
||||
{
|
||||
*ppStoreContext =
|
||||
(PCCERT_CONTEXT)CRYPT_CollectionCreateContextFromChild(
|
||||
(PWINE_COLLECTIONSTORE)store, storeEntry,
|
||||
(PWINE_CERT_CONTEXT)childContext);
|
||||
}
|
||||
CertFreeCertificateContext(childContext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -574,7 +580,8 @@ static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
|
|||
{
|
||||
/* Ref-counting funny business: "duplicate" (addref) the child, because
|
||||
* the CertFreeCertificateContext(pPrev) below can cause the ref count
|
||||
* to become negative. See comment below as well.
|
||||
* to become negative. See comment in
|
||||
* CRYPT_CollectionCreateContextFromChild as well.
|
||||
*/
|
||||
child = ((PWINE_COLLECTION_CERT_CONTEXT)pPrev)->cert.linked;
|
||||
CertDuplicateCertificateContext((PCCERT_CONTEXT)child);
|
||||
|
@ -587,22 +594,7 @@ static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
|
|||
child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
|
||||
NULL);
|
||||
if (child)
|
||||
{
|
||||
ret = CryptMemAlloc(sizeof(WINE_COLLECTION_CERT_CONTEXT));
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_InitCertRef((PWINE_CERT_CONTEXT_LINK)ret, child, store);
|
||||
/* enumCert already addref'd once, and CRYPT_InitCertRef does again,
|
||||
* so free child once to get the ref count right. (Not doing so
|
||||
* will leak memory if the caller calls CertFreeCertificateContext
|
||||
* rather than CertEnumCertificatesInStore.)
|
||||
*/
|
||||
CertFreeCertificateContext((PCCERT_CONTEXT)child);
|
||||
ret->storeEntry = storeEntry;
|
||||
}
|
||||
else
|
||||
CertFreeCertificateContext((PCCERT_CONTEXT)child);
|
||||
}
|
||||
ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child);
|
||||
else
|
||||
{
|
||||
if (storeNext)
|
||||
|
@ -713,36 +705,40 @@ static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
|
|||
}
|
||||
|
||||
static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store,
|
||||
PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition,
|
||||
PWINE_CERT_CONTEXT cert, PWINE_CERT_CONTEXT toReplace,
|
||||
PCCERT_CONTEXT *ppStoreContext)
|
||||
{
|
||||
PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
|
||||
BOOL ret;
|
||||
|
||||
TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext);
|
||||
TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
|
||||
|
||||
if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
|
||||
{
|
||||
SetLastError(ERROR_ACCESS_DENIED);
|
||||
ret = FALSE;
|
||||
}
|
||||
if (toReplace)
|
||||
ret = ps->memStore->addCert(ps->memStore, cert, toReplace,
|
||||
ppStoreContext);
|
||||
else
|
||||
{
|
||||
ret = TRUE;
|
||||
if (ps->provWriteCert)
|
||||
ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
|
||||
CERT_STORE_PROV_WRITE_ADD_FLAG);
|
||||
if (ret)
|
||||
if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
|
||||
{
|
||||
ret = ps->memStore->addCert(ps->memStore, cert,
|
||||
dwAddDisposition, ppStoreContext);
|
||||
/* dirty trick: replace the returned context's hCertStore with
|
||||
* store.
|
||||
*/
|
||||
if (ppStoreContext)
|
||||
(*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store;
|
||||
SetLastError(ERROR_ACCESS_DENIED);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = TRUE;
|
||||
if (ps->provWriteCert)
|
||||
ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
|
||||
CERT_STORE_PROV_WRITE_ADD_FLAG);
|
||||
if (ret)
|
||||
ret = ps->memStore->addCert(ps->memStore, cert, NULL,
|
||||
ppStoreContext);
|
||||
}
|
||||
}
|
||||
/* dirty trick: replace the returned context's hCertStore with
|
||||
* store.
|
||||
*/
|
||||
if (ppStoreContext)
|
||||
(*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2094,43 +2090,84 @@ PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
|
|||
return pCertContext;
|
||||
}
|
||||
|
||||
static void CertContext_CopyProperties(PCCERT_CONTEXT to, PCCERT_CONTEXT from)
|
||||
{
|
||||
PWINE_CERT_CONTEXT_DATA toData, fromData;
|
||||
|
||||
toData = CertContext_GetDataContext((PWINE_CERT_CONTEXT)to);
|
||||
fromData = CertContext_GetDataContext((PWINE_CERT_CONTEXT)from);
|
||||
ContextPropertyList_Copy(toData->properties, fromData->properties);
|
||||
}
|
||||
|
||||
BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
|
||||
PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
|
||||
PCCERT_CONTEXT *ppStoreContext)
|
||||
{
|
||||
PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
|
||||
PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(
|
||||
(PWINE_CERT_CONTEXT)pCertContext);
|
||||
PWINE_CERT_CONTEXT cert;
|
||||
BOOL ret;
|
||||
BOOL ret = TRUE;
|
||||
PCCERT_CONTEXT toAdd = NULL, existing = NULL;
|
||||
|
||||
TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
|
||||
dwAddDisposition, ppStoreContext);
|
||||
|
||||
/* FIXME: some tests needed to verify return codes */
|
||||
if (!store)
|
||||
if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
BYTE hashToAdd[20];
|
||||
DWORD size = sizeof(hashToAdd);
|
||||
|
||||
ret = CRYPT_GetCertificateContextProperty(
|
||||
(PWINE_CERT_CONTEXT)pCertContext, CERT_HASH_PROP_ID, hashToAdd, &size);
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
|
||||
|
||||
existing = CertFindCertificateInStore(hCertStore,
|
||||
pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
cert = CRYPT_CreateCertificateContext(pCertContext->dwCertEncodingType,
|
||||
pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
|
||||
if (cert)
|
||||
switch (dwAddDisposition)
|
||||
{
|
||||
PWINE_CERT_CONTEXT_DATA certData = CertContext_GetDataContext(cert);
|
||||
|
||||
ContextPropertyList_Copy(certData->properties, linked->properties);
|
||||
ret = store->addCert(store, cert, dwAddDisposition, ppStoreContext);
|
||||
CertFreeCertificateContext((PCCERT_CONTEXT)cert);
|
||||
}
|
||||
else
|
||||
case CERT_STORE_ADD_ALWAYS:
|
||||
toAdd = CertDuplicateCertificateContext(pCertContext);
|
||||
break;
|
||||
case CERT_STORE_ADD_NEW:
|
||||
if (existing)
|
||||
{
|
||||
TRACE("found matching certificate, not adding\n");
|
||||
SetLastError(CRYPT_E_EXISTS);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
toAdd = CertDuplicateCertificateContext(pCertContext);
|
||||
break;
|
||||
case CERT_STORE_ADD_REPLACE_EXISTING:
|
||||
toAdd = CertDuplicateCertificateContext(pCertContext);
|
||||
break;
|
||||
case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
|
||||
toAdd = CertDuplicateCertificateContext(pCertContext);
|
||||
if (existing)
|
||||
CertContext_CopyProperties(toAdd, existing);
|
||||
break;
|
||||
case CERT_STORE_ADD_USE_EXISTING:
|
||||
if (existing)
|
||||
CertContext_CopyProperties(existing, pCertContext);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
if (toAdd)
|
||||
{
|
||||
ret = store->addCert(store, (PWINE_CERT_CONTEXT)toAdd,
|
||||
(PWINE_CERT_CONTEXT)existing, ppStoreContext);
|
||||
CertFreeCertificateContext(toAdd);
|
||||
}
|
||||
CertFreeCertificateContext(existing);
|
||||
|
||||
TRACE("returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2155,7 +2192,8 @@ BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
|
|||
|
||||
if (cert)
|
||||
{
|
||||
ret = hcs->addCert(hcs, cert, dwAddDisposition, ppCertContext);
|
||||
ret = CertAddCertificateContextToStore(hCertStore,
|
||||
(PCCERT_CONTEXT)cert, dwAddDisposition, ppCertContext);
|
||||
CertFreeCertificateContext((PCCERT_CONTEXT)cert);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -101,6 +101,8 @@ static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
|
|||
static const BYTE subjectName2[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
|
||||
0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61,
|
||||
0x6e, 0x67, 0x00 };
|
||||
static const BYTE bigCert2Hash[] = { 0x4a, 0x7f, 0x32, 0x1f, 0xcf, 0x3b, 0xc0,
|
||||
0x87, 0x48, 0x2b, 0xa1, 0x86, 0x54, 0x18, 0xe4, 0x3a, 0x0e, 0x53, 0x7e, 0x2b };
|
||||
static const BYTE certWithUsage[] = { 0x30, 0x81, 0x93, 0x02, 0x01, 0x01, 0x30,
|
||||
0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
|
||||
0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00,
|
||||
|
@ -115,6 +117,110 @@ static const BYTE certWithUsage[] = { 0x30, 0x81, 0x93, 0x02, 0x01, 0x01, 0x30,
|
|||
0x03, 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
|
||||
static const BYTE serialNum[] = { 1 };
|
||||
|
||||
static void testAddCert(void)
|
||||
{
|
||||
HCERTSTORE store;
|
||||
|
||||
store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
|
||||
CERT_STORE_CREATE_NEW_FLAG, NULL);
|
||||
ok(store != NULL, "CertOpenStore failed: %ld\n", GetLastError());
|
||||
if (store != NULL)
|
||||
{
|
||||
HCERTSTORE collection;
|
||||
PCCERT_CONTEXT context;
|
||||
BOOL ret;
|
||||
|
||||
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
|
||||
bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
|
||||
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
|
||||
GetLastError());
|
||||
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
|
||||
bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, NULL);
|
||||
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
|
||||
GetLastError());
|
||||
/* This has the same name as bigCert, so finding isn't done by name */
|
||||
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
|
||||
certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, &context);
|
||||
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
|
||||
GetLastError());
|
||||
ok(context != NULL, "Expected a context\n");
|
||||
if (context)
|
||||
{
|
||||
CRYPT_DATA_BLOB hash = { sizeof(bigCert2Hash),
|
||||
(LPBYTE)bigCert2Hash };
|
||||
|
||||
CertDeleteCertificateFromStore(context);
|
||||
/* Set the same hash as bigCert2, and try to readd it */
|
||||
ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID,
|
||||
0, &hash);
|
||||
ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
|
||||
GetLastError());
|
||||
ret = CertAddCertificateContextToStore(store, context,
|
||||
CERT_STORE_ADD_NEW, NULL);
|
||||
/* The failure is a bit odd (CRYPT_E_ASN1_BADTAG), so just check
|
||||
* that it fails.
|
||||
*/
|
||||
ok(!ret, "Expected failure\n");
|
||||
CertFreeCertificateContext(context);
|
||||
}
|
||||
context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2,
|
||||
sizeof(bigCert2));
|
||||
ok(context != NULL, "Expected a context\n");
|
||||
if (context)
|
||||
{
|
||||
/* Try to readd bigCert2 to the store */
|
||||
ret = CertAddCertificateContextToStore(store, context,
|
||||
CERT_STORE_ADD_NEW, NULL);
|
||||
ok(!ret && GetLastError() == CRYPT_E_EXISTS,
|
||||
"Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
|
||||
CertFreeCertificateContext(context);
|
||||
}
|
||||
|
||||
/* FIXME: test whether adding a cert with the same subject name and
|
||||
* serial number (but different otherwise) as an existing cert works.
|
||||
*/
|
||||
collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
|
||||
CERT_STORE_CREATE_NEW_FLAG, NULL);
|
||||
ok(collection != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
|
||||
if (collection)
|
||||
{
|
||||
/* Add store to the collection, but disable updates */
|
||||
CertAddStoreToCollection(collection, store, 0, 0);
|
||||
|
||||
context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2,
|
||||
sizeof(bigCert2));
|
||||
ok(context != NULL, "Expected a context\n");
|
||||
if (context)
|
||||
{
|
||||
/* Try to readd bigCert2 to the collection */
|
||||
ret = CertAddCertificateContextToStore(collection, context,
|
||||
CERT_STORE_ADD_NEW, NULL);
|
||||
ok(!ret && GetLastError() == CRYPT_E_EXISTS,
|
||||
"Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
|
||||
/* Replacing an existing certificate context is allowed, even
|
||||
* though updates to the collection aren't..
|
||||
*/
|
||||
ret = CertAddCertificateContextToStore(collection, context,
|
||||
CERT_STORE_ADD_REPLACE_EXISTING, NULL);
|
||||
ok(ret, "CertAddCertificateContextToStore failed: %08lx\n",
|
||||
GetLastError());
|
||||
/* but adding a new certificate isn't allowed. */
|
||||
ret = CertAddCertificateContextToStore(collection, context,
|
||||
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());
|
||||
CertFreeCertificateContext(context);
|
||||
}
|
||||
|
||||
CertCloseStore(collection, 0);
|
||||
}
|
||||
|
||||
CertCloseStore(store, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void testDupCert(void)
|
||||
{
|
||||
HCERTSTORE store;
|
||||
|
@ -1592,6 +1698,7 @@ static void testAddSerialized(void)
|
|||
|
||||
START_TEST(store)
|
||||
{
|
||||
testAddCert();
|
||||
testDupCert();
|
||||
testFindCert();
|
||||
testGetSubjectCert();
|
||||
|
|
Loading…
Reference in New Issue