security/nss/lib/certdb/certxutl.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 /*
     6  * Certificate Extensions handling code
     7  *
     8  */
    10 #include "cert.h"
    11 #include "secitem.h"
    12 #include "secoid.h"
    13 #include "secder.h"
    14 #include "secasn1.h"
    15 #include "certxutl.h"
    16 #include "secerr.h"
    18 #ifdef OLD
    19 #include "ocspti.h"	/* XXX a better extensions interface would not
    20 			 * require knowledge of data structures of callers */
    21 #endif
    23 static CERTCertExtension *
    24 GetExtension (CERTCertExtension **extensions, SECItem *oid)
    25 {
    26     CERTCertExtension **exts;
    27     CERTCertExtension *ext = NULL;
    28     SECComparison comp;
    30     exts = extensions;
    32     if (exts) {
    33 	while ( *exts ) {
    34 	    ext = *exts;
    35 	    comp = SECITEM_CompareItem(oid, &ext->id);
    36 	    if ( comp == SECEqual ) 
    37 		break;
    39 	    exts++;
    40 	}
    41 	return (*exts ? ext : NULL);
    42     }
    43     return (NULL);
    44 }
    46 SECStatus
    47 cert_FindExtensionByOID (CERTCertExtension **extensions, SECItem *oid, SECItem *value)
    48 {
    49     CERTCertExtension *ext;
    50     SECStatus rv = SECSuccess;
    52     ext = GetExtension (extensions, oid);
    53     if (ext == NULL) {
    54 	PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
    55 	return (SECFailure);
    56     }
    57     if (value)
    58 	rv = SECITEM_CopyItem(NULL, value, &ext->value);
    59     return (rv);
    60 }
    63 SECStatus
    64 CERT_GetExtenCriticality (CERTCertExtension **extensions, int tag, PRBool *isCritical)
    65 {
    66     CERTCertExtension *ext;
    67     SECOidData *oid;
    69     if (!isCritical)
    70 	return (SECSuccess);
    72     /* find the extension in the extensions list */
    73     oid = SECOID_FindOIDByTag((SECOidTag)tag);
    74     if ( !oid ) {
    75 	return(SECFailure);
    76     }
    77     ext = GetExtension (extensions, &oid->oid);
    78     if (ext == NULL) {
    79 	PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
    80 	return (SECFailure);
    81     }
    83     /* If the criticality is omitted, then it is false by default.
    84        ex->critical.data is NULL */
    85     if (ext->critical.data == NULL)
    86 	*isCritical = PR_FALSE;
    87     else
    88 	*isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
    89     return (SECSuccess);    
    90 }
    92 SECStatus
    93 cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
    94 {
    95     SECOidData *oid;
    97     oid = SECOID_FindOIDByTag((SECOidTag)tag);
    98     if ( !oid ) {
    99 	return(SECFailure);
   100     }
   102     return(cert_FindExtensionByOID(extensions, &oid->oid, value));
   103 }
   106 typedef struct _extNode {
   107     struct _extNode *next;
   108     CERTCertExtension *ext;
   109 } extNode;
   111 typedef struct {
   112     void (*setExts)(void *object, CERTCertExtension **exts);
   113     void *object;
   114     PLArenaPool *ownerArena;
   115     PLArenaPool *arena;
   116     extNode *head;
   117     int count;
   118 }extRec;
   120 /*
   121  * cert_StartExtensions
   122  *
   123  * NOTE: This interface changed significantly to remove knowledge
   124  *   about callers data structures (owner objects)
   125  */
   126 void *
   127 cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
   128    void (*setExts)(void *object, CERTCertExtension **exts))
   129 {
   130     PLArenaPool *arena;
   131     extRec *handle;
   133     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   134     if ( !arena ) {
   135 	return(0);
   136     }
   138     handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
   139     if ( !handle ) {
   140 	PORT_FreeArena(arena, PR_FALSE);
   141 	return(0);
   142     }
   144     handle->object = owner;
   145     handle->ownerArena = ownerArena;
   146     handle->setExts = setExts;
   148     handle->arena = arena;
   149     handle->head = 0;
   150     handle->count = 0;
   152     return(handle);
   153 }
   155 static unsigned char hextrue = 0xff;
   157 /*
   158  * Note - assumes that data pointed to by oid->data will not move
   159  */
   160 SECStatus
   161 CERT_AddExtensionByOID (void *exthandle, SECItem *oid, SECItem *value,
   162 			PRBool critical, PRBool copyData)
   163 {
   164     CERTCertExtension *ext;
   165     SECStatus rv;
   166     extNode *node;
   167     extRec *handle;
   169     handle = (extRec *)exthandle;
   171     /* allocate space for extension and list node */
   172     ext = (CERTCertExtension*)PORT_ArenaZAlloc(handle->ownerArena,
   173                                                sizeof(CERTCertExtension));
   174     if ( !ext ) {
   175 	return(SECFailure);
   176     }
   178     node = (extNode*)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
   179     if ( !node ) {
   180 	return(SECFailure);
   181     }
   183     /* add to list */
   184     node->next = handle->head;
   185     handle->head = node;
   187     /* point to ext struct */
   188     node->ext = ext;
   190     /* the object ID of the extension */
   191     ext->id = *oid;
   193     /* set critical field */
   194     if ( critical ) {
   195 	ext->critical.data = (unsigned char*)&hextrue;
   196 	ext->critical.len = 1;
   197     }
   199     /* set the value */
   200     if ( copyData ) {
   201 	rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
   202 	if ( rv ) {
   203 	    return(SECFailure);
   204 	}
   205     } else {
   206 	ext->value = *value;
   207     }
   209     handle->count++;
   211     return(SECSuccess);
   213 }
   215 SECStatus
   216 CERT_AddExtension(void *exthandle, int idtag, SECItem *value,
   217 		     PRBool critical, PRBool copyData)
   218 {
   219     SECOidData *oid;
   221     oid = SECOID_FindOIDByTag((SECOidTag)idtag);
   222     if ( !oid ) {
   223 	return(SECFailure);
   224     }
   226     return(CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical, copyData));
   227 }
   229 SECStatus
   230 CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
   231 			   PRBool critical, const SEC_ASN1Template *atemplate)
   232 {
   233     extRec *handle;
   234     SECItem *encitem;
   236     handle = (extRec *)exthandle;
   238     encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
   239     if ( encitem == NULL ) {
   240 	return(SECFailure);
   241     }
   243     return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
   244 }
   246 void
   247 PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
   248 {
   249   unsigned char onebyte;
   250   unsigned int i, len = 0;
   252   /* to prevent warning on some platform at compile time */ 
   253   onebyte = '\0';   
   254   /* Get the position of the right-most turn-on bit */ 
   255   for (i = 0; i < (value->len ) * 8; ++i) {
   256       if (i % 8 == 0)
   257 	  onebyte = value->data[i/8];
   258       if (onebyte & 0x80)
   259 	  len = i;            
   260       onebyte <<= 1;
   262   }
   263   bitsmap->data = value->data;
   264   /* Add one here since we work with base 1 */ 
   265   bitsmap->len = len + 1;
   266 }
   268 SECStatus
   269 CERT_EncodeAndAddBitStrExtension (void *exthandle, int idtag,
   270 				  SECItem *value, PRBool critical)
   271 {
   272   SECItem bitsmap;
   274   PrepareBitStringForEncoding (&bitsmap, value);
   275   return (CERT_EncodeAndAddExtension
   276 	  (exthandle, idtag, &bitsmap, critical,
   277           SEC_ASN1_GET(SEC_BitStringTemplate)));
   278 }
   280 SECStatus
   281 CERT_FinishExtensions(void *exthandle)
   282 {
   283     extRec *handle;
   284     extNode *node;
   285     CERTCertExtension **exts;
   286     SECStatus rv = SECFailure;
   288     handle = (extRec *)exthandle;
   290     /* allocate space for extensions array */
   291     exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
   292 			      handle->count + 1);
   293     if (exts == NULL) {
   294 	goto loser;
   295     }
   297     /* put extensions in owner object and update its version number */
   299 #ifdef OLD
   300     switch (handle->type) {
   301       case CertificateExtensions:
   302 	handle->owner.cert->extensions = exts;
   303 	DER_SetUInteger (ownerArena, &(handle->owner.cert->version),
   304 			 SEC_CERTIFICATE_VERSION_3);
   305 	break;
   306       case CrlExtensions:
   307 	handle->owner.crl->extensions = exts;
   308 	DER_SetUInteger (ownerArena, &(handle->owner.crl->version),
   309 			 SEC_CRL_VERSION_2);
   310 	break;
   311       case OCSPRequestExtensions:
   312 	handle->owner.request->tbsRequest->requestExtensions = exts;
   313 	break;
   314       case OCSPSingleRequestExtensions:
   315 	handle->owner.singleRequest->singleRequestExtensions = exts;	
   316 	break;
   317       case OCSPResponseSingleExtensions:
   318 	handle->owner.singleResponse->singleExtensions = exts;	
   319 	break;
   320     }
   321 #endif
   323     handle->setExts(handle->object, exts);
   325     /* update the version number */
   327     /* copy each extension pointer */
   328     node = handle->head;
   329     while ( node ) {
   330 	*exts = node->ext;
   332 	node = node->next;
   333 	exts++;
   334     }
   336     /* terminate the array of extensions */
   337     *exts = 0;
   339     rv = SECSuccess;
   341 loser:
   342     /* free working arena */
   343     PORT_FreeArena(handle->arena, PR_FALSE);
   344     return rv;
   345 }
   347 SECStatus
   348 CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
   349 {
   350     CERTCertExtension *ext;
   351     SECStatus rv = SECSuccess;
   352     SECOidTag tag;
   353     extNode *node;
   354     extRec *handle = exthandle;
   356     if (!exthandle || !extensions) {
   357 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   358         return SECFailure;
   359     }
   360     while ((ext = *extensions++) != NULL) {
   361         tag = SECOID_FindOIDTag(&ext->id);
   362         for (node=handle->head; node != NULL; node=node->next) {
   363             if (tag == 0) {
   364                 if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
   365                     break;
   366             }
   367             else {
   368                 if (SECOID_FindOIDTag(&node->ext->id) == tag) {
   369                     break;
   370                 }
   371             }
   372         }
   373         if (node == NULL) {
   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);
   378                rv = SECFailure;
   379                break;
   380             }
   381             /* add to list */
   382             rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value,
   383                                          critical, PR_TRUE);
   384             if (rv != SECSuccess)
   385                 break;
   386         }
   387     }
   388     return rv;
   389 }
   391 /*
   392  * get the value of the Netscape Certificate Type Extension
   393  */
   394 SECStatus
   395 CERT_FindBitStringExtension (CERTCertExtension **extensions, int tag,
   396 			     SECItem *retItem)
   397 {
   398     SECItem wrapperItem, tmpItem = {siBuffer,0};
   399     SECStatus rv;
   400     PLArenaPool *arena = NULL;
   402     wrapperItem.data = NULL;
   403     tmpItem.data = NULL;
   405     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   407     if ( ! arena ) {
   408 	return(SECFailure);
   409     }
   411     rv = cert_FindExtension(extensions, tag, &wrapperItem);
   412     if ( rv != SECSuccess ) {
   413 	goto loser;
   414     }
   416     rv = SEC_QuickDERDecodeItem(arena, &tmpItem,
   417                                 SEC_ASN1_GET(SEC_BitStringTemplate),
   418                                 &wrapperItem);
   420     if ( rv != SECSuccess ) {
   421 	goto loser;
   422     }
   424     retItem->data = (unsigned char *)PORT_Alloc( ( tmpItem.len + 7 ) >> 3 );
   425     if ( retItem->data == NULL ) {
   426 	goto loser;
   427     }
   429     PORT_Memcpy(retItem->data, tmpItem.data, ( tmpItem.len + 7 ) >> 3);
   430     retItem->len = tmpItem.len;
   432     rv = SECSuccess;
   433     goto done;
   435 loser:
   436     rv = SECFailure;
   438 done:
   439     if ( arena ) {
   440 	PORT_FreeArena(arena, PR_FALSE);
   441     }
   443     if ( wrapperItem.data ) {
   444 	PORT_Free(wrapperItem.data);
   445     }
   447     return(rv);
   448 }
   450 PRBool
   451 cert_HasCriticalExtension (CERTCertExtension **extensions)
   452 {
   453     CERTCertExtension **exts;
   454     CERTCertExtension *ext = NULL;
   455     PRBool hasCriticalExten = PR_FALSE;
   457     exts = extensions;
   459     if (exts) {
   460 	while ( *exts ) {
   461 	    ext = *exts;
   462 	    /* If the criticality is omitted, it's non-critical */
   463 	    if (ext->critical.data && ext->critical.data[0] == 0xff) {
   464 		hasCriticalExten = PR_TRUE;
   465 		break;
   466 	    }
   467 	    exts++;
   468 	}
   469     }
   470     return (hasCriticalExten);
   471 }
   473 PRBool
   474 cert_HasUnknownCriticalExten (CERTCertExtension **extensions)
   475 {
   476     CERTCertExtension **exts;
   477     CERTCertExtension *ext = NULL;
   478     PRBool hasUnknownCriticalExten = PR_FALSE;
   480     exts = extensions;
   482     if (exts) {
   483 	while ( *exts ) {
   484 	    ext = *exts;
   485 	    /* If the criticality is omitted, it's non-critical.
   486 	       If an extension is critical, make sure that we know
   487 	       how to process the extension.
   488              */
   489 	    if (ext->critical.data && ext->critical.data[0] == 0xff) {
   490 		if (SECOID_KnownCertExtenOID (&ext->id) == PR_FALSE) {
   491 		    hasUnknownCriticalExten = PR_TRUE;
   492 		    break;
   493 		}
   494 	    }
   495 	    exts++;
   496 	}
   497     }
   498     return (hasUnknownCriticalExten);
   499 }

mercurial