windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pki/setx509/setx509.cpp
2020-09-26 16:20:57 +08:00

1341 lines
41 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: setx509.cpp
//
// Contents: SET Certificate Extension Encode/Decode Functions
//
// ASN.1 implementation uses the OSS compiler.
//
// Functions: DllRegisterServer
// DllUnregisterServer
// DllMain
// SetAsn1AccountAliasEncode
// SetAsn1AccountAliasDecode
// SetAsn1HashedRootKeyEncode
// SetAsn1HashedRootKeyDecode
// SetAsn1CertificateTypeEncode
// SetAsn1CertificateTypeDecode
// SetAsn1MerchantDataEncode
// SetAsn1MerchantDataDecode
//
// CertDllVerifyRevocation
//
// History: 21-Nov-96 philh created
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
// All the *pvInfo extra stuff needs to be aligned
#define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
static HCRYPTASN1MODULE hAsn1Module;
// The following is for test purposes
#define TLS_TEST_COUNT 20
static HCRYPTTLS hTlsTest[TLS_TEST_COUNT];
static HMODULE hMyModule;
// Set to 1 via InterlockedExchange when installed. Only install the
// first time when changed from 0 to 1.
static LONG lInstallDecodeFunctions = 0;
static LONG lInstallRevFunctions = 0;
//+-------------------------------------------------------------------------
// Function: GetEncoder/GetDecoder
//
// Synopsis: Initialize thread local storage for the asn libs
//
// Returns: pointer to an initialized Asn1 encoder/decoder data
// structures
//--------------------------------------------------------------------------
static ASN1encoding_t GetEncoder(void)
{
// The following is for test purposes only
for (DWORD i = 0; i < TLS_TEST_COUNT; i++) {
DWORD_PTR dw = (DWORD_PTR) I_CryptGetTls(hTlsTest[i]);
if (dw == 0)
dw = i;
else
dw++;
I_CryptSetTls(hTlsTest[i], (void *) dw);
}
return I_CryptGetAsn1Encoder(hAsn1Module);
}
static ASN1decoding_t GetDecoder(void)
{
// The following is for test purposes only
for (DWORD i = 0; i < TLS_TEST_COUNT; i++) {
DWORD_PTR dw = (DWORD_PTR) I_CryptGetTls(hTlsTest[i]);
if (dw == 0)
dw = i;
else
dw++;
I_CryptSetTls(hTlsTest[i], (void *) dw);
}
return I_CryptGetAsn1Decoder(hAsn1Module);
}
//+-------------------------------------------------------------------------
// SetX509 allocation and free functions
//--------------------------------------------------------------------------
static void *SetX509Alloc(
IN size_t cbBytes
)
{
void *pv;
pv = malloc(cbBytes);
if (pv == NULL)
SetLastError((DWORD) E_OUTOFMEMORY);
return pv;
}
static void SetX509Free(
IN void *pv
)
{
free(pv);
}
static HRESULT HError()
{
DWORD dw = GetLastError();
HRESULT hr;
if ( dw <= 0xFFFF )
hr = HRESULT_FROM_WIN32 ( dw );
else
hr = dw;
if ( ! FAILED ( hr ) )
{
// somebody failed a call without properly setting an error condition
hr = E_UNEXPECTED;
}
return hr;
}
//+-------------------------------------------------------------------------
// OSS X509 v3 SET Private Extension ASN.1 Encode / Decode functions
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1AccountAliasEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN BOOL *pbInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
);
BOOL
WINAPI
SetAsn1AccountAliasDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT BOOL *pbInfo,
IN OUT DWORD *pcbInfo
);
BOOL
WINAPI
SetAsn1HashedRootKeyEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN BYTE rgbInfo[SET_HASHED_ROOT_LEN],
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
);
BOOL
WINAPI
SetAsn1HashedRootKeyDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT BYTE rgbInfo[SET_HASHED_ROOT_LEN],
IN OUT DWORD *pcbInfo
);
BOOL
WINAPI
SetAsn1CertificateTypeEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCRYPT_BIT_BLOB pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
);
BOOL
WINAPI
SetAsn1CertificateTypeDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCRYPT_BIT_BLOB pInfo,
IN OUT DWORD *pcbInfo
);
BOOL
WINAPI
SetAsn1MerchantDataEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PSET_MERCHANT_DATA_INFO pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
);
BOOL
WINAPI
SetAsn1MerchantDataDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PSET_MERCHANT_DATA_INFO pInfo,
IN OUT DWORD *pcbInfo
);
typedef struct _OID_REG_ENTRY {
LPCSTR pszOID;
LPCSTR pszOverrideFuncName;
} OID_REG_ENTRY, *POID_REG_ENTRY;
static const OID_REG_ENTRY RegEncodeBeforeTable[] = {
szOID_SET_ACCOUNT_ALIAS, "SetAsn1AccountAliasEncode",
szOID_SET_HASHED_ROOT_KEY, "SetAsn1HashedRootKeyEncode",
X509_SET_ACCOUNT_ALIAS, "SetAsn1AccountAliasEncode",
X509_SET_HASHED_ROOT_KEY, "SetAsn1HashedRootKeyEncode",
};
#define REG_ENCODE_BEFORE_COUNT (sizeof(RegEncodeBeforeTable) / sizeof(RegEncodeBeforeTable[0]))
static const OID_REG_ENTRY RegEncodeAfterTable[] = {
szOID_SET_CERTIFICATE_TYPE, "SetAsn1CertificateTypeEncode",
szOID_SET_MERCHANT_DATA, "SetAsn1MerchantDataEncode",
X509_SET_CERTIFICATE_TYPE, "SetAsn1CertificateTypeEncode",
X509_SET_MERCHANT_DATA, "SetAsn1MerchantDataEncode"
};
#define REG_ENCODE_AFTER_COUNT (sizeof(RegEncodeAfterTable) / sizeof(RegEncodeAfterTable[0]))
static const OID_REG_ENTRY RegDecodeTable[] = {
szOID_SET_ACCOUNT_ALIAS, "SetAsn1AccountAliasDecode",
szOID_SET_HASHED_ROOT_KEY, "SetAsn1HashedRootKeyDecode",
szOID_SET_CERTIFICATE_TYPE, "SetAsn1CertificateTypeDecode",
szOID_SET_MERCHANT_DATA, "SetAsn1MerchantDataDecode",
X509_SET_ACCOUNT_ALIAS, "SetAsn1AccountAliasDecode",
X509_SET_HASHED_ROOT_KEY, "SetAsn1HashedRootKeyDecode",
X509_SET_CERTIFICATE_TYPE, "SetAsn1CertificateTypeDecode",
X509_SET_MERCHANT_DATA, "SetAsn1MerchantDataDecode"
};
#define REG_DECODE_COUNT (sizeof(RegDecodeTable) / sizeof(RegDecodeTable[0]))
#define OID_INFO_LEN sizeof(CRYPT_OID_INFO)
// Ordered lists of acceptable RDN attribute value types. 0 terminates.
static const DWORD rgdwPrintableValueType[] = { CERT_RDN_PRINTABLE_STRING, 0 };
static const DWORD rgdwIA5ValueType[] = { CERT_RDN_IA5_STRING, 0 };
static const DWORD rgdwNumericValueType[] = { CERT_RDN_NUMERIC_STRING, 0 };
#define RDN_ATTR_ENTRY(pszOID, pwszName, rgdwValueType) \
OID_INFO_LEN, pszOID, pwszName, CRYPT_RDN_ATTR_OID_GROUP_ID, 64, \
sizeof(rgdwValueType), (BYTE *) rgdwValueType
#define DEFAULT_RDN_ATTR_ENTRY(pszOID, pwszName) \
OID_INFO_LEN, pszOID, pwszName, CRYPT_RDN_ATTR_OID_GROUP_ID, 128, 0, NULL
#define EXT_ATTR_ENTRY(pszOID, pwszName) \
OID_INFO_LEN, pszOID, pwszName, CRYPT_EXT_OR_ATTR_OID_GROUP_ID, 0, 0, NULL
#define PUBKEY_ALG_ENTRY(pszOID, pwszName, Algid) \
OID_INFO_LEN, pszOID, pwszName, CRYPT_PUBKEY_ALG_OID_GROUP_ID, \
Algid, 0, NULL
#define PUBKEY_EXTRA_ALG_ENTRY(pszOID, pwszName, Algid, dwFlags) \
OID_INFO_LEN, pszOID, pwszName, CRYPT_PUBKEY_ALG_OID_GROUP_ID, \
Algid, sizeof(dwFlags), (BYTE *) &dwFlags
static const DWORD dwDSSTestFlags = CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG;
static const DWORD rgdwTestRsaSign[] = {
CALG_RSA_SIGN,
0,
PROV_RSA_FULL
};
#define TEST_SIGN_EXTRA_ALG_ENTRY(pszOID, pwszName, aiHash, rgdwExtra) \
OID_INFO_LEN, pszOID, pwszName, CRYPT_SIGN_ALG_OID_GROUP_ID, aiHash, \
sizeof(rgdwExtra), (BYTE *) rgdwExtra
#define TEST_RSA_SIGN_ALG_ENTRY(pszOID, pwszName, aiHash) \
TEST_SIGN_EXTRA_ALG_ENTRY(pszOID, pwszName, aiHash, rgdwTestRsaSign)
static CCRYPT_OID_INFO OIDInfoAfterTable[] = {
DEFAULT_RDN_ATTR_ENTRY("1.2.1", L"TestRDNAttr #1"),
RDN_ATTR_ENTRY("1.2.2", L"TestRDNAttr #2", rgdwPrintableValueType),
EXT_ATTR_ENTRY(szOID_SET_CERTIFICATE_TYPE, L"SETCertificateType"),
EXT_ATTR_ENTRY(szOID_SET_HASHED_ROOT_KEY, L"SETHashedRootKey"),
};
#define OID_INFO_AFTER_CNT (sizeof(OIDInfoAfterTable) / \
sizeof(OIDInfoAfterTable[0]))
static CCRYPT_OID_INFO OIDInfoBeforeTable[] = {
// PUBKEY_EXTRA_ALG_ENTRY(szOID_OIWSEC_dsa, L"SETDSSTest", CALG_DSS_SIGN,
// dwDSSTestFlags),
// TEST_RSA_SIGN_ALG_ENTRY(szOID_RSA_SHA1RSA, L"sha1RSA", CALG_SHA1),
// TEST_RSA_SIGN_ALG_ENTRY(szOID_RSA_MD5RSA, L"md5RSA", CALG_MD5),
EXT_ATTR_ENTRY(szOID_SET_ACCOUNT_ALIAS, L"SETAccountAlias"),
EXT_ATTR_ENTRY(szOID_SET_MERCHANT_DATA, L"SETMerchantData"),
};
#define OID_INFO_BEFORE_CNT (sizeof(OIDInfoBeforeTable) / \
sizeof(OIDInfoBeforeTable[0]))
//+-------------------------------------------------------------------------
// Localized Name Table
//--------------------------------------------------------------------------
typedef struct _LOCALIZED_NAME_INFO {
LPCWSTR pwszCryptName;
LPCWSTR pwszLocalizedName;
} LOCALIZED_NAME_INFO, *PLOCALIZED_NAME_INFO;
static LOCALIZED_NAME_INFO LocalizedNameTable[] = {
L"Test", L"*** Test ***",
L"TestTrust", L"### TestTrust ###",
};
#define LOCALIZED_NAME_CNT (sizeof(LocalizedNameTable) / \
sizeof(LocalizedNameTable[0]))
BOOL
WINAPI
CertDllVerifyRevocation(
IN DWORD dwEncodingType,
IN DWORD dwRevType,
IN DWORD cContext,
IN PVOID rgpvContext[],
IN DWORD dwRevFlags,
IN PVOID pvReserved,
IN OUT PCERT_REVOCATION_STATUS pRevStatus
);
STDAPI DllRegisterServer(void)
{
int i;
for (i = 0; i < REG_ENCODE_BEFORE_COUNT; i++) {
DWORD dwFlags = CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG;
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
RegEncodeBeforeTable[i].pszOID,
L"setx509.dll",
RegEncodeBeforeTable[i].pszOverrideFuncName
))
return HError();
if (!CryptSetOIDFunctionValue(
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
RegEncodeBeforeTable[i].pszOID,
CRYPT_OID_REG_FLAGS_VALUE_NAME,
REG_DWORD,
(BYTE *) &dwFlags,
sizeof(dwFlags)
))
return HError();
}
for (i = 0; i < REG_ENCODE_AFTER_COUNT; i++)
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
RegEncodeAfterTable[i].pszOID,
L"setx509.dll",
RegEncodeAfterTable[i].pszOverrideFuncName
))
return HError();
for (i = 0; i < REG_DECODE_COUNT; i++)
if (!CryptRegisterOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_DECODE_OBJECT_FUNC,
RegDecodeTable[i].pszOID,
L"setx509.dll",
RegDecodeTable[i].pszOverrideFuncName
))
return HError();
if (!CryptRegisterDefaultOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_VERIFY_REVOCATION_FUNC,
CRYPT_REGISTER_LAST_INDEX,
L"setx509.dll"
)) {
if (ERROR_FILE_EXISTS != GetLastError())
return HError();
}
for (i = 0; i < OID_INFO_BEFORE_CNT; i++)
if (!CryptRegisterOIDInfo(
&OIDInfoBeforeTable[i],
CRYPT_INSTALL_OID_INFO_BEFORE_FLAG
))
return HError();
for (i = 0; i < OID_INFO_AFTER_CNT; i++)
if (!CryptRegisterOIDInfo(
&OIDInfoAfterTable[i],
0 // dwFlags
))
return HError();
for (i = 0; i < LOCALIZED_NAME_CNT; i++)
if (!CryptSetOIDFunctionValue(
CRYPT_LOCALIZED_NAME_ENCODING_TYPE,
CRYPT_OID_FIND_LOCALIZED_NAME_FUNC,
CRYPT_LOCALIZED_NAME_OID,
LocalizedNameTable[i].pwszCryptName,
REG_SZ,
(const BYTE *) LocalizedNameTable[i].pwszLocalizedName,
(wcslen(LocalizedNameTable[i].pwszLocalizedName) + 1) *
sizeof(WCHAR)
))
return HError();
return S_OK;
}
STDAPI DllUnregisterServer(void)
{
HRESULT hr = S_OK;
int i;
for (i = 0; i < REG_ENCODE_BEFORE_COUNT; i++) {
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
RegEncodeBeforeTable[i].pszOID
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
for (i = 0; i < REG_ENCODE_AFTER_COUNT; i++) {
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
RegEncodeAfterTable[i].pszOID
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
for (i = 0; i < REG_DECODE_COUNT; i++) {
if (!CryptUnregisterOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_DECODE_OBJECT_FUNC,
RegDecodeTable[i].pszOID
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
if (!CryptUnregisterDefaultOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_VERIFY_REVOCATION_FUNC,
L"setx509.dll"
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
for (i = 0; i < OID_INFO_BEFORE_CNT; i++) {
if (!CryptUnregisterOIDInfo(
&OIDInfoBeforeTable[i]
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
for (i = 0; i < OID_INFO_AFTER_CNT; i++) {
if (!CryptUnregisterOIDInfo(
&OIDInfoAfterTable[i]
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
hr = HError();
}
}
for (i = 0; i < LOCALIZED_NAME_CNT; i++)
if (!CryptSetOIDFunctionValue(
CRYPT_LOCALIZED_NAME_ENCODING_TYPE,
CRYPT_OID_FIND_LOCALIZED_NAME_FUNC,
CRYPT_LOCALIZED_NAME_OID,
LocalizedNameTable[i].pwszCryptName,
REG_SZ,
NULL,
0
))
return HError();
return hr;
}
static const CRYPT_OID_FUNC_ENTRY SetEncodeFuncTable[] = {
szOID_SET_ACCOUNT_ALIAS, SetAsn1AccountAliasEncode,
szOID_SET_HASHED_ROOT_KEY, SetAsn1HashedRootKeyEncode,
szOID_SET_CERTIFICATE_TYPE, SetAsn1CertificateTypeEncode,
szOID_SET_MERCHANT_DATA, SetAsn1MerchantDataEncode,
X509_SET_ACCOUNT_ALIAS, SetAsn1AccountAliasEncode,
X509_SET_HASHED_ROOT_KEY, SetAsn1HashedRootKeyEncode,
X509_SET_CERTIFICATE_TYPE, SetAsn1CertificateTypeEncode,
X509_SET_MERCHANT_DATA, SetAsn1MerchantDataEncode,
};
#define SET_ENCODE_FUNC_COUNT (sizeof(SetEncodeFuncTable) / \
sizeof(SetEncodeFuncTable[0]))
static const CRYPT_OID_FUNC_ENTRY SetDecodeFuncTable[] = {
szOID_SET_ACCOUNT_ALIAS, SetAsn1AccountAliasDecode,
szOID_SET_HASHED_ROOT_KEY, SetAsn1HashedRootKeyDecode,
szOID_SET_CERTIFICATE_TYPE, SetAsn1CertificateTypeDecode,
szOID_SET_MERCHANT_DATA, SetAsn1MerchantDataDecode,
X509_SET_ACCOUNT_ALIAS, SetAsn1AccountAliasDecode,
X509_SET_HASHED_ROOT_KEY, SetAsn1HashedRootKeyDecode,
X509_SET_CERTIFICATE_TYPE, SetAsn1CertificateTypeDecode,
X509_SET_MERCHANT_DATA, SetAsn1MerchantDataDecode
};
#define SET_DECODE_FUNC_COUNT (sizeof(SetDecodeFuncTable) / \
sizeof(SetDecodeFuncTable[0]))
static const CRYPT_OID_FUNC_ENTRY SetRevFuncTable[] = {
CRYPT_DEFAULT_OID, CertDllVerifyRevocation
};
#define SET_REV_FUNC_COUNT (sizeof(SetRevFuncTable) / \
sizeof(SetRevFuncTable[0]))
//+-------------------------------------------------------------------------
// Dll initialization
//--------------------------------------------------------------------------
BOOL
WINAPI
DllMain(
HMODULE hModule,
ULONG ulReason,
LPVOID lpReserved)
{
BOOL fRet;
DWORD i;
DWORD_PTR dwTlsValue;
switch (ulReason) {
case DLL_PROCESS_ATTACH:
// The following is for test purposes only
for (i = 0; i < TLS_TEST_COUNT; i++) {
if (NULL == (hTlsTest[i] = I_CryptAllocTls()))
goto CryptAllocTlsError;
}
#ifdef OSS_CRYPT_ASN1
if (0 == (hAsn1Module = I_CryptInstallAsn1Module(ossx509, 0, NULL)))
#else
X509_Module_Startup();
if (0 == (hAsn1Module = I_CryptInstallAsn1Module(
X509_Module, 0, NULL)))
#endif // OSS_CRYPT_ASN1
goto CryptInstallAsn1ModuleError;
#if 0
// For testing purposes not installed. Always want to call the
// encode functions via dll load.
if (!CryptInstallOIDFunctionAddress(
hModule,
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
SET_ENCODE_FUNC_COUNT,
SetEncodeFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
#endif
#if 0
// For testing purposes deferred until first Decode
if (!CryptInstallOIDFunctionAddress(
hModule,
X509_ASN_ENCODING,
CRYPT_OID_DECODE_OBJECT_FUNC,
SET_DECODE_FUNC_COUNT,
SetDecodeFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
#endif
hMyModule = hModule;
break;
case DLL_PROCESS_DETACH:
I_CryptUninstallAsn1Module(hAsn1Module);
#ifndef OSS_CRYPT_ASN1
X509_Module_Cleanup();
#endif // OSS_CRYPT_ASN1
// The following is for test purposes only
for (i = 0; i < TLS_TEST_COUNT; i++) {
I_CryptFreeTls(hTlsTest[i], NULL);
}
break;
case DLL_THREAD_DETACH:
// The following is for test purposes only
for (i = 0; i < TLS_TEST_COUNT; i++)
dwTlsValue = (DWORD_PTR) I_CryptDetachTls(hTlsTest[i]);
break;
default:
break;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CryptAllocTlsError)
TRACE_ERROR(CryptInstallAsn1ModuleError)
#if 0
TRACE_ERROR(CryptInstallOIDFunctionAddressError)
#endif
}
// Defer installation until the first decode. Called by each of the decode
// functions.
//
// Do the InterlockedExchange to ensure a single installation
static void InstallDecodeFunctions()
{
#if 0
if (0 == InterlockedExchange(&lInstallDecodeFunctions, 1)) {
if (!CryptInstallOIDFunctionAddress(
hMyModule,
X509_ASN_ENCODING,
CRYPT_OID_DECODE_OBJECT_FUNC,
SET_DECODE_FUNC_COUNT,
SetDecodeFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
}
CommonReturn:
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(CryptInstallOIDFunctionAddressError)
#endif
}
// Defer installation until the first revocation.
//
// Do the InterlockedExchange to ensure a single installation
static void InstallRevFunctions()
{
if (0 == InterlockedExchange(&lInstallRevFunctions, 1)) {
if (!CryptInstallOIDFunctionAddress(
hMyModule,
X509_ASN_ENCODING,
CRYPT_OID_VERIFY_REVOCATION_FUNC,
SET_REV_FUNC_COUNT,
SetRevFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
}
CommonReturn:
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(CryptInstallOIDFunctionAddressError)
}
BOOL
WINAPI
CertDllVerifyRevocation(
IN DWORD dwEncodingType,
IN DWORD dwRevType,
IN DWORD cContext,
IN PVOID rgpvContext[],
IN DWORD dwRevFlags,
IN PVOID pvReserved,
IN OUT PCERT_REVOCATION_STATUS pRevStatus
)
{
BOOL fResult = FALSE;
DWORD dwIndex = 0;
DWORD dwError = 0;
HCERTSTORE hStore = NULL;
HCERTSTORE hLinkStore = NULL;
InstallRevFunctions();
if (GET_CERT_ENCODING_TYPE(dwEncodingType) != CRYPT_ASN_ENCODING)
goto NoRevocationCheckForEncodingTypeError;
if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE)
goto NoRevocationCheckForRevTypeError;
hStore = CertOpenSystemStore(NULL, "Test");
if (NULL == hStore)
goto OpenTestStoreError;
hLinkStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
0, // dwEncodingType
0, // hCryptProv
0, // dwFlags
NULL // pvPara
);
if (NULL == hLinkStore)
goto OpenLinkStoreError;
for (dwIndex = 0; dwIndex < cContext; dwIndex++) {
PCCERT_CONTEXT pCert = (PCCERT_CONTEXT) rgpvContext[dwIndex];
PCERT_EXTENSION pExt;
PCCERT_CONTEXT pIssuer;
DWORD dwFlags;
// Check that the certificate has a SET extension
if (NULL == (pExt = CertFindExtension(szOID_SET_CERTIFICATE_TYPE,
pCert->pCertInfo->cExtension,
pCert->pCertInfo->rgExtension)))
goto NoSETX509ExtensionError;
// Attempt to get the certificate's issuer from the test store.
// If found check signature and revocation.
// For testing purposes: first found issuer.
dwFlags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
if (NULL == (pIssuer = CertGetIssuerCertificateFromStore(
hStore,
pCert,
NULL, // pPrevIssuerContext,
&dwFlags)))
goto NoIssuerError;
else {
BOOL fLinkResult;
DWORD dwLinkFlags =
CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
PCCERT_CONTEXT pLinkIssuer = NULL;
// Check that we get the same results if we put a link to the
// issuer in a store and try to verify using the link.
fLinkResult = CertAddCertificateLinkToStore(
hLinkStore,
pIssuer,
CERT_STORE_ADD_ALWAYS,
&pLinkIssuer
);
CertFreeCertificateContext(pIssuer);
if (!fLinkResult)
goto AddCertificateLinkError;
if (!CertVerifySubjectCertificateContext(
pCert,
pLinkIssuer,
&dwLinkFlags
))
goto VerifySubjectCertificateContextError;
if (dwLinkFlags != dwFlags)
goto BadLinkVerifyResults;
if (dwFlags & CERT_STORE_SIGNATURE_FLAG)
goto BadCertificateSignatureError;
if (dwFlags & CERT_STORE_NO_CRL_FLAG)
goto NoCRLError;
if (dwFlags & CERT_STORE_REVOCATION_FLAG) {
pRevStatus->dwReason = CRL_REASON_KEY_COMPROMISE;
goto CertificateRevocationError;
}
// else
// A checked certificate that hasn't been revoked.
assert(dwFlags == 0);
}
}
fResult = TRUE;
dwIndex = 0;
CommonReturn:
if (hStore)
CertCloseStore(hStore, 0);
if (hLinkStore)
CertCloseStore(hLinkStore, CERT_CLOSE_STORE_FORCE_FLAG);
pRevStatus->dwIndex = dwIndex;
pRevStatus->dwError = dwError;
return fResult;
ErrorReturn:
dwError = GetLastError();
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenTestStoreError)
TRACE_ERROR(OpenLinkStoreError)
SET_ERROR(NoRevocationCheckForEncodingTypeError, CRYPT_E_NO_REVOCATION_CHECK)
SET_ERROR(NoRevocationCheckForRevTypeError, CRYPT_E_NO_REVOCATION_CHECK)
SET_ERROR(NoSETX509ExtensionError, CRYPT_E_NO_REVOCATION_CHECK)
TRACE_ERROR(NoIssuerError)
SET_ERROR(BadCertificateSignatureError, CRYPT_E_NO_REVOCATION_CHECK)
SET_ERROR(NoCRLError, CRYPT_E_NO_REVOCATION_CHECK)
SET_ERROR(CertificateRevocationError, CRYPT_E_REVOKED)
TRACE_ERROR(AddCertificateLinkError)
TRACE_ERROR(VerifySubjectCertificateContextError)
SET_ERROR(BadLinkVerifyResults, E_UNEXPECTED)
}
//+-------------------------------------------------------------------------
// OSS X509 v3 ASN.1 Set / Get functions
//
// Called by the OSS X509 encode/decode functions.
//
// Assumption: all types are UNBOUNDED.
//
// The Get functions decrement *plRemainExtra and advance
// *ppbExtra. When *plRemainExtra becomes negative, the functions continue
// with the length calculation but stop doing any copies.
// The functions don't return an error for a negative *plRemainExtra.
//--------------------------------------------------------------------------
//+-------------------------------------------------------------------------
// Set/Get CRYPT_DATA_BLOB (Octet String)
//--------------------------------------------------------------------------
static inline void SetX509SetOctetString(
IN PCRYPT_DATA_BLOB pInfo,
OUT OCTETSTRING *pOss
)
{
pOss->value = pInfo->pbData;
pOss->length = pInfo->cbData;
}
static inline void SetX509GetOctetString(
IN OCTETSTRING *pOss,
IN DWORD dwFlags,
OUT PCRYPT_DATA_BLOB pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
PkiAsn1GetOctetString(pOss->length, pOss->value, dwFlags,
pInfo, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Set/Get CRYPT_BIT_BLOB
//--------------------------------------------------------------------------
static inline void SetX509SetBit(
IN PCRYPT_BIT_BLOB pInfo,
OUT BITSTRING *pOss
)
{
PkiAsn1SetBitString(pInfo, &pOss->length, &pOss->value);
}
static inline void SetX509GetBit(
IN BITSTRING *pOss,
IN DWORD dwFlags,
OUT PCRYPT_BIT_BLOB pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
PkiAsn1GetBitString(pOss->length, pOss->value, dwFlags,
pInfo, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Set/Get LPSTR (IA5 String)
//--------------------------------------------------------------------------
static inline void SetX509SetIA5(
IN LPSTR psz,
OUT IA5STRING *pOss
)
{
pOss->value = psz;
pOss->length = strlen(psz);
}
static inline void SetX509GetIA5(
IN IA5STRING *pOss,
IN DWORD dwFlags,
OUT LPSTR *ppsz,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
PkiAsn1GetIA5String(pOss->length, pOss->value, dwFlags,
ppsz, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Encode an OSS formatted info structure
//
// Called by the SetX509*Encode() functions.
//--------------------------------------------------------------------------
static BOOL SetAsn1Encode(
IN int pdunum,
IN void *pOssInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
return PkiAsn1EncodeInfo(
GetEncoder(),
pdunum,
pOssInfo,
pbEncoded,
pcbEncoded);
}
//+-------------------------------------------------------------------------
// Decode into an allocated, OSS formatted info structure
//
// Called by the SetX509*Decode() functions.
//--------------------------------------------------------------------------
static BOOL SetAsn1DecodeAndAlloc(
IN int pdunum,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
OUT void **ppOssInfo
)
{
// For testing purposes, defer installation of decode functions until
// first decode which is loaded via being registered.
InstallDecodeFunctions();
return PkiAsn1DecodeAndAllocInfo(
GetDecoder(),
pdunum,
pbEncoded,
cbEncoded,
ppOssInfo);
}
//+-------------------------------------------------------------------------
// Free an allocated, OSS formatted info structure
//
// Called by the SetX509*Decode() functions.
//--------------------------------------------------------------------------
static void SetAsn1Free(
IN int pdunum,
IN void *pOssInfo
)
{
if (pOssInfo) {
DWORD dwErr = GetLastError();
// TlsGetValue globbers LastError
PkiAsn1FreeInfo(GetDecoder(), pdunum, pOssInfo);
SetLastError(dwErr);
}
}
//+-------------------------------------------------------------------------
// SET Account Alias Private Extension Encode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1AccountAliasEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN BOOL *pbInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
ossBoolean OssSETAccountAlias = (ossBoolean) *pbInfo;
return SetAsn1Encode(
SETAccountAlias_PDU,
&OssSETAccountAlias,
pbEncoded,
pcbEncoded
);
}
//+-------------------------------------------------------------------------
// SET Account Alias Private Extension Decode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1AccountAliasDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT BOOL *pbInfo,
IN OUT DWORD *pcbInfo
)
{
BOOL fResult;
ossBoolean *pSETAccountAlias = NULL;
if ((fResult = SetAsn1DecodeAndAlloc(
SETAccountAlias_PDU,
pbEncoded,
cbEncoded,
(void **) &pSETAccountAlias))) {
if (*pcbInfo < sizeof(BOOL)) {
if (pbInfo) {
fResult = FALSE;
SetLastError((DWORD) ERROR_MORE_DATA);
}
} else
*pbInfo = (BOOL) *pSETAccountAlias;
*pcbInfo = sizeof(BOOL);
} else {
if (*pcbInfo >= sizeof(BOOL))
*pbInfo = FALSE;
*pcbInfo = 0;
}
SetAsn1Free(SETAccountAlias_PDU, pSETAccountAlias);
return fResult;
}
//+-------------------------------------------------------------------------
// SET Hashed Root Private Extension Encode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1HashedRootKeyEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN BYTE rgbInfo[SET_HASHED_ROOT_LEN],
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
OCTETSTRING OssSETHashedRootKey;
OssSETHashedRootKey.value = rgbInfo;
OssSETHashedRootKey.length = SET_HASHED_ROOT_LEN;
return SetAsn1Encode(
SETHashedRootKey_PDU,
&OssSETHashedRootKey,
pbEncoded,
pcbEncoded
);
}
//+-------------------------------------------------------------------------
// SET Hashed Root Private Extension Decode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1HashedRootKeyDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT BYTE rgbInfo[SET_HASHED_ROOT_LEN],
IN OUT DWORD *pcbInfo
)
{
BOOL fResult;
OCTETSTRING *pSETHashedRootKey = NULL;
if ((fResult = SetAsn1DecodeAndAlloc(
SETHashedRootKey_PDU,
pbEncoded,
cbEncoded,
(void **) &pSETHashedRootKey))) {
if (pSETHashedRootKey->length != SET_HASHED_ROOT_LEN) {
fResult = FALSE;
SetLastError((DWORD) CRYPT_E_BAD_ENCODE);
*pcbInfo = 0;
} else {
if (*pcbInfo < SET_HASHED_ROOT_LEN) {
if (rgbInfo) {
fResult = FALSE;
SetLastError((DWORD) ERROR_MORE_DATA);
}
} else
memcpy(rgbInfo, pSETHashedRootKey->value, SET_HASHED_ROOT_LEN);
*pcbInfo = SET_HASHED_ROOT_LEN;
}
} else
*pcbInfo = 0;
SetAsn1Free(SETHashedRootKey_PDU, pSETHashedRootKey);
return fResult;
}
//+-------------------------------------------------------------------------
// SET Certificate Type Private Extension Encode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1CertificateTypeEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCRYPT_BIT_BLOB pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
BITSTRING OssSETCertificateType;
SetX509SetBit(pInfo, &OssSETCertificateType);
return SetAsn1Encode(
SETCertificateType_PDU,
&OssSETCertificateType,
pbEncoded,
pcbEncoded
);
}
//+-------------------------------------------------------------------------
// SET Certificate Type Private Extension Decode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1CertificateTypeDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCRYPT_BIT_BLOB pInfo,
IN OUT DWORD *pcbInfo
)
{
BOOL fResult;
BITSTRING *pSETCertificateType = NULL;
BYTE *pbExtra;
LONG lRemainExtra;
if (pInfo == NULL)
*pcbInfo = 0;
if (!SetAsn1DecodeAndAlloc(
SETCertificateType_PDU,
pbEncoded,
cbEncoded,
(void **) &pSETCertificateType))
goto ErrorReturn;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lRemainExtra = (LONG) *pcbInfo - sizeof(CRYPT_BIT_BLOB);
if (lRemainExtra < 0) {
pbExtra = NULL;
} else
pbExtra = (BYTE *) pInfo + sizeof(CRYPT_BIT_BLOB);
SetX509GetBit(pSETCertificateType, dwFlags, pInfo, &pbExtra, &lRemainExtra);
if (lRemainExtra >= 0)
*pcbInfo = *pcbInfo - (DWORD) lRemainExtra;
else {
*pcbInfo = *pcbInfo + (DWORD) -lRemainExtra;
if (pInfo) goto LengthError;
}
fResult = TRUE;
goto CommonReturn;
LengthError:
SetLastError((DWORD) ERROR_MORE_DATA);
fResult = FALSE;
goto CommonReturn;
ErrorReturn:
*pcbInfo = 0;
fResult = FALSE;
CommonReturn:
SetAsn1Free(SETCertificateType_PDU, pSETCertificateType);
return fResult;
}
//+-------------------------------------------------------------------------
// SET Merchant Data Private Extension Encode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1MerchantDataEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PSET_MERCHANT_DATA_INFO pInfo,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
SETMerchantData OssSETMerchantData;
HCRYPTOIDFUNCSET hX509EncodeFuncSet;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
SetX509SetIA5(pInfo->pszMerID, &OssSETMerchantData.merID);
SetX509SetIA5(pInfo->pszMerAcquirerBIN,
(IA5STRING *) &OssSETMerchantData.merAcquirerBIN);
SetX509SetIA5(pInfo->pszMerTermID, &OssSETMerchantData.merTermID);
SetX509SetIA5(pInfo->pszMerName, &OssSETMerchantData.merName);
SetX509SetIA5(pInfo->pszMerCity, &OssSETMerchantData.merCity);
SetX509SetIA5(pInfo->pszMerStateProvince,
&OssSETMerchantData.merStateProvince);
SetX509SetIA5(pInfo->pszMerPostalCode, &OssSETMerchantData.merPostalCode);
SetX509SetIA5(pInfo->pszMerCountry, &OssSETMerchantData.merCountry);
SetX509SetIA5(pInfo->pszMerPhone, &OssSETMerchantData.merPhone);
OssSETMerchantData.merPhoneRelease = (pInfo->fMerPhoneRelease != 0);
OssSETMerchantData.merAuthFlag = (pInfo->fMerAuthFlag != 0);
// For testing purposes, verify that CryptGetOIDFunctionAddress fails
// to find a pre-installed function
if (NULL == (hX509EncodeFuncSet = CryptInitOIDFunctionSet(
CRYPT_OID_ENCODE_OBJECT_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (CryptGetOIDFunctionAddress(
hX509EncodeFuncSet,
X509_ASN_ENCODING,
szOID_SET_MERCHANT_DATA,
CRYPT_GET_INSTALLED_OID_FUNC_FLAG,
&pvFuncAddr,
&hFuncAddr
)) {
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
goto GotUnexpectedPreinstalledFunction;
}
// Verify we get our registered address
if (!CryptGetOIDFunctionAddress(
hX509EncodeFuncSet,
X509_ASN_ENCODING,
szOID_SET_MERCHANT_DATA,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr
))
goto DidNotGetRegisteredFunction;
else
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return SetAsn1Encode(
SETMerchantData_PDU,
&OssSETMerchantData,
pbEncoded,
pcbEncoded
);
ErrorReturn:
*pcbEncoded = 0;
return FALSE;
TRACE_ERROR(CryptInitOIDFunctionSetError)
SET_ERROR(GotUnexpectedPreinstalledFunction, E_UNEXPECTED)
SET_ERROR(DidNotGetRegisteredFunction, E_UNEXPECTED)
}
//+-------------------------------------------------------------------------
// SET Merchant Data Private Extension Decode (OSS X509)
//--------------------------------------------------------------------------
BOOL
WINAPI
SetAsn1MerchantDataDecode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PSET_MERCHANT_DATA_INFO pInfo,
IN OUT DWORD *pcbInfo
)
{
BOOL fResult;
SETMerchantData *pSETMerchantData = NULL;
BYTE *pbExtra;
LONG lRemainExtra;
if (pInfo == NULL)
*pcbInfo = 0;
if (!SetAsn1DecodeAndAlloc(
SETMerchantData_PDU,
pbEncoded,
cbEncoded,
(void **) &pSETMerchantData))
goto ErrorReturn;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lRemainExtra = (LONG) *pcbInfo - sizeof(SET_MERCHANT_DATA_INFO);
if (lRemainExtra < 0) {
pbExtra = NULL;
} else {
// Update fields not needing extra memory after the
// SET_MERCHANT_DATA_INFO
pInfo->fMerPhoneRelease = pSETMerchantData->merPhoneRelease;
pInfo->fMerAuthFlag = pSETMerchantData->merAuthFlag;
pbExtra = (BYTE *) pInfo + sizeof(SET_MERCHANT_DATA_INFO);
}
SetX509GetIA5(&pSETMerchantData->merID, dwFlags, &pInfo->pszMerID,
&pbExtra, &lRemainExtra);
SetX509GetIA5((IA5STRING *) &pSETMerchantData->merAcquirerBIN, dwFlags,
&pInfo->pszMerAcquirerBIN, &pbExtra, &lRemainExtra);
SetX509GetIA5(&pSETMerchantData->merTermID, dwFlags, &pInfo->pszMerTermID,
&pbExtra, &lRemainExtra);
SetX509GetIA5(&pSETMerchantData->merName, dwFlags, &pInfo->pszMerName,
&pbExtra, &lRemainExtra);
SetX509GetIA5(&pSETMerchantData->merCity, dwFlags, &pInfo->pszMerCity,
&pbExtra, &lRemainExtra);
SetX509GetIA5(&pSETMerchantData->merStateProvince, dwFlags,
&pInfo->pszMerStateProvince, &pbExtra, &lRemainExtra);
SetX509GetIA5(&pSETMerchantData->merPostalCode, dwFlags,
&pInfo->pszMerPostalCode, &pbExtra, &lRemainExtra);
SetX509GetIA5(&pSETMerchantData->merCountry, dwFlags, &pInfo->pszMerCountry,
&pbExtra, &lRemainExtra);
SetX509GetIA5(&pSETMerchantData->merPhone, dwFlags, &pInfo->pszMerPhone,
&pbExtra, &lRemainExtra);
if (lRemainExtra >= 0)
*pcbInfo = *pcbInfo - (DWORD) lRemainExtra;
else {
*pcbInfo = *pcbInfo + (DWORD) -lRemainExtra;
if (pInfo) goto LengthError;
}
fResult = TRUE;
goto CommonReturn;
LengthError:
SetLastError((DWORD) ERROR_MORE_DATA);
fResult = FALSE;
goto CommonReturn;
ErrorReturn:
*pcbInfo = 0;
fResult = FALSE;
CommonReturn:
SetAsn1Free(SETMerchantData_PDU, pSETMerchantData);
return fResult;
}