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