no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / security / nss / lib / certdb / certxutl.c
blob5db2eb9ef000b49ac853c118eee4ade30aa76d94
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/. */
5 /*
6 * Certificate Extensions handling code
8 */
10 #include "cert.h"
11 #include "secitem.h"
12 #include "secoid.h"
13 #include "secder.h"
14 #include "secasn1.h"
15 #include "certxutl.h"
16 #include "secerr.h"
18 #ifdef OLD
19 #include "ocspti.h" /* XXX a better extensions interface would not
20 * require knowledge of data structures of callers */
21 #endif
23 static CERTCertExtension *
24 GetExtension(CERTCertExtension **extensions, SECItem *oid)
26 CERTCertExtension **exts;
27 CERTCertExtension *ext = NULL;
28 SECComparison comp;
30 exts = extensions;
32 if (exts) {
33 while (*exts) {
34 ext = *exts;
35 comp = SECITEM_CompareItem(oid, &ext->id);
36 if (comp == SECEqual)
37 break;
39 exts++;
41 return (*exts ? ext : NULL);
43 return (NULL);
46 SECStatus
47 cert_FindExtensionByOID(CERTCertExtension **extensions, SECItem *oid,
48 SECItem *value)
50 CERTCertExtension *ext;
51 SECStatus rv = SECSuccess;
53 ext = GetExtension(extensions, oid);
54 if (ext == NULL) {
55 PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
56 return (SECFailure);
58 if (value)
59 rv = SECITEM_CopyItem(NULL, value, &ext->value);
60 return (rv);
63 SECStatus
64 CERT_GetExtenCriticality(CERTCertExtension **extensions, int tag,
65 PRBool *isCritical)
67 CERTCertExtension *ext;
68 SECOidData *oid;
70 if (!isCritical)
71 return (SECSuccess);
73 /* find the extension in the extensions list */
74 oid = SECOID_FindOIDByTag((SECOidTag)tag);
75 if (!oid) {
76 return (SECFailure);
78 ext = GetExtension(extensions, &oid->oid);
79 if (ext == NULL) {
80 PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
81 return (SECFailure);
84 /* If the criticality is omitted, then it is false by default.
85 ex->critical.data is NULL */
86 if (ext->critical.data == NULL)
87 *isCritical = PR_FALSE;
88 else
89 *isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
90 return (SECSuccess);
93 SECStatus
94 cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
96 SECOidData *oid;
98 oid = SECOID_FindOIDByTag((SECOidTag)tag);
99 if (!oid) {
100 return (SECFailure);
103 return (cert_FindExtensionByOID(extensions, &oid->oid, value));
106 typedef struct _extNode {
107 struct _extNode *next;
108 CERTCertExtension *ext;
109 } extNode;
111 typedef struct {
112 void (*setExts)(void *object, CERTCertExtension **exts);
113 void *object;
114 PLArenaPool *ownerArena;
115 PLArenaPool *arena;
116 extNode *head;
117 int count;
118 } extRec;
121 * cert_StartExtensions
123 * NOTE: This interface changed significantly to remove knowledge
124 * about callers data structures (owner objects)
126 void *
127 cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
128 void (*setExts)(void *object, CERTCertExtension **exts))
130 PLArenaPool *arena;
131 extRec *handle;
133 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
134 if (!arena) {
135 return (0);
138 handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
139 if (!handle) {
140 PORT_FreeArena(arena, PR_FALSE);
141 return (0);
144 handle->object = owner;
145 handle->ownerArena = ownerArena;
146 handle->setExts = setExts;
148 handle->arena = arena;
149 handle->head = 0;
150 handle->count = 0;
152 return (handle);
155 static unsigned char hextrue = 0xff;
158 * Note - assumes that data pointed to by oid->data will not move
160 SECStatus
161 CERT_AddExtensionByOID(void *exthandle, SECItem *oid, SECItem *value,
162 PRBool critical, PRBool copyData)
164 CERTCertExtension *ext;
165 SECStatus rv;
166 extNode *node;
167 extRec *handle;
169 handle = (extRec *)exthandle;
171 /* allocate space for extension and list node */
172 ext = (CERTCertExtension *)PORT_ArenaZAlloc(handle->ownerArena,
173 sizeof(CERTCertExtension));
174 if (!ext) {
175 return (SECFailure);
178 node = (extNode *)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
179 if (!node) {
180 return (SECFailure);
183 /* add to list */
184 node->next = handle->head;
185 handle->head = node;
187 /* point to ext struct */
188 node->ext = ext;
190 /* set critical field */
191 if (critical) {
192 ext->critical.data = (unsigned char *)&hextrue;
193 ext->critical.len = 1;
196 /* set object ID of the extension and its value */
197 if (copyData) {
198 rv = SECITEM_CopyItem(handle->ownerArena, &ext->id, oid);
199 if (rv) {
200 return (SECFailure);
203 rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
204 if (rv) {
205 return (SECFailure);
207 } else {
208 ext->id = *oid;
209 ext->value = *value;
212 handle->count++;
214 return (SECSuccess);
217 SECStatus
218 CERT_AddExtension(void *exthandle, int idtag, SECItem *value, PRBool critical,
219 PRBool copyData)
221 SECOidData *oid;
223 oid = SECOID_FindOIDByTag((SECOidTag)idtag);
224 if (!oid) {
225 return (SECFailure);
228 return (CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical,
229 copyData));
232 SECStatus
233 CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
234 PRBool critical, const SEC_ASN1Template *atemplate)
236 extRec *handle;
237 SECItem *encitem;
239 handle = (extRec *)exthandle;
241 encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
242 if (encitem == NULL) {
243 return (SECFailure);
246 return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
249 void
250 PrepareBitStringForEncoding(SECItem *bitsmap, SECItem *value)
252 unsigned char onebyte;
253 unsigned int i, len = 0;
255 /* to prevent warning on some platform at compile time */
256 onebyte = '\0';
257 /* Get the position of the right-most turn-on bit */
258 for (i = 0; i < (value->len) * 8; ++i) {
259 if (i % 8 == 0)
260 onebyte = value->data[i / 8];
261 if (onebyte & 0x80)
262 len = i;
263 onebyte <<= 1;
265 bitsmap->data = value->data;
266 /* Add one here since we work with base 1 */
267 bitsmap->len = len + 1;
270 SECStatus
271 CERT_EncodeAndAddBitStrExtension(void *exthandle, int idtag, SECItem *value,
272 PRBool critical)
274 SECItem bitsmap;
276 PrepareBitStringForEncoding(&bitsmap, value);
277 return (CERT_EncodeAndAddExtension(exthandle, idtag, &bitsmap, critical,
278 SEC_ASN1_GET(SEC_BitStringTemplate)));
281 SECStatus
282 CERT_FinishExtensions(void *exthandle)
284 extRec *handle;
285 extNode *node;
286 CERTCertExtension **exts;
287 SECStatus rv = SECFailure;
289 handle = (extRec *)exthandle;
291 /* allocate space for extensions array */
292 exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
293 handle->count + 1);
294 if (exts == NULL) {
295 goto loser;
298 /* put extensions in owner object and update its version number */
300 #ifdef OLD
301 switch (handle->type) {
302 case CertificateExtensions:
303 handle->owner.cert->extensions = exts;
304 DER_SetUInteger(ownerArena, &(handle->owner.cert->version),
305 SEC_CERTIFICATE_VERSION_3);
306 break;
307 case CrlExtensions:
308 handle->owner.crl->extensions = exts;
309 DER_SetUInteger(ownerArena, &(handle->owner.crl->version),
310 SEC_CRL_VERSION_2);
311 break;
312 case OCSPRequestExtensions:
313 handle->owner.request->tbsRequest->requestExtensions = exts;
314 break;
315 case OCSPSingleRequestExtensions:
316 handle->owner.singleRequest->singleRequestExtensions = exts;
317 break;
318 case OCSPResponseSingleExtensions:
319 handle->owner.singleResponse->singleExtensions = exts;
320 break;
322 #endif
324 handle->setExts(handle->object, exts);
326 /* update the version number */
328 /* copy each extension pointer */
329 node = handle->head;
330 while (node) {
331 *exts = node->ext;
333 node = node->next;
334 exts++;
337 /* terminate the array of extensions */
338 *exts = 0;
340 rv = SECSuccess;
342 loser:
343 /* free working arena */
344 PORT_FreeArena(handle->arena, PR_FALSE);
345 return rv;
348 SECStatus
349 CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
351 CERTCertExtension *ext;
352 SECStatus rv = SECSuccess;
353 SECOidTag tag;
354 extNode *node;
355 extRec *handle = exthandle;
357 if (!exthandle || !extensions) {
358 PORT_SetError(SEC_ERROR_INVALID_ARGS);
359 return SECFailure;
361 while ((ext = *extensions++) != NULL) {
362 tag = SECOID_FindOIDTag(&ext->id);
363 for (node = handle->head; node != NULL; node = node->next) {
364 if (tag == 0) {
365 if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
366 break;
367 } else {
368 if (SECOID_FindOIDTag(&node->ext->id) == tag) {
369 break;
373 if (node == NULL) {
374 PRBool critical = (ext->critical.len != 0 &&
375 ext->critical.data[ext->critical.len - 1] != 0);
376 if (critical && tag == SEC_OID_UNKNOWN) {
377 PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
378 rv = SECFailure;
379 break;
381 /* add to list */
382 rv = CERT_AddExtensionByOID(exthandle, &ext->id, &ext->value,
383 critical, PR_TRUE);
384 if (rv != SECSuccess)
385 break;
388 return rv;
392 * get the value of the Netscape Certificate Type Extension
394 SECStatus
395 CERT_FindBitStringExtension(CERTCertExtension **extensions, int tag,
396 SECItem *retItem)
398 SECItem wrapperItem, tmpItem = { siBuffer, 0 };
399 SECStatus rv;
400 PORTCheapArenaPool tmpArena;
402 wrapperItem.data = NULL;
403 tmpItem.data = NULL;
405 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
407 rv = cert_FindExtension(extensions, tag, &wrapperItem);
408 if (rv != SECSuccess) {
409 goto loser;
412 rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &tmpItem,
413 SEC_ASN1_GET(SEC_BitStringTemplate),
414 &wrapperItem);
416 if (rv != SECSuccess) {
417 goto loser;
420 retItem->data = (unsigned char *)PORT_ZAlloc((tmpItem.len + 7) >> 3);
421 if (retItem->data == NULL) {
422 goto loser;
425 if (tmpItem.len > 0) {
426 PORT_Memcpy(retItem->data, tmpItem.data, (tmpItem.len + 7) >> 3);
429 retItem->len = tmpItem.len;
431 rv = SECSuccess;
432 goto done;
434 loser:
435 rv = SECFailure;
437 done:
438 PORT_DestroyCheapArena(&tmpArena);
440 if (wrapperItem.data) {
441 PORT_Free(wrapperItem.data);
444 return (rv);
447 PRBool
448 cert_HasCriticalExtension(CERTCertExtension **extensions)
450 CERTCertExtension **exts;
451 CERTCertExtension *ext = NULL;
452 PRBool hasCriticalExten = PR_FALSE;
454 exts = extensions;
456 if (exts) {
457 while (*exts) {
458 ext = *exts;
459 /* If the criticality is omitted, it's non-critical */
460 if (ext->critical.data && ext->critical.data[0] == 0xff) {
461 hasCriticalExten = PR_TRUE;
462 break;
464 exts++;
467 return (hasCriticalExten);
470 PRBool
471 cert_HasUnknownCriticalExten(CERTCertExtension **extensions)
473 CERTCertExtension **exts;
474 CERTCertExtension *ext = NULL;
475 PRBool hasUnknownCriticalExten = PR_FALSE;
477 exts = extensions;
479 if (exts) {
480 while (*exts) {
481 ext = *exts;
482 /* If the criticality is omitted, it's non-critical.
483 If an extension is critical, make sure that we know
484 how to process the extension.
486 if (ext->critical.data && ext->critical.data[0] == 0xff) {
487 if (SECOID_KnownCertExtenOID(&ext->id) == PR_FALSE) {
488 hasUnknownCriticalExten = PR_TRUE;
489 break;
492 exts++;
495 return (hasUnknownCriticalExten);