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 /* 33 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 34 * Use is subject to license terms. 35 */ 36 37 #include <sys/types.h> 38 #include <netinet/in.h> 39 #include <inttypes.h> 40 41 #include <ber_der.h> 42 #include "kmfber_int.h" 43 44 /* the following constants are used in kmfber_calc_lenlen */ 45 46 #define LENMASK1 0xFF 47 #define LENMASK2 0xFFFF 48 #define LENMASK3 0xFFFFFF 49 #define LENMASK4 0xFFFFFFFF 50 #define _MASK 0x80 51 52 int 53 kmfber_calc_taglen(ber_tag_t tag) 54 { 55 int i; 56 ber_int_t mask; 57 58 /* find the first non-all-zero byte in the tag */ 59 for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 60 mask = (LENMASK3 << (i * 8)); 61 /* not all zero */ 62 if (tag & mask) 63 break; 64 } 65 66 return (i + 1); 67 } 68 69 static int 70 ber_put_tag(BerElement *ber, ber_tag_t tag, int nosos) 71 { 72 ber_int_t taglen; 73 ber_tag_t ntag; 74 75 taglen = kmfber_calc_taglen(tag); 76 77 ntag = htonl(tag); 78 79 return (kmfber_write(ber, 80 ((char *) &ntag) + sizeof (ber_int_t) - taglen, 81 taglen, nosos)); 82 } 83 84 int 85 kmfber_calc_lenlen(ber_int_t len) 86 { 87 /* 88 * short len if it's less than 128 - one byte giving the len, 89 * with bit 8 0. 90 */ 91 92 if (len <= 0x7F) 93 return (1); 94 95 /* 96 * long len otherwise - one byte with bit 8 set, giving the 97 * length of the length, followed by the length itself. 98 */ 99 100 if (len <= LENMASK1) 101 return (2); 102 if (len <= LENMASK2) 103 return (3); 104 if (len <= LENMASK3) 105 return (4); 106 107 return (5); 108 } 109 110 int 111 kmfber_put_len(BerElement *ber, ber_int_t len, int nosos) 112 { 113 int i; 114 char lenlen; 115 ber_int_t mask, netlen; 116 117 /* 118 * short len if it's less than 128 - one byte giving the len, 119 * with bit 8 0. 120 */ 121 if (len <= 127) { 122 netlen = htonl(len); 123 return (kmfber_write(ber, 124 (char *)&netlen + sizeof (ber_int_t) - 1, 125 1, nosos)); 126 } 127 128 /* 129 * long len otherwise - one byte with bit 8 set, giving the 130 * length of the length, followed by the length itself. 131 */ 132 133 /* find the first non-all-zero byte */ 134 for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 135 mask = (LENMASK1 << (i * 8)); 136 /* not all zero */ 137 if (len & mask) 138 break; 139 } 140 lenlen = ++i; 141 if (lenlen > 4) 142 return (-1); 143 lenlen |= 0x80; 144 145 /* write the length of the length */ 146 if (kmfber_write(ber, &lenlen, 1, nosos) != 1) 147 return (-1); 148 149 /* write the length itself */ 150 netlen = htonl(len); 151 if (kmfber_write(ber, 152 (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i) 153 return (-1); 154 155 return (i + 1); 156 } 157 158 static int 159 ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 160 { 161 int i, sign; 162 ber_int_t len, lenlen, taglen, netnum, mask; 163 164 sign = (num < 0); 165 166 /* 167 * high bit is set - look for first non-all-one byte 168 * high bit is clear - look for first non-all-zero byte 169 */ 170 for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 171 mask = (LENMASK1 << (i * 8)); 172 173 if (sign) { 174 /* not all ones */ 175 if ((num & mask) != mask) 176 break; 177 } else { 178 /* not all zero */ 179 if (num & mask) 180 break; 181 } 182 } 183 184 /* 185 * we now have the "leading byte". if the high bit on this 186 * byte matches the sign bit, we need to "back up" a byte. 187 */ 188 mask = (num & (_MASK << (i * 8))); 189 if ((mask && !sign) || (sign && !mask)) 190 i++; 191 192 len = i + 1; 193 194 if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 195 return (-1); 196 197 if ((lenlen = kmfber_put_len(ber, len, 0)) == -1) 198 return (-1); 199 i++; 200 netnum = htonl(num); 201 if (kmfber_write(ber, 202 (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i) 203 /* length of tag + length + contents */ 204 return (taglen + lenlen + i); 205 206 return (-1); 207 } 208 209 static int 210 kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 211 { 212 if (tag == KMFBER_DEFAULT) 213 tag = BER_ENUMERATED; 214 215 return (ber_put_int_or_enum(ber, num, tag)); 216 } 217 218 int 219 ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag) 220 { 221 if (tag == KMFBER_DEFAULT) 222 tag = BER_INTEGER; 223 224 return (ber_put_int_or_enum(ber, num, tag)); 225 } 226 227 int 228 ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag) 229 { 230 ber_int_t taglen, lenlen, rc, len; 231 232 if (tag == KMFBER_DEFAULT) 233 tag = 0x06; /* TODO: Add new OID constant to header */ 234 235 if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 236 return (-1); 237 238 len = (ber_int_t)oid->bv_len; 239 if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 || 240 kmfber_write(ber, oid->bv_val, oid->bv_len, 0) != 241 (ber_int_t)oid->bv_len) { 242 rc = -1; 243 } else { 244 /* return length of tag + length + contents */ 245 rc = taglen + lenlen + oid->bv_len; 246 } 247 return (rc); 248 } 249 250 int 251 ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data, 252 ber_len_t len) 253 { 254 ber_int_t taglen, lenlen, ilen, rc; 255 char zero = 0x00; 256 257 if (tag == KMFBER_DEFAULT) 258 tag = BER_INTEGER; 259 260 if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 261 return (-1); 262 263 /* Add a leading 0 if the high order bit is set */ 264 if (data[0] & 0x80) 265 len++; 266 267 ilen = (ber_int_t)len; 268 if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1) 269 return (-1); 270 271 /* add leading 0 if hi bit set */ 272 if ((data[0] & 0x80) && kmfber_write(ber, &zero, 1, 0) != 1) 273 return (-1); 274 275 /* Adjust the length of the write if hi-order bit is set */ 276 if (data[0] & 0x80) 277 ilen = len - 1; 278 if (kmfber_write(ber, data, ilen, 0) != (ber_int_t)ilen) { 279 return (-1); 280 } else { 281 /* return length of tag + length + contents */ 282 rc = taglen + lenlen + len; 283 } 284 return (rc); 285 } 286 287 static int 288 kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len, 289 ber_tag_t tag) 290 { 291 ber_int_t taglen, lenlen, ilen, rc; 292 #ifdef STR_TRANSLATION 293 int free_str; 294 #endif /* STR_TRANSLATION */ 295 296 if (tag == KMFBER_DEFAULT) 297 tag = BER_OCTET_STRING; 298 299 if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 300 return (-1); 301 302 #ifdef STR_TRANSLATION 303 if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 && 304 ber->ber_encode_translate_proc != NULL) { 305 if ((*(ber->ber_encode_translate_proc))(&str, &len, 0) 306 != 0) { 307 return (-1); 308 } 309 free_str = 1; 310 } else { 311 free_str = 0; 312 } 313 #endif /* STR_TRANSLATION */ 314 315 /* 316 * Note: below is a spot where we limit ber_write 317 * to signed long (instead of unsigned long) 318 */ 319 ilen = (ber_int_t)len; 320 if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 || 321 kmfber_write(ber, str, len, 0) != (ber_int_t)len) { 322 rc = -1; 323 } else { 324 /* return length of tag + length + contents */ 325 rc = taglen + lenlen + len; 326 } 327 328 #ifdef STR_TRANSLATION 329 if (free_str) { 330 free(str); 331 } 332 #endif /* STR_TRANSLATION */ 333 334 return (rc); 335 } 336 337 static int 338 kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag) 339 { 340 return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag)); 341 } 342 343 static int 344 kmfber_put_bitstring(BerElement *ber, char *str, 345 ber_len_t blen /* in bits */, ber_tag_t tag) 346 { 347 ber_int_t taglen, lenlen, len; 348 unsigned char unusedbits; 349 350 if (tag == KMFBER_DEFAULT) 351 tag = BER_BIT_STRING; 352 353 if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 354 return (-1); 355 356 len = (blen + 7) / 8; 357 unusedbits = (unsigned char) (len * 8 - blen); 358 if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1) 359 return (-1); 360 361 if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1) 362 return (-1); 363 364 if (kmfber_write(ber, str, len, 0) != len) 365 return (-1); 366 367 /* return length of tag + length + unused bit count + contents */ 368 return (taglen + 1 + lenlen + len); 369 } 370 371 static int 372 kmfber_put_null(BerElement *ber, ber_tag_t tag) 373 { 374 int taglen; 375 376 if (tag == KMFBER_DEFAULT) 377 tag = BER_NULL; 378 379 if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 380 return (-1); 381 382 if (kmfber_put_len(ber, 0, 0) != 1) 383 return (-1); 384 385 return (taglen + 1); 386 } 387 388 static int 389 kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag) 390 { 391 int taglen; 392 unsigned char trueval = 0xff; 393 unsigned char falseval = 0x00; 394 395 if (tag == KMFBER_DEFAULT) 396 tag = BER_BOOLEAN; 397 398 if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 399 return (-1); 400 401 if (kmfber_put_len(ber, 1, 0) != 1) 402 return (-1); 403 404 if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0) 405 != 1) 406 return (-1); 407 408 return (taglen + 2); 409 } 410 411 #define FOUR_BYTE_LEN 5 412 413 414 /* 415 * The idea here is roughly this: we maintain a stack of these Seqorset 416 * structures. This is pushed when we see the beginning of a new set or 417 * sequence. It is popped when we see the end of a set or sequence. 418 * Since we don't want to malloc and free these structures all the time, 419 * we pre-allocate a small set of them within the ber element structure. 420 * thus we need to spot when we've overflowed this stack and fall back to 421 * malloc'ing instead. 422 */ 423 static int 424 ber_start_seqorset(BerElement *ber, ber_tag_t tag) 425 { 426 Seqorset *new_sos; 427 428 /* can we fit into the local stack ? */ 429 if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) { 430 /* yes */ 431 new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn]; 432 } else { 433 /* no */ 434 if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset))) 435 == NULLSEQORSET) { 436 return (-1); 437 } 438 } 439 ber->ber_sos_stack_posn++; 440 441 if (ber->ber_sos == NULLSEQORSET) 442 new_sos->sos_first = ber->ber_ptr; 443 else 444 new_sos->sos_first = ber->ber_sos->sos_ptr; 445 446 /* Set aside room for a 4 byte length field */ 447 new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) + 448 FOUR_BYTE_LEN; 449 new_sos->sos_tag = tag; 450 451 new_sos->sos_next = ber->ber_sos; 452 new_sos->sos_clen = 0; 453 454 ber->ber_sos = new_sos; 455 if (ber->ber_sos->sos_ptr > ber->ber_end) { 456 if (kmfber_realloc(ber, ber->ber_sos->sos_ptr - 457 ber->ber_end) != 0) 458 return (-1); 459 } 460 return (0); 461 } 462 463 static int 464 kmfber_start_seq(BerElement *ber, ber_tag_t tag) 465 { 466 if (tag == KMFBER_DEFAULT) 467 tag = BER_CONSTRUCTED_SEQUENCE; 468 469 return (ber_start_seqorset(ber, tag)); 470 } 471 472 static int 473 kmfber_start_set(BerElement *ber, ber_tag_t tag) 474 { 475 if (tag == KMFBER_DEFAULT) 476 tag = BER_CONSTRUCTED_SET; 477 478 return (ber_start_seqorset(ber, tag)); 479 } 480 481 static int 482 ber_put_seqorset(BerElement *ber) 483 { 484 ber_int_t netlen, len, taglen, lenlen; 485 unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; 486 Seqorset *next; 487 Seqorset **sos = &ber->ber_sos; 488 489 /* 490 * If this is the toplevel sequence or set, we need to actually 491 * write the stuff out. Otherwise, it's already been put in 492 * the appropriate buffer and will be written when the toplevel 493 * one is written. In this case all we need to do is update the 494 * length and tag. 495 */ 496 497 len = (*sos)->sos_clen; 498 netlen = (ber_len_t)htonl(len); 499 500 if (ber->ber_options & KMFBER_OPT_USE_DER) { 501 lenlen = kmfber_calc_lenlen(len); 502 } else { 503 lenlen = FOUR_BYTE_LEN; 504 } 505 506 if ((next = (*sos)->sos_next) == NULLSEQORSET) { 507 /* write the tag */ 508 if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1) 509 return (-1); 510 511 if (ber->ber_options & KMFBER_OPT_USE_DER) { 512 /* Write the length in the minimum # of octets */ 513 if (kmfber_put_len(ber, len, 1) == -1) 514 return (-1); 515 516 if (lenlen != FOUR_BYTE_LEN) { 517 /* 518 * We set aside FOUR_BYTE_LEN bytes for 519 * the length field. Move the data if 520 * we don't actually need that much 521 */ 522 (void) memmove((*sos)->sos_first + taglen + 523 lenlen, (*sos)->sos_first + taglen + 524 FOUR_BYTE_LEN, len); 525 } 526 } else { 527 /* Fill FOUR_BYTE_LEN bytes for length field */ 528 /* one byte of length length */ 529 if (kmfber_write(ber, (char *)<ag, 1, 1) != 1) 530 return (-1); 531 532 /* the length itself */ 533 if (kmfber_write(ber, 534 (char *)&netlen + sizeof (ber_int_t) 535 - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) != 536 FOUR_BYTE_LEN - 1) 537 return (-1); 538 } 539 /* The ber_ptr is at the set/seq start - move it to the end */ 540 ber->ber_ptr += len; 541 } else { 542 ber_tag_t ntag; 543 544 /* the tag */ 545 taglen = kmfber_calc_taglen((*sos)->sos_tag); 546 ntag = htonl((*sos)->sos_tag); 547 (void) memmove((*sos)->sos_first, (char *)&ntag + 548 sizeof (ber_int_t) - taglen, taglen); 549 550 if (ber->ber_options & KMFBER_OPT_USE_DER) { 551 ltag = (lenlen == 1) ? (unsigned char)len : 552 (unsigned char) (0x80 + (lenlen - 1)); 553 } 554 555 /* one byte of length length */ 556 (void) memmove((*sos)->sos_first + 1, <ag, 1); 557 558 if (ber->ber_options & KMFBER_OPT_USE_DER) { 559 if (lenlen > 1) { 560 /* Write the length itself */ 561 (void) memmove((*sos)->sos_first + 2, 562 (char *)&netlen + sizeof (ber_uint_t) - 563 (lenlen - 1), 564 lenlen - 1); 565 } 566 if (lenlen != FOUR_BYTE_LEN) { 567 /* 568 * We set aside FOUR_BYTE_LEN bytes for 569 * the length field. Move the data if 570 * we don't actually need that much 571 */ 572 (void) memmove((*sos)->sos_first + taglen + 573 lenlen, (*sos)->sos_first + taglen + 574 FOUR_BYTE_LEN, len); 575 } 576 } else { 577 /* the length itself */ 578 (void) memmove((*sos)->sos_first + taglen + 1, 579 (char *) &netlen + sizeof (ber_int_t) - 580 (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1); 581 } 582 583 next->sos_clen += (taglen + lenlen + len); 584 next->sos_ptr += (taglen + lenlen + len); 585 } 586 587 /* we're done with this seqorset, so free it up */ 588 /* was this one from the local stack ? */ 589 if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) { 590 free((char *)(*sos)); 591 } 592 ber->ber_sos_stack_posn--; 593 *sos = next; 594 595 return (taglen + lenlen + len); 596 } 597 598 /* VARARGS */ 599 int 600 kmfber_printf(BerElement *ber, const char *fmt, ...) 601 { 602 va_list ap; 603 char *s, **ss; 604 struct berval **bv, *oid; 605 int rc, i, t; 606 ber_int_t len; 607 608 va_start(ap, fmt); 609 610 #ifdef KMFBER_DEBUG 611 if (lber_debug & 64) { 612 char msg[80]; 613 sprintf(msg, "kmfber_printf fmt (%s)\n", fmt); 614 ber_err_print(msg); 615 } 616 #endif 617 618 for (rc = 0; *fmt && rc != -1; fmt++) { 619 switch (*fmt) { 620 case 'b': /* boolean */ 621 i = va_arg(ap, int); 622 rc = kmfber_put_boolean(ber, i, ber->ber_tag); 623 break; 624 625 case 'i': /* int */ 626 i = va_arg(ap, int); 627 rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag); 628 break; 629 630 case 'D': /* Object ID */ 631 if ((oid = va_arg(ap, struct berval *)) == NULL) 632 break; 633 rc = ber_put_oid(ber, oid, ber->ber_tag); 634 break; 635 case 'I': /* int */ 636 s = va_arg(ap, char *); 637 len = va_arg(ap, ber_int_t); 638 rc = ber_put_big_int(ber, ber->ber_tag, s, len); 639 break; 640 641 case 'e': /* enumeration */ 642 i = va_arg(ap, int); 643 rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag); 644 break; 645 646 case 'l': 647 t = va_arg(ap, int); 648 rc = kmfber_put_len(ber, t, 0); 649 break; 650 case 'n': /* null */ 651 rc = kmfber_put_null(ber, ber->ber_tag); 652 break; 653 654 case 'o': /* octet string (non-null terminated) */ 655 s = va_arg(ap, char *); 656 len = va_arg(ap, int); 657 rc = kmfber_put_ostring(ber, s, len, ber->ber_tag); 658 break; 659 660 case 's': /* string */ 661 s = va_arg(ap, char *); 662 rc = kmfber_put_string(ber, s, ber->ber_tag); 663 break; 664 665 case 'B': /* bit string */ 666 s = va_arg(ap, char *); 667 len = va_arg(ap, int); /* in bits */ 668 rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag); 669 break; 670 671 case 't': /* tag for the next element */ 672 ber->ber_tag = va_arg(ap, ber_tag_t); 673 ber->ber_usertag = 1; 674 break; 675 676 case 'T': /* Write an explicit tag, but don't change current */ 677 t = va_arg(ap, int); 678 rc = ber_put_tag(ber, t, 0); 679 break; 680 681 case 'v': /* vector of strings */ 682 if ((ss = va_arg(ap, char **)) == NULL) 683 break; 684 for (i = 0; ss[i] != NULL; i++) { 685 if ((rc = kmfber_put_string(ber, ss[i], 686 ber->ber_tag)) == -1) 687 break; 688 } 689 break; 690 691 case 'V': /* sequences of strings + lengths */ 692 if ((bv = va_arg(ap, struct berval **)) == NULL) 693 break; 694 for (i = 0; bv[i] != NULL; i++) { 695 if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val, 696 bv[i]->bv_len, ber->ber_tag)) == -1) 697 break; 698 } 699 break; 700 701 case '{': /* begin sequence */ 702 rc = kmfber_start_seq(ber, ber->ber_tag); 703 break; 704 705 case '}': /* end sequence */ 706 rc = ber_put_seqorset(ber); 707 break; 708 709 case '[': /* begin set */ 710 rc = kmfber_start_set(ber, ber->ber_tag); 711 break; 712 713 case ']': /* end set */ 714 rc = ber_put_seqorset(ber); 715 break; 716 717 default: { 718 #ifdef KMFBER_DEBUG 719 char msg[80]; 720 sprintf(msg, "unknown fmt %c\n", *fmt); 721 ber_err_print(msg); 722 #endif 723 rc = -1; 724 break; 725 } 726 } 727 728 if (ber->ber_usertag == 0) 729 ber->ber_tag = KMFBER_DEFAULT; 730 else 731 ber->ber_usertag = 0; 732 } 733 734 va_end(ap); 735 736 return (rc); 737 } 738