certxutl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  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. * Certificate Extensions handling code
  6. *
  7. */
  8. #include "cert.h"
  9. #include "secitem.h"
  10. #include "secoid.h"
  11. #include "secder.h"
  12. #include "secasn1.h"
  13. #include "certxutl.h"
  14. #include "secerr.h"
  15. #ifdef OLD
  16. #include "ocspti.h" /* XXX a better extensions interface would not
  17. * require knowledge of data structures of callers */
  18. #endif
  19. static CERTCertExtension *
  20. GetExtension(CERTCertExtension **extensions, SECItem *oid)
  21. {
  22. CERTCertExtension **exts;
  23. CERTCertExtension *ext = NULL;
  24. SECComparison comp;
  25. exts = extensions;
  26. if (exts) {
  27. while (*exts) {
  28. ext = *exts;
  29. comp = SECITEM_CompareItem(oid, &ext->id);
  30. if (comp == SECEqual)
  31. break;
  32. exts++;
  33. }
  34. return (*exts ? ext : NULL);
  35. }
  36. return (NULL);
  37. }
  38. SECStatus
  39. cert_FindExtensionByOID(CERTCertExtension **extensions, SECItem *oid,
  40. SECItem *value)
  41. {
  42. CERTCertExtension *ext;
  43. SECStatus rv = SECSuccess;
  44. ext = GetExtension(extensions, oid);
  45. if (ext == NULL) {
  46. PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
  47. return (SECFailure);
  48. }
  49. if (value)
  50. rv = SECITEM_CopyItem(NULL, value, &ext->value);
  51. return (rv);
  52. }
  53. SECStatus
  54. CERT_GetExtenCriticality(CERTCertExtension **extensions, int tag,
  55. PRBool *isCritical)
  56. {
  57. CERTCertExtension *ext;
  58. SECOidData *oid;
  59. if (!isCritical)
  60. return (SECSuccess);
  61. /* find the extension in the extensions list */
  62. oid = SECOID_FindOIDByTag((SECOidTag)tag);
  63. if (!oid) {
  64. return (SECFailure);
  65. }
  66. ext = GetExtension(extensions, &oid->oid);
  67. if (ext == NULL) {
  68. PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
  69. return (SECFailure);
  70. }
  71. /* If the criticality is omitted, then it is false by default.
  72. ex->critical.data is NULL */
  73. if (ext->critical.data == NULL)
  74. *isCritical = PR_FALSE;
  75. else
  76. *isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
  77. return (SECSuccess);
  78. }
  79. SECStatus
  80. cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
  81. {
  82. SECOidData *oid;
  83. oid = SECOID_FindOIDByTag((SECOidTag)tag);
  84. if (!oid) {
  85. return (SECFailure);
  86. }
  87. return (cert_FindExtensionByOID(extensions, &oid->oid, value));
  88. }
  89. typedef struct _extNode {
  90. struct _extNode *next;
  91. CERTCertExtension *ext;
  92. } extNode;
  93. typedef struct {
  94. void (*setExts)(void *object, CERTCertExtension **exts);
  95. void *object;
  96. PLArenaPool *ownerArena;
  97. PLArenaPool *arena;
  98. extNode *head;
  99. int count;
  100. } extRec;
  101. /*
  102. * cert_StartExtensions
  103. *
  104. * NOTE: This interface changed significantly to remove knowledge
  105. * about callers data structures (owner objects)
  106. */
  107. void *
  108. cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
  109. void (*setExts)(void *object, CERTCertExtension **exts))
  110. {
  111. PLArenaPool *arena;
  112. extRec *handle;
  113. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  114. if (!arena) {
  115. return (0);
  116. }
  117. handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
  118. if (!handle) {
  119. PORT_FreeArena(arena, PR_FALSE);
  120. return (0);
  121. }
  122. handle->object = owner;
  123. handle->ownerArena = ownerArena;
  124. handle->setExts = setExts;
  125. handle->arena = arena;
  126. handle->head = 0;
  127. handle->count = 0;
  128. return (handle);
  129. }
  130. static unsigned char hextrue = 0xff;
  131. /*
  132. * Note - assumes that data pointed to by oid->data will not move
  133. */
  134. SECStatus
  135. CERT_AddExtensionByOID(void *exthandle, SECItem *oid, SECItem *value,
  136. PRBool critical, PRBool copyData)
  137. {
  138. CERTCertExtension *ext;
  139. SECStatus rv;
  140. extNode *node;
  141. extRec *handle;
  142. handle = (extRec *)exthandle;
  143. /* allocate space for extension and list node */
  144. ext = (CERTCertExtension *)PORT_ArenaZAlloc(handle->ownerArena,
  145. sizeof(CERTCertExtension));
  146. if (!ext) {
  147. return (SECFailure);
  148. }
  149. node = (extNode *)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
  150. if (!node) {
  151. return (SECFailure);
  152. }
  153. /* add to list */
  154. node->next = handle->head;
  155. handle->head = node;
  156. /* point to ext struct */
  157. node->ext = ext;
  158. /* set critical field */
  159. if (critical) {
  160. ext->critical.data = (unsigned char *)&hextrue;
  161. ext->critical.len = 1;
  162. }
  163. /* set object ID of the extension and its value */
  164. if (copyData) {
  165. rv = SECITEM_CopyItem(handle->ownerArena, &ext->id, oid);
  166. if (rv) {
  167. return (SECFailure);
  168. }
  169. rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
  170. if (rv) {
  171. return (SECFailure);
  172. }
  173. } else {
  174. ext->id = *oid;
  175. ext->value = *value;
  176. }
  177. handle->count++;
  178. return (SECSuccess);
  179. }
  180. SECStatus
  181. CERT_AddExtension(void *exthandle, int idtag, SECItem *value, PRBool critical,
  182. PRBool copyData)
  183. {
  184. SECOidData *oid;
  185. oid = SECOID_FindOIDByTag((SECOidTag)idtag);
  186. if (!oid) {
  187. return (SECFailure);
  188. }
  189. return (CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical,
  190. copyData));
  191. }
  192. SECStatus
  193. CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
  194. PRBool critical, const SEC_ASN1Template *atemplate)
  195. {
  196. extRec *handle;
  197. SECItem *encitem;
  198. handle = (extRec *)exthandle;
  199. encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
  200. if (encitem == NULL) {
  201. return (SECFailure);
  202. }
  203. return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
  204. }
  205. void
  206. PrepareBitStringForEncoding(SECItem *bitsmap, SECItem *value)
  207. {
  208. unsigned char onebyte;
  209. unsigned int i, len = 0;
  210. /* to prevent warning on some platform at compile time */
  211. onebyte = '\0';
  212. /* Get the position of the right-most turn-on bit */
  213. for (i = 0; i < (value->len) * 8; ++i) {
  214. if (i % 8 == 0)
  215. onebyte = value->data[i / 8];
  216. if (onebyte & 0x80)
  217. len = i;
  218. onebyte <<= 1;
  219. }
  220. bitsmap->data = value->data;
  221. /* Add one here since we work with base 1 */
  222. bitsmap->len = len + 1;
  223. }
  224. SECStatus
  225. CERT_EncodeAndAddBitStrExtension(void *exthandle, int idtag, SECItem *value,
  226. PRBool critical)
  227. {
  228. SECItem bitsmap;
  229. PrepareBitStringForEncoding(&bitsmap, value);
  230. return (CERT_EncodeAndAddExtension(exthandle, idtag, &bitsmap, critical,
  231. SEC_ASN1_GET(SEC_BitStringTemplate)));
  232. }
  233. SECStatus
  234. CERT_FinishExtensions(void *exthandle)
  235. {
  236. extRec *handle;
  237. extNode *node;
  238. CERTCertExtension **exts;
  239. SECStatus rv = SECFailure;
  240. handle = (extRec *)exthandle;
  241. /* allocate space for extensions array */
  242. exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
  243. handle->count + 1);
  244. if (exts == NULL) {
  245. goto loser;
  246. }
  247. /* put extensions in owner object and update its version number */
  248. #ifdef OLD
  249. switch (handle->type) {
  250. case CertificateExtensions:
  251. handle->owner.cert->extensions = exts;
  252. DER_SetUInteger(ownerArena, &(handle->owner.cert->version),
  253. SEC_CERTIFICATE_VERSION_3);
  254. break;
  255. case CrlExtensions:
  256. handle->owner.crl->extensions = exts;
  257. DER_SetUInteger(ownerArena, &(handle->owner.crl->version),
  258. SEC_CRL_VERSION_2);
  259. break;
  260. case OCSPRequestExtensions:
  261. handle->owner.request->tbsRequest->requestExtensions = exts;
  262. break;
  263. case OCSPSingleRequestExtensions:
  264. handle->owner.singleRequest->singleRequestExtensions = exts;
  265. break;
  266. case OCSPResponseSingleExtensions:
  267. handle->owner.singleResponse->singleExtensions = exts;
  268. break;
  269. }
  270. #endif
  271. handle->setExts(handle->object, exts);
  272. /* update the version number */
  273. /* copy each extension pointer */
  274. node = handle->head;
  275. while (node) {
  276. *exts = node->ext;
  277. node = node->next;
  278. exts++;
  279. }
  280. /* terminate the array of extensions */
  281. *exts = 0;
  282. rv = SECSuccess;
  283. loser:
  284. /* free working arena */
  285. PORT_FreeArena(handle->arena, PR_FALSE);
  286. return rv;
  287. }
  288. SECStatus
  289. CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
  290. {
  291. CERTCertExtension *ext;
  292. SECStatus rv = SECSuccess;
  293. SECOidTag tag;
  294. extNode *node;
  295. extRec *handle = exthandle;
  296. if (!exthandle || !extensions) {
  297. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  298. return SECFailure;
  299. }
  300. while ((ext = *extensions++) != NULL) {
  301. tag = SECOID_FindOIDTag(&ext->id);
  302. for (node = handle->head; node != NULL; node = node->next) {
  303. if (tag == 0) {
  304. if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
  305. break;
  306. } else {
  307. if (SECOID_FindOIDTag(&node->ext->id) == tag) {
  308. break;
  309. }
  310. }
  311. }
  312. if (node == NULL) {
  313. PRBool critical = (ext->critical.len != 0 &&
  314. ext->critical.data[ext->critical.len - 1] != 0);
  315. if (critical && tag == SEC_OID_UNKNOWN) {
  316. PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
  317. rv = SECFailure;
  318. break;
  319. }
  320. /* add to list */
  321. rv = CERT_AddExtensionByOID(exthandle, &ext->id, &ext->value,
  322. critical, PR_TRUE);
  323. if (rv != SECSuccess)
  324. break;
  325. }
  326. }
  327. return rv;
  328. }
  329. /*
  330. * get the value of the Netscape Certificate Type Extension
  331. */
  332. SECStatus
  333. CERT_FindBitStringExtension(CERTCertExtension **extensions, int tag,
  334. SECItem *retItem)
  335. {
  336. SECItem wrapperItem, tmpItem = { siBuffer, 0 };
  337. SECStatus rv;
  338. PORTCheapArenaPool tmpArena;
  339. wrapperItem.data = NULL;
  340. tmpItem.data = NULL;
  341. PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
  342. rv = cert_FindExtension(extensions, tag, &wrapperItem);
  343. if (rv != SECSuccess) {
  344. goto loser;
  345. }
  346. rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &tmpItem,
  347. SEC_ASN1_GET(SEC_BitStringTemplate),
  348. &wrapperItem);
  349. if (rv != SECSuccess) {
  350. goto loser;
  351. }
  352. retItem->data = (unsigned char *)PORT_Alloc((tmpItem.len + 7) >> 3);
  353. if (retItem->data == NULL) {
  354. goto loser;
  355. }
  356. PORT_Memcpy(retItem->data, tmpItem.data, (tmpItem.len + 7) >> 3);
  357. retItem->len = tmpItem.len;
  358. rv = SECSuccess;
  359. goto done;
  360. loser:
  361. rv = SECFailure;
  362. done:
  363. PORT_DestroyCheapArena(&tmpArena);
  364. if (wrapperItem.data) {
  365. PORT_Free(wrapperItem.data);
  366. }
  367. return (rv);
  368. }
  369. PRBool
  370. cert_HasCriticalExtension(CERTCertExtension **extensions)
  371. {
  372. CERTCertExtension **exts;
  373. CERTCertExtension *ext = NULL;
  374. PRBool hasCriticalExten = PR_FALSE;
  375. exts = extensions;
  376. if (exts) {
  377. while (*exts) {
  378. ext = *exts;
  379. /* If the criticality is omitted, it's non-critical */
  380. if (ext->critical.data && ext->critical.data[0] == 0xff) {
  381. hasCriticalExten = PR_TRUE;
  382. break;
  383. }
  384. exts++;
  385. }
  386. }
  387. return (hasCriticalExten);
  388. }
  389. PRBool
  390. cert_HasUnknownCriticalExten(CERTCertExtension **extensions)
  391. {
  392. CERTCertExtension **exts;
  393. CERTCertExtension *ext = NULL;
  394. PRBool hasUnknownCriticalExten = PR_FALSE;
  395. exts = extensions;
  396. if (exts) {
  397. while (*exts) {
  398. ext = *exts;
  399. /* If the criticality is omitted, it's non-critical.
  400. If an extension is critical, make sure that we know
  401. how to process the extension.
  402. */
  403. if (ext->critical.data && ext->critical.data[0] == 0xff) {
  404. if (SECOID_KnownCertExtenOID(&ext->id) == PR_FALSE) {
  405. hasUnknownCriticalExten = PR_TRUE;
  406. break;
  407. }
  408. }
  409. exts++;
  410. }
  411. }
  412. return (hasUnknownCriticalExten);
  413. }