cmsmessage.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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 message methods.
  6. */
  7. #include "cmslocal.h"
  8. #include "cert.h"
  9. #include "secasn1.h"
  10. #include "secitem.h"
  11. #include "secoid.h"
  12. #include "pk11func.h"
  13. #include "secerr.h"
  14. /*
  15. * NSS_CMSMessage_Create - create a CMS message object
  16. *
  17. * "poolp" - arena to allocate memory from, or NULL if new arena should be created
  18. */
  19. NSSCMSMessage *
  20. NSS_CMSMessage_Create(PLArenaPool *poolp)
  21. {
  22. void *mark = NULL;
  23. NSSCMSMessage *cmsg;
  24. PRBool poolp_is_ours = PR_FALSE;
  25. if (poolp == NULL) {
  26. poolp = PORT_NewArena(1024); /* XXX what is right value? */
  27. if (poolp == NULL) {
  28. return NULL;
  29. }
  30. poolp_is_ours = PR_TRUE;
  31. }
  32. if (!poolp_is_ours)
  33. mark = PORT_ArenaMark(poolp);
  34. cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSMessage));
  35. if (cmsg == NULL ||
  36. NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo)) != SECSuccess) {
  37. if (!poolp_is_ours) {
  38. if (mark) {
  39. PORT_ArenaRelease(poolp, mark);
  40. }
  41. } else {
  42. PORT_FreeArena(poolp, PR_FALSE);
  43. }
  44. return NULL;
  45. }
  46. cmsg->poolp = poolp;
  47. cmsg->poolp_is_ours = poolp_is_ours;
  48. cmsg->refCount = 1;
  49. if (mark) {
  50. PORT_ArenaUnmark(poolp, mark);
  51. }
  52. return cmsg;
  53. }
  54. /*
  55. * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
  56. *
  57. * "cmsg" - message object
  58. * "pwfn", pwfn_arg" - callback function for getting token password
  59. * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
  60. * "detached_digestalgs", "detached_digests" - digests from detached content
  61. */
  62. void
  63. NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
  64. PK11PasswordFunc pwfn, void *pwfn_arg,
  65. NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
  66. SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
  67. {
  68. if (cmsg == NULL) {
  69. return;
  70. }
  71. if (pwfn) {
  72. PK11_SetPasswordFunc(pwfn);
  73. }
  74. cmsg->pwfn_arg = pwfn_arg;
  75. cmsg->decrypt_key_cb = decrypt_key_cb;
  76. cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg;
  77. cmsg->detached_digestalgs = detached_digestalgs;
  78. cmsg->detached_digests = detached_digests;
  79. }
  80. /*
  81. * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
  82. */
  83. void
  84. NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
  85. {
  86. if (cmsg == NULL)
  87. return;
  88. PORT_Assert(cmsg->refCount > 0);
  89. if (cmsg->refCount <= 0) { /* oops */
  90. return;
  91. }
  92. cmsg->refCount--; /* thread safety? */
  93. if (cmsg->refCount > 0) {
  94. return;
  95. }
  96. NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo));
  97. /* if poolp is not NULL, cmsg is the owner of its arena */
  98. if (cmsg->poolp_is_ours) {
  99. PORT_FreeArena(cmsg->poolp, PR_FALSE); /* XXX clear it? */
  100. }
  101. }
  102. /*
  103. * NSS_CMSMessage_Copy - return a copy of the given message.
  104. *
  105. * The copy may be virtual or may be real -- either way, the result needs
  106. * to be passed to NSS_CMSMessage_Destroy later (as does the original).
  107. */
  108. NSSCMSMessage *
  109. NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
  110. {
  111. if (cmsg == NULL) {
  112. return NULL;
  113. }
  114. PORT_Assert(cmsg->refCount > 0);
  115. cmsg->refCount++; /* XXX chrisk thread safety? */
  116. return cmsg;
  117. }
  118. /*
  119. * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
  120. */
  121. PLArenaPool *
  122. NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
  123. {
  124. if (cmsg == NULL) {
  125. return NULL;
  126. }
  127. return cmsg->poolp;
  128. }
  129. /*
  130. * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
  131. */
  132. NSSCMSContentInfo *
  133. NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
  134. {
  135. if (cmsg == NULL) {
  136. return NULL;
  137. }
  138. return &(cmsg->contentInfo);
  139. }
  140. /*
  141. * Return a pointer to the actual content.
  142. * In the case of those types which are encrypted, this returns the *plain* content.
  143. * In case of nested contentInfos, this descends and retrieves the innermost content.
  144. */
  145. SECItem *
  146. NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg)
  147. {
  148. if (cmsg == NULL) {
  149. return NULL;
  150. }
  151. /* this is a shortcut */
  152. NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  153. SECItem *pItem = NSS_CMSContentInfo_GetInnerContent(cinfo);
  154. return pItem;
  155. }
  156. /*
  157. * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
  158. *
  159. * CMS data content objects do not count.
  160. */
  161. int
  162. NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg)
  163. {
  164. int count = 0;
  165. NSSCMSContentInfo *cinfo;
  166. if (cmsg == NULL) {
  167. return 0;
  168. }
  169. /* walk down the chain of contentinfos */
  170. for (cinfo = &(cmsg->contentInfo); cinfo != NULL;) {
  171. count++;
  172. cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
  173. }
  174. return count;
  175. }
  176. /*
  177. * NSS_CMSMessage_ContentLevel - find content level #n
  178. *
  179. * CMS data content objects do not count.
  180. */
  181. NSSCMSContentInfo *
  182. NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n)
  183. {
  184. int count = 0;
  185. NSSCMSContentInfo *cinfo;
  186. if (cmsg == NULL) {
  187. return NULL;
  188. }
  189. /* walk down the chain of contentinfos */
  190. for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n;
  191. cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
  192. count++;
  193. }
  194. return cinfo;
  195. }
  196. /*
  197. * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
  198. */
  199. PRBool
  200. NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg)
  201. {
  202. NSSCMSContentInfo *cinfo;
  203. if (cmsg == NULL) {
  204. return PR_FALSE;
  205. }
  206. /* descend into CMS message */
  207. for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
  208. cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
  209. if (!NSS_CMSType_IsData(NSS_CMSContentInfo_GetContentTypeTag(cinfo)))
  210. continue; /* next level */
  211. if (NSS_CMSSignedData_ContainsCertsOrCrls(cinfo->content.signedData))
  212. return PR_TRUE;
  213. /* callback here for generic wrappers? */
  214. }
  215. return PR_FALSE;
  216. }
  217. /*
  218. * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
  219. */
  220. PRBool
  221. NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg)
  222. {
  223. NSSCMSContentInfo *cinfo;
  224. if (cmsg == NULL) {
  225. return PR_FALSE;
  226. }
  227. /* walk down the chain of contentinfos */
  228. for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
  229. cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
  230. switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
  231. case SEC_OID_PKCS7_ENVELOPED_DATA:
  232. case SEC_OID_PKCS7_ENCRYPTED_DATA:
  233. return PR_TRUE;
  234. default:
  235. /* callback here for generic wrappers? */
  236. break;
  237. }
  238. }
  239. return PR_FALSE;
  240. }
  241. /*
  242. * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
  243. *
  244. * If the CMS message has a SignedData with a signature (not just a SignedData)
  245. * return true; false otherwise. This can/should be called before calling
  246. * VerifySignature, which will always indicate failure if no signature is
  247. * present, but that does not mean there even was a signature!
  248. * Note that the content itself can be empty (detached content was sent
  249. * another way); it is the presence of the signature that matters.
  250. */
  251. PRBool
  252. NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
  253. {
  254. NSSCMSContentInfo *cinfo;
  255. if (cmsg == NULL) {
  256. return PR_FALSE;
  257. }
  258. /* walk down the chain of contentinfos */
  259. for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
  260. cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
  261. switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
  262. case SEC_OID_PKCS7_SIGNED_DATA:
  263. if (cinfo->content.signedData == NULL) {
  264. return PR_FALSE;
  265. }
  266. if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos)) {
  267. return PR_TRUE;
  268. }
  269. break;
  270. default:
  271. /* callback here for generic wrappers? */
  272. break;
  273. }
  274. }
  275. return PR_FALSE;
  276. }
  277. /*
  278. * NSS_CMSMessage_IsContentEmpty - see if content is empty
  279. *
  280. * returns PR_TRUE is innermost content length is < minLen
  281. * XXX need the encrypted content length (why?)
  282. */
  283. PRBool
  284. NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen)
  285. {
  286. SECItem *item = NULL;
  287. if (cmsg == NULL) {
  288. return PR_TRUE;
  289. }
  290. item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg));
  291. if (!item) {
  292. return PR_TRUE;
  293. } else if (item->len <= minLen) {
  294. return PR_TRUE;
  295. }
  296. return PR_FALSE;
  297. }