You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
416 lines
11 KiB
416 lines
11 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: oidconv.cpp
|
|
//
|
|
// Contents: Object ID (OID) Conv Functions
|
|
//
|
|
// Functions: I_CryptOIDConvDllMain
|
|
// I_CryptSetEncodedOID
|
|
// I_CryptGetEncodedOID
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: 08_Feb-98 philh created
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "global.hxx"
|
|
#include <dbgdef.h>
|
|
|
|
// All the *pvInfo extra stuff needs to be aligned
|
|
#define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
|
|
|
|
typedef struct _OID_HASH_BUCKET_ENTRY
|
|
OID_HASH_BUCKET_ENTRY, *POID_HASH_BUCKET_ENTRY;
|
|
|
|
// pbEncodedOID immediately follows the data structure. pszDotOID
|
|
// is at pbEncodedOID + cbEncodedOID. pszDotOID is null terminated.
|
|
// cchDotOID doesn't include the null terminator.
|
|
struct _OID_HASH_BUCKET_ENTRY {
|
|
DWORD cbEncodedOID;
|
|
DWORD cchDotOID;
|
|
POID_HASH_BUCKET_ENTRY pEncodedNext;
|
|
POID_HASH_BUCKET_ENTRY pDotNext;
|
|
};
|
|
|
|
static inline BYTE * GetEncodedOIDPointer(
|
|
IN POID_HASH_BUCKET_ENTRY pEntry
|
|
)
|
|
{
|
|
return ((BYTE *) pEntry) + sizeof(OID_HASH_BUCKET_ENTRY);
|
|
}
|
|
static inline LPSTR GetDotOIDPointer(
|
|
IN POID_HASH_BUCKET_ENTRY pEntry
|
|
)
|
|
{
|
|
return (LPSTR) (((BYTE *) pEntry) + sizeof(OID_HASH_BUCKET_ENTRY) +
|
|
pEntry->cbEncodedOID);
|
|
}
|
|
|
|
// Some prime numbers: 11, 13, 19, 23, 29, 31, 47, 53, 61, 73, 97,
|
|
// 101, 127, 251, 509
|
|
|
|
#define ENCODED_OID_HASH_BUCKET_COUNT 47
|
|
#define DOT_OID_HASH_BUCKET_COUNT 31
|
|
|
|
static POID_HASH_BUCKET_ENTRY
|
|
rgpEncodedOIDHashBucket[ENCODED_OID_HASH_BUCKET_COUNT];
|
|
static POID_HASH_BUCKET_ENTRY rgpDotOIDHashBucket[DOT_OID_HASH_BUCKET_COUNT];
|
|
|
|
static CRITICAL_SECTION OIDHashBucketCriticalSection;
|
|
|
|
static BOOL OIDHashBucketProcessAttach()
|
|
{
|
|
return Pki_InitializeCriticalSection(&OIDHashBucketCriticalSection);
|
|
}
|
|
|
|
static void OIDHashBucketProcessDetach()
|
|
{
|
|
DWORD i;
|
|
for (i = 0; i < DOT_OID_HASH_BUCKET_COUNT; i++) {
|
|
POID_HASH_BUCKET_ENTRY pEntry = rgpDotOIDHashBucket[i];
|
|
while (pEntry) {
|
|
POID_HASH_BUCKET_ENTRY pFreeEntry = pEntry;
|
|
pEntry = pEntry->pDotNext;
|
|
PkiFree(pFreeEntry);
|
|
}
|
|
}
|
|
|
|
DeleteCriticalSection(&OIDHashBucketCriticalSection);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
I_CryptOIDConvDllMain(
|
|
HMODULE hInst,
|
|
ULONG ulReason,
|
|
LPVOID lpReserved)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
switch (ulReason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
fRet = OIDHashBucketProcessAttach();
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
OIDHashBucketProcessDetach();
|
|
break;
|
|
case DLL_THREAD_DETACH:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
extern HCRYPTASN1MODULE hX509Asn1Module; // From wincert.cpp
|
|
static inline ASN1encoding_t GetEncoder(void)
|
|
{
|
|
return I_CryptGetAsn1Encoder(hX509Asn1Module);
|
|
}
|
|
static inline ASN1decoding_t GetDecoder(void)
|
|
{
|
|
return I_CryptGetAsn1Decoder(hX509Asn1Module);
|
|
}
|
|
|
|
static DWORD GetOIDHashBucketIndex(
|
|
IN DWORD cHashBucket,
|
|
IN const BYTE *pb,
|
|
IN DWORD cb
|
|
)
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
dwIndex = 0;
|
|
while (cb--) {
|
|
if (dwIndex & 0x80000000)
|
|
dwIndex = (dwIndex << 1) | 1;
|
|
else
|
|
dwIndex = dwIndex << 1;
|
|
dwIndex += *pb++;
|
|
}
|
|
return dwIndex % cHashBucket;
|
|
}
|
|
|
|
static POID_HASH_BUCKET_ENTRY FindOIDHashBucketEntryFromEncodedOID(
|
|
IN ASN1encodedOID_t *pEncodedOid
|
|
)
|
|
{
|
|
POID_HASH_BUCKET_ENTRY pEntry;
|
|
BYTE *pbEncodedOID = pEncodedOid->value;
|
|
DWORD cbEncodedOID = pEncodedOid->length;
|
|
DWORD dwIndex;
|
|
|
|
dwIndex = GetOIDHashBucketIndex(
|
|
ENCODED_OID_HASH_BUCKET_COUNT,
|
|
pbEncodedOID,
|
|
cbEncodedOID
|
|
);
|
|
|
|
for (pEntry = rgpEncodedOIDHashBucket[dwIndex]; pEntry;
|
|
pEntry = pEntry->pEncodedNext) {
|
|
if (cbEncodedOID == pEntry->cbEncodedOID &&
|
|
0 == memcmp(pbEncodedOID, GetEncodedOIDPointer(pEntry),
|
|
cbEncodedOID))
|
|
return pEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static POID_HASH_BUCKET_ENTRY FindOIDHashBucketEntryFromDotOID(
|
|
IN LPSTR pszDotOID
|
|
)
|
|
{
|
|
POID_HASH_BUCKET_ENTRY pEntry;
|
|
DWORD cchDotOID = strlen(pszDotOID);
|
|
DWORD dwIndex;
|
|
|
|
dwIndex = GetOIDHashBucketIndex(
|
|
DOT_OID_HASH_BUCKET_COUNT,
|
|
(const BYTE *) pszDotOID,
|
|
cchDotOID
|
|
);
|
|
|
|
for (pEntry = rgpDotOIDHashBucket[dwIndex]; pEntry;
|
|
pEntry = pEntry->pDotNext) {
|
|
if (cchDotOID == pEntry->cchDotOID &&
|
|
0 == memcmp(pszDotOID, GetDotOIDPointer(pEntry), cchDotOID))
|
|
return pEntry;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// If after entering the critical section, the entry already exists, then,
|
|
// return it and free the input entry. Otherwise, add the input entry and
|
|
// return it.
|
|
static POID_HASH_BUCKET_ENTRY AddOIDHashBucketEntry(
|
|
IN POID_HASH_BUCKET_ENTRY pEntry
|
|
)
|
|
{
|
|
POID_HASH_BUCKET_ENTRY pFindEntry;
|
|
ASN1encodedOID_t EncodedOid;
|
|
|
|
EnterCriticalSection(&OIDHashBucketCriticalSection);
|
|
|
|
EncodedOid.value = GetEncodedOIDPointer(pEntry);
|
|
EncodedOid.length = (ASN1uint16_t) pEntry->cbEncodedOID;
|
|
if (pFindEntry = FindOIDHashBucketEntryFromEncodedOID(&EncodedOid)) {
|
|
PkiFree(pEntry);
|
|
pEntry = pFindEntry;
|
|
} else {
|
|
DWORD dwIndex;
|
|
|
|
dwIndex = GetOIDHashBucketIndex(
|
|
ENCODED_OID_HASH_BUCKET_COUNT,
|
|
GetEncodedOIDPointer(pEntry),
|
|
pEntry->cbEncodedOID
|
|
);
|
|
pEntry->pEncodedNext = rgpEncodedOIDHashBucket[dwIndex];
|
|
// Since we do finds outside of CriticalSection, must update
|
|
// the following last!!!
|
|
rgpEncodedOIDHashBucket[dwIndex] = pEntry;
|
|
|
|
dwIndex = GetOIDHashBucketIndex(
|
|
DOT_OID_HASH_BUCKET_COUNT,
|
|
(const BYTE *) GetDotOIDPointer(pEntry),
|
|
pEntry->cchDotOID
|
|
);
|
|
pEntry->pDotNext = rgpDotOIDHashBucket[dwIndex];
|
|
// Since we do finds outside of CriticalSection, must update
|
|
// the following last!!!
|
|
rgpDotOIDHashBucket[dwIndex] = pEntry;
|
|
}
|
|
|
|
LeaveCriticalSection(&OIDHashBucketCriticalSection);
|
|
|
|
return pEntry;
|
|
}
|
|
|
|
|
|
static POID_HASH_BUCKET_ENTRY CreateOIDHashBucketEntry(
|
|
IN const BYTE *pbEncodedOID,
|
|
IN DWORD cbEncodedOID,
|
|
IN LPSTR pszDotOID,
|
|
IN DWORD cchDotOID
|
|
)
|
|
{
|
|
POID_HASH_BUCKET_ENTRY pEntry;
|
|
DWORD cbEntry;
|
|
|
|
cbEntry = sizeof(OID_HASH_BUCKET_ENTRY) + cbEncodedOID + cchDotOID + 1;
|
|
if (NULL == (pEntry = (POID_HASH_BUCKET_ENTRY) PkiZeroAlloc(cbEntry)))
|
|
return NULL;
|
|
|
|
pEntry->cbEncodedOID = cbEncodedOID;
|
|
pEntry->cchDotOID = cchDotOID;
|
|
memcpy(GetEncodedOIDPointer(pEntry), pbEncodedOID, cbEncodedOID);
|
|
memcpy(GetDotOIDPointer(pEntry), pszDotOID, cchDotOID + 1);
|
|
|
|
return pEntry;
|
|
}
|
|
|
|
static POID_HASH_BUCKET_ENTRY CreateOIDHashBucketEntryFromEncodedOID(
|
|
IN ASN1encodedOID_t *pEncodedOid
|
|
)
|
|
{
|
|
POID_HASH_BUCKET_ENTRY pEntry;
|
|
ASN1decoding_t pDec = GetDecoder();
|
|
const BYTE *pbEncodedOID; // not allocated
|
|
DWORD cbEncodedOID;
|
|
LPSTR pszDotOID = NULL;
|
|
DWORD cchDotOID;
|
|
|
|
if (NULL == (pszDotOID = PkiAsn1EncodedOidToDotVal(pDec, pEncodedOid)))
|
|
goto EncodedOidToDotValError;
|
|
cchDotOID = (DWORD) strlen(pszDotOID);
|
|
|
|
pbEncodedOID = pEncodedOid->value;
|
|
cbEncodedOID = pEncodedOid->length;
|
|
pEntry = CreateOIDHashBucketEntry(
|
|
pbEncodedOID,
|
|
cbEncodedOID,
|
|
pszDotOID,
|
|
cchDotOID
|
|
);
|
|
|
|
CommonReturn:
|
|
PkiAsn1FreeDotVal(pDec, pszDotOID);
|
|
return pEntry;
|
|
|
|
ErrorReturn:
|
|
pEntry = NULL;
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(EncodedOidToDotValError)
|
|
}
|
|
|
|
static POID_HASH_BUCKET_ENTRY CreateOIDHashBucketEntryFromDotOID(
|
|
IN LPSTR pszDotOID
|
|
)
|
|
{
|
|
POID_HASH_BUCKET_ENTRY pEntry;
|
|
ASN1encoding_t pEnc = GetEncoder();
|
|
ASN1encodedOID_t EncodedOid;
|
|
memset(&EncodedOid, 0, sizeof(EncodedOid));
|
|
|
|
const BYTE *pbEncodedOID;
|
|
DWORD cbEncodedOID;
|
|
|
|
if (NULL == pszDotOID || '\0' == *pszDotOID)
|
|
goto EmptyDotOIDError;
|
|
if (!PkiAsn1DotValToEncodedOid(pEnc, pszDotOID, &EncodedOid))
|
|
goto DotValToEncodedOidError;
|
|
pbEncodedOID = EncodedOid.value;
|
|
cbEncodedOID = EncodedOid.length;
|
|
|
|
pEntry = CreateOIDHashBucketEntry(
|
|
pbEncodedOID,
|
|
cbEncodedOID,
|
|
pszDotOID,
|
|
strlen(pszDotOID)
|
|
);
|
|
|
|
CommonReturn:
|
|
PkiAsn1FreeEncodedOid(pEnc, &EncodedOid);
|
|
return pEntry;
|
|
ErrorReturn:
|
|
pEntry = NULL;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(EmptyDotOIDError, E_INVALIDARG)
|
|
SET_ERROR_VAR(DotValToEncodedOidError, PkiAsn1ErrToHr(ASN1_ERR_BADARGS))
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Set/Get Encoded OID
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
I_CryptSetEncodedOID(
|
|
IN LPSTR pszObjId,
|
|
OUT ASN1encodedOID_t *pEncodedOid
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
POID_HASH_BUCKET_ENTRY pEntry;
|
|
|
|
if (NULL == (pEntry = FindOIDHashBucketEntryFromDotOID(pszObjId))) {
|
|
if (NULL == (pEntry = CreateOIDHashBucketEntryFromDotOID(pszObjId)))
|
|
goto CreateOIDHashBucketEntryError;
|
|
pEntry = AddOIDHashBucketEntry(pEntry);
|
|
}
|
|
|
|
pEncodedOid->length = (ASN1uint16_t) pEntry->cbEncodedOID;
|
|
pEncodedOid->value = GetEncodedOIDPointer(pEntry);
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
return fResult;
|
|
ErrorReturn:
|
|
pEncodedOid->length = 0;
|
|
pEncodedOid->value = NULL;
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
TRACE_ERROR(CreateOIDHashBucketEntryError)
|
|
}
|
|
|
|
|
|
static const LPCSTR pszInvalidOID = "";
|
|
|
|
void
|
|
WINAPI
|
|
I_CryptGetEncodedOID(
|
|
IN ASN1encodedOID_t *pEncodedOid,
|
|
IN DWORD dwFlags,
|
|
OUT LPSTR *ppszObjId,
|
|
IN OUT BYTE **ppbExtra,
|
|
IN OUT LONG *plRemainExtra
|
|
)
|
|
{
|
|
POID_HASH_BUCKET_ENTRY pEntry;
|
|
LONG lRemainExtra = *plRemainExtra;
|
|
LPSTR pszDotOID;
|
|
DWORD cchDotOID;
|
|
|
|
if ((dwFlags & CRYPT_DECODE_SHARE_OID_STRING_FLAG) &&
|
|
lRemainExtra < 0)
|
|
// Length only calculation. Don't need any extra bytes.
|
|
return;
|
|
|
|
if (NULL == (pEntry = FindOIDHashBucketEntryFromEncodedOID(pEncodedOid))) {
|
|
if (pEntry = CreateOIDHashBucketEntryFromEncodedOID(pEncodedOid))
|
|
pEntry = AddOIDHashBucketEntry(pEntry);
|
|
}
|
|
|
|
if (pEntry) {
|
|
pszDotOID = GetDotOIDPointer(pEntry);
|
|
cchDotOID = pEntry->cchDotOID + 1;
|
|
} else {
|
|
pszDotOID = (LPSTR) pszInvalidOID;
|
|
cchDotOID = strlen(pszInvalidOID) + 1;
|
|
}
|
|
|
|
if (dwFlags & CRYPT_DECODE_SHARE_OID_STRING_FLAG) {
|
|
assert(lRemainExtra >= 0);
|
|
*ppszObjId = pszDotOID;
|
|
} else {
|
|
LONG lAlignExtra = INFO_LEN_ALIGN(cchDotOID);
|
|
lRemainExtra -= lAlignExtra;
|
|
if (lRemainExtra >= 0) {
|
|
memcpy(*ppbExtra, pszDotOID, cchDotOID);
|
|
*ppszObjId = (LPSTR) *ppbExtra;
|
|
*ppbExtra += lAlignExtra;
|
|
}
|
|
|
|
*plRemainExtra = lRemainExtra;
|
|
}
|
|
}
|