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 42SECItem * 43SECITEM_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 80loser: 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 97SECStatus 98SECITEM_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 137SECComparison 138SECITEM_CompareItem(const SECItem *a, const SECItem *b) 139{ 140 CSSM_SIZE 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 158Boolean 159SECITEM_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 172SECItem * 173SECITEM_DupItem(const SECItem *from) 174{ 175 return SECITEM_ArenaDupItem(NULL, from); 176} 177 178SECItem * 179SECITEM_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 215SECStatus 216SECITEM_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 238void 239SECITEM_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 251void 252SECITEM_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 */ 273PLHashNumber PR_CALLBACK 274SECITEM_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 */ 297PRIntn PR_CALLBACK 298SECITEM_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} 305