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