Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Toto téma popisuje, jak ověřit podpisy v dokumentu XPS a jak ověřit certifikáty, které souvisejí s těmito podpisy.
Před použitím následujících příkladů kódu v programu si přečtěte prohlášení o vyloučení odpovědnosti v Common Digital Signature Programming Tasks.
Následující příklad kódu zkontroluje digitální podpisy nalezené v dokumentu XPS.
Pokud chcete zkontrolovat podpisy v dokumentu XPS, proveďte následující kroky:
- Načtěte dokument do správce podpisu, jak je popsáno v Inicializace správce podpisů.
- Získejte kolekci podpisů od správce digitálních podpisů.
- Získejte počet podpisů v kolekci.
- Pro každý podpis v kolekci volejte metodu Verify, jak je znázorněno v následujícím příkladu kódu.
HRESULT
VerifyAllDigitalSignaturesAndAuthenticateCertificates(
IXpsSignatureManager *signatureManager
)
{
HRESULT hr = S_OK;
IXpsSignature *signature = NULL;
IXpsSignatureCollection *signaturesInDocument = NULL;
UINT32 numberOfSignaturesInDocument = NULL;
hr = signatureManager->GetSignatures(&signaturesInDocument);
if (SUCCEEDED(hr)) {
hr = signaturesInDocument->GetCount(&numberOfSignaturesInDocument);
}
if (SUCCEEDED(hr)) {
// Check each signature in the XPS document that was opened in
// the signature manager.
for (UINT32 index = 0; index < numberOfSignaturesInDocument; index++)
{
// Get the signature in the current index of the
// IXpsSignatureCollection object
hr = signaturesInDocument->GetAt(index, &signature);
if (SUCCEEDED(hr)) {
PCCERT_CONTEXT signingCertificate = NULL;
XPS_SIGNATURE_STATUS signatureStatus;
signatureStatus = XPS_SIGNATURE_STATUS_BROKEN;
// Verify the signature and authenticate
// its signing certificate
hr = VerifySignatureAndCertificates (
signature,
&signingCertificate,
&signatureStatus);
if (FAILED(hr)) {
// If a FACILITY_SECURITY error code is returned then
// the current certificate was not the
// signing certificate, so continue with
// the enumeration.
if (HRESULT_FACILITY(hr) != FACILITY_SECURITY)
{
// If the error was not a FACILITY_SECURITY error
// then exit and return the error
break; // out of for loop
}
}
// release pointers for next loop
if (NULL != signature) {
signature->Release();
signature = NULL;
}
if (NULL != signingCertificate) {
CertFreeCertificateContext (signingCertificate);
signingCertificate = NULL;
}
}
}
}
if (NULL != signaturesInDocument) signaturesInDocument->Release();
return hr;
}
Pokud chcete ověřit digitální podpis, nejprve ověřte podpis vytvořený podpisovým certifikátem, a poté zkontrolujte samotný podpisový certifikát. Metoda ověřování použitá v následujícím příkladu kódu ukládá certifikáty do dočasného úložiště certifikátů, které funkce rozhraní Crypto API používají, když jsou volány později v tomto příkladu.
Pokud chcete vytvořit dočasné úložiště certifikátů, proveďte následující kroky:
- Vytvořte dočasné úložiště certifikátů pro uložení certifikátů používaných podpisem.
- Iterujte prostřednictvím sady certifikátů podpisu a načtěte každý certifikát do dočasného úložiště certifikátů.
HRESULT VerifySignatureAndCertificates (
IXpsSignature *signature,
PCCERT_CONTEXT *signingCertificate,
XPS_SIGNATURE_STATUS *signatureStatus
)
{
HRESULT hr = S_OK;
BOOL moreCertificates = FALSE;
IOpcCertificateEnumerator *certificatesInSignature = NULL;
HCERTSTORE signatureCertificateStore = NULL;
// Create a temporary certificate store.
signatureCertificateStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING,
NULL,
0,
NULL);
// Create a certificate enumerator to store the certificates
// that are associated with the current signature.
hr = signature->GetCertificateEnumerator(&certificatesInSignature);
if (SUCCEEDED(hr))
{
// We need to call the MoveNext method to initialize the enumerator.
hr = certificatesInSignature->MoveNext(&moreCertificates);
}
if (SUCCEEDED(hr))
{
// Iterate through the certificates in the signature,
// and add each one to the temporary certificate store.
// This temporary certificate store simplifies
// authentication of the signing certificate.
while (moreCertificates)
{
PCCERT_CONTEXT certificate = NULL;
hr = certificatesInSignature->GetCurrent(&certificate);
if (SUCCEEDED(hr))
{
// got the next certificate so
// add the current certificate to the temporary certificate store.
if (!CertAddCertificateContextToStore(signatureCertificateStore,
certificate,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL))
{
hr = E_FAIL;
// ERROR: could not add the certificate to the certificate store
break; // out of while loop
}
CertFreeCertificateContext (certificate);
}
else
{
// unable to get the certificate so skip
}
// move to next certificate in set
if (FAILED(hr = certificatesInSignature->MoveNext(&moreCertificates)))
{
// ERROR: could not move to the next certificate in the enumerator
break; // out of while loop
}
// moreCertificates == FALSE when the end of the set has been reached.
}//End while
}
if (NULL != certificatesInSignature) certificatesInSignature->Release();
Pokud chcete ověřit digitální podpis a certifikát použitý k podepsání dokumentu, proveďte následující kroky:
- Najděte podpisový certifikát procházením certifikátů, které jsou použity podpisem.
- Otestujte certifikát ověřením podpisu s certifikátem. Podpisový certifikát se najde, když metoda Verify vrátí XPS_SIGNATURE_STATUSXPS_SIGNATURE_STATUS_VALID nebo XPS_SIGNATURE_STATUS_QUESTIONABLEa nevrací chybu FACILITY_SECURITY.
// Reset the enumerator
hr = signature->GetCertificateEnumerator(&certificatesInSignature);
if (SUCCEEDED (hr))
{
moreCertificates = FALSE;
hr = certificatesInSignature->MoveNext(&moreCertificates);
}
if (SUCCEEDED(hr))
{
// Iterate through the certificates in the signature,
// and call the IXpsSignature.Verify() method
// on each certificate.
// A signature can include an entire certificate chain, and so
// only one of the certificates found in this enumeration
// is the certificate that was used to sign the package.
// The signing certificate is the one to authenticate.
// To find the signing certificate, iterate through
// the certificates in the signature and select the certificate that
// returns an XPS_SIGNATURE_STATUS of XPS_SIGNATURE_STATUS_VALID
// or XPS_SIGNATURE_STATUS_QUESTIONABLE and does not return a
// FACILITY_SECURITY error.
XPS_SIGNATURE_STATUS localSignatureStatus;
localSignatureStatus = XPS_SIGNATURE_STATUS_INCOMPLIANT;
do
{
PCCERT_CONTEXT certificate = NULL;
DWORD certificateStatus = NULL;
if (FAILED(hr = certificatesInSignature->GetCurrent(&certificate)))
{
// We will skip corrupted certificates
// free this one and move to the next
CertFreeCertificateContext (certificate);
hr = certificatesInSignature->MoveNext(&moreCertificates);
if (FAILED(hr))
{
// ERROR: could not move to the next
// certificate in the enumerator
break; // out of do loop with failed hr
}
// continue with next loop iteration
continue;
}
// Verify that the signature conforms to the XPS signing policy.
hr = signature->Verify(certificate, &localSignatureStatus);
if (FAILED(hr))
{
// If a FACILITY_SECURITY error code is returned, then the
// current certificate was not the signing certificate,
// so continue to the next certificate.
if (HRESULT_FACILITY(hr) == FACILITY_SECURITY)
{
// free this one and move to the next
CertFreeCertificateContext (certificate);
hr = certificatesInSignature->MoveNext(&moreCertificates);
if (FAILED(hr))
{
// ERROR: could not move to the next certificate
// in the enumerator
break; // out of do loop with failed hr
}
continue;
}
// ERROR: An attempt to verify the signature has failed
break; // out of do loop with failed hr
}
// if verification was successful, localSignatureStatus will
// contain the status of the signature.
//
// do loop continues in next code example
Po nalezení podpisového certifikátu proveďte následující kroky:
- Uložte vrácený stav podpisu.
- V případě potřeby aktualizujte místní stav a proveďte následné testy certifikátů:
- Pokud je stav podpisu úspěšný, nastavte místní stav na sporný pro testování certifikátů.
- Pokud stav podpisu nesplňuje normy, ponechte místní stav jako nevyhovující.
- Pokud je stav podpisu přerušený nebo neúplný, nastavte místní stav na přerušený.
Stav podpisu XPS_SIGNATURE_STATUS_INCOMPLIANT znamená, že části dokumentu XPS, které by neměly být podepsány, byly podepsány nebo části dokumentu XPS, které by měly být podepsány, nebyly. Pokud Ověřit vrátí tento stav podpisu, bude další kontrola podpisu zbytečná.
// continuing do loop from previous code example
*signingCertificate = certificate;
*signatureStatus = localSignatureStatus;
// note that this test should only downgrade the
// signature status, it should not upgrade it.
switch (localSignatureStatus) {
case XPS_SIGNATURE_STATUS_VALID:
case XPS_SIGNATURE_STATUS_QUESTIONABLE:
// the signature is valid or questionable so
// save the actual status and set the new status
// to questionable so the certificates will be checked.
localSignatureStatus = XPS_SIGNATURE_STATUS_QUESTIONABLE;
break;
case XPS_SIGNATURE_STATUS_INCOMPLIANT:
// the signature is not compliant
break;
case XPS_SIGNATURE_STATUS_INCOMPLETE:
case XPS_SIGNATURE_STATUS_BROKEN:
// The Windows 7 XPS viewer displays incomplete signatures
// and broken signatures as broken.
*signatureStatus = XPS_SIGNATURE_STATUS_BROKEN;
localSignatureStatus = XPS_SIGNATURE_STATUS_BROKEN;
break;
default:
// there should be no other possible status values
break;
}
// do loop continues in next code example
Chcete-li ověřit důvěryhodnost certifikátu, když je stav podpisu platný nebo pochybný, proveďte následující kroky:
- Získejte stav důvěryhodnosti certifikátu.
- Vyhodnoťte vrácený stav důvěryhodnosti certifikátu.
- Vrátí výsledný stav.
Následující příklad kódu netestuje pro každý možný stav důvěryhodnosti certifikátu. Další podrobnosti o stavových hodnotách, které lze vrátit, najdete v tématu CERT_TRUST_STATUS.
// continuing do loop from previous code example
//
// at this point, localSignatureStatus should be less than or
// equal to what it was before the test.
// Check the certificate to see if it is valid
if ((localSignatureStatus == XPS_SIGNATURE_STATUS_VALID) ||
(localSignatureStatus == XPS_SIGNATURE_STATUS_QUESTIONABLE))
{
// This call builds the certificate trust chain from the
// supplied certificate. The certificate chain is used to
// authenticate the supplied certificate.
hr = GetCertificateTrustStatus (
*signingCertificate,
&signatureCertificateStore,
&certificateStatus);
if (FAILED(hr))
{
// ERROR: An attempt to authenticate the certificate
// has failed
break; // out of do loop with failed hr
}
// The Crypt API returns a status that can contain more than
// one status value.
// statusFlagMask is set to test all bits except for the
// CERT_TRUST_REVOCATION_STATUS_UNKNOWN
// CERT_TRUST_IS_OFFLINE_REVOCATION
// CERT_TRUST_IS_NOT_TIME_VALID
// values because, for this test, these are not considered
// to be error conditions.
DWORD statusFlagMask = ~(
CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
CERT_TRUST_IS_OFFLINE_REVOCATION |
CERT_TRUST_IS_NOT_TIME_VALID);
if (CERT_TRUST_NO_ERROR == (certificateStatus & statusFlagMask))
{
// If *signatureStatus is already
// XPS_SIGNATURE_STATUS_VALID then there is no need to
// change the status as the certificate status has no
// certificate trust errors.
// If *signatureStatus is already
// XPS_SIGNATURE_STATUS_QUESTIONABLE then we will not
// upgrade the trust status of the signature just
// because there is no trust issue with the certificate.
}
else
{
// If trust errors were detected with the certificate,
// then this XPS signature is given a status of
// XPS_SIGNATURE_STATUS_QUESTIONABLE
*signatureStatus = XPS_SIGNATURE_STATUS_QUESTIONABLE;
}
// Handle additional certificate errors.
// This is not an exhaustive list of possible errors.
if (certificateStatus & CERT_TRUST_IS_NOT_TIME_VALID)
{
// The XPS Viewer considers signatures with
// expired certificates as valid.
}
if (certificateStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
{
// This test ensures that we only degrade the
// trust status and never upgrade it
if (XPS_SIGNATURE_STATUS_VALID == *signatureStatus)
{
*signatureStatus = XPS_SIGNATURE_STATUS_QUESTIONABLE;
}
}
if (certificateStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
{
// This test ensures that we only degrade the
// trust status and never upgrade it
if (XPS_SIGNATURE_STATUS_VALID == *signatureStatus)
{
*signatureStatus = XPS_SIGNATURE_STATUS_QUESTIONABLE;
}
}
if (certificateStatus & CERT_TRUST_IS_SELF_SIGNED)
{
// This test ensures that we only degrade the
// trust status and never upgrade it
if (XPS_SIGNATURE_STATUS_VALID == *signatureStatus)
{
*signatureStatus = XPS_SIGNATURE_STATUS_QUESTIONABLE;
}
}
if (certificateStatus & CERT_TRUST_IS_UNTRUSTED_ROOT)
{
// This test ensures that we only degrade the
// trust status and never upgrade it
if (XPS_SIGNATURE_STATUS_VALID == *signatureStatus)
{
*signatureStatus = XPS_SIGNATURE_STATUS_QUESTIONABLE;
}
}
}//End if
hr = certificatesInSignature->MoveNext(&moreCertificates);
if (FAILED(hr))
{
// ERROR: could not move to the next
// certificate in the enumerator
break; // out of do loop with failed hr
}
} while((*signatureStatus != XPS_SIGNATURE_STATUS_VALID) &&
moreCertificates);
} // end if successful
if (NULL != certificatesInSignature) certificatesInSignature->Release();
return hr;
}
V dalším příkladu kódu se stav důvěryhodnosti certifikátu získá voláním metody uvedené v následujícím příkladu kódu.
HRESULT GetCertificateTrustStatus(
__in PCCERT_CONTEXT certificate,
__in HCERTSTORE* certificateStore,
__out DWORD* certificateStatus
)
{
HRESULT hr = S_OK;
// The certificate chain that will be created from
// the PCCERT_CONTEXT object passed in.
PCCERT_CHAIN_CONTEXT certificateChain = NULL;
hr = CreateCertificateChain(
certificate,
*certificateStore,
&certificateChain);
if (SUCCEEDED(hr)) {
*certificateStatus =
certificateChain->TrustStatus.dwErrorStatus;
}
return hr;
}
Řetěz certifikátů použitý v předchozím příkladu kódu je vytvořen voláním metody uvedené v následujícím příkladu kódu.
HRESULT
CreateCertificateChain (
__in PCCERT_CONTEXT certificate,
__in HCERTSTORE certificateStore,
__out PCCERT_CHAIN_CONTEXT* certificateChain
)
{
HRESULT hr = S_OK;
CERT_CHAIN_PARA certificateChainParameters = {0};
certificateChainParameters.cbSize = sizeof(CERT_CHAIN_PARA);
certificateChainParameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
// CertGetCertificateChain builds a certificate chain that starts
// from the PCCERT_CONTEXT structure provided by the caller.
// After the certificate chain has been successfully created,
// then the authenticity of the certificate can be determined
// by examining the errors, if any, that occurred while the chain
// was created.
BOOL successCreatingCertChain = CertGetCertificateChain (
NULL,
certificate,
NULL,
certificateStore,
&certificateChainParameters,
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
NULL,
certificateChain);
if (!successCreatingCertChain)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
Související témata
-
použitá v této části
-
Další Informace
-
Vložte řetězce certifikátů do dokumentu
-
chyby dokumentu XPS