cmsudf.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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 User Define Types
  6. */
  7. #include "cmslocal.h"
  8. #include "prinit.h"
  9. #include "pk11func.h"
  10. #include "secitem.h"
  11. #include "secoid.h"
  12. #include "secerr.h"
  13. #include "nss.h"
  14. typedef struct nsscmstypeInfoStr nsscmstypeInfo;
  15. struct nsscmstypeInfoStr {
  16. SECOidTag type;
  17. SEC_ASN1Template *template;
  18. size_t size;
  19. PRBool isData;
  20. NSSCMSGenericWrapperDataDestroy destroy;
  21. NSSCMSGenericWrapperDataCallback decode_before;
  22. NSSCMSGenericWrapperDataCallback decode_after;
  23. NSSCMSGenericWrapperDataCallback decode_end;
  24. NSSCMSGenericWrapperDataCallback encode_start;
  25. NSSCMSGenericWrapperDataCallback encode_before;
  26. NSSCMSGenericWrapperDataCallback encode_after;
  27. };
  28. /* make sure the global tables are only initialized once */
  29. static PRCallOnceType nsscmstypeOnce;
  30. static PRCallOnceType nsscmstypeClearOnce;
  31. /* lock for adding a new entry */
  32. static PRLock *nsscmstypeAddLock;
  33. /* lock for the hash table */
  34. static PRLock *nsscmstypeHashLock;
  35. /* the hash table itself */
  36. static PLHashTable *nsscmstypeHash;
  37. /* arena to hold all the hash table data */
  38. static PLArenaPool *nsscmstypeArena;
  39. /*
  40. * clean up our global tables
  41. */
  42. SECStatus
  43. nss_cmstype_shutdown(void *appData, void *reserved)
  44. {
  45. if (nsscmstypeHashLock) {
  46. PR_Lock(nsscmstypeHashLock);
  47. }
  48. if (nsscmstypeHash) {
  49. PL_HashTableDestroy(nsscmstypeHash);
  50. nsscmstypeHash = NULL;
  51. }
  52. if (nsscmstypeArena) {
  53. PORT_FreeArena(nsscmstypeArena, PR_FALSE);
  54. nsscmstypeArena = NULL;
  55. }
  56. if (nsscmstypeAddLock) {
  57. PR_DestroyLock(nsscmstypeAddLock);
  58. }
  59. if (nsscmstypeHashLock) {
  60. PRLock *oldLock = nsscmstypeHashLock;
  61. nsscmstypeHashLock = NULL;
  62. PR_Unlock(oldLock);
  63. PR_DestroyLock(oldLock);
  64. }
  65. /* don't clear out the PR_ONCE data if we failed our inital call */
  66. if (appData == NULL) {
  67. nsscmstypeOnce = nsscmstypeClearOnce;
  68. }
  69. return SECSuccess;
  70. }
  71. static PLHashNumber
  72. nss_cmstype_hash_key(const void *key)
  73. {
  74. return (PLHashNumber)((char *)key - (char *)NULL);
  75. }
  76. static PRIntn
  77. nss_cmstype_compare_keys(const void *v1, const void *v2)
  78. {
  79. PLHashNumber value1 = nss_cmstype_hash_key(v1);
  80. PLHashNumber value2 = nss_cmstype_hash_key(v2);
  81. return (value1 == value2);
  82. }
  83. /*
  84. * initialize our hash tables, called once on the first attemat to register
  85. * a new SMIME type.
  86. */
  87. static PRStatus
  88. nss_cmstype_init(void)
  89. {
  90. SECStatus rv;
  91. nsscmstypeHashLock = PR_NewLock();
  92. if (nsscmstypeHashLock == NULL) {
  93. return PR_FAILURE;
  94. }
  95. nsscmstypeAddLock = PR_NewLock();
  96. if (nsscmstypeHashLock == NULL) {
  97. goto fail;
  98. }
  99. nsscmstypeHash = PL_NewHashTable(64, nss_cmstype_hash_key,
  100. nss_cmstype_compare_keys,
  101. PL_CompareValues, NULL, NULL);
  102. if (nsscmstypeHash == NULL) {
  103. goto fail;
  104. }
  105. nsscmstypeArena = PORT_NewArena(2048);
  106. if (nsscmstypeArena == NULL) {
  107. goto fail;
  108. }
  109. rv = NSS_RegisterShutdown(nss_cmstype_shutdown, NULL);
  110. if (rv != SECSuccess) {
  111. goto fail;
  112. }
  113. return PR_SUCCESS;
  114. fail:
  115. nss_cmstype_shutdown(&nsscmstypeOnce, NULL);
  116. return PR_FAILURE;
  117. }
  118. /*
  119. * look up and registered SIME type
  120. */
  121. static const nsscmstypeInfo *
  122. nss_cmstype_lookup(SECOidTag type)
  123. {
  124. nsscmstypeInfo *typeInfo = NULL;
  125. ;
  126. if (!nsscmstypeHash) {
  127. return NULL;
  128. }
  129. PR_Lock(nsscmstypeHashLock);
  130. if (nsscmstypeHash) {
  131. typeInfo = PL_HashTableLookupConst(nsscmstypeHash, (void *)type);
  132. }
  133. PR_Unlock(nsscmstypeHashLock);
  134. return typeInfo;
  135. }
  136. /*
  137. * add a new type to the SMIME type table
  138. */
  139. static SECStatus
  140. nss_cmstype_add(SECOidTag type, nsscmstypeInfo *typeinfo)
  141. {
  142. PLHashEntry *entry;
  143. if (!nsscmstypeHash) {
  144. /* assert? this shouldn't happen */
  145. return SECFailure;
  146. }
  147. PR_Lock(nsscmstypeHashLock);
  148. /* this is really paranoia. If we really are racing nsscmstypeHash, we'll
  149. * also be racing nsscmstypeHashLock... */
  150. if (!nsscmstypeHash) {
  151. PR_Unlock(nsscmstypeHashLock);
  152. return SECFailure;
  153. }
  154. entry = PL_HashTableAdd(nsscmstypeHash, (void *)type, typeinfo);
  155. PR_Unlock(nsscmstypeHashLock);
  156. return entry ? SECSuccess : SECFailure;
  157. }
  158. /* helper functions to manage new content types
  159. */
  160. PRBool
  161. NSS_CMSType_IsWrapper(SECOidTag type)
  162. {
  163. const nsscmstypeInfo *typeInfo = NULL;
  164. switch (type) {
  165. case SEC_OID_PKCS7_SIGNED_DATA:
  166. case SEC_OID_PKCS7_ENVELOPED_DATA:
  167. case SEC_OID_PKCS7_DIGESTED_DATA:
  168. case SEC_OID_PKCS7_ENCRYPTED_DATA:
  169. return PR_TRUE;
  170. default:
  171. typeInfo = nss_cmstype_lookup(type);
  172. if (typeInfo && !typeInfo->isData) {
  173. return PR_TRUE;
  174. }
  175. }
  176. return PR_FALSE;
  177. }
  178. PRBool
  179. NSS_CMSType_IsData(SECOidTag type)
  180. {
  181. const nsscmstypeInfo *typeInfo = NULL;
  182. switch (type) {
  183. case SEC_OID_PKCS7_DATA:
  184. return PR_TRUE;
  185. default:
  186. typeInfo = nss_cmstype_lookup(type);
  187. if (typeInfo && typeInfo->isData) {
  188. return PR_TRUE;
  189. }
  190. }
  191. return PR_FALSE;
  192. }
  193. const SEC_ASN1Template *
  194. NSS_CMSType_GetTemplate(SECOidTag type)
  195. {
  196. const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
  197. if (typeInfo && typeInfo->template) {
  198. return typeInfo->template;
  199. }
  200. return SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
  201. }
  202. size_t
  203. NSS_CMSType_GetContentSize(SECOidTag type)
  204. {
  205. const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
  206. if (typeInfo) {
  207. return typeInfo->size;
  208. }
  209. return sizeof(SECItem *);
  210. }
  211. void
  212. NSS_CMSGenericWrapperData_Destroy(SECOidTag type, NSSCMSGenericWrapperData *gd)
  213. {
  214. const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
  215. if (typeInfo && (typeInfo->destroy) && (gd != NULL)) {
  216. (*typeInfo->destroy)(gd);
  217. }
  218. }
  219. SECStatus
  220. NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type,
  221. NSSCMSGenericWrapperData *gd)
  222. {
  223. const nsscmstypeInfo *typeInfo;
  224. /* short cut common case */
  225. if (type == SEC_OID_PKCS7_DATA) {
  226. return SECSuccess;
  227. }
  228. typeInfo = nss_cmstype_lookup(type);
  229. if (typeInfo) {
  230. if (typeInfo->decode_before) {
  231. return (*typeInfo->decode_before)(gd);
  232. }
  233. /* decoder ops optional for data tags */
  234. if (typeInfo->isData) {
  235. return SECSuccess;
  236. }
  237. }
  238. /* expected a function, but none existed */
  239. return SECFailure;
  240. }
  241. SECStatus
  242. NSS_CMSGenericWrapperData_Decode_AfterData(SECOidTag type,
  243. NSSCMSGenericWrapperData *gd)
  244. {
  245. const nsscmstypeInfo *typeInfo;
  246. /* short cut common case */
  247. if (type == SEC_OID_PKCS7_DATA) {
  248. return SECSuccess;
  249. }
  250. typeInfo = nss_cmstype_lookup(type);
  251. if (typeInfo) {
  252. if (typeInfo->decode_after) {
  253. return (*typeInfo->decode_after)(gd);
  254. }
  255. /* decoder ops optional for data tags */
  256. if (typeInfo->isData) {
  257. return SECSuccess;
  258. }
  259. }
  260. /* expected a function, but none existed */
  261. return SECFailure;
  262. }
  263. SECStatus
  264. NSS_CMSGenericWrapperData_Decode_AfterEnd(SECOidTag type,
  265. NSSCMSGenericWrapperData *gd)
  266. {
  267. const nsscmstypeInfo *typeInfo;
  268. /* short cut common case */
  269. if (type == SEC_OID_PKCS7_DATA) {
  270. return SECSuccess;
  271. }
  272. typeInfo = nss_cmstype_lookup(type);
  273. if (typeInfo) {
  274. if (typeInfo->decode_end) {
  275. return (*typeInfo->decode_end)(gd);
  276. }
  277. /* decoder ops optional for data tags */
  278. if (typeInfo->isData) {
  279. return SECSuccess;
  280. }
  281. }
  282. /* expected a function, but none existed */
  283. return SECFailure;
  284. }
  285. SECStatus
  286. NSS_CMSGenericWrapperData_Encode_BeforeStart(SECOidTag type,
  287. NSSCMSGenericWrapperData *gd)
  288. {
  289. const nsscmstypeInfo *typeInfo;
  290. /* short cut common case */
  291. if (type == SEC_OID_PKCS7_DATA) {
  292. return SECSuccess;
  293. }
  294. typeInfo = nss_cmstype_lookup(type);
  295. if (typeInfo) {
  296. if (typeInfo->encode_start) {
  297. return (*typeInfo->encode_start)(gd);
  298. }
  299. /* decoder ops optional for data tags */
  300. if (typeInfo->isData) {
  301. return SECSuccess;
  302. }
  303. }
  304. /* expected a function, but none existed */
  305. return SECFailure;
  306. }
  307. SECStatus
  308. NSS_CMSGenericWrapperData_Encode_BeforeData(SECOidTag type,
  309. NSSCMSGenericWrapperData *gd)
  310. {
  311. const nsscmstypeInfo *typeInfo;
  312. /* short cut common case */
  313. if (type == SEC_OID_PKCS7_DATA) {
  314. return SECSuccess;
  315. }
  316. typeInfo = nss_cmstype_lookup(type);
  317. if (typeInfo) {
  318. if (typeInfo->encode_before) {
  319. return (*typeInfo->encode_before)(gd);
  320. }
  321. /* decoder ops optional for data tags */
  322. if (typeInfo->isData) {
  323. return SECSuccess;
  324. }
  325. }
  326. /* expected a function, but none existed */
  327. return SECFailure;
  328. }
  329. SECStatus
  330. NSS_CMSGenericWrapperData_Encode_AfterData(SECOidTag type,
  331. NSSCMSGenericWrapperData *gd)
  332. {
  333. const nsscmstypeInfo *typeInfo;
  334. /* short cut common case */
  335. if (type == SEC_OID_PKCS7_DATA) {
  336. return SECSuccess;
  337. }
  338. typeInfo = nss_cmstype_lookup(type);
  339. if (typeInfo) {
  340. if (typeInfo->encode_after) {
  341. return (*typeInfo->encode_after)(gd);
  342. }
  343. /* decoder ops optional for data tags */
  344. if (typeInfo->isData) {
  345. return SECSuccess;
  346. }
  347. }
  348. /* expected a function, but none existed */
  349. return SECFailure;
  350. }
  351. SECStatus
  352. NSS_CMSType_RegisterContentType(SECOidTag type,
  353. SEC_ASN1Template *asn1Template, size_t size,
  354. NSSCMSGenericWrapperDataDestroy destroy,
  355. NSSCMSGenericWrapperDataCallback decode_before,
  356. NSSCMSGenericWrapperDataCallback decode_after,
  357. NSSCMSGenericWrapperDataCallback decode_end,
  358. NSSCMSGenericWrapperDataCallback encode_start,
  359. NSSCMSGenericWrapperDataCallback encode_before,
  360. NSSCMSGenericWrapperDataCallback encode_after,
  361. PRBool isData)
  362. {
  363. PRStatus rc;
  364. SECStatus rv;
  365. nsscmstypeInfo *typeInfo;
  366. const nsscmstypeInfo *exists;
  367. rc = PR_CallOnce(&nsscmstypeOnce, nss_cmstype_init);
  368. if (rc == PR_FAILURE) {
  369. return SECFailure;
  370. }
  371. PR_Lock(nsscmstypeAddLock);
  372. exists = nss_cmstype_lookup(type);
  373. if (exists) {
  374. PR_Unlock(nsscmstypeAddLock);
  375. /* already added */
  376. return SECSuccess;
  377. }
  378. typeInfo = PORT_ArenaNew(nsscmstypeArena, nsscmstypeInfo);
  379. typeInfo->type = type;
  380. typeInfo->size = size;
  381. typeInfo->isData = isData;
  382. typeInfo->template = asn1Template;
  383. typeInfo->destroy = destroy;
  384. typeInfo->decode_before = decode_before;
  385. typeInfo->decode_after = decode_after;
  386. typeInfo->decode_end = decode_end;
  387. typeInfo->encode_start = encode_start;
  388. typeInfo->encode_before = encode_before;
  389. typeInfo->encode_after = encode_after;
  390. rv = nss_cmstype_add(type, typeInfo);
  391. PR_Unlock(nsscmstypeAddLock);
  392. return rv;
  393. }