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/. */
6 * Certificate Extensions handling code
19 #include "ocspti.h" /* XXX a better extensions interface would not
20 * require knowledge of data structures of callers */
23 static CERTCertExtension
*
24 GetExtension(CERTCertExtension
**extensions
, SECItem
*oid
)
26 CERTCertExtension
**exts
;
27 CERTCertExtension
*ext
= NULL
;
35 comp
= SECITEM_CompareItem(oid
, &ext
->id
);
41 return (*exts
? ext
: NULL
);
47 cert_FindExtensionByOID(CERTCertExtension
**extensions
, SECItem
*oid
,
50 CERTCertExtension
*ext
;
51 SECStatus rv
= SECSuccess
;
53 ext
= GetExtension(extensions
, oid
);
55 PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND
);
59 rv
= SECITEM_CopyItem(NULL
, value
, &ext
->value
);
64 CERT_GetExtenCriticality(CERTCertExtension
**extensions
, int tag
,
67 CERTCertExtension
*ext
;
73 /* find the extension in the extensions list */
74 oid
= SECOID_FindOIDByTag((SECOidTag
)tag
);
78 ext
= GetExtension(extensions
, &oid
->oid
);
80 PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND
);
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
;
89 *isCritical
= (ext
->critical
.data
[0] == 0xff) ? PR_TRUE
: PR_FALSE
;
94 cert_FindExtension(CERTCertExtension
**extensions
, int tag
, SECItem
*value
)
98 oid
= SECOID_FindOIDByTag((SECOidTag
)tag
);
103 return (cert_FindExtensionByOID(extensions
, &oid
->oid
, value
));
106 typedef struct _extNode
{
107 struct _extNode
*next
;
108 CERTCertExtension
*ext
;
112 void (*setExts
)(void *object
, CERTCertExtension
**exts
);
114 PLArenaPool
*ownerArena
;
121 * cert_StartExtensions
123 * NOTE: This interface changed significantly to remove knowledge
124 * about callers data structures (owner objects)
127 cert_StartExtensions(void *owner
, PLArenaPool
*ownerArena
,
128 void (*setExts
)(void *object
, CERTCertExtension
**exts
))
133 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
138 handle
= (extRec
*)PORT_ArenaAlloc(arena
, sizeof(extRec
));
140 PORT_FreeArena(arena
, PR_FALSE
);
144 handle
->object
= owner
;
145 handle
->ownerArena
= ownerArena
;
146 handle
->setExts
= setExts
;
148 handle
->arena
= arena
;
155 static unsigned char hextrue
= 0xff;
158 * Note - assumes that data pointed to by oid->data will not move
161 CERT_AddExtensionByOID(void *exthandle
, SECItem
*oid
, SECItem
*value
,
162 PRBool critical
, PRBool copyData
)
164 CERTCertExtension
*ext
;
169 handle
= (extRec
*)exthandle
;
171 /* allocate space for extension and list node */
172 ext
= (CERTCertExtension
*)PORT_ArenaZAlloc(handle
->ownerArena
,
173 sizeof(CERTCertExtension
));
178 node
= (extNode
*)PORT_ArenaAlloc(handle
->arena
, sizeof(extNode
));
184 node
->next
= handle
->head
;
187 /* point to ext struct */
190 /* set critical field */
192 ext
->critical
.data
= (unsigned char *)&hextrue
;
193 ext
->critical
.len
= 1;
196 /* set object ID of the extension and its value */
198 rv
= SECITEM_CopyItem(handle
->ownerArena
, &ext
->id
, oid
);
203 rv
= SECITEM_CopyItem(handle
->ownerArena
, &ext
->value
, value
);
218 CERT_AddExtension(void *exthandle
, int idtag
, SECItem
*value
, PRBool critical
,
223 oid
= SECOID_FindOIDByTag((SECOidTag
)idtag
);
228 return (CERT_AddExtensionByOID(exthandle
, &oid
->oid
, value
, critical
,
233 CERT_EncodeAndAddExtension(void *exthandle
, int idtag
, void *value
,
234 PRBool critical
, const SEC_ASN1Template
*atemplate
)
239 handle
= (extRec
*)exthandle
;
241 encitem
= SEC_ASN1EncodeItem(handle
->ownerArena
, NULL
, value
, atemplate
);
242 if (encitem
== NULL
) {
246 return CERT_AddExtension(exthandle
, idtag
, encitem
, critical
, PR_FALSE
);
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 */
257 /* Get the position of the right-most turn-on bit */
258 for (i
= 0; i
< (value
->len
) * 8; ++i
) {
260 onebyte
= value
->data
[i
/ 8];
265 bitsmap
->data
= value
->data
;
266 /* Add one here since we work with base 1 */
267 bitsmap
->len
= len
+ 1;
271 CERT_EncodeAndAddBitStrExtension(void *exthandle
, int idtag
, SECItem
*value
,
276 PrepareBitStringForEncoding(&bitsmap
, value
);
277 return (CERT_EncodeAndAddExtension(exthandle
, idtag
, &bitsmap
, critical
,
278 SEC_ASN1_GET(SEC_BitStringTemplate
)));
282 CERT_FinishExtensions(void *exthandle
)
286 CERTCertExtension
**exts
;
287 SECStatus rv
= SECFailure
;
289 handle
= (extRec
*)exthandle
;
291 /* allocate space for extensions array */
292 exts
= PORT_ArenaNewArray(handle
->ownerArena
, CERTCertExtension
*,
298 /* put extensions in owner object and update its version number */
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
);
308 handle
->owner
.crl
->extensions
= exts
;
309 DER_SetUInteger(ownerArena
, &(handle
->owner
.crl
->version
),
312 case OCSPRequestExtensions
:
313 handle
->owner
.request
->tbsRequest
->requestExtensions
= exts
;
315 case OCSPSingleRequestExtensions
:
316 handle
->owner
.singleRequest
->singleRequestExtensions
= exts
;
318 case OCSPResponseSingleExtensions
:
319 handle
->owner
.singleResponse
->singleExtensions
= exts
;
324 handle
->setExts(handle
->object
, exts
);
326 /* update the version number */
328 /* copy each extension pointer */
337 /* terminate the array of extensions */
343 /* free working arena */
344 PORT_FreeArena(handle
->arena
, PR_FALSE
);
349 CERT_MergeExtensions(void *exthandle
, CERTCertExtension
**extensions
)
351 CERTCertExtension
*ext
;
352 SECStatus rv
= SECSuccess
;
355 extRec
*handle
= exthandle
;
357 if (!exthandle
|| !extensions
) {
358 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
361 while ((ext
= *extensions
++) != NULL
) {
362 tag
= SECOID_FindOIDTag(&ext
->id
);
363 for (node
= handle
->head
; node
!= NULL
; node
= node
->next
) {
365 if (SECITEM_ItemsAreEqual(&ext
->id
, &node
->ext
->id
))
368 if (SECOID_FindOIDTag(&node
->ext
->id
) == tag
) {
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
);
382 rv
= CERT_AddExtensionByOID(exthandle
, &ext
->id
, &ext
->value
,
384 if (rv
!= SECSuccess
)
392 * get the value of the Netscape Certificate Type Extension
395 CERT_FindBitStringExtension(CERTCertExtension
**extensions
, int tag
,
398 SECItem wrapperItem
, tmpItem
= { siBuffer
, 0 };
400 PORTCheapArenaPool tmpArena
;
402 wrapperItem
.data
= NULL
;
405 PORT_InitCheapArena(&tmpArena
, DER_DEFAULT_CHUNKSIZE
);
407 rv
= cert_FindExtension(extensions
, tag
, &wrapperItem
);
408 if (rv
!= SECSuccess
) {
412 rv
= SEC_QuickDERDecodeItem(&tmpArena
.arena
, &tmpItem
,
413 SEC_ASN1_GET(SEC_BitStringTemplate
),
416 if (rv
!= SECSuccess
) {
420 retItem
->data
= (unsigned char *)PORT_ZAlloc((tmpItem
.len
+ 7) >> 3);
421 if (retItem
->data
== NULL
) {
425 if (tmpItem
.len
> 0) {
426 PORT_Memcpy(retItem
->data
, tmpItem
.data
, (tmpItem
.len
+ 7) >> 3);
429 retItem
->len
= tmpItem
.len
;
438 PORT_DestroyCheapArena(&tmpArena
);
440 if (wrapperItem
.data
) {
441 PORT_Free(wrapperItem
.data
);
448 cert_HasCriticalExtension(CERTCertExtension
**extensions
)
450 CERTCertExtension
**exts
;
451 CERTCertExtension
*ext
= NULL
;
452 PRBool hasCriticalExten
= PR_FALSE
;
459 /* If the criticality is omitted, it's non-critical */
460 if (ext
->critical
.data
&& ext
->critical
.data
[0] == 0xff) {
461 hasCriticalExten
= PR_TRUE
;
467 return (hasCriticalExten
);
471 cert_HasUnknownCriticalExten(CERTCertExtension
**extensions
)
473 CERTCertExtension
**exts
;
474 CERTCertExtension
*ext
= NULL
;
475 PRBool hasUnknownCriticalExten
= PR_FALSE
;
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
;
495 return (hasUnknownCriticalExten
);