cmsdigest.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. /*
  5. * CMS digesting.
  6. */
  7. #include "cmslocal.h"
  8. #include "cert.h"
  9. #include "keyhi.h"
  10. #include "secitem.h"
  11. #include "secoid.h"
  12. #include "pk11func.h"
  13. #include "prtime.h"
  14. #include "secerr.h"
  15. /* #define CMS_FIND_LEAK_MULTIPLE 1 */
  16. #ifdef CMS_FIND_LEAK_MULTIPLE
  17. static int stop_on_err = 1;
  18. static int global_num_digests = 0;
  19. #endif
  20. struct digestPairStr {
  21. const SECHashObject *digobj;
  22. void *digcx;
  23. };
  24. typedef struct digestPairStr digestPair;
  25. struct NSSCMSDigestContextStr {
  26. PRBool saw_contents;
  27. PLArenaPool *pool;
  28. int digcnt;
  29. digestPair *digPairs;
  30. };
  31. /*
  32. * NSS_CMSDigestContext_StartMultiple - start digest calculation using all the
  33. * digest algorithms in "digestalgs" in parallel.
  34. */
  35. NSSCMSDigestContext *
  36. NSS_CMSDigestContext_StartMultiple(SECAlgorithmID **digestalgs)
  37. {
  38. PLArenaPool *pool;
  39. NSSCMSDigestContext *cmsdigcx;
  40. int digcnt;
  41. int i;
  42. #ifdef CMS_FIND_LEAK_MULTIPLE
  43. PORT_Assert(global_num_digests == 0 || !stop_on_err);
  44. #endif
  45. digcnt = (digestalgs == NULL) ? 0 : NSS_CMSArray_Count((void **)digestalgs);
  46. /* It's OK if digcnt is zero. We have to allow this for "certs only"
  47. ** messages.
  48. */
  49. pool = PORT_NewArena(2048);
  50. if (!pool)
  51. return NULL;
  52. cmsdigcx = PORT_ArenaNew(pool, NSSCMSDigestContext);
  53. if (cmsdigcx == NULL)
  54. goto loser;
  55. cmsdigcx->saw_contents = PR_FALSE;
  56. cmsdigcx->pool = pool;
  57. cmsdigcx->digcnt = digcnt;
  58. cmsdigcx->digPairs = PORT_ArenaZNewArray(pool, digestPair, digcnt);
  59. if (cmsdigcx->digPairs == NULL) {
  60. goto loser;
  61. }
  62. /*
  63. * Create a digest object context for each algorithm.
  64. */
  65. for (i = 0; i < digcnt; i++) {
  66. const SECHashObject *digobj;
  67. void *digcx;
  68. digobj = NSS_CMSUtil_GetHashObjByAlgID(digestalgs[i]);
  69. /*
  70. * Skip any algorithm we do not even recognize; obviously,
  71. * this could be a problem, but if it is critical then the
  72. * result will just be that the signature does not verify.
  73. * We do not necessarily want to error out here, because
  74. * the particular algorithm may not actually be important,
  75. * but we cannot know that until later.
  76. */
  77. if (digobj == NULL)
  78. continue;
  79. digcx = (*digobj->create)();
  80. if (digcx != NULL) {
  81. (*digobj->begin)(digcx);
  82. cmsdigcx->digPairs[i].digobj = digobj;
  83. cmsdigcx->digPairs[i].digcx = digcx;
  84. #ifdef CMS_FIND_LEAK_MULTIPLE
  85. global_num_digests++;
  86. #endif
  87. }
  88. }
  89. return cmsdigcx;
  90. loser:
  91. /* no digest objects have been created, or need to be destroyed. */
  92. if (pool) {
  93. PORT_FreeArena(pool, PR_FALSE);
  94. }
  95. return NULL;
  96. }
  97. /*
  98. * NSS_CMSDigestContext_StartSingle - same as
  99. * NSS_CMSDigestContext_StartMultiple, but only one algorithm.
  100. */
  101. NSSCMSDigestContext *
  102. NSS_CMSDigestContext_StartSingle(SECAlgorithmID *digestalg)
  103. {
  104. SECAlgorithmID *digestalgs[] = { NULL, NULL }; /* fake array */
  105. digestalgs[0] = digestalg;
  106. return NSS_CMSDigestContext_StartMultiple(digestalgs);
  107. }
  108. /*
  109. * NSS_CMSDigestContext_Update - feed more data into the digest machine
  110. */
  111. void
  112. NSS_CMSDigestContext_Update(NSSCMSDigestContext *cmsdigcx,
  113. const unsigned char *data, int len)
  114. {
  115. int i;
  116. digestPair *pair = cmsdigcx->digPairs;
  117. cmsdigcx->saw_contents = PR_TRUE;
  118. for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
  119. if (pair->digcx) {
  120. (*pair->digobj->update)(pair->digcx, data, len);
  121. }
  122. }
  123. }
  124. /*
  125. * NSS_CMSDigestContext_Cancel - cancel digesting operation
  126. */
  127. void
  128. NSS_CMSDigestContext_Cancel(NSSCMSDigestContext *cmsdigcx)
  129. {
  130. int i;
  131. digestPair *pair = cmsdigcx->digPairs;
  132. for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
  133. if (pair->digcx) {
  134. (*pair->digobj->destroy)(pair->digcx, PR_TRUE);
  135. #ifdef CMS_FIND_LEAK_MULTIPLE
  136. --global_num_digests;
  137. #endif
  138. }
  139. }
  140. #ifdef CMS_FIND_LEAK_MULTIPLE
  141. PORT_Assert(global_num_digests == 0 || !stop_on_err);
  142. #endif
  143. PORT_FreeArena(cmsdigcx->pool, PR_FALSE);
  144. }
  145. /*
  146. * NSS_CMSDigestContext_FinishMultiple - finish the digests and put them
  147. * into an array of SECItems (allocated on poolp)
  148. */
  149. SECStatus
  150. NSS_CMSDigestContext_FinishMultiple(NSSCMSDigestContext *cmsdigcx,
  151. PLArenaPool *poolp,
  152. SECItem ***digestsp)
  153. {
  154. SECItem **digests = NULL;
  155. digestPair *pair;
  156. void *mark;
  157. int i;
  158. SECStatus rv;
  159. /* no contents? do not finish digests */
  160. if (digestsp == NULL || !cmsdigcx->saw_contents) {
  161. rv = SECSuccess;
  162. goto cleanup;
  163. }
  164. mark = PORT_ArenaMark(poolp);
  165. /* allocate digest array & SECItems on arena */
  166. digests = PORT_ArenaNewArray(poolp, SECItem *, cmsdigcx->digcnt + 1);
  167. rv = ((digests == NULL) ? SECFailure : SECSuccess);
  168. pair = cmsdigcx->digPairs;
  169. for (i = 0; rv == SECSuccess && i < cmsdigcx->digcnt; i++, pair++) {
  170. SECItem digest;
  171. unsigned char hash[HASH_LENGTH_MAX];
  172. if (!pair->digcx) {
  173. digests[i] = NULL;
  174. continue;
  175. }
  176. digest.type = siBuffer;
  177. digest.data = hash;
  178. digest.len = pair->digobj->length;
  179. (*pair->digobj->end)(pair->digcx, hash, &digest.len, digest.len);
  180. digests[i] = SECITEM_ArenaDupItem(poolp, &digest);
  181. if (!digests[i]) {
  182. rv = SECFailure;
  183. }
  184. }
  185. digests[i] = NULL;
  186. if (rv == SECSuccess) {
  187. PORT_ArenaUnmark(poolp, mark);
  188. } else
  189. PORT_ArenaRelease(poolp, mark);
  190. cleanup:
  191. NSS_CMSDigestContext_Cancel(cmsdigcx);
  192. /* Don't change the caller's digests pointer if we have no digests.
  193. ** NSS_CMSSignedData_Encode_AfterData depends on this behavior.
  194. */
  195. if (rv == SECSuccess && digestsp && digests) {
  196. *digestsp = digests;
  197. }
  198. return rv;
  199. }
  200. /*
  201. * NSS_CMSDigestContext_FinishSingle - same as
  202. * NSS_CMSDigestContext_FinishMultiple, but for one digest.
  203. */
  204. SECStatus
  205. NSS_CMSDigestContext_FinishSingle(NSSCMSDigestContext *cmsdigcx,
  206. PLArenaPool *poolp,
  207. SECItem *digest)
  208. {
  209. SECStatus rv = SECFailure;
  210. SECItem **dp;
  211. PLArenaPool *arena = NULL;
  212. if ((arena = PORT_NewArena(1024)) == NULL)
  213. goto loser;
  214. /* get the digests into arena, then copy the first digest into poolp */
  215. rv = NSS_CMSDigestContext_FinishMultiple(cmsdigcx, arena, &dp);
  216. if (rv == SECSuccess) {
  217. /* now copy it into poolp */
  218. rv = SECITEM_CopyItem(poolp, digest, dp[0]);
  219. }
  220. loser:
  221. if (arena)
  222. PORT_FreeArena(arena, PR_FALSE);
  223. return rv;
  224. }