//+------------------------------------------------------------------------- // // 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 // 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; }