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
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.
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
51 #include "ocspti.h" /* XXX a better extensions interface would not
52 * require knowledge of data structures of callers */
55 static CERTCertExtension
*
56 GetExtension (CERTCertExtension
**extensions
, SECItem
*oid
)
58 CERTCertExtension
**exts
;
59 CERTCertExtension
*ext
= NULL
;
67 comp
= SECITEM_CompareItem(oid
, &ext
->id
);
68 if ( comp
== SECEqual
)
73 return (*exts
? ext
: NULL
);
79 cert_FindExtensionByOID (CERTCertExtension
**extensions
, SECItem
*oid
, SECItem
*value
)
81 CERTCertExtension
*ext
;
82 SECStatus rv
= SECSuccess
;
84 ext
= GetExtension (extensions
, oid
);
86 PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND
);
90 rv
= SECITEM_CopyItem(NULL
, value
, &ext
->value
);
96 CERT_GetExtenCriticality (CERTCertExtension
**extensions
, int tag
, PRBool
*isCritical
)
98 CERTCertExtension
*ext
;
104 /* find the extension in the extensions list */
105 oid
= SECOID_FindOIDByTag((SECOidTag
)tag
);
109 ext
= GetExtension (extensions
, &oid
->oid
);
111 PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND
);
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
;
120 *isCritical
= (ext
->critical
.data
[0] == 0xff) ? PR_TRUE
: PR_FALSE
;
125 cert_FindExtension(CERTCertExtension
**extensions
, int tag
, SECItem
*value
)
129 oid
= SECOID_FindOIDByTag((SECOidTag
)tag
);
134 return(cert_FindExtensionByOID(extensions
, &oid
->oid
, value
));
138 typedef struct _extNode
{
139 struct _extNode
*next
;
140 CERTCertExtension
*ext
;
144 void (*setExts
)(void *object
, CERTCertExtension
**exts
);
146 PRArenaPool
*ownerArena
;
153 * cert_StartExtensions
155 * NOTE: This interface changed significantly to remove knowledge
156 * about callers data structures (owner objects)
159 cert_StartExtensions(void *owner
, PRArenaPool
*ownerArena
,
160 void (*setExts
)(void *object
, CERTCertExtension
**exts
))
165 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
170 handle
= (extRec
*)PORT_ArenaAlloc(arena
, sizeof(extRec
));
172 PORT_FreeArena(arena
, PR_FALSE
);
176 handle
->object
= owner
;
177 handle
->ownerArena
= ownerArena
;
178 handle
->setExts
= setExts
;
180 handle
->arena
= arena
;
187 static unsigned char hextrue
= 0xff;
190 * Note - assumes that data pointed to by oid->data will not move
193 CERT_AddExtensionByOID (void *exthandle
, SECItem
*oid
, SECItem
*value
,
194 PRBool critical
, PRBool copyData
)
196 CERTCertExtension
*ext
;
201 handle
= (extRec
*)exthandle
;
203 /* allocate space for extension and list node */
204 ext
= (CERTCertExtension
*)PORT_ArenaZAlloc(handle
->ownerArena
,
205 sizeof(CERTCertExtension
));
210 node
= (extNode
*)PORT_ArenaAlloc(handle
->arena
, sizeof(extNode
));
216 node
->next
= handle
->head
;
219 /* point to ext struct */
222 /* the object ID of the extension */
225 /* set critical field */
227 ext
->critical
.data
= (unsigned char*)&hextrue
;
228 ext
->critical
.len
= 1;
233 rv
= SECITEM_CopyItem(handle
->ownerArena
, &ext
->value
, value
);
248 CERT_AddExtension(void *exthandle
, int idtag
, SECItem
*value
,
249 PRBool critical
, PRBool copyData
)
253 oid
= SECOID_FindOIDByTag((SECOidTag
)idtag
);
258 return(CERT_AddExtensionByOID(exthandle
, &oid
->oid
, value
, critical
, copyData
));
262 CERT_EncodeAndAddExtension(void *exthandle
, int idtag
, void *value
,
263 PRBool critical
, const SEC_ASN1Template
*atemplate
)
268 handle
= (extRec
*)exthandle
;
270 encitem
= SEC_ASN1EncodeItem(handle
->ownerArena
, NULL
, value
, atemplate
);
271 if ( encitem
== NULL
) {
275 return CERT_AddExtension(exthandle
, idtag
, encitem
, critical
, PR_FALSE
);
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 */
286 /* Get the position of the right-most turn-on bit */
287 for (i
= 0; i
< (value
->len
) * 8; ++i
) {
289 onebyte
= value
->data
[i
/8];
295 bitsmap
->data
= value
->data
;
296 /* Add one here since we work with base 1 */
297 bitsmap
->len
= len
+ 1;
301 CERT_EncodeAndAddBitStrExtension (void *exthandle
, int idtag
,
302 SECItem
*value
, PRBool critical
)
306 PrepareBitStringForEncoding (&bitsmap
, value
);
307 return (CERT_EncodeAndAddExtension
308 (exthandle
, idtag
, &bitsmap
, critical
,
309 SEC_ASN1_GET(SEC_BitStringTemplate
)));
313 CERT_FinishExtensions(void *exthandle
)
317 CERTCertExtension
**exts
;
318 SECStatus rv
= SECFailure
;
320 handle
= (extRec
*)exthandle
;
322 /* allocate space for extensions array */
323 exts
= PORT_ArenaNewArray(handle
->ownerArena
, CERTCertExtension
*,
329 /* put extensions in owner object and update its version number */
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
);
339 handle
->owner
.crl
->extensions
= exts
;
340 DER_SetUInteger (ownerArena
, &(handle
->owner
.crl
->version
),
343 case OCSPRequestExtensions
:
344 handle
->owner
.request
->tbsRequest
->requestExtensions
= exts
;
346 case OCSPSingleRequestExtensions
:
347 handle
->owner
.singleRequest
->singleRequestExtensions
= exts
;
349 case OCSPResponseSingleExtensions
:
350 handle
->owner
.singleResponse
->singleExtensions
= exts
;
355 handle
->setExts(handle
->object
, exts
);
357 /* update the version number */
359 /* copy each extension pointer */
368 /* terminate the array of extensions */
374 /* free working arena */
375 PORT_FreeArena(handle
->arena
, PR_FALSE
);
380 CERT_MergeExtensions(void *exthandle
, CERTCertExtension
**extensions
)
382 CERTCertExtension
*ext
;
383 SECStatus rv
= SECSuccess
;
386 extRec
*handle
= exthandle
;
388 if (!exthandle
|| !extensions
) {
389 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
392 while ((ext
= *extensions
++) != NULL
) {
393 tag
= SECOID_FindOIDTag(&ext
->id
);
394 for (node
=handle
->head
; node
!= NULL
; node
=node
->next
) {
396 if (SECITEM_ItemsAreEqual(&ext
->id
, &node
->ext
->id
))
400 if (SECOID_FindOIDTag(&node
->ext
->id
) == tag
) {
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
);
414 rv
= CERT_AddExtensionByOID (exthandle
, &ext
->id
, &ext
->value
,
416 if (rv
!= SECSuccess
)
424 * get the value of the Netscape Certificate Type Extension
427 CERT_FindBitStringExtension (CERTCertExtension
**extensions
, int tag
,
430 SECItem wrapperItem
, tmpItem
= {siBuffer
,0};
432 PRArenaPool
*arena
= NULL
;
434 wrapperItem
.data
= NULL
;
437 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
443 rv
= cert_FindExtension(extensions
, tag
, &wrapperItem
);
444 if ( rv
!= SECSuccess
) {
448 rv
= SEC_QuickDERDecodeItem(arena
, &tmpItem
,
449 SEC_ASN1_GET(SEC_BitStringTemplate
),
452 if ( rv
!= SECSuccess
) {
456 retItem
->data
= (unsigned char *)PORT_Alloc( ( tmpItem
.len
+ 7 ) >> 3 );
457 if ( retItem
->data
== NULL
) {
461 PORT_Memcpy(retItem
->data
, tmpItem
.data
, ( tmpItem
.len
+ 7 ) >> 3);
462 retItem
->len
= tmpItem
.len
;
472 PORT_FreeArena(arena
, PR_FALSE
);
475 if ( wrapperItem
.data
) {
476 PORT_Free(wrapperItem
.data
);
483 cert_HasCriticalExtension (CERTCertExtension
**extensions
)
485 CERTCertExtension
**exts
;
486 CERTCertExtension
*ext
= NULL
;
487 PRBool hasCriticalExten
= PR_FALSE
;
494 /* If the criticality is omitted, it's non-critical */
495 if (ext
->critical
.data
&& ext
->critical
.data
[0] == 0xff) {
496 hasCriticalExten
= PR_TRUE
;
502 return (hasCriticalExten
);
506 cert_HasUnknownCriticalExten (CERTCertExtension
**extensions
)
508 CERTCertExtension
**exts
;
509 CERTCertExtension
*ext
= NULL
;
510 PRBool hasUnknownCriticalExten
= PR_FALSE
;
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
;
530 return (hasUnknownCriticalExten
);