#include #include #include // iis metabase includes #define INITGUID // must be before iadmw.h #include // Interface header #include // MD_ & IIS_MD_ defines // other includes #include #include #include #include "utils.h" const CLSID CLSID_CEnroll = {0x43F8F289, 0x7A20, 0x11D0, {0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1}}; const IID IID_IEnroll = {0xacaa7838, 0x4585, 0x11d1, {0xab, 0x57, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}}; #define ARRAYSIZE(x)\ (sizeof(x)/sizeof(x[0])) int g_iDo_A = FALSE; int g_iDo_B = FALSE; int g_iDo_C = FALSE; // prototypes void ShowHelp(void); int DoStuff(void); int PrintCertDescList(void); DWORD CheckCertConstraints(PCCERT_CONTEXT pCC); // begin void ShowHelp(void) { _tprintf(_T("Certificate Looker test program\n\n")); _tprintf(_T("Usage:Certlook.exe [-b] [-c]\n\n")); _tprintf(_T("no parameters opens the 'MY' store\n")); _tprintf(_T(" -b opens the 'CA' store\n")); _tprintf(_T(" -c opens the 'ROOT' store\n")); return; } int __cdecl main(int argc,char *argv[]) { int iRet = 0; int argno; char * pArg = NULL; char * pCmdStart = NULL; TCHAR szFilePath1[_MAX_PATH]; TCHAR szFilePath2[_MAX_PATH]; TCHAR szParamString_Z[_MAX_PATH]; int iDoVersion = FALSE; int iGotParamZ = FALSE; *szFilePath1 = '\0'; *szFilePath2 = '\0'; *szParamString_Z = '\0'; _tcscpy(szFilePath1,_T("")); _tcscpy(szFilePath2,_T("")); _tcscpy(szParamString_Z,_T("")); for(argno=1; argnocUsageIdentifier == 0) { _tprintf(_T("cUsageIdentifier=0 <---\n")); bRes = TRUE; } else { for (DWORD i = 0; i < pKeyUsage->cUsageIdentifier; i++) { // Our friends from CAPI made this property ASCII even for // UNICODE program if (strstr(pKeyUsage->rgpszUsageIdentifier[i], szOID_PKIX_KP_SERVER_AUTH) != NULL) { _tprintf(_T("cUsageIdentifier=szOID_PKIX_KP_SERVER_AUTH\n")); bRes = TRUE; break; } if (strstr(pKeyUsage->rgpszUsageIdentifier[i], szOID_SERVER_GATED_CRYPTO) != NULL) { _tprintf(_T("cUsageIdentifier=szOID_SERVER_GATED_CRYPTO\n")); bRes = TRUE; break; } if (strstr(pKeyUsage->rgpszUsageIdentifier[i], szOID_SGC_NETSCAPE) != NULL) { _tprintf(_T("cUsageIdentifier=szOID_SGC_NETSCAPE\n")); bRes = TRUE; break; } } } if (pKeyUsage){free(pKeyUsage);} } return bRes; } BOOL GetNameString(PCCERT_CONTEXT pCertContext, DWORD type, DWORD flag, WCHAR * TheName, HRESULT * phRes) { BOOL bRes = FALSE; LPTSTR pName = NULL; DWORD cchName = CertGetNameString(pCertContext, type, flag, NULL, NULL, 0); if (cchName > 1) { pName = (LPTSTR) malloc(cchName); if (pName) { bRes = (1 != CertGetNameString(pCertContext, type, flag, NULL, pName, cchName)); ZeroMemory(TheName,sizeof(TheName)); memcpy(TheName,pName,cchName); } } else { *phRes = HRESULT_FROM_WIN32(GetLastError()); } return bRes; } BOOL GetFriendlyName(PCCERT_CONTEXT pCertContext, WCHAR * TheName, HRESULT * phRes) { BOOL bRes = FALSE; DWORD cb; TCHAR * pName = NULL; if (CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, NULL, &cb)) { pName = (LPTSTR) malloc(cb); if (pName) { if (CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, pName, &cb)) { pName[cb] = 0; bRes = TRUE; ZeroMemory(TheName,sizeof(TheName)); memcpy(TheName,pName,cb); } else { *phRes = HRESULT_FROM_WIN32(GetLastError()); } } else { *phRes = HRESULT_FROM_WIN32(GetLastError()); } } else { *phRes = HRESULT_FROM_WIN32(GetLastError()); } return bRes; } BOOL MyGetOIDInfo(LPWSTR string, DWORD stringSize, LPSTR pszObjId) { PCCRYPT_OID_INFO pOIDInfo; if (NULL != (pOIDInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pszObjId, 0))) { if ((DWORD)wcslen(pOIDInfo->pwszName)+1 <= stringSize) { wcscpy(string, pOIDInfo->pwszName); } else { return FALSE; } } else { return (MultiByteToWideChar(CP_ACP, 0, pszObjId, -1, string, stringSize) != 0); } return TRUE; } BOOL FormatEnhancedKeyUsageString(PCCERT_CONTEXT pCertContext, BOOL fPropertiesOnly, BOOL fMultiline, HRESULT * phRes) { CERT_ENHKEY_USAGE * pKeyUsage = NULL; WCHAR szText[255]; BOOL bRes = FALSE; if (GetKeyUsageProperty(pCertContext, &pKeyUsage, fPropertiesOnly, phRes)) { _tprintf(_T("EnhancedKeyUsage=")); // loop for each usage and add it to the display string for (DWORD i = 0; i < pKeyUsage->cUsageIdentifier; i++) { if (!(bRes = MyGetOIDInfo(szText, ARRAYSIZE(szText), pKeyUsage->rgpszUsageIdentifier[i]))) break; // add delimeter if not first iteration wprintf(szText); wprintf(L","); } wprintf(L"\n"); free (pKeyUsage); } return bRes; } BOOL PrintCertDescription(PCCERT_CONTEXT pCert) { BOOL bRes = FALSE; HRESULT hRes = 0; DWORD cb; UINT i, j; CERT_NAME_INFO * pNameInfo; WCHAR wCA_Name[255]; if (pCert == NULL) goto ErrExit; if (!CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME, pCert->pCertInfo->Subject.pbData, pCert->pCertInfo->Subject.cbData, 0, NULL, &cb) || NULL == (pNameInfo = (CERT_NAME_INFO *)_alloca(cb)) || !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME, pCert->pCertInfo->Subject.pbData, pCert->pCertInfo->Subject.cbData, 0, pNameInfo, &cb) ) { goto ErrExit; } for (i = 0; i < pNameInfo->cRDN; i++) { CERT_RDN_VALUE_BLOB Blobber; CERT_RDN rdn = pNameInfo->rgRDN[i]; for (j = 0; j < rdn.cRDNAttr; j++) { CERT_RDN_ATTR attr = rdn.rgRDNAttr[j]; Blobber = (CERT_RDN_VALUE_BLOB) attr.Value; WCHAR TempString[255]; ZeroMemory(TempString,sizeof(TempString)); memcpy(TempString, Blobber.pbData,Blobber.cbData); if (strcmp(attr.pszObjId, szOID_COMMON_NAME) == 0) { _tprintf(_T("szOID_COMMON_NAME="));wprintf(TempString);_tprintf(_T("\n")); } else if (strcmp(attr.pszObjId, szOID_COUNTRY_NAME) == 0) { _tprintf(_T("szOID_COUNTRY_NAME="));wprintf(TempString);_tprintf(_T("\n")); } else if (strcmp(attr.pszObjId, szOID_LOCALITY_NAME) == 0) { _tprintf(_T("szOID_LOCALITY_NAME="));wprintf(TempString);_tprintf(_T("\n")); } else if (strcmp(attr.pszObjId, szOID_STATE_OR_PROVINCE_NAME) == 0) { _tprintf(_T("szOID_STATE_OR_PROVINCE_NAME="));wprintf(TempString);_tprintf(_T("\n")); } else if (strcmp(attr.pszObjId, szOID_ORGANIZATION_NAME) == 0) { _tprintf(_T("szOID_ORGANIZATION_NAME="));wprintf(TempString);_tprintf(_T("\n")); } else if (strcmp(attr.pszObjId, szOID_ORGANIZATIONAL_UNIT_NAME) == 0) { _tprintf(_T("szOID_ORGANIZATIONAL_UNIT_NAME="));wprintf(TempString);_tprintf(_T("\n")); } } } // issued to if (!GetNameString(pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, wCA_Name, &hRes)) { goto ErrExit; } _tprintf(_T("Name="));wprintf(wCA_Name);_tprintf(_T("\n")); if (wCA_Name){free(wCA_Name);} /* // expiration date if (!FormatDateString(desc.m_ExpirationDate, pCert->pCertInfo->NotAfter, FALSE, FALSE)) { goto ErrExit; } */ // purpose if (!FormatEnhancedKeyUsageString(pCert, FALSE, FALSE, &hRes)) { // According to local experts, we should also use certs without this property set _tprintf(_T("There is no EnhancedKeyUsage on this one.\n")); //goto ErrExit; } // friendly name if (GetFriendlyName(pCert, wCA_Name, &hRes)) { _tprintf(_T("FriendlyName="));wprintf(wCA_Name);_tprintf(_T("\n")); if (wCA_Name){free(wCA_Name);} } bRes = TRUE; ErrExit: return bRes; } HCERTSTORE OpenMyStore(IEnroll * pEnroll, HRESULT * phResult) { HCERTSTORE hStore = NULL; BSTR bstrStoreName = NULL; BSTR bstrStoreType = NULL; long dwStoreFlags; if(SUCCEEDED(pEnroll->get_MyStoreNameWStr(&bstrStoreName))) { if(SUCCEEDED(pEnroll->get_MyStoreTypeWStr(&bstrStoreType))) { if(SUCCEEDED(pEnroll->get_MyStoreFlags(&dwStoreFlags))) { size_t store_type_len = wcslen(bstrStoreType); char * szStoreProvider = (char *)_alloca(store_type_len + 1); //ASSERT(szStoreProvider != NULL); size_t n = wcstombs(szStoreProvider, bstrStoreType, store_type_len); //ASSERT(n != -1); // this converter doesn't set zero byte!!! szStoreProvider[n] = '\0'; if (g_iDo_B) { _tprintf(_T("CertOpenStore:CA\n")); hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"CA"); } else if (g_iDo_C) { _tprintf(_T("CertOpenStore:ROOT\n")); hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"ROOT"); } else { wprintf(L"CertOpenStore:%s\n",bstrStoreName); hStore = CertOpenStore( szStoreProvider, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL, dwStoreFlags, bstrStoreName ); } } } } if (bstrStoreName) {CoTaskMemFree(bstrStoreName);} if (bstrStoreType) {CoTaskMemFree(bstrStoreType);} if (hStore == NULL){*phResult = HRESULT_FROM_WIN32(GetLastError());} return hStore; } IEnroll * GetEnrollObject(void) { HRESULT hRes = 0; IEnroll * pEnroll; BOOL bPleaseDoCoUninit = FALSE; hRes = CoInitialize(NULL); if(FAILED(hRes)) { return NULL; } bPleaseDoCoUninit = TRUE; hRes = CoCreateInstance(CLSID_CEnroll,NULL,CLSCTX_INPROC_SERVER,IID_IEnroll,(void **)&pEnroll); // now we need to change defaults for this // object to LOCAL_MACHINE if (pEnroll != NULL) { long dwFlags; pEnroll->get_MyStoreFlags(&dwFlags); dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK; dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; // following call will change Request store flags also pEnroll->put_MyStoreFlags(dwFlags); pEnroll->get_GenKeyFlags(&dwFlags); dwFlags |= CRYPT_EXPORTABLE; pEnroll->put_GenKeyFlags(dwFlags); pEnroll->put_KeySpec(AT_KEYEXCHANGE); pEnroll->put_ProviderType(PROV_RSA_SCHANNEL); pEnroll->put_DeleteRequestCert(TRUE); } else { _tprintf(_T("GetEnrollObject failed!\n")); } if (bPleaseDoCoUninit) { CoUninitialize(); } return pEnroll; } int PrintCertDescList(void) { BOOL bRes = FALSE; HRESULT hRes = 0; HCERTSTORE hStore = NULL; int iCount = 0; // we are looking to MY store only IEnroll * pXEnroll = GetEnrollObject(); if (!pXEnroll){goto PrintCertDescList_Exit;} hStore = OpenMyStore(GetEnrollObject(), &hRes); if (hStore != NULL) { PCCERT_CONTEXT pCert = NULL; // do not include certs with improper usage while (NULL != (pCert = CertEnumCertificatesInStore(hStore, pCert))) { _tprintf(_T("========================================\n")); if (TRUE == g_iDo_A) { AttachFriendlyName(pCert); } CheckCertConstraints(pCert); if (!ContainsKeyUsageProperty(pCert, &hRes)) { _tprintf(_T("There is a key missing KeyUsage Property. skipping.\n")); if (SUCCEEDED(hRes) || hRes == CRYPT_E_NOT_FOUND) continue; else goto PrintCertDescList_ExitErr; } if (!PrintCertDescription(pCert)) { if (hRes == CRYPT_E_NOT_FOUND) continue; goto PrintCertDescList_ExitErr; } } _tprintf(_T("========================================\n")); bRes = TRUE; PrintCertDescList_ExitErr: if (pCert != NULL){CertFreeCertificateContext(pCert);} CertCloseStore(hStore, 0); } else { _tprintf(_T("CertOpenStore failed\n")); } PrintCertDescList_Exit: return bRes; } DWORD CheckCertConstraints(PCCERT_CONTEXT pCC) { PCERT_EXTENSION pCExt; // returned ext LPCSTR pszObjId; // Object identifier DWORD i; CERT_BASIC_CONSTRAINTS_INFO *pConstraints=NULL; CERT_BASIC_CONSTRAINTS2_INFO *p2Constraints=NULL; DWORD ConstraintSize=0; DWORD RV=ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR; BOOL Using2=FALSE; void* ConstraintBlob=NULL; pszObjId = szOID_BASIC_CONSTRAINTS; pCExt = CertFindExtension( pszObjId, // in, Pointer to object identifier pCC->pCertInfo->cExtension, // in, # of extensions in the array pCC->pCertInfo->rgExtension); // in, The array of attributes if (pCExt == NULL) { pszObjId = szOID_BASIC_CONSTRAINTS2; pCExt = CertFindExtension( pszObjId, // in, Pointer to object identifier pCC->pCertInfo->cExtension, // in, # of extensions in the array pCC->pCertInfo->rgExtension); // in, The array of attributes Using2=TRUE; } if (pCExt == NULL) { _tprintf(_T("No BasicConstraints in cert\n")); goto ret; } // Decode extension if (!CryptDecodeObject( X509_ASN_ENCODING, pCExt->pszObjId, pCExt->Value.pbData, pCExt->Value.cbData, 0, NULL, &ConstraintSize)) { _tprintf(_T("Error %d when Decoding extension\n"),GetLastError()); goto ret; } ConstraintBlob=malloc(ConstraintSize); if (ConstraintBlob == NULL) { _tprintf(_T("out of memory!!!!...\n")); goto ret; } if (!CryptDecodeObject( X509_ASN_ENCODING, pCExt->pszObjId, pCExt->Value.pbData, pCExt->Value.cbData, 0, (void*)ConstraintBlob, &ConstraintSize)) { _tprintf(_T("Error %d when Decoding extension\n"),GetLastError()); goto ret; } if (Using2) { _tprintf(_T("Using2....\n")); p2Constraints=(CERT_BASIC_CONSTRAINTS2_INFO*)ConstraintBlob; if (!p2Constraints->fCA) { _tprintf(_T("Yes, there is constraints in here! it's not a CA!\n")); RV=ERROR_SUCCESS; } else { _tprintf(_T("Yes, there is constraints in here! it's a CA!\n")); } } else { _tprintf(_T("!Using2....\n")); pConstraints=(CERT_BASIC_CONSTRAINTS_INFO*)ConstraintBlob; if (((pConstraints->SubjectType.cbData * 8) - pConstraints->SubjectType.cUnusedBits) >= 2) { if ((*pConstraints->SubjectType.pbData) & CERT_END_ENTITY_SUBJECT_FLAG) { _tprintf(_T("Yes, there is constraints in here! CERT_END_ENTITY_SUBJECT_FLAG = true!\n")); RV=ERROR_SUCCESS; } else { _tprintf(_T("Yes, there is constraints in here but CERT_END_ENTITY_SUBJECT_FLAG = false!\n")); } } } ret: free(ConstraintBlob); return (RV); }