Leaked source code of windows server 2003
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

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: oidconv.cpp
  8. //
  9. // Contents: Object ID (OID) Conv Functions
  10. //
  11. // Functions: I_CryptOIDConvDllMain
  12. // I_CryptSetEncodedOID
  13. // I_CryptGetEncodedOID
  14. //
  15. // Comments:
  16. //
  17. // History: 08_Feb-98 philh created
  18. //--------------------------------------------------------------------------
  19. #include "global.hxx"
  20. #include <dbgdef.h>
  21. // All the *pvInfo extra stuff needs to be aligned
  22. #define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
  23. typedef struct _OID_HASH_BUCKET_ENTRY
  24. OID_HASH_BUCKET_ENTRY, *POID_HASH_BUCKET_ENTRY;
  25. // pbEncodedOID immediately follows the data structure. pszDotOID
  26. // is at pbEncodedOID + cbEncodedOID. pszDotOID is null terminated.
  27. // cchDotOID doesn't include the null terminator.
  28. struct _OID_HASH_BUCKET_ENTRY {
  29. DWORD cbEncodedOID;
  30. DWORD cchDotOID;
  31. POID_HASH_BUCKET_ENTRY pEncodedNext;
  32. POID_HASH_BUCKET_ENTRY pDotNext;
  33. };
  34. static inline BYTE * GetEncodedOIDPointer(
  35. IN POID_HASH_BUCKET_ENTRY pEntry
  36. )
  37. {
  38. return ((BYTE *) pEntry) + sizeof(OID_HASH_BUCKET_ENTRY);
  39. }
  40. static inline LPSTR GetDotOIDPointer(
  41. IN POID_HASH_BUCKET_ENTRY pEntry
  42. )
  43. {
  44. return (LPSTR) (((BYTE *) pEntry) + sizeof(OID_HASH_BUCKET_ENTRY) +
  45. pEntry->cbEncodedOID);
  46. }
  47. // Some prime numbers: 11, 13, 19, 23, 29, 31, 47, 53, 61, 73, 97,
  48. // 101, 127, 251, 509
  49. #define ENCODED_OID_HASH_BUCKET_COUNT 47
  50. #define DOT_OID_HASH_BUCKET_COUNT 31
  51. static POID_HASH_BUCKET_ENTRY
  52. rgpEncodedOIDHashBucket[ENCODED_OID_HASH_BUCKET_COUNT];
  53. static POID_HASH_BUCKET_ENTRY rgpDotOIDHashBucket[DOT_OID_HASH_BUCKET_COUNT];
  54. static CRITICAL_SECTION OIDHashBucketCriticalSection;
  55. static BOOL OIDHashBucketProcessAttach()
  56. {
  57. return Pki_InitializeCriticalSection(&OIDHashBucketCriticalSection);
  58. }
  59. static void OIDHashBucketProcessDetach()
  60. {
  61. DWORD i;
  62. for (i = 0; i < DOT_OID_HASH_BUCKET_COUNT; i++) {
  63. POID_HASH_BUCKET_ENTRY pEntry = rgpDotOIDHashBucket[i];
  64. while (pEntry) {
  65. POID_HASH_BUCKET_ENTRY pFreeEntry = pEntry;
  66. pEntry = pEntry->pDotNext;
  67. PkiFree(pFreeEntry);
  68. }
  69. }
  70. DeleteCriticalSection(&OIDHashBucketCriticalSection);
  71. }
  72. BOOL
  73. WINAPI
  74. I_CryptOIDConvDllMain(
  75. HMODULE hInst,
  76. ULONG ulReason,
  77. LPVOID lpReserved)
  78. {
  79. BOOL fRet = TRUE;
  80. switch (ulReason) {
  81. case DLL_PROCESS_ATTACH:
  82. fRet = OIDHashBucketProcessAttach();
  83. break;
  84. case DLL_PROCESS_DETACH:
  85. OIDHashBucketProcessDetach();
  86. break;
  87. case DLL_THREAD_DETACH:
  88. default:
  89. break;
  90. }
  91. return fRet;
  92. }
  93. extern HCRYPTASN1MODULE hX509Asn1Module; // From wincert.cpp
  94. static inline ASN1encoding_t GetEncoder(void)
  95. {
  96. return I_CryptGetAsn1Encoder(hX509Asn1Module);
  97. }
  98. static inline ASN1decoding_t GetDecoder(void)
  99. {
  100. return I_CryptGetAsn1Decoder(hX509Asn1Module);
  101. }
  102. static DWORD GetOIDHashBucketIndex(
  103. IN DWORD cHashBucket,
  104. IN const BYTE *pb,
  105. IN DWORD cb
  106. )
  107. {
  108. DWORD dwIndex;
  109. dwIndex = 0;
  110. while (cb--) {
  111. if (dwIndex & 0x80000000)
  112. dwIndex = (dwIndex << 1) | 1;
  113. else
  114. dwIndex = dwIndex << 1;
  115. dwIndex += *pb++;
  116. }
  117. return dwIndex % cHashBucket;
  118. }
  119. static POID_HASH_BUCKET_ENTRY FindOIDHashBucketEntryFromEncodedOID(
  120. IN ASN1encodedOID_t *pEncodedOid
  121. )
  122. {
  123. POID_HASH_BUCKET_ENTRY pEntry;
  124. BYTE *pbEncodedOID = pEncodedOid->value;
  125. DWORD cbEncodedOID = pEncodedOid->length;
  126. DWORD dwIndex;
  127. dwIndex = GetOIDHashBucketIndex(
  128. ENCODED_OID_HASH_BUCKET_COUNT,
  129. pbEncodedOID,
  130. cbEncodedOID
  131. );
  132. for (pEntry = rgpEncodedOIDHashBucket[dwIndex]; pEntry;
  133. pEntry = pEntry->pEncodedNext) {
  134. if (cbEncodedOID == pEntry->cbEncodedOID &&
  135. 0 == memcmp(pbEncodedOID, GetEncodedOIDPointer(pEntry),
  136. cbEncodedOID))
  137. return pEntry;
  138. }
  139. return NULL;
  140. }
  141. static POID_HASH_BUCKET_ENTRY FindOIDHashBucketEntryFromDotOID(
  142. IN LPSTR pszDotOID
  143. )
  144. {
  145. POID_HASH_BUCKET_ENTRY pEntry;
  146. DWORD cchDotOID = strlen(pszDotOID);
  147. DWORD dwIndex;
  148. dwIndex = GetOIDHashBucketIndex(
  149. DOT_OID_HASH_BUCKET_COUNT,
  150. (const BYTE *) pszDotOID,
  151. cchDotOID
  152. );
  153. for (pEntry = rgpDotOIDHashBucket[dwIndex]; pEntry;
  154. pEntry = pEntry->pDotNext) {
  155. if (cchDotOID == pEntry->cchDotOID &&
  156. 0 == memcmp(pszDotOID, GetDotOIDPointer(pEntry), cchDotOID))
  157. return pEntry;
  158. }
  159. return NULL;
  160. }
  161. // If after entering the critical section, the entry already exists, then,
  162. // return it and free the input entry. Otherwise, add the input entry and
  163. // return it.
  164. static POID_HASH_BUCKET_ENTRY AddOIDHashBucketEntry(
  165. IN POID_HASH_BUCKET_ENTRY pEntry
  166. )
  167. {
  168. POID_HASH_BUCKET_ENTRY pFindEntry;
  169. ASN1encodedOID_t EncodedOid;
  170. EnterCriticalSection(&OIDHashBucketCriticalSection);
  171. EncodedOid.value = GetEncodedOIDPointer(pEntry);
  172. EncodedOid.length = (ASN1uint16_t) pEntry->cbEncodedOID;
  173. if (pFindEntry = FindOIDHashBucketEntryFromEncodedOID(&EncodedOid)) {
  174. PkiFree(pEntry);
  175. pEntry = pFindEntry;
  176. } else {
  177. DWORD dwIndex;
  178. dwIndex = GetOIDHashBucketIndex(
  179. ENCODED_OID_HASH_BUCKET_COUNT,
  180. GetEncodedOIDPointer(pEntry),
  181. pEntry->cbEncodedOID
  182. );
  183. pEntry->pEncodedNext = rgpEncodedOIDHashBucket[dwIndex];
  184. // Since we do finds outside of CriticalSection, must update
  185. // the following last!!!
  186. rgpEncodedOIDHashBucket[dwIndex] = pEntry;
  187. dwIndex = GetOIDHashBucketIndex(
  188. DOT_OID_HASH_BUCKET_COUNT,
  189. (const BYTE *) GetDotOIDPointer(pEntry),
  190. pEntry->cchDotOID
  191. );
  192. pEntry->pDotNext = rgpDotOIDHashBucket[dwIndex];
  193. // Since we do finds outside of CriticalSection, must update
  194. // the following last!!!
  195. rgpDotOIDHashBucket[dwIndex] = pEntry;
  196. }
  197. LeaveCriticalSection(&OIDHashBucketCriticalSection);
  198. return pEntry;
  199. }
  200. static POID_HASH_BUCKET_ENTRY CreateOIDHashBucketEntry(
  201. IN const BYTE *pbEncodedOID,
  202. IN DWORD cbEncodedOID,
  203. IN LPSTR pszDotOID,
  204. IN DWORD cchDotOID
  205. )
  206. {
  207. POID_HASH_BUCKET_ENTRY pEntry;
  208. DWORD cbEntry;
  209. cbEntry = sizeof(OID_HASH_BUCKET_ENTRY) + cbEncodedOID + cchDotOID + 1;
  210. if (NULL == (pEntry = (POID_HASH_BUCKET_ENTRY) PkiZeroAlloc(cbEntry)))
  211. return NULL;
  212. pEntry->cbEncodedOID = cbEncodedOID;
  213. pEntry->cchDotOID = cchDotOID;
  214. memcpy(GetEncodedOIDPointer(pEntry), pbEncodedOID, cbEncodedOID);
  215. memcpy(GetDotOIDPointer(pEntry), pszDotOID, cchDotOID + 1);
  216. return pEntry;
  217. }
  218. static POID_HASH_BUCKET_ENTRY CreateOIDHashBucketEntryFromEncodedOID(
  219. IN ASN1encodedOID_t *pEncodedOid
  220. )
  221. {
  222. POID_HASH_BUCKET_ENTRY pEntry;
  223. ASN1decoding_t pDec = GetDecoder();
  224. const BYTE *pbEncodedOID; // not allocated
  225. DWORD cbEncodedOID;
  226. LPSTR pszDotOID = NULL;
  227. DWORD cchDotOID;
  228. if (NULL == (pszDotOID = PkiAsn1EncodedOidToDotVal(pDec, pEncodedOid)))
  229. goto EncodedOidToDotValError;
  230. cchDotOID = (DWORD) strlen(pszDotOID);
  231. pbEncodedOID = pEncodedOid->value;
  232. cbEncodedOID = pEncodedOid->length;
  233. pEntry = CreateOIDHashBucketEntry(
  234. pbEncodedOID,
  235. cbEncodedOID,
  236. pszDotOID,
  237. cchDotOID
  238. );
  239. CommonReturn:
  240. PkiAsn1FreeDotVal(pDec, pszDotOID);
  241. return pEntry;
  242. ErrorReturn:
  243. pEntry = NULL;
  244. goto CommonReturn;
  245. TRACE_ERROR(EncodedOidToDotValError)
  246. }
  247. static POID_HASH_BUCKET_ENTRY CreateOIDHashBucketEntryFromDotOID(
  248. IN LPSTR pszDotOID
  249. )
  250. {
  251. POID_HASH_BUCKET_ENTRY pEntry;
  252. ASN1encoding_t pEnc = GetEncoder();
  253. ASN1encodedOID_t EncodedOid;
  254. memset(&EncodedOid, 0, sizeof(EncodedOid));
  255. const BYTE *pbEncodedOID;
  256. DWORD cbEncodedOID;
  257. if (NULL == pszDotOID || '\0' == *pszDotOID)
  258. goto EmptyDotOIDError;
  259. if (!PkiAsn1DotValToEncodedOid(pEnc, pszDotOID, &EncodedOid))
  260. goto DotValToEncodedOidError;
  261. pbEncodedOID = EncodedOid.value;
  262. cbEncodedOID = EncodedOid.length;
  263. pEntry = CreateOIDHashBucketEntry(
  264. pbEncodedOID,
  265. cbEncodedOID,
  266. pszDotOID,
  267. strlen(pszDotOID)
  268. );
  269. CommonReturn:
  270. PkiAsn1FreeEncodedOid(pEnc, &EncodedOid);
  271. return pEntry;
  272. ErrorReturn:
  273. pEntry = NULL;
  274. goto CommonReturn;
  275. SET_ERROR(EmptyDotOIDError, E_INVALIDARG)
  276. SET_ERROR_VAR(DotValToEncodedOidError, PkiAsn1ErrToHr(ASN1_ERR_BADARGS))
  277. }
  278. //+-------------------------------------------------------------------------
  279. // Set/Get Encoded OID
  280. //--------------------------------------------------------------------------
  281. BOOL
  282. WINAPI
  283. I_CryptSetEncodedOID(
  284. IN LPSTR pszObjId,
  285. OUT ASN1encodedOID_t *pEncodedOid
  286. )
  287. {
  288. BOOL fResult;
  289. POID_HASH_BUCKET_ENTRY pEntry;
  290. if (NULL == (pEntry = FindOIDHashBucketEntryFromDotOID(pszObjId))) {
  291. if (NULL == (pEntry = CreateOIDHashBucketEntryFromDotOID(pszObjId)))
  292. goto CreateOIDHashBucketEntryError;
  293. pEntry = AddOIDHashBucketEntry(pEntry);
  294. }
  295. pEncodedOid->length = (ASN1uint16_t) pEntry->cbEncodedOID;
  296. pEncodedOid->value = GetEncodedOIDPointer(pEntry);
  297. fResult = TRUE;
  298. CommonReturn:
  299. return fResult;
  300. ErrorReturn:
  301. pEncodedOid->length = 0;
  302. pEncodedOid->value = NULL;
  303. fResult = FALSE;
  304. goto CommonReturn;
  305. TRACE_ERROR(CreateOIDHashBucketEntryError)
  306. }
  307. static const LPCSTR pszInvalidOID = "";
  308. void
  309. WINAPI
  310. I_CryptGetEncodedOID(
  311. IN ASN1encodedOID_t *pEncodedOid,
  312. IN DWORD dwFlags,
  313. OUT LPSTR *ppszObjId,
  314. IN OUT BYTE **ppbExtra,
  315. IN OUT LONG *plRemainExtra
  316. )
  317. {
  318. POID_HASH_BUCKET_ENTRY pEntry;
  319. LONG lRemainExtra = *plRemainExtra;
  320. LPSTR pszDotOID;
  321. DWORD cchDotOID;
  322. if ((dwFlags & CRYPT_DECODE_SHARE_OID_STRING_FLAG) &&
  323. lRemainExtra < 0)
  324. // Length only calculation. Don't need any extra bytes.
  325. return;
  326. if (NULL == (pEntry = FindOIDHashBucketEntryFromEncodedOID(pEncodedOid))) {
  327. if (pEntry = CreateOIDHashBucketEntryFromEncodedOID(pEncodedOid))
  328. pEntry = AddOIDHashBucketEntry(pEntry);
  329. }
  330. if (pEntry) {
  331. pszDotOID = GetDotOIDPointer(pEntry);
  332. cchDotOID = pEntry->cchDotOID + 1;
  333. } else {
  334. pszDotOID = (LPSTR) pszInvalidOID;
  335. cchDotOID = strlen(pszInvalidOID) + 1;
  336. }
  337. if (dwFlags & CRYPT_DECODE_SHARE_OID_STRING_FLAG) {
  338. assert(lRemainExtra >= 0);
  339. *ppszObjId = pszDotOID;
  340. } else {
  341. LONG lAlignExtra = INFO_LEN_ALIGN(cchDotOID);
  342. lRemainExtra -= lAlignExtra;
  343. if (lRemainExtra >= 0) {
  344. memcpy(*ppbExtra, pszDotOID, cchDotOID);
  345. *ppszObjId = (LPSTR) *ppbExtra;
  346. *ppbExtra += lAlignExtra;
  347. }
  348. *plRemainExtra = lRemainExtra;
  349. }
  350. }