From aa6dc003a42f5ef1e1876b4621687e85eb010a31 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 22 Feb 2006 13:44:56 -0800 Subject: [PATCH] crypt32: Implement CertFindCertificateInStore, with tests. --- dlls/crypt32/store.c | 138 ++++++++++++++++++++++++++++++++-- dlls/crypt32/tests/store.c | 150 ++++++++++++++++++++++++++++++++++--- 2 files changed, 269 insertions(+), 19 deletions(-) diff --git a/dlls/crypt32/store.c b/dlls/crypt32/store.c index b06ea4812e..fcec33b2d4 100644 --- a/dlls/crypt32/store.c +++ b/dlls/crypt32/store.c @@ -460,7 +460,6 @@ static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert, { TRACE("adding %p\n", entry); CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store); - list_init(&entry->entry); EnterCriticalSection(&ms->cs); list_add_tail(&ms->certs, &entry->entry); LeaveCriticalSection(&ms->cs); @@ -512,8 +511,6 @@ static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, return (PWINE_CERT_CONTEXT_REF)ret; } -static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref); - static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext, DWORD dwFlags) { @@ -2321,7 +2318,7 @@ static BOOL WINAPI CRYPT_SetCertificateContextProperty( switch (dwPropId) { case CERT_AUTO_ENROLL_PROP_ID: - case CERT_CTL_USAGE_PROP_ID: + case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */ case CERT_DESCRIPTION_PROP_ID: case CERT_FRIENDLY_NAME_PROP_ID: case CERT_HASH_PROP_ID: @@ -3108,14 +3105,139 @@ BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext) return TRUE; } +typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara); + +static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + return TRUE; +} + +static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + BYTE hash[16]; + DWORD size = sizeof(hash); + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_MD5_HASH_PROP_ID, hash, &size); + if (ret) + { + const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; + + if (size == pHash->cbData) + ret = !memcmp(pHash->pbData, hash, size); + else + ret = FALSE; + } + return ret; +} + +static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + BYTE hash[20]; + DWORD size = sizeof(hash); + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_SHA1_HASH_PROP_ID, hash, &size); + if (ret) + { + const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; + + if (size == pHash->cbData) + ret = !memcmp(pHash->pbData, hash, size); + else + ret = FALSE; + } + return ret; +} + +static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + const CERT_NAME_BLOB *blob = (const CERT_NAME_BLOB *)pvPara, *toCompare; + BOOL ret; + + if (dwType & CERT_INFO_SUBJECT_FLAG) + toCompare = &pCertContext->pCertInfo->Subject; + else + toCompare = &pCertContext->pCertInfo->Issuer; + if (toCompare->cbData == blob->cbData) + ret = !memcmp(toCompare->pbData, blob->pbData, blob->cbData); + else + ret = FALSE; + return ret; +} + +static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, + DWORD dwType, DWORD dwFlags, const void *pvPara) +{ + const CERT_INFO *pCertInfo = (const CERT_INFO *)pvPara; + BOOL ret; + + if (pCertInfo->Issuer.cbData == pCertContext->pCertInfo->Subject.cbData) + ret = !memcmp(pCertInfo->Issuer.pbData, + pCertContext->pCertInfo->Subject.pbData, pCertInfo->Issuer.cbData); + else + ret = FALSE; + return ret; +} + PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara, PCCERT_CONTEXT pPrevCertContext) { - FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType, - dwFlags, dwType, pvPara, pPrevCertContext); - SetLastError(CRYPT_E_NOT_FOUND); - return NULL; + PCCERT_CONTEXT ret; + CertCompareFunc compare; + + TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore, dwCertEncodingType, + dwFlags, dwType, pvPara, pPrevCertContext); + + switch (dwType >> CERT_COMPARE_SHIFT) + { + case CERT_COMPARE_ANY: + compare = compare_cert_any; + break; + case CERT_COMPARE_MD5_HASH: + compare = compare_cert_by_md5_hash; + break; + case CERT_COMPARE_SHA1_HASH: + compare = compare_cert_by_sha1_hash; + break; + case CERT_COMPARE_NAME: + compare = compare_cert_by_name; + break; + case CERT_COMPARE_SUBJECT_CERT: + compare = compare_cert_by_subject_cert; + break; + default: + FIXME("find type %08lx unimplemented\n", dwType); + compare = NULL; + } + + if (compare) + { + BOOL matches = FALSE; + + ret = pPrevCertContext; + do { + ret = CertEnumCertificatesInStore(hCertStore, ret); + if (ret) + matches = compare(ret, dwType, dwFlags, pvPara); + } while (ret != NULL && !matches); + if (!ret) + SetLastError(CRYPT_E_NOT_FOUND); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + return ret; } BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c index ee425155f9..2ca59b8b12 100644 --- a/dlls/crypt32/tests/store.c +++ b/dlls/crypt32/tests/store.c @@ -52,6 +52,11 @@ static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE subjectName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, + 0x6e, 0x67, 0x00 }; +static const BYTE bigCertHash[] = { 0x6e, 0x30, 0x90, 0x71, 0x5f, 0xd9, 0x23, + 0x56, 0xeb, 0xae, 0x25, 0x40, 0xe6, 0x22, 0xda, 0x19, 0x26, 0x02, 0xa6, 0x08 }; static const BYTE signedBigCert[] = { 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, @@ -83,6 +88,32 @@ static const BYTE signedCRL[] = { 0x30, 0x45, 0x30, 0x2c, 0x30, 0x02, 0x06, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; +static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +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 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, + 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, + 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, + 0x03, 0x01, 0x00, 0xa3, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x01, 0x01, 0xff, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 }; +static const BYTE serialNum[] = { 1 }; static void testDupCert(void) { @@ -129,6 +160,113 @@ static void testDupCert(void) } } +static void testFindCert(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) + { + PCCERT_CONTEXT context = NULL; + BOOL ret; + CERT_INFO certInfo = { 0 }; + CRYPT_HASH_BLOB blob; + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_NEW, 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 */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", + GetLastError()); + + /* Crashes + context = CertFindCertificateInStore(NULL, 0, 0, 0, NULL, NULL); + */ + + /* Check first cert's there, by issuer */ + certInfo.Subject.pbData = (LPBYTE)subjectName; + certInfo.Subject.cbData = sizeof(subjectName); + certInfo.SerialNumber.pbData = (LPBYTE)serialNum; + certInfo.SerialNumber.cbData = sizeof(serialNum); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_NAME, &certInfo.Subject, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_NAME, &certInfo.Subject, context); + ok(context != NULL, "Expected more than one cert\n"); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, + 0, CERT_FIND_ISSUER_NAME, &certInfo.Subject, context); + ok(context == NULL, "Expected precisely two certs\n"); + } + } + + /* Check second cert's there as well, by subject name */ + certInfo.Subject.pbData = (LPBYTE)subjectName2; + certInfo.Subject.cbData = sizeof(subjectName2); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_NAME, &certInfo.Subject, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_NAME, &certInfo.Subject, context); + ok(context == NULL, "Expected one cert only\n"); + } + + /* Strange but true: searching for the subject cert requires you to set + * the issuer, not the subject + */ + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo.Subject, NULL); + ok(context == NULL, "Expected no certificate\n"); + certInfo.Subject.pbData = NULL; + certInfo.Subject.cbData = 0; + certInfo.Issuer.pbData = (LPBYTE)subjectName2; + certInfo.Issuer.cbData = sizeof(subjectName2); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_NAME, &certInfo.Subject, context); + ok(context == NULL, "Expected one cert only\n"); + } + + /* The nice thing about hashes, they're unique */ + blob.pbData = (LPBYTE)bigCertHash; + blob.cbData = sizeof(bigCertHash); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SHA1_HASH, &blob, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_NAME, &certInfo.Subject, context); + ok(context == NULL, "Expected one cert only\n"); + } + + CertCloseStore(store, 0); + } +} + static void testMemStore(void) { HCERTSTORE store1, store2; @@ -303,17 +441,6 @@ static void testMemStore(void) CertCloseStore(store1, 0); } -static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, - 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, - 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, - 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, - 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, - 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, - 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, - 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, - 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; - static void testCollectionStore(void) { HCERTSTORE store1, store2, collection, collection2; @@ -1412,6 +1539,7 @@ static void testAddSerialized(void) START_TEST(store) { testDupCert(); + testFindCert(); /* various combinations of CertOpenStore */ testMemStore(); -- 2.32.0.93.g670b81a890