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