security/nss/lib/util/secitem.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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  * Support routines for SECItem data structure.
     7  */
     9 #include "seccomon.h"
    10 #include "secitem.h"
    11 #include "secerr.h"
    12 #include "secport.h"
    14 SECItem *
    15 SECITEM_AllocItem(PLArenaPool *arena, SECItem *item, unsigned int len)
    16 {
    17     SECItem *result = NULL;
    18     void *mark = NULL;
    20     if (arena != NULL) {
    21 	mark = PORT_ArenaMark(arena);
    22     }
    24     if (item == NULL) {
    25 	if (arena != NULL) {
    26 	    result = PORT_ArenaZAlloc(arena, sizeof(SECItem));
    27 	} else {
    28 	    result = PORT_ZAlloc(sizeof(SECItem));
    29 	}
    30 	if (result == NULL) {
    31 	    goto loser;
    32 	}
    33     } else {
    34 	PORT_Assert(item->data == NULL);
    35 	result = item;
    36     }
    38     result->len = len;
    39     if (len) {
    40 	if (arena != NULL) {
    41 	    result->data = PORT_ArenaAlloc(arena, len);
    42 	} else {
    43 	    result->data = PORT_Alloc(len);
    44 	}
    45 	if (result->data == NULL) {
    46 	    goto loser;
    47 	}
    48     } else {
    49 	result->data = NULL;
    50     }
    52     if (mark) {
    53 	PORT_ArenaUnmark(arena, mark);
    54     }
    55     return(result);
    57 loser:
    58     if ( arena != NULL ) {
    59 	if (mark) {
    60 	    PORT_ArenaRelease(arena, mark);
    61 	}
    62 	if (item != NULL) {
    63 	    item->data = NULL;
    64 	    item->len = 0;
    65 	}
    66     } else {
    67 	if (result != NULL) {
    68 	    SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
    69 	}
    70 	/*
    71 	 * If item is not NULL, the above has set item->data and
    72 	 * item->len to 0.
    73 	 */
    74     }
    75     return(NULL);
    76 }
    78 SECStatus
    79 SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item, unsigned int oldlen,
    80 		    unsigned int newlen)
    81 {
    82     PORT_Assert(item != NULL);
    83     if (item == NULL) {
    84 	/* XXX Set error.  But to what? */
    85 	return SECFailure;
    86     }
    88     /*
    89      * If no old length, degenerate to just plain alloc.
    90      */
    91     if (oldlen == 0) {
    92 	PORT_Assert(item->data == NULL || item->len == 0);
    93 	if (newlen == 0) {
    94 	    /* Nothing to do.  Weird, but not a failure.  */
    95 	    return SECSuccess;
    96 	}
    97 	item->len = newlen;
    98 	if (arena != NULL) {
    99 	    item->data = PORT_ArenaAlloc(arena, newlen);
   100 	} else {
   101 	    item->data = PORT_Alloc(newlen);
   102 	}
   103     } else {
   104 	if (arena != NULL) {
   105 	    item->data = PORT_ArenaGrow(arena, item->data, oldlen, newlen);
   106 	} else {
   107 	    item->data = PORT_Realloc(item->data, newlen);
   108 	}
   109     }
   111     if (item->data == NULL) {
   112 	return SECFailure;
   113     }
   115     return SECSuccess;
   116 }
   118 SECStatus
   119 SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item, unsigned int newlen)
   120 {
   121     unsigned char *newdata = NULL;
   123     PORT_Assert(item);
   124     if (!item) {
   125 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   126 	return SECFailure;
   127     }
   129     if (item->len == newlen) {
   130 	return SECSuccess;
   131     }
   133     if (!newlen) {
   134 	if (!arena) {
   135 	    PORT_Free(item->data);
   136 	}
   137 	item->data = NULL;
   138 	item->len = 0;
   139 	return SECSuccess;
   140     }
   142     if (!item->data) {
   143 	/* allocate fresh block of memory */
   144 	PORT_Assert(!item->len);
   145 	if (arena) {
   146 	    newdata = PORT_ArenaAlloc(arena, newlen);
   147 	} else {
   148 	    newdata = PORT_Alloc(newlen);
   149 	}
   150     } else {
   151 	/* reallocate or adjust existing block of memory */
   152 	if (arena) {
   153 	    if (item->len > newlen) {
   154 		/* There's no need to realloc a shorter block from the arena,
   155 		 * because it would result in using even more memory!
   156 		 * Therefore we'll continue to use the old block and 
   157 		 * set the item to the shorter size.
   158 		 */
   159 		item->len = newlen;
   160 		return SECSuccess;
   161 	    }
   162 	    newdata = PORT_ArenaGrow(arena, item->data, item->len, newlen);
   163 	} else {
   164 	    newdata = PORT_Realloc(item->data, newlen);
   165 	}
   166     }
   168     if (!newdata) {
   169 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   170 	return SECFailure;
   171     }
   173     item->len = newlen;
   174     item->data = newdata;
   175     return SECSuccess;
   176 }
   178 SECComparison
   179 SECITEM_CompareItem(const SECItem *a, const SECItem *b)
   180 {
   181     unsigned m;
   182     int rv;
   184     if (a == b)
   185     	return SECEqual;
   186     if (!a || !a->len || !a->data) 
   187         return (!b || !b->len || !b->data) ? SECEqual : SECLessThan;
   188     if (!b || !b->len || !b->data) 
   189     	return SECGreaterThan;
   191     m = ( ( a->len < b->len ) ? a->len : b->len );
   193     rv = PORT_Memcmp(a->data, b->data, m);
   194     if (rv) {
   195 	return rv < 0 ? SECLessThan : SECGreaterThan;
   196     }
   197     if (a->len < b->len) {
   198 	return SECLessThan;
   199     }
   200     if (a->len == b->len) {
   201 	return SECEqual;
   202     }
   203     return SECGreaterThan;
   204 }
   206 PRBool
   207 SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
   208 {
   209     if (a->len != b->len)
   210         return PR_FALSE;
   211     if (!a->len)
   212     	return PR_TRUE;
   213     if (!a->data || !b->data) {
   214         /* avoid null pointer crash. */
   215 	return (PRBool)(a->data == b->data);
   216     }
   217     return (PRBool)!PORT_Memcmp(a->data, b->data, a->len);
   218 }
   220 SECItem *
   221 SECITEM_DupItem(const SECItem *from)
   222 {
   223     return SECITEM_ArenaDupItem(NULL, from);
   224 }
   226 SECItem *
   227 SECITEM_ArenaDupItem(PLArenaPool *arena, const SECItem *from)
   228 {
   229     SECItem *to;
   231     if ( from == NULL ) {
   232 	return(NULL);
   233     }
   235     if ( arena != NULL ) {
   236 	to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
   237     } else {
   238 	to = (SECItem *)PORT_Alloc(sizeof(SECItem));
   239     }
   240     if ( to == NULL ) {
   241 	return(NULL);
   242     }
   244     if ( arena != NULL ) {
   245 	to->data = (unsigned char *)PORT_ArenaAlloc(arena, from->len);
   246     } else {
   247 	to->data = (unsigned char *)PORT_Alloc(from->len);
   248     }
   249     if ( to->data == NULL ) {
   250 	PORT_Free(to);
   251 	return(NULL);
   252     }
   254     to->len = from->len;
   255     to->type = from->type;
   256     if ( to->len ) {
   257 	PORT_Memcpy(to->data, from->data, to->len);
   258     }
   260     return(to);
   261 }
   263 SECStatus
   264 SECITEM_CopyItem(PLArenaPool *arena, SECItem *to, const SECItem *from)
   265 {
   266     to->type = from->type;
   267     if (from->data && from->len) {
   268 	if ( arena ) {
   269 	    to->data = (unsigned char*) PORT_ArenaAlloc(arena, from->len);
   270 	} else {
   271 	    to->data = (unsigned char*) PORT_Alloc(from->len);
   272 	}
   274 	if (!to->data) {
   275 	    return SECFailure;
   276 	}
   277 	PORT_Memcpy(to->data, from->data, from->len);
   278 	to->len = from->len;
   279     } else {
   280 	/*
   281 	 * If from->data is NULL but from->len is nonzero, this function
   282 	 * will succeed.  Is this right?
   283 	 */
   284 	to->data = 0;
   285 	to->len = 0;
   286     }
   287     return SECSuccess;
   288 }
   290 void
   291 SECITEM_FreeItem(SECItem *zap, PRBool freeit)
   292 {
   293     if (zap) {
   294 	PORT_Free(zap->data);
   295 	zap->data = 0;
   296 	zap->len = 0;
   297 	if (freeit) {
   298 	    PORT_Free(zap);
   299 	}
   300     }
   301 }
   303 void
   304 SECITEM_ZfreeItem(SECItem *zap, PRBool freeit)
   305 {
   306     if (zap) {
   307 	PORT_ZFree(zap->data, zap->len);
   308 	zap->data = 0;
   309 	zap->len = 0;
   310 	if (freeit) {
   311 	    PORT_ZFree(zap, sizeof(SECItem));
   312 	}
   313     }
   314 }
   315 /* these reroutines were taken from pkix oid.c, which is supposed to
   316  * replace this file some day */
   317 /*
   318  * This is the hash function.  We simply XOR the encoded form with
   319  * itself in sizeof(PLHashNumber)-byte chunks.  Improving this
   320  * routine is left as an excercise for the more mathematically
   321  * inclined student.
   322  */
   323 PLHashNumber PR_CALLBACK
   324 SECITEM_Hash ( const void *key)
   325 {
   326     const SECItem *item = (const SECItem *)key;
   327     PLHashNumber rv = 0;
   329     PRUint8 *data = (PRUint8 *)item->data;
   330     PRUint32 i;
   331     PRUint8 *rvc = (PRUint8 *)&rv;
   333     for( i = 0; i < item->len; i++ ) {
   334         rvc[ i % sizeof(rv) ] ^= *data;
   335         data++;
   336     }
   338     return rv;
   339 }
   341 /*
   342  * This is the key-compare function.  It simply does a lexical
   343  * comparison on the item data.  This does not result in
   344  * quite the same ordering as the "sequence of numbers" order,
   345  * but heck it's only used internally by the hash table anyway.
   346  */
   347 PRIntn PR_CALLBACK
   348 SECITEM_HashCompare ( const void *k1, const void *k2)
   349 {
   350     const SECItem *i1 = (const SECItem *)k1;
   351     const SECItem *i2 = (const SECItem *)k2;
   353     return SECITEM_ItemsAreEqual(i1,i2);
   354 }
   356 SECItemArray *
   357 SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len)
   358 {
   359     SECItemArray *result = NULL;
   360     void *mark = NULL;
   362     if (array != NULL && array->items != NULL) {
   363         PORT_Assert(0);
   364         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   365         return NULL;
   366     }
   368     if (arena != NULL) {
   369         mark = PORT_ArenaMark(arena);
   370     }
   372     if (array == NULL) {
   373         if (arena != NULL) {
   374             result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray));
   375         } else {
   376             result = PORT_ZAlloc(sizeof(SECItemArray));
   377         }
   378         if (result == NULL) {
   379             goto loser;
   380         }
   381     } else {
   382         result = array;
   383     }
   385     result->len = len;
   386     if (len) {
   387         if (arena != NULL) {
   388             result->items = PORT_ArenaZNewArray(arena, SECItem, len);
   389         } else {
   390             result->items = PORT_ZNewArray(SECItem, len);
   391         }
   392         if (result->items == NULL) {
   393             goto loser;
   394         }
   395     } else {
   396         result->items = NULL;
   397     }
   399     if (mark) {
   400         PORT_ArenaUnmark(arena, mark);
   401     }
   402     return result;
   404 loser:
   405     if ( arena != NULL ) {
   406         if (mark) {
   407             PORT_ArenaRelease(arena, mark);
   408         }
   409     } else {
   410         if (result != NULL && array == NULL) {
   411             PORT_Free(result);
   412         }
   413     }
   414     if (array != NULL) {
   415         array->items = NULL;
   416         array->len = 0;
   417     }
   418     return NULL;
   419 }
   421 static void
   422 secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit)
   423 {
   424     unsigned int i;
   426     if (!array || !array->len || !array->items)
   427         return;
   429     for (i = 0; i < array->len; ++i) {
   430         SECItem *item = &array->items[i];
   432         if (item->data) {
   433             if (zero_items) {
   434                 SECITEM_ZfreeItem(item, PR_FALSE);
   435             } else {
   436                 SECITEM_FreeItem(item, PR_FALSE);
   437             }
   438         }
   439     }
   440     PORT_Free(array->items);
   441     array->items = NULL;
   442     array->len = 0;
   444     if (freeit)
   445         PORT_Free(array);
   446 }
   448 void SECITEM_FreeArray(SECItemArray *array, PRBool freeit)
   449 {
   450     secitem_FreeArray(array, PR_FALSE, freeit);
   451 }
   453 void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit)
   454 {
   455     secitem_FreeArray(array, PR_TRUE, freeit);
   456 }
   458 SECItemArray *
   459 SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from)
   460 {
   461     SECItemArray *result;
   462     unsigned int i;
   464     /* Require a "from" array.
   465      * Reject an inconsistent "from" array with NULL data and nonzero length.
   466      * However, allow a "from" array of zero length.
   467      */
   468     if (!from || (!from->items && from->len))
   469         return NULL;
   471     result = SECITEM_AllocArray(arena, NULL, from->len);
   472     if (!result)
   473         return NULL;
   475     for (i = 0; i < from->len; ++i) {
   476         SECStatus rv = SECITEM_CopyItem(arena,
   477                                         &result->items[i], &from->items[i]);
   478         if (rv != SECSuccess) {
   479             SECITEM_ZfreeArray(result, PR_TRUE);
   480             return NULL;
   481         }
   482     }
   484     return result;
   485 }

mercurial