1 /* 2 * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 3 * 4 * The contents of this file are subject to the Netscape Public License 5 * Version 1.0 (the "NPL"); you may not use this file except in 6 * compliance with the NPL. You may obtain a copy of the NPL at 7 * http://www.mozilla.org/NPL/ 8 * 9 * Software distributed under the NPL is distributed on an "AS IS" basis, 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 11 * for the specific language governing rights and limitations under the 12 * NPL. 13 * 14 * The Initial Developer of this code under the NPL is Netscape 15 * Communications Corporation. Portions created by Netscape are 16 * Copyright (C) 1998 Netscape Communications Corporation. All Rights 17 * Reserved. 18 */ 19 20 /* 21 * Copyright (c) 1990 Regents of the University of Michigan. 22 * All rights reserved. 23 * 24 * Redistribution and use in source and binary forms are permitted 25 * provided that this notice is preserved and that due credit is given 26 * to the University of Michigan at Ann Arbor. The name of the University 27 * may not be used to endorse or promote products derived from this 28 * software without specific prior written permission. This software 29 * is provided ``as is'' without express or implied warranty. 30 */ 31 /* 32 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 33 * Use is subject to license terms. 34 */ 35 36 #pragma ident "%Z%%M% %I% %E% SMI" 37 38 39 #include <stdlib.h> 40 #include <ber_der.h> 41 #include "kmfber_int.h" 42 43 #define EXBUFSIZ 1024 44 45 /* 46 * Note: kmfber_read() only uses the ber_end and ber_ptr elements of ber. 47 * Functions like kmfber_get_tag(), kmfber_skip_tag, and kmfber_peek_tag() 48 * rely on that fact, so if this code is changed to use any additional 49 * elements of the ber structure, those functions will need to be changed 50 * as well. 51 */ 52 ber_int_t 53 kmfber_read(BerElement *ber, char *buf, ber_len_t len) 54 { 55 size_t actuallen; 56 size_t nleft; 57 58 nleft = ber->ber_end - ber->ber_ptr; 59 actuallen = nleft < len ? nleft : len; 60 61 (void) memmove(buf, ber->ber_ptr, (size_t)actuallen); 62 63 ber->ber_ptr += actuallen; 64 65 return ((ber_int_t)actuallen); 66 } 67 68 /* 69 * enlarge the ber buffer. 70 * return 0 on success, -1 on error. 71 */ 72 static int 73 kmfber_realloc(BerElement *ber, ber_len_t len) 74 { 75 ber_uint_t need, have, total; 76 size_t have_bytes; 77 Seqorset *s; 78 size_t off; 79 char *oldbuf; 80 81 have_bytes = ber->ber_end - ber->ber_buf; 82 have = have_bytes / EXBUFSIZ; 83 need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ); 84 total = have * EXBUFSIZ + need * EXBUFSIZ; 85 86 oldbuf = ber->ber_buf; 87 88 if (ber->ber_buf == NULL) { 89 if ((ber->ber_buf = (char *)malloc((size_t)total)) 90 == NULL) { 91 return (-1); 92 } 93 ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER; 94 } else { 95 if (ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER) { 96 /* transition to malloc'd buffer */ 97 if ((ber->ber_buf = (char *)malloc( 98 (size_t)total)) == NULL) { 99 return (-1); 100 } 101 ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER; 102 /* copy existing data into new malloc'd buffer */ 103 (void) memmove(ber->ber_buf, oldbuf, have_bytes); 104 } else { 105 if ((ber->ber_buf = (char *)realloc( 106 ber->ber_buf, (size_t)total)) == NULL) { 107 return (-1); 108 } 109 } 110 } 111 112 ber->ber_end = ber->ber_buf + total; 113 114 /* 115 * If the stinking thing was moved, we need to go through and 116 * reset all the sos and ber pointers. Offsets would've been 117 * a better idea... oh well. 118 */ 119 120 if (ber->ber_buf != oldbuf) { 121 ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf); 122 123 for (s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next) { 124 off = s->sos_first - oldbuf; 125 s->sos_first = ber->ber_buf + off; 126 127 off = s->sos_ptr - oldbuf; 128 s->sos_ptr = ber->ber_buf + off; 129 } 130 } 131 132 return (0); 133 } 134 135 /* 136 * returns "len" on success and -1 on failure. 137 */ 138 ber_int_t 139 kmfber_write(BerElement *ber, char *buf, ber_len_t len, int nosos) 140 { 141 if (nosos || ber->ber_sos == NULL) { 142 if (ber->ber_ptr + len > ber->ber_end) { 143 if (kmfber_realloc(ber, len) != 0) 144 return (-1); 145 } 146 (void) memmove(ber->ber_ptr, buf, (size_t)len); 147 ber->ber_ptr += len; 148 return (len); 149 } else { 150 if (ber->ber_sos->sos_ptr + len > ber->ber_end) { 151 if (kmfber_realloc(ber, len) != 0) 152 return (-1); 153 } 154 (void) memmove(ber->ber_sos->sos_ptr, buf, (size_t)len); 155 ber->ber_sos->sos_ptr += len; 156 ber->ber_sos->sos_clen += len; 157 return (len); 158 } 159 } 160 161 void 162 kmfber_free(BerElement *ber, int freebuf) 163 { 164 if (ber != NULL) { 165 if (freebuf && 166 !(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER)) { 167 free(ber->ber_buf); 168 } 169 free((char *)ber); 170 } 171 } 172 173 /* we pre-allocate a buffer to save the extra malloc later */ 174 BerElement * 175 kmfber_alloc_t(int options) 176 { 177 BerElement *ber; 178 179 if ((ber = (BerElement*)calloc(1, 180 sizeof (struct berelement) + EXBUFSIZ)) == NULL) { 181 return (NULL); 182 } 183 184 ber->ber_tag = KMFBER_DEFAULT; 185 ber->ber_options = options; 186 ber->ber_buf = (char *)ber + sizeof (struct berelement); 187 ber->ber_ptr = ber->ber_buf; 188 ber->ber_end = ber->ber_buf + EXBUFSIZ; 189 ber->ber_flags = KMFBER_FLAG_NO_FREE_BUFFER; 190 191 return (ber); 192 } 193 194 195 BerElement * 196 kmfber_alloc() 197 { 198 return (kmfber_alloc_t(0)); 199 } 200 201 BerElement * 202 kmfder_alloc() 203 { 204 return (kmfber_alloc_t(KMFBER_OPT_USE_DER)); 205 } 206 207 BerElement * 208 kmfber_dup(BerElement *ber) 209 { 210 BerElement *new; 211 212 if ((new = kmfber_alloc()) == NULL) 213 return (NULL); 214 215 *new = *ber; 216 217 return (new); 218 } 219 220 221 void 222 ber_init_w_nullchar(BerElement *ber, int options) 223 { 224 (void) memset((char *)ber, '\0', sizeof (struct berelement)); 225 ber->ber_tag = KMFBER_DEFAULT; 226 227 ber->ber_options = options; 228 } 229 230 231 void 232 kmfber_reset(BerElement *ber, int was_writing) 233 { 234 if (was_writing) { 235 ber->ber_end = ber->ber_ptr; 236 ber->ber_ptr = ber->ber_buf; 237 } else { 238 ber->ber_ptr = ber->ber_end; 239 } 240 241 ber->ber_rwptr = NULL; 242 } 243 244 245 #ifdef KMFBER_DEBUG 246 247 void 248 ber_dump(BerElement *ber, int inout) 249 { 250 char msg[128]; 251 sprintf(msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n", 252 ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end); 253 ber_err_print(msg); 254 if (inout == 1) { 255 sprintf(msg, " current len %ld, contents:\n", 256 ber->ber_end - ber->ber_ptr); 257 ber_err_print(msg); 258 lber_bprint(ber->ber_ptr, ber->ber_end - ber->ber_ptr); 259 } else { 260 sprintf(msg, " current len %ld, contents:\n", 261 ber->ber_ptr - ber->ber_buf); 262 ber_err_print(msg); 263 lber_bprint(ber->ber_buf, ber->ber_ptr - ber->ber_buf); 264 } 265 } 266 267 void 268 ber_sos_dump(Seqorset *sos) 269 { 270 char msg[80]; 271 ber_err_print("*** sos dump ***\n"); 272 while (sos != NULLSEQORSET) { 273 sprintf(msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n", 274 sos->sos_clen, sos->sos_first, sos->sos_ptr); 275 ber_err_print(msg); 276 sprintf(msg, " current len %ld contents:\n", 277 sos->sos_ptr - sos->sos_first); 278 ber_err_print(msg); 279 lber_bprint(sos->sos_first, sos->sos_ptr - sos->sos_first); 280 281 sos = sos->sos_next; 282 } 283 ber_err_print("*** end dump ***\n"); 284 } 285 286 #endif 287 288 /* new dboreham code below: */ 289 struct byte_buffer { 290 unsigned char *p; 291 int offset; 292 int length; 293 }; 294 typedef struct byte_buffer byte_buffer; 295 296 /* 297 * The kmfber_flatten routine allocates a struct berval whose contents 298 * are a BER encoding taken from the ber argument. The bvPtr pointer 299 * points to the returned berval, which must be freed using 300 * kmfber_bvfree(). This routine returns 0 on success and -1 on error. 301 * The use of kmfber_flatten on a BerElement in which all '{' and '}' 302 * format modifiers have not been properly matched can result in a 303 * berval whose contents are not a valid BER encoding. 304 * Note that the ber_ptr is not modified. 305 */ 306 int 307 kmfber_flatten(BerElement *ber, struct berval **bvPtr) 308 { 309 struct berval *new; 310 ber_len_t len; 311 312 /* allocate a struct berval */ 313 new = (struct berval *)malloc((size_t)(sizeof (struct berval))); 314 if (new == NULL) { 315 return (-1); 316 } 317 (void) memset(new, 0, sizeof (struct berval)); 318 319 /* 320 * Copy everything from the BerElement's ber_buf to ber_ptr 321 * into the berval structure. 322 */ 323 if (ber == NULL) { 324 new->bv_val = NULL; 325 new->bv_len = 0; 326 } else { 327 len = ber->ber_ptr - ber->ber_buf; 328 new->bv_val = (char *)malloc((size_t)(len + 1)); 329 if (new->bv_val == NULL) { 330 kmfber_bvfree(new); 331 return (-1); 332 } 333 (void) memmove(new->bv_val, ber->ber_buf, (size_t)len); 334 new->bv_val[len] = '\0'; 335 new->bv_len = len; 336 } 337 338 /* set bvPtr pointer to point to the returned berval */ 339 *bvPtr = new; 340 341 return (0); 342 } 343 344 BerElement * 345 kmfder_init(const struct berval *bv) 346 { 347 BerElement *ber; 348 349 /* construct BerElement */ 350 if ((ber = kmfber_alloc_t(KMFBER_OPT_USE_DER)) != NULL) { 351 /* copy data from the bv argument into BerElement */ 352 /* XXXmcs: had to cast unsigned long bv_len to long */ 353 if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) != 354 (ber_slen_t)bv->bv_len) { 355 kmfber_free(ber, 1); 356 return (NULL); 357 } 358 } 359 /* 360 * reset ber_ptr back to the beginning of buffer so that this new 361 * and initialized ber element can be READ 362 */ 363 kmfber_reset(ber, 1); 364 365 /* 366 * return a ptr to a new BerElement containing a copy of the data 367 * in the bv argument or a null pointer on error 368 */ 369 return (ber); 370 } 371 372 BerElement * 373 kmfber_init(const struct berval *bv) 374 { 375 BerElement *ber; 376 377 /* construct BerElement */ 378 if ((ber = kmfber_alloc_t(0)) != NULL) { 379 /* copy data from the bv argument into BerElement */ 380 /* XXXmcs: had to cast unsigned long bv_len to long */ 381 if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) != 382 (ber_slen_t)bv->bv_len) { 383 kmfber_free(ber, 1); 384 return (NULL); 385 } 386 } 387 /* 388 * reset ber_ptr back to the beginning of buffer so that this new 389 * and initialized ber element can be READ 390 */ 391 kmfber_reset(ber, 1); 392 393 /* 394 * return a ptr to a new BerElement containing a copy of the data 395 * in the bv argument or a null pointer on error 396 */ 397 return (ber); 398 } 399