windows-nt/Source/XPSP1/NT/ds/security/inc/protrust.h

482 lines
21 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: protrust.h
//
// Contents: Protected Trust Provider
// API Prototypes and Definitions
//
// Implements a generic trust provider that allows verification of certifciates
// and uses a call back to check the policy. The policy is called for each signature
// in the subject and for each signer within the signature
//
// Documentation is at the bottom of the file.
//
//--------------------------------------------------------------------------
#ifndef _PROTRUST_H_
#define _PROTRUST_H_
#include "signcde.h"
#ifdef __cplusplus
extern "C" {
#endif
//+-------------------------------------------------------------------------
// PROTRUST optional certificate verification checks (elements to check)
//--------------------------------------------------------------------------
// PROTRUST_CERT_SIGNATURE_FLAG - verify certificate signature
// PROTRUST_CERT_TIME_VALIDITY_FLAG - verify certificate time
// PROTRUST_CERT_REVOCATION_VALIDITY_FLAG - verify revocation of certificates
//
// PROTRUST_TIMESTAMP_SIGNATURE_FLAG - verify timestamp certificate
// PROTRUST_TRUST_TEST_ROOT - verify up to the test root
#define PROTRUST_CERT_SIGNATURE_FLAG CERT_STORE_SIGNATURE_FLAG
#define PROTRUST_CERT_TIME_VALIDITY_FLAG CERT_STORE_TIME_VALIDITY_FLAG
#define PROTRUST_CERT_REVOCATION_VALIDITY_FLAG CERT_STORE_REVOCATION_FLAG
#define PROTRUST_TIMESTAMP_SIGNATURE_FLAG 0x00040000
#define PROTRUST_TRUST_TEST_ROOT 0x00080000
//+-------------------------------------------------------------------------
// PROTRUST signature verification (elements that failed; See dwStatusFlags below)
//--------------------------------------------------------------------------
// PROTRUST_TIME_FLAG - Time of the signer certificate is not valid
// PROTRUST_DIGEST_FLAG - digest of signature did not verify
// PROTRUST_ROOT_FLAG - unable to find a trusted root
// (NOTE. check pRoot to see if a root was found)
// These flags are supplied only to a policy call back. They are not returned
// to the caller of WinVerifyTrust.
#define PROTRUST_TIME_FLAG 0x20000000 // Time of a certificate in chain is not valid
#define PROTRUST_DIGEST_FLAG 0x40000000 //
#define PROTRUST_ROOT_FLAG 0x80000000
//+-------------------------------------------------------------------------
#define REGSTR_PATH_PROTRUST REGSTR_PATH_SERVICES "\\WinTrust\\TrustProviders\\Protected Trust"
#define WIN_PROTECTED_ACTION \
{ 0xa692ba40, 0x6da8, 0x11d0, { 0xa7, 0x0, 0x0, 0xa0, 0xc9, 0x3, 0xb8, 0x3d } }
// Policy Information supplied to the call back, Use only what is required to
// determine if the signature is to be trusted.
typedef struct _PROTECTED_POLICY_INFO {
HCRYPTPROV hCryptProv; // The provider used in verfication
DWORD dwEncodingType; // Encoding type of certificate
DWORD dwSignCount; // Signature, may be more then one signature
DWORD dwSigner; // Which signer in signature, may be more then one signer
DWORD dwVerifyFlags; // Search flags used to find certificates in chain
PCCERT_CONTEXT pCertContext; // Signing Certificate found
PCCERT_CONTEXT pRoot; // Root Certificate found
PCCERT_CONTEXTLIST pCertChain; // Chain used to verify certificate
FILETIME sTime; // Valid date for certificates (ie time stamp)
CRYPT_DIGEST_BLOB sDigest; // Digest (unsigned hash) from signature
PCRYPT_ATTRIBUTES pAuthenticatedAttributes; // List of authenticated attributes
PCRYPT_ATTRIBUTES pUnauthenticatedAttributes; // List of unauthenticated attributes
PBYTE pbSignature; // Encoded Signature
DWORD cbSignature; // Size of Encoded Signature
DWORD dwStatusFlags; // Status flags defined in PROTECTED trust model
} PROTECTED_POLICY_INFO, *PPROTECTED_POLICY_INFO;
// PROTECTED Trust Policy is defined as:
typedef HRESULT (WINAPI *_PROTECTED_TRUST_POLICY)(IN HANDLE hClientToken,
IN PPROTECTED_POLICY_INFO pInfo);
// Policy List is defined as:
typedef struct _PROTECTED_TRUST_INFO {
DWORD cbSize; // sizeof(_PROTECTED_TRUST_POLICY_LIST)
DWORD dwVerifyFlags; // Should contain at least PROTRUST_CERT_SIGNATURE_FLAG
DWORD dwCertEncodingType; // Optional, defaults to X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
HCRYPTPROV hCryptProv; // Optional, pass in provider for doing verification
HCERTSTORE hTrustedStore; // Optional, list of trusted roots
HCERTSTORE hCertificateStore; // Optional, additional certs to use in verification
_PROTECTED_TRUST_POLICY pfnPolicy; // Optional, application defined user policy
} PROTECTED_TRUST_INFO, *PPROTECTED_TRUST_INFO;
typedef struct _PROTECTED_TRUST_ACTDATA_CALLER_CONTEXT {
HANDLE hClientToken;
GUID * SubjectType;
WIN_TRUST_SUBJECT Subject;
PROTECTED_TRUST_INFO sTrustInfo;
} PROTECTED_TRUST_ACTDATA_CALLER_CONTEXT, *LPPROTECTED_TRUST_ACTDATA_CALLER_CONTEXT;
// The policy provider must use the following return codes
// Returns S_OK: - valid signature, returns from the trust provider
// S_FALSE: - continue on to the next signature or signer
// ERROR: - aborts trust provider and exists with this error code.
//
//---------------------------------------------------------------------------
/*
Generic Trust Provider
Usage: The generic trust provider is designed to provide a flexible manner for
implementing a policy where the developer can let the provider do as much or
as little of the decision making as required. Verifying is composed of two stages,
the first is to determine if the signature matches the item that was signed. The
second stage is to determine if the certificate used to do the signing was valid.
This second stage is dependent on the policy of the calling application, criteria
like, root certificates, specific signature certicates, certificate extensions can
all be used to determine if the signature is valid.
There are three ways of using the generic trust provider (GTB) to do the verification,
1) let the GTB verify the digest and verify the certificate.
2) let the GTB verify the digest and verify the certificate supplying the GTB root
certificates that can be trusted.
3) supply a policy call back that the GTB calls providing the signature, certificates
and its status for the digest and the certifcate to the policy call back.
METHOD 1) Let the trust provider do the verfication
Fill in a PROTECTED_TRUST_INFO structure. The only fields that must be filled in are
cbSize and dwVerifyFlags. dwVerifyFlags specify how to determine if the signing certificate
and all the issuer certificates are valid (validity flags can be combined).
cbSize = sizeof(PROTECTED_TRUST_INFO);
dwVerifyFlags = zero or more of PROTRUST_CERT_SIGNATURE_FLAG
PROTRUST_CERT_TIME_VALIDITY_FLAG
PROTRUST_TIMESTAMP_SIGNATURE_FLAG
PROTRUST_TRUST_TEST_ROOT.
(where:
PROTRUST_CERT_SIGNATURE_FLAG - verify certificates on signatures
(ie find the issuer certificate and
verify the signature of the certificate).
PROTRUST_CERT_TIME_VALIDITY_FLAG - verify that the certificate is
valid at the current time.
PROTRUST_TIMESTAMP_SIGNATURE_FLAG - verify that the certificate was
valid at the time a time-stamp was
placed on the signature. If there
is no time stamp then use the current time.
PROTRUST_TRUST_TEST_ROOT - Verifying the certifcate chain to the test
root is valid.)
WinVerifyTrust will return:
S_OK - signature verified
TRUST_E_NOSIGNATURE - no signature found
NTE_BAD_SIGNATURE - signature did not verify to digest
CERT_E_UNTRUSTEDROOT - verifyied to an untrusted root
CERT_E_CHAINING - a certificate could not be verified (issuer not found)
CERT_E_EXPIRED - a valid certificate chain could not be found
(ceritifcate or issuer expired)
METHOD 2) Let the trust provider verify to a list of certificates.
Add a store to the PROTECTED_TRUST_INFO structure in addition to the entries
specified in method 1.
hTrustedStore = a store that contains all roots that are to be trusted.
(This store can be opened using CertOpenSystemStore etc.)
cbSize = sizeof(PROTECTED_TRUST_INFO);
dwVerifyFlags = zero or more of PROTRUST_CERT_SIGNATURE_FLAG
PROTRUST_CERT_TIME_VALIDITY_FLAG
PROTRUST_TIMESTAMP_SIGNATURE_FLAG
PROTRUST_TRUST_TEST_ROOT.
(where:
PROTRUST_CERT_SIGNATURE_FLAG - verify certificates on signatures
(ie find the issuer certificate and
verify the signature of the certificate).
PROTRUST_CERT_TIME_VALIDITY_FLAG - verify that the certificate is
valid at the current time.
PROTRUST_TIMESTAMP_SIGNATURE_FLAG - verify that the certificate was
valid at the time a time-stamp was
placed on the signature. If there
is no time stamp then use the current time.
PROTRUST_TRUST_TEST_ROOT - Verifying the certifcate chain to the test
root is valid.)
WinVerifyTrust will return:
S_OK - signature verified
TRUST_E_NOSIGNATURE - no signature found
NTE_BAD_SIGNATURE - signature did not verify to digest
CERT_E_UNTRUSTEDROOT - verifyied to an untrusted root
CERT_E_CHAINING - a certificate could not be verified (issuer not found)
CERT_E_EXPIRED - a valid certificate chain could not be found
(ceritifcate or issuer expired)
METHOD 3) Pass in a policy call back that is called prior to returning from
WinVerifyTrust. The call back is called for every signature found and for
each signer in a signature. When then call back returns S_OK then the WinVerifyTrust
returns. If S_FALSE is returned from the call back then the next signer or signature
is tried. If and error is found then WinVerifyTrust returns this error immediately.
The call back must by of type _PROTECTED_TRUST_POLICY. This function takes a HANDLE
and a PPROTECTED_POLICY_INFO. The handle points to client data that is passed into
WinVerifyTrust, it can contain data, returned elements, status flags etc. The
PPROTECTED_POLICY_INFO points to a structure that contains all the information the
general trust provider found in the signature. The policy call back can use some or
all of this data in determining if the signature is valid.
In addition to method 1 and method 2 a call back procedure is added to the
PROTECTED_TRUST_INFO structure.
pfnPolicy = MyPolicy;
(where:
MyPolicy is a function defined by the caller.)
hTrustedStore = a store that contains all roots that are to be trusted.
(This store can be opened using CertOpenSystemStore etc.)
cbSize = sizeof(PROTECTED_TRUST_INFO);
dwVerifyFlags = zero or more of PROTRUST_CERT_SIGNATURE_FLAG
PROTRUST_CERT_TIME_VALIDITY_FLAG
PROTRUST_TIMESTAMP_SIGNATURE_FLAG
PROTRUST_TRUST_TEST_ROOT.
(where:
PROTRUST_CERT_SIGNATURE_FLAG - verify certificates on signatures
(ie find the issuer certificate and
verify the signature of the certificate).
PROTRUST_CERT_TIME_VALIDITY_FLAG - verify that the certificate is
valid at the current time.
PROTRUST_TIMESTAMP_SIGNATURE_FLAG - verify that the certificate was
valid at the time a time-stamp was
placed on the signature. If there
is no time stamp then use the current time.
PROTRUST_TRUST_TEST_ROOT - Verifying the certifcate chain to the test
root is valid.)
WinVerifyTrust will return:
The return code from the policy module.
Example: of policy callback.
//
// Protest3 - tool for manually calling WinVerifyTrust
//
#include <stdio.h>
#include <windows.h>
#include "wincrypt.h"
#include "signcde.h"
#include "protrust.h"
// Potential Subject ids
GUID guidProtectedTrust = WIN_PROTECTED_ACTION;
GUID guidSubjectPeImage = WIN_TRUST_SUBJTYPE_PE_IMAGE;
GUID guidSubjectJavaClass = WIN_TRUST_SUBJTYPE_JAVA_CLASS;
GUID guidSubjectCabinet = WIN_TRUST_SUBJTYPE_CABINET;
// Which action and subject will be used
GUID* pguidActionID = &guidProtectedTrust;
GUID* pguidSubject = &guidSubjectPeImage;
// Structures used to call WinVerifyTrust
PROTECTED_TRUST_ACTDATA_CALLER_CONTEXT sSetup;
WIN_TRUST_SUBJECT_FILE sSubjectFile;
// Set up my own error codes
#define MY_CODE_NO_ROOT 0x00010000
#define MY_CODE_BAD_DIGEST 0x00100000
#define MY_CODE_BAD_TIME 0x00200000
// Define my structure for use in the Policy call back.
typedef struct _CLIENT_DATA {
DWORD dwStatusFlags; // Verification Status
BOOL dwRealRoot; // Did it verify to the real microsoft root
BOOL dwTestRoot; // Did it verify to the test root
} CLIENT_DATA, *PCLIENT_DATA;
HRESULT WINAPI MyPolicy(IN HANDLE hClientToken,
IN PPROTECTED_POLICY_INFO pInfo)
{
HRESULT hr = S_OK;
PCLIENT_DATA pClient = (PCLIENT_DATA) hClientToken;
if(pInfo->dwStatusFlags & PROTRUST_DIGEST_FLAG) {
// Bad digest
pClient->dwStatusFlags |= MY_CODE_BAD_DIGEST;
return S_FALSE; // Try next one
}
// Check to see if the signing certificate had a valid time
if(pInfo->dwStatusFlags & PROTRUST_TIME_FLAG) {
// time expired on certificate or issuer
pClient->dwStatusFlags |= MY_CODE_BAD_TIME;
return S_FALSE; // Try next one
}
// Check to see we got a root cert. If not then we did
// not verify up to a root.
if(!pInfo->pRoot) {
pClient->dwStatusFlags |= MY_CODE_NO_ROOT;
hr = CERT_E_ISSUERCHAINING;
}
else {
// Test the Cert to see which one it is
hr = SpcIsRootCert(pInfo->pRoot);
if(hr == S_FALSE) { // The certificate is the test root cert
pClient->dwRealRoot = FALSE;
pClient->dwTestRoot = TRUE;
}
else if(hr == S_OK) {
pClient->dwRealRoot = TRUE;
pClient->dwTestRoot = FALSE;
}
}
return hr;
}
// Information defined by me for use in my policy
WCHAR rgwSubjectPath[_MAX_PATH];
BOOL fCheckTimeStamp = FALSE;
BOOL fCheckCurrentTime = FALSE;
BOOL fTestRootOk = FALSE;
void Usage ()
{
printf ( "Usage: CHKTRUST [-options] file-name\n" );
printf ( "Options:\n" );
printf ( " -I : subject type is PE executable image file (default)\n" );
printf ( " -J : subject type is Java class\n" );
printf ( " -C : subject type is Cabinet file\n" );
printf ( " -S : check for a time stamp\n");
printf ( " -T : test root is valid\n");
printf ( " -U : use current time to see if certificates are valid\n");
exit ( 0 );
}
VOID
WINAPI
ParseSwitch (CHAR chSwitch,
int *pArgc,
char **pArgv[])
{
switch (toupper (chSwitch)) {
case '?':
Usage();
break;
case 'I':
pguidSubject = &guidSubjectPeImage;
break;
case 'J':
pguidSubject = &guidSubjectJavaClass;
break;
case 'C':
pguidSubject = &guidSubjectCabinet;
break;
case 'S':
fCheckTimeStamp = TRUE;
break;
case 'T':
fTestRootOk = TRUE;
break;
case 'U':
fCheckCurrentTime = TRUE;
break;
default:
Usage ();
break;
}
}
void _cdecl main ( int argc, char** argv )
{
HCERTSTORE hRoots = NULL;
WCHAR wpath[_MAX_PATH];
char chChar, *pchChar;
if ( argc <= 1 ) Usage ();
while (--argc) {
pchChar = *++argv;
if (*pchChar == '/' || *pchChar == '-') {
while (chChar = *++pchChar) {
ParseSwitch (chChar, &argc, &argv);
}
}
else {
MultiByteToWideChar ( CP_ACP, 0, pchChar, -1, wpath, _MAX_PATH );
sSubjectFile.hFile = INVALID_HANDLE_VALUE;
sSubjectFile.lpPath = &(wpath[0]);
sSetup.SubjectType = pguidSubject;
sSetup.Subject = &sSubjectFile;
}
}
// Make sure we have a file
if ( sSubjectFile.lpPath == NULL )
Usage();
// Setup up client data for policy (application decides what this is)
CLIENT_DATA sClientData;
// Zero out structure
ZeroMemory(&sClientData, sizeof(CLIENT_DATA));
// Set the Client structure to return status codes
sSetup.hClientToken = (HANDLE) &sClientData;
//==================
// Setup the Protrust structure
// Setup the Protected Trust info (Most fields are optional)
// Zero out structure
ZeroMemory(&sSetup.sTrustInfo, sizeof(PROTECTED_TRUST_INFO));
// Set size of structure for extensibility
sSetup.sTrustInfo.cbSize = sizeof(PROTECTED_TRUST_INFO); //
// Check the possible flags for verifying certificates
sSetup.sTrustInfo.dwVerifyFlags = PROTRUST_CERT_SIGNATURE_FLAG;
if(fTestRootOk)
sSetup.sTrustInfo.dwVerifyFlags |= PROTRUST_TRUST_TEST_ROOT;
if(fCheckTimeStamp)
sSetup.sTrustInfo.dwVerifyFlags |= PROTRUST_TIMESTAMP_SIGNATURE_FLAG;
if(fCheckCurrentTime)
sSetup.sTrustInfo.dwVerifyFlags |= PROTRUST_CERT_TIME_VALIDITY_FLAG;
// Set the policy (defined above)
sSetup.sTrustInfo.pfnPolicy = MyPolicy;
// The rest of sSetup.sTrustInfo is the default values
//==================
// Check the file
DWORD r = WinVerifyTrust ( NULL, pguidActionID, &sSetup );
if(sClientData.dwStatusFlags & MY_CODE_NO_ROOT)
printf ("Did not find a root certificate\n");
if(sClientData.dwStatusFlags & MY_CODE_BAD_DIGEST)
printf ("There was no valid signature\n");
if(sClientData.dwStatusFlags & MY_CODE_BAD_TIME)
printf ("The certificate had an invalid time\n");
switch(r) {
case TRUST_E_NOSIGNATURE:
printf ("No signature found\n");
break;
default:
printf ("Result: %0x\n", r );
}
if(hRoots)
CertCloseStore(hRoots, 0);
exit ( r == 0 ? 0 : 1 );
}
*/
//---------------------------------------------------------------------------
#ifdef __cplusplus
}
#endif
#endif //_PROTRUST_H_