1 /* encode.c - ber output encoding routines */
4 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
8 * Copyright (c) 1990 Regents of the University of Michigan.
11 * Redistribution and use in source and binary forms are permitted
12 * provided that this notice is preserved and that due credit is given
13 * to the University of Michigan at Ann Arbor. The name of the University
14 * may not be used to endorse or promote products derived from this
15 * software without specific prior written permission. This software
16 * is provided ``as is'' without express or implied warranty.
23 #include <ac/stdlib.h>
25 #include <ac/stdarg.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
31 static int ber_put_len LDAP_P((
36 static int ber_start_seqorset LDAP_P((
40 static int ber_put_seqorset LDAP_P(( BerElement *ber ));
42 static int ber_put_int_or_enum LDAP_P((
49 ber_calc_taglen( ber_tag_t tag )
54 /* find the first non-all-zero byte in the tag */
55 for ( i = sizeof(ber_tag_t) - 1; i > 0; i-- ) {
56 mask = ((ber_tag_t)0xffU << (i * 8));
74 unsigned char nettag[sizeof(ber_tag_t)];
76 assert( ber != NULL );
77 assert( BER_VALID( ber ) );
79 taglen = ber_calc_taglen( tag );
81 for( i=0; i<taglen; i++ ) {
82 nettag[(sizeof(ber_tag_t)-1) - i] = (unsigned char)(tag & 0xffU);
87 &nettag[sizeof(ber_tag_t) - taglen],
94 ber_calc_lenlen( ber_len_t len )
97 * short len if it's less than 128 - one byte giving the len,
101 if ( len <= (ber_len_t) 0x7FU )
105 * long len otherwise - one byte with bit 8 set, giving the
106 * length of the length, followed by the length itself.
109 if ( len <= (ber_len_t) 0xffU )
111 if ( len <= (ber_len_t) 0xffffU )
113 if ( len <= (ber_len_t) 0xffffffU )
120 ber_put_len( BerElement *ber, ber_len_t len, int nosos )
126 unsigned char netlen[sizeof(ber_len_t)];
128 assert( ber != NULL );
129 assert( BER_VALID( ber ) );
132 * short len if it's less than 128 - one byte giving the len,
137 char length_byte = (char) len;
138 return( ber_write( ber, &length_byte, 1, nosos ) );
142 * long len otherwise - one byte with bit 8 set, giving the
143 * length of the length, followed by the length itself.
146 /* find the first non-all-zero byte */
147 for ( i = sizeof(ber_len_t) - 1; i > 0; i-- ) {
148 mask = ((ber_len_t)0xffU << (i * 8));
153 lenlen = (unsigned char) ++i;
159 /* write the length of the length */
160 if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
163 for( j=0; j<i; j++) {
164 netlen[(sizeof(ber_len_t)-1) - j] = (unsigned char)(len & 0xffU);
168 /* write the length itself */
170 &netlen[sizeof(ber_len_t)-i],
173 return rc == i ? i+1 : -1;
184 ber_len_t len, lenlen, taglen;
185 ber_uint_t unum, mask;
186 unsigned char netnum[sizeof(ber_uint_t)];
188 assert( ber != NULL );
189 assert( BER_VALID( ber ) );
192 unum = num; /* Bit fiddling should be done with unsigned values */
195 * high bit is set - look for first non-all-one byte
196 * high bit is clear - look for first non-all-zero byte
198 for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
199 mask = ((ber_uint_t)0xffU << (i * 8));
203 if ( (unum & mask) != mask )
213 * we now have the "leading byte". if the high bit on this
214 * byte matches the sign bit, we need to "back up" a byte.
216 mask = (unum & ((ber_uint_t)0x80U << (i * 8)));
217 if ( (mask && !sign) || (sign && !mask) )
222 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
225 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
229 for( j=0; j<i; j++ ) {
230 netnum[(sizeof(ber_int_t)-1) - j] = (unsigned char)(unum & 0xffU);
235 &netnum[sizeof(ber_int_t) - i],
238 /* length of tag + length + contents */
239 return rc == i ? taglen + lenlen + i : -1;
248 assert( ber != NULL );
249 assert( BER_VALID( ber ) );
251 if ( tag == LBER_DEFAULT )
252 tag = LBER_ENUMERATED;
254 return( ber_put_int_or_enum( ber, num, tag ) );
263 assert( ber != NULL );
264 assert( BER_VALID( ber ) );
266 if ( tag == LBER_DEFAULT )
269 return( ber_put_int_or_enum( ber, num, tag ) );
275 LDAP_CONST char *str,
279 ber_len_t taglen, lenlen;
282 assert( ber != NULL );
283 assert( str != NULL );
285 assert( BER_VALID( ber ) );
287 if ( tag == LBER_DEFAULT )
288 tag = LBER_OCTETSTRING;
290 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
293 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
294 (ber_len_t) ber_write( ber, str, len, 0 ) != len ) {
297 /* return length of tag + length + contents */
298 rc = taglen + lenlen + len;
307 LDAP_CONST struct berval *bv,
310 assert( ber != NULL );
311 assert( BER_VALID( ber ) );
313 if( bv == NULL || bv->bv_len == 0 ) {
314 return ber_put_ostring( ber, "", (ber_len_t) 0, tag );
317 return ber_put_ostring( ber, bv->bv_val, bv->bv_len, tag );
323 LDAP_CONST char *str,
326 assert( ber != NULL );
327 assert( str != NULL );
329 assert( BER_VALID( ber ) );
331 return( ber_put_ostring( ber, str, strlen( str ), tag ));
337 LDAP_CONST char *str,
338 ber_len_t blen /* in bits */,
341 ber_len_t taglen, lenlen, len;
342 unsigned char unusedbits;
344 assert( ber != NULL );
345 assert( str != NULL );
347 assert( BER_VALID( ber ) );
349 if ( tag == LBER_DEFAULT )
350 tag = LBER_BITSTRING;
352 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
355 len = ( blen + 7 ) / 8;
356 unusedbits = (unsigned char) ((len * 8) - blen);
357 if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
360 if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
363 if ( (ber_len_t) ber_write( ber, str, len, 0 ) != len )
366 /* return length of tag + length + unused bit count + contents */
367 return( taglen + 1 + lenlen + len );
371 ber_put_null( BerElement *ber, ber_tag_t tag )
375 assert( ber != NULL );
376 assert( BER_VALID( ber ) );
378 if ( tag == LBER_DEFAULT )
381 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
384 if ( ber_put_len( ber, 0, 0 ) != 1 )
387 return( taglen + 1 );
397 unsigned char trueval = (unsigned char) -1;
398 unsigned char falseval = 0;
400 assert( ber != NULL );
401 assert( BER_VALID( ber ) );
403 if ( tag == LBER_DEFAULT )
406 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
409 if ( ber_put_len( ber, 1, 0 ) != 1 )
412 if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
416 return( taglen + 2 );
419 #define FOUR_BYTE_LEN 5
428 assert( ber != NULL );
429 assert( BER_VALID( ber ) );
431 new = (Seqorset *) LBER_CALLOC( 1, sizeof(Seqorset) );
437 if ( ber->ber_sos == NULL )
438 new->sos_first = ber->ber_ptr;
440 new->sos_first = ber->ber_sos->sos_ptr;
442 /* Set aside room for a 4 byte length field */
443 new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
446 new->sos_next = ber->ber_sos;
453 ber_start_seq( BerElement *ber, ber_tag_t tag )
455 assert( ber != NULL );
456 assert( BER_VALID( ber ) );
458 if ( tag == LBER_DEFAULT )
461 return( ber_start_seqorset( ber, tag ) );
465 ber_start_set( BerElement *ber, ber_tag_t tag )
467 assert( ber != NULL );
468 assert( BER_VALID( ber ) );
470 if ( tag == LBER_DEFAULT )
473 return( ber_start_seqorset( ber, tag ) );
477 ber_put_seqorset( BerElement *ber )
481 unsigned char netlen[sizeof(ber_len_t)];
482 ber_len_t taglen, lenlen;
483 unsigned char ltag = 0x80U + FOUR_BYTE_LEN - 1;
485 Seqorset **sos = &ber->ber_sos;
487 assert( ber != NULL );
488 assert( BER_VALID( ber ) );
491 * If this is the toplevel sequence or set, we need to actually
492 * write the stuff out. Otherwise, it's already been put in
493 * the appropriate buffer and will be written when the toplevel
494 * one is written. In this case all we need to do is update the
498 len = (*sos)->sos_clen;
500 if ( sizeof(ber_len_t) > 4 && len > 0xffffffffUL )
503 if ( ber->ber_options & LBER_USE_DER ) {
504 lenlen = ber_calc_lenlen( len );
507 lenlen = FOUR_BYTE_LEN;
512 for( i=0; i < lenlen-1; i++ ) {
513 netlen[(sizeof(ber_len_t)-1) - i] =
514 (unsigned char)((len >> i*8) & 0xffU);
517 netlen[sizeof(ber_len_t)-1] = (unsigned char)(len & 0x7fU);
520 if ( (next = (*sos)->sos_next) == NULL ) {
522 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
525 if ( ber->ber_options & LBER_USE_DER ) {
526 /* Write the length in the minimum # of octets */
527 if ( ber_put_len( ber, len, 1 ) == -1 )
530 if (lenlen != FOUR_BYTE_LEN) {
532 * We set aside FOUR_BYTE_LEN bytes for
533 * the length field. Move the data if
534 * we don't actually need that much
536 AC_MEMCPY( (*sos)->sos_first + taglen +
537 lenlen, (*sos)->sos_first + taglen +
538 FOUR_BYTE_LEN, len );
541 /* Fill FOUR_BYTE_LEN bytes for length field */
542 /* one byte of length length */
543 if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 )
546 /* the length itself */
548 &netlen[sizeof(ber_len_t) - (FOUR_BYTE_LEN-1)],
549 FOUR_BYTE_LEN-1, 1 );
551 if( rc != FOUR_BYTE_LEN - 1 ) {
555 /* The ber_ptr is at the set/seq start - move it to the end */
556 (*sos)->sos_ber->ber_ptr += len;
560 unsigned char nettag[sizeof(ber_tag_t)];
561 ber_tag_t tmptag = (*sos)->sos_tag;
563 if( ber->ber_sos->sos_ptr > ber->ber_end ) {
564 /* The sos_ptr exceeds the end of the BerElement
565 * this can happen, for example, when the sos_ptr
566 * is near the end and no data was written for the
567 * 'V'. We must realloc the BerElement to ensure
568 * we don't overwrite the buffer when writing
569 * the tag and length fields.
571 ber_len_t ext = ber->ber_sos->sos_ptr - ber->ber_end;
573 if( ber_realloc( ber, ext ) != 0 ) {
579 taglen = ber_calc_taglen( tmptag );
581 for( i = 0; i < taglen; i++ ) {
582 nettag[(sizeof(ber_tag_t)-1) - i] = (unsigned char)(tmptag & 0xffU);
586 AC_FMEMCPY( (*sos)->sos_first,
587 &nettag[sizeof(ber_tag_t) - taglen],
590 if ( ber->ber_options & LBER_USE_DER ) {
592 ? (unsigned char) len
593 : (unsigned char) (0x80U + (lenlen - 1));
596 /* one byte of length length */
597 (*sos)->sos_first[1] = ltag;
599 if ( ber->ber_options & LBER_USE_DER ) {
601 /* Write the length itself */
602 AC_FMEMCPY( (*sos)->sos_first + 2,
603 &netlen[sizeof(ber_len_t) - (lenlen - 1)],
606 if (lenlen != FOUR_BYTE_LEN) {
608 * We set aside FOUR_BYTE_LEN bytes for
609 * the length field. Move the data if
610 * we don't actually need that much
612 AC_FMEMCPY( (*sos)->sos_first + taglen +
613 lenlen, (*sos)->sos_first + taglen +
614 FOUR_BYTE_LEN, len );
617 /* the length itself */
618 AC_FMEMCPY( (*sos)->sos_first + taglen + 1,
619 &netlen[sizeof(ber_len_t) - (FOUR_BYTE_LEN - 1)],
623 next->sos_clen += (taglen + lenlen + len);
624 next->sos_ptr += (taglen + lenlen + len);
627 /* we're done with this seqorset, so free it up */
628 LBER_FREE( (char *) (*sos) );
631 return( taglen + lenlen + len );
635 ber_put_seq( BerElement *ber )
637 assert( ber != NULL );
638 assert( BER_VALID( ber ) );
640 return( ber_put_seqorset( ber ) );
644 ber_put_set( BerElement *ber )
646 assert( ber != NULL );
647 assert( BER_VALID( ber ) );
649 return( ber_put_seqorset( ber ) );
653 static ber_tag_t lber_int_null = 0;
657 ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... )
661 struct berval *bv, **bvp;
666 assert( ber != NULL );
667 assert( fmt != NULL );
669 assert( BER_VALID( ber ) );
673 for ( rc = 0; *fmt && rc != -1; fmt++ ) {
675 case '!': { /* hook */
676 BEREncodeCallback *f;
679 f = va_arg( ap, BEREncodeCallback * );
680 p = va_arg( ap, void * );
685 case 'b': /* boolean */
686 i = va_arg( ap, ber_int_t );
687 rc = ber_put_boolean( ber, i, ber->ber_tag );
691 i = va_arg( ap, ber_int_t );
692 rc = ber_put_int( ber, i, ber->ber_tag );
695 case 'e': /* enumeration */
696 i = va_arg( ap, ber_int_t );
697 rc = ber_put_enum( ber, i, ber->ber_tag );
701 rc = ber_put_null( ber, ber->ber_tag );
704 case 'N': /* Debug NULL */
705 if( lber_int_null != 0 ) {
706 /* Insert NULL to ensure peer ignores unknown tags */
707 rc = ber_put_null( ber, lber_int_null );
713 case 'o': /* octet string (non-null terminated) */
714 s = va_arg( ap, char * );
715 len = va_arg( ap, ber_len_t );
716 rc = ber_put_ostring( ber, s, len, ber->ber_tag );
719 case 'O': /* berval octet string */
720 bv = va_arg( ap, struct berval * );
721 if( bv == NULL ) break;
722 rc = ber_put_berval( ber, bv, ber->ber_tag );
725 case 's': /* string */
726 s = va_arg( ap, char * );
727 rc = ber_put_string( ber, s, ber->ber_tag );
730 case 'B': /* bit string */
731 case 'X': /* bit string (deprecated) */
732 s = va_arg( ap, char * );
733 len = va_arg( ap, int ); /* in bits */
734 rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
737 case 't': /* tag for the next element */
738 ber->ber_tag = va_arg( ap, ber_tag_t );
739 ber->ber_usertag = 1;
742 case 'v': /* vector of strings */
743 if ( (ss = va_arg( ap, char ** )) == NULL )
745 for ( i = 0; ss[i] != NULL; i++ ) {
746 if ( (rc = ber_put_string( ber, ss[i],
747 ber->ber_tag )) == -1 )
752 case 'V': /* sequences of strings + lengths */
753 if ( (bvp = va_arg( ap, struct berval ** )) == NULL )
755 for ( i = 0; bvp[i] != NULL; i++ ) {
756 if ( (rc = ber_put_berval( ber, bvp[i],
757 ber->ber_tag )) == -1 )
762 case '{': /* begin sequence */
763 rc = ber_start_seq( ber, ber->ber_tag );
766 case '}': /* end sequence */
767 rc = ber_put_seqorset( ber );
770 case '[': /* begin set */
771 rc = ber_start_set( ber, ber->ber_tag );
774 case ']': /* end set */
775 rc = ber_put_seqorset( ber );
779 if( ber->ber_debug ) {
780 ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
781 "ber_printf: unknown fmt %c\n", *fmt );
787 if ( ber->ber_usertag == 0 )
788 ber->ber_tag = LBER_DEFAULT;
790 ber->ber_usertag = 0;