[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS Utility Routines Manual


Previous Contents Index

14.20.1.1 Encoding Example

The following is an example of encoding the following ASN.1 data type:


        Example1Request ::= SEQUENCE {
                s     OCTET STRING, -- must be printable
                val1  INTEGER,
                val2  [0] INTEGER DEFAULT 0
        }

        int encode_example1(char *s,ber_int_t val1,ber_int_t val2,
                                  struct berval **bvPtr)

        {
                 BerElement *ber;
                int rc;

                ber = ber_alloc_t(LBER_USE_DER);

                if (ber == NULL) return -1;

                if (ber_printf(ber,"{si",s,val1) == -1) {
                        ber_free(ber,1);
                        return -1;
        }

        if (val2 != 0) {
        if (ber_printf(ber,"ti",(ber_tag_t)0x80,val2) == -1) {
                ber_free(ber,1);
                return -1;
                }
        }

        if (ber_printf(ber,"}") == -1) {
                ber_free(ber,1);
                return -1;
        }


        rc = ber_flatten(ber,bvPtr);
        ber_free(ber,1);
        return rc;
        }

14.20.2 Decoding

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() , as shown in the following example:

14.20.2.1 Decoding Example

The following is an example of decoding an ASN.1 data type:


        Example2Request ::= SEQUENCE {
                dn OCTET STRING, -- must be printable
                scope ENUMERATED { b (0), s (1), w (2) },
                ali ENUMERATED { n (0), s (1), f (2), a (3) },
                size INTEGER,
                time INTEGER,
                tonly BOOLEAN,
                attrs SEQUENCE OF OCTET STRING, -- must be printable
                [0] SEQUENCE OF SEQUENCE {
                        type OCTET STRING -- must be printable,
                        crit BOOLEAN DEFAULT FALSE,
                        value OCTET STRING
        } OPTIONAL }

        #define TAG_CONTROL_LIST 0xA0U /* context specific cons 0 */

        int decode_example2(struct berval *bv)
{
        BerElement *ber;
        ber_len_t len;
        ber_tag_t res;
        ber_int_t scope, ali, size, time, tonly;
        char *dn = NULL, **attrs = NULL;
        int i,rc = 0;
        ber = ber_init(bv);
        if (ber == NULL) {
                        fputs("ERROR ber_init failed\n", stderr);
                        return -1;
        }

        res = ber_scanf(ber,"{aiiiib{v}",&dn,&scope,&ali,
                                &size,&time,&tonly,&attrs);

        if (res == LBER_ERROR) {
                        fputs("ERROR ber_scanf failed\n", stderr);
                        ber_free(ber,1);
                        return -1;
        }

        /* *** use dn */
        ldap_memfree(dn);

        for (i = 0; attrs != NULL && attrs[i] != NULL; i++) {
                /* *** use attrs[i] */
                ldap_memfree(attrs[i]);
        }
        ldap_memfree(attrs);

        if (ber_peek_tag(ber,&len) == TAG_CONTROL_LIST) {
                char *opaque;
                ber_tag_t tag;

                for (tag = ber_first_element(ber,&len,&opaque);
                     tag != LBER_DEFAULT;
                     tag = ber_next_element (ber,&len,opaque)) {

                                ber_len_t tlen;
                                ber_tag_t ttag;
                                char *type;
                                ber_int_t crit;
                                struct berval *value;

                                if (ber_scanf(ber,"{a",&type) == LBER_ERROR) {
                                        fputs("ERROR cannot parse type\n",
                                        stderr);
                                        break;
                                }
                                /* *** use type */
                                ldap_memfree(type);

                                ttag = ber_peek_tag(ber,&tlen);
                                if (ttag == 0x01U) { /* boolean */
                                        if (ber_scanf(ber,"b",
                                                     &crit) == LBER_ERROR){
                                             fputs("ERROR cannot parse crit\n",
                                                     stderr);
                                             rc = -1;
                                             break;
                                        }


                        } else if (ttag == 0x04U) { /* octet string */
                                        crit = 0;
                        } else {
                                        fputs("ERROR extra field in controls\n",
                                            stderr );
                                        break;
                        }

                        if (ber_scanf(ber,"O}",&value) == LBER_ERROR) {
                                fputs("ERROR cannot parse value\n",
                                stderr);
                                rc = -1;
                                break;
                        }
                        /* *** use value */
                        ber_bvfree(value);
                }
        }

        if ( rc == 0 ) { /* no errors so far */
                if (ber_scanf(ber,"}") == LBER_ERROR) {
                          rc = -1;
                }
        }

        ber_free(ber,1);

        return rc;

}

14.21 Using LDAP with HP SSL for OpenVMS

Secure Sockets Layer (SSL) is the open standard security protocol for the secure transfer of sensitive information over the Internet.

You can establish HP SSL for OpenVMS Alpha on an LDAP session if the server supports such sessions. SSL uses X.509 public key technology to provide the following security functions:

  • Integrity and confidentiality of the LDAP dialog
    This is the most common use of HP SSL. The bytes sent over the wire are encrypted.
  • Authentication of the client
    Some servers use SSL to authenticate the client and make access control decisions based on the client identity. In this case, the client must have access to its private key and its certificate. The client certificate subject is a DN.
  • Authentication of the server
    It might be important for the client to verify the identity of the server to which it is talking. In this case, the client must have access to the appropriate certification authority (CA) public keys.

There are several versions of SSL: SSLv2 (2.0), SSLv3 (3.0), and TLSv1 (3.1). TLS is the latest Internet standard. It does not require the use of RSA algorithms. Usually the client specifies the highest version it supports, and the server negotiates downward, if necessary. The client library supports all the versions listed here.

You can establish SSL over LDAP two different ways:

  • LDAPS
    This older, de facto standard uses a separate TCP/IP port (usually 636) specifically for SSL over LDAP. In this case, the second parameter to the ldap_tls_start() function must be set to zero.
  • StartTLS
    This proposed Internet standard uses a regular LDAP port (usually 389) and requires the client to request the use of SSL. In this case, the second parameter to the ldap_tls_start() function must be set to 1.

14.21.1 HP SSL Certificate Options

The following session-handle options are specific to SSL and can be set by the ldap_set_option() function:

  • LDAP_OPT_TLS_CERT_REQUIRED (0x7001) void *
    Set to LDAP_OPT_ON if the client library requires a server certificate to be present the next time the ldap_tls_start() function is called. The default value is LDAP_OPT_OFF; a server certificate is not required.
  • LDAP_OPT_TLS_VERIFY_REQUIRED (0x7002) void *
    Set to LDAP_OPT_ON if the client library requires that a server certificate path be validated the next time the ldap_tls_start() function is called. The default value is LDAP_OPT_OFF; the server certificate, if any, is not verified.
  • LDAP_OPT_TLS_CERT_FILE (0x7003) char *
    Set to the name of a file containing the client's certificate for use by the ldap_tls_start() function.
  • LDAP_OPT_TLS_PKEY_FILE (0x7004) char *
    Set to the name of a file containing the client's private key for use by the ldap_tls_start() function.
  • LDAP_OPT_TLS_CA_FILE (0x7005) char *
    Set to the name of a file containing CA public keys used for validation of the server by the ldap_tls_start() function.
  • LDAP_OPT_TLS_CA_PATH (0x7006) char *
    Set to the name of a directory on disk containing CA public key files used for validation of the server by the ldap_tls_start() function.
  • LDAP_OPT_TLS_VERSION (0x7007) int *
    Set to the desired SSL protocol version. This option takes one of the following values:
    1: TLSv1 only
    20: SSLv2 only
    23: SSLv2 or SSLv3
    30: SSLv3 only (default)
    31: TLSv1 only

If LDAP_OPT_TLS_VERIFY_REQUIRED is set to ON, either the LDAP_OPT_TLS_CA_FILE or the LDAP_OPT_TLS_CA_PATH option must be set.

If client authentication is required, both LDAP_OPT_TLS_CERT_FILE and LDAP_OPT_TLS_PKEY_FILE must be set.

14.21.2 Obtaining a Key Pair

In order for TLS to authenticate a client, the client must have a private key and a certificate. Obtain these from either a Certification Authority or a self-sign program. A self-sign program is included in the Open Source Security for OpenVMS product.

14.22 Sample LDAP API Code

The following is a sample of LDAP API code.


   #include <ldap.h>

   main()
   {
           LDAP            *ld;
           LDAPMessage     *res, *e;
           int             i, rc;
           char            *a, *dn;
           BerElement      *ptr;
           char            **vals;

           /* open an LDAP session */
           if ( (ld = ldap_init( "dotted.host.name", ldap_PORT )) == NULL )
                   exit( 1 );

           /* authenticate as nobody */
           if (( rc = ldap_simple_bind_s( ld, NULL, NULL )) != ldap_SUCCESS ) {
                   fprintf( stderr, "ldap_simple_bind_s: %s\n",
                       ldap_err2string( rc ));
                   exit( 1 );
           }

           /* search for entries with cn of "Babs Jensen", return all attrs  */
           if (( rc = ldap_search_s( ld, "o=University of Michigan, c=US",
               ldap_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res ))
               != ldap_SUCCESS ) {
                   fprintf( stderr, "ldap_search_s: %s\n",
                       ldap_err2string( rc ));
                   exit( 1 );
           }

           /* step through each entry returned */
           for ( e = ldap_first_entry( ld, res ); e != NULL;
               e = ldap_next_entry( ld, e ) ) {
                   /* print its name */
                   dn = ldap_get_dn( ld, e );
                   printf( "dn: %s\n", dn );
                   ldap_memfree( dn );

                   /* print each attribute */
                   for ( a = ldap_first_attribute( ld, e, &ptr ); a != NULL;
                       a = ldap_next_attribute( ld, e, ptr ) ) {
                           printf( "attribute: %s\n", a );

                           /* print each value */
                           vals = ldap_get_values( ld, e, a );
                           for ( i = 0; vals[i] != NULL; i++ ) {
                                   printf( "value: %s\n", vals[i] );
                           }
                           ldap_value_free( vals );
                           ldap_memfree( a );
                   }
                   if ( ptr != NULL ) {

                           ber_free( ptr, 0 );
                   }
           }

           /* free the search results */
           ldap_msgfree( res );

           /* close and free connection resources */
           ldap_unbind( ld );
   }


Previous Next Contents Index