//////////////////////////////////////////////////////////////////////// // // Module : Dynamic/Nshcertmgmt.cpp // // Purpose : Smartdefaults implementation. // // Developers Name : Bharat/Radhika // // History : // // Date Author Comments // 10-13-2001 Bharat Initial Version. V1.0 // //////////////////////////////////////////////////////////////////////// #ifndef UNICODE #define UNICODE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "memory.h" #include "nshcertmgmt.h" /////////////////////////////////////////////////////////////////////////////////////////// // // Function : fIsCertStoreEmpty // // Date of Creation : 10-10-2001 // // Parameters : IN HCERTSTORE hCertStore // Return : BOOL // // Description : Check if certificate store is empty. // // Revision History : // // Date Author Comments // //////////////////////////////////////////////////////////////////////////////////////////// BOOL fIsCertStoreEmpty( IN HCERTSTORE hCertStore ) { PCCERT_CONTEXT pCertContext = NULL; BOOL fResult = FALSE; pCertContext = CertEnumCertificatesInStore(hCertStore, NULL); if(NULL == pCertContext) { fResult = TRUE; } else { CertFreeCertificateContext(pCertContext); } return fResult; } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : ListCertsInStore // // Date of Creation: 10-10-2001 // // Parameters : IN HCERTSTORE hCertStore, // OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo, // OUT PDWORD pdwNumCertificates // Return : DWORD // // Description : Lists Certificates InStore hCertStore and fills in ppAuth. // // Revision History: // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// DWORD ListCertsInStore( IN HCERTSTORE hCertStore, OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo, OUT PDWORD pdwNumCertificates ) { PCCERT_CONTEXT pPrevCertContext = NULL; PCCERT_CONTEXT pCertContext = NULL; CERT_NAME_BLOB NameBlob; PCERT_ENHKEY_USAGE pUsage = NULL; PCERT_NODE pCertificateList = NULL; PCERT_NODE pTemp = NULL; INT_IPSEC_MM_AUTH_INFO * pAuthInfo = NULL; INT_IPSEC_MM_AUTH_INFO * pCurrentAuth = NULL; LPWSTR pszSubjectName = NULL; DWORD i = 0; DWORD dwNumCertificates = 0; DWORD dwError = 0; DWORD Usage = 0; BOOL bValid = FALSE; while(TRUE) { pCertContext = CertEnumCertificatesInStore(hCertStore, pPrevCertContext); if (!pCertContext) { break; } pUsage = NULL; Usage = 0; bValid = FALSE; dwError = CertGetEnhancedKeyUsage(pCertContext, 0, NULL, &Usage); if(Usage) { pUsage = (PCERT_ENHKEY_USAGE)LocalAlloc(LPTR, Usage); if(!pUsage) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwError) } CertGetEnhancedKeyUsage(pCertContext, 0, pUsage, &Usage); for (Usage = 0; Usage < pUsage->cUsageIdentifier; Usage++) { if(!strcmp(pUsage->rgpszUsageIdentifier[Usage],szOID_PKIX_KP_SERVER_AUTH)) { bValid = TRUE; } else if(!strcmp(pUsage->rgpszUsageIdentifier[Usage],szOID_PKIX_KP_CLIENT_AUTH)) { bValid = TRUE; } else if(!strcmp(pUsage->rgpszUsageIdentifier[Usage],szOID_ANY_CERT_POLICY)) { bValid = TRUE; } } if(pUsage) { LocalFree(pUsage); pUsage = NULL; } } else { dwError = ERROR_SUCCESS; } if(bValid) { NameBlob = pCertContext->pCertInfo->Issuer; dwError = GetCertificateName(&NameBlob, &pszSubjectName); if (dwError) { if(NULL != pPrevCertContext) { CertFreeCertificateContext(pCertContext); } break; } if (!FindCertificateInList(pCertificateList, pszSubjectName)) { // // Append this CA to the list of CAs // pCertificateList = AppendCertificateNode(pCertificateList, pszSubjectName); dwNumCertificates++; } else { FreeADsStr(pszSubjectName); } } pPrevCertContext = pCertContext; } pAuthInfo = (INT_IPSEC_MM_AUTH_INFO *)AllocADsMem( sizeof(INT_IPSEC_MM_AUTH_INFO)*dwNumCertificates ); if (!pAuthInfo) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwError) } pTemp = pCertificateList; for (i = 0; i < dwNumCertificates; i++) { pCurrentAuth = pAuthInfo + i; dwError = CopyCertificateNode(pCurrentAuth, pTemp); BAIL_ON_WIN32ERROR(dwError) pTemp = pTemp->pNext; } if (pCertificateList) { FreeCertificateList(pCertificateList); } *ppAuthInfo = pAuthInfo; *pdwNumCertificates = dwNumCertificates; return(dwError); error: if (pCertificateList) { FreeCertificateList(pCertificateList); } if(NULL != pAuthInfo) { FreeADsMem(pAuthInfo); } *ppAuthInfo = NULL; *pdwNumCertificates = 0; return(dwError); } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : CopyCertificateNode // // Date of Creation : 10-10-2001 // // Parameters : OUT PINT_IPSEC_MM_AUTH_INFO pCurrentAuth, // IN PCERT_NODE pTemp // Return : DWORD // // Description : This function copies certificate from node to authentication. // // Revision History : // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// DWORD CopyCertificateNode( OUT PINT_IPSEC_MM_AUTH_INFO pCurrentAuth, IN PCERT_NODE pTemp ) { DWORD dwError = ERROR_SUCCESS; LPWSTR pszSubjectName = NULL; pCurrentAuth->AuthMethod = IKE_RSA_SIGNATURE; //value is 3 pszSubjectName = AllocADsStr(pTemp->pszSubjectName); if (!pszSubjectName) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwError) } pCurrentAuth->pAuthInfo = (LPBYTE) pszSubjectName; // // The AuthInfoSize is in number of characters -1 the leading character // see oakley\isadb.c // pCurrentAuth->dwAuthInfoSize = wcslen(pTemp->pszSubjectName)*sizeof(WCHAR); error: return dwError; } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : AppendCertificateNode // // Date of Creation: 10-10-2001 // // Parameters : OUT PCERT_NODE pCertificateList, // IN LPWSTR pszSubjectName // Return : PCERT_NODE // // Description : Add node and allocates memory. // // Revision History: // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// PCERT_NODE AppendCertificateNode( OUT PCERT_NODE pCertificateList, IN LPWSTR pszSubjectName ) { PCERT_NODE pCertificateNode = NULL; pCertificateNode = (PCERT_NODE)AllocADsMem(sizeof(CERT_NODE)); if (!pCertificateNode) { pCertificateNode = pCertificateList; BAILOUT; } pCertificateNode->pszSubjectName = pszSubjectName; pCertificateNode->pNext = pCertificateList; error: return(pCertificateNode); } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : FreeCertificateList // // Date of Creation: 10-10-2001 // // Parameters : IN PCERT_NODE pCertificateList // Return : VOID // // Description : Frees node // // Revision History: // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// VOID FreeCertificateList( IN PCERT_NODE pCertificateList ) { PCERT_NODE pTemp = NULL; pTemp = pCertificateList; while (pCertificateList) { pTemp = pCertificateList; pCertificateList = pCertificateList->pNext; if (pTemp) { FreeADsStr(pTemp->pszSubjectName); FreeADsMem(pTemp); } } return; } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : GetCertificateName // // Date of Creation : 10-10-2001 // // Parameters : IN CERT_NAME_BLOB * pCertNameBlob, // IN LPWSTR * ppszSubjectName // Return : DWORD // // Description : Gets certificate // // Revision History : // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// DWORD GetCertificateName( IN CERT_NAME_BLOB * pCertNameBlob, IN LPWSTR * ppszSubjectName ) { DWORD dwSize = 0; DWORD dwError = 0; LPWSTR pszSubjectName = NULL; *ppszSubjectName = NULL; dwSize = CertNameToStrW(MY_ENCODING_TYPE_CERT, pCertNameBlob, CERT_X500_NAME_STR, NULL, dwSize ); if (dwSize <= 1) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwError) } pszSubjectName = (LPWSTR)AllocADsMem((dwSize + 1)*sizeof(WCHAR)); if (!pszSubjectName) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwError) } dwSize = CertNameToStrW(MY_ENCODING_TYPE_CERT, pCertNameBlob, CERT_X500_NAME_STR, pszSubjectName, dwSize ); if(dwSize <= 1) { FreeADsMem(pszSubjectName); dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwError) } *ppszSubjectName = pszSubjectName; error: return(dwError); } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : FreeCertificatesList // // Date of Creation : 10-10-2001 // // Parameters : IN INT_IPSEC_MM_AUTH_INFO * pAuthInfo, // IN DWORD dwNumCertificates // Return : VOID // // Description : Frees list of certificates from pAuth // // Revision History : // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// VOID FreeCertificatesList( IN INT_IPSEC_MM_AUTH_INFO * pAuthInfo, IN DWORD dwNumCertificates ) { DWORD i = 0; INT_IPSEC_MM_AUTH_INFO * pThisAuthInfo = NULL; if (!pAuthInfo) { BAILOUT; } for (i = 0; i < dwNumCertificates; i++) { pThisAuthInfo = pAuthInfo + i; if (pThisAuthInfo->pAuthInfo) { FreeADsMem(pThisAuthInfo->pAuthInfo); pThisAuthInfo->pAuthInfo = NULL; } } FreeADsMem(pAuthInfo); error: return; } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : FindCertificateInList // // Date of Creation : 10-10-2001 // // Parameters : IN PCERT_NODE pCertificateList, // IN LPWSTR pszSubjectName // Return : BOOL // // Description : Finds certificate in List // // Revision History : // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// BOOL FindCertificateInList( IN PCERT_NODE pCertificateList, IN LPWSTR pszSubjectName ) { BOOL bReturn = FALSE; while (pCertificateList) { if (!_wcsicmp(pCertificateList->pszSubjectName, pszSubjectName)) { bReturn = TRUE; BAILOUT; } pCertificateList = pCertificateList->pNext; } error: return bReturn; } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : ListCertChainsInStore // // Date of Creation: 10-10-2001 // // Parameters : IN HCERTSTORE hCertStore, // OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo, // IN PDWORD pdwNumCertificates, // IN LPCSTR pszUsageIdentifier // // Return : DWORD // // Description : Lists certificate in store // // Revision History: // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// DWORD ListCertChainsInStore( IN HCERTSTORE hCertStore, OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo, IN PDWORD pdwNumCertificates, IN LPCSTR pszUsageIdentifier ) { PCCERT_CHAIN_CONTEXT pPrevChain=NULL; PCCERT_CHAIN_CONTEXT pCertChain = NULL; DWORD dwError = 0; CERT_CHAIN_FIND_BY_ISSUER_PARA FindPara; CERT_NAME_BLOB *NameArray=NULL; DWORD ArraySize=0; PCERT_SIMPLE_CHAIN pSimpChain = NULL; PCERT_CHAIN_ELEMENT pRoot = NULL; DWORD dwRootIndex = 0; LPWSTR pszSubjectName = NULL; PCERT_NODE pCertificateList = NULL; PCERT_NODE pTemp = NULL; INT_IPSEC_MM_AUTH_INFO * pAuthInfo = NULL; INT_IPSEC_MM_AUTH_INFO * pCurrentAuth = NULL; DWORD i = 0; DWORD dwNumCertificates = 0; FindPara.pszUsageIdentifier = pszUsageIdentifier; FindPara.cbSize = sizeof(FindPara); FindPara.dwKeySpec = 0; FindPara.cIssuer = ArraySize; FindPara.rgIssuer = NameArray; FindPara.pfnFindCallback = NULL; FindPara.pvFindArg = NULL; while (TRUE) { pCertChain=CertFindChainInStore(hCertStore, X509_ASN_ENCODING, CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG | CERT_CHAIN_FIND_BY_ISSUER_LOCAL_MACHINE_FLAG | CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG | CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG, CERT_CHAIN_FIND_BY_ISSUER, &FindPara, pPrevChain ); if (!pCertChain) { break; } pSimpChain=*(pCertChain->rgpChain); dwRootIndex=pSimpChain->cElement-1; pRoot=pSimpChain->rgpElement[dwRootIndex]; dwError = GetCertificateName( &(pRoot->pCertContext->pCertInfo->Issuer), &pszSubjectName ); BAIL_ON_WIN32ERROR(dwError) if (!FindCertificateInList(pCertificateList, pszSubjectName)) { // // Append this CA to the list of CAs // pCertificateList = AppendCertificateNode( pCertificateList, pszSubjectName ); dwNumCertificates++; } else { // // This is a duplicate - certificate payloads will not accept dupes. // FreeADsStr(pszSubjectName); } pPrevChain = pCertChain; } if (!dwNumCertificates) { dwError = ERROR_NO_MORE_ITEMS; BAIL_ON_WIN32ERROR(dwError); } // // Allocate one more authinfo for pre-sharedkey. // pAuthInfo = (INT_IPSEC_MM_AUTH_INFO *)AllocADsMem(sizeof(INT_IPSEC_MM_AUTH_INFO) * (1 + dwNumCertificates)); if (!pAuthInfo) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwError); } pTemp = pCertificateList; for (i = 0; i < dwNumCertificates; i++) { pCurrentAuth = pAuthInfo + i; dwError = CopyCertificateNode( pCurrentAuth, pTemp); BAIL_ON_WIN32ERROR(dwError); pTemp = pTemp->pNext; } *ppAuthInfo = pAuthInfo; *pdwNumCertificates = dwNumCertificates; error: if (pCertificateList) { FreeCertificateList(pCertificateList); } if(dwError != 0) { *ppAuthInfo = NULL; *pdwNumCertificates = 0; } return(dwError); } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : CopyCertificate // // Date of Creation: 10-10-2001 // // Parameters : IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuth, // IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuthFrom // Return : DWORD // // Description : Copies certificate // // Revision History: // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// DWORD CopyCertificate( IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuth, IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuthFrom ) { DWORD dwReturn = ERROR_SUCCESS; pCurrentAuth->AuthMethod = pCurrentAuthFrom->AuthMethod; dwReturn = EncodeCertificateName ((LPTSTR)pCurrentAuthFrom->pAuthInfo, &pCurrentAuth->pAuthInfo, &pCurrentAuth->dwAuthInfoSize); return dwReturn; } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : IsDomainMember // // Date of Creation: 10-10-2001 // // Parameters : IN LPTSTR pszMachine // // Return : BOOL // // Description : Checks for member of a domain(2k) or not of pszMachine. // // Revision History: // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// BOOL IsDomainMember( IN LPTSTR pszMachine ) { BOOL bIsDomainMember = FALSE; do { NTSTATUS lStatus; LSA_HANDLE hLsa; LSA_OBJECT_ATTRIBUTES ObjectAttributes; LSA_UNICODE_STRING LsaString; // Initialize the object attributes to all zeroes. ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) ); if ((pszMachine == NULL) || !wcscmp(pszMachine, L"\0")) { LsaString.Buffer = NULL; LsaString.Length = 0; LsaString.MaximumLength = 0; } else { LsaString.Buffer = pszMachine; LsaString.Length = (USHORT) (wcslen(pszMachine)* sizeof(WCHAR)); LsaString.MaximumLength = (USHORT) (wcslen(pszMachine) + 1) * sizeof(WCHAR); } // Attempt to open the policy. lStatus = LsaOpenPolicy( &LsaString, &ObjectAttributes, GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, &hLsa ); // Exit on error. if (lStatus) { break; } // Query domain information PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo; lStatus = LsaQueryInformationPolicy( hLsa, PolicyPrimaryDomainInformation, (PVOID*)&ppdiDomainInfo ); // Exit on error. if (lStatus) { break; } // // Check the Sid pointer, if it is null, the workstation is either a // stand-alone computer or a member of a workgroup. // if( ppdiDomainInfo->Sid ) { bIsDomainMember = TRUE; } // // Clean up // if (NULL != ppdiDomainInfo) LsaFreeMemory( ppdiDomainInfo ); } while (0); return bIsDomainMember; } /////////////////////////////////////////////////////////////////////////////////////////// // // Function : SmartDefaults // // Date of Creation: 10-10-2001 // // Parameters : IN PINT_IPSEC_MM_AUTH_INFO pAuthInfo, // IN LPTSTRT pszMachine, // IN DWORD * pdwNumberOfAuth, // IN BOOL bIsDomainPolicy // // Return : DWORD // // Description : Loads smart defaults of pszMachine in pAuthinfo. // // Revision History: // // Date Author Comments // ////////////////////////////////////////////////////////////////////////////////////////// DWORD SmartDefaults( IN PINT_IPSEC_MM_AUTH_INFO *ppAuthInfo, IN LPTSTR pszMachine, IN DWORD * pdwNumberOfAuth, IN BOOL bIsDomainPolicy ) { HCERTSTORE hCertStore = NULL; INT_IPSEC_MM_AUTH_INFO * pAuthInfoIKE = NULL, * pAuthInfoOthers = NULL; PINT_IPSEC_MM_AUTH_INFO pAuthInfo = NULL; DWORD dwReturn = ERROR_SUCCESS, i=0; DWORD dwNumCertificatesIKE = 0, dwNumCertificatesOthers = 0; _TCHAR szMachine[MACHINE_NAME] = {0}; if((pszMachine == NULL) || (!wcscmp(pszMachine, L"\0"))) { wcscpy(szMachine, L"MY\0"); } else { wcscpy(szMachine, pszMachine); wcscat(szMachine, L"\\MY\0"); } if (bIsDomainPolicy || IsDomainMember(pszMachine)) { hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE, szMachine); if(hCertStore) { // // First fill IKE intermediate // dwReturn = ListCertChainsInStore( hCertStore, &pAuthInfoIKE, &dwNumCertificatesIKE, szOID_IPSEC_KP_IKE_INTERMEDIATE ); if(dwNumCertificatesIKE == 0) { dwReturn = ERROR_SUCCESS; } if(dwReturn == ERROR_SUCCESS) { dwReturn = ListCertsInStore( hCertStore, &pAuthInfoOthers, &dwNumCertificatesOthers); } if(dwNumCertificatesOthers == 0) { dwReturn = ERROR_SUCCESS; } } else { dwReturn = GetLastError(); BAIL_ON_WIN32ERROR(dwReturn) } } *pdwNumberOfAuth = dwNumCertificatesIKE + dwNumCertificatesOthers + 1; pAuthInfo = new INT_IPSEC_MM_AUTH_INFO[(*pdwNumberOfAuth)]; if(pAuthInfo == NULL) { dwReturn = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwReturn) } ZeroMemory(pAuthInfo, sizeof(INT_IPSEC_MM_AUTH_INFO) * (*pdwNumberOfAuth)); if(dwReturn == ERROR_SUCCESS) { for( i=0; i< dwNumCertificatesIKE; i++) { CopyCertificate( &pAuthInfo[i], &pAuthInfoIKE[i]); } for( i=0; i< dwNumCertificatesOthers; i++) { CopyCertificate( &pAuthInfo[i+dwNumCertificatesIKE], &pAuthInfoOthers[i]); } pAuthInfo[(*pdwNumberOfAuth)-1].AuthMethod = IKE_SSPI; pAuthInfo[(*pdwNumberOfAuth)-1].dwAuthInfoSize = 0; pAuthInfo[(*pdwNumberOfAuth)-1].pAuthInfo = (LPBYTE)new _TCHAR[1]; if(pAuthInfo[(*pdwNumberOfAuth)-1].pAuthInfo != NULL) { pAuthInfo[(*pdwNumberOfAuth)-1].pAuthInfo[0] = UNICODE_NULL; } else { dwReturn = ERROR_OUTOFMEMORY; BAIL_ON_WIN32ERROR(dwReturn) } } error: *ppAuthInfo = pAuthInfo; if(pAuthInfoIKE) FreeADsMem(pAuthInfoIKE); if(pAuthInfoOthers) FreeADsMem(pAuthInfoOthers); return dwReturn; }