1 /* encode.c - ber output encoding routines */
2 /* $OpenLDAP: pkg/ldap/libraries/liblber/encode.c,v 1.64.2.3 2008/02/11 23:26:41 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
17 * All rights reserved.
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.
27 * This work was originally developed by the University of Michigan
28 * (as part of U-MICH LDAP).
36 #include <ac/stdlib.h>
38 #include <ac/stdarg.h>
39 #include <ac/socket.h>
40 #include <ac/string.h>
44 static int ber_put_len
LDAP_P((
49 static int ber_start_seqorset
LDAP_P((
53 static int ber_put_seqorset
LDAP_P(( BerElement
*ber
));
55 static int ber_put_int_or_enum
LDAP_P((
60 #define BER_TOP_BYTE(type) (sizeof(type)-1)
61 #define BER_TOP_MASK(type) ((type)0xffU << (BER_TOP_BYTE(type)*8))
64 ber_calc_taglen( ber_tag_t tag
)
66 int i
= BER_TOP_BYTE(ber_tag_t
);
67 ber_tag_t mask
= BER_TOP_MASK(ber_tag_t
);
69 /* find the first non-all-zero byte in the tag */
70 for ( ; i
> 0; i
-- ) {
72 if ( tag
& mask
) break;
88 unsigned char nettag
[sizeof(ber_tag_t
)];
90 assert( ber
!= NULL
);
91 assert( LBER_VALID( ber
) );
93 taglen
= ber_calc_taglen( tag
);
95 for( i
=taglen
-1; i
>=0; i
-- ) {
96 nettag
[i
] = (unsigned char)(tag
& 0xffU
);
100 rc
= ber_write( ber
, (char *) nettag
, taglen
, nosos
);
106 ber_calc_lenlen( ber_len_t len
)
109 * short len if it's less than 128 - one byte giving the len,
113 if ( len
<= (ber_len_t
) 0x7FU
) return 1;
116 * long len otherwise - one byte with bit 8 set, giving the
117 * length of the length, followed by the length itself.
120 if ( len
<= (ber_len_t
) 0xffU
) return 2;
121 if ( len
<= (ber_len_t
) 0xffffU
) return 3;
122 if ( len
<= (ber_len_t
) 0xffffffU
) return 4;
128 ber_put_len( BerElement
*ber
, ber_len_t len
, int nosos
)
134 unsigned char netlen
[sizeof(ber_len_t
)];
136 assert( ber
!= NULL
);
137 assert( LBER_VALID( ber
) );
140 * short len if it's less than 128 - one byte giving the len,
145 char length_byte
= (char) len
;
146 return ber_write( ber
, &length_byte
, 1, nosos
);
150 * long len otherwise - one byte with bit 8 set, giving the
151 * length of the length, followed by the length itself.
154 /* find the first non-all-zero byte */
155 i
= BER_TOP_BYTE(ber_len_t
);
156 mask
= BER_TOP_MASK(ber_len_t
);
157 for ( ; i
> 0; i
-- ) {
159 if ( len
& mask
) break;
162 lenlen
= (unsigned char) ++i
;
163 if ( lenlen
> 4 ) return -1;
167 /* write the length of the length */
168 if ( ber_write( ber
, &lenlen
, 1, nosos
) != 1 ) return -1;
170 for( j
=i
-1; j
>=0; j
-- ) {
171 netlen
[j
] = (unsigned char)(len
& 0xffU
);
175 /* write the length itself */
176 rc
= ber_write( ber
, (char *) netlen
, i
, nosos
);
178 return rc
== i
? i
+1 : -1;
181 /* out->bv_len should be the buffer size on input */
183 ber_encode_oid( BerValue
*in
, BerValue
*out
)
186 unsigned long val1
, val
;
188 char *ptr
, *end
, *inend
;
190 assert( in
!= NULL
);
191 assert( out
!= NULL
);
193 if ( !out
->bv_val
|| out
->bv_len
< in
->bv_len
/2 )
196 der
= (unsigned char *) out
->bv_val
;
198 inend
= ptr
+ in
->bv_len
;
200 /* OIDs start with <0-1>.<0-39> or 2.<any>, DER-encoded 40*val1+val2 */
201 if ( !isdigit( (unsigned char) *ptr
)) return -1;
202 val1
= strtoul( ptr
, &end
, 10 );
203 if ( end
== ptr
|| val1
> 2 ) return -1;
204 if ( *end
++ != '.' || !isdigit( (unsigned char) *end
)) return -1;
205 val
= strtoul( end
, &ptr
, 10 );
206 if ( ptr
== end
) return -1;
207 if ( val
> (val1
< 2 ? 39 : LBER_OID_COMPONENT_MAX
- 80) ) return -1;
211 if ( ptr
> inend
) return -1;
215 der
[len
++] = (val
& 0xff) | 0x80;
216 } while ( (val
>>= 7) != 0 );
218 for ( i
= 0, j
= len
; i
< --j
; i
++ ) {
219 unsigned char tmp
= der
[i
];
227 if ( *ptr
++ != '.' ) return -1;
228 if ( !isdigit( (unsigned char) *ptr
)) return -1;
229 val
= strtoul( ptr
, &end
, 10 );
230 if ( end
== ptr
|| val
> LBER_OID_COMPONENT_MAX
) return -1;
234 out
->bv_len
= (char *)der
- out
->bv_val
;
245 int i
, j
, sign
, taglen
, lenlen
;
247 ber_uint_t unum
, mask
;
248 unsigned char netnum
[sizeof(ber_uint_t
)];
250 assert( ber
!= NULL
);
251 assert( LBER_VALID( ber
) );
254 unum
= num
; /* Bit fiddling should be done with unsigned values */
257 * high bit is set - look for first non-all-one byte
258 * high bit is clear - look for first non-all-zero byte
260 i
= BER_TOP_BYTE(ber_int_t
);
261 mask
= BER_TOP_MASK(ber_uint_t
);
262 for ( ; i
> 0; i
-- ) {
265 if ( (unum
& mask
) != mask
) break;
268 if ( unum
& mask
) break;
274 * we now have the "leading byte". if the high bit on this
275 * byte matches the sign bit, we need to "back up" a byte.
277 mask
= (unum
& ((ber_uint_t
)0x80U
<< (i
* 8)));
278 if ( (mask
&& !sign
) || (sign
&& !mask
) ) {
284 if ( (taglen
= ber_put_tag( ber
, tag
, 0 )) == -1 ) {
288 if ( (lenlen
= ber_put_len( ber
, len
, 0 )) == -1 ) {
293 for( j
=i
-1; j
>=0; j
-- ) {
294 netnum
[j
] = (unsigned char)(unum
& 0xffU
);
298 rc
= ber_write( ber
, (char *) netnum
, i
, 0 );
300 /* length of tag + length + contents */
301 return rc
== i
? taglen
+ lenlen
+ i
: -1;
310 assert( ber
!= NULL
);
311 assert( LBER_VALID( ber
) );
313 if ( tag
== LBER_DEFAULT
) {
314 tag
= LBER_ENUMERATED
;
317 return ber_put_int_or_enum( ber
, num
, tag
);
326 assert( ber
!= NULL
);
327 assert( LBER_VALID( ber
) );
329 if ( tag
== LBER_DEFAULT
) {
333 return ber_put_int_or_enum( ber
, num
, tag
);
339 LDAP_CONST
char *str
,
343 int taglen
, lenlen
, rc
;
345 assert( ber
!= NULL
);
346 assert( str
!= NULL
);
348 assert( LBER_VALID( ber
) );
350 if ( tag
== LBER_DEFAULT
) {
351 tag
= LBER_OCTETSTRING
;
354 if ( (taglen
= ber_put_tag( ber
, tag
, 0 )) == -1 )
357 if ( (lenlen
= ber_put_len( ber
, len
, 0 )) == -1 ||
358 (ber_len_t
) ber_write( ber
, str
, len
, 0 ) != len
)
362 /* return length of tag + length + contents */
363 rc
= taglen
+ lenlen
+ len
;
375 assert( ber
!= NULL
);
376 assert( LBER_VALID( ber
) );
378 if( bv
== NULL
|| bv
->bv_len
== 0 ) {
379 return ber_put_ostring( ber
, "", (ber_len_t
) 0, tag
);
382 return ber_put_ostring( ber
, bv
->bv_val
, bv
->bv_len
, tag
);
388 LDAP_CONST
char *str
,
391 assert( ber
!= NULL
);
392 assert( str
!= NULL
);
394 assert( LBER_VALID( ber
) );
396 return ber_put_ostring( ber
, str
, strlen( str
), tag
);
402 LDAP_CONST
char *str
,
403 ber_len_t blen
/* in bits */,
408 unsigned char unusedbits
;
410 assert( ber
!= NULL
);
411 assert( str
!= NULL
);
413 assert( LBER_VALID( ber
) );
415 if ( tag
== LBER_DEFAULT
) {
416 tag
= LBER_BITSTRING
;
419 if ( (taglen
= ber_put_tag( ber
, tag
, 0 )) == -1 ) {
423 len
= ( blen
+ 7 ) / 8;
424 unusedbits
= (unsigned char) ((len
* 8) - blen
);
425 if ( (lenlen
= ber_put_len( ber
, len
+ 1, 0 )) == -1 ) {
429 if ( ber_write( ber
, (char *)&unusedbits
, 1, 0 ) != 1 ) {
433 if ( (ber_len_t
) ber_write( ber
, str
, len
, 0 ) != len
) {
437 /* return length of tag + length + unused bit count + contents */
438 return taglen
+ 1 + lenlen
+ len
;
442 ber_put_null( BerElement
*ber
, ber_tag_t tag
)
446 assert( ber
!= NULL
);
447 assert( LBER_VALID( ber
) );
449 if ( tag
== LBER_DEFAULT
) {
453 if ( (taglen
= ber_put_tag( ber
, tag
, 0 )) == -1 ) {
457 if ( ber_put_len( ber
, 0, 0 ) != 1 ) {
473 assert( ber
!= NULL
);
474 assert( LBER_VALID( ber
) );
476 if ( tag
== LBER_DEFAULT
)
479 if ( (taglen
= ber_put_tag( ber
, tag
, 0 )) == -1 ) {
483 if ( ber_put_len( ber
, 1, 0 ) != 1 ) {
487 c
= boolval
? (unsigned char) ~0U : (unsigned char) 0U;
489 if ( ber_write( ber
, (char *) &c
, 1, 0 ) != 1 ) {
496 #define FOUR_BYTE_LEN 5
505 assert( ber
!= NULL
);
506 assert( LBER_VALID( ber
) );
508 new = (Seqorset
*) ber_memcalloc_x( 1, sizeof(Seqorset
), ber
->ber_memctx
);
515 if ( ber
->ber_sos
== NULL
) {
516 new->sos_first
= ber
->ber_ptr
;
518 new->sos_first
= ber
->ber_sos
->sos_ptr
;
521 /* Set aside room for a 4 byte length field */
522 new->sos_ptr
= new->sos_first
+ ber_calc_taglen( tag
) + FOUR_BYTE_LEN
;
525 new->sos_next
= ber
->ber_sos
;
532 ber_start_seq( BerElement
*ber
, ber_tag_t tag
)
534 assert( ber
!= NULL
);
535 assert( LBER_VALID( ber
) );
537 if ( tag
== LBER_DEFAULT
) {
541 return ber_start_seqorset( ber
, tag
);
545 ber_start_set( BerElement
*ber
, ber_tag_t tag
)
547 assert( ber
!= NULL
);
548 assert( LBER_VALID( ber
) );
550 if ( tag
== LBER_DEFAULT
) {
554 return ber_start_seqorset( ber
, tag
);
558 ber_put_seqorset( BerElement
*ber
)
562 unsigned char netlen
[sizeof(ber_len_t
)];
565 unsigned char ltag
= 0x80U
+ FOUR_BYTE_LEN
- 1;
567 Seqorset
**sos
= &ber
->ber_sos
;
569 assert( ber
!= NULL
);
570 assert( LBER_VALID( ber
) );
572 if( *sos
== NULL
) return -1;
575 * If this is the toplevel sequence or set, we need to actually
576 * write the stuff out. Otherwise, it's already been put in
577 * the appropriate buffer and will be written when the toplevel
578 * one is written. In this case all we need to do is update the
582 len
= (*sos
)->sos_clen
;
584 if ( sizeof(ber_len_t
) > 4 && len
> 0xffffffffUL
) {
588 if ( ber
->ber_options
& LBER_USE_DER
) {
589 lenlen
= ber_calc_lenlen( len
);
592 lenlen
= FOUR_BYTE_LEN
;
598 for( i
=lenlen
-2; i
>= 0; i
-- ) {
599 netlen
[i
] = j
& 0xffU
;
603 netlen
[0] = (unsigned char)(len
& 0x7fU
);
606 if ( (next
= (*sos
)->sos_next
) == NULL
) {
608 if ( (taglen
= ber_put_tag( ber
, (*sos
)->sos_tag
, 1 )) == -1 ) {
612 if ( ber
->ber_options
& LBER_USE_DER
) {
613 /* Write the length in the minimum # of octets */
614 if ( ber_put_len( ber
, len
, 1 ) == -1 ) {
618 if (lenlen
!= FOUR_BYTE_LEN
) {
620 * We set aside FOUR_BYTE_LEN bytes for
621 * the length field. Move the data if
622 * we don't actually need that much
624 AC_MEMCPY( (*sos
)->sos_first
+ taglen
+
625 lenlen
, (*sos
)->sos_first
+ taglen
+
626 FOUR_BYTE_LEN
, len
);
629 /* Fill FOUR_BYTE_LEN bytes for length field */
630 /* one byte of length length */
631 if ( ber_write( ber
, (char *)<ag
, 1, 1 ) != 1 ) {
635 /* the length itself */
636 rc
= ber_write( ber
, (char *) netlen
, FOUR_BYTE_LEN
-1, 1 );
638 if( rc
!= FOUR_BYTE_LEN
- 1 ) {
642 /* The ber_ptr is at the set/seq start - move it to the end */
643 (*sos
)->sos_ber
->ber_ptr
+= len
;
647 unsigned char nettag
[sizeof(ber_tag_t
)];
648 ber_tag_t tmptag
= (*sos
)->sos_tag
;
650 if( ber
->ber_sos
->sos_ptr
> ber
->ber_end
) {
651 /* The sos_ptr exceeds the end of the BerElement
652 * this can happen, for example, when the sos_ptr
653 * is near the end and no data was written for the
654 * 'V'. We must realloc the BerElement to ensure
655 * we don't overwrite the buffer when writing
656 * the tag and length fields.
658 ber_len_t ext
= ber
->ber_sos
->sos_ptr
- ber
->ber_end
;
660 if( ber_realloc( ber
, ext
) != 0 ) {
666 taglen
= ber_calc_taglen( tmptag
);
668 for( i
= taglen
-1; i
>= 0; i
-- ) {
669 nettag
[i
] = (unsigned char)(tmptag
& 0xffU
);
673 AC_FMEMCPY( (*sos
)->sos_first
, nettag
, taglen
);
675 if ( ber
->ber_options
& LBER_USE_DER
) {
677 ? (unsigned char) len
678 : (unsigned char) (0x80U
+ (lenlen
- 1));
681 /* one byte of length length */
682 (*sos
)->sos_first
[1] = ltag
;
684 if ( ber
->ber_options
& LBER_USE_DER
) {
686 /* Write the length itself */
687 AC_FMEMCPY( (*sos
)->sos_first
+ 2, netlen
, lenlen
- 1 );
689 if (lenlen
!= FOUR_BYTE_LEN
) {
691 * We set aside FOUR_BYTE_LEN bytes for
692 * the length field. Move the data if
693 * we don't actually need that much
695 AC_FMEMCPY( (*sos
)->sos_first
+ taglen
+
696 lenlen
, (*sos
)->sos_first
+ taglen
+
697 FOUR_BYTE_LEN
, len
);
700 /* the length itself */
701 AC_FMEMCPY( (*sos
)->sos_first
+ taglen
+ 1,
702 netlen
, FOUR_BYTE_LEN
- 1 );
705 next
->sos_clen
+= (taglen
+ lenlen
+ len
);
706 next
->sos_ptr
+= (taglen
+ lenlen
+ len
);
709 /* we're done with this seqorset, so free it up */
710 ber_memfree_x( (char *) (*sos
), ber
->ber_memctx
);
713 return taglen
+ lenlen
+ len
;
717 ber_put_seq( BerElement
*ber
)
719 assert( ber
!= NULL
);
720 assert( LBER_VALID( ber
) );
722 return ber_put_seqorset( ber
);
726 ber_put_set( BerElement
*ber
)
728 assert( ber
!= NULL
);
729 assert( LBER_VALID( ber
) );
731 return ber_put_seqorset( ber
);
735 static ber_tag_t lber_int_null
= 0;
739 ber_printf( BerElement
*ber
, LDAP_CONST
char *fmt
, ... )
743 struct berval
*bv
, **bvp
;
748 assert( ber
!= NULL
);
749 assert( fmt
!= NULL
);
751 assert( LBER_VALID( ber
) );
755 for ( rc
= 0; *fmt
&& rc
!= -1; fmt
++ ) {
757 case '!': { /* hook */
758 BEREncodeCallback
*f
;
761 f
= va_arg( ap
, BEREncodeCallback
* );
762 p
= va_arg( ap
, void * );
767 case 'b': /* boolean */
768 i
= va_arg( ap
, ber_int_t
);
769 rc
= ber_put_boolean( ber
, i
, ber
->ber_tag
);
773 i
= va_arg( ap
, ber_int_t
);
774 rc
= ber_put_int( ber
, i
, ber
->ber_tag
);
777 case 'e': /* enumeration */
778 i
= va_arg( ap
, ber_int_t
);
779 rc
= ber_put_enum( ber
, i
, ber
->ber_tag
);
783 rc
= ber_put_null( ber
, ber
->ber_tag
);
786 case 'N': /* Debug NULL */
787 if( lber_int_null
!= 0 ) {
788 /* Insert NULL to ensure peer ignores unknown tags */
789 rc
= ber_put_null( ber
, lber_int_null
);
795 case 'o': /* octet string (non-null terminated) */
796 s
= va_arg( ap
, char * );
797 len
= va_arg( ap
, ber_len_t
);
798 rc
= ber_put_ostring( ber
, s
, len
, ber
->ber_tag
);
801 case 'O': /* berval octet string */
802 bv
= va_arg( ap
, struct berval
* );
803 if( bv
== NULL
) break;
804 rc
= ber_put_berval( ber
, bv
, ber
->ber_tag
);
807 case 's': /* string */
808 s
= va_arg( ap
, char * );
809 rc
= ber_put_string( ber
, s
, ber
->ber_tag
);
812 case 'B': /* bit string */
813 case 'X': /* bit string (deprecated) */
814 s
= va_arg( ap
, char * );
815 len
= va_arg( ap
, int ); /* in bits */
816 rc
= ber_put_bitstring( ber
, s
, len
, ber
->ber_tag
);
819 case 't': /* tag for the next element */
820 ber
->ber_tag
= va_arg( ap
, ber_tag_t
);
821 ber
->ber_usertag
= 1;
824 case 'v': /* vector of strings */
825 if ( (ss
= va_arg( ap
, char ** )) == NULL
)
827 for ( i
= 0; ss
[i
] != NULL
; i
++ ) {
828 if ( (rc
= ber_put_string( ber
, ss
[i
],
829 ber
->ber_tag
)) == -1 )
834 case 'V': /* sequences of strings + lengths */
835 if ( (bvp
= va_arg( ap
, struct berval
** )) == NULL
)
837 for ( i
= 0; bvp
[i
] != NULL
; i
++ ) {
838 if ( (rc
= ber_put_berval( ber
, bvp
[i
],
839 ber
->ber_tag
)) == -1 )
844 case 'W': /* BerVarray */
845 if ( (bv
= va_arg( ap
, BerVarray
)) == NULL
)
847 for ( i
= 0; bv
[i
].bv_val
!= NULL
; i
++ ) {
848 if ( (rc
= ber_put_berval( ber
, &bv
[i
],
849 ber
->ber_tag
)) == -1 )
854 case '{': /* begin sequence */
855 rc
= ber_start_seq( ber
, ber
->ber_tag
);
858 case '}': /* end sequence */
859 rc
= ber_put_seqorset( ber
);
862 case '[': /* begin set */
863 rc
= ber_start_set( ber
, ber
->ber_tag
);
866 case ']': /* end set */
867 rc
= ber_put_seqorset( ber
);
871 if( ber
->ber_debug
) {
872 ber_log_printf( LDAP_DEBUG_ANY
, ber
->ber_debug
,
873 "ber_printf: unknown fmt %c\n", *fmt
);
879 if ( ber
->ber_usertag
== 0 ) {
880 ber
->ber_tag
= LBER_DEFAULT
;
882 ber
->ber_usertag
= 0;