1/* encode.c - ber output encoding routines */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16/* Portions Copyright (c) 1990 Regents of the University of Michigan. 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms are permitted 20 * provided that this notice is preserved and that due credit is given 21 * to the University of Michigan at Ann Arbor. The name of the University 22 * may not be used to endorse or promote products derived from this 23 * software without specific prior written permission. This software 24 * is provided ``as is'' without express or implied warranty. 25 */ 26/* ACKNOWLEDGEMENTS: 27 * This work was originally developed by the University of Michigan 28 * (as part of U-MICH LDAP). 29 */ 30 31#include "portable.h" 32 33#include <ctype.h> 34#include <limits.h> 35#include <stdio.h> 36 37#include <ac/stdlib.h> 38 39#include <ac/stdarg.h> 40#include <ac/socket.h> 41#include <ac/string.h> 42 43#include "lber-int.h" 44 45 46#define OCTET_SIZE(type) ((ber_len_t) (sizeof(type)*CHAR_BIT + 7) / 8) 47#define TAGBUF_SIZE OCTET_SIZE(ber_tag_t) 48#define LENBUF_SIZE (1 + OCTET_SIZE(ber_len_t)) 49#define HEADER_SIZE (TAGBUF_SIZE + LENBUF_SIZE) 50 51/* 52 * BER element size constrains: 53 * 54 * - We traditionally support a length of max 0xffffffff. However 55 * some functions return an int length so that is their max. 56 * MAXINT_BERSIZE is the max for those functions. 57 * 58 * - MAXINT_BERSIZE must fit in MAXINT_BERSIZE_OCTETS octets. 59 * 60 * - sizeof(ber_elem_size_t) is normally MAXINT_BERSIZE_OCTETS: 61 * Big enough for MAXINT_BERSIZE, but not more. (Larger wastes 62 * space in the working encoding and DER encoding of a sequence 63 * or set. Smaller further limits sizes near a sequence/set.) 64 * 65 * ber_len_t is mostly unrelated to this. Which may be for the best, 66 * since it is also used for lengths of data that are never encoded. 67 */ 68#define MAXINT_BERSIZE \ 69 (INT_MAX>0xffffffffUL ? (ber_len_t) 0xffffffffUL : INT_MAX-HEADER_SIZE) 70#define MAXINT_BERSIZE_OCTETS 4 71typedef ber_uint_t ber_elem_size_t; /* normally 32 bits */ 72 73 74/* Prepend tag to ptr, which points to the end of a tag buffer */ 75static unsigned char * 76ber_prepend_tag( unsigned char *ptr, ber_tag_t tag ) 77{ 78 do { 79 *--ptr = (unsigned char) tag & 0xffU; 80 } while ( (tag >>= 8) != 0 ); 81 82 return ptr; 83} 84 85/* Prepend ber length to ptr, which points to the end of a length buffer */ 86static unsigned char * 87ber_prepend_len( unsigned char *ptr, ber_len_t len ) 88{ 89 /* 90 * short len if it's less than 128 - one byte giving the len, 91 * with bit 8 0. 92 * long len otherwise - one byte with bit 8 set, giving the 93 * length of the length, followed by the length itself. 94 */ 95 96 *--ptr = (unsigned char) len & 0xffU; 97 98 if ( len >= 0x80 ) { 99 unsigned char *endptr = ptr--; 100 101 while ( (len >>= 8) != 0 ) { 102 *ptr-- = (unsigned char) len & 0xffU; 103 } 104 *ptr = (unsigned char) (endptr - ptr) + 0x80U; 105 } 106 107 return ptr; 108} 109 110/* out->bv_len should be the buffer size on input */ 111int 112ber_encode_oid( BerValue *in, BerValue *out ) 113{ 114 unsigned char *der; 115 unsigned long val1, val; 116 int i, j, len; 117 char *ptr, *end, *inend; 118 119 assert( in != NULL ); 120 assert( out != NULL ); 121 122 if ( !out->bv_val || out->bv_len < in->bv_len/2 ) 123 return -1; 124 125 der = (unsigned char *) out->bv_val; 126 ptr = in->bv_val; 127 inend = ptr + in->bv_len; 128 129 /* OIDs start with <0-1>.<0-39> or 2.<any>, DER-encoded 40*val1+val2 */ 130 if ( !isdigit( (unsigned char) *ptr )) return -1; 131 val1 = strtoul( ptr, &end, 10 ); 132 if ( end == ptr || val1 > 2 ) return -1; 133 if ( *end++ != '.' || !isdigit( (unsigned char) *end )) return -1; 134 val = strtoul( end, &ptr, 10 ); 135 if ( ptr == end ) return -1; 136 if ( val > (val1 < 2 ? 39 : LBER_OID_COMPONENT_MAX - 80) ) return -1; 137 val += val1 * 40; 138 139 for (;;) { 140 if ( ptr > inend ) return -1; 141 142 /* Write the OID component little-endian, then reverse it */ 143 len = 0; 144 do { 145 der[len++] = (val & 0xff) | 0x80; 146 } while ( (val >>= 7) != 0 ); 147 der[0] &= 0x7f; 148 for ( i = 0, j = len; i < --j; i++ ) { 149 unsigned char tmp = der[i]; 150 der[i] = der[j]; 151 der[j] = tmp; 152 } 153 der += len; 154 155 if ( ptr == inend ) 156 break; 157 158 if ( *ptr++ != '.' ) return -1; 159 if ( !isdigit( (unsigned char) *ptr )) return -1; 160 val = strtoul( ptr, &end, 10 ); 161 if ( end == ptr || val > LBER_OID_COMPONENT_MAX ) return -1; 162 ptr = end; 163 } 164 165 out->bv_len = (char *)der - out->bv_val; 166 return 0; 167} 168 169static int 170ber_put_int_or_enum( 171 BerElement *ber, 172 ber_int_t num, 173 ber_tag_t tag ) 174{ 175 ber_uint_t unum; 176 unsigned char sign, data[TAGBUF_SIZE+1 + OCTET_SIZE(ber_int_t)], *ptr; 177 178 sign = 0; 179 unum = num; /* Bit fiddling should be done with unsigned values */ 180 if ( num < 0 ) { 181 sign = 0xffU; 182 unum = ~unum; 183 } 184 for ( ptr = &data[sizeof(data) - 1] ;; unum >>= 8 ) { 185 *ptr-- = (sign ^ (unsigned char) unum) & 0xffU; 186 if ( unum < 0x80 ) /* top bit at *ptr is sign bit */ 187 break; 188 } 189 190 *ptr = (unsigned char) (&data[sizeof(data) - 1] - ptr); /* length */ 191 ptr = ber_prepend_tag( ptr, tag ); 192 193 return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 ); 194} 195 196int 197ber_put_enum( 198 BerElement *ber, 199 ber_int_t num, 200 ber_tag_t tag ) 201{ 202 if ( tag == LBER_DEFAULT ) { 203 tag = LBER_ENUMERATED; 204 } 205 206 return ber_put_int_or_enum( ber, num, tag ); 207} 208 209int 210ber_put_int( 211 BerElement *ber, 212 ber_int_t num, 213 ber_tag_t tag ) 214{ 215 if ( tag == LBER_DEFAULT ) { 216 tag = LBER_INTEGER; 217 } 218 219 return ber_put_int_or_enum( ber, num, tag ); 220} 221 222int 223ber_put_ostring( 224 BerElement *ber, 225 LDAP_CONST char *str, 226 ber_len_t len, 227 ber_tag_t tag ) 228{ 229 int rc; 230 unsigned char header[HEADER_SIZE], *ptr; 231 232 if ( tag == LBER_DEFAULT ) { 233 tag = LBER_OCTETSTRING; 234 } 235 236 if ( len > MAXINT_BERSIZE ) { 237 return -1; 238 } 239 240 ptr = ber_prepend_len( &header[sizeof(header)], len ); 241 ptr = ber_prepend_tag( ptr, tag ); 242 243 rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 ); 244 if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) { 245 /* length(tag + length + contents) */ 246 return rc + (int) len; 247 } 248 249 return -1; 250} 251 252int 253ber_put_berval( 254 BerElement *ber, 255 struct berval *bv, 256 ber_tag_t tag ) 257{ 258 if( bv == NULL || bv->bv_len == 0 ) { 259 return ber_put_ostring( ber, "", (ber_len_t) 0, tag ); 260 } 261 262 return ber_put_ostring( ber, bv->bv_val, bv->bv_len, tag ); 263} 264 265int 266ber_put_string( 267 BerElement *ber, 268 LDAP_CONST char *str, 269 ber_tag_t tag ) 270{ 271 assert( str != NULL ); 272 273 return ber_put_ostring( ber, str, strlen( str ), tag ); 274} 275 276int 277ber_put_bitstring( 278 BerElement *ber, 279 LDAP_CONST char *str, 280 ber_len_t blen /* in bits */, 281 ber_tag_t tag ) 282{ 283 int rc; 284 ber_len_t len; 285 unsigned char unusedbits, header[HEADER_SIZE + 1], *ptr; 286 287 if ( tag == LBER_DEFAULT ) { 288 tag = LBER_BITSTRING; 289 } 290 291 unusedbits = (unsigned char) -blen & 7; 292 len = blen / 8 + (unusedbits != 0); /* (blen+7)/8 without overflow */ 293 if ( len >= MAXINT_BERSIZE ) { 294 return -1; 295 } 296 297 header[sizeof(header) - 1] = unusedbits; 298 ptr = ber_prepend_len( &header[sizeof(header) - 1], len + 1 ); 299 ptr = ber_prepend_tag( ptr, tag ); 300 301 rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 ); 302 if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) { 303 /* length(tag + length + unused bit count + bitstring) */ 304 return rc + (int) len; 305 } 306 307 return -1; 308} 309 310int 311ber_put_null( BerElement *ber, ber_tag_t tag ) 312{ 313 unsigned char data[TAGBUF_SIZE + 1], *ptr; 314 315 if ( tag == LBER_DEFAULT ) { 316 tag = LBER_NULL; 317 } 318 319 data[sizeof(data) - 1] = 0; /* length */ 320 ptr = ber_prepend_tag( &data[sizeof(data) - 1], tag ); 321 322 return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 ); 323} 324 325int 326ber_put_boolean( 327 BerElement *ber, 328 ber_int_t boolval, 329 ber_tag_t tag ) 330{ 331 unsigned char data[TAGBUF_SIZE + 2], *ptr; 332 333 if ( tag == LBER_DEFAULT ) 334 tag = LBER_BOOLEAN; 335 336 data[sizeof(data) - 1] = boolval ? 0xff : 0; 337 data[sizeof(data) - 2] = 1; /* length */ 338 ptr = ber_prepend_tag( &data[sizeof(data) - 2], tag ); 339 340 return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 ); 341} 342 343 344/* Max number of length octets in a sequence or set, normally 5 */ 345#define SOS_LENLEN (1 + (sizeof(ber_elem_size_t) > MAXINT_BERSIZE_OCTETS ? \ 346 (ber_len_t) sizeof(ber_elem_size_t) : MAXINT_BERSIZE_OCTETS)) 347 348/* Header of incomplete sequence or set */ 349typedef struct seqorset_header { 350 char xtagbuf[TAGBUF_SIZE + 1]; /* room for tag + len(tag or len) */ 351 union { 352 ber_elem_size_t offset; /* enclosing seqence/set */ 353 char padding[SOS_LENLEN-1]; /* for final length encoding */ 354 } next_sos; 355# define SOS_TAG_END(header) ((unsigned char *) &(header).next_sos - 1) 356} Seqorset_header; 357 358/* Start a sequence or set */ 359static int 360ber_start_seqorset( 361 BerElement *ber, 362 ber_tag_t tag ) 363{ 364 /* 365 * Write the tag and SOS_LENLEN octets reserved for length, to ber. 366 * For now, length octets = (tag length, previous ber_sos_inner). 367 * 368 * Update ber_sos_inner and the write-cursor ber_sos_ptr. ber_ptr 369 * will not move until the outermost sequence or set is complete. 370 */ 371 372 Seqorset_header header; 373 unsigned char *headptr; 374 ber_len_t taglen, headlen; 375 char *dest, **p; 376 377 assert( ber != NULL ); 378 assert( LBER_VALID( ber ) ); 379 380 if ( ber->ber_sos_ptr == NULL ) { /* outermost sequence/set? */ 381 header.next_sos.offset = 0; 382 p = &ber->ber_ptr; 383 } else { 384 if ( (ber_len_t) -1 > (ber_elem_size_t) -1 ) { 385 if ( ber->ber_sos_inner > (ber_elem_size_t) -1 ) 386 return -1; 387 } 388 header.next_sos.offset = ber->ber_sos_inner; 389 p = &ber->ber_sos_ptr; 390 } 391 headptr = ber_prepend_tag( SOS_TAG_END(header), tag ); 392 *SOS_TAG_END(header) = taglen = SOS_TAG_END(header) - headptr; 393 headlen = taglen + SOS_LENLEN; 394 395 /* As ber_write(,headptr,headlen,) except update ber_sos_ptr, not *p */ 396 if ( headlen > (ber_len_t) (ber->ber_end - *p) ) { 397 if ( ber_realloc( ber, headlen ) != 0 ) 398 return -1; 399 } 400 dest = *p; 401 AC_MEMCPY( dest, headptr, headlen ); 402 ber->ber_sos_ptr = dest + headlen; 403 404 ber->ber_sos_inner = dest + taglen - ber->ber_buf; 405 406 /* 407 * Do not return taglen + SOS_LENLEN here - then ber_put_seqorset() 408 * should return lenlen - SOS_LENLEN + len, which can be < 0. 409 */ 410 return 0; 411} 412 413int 414ber_start_seq( BerElement *ber, ber_tag_t tag ) 415{ 416 if ( tag == LBER_DEFAULT ) { 417 tag = LBER_SEQUENCE; 418 } 419 420 return ber_start_seqorset( ber, tag ); 421} 422 423int 424ber_start_set( BerElement *ber, ber_tag_t tag ) 425{ 426 if ( tag == LBER_DEFAULT ) { 427 tag = LBER_SET; 428 } 429 430 return ber_start_seqorset( ber, tag ); 431} 432 433/* End a sequence or set */ 434static int 435ber_put_seqorset( BerElement *ber ) 436{ 437 Seqorset_header header; 438 unsigned char *lenptr; /* length octets in the sequence/set */ 439 ber_len_t len; /* length(contents) */ 440 ber_len_t xlen; /* len + length(length) */ 441 442 assert( ber != NULL ); 443 assert( LBER_VALID( ber ) ); 444 445 if ( ber->ber_sos_ptr == NULL ) return -1; 446 447 lenptr = (unsigned char *) ber->ber_buf + ber->ber_sos_inner; 448 xlen = ber->ber_sos_ptr - (char *) lenptr; 449 if ( xlen > MAXINT_BERSIZE + SOS_LENLEN ) { 450 return -1; 451 } 452 453 /* Extract sequence/set information from length octets */ 454 memcpy( SOS_TAG_END(header), lenptr, SOS_LENLEN ); 455 456 /* Store length, and close gap of leftover reserved length octets */ 457 len = xlen - SOS_LENLEN; 458 if ( !(ber->ber_options & LBER_USE_DER) ) { 459 int i; 460 lenptr[0] = SOS_LENLEN - 1 + 0x80; /* length(length)-1 */ 461 for( i = SOS_LENLEN; --i > 0; len >>= 8 ) { 462 lenptr[i] = len & 0xffU; 463 } 464 } else { 465 unsigned char *p = ber_prepend_len( lenptr + SOS_LENLEN, len ); 466 ber_len_t unused = p - lenptr; 467 if ( unused != 0 ) { 468 /* length(length) < the reserved SOS_LENLEN bytes */ 469 xlen -= unused; 470 AC_MEMCPY( lenptr, p, xlen ); 471 ber->ber_sos_ptr = (char *) lenptr + xlen; 472 } 473 } 474 475 ber->ber_sos_inner = header.next_sos.offset; 476 if ( header.next_sos.offset == 0 ) { /* outermost sequence/set? */ 477 /* The ber_ptr is at the set/seq start - move it to the end */ 478 ber->ber_ptr = ber->ber_sos_ptr; 479 ber->ber_sos_ptr = NULL; 480 } 481 482 return xlen + *SOS_TAG_END(header); /* lenlen + len + taglen */ 483} 484 485int 486ber_put_seq( BerElement *ber ) 487{ 488 return ber_put_seqorset( ber ); 489} 490 491int 492ber_put_set( BerElement *ber ) 493{ 494 return ber_put_seqorset( ber ); 495} 496 497/* N tag */ 498static ber_tag_t lber_int_null = 0; 499 500/* VARARGS */ 501int 502ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... ) 503{ 504 va_list ap; 505 char *s, **ss; 506 struct berval *bv, **bvp; 507 int rc; 508 ber_int_t i; 509 ber_len_t len; 510 511 assert( ber != NULL ); 512 assert( fmt != NULL ); 513 assert( LBER_VALID( ber ) ); 514 515 va_start( ap, fmt ); 516 517 for ( rc = 0; *fmt && rc != -1; fmt++ ) { 518 switch ( *fmt ) { 519 case '!': { /* hook */ 520 BEREncodeCallback *f; 521 void *p; 522 523 ber->ber_usertag = 0; 524 525 f = va_arg( ap, BEREncodeCallback * ); 526 p = va_arg( ap, void * ); 527 rc = (*f)( ber, p ); 528 529 if ( ber->ber_usertag ) { 530 goto next; 531 } 532 } break; 533 534 case 'b': /* boolean */ 535 i = va_arg( ap, ber_int_t ); 536 rc = ber_put_boolean( ber, i, ber->ber_tag ); 537 break; 538 539 case 'i': /* int */ 540 i = va_arg( ap, ber_int_t ); 541 rc = ber_put_int( ber, i, ber->ber_tag ); 542 break; 543 544 case 'e': /* enumeration */ 545 i = va_arg( ap, ber_int_t ); 546 rc = ber_put_enum( ber, i, ber->ber_tag ); 547 break; 548 549 case 'n': /* null */ 550 rc = ber_put_null( ber, ber->ber_tag ); 551 break; 552 553 case 'N': /* Debug NULL */ 554 rc = 0; 555 if( lber_int_null != 0 ) { 556 /* Insert NULL to ensure peer ignores unknown tags */ 557 rc = ber_put_null( ber, lber_int_null ); 558 } 559 break; 560 561 case 'o': /* octet string (non-null terminated) */ 562 s = va_arg( ap, char * ); 563 len = va_arg( ap, ber_len_t ); 564 rc = ber_put_ostring( ber, s, len, ber->ber_tag ); 565 break; 566 567 case 'O': /* berval octet string */ 568 bv = va_arg( ap, struct berval * ); 569 if( bv == NULL ) break; 570 rc = ber_put_berval( ber, bv, ber->ber_tag ); 571 break; 572 573 case 's': /* string */ 574 s = va_arg( ap, char * ); 575 rc = ber_put_string( ber, s, ber->ber_tag ); 576 break; 577 578 case 'B': /* bit string */ 579 case 'X': /* bit string (deprecated) */ 580 s = va_arg( ap, char * ); 581 len = va_arg( ap, ber_len_t ); /* in bits */ 582 rc = ber_put_bitstring( ber, s, len, ber->ber_tag ); 583 break; 584 585 case 't': /* tag for the next element */ 586 ber->ber_tag = va_arg( ap, ber_tag_t ); 587 goto next; 588 589 case 'v': /* vector of strings */ 590 if ( (ss = va_arg( ap, char ** )) == NULL ) 591 break; 592 for ( i = 0; ss[i] != NULL; i++ ) { 593 if ( (rc = ber_put_string( ber, ss[i], 594 ber->ber_tag )) == -1 ) 595 break; 596 } 597 break; 598 599 case 'V': /* sequences of strings + lengths */ 600 if ( (bvp = va_arg( ap, struct berval ** )) == NULL ) 601 break; 602 for ( i = 0; bvp[i] != NULL; i++ ) { 603 if ( (rc = ber_put_berval( ber, bvp[i], 604 ber->ber_tag )) == -1 ) 605 break; 606 } 607 break; 608 609 case 'W': /* BerVarray */ 610 if ( (bv = va_arg( ap, BerVarray )) == NULL ) 611 break; 612 for ( i = 0; bv[i].bv_val != NULL; i++ ) { 613 if ( (rc = ber_put_berval( ber, &bv[i], 614 ber->ber_tag )) == -1 ) 615 break; 616 } 617 break; 618 619 case '{': /* begin sequence */ 620 rc = ber_start_seq( ber, ber->ber_tag ); 621 break; 622 623 case '}': /* end sequence */ 624 rc = ber_put_seqorset( ber ); 625 break; 626 627 case '[': /* begin set */ 628 rc = ber_start_set( ber, ber->ber_tag ); 629 break; 630 631 case ']': /* end set */ 632 rc = ber_put_seqorset( ber ); 633 break; 634 635 default: 636 if( ber->ber_debug ) { 637 ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, 638 "ber_printf: unknown fmt %c\n", *fmt ); 639 } 640 rc = -1; 641 break; 642 } 643 644 ber->ber_tag = LBER_DEFAULT; 645 next:; 646 } 647 648 va_end( ap ); 649 650 return rc; 651} 652