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