/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.c

http://github.com/zpao/v8monkey · C · 500 lines · 337 code · 60 blank · 103 comment · 36 complexity · 0f8ec85ae2cfc04e16033b22b3b56f9b MD5 · raw file

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the PKIX-C library.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Sun Microsystems, Inc.
  18. * Portions created by the Initial Developer are
  19. * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. * Sun Microsystems, Inc.
  23. *
  24. * Alternatively, the contents of this file may be used under the terms of
  25. * either the GNU General Public License Version 2 or later (the "GPL"), or
  26. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. * in which case the provisions of the GPL or the LGPL are applicable instead
  28. * of those above. If you wish to allow use of your version of this file only
  29. * under the terms of either the GPL or the LGPL, and not to allow others to
  30. * use your version of this file under the terms of the MPL, indicate your
  31. * decision by deleting the provisions above and replace them with the notice
  32. * and other provisions required by the GPL or the LGPL. If you do not delete
  33. * the provisions above, a recipient may use your version of this file under
  34. * the terms of any one of the MPL, the GPL or the LGPL.
  35. *
  36. * ***** END LICENSE BLOCK ***** */
  37. /*
  38. * pkix_revocationchecker.c
  39. *
  40. * RevocationChecker Object Functions
  41. *
  42. */
  43. #include "pkix_revocationchecker.h"
  44. #include "pkix_tools.h"
  45. /* --Private-Functions-------------------------------------------- */
  46. /*
  47. * FUNCTION: pkix_RevocationChecker_Destroy
  48. * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
  49. */
  50. static PKIX_Error *
  51. pkix_RevocationChecker_Destroy(
  52. PKIX_PL_Object *object,
  53. void *plContext)
  54. {
  55. PKIX_RevocationChecker *checker = NULL;
  56. PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Destroy");
  57. PKIX_NULLCHECK_ONE(object);
  58. /* Check that this object is a revocation checker */
  59. PKIX_CHECK(pkix_CheckType
  60. (object, PKIX_REVOCATIONCHECKER_TYPE, plContext),
  61. PKIX_OBJECTNOTREVOCATIONCHECKER);
  62. checker = (PKIX_RevocationChecker *)object;
  63. PKIX_DECREF(checker->leafMethodList);
  64. PKIX_DECREF(checker->chainMethodList);
  65. cleanup:
  66. PKIX_RETURN(REVOCATIONCHECKER);
  67. }
  68. /*
  69. * FUNCTION: pkix_RevocationChecker_Duplicate
  70. * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h)
  71. */
  72. static PKIX_Error *
  73. pkix_RevocationChecker_Duplicate(
  74. PKIX_PL_Object *object,
  75. PKIX_PL_Object **pNewObject,
  76. void *plContext)
  77. {
  78. PKIX_RevocationChecker *checker = NULL;
  79. PKIX_RevocationChecker *checkerDuplicate = NULL;
  80. PKIX_List *dupLeafList = NULL;
  81. PKIX_List *dupChainList = NULL;
  82. PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Duplicate");
  83. PKIX_NULLCHECK_TWO(object, pNewObject);
  84. PKIX_CHECK(pkix_CheckType
  85. (object, PKIX_REVOCATIONCHECKER_TYPE, plContext),
  86. PKIX_OBJECTNOTCERTCHAINCHECKER);
  87. checker = (PKIX_RevocationChecker *)object;
  88. if (checker->leafMethodList){
  89. PKIX_CHECK(PKIX_PL_Object_Duplicate
  90. ((PKIX_PL_Object *)checker->leafMethodList,
  91. (PKIX_PL_Object **)&dupLeafList,
  92. plContext),
  93. PKIX_OBJECTDUPLICATEFAILED);
  94. }
  95. if (checker->chainMethodList){
  96. PKIX_CHECK(PKIX_PL_Object_Duplicate
  97. ((PKIX_PL_Object *)checker->chainMethodList,
  98. (PKIX_PL_Object **)&dupChainList,
  99. plContext),
  100. PKIX_OBJECTDUPLICATEFAILED);
  101. }
  102. PKIX_CHECK(
  103. PKIX_RevocationChecker_Create(checker->leafMethodListFlags,
  104. checker->chainMethodListFlags,
  105. &checkerDuplicate,
  106. plContext),
  107. PKIX_REVOCATIONCHECKERCREATEFAILED);
  108. checkerDuplicate->leafMethodList = dupLeafList;
  109. checkerDuplicate->chainMethodList = dupChainList;
  110. dupLeafList = NULL;
  111. dupChainList = NULL;
  112. *pNewObject = (PKIX_PL_Object *)checkerDuplicate;
  113. cleanup:
  114. PKIX_DECREF(dupLeafList);
  115. PKIX_DECREF(dupChainList);
  116. PKIX_RETURN(REVOCATIONCHECKER);
  117. }
  118. /*
  119. * FUNCTION: pkix_RevocationChecker_RegisterSelf
  120. * DESCRIPTION:
  121. * Registers PKIX_REVOCATIONCHECKER_TYPE and its related functions with
  122. * systemClasses[]
  123. * THREAD SAFETY:
  124. * Not Thread Safe - for performance and complexity reasons
  125. *
  126. * Since this function is only called by PKIX_PL_Initialize, which should
  127. * only be called once, it is acceptable that this function is not
  128. * thread-safe.
  129. */
  130. PKIX_Error *
  131. pkix_RevocationChecker_RegisterSelf(void *plContext)
  132. {
  133. extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
  134. pkix_ClassTable_Entry entry;
  135. PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_RegisterSelf");
  136. entry.description = "RevocationChecker";
  137. entry.objCounter = 0;
  138. entry.typeObjectSize = sizeof(PKIX_RevocationChecker);
  139. entry.destructor = pkix_RevocationChecker_Destroy;
  140. entry.equalsFunction = NULL;
  141. entry.hashcodeFunction = NULL;
  142. entry.toStringFunction = NULL;
  143. entry.comparator = NULL;
  144. entry.duplicateFunction = pkix_RevocationChecker_Duplicate;
  145. systemClasses[PKIX_REVOCATIONCHECKER_TYPE] = entry;
  146. PKIX_RETURN(REVOCATIONCHECKER);
  147. }
  148. /* Sort methods by theirs priorities */
  149. static PKIX_Error *
  150. pkix_RevocationChecker_SortComparator(
  151. PKIX_PL_Object *obj1,
  152. PKIX_PL_Object *obj2,
  153. PKIX_Int32 *pResult,
  154. void *plContext)
  155. {
  156. pkix_RevocationMethod *method1 = NULL, *method2 = NULL;
  157. PKIX_ENTER(BUILD, "pkix_RevocationChecker_SortComparator");
  158. method1 = (pkix_RevocationMethod *)obj1;
  159. method2 = (pkix_RevocationMethod *)obj2;
  160. *pResult = (method1->priority > method2->priority);
  161. PKIX_RETURN(BUILD);
  162. }
  163. /* --Public-Functions--------------------------------------------- */
  164. /*
  165. * FUNCTION: PKIX_RevocationChecker_Create (see comments in pkix_revchecker.h)
  166. */
  167. PKIX_Error *
  168. PKIX_RevocationChecker_Create(
  169. PKIX_UInt32 leafMethodListFlags,
  170. PKIX_UInt32 chainMethodListFlags,
  171. PKIX_RevocationChecker **pChecker,
  172. void *plContext)
  173. {
  174. PKIX_RevocationChecker *checker = NULL;
  175. PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Create");
  176. PKIX_NULLCHECK_ONE(pChecker);
  177. PKIX_CHECK(
  178. PKIX_PL_Object_Alloc(PKIX_REVOCATIONCHECKER_TYPE,
  179. sizeof (PKIX_RevocationChecker),
  180. (PKIX_PL_Object **)&checker,
  181. plContext),
  182. PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT);
  183. checker->leafMethodListFlags = leafMethodListFlags;
  184. checker->chainMethodListFlags = chainMethodListFlags;
  185. checker->leafMethodList = NULL;
  186. checker->chainMethodList = NULL;
  187. *pChecker = checker;
  188. checker = NULL;
  189. cleanup:
  190. PKIX_DECREF(checker);
  191. PKIX_RETURN(REVOCATIONCHECKER);
  192. }
  193. /*
  194. * FUNCTION: PKIX_RevocationChecker_CreateAndAddMethod
  195. */
  196. PKIX_Error *
  197. PKIX_RevocationChecker_CreateAndAddMethod(
  198. PKIX_RevocationChecker *revChecker,
  199. PKIX_ProcessingParams *params,
  200. PKIX_RevocationMethodType methodType,
  201. PKIX_UInt32 flags,
  202. PKIX_UInt32 priority,
  203. PKIX_PL_VerifyCallback verificationFn,
  204. PKIX_Boolean isLeafMethod,
  205. void *plContext)
  206. {
  207. PKIX_List **methodList = NULL;
  208. PKIX_List *unsortedList = NULL;
  209. PKIX_List *certStores = NULL;
  210. pkix_RevocationMethod *method = NULL;
  211. pkix_LocalRevocationCheckFn *localRevChecker = NULL;
  212. pkix_ExternalRevocationCheckFn *externRevChecker = NULL;
  213. PKIX_UInt32 miFlags;
  214. PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_CreateAndAddMethod");
  215. PKIX_NULLCHECK_ONE(revChecker);
  216. /* If the caller has said "Either one is sufficient, then don't let the
  217. * absence of any one method's info lead to an overall failure.
  218. */
  219. miFlags = isLeafMethod ? revChecker->leafMethodListFlags
  220. : revChecker->chainMethodListFlags;
  221. if (miFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE)
  222. flags &= ~PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO;
  223. switch (methodType) {
  224. case PKIX_RevocationMethod_CRL:
  225. localRevChecker = pkix_CrlChecker_CheckLocal;
  226. externRevChecker = pkix_CrlChecker_CheckExternal;
  227. PKIX_CHECK(
  228. PKIX_ProcessingParams_GetCertStores(params, &certStores,
  229. plContext),
  230. PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED);
  231. PKIX_CHECK(
  232. pkix_CrlChecker_Create(methodType, flags, priority,
  233. localRevChecker, externRevChecker,
  234. certStores, verificationFn,
  235. &method,
  236. plContext),
  237. PKIX_COULDNOTCREATECRLCHECKEROBJECT);
  238. break;
  239. case PKIX_RevocationMethod_OCSP:
  240. localRevChecker = pkix_OcspChecker_CheckLocal;
  241. externRevChecker = pkix_OcspChecker_CheckExternal;
  242. PKIX_CHECK(
  243. pkix_OcspChecker_Create(methodType, flags, priority,
  244. localRevChecker, externRevChecker,
  245. verificationFn,
  246. &method,
  247. plContext),
  248. PKIX_COULDNOTCREATEOCSPCHECKEROBJECT);
  249. break;
  250. default:
  251. PKIX_ERROR(PKIX_INVALIDREVOCATIONMETHOD);
  252. }
  253. if (isLeafMethod) {
  254. methodList = &revChecker->leafMethodList;
  255. } else {
  256. methodList = &revChecker->chainMethodList;
  257. }
  258. if (*methodList == NULL) {
  259. PKIX_CHECK(
  260. PKIX_List_Create(methodList, plContext),
  261. PKIX_LISTCREATEFAILED);
  262. }
  263. unsortedList = *methodList;
  264. PKIX_CHECK(
  265. PKIX_List_AppendItem(unsortedList, (PKIX_PL_Object*)method, plContext),
  266. PKIX_LISTAPPENDITEMFAILED);
  267. PKIX_CHECK(
  268. pkix_List_BubbleSort(unsortedList,
  269. pkix_RevocationChecker_SortComparator,
  270. methodList, plContext),
  271. PKIX_LISTBUBBLESORTFAILED);
  272. cleanup:
  273. PKIX_DECREF(method);
  274. PKIX_DECREF(unsortedList);
  275. PKIX_DECREF(certStores);
  276. PKIX_RETURN(REVOCATIONCHECKER);
  277. }
  278. /*
  279. * FUNCTION: PKIX_RevocationChecker_Check
  280. */
  281. PKIX_Error *
  282. PKIX_RevocationChecker_Check(
  283. PKIX_PL_Cert *cert,
  284. PKIX_PL_Cert *issuer,
  285. PKIX_RevocationChecker *revChecker,
  286. PKIX_ProcessingParams *procParams,
  287. PKIX_Boolean chainVerificationState,
  288. PKIX_Boolean testingLeafCert,
  289. PKIX_RevocationStatus *pRevStatus,
  290. PKIX_UInt32 *pReasonCode,
  291. void **pNbioContext,
  292. void *plContext)
  293. {
  294. PKIX_RevocationStatus overallStatus = PKIX_RevStatus_NoInfo;
  295. PKIX_RevocationStatus methodStatus[PKIX_RevocationMethod_MAX];
  296. PKIX_Boolean onlyUseRemoteMethods = PKIX_FALSE;
  297. PKIX_UInt32 revFlags = 0;
  298. PKIX_List *revList = NULL;
  299. PKIX_PL_Date *date = NULL;
  300. pkix_RevocationMethod *method = NULL;
  301. void *nbioContext;
  302. int tries;
  303. PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check");
  304. PKIX_NULLCHECK_TWO(revChecker, procParams);
  305. nbioContext = *pNbioContext;
  306. *pNbioContext = NULL;
  307. if (testingLeafCert) {
  308. revList = revChecker->leafMethodList;
  309. revFlags = revChecker->leafMethodListFlags;
  310. } else {
  311. revList = revChecker->chainMethodList;
  312. revFlags = revChecker->chainMethodListFlags;
  313. }
  314. if (!revList) {
  315. /* Return NoInfo status */
  316. goto cleanup;
  317. }
  318. PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo,
  319. sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX);
  320. date = procParams->date;
  321. /* Need to have two loops if we testing all local info first:
  322. * first we are going to test all local(cached) info
  323. * second, all remote info(fetching) */
  324. for (tries = 0;tries < 2;tries++) {
  325. int methodNum = 0;
  326. for (;methodNum < revList->length;methodNum++) {
  327. PKIX_UInt32 methodFlags = 0;
  328. PKIX_DECREF(method);
  329. PKIX_CHECK(
  330. PKIX_List_GetItem(revList, methodNum,
  331. (PKIX_PL_Object**)&method, plContext),
  332. PKIX_LISTGETITEMFAILED);
  333. methodFlags = method->flags;
  334. if (!(methodFlags & PKIX_REV_M_TEST_USING_THIS_METHOD)) {
  335. /* Will not check with this method. Skipping... */
  336. continue;
  337. }
  338. if (!onlyUseRemoteMethods &&
  339. methodStatus[methodNum] == PKIX_RevStatus_NoInfo) {
  340. PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
  341. PKIX_CHECK_NO_GOTO(
  342. (*method->localRevChecker)(cert, issuer, date,
  343. method, procParams,
  344. methodFlags,
  345. chainVerificationState,
  346. &revStatus,
  347. pReasonCode, plContext),
  348. PKIX_REVCHECKERCHECKFAILED);
  349. methodStatus[methodNum] = revStatus;
  350. if (revStatus == PKIX_RevStatus_Revoked) {
  351. /* if error was generated use it as final error. */
  352. overallStatus = PKIX_RevStatus_Revoked;
  353. goto cleanup;
  354. }
  355. if (pkixErrorResult) {
  356. /* Disregard errors. Only returned revStatus matters. */
  357. PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult,
  358. plContext);
  359. pkixErrorResult = NULL;
  360. }
  361. }
  362. if ((!(revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST) ||
  363. onlyUseRemoteMethods) &&
  364. chainVerificationState &&
  365. methodStatus[methodNum] == PKIX_RevStatus_NoInfo) {
  366. if (!(methodFlags & PKIX_REV_M_FORBID_NETWORK_FETCHING)) {
  367. PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
  368. PKIX_CHECK_NO_GOTO(
  369. (*method->externalRevChecker)(cert, issuer, date,
  370. method,
  371. procParams, methodFlags,
  372. &revStatus, pReasonCode,
  373. &nbioContext, plContext),
  374. PKIX_REVCHECKERCHECKFAILED);
  375. methodStatus[methodNum] = revStatus;
  376. if (revStatus == PKIX_RevStatus_Revoked) {
  377. /* if error was generated use it as final error. */
  378. overallStatus = PKIX_RevStatus_Revoked;
  379. goto cleanup;
  380. }
  381. if (pkixErrorResult) {
  382. /* Disregard errors. Only returned revStatus matters. */
  383. PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult,
  384. plContext);
  385. pkixErrorResult = NULL;
  386. }
  387. } else if (methodFlags &
  388. PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) {
  389. /* Info is not in the local cache. Network fetching is not
  390. * allowed. If need to fail on missing fresh info for the
  391. * the method, then we should fail right here.*/
  392. overallStatus = PKIX_RevStatus_Revoked;
  393. goto cleanup;
  394. }
  395. }
  396. /* If success and we should not check the next method, then
  397. * return a success. */
  398. if (methodStatus[methodNum] == PKIX_RevStatus_Success &&
  399. !(methodFlags & PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO)) {
  400. overallStatus = PKIX_RevStatus_Success;
  401. goto cleanup;
  402. }
  403. } /* inner loop */
  404. if (!onlyUseRemoteMethods &&
  405. revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST &&
  406. chainVerificationState) {
  407. onlyUseRemoteMethods = PKIX_TRUE;
  408. continue;
  409. }
  410. break;
  411. } /* outer loop */
  412. if (overallStatus == PKIX_RevStatus_NoInfo &&
  413. chainVerificationState) {
  414. /* The following check makes sence only for chain
  415. * validation step, sinse we do not fetch info while
  416. * in the process of finding trusted anchor.
  417. * For chain building step it is enough to know, that
  418. * the cert was not directly revoked by any of the
  419. * methods. */
  420. /* Still have no info. But one of the method could
  421. * have returned success status(possible if CONTINUE
  422. * TESTING ON FRESH INFO flag was used).
  423. * If any of the methods have returned Success status,
  424. * the overallStatus should be success. */
  425. int methodNum = 0;
  426. for (;methodNum < PKIX_RevocationMethod_MAX;methodNum++) {
  427. if (methodStatus[methodNum] == PKIX_RevStatus_Success) {
  428. overallStatus = PKIX_RevStatus_Success;
  429. goto cleanup;
  430. }
  431. }
  432. if (revFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) {
  433. overallStatus = PKIX_RevStatus_Revoked;
  434. }
  435. }
  436. cleanup:
  437. *pRevStatus = overallStatus;
  438. PKIX_DECREF(method);
  439. PKIX_RETURN(REVOCATIONCHECKER);
  440. }