cmsencdata.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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 encryptedData methods.
  6. */
  7. #include "cmslocal.h"
  8. #include "keyhi.h"
  9. #include "secasn1.h"
  10. #include "secitem.h"
  11. #include "secoid.h"
  12. #include "pk11func.h"
  13. #include "prtime.h"
  14. #include "secerr.h"
  15. #include "secpkcs5.h"
  16. /*
  17. * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
  18. *
  19. * "algorithm" specifies the bulk encryption algorithm to use.
  20. * "keysize" is the key size.
  21. *
  22. * An error results in a return value of NULL and an error set.
  23. * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
  24. */
  25. NSSCMSEncryptedData *
  26. NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm,
  27. int keysize)
  28. {
  29. void *mark;
  30. NSSCMSEncryptedData *encd;
  31. PLArenaPool *poolp;
  32. SECAlgorithmID *pbe_algid;
  33. SECStatus rv;
  34. poolp = cmsg->poolp;
  35. mark = PORT_ArenaMark(poolp);
  36. encd = PORT_ArenaZNew(poolp, NSSCMSEncryptedData);
  37. if (encd == NULL)
  38. goto loser;
  39. encd->cmsg = cmsg;
  40. /* version is set in NSS_CMSEncryptedData_Encode_BeforeStart() */
  41. if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
  42. rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(encd->contentInfo),
  43. algorithm, NULL, keysize);
  44. } else {
  45. /* Assume password-based-encryption.
  46. * Note: we can't generate pkcs5v2 from this interface.
  47. * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
  48. * non-PBE oids and assuming that they are pkcs5v2 oids, but
  49. * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
  50. * CMS encrypted data, so we can't tell NSS_CMS_EncryptedData_Create
  51. * to create pkcs5v2 PBEs */
  52. pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
  53. if (pbe_algid == NULL) {
  54. rv = SECFailure;
  55. } else {
  56. rv = NSS_CMSContentInfo_SetContentEncAlgID(poolp,
  57. &(encd->contentInfo),
  58. pbe_algid, keysize);
  59. SECOID_DestroyAlgorithmID(pbe_algid, PR_TRUE);
  60. }
  61. }
  62. if (rv != SECSuccess)
  63. goto loser;
  64. PORT_ArenaUnmark(poolp, mark);
  65. return encd;
  66. loser:
  67. PORT_ArenaRelease(poolp, mark);
  68. return NULL;
  69. }
  70. /*
  71. * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
  72. */
  73. void
  74. NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
  75. {
  76. /* everything's in a pool, so don't worry about the storage */
  77. if (encd != NULL) {
  78. NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
  79. }
  80. return;
  81. }
  82. /*
  83. * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
  84. */
  85. NSSCMSContentInfo *
  86. NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
  87. {
  88. return &(encd->contentInfo);
  89. }
  90. /*
  91. * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
  92. * before encoding begins.
  93. *
  94. * In particular:
  95. * - set the correct version value.
  96. * - get the encryption key
  97. */
  98. SECStatus
  99. NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
  100. {
  101. int version;
  102. PK11SymKey *bulkkey = NULL;
  103. SECItem *dummy;
  104. NSSCMSContentInfo *cinfo = &(encd->contentInfo);
  105. if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
  106. version = NSS_CMS_ENCRYPTED_DATA_VERSION;
  107. else
  108. version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
  109. dummy = SEC_ASN1EncodeInteger(encd->cmsg->poolp, &(encd->version), version);
  110. if (dummy == NULL)
  111. return SECFailure;
  112. /* now get content encryption key (bulk key) by using our cmsg callback */
  113. if (encd->cmsg->decrypt_key_cb)
  114. bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg,
  115. NSS_CMSContentInfo_GetContentEncAlg(cinfo));
  116. if (bulkkey == NULL)
  117. return SECFailure;
  118. /* store the bulk key in the contentInfo so that the encoder can find it */
  119. NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
  120. PK11_FreeSymKey(bulkkey);
  121. return SECSuccess;
  122. }
  123. /*
  124. * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
  125. */
  126. SECStatus
  127. NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd)
  128. {
  129. NSSCMSContentInfo *cinfo;
  130. PK11SymKey *bulkkey;
  131. SECAlgorithmID *algid;
  132. SECStatus rv;
  133. cinfo = &(encd->contentInfo);
  134. /* find bulkkey and algorithm - must have been set by NSS_CMSEncryptedData_Encode_BeforeStart */
  135. bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
  136. if (bulkkey == NULL)
  137. return SECFailure;
  138. algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
  139. if (algid == NULL)
  140. return SECFailure;
  141. rv = NSS_CMSContentInfo_Private_Init(cinfo);
  142. if (rv != SECSuccess) {
  143. return SECFailure;
  144. }
  145. /* this may modify algid (with IVs generated in a token).
  146. * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
  147. * not just to a copy */
  148. cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp,
  149. bulkkey, algid);
  150. PK11_FreeSymKey(bulkkey);
  151. if (cinfo->privateInfo->ciphcx == NULL)
  152. return SECFailure;
  153. return SECSuccess;
  154. }
  155. /*
  156. * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
  157. */
  158. SECStatus
  159. NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd)
  160. {
  161. if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
  162. NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
  163. encd->contentInfo.privateInfo->ciphcx = NULL;
  164. }
  165. /* nothing to do after data */
  166. return SECSuccess;
  167. }
  168. /*
  169. * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
  170. */
  171. SECStatus
  172. NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd)
  173. {
  174. PK11SymKey *bulkkey = NULL;
  175. NSSCMSContentInfo *cinfo;
  176. SECAlgorithmID *bulkalg;
  177. SECStatus rv = SECFailure;
  178. cinfo = &(encd->contentInfo);
  179. bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
  180. if (encd->cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */
  181. goto loser;
  182. bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
  183. if (bulkkey == NULL)
  184. /* no success finding a bulk key */
  185. goto loser;
  186. NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
  187. rv = NSS_CMSContentInfo_Private_Init(cinfo);
  188. if (rv != SECSuccess) {
  189. goto loser;
  190. }
  191. rv = SECFailure;
  192. cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
  193. if (cinfo->privateInfo->ciphcx == NULL)
  194. goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */
  195. /* we are done with (this) bulkkey now. */
  196. PK11_FreeSymKey(bulkkey);
  197. rv = SECSuccess;
  198. loser:
  199. return rv;
  200. }
  201. /*
  202. * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
  203. */
  204. SECStatus
  205. NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd)
  206. {
  207. if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
  208. NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
  209. encd->contentInfo.privateInfo->ciphcx = NULL;
  210. }
  211. return SECSuccess;
  212. }
  213. /*
  214. * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
  215. */
  216. SECStatus
  217. NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd)
  218. {
  219. /* apply final touches */
  220. return SECSuccess;
  221. }