security/nss/lib/certdb/certxutl.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/certdb/certxutl.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,499 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * Certificate Extensions handling code
    1.10 + *
    1.11 + */
    1.12 +
    1.13 +#include "cert.h"
    1.14 +#include "secitem.h"
    1.15 +#include "secoid.h"
    1.16 +#include "secder.h"
    1.17 +#include "secasn1.h"
    1.18 +#include "certxutl.h"
    1.19 +#include "secerr.h"
    1.20 +
    1.21 +#ifdef OLD
    1.22 +#include "ocspti.h"	/* XXX a better extensions interface would not
    1.23 +			 * require knowledge of data structures of callers */
    1.24 +#endif
    1.25 +
    1.26 +static CERTCertExtension *
    1.27 +GetExtension (CERTCertExtension **extensions, SECItem *oid)
    1.28 +{
    1.29 +    CERTCertExtension **exts;
    1.30 +    CERTCertExtension *ext = NULL;
    1.31 +    SECComparison comp;
    1.32 +
    1.33 +    exts = extensions;
    1.34 +    
    1.35 +    if (exts) {
    1.36 +	while ( *exts ) {
    1.37 +	    ext = *exts;
    1.38 +	    comp = SECITEM_CompareItem(oid, &ext->id);
    1.39 +	    if ( comp == SECEqual ) 
    1.40 +		break;
    1.41 +
    1.42 +	    exts++;
    1.43 +	}
    1.44 +	return (*exts ? ext : NULL);
    1.45 +    }
    1.46 +    return (NULL);
    1.47 +}
    1.48 +
    1.49 +SECStatus
    1.50 +cert_FindExtensionByOID (CERTCertExtension **extensions, SECItem *oid, SECItem *value)
    1.51 +{
    1.52 +    CERTCertExtension *ext;
    1.53 +    SECStatus rv = SECSuccess;
    1.54 +    
    1.55 +    ext = GetExtension (extensions, oid);
    1.56 +    if (ext == NULL) {
    1.57 +	PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
    1.58 +	return (SECFailure);
    1.59 +    }
    1.60 +    if (value)
    1.61 +	rv = SECITEM_CopyItem(NULL, value, &ext->value);
    1.62 +    return (rv);
    1.63 +}
    1.64 +    
    1.65 +
    1.66 +SECStatus
    1.67 +CERT_GetExtenCriticality (CERTCertExtension **extensions, int tag, PRBool *isCritical)
    1.68 +{
    1.69 +    CERTCertExtension *ext;
    1.70 +    SECOidData *oid;
    1.71 +
    1.72 +    if (!isCritical)
    1.73 +	return (SECSuccess);
    1.74 +    
    1.75 +    /* find the extension in the extensions list */
    1.76 +    oid = SECOID_FindOIDByTag((SECOidTag)tag);
    1.77 +    if ( !oid ) {
    1.78 +	return(SECFailure);
    1.79 +    }
    1.80 +    ext = GetExtension (extensions, &oid->oid);
    1.81 +    if (ext == NULL) {
    1.82 +	PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
    1.83 +	return (SECFailure);
    1.84 +    }
    1.85 +
    1.86 +    /* If the criticality is omitted, then it is false by default.
    1.87 +       ex->critical.data is NULL */
    1.88 +    if (ext->critical.data == NULL)
    1.89 +	*isCritical = PR_FALSE;
    1.90 +    else
    1.91 +	*isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
    1.92 +    return (SECSuccess);    
    1.93 +}
    1.94 +
    1.95 +SECStatus
    1.96 +cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
    1.97 +{
    1.98 +    SECOidData *oid;
    1.99 +    
   1.100 +    oid = SECOID_FindOIDByTag((SECOidTag)tag);
   1.101 +    if ( !oid ) {
   1.102 +	return(SECFailure);
   1.103 +    }
   1.104 +
   1.105 +    return(cert_FindExtensionByOID(extensions, &oid->oid, value));
   1.106 +}
   1.107 +
   1.108 +
   1.109 +typedef struct _extNode {
   1.110 +    struct _extNode *next;
   1.111 +    CERTCertExtension *ext;
   1.112 +} extNode;
   1.113 +
   1.114 +typedef struct {
   1.115 +    void (*setExts)(void *object, CERTCertExtension **exts);
   1.116 +    void *object;
   1.117 +    PLArenaPool *ownerArena;
   1.118 +    PLArenaPool *arena;
   1.119 +    extNode *head;
   1.120 +    int count;
   1.121 +}extRec;
   1.122 +
   1.123 +/*
   1.124 + * cert_StartExtensions
   1.125 + *
   1.126 + * NOTE: This interface changed significantly to remove knowledge
   1.127 + *   about callers data structures (owner objects)
   1.128 + */
   1.129 +void *
   1.130 +cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
   1.131 +   void (*setExts)(void *object, CERTCertExtension **exts))
   1.132 +{
   1.133 +    PLArenaPool *arena;
   1.134 +    extRec *handle;
   1.135 +
   1.136 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.137 +    if ( !arena ) {
   1.138 +	return(0);
   1.139 +    }
   1.140 +
   1.141 +    handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
   1.142 +    if ( !handle ) {
   1.143 +	PORT_FreeArena(arena, PR_FALSE);
   1.144 +	return(0);
   1.145 +    }
   1.146 +
   1.147 +    handle->object = owner;
   1.148 +    handle->ownerArena = ownerArena;
   1.149 +    handle->setExts = setExts;
   1.150 +
   1.151 +    handle->arena = arena;
   1.152 +    handle->head = 0;
   1.153 +    handle->count = 0;
   1.154 +    
   1.155 +    return(handle);
   1.156 +}
   1.157 +
   1.158 +static unsigned char hextrue = 0xff;
   1.159 +
   1.160 +/*
   1.161 + * Note - assumes that data pointed to by oid->data will not move
   1.162 + */
   1.163 +SECStatus
   1.164 +CERT_AddExtensionByOID (void *exthandle, SECItem *oid, SECItem *value,
   1.165 +			PRBool critical, PRBool copyData)
   1.166 +{
   1.167 +    CERTCertExtension *ext;
   1.168 +    SECStatus rv;
   1.169 +    extNode *node;
   1.170 +    extRec *handle;
   1.171 +    
   1.172 +    handle = (extRec *)exthandle;
   1.173 +
   1.174 +    /* allocate space for extension and list node */
   1.175 +    ext = (CERTCertExtension*)PORT_ArenaZAlloc(handle->ownerArena,
   1.176 +                                               sizeof(CERTCertExtension));
   1.177 +    if ( !ext ) {
   1.178 +	return(SECFailure);
   1.179 +    }
   1.180 +
   1.181 +    node = (extNode*)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
   1.182 +    if ( !node ) {
   1.183 +	return(SECFailure);
   1.184 +    }
   1.185 +
   1.186 +    /* add to list */
   1.187 +    node->next = handle->head;
   1.188 +    handle->head = node;
   1.189 +   
   1.190 +    /* point to ext struct */
   1.191 +    node->ext = ext;
   1.192 +    
   1.193 +    /* the object ID of the extension */
   1.194 +    ext->id = *oid;
   1.195 +    
   1.196 +    /* set critical field */
   1.197 +    if ( critical ) {
   1.198 +	ext->critical.data = (unsigned char*)&hextrue;
   1.199 +	ext->critical.len = 1;
   1.200 +    }
   1.201 +
   1.202 +    /* set the value */
   1.203 +    if ( copyData ) {
   1.204 +	rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
   1.205 +	if ( rv ) {
   1.206 +	    return(SECFailure);
   1.207 +	}
   1.208 +    } else {
   1.209 +	ext->value = *value;
   1.210 +    }
   1.211 +    
   1.212 +    handle->count++;
   1.213 +    
   1.214 +    return(SECSuccess);
   1.215 +
   1.216 +}
   1.217 +
   1.218 +SECStatus
   1.219 +CERT_AddExtension(void *exthandle, int idtag, SECItem *value,
   1.220 +		     PRBool critical, PRBool copyData)
   1.221 +{
   1.222 +    SECOidData *oid;
   1.223 +    
   1.224 +    oid = SECOID_FindOIDByTag((SECOidTag)idtag);
   1.225 +    if ( !oid ) {
   1.226 +	return(SECFailure);
   1.227 +    }
   1.228 +
   1.229 +    return(CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical, copyData));
   1.230 +}
   1.231 +
   1.232 +SECStatus
   1.233 +CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
   1.234 +			   PRBool critical, const SEC_ASN1Template *atemplate)
   1.235 +{
   1.236 +    extRec *handle;
   1.237 +    SECItem *encitem;
   1.238 +
   1.239 +    handle = (extRec *)exthandle;
   1.240 +
   1.241 +    encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
   1.242 +    if ( encitem == NULL ) {
   1.243 +	return(SECFailure);
   1.244 +    }
   1.245 +
   1.246 +    return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
   1.247 +}
   1.248 +
   1.249 +void
   1.250 +PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
   1.251 +{
   1.252 +  unsigned char onebyte;
   1.253 +  unsigned int i, len = 0;
   1.254 +
   1.255 +  /* to prevent warning on some platform at compile time */ 
   1.256 +  onebyte = '\0';   
   1.257 +  /* Get the position of the right-most turn-on bit */ 
   1.258 +  for (i = 0; i < (value->len ) * 8; ++i) {
   1.259 +      if (i % 8 == 0)
   1.260 +	  onebyte = value->data[i/8];
   1.261 +      if (onebyte & 0x80)
   1.262 +	  len = i;            
   1.263 +      onebyte <<= 1;
   1.264 +      
   1.265 +  }
   1.266 +  bitsmap->data = value->data;
   1.267 +  /* Add one here since we work with base 1 */ 
   1.268 +  bitsmap->len = len + 1;
   1.269 +}
   1.270 +
   1.271 +SECStatus
   1.272 +CERT_EncodeAndAddBitStrExtension (void *exthandle, int idtag,
   1.273 +				  SECItem *value, PRBool critical)
   1.274 +{
   1.275 +  SECItem bitsmap;
   1.276 +  
   1.277 +  PrepareBitStringForEncoding (&bitsmap, value);
   1.278 +  return (CERT_EncodeAndAddExtension
   1.279 +	  (exthandle, idtag, &bitsmap, critical,
   1.280 +          SEC_ASN1_GET(SEC_BitStringTemplate)));
   1.281 +}
   1.282 +
   1.283 +SECStatus
   1.284 +CERT_FinishExtensions(void *exthandle)
   1.285 +{
   1.286 +    extRec *handle;
   1.287 +    extNode *node;
   1.288 +    CERTCertExtension **exts;
   1.289 +    SECStatus rv = SECFailure;
   1.290 +    
   1.291 +    handle = (extRec *)exthandle;
   1.292 +
   1.293 +    /* allocate space for extensions array */
   1.294 +    exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
   1.295 +			      handle->count + 1);
   1.296 +    if (exts == NULL) {
   1.297 +	goto loser;
   1.298 +    }
   1.299 +
   1.300 +    /* put extensions in owner object and update its version number */
   1.301 +
   1.302 +#ifdef OLD
   1.303 +    switch (handle->type) {
   1.304 +      case CertificateExtensions:
   1.305 +	handle->owner.cert->extensions = exts;
   1.306 +	DER_SetUInteger (ownerArena, &(handle->owner.cert->version),
   1.307 +			 SEC_CERTIFICATE_VERSION_3);
   1.308 +	break;
   1.309 +      case CrlExtensions:
   1.310 +	handle->owner.crl->extensions = exts;
   1.311 +	DER_SetUInteger (ownerArena, &(handle->owner.crl->version),
   1.312 +			 SEC_CRL_VERSION_2);
   1.313 +	break;
   1.314 +      case OCSPRequestExtensions:
   1.315 +	handle->owner.request->tbsRequest->requestExtensions = exts;
   1.316 +	break;
   1.317 +      case OCSPSingleRequestExtensions:
   1.318 +	handle->owner.singleRequest->singleRequestExtensions = exts;	
   1.319 +	break;
   1.320 +      case OCSPResponseSingleExtensions:
   1.321 +	handle->owner.singleResponse->singleExtensions = exts;	
   1.322 +	break;
   1.323 +    }
   1.324 +#endif
   1.325 +
   1.326 +    handle->setExts(handle->object, exts);
   1.327 +	
   1.328 +    /* update the version number */
   1.329 +
   1.330 +    /* copy each extension pointer */
   1.331 +    node = handle->head;
   1.332 +    while ( node ) {
   1.333 +	*exts = node->ext;
   1.334 +	
   1.335 +	node = node->next;
   1.336 +	exts++;
   1.337 +    }
   1.338 +
   1.339 +    /* terminate the array of extensions */
   1.340 +    *exts = 0;
   1.341 +
   1.342 +    rv = SECSuccess;
   1.343 +
   1.344 +loser:
   1.345 +    /* free working arena */
   1.346 +    PORT_FreeArena(handle->arena, PR_FALSE);
   1.347 +    return rv;
   1.348 +}
   1.349 +
   1.350 +SECStatus
   1.351 +CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
   1.352 +{
   1.353 +    CERTCertExtension *ext;
   1.354 +    SECStatus rv = SECSuccess;
   1.355 +    SECOidTag tag;
   1.356 +    extNode *node;
   1.357 +    extRec *handle = exthandle;
   1.358 +    
   1.359 +    if (!exthandle || !extensions) {
   1.360 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.361 +        return SECFailure;
   1.362 +    }
   1.363 +    while ((ext = *extensions++) != NULL) {
   1.364 +        tag = SECOID_FindOIDTag(&ext->id);
   1.365 +        for (node=handle->head; node != NULL; node=node->next) {
   1.366 +            if (tag == 0) {
   1.367 +                if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
   1.368 +                    break;
   1.369 +            }
   1.370 +            else {
   1.371 +                if (SECOID_FindOIDTag(&node->ext->id) == tag) {
   1.372 +                    break;
   1.373 +                }
   1.374 +            }
   1.375 +        }
   1.376 +        if (node == NULL) {
   1.377 +            PRBool critical = (ext->critical.len != 0 &&
   1.378 +                            ext->critical.data[ext->critical.len - 1] != 0);
   1.379 +            if (critical && tag == SEC_OID_UNKNOWN) {
   1.380 +               PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
   1.381 +               rv = SECFailure;
   1.382 +               break;
   1.383 +            }
   1.384 +            /* add to list */
   1.385 +            rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value,
   1.386 +                                         critical, PR_TRUE);
   1.387 +            if (rv != SECSuccess)
   1.388 +                break;
   1.389 +        }
   1.390 +    }
   1.391 +    return rv;
   1.392 +}
   1.393 +
   1.394 +/*
   1.395 + * get the value of the Netscape Certificate Type Extension
   1.396 + */
   1.397 +SECStatus
   1.398 +CERT_FindBitStringExtension (CERTCertExtension **extensions, int tag,
   1.399 +			     SECItem *retItem)
   1.400 +{
   1.401 +    SECItem wrapperItem, tmpItem = {siBuffer,0};
   1.402 +    SECStatus rv;
   1.403 +    PLArenaPool *arena = NULL;
   1.404 +    
   1.405 +    wrapperItem.data = NULL;
   1.406 +    tmpItem.data = NULL;
   1.407 +    
   1.408 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.409 +    
   1.410 +    if ( ! arena ) {
   1.411 +	return(SECFailure);
   1.412 +    }
   1.413 +    
   1.414 +    rv = cert_FindExtension(extensions, tag, &wrapperItem);
   1.415 +    if ( rv != SECSuccess ) {
   1.416 +	goto loser;
   1.417 +    }
   1.418 +
   1.419 +    rv = SEC_QuickDERDecodeItem(arena, &tmpItem,
   1.420 +                                SEC_ASN1_GET(SEC_BitStringTemplate),
   1.421 +                                &wrapperItem);
   1.422 +
   1.423 +    if ( rv != SECSuccess ) {
   1.424 +	goto loser;
   1.425 +    }
   1.426 +
   1.427 +    retItem->data = (unsigned char *)PORT_Alloc( ( tmpItem.len + 7 ) >> 3 );
   1.428 +    if ( retItem->data == NULL ) {
   1.429 +	goto loser;
   1.430 +    }
   1.431 +    
   1.432 +    PORT_Memcpy(retItem->data, tmpItem.data, ( tmpItem.len + 7 ) >> 3);
   1.433 +    retItem->len = tmpItem.len;
   1.434 +    
   1.435 +    rv = SECSuccess;
   1.436 +    goto done;
   1.437 +    
   1.438 +loser:
   1.439 +    rv = SECFailure;
   1.440 +
   1.441 +done:
   1.442 +    if ( arena ) {
   1.443 +	PORT_FreeArena(arena, PR_FALSE);
   1.444 +    }
   1.445 +    
   1.446 +    if ( wrapperItem.data ) {
   1.447 +	PORT_Free(wrapperItem.data);
   1.448 +    }
   1.449 +
   1.450 +    return(rv);
   1.451 +}
   1.452 +
   1.453 +PRBool
   1.454 +cert_HasCriticalExtension (CERTCertExtension **extensions)
   1.455 +{
   1.456 +    CERTCertExtension **exts;
   1.457 +    CERTCertExtension *ext = NULL;
   1.458 +    PRBool hasCriticalExten = PR_FALSE;
   1.459 +    
   1.460 +    exts = extensions;
   1.461 +    
   1.462 +    if (exts) {
   1.463 +	while ( *exts ) {
   1.464 +	    ext = *exts;
   1.465 +	    /* If the criticality is omitted, it's non-critical */
   1.466 +	    if (ext->critical.data && ext->critical.data[0] == 0xff) {
   1.467 +		hasCriticalExten = PR_TRUE;
   1.468 +		break;
   1.469 +	    }
   1.470 +	    exts++;
   1.471 +	}
   1.472 +    }
   1.473 +    return (hasCriticalExten);
   1.474 +}
   1.475 +
   1.476 +PRBool
   1.477 +cert_HasUnknownCriticalExten (CERTCertExtension **extensions)
   1.478 +{
   1.479 +    CERTCertExtension **exts;
   1.480 +    CERTCertExtension *ext = NULL;
   1.481 +    PRBool hasUnknownCriticalExten = PR_FALSE;
   1.482 +    
   1.483 +    exts = extensions;
   1.484 +    
   1.485 +    if (exts) {
   1.486 +	while ( *exts ) {
   1.487 +	    ext = *exts;
   1.488 +	    /* If the criticality is omitted, it's non-critical.
   1.489 +	       If an extension is critical, make sure that we know
   1.490 +	       how to process the extension.
   1.491 +             */
   1.492 +	    if (ext->critical.data && ext->critical.data[0] == 0xff) {
   1.493 +		if (SECOID_KnownCertExtenOID (&ext->id) == PR_FALSE) {
   1.494 +		    hasUnknownCriticalExten = PR_TRUE;
   1.495 +		    break;
   1.496 +		}
   1.497 +	    }
   1.498 +	    exts++;
   1.499 +	}
   1.500 +    }
   1.501 +    return (hasUnknownCriticalExten);
   1.502 +}

mercurial