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, SEC_BitStringTemplate));
312
CERT_FinishExtensions(void *exthandle)
316
CERTCertExtension **exts;
317
SECStatus rv = SECFailure;
319
handle = (extRec *)exthandle;
321
/* allocate space for extensions array */
322
exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
328
/* put extensions in owner object and update its version number */
331
switch (handle->type) {
332
case CertificateExtensions:
333
handle->owner.cert->extensions = exts;
334
DER_SetUInteger (ownerArena, &(handle->owner.cert->version),
335
SEC_CERTIFICATE_VERSION_3);
338
handle->owner.crl->extensions = exts;
339
DER_SetUInteger (ownerArena, &(handle->owner.crl->version),
342
case OCSPRequestExtensions:
343
handle->owner.request->tbsRequest->requestExtensions = exts;
345
case OCSPSingleRequestExtensions:
346
handle->owner.singleRequest->singleRequestExtensions = exts;
348
case OCSPResponseSingleExtensions:
349
handle->owner.singleResponse->singleExtensions = exts;
354
handle->setExts(handle->object, exts);
356
/* update the version number */
358
/* copy each extension pointer */
367
/* terminate the array of extensions */
373
/* free working arena */
374
PORT_FreeArena(handle->arena, PR_FALSE);
379
CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
381
CERTCertExtension *ext;
382
SECStatus rv = SECSuccess;
385
extRec *handle = exthandle;
387
if (!exthandle || !extensions) {
388
PORT_SetError(SEC_ERROR_INVALID_ARGS);
391
while ((ext = *extensions++) != NULL) {
392
tag = SECOID_FindOIDTag(&ext->id);
393
for (node=handle->head; node != NULL; node=node->next) {
395
if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
399
if (SECOID_FindOIDTag(&node->ext->id) == tag) {
405
PRBool critical = (ext->critical.len != 0 &&
406
ext->critical.data[ext->critical.len - 1] != 0);
407
if (critical && tag == SEC_OID_UNKNOWN) {
408
PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
413
rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value,
415
if (rv != SECSuccess)
423
* get the value of the Netscape Certificate Type Extension
426
CERT_FindBitStringExtension (CERTCertExtension **extensions, int tag,
429
SECItem wrapperItem, tmpItem = {siBuffer,0};
431
PRArenaPool *arena = NULL;
433
wrapperItem.data = NULL;
436
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
442
rv = cert_FindExtension(extensions, tag, &wrapperItem);
443
if ( rv != SECSuccess ) {
447
rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_BitStringTemplate,
450
if ( rv != SECSuccess ) {
454
retItem->data = (unsigned char *)PORT_Alloc( ( tmpItem.len + 7 ) >> 3 );
455
if ( retItem->data == NULL ) {
459
PORT_Memcpy(retItem->data, tmpItem.data, ( tmpItem.len + 7 ) >> 3);
460
retItem->len = tmpItem.len;
470
PORT_FreeArena(arena, PR_FALSE);
473
if ( wrapperItem.data ) {
474
PORT_Free(wrapperItem.data);
481
cert_HasCriticalExtension (CERTCertExtension **extensions)
483
CERTCertExtension **exts;
484
CERTCertExtension *ext = NULL;
485
PRBool hasCriticalExten = PR_FALSE;
492
/* If the criticality is omitted, it's non-critical */
493
if (ext->critical.data && ext->critical.data[0] == 0xff) {
494
hasCriticalExten = PR_TRUE;
500
return (hasCriticalExten);
504
cert_HasUnknownCriticalExten (CERTCertExtension **extensions)
506
CERTCertExtension **exts;
507
CERTCertExtension *ext = NULL;
508
PRBool hasUnknownCriticalExten = PR_FALSE;
515
/* If the criticality is omitted, it's non-critical.
516
If an extension is critical, make sure that we know
517
how to process the extension.
519
if (ext->critical.data && ext->critical.data[0] == 0xff) {
520
if (SECOID_KnownCertExtenOID (&ext->id) == PR_FALSE) {
521
hasUnknownCriticalExten = PR_TRUE;
528
return (hasUnknownCriticalExten);