crypt32: Partially implement CertGetIssuerCertificateFromStore.
diff --git a/dlls/crypt32/crypt32.spec b/dlls/crypt32/crypt32.spec
index 3fa460c..836c6b9 100644
--- a/dlls/crypt32/crypt32.spec
+++ b/dlls/crypt32/crypt32.spec
@@ -52,7 +52,7 @@
@ stdcall CertGetCertificateContextProperty(ptr long ptr ptr)
@ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr)
@ stub CertGetIntendedKeyUsage
-@ stub CertGetIssuerCertificateFromStore
+@ stdcall CertGetIssuerCertificateFromStore(long ptr ptr ptr)
@ stdcall CertGetNameStringA(ptr long long ptr ptr long)
@ stdcall CertGetNameStringW(ptr long long ptr ptr long)
@ stub CertGetPublicKeyLength
diff --git a/dlls/crypt32/store.c b/dlls/crypt32/store.c
index 712c93d..1a7b72b 100644
--- a/dlls/crypt32/store.c
+++ b/dlls/crypt32/store.c
@@ -2646,6 +2646,13 @@
return ret;
}
+static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext,
+ DWORD dwType, DWORD dwFlags, const void *pvPara)
+{
+ return compare_cert_by_subject_cert(pCertContext, dwType, dwFlags,
+ ((PCCERT_CONTEXT)pvPara)->pCertInfo);
+}
+
PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
@@ -2673,6 +2680,9 @@
case CERT_COMPARE_SUBJECT_CERT:
compare = compare_cert_by_subject_cert;
break;
+ case CERT_COMPARE_ISSUER_OF:
+ compare = compare_cert_by_issuer;
+ break;
default:
FIXME("find type %08lx unimplemented\n", dwType);
compare = NULL;
@@ -2713,6 +2723,50 @@
CERT_FIND_SUBJECT_CERT, pCertId, NULL);
}
+PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
+ PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
+ DWORD *pdwFlags)
+{
+ static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
+ CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
+ PCCERT_CONTEXT ret;
+
+ TRACE("(%p, %p, %p, %08lx)\n", hCertStore, pSubjectContext,
+ pPrevIssuerContext, *pdwFlags);
+
+ if (*pdwFlags & ~supportedFlags)
+ {
+ SetLastError(E_INVALIDARG);
+ return NULL;
+ }
+ ret = CertFindCertificateInStore(hCertStore,
+ pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
+ pSubjectContext, pPrevIssuerContext);
+ if (ret)
+ {
+ if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
+ {
+ FIXME("revocation check requires CRL support\n");
+ *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
+ }
+ if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
+ {
+ if (0 == CertVerifyTimeValidity(NULL, pSubjectContext->pCertInfo))
+ *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
+ }
+ if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
+ {
+ if (CryptVerifyCertificateSignatureEx(0,
+ pSubjectContext->dwCertEncodingType,
+ CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubjectContext,
+ CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)ret, 0, NULL))
+ *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
+ }
+ }
+
+ return ret;
+}
+
BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
{
diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c
index b5dd1d6..f9ecc6a 100644
--- a/dlls/crypt32/tests/store.c
+++ b/dlls/crypt32/tests/store.c
@@ -427,6 +427,129 @@
}
}
+/* This expires in 1970 or so */
+static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
+ 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
+ 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
+ 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
+ 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
+ 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
+ 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
+ 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
+ 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
+ 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
+ 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
+ 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
+ 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
+ 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
+ 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
+ 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
+ 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
+ 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
+ 0x49, 0xe5, 0xf9, 0x65, 0xf3 };
+
+/* This expires in 2036 or so */
+static const BYTE childOfExpired[] = { 0x30, 0x81, 0xcc, 0x30, 0x78, 0xa0,
+ 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d,
+ 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63,
+ 0x40, 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x35, 0x30, 0x35,
+ 0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x35,
+ 0x30, 0x35, 0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 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, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x20, 0x3b, 0xdb, 0x4d, 0x67, 0x50,
+ 0xec, 0x73, 0x9d, 0xf9, 0x85, 0x5d, 0x18, 0xe9, 0xb4, 0x98, 0xe3, 0x31, 0xb7,
+ 0x03, 0x0b, 0xc0, 0x39, 0x93, 0x56, 0x81, 0x0a, 0xfc, 0x78, 0xa8, 0x29, 0x42,
+ 0x5f, 0x69, 0xfb, 0xbc, 0x5b, 0xf2, 0xa6, 0x2a, 0xbe, 0x91, 0x2c, 0xfc, 0x89,
+ 0x69, 0x15, 0x18, 0x58, 0xe5, 0x02, 0x75, 0xf7, 0x2a, 0xb6, 0xa9, 0xfb, 0x47,
+ 0x6a, 0x6e, 0x0a, 0x9b, 0xe9, 0xdc };
+
+static void testGetIssuerCert(void)
+{
+ BOOL ret;
+ PCCERT_CONTEXT parent, child;
+ DWORD flags = 0xffffffff;
+ HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
+ CERT_STORE_CREATE_NEW_FLAG, NULL);
+
+ ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
+
+ ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
+ expiredCert, sizeof(expiredCert), CERT_STORE_ADD_ALWAYS, NULL);
+ ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
+ GetLastError());
+
+ ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
+ childOfExpired, sizeof(childOfExpired), CERT_STORE_ADD_ALWAYS, &child);
+ ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
+ GetLastError());
+
+ /* These crash:
+ parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, NULL);
+ parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, NULL);
+ */
+ parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, &flags);
+ ok(!parent && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08lx\n", GetLastError());
+ parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, &flags);
+ ok(!parent && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08lx\n", GetLastError());
+ parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
+ ok(!parent && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08lx\n", GetLastError());
+ /* Confusing: the caller cannot set either of the
+ * CERT_STORE_NO_*_FLAGs, as these are not checks,
+ * they're results:
+ */
+ flags = CERT_STORE_NO_CRL_FLAG | CERT_STORE_NO_ISSUER_FLAG;
+ parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
+ ok(!parent && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %08lx\n", GetLastError());
+ /* Perform no checks */
+ flags = 0;
+ parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
+ ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08lx\n",
+ GetLastError());
+ if (parent)
+ CertFreeCertificateContext(parent);
+ /* Check revocation and signature only */
+ flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
+ parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
+ ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08lx\n",
+ GetLastError());
+ /* Confusing: CERT_STORE_REVOCATION_FLAG succeeds when there is no CRL by
+ * setting CERT_STORE_NO_CRL_FLAG.
+ */
+ ok(flags == (CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG),
+ "Expected CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG, got %08lx\n",
+ flags);
+ if (parent)
+ CertFreeCertificateContext(parent);
+ /* Now check just the time */
+ flags = CERT_STORE_TIME_VALIDITY_FLAG;
+ parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
+ ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08lx\n",
+ GetLastError());
+ /* Oops: the child is not expired, so the time validity check actually
+ * succeeds, even though the signing cert is expired.
+ */
+ ok(!flags, "Expected check to succeed, got %08lx\n", flags);
+ if (parent)
+ CertFreeCertificateContext(parent);
+
+ CertFreeCertificateContext(child);
+ CertCloseStore(store, 0);
+}
+
static void testMemStore(void)
{
HCERTSTORE store1, store2;
@@ -1702,6 +1825,7 @@
testDupCert();
testFindCert();
testGetSubjectCert();
+ testGetIssuerCert();
/* various combinations of CertOpenStore */
testMemStore();
diff --git a/include/wincrypt.h b/include/wincrypt.h
index 32e3c8d..7017f5a 100644
--- a/include/wincrypt.h
+++ b/include/wincrypt.h
@@ -2389,6 +2389,15 @@
#define CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG \
CERT_RDN_DISABLE_IE4_UTF8_FLAG
+#define CERT_STORE_SIGNATURE_FLAG 0x00000001
+#define CERT_STORE_TIME_VALIDITY_FLAG 0x00000002
+#define CERT_STORE_REVOCATION_FLAG 0x00000004
+#define CERT_STORE_NO_CRL_FLAG 0x00010000
+#define CERT_STORE_NO_ISSUER_FLAG 0x00020000
+
+#define CERT_STORE_BASE_CRL_FLAG 0x00000100
+#define CERT_STORE_DELTA_CRL_FLAG 0x00000200
+
/* subject types for CryptVerifyCertificateSignatureEx */
#define CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB 1
#define CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT 2
@@ -2728,6 +2737,10 @@
DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext);
+PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
+ PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
+ DWORD *pdwFlags);
+
PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
DWORD dwCertEncodingType, PCERT_INFO pCertId);