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