//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 2002 // // File: cert.cpp // //-------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////// // Cert.cpp // // This file is the implementation of the CCertificate object. // // GLOSSARY // - BLOB Binary Large Object // - DER Distinguished Encoding Rules // - RDN Relative Distinguished Names // // HISTORY // 19-Jun-97 t-danm Creation. ///////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "common.h" #include "cert.h" ///////////////////////////////////////////////////////////////////// CCertificate::CCertificate() { m_paCertContext = NULL; m_blobCertData.pbData = NULL; } CCertificate::~CCertificate() { // Free the certificate ::CertFreeCertificateContext(m_paCertContext); delete m_blobCertData.pbData; } void DisplaySystemError (HWND hParent, DWORD dwErr) { AFX_MANAGE_STATE (AfxGetStaticModuleState ()); CThemeContextActivator activator; LPVOID lpMsgBuf = 0; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL); // Display the string. CString caption; //NTRAID#NTBUG9-571300-2002/03/10-jmessec LoadString can fail... VERIFY (caption.LoadString (IDS_ADD_CERTIFICATE_MAPPING)); ::MessageBox (hParent, (LPWSTR) lpMsgBuf, (LPCTSTR) caption, MB_OK | MB_ICONINFORMATION); // Free the buffer. LocalFree (lpMsgBuf); } // This code copied from CertMgr project - LOCATE.C BOOL CCertificate::FLoadCertificate (LPCTSTR szFile) { CThemeContextActivator activator; ASSERT (szFile); if ( !szFile ) return FALSE; BOOL bReturn = FALSE; PVOID FileNameVoidP = (PVOID) szFile; PCCERT_CONTEXT pCertContext = NULL; DWORD dwEncodingType = 0; DWORD dwContentType = 0; DWORD dwFormatType = 0; // NB. It's possible to read in a serialized store at this point, too. // We've have to add the UI to display the certs in the file so the // user could pick one. Use CryptUIDlgSelectCertificate (). bReturn = ::CryptQueryObject ( CERT_QUERY_OBJECT_FILE, FileNameVoidP, CERT_QUERY_CONTENT_FLAG_ALL, //CERT_QUERY_CONTENT_CERT | CERT_QUERY_CONTENT_SERIALIZED_CERT, CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (const void **)&pCertContext); ASSERT (bReturn); if ( bReturn ) { // // Success. See what we get back. // if ( (dwContentType != CERT_QUERY_CONTENT_CERT) || !pCertContext ) { // // Not a valid cert file. // if ( pCertContext ) ::CertFreeCertificateContext (pCertContext); CString text; CString caption; VERIFY (text.LoadString (IDS_CERTFILEFORMATERR)); VERIFY (caption.LoadString (IDS_ADD_CERTIFICATE_MAPPING)); MessageBox (NULL, text, caption, MB_OK | MB_ICONINFORMATION); bReturn = FALSE; } else { // Cert context is valid - let's save it to the global handle m_paCertContext = pCertContext; } } else { DWORD dwErr = GetLastError (); DisplaySystemError (NULL, dwErr); } return bReturn; } ///////////////////////////////////////////////////////////////////// // This routine is a wrapper to API ::CertNameToStr() automatically // calculating the length of the output string and returning the data // into the CString object. void CCertificate::CertNameToCString( IN DWORD dwCertEncodingType, IN CERT_NAME_BLOB * pName, OUT CString * pstrData) { ASSERT(pstrData != NULL); // Calculate how many characters are needed int cch = ::CertNameToStr( IN dwCertEncodingType, IN pName, IN c_dwCertNameStrType, NULL, 0); TCHAR * pchT = pstrData->GetBuffer(cch); ASSERT(pchT != NULL); ASSERT(lstrlen(pchT) == 0); (void)::CertNameToStr( IN dwCertEncodingType, IN pName, IN c_dwCertNameStrType, OUT pchT, IN cch); pstrData->ReleaseBuffer(); } // CCertificate::CertNameToCString() ///////////////////////////////////////////////////////////////////// void CCertificate::GetIssuer(OUT CString * pstrName) { ASSERT(pstrName != NULL); ASSERT(m_paCertContext != NULL); ASSERT(m_paCertContext->pCertInfo != NULL); CERT_INFO * pCertInfo = m_paCertContext->pCertInfo; BOOL fSelfIssued = CertCompareCertificateName( m_paCertContext->dwCertEncodingType, &pCertInfo->Subject, &pCertInfo->Issuer); if (fSelfIssued) { // Self issued certificate GetSubject(OUT pstrName); return; } // Get the issuer CertNameToCString( IN m_paCertContext->dwCertEncodingType, IN &pCertInfo->Issuer, OUT pstrName); } // CCertificate::GetIssuer() ///////////////////////////////////////////////////////////////////// void CCertificate::GetSubject(OUT CString * pstrName) { ASSERT(pstrName != NULL); ASSERT(m_paCertContext != NULL); ASSERT(m_paCertContext->pCertInfo != NULL); CertNameToCString( IN m_paCertContext->dwCertEncodingType, IN &m_paCertContext->pCertInfo->Subject, OUT pstrName); } // CCertificate::GetSubject() ///////////////////////////////////////////////////////////////////// void CCertificate::GetAltSubject(OUT CString * pstrName) { ASSERT(pstrName != NULL); ASSERT(m_paCertContext != NULL); ASSERT(m_paCertContext->pCertInfo != NULL); pstrName->Empty(); CERT_INFO * pCertInfo = m_paCertContext->pCertInfo; CERT_EXTENSION * pCertExtension; // Search for the AltSubject in the extensions pCertExtension = ::CertFindExtension( IN szOID_SUBJECT_ALT_NAME, // Same as X509_ALTERNATE_NAME IN pCertInfo->cExtension, IN pCertInfo->rgExtension); if (pCertExtension == NULL) return; // No AltSubject DWORD dwErr = ERROR_SUCCESS; BOOL fSuccess; DWORD cbData = 0; // Find out how many bytes are needed for AltSubject fSuccess = ::CryptDecodeObject( m_paCertContext->dwCertEncodingType, X509_ALTERNATE_NAME, IN pCertExtension->Value.pbData, IN pCertExtension->Value.cbData, 0, // dwFlags NULL, INOUT &cbData); if (!fSuccess) { dwErr = ::GetLastError(); TRACE1("CryptDecodeObject() returned error %u", dwErr); return; } ASSERT(cbData > 0); BYTE * pbDataT = new BYTE[cbData]; // Decode the AltSubject name fSuccess = ::CryptDecodeObject( m_paCertContext->dwCertEncodingType, X509_ALTERNATE_NAME, IN pCertExtension->Value.pbData, IN pCertExtension->Value.cbData, 0, // dwFlags OUT pbDataT, INOUT &cbData); if (!fSuccess) { dwErr = ::GetLastError(); TRACE1("CryptDecodeObject() returned error %u", dwErr); } else { CERT_ALT_NAME_INFO * pCertAltNameInfo = (CERT_ALT_NAME_INFO *)pbDataT; CERT_ALT_NAME_ENTRY * pEntry = pCertAltNameInfo->rgAltEntry; ASSERT(pEntry != NULL); for (UINT i = 0; i < pCertAltNameInfo->cAltEntry; i++, pEntry++) { if (pEntry->dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) { *pstrName = pEntry->pwszDNSName; break; } } // for } // if...else delete [] pbDataT; } // CCertificate::GetAltSubject() ///////////////////////////////////////////////////////////////////// void CCertificate::GetSimString(OUT CString * pstrData) { ASSERT(pstrData != NULL); CString strIssuer; CString strSubject; CString strAltSubject; GetIssuer(OUT &strIssuer); GetSubject(OUT &strSubject); GetAltSubject(OUT &strAltSubject); LPTSTR * pargzpszIssuer = ParseSimString(strIssuer); LPTSTR * pargzpszSubject = ParseSimString(strSubject); LPTSTR * pargzpszAltSubject = ParseSimString(strAltSubject); // Make a "X509" string UnsplitX509String(OUT pstrData, pargzpszIssuer, pargzpszSubject, pargzpszAltSubject); delete pargzpszIssuer; delete pargzpszSubject; delete pargzpszAltSubject; } // CCertificate::GetSimString()