windows-nt/Source/XPSP1/NT/admin/snapin/dsadmin/cert.cpp
2020-09-26 16:20:57 +08:00

299 lines
7.7 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1998
//
// 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 ());
LPVOID lpMsgBuf;
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;
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)
{
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()