Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / security / nss / lib / certdb / certxutl.c
blobc28ef211db2c19042804b7249f85c60d611c3851
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * Certificate Extensions handling code
42 #include "cert.h"
43 #include "secitem.h"
44 #include "secoid.h"
45 #include "secder.h"
46 #include "secasn1.h"
47 #include "certxutl.h"
48 #include "secerr.h"
50 #ifdef OLD
51 #include "ocspti.h" /* XXX a better extensions interface would not
52 * require knowledge of data structures of callers */
53 #endif
55 static CERTCertExtension *
56 GetExtension (CERTCertExtension **extensions, SECItem *oid)
58 CERTCertExtension **exts;
59 CERTCertExtension *ext = NULL;
60 SECComparison comp;
62 exts = extensions;
64 if (exts) {
65 while ( *exts ) {
66 ext = *exts;
67 comp = SECITEM_CompareItem(oid, &ext->id);
68 if ( comp == SECEqual )
69 break;
71 exts++;
73 return (*exts ? ext : NULL);
75 return (NULL);
78 SECStatus
79 cert_FindExtensionByOID (CERTCertExtension **extensions, SECItem *oid, SECItem *value)
81 CERTCertExtension *ext;
82 SECStatus rv = SECSuccess;
84 ext = GetExtension (extensions, oid);
85 if (ext == NULL) {
86 PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
87 return (SECFailure);
89 if (value)
90 rv = SECITEM_CopyItem(NULL, value, &ext->value);
91 return (rv);
95 SECStatus
96 CERT_GetExtenCriticality (CERTCertExtension **extensions, int tag, PRBool *isCritical)
98 CERTCertExtension *ext;
99 SECOidData *oid;
101 if (!isCritical)
102 return (SECSuccess);
104 /* find the extension in the extensions list */
105 oid = SECOID_FindOIDByTag((SECOidTag)tag);
106 if ( !oid ) {
107 return(SECFailure);
109 ext = GetExtension (extensions, &oid->oid);
110 if (ext == NULL) {
111 PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
112 return (SECFailure);
115 /* If the criticality is omitted, then it is false by default.
116 ex->critical.data is NULL */
117 if (ext->critical.data == NULL)
118 *isCritical = PR_FALSE;
119 else
120 *isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
121 return (SECSuccess);
124 SECStatus
125 cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
127 SECOidData *oid;
129 oid = SECOID_FindOIDByTag((SECOidTag)tag);
130 if ( !oid ) {
131 return(SECFailure);
134 return(cert_FindExtensionByOID(extensions, &oid->oid, value));
138 typedef struct _extNode {
139 struct _extNode *next;
140 CERTCertExtension *ext;
141 } extNode;
143 typedef struct {
144 void (*setExts)(void *object, CERTCertExtension **exts);
145 void *object;
146 PRArenaPool *ownerArena;
147 PRArenaPool *arena;
148 extNode *head;
149 int count;
150 }extRec;
153 * cert_StartExtensions
155 * NOTE: This interface changed significantly to remove knowledge
156 * about callers data structures (owner objects)
158 void *
159 cert_StartExtensions(void *owner, PRArenaPool *ownerArena,
160 void (*setExts)(void *object, CERTCertExtension **exts))
162 PRArenaPool *arena;
163 extRec *handle;
165 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
166 if ( !arena ) {
167 return(0);
170 handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
171 if ( !handle ) {
172 PORT_FreeArena(arena, PR_FALSE);
173 return(0);
176 handle->object = owner;
177 handle->ownerArena = ownerArena;
178 handle->setExts = setExts;
180 handle->arena = arena;
181 handle->head = 0;
182 handle->count = 0;
184 return(handle);
187 static unsigned char hextrue = 0xff;
190 * Note - assumes that data pointed to by oid->data will not move
192 SECStatus
193 CERT_AddExtensionByOID (void *exthandle, SECItem *oid, SECItem *value,
194 PRBool critical, PRBool copyData)
196 CERTCertExtension *ext;
197 SECStatus rv;
198 extNode *node;
199 extRec *handle;
201 handle = (extRec *)exthandle;
203 /* allocate space for extension and list node */
204 ext = (CERTCertExtension*)PORT_ArenaZAlloc(handle->ownerArena,
205 sizeof(CERTCertExtension));
206 if ( !ext ) {
207 return(SECFailure);
210 node = (extNode*)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
211 if ( !node ) {
212 return(SECFailure);
215 /* add to list */
216 node->next = handle->head;
217 handle->head = node;
219 /* point to ext struct */
220 node->ext = ext;
222 /* the object ID of the extension */
223 ext->id = *oid;
225 /* set critical field */
226 if ( critical ) {
227 ext->critical.data = (unsigned char*)&hextrue;
228 ext->critical.len = 1;
231 /* set the value */
232 if ( copyData ) {
233 rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
234 if ( rv ) {
235 return(SECFailure);
237 } else {
238 ext->value = *value;
241 handle->count++;
243 return(SECSuccess);
247 SECStatus
248 CERT_AddExtension(void *exthandle, int idtag, SECItem *value,
249 PRBool critical, PRBool copyData)
251 SECOidData *oid;
253 oid = SECOID_FindOIDByTag((SECOidTag)idtag);
254 if ( !oid ) {
255 return(SECFailure);
258 return(CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical, copyData));
261 SECStatus
262 CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
263 PRBool critical, const SEC_ASN1Template *atemplate)
265 extRec *handle;
266 SECItem *encitem;
268 handle = (extRec *)exthandle;
270 encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
271 if ( encitem == NULL ) {
272 return(SECFailure);
275 return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
278 void
279 PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
281 unsigned char onebyte;
282 unsigned int i, len = 0;
284 /* to prevent warning on some platform at compile time */
285 onebyte = '\0';
286 /* Get the position of the right-most turn-on bit */
287 for (i = 0; i < (value->len ) * 8; ++i) {
288 if (i % 8 == 0)
289 onebyte = value->data[i/8];
290 if (onebyte & 0x80)
291 len = i;
292 onebyte <<= 1;
295 bitsmap->data = value->data;
296 /* Add one here since we work with base 1 */
297 bitsmap->len = len + 1;
300 SECStatus
301 CERT_EncodeAndAddBitStrExtension (void *exthandle, int idtag,
302 SECItem *value, PRBool critical)
304 SECItem bitsmap;
306 PrepareBitStringForEncoding (&bitsmap, value);
307 return (CERT_EncodeAndAddExtension
308 (exthandle, idtag, &bitsmap, critical,
309 SEC_ASN1_GET(SEC_BitStringTemplate)));
312 SECStatus
313 CERT_FinishExtensions(void *exthandle)
315 extRec *handle;
316 extNode *node;
317 CERTCertExtension **exts;
318 SECStatus rv = SECFailure;
320 handle = (extRec *)exthandle;
322 /* allocate space for extensions array */
323 exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
324 handle->count + 1);
325 if (exts == NULL) {
326 goto loser;
329 /* put extensions in owner object and update its version number */
331 #ifdef OLD
332 switch (handle->type) {
333 case CertificateExtensions:
334 handle->owner.cert->extensions = exts;
335 DER_SetUInteger (ownerArena, &(handle->owner.cert->version),
336 SEC_CERTIFICATE_VERSION_3);
337 break;
338 case CrlExtensions:
339 handle->owner.crl->extensions = exts;
340 DER_SetUInteger (ownerArena, &(handle->owner.crl->version),
341 SEC_CRL_VERSION_2);
342 break;
343 case OCSPRequestExtensions:
344 handle->owner.request->tbsRequest->requestExtensions = exts;
345 break;
346 case OCSPSingleRequestExtensions:
347 handle->owner.singleRequest->singleRequestExtensions = exts;
348 break;
349 case OCSPResponseSingleExtensions:
350 handle->owner.singleResponse->singleExtensions = exts;
351 break;
353 #endif
355 handle->setExts(handle->object, exts);
357 /* update the version number */
359 /* copy each extension pointer */
360 node = handle->head;
361 while ( node ) {
362 *exts = node->ext;
364 node = node->next;
365 exts++;
368 /* terminate the array of extensions */
369 *exts = 0;
371 rv = SECSuccess;
373 loser:
374 /* free working arena */
375 PORT_FreeArena(handle->arena, PR_FALSE);
376 return rv;
379 SECStatus
380 CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
382 CERTCertExtension *ext;
383 SECStatus rv = SECSuccess;
384 SECOidTag tag;
385 extNode *node;
386 extRec *handle = exthandle;
388 if (!exthandle || !extensions) {
389 PORT_SetError(SEC_ERROR_INVALID_ARGS);
390 return SECFailure;
392 while ((ext = *extensions++) != NULL) {
393 tag = SECOID_FindOIDTag(&ext->id);
394 for (node=handle->head; node != NULL; node=node->next) {
395 if (tag == 0) {
396 if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
397 break;
399 else {
400 if (SECOID_FindOIDTag(&node->ext->id) == tag) {
401 break;
405 if (node == NULL) {
406 PRBool critical = (ext->critical.len != 0 &&
407 ext->critical.data[ext->critical.len - 1] != 0);
408 if (critical && tag == SEC_OID_UNKNOWN) {
409 PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
410 rv = SECFailure;
411 break;
413 /* add to list */
414 rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value,
415 critical, PR_TRUE);
416 if (rv != SECSuccess)
417 break;
420 return rv;
424 * get the value of the Netscape Certificate Type Extension
426 SECStatus
427 CERT_FindBitStringExtension (CERTCertExtension **extensions, int tag,
428 SECItem *retItem)
430 SECItem wrapperItem, tmpItem = {siBuffer,0};
431 SECStatus rv;
432 PRArenaPool *arena = NULL;
434 wrapperItem.data = NULL;
435 tmpItem.data = NULL;
437 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
439 if ( ! arena ) {
440 return(SECFailure);
443 rv = cert_FindExtension(extensions, tag, &wrapperItem);
444 if ( rv != SECSuccess ) {
445 goto loser;
448 rv = SEC_QuickDERDecodeItem(arena, &tmpItem,
449 SEC_ASN1_GET(SEC_BitStringTemplate),
450 &wrapperItem);
452 if ( rv != SECSuccess ) {
453 goto loser;
456 retItem->data = (unsigned char *)PORT_Alloc( ( tmpItem.len + 7 ) >> 3 );
457 if ( retItem->data == NULL ) {
458 goto loser;
461 PORT_Memcpy(retItem->data, tmpItem.data, ( tmpItem.len + 7 ) >> 3);
462 retItem->len = tmpItem.len;
464 rv = SECSuccess;
465 goto done;
467 loser:
468 rv = SECFailure;
470 done:
471 if ( arena ) {
472 PORT_FreeArena(arena, PR_FALSE);
475 if ( wrapperItem.data ) {
476 PORT_Free(wrapperItem.data);
479 return(rv);
482 PRBool
483 cert_HasCriticalExtension (CERTCertExtension **extensions)
485 CERTCertExtension **exts;
486 CERTCertExtension *ext = NULL;
487 PRBool hasCriticalExten = PR_FALSE;
489 exts = extensions;
491 if (exts) {
492 while ( *exts ) {
493 ext = *exts;
494 /* If the criticality is omitted, it's non-critical */
495 if (ext->critical.data && ext->critical.data[0] == 0xff) {
496 hasCriticalExten = PR_TRUE;
497 break;
499 exts++;
502 return (hasCriticalExten);
505 PRBool
506 cert_HasUnknownCriticalExten (CERTCertExtension **extensions)
508 CERTCertExtension **exts;
509 CERTCertExtension *ext = NULL;
510 PRBool hasUnknownCriticalExten = PR_FALSE;
512 exts = extensions;
514 if (exts) {
515 while ( *exts ) {
516 ext = *exts;
517 /* If the criticality is omitted, it's non-critical.
518 If an extension is critical, make sure that we know
519 how to process the extension.
521 if (ext->critical.data && ext->critical.data[0] == 0xff) {
522 if (SECOID_KnownCertExtenOID (&ext->id) == PR_FALSE) {
523 hasUnknownCriticalExten = PR_TRUE;
524 break;
527 exts++;
530 return (hasUnknownCriticalExten);