]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/secitem.c
Security-55179.11.tar.gz
[apple/security.git] / libsecurity_smime / lib / secitem.c
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 SECItem data structure.
36 */
37
38 #include "secitem.h"
39 #include <security_asn1/seccomon.h>
40 #include <security_asn1/secerr.h>
41
42 SECItem *
43 SECITEM_AllocItem(PRArenaPool *arena, SECItem *item, unsigned int len)
44 {
45 SECItem *result = NULL;
46 void *mark = NULL;
47
48 if (arena != NULL) {
49 mark = PORT_ArenaMark(arena);
50 }
51
52 if (item == NULL) {
53 if (arena != NULL) {
54 result = PORT_ArenaZAlloc(arena, sizeof(SECItem));
55 } else {
56 result = PORT_ZAlloc(sizeof(SECItem));
57 }
58 if (result == NULL) {
59 goto loser;
60 }
61 } else {
62 PORT_Assert(item->Data == NULL);
63 result = item;
64 }
65
66 result->Length = len;
67 if (len) {
68 if (arena != NULL) {
69 result->Data = PORT_ArenaAlloc(arena, len);
70 } else {
71 result->Data = PORT_Alloc(len);
72 }
73 }
74
75 if (mark) {
76 PORT_ArenaUnmark(arena, mark);
77 }
78 return(result);
79
80 loser:
81 if ( arena != NULL ) {
82 if (mark) {
83 PORT_ArenaRelease(arena, mark);
84 }
85 if (item != NULL) {
86 item->Data = NULL;
87 item->Length = 0;
88 }
89 } else {
90 if (result != NULL) {
91 SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
92 }
93 }
94 return(NULL);
95 }
96
97 SECStatus
98 SECITEM_ReallocItem(PRArenaPool *arena, SECItem *item, unsigned int oldlen,
99 unsigned int newlen)
100 {
101 PORT_Assert(item != NULL);
102 if (item == NULL) {
103 /* XXX Set error. But to what? */
104 return SECFailure;
105 }
106
107 /*
108 * If no old length, degenerate to just plain alloc.
109 */
110 if (oldlen == 0) {
111 PORT_Assert(item->Data == NULL || item->Length == 0);
112 if (newlen == 0) {
113 /* Nothing to do. Weird, but not a failure. */
114 return SECSuccess;
115 }
116 item->Length = newlen;
117 if (arena != NULL) {
118 item->Data = PORT_ArenaAlloc(arena, newlen);
119 } else {
120 item->Data = PORT_Alloc(newlen);
121 }
122 } else {
123 if (arena != NULL) {
124 item->Data = PORT_ArenaGrow(arena, item->Data, oldlen, newlen);
125 } else {
126 item->Data = PORT_Realloc(item->Data, newlen);
127 }
128 }
129
130 if (item->Data == NULL) {
131 return SECFailure;
132 }
133
134 return SECSuccess;
135 }
136
137 SECComparison
138 SECITEM_CompareItem(const SECItem *a, const SECItem *b)
139 {
140 unsigned m;
141 SECComparison rv;
142
143 m = ( ( a->Length < b->Length ) ? a->Length : b->Length );
144
145 rv = (SECComparison) PORT_Memcmp(a->Data, b->Data, m);
146 if (rv) {
147 return rv;
148 }
149 if (a->Length < b->Length) {
150 return SECLessThan;
151 }
152 if (a->Length == b->Length) {
153 return SECEqual;
154 }
155 return SECGreaterThan;
156 }
157
158 Boolean
159 SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
160 {
161 if (a->Length != b->Length)
162 return PR_FALSE;
163 if (!a->Length)
164 return PR_TRUE;
165 if (!a->Data || !b->Data) {
166 /* avoid null pointer crash. */
167 return (Boolean)(a->Data == b->Data);
168 }
169 return (Boolean)!PORT_Memcmp(a->Data, b->Data, a->Length);
170 }
171
172 SECItem *
173 SECITEM_DupItem(const SECItem *from)
174 {
175 return SECITEM_ArenaDupItem(NULL, from);
176 }
177
178 SECItem *
179 SECITEM_ArenaDupItem(PRArenaPool *arena, const SECItem *from)
180 {
181 SECItem *to;
182
183 if ( from == NULL ) {
184 return(NULL);
185 }
186
187 if ( arena != NULL ) {
188 to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
189 } else {
190 to = (SECItem *)PORT_Alloc(sizeof(SECItem));
191 }
192 if ( to == NULL ) {
193 return(NULL);
194 }
195
196 if ( arena != NULL ) {
197 to->Data = (unsigned char *)PORT_ArenaAlloc(arena, from->Length);
198 } else {
199 to->Data = (unsigned char *)PORT_Alloc(from->Length);
200 }
201 if ( to->Data == NULL ) {
202 PORT_Free(to);
203 return(NULL);
204 }
205
206 to->Length = from->Length;
207 // to->type = from->type;
208 if ( to->Length ) {
209 PORT_Memcpy(to->Data, from->Data, to->Length);
210 }
211
212 return(to);
213 }
214
215 SECStatus
216 SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, const SECItem *from)
217 {
218 // to->type = from->type;
219 if (from->Data && from->Length) {
220 if ( arena ) {
221 to->Data = (unsigned char*) PORT_ArenaAlloc(arena, from->Length);
222 } else {
223 to->Data = (unsigned char*) PORT_Alloc(from->Length);
224 }
225
226 if (!to->Data) {
227 return SECFailure;
228 }
229 PORT_Memcpy(to->Data, from->Data, from->Length);
230 to->Length = from->Length;
231 } else {
232 to->Data = 0;
233 to->Length = 0;
234 }
235 return SECSuccess;
236 }
237
238 void
239 SECITEM_FreeItem(SECItem *zap, Boolean freeit)
240 {
241 if (zap) {
242 PORT_Free(zap->Data);
243 zap->Data = 0;
244 zap->Length = 0;
245 if (freeit) {
246 PORT_Free(zap);
247 }
248 }
249 }
250
251 void
252 SECITEM_ZfreeItem(SECItem *zap, Boolean freeit)
253 {
254 if (zap) {
255 PORT_ZFree(zap->Data, zap->Length);
256 zap->Data = 0;
257 zap->Length = 0;
258 if (freeit) {
259 PORT_ZFree(zap, sizeof(SECItem));
260 }
261 }
262 }
263
264
265 /* these reroutines were taken from pkix oid.c, which is supposed to
266 * replace this file some day */
267 /*
268 * This is the hash function. We simply XOR the encoded form with
269 * itself in sizeof(PLHashNumber)-byte chunks. Improving this
270 * routine is left as an excercise for the more mathematically
271 * inclined student.
272 */
273 PLHashNumber PR_CALLBACK
274 SECITEM_Hash ( const void *key)
275 {
276 const SECItem *item = (const SECItem *)key;
277 PLHashNumber rv = 0;
278
279 PRUint8 *data = (PRUint8 *)item->Data;
280 PRUint32 i;
281 PRUint8 *rvc = (PRUint8 *)&rv;
282
283 for( i = 0; i < item->Length; i++ ) {
284 rvc[ i % sizeof(rv) ] ^= *data;
285 data++;
286 }
287
288 return rv;
289 }
290
291 /*
292 * This is the key-compare function. It simply does a lexical
293 * comparison on the item data. This does not result in
294 * quite the same ordering as the "sequence of numbers" order,
295 * but heck it's only used internally by the hash table anyway.
296 */
297 PRIntn PR_CALLBACK
298 SECITEM_HashCompare ( const void *k1, const void *k2)
299 {
300 const SECItem *i1 = (const SECItem *)k1;
301 const SECItem *i2 = (const SECItem *)k2;
302
303 return SECITEM_ItemsAreEqual(i1,i2);
304 }