1 /* encode.c - ber output encoding routines */
3 * Copyright (c) 1990 Regents of the University of Michigan.
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and that due credit is given
8 * to the University of Michigan at Ann Arbor. The name of the University
9 * may not be used to endorse or promote products derived from this
10 * software without specific prior written permission. This software
11 * is provided ``as is'' without express or implied warranty.
20 #if defined(NeXT) || defined(VMS)
22 #else /* next || vms */
26 #endif /* next || vms */
27 #if defined( BC31 ) || defined( _WIN32 )
29 #else /* BC31 || _WIN32 */
31 #endif /* BC31 || _WIN32 */
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
45 #if defined( DOS ) || defined( _WIN32 )
50 static int ber_put_len( BerElement *ber, unsigned long len, int nosos );
51 static int ber_start_seqorset( BerElement *ber, unsigned long tag );
52 static int ber_put_seqorset( BerElement *ber );
53 static int ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag );
54 #endif /* NEEDPROTOS */
58 ber_calc_taglen( unsigned long tag )
63 /* find the first non-all-zero byte in the tag */
64 for ( i = sizeof(long) - 1; i > 0; i-- ) {
65 mask = (0xffL << (i * 8));
75 ber_put_tag( BerElement *ber, unsigned long tag, int nosos )
80 taglen = ber_calc_taglen( tag );
82 ntag = LBER_HTONL( tag );
84 return( ber_write( ber, ((char *) &ntag) + sizeof(long) - taglen,
89 ber_calc_lenlen( unsigned long len )
92 * short len if it's less than 128 - one byte giving the len,
100 * long len otherwise - one byte with bit 8 set, giving the
101 * length of the length, followed by the length itself.
106 if ( len <= 0xFFFFL )
108 if ( len <= 0xFFFFFFL )
115 ber_put_len( BerElement *ber, unsigned long len, int nosos )
120 unsigned long netlen;
123 * short len if it's less than 128 - one byte giving the len,
128 netlen = LBER_HTONL( len );
129 return( ber_write( ber, (char *) &netlen + sizeof(long) - 1,
134 * long len otherwise - one byte with bit 8 set, giving the
135 * length of the length, followed by the length itself.
138 /* find the first non-all-zero byte */
139 for ( i = sizeof(long) - 1; i > 0; i-- ) {
140 mask = (0xffL << (i * 8));
150 /* write the length of the length */
151 if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
154 /* write the length itself */
155 netlen = LBER_HTONL( len );
156 if ( ber_write( ber, (char *) &netlen + (sizeof(long) - i), i, nosos )
164 ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag )
173 * high bit is set - look for first non-all-one byte
174 * high bit is clear - look for first non-all-zero byte
176 for ( i = sizeof(long) - 1; i > 0; i-- ) {
177 mask = (0xffL << (i * 8));
181 if ( (num & mask) != mask )
191 * we now have the "leading byte". if the high bit on this
192 * byte matches the sign bit, we need to "back up" a byte.
194 mask = (num & (0x80L << (i * 8)));
195 if ( (mask && !sign) || (sign && !mask) )
200 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
203 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
206 netnum = LBER_HTONL( num );
207 if ( ber_write( ber, (char *) &netnum + (sizeof(long) - i), i, 0 )
211 /* length of tag + length + contents */
212 return( taglen + lenlen + i );
216 ber_put_enum( BerElement *ber, long num, unsigned long tag )
218 if ( tag == LBER_DEFAULT )
219 tag = LBER_ENUMERATED;
221 return( ber_put_int_or_enum( ber, num, tag ) );
225 ber_put_int( BerElement *ber, long num, unsigned long tag )
227 if ( tag == LBER_DEFAULT )
230 return( ber_put_int_or_enum( ber, num, tag ) );
234 ber_put_ostring( BerElement *ber, char *str, unsigned long len,
237 int taglen, lenlen, rc;
238 #ifdef STR_TRANSLATION
240 #endif /* STR_TRANSLATION */
242 if ( tag == LBER_DEFAULT )
243 tag = LBER_OCTETSTRING;
245 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
248 #ifdef STR_TRANSLATION
249 if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0 &&
250 ber->ber_encode_translate_proc != NULL ) {
251 if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
259 #endif /* STR_TRANSLATION */
261 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
262 ber_write( ber, str, len, 0 ) != len ) {
265 /* return length of tag + length + contents */
266 rc = taglen + lenlen + len;
269 #ifdef STR_TRANSLATION
273 #endif /* STR_TRANSLATION */
279 ber_put_string( BerElement *ber, char *str, unsigned long tag )
281 return( ber_put_ostring( ber, str, strlen( str ), tag ));
285 ber_put_bitstring( BerElement *ber, char *str,
286 unsigned long blen /* in bits */, unsigned long tag )
288 int taglen, lenlen, len;
289 unsigned char unusedbits;
291 if ( tag == LBER_DEFAULT )
292 tag = LBER_BITSTRING;
294 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
297 len = ( blen + 7 ) / 8;
298 unusedbits = len * 8 - blen;
299 if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
302 if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
305 if ( ber_write( ber, str, len, 0 ) != len )
308 /* return length of tag + length + unused bit count + contents */
309 return( taglen + 1 + lenlen + len );
313 ber_put_null( BerElement *ber, unsigned long tag )
317 if ( tag == LBER_DEFAULT )
320 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
323 if ( ber_put_len( ber, 0, 0 ) != 1 )
326 return( taglen + 1 );
330 ber_put_boolean( BerElement *ber, int boolval, unsigned long tag )
333 unsigned char trueval = 0xff;
334 unsigned char falseval = 0x00;
336 if ( tag == LBER_DEFAULT )
339 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
342 if ( ber_put_len( ber, 1, 0 ) != 1 )
345 if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
349 return( taglen + 2 );
352 #define FOUR_BYTE_LEN 5
355 ber_start_seqorset( BerElement *ber, unsigned long tag )
359 if ( (new = (Seqorset *) calloc( sizeof(Seqorset), 1 ))
363 if ( ber->ber_sos == NULLSEQORSET )
364 new->sos_first = ber->ber_ptr;
366 new->sos_first = ber->ber_sos->sos_ptr;
368 /* Set aside room for a 4 byte length field */
369 new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
372 new->sos_next = ber->ber_sos;
379 ber_start_seq( BerElement *ber, unsigned long tag )
381 if ( tag == LBER_DEFAULT )
384 return( ber_start_seqorset( ber, tag ) );
388 ber_start_set( BerElement *ber, unsigned long tag )
390 if ( tag == LBER_DEFAULT )
393 return( ber_start_seqorset( ber, tag ) );
397 ber_put_seqorset( BerElement *ber )
399 unsigned long len, netlen;
401 unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1;
403 Seqorset **sos = &ber->ber_sos;
406 * If this is the toplevel sequence or set, we need to actually
407 * write the stuff out. Otherwise, it's already been put in
408 * the appropriate buffer and will be written when the toplevel
409 * one is written. In this case all we need to do is update the
413 len = (*sos)->sos_clen;
414 netlen = LBER_HTONL( len );
415 if ( sizeof(long) > 4 && len > 0xFFFFFFFFL )
418 if ( ber->ber_options & LBER_USE_DER ) {
419 lenlen = ber_calc_lenlen( len );
421 lenlen = FOUR_BYTE_LEN;
424 if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
426 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
429 if ( ber->ber_options & LBER_USE_DER ) {
430 /* Write the length in the minimum # of octets */
431 if ( ber_put_len( ber, len, 1 ) == -1 )
434 if (lenlen != FOUR_BYTE_LEN) {
436 * We set aside FOUR_BYTE_LEN bytes for
437 * the length field. Move the data if
438 * we don't actually need that much
440 SAFEMEMCPY( (*sos)->sos_first + taglen +
441 lenlen, (*sos)->sos_first + taglen +
442 FOUR_BYTE_LEN, len );
445 /* Fill FOUR_BYTE_LEN bytes for length field */
446 /* one byte of length length */
447 if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 )
450 /* the length itself */
451 if ( ber_write( ber, (char *) &netlen + sizeof(long)
452 - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
453 != FOUR_BYTE_LEN - 1 )
456 /* The ber_ptr is at the set/seq start - move it to the end */
457 (*sos)->sos_ber->ber_ptr += len;
462 taglen = ber_calc_taglen( (*sos)->sos_tag );
463 ntag = LBER_HTONL( (*sos)->sos_tag );
464 SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
465 sizeof(long) - taglen, taglen );
467 if ( ber->ber_options & LBER_USE_DER ) {
468 ltag = (lenlen == 1) ? len : 0x80 + (lenlen - 1);
471 /* one byte of length length */
472 SAFEMEMCPY( (*sos)->sos_first + 1, <ag, 1 );
474 if ( ber->ber_options & LBER_USE_DER ) {
476 /* Write the length itself */
477 SAFEMEMCPY( (*sos)->sos_first + 2,
478 (char *)&netlen + sizeof(unsigned long) -
482 if (lenlen != FOUR_BYTE_LEN) {
484 * We set aside FOUR_BYTE_LEN bytes for
485 * the length field. Move the data if
486 * we don't actually need that much
488 SAFEMEMCPY( (*sos)->sos_first + taglen +
489 lenlen, (*sos)->sos_first + taglen +
490 FOUR_BYTE_LEN, len );
493 /* the length itself */
494 SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
495 (char *) &netlen + sizeof(long) -
496 (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
499 next->sos_clen += (taglen + lenlen + len);
500 next->sos_ptr += (taglen + lenlen + len);
503 /* we're done with this seqorset, so free it up */
504 free( (char *) (*sos) );
507 return( taglen + lenlen + len );
511 ber_put_seq( BerElement *ber )
513 return( ber_put_seqorset( ber ) );
517 ber_put_set( BerElement *ber )
519 return( ber_put_seqorset( ber ) );
525 #if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
526 BerElement *ber, char *fmt, ... )
527 #else /* MACOS || _WIN32 || BC31 */
530 #endif /* MACOS || _WIN32 || BC31 */
533 #if !defined( MACOS ) && !defined( _WIN32 ) && !defined( BC31 )
536 #endif /* !MACOS && !_WIN32 && !BC31 */
542 #if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
544 #else /* MACOS || _WIN32 || BC31 */
546 ber = va_arg( ap, BerElement * );
547 fmt = va_arg( ap, char * );
548 #endif /* MACOS || _WIN32 || BC31 */
550 for ( rc = 0; *fmt && rc != -1; fmt++ ) {
552 case 'b': /* boolean */
553 i = va_arg( ap, int );
554 rc = ber_put_boolean( ber, i, ber->ber_tag );
558 i = va_arg( ap, int );
559 rc = ber_put_int( ber, i, ber->ber_tag );
562 case 'e': /* enumeration */
563 i = va_arg( ap, int );
564 rc = ber_put_enum( ber, i, ber->ber_tag );
568 rc = ber_put_null( ber, ber->ber_tag );
571 case 'o': /* octet string (non-null terminated) */
572 s = va_arg( ap, char * );
573 len = va_arg( ap, int );
574 rc = ber_put_ostring( ber, s, len, ber->ber_tag );
577 case 's': /* string */
578 s = va_arg( ap, char * );
579 rc = ber_put_string( ber, s, ber->ber_tag );
582 case 'B': /* bit string */
583 s = va_arg( ap, char * );
584 len = va_arg( ap, int ); /* in bits */
585 rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
588 case 't': /* tag for the next element */
589 ber->ber_tag = va_arg( ap, unsigned long );
590 ber->ber_usertag = 1;
593 case 'v': /* vector of strings */
594 if ( (ss = va_arg( ap, char ** )) == NULL )
596 for ( i = 0; ss[i] != NULL; i++ ) {
597 if ( (rc = ber_put_string( ber, ss[i],
598 ber->ber_tag )) == -1 )
603 case 'V': /* sequences of strings + lengths */
604 if ( (bv = va_arg( ap, struct berval ** )) == NULL )
606 for ( i = 0; bv[i] != NULL; i++ ) {
607 if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
608 bv[i]->bv_len, ber->ber_tag )) == -1 )
613 case '{': /* begin sequence */
614 rc = ber_start_seq( ber, ber->ber_tag );
617 case '}': /* end sequence */
618 rc = ber_put_seqorset( ber );
621 case '[': /* begin set */
622 rc = ber_start_set( ber, ber->ber_tag );
625 case ']': /* end set */
626 rc = ber_put_seqorset( ber );
630 #ifndef NO_USERINTERFACE
631 fprintf( stderr, "unknown fmt %c\n", *fmt );
632 #endif /* NO_USERINTERFACE */
637 if ( ber->ber_usertag == 0 )
638 ber->ber_tag = LBER_DEFAULT;
640 ber->ber_usertag = 0;