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 */
24 #endif /* next || vms */
25 #if defined( BC31 ) || defined( _WIN32 )
27 #else /* BC31 || _WIN32 */
29 #endif /* BC31 || _WIN32 */
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
43 #if defined( DOS ) || defined( _WIN32 )
48 static int ber_put_len( BerElement *ber, unsigned long len, int nosos );
49 static int ber_start_seqorset( BerElement *ber, unsigned long tag );
50 static int ber_put_seqorset( BerElement *ber );
51 static int ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag );
52 #endif /* NEEDPROTOS */
56 ber_calc_taglen( unsigned long tag )
61 /* find the first non-all-zero byte in the tag */
62 for ( i = sizeof(long) - 1; i > 0; i-- ) {
63 mask = (0xffL << (i * 8));
73 ber_put_tag( BerElement *ber, unsigned long tag, int nosos )
78 taglen = ber_calc_taglen( tag );
80 ntag = LBER_HTONL( tag );
82 return( ber_write( ber, ((char *) &ntag) + sizeof(long) - taglen,
87 ber_calc_lenlen( unsigned long len )
90 * short len if it's less than 128 - one byte giving the len,
98 * long len otherwise - one byte with bit 8 set, giving the
99 * length of the length, followed by the length itself.
104 if ( len <= 0xFFFFL )
106 if ( len <= 0xFFFFFFL )
113 ber_put_len( BerElement *ber, unsigned long len, int nosos )
118 unsigned long netlen;
121 * short len if it's less than 128 - one byte giving the len,
126 netlen = LBER_HTONL( len );
127 return( ber_write( ber, (char *) &netlen + sizeof(long) - 1,
132 * long len otherwise - one byte with bit 8 set, giving the
133 * length of the length, followed by the length itself.
136 /* find the first non-all-zero byte */
137 for ( i = sizeof(long) - 1; i > 0; i-- ) {
138 mask = (0xffL << (i * 8));
148 /* write the length of the length */
149 if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
152 /* write the length itself */
153 netlen = LBER_HTONL( len );
154 if ( ber_write( ber, (char *) &netlen + (sizeof(long) - i), i, nosos )
162 ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag )
171 * high bit is set - look for first non-all-one byte
172 * high bit is clear - look for first non-all-zero byte
174 for ( i = sizeof(long) - 1; i > 0; i-- ) {
175 mask = (0xffL << (i * 8));
179 if ( (num & mask) != mask )
189 * we now have the "leading byte". if the high bit on this
190 * byte matches the sign bit, we need to "back up" a byte.
192 mask = (num & (0x80L << (i * 8)));
193 if ( (mask && !sign) || (sign && !mask) )
198 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
201 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
204 netnum = LBER_HTONL( num );
205 if ( ber_write( ber, (char *) &netnum + (sizeof(long) - i), i, 0 )
209 /* length of tag + length + contents */
210 return( taglen + lenlen + i );
214 ber_put_enum( BerElement *ber, long num, unsigned long tag )
216 if ( tag == LBER_DEFAULT )
217 tag = LBER_ENUMERATED;
219 return( ber_put_int_or_enum( ber, num, tag ) );
223 ber_put_int( BerElement *ber, long num, unsigned long tag )
225 if ( tag == LBER_DEFAULT )
228 return( ber_put_int_or_enum( ber, num, tag ) );
232 ber_put_ostring( BerElement *ber, char *str, unsigned long len,
235 int taglen, lenlen, rc;
236 #ifdef STR_TRANSLATION
238 #endif /* STR_TRANSLATION */
240 if ( tag == LBER_DEFAULT )
241 tag = LBER_OCTETSTRING;
243 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
246 #ifdef STR_TRANSLATION
247 if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0 &&
248 ber->ber_encode_translate_proc != NULL ) {
249 if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
257 #endif /* STR_TRANSLATION */
259 if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
260 ber_write( ber, str, len, 0 ) != len ) {
263 /* return length of tag + length + contents */
264 rc = taglen + lenlen + len;
267 #ifdef STR_TRANSLATION
271 #endif /* STR_TRANSLATION */
277 ber_put_string( BerElement *ber, char *str, unsigned long tag )
279 return( ber_put_ostring( ber, str, strlen( str ), tag ));
283 ber_put_bitstring( BerElement *ber, char *str,
284 unsigned long blen /* in bits */, unsigned long tag )
286 int taglen, lenlen, len;
287 unsigned char unusedbits;
289 if ( tag == LBER_DEFAULT )
290 tag = LBER_BITSTRING;
292 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
295 len = ( blen + 7 ) / 8;
296 unusedbits = len * 8 - blen;
297 if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
300 if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
303 if ( ber_write( ber, str, len, 0 ) != len )
306 /* return length of tag + length + unused bit count + contents */
307 return( taglen + 1 + lenlen + len );
311 ber_put_null( BerElement *ber, unsigned long tag )
315 if ( tag == LBER_DEFAULT )
318 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
321 if ( ber_put_len( ber, 0, 0 ) != 1 )
324 return( taglen + 1 );
328 ber_put_boolean( BerElement *ber, int boolval, unsigned long tag )
331 unsigned char trueval = 0xff;
332 unsigned char falseval = 0x00;
334 if ( tag == LBER_DEFAULT )
337 if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
340 if ( ber_put_len( ber, 1, 0 ) != 1 )
343 if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
347 return( taglen + 2 );
350 #define FOUR_BYTE_LEN 5
353 ber_start_seqorset( BerElement *ber, unsigned long tag )
357 if ( (new = (Seqorset *) calloc( sizeof(Seqorset), 1 ))
361 if ( ber->ber_sos == NULLSEQORSET )
362 new->sos_first = ber->ber_ptr;
364 new->sos_first = ber->ber_sos->sos_ptr;
366 /* Set aside room for a 4 byte length field */
367 new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
370 new->sos_next = ber->ber_sos;
377 ber_start_seq( BerElement *ber, unsigned long tag )
379 if ( tag == LBER_DEFAULT )
382 return( ber_start_seqorset( ber, tag ) );
386 ber_start_set( BerElement *ber, unsigned long tag )
388 if ( tag == LBER_DEFAULT )
391 return( ber_start_seqorset( ber, tag ) );
395 ber_put_seqorset( BerElement *ber )
397 unsigned long len, netlen;
399 unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1;
401 Seqorset **sos = &ber->ber_sos;
404 * If this is the toplevel sequence or set, we need to actually
405 * write the stuff out. Otherwise, it's already been put in
406 * the appropriate buffer and will be written when the toplevel
407 * one is written. In this case all we need to do is update the
411 len = (*sos)->sos_clen;
412 netlen = LBER_HTONL( len );
413 if ( sizeof(long) > 4 && len > 0xFFFFFFFFL )
416 if ( ber->ber_options & LBER_USE_DER ) {
417 lenlen = ber_calc_lenlen( len );
419 lenlen = FOUR_BYTE_LEN;
422 if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
424 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
427 if ( ber->ber_options & LBER_USE_DER ) {
428 /* Write the length in the minimum # of octets */
429 if ( ber_put_len( ber, len, 1 ) == -1 )
432 if (lenlen != FOUR_BYTE_LEN) {
434 * We set aside FOUR_BYTE_LEN bytes for
435 * the length field. Move the data if
436 * we don't actually need that much
438 SAFEMEMCPY( (*sos)->sos_first + taglen +
439 lenlen, (*sos)->sos_first + taglen +
440 FOUR_BYTE_LEN, len );
443 /* Fill FOUR_BYTE_LEN bytes for length field */
444 /* one byte of length length */
445 if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 )
448 /* the length itself */
449 if ( ber_write( ber, (char *) &netlen + sizeof(long)
450 - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
451 != FOUR_BYTE_LEN - 1 )
454 /* The ber_ptr is at the set/seq start - move it to the end */
455 (*sos)->sos_ber->ber_ptr += len;
460 taglen = ber_calc_taglen( (*sos)->sos_tag );
461 ntag = LBER_HTONL( (*sos)->sos_tag );
462 SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
463 sizeof(long) - taglen, taglen );
465 if ( ber->ber_options & LBER_USE_DER ) {
466 ltag = (lenlen == 1) ? len : 0x80 + (lenlen - 1);
469 /* one byte of length length */
470 SAFEMEMCPY( (*sos)->sos_first + 1, <ag, 1 );
472 if ( ber->ber_options & LBER_USE_DER ) {
474 /* Write the length itself */
475 SAFEMEMCPY( (*sos)->sos_first + 2,
476 (char *)&netlen + sizeof(unsigned long) -
480 if (lenlen != FOUR_BYTE_LEN) {
482 * We set aside FOUR_BYTE_LEN bytes for
483 * the length field. Move the data if
484 * we don't actually need that much
486 SAFEMEMCPY( (*sos)->sos_first + taglen +
487 lenlen, (*sos)->sos_first + taglen +
488 FOUR_BYTE_LEN, len );
491 /* the length itself */
492 SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
493 (char *) &netlen + sizeof(long) -
494 (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
497 next->sos_clen += (taglen + lenlen + len);
498 next->sos_ptr += (taglen + lenlen + len);
501 /* we're done with this seqorset, so free it up */
502 free( (char *) (*sos) );
505 return( taglen + lenlen + len );
509 ber_put_seq( BerElement *ber )
511 return( ber_put_seqorset( ber ) );
515 ber_put_set( BerElement *ber )
517 return( ber_put_seqorset( ber ) );
523 #if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
524 BerElement *ber, char *fmt, ... )
525 #else /* MACOS || _WIN32 || BC31 */
528 #endif /* MACOS || _WIN32 || BC31 */
531 #if !defined( MACOS ) && !defined( _WIN32 ) && !defined( BC31 )
534 #endif /* !MACOS && !_WIN32 && !BC31 */
540 #if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
542 #else /* MACOS || _WIN32 || BC31 */
544 ber = va_arg( ap, BerElement * );
545 fmt = va_arg( ap, char * );
546 #endif /* MACOS || _WIN32 || BC31 */
548 for ( rc = 0; *fmt && rc != -1; fmt++ ) {
550 case 'b': /* boolean */
551 i = va_arg( ap, int );
552 rc = ber_put_boolean( ber, i, ber->ber_tag );
556 i = va_arg( ap, int );
557 rc = ber_put_int( ber, i, ber->ber_tag );
560 case 'e': /* enumeration */
561 i = va_arg( ap, int );
562 rc = ber_put_enum( ber, i, ber->ber_tag );
566 rc = ber_put_null( ber, ber->ber_tag );
569 case 'o': /* octet string (non-null terminated) */
570 s = va_arg( ap, char * );
571 len = va_arg( ap, int );
572 rc = ber_put_ostring( ber, s, len, ber->ber_tag );
575 case 's': /* string */
576 s = va_arg( ap, char * );
577 rc = ber_put_string( ber, s, ber->ber_tag );
580 case 'B': /* bit string */
581 s = va_arg( ap, char * );
582 len = va_arg( ap, int ); /* in bits */
583 rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
586 case 't': /* tag for the next element */
587 ber->ber_tag = va_arg( ap, unsigned long );
588 ber->ber_usertag = 1;
591 case 'v': /* vector of strings */
592 if ( (ss = va_arg( ap, char ** )) == NULL )
594 for ( i = 0; ss[i] != NULL; i++ ) {
595 if ( (rc = ber_put_string( ber, ss[i],
596 ber->ber_tag )) == -1 )
601 case 'V': /* sequences of strings + lengths */
602 if ( (bv = va_arg( ap, struct berval ** )) == NULL )
604 for ( i = 0; bv[i] != NULL; i++ ) {
605 if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
606 bv[i]->bv_len, ber->ber_tag )) == -1 )
611 case '{': /* begin sequence */
612 rc = ber_start_seq( ber, ber->ber_tag );
615 case '}': /* end sequence */
616 rc = ber_put_seqorset( ber );
619 case '[': /* begin set */
620 rc = ber_start_set( ber, ber->ber_tag );
623 case ']': /* end set */
624 rc = ber_put_seqorset( ber );
628 #ifndef NO_USERINTERFACE
629 fprintf( stderr, "unknown fmt %c\n", *fmt );
630 #endif /* NO_USERINTERFACE */
635 if ( ber->ber_usertag == 0 )
636 ber->ber_tag = LBER_DEFAULT;
638 ber->ber_usertag = 0;