1/*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation.  Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above.  If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL.  If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34/*
35 * Support routines for SecAsn1Item data structure.
36 */
37
38#include "SecAsn1Item.h"
39#include <security_asn1/seccomon.h>
40#include <security_asn1/secerr.h>
41#include <security_asn1/secport.h>
42
43SecAsn1Item *
44SECITEM_AllocItem(PRArenaPool *arena, SecAsn1Item *item, size_t len)
45{
46    SecAsn1Item *result = NULL;
47    void *mark = NULL;
48
49    if (arena != NULL) {
50	mark = PORT_ArenaMark(arena);
51    }
52
53    if (item == NULL) {
54	if (arena != NULL) {
55	    result = PORT_ArenaZAlloc(arena, sizeof(SecAsn1Item));
56	} else {
57	    result = PORT_ZAlloc(sizeof(SecAsn1Item));
58	}
59	if (result == NULL) {
60	    goto loser;
61	}
62    } else {
63	PORT_Assert(item->Data == NULL);
64	result = item;
65    }
66
67    result->Length = len;
68    if (len) {
69	if (arena != NULL) {
70	    result->Data = PORT_ArenaAlloc(arena, len);
71	} else {
72	    result->Data = PORT_Alloc(len);
73	}
74    }
75
76    if (mark) {
77	PORT_ArenaUnmark(arena, mark);
78    }
79    return(result);
80
81loser:
82    if ( arena != NULL ) {
83	if (mark) {
84	    PORT_ArenaRelease(arena, mark);
85	}
86	if (item != NULL) {
87	    item->Data = NULL;
88	    item->Length = 0;
89	}
90    } else {
91	if (result != NULL) {
92	    SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
93	}
94    }
95    return(NULL);
96}
97
98SECStatus
99SECITEM_ReallocItem(PRArenaPool *arena, SecAsn1Item *item, size_t oldlen,
100		    size_t newlen)
101{
102    PORT_Assert(item != NULL);
103    if (item == NULL) {
104	/* XXX Set error.  But to what? */
105	return SECFailure;
106    }
107
108    /*
109     * If no old length, degenerate to just plain alloc.
110     */
111    if (oldlen == 0) {
112	PORT_Assert(item->Data == NULL || item->Length == 0);
113	if (newlen == 0) {
114	    /* Nothing to do.  Weird, but not a failure.  */
115	    return SECSuccess;
116	}
117	item->Length = newlen;
118	if (arena != NULL) {
119	    item->Data = PORT_ArenaAlloc(arena, newlen);
120	} else {
121	    item->Data = PORT_Alloc(newlen);
122	}
123    } else {
124	if (arena != NULL) {
125	    item->Data = PORT_ArenaGrow(arena, item->Data, oldlen, newlen);
126	} else {
127	    item->Data = PORT_Realloc(item->Data, newlen);
128	}
129    }
130
131    if (item->Data == NULL) {
132	return SECFailure;
133    }
134
135    return SECSuccess;
136}
137
138SECComparison
139SECITEM_CompareItem(const SecAsn1Item *a, const SecAsn1Item *b)
140{
141    size_t m;
142    SECComparison rv;
143
144    m = ( ( a->Length < b->Length ) ? a->Length : b->Length );
145
146    rv = (SECComparison) PORT_Memcmp(a->Data, b->Data, m);
147    if (rv) {
148	return rv;
149    }
150    if (a->Length < b->Length) {
151	return SECLessThan;
152    }
153    if (a->Length == b->Length) {
154	return SECEqual;
155    }
156    return SECGreaterThan;
157}
158
159Boolean
160SECITEM_ItemsAreEqual(const SecAsn1Item *a, const SecAsn1Item *b)
161{
162    if (a->Length != b->Length)
163        return PR_FALSE;
164    if (!a->Length)
165    	return PR_TRUE;
166    if (!a->Data || !b->Data) {
167        /* avoid null pointer crash. */
168		return (Boolean)(a->Data == b->Data);
169    }
170    return (Boolean)!PORT_Memcmp(a->Data, b->Data, a->Length);
171}
172
173SecAsn1Item *
174SECITEM_DupItem(const SecAsn1Item *from)
175{
176    return SECITEM_ArenaDupItem(NULL, from);
177}
178
179SecAsn1Item *
180SECITEM_ArenaDupItem(PRArenaPool *arena, const SecAsn1Item *from)
181{
182    SecAsn1Item *to;
183
184    if ( from == NULL ) {
185		return(NULL);
186    }
187
188    if ( arena != NULL ) {
189		to = (SecAsn1Item *)PORT_ArenaAlloc(arena, sizeof(SecAsn1Item));
190    } else {
191		to = (SecAsn1Item *)PORT_Alloc(sizeof(SecAsn1Item));
192    }
193    if ( to == NULL ) {
194		return(NULL);
195    }
196
197    if ( arena != NULL ) {
198		to->Data = (unsigned char *)PORT_ArenaAlloc(arena, from->Length);
199    } else {
200		to->Data = (unsigned char *)PORT_Alloc(from->Length);
201    }
202    if ( to->Data == NULL ) {
203		PORT_Free(to);
204		return(NULL);
205    }
206
207    to->Length = from->Length;
208    // to->type = from->type;
209    if ( to->Length ) {
210		PORT_Memcpy(to->Data, from->Data, to->Length);
211    }
212
213    return(to);
214}
215
216SECStatus
217SECITEM_CopyItem(PRArenaPool *arena, SecAsn1Item *to, const SecAsn1Item *from)
218{
219    // to->type = from->type;
220    if (from->Data && from->Length) {
221	if ( arena ) {
222	    to->Data = (unsigned char*) PORT_ArenaAlloc(arena, from->Length);
223	} else {
224	    to->Data = (unsigned char*) PORT_Alloc(from->Length);
225	}
226
227	if (!to->Data) {
228	    return SECFailure;
229	}
230	PORT_Memcpy(to->Data, from->Data, from->Length);
231	to->Length = from->Length;
232    } else {
233	to->Data = 0;
234	to->Length = 0;
235    }
236    return SECSuccess;
237}
238
239void
240SECITEM_FreeItem(SecAsn1Item *zap, Boolean freeit)
241{
242    if (zap) {
243	PORT_Free(zap->Data);
244	zap->Data = 0;
245	zap->Length = 0;
246	if (freeit) {
247	    PORT_Free(zap);
248	}
249    }
250}
251
252void
253SECITEM_ZfreeItem(SecAsn1Item *zap, Boolean freeit)
254{
255    if (zap) {
256	PORT_ZFree(zap->Data, zap->Length);
257	zap->Data = 0;
258	zap->Length = 0;
259	if (freeit) {
260	    PORT_ZFree(zap, sizeof(SecAsn1Item));
261	}
262    }
263}
264
265
266/* these reroutines were taken from pkix oid.c, which is supposed to
267 * replace this file some day */
268/*
269 * This is the hash function.  We simply XOR the encoded form with
270 * itself in sizeof(PLHashNumber)-byte chunks.  Improving this
271 * routine is left as an excercise for the more mathematically
272 * inclined student.
273 */
274PLHashNumber PR_CALLBACK
275SECITEM_Hash ( const void *key)
276{
277    const SecAsn1Item *item = (const SecAsn1Item *)key;
278    PLHashNumber rv = 0;
279
280    PRUint8 *data = (PRUint8 *)item->Data;
281    PRUint8 *rvc = (PRUint8 *)&rv;
282
283    size_t i;
284
285    for( i = 0; i < item->Length; i++ ) {
286        rvc[ i % sizeof(rv) ] ^= *data;
287        data++;
288    }
289
290    return rv;
291}
292
293/*
294 * This is the key-compare function.  It simply does a lexical
295 * comparison on the item data.  This does not result in
296 * quite the same ordering as the "sequence of numbers" order,
297 * but heck it's only used internally by the hash table anyway.
298 */
299PRIntn PR_CALLBACK
300SECITEM_HashCompare ( const void *k1, const void *k2)
301{
302    const SecAsn1Item *i1 = (const SecAsn1Item *)k1;
303    const SecAsn1Item *i2 = (const SecAsn1Item *)k2;
304
305    return SECITEM_ItemsAreEqual(i1,i2);
306}
307