Back to index

openldap  2.4.31
encode.c
Go to the documentation of this file.
00001 /* encode.c - ber output encoding routines */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
00017  * All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms are permitted
00020  * provided that this notice is preserved and that due credit is given
00021  * to the University of Michigan at Ann Arbor. The name of the University
00022  * may not be used to endorse or promote products derived from this
00023  * software without specific prior written permission. This software
00024  * is provided ``as is'' without express or implied warranty.
00025  */
00026 /* ACKNOWLEDGEMENTS:
00027  * This work was originally developed by the University of Michigan
00028  * (as part of U-MICH LDAP).
00029  */
00030 
00031 #include "portable.h"
00032 
00033 #include <ctype.h>
00034 #include <limits.h>
00035 #include <stdio.h>
00036 
00037 #include <ac/stdlib.h>
00038 
00039 #include <ac/stdarg.h>
00040 #include <ac/socket.h>
00041 #include <ac/string.h>
00042 
00043 #include "lber-int.h"
00044 
00045 
00046 #define OCTET_SIZE(type) ((ber_len_t) (sizeof(type)*CHAR_BIT + 7) / 8)
00047 #define TAGBUF_SIZE OCTET_SIZE(ber_tag_t)
00048 #define LENBUF_SIZE (1 + OCTET_SIZE(ber_len_t))
00049 #define HEADER_SIZE (TAGBUF_SIZE + LENBUF_SIZE)
00050 
00051 /*
00052  * BER element size constrains:
00053  *
00054  * - We traditionally support a length of max 0xffffffff.  However
00055  *   some functions return an int length so that is their max.
00056  *   MAXINT_BERSIZE is the max for those functions.
00057  *
00058  * - MAXINT_BERSIZE must fit in MAXINT_BERSIZE_OCTETS octets.
00059  *
00060  * - sizeof(ber_elem_size_t) is normally MAXINT_BERSIZE_OCTETS:
00061  *   Big enough for MAXINT_BERSIZE, but not more.  (Larger wastes
00062  *   space in the working encoding and DER encoding of a sequence
00063  *   or set.  Smaller further limits sizes near a sequence/set.)
00064  *
00065  * ber_len_t is mostly unrelated to this.  Which may be for the best,
00066  * since it is also used for lengths of data that are never encoded.
00067  */
00068 #define MAXINT_BERSIZE \
00069        (INT_MAX>0xffffffffUL ? (ber_len_t) 0xffffffffUL : INT_MAX-HEADER_SIZE)
00070 #define MAXINT_BERSIZE_OCTETS 4
00071 typedef ber_uint_t ber_elem_size_t; /* normally 32 bits */
00072 
00073 
00074 /* Prepend tag to ptr, which points to the end of a tag buffer */
00075 static unsigned char *
00076 ber_prepend_tag( unsigned char *ptr, ber_tag_t tag )
00077 {
00078        do {
00079               *--ptr = (unsigned char) tag & 0xffU;
00080        } while ( (tag >>= 8) != 0 );
00081 
00082        return ptr;
00083 }
00084 
00085 /* Prepend ber length to ptr, which points to the end of a length buffer */
00086 static unsigned char *
00087 ber_prepend_len( unsigned char *ptr, ber_len_t len )
00088 {
00089        /*
00090         * short len if it's less than 128 - one byte giving the len,
00091         * with bit 8 0.
00092         * long len otherwise - one byte with bit 8 set, giving the
00093         * length of the length, followed by the length itself.
00094         */
00095 
00096        *--ptr = (unsigned char) len & 0xffU;
00097 
00098        if ( len >= 0x80 ) {
00099               unsigned char *endptr = ptr--;
00100 
00101               while ( (len >>= 8) != 0 ) {
00102                      *ptr-- = (unsigned char) len & 0xffU;
00103               }
00104               *ptr = (unsigned char) (endptr - ptr) + 0x80U;
00105        }
00106 
00107        return ptr;
00108 }
00109 
00110 /* out->bv_len should be the buffer size on input */
00111 int
00112 ber_encode_oid( BerValue *in, BerValue *out )
00113 {
00114        unsigned char *der;
00115        unsigned long val1, val;
00116        int i, j, len;
00117        char *ptr, *end, *inend;
00118 
00119        assert( in != NULL );
00120        assert( out != NULL );
00121 
00122        if ( !out->bv_val || out->bv_len < in->bv_len/2 )
00123               return -1;
00124 
00125        der = (unsigned char *) out->bv_val;
00126        ptr = in->bv_val;
00127        inend = ptr + in->bv_len;
00128 
00129        /* OIDs start with <0-1>.<0-39> or 2.<any>, DER-encoded 40*val1+val2 */
00130        if ( !isdigit( (unsigned char) *ptr )) return -1;
00131        val1 = strtoul( ptr, &end, 10 );
00132        if ( end == ptr || val1 > 2 ) return -1;
00133        if ( *end++ != '.' || !isdigit( (unsigned char) *end )) return -1;
00134        val = strtoul( end, &ptr, 10 );
00135        if ( ptr == end ) return -1;
00136        if ( val > (val1 < 2 ? 39 : LBER_OID_COMPONENT_MAX - 80) ) return -1;
00137        val += val1 * 40;
00138 
00139        for (;;) {
00140               if ( ptr > inend ) return -1;
00141 
00142               /* Write the OID component little-endian, then reverse it */
00143               len = 0;
00144               do {
00145                      der[len++] = (val & 0xff) | 0x80;
00146               } while ( (val >>= 7) != 0 );
00147               der[0] &= 0x7f;
00148               for ( i = 0, j = len; i < --j; i++ ) {
00149                      unsigned char tmp = der[i];
00150                      der[i] = der[j];
00151                      der[j] = tmp;
00152               }
00153               der += len;
00154 
00155               if ( ptr == inend )
00156                      break;
00157 
00158               if ( *ptr++ != '.' ) return -1;
00159               if ( !isdigit( (unsigned char) *ptr )) return -1;
00160               val = strtoul( ptr, &end, 10 );
00161               if ( end == ptr || val > LBER_OID_COMPONENT_MAX ) return -1;
00162               ptr = end;
00163        }
00164 
00165        out->bv_len = (char *)der - out->bv_val;
00166        return 0;
00167 }
00168 
00169 static int
00170 ber_put_int_or_enum(
00171        BerElement *ber,
00172        ber_int_t num,
00173        ber_tag_t tag )
00174 {
00175        ber_uint_t unum;
00176        unsigned char sign, data[TAGBUF_SIZE+1 + OCTET_SIZE(ber_int_t)], *ptr;
00177 
00178        sign = 0;
00179        unum = num;   /* Bit fiddling should be done with unsigned values */
00180        if ( num < 0 ) {
00181               sign = 0xffU;
00182               unum = ~unum;
00183        }
00184        for ( ptr = &data[sizeof(data) - 1] ;; unum >>= 8 ) {
00185               *ptr-- = (sign ^ (unsigned char) unum) & 0xffU;
00186               if ( unum < 0x80 )   /* top bit at *ptr is sign bit */
00187                      break;
00188        }
00189 
00190        *ptr = (unsigned char) (&data[sizeof(data) - 1] - ptr); /* length */
00191        ptr = ber_prepend_tag( ptr, tag );
00192 
00193        return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
00194 }
00195 
00196 int
00197 ber_put_enum(
00198        BerElement *ber,
00199        ber_int_t num,
00200        ber_tag_t tag )
00201 {
00202        if ( tag == LBER_DEFAULT ) {
00203               tag = LBER_ENUMERATED;
00204        }
00205 
00206        return ber_put_int_or_enum( ber, num, tag );
00207 }
00208 
00209 int
00210 ber_put_int(
00211        BerElement *ber,
00212        ber_int_t num,
00213        ber_tag_t tag )
00214 {
00215        if ( tag == LBER_DEFAULT ) {
00216               tag = LBER_INTEGER;
00217        }
00218 
00219        return ber_put_int_or_enum( ber, num, tag );
00220 }
00221 
00222 int
00223 ber_put_ostring(
00224        BerElement *ber,
00225        LDAP_CONST char *str,
00226        ber_len_t len,
00227        ber_tag_t tag )
00228 {
00229        int rc;
00230        unsigned char header[HEADER_SIZE], *ptr;
00231 
00232        if ( tag == LBER_DEFAULT ) {
00233               tag = LBER_OCTETSTRING;
00234        }
00235 
00236        if ( len > MAXINT_BERSIZE ) {
00237               return -1;
00238        }
00239 
00240        ptr = ber_prepend_len( &header[sizeof(header)], len );
00241        ptr = ber_prepend_tag( ptr, tag );
00242 
00243        rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 );
00244        if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) {
00245               /* length(tag + length + contents) */
00246               return rc + (int) len;
00247        }
00248 
00249        return -1;
00250 }
00251 
00252 int
00253 ber_put_berval(
00254        BerElement *ber,
00255        struct berval *bv,
00256        ber_tag_t tag )
00257 {
00258        if( bv == NULL || bv->bv_len == 0 ) {
00259               return ber_put_ostring( ber, "", (ber_len_t) 0, tag );
00260        }
00261 
00262        return ber_put_ostring( ber, bv->bv_val, bv->bv_len, tag );
00263 }
00264 
00265 int
00266 ber_put_string(
00267        BerElement *ber,
00268        LDAP_CONST char *str,
00269        ber_tag_t tag )
00270 {
00271        assert( str != NULL );
00272 
00273        return ber_put_ostring( ber, str, strlen( str ), tag );
00274 }
00275 
00276 int
00277 ber_put_bitstring(
00278        BerElement *ber,
00279        LDAP_CONST char *str,
00280        ber_len_t blen /* in bits */,
00281        ber_tag_t tag )
00282 {
00283        int rc;
00284        ber_len_t            len;
00285        unsigned char unusedbits, header[HEADER_SIZE + 1], *ptr;
00286 
00287        if ( tag == LBER_DEFAULT ) {
00288               tag = LBER_BITSTRING;
00289        }
00290 
00291        unusedbits = (unsigned char) -blen & 7;
00292        len = blen / 8 + (unusedbits != 0); /* (blen+7)/8 without overflow */
00293        if ( len >= MAXINT_BERSIZE ) {
00294               return -1;
00295        }
00296 
00297        header[sizeof(header) - 1] = unusedbits;
00298        ptr = ber_prepend_len( &header[sizeof(header) - 1], len + 1 );
00299        ptr = ber_prepend_tag( ptr, tag );
00300 
00301        rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 );
00302        if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) {
00303               /* length(tag + length + unused bit count + bitstring) */
00304               return rc + (int) len;
00305        }
00306 
00307        return -1;
00308 }
00309 
00310 int
00311 ber_put_null( BerElement *ber, ber_tag_t tag )
00312 {
00313        unsigned char data[TAGBUF_SIZE + 1], *ptr;
00314 
00315        if ( tag == LBER_DEFAULT ) {
00316               tag = LBER_NULL;
00317        }
00318 
00319        data[sizeof(data) - 1] = 0;               /* length */
00320        ptr = ber_prepend_tag( &data[sizeof(data) - 1], tag );
00321 
00322        return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
00323 }
00324 
00325 int
00326 ber_put_boolean(
00327        BerElement *ber,
00328        ber_int_t boolval,
00329        ber_tag_t tag )
00330 {
00331        unsigned char data[TAGBUF_SIZE + 2], *ptr;
00332 
00333        if ( tag == LBER_DEFAULT )
00334               tag = LBER_BOOLEAN;
00335 
00336        data[sizeof(data) - 1] = boolval ? 0xff : 0;
00337        data[sizeof(data) - 2] = 1;               /* length */
00338        ptr = ber_prepend_tag( &data[sizeof(data) - 2], tag );
00339 
00340        return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
00341 }
00342 
00343 
00344 /* Max number of length octets in a sequence or set, normally 5 */
00345 #define SOS_LENLEN (1 + (sizeof(ber_elem_size_t) > MAXINT_BERSIZE_OCTETS ? \
00346               (ber_len_t) sizeof(ber_elem_size_t) : MAXINT_BERSIZE_OCTETS))
00347 
00348 /* Header of incomplete sequence or set */
00349 typedef struct seqorset_header {
00350        char xtagbuf[TAGBUF_SIZE + 1];     /* room for tag + len(tag or len) */
00351        union {
00352               ber_elem_size_t offset;            /* enclosing seqence/set */
00353               char padding[SOS_LENLEN-1]; /* for final length encoding */
00354        } next_sos;
00355 #      define SOS_TAG_END(header) ((unsigned char *) &(header).next_sos - 1)
00356 } Seqorset_header;
00357 
00358 /* Start a sequence or set */
00359 static int
00360 ber_start_seqorset(
00361        BerElement *ber,
00362        ber_tag_t tag )
00363 {
00364        /*
00365         * Write the tag and SOS_LENLEN octets reserved for length, to ber.
00366         * For now, length octets = (tag length, previous ber_sos_inner).
00367         *
00368         * Update ber_sos_inner and the write-cursor ber_sos_ptr.  ber_ptr
00369         * will not move until the outermost sequence or set is complete.
00370         */
00371 
00372        Seqorset_header      header;
00373        unsigned char *headptr;
00374        ber_len_t            taglen, headlen;
00375        char                 *dest, **p;
00376 
00377        assert( ber != NULL );
00378        assert( LBER_VALID( ber ) );
00379 
00380        if ( ber->ber_sos_ptr == NULL ) {  /* outermost sequence/set? */
00381               header.next_sos.offset = 0;
00382               p = &ber->ber_ptr;
00383        } else {
00384               if ( (ber_len_t) -1 > (ber_elem_size_t) -1 ) {
00385                      if ( ber->ber_sos_inner > (ber_elem_size_t) -1 )
00386                             return -1;
00387               }
00388               header.next_sos.offset = ber->ber_sos_inner;
00389               p = &ber->ber_sos_ptr;
00390        }
00391        headptr = ber_prepend_tag( SOS_TAG_END(header), tag );
00392        *SOS_TAG_END(header) = taglen = SOS_TAG_END(header) - headptr;
00393        headlen = taglen + SOS_LENLEN;
00394 
00395        /* As ber_write(,headptr,headlen,) except update ber_sos_ptr, not *p */
00396        if ( headlen > (ber_len_t) (ber->ber_end - *p) ) {
00397               if ( ber_realloc( ber, headlen ) != 0 )
00398                      return -1;
00399        }
00400        dest = *p;
00401        AC_MEMCPY( dest, headptr, headlen );
00402        ber->ber_sos_ptr = dest + headlen;
00403 
00404        ber->ber_sos_inner = dest + taglen - ber->ber_buf;
00405 
00406        /*
00407         * Do not return taglen + SOS_LENLEN here - then ber_put_seqorset()
00408         * should return lenlen - SOS_LENLEN + len, which can be < 0.
00409         */
00410        return 0;
00411 }
00412 
00413 int
00414 ber_start_seq( BerElement *ber, ber_tag_t tag )
00415 {
00416        if ( tag == LBER_DEFAULT ) {
00417               tag = LBER_SEQUENCE;
00418        }
00419 
00420        return ber_start_seqorset( ber, tag );
00421 }
00422 
00423 int
00424 ber_start_set( BerElement *ber, ber_tag_t tag )
00425 {
00426        if ( tag == LBER_DEFAULT ) {
00427               tag = LBER_SET;
00428        }
00429 
00430        return ber_start_seqorset( ber, tag );
00431 }
00432 
00433 /* End a sequence or set */
00434 static int
00435 ber_put_seqorset( BerElement *ber )
00436 {
00437        Seqorset_header      header;
00438        unsigned char *lenptr;      /* length octets in the sequence/set */
00439        ber_len_t            len;          /* length(contents) */
00440        ber_len_t            xlen;         /* len + length(length) */
00441 
00442        assert( ber != NULL );
00443        assert( LBER_VALID( ber ) );
00444 
00445        if ( ber->ber_sos_ptr == NULL ) return -1;
00446 
00447        lenptr = (unsigned char *) ber->ber_buf + ber->ber_sos_inner;
00448        xlen = ber->ber_sos_ptr - (char *) lenptr;
00449        if ( xlen > MAXINT_BERSIZE + SOS_LENLEN ) {
00450               return -1;
00451        }
00452 
00453        /* Extract sequence/set information from length octets */
00454        memcpy( SOS_TAG_END(header), lenptr, SOS_LENLEN );
00455 
00456        /* Store length, and close gap of leftover reserved length octets */
00457        len = xlen - SOS_LENLEN;
00458        if ( !(ber->ber_options & LBER_USE_DER) ) {
00459               int i;
00460               lenptr[0] = SOS_LENLEN - 1 + 0x80; /* length(length)-1 */
00461               for( i = SOS_LENLEN; --i > 0; len >>= 8 ) {
00462                      lenptr[i] = len & 0xffU;
00463               }
00464        } else {
00465               unsigned char *p = ber_prepend_len( lenptr + SOS_LENLEN, len );
00466               ber_len_t unused = p - lenptr;
00467               if ( unused != 0 ) {
00468                      /* length(length) < the reserved SOS_LENLEN bytes */
00469                      xlen -= unused;
00470                      AC_MEMCPY( lenptr, p, xlen );
00471                      ber->ber_sos_ptr = (char *) lenptr + xlen;
00472               }
00473        }
00474 
00475        ber->ber_sos_inner = header.next_sos.offset;
00476        if ( header.next_sos.offset == 0 ) { /* outermost sequence/set? */
00477               /* The ber_ptr is at the set/seq start - move it to the end */
00478               ber->ber_ptr = ber->ber_sos_ptr;
00479               ber->ber_sos_ptr = NULL;
00480        }
00481 
00482        return xlen + *SOS_TAG_END(header); /* lenlen + len + taglen */
00483 }
00484 
00485 int
00486 ber_put_seq( BerElement *ber )
00487 {
00488        return ber_put_seqorset( ber );
00489 }
00490 
00491 int
00492 ber_put_set( BerElement *ber )
00493 {
00494        return ber_put_seqorset( ber );
00495 }
00496 
00497 /* N tag */
00498 static ber_tag_t lber_int_null = 0;
00499 
00500 /* VARARGS */
00501 int
00502 ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... )
00503 {
00504        va_list              ap;
00505        char          *s, **ss;
00506        struct berval *bv, **bvp;
00507        int           rc;
00508        ber_int_t     i;
00509        ber_len_t     len;
00510 
00511        assert( ber != NULL );
00512        assert( fmt != NULL );
00513        assert( LBER_VALID( ber ) );
00514 
00515        va_start( ap, fmt );
00516 
00517        for ( rc = 0; *fmt && rc != -1; fmt++ ) {
00518               switch ( *fmt ) {
00519               case '!': { /* hook */
00520                             BEREncodeCallback *f;
00521                             void *p;
00522 
00523                             ber->ber_usertag = 0;
00524 
00525                             f = va_arg( ap, BEREncodeCallback * );
00526                             p = va_arg( ap, void * );
00527                             rc = (*f)( ber, p );
00528 
00529                             if ( ber->ber_usertag ) {
00530                                    goto next;
00531                             }
00532                      } break;
00533 
00534               case 'b':     /* boolean */
00535                      i = va_arg( ap, ber_int_t );
00536                      rc = ber_put_boolean( ber, i, ber->ber_tag );
00537                      break;
00538 
00539               case 'i':     /* int */
00540                      i = va_arg( ap, ber_int_t );
00541                      rc = ber_put_int( ber, i, ber->ber_tag );
00542                      break;
00543 
00544               case 'e':     /* enumeration */
00545                      i = va_arg( ap, ber_int_t );
00546                      rc = ber_put_enum( ber, i, ber->ber_tag );
00547                      break;
00548 
00549               case 'n':     /* null */
00550                      rc = ber_put_null( ber, ber->ber_tag );
00551                      break;
00552 
00553               case 'N':     /* Debug NULL */
00554                      rc = 0;
00555                      if( lber_int_null != 0 ) {
00556                             /* Insert NULL to ensure peer ignores unknown tags */
00557                             rc = ber_put_null( ber, lber_int_null );
00558                      }
00559                      break;
00560 
00561               case 'o':     /* octet string (non-null terminated) */
00562                      s = va_arg( ap, char * );
00563                      len = va_arg( ap, ber_len_t );
00564                      rc = ber_put_ostring( ber, s, len, ber->ber_tag );
00565                      break;
00566 
00567               case 'O':     /* berval octet string */
00568                      bv = va_arg( ap, struct berval * );
00569                      if( bv == NULL ) break;
00570                      rc = ber_put_berval( ber, bv, ber->ber_tag );
00571                      break;
00572 
00573               case 's':     /* string */
00574                      s = va_arg( ap, char * );
00575                      rc = ber_put_string( ber, s, ber->ber_tag );
00576                      break;
00577 
00578               case 'B':     /* bit string */
00579               case 'X':     /* bit string (deprecated) */
00580                      s = va_arg( ap, char * );
00581                      len = va_arg( ap, ber_len_t );     /* in bits */
00582                      rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
00583                      break;
00584 
00585               case 't':     /* tag for the next element */
00586                      ber->ber_tag = va_arg( ap, ber_tag_t );
00587                      goto next;
00588 
00589               case 'v':     /* vector of strings */
00590                      if ( (ss = va_arg( ap, char ** )) == NULL )
00591                             break;
00592                      for ( i = 0; ss[i] != NULL; i++ ) {
00593                             if ( (rc = ber_put_string( ber, ss[i],
00594                                 ber->ber_tag )) == -1 )
00595                                    break;
00596                      }
00597                      break;
00598 
00599               case 'V':     /* sequences of strings + lengths */
00600                      if ( (bvp = va_arg( ap, struct berval ** )) == NULL )
00601                             break;
00602                      for ( i = 0; bvp[i] != NULL; i++ ) {
00603                             if ( (rc = ber_put_berval( ber, bvp[i],
00604                                 ber->ber_tag )) == -1 )
00605                                    break;
00606                      }
00607                      break;
00608 
00609               case 'W':     /* BerVarray */
00610                      if ( (bv = va_arg( ap, BerVarray )) == NULL )
00611                             break;
00612                      for ( i = 0; bv[i].bv_val != NULL; i++ ) {
00613                             if ( (rc = ber_put_berval( ber, &bv[i],
00614                                 ber->ber_tag )) == -1 )
00615                                    break;
00616                      }
00617                      break;
00618 
00619               case '{':     /* begin sequence */
00620                      rc = ber_start_seq( ber, ber->ber_tag );
00621                      break;
00622 
00623               case '}':     /* end sequence */
00624                      rc = ber_put_seqorset( ber );
00625                      break;
00626 
00627               case '[':     /* begin set */
00628                      rc = ber_start_set( ber, ber->ber_tag );
00629                      break;
00630 
00631               case ']':     /* end set */
00632                      rc = ber_put_seqorset( ber );
00633                      break;
00634 
00635               default:
00636                      if( ber->ber_debug ) {
00637                             ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
00638                                    "ber_printf: unknown fmt %c\n", *fmt );
00639                      }
00640                      rc = -1;
00641                      break;
00642               }
00643 
00644               ber->ber_tag = LBER_DEFAULT;
00645        next:;
00646        }
00647 
00648        va_end( ap );
00649 
00650        return rc;
00651 }