1 /* encode.c - ber output encoding routines */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 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).
37 #include <ac/stdlib.h>
39 #include <ac/stdarg.h>
40 #include <ac/socket.h>
41 #include <ac/string.h>
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)
52 * BER element size constrains:
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.
58 * - MAXINT_BERSIZE must fit in MAXINT_BERSIZE_OCTETS octets.
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.)
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.
68 #define MAXINT_BERSIZE \
69 (INT_MAX>0xffffffffUL ? (ber_len_t) 0xffffffffUL : INT_MAX-HEADER_SIZE)
70 #define MAXINT_BERSIZE_OCTETS 4
71 typedef ber_uint_t ber_elem_size_t
; /* normally 32 bits */
74 /* Prepend tag to ptr, which points to the end of a tag buffer */
75 static unsigned char *
76 ber_prepend_tag( unsigned char *ptr
, ber_tag_t tag
)
79 *--ptr
= (unsigned char) tag
& 0xffU
;
80 } while ( (tag
>>= 8) != 0 );
85 /* Prepend ber length to ptr, which points to the end of a length buffer */
86 static unsigned char *
87 ber_prepend_len( unsigned char *ptr
, ber_len_t len
)
90 * short len if it's less than 128 - one byte giving the len,
92 * long len otherwise - one byte with bit 8 set, giving the
93 * length of the length, followed by the length itself.
96 *--ptr
= (unsigned char) len
& 0xffU
;
99 unsigned char *endptr
= ptr
--;
101 while ( (len
>>= 8) != 0 ) {
102 *ptr
-- = (unsigned char) len
& 0xffU
;
104 *ptr
= (unsigned char) (endptr
- ptr
) + 0x80U
;
110 /* out->bv_len should be the buffer size on input */
112 ber_encode_oid( BerValue
*in
, BerValue
*out
)
115 unsigned long val1
, val
;
117 char *ptr
, *end
, *inend
;
119 assert( in
!= NULL
);
120 assert( out
!= NULL
);
122 if ( !out
->bv_val
|| out
->bv_len
< in
->bv_len
/2 )
125 der
= (unsigned char *) out
->bv_val
;
127 inend
= ptr
+ in
->bv_len
;
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;
140 if ( ptr
> inend
) return -1;
142 /* Write the OID component little-endian, then reverse it */
145 der
[len
++] = (val
& 0xff) | 0x80;
146 } while ( (val
>>= 7) != 0 );
148 for ( i
= 0, j
= len
; i
< --j
; i
++ ) {
149 unsigned char tmp
= der
[i
];
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;
165 out
->bv_len
= (char *)der
- out
->bv_val
;
176 unsigned char sign
, data
[TAGBUF_SIZE
+1 + OCTET_SIZE(ber_int_t
)], *ptr
;
179 unum
= num
; /* Bit fiddling should be done with unsigned values */
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 */
190 *ptr
= (unsigned char) (&data
[sizeof(data
) - 1] - ptr
); /* length */
191 ptr
= ber_prepend_tag( ptr
, tag
);
193 return ber_write( ber
, (char *) ptr
, &data
[sizeof(data
)] - ptr
, 0 );
202 if ( tag
== LBER_DEFAULT
) {
203 tag
= LBER_ENUMERATED
;
206 return ber_put_int_or_enum( ber
, num
, tag
);
215 if ( tag
== LBER_DEFAULT
) {
219 return ber_put_int_or_enum( ber
, num
, tag
);
225 LDAP_CONST
char *str
,
230 unsigned char header
[HEADER_SIZE
], *ptr
;
232 if ( tag
== LBER_DEFAULT
) {
233 tag
= LBER_OCTETSTRING
;
236 if ( len
> MAXINT_BERSIZE
) {
240 ptr
= ber_prepend_len( &header
[sizeof(header
)], len
);
241 ptr
= ber_prepend_tag( ptr
, tag
);
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
;
258 if( bv
== NULL
|| bv
->bv_len
== 0 ) {
259 return ber_put_ostring( ber
, "", (ber_len_t
) 0, tag
);
262 return ber_put_ostring( ber
, bv
->bv_val
, bv
->bv_len
, tag
);
268 LDAP_CONST
char *str
,
271 assert( str
!= NULL
);
273 return ber_put_ostring( ber
, str
, strlen( str
), tag
);
279 LDAP_CONST
char *str
,
280 ber_len_t blen
/* in bits */,
285 unsigned char unusedbits
, header
[HEADER_SIZE
+ 1], *ptr
;
287 if ( tag
== LBER_DEFAULT
) {
288 tag
= LBER_BITSTRING
;
291 unusedbits
= (unsigned char) -blen
& 7;
292 len
= blen
/ 8 + (unusedbits
!= 0); /* (blen+7)/8 without overflow */
293 if ( len
>= MAXINT_BERSIZE
) {
297 header
[sizeof(header
) - 1] = unusedbits
;
298 ptr
= ber_prepend_len( &header
[sizeof(header
) - 1], len
+ 1 );
299 ptr
= ber_prepend_tag( ptr
, tag
);
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
;
311 ber_put_null( BerElement
*ber
, ber_tag_t tag
)
313 unsigned char data
[TAGBUF_SIZE
+ 1], *ptr
;
315 if ( tag
== LBER_DEFAULT
) {
319 data
[sizeof(data
) - 1] = 0; /* length */
320 ptr
= ber_prepend_tag( &data
[sizeof(data
) - 1], tag
);
322 return ber_write( ber
, (char *) ptr
, &data
[sizeof(data
)] - ptr
, 0 );
331 unsigned char data
[TAGBUF_SIZE
+ 2], *ptr
;
333 if ( tag
== LBER_DEFAULT
)
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
);
340 return ber_write( ber
, (char *) ptr
, &data
[sizeof(data
)] - ptr
, 0 );
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))
348 /* Header of incomplete sequence or set */
349 typedef struct seqorset_header
{
350 char xtagbuf
[TAGBUF_SIZE
+ 1]; /* room for tag + len(tag or len) */
352 ber_elem_size_t offset
; /* enclosing sequence/set */
353 char padding
[SOS_LENLEN
-1]; /* for final length encoding */
355 # define SOS_TAG_END(header) ((unsigned char *) &(header).next_sos - 1)
358 /* Start a sequence or set */
365 * Write the tag and SOS_LENLEN octets reserved for length, to ber.
366 * For now, length octets = (tag length, previous ber_sos_inner).
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.
372 Seqorset_header header
;
373 unsigned char *headptr
;
374 ber_len_t taglen
, headlen
;
377 assert( ber
!= NULL
);
378 assert( LBER_VALID( ber
) );
380 if ( ber
->ber_sos_ptr
== NULL
) { /* outermost sequence/set? */
381 header
.next_sos
.offset
= 0;
384 if ( (ber_len_t
) -1 > (ber_elem_size_t
) -1 ) {
385 if ( ber
->ber_sos_inner
> (ber_elem_size_t
) -1 )
388 header
.next_sos
.offset
= ber
->ber_sos_inner
;
389 p
= &ber
->ber_sos_ptr
;
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
;
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 )
401 AC_MEMCPY( dest
, headptr
, headlen
);
402 ber
->ber_sos_ptr
= dest
+ headlen
;
404 ber
->ber_sos_inner
= dest
+ taglen
- ber
->ber_buf
;
407 * Do not return taglen + SOS_LENLEN here - then ber_put_seqorset()
408 * should return lenlen - SOS_LENLEN + len, which can be < 0.
414 ber_start_seq( BerElement
*ber
, ber_tag_t tag
)
416 if ( tag
== LBER_DEFAULT
) {
420 return ber_start_seqorset( ber
, tag
);
424 ber_start_set( BerElement
*ber
, ber_tag_t tag
)
426 if ( tag
== LBER_DEFAULT
) {
430 return ber_start_seqorset( ber
, tag
);
433 /* End a sequence or set */
435 ber_put_seqorset( BerElement
*ber
)
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) */
442 assert( ber
!= NULL
);
443 assert( LBER_VALID( ber
) );
445 if ( ber
->ber_sos_ptr
== NULL
) return -1;
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
) {
453 /* Extract sequence/set information from length octets */
454 memcpy( SOS_TAG_END(header
), lenptr
, SOS_LENLEN
);
456 /* Store length, and close gap of leftover reserved length octets */
457 len
= xlen
- SOS_LENLEN
;
458 if ( !(ber
->ber_options
& LBER_USE_DER
) ) {
460 lenptr
[0] = SOS_LENLEN
- 1 + 0x80; /* length(length)-1 */
461 for( i
= SOS_LENLEN
; --i
> 0; len
>>= 8 ) {
462 lenptr
[i
] = len
& 0xffU
;
465 unsigned char *p
= ber_prepend_len( lenptr
+ SOS_LENLEN
, len
);
466 ber_len_t unused
= p
- lenptr
;
468 /* length(length) < the reserved SOS_LENLEN bytes */
470 AC_MEMCPY( lenptr
, p
, xlen
);
471 ber
->ber_sos_ptr
= (char *) lenptr
+ xlen
;
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
;
482 return xlen
+ *SOS_TAG_END(header
); /* lenlen + len + taglen */
486 ber_put_seq( BerElement
*ber
)
488 return ber_put_seqorset( ber
);
492 ber_put_set( BerElement
*ber
)
494 return ber_put_seqorset( ber
);
498 static ber_tag_t lber_int_null
= 0;
502 ber_printf( BerElement
*ber
, LDAP_CONST
char *fmt
, ... )
506 struct berval
*bv
, **bvp
;
511 assert( ber
!= NULL
);
512 assert( fmt
!= NULL
);
513 assert( LBER_VALID( ber
) );
517 for ( rc
= 0; *fmt
&& rc
!= -1; fmt
++ ) {
519 case '!': { /* hook */
520 BEREncodeCallback
*f
;
523 ber
->ber_usertag
= 0;
525 f
= va_arg( ap
, BEREncodeCallback
* );
526 p
= va_arg( ap
, void * );
529 if ( ber
->ber_usertag
) {
534 case 'b': /* boolean */
535 i
= va_arg( ap
, ber_int_t
);
536 rc
= ber_put_boolean( ber
, i
, ber
->ber_tag
);
540 i
= va_arg( ap
, ber_int_t
);
541 rc
= ber_put_int( ber
, i
, ber
->ber_tag
);
544 case 'e': /* enumeration */
545 i
= va_arg( ap
, ber_int_t
);
546 rc
= ber_put_enum( ber
, i
, ber
->ber_tag
);
550 rc
= ber_put_null( ber
, ber
->ber_tag
);
553 case 'N': /* Debug NULL */
555 if( lber_int_null
!= 0 ) {
556 /* Insert NULL to ensure peer ignores unknown tags */
557 rc
= ber_put_null( ber
, lber_int_null
);
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
);
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
);
573 case 's': /* string */
574 s
= va_arg( ap
, char * );
575 rc
= ber_put_string( ber
, s
, ber
->ber_tag
);
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
);
585 case 't': /* tag for the next element */
586 ber
->ber_tag
= va_arg( ap
, ber_tag_t
);
589 case 'v': /* vector of strings */
590 if ( (ss
= va_arg( ap
, char ** )) == NULL
)
592 for ( i
= 0; ss
[i
] != NULL
; i
++ ) {
593 if ( (rc
= ber_put_string( ber
, ss
[i
],
594 ber
->ber_tag
)) == -1 )
599 case 'V': /* sequences of strings + lengths */
600 if ( (bvp
= va_arg( ap
, struct berval
** )) == NULL
)
602 for ( i
= 0; bvp
[i
] != NULL
; i
++ ) {
603 if ( (rc
= ber_put_berval( ber
, bvp
[i
],
604 ber
->ber_tag
)) == -1 )
609 case 'W': /* BerVarray */
610 if ( (bv
= va_arg( ap
, BerVarray
)) == NULL
)
612 for ( i
= 0; bv
[i
].bv_val
!= NULL
; i
++ ) {
613 if ( (rc
= ber_put_berval( ber
, &bv
[i
],
614 ber
->ber_tag
)) == -1 )
619 case '{': /* begin sequence */
620 rc
= ber_start_seq( ber
, ber
->ber_tag
);
623 case '}': /* end sequence */
624 rc
= ber_put_seqorset( ber
);
627 case '[': /* begin set */
628 rc
= ber_start_set( ber
, ber
->ber_tag
);
631 case ']': /* end set */
632 rc
= ber_put_seqorset( ber
);
636 if( ber
->ber_debug
) {
637 ber_log_printf( LDAP_DEBUG_ANY
, ber
->ber_debug
,
638 "ber_printf: unknown fmt %c\n", *fmt
);
644 ber
->ber_tag
= LBER_DEFAULT
;