windows-nt/Source/XPSP1/NT/ds/security/services/ca/certenc/altname.cpp
2020-09-26 16:20:57 +08:00

765 lines
16 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: crldist.cpp
//
// Contents: Cert Server Extension Encoding/Decoding implementation
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include <assert.h>
#include "resource.h"
#include "altname.h"
#include "celib.h"
#ifndef EAN_NAMEOBJECTID
#define EAN_NAMEOBJECTID ( 0x80000000 )
#endif EAN_NAMEOBJECTID
//+--------------------------------------------------------------------------
// CCertEncodeAltName::CCertEncodeAltName -- constructor
//
// initialize class
//+--------------------------------------------------------------------------
CCertEncodeAltName::CCertEncodeAltName()
{
m_aValue = NULL;
m_DecodeInfo = NULL;
m_fConstructing = FALSE;
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::~CCertEncodeAltName -- destructor
//
// free memory associated with this instance
//+--------------------------------------------------------------------------
CCertEncodeAltName::~CCertEncodeAltName()
{
_Cleanup();
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::_NameType -- determine name type tag
//
//+--------------------------------------------------------------------------
CCertEncodeAltName::enumNameType
CCertEncodeAltName::_NameType(
IN DWORD NameChoice)
{
enumNameType Type = enumUnknown;
switch (NameChoice)
{
case CERT_ALT_NAME_RFC822_NAME:
case CERT_ALT_NAME_DNS_NAME:
case CERT_ALT_NAME_URL:
Type = enumUnicode;
break;
case CERT_ALT_NAME_REGISTERED_ID:
Type = enumAnsi;
break;
case CERT_ALT_NAME_DIRECTORY_NAME:
case CERT_ALT_NAME_IP_ADDRESS:
Type = enumBlob;
break;
case CERT_ALT_NAME_OTHER_NAME:
Type = enumOther;
break;
//case CERT_ALT_NAME_X400_ADDRESS:
//case CERT_ALT_NAME_EDI_PARTY_NAME:
}
return(Type);
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::_Cleanup -- release all resources
//
// free memory associated with this instance
//+--------------------------------------------------------------------------
VOID
CCertEncodeAltName::_Cleanup()
{
if (NULL != m_aValue)
{
if (!m_fConstructing)
{
if (NULL != m_DecodeInfo)
{
LocalFree(m_DecodeInfo);
m_DecodeInfo = NULL;
}
}
else
{
CERT_ALT_NAME_ENTRY *pName;
CERT_ALT_NAME_ENTRY *pNameEnd;
for (pName = m_aValue, pNameEnd = &m_aValue[m_cValue];
pName < pNameEnd;
pName++)
{
BYTE **ppb;
ppb = NULL;
switch (_NameType(pName->dwAltNameChoice))
{
case enumUnicode:
case enumAnsi:
ppb = (BYTE **) &pName->pwszURL;
break;
case enumBlob:
ppb = (BYTE **) &pName->DirectoryName.pbData;
break;
case enumOther:
{
CERT_OTHER_NAME *pOther = pName->pOtherName;
if (NULL != pOther)
{
if (NULL != pOther->pszObjId)
{
LocalFree(pOther->pszObjId);
}
if (NULL != pOther->Value.pbData)
{
LocalFree(pOther->Value.pbData);
}
}
ppb = (BYTE **) &pName->pOtherName;
break;
}
}
if (NULL != ppb && NULL != *ppb)
{
LocalFree(*ppb);
}
}
LocalFree(m_aValue);
}
m_aValue = NULL;
}
assert(NULL == m_DecodeInfo);
m_fConstructing = FALSE;
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::_MapName -- map a distribution point
//
//+--------------------------------------------------------------------------
HRESULT
CCertEncodeAltName::_MapName(
IN BOOL fEncode,
IN LONG NameIndex, // NameIndex | EAN_*
OUT CERT_ALT_NAME_ENTRY **ppName)
{
HRESULT hr = S_OK;
CERT_ALT_NAME_ENTRY *pName;
if (fEncode)
{
pName = m_fConstructing? m_aValue : NULL;
}
else
{
pName = m_aValue;
}
if (NULL == pName)
{
hr = E_INVALIDARG;
ceERRORPRINTLINE("bad parameter", hr);
goto error;
}
NameIndex &= ~EAN_NAMEOBJECTID;
if (m_cValue <= NameIndex)
{
ceERRORPRINTLINE("bad NameIndex parameter", hr);
hr = E_INVALIDARG;
goto error;
}
*ppName = &pName[NameIndex];
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::Decode -- Decode AltName
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertEncodeAltName::Decode(
/* [in] */ BSTR const strBinary)
{
HRESULT hr = S_OK;
_Cleanup();
if (NULL == strBinary)
{
hr = E_POINTER;
ceERRORPRINTLINE("NULL parm", hr);
goto error;
}
// Decode CERT_ALT_NAME_INFO:
if (!ceDecodeObject(
X509_ASN_ENCODING,
X509_ALTERNATE_NAME,
(BYTE *) strBinary,
SysStringByteLen(strBinary),
FALSE,
(VOID **) &m_DecodeInfo,
&m_DecodeLength))
{
hr = ceHLastError();
ceERRORPRINTLINE("ceDecodeObject", hr);
goto error;
}
m_aValue = m_DecodeInfo->rgAltEntry;
m_cValue = m_DecodeInfo->cAltEntry;
error:
if (S_OK != hr)
{
_Cleanup();
}
return(_SetErrorInfo(hr, L"CCertEncodeAltName::Decode"));
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::GetNameCount -- Get the Distribution Name Count
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertEncodeAltName::GetNameCount(
/* [out, retval] */ LONG __RPC_FAR *pNameCount)
{
HRESULT hr = E_INVALIDARG;
if (NULL == pNameCount)
{
hr = E_POINTER;
ceERRORPRINTLINE("NULL parm", hr);
goto error;
}
if (NULL == m_aValue)
{
ceERRORPRINTLINE("bad parameter", hr);
goto error;
}
*pNameCount = m_cValue;
hr = S_OK;
error:
return(_SetErrorInfo(hr, L"CCertEncodeAltName::GetNameCount"));
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::GetNameChoice -- Get a Name Choice
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertEncodeAltName::GetNameChoice(
/* [in] */ LONG NameIndex,
/* [out, retval] */ LONG __RPC_FAR *pNameChoice)
{
HRESULT hr;
CERT_ALT_NAME_ENTRY *pName;
if (NULL == pNameChoice)
{
hr = E_POINTER;
ceERRORPRINTLINE("NULL parm", hr);
goto error;
}
hr = _MapName(FALSE, NameIndex, &pName);
if (S_OK != hr)
{
ceERRORPRINTLINE("_MapName", hr);
goto error;
}
if (enumUnknown == _NameType(pName->dwAltNameChoice))
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
ceERRORPRINTLINE("uninitialized", hr);
goto error;
}
*pNameChoice = pName->dwAltNameChoice;
error:
return(_SetErrorInfo(hr, L"CCertEncodeAltName::GetNameChoice"));
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::GetName -- Get a Name
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertEncodeAltName::GetName(
/* [in] */ LONG NameIndex, // NameIndex | EAN_*
/* [out, retval] */ BSTR __RPC_FAR *pstrName)
{
HRESULT hr;
CERT_ALT_NAME_ENTRY *pName;
if (NULL == pstrName)
{
hr = E_POINTER;
ceERRORPRINTLINE("NULL parm", hr);
goto error;
}
ceFreeBstr(pstrName);
hr = _MapName(FALSE, NameIndex, &pName);
if (S_OK != hr)
{
ceERRORPRINTLINE("_MapName", hr);
goto error;
}
hr = E_OUTOFMEMORY;
switch (_NameType(pName->dwAltNameChoice))
{
case enumUnicode:
if (!ceConvertWszToBstr(pstrName, pName->pwszURL, -1))
{
ceERRORPRINTLINE("no memory", hr);
goto error;
}
break;
case enumAnsi:
if (!ceConvertSzToBstr(pstrName, pName->pszRegisteredID, -1))
{
ceERRORPRINTLINE("no memory", hr);
goto error;
}
break;
case enumBlob:
if (!ceConvertWszToBstr(
pstrName,
(WCHAR const *) pName->DirectoryName.pbData,
pName->DirectoryName.cbData))
{
ceERRORPRINTLINE("no memory", hr);
goto error;
}
break;
case enumOther:
if (EAN_NAMEOBJECTID & NameIndex)
{
if (!ceConvertSzToBstr(
pstrName,
pName->pOtherName->pszObjId,
-1))
{
ceERRORPRINTLINE("no memory", hr);
goto error;
}
}
else
{
if (!ceConvertWszToBstr(
pstrName,
(WCHAR const *) pName->pOtherName->Value.pbData,
pName->pOtherName->Value.cbData))
{
ceERRORPRINTLINE("no memory", hr);
goto error;
}
}
break;
default:
assert(enumUnknown == _NameType(pName->dwAltNameChoice));
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
ceERRORPRINTLINE("uninitialized", hr);
goto error;
}
hr = S_OK;
error:
return(_SetErrorInfo(hr, L"CCertEncodeAltName::GetName"));
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::Reset -- clear out data
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertEncodeAltName::Reset(
/* [in] */ LONG NameCount)
{
HRESULT hr = S_OK;
CERT_NAME_VALUE *aNameValue = NULL;
_Cleanup();
m_fConstructing = TRUE;
if (CENCODEMAX < NameCount || 0 > NameCount)
{
hr = E_INVALIDARG;
ceERRORPRINTLINE("bad count parameter", hr);
goto error;
}
m_aValue = (CERT_ALT_NAME_ENTRY *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
NameCount * sizeof(m_aValue[0]));
if (NULL == m_aValue)
{
hr = E_OUTOFMEMORY;
ceERRORPRINTLINE("LocalAlloc", hr);
goto error;
}
m_cValue = NameCount;
error:
if (S_OK != hr)
{
_Cleanup();
}
return(_SetErrorInfo(hr, L"CCertEncodeAltName::Reset"));
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::SetNameEntry -- Set a Name Netry
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertEncodeAltName::SetNameEntry(
/* [in] */ LONG NameIndex, // NameIndex | EAN_*
/* [in] */ LONG NameChoice,
/* [in] */ BSTR const strName)
{
HRESULT hr;
CERT_ALT_NAME_ENTRY *pName;
DATA_BLOB *pBlob = NULL;
if (NULL == strName)
{
hr = E_POINTER;
ceERRORPRINTLINE("NULL parm", hr);
goto error;
}
if (!m_fConstructing)
{
hr = E_INVALIDARG;
ceERRORPRINTLINE("bad parameter", hr);
goto error;
}
hr = _MapName(TRUE, NameIndex, &pName);
if (S_OK != hr)
{
ceERRORPRINTLINE("_MapName", hr);
goto error;
}
if (enumUnknown != _NameType(pName->dwAltNameChoice))
{
hr = E_INVALIDARG;
ceERRORPRINTLINE("bad parameter", hr);
goto error;
}
hr = ceVerifyAltNameString(NameChoice, strName);
if (S_OK != hr)
{
ceERRORPRINTLINE("ceVerifyAltNameString", hr);
goto error;
}
switch (_NameType(NameChoice))
{
case enumUnicode:
pName->pwszURL = ceDuplicateString(strName);
if (NULL == pName->pwszURL)
{
hr = E_OUTOFMEMORY;
ceERRORPRINTLINE("ceDuplicateString", hr);
goto error;
}
break;
case enumAnsi:
if (CERT_ALT_NAME_REGISTERED_ID == NameChoice)
{
hr = ceVerifyObjId(strName);
if (S_OK != hr)
{
ceERRORPRINTLINE("ceVerifyObjId", hr);
goto error;
}
}
if (!ceConvertWszToSz(&pName->pszRegisteredID, strName, -1))
{
hr = E_OUTOFMEMORY;
ceERRORPRINTLINE("ceConvertWszToSz", hr);
goto error;
}
break;
case enumBlob:
pBlob = &pName->DirectoryName;
break;
case enumOther:
if (NULL == pName->pOtherName)
{
pName->pOtherName = (CERT_OTHER_NAME *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
sizeof(*pName->pOtherName));
if (NULL == pName->pOtherName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
}
else if (CERT_ALT_NAME_OTHER_NAME != pName->dwAltNameChoice)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "NameChoice conflict");
}
if (EAN_NAMEOBJECTID & NameIndex)
{
if (NULL != pName->pOtherName->pszObjId)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "pszObjId already set");
}
if (!ceConvertWszToSz(&pName->pOtherName->pszObjId, strName, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ceConvertWszToSz");
}
}
else
{
pBlob = &pName->pOtherName->Value;
}
break;
default:
hr = E_INVALIDARG;
ceERRORPRINTLINE("bad NameChoice parameter", hr);
goto error;
break;
}
if (NULL != pBlob)
{
if (NULL != pBlob->pbData)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "pbData already set");
}
pBlob->cbData = SysStringByteLen(strName);
pBlob->pbData = (BYTE *) LocalAlloc(LMEM_FIXED, pBlob->cbData);
if (NULL == pBlob->pbData)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(pBlob->pbData, strName, pBlob->cbData);
}
pName->dwAltNameChoice = NameChoice;
error:
return(_SetErrorInfo(hr, L"CCertEncodeAltName::SetNameEntry"));
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::_VerifyName -- Verify name
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
BOOL
CCertEncodeAltName::_VerifyName(
IN LONG NameIndex)
{
HRESULT hr;
BOOL fOk = FALSE;
CERT_ALT_NAME_ENTRY *pName;
assert(m_fConstructing);
hr = _MapName(TRUE, NameIndex, &pName);
if (S_OK != hr)
{
ceERRORPRINTLINE("_MapName", hr);
goto error;
}
assert(NULL != pName);
switch (_NameType(pName->dwAltNameChoice))
{
case enumOther:
if (NULL != pName->pOtherName &&
NULL != pName->pOtherName->pszObjId &&
NULL != pName->pOtherName->Value.pbData)
{
break;
}
// FALLTHROUGH
case enumUnknown:
hr = E_INVALIDARG;
ceERRORPRINTLINE("uninitialized name", hr);
goto error;
}
fOk = TRUE;
error:
return(fOk);
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::Encode -- Encode AltName
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertEncodeAltName::Encode(
/* [out, retval] */ BSTR __RPC_FAR *pstrBinary)
{
HRESULT hr = S_OK;
CERT_ALT_NAME_INFO AltName;
BYTE *pbEncoded = NULL;
DWORD cbEncoded;
LONG i;
if (NULL == pstrBinary)
{
hr = E_POINTER;
ceERRORPRINTLINE("NULL parm", hr);
goto error;
}
AltName.cAltEntry = m_cValue;
AltName.rgAltEntry = m_aValue;
ceFreeBstr(pstrBinary);
if (!m_fConstructing || NULL == m_aValue)
{
hr = E_INVALIDARG;
ceERRORPRINTLINE("bad parameter", hr);
goto error;
}
for (i = 0; i < m_cValue; i++)
{
// Verify all entries are initialized:
if (!_VerifyName(i))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
ceERRORPRINTLINE("uninitialized name", hr);
goto error;
}
}
// Encode CERT_ALT_NAME_INFO:
if (!ceEncodeObject(
X509_ASN_ENCODING,
X509_ALTERNATE_NAME,
&AltName,
0,
FALSE,
&pbEncoded,
&cbEncoded))
{
hr = ceHLastError();
ceERRORPRINTLINE("ceEncodeObject", hr);
goto error;
}
if (!ceConvertWszToBstr(pstrBinary, (WCHAR const *) pbEncoded, cbEncoded))
{
hr = E_OUTOFMEMORY;
ceERRORPRINTLINE("ceConvertWszToBstr", hr);
goto error;
}
error:
if (NULL != pbEncoded)
{
LocalFree(pbEncoded);
}
return(_SetErrorInfo(hr, L"CCertEncodeAltName::Encode"));
}
//+--------------------------------------------------------------------------
// CCertEncodeAltName::_SetErrorInfo -- set error object information
//
// Returns passed HRESULT
//+--------------------------------------------------------------------------
HRESULT
CCertEncodeAltName::_SetErrorInfo(
IN HRESULT hrError,
IN WCHAR const *pwszDescription)
{
assert(FAILED(hrError) || S_OK == hrError || S_FALSE == hrError);
if (FAILED(hrError))
{
HRESULT hr;
hr = ceDispatchSetErrorInfo(
hrError,
pwszDescription,
wszCLASS_CERTENCODEALTNAME,
&IID_ICertEncodeAltName);
assert(hr == hrError);
}
return(hrError);
}