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