X509_NAME Handling -- SSLeay 0.9.0b -- January 1999

NAME

X509_NAME_dup, X509_NAME_set, X509_NAME_oneline, X509_NAME_cmp, X509_NAME_hash,
X509_NAME_print, X509_NAME_entry_count, X509_NAME_get_index_by_OBJ,
X509_NAME_get_index_by_NID, X509_NAME_get_text_by_OBJ, X509_NAME_get_text_by_NID,
X509_NAME_get_entry, X509_NAME_delete_entry, X509_NAME_add_entry -- X509_NAME Handling

SYNOPSIS

#include "x509.h"

int X509_NAME_set(xn, name)
X509_NAME **xn; X509_NAME *name;

char *X509_NAME_oneline(a, buf, size)
X509_NAME *a; char *buf; int size;

int X509_NAME_cmp(a, b)
X509_NAME *a; X509_NAME *b;

unsigned long X509_NAME_hash(x)
X509_NAME *x;

int X509_NAME_print(bp, name, obase)
BIO *bp; X509_NAME *name; int obase;

int X509_NAME_entry_count(name)
X509_NAME *name;

int X509_NAME_get_index_by_OBJ(name, obj, lastpos)
X509_NAME *name;
ASN1_OBJECT *obj;
int lastpos;

int X509_NAME_get_index_by_NID(name, nid, lastpos)
X509_NAME *name;
int nid;
int lastpos;

int X509_NAME_get_text_by_OBJ(name, obj, buf, len)
X509_NAME *name;
ASN1_OBJECT *obj;
char *buf;
int len;

int X509_NAME_get_text_by_NID(name, nid, buf, len)
X509_NAME *name;
int nid;
char *buf;
int len;

X509_NAME_ENTRY *X509_NAME_get_entry(name, loc)
X509_NAME *name;
int loc;

X509_NAME_ENTRY *X509_NAME_delete_entry(name, loc)
X509_NAME *name;
int loc;

int X509_NAME_add_entry(name, ne, loc, set)br> X509_NAME *name;
X509_NAME_ENTRY *ne;
int loc;
int set;

DESCRIPTION

If you haven't read through the ASN.1 documentation, you probably had better do so; this library relies heavily on that code.

Here's the ASN.1 for the Name subfield of the certificate:

Name            ::=   CHOICE { -- only one possibility for now --
                                 rdnSequence  RDNSequence }

RDNSequence     ::=   SEQUENCE OF RelativeDistinguishedName

DistinguishedName       ::=   RDNSequence

RelativeDistinguishedName  ::=
                    SET SIZE (1 .. MAX) OF AttributeTypeAndValue

AttributeTypeAndValue           ::=     SEQUENCE {
        type    AttributeType,
        value   AttributeValue }

AttributeType           ::=   OBJECT IDENTIFIER

AttributeValue          ::=   ANY

Now let's look at the NAME subfield as the library defines it:

typedef struct X509_name_entry_st
        {
        ASN1_OBJECT *object;
        ASN1_STRING *value;
        int set;
        int size;       /* temp variable */
        } X509_NAME_ENTRY;

typedef struct X509_name_st
        {
        STACK *entries; /* of X509_NAME_ENTRY */
        int modified;   /* true if 'bytes' needs to be built */
#ifdef HEADER_BUFFER_H
        BUF_MEM *bytes;
#else
        char *bytes;
#endif
        unsigned long hash; /* Keep the hash around for lookups */
        } X509_NAME;

The generic routines for new, free, and i2d/d2i conversion for X509_NAME are discussed in X.509 Certificate Substructures; the functions specific to X509_NAME only are described here.

X509_NAME_dup is actually a macro:

#define X509_NAME_dup(xn) 
  (X509_NAME *)ASN1_dup((int (*)())i2d_X509_NAME,(char *(*)())d2i_X509_NAME,
  (char *)xn)

It makes a copy of the X509_NAME structure that xn points to and returns it, or NULL on error.

X509_NAME_set duplicates name, frees *xn, and then sets *xn to point to the new structure. *xn must not be NULL on entry. I don't know why you're expected to malloc a new NAME structure to pass as an argument just so that it can be freed. Oh well. The function returns 1 on success or 0 on error (or if *xn is NULL).

X509_NAME_oneline converts the X509_NAME pointed to by a to a human-readable string. If a is NULL, the string "NO X509_NAME" is returned. Otherwise, the name is written into buf, up to size bytes of it, and a pointer to buf is returned.

If buf is NULL, then a new string will be allocated and a pointer to that will be returned.

Null is returned on error.

Each entry in the X509_NAME stack is checked for a NID; if there is no NID (we don't recognize the OID) then the OID is written out in numeric form. Otherwise, the short name (sn) of the entry is written out. Then '=' is written, followed by the string value of the entry. A dividing '/' is written between entries. An example follows:

/C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Server test cert

X509_NAME_cmp returns an integer less than, equal to, or greater than zero, depending on whether a is less than, equal to, or greater than b. First, the number of entries in each stack is compared; then, the entries themselves are compared, first by length and then by a byte-by-byte comparison.

X509_NAME_hash converts x to DER-encoded form, computes an MD5 digest of it, and returns the first four bytes of the digest in an unsigned long.

X509_NAME_print calls X509_NAME_oneline to convert name to a human-readable string and then writes it out to bp, substituting commas for the dividing slash. An example appears below.

C=AU, ST=Queensland, O=CryptSoft Pty Ltd, CN=Test CA

1 is returned on success or 0 on error.

X509_NAME_entry_count returns the number of entries in the stack name, or 0 if name is NULL.

/* NOTE: you should be passsing -1, not 0 as lastpos. The functions that use * lastpos, seach after that position on. */ X509_NAME_get_index_by_OBJ searches through the stack name, starting *after* the lastposth element in the stack, until it finds one with the same nid/sn/ln/oid as obj.

If you want to search the entire stack, pass -1 for lastpos so that the search will start from the 0th element.

The function returns the number of the matching element, or -1 if there was no match.

X509_NAME_get_index_by_NID does exactly what X509_NAME_get_index_by_OBJ does, except that you pass it nid instead of obj, and the function calls OBJ_nid2obj to get an object from the nid.

X509_NAME_get_text_by_OBJ calls X509_NAME_get_index_by_OBJ to find the number of the stack entry which has sn/ln/nid/oid matching that of obj; assuming that one is found, the string data part of the entry is copied into buf, which must be big enough to hold it. The number of bytes written is returned.

If buf is NULL then no data is copied and the size of the data is returned, so that you can call this function once with NULL to get the length, malloc buf to the right size, and then call it again to get the actual data.

X509_NAME_get_text_by_NID does exactly what X509_NAME_get_text_by_OBJ does, except that you pass it nid instead of obj, and the function calls OBJ_nid2obj to get an object from the nid.

X509_NAME_get_entry returns a pointer to the locth element of the stack name, properly typecast as an X509_NAME_ENTRY.

X509_NAME_delete_entry deletes the locth entry of the stack name and returns a pointer to the data just in case you want to do something else with it.

If the stack was NULL, or doesn't contain a locth element, then NULL is returned.

X509_NAME_add_entry adds the X509_NAME_ENTRY ne to the stack name, based on the following obscure algorithm:

If loc is less than 0 or greater than the number of elements on the stack, it is reset to the number of elements on the stack.

The new entry is always inserted before the locth element of the stack (or at the end, if loc points to the end of the stack)

If set is -1, then this new entry is appended to the previous set, which if it goes at the beginning of the stack means it gets set number 0 and the rest get incremented, if it goes in the middle or at the end then it gets the set number of the element previous to it. The other elements of the stack are unchanged.

If set is 0, then this new entry is a set all its own, which if it goes at the beginning of the stack means it gets set number 0 and the rest get incremented, if it goes in the middle then it steals the set number of the one it displaces and the rest get their set numbers incremented, and if it goes at the end, it gets the next unused integer for a set number.

If set is 1, then this new entry is appended to the following set, which if it goes at the beginning of the stack means it gets set number 0, if it goes in the middle then it gets the set number of the one it displaces, and if it goes at the end, it gets the next unused integer for a set number. All other elements are unchanged.