security/nss/lib/util/secitem.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

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

mercurial