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.

1491 lines
39 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1992 - 1999
  5. //
  6. // File: ekuhlpr.cpp
  7. //
  8. // Contents: Certificate Enhanced Key Usage Helper API implementation
  9. //
  10. // History: 21-May-97 kirtd Created
  11. // xx-xxx-xx reidk Added CertGetValidUsages
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <global.hxx>
  15. #include <dbgdef.h>
  16. //+---------------------------------------------------------------------------
  17. //
  18. // Function: CertGetEnhancedKeyUsage
  19. //
  20. // Synopsis: gets the enhanced key usage extension/property from the
  21. // certificate
  22. //
  23. //----------------------------------------------------------------------------
  24. BOOL WINAPI CertGetEnhancedKeyUsage (
  25. IN PCCERT_CONTEXT pCertContext,
  26. IN DWORD dwFlags,
  27. OUT PCERT_ENHKEY_USAGE pUsage,
  28. IN OUT DWORD* pcbUsage
  29. )
  30. {
  31. HRESULT hr = S_OK;
  32. CRYPT_OBJID_BLOB cob;
  33. BOOL fExtCertPolicies = FALSE;
  34. PCRYPT_OBJID_BLOB pExtBlob = NULL;
  35. PCRYPT_OBJID_BLOB pPropBlob = NULL;
  36. //
  37. // If the flags are zero then assume they want everything
  38. //
  39. if ( dwFlags == 0 )
  40. {
  41. dwFlags = CERT_FIND_ALL_ENHKEY_USAGE_FLAG;
  42. }
  43. //
  44. // Validate the parameters
  45. //
  46. if ( ( ( dwFlags & CERT_FIND_ALL_ENHKEY_USAGE_FLAG ) == 0 ) ||
  47. ( pCertContext == NULL ) || ( pcbUsage == NULL ) )
  48. {
  49. SetLastError((DWORD) ERROR_INVALID_PARAMETER);
  50. return( FALSE );
  51. }
  52. //
  53. // If they want everything, call CertGetValidUsages
  54. //
  55. if ( dwFlags == CERT_FIND_ALL_ENHKEY_USAGE_FLAG )
  56. {
  57. return( EkuGetIntersectedUsageViaGetValidUsages(
  58. pCertContext,
  59. pcbUsage,
  60. pUsage
  61. ) );
  62. }
  63. //
  64. // If they want extensions get the extension blob, if they want
  65. // properties get the property blob
  66. //
  67. if ( dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG )
  68. {
  69. pExtBlob = EkuGetExtension(pCertContext, &fExtCertPolicies);
  70. }
  71. if ( dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG )
  72. {
  73. hr = EkuGetProperty(pCertContext, &cob);
  74. if ( hr == S_OK )
  75. {
  76. pPropBlob = &cob;
  77. }
  78. }
  79. //
  80. // Make sure that at least something was found and that what has occurred
  81. // is correctly indicated
  82. //
  83. if ( ( pExtBlob == NULL ) && ( pPropBlob == NULL ) )
  84. {
  85. if ( hr == S_OK )
  86. {
  87. hr = CRYPT_E_NOT_FOUND;
  88. }
  89. }
  90. else
  91. {
  92. hr = S_OK;
  93. }
  94. //
  95. // If all they wanted was the size, give it to them, otherwise, we
  96. // need to decode and give the caller what they requested
  97. //
  98. if ( hr == S_OK )
  99. {
  100. if ( pUsage == NULL )
  101. {
  102. DWORD cbSize = 0;
  103. DWORD cbExtSize = 0;
  104. DWORD cbPropSize = 0;
  105. hr = EkuGetDecodedUsageSizes(
  106. fExtCertPolicies,
  107. pExtBlob,
  108. pPropBlob,
  109. &cbSize,
  110. &cbExtSize,
  111. &cbPropSize
  112. );
  113. if ( hr == S_OK )
  114. {
  115. if ( cbSize > 0 )
  116. {
  117. *pcbUsage = cbSize;
  118. }
  119. else
  120. {
  121. // Need better last error code
  122. hr = E_INVALIDARG;
  123. }
  124. }
  125. }
  126. else
  127. {
  128. hr = EkuGetMergedDecodedUsage(
  129. fExtCertPolicies,
  130. pExtBlob,
  131. pPropBlob,
  132. pcbUsage,
  133. pUsage
  134. );
  135. }
  136. }
  137. //
  138. // Cleanup and return
  139. //
  140. if ( pPropBlob != NULL )
  141. {
  142. delete pPropBlob->pbData;
  143. }
  144. if ( hr != S_OK )
  145. {
  146. SetLastError(hr);
  147. return( FALSE );
  148. }
  149. return( TRUE );
  150. }
  151. //+---------------------------------------------------------------------------
  152. //
  153. // Function: CertSetEnhancedKeyUsage
  154. //
  155. // Synopsis: sets the enhanced key usage property on the certificate
  156. //
  157. //----------------------------------------------------------------------------
  158. BOOL WINAPI CertSetEnhancedKeyUsage (
  159. IN PCCERT_CONTEXT pCertContext,
  160. IN PCERT_ENHKEY_USAGE pUsage
  161. )
  162. {
  163. HRESULT hr;
  164. CRYPT_OBJID_BLOB EkuBlob;
  165. //
  166. // if pUsage is NULL, then just set the NULL property
  167. //
  168. if (pUsage == NULL)
  169. {
  170. hr = EkuSetProperty(pCertContext, NULL);
  171. }
  172. else
  173. {
  174. //
  175. // Encode the usage and set the property
  176. //
  177. hr = EkuEncodeUsage(pUsage, &EkuBlob);
  178. if ( hr == S_OK )
  179. {
  180. hr = EkuSetProperty(pCertContext, &EkuBlob);
  181. delete EkuBlob.pbData;
  182. }
  183. }
  184. if ( hr != S_OK )
  185. {
  186. SetLastError(hr);
  187. return( FALSE );
  188. }
  189. return( TRUE );
  190. }
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Function: CertAddEnhancedKeyUsageIdentifier
  194. //
  195. // Synopsis: adds a key usage identifier to the enhanced key usage property
  196. // on the certificate
  197. //
  198. //----------------------------------------------------------------------------
  199. BOOL WINAPI CertAddEnhancedKeyUsageIdentifier (
  200. IN PCCERT_CONTEXT pCertContext,
  201. IN LPCSTR pszUsageIdentifier
  202. )
  203. {
  204. HRESULT hr;
  205. DWORD cbUsage1 = 0;
  206. DWORD cbUsage2 = 0;
  207. DWORD cbUsageM = 0;
  208. DWORD cId;
  209. PCERT_ENHKEY_USAGE pUsage1 = NULL;
  210. PCERT_ENHKEY_USAGE pUsage2 = NULL;
  211. PCERT_ENHKEY_USAGE pUsageM = NULL;
  212. //
  213. // Create a one element, properly "encoded" (see EkuMergeUsage) enhanced
  214. // key usage structure
  215. //
  216. cId = strlen(pszUsageIdentifier)+1;
  217. cbUsage1 = sizeof(CERT_ENHKEY_USAGE)+sizeof(LPSTR)+cId;
  218. pUsage1 = (PCERT_ENHKEY_USAGE)new BYTE [cbUsage1];
  219. if ( pUsage1 == NULL )
  220. {
  221. SetLastError((DWORD) E_OUTOFMEMORY);
  222. return( FALSE );
  223. }
  224. pUsage1->cUsageIdentifier = 1;
  225. pUsage1->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage1+sizeof(CERT_ENHKEY_USAGE));
  226. pUsage1->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)pUsage1->rgpszUsageIdentifier+sizeof(LPSTR));
  227. strcpy(pUsage1->rgpszUsageIdentifier[0], pszUsageIdentifier);
  228. //
  229. // Get the current enhanced key usage properties and get an appropriately
  230. // sized block for the merged data unless there are no current usage
  231. // properties in which case we just set the one we have now
  232. //
  233. hr = EkuGetUsage(
  234. pCertContext,
  235. CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
  236. &cbUsage2,
  237. &pUsage2
  238. );
  239. if ( hr == S_OK )
  240. {
  241. cbUsageM = cbUsage1 + cbUsage2;
  242. pUsageM = (PCERT_ENHKEY_USAGE)new BYTE [cbUsageM];
  243. if ( pUsageM == NULL )
  244. {
  245. hr = E_OUTOFMEMORY;
  246. }
  247. }
  248. else if ( hr == CRYPT_E_NOT_FOUND )
  249. {
  250. BOOL fReturn;
  251. fReturn = CertSetEnhancedKeyUsage(pCertContext, pUsage1);
  252. delete pUsage1;
  253. return( fReturn );
  254. }
  255. else
  256. {
  257. SetLastError(hr);
  258. return( FALSE );
  259. }
  260. //
  261. // Merge the usage structures and set the properties
  262. //
  263. hr = EkuMergeUsage(cbUsage1, pUsage1, cbUsage2, pUsage2, cbUsageM, pUsageM);
  264. if ( hr == S_OK )
  265. {
  266. if ( CertSetEnhancedKeyUsage(pCertContext, pUsageM) == FALSE )
  267. {
  268. hr = GetLastError();
  269. }
  270. }
  271. //
  272. // Cleanup
  273. //
  274. delete pUsage1;
  275. delete pUsage2;
  276. delete pUsageM;
  277. if ( hr != S_OK )
  278. {
  279. SetLastError(hr);
  280. return( FALSE );
  281. }
  282. return( TRUE );
  283. }
  284. //+---------------------------------------------------------------------------
  285. //
  286. // Function: CertRemoveEnhancedKeyUsageIdentifier
  287. //
  288. // Synopsis: removes a key usage identifier from the enhanced key usage
  289. // property on the certificate
  290. //
  291. //----------------------------------------------------------------------------
  292. BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier (
  293. IN PCCERT_CONTEXT pCertContext,
  294. IN LPCSTR pszUsageIdentifier
  295. )
  296. {
  297. HRESULT hr;
  298. DWORD cFound = 0;
  299. DWORD cCount;
  300. PCERT_ENHKEY_USAGE pUsage;
  301. LPSTR* apsz;
  302. //
  303. // Get the current usage properties
  304. //
  305. hr = EkuGetUsage(
  306. pCertContext,
  307. CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
  308. NULL,
  309. &pUsage
  310. );
  311. if ( hr != S_OK )
  312. {
  313. SetLastError(hr);
  314. return( FALSE );
  315. }
  316. //
  317. // Loop through the usage identifiers and remove ones that match
  318. // the passed in id
  319. //
  320. apsz = pUsage->rgpszUsageIdentifier;
  321. for (cCount = 0; cCount < pUsage->cUsageIdentifier; cCount++)
  322. {
  323. if ( strcmp(apsz[cCount], pszUsageIdentifier) == 0 )
  324. {
  325. cFound++;
  326. }
  327. else if ( cFound > 0 )
  328. {
  329. apsz[cCount-cFound] = apsz[cCount];
  330. }
  331. }
  332. //
  333. // If we removed any, update the usage id count and set the new property
  334. //
  335. if ( cFound > 0 )
  336. {
  337. pUsage->cUsageIdentifier -= cFound;
  338. if ( pUsage->cUsageIdentifier == 0 )
  339. {
  340. // Delete the property if we are down to zero
  341. hr = EkuSetProperty(pCertContext, NULL);
  342. }
  343. else if ( CertSetEnhancedKeyUsage(pCertContext, pUsage) == FALSE )
  344. {
  345. hr = GetLastError();
  346. }
  347. }
  348. //
  349. // Cleanup
  350. //
  351. delete pUsage;
  352. if ( hr != S_OK )
  353. {
  354. SetLastError(hr);
  355. return( FALSE );
  356. }
  357. return( TRUE );
  358. }
  359. //+---------------------------------------------------------------------------
  360. //
  361. // Function: EkuGetExtension
  362. //
  363. // Synopsis: gets the application cert policies or enhanced key usage
  364. // extension blob from the certificate
  365. //
  366. // *pfAppCertPolicies is set to TRUE for an
  367. // szOID_APPLICATION_CERT_POLICIES extension.
  368. //
  369. //----------------------------------------------------------------------------
  370. PCRYPT_OBJID_BLOB EkuGetExtension (
  371. PCCERT_CONTEXT pCertContext,
  372. BOOL *pfAppCertPolicies
  373. )
  374. {
  375. PCERT_EXTENSION pExtension;
  376. //
  377. // Get the application cert policies or enhanced key usage extension
  378. // from the certificate and if we couldn't find either
  379. // extension return NULL otherwise, return
  380. // the appropriate field of the found extension
  381. //
  382. pExtension = CertFindExtension(
  383. szOID_APPLICATION_CERT_POLICIES,
  384. pCertContext->pCertInfo->cExtension,
  385. pCertContext->pCertInfo->rgExtension
  386. );
  387. if ( pExtension )
  388. {
  389. *pfAppCertPolicies = TRUE;
  390. }
  391. else
  392. {
  393. *pfAppCertPolicies = FALSE;
  394. pExtension = CertFindExtension(
  395. szOID_ENHANCED_KEY_USAGE,
  396. pCertContext->pCertInfo->cExtension,
  397. pCertContext->pCertInfo->rgExtension
  398. );
  399. if ( pExtension == NULL )
  400. {
  401. return( NULL );
  402. }
  403. }
  404. return( &pExtension->Value );
  405. }
  406. //+---------------------------------------------------------------------------
  407. //
  408. // Function: EkuGetProperty
  409. //
  410. // Synopsis: gets the enhanced key usage property from the certificate
  411. //
  412. //----------------------------------------------------------------------------
  413. HRESULT EkuGetProperty (
  414. PCCERT_CONTEXT pCertContext,
  415. PCRYPT_OBJID_BLOB pEkuBlob
  416. )
  417. {
  418. DWORD cb;
  419. if ( CertGetCertificateContextProperty(
  420. pCertContext,
  421. CERT_ENHKEY_USAGE_PROP_ID,
  422. NULL,
  423. &cb
  424. ) == FALSE )
  425. {
  426. return( GetLastError() );
  427. }
  428. pEkuBlob->cbData = cb;
  429. pEkuBlob->pbData = new BYTE [cb];
  430. if ( pEkuBlob->pbData == NULL )
  431. {
  432. return( E_OUTOFMEMORY );
  433. }
  434. if ( CertGetCertificateContextProperty(
  435. pCertContext,
  436. CERT_ENHKEY_USAGE_PROP_ID,
  437. pEkuBlob->pbData,
  438. &cb
  439. ) == FALSE )
  440. {
  441. return( GetLastError() );
  442. }
  443. return( S_OK );
  444. }
  445. //+---------------------------------------------------------------------------
  446. //
  447. // Function: EkuSetProperty
  448. //
  449. // Synopsis: sets an enhanced key usage property on the certificate
  450. //
  451. //----------------------------------------------------------------------------
  452. HRESULT EkuSetProperty (
  453. PCCERT_CONTEXT pCertContext,
  454. PCRYPT_OBJID_BLOB pEkuBlob
  455. )
  456. {
  457. if ( CertSetCertificateContextProperty(
  458. pCertContext,
  459. CERT_ENHKEY_USAGE_PROP_ID,
  460. 0,
  461. pEkuBlob
  462. ) == FALSE )
  463. {
  464. return( GetLastError() );
  465. }
  466. return( S_OK );
  467. }
  468. //+---------------------------------------------------------------------------
  469. //
  470. // Function: EkuDecodeCertPoliciesAndConvertToUsage
  471. //
  472. // Synopsis: decodes an encoded cert policies and converts to enhanced
  473. // key usage
  474. //
  475. //----------------------------------------------------------------------------
  476. HRESULT EkuDecodeCertPoliciesAndConvertToUsage (
  477. PCRYPT_OBJID_BLOB pEkuBlob,
  478. DWORD* pcbSize,
  479. PCERT_ENHKEY_USAGE pUsage // OPTIONAL
  480. )
  481. {
  482. HRESULT hr = S_OK;
  483. DWORD cbCertPolicies = 0;
  484. PCERT_POLICIES_INFO pCertPolicies = NULL;
  485. DWORD cbSize = 0;
  486. if ( !CryptDecodeObject(
  487. X509_ASN_ENCODING,
  488. X509_CERT_POLICIES,
  489. pEkuBlob->pbData,
  490. pEkuBlob->cbData,
  491. CRYPT_DECODE_NOCOPY_FLAG |
  492. CRYPT_DECODE_SHARE_OID_STRING_FLAG |
  493. CRYPT_DECODE_ALLOC_FLAG,
  494. (void *) &pCertPolicies,
  495. &cbCertPolicies
  496. ))
  497. {
  498. hr = GetLastError();
  499. }
  500. else
  501. {
  502. // Convert policies OIDs to EKU OIDs
  503. LONG lRemainExtra;
  504. DWORD cOID;
  505. LPSTR *ppszOID;
  506. LPSTR pszOID;
  507. PCERT_POLICY_INFO pPolicy;
  508. cOID = pCertPolicies->cPolicyInfo;
  509. pPolicy = pCertPolicies->rgPolicyInfo;
  510. if ( pUsage )
  511. {
  512. cbSize = *pcbSize;
  513. }
  514. lRemainExtra = cbSize - sizeof(CERT_ENHKEY_USAGE) -
  515. sizeof(LPSTR) * cOID;
  516. if ( lRemainExtra < 0 )
  517. {
  518. ppszOID = NULL;
  519. pszOID = NULL;
  520. }
  521. else
  522. {
  523. ppszOID = (LPSTR *) &pUsage[1];
  524. pszOID = (LPSTR) &ppszOID[cOID];
  525. pUsage->cUsageIdentifier = cOID;
  526. pUsage->rgpszUsageIdentifier = ppszOID;
  527. }
  528. for ( ; cOID > 0; cOID--, ppszOID++, pPolicy++ )
  529. {
  530. DWORD cchOID;
  531. cchOID = strlen(pPolicy->pszPolicyIdentifier) + 1;
  532. lRemainExtra -= cchOID;
  533. if ( lRemainExtra >= 0 )
  534. {
  535. *ppszOID = pszOID;
  536. memcpy(pszOID, pPolicy->pszPolicyIdentifier, cchOID);
  537. pszOID += cchOID;
  538. }
  539. }
  540. if ( lRemainExtra >= 0)
  541. {
  542. cbSize -= (DWORD) lRemainExtra;
  543. }
  544. else
  545. {
  546. cbSize += (DWORD) -lRemainExtra;
  547. if ( pUsage )
  548. {
  549. hr = ERROR_MORE_DATA;
  550. }
  551. }
  552. }
  553. if ( pCertPolicies )
  554. {
  555. LocalFree( pCertPolicies );
  556. }
  557. *pcbSize = cbSize;
  558. return( hr );
  559. }
  560. //+---------------------------------------------------------------------------
  561. //
  562. // Function: EkuGetDecodedSize
  563. //
  564. // Synopsis: gets the decoded size of the enhanced key usage blob
  565. //
  566. //----------------------------------------------------------------------------
  567. HRESULT EkuGetDecodedSize (
  568. PCRYPT_OBJID_BLOB pEkuBlob,
  569. DWORD* pcbSize
  570. )
  571. {
  572. if ( CryptDecodeObject(
  573. X509_ASN_ENCODING,
  574. szOID_ENHANCED_KEY_USAGE,
  575. pEkuBlob->pbData,
  576. pEkuBlob->cbData,
  577. 0,
  578. NULL,
  579. pcbSize
  580. ) == FALSE )
  581. {
  582. return( GetLastError() );
  583. }
  584. return( S_OK );
  585. }
  586. //+---------------------------------------------------------------------------
  587. //
  588. // Function: EkuGetDecodedUsageSizes
  589. //
  590. // Synopsis: gets the decoded sizes for enhanced key usage blobs from the
  591. // certificate extension and/or the certificate context property
  592. //
  593. //----------------------------------------------------------------------------
  594. HRESULT EkuGetDecodedUsageSizes (
  595. BOOL fExtCertPolicies,
  596. PCRYPT_OBJID_BLOB pExtBlob,
  597. PCRYPT_OBJID_BLOB pPropBlob,
  598. DWORD* pcbSize,
  599. DWORD* pcbExtSize,
  600. DWORD* pcbPropSize
  601. )
  602. {
  603. HRESULT hr = S_OK;
  604. DWORD cbExtSize = 0;
  605. DWORD cbPropSize = 0;
  606. //
  607. // Get the appropriate decoded size based on what was requested
  608. //
  609. if ( pExtBlob != NULL )
  610. {
  611. if ( fExtCertPolicies )
  612. {
  613. hr = EkuDecodeCertPoliciesAndConvertToUsage(
  614. pExtBlob, &cbExtSize, NULL);
  615. }
  616. else
  617. {
  618. hr = EkuGetDecodedSize(pExtBlob, &cbExtSize);
  619. }
  620. }
  621. if ( ( hr == S_OK ) && ( pPropBlob != NULL ) )
  622. {
  623. hr = EkuGetDecodedSize(pPropBlob, &cbPropSize);
  624. }
  625. //
  626. // Collect into the out parameters
  627. //
  628. if ( hr == S_OK )
  629. {
  630. *pcbExtSize = cbExtSize;
  631. *pcbPropSize = cbPropSize;
  632. *pcbSize = cbExtSize + cbPropSize;
  633. }
  634. return( hr );
  635. }
  636. //+---------------------------------------------------------------------------
  637. //
  638. // Function: EkuGetDecodedUsage
  639. //
  640. // Synopsis: gets the decoded enhanced key usage from the encoded blob
  641. //
  642. //----------------------------------------------------------------------------
  643. HRESULT EkuGetDecodedUsage (
  644. PCRYPT_OBJID_BLOB pEkuBlob,
  645. DWORD* pcbSize,
  646. PCERT_ENHKEY_USAGE pUsage
  647. )
  648. {
  649. if ( CryptDecodeObject(
  650. X509_ASN_ENCODING,
  651. szOID_ENHANCED_KEY_USAGE,
  652. pEkuBlob->pbData,
  653. pEkuBlob->cbData,
  654. 0,
  655. pUsage,
  656. pcbSize
  657. ) == FALSE )
  658. {
  659. return( GetLastError() );
  660. }
  661. return( S_OK );
  662. }
  663. //+---------------------------------------------------------------------------
  664. //
  665. // Function: EkuMergeUsage
  666. //
  667. // Synopsis: merges enhanced key usage structures
  668. //
  669. // NOTE: The structures are assumed to be in single allocated
  670. // block form where the string pointers point back into
  671. // the bottom part of the allocated block where the
  672. // have been placed
  673. //
  674. //----------------------------------------------------------------------------
  675. HRESULT EkuMergeUsage (
  676. DWORD cbSize1,
  677. PCERT_ENHKEY_USAGE pUsage1,
  678. DWORD cbSize2,
  679. PCERT_ENHKEY_USAGE pUsage2,
  680. DWORD cbSizeM,
  681. PCERT_ENHKEY_USAGE pUsageM
  682. )
  683. {
  684. DWORD cUsage1;
  685. DWORD cUsage2;
  686. DWORD cUsageM;
  687. DWORD cbOids1;
  688. DWORD cbOids2;
  689. DWORD cbUsage1;
  690. DWORD cbUsage2;
  691. DWORD cCount;
  692. DWORD cbOffset;
  693. LPSTR* apsz1;
  694. LPSTR* apsz2;
  695. LPSTR* apszM;
  696. //
  697. // Copy the data from the source to the destination
  698. //
  699. cUsage1 = pUsage1->cUsageIdentifier;
  700. cUsage2 = pUsage2->cUsageIdentifier;
  701. cUsageM = cUsage1 + cUsage2;
  702. cbUsage1 = ( cUsage1 * sizeof(LPSTR) ) + sizeof(CERT_ENHKEY_USAGE);
  703. cbUsage2 = ( cUsage2 * sizeof(LPSTR) ) + sizeof(CERT_ENHKEY_USAGE);
  704. apsz1 = pUsage1->rgpszUsageIdentifier;
  705. apsz2 = pUsage2->rgpszUsageIdentifier;
  706. apszM = (LPSTR *)((LPBYTE)pUsageM+sizeof(CERT_ENHKEY_USAGE));
  707. pUsageM->cUsageIdentifier = cUsageM;
  708. pUsageM->rgpszUsageIdentifier = apszM;
  709. memcpy(apszM, apsz1, cUsage1*sizeof(LPSTR));
  710. memcpy(&apszM[cUsage1], apsz2, cUsage2*sizeof(LPSTR));
  711. cbOids1 = cbSize1 - cbUsage1;
  712. cbOids2 = cbSize2 - cbUsage2;
  713. memcpy(&apszM[cUsageM], &apsz1[cUsage1], cbOids1);
  714. memcpy(
  715. (LPBYTE)(&apszM[cUsageM])+cbOids1,
  716. &apsz2[cUsage2],
  717. cbOids2
  718. );
  719. //
  720. // Fix up the pointers
  721. //
  722. for ( cCount = 0; cCount < cUsage1; cCount++)
  723. {
  724. cbOffset = (DWORD)((LPBYTE)(apsz1[cCount]) - (LPBYTE)apsz1) + cbUsage2;
  725. apszM[cCount] = (LPSTR)((LPBYTE)pUsageM+cbOffset);
  726. }
  727. for ( cCount = 0; cCount < cUsage2; cCount++ )
  728. {
  729. cbOffset = (DWORD)((LPBYTE)(apsz2[cCount]) - (LPBYTE)apsz2) + cbUsage1 + cbOids1;
  730. apszM[cCount+cUsage1] = (LPSTR)((LPBYTE)pUsageM+cbOffset);
  731. }
  732. return( S_OK );
  733. }
  734. //+---------------------------------------------------------------------------
  735. //
  736. // Function: EkuGetMergedDecodedUsage
  737. //
  738. // Synopsis: gets merged decoded enhanced key usage from the certificate
  739. // extension and the certificate properties
  740. //
  741. //----------------------------------------------------------------------------
  742. HRESULT EkuGetMergedDecodedUsage (
  743. BOOL fExtCertPolicies,
  744. PCRYPT_OBJID_BLOB pExtBlob,
  745. PCRYPT_OBJID_BLOB pPropBlob,
  746. DWORD* pcbSize,
  747. PCERT_ENHKEY_USAGE pUsage
  748. )
  749. {
  750. HRESULT hr;
  751. DWORD cbExtSize = 0;
  752. DWORD cbPropSize = 0;
  753. DWORD cbMergedSize = 0;
  754. PCERT_ENHKEY_USAGE pExtUsage = NULL;
  755. PCERT_ENHKEY_USAGE pPropUsage = NULL;
  756. //
  757. // If either the extension or the properties are NULL, we just need
  758. // to get the other one
  759. //
  760. if ( pExtBlob == NULL )
  761. {
  762. return( EkuGetDecodedUsage(pPropBlob, pcbSize, pUsage) );
  763. }
  764. else if ( pPropBlob == NULL )
  765. {
  766. if ( fExtCertPolicies )
  767. {
  768. return( EkuDecodeCertPoliciesAndConvertToUsage(
  769. pExtBlob, pcbSize, pUsage) );
  770. }
  771. else
  772. {
  773. return( EkuGetDecodedUsage(pExtBlob, pcbSize, pUsage) );
  774. }
  775. }
  776. //
  777. // Get the sizes we will need to allocate for decoding and validate
  778. // the total against what was passed in
  779. //
  780. hr = EkuGetDecodedUsageSizes(
  781. fExtCertPolicies,
  782. pExtBlob,
  783. pPropBlob,
  784. &cbMergedSize,
  785. &cbExtSize,
  786. &cbPropSize
  787. );
  788. if ( hr != S_OK )
  789. {
  790. return( hr );
  791. }
  792. else if ( *pcbSize < cbMergedSize )
  793. {
  794. *pcbSize = cbMergedSize;
  795. return( ERROR_MORE_DATA );
  796. }
  797. //
  798. // Allocate the enhanced key usage structures and decode into them
  799. //
  800. pExtUsage = (PCERT_ENHKEY_USAGE)new BYTE [cbExtSize];
  801. pPropUsage = (PCERT_ENHKEY_USAGE)new BYTE [cbPropSize];
  802. if ( ( pExtUsage == NULL ) || ( pPropUsage == NULL ) )
  803. {
  804. delete pExtUsage;
  805. delete pPropUsage;
  806. return( E_OUTOFMEMORY );
  807. }
  808. if ( fExtCertPolicies )
  809. {
  810. hr = EkuDecodeCertPoliciesAndConvertToUsage(
  811. pExtBlob, &cbExtSize, pExtUsage);
  812. }
  813. else
  814. {
  815. hr = EkuGetDecodedUsage(pExtBlob, &cbExtSize, pExtUsage);
  816. }
  817. if ( hr == S_OK )
  818. {
  819. hr = EkuGetDecodedUsage(pPropBlob, &cbPropSize, pPropUsage);
  820. }
  821. //
  822. // Merge the usage structures
  823. //
  824. if ( hr == S_OK )
  825. {
  826. hr = EkuMergeUsage(
  827. cbExtSize,
  828. pExtUsage,
  829. cbPropSize,
  830. pPropUsage,
  831. *pcbSize,
  832. pUsage
  833. );
  834. }
  835. //
  836. // Cleanup
  837. //
  838. delete pExtUsage;
  839. delete pPropUsage;
  840. return( hr );
  841. }
  842. //+---------------------------------------------------------------------------
  843. //
  844. // Function: EkuEncodeUsage
  845. //
  846. // Synopsis: encodes the enhanced key usage into a blob useful for setting
  847. // as a certificate property
  848. //
  849. //----------------------------------------------------------------------------
  850. HRESULT EkuEncodeUsage (
  851. PCERT_ENHKEY_USAGE pUsage,
  852. PCRYPT_OBJID_BLOB pEkuBlob
  853. )
  854. {
  855. HRESULT hr = S_OK;
  856. DWORD cbData = 0;
  857. LPBYTE pbData;
  858. if ( CryptEncodeObject(
  859. X509_ASN_ENCODING,
  860. szOID_ENHANCED_KEY_USAGE,
  861. pUsage,
  862. NULL,
  863. &cbData
  864. ) == FALSE )
  865. {
  866. return( GetLastError() );
  867. }
  868. pbData = new BYTE [cbData];
  869. if ( pbData != NULL )
  870. {
  871. if ( CryptEncodeObject(
  872. X509_ASN_ENCODING,
  873. szOID_ENHANCED_KEY_USAGE,
  874. pUsage,
  875. pbData,
  876. &cbData
  877. ) == FALSE )
  878. {
  879. hr = GetLastError();
  880. }
  881. }
  882. else
  883. {
  884. hr = E_OUTOFMEMORY;
  885. }
  886. if ( hr == S_OK )
  887. {
  888. pEkuBlob->cbData = cbData;
  889. pEkuBlob->pbData = pbData;
  890. }
  891. else
  892. {
  893. delete pbData;
  894. }
  895. return( hr );
  896. }
  897. //+---------------------------------------------------------------------------
  898. //
  899. // Function: EkuGetUsage
  900. //
  901. // Synopsis: gets the usage based on the flags with CertGetEnhancedKeyUsage
  902. //
  903. //----------------------------------------------------------------------------
  904. HRESULT EkuGetUsage (
  905. PCCERT_CONTEXT pCertContext,
  906. DWORD dwFlags,
  907. DWORD* pcbSize,
  908. PCERT_ENHKEY_USAGE* ppUsage
  909. )
  910. {
  911. DWORD cbSize;
  912. PCERT_ENHKEY_USAGE pUsage;
  913. //
  914. // Get an appropriately sized block to hold the usage
  915. //
  916. if ( CertGetEnhancedKeyUsage(
  917. pCertContext,
  918. dwFlags,
  919. NULL,
  920. &cbSize
  921. ) == FALSE )
  922. {
  923. return( GetLastError() );
  924. }
  925. pUsage = (PCERT_ENHKEY_USAGE)new BYTE [cbSize];
  926. if ( pUsage == NULL )
  927. {
  928. return( E_OUTOFMEMORY );
  929. }
  930. //
  931. // Now get the enhanced key usage data and fill in the out parameters
  932. //
  933. if ( CertGetEnhancedKeyUsage(
  934. pCertContext,
  935. dwFlags,
  936. pUsage,
  937. &cbSize
  938. ) == FALSE )
  939. {
  940. delete pUsage;
  941. return( GetLastError() );
  942. }
  943. if ( pcbSize != NULL )
  944. {
  945. *pcbSize = cbSize;
  946. }
  947. *ppUsage = pUsage;
  948. return( S_OK );
  949. }
  950. //////////////////////////////////////////////////////////////////////////////////////
  951. //
  952. //////////////////////////////////////////////////////////////////////////////////////
  953. static BOOL OIDInUsages(PCERT_ENHKEY_USAGE pUsage, LPCSTR pszOID)
  954. {
  955. DWORD i;
  956. // check every extension
  957. for(i=0; i<pUsage->cUsageIdentifier; i++)
  958. {
  959. if(!strcmp(pUsage->rgpszUsageIdentifier[i], pszOID))
  960. break;
  961. }
  962. return (i < pUsage->cUsageIdentifier);
  963. }
  964. //////////////////////////////////////////////////////////////////////////////////////
  965. //
  966. //////////////////////////////////////////////////////////////////////////////////////
  967. static BOOL OIDExistsInArray(LPSTR *rghPropOIDs, DWORD cPropOIDs, LPSTR pszOID)
  968. {
  969. DWORD i;
  970. // check every extension
  971. for(i=0; i<cPropOIDs; i++)
  972. {
  973. if(!strcmp(rghPropOIDs[i], pszOID))
  974. break;
  975. }
  976. return (i < cPropOIDs);
  977. }
  978. //////////////////////////////////////////////////////////////////////////////////////
  979. //
  980. //////////////////////////////////////////////////////////////////////////////////////
  981. static LPSTR AllocAndCopyStr(LPSTR psz)
  982. {
  983. LPSTR pszNew;
  984. pszNew = (LPSTR) new BYTE[strlen(psz)+1];
  985. if (pszNew == NULL)
  986. {
  987. SetLastError((DWORD) E_OUTOFMEMORY);
  988. return NULL;
  989. }
  990. strcpy(pszNew, psz);
  991. return (pszNew);
  992. }
  993. //////////////////////////////////////////////////////////////////////////////////////
  994. //
  995. //////////////////////////////////////////////////////////////////////////////////////
  996. static void IntersectUsages(DWORD *pcExtOIDs, LPSTR *rghExtOIDs, PCERT_ENHKEY_USAGE pUsageExt)
  997. {
  998. DWORD i;
  999. DWORD dwNumOIDs;
  1000. dwNumOIDs = *pcExtOIDs;
  1001. *pcExtOIDs = 0;
  1002. for (i=0; i<dwNumOIDs; i++)
  1003. {
  1004. if (OIDInUsages(pUsageExt, rghExtOIDs[i]))
  1005. {
  1006. if (*pcExtOIDs != i)
  1007. {
  1008. rghExtOIDs[*pcExtOIDs] = rghExtOIDs[i];
  1009. rghExtOIDs[i] = NULL;
  1010. }
  1011. (*pcExtOIDs)++;
  1012. }
  1013. else
  1014. {
  1015. delete(rghExtOIDs[i]);
  1016. rghExtOIDs[i] = NULL;
  1017. }
  1018. }
  1019. }
  1020. //////////////////////////////////////////////////////////////////////////////////////
  1021. //
  1022. //////////////////////////////////////////////////////////////////////////////////////
  1023. static BOOL ProcessCertForEKU(
  1024. PCCERT_CONTEXT pCert,
  1025. BOOL *pfAllProp,
  1026. DWORD *pcPropOIDs,
  1027. LPSTR *rghPropOIDs,
  1028. BOOL *pfAllExt,
  1029. DWORD *pcExtOIDs,
  1030. LPSTR *rghExtOIDs)
  1031. {
  1032. BOOL fRet = TRUE;
  1033. PCERT_ENHKEY_USAGE pExtUsage = NULL;
  1034. PCERT_ENHKEY_USAGE pPropUsage = NULL;
  1035. DWORD i;
  1036. EkuGetUsage(pCert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &pExtUsage);
  1037. EkuGetUsage(pCert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &pPropUsage);
  1038. //
  1039. // if there are EKU extensions then we are limited to that set of EKUs at the maximum
  1040. //
  1041. if (pExtUsage != NULL)
  1042. {
  1043. //
  1044. // if this is the first cert with extensions then just copy all the EKUs,
  1045. // otherwise take the intersection of the current certs EKUs and the intersection
  1046. // of all the previous certs EKUs
  1047. //
  1048. if (*pfAllExt == TRUE)
  1049. {
  1050. *pfAllExt = FALSE;
  1051. for (i=0; i<pExtUsage->cUsageIdentifier; i++)
  1052. {
  1053. rghExtOIDs[i] = AllocAndCopyStr(pExtUsage->rgpszUsageIdentifier[i]);
  1054. if (rghExtOIDs[i] == NULL)
  1055. {
  1056. goto ErrorCleanUp;
  1057. }
  1058. (*pcExtOIDs)++;
  1059. }
  1060. }
  1061. else
  1062. {
  1063. IntersectUsages(pcExtOIDs, rghExtOIDs, pExtUsage);
  1064. }
  1065. }
  1066. //
  1067. // if there are EKU propertis then we are limited to that set of EKUs at the maximum
  1068. //
  1069. if (pPropUsage != NULL)
  1070. {
  1071. //
  1072. // if this is the first cert with extensions then just copy all the EKUs,
  1073. // otherwise take the intersection of the current certs EKUs and the intersection
  1074. // of all the previous certs EKUs
  1075. //
  1076. if (*pfAllProp == TRUE)
  1077. {
  1078. *pfAllProp = FALSE;
  1079. for (i=0; i<pPropUsage->cUsageIdentifier; i++)
  1080. {
  1081. rghPropOIDs[i] = AllocAndCopyStr(pPropUsage->rgpszUsageIdentifier[i]);
  1082. if (rghPropOIDs[i] == NULL)
  1083. {
  1084. goto ErrorCleanUp;
  1085. }
  1086. (*pcPropOIDs)++;
  1087. }
  1088. }
  1089. else
  1090. {
  1091. IntersectUsages(pcPropOIDs, rghPropOIDs, pPropUsage);
  1092. }
  1093. }
  1094. CleanUp:
  1095. if (pExtUsage != NULL)
  1096. delete(pExtUsage);
  1097. if (pPropUsage != NULL)
  1098. delete(pPropUsage);
  1099. return(fRet);
  1100. ErrorCleanUp:
  1101. fRet = FALSE;
  1102. goto CleanUp;
  1103. }
  1104. //+---------------------------------------------------------------------------
  1105. //
  1106. // Function: CertGetValidUsages
  1107. //
  1108. // Synopsis: takes an array of certs and returns an array of usages
  1109. // which consists of the intersection of the the valid usages for each cert.
  1110. // if each cert is good for all possible usages then cNumOIDs is set to -1.
  1111. //
  1112. //----------------------------------------------------------------------------
  1113. BOOL WINAPI CertGetValidUsages(
  1114. IN DWORD cCerts,
  1115. IN PCCERT_CONTEXT *rghCerts,
  1116. OUT int *cNumOIDs,
  1117. OUT LPSTR *rghOIDs,
  1118. IN OUT DWORD *pcbOIDs)
  1119. {
  1120. BOOL fAllExt = TRUE;
  1121. BOOL fAllProp = TRUE;
  1122. DWORD cPropOIDs = 0;
  1123. LPSTR rghPropOIDs[100];
  1124. DWORD cExtOIDs = 0;
  1125. LPSTR rghExtOIDs[100];
  1126. BOOL fRet = TRUE;
  1127. BYTE *pbBufferLocation;
  1128. DWORD cIntersectOIDs = 0;
  1129. DWORD i;
  1130. DWORD cbNeeded = 0;
  1131. for (i=0; i<cCerts; i++)
  1132. {
  1133. if (!ProcessCertForEKU(rghCerts[i], &fAllProp, &cPropOIDs, rghPropOIDs, &fAllExt, &cExtOIDs, rghExtOIDs))
  1134. {
  1135. goto ErrorCleanUp;
  1136. }
  1137. }
  1138. *cNumOIDs = 0;
  1139. if (fAllExt && fAllProp)
  1140. {
  1141. *pcbOIDs = 0;
  1142. *cNumOIDs = -1;
  1143. }
  1144. else if (!fAllExt && fAllProp)
  1145. {
  1146. for (i=0; i<cExtOIDs; i++)
  1147. {
  1148. cbNeeded += strlen(rghExtOIDs[i]) + 1 + sizeof(LPSTR);
  1149. (*cNumOIDs)++;
  1150. }
  1151. if (*pcbOIDs == 0)
  1152. {
  1153. *pcbOIDs = cbNeeded;
  1154. goto CleanUp;
  1155. }
  1156. if (cbNeeded > *pcbOIDs)
  1157. {
  1158. *pcbOIDs = cbNeeded;
  1159. SetLastError((DWORD) ERROR_MORE_DATA);
  1160. goto ErrorCleanUp;
  1161. }
  1162. pbBufferLocation = ((BYTE *)rghOIDs) + (cExtOIDs * sizeof(LPSTR));
  1163. for (i=0; i<cExtOIDs; i++)
  1164. {
  1165. rghOIDs[i] = (LPSTR) pbBufferLocation;
  1166. strcpy(rghOIDs[i], rghExtOIDs[i]);
  1167. pbBufferLocation += strlen(rghExtOIDs[i]) + 1;
  1168. }
  1169. }
  1170. else if (fAllExt && !fAllProp)
  1171. {
  1172. for (i=0; i<cPropOIDs; i++)
  1173. {
  1174. cbNeeded += strlen(rghPropOIDs[i]) + 1 + sizeof(LPSTR);
  1175. (*cNumOIDs)++;
  1176. }
  1177. if (*pcbOIDs == 0)
  1178. {
  1179. *pcbOIDs = cbNeeded;
  1180. goto CleanUp;
  1181. }
  1182. if (cbNeeded > *pcbOIDs)
  1183. {
  1184. *pcbOIDs = cbNeeded;
  1185. SetLastError((DWORD) ERROR_MORE_DATA);
  1186. goto ErrorCleanUp;
  1187. }
  1188. pbBufferLocation = ((BYTE *)rghOIDs) + (cPropOIDs * sizeof(LPSTR));
  1189. for (i=0; i<cPropOIDs; i++)
  1190. {
  1191. rghOIDs[i] = (LPSTR) pbBufferLocation;
  1192. strcpy(rghOIDs[i], rghPropOIDs[i]);
  1193. pbBufferLocation += strlen(rghPropOIDs[i]) + 1;
  1194. }
  1195. }
  1196. else
  1197. {
  1198. for (i=0; i<cExtOIDs; i++)
  1199. {
  1200. if (OIDExistsInArray(rghPropOIDs, cPropOIDs, rghExtOIDs[i]))
  1201. {
  1202. cbNeeded += strlen(rghExtOIDs[i]) + 1 + sizeof(LPSTR);
  1203. (*cNumOIDs)++;
  1204. cIntersectOIDs++;
  1205. }
  1206. }
  1207. if (*pcbOIDs == 0)
  1208. {
  1209. *pcbOIDs = cbNeeded;
  1210. goto CleanUp;
  1211. }
  1212. if (cbNeeded > *pcbOIDs)
  1213. {
  1214. *pcbOIDs = cbNeeded;
  1215. SetLastError((DWORD) ERROR_MORE_DATA);
  1216. goto ErrorCleanUp;
  1217. }
  1218. pbBufferLocation = ((BYTE *)rghOIDs) + (cIntersectOIDs * sizeof(LPSTR));
  1219. for (i=0; i<cExtOIDs; i++)
  1220. {
  1221. if (OIDExistsInArray(rghPropOIDs, cPropOIDs, rghExtOIDs[i]))
  1222. {
  1223. cIntersectOIDs--;
  1224. rghOIDs[cIntersectOIDs] = (LPSTR) pbBufferLocation;
  1225. strcpy(rghOIDs[cIntersectOIDs], rghExtOIDs[i]);
  1226. pbBufferLocation += strlen(rghExtOIDs[i]) + 1;
  1227. }
  1228. }
  1229. }
  1230. CleanUp:
  1231. for (i=0; i<cExtOIDs; i++)
  1232. {
  1233. delete(rghExtOIDs[i]);
  1234. }
  1235. for (i=0; i<cPropOIDs; i++)
  1236. {
  1237. delete(rghPropOIDs[i]);
  1238. }
  1239. return (fRet);
  1240. ErrorCleanUp:
  1241. fRet = FALSE;
  1242. goto CleanUp;
  1243. }
  1244. //+---------------------------------------------------------------------------
  1245. //
  1246. // Function: EkuGetIntersectedUsageViaGetValidUsages
  1247. //
  1248. // Synopsis: get the intersected extension and property usages
  1249. //
  1250. //----------------------------------------------------------------------------
  1251. BOOL
  1252. EkuGetIntersectedUsageViaGetValidUsages (
  1253. PCCERT_CONTEXT pCertContext,
  1254. DWORD* pcbSize,
  1255. PCERT_ENHKEY_USAGE pUsage
  1256. )
  1257. {
  1258. BOOL fResult;
  1259. int cUsage = 0;
  1260. DWORD cbUsage = 0;
  1261. DWORD cbSize = 0;
  1262. fResult = CertGetValidUsages( 1, &pCertContext, &cUsage, NULL, &cbUsage );
  1263. if ( fResult == TRUE )
  1264. {
  1265. cbSize = cbUsage + sizeof( CERT_ENHKEY_USAGE );
  1266. if ( pUsage == NULL )
  1267. {
  1268. *pcbSize = cbSize;
  1269. return( TRUE );
  1270. }
  1271. else if ( ( pUsage != NULL ) && ( *pcbSize < cbSize ) )
  1272. {
  1273. *pcbSize = cbSize;
  1274. SetLastError( (DWORD) ERROR_MORE_DATA );
  1275. return( FALSE );
  1276. }
  1277. pUsage->cUsageIdentifier = 0;
  1278. pUsage->rgpszUsageIdentifier = (LPSTR *)( (LPBYTE)pUsage + sizeof( CERT_ENHKEY_USAGE ) );
  1279. cbUsage = *pcbSize - sizeof( CERT_ENHKEY_USAGE );
  1280. fResult = CertGetValidUsages(
  1281. 1,
  1282. &pCertContext,
  1283. (int *)&pUsage->cUsageIdentifier,
  1284. pUsage->rgpszUsageIdentifier,
  1285. &cbUsage
  1286. );
  1287. if ( fResult == TRUE )
  1288. {
  1289. if ( pUsage->cUsageIdentifier == 0xFFFFFFFF )
  1290. {
  1291. pUsage->cUsageIdentifier = 0;
  1292. SetLastError( (DWORD) CRYPT_E_NOT_FOUND );
  1293. }
  1294. else if ( pUsage->cUsageIdentifier == 0 )
  1295. {
  1296. SetLastError( 0 );
  1297. }
  1298. }
  1299. }
  1300. return( fResult );
  1301. }