windows-nt/Source/XPSP1/NT/ds/security/services/ca/certclib/autoenrl.cpp
2020-09-26 16:20:57 +08:00

504 lines
13 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: autoenrl.cpp
//
// Contents: Autoenrollment API implementation
//
// History: 3-Apr-98 petesk created
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include "cainfoc.h"
#include <stdlib.h>
#include <ctype.h>
#include <windows.h>
#include <wincrypt.h>
#include <certca.h>
#define SHA_HASH_SIZE 20
//
// Build the CTL_ENTRY structure for
HRESULT BuildCTLEntry(
IN WCHAR ** awszCAs,
OUT PCTL_ENTRY *ppCTLEntry,
OUT DWORD *pcCTLEntry
)
{
HRESULT hr = S_OK;
PCCERT_CONTEXT pCertContext = NULL;
DWORD cbCert;
BYTE *pbCert = NULL;
DWORD cbHash = SHA_HASH_SIZE;
PCTL_ENTRY pCTLEntry = NULL;
HCAINFO hCACurrent = NULL;
DWORD cCA = 0;
PBYTE pbHash;
// Passing in NULL or a zero length list implies that
// we do lazy evaluation of 'pick any'. Therefore, the
// ctl list should be zero size.
if((ppCTLEntry == NULL) ||
(pcCTLEntry == NULL))
{
hr = E_INVALIDARG;
goto error;
}
if((awszCAs == NULL) ||
(awszCAs[0] == NULL))
{
*pcCTLEntry = 0;
*ppCTLEntry = NULL;
goto error;
}
cCA = 0;
while(awszCAs[cCA])
{
cCA++;
}
pCTLEntry = (PCTL_ENTRY)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
sizeof(CTL_ENTRY)*cCA + SHA_HASH_SIZE*cCA);
if(pCTLEntry == NULL)
{
hr = E_OUTOFMEMORY;
goto error;
}
pbHash = (PBYTE)(pCTLEntry + cCA);
cCA=0;
while(awszCAs[cCA])
{
hr = CAFindByName(awszCAs[cCA], NULL, 0, &hCACurrent);
if(hr != S_OK)
{
goto error;
}
hr = CAGetCACertificate(hCACurrent, &pCertContext);
if(hr != S_OK)
{
goto error;
}
cbHash = SHA_HASH_SIZE;
if(!CertGetCertificateContextProperty(pCertContext,
CERT_SHA1_HASH_PROP_ID,
pbHash,
&cbHash))
{
hr = myHLastError();
goto error;
}
pCTLEntry[cCA].SubjectIdentifier.cbData = cbHash;
pCTLEntry[cCA].SubjectIdentifier.pbData = pbHash;
pbHash += cbHash;
CertFreeCertificateContext(pCertContext);
pCertContext = NULL;
cCA++;
CACloseCA(hCACurrent);
}
*pcCTLEntry = cCA;
*ppCTLEntry = pCTLEntry;
pCTLEntry = NULL;
error:
if (pCTLEntry)
{
LocalFree(pCTLEntry);
}
if(pCertContext)
{
CertFreeCertificateContext(pCertContext);
}
return hr;
}
HRESULT
BuildAutoEnrollmentCTL(
IN LPCWSTR pwszCertType,
IN LPCWSTR pwszObjectID,
IN BOOL fMachine,
IN WCHAR ** awszCAs,
IN PCMSG_SIGNED_ENCODE_INFO pSignerInfo,
OUT BYTE **ppbEncodedCTL,
OUT DWORD *pcbEncodedCTL
)
{
HRESULT hr = S_OK;
PCERT_ENHKEY_USAGE pKeyUsage = NULL;
DWORD cbKeyUsage;
CTL_INFO CTLInfo;
BYTE *pbEncodedCTL = NULL;
DWORD cbEncodedCTL;
LPSTR pszUsageIdentifier;
CERT_EXTENSION CertExt;
CMSG_SIGNED_ENCODE_INFO SignerInfo;
PCERT_EXTENSIONS pCertExtensions = NULL;
DWORD cch = 0;
PCMSG_SIGNED_ENCODE_INFO pSigner = NULL;
HCERTTYPE hCertType = NULL;
ZeroMemory(&CTLInfo, sizeof(CTLInfo));
ZeroMemory(&CertExt, sizeof(CertExt));
ZeroMemory(&SignerInfo, sizeof(SignerInfo));
if(pSignerInfo)
{
pSigner = pSignerInfo;
}
else
{
pSigner = &SignerInfo;
}
#if 0
hr = CAFindCertTypeByName(pwszCertType,
NULL,
(fMachine?CT_ENUM_MACHINE_TYPES | CT_FIND_LOCAL_SYSTEM:CT_ENUM_USER_TYPES),
&hCertType);
if (S_OK != hr)
{
goto error;
}
hr = CAGetCertTypeExtensions(hCertType, &pCertExtensions);
if (S_OK != hr)
{
goto error;
}
#endif
// set up the CTL info
CTLInfo.dwVersion = sizeof(CTLInfo);
CTLInfo.SubjectUsage.cUsageIdentifier = 1;
pszUsageIdentifier = szOID_AUTO_ENROLL_CTL_USAGE;
CTLInfo.SubjectUsage.rgpszUsageIdentifier = &pszUsageIdentifier;
CTLInfo.ListIdentifier.cbData = (wcslen(pwszCertType) + 1) * sizeof(WCHAR);
if(pwszObjectID)
{
CTLInfo.ListIdentifier.cbData += (wcslen(pwszObjectID)+1) * sizeof(WCHAR);
}
CTLInfo.ListIdentifier.pbData = (BYTE *)LocalAlloc(LMEM_ZEROINIT, CTLInfo.ListIdentifier.cbData);
if(CTLInfo.ListIdentifier.pbData == NULL)
{
hr = E_OUTOFMEMORY;
goto error;
}
if(pwszObjectID)
{
wcscpy((LPWSTR)CTLInfo.ListIdentifier.pbData, pwszObjectID);
wcscat((LPWSTR)CTLInfo.ListIdentifier.pbData, L"|");
}
// wcscat can be used as the memory is initialized to zero
wcscat((LPWSTR)CTLInfo.ListIdentifier.pbData, pwszCertType);
GetSystemTimeAsFileTime(&CTLInfo.ThisUpdate);
CTLInfo.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1;
hr = BuildCTLEntry(awszCAs,
&CTLInfo.rgCTLEntry,
&CTLInfo.cCTLEntry);
if (S_OK != hr)
{
goto error;
}
#if 0
// add all the reg info as an extension
CTLInfo.cExtension = pCertExtensions->cExtension;
CTLInfo.rgExtension = pCertExtensions->rgExtension;
#endif
CTLInfo.cExtension = 0;
CTLInfo.rgExtension = NULL;
// encode the CTL
*pcbEncodedCTL = 0;
SignerInfo.cbSize = sizeof(SignerInfo);
if (!CryptMsgEncodeAndSignCTL(PKCS_7_ASN_ENCODING,
&CTLInfo, &SignerInfo, 0,
NULL, pcbEncodedCTL))
{
hr = myHLastError();
goto error;
}
if (NULL == (*ppbEncodedCTL =
(BYTE*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, *pcbEncodedCTL)))
{
hr = E_OUTOFMEMORY;
goto error;
}
if (!CryptMsgEncodeAndSignCTL(PKCS_7_ASN_ENCODING,
&CTLInfo, pSigner, 0,
*ppbEncodedCTL,
pcbEncodedCTL))
{
hr = myHLastError();
goto error;
}
error:
if(CTLInfo.rgCTLEntry)
{
LocalFree(CTLInfo.rgCTLEntry);
}
if(CTLInfo.ListIdentifier.pbData)
{
LocalFree(CTLInfo.ListIdentifier.pbData);
}
#if 0
if (pCertExtensions)
{
LocalFree(pCertExtensions);
}
#endif
if(hCertType)
{
CACloseCertType(hCertType);
}
return hr;
}
HRESULT
CACreateAutoEnrollmentObjectEx(
IN LPCWSTR pwszCertType,
IN LPCWSTR wszObjectID,
IN WCHAR ** awszCAs,
IN PCMSG_SIGNED_ENCODE_INFO pSignerInfo,
IN LPCSTR StoreProvider,
IN DWORD dwFlags,
IN const void * pvPara)
{
HRESULT hr = S_OK;
BYTE *pbEncodedCTL = NULL;
DWORD cbEncodedCTL;
HCERTSTORE hStore = 0;
BOOL fMachine = ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) == CERT_SYSTEM_STORE_LOCAL_MACHINE);
hr = BuildAutoEnrollmentCTL(pwszCertType,
wszObjectID,
fMachine,
awszCAs,
pSignerInfo,
&pbEncodedCTL,
&cbEncodedCTL
);
if(hr != S_OK)
{
goto error;
}
// open the Trust store and fine the CTL based on the auto enrollment usage
hStore = CertOpenStore(StoreProvider, 0, NULL, dwFlags, pvPara);
if(hStore == NULL)
{
hr = myHLastError();
goto error;
}
if (!CertAddEncodedCTLToStore(hStore,
X509_ASN_ENCODING,
pbEncodedCTL,
cbEncodedCTL,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL))
{
hr = myHLastError();
goto error;
}
error:
if (pbEncodedCTL)
{
LocalFree(pbEncodedCTL);
}
if (hStore)
{
CertCloseStore(hStore, 0);
}
return hr;
}
HRESULT
CACreateLocalAutoEnrollmentObject(
IN LPCWSTR pwszCertType,
IN WCHAR ** awszCAs,
IN PCMSG_SIGNED_ENCODE_INFO pSignerInfo,
IN DWORD dwFlags)
{
HRESULT hr = S_OK;
BYTE *pbEncodedCTL = NULL;
DWORD cbEncodedCTL;
HCERTSTORE hStore = 0;
BOOL fMachine = ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) == CERT_SYSTEM_STORE_LOCAL_MACHINE);
hr = BuildAutoEnrollmentCTL(pwszCertType,
NULL,
fMachine,
awszCAs,
pSignerInfo,
&pbEncodedCTL,
&cbEncodedCTL
);
if(hr != S_OK)
{
goto error;
}
// open the Trust store and fine the CTL based on the auto enrollment usage
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, NULL, dwFlags, L"ACRS");
if(hStore == NULL)
{
hr = myHLastError();
goto error;
}
if (!CertAddEncodedCTLToStore(hStore,
X509_ASN_ENCODING,
pbEncodedCTL,
cbEncodedCTL,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL))
{
hr = myHLastError();
goto error;
}
error:
if (pbEncodedCTL)
{
LocalFree(pbEncodedCTL);
}
if (hStore)
{
CertCloseStore(hStore, 0);
}
return hr;
}
//--------------------------------------------------------------------------------
//
// CADeleteLocalAutoEnrollmentObject
//
//---------------------------------------------------------------------------------
HRESULT
CADeleteLocalAutoEnrollmentObject(
IN LPCWSTR pwszCertType,
IN OPTIONAL WCHAR ** awszCAs,
IN OPTIONAL PCMSG_SIGNED_ENCODE_INFO pSignerInfo,
IN DWORD dwFlags)
{
HRESULT hr=E_FAIL;
CTL_FIND_USAGE_PARA CTLFindParam;
LPSTR pszUsageIdentifier=NULL;
HCERTSTORE hCertStore=NULL;
PCCTL_CONTEXT pCTLContext=NULL; //no need to free the CTL since it is freed by the DeleteCTL call
memset(&CTLFindParam, 0, sizeof(CTL_FIND_USAGE_PARA));
if((NULL==pwszCertType)||(NULL!=awszCAs)||(NULL!=pSignerInfo))
{
hr=E_INVALIDARG;
goto error;
}
//open the store based on dwFlags
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, NULL, dwFlags, L"ACRS");
if(NULL == hCertStore)
{
hr = myHLastError();
goto error;
}
//set up the find parameter
CTLFindParam.cbSize=sizeof(CTLFindParam);
CTLFindParam.SubjectUsage.cUsageIdentifier = 1;
pszUsageIdentifier = szOID_AUTO_ENROLL_CTL_USAGE;
CTLFindParam.SubjectUsage.rgpszUsageIdentifier = &pszUsageIdentifier;
CTLFindParam.ListIdentifier.cbData=(wcslen(pwszCertType) + 1) * sizeof(WCHAR);
CTLFindParam.ListIdentifier.pbData=(BYTE *)(pwszCertType);
//only find CTLs with no signers
CTLFindParam.pSigner=CTL_FIND_NO_SIGNER_PTR;
//find the CTL based on the pwszCertType
if(NULL == (pCTLContext=CertFindCTLInStore(
hCertStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CTL_FIND_USAGE,
&CTLFindParam,
NULL)))
{
hr=CRYPT_E_NOT_FOUND;
goto error;
}
//delete the CTL. The CTL is automatically freed
if(!CertDeleteCTLFromStore(pCTLContext))
{
hr = myHLastError();
goto error;
}
hr=S_OK;
error:
if(hCertStore)
CertCloseStore(hCertStore, 0);
return hr;
}