1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/secitem.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,485 @@ 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 + * Support routines for SECItem data structure. 1.10 + */ 1.11 + 1.12 +#include "seccomon.h" 1.13 +#include "secitem.h" 1.14 +#include "secerr.h" 1.15 +#include "secport.h" 1.16 + 1.17 +SECItem * 1.18 +SECITEM_AllocItem(PLArenaPool *arena, SECItem *item, unsigned int len) 1.19 +{ 1.20 + SECItem *result = NULL; 1.21 + void *mark = NULL; 1.22 + 1.23 + if (arena != NULL) { 1.24 + mark = PORT_ArenaMark(arena); 1.25 + } 1.26 + 1.27 + if (item == NULL) { 1.28 + if (arena != NULL) { 1.29 + result = PORT_ArenaZAlloc(arena, sizeof(SECItem)); 1.30 + } else { 1.31 + result = PORT_ZAlloc(sizeof(SECItem)); 1.32 + } 1.33 + if (result == NULL) { 1.34 + goto loser; 1.35 + } 1.36 + } else { 1.37 + PORT_Assert(item->data == NULL); 1.38 + result = item; 1.39 + } 1.40 + 1.41 + result->len = len; 1.42 + if (len) { 1.43 + if (arena != NULL) { 1.44 + result->data = PORT_ArenaAlloc(arena, len); 1.45 + } else { 1.46 + result->data = PORT_Alloc(len); 1.47 + } 1.48 + if (result->data == NULL) { 1.49 + goto loser; 1.50 + } 1.51 + } else { 1.52 + result->data = NULL; 1.53 + } 1.54 + 1.55 + if (mark) { 1.56 + PORT_ArenaUnmark(arena, mark); 1.57 + } 1.58 + return(result); 1.59 + 1.60 +loser: 1.61 + if ( arena != NULL ) { 1.62 + if (mark) { 1.63 + PORT_ArenaRelease(arena, mark); 1.64 + } 1.65 + if (item != NULL) { 1.66 + item->data = NULL; 1.67 + item->len = 0; 1.68 + } 1.69 + } else { 1.70 + if (result != NULL) { 1.71 + SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE); 1.72 + } 1.73 + /* 1.74 + * If item is not NULL, the above has set item->data and 1.75 + * item->len to 0. 1.76 + */ 1.77 + } 1.78 + return(NULL); 1.79 +} 1.80 + 1.81 +SECStatus 1.82 +SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item, unsigned int oldlen, 1.83 + unsigned int newlen) 1.84 +{ 1.85 + PORT_Assert(item != NULL); 1.86 + if (item == NULL) { 1.87 + /* XXX Set error. But to what? */ 1.88 + return SECFailure; 1.89 + } 1.90 + 1.91 + /* 1.92 + * If no old length, degenerate to just plain alloc. 1.93 + */ 1.94 + if (oldlen == 0) { 1.95 + PORT_Assert(item->data == NULL || item->len == 0); 1.96 + if (newlen == 0) { 1.97 + /* Nothing to do. Weird, but not a failure. */ 1.98 + return SECSuccess; 1.99 + } 1.100 + item->len = newlen; 1.101 + if (arena != NULL) { 1.102 + item->data = PORT_ArenaAlloc(arena, newlen); 1.103 + } else { 1.104 + item->data = PORT_Alloc(newlen); 1.105 + } 1.106 + } else { 1.107 + if (arena != NULL) { 1.108 + item->data = PORT_ArenaGrow(arena, item->data, oldlen, newlen); 1.109 + } else { 1.110 + item->data = PORT_Realloc(item->data, newlen); 1.111 + } 1.112 + } 1.113 + 1.114 + if (item->data == NULL) { 1.115 + return SECFailure; 1.116 + } 1.117 + 1.118 + return SECSuccess; 1.119 +} 1.120 + 1.121 +SECStatus 1.122 +SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item, unsigned int newlen) 1.123 +{ 1.124 + unsigned char *newdata = NULL; 1.125 + 1.126 + PORT_Assert(item); 1.127 + if (!item) { 1.128 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.129 + return SECFailure; 1.130 + } 1.131 + 1.132 + if (item->len == newlen) { 1.133 + return SECSuccess; 1.134 + } 1.135 + 1.136 + if (!newlen) { 1.137 + if (!arena) { 1.138 + PORT_Free(item->data); 1.139 + } 1.140 + item->data = NULL; 1.141 + item->len = 0; 1.142 + return SECSuccess; 1.143 + } 1.144 + 1.145 + if (!item->data) { 1.146 + /* allocate fresh block of memory */ 1.147 + PORT_Assert(!item->len); 1.148 + if (arena) { 1.149 + newdata = PORT_ArenaAlloc(arena, newlen); 1.150 + } else { 1.151 + newdata = PORT_Alloc(newlen); 1.152 + } 1.153 + } else { 1.154 + /* reallocate or adjust existing block of memory */ 1.155 + if (arena) { 1.156 + if (item->len > newlen) { 1.157 + /* There's no need to realloc a shorter block from the arena, 1.158 + * because it would result in using even more memory! 1.159 + * Therefore we'll continue to use the old block and 1.160 + * set the item to the shorter size. 1.161 + */ 1.162 + item->len = newlen; 1.163 + return SECSuccess; 1.164 + } 1.165 + newdata = PORT_ArenaGrow(arena, item->data, item->len, newlen); 1.166 + } else { 1.167 + newdata = PORT_Realloc(item->data, newlen); 1.168 + } 1.169 + } 1.170 + 1.171 + if (!newdata) { 1.172 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.173 + return SECFailure; 1.174 + } 1.175 + 1.176 + item->len = newlen; 1.177 + item->data = newdata; 1.178 + return SECSuccess; 1.179 +} 1.180 + 1.181 +SECComparison 1.182 +SECITEM_CompareItem(const SECItem *a, const SECItem *b) 1.183 +{ 1.184 + unsigned m; 1.185 + int rv; 1.186 + 1.187 + if (a == b) 1.188 + return SECEqual; 1.189 + if (!a || !a->len || !a->data) 1.190 + return (!b || !b->len || !b->data) ? SECEqual : SECLessThan; 1.191 + if (!b || !b->len || !b->data) 1.192 + return SECGreaterThan; 1.193 + 1.194 + m = ( ( a->len < b->len ) ? a->len : b->len ); 1.195 + 1.196 + rv = PORT_Memcmp(a->data, b->data, m); 1.197 + if (rv) { 1.198 + return rv < 0 ? SECLessThan : SECGreaterThan; 1.199 + } 1.200 + if (a->len < b->len) { 1.201 + return SECLessThan; 1.202 + } 1.203 + if (a->len == b->len) { 1.204 + return SECEqual; 1.205 + } 1.206 + return SECGreaterThan; 1.207 +} 1.208 + 1.209 +PRBool 1.210 +SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b) 1.211 +{ 1.212 + if (a->len != b->len) 1.213 + return PR_FALSE; 1.214 + if (!a->len) 1.215 + return PR_TRUE; 1.216 + if (!a->data || !b->data) { 1.217 + /* avoid null pointer crash. */ 1.218 + return (PRBool)(a->data == b->data); 1.219 + } 1.220 + return (PRBool)!PORT_Memcmp(a->data, b->data, a->len); 1.221 +} 1.222 + 1.223 +SECItem * 1.224 +SECITEM_DupItem(const SECItem *from) 1.225 +{ 1.226 + return SECITEM_ArenaDupItem(NULL, from); 1.227 +} 1.228 + 1.229 +SECItem * 1.230 +SECITEM_ArenaDupItem(PLArenaPool *arena, const SECItem *from) 1.231 +{ 1.232 + SECItem *to; 1.233 + 1.234 + if ( from == NULL ) { 1.235 + return(NULL); 1.236 + } 1.237 + 1.238 + if ( arena != NULL ) { 1.239 + to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem)); 1.240 + } else { 1.241 + to = (SECItem *)PORT_Alloc(sizeof(SECItem)); 1.242 + } 1.243 + if ( to == NULL ) { 1.244 + return(NULL); 1.245 + } 1.246 + 1.247 + if ( arena != NULL ) { 1.248 + to->data = (unsigned char *)PORT_ArenaAlloc(arena, from->len); 1.249 + } else { 1.250 + to->data = (unsigned char *)PORT_Alloc(from->len); 1.251 + } 1.252 + if ( to->data == NULL ) { 1.253 + PORT_Free(to); 1.254 + return(NULL); 1.255 + } 1.256 + 1.257 + to->len = from->len; 1.258 + to->type = from->type; 1.259 + if ( to->len ) { 1.260 + PORT_Memcpy(to->data, from->data, to->len); 1.261 + } 1.262 + 1.263 + return(to); 1.264 +} 1.265 + 1.266 +SECStatus 1.267 +SECITEM_CopyItem(PLArenaPool *arena, SECItem *to, const SECItem *from) 1.268 +{ 1.269 + to->type = from->type; 1.270 + if (from->data && from->len) { 1.271 + if ( arena ) { 1.272 + to->data = (unsigned char*) PORT_ArenaAlloc(arena, from->len); 1.273 + } else { 1.274 + to->data = (unsigned char*) PORT_Alloc(from->len); 1.275 + } 1.276 + 1.277 + if (!to->data) { 1.278 + return SECFailure; 1.279 + } 1.280 + PORT_Memcpy(to->data, from->data, from->len); 1.281 + to->len = from->len; 1.282 + } else { 1.283 + /* 1.284 + * If from->data is NULL but from->len is nonzero, this function 1.285 + * will succeed. Is this right? 1.286 + */ 1.287 + to->data = 0; 1.288 + to->len = 0; 1.289 + } 1.290 + return SECSuccess; 1.291 +} 1.292 + 1.293 +void 1.294 +SECITEM_FreeItem(SECItem *zap, PRBool freeit) 1.295 +{ 1.296 + if (zap) { 1.297 + PORT_Free(zap->data); 1.298 + zap->data = 0; 1.299 + zap->len = 0; 1.300 + if (freeit) { 1.301 + PORT_Free(zap); 1.302 + } 1.303 + } 1.304 +} 1.305 + 1.306 +void 1.307 +SECITEM_ZfreeItem(SECItem *zap, PRBool freeit) 1.308 +{ 1.309 + if (zap) { 1.310 + PORT_ZFree(zap->data, zap->len); 1.311 + zap->data = 0; 1.312 + zap->len = 0; 1.313 + if (freeit) { 1.314 + PORT_ZFree(zap, sizeof(SECItem)); 1.315 + } 1.316 + } 1.317 +} 1.318 +/* these reroutines were taken from pkix oid.c, which is supposed to 1.319 + * replace this file some day */ 1.320 +/* 1.321 + * This is the hash function. We simply XOR the encoded form with 1.322 + * itself in sizeof(PLHashNumber)-byte chunks. Improving this 1.323 + * routine is left as an excercise for the more mathematically 1.324 + * inclined student. 1.325 + */ 1.326 +PLHashNumber PR_CALLBACK 1.327 +SECITEM_Hash ( const void *key) 1.328 +{ 1.329 + const SECItem *item = (const SECItem *)key; 1.330 + PLHashNumber rv = 0; 1.331 + 1.332 + PRUint8 *data = (PRUint8 *)item->data; 1.333 + PRUint32 i; 1.334 + PRUint8 *rvc = (PRUint8 *)&rv; 1.335 + 1.336 + for( i = 0; i < item->len; i++ ) { 1.337 + rvc[ i % sizeof(rv) ] ^= *data; 1.338 + data++; 1.339 + } 1.340 + 1.341 + return rv; 1.342 +} 1.343 + 1.344 +/* 1.345 + * This is the key-compare function. It simply does a lexical 1.346 + * comparison on the item data. This does not result in 1.347 + * quite the same ordering as the "sequence of numbers" order, 1.348 + * but heck it's only used internally by the hash table anyway. 1.349 + */ 1.350 +PRIntn PR_CALLBACK 1.351 +SECITEM_HashCompare ( const void *k1, const void *k2) 1.352 +{ 1.353 + const SECItem *i1 = (const SECItem *)k1; 1.354 + const SECItem *i2 = (const SECItem *)k2; 1.355 + 1.356 + return SECITEM_ItemsAreEqual(i1,i2); 1.357 +} 1.358 + 1.359 +SECItemArray * 1.360 +SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len) 1.361 +{ 1.362 + SECItemArray *result = NULL; 1.363 + void *mark = NULL; 1.364 + 1.365 + if (array != NULL && array->items != NULL) { 1.366 + PORT_Assert(0); 1.367 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.368 + return NULL; 1.369 + } 1.370 + 1.371 + if (arena != NULL) { 1.372 + mark = PORT_ArenaMark(arena); 1.373 + } 1.374 + 1.375 + if (array == NULL) { 1.376 + if (arena != NULL) { 1.377 + result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray)); 1.378 + } else { 1.379 + result = PORT_ZAlloc(sizeof(SECItemArray)); 1.380 + } 1.381 + if (result == NULL) { 1.382 + goto loser; 1.383 + } 1.384 + } else { 1.385 + result = array; 1.386 + } 1.387 + 1.388 + result->len = len; 1.389 + if (len) { 1.390 + if (arena != NULL) { 1.391 + result->items = PORT_ArenaZNewArray(arena, SECItem, len); 1.392 + } else { 1.393 + result->items = PORT_ZNewArray(SECItem, len); 1.394 + } 1.395 + if (result->items == NULL) { 1.396 + goto loser; 1.397 + } 1.398 + } else { 1.399 + result->items = NULL; 1.400 + } 1.401 + 1.402 + if (mark) { 1.403 + PORT_ArenaUnmark(arena, mark); 1.404 + } 1.405 + return result; 1.406 + 1.407 +loser: 1.408 + if ( arena != NULL ) { 1.409 + if (mark) { 1.410 + PORT_ArenaRelease(arena, mark); 1.411 + } 1.412 + } else { 1.413 + if (result != NULL && array == NULL) { 1.414 + PORT_Free(result); 1.415 + } 1.416 + } 1.417 + if (array != NULL) { 1.418 + array->items = NULL; 1.419 + array->len = 0; 1.420 + } 1.421 + return NULL; 1.422 +} 1.423 + 1.424 +static void 1.425 +secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit) 1.426 +{ 1.427 + unsigned int i; 1.428 + 1.429 + if (!array || !array->len || !array->items) 1.430 + return; 1.431 + 1.432 + for (i = 0; i < array->len; ++i) { 1.433 + SECItem *item = &array->items[i]; 1.434 + 1.435 + if (item->data) { 1.436 + if (zero_items) { 1.437 + SECITEM_ZfreeItem(item, PR_FALSE); 1.438 + } else { 1.439 + SECITEM_FreeItem(item, PR_FALSE); 1.440 + } 1.441 + } 1.442 + } 1.443 + PORT_Free(array->items); 1.444 + array->items = NULL; 1.445 + array->len = 0; 1.446 + 1.447 + if (freeit) 1.448 + PORT_Free(array); 1.449 +} 1.450 + 1.451 +void SECITEM_FreeArray(SECItemArray *array, PRBool freeit) 1.452 +{ 1.453 + secitem_FreeArray(array, PR_FALSE, freeit); 1.454 +} 1.455 + 1.456 +void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit) 1.457 +{ 1.458 + secitem_FreeArray(array, PR_TRUE, freeit); 1.459 +} 1.460 + 1.461 +SECItemArray * 1.462 +SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from) 1.463 +{ 1.464 + SECItemArray *result; 1.465 + unsigned int i; 1.466 + 1.467 + /* Require a "from" array. 1.468 + * Reject an inconsistent "from" array with NULL data and nonzero length. 1.469 + * However, allow a "from" array of zero length. 1.470 + */ 1.471 + if (!from || (!from->items && from->len)) 1.472 + return NULL; 1.473 + 1.474 + result = SECITEM_AllocArray(arena, NULL, from->len); 1.475 + if (!result) 1.476 + return NULL; 1.477 + 1.478 + for (i = 0; i < from->len; ++i) { 1.479 + SECStatus rv = SECITEM_CopyItem(arena, 1.480 + &result->items[i], &from->items[i]); 1.481 + if (rv != SECSuccess) { 1.482 + SECITEM_ZfreeArray(result, PR_TRUE); 1.483 + return NULL; 1.484 + } 1.485 + } 1.486 + 1.487 + return result; 1.488 +}