VMS Help
LDAP, Encoded ASN.1
*Conan The Librarian
|
LDAP contains functions that may be used to encode and decode
BER-encoded ASN.1 values, which are often used inside of control
and extension values.
The following additional integral types are defined for use in
manipulation of BER encoded ASN.1 values:
typedef unsigned long ber_tag_t; /* for BER tags */
typedef long ber_int_t; /* for BER ints, enums, and Booleans */
With the exceptions of two new functions, ber_flatten() and ber_
init(), these functions are compatible with the University of
Michigan LDAP 3.3 implementation of BER.
typedef struct berval {
ber_len_t bv_len;
char *bv_val;
} BerValue;
A struct berval contains a sequence of bytes and an indication
of its length. The bv_val is not null terminated. A bv_len must
always be a nonnegative number. Applications may allocate their
own berval structures.
typedef struct berelement {
/* opaque */
} BerElement;
The BerElement structure contains not only a copy of the encoded
value, but also state information used in encoding or decoding.
Applications cannot allocate their own BerElement structures.
The internal state is neither thread-specific nor locked, so
two threads should not manipulate the same BerElement value
simultaneously.
A single BerElement value cannot be used for both encoding and
decoding.
void ber_bvfree( struct berval *bv );
The ber_bvfree() function frees a berval returned from this
API. Both the bv->bv_val string and the berval itself are freed.
Applications should not use ber_bvfree() with bervals which the
application has allocated.
void ber_bvecfree ( struct berval **bv );
The ber_bvecfree() function frees an array of bervals returned
from this API. Each of the bervals in the array are freed using
ber_bvfree(), then the array itself is freed.
struct berval *ber_bvdup (struct berval *bv );
The ber_bvdup() function returns a copy of a berval. The bv_val
field in the returned berval points to a different area of memory
as the bv_val field in the argument berval. The null pointer is
returned on error (for example, out of memory).
void ber_free ( BerElement *ber, int fbuf );
The ber_free() function frees a BerElement which is returned from
the API calls ber_alloc_t() or ber_init(). Each BerElement must
be freed by the caller. The second argument fbuf should always
be set to 1 to ensure that the internal buffer used by the BER
functions is freed as well as the BerElement container itself.
The following is an example of encoding:
BerElement *ber_alloc_t(int options);
The ber_alloc_t() function constructs and returns BerElement.
The null pointer is returned on error. The options field contains
a bitwise-or of options which are to be used when generating
the encoding of this BerElement. One option is defined and must
always be supplied:
#define LBER_USE_DER 0x01
When this option is present, lengths will always be encoded
in the minimum number of octets. Note that this option does
not cause values of sets and sequences to be rearranged in
tag and byte order, so these functions are not sufficient for
generating DER output as defined in X.509 and X.680. If the
caller takes responsibility for ordering values of sets and
sequences correctly, DER output as defined in X.509 and X.680
can be produced.
Unrecognized option bits are ignored.
The BerElement returned by ber_alloc_t() is initially empty.
Calls to ber_printf() will append bytes to the end of the
BerElement.
int ber_printf(BerElement *ber, char *fmt, ... )
The ber_printf() function is used to encode a BER element in
much the same way that sprintf() works. One important difference,
though, is that state information is kept in the BER argument so
that multiple calls can be made to ber_printf() to append to the
end of the BER element. BER must be a pointer to a BerElement
returned by ber_alloc_t(). The ber_printf() function interprets
and formats its arguments according to the format string fmt.
The ber_printf() function returns -1 if there is an error during
encoding and a positive number if successful. As with sprintf(),
each character in fmt refers to an argument to ber_printf().
The format string can contain the following format characters:
t Tag. The next argument is a ber_tag_t specifying the tag
to override the next element to be written to the ber. This
works across calls. The value must contain the tag class,
constructed bit, and tag value. The tag value must fit in
a single octet (tag value is less than 32). For example, a
tag of "[3]" for a constructed type is 0xA3.
b Boolean. The next argument is a ber_int_t, containing
either 0 for FALSE or 0xff for TRUE. A boolean element
is output. If this format character is not preceded by the
't' format modifier, the tag 0x01 is used for the element.
e Enumerated. The next argument is a ber_int_t, containing
the enumerated value in the host's byte order. An
enumerated element is output. If this format character
is not preceded by the 't' format modifier, the tag 0x0A is
used for the element.
i Integer. The next argument is a ber_int_t, containing the
integer in the host's byte order. An integer element is
output. If this format character is not preceded by the 't'
format modifier, the tag 0x02 is used for the element.
B Bitstring. The next two arguments are a char * pointer
to the start of the bitstring, followed by a ber_len_t
containing the number of bits in the bitstring. A bitstring
element is output, in primitive form. If this format
character is not preceded by the 't' format modifier, the
tag 0x03 is used for the element.
n Null. No argument is required. An ASN.1 NULL element is
output. If this format character is not preceded by the 't'
format modifier, the tag 0x05 is used for the element.
o Octet string. The next two arguments are a char *, followed
by a ber_len_t with the length of the string. The string
may contain null bytes and need not by zero-terminated.
An octet string element is output, in primitive form. If
this format character is not preceded by the 't' format
modifier, the tag 0x04 is used for the element.
s Octet string. The next argument is a char * pointing
to a zero-terminated string. An octet string element
in primitive form is output, which does not include
the trailing '\0' byte. If this format character is not
preceded by the 't' format modifier, the tag 0x04 is used
for the element.
v Several octet strings. The next argument is a char **,
an array of char * pointers to zero-terminated strings.
The last element in the array must be a null pointer. The
octet strings do not include the leading SEQUENCE OF octet
strings. The 't' format modifier cannot be used with this
format character.
V Several octet strings. A NULL-terminated array of struct
berval *'s is supplied. Note that a construct like '{V}'
is required to get an actual SEQUENCE OF octet strings.
The 't' format modifier cannot be used with this format
character.
{ Begin sequence. No argument is required. If this format
character is not preceded by the 't' format modifier, the
tag 0x30 is used.
} End sequence. No argument is required. The 't' format
modifier cannot be used with this format character.
[ Begin set. No argument is required. If this format
character is not preceded by the 't' format modifier, the
tag 0x31 is used.
] End set. No argument is required. The 't' format modifier
cannot be used with this format character.
Each use of a '{' format character must be matched by a '}'
character, either later in the format string, or in the format
string of a subsequent call to ber_printf() for that BerElement.
The same applies to the '[' and ']'.
Sequences and sets nest, and implementations of this API must
maintain internal state to be able to properly calculate the
lengths.
int ber_flatten (BerElement *ber, struct berval **bvPtr);
The ber_flatten() function allocates a struct berval whose
contents are a BER encoding taken from the ber argument. The
bvPtr pointer points to the returned berval, which must be freed
using ber_bvfree(). This function returns 0 on success and -1 on
error.
The ber_flatten() API call is not present in U-M LDAP 3.3.
The use of ber_flatten() on a BerElement in which all '{' and '}'
format modifiers have not been properly matched is an error (that
is, -1 will be returned by ber_flatten() if this situation is
exists).
The following two symbols are available to applications.
#define LBER_ERROR 0xffffffffL
#define LBER_DEFAULT 0xffffffffL
BerElement *ber_init (struct berval *bv);
The ber_init() function constructs a BerElement and returns a new
BerElement containing a copy of the data in the bv argument. The
ber_init() function returns the null pointer on error.
ber_tag_t ber_scanf (BerElement *ber, char *fmt, ... );
The ber_scanf() function is used to decode a BER element in much
the same way that sscanf() works. One important difference,
though, is that some state information is kept with the ber
argument so that multiple calls can be made to ber_scanf() to
sequentially read from the BER element. The ber argument must
be a pointer to a BerElement returned by ber_init(). The ber_
scanf() function interprets function the bytes according to
the format string fmt, and stores the results in its additional
arguments. The ber_scanf() function returns LBER_ERROR on error,
and a different value on success.
The format string contains conversion specifications which are
used to direct the interpretation of the BER element. The format
string can contain the following characters:
a Octet string. A char ** argument should be supplied. Memory
is allocated, filled with the contents of the octet string,
null- terminated, and the pointer to the string is stored
in the argument. The returned value must be freed using
ldap_memfree(). The tag of the element must indicate the
primitive form (constructed strings are not supported) but
is otherwise ignored and discarded during the decoding.
This format cannot be used with octet strings which could
contain null bytes.
O Octet string. A struct berval ** argument should be
supplied, which upon return points to a allocated struct
berval containing the octet string and its length. The
ber_bvfree() function must be called to free the allocated
memory. The tag of the element must indicate the primitive
form (constructed strings are not supported) but is
otherwise ignored during the decoding.
b Boolean. A pointer to a ber_int_t should be supplied. The
value stored will be 0 for FALSE or nonzero for TRUE. The
tag of the element must indicate the primitive form but is
otherwise ignored during the decoding.
e Enumerated value stored will be in host byte order. The
tag of the element must indicate the primitive form but is
otherwise ignored during the decoding. The ber_scanf()
function will return an error if the enumerated value
cannot be stored in a ber_int_t.
i Integer. A pointer to a ber_int_t should be supplied. The
value stored will be in host byte order. The tag of the
element must indicate the primitive form but is otherwise
ignored during the decoding. The ber_scanf() function will
return an error if the integer cannot be stored in a ber_
int_t.
B Bitstring. A char ** argument should be supplied which
will point to the allocated bits, followed by a ber_len_t *
argument, which will point to the length (in bits) of the
bit-string returned. The ldap_memfree() function must be
called to free the bit-string. The tag of the element must
indicate the primitive form (constructed bitstrings are not
supported) but is otherwise ignored during the decoding.
n Null. No argument is required. The element is simply
skipped if it is recognized as a zero-length element. The
tag is ignored.
v Several octet strings. A char *** argument should be
supplied, which upon return points to a allocated null-
terminated array of char *'s containing the octet strings.
NULL is stored if the sequence is empty. The ldap_
memfree() function must be called to free each element
of the array and the array itself. The tag of the sequence
and of the octet strings are ignored.
V Several octet strings (which could contain null bytes).
A struct berval *** should be supplied, which upon
return points to a allocated null-terminated array of
struct berval *'s containing the octet strings and their
lengths. NULL is stored if the sequence is empty. The ber_
bvecfree() function can be called to free the allocated
memory. The tag of the sequence and of the octet strings
are ignored.
x Skip element. The next element is skipped. No argument is
required.
{ Begin sequence. No argument is required. The initial
sequence tag and length are skipped.
} End sequence. No argument is required.
[ Begin set. No argument is required. The initial set tag and
length are skipped.
] End set. No argument is required.
ber_tag_t ber_peek_tag (BerElement *ber, ber_len_t *lenPtr);
The ber_peek_tag() function returns the tag of the next element
to be parsed in the BerElement argument. The length of this
element is stored in the *lenPtr argument. LBER_DEFAULT is
returned if there is no further data to be read. The ber argument
is not modified.
ber_tag_t ber_skip_tag (BerElement *ber, ber_len_t *lenPtr);
The ber_skip_tag() function is similar to ber_peek_tag(), except
that the state pointer in the BerElement argument is advanced
past the first tag and length, and is pointed to the value part
of the next element. This function should only be used with
constructed types and situations when a BER encoding is used as
the value of an OCTET STRING. The length of the value is stored
in *lenPtr.
ber_tag_t ber_first_element(BerElement *ber,
ber_len_t *lenPtr, char **opaquePtr);
ber_tag_t ber_next_element (BerElement *ber,
ber_len_t *lenPtr, char *opaque);
The ber_first_element() and ber_next_element() functions are
used to traverse a SET, SET OF, SEQUENCE or SEQUENCE OF data
value. The ber_first_element() function calls ber_skip_tag(),
stores internal information in *lenPtr and *opaquePtr, and calls
ber_peek_tag() for the first element inside the constructed
value. LBER_DEFAULT is returned if the constructed value is
empty. The ber_next_element() function positions the state at the
start of the next element in the constructed type. LBER_DEFAULT
is returned if there are no further values.
The len and opaque values should not be used by applications
other than as arguments to ber_next_element(). (Refer to the HP
OpenVMS Utility Routines Manual for an example of this usage.)