X509_CRL Handling -- SSLeay 0.9.0b -- January 1999

NAME

X509_CRL_new, X509_CRL_free, X509_CRL_dup, i2d_X509_CRL, d2i_X509_CRL,
d2i_X509_CRL_fp, i2d_X509_CRL_fp, d2i_X509_CRL_bio, i2d_X509_CRL_bio,
X509_CRL_verify, X509_CRL_sign, X509_CRL_get_ext_count, X509_CRL_get_ext_by_NID,
X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext_by_critical, X509_CRL_get_ext,
X509_CRL_delete_ext, X509_CRL_add_ext, X509_CRL_cmp, X509_CRL_INFO_new,
X509_CRL_INFO_free, i2d_X509_CRL_INFO, d2i_X509_CRL_INFO -- X509_CRL Handling

SYNOPSIS

#include "x509.h"

X509_CRL *X509_CRL_new();

void X509_CRL_free(a)
X509_CRL *a;

int X509_CRL_get_ext_count(x)
X509_CRL *x;

int X509_CRL_get_ext_by_NID(x, nid, lastpos)
X509_CRL *x;
int nid;
int lastpos;

int X509_CRL_get_ext_by_OBJ(x, obj, lastpos)
X509_CRL *x;
ASN1_OBJECT *obj;
int lastpos;

int X509_CRL_get_ext_by_critical(x, crit, lastpos)
X509_CRL *x;
int crit;
int lastpos;

X509_EXTENSION *X509_CRL_get_ext(x, loc)
X509_CRL *x;
int loc;

X509_EXTENSION *X509_CRL_delete_ext(x, loc)
X509_CRL *x;
int loc;

int X509_CRL_add_ext(x, ex, loc)
X509_CRL *x;
X509_EXTENSION *ex;
int loc;

int X509_CRL_cmp(a, b)
X509_CRL *a;
X509_CRL *b;

X509_CRL_INFO *X509_CRL_INFO_new();

void X509_CRL_INFO_free(a)
X509_CRL_INFO *a;

int i2d_X509_CRL_INFO(a, pp)
X509_CRL_INFO *a;
unsigned char **pp;

X509_CRL_INFO *d2i_X509_CRL_INFO(a, pp, length)
X509_CRL_INFO **a;
unsigned char **pp;
long length;

int i2d_X509_CRL(a, pp)
X509_CRL *a;
unsigned char **pp;

X509_CRL *d2i_X509_CRL(a, pp, length)
X509_CRL **a;
unsigned char **pp;
long length;

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 certificate revocation list:

CertificateList ::=    SIGNED { SEQUENCE {
   version                Version  OPTIONAL, -- if present, shall be v2
   signature              AlgorithmIdentifier,
   issuer                 Name,
   thisUpdate             Time,
   nextUpdate             Time OPTIONAL,
   revokedCertificates    SEQUENCE OF SEQUENCE {
   userCertificate        CertificateSerialNumber,
   revocationDate         Time,
   crlEntryExtensions     EntryExtensions OPTIONAL } OPTIONAL,
   crlExtensions          [0]   CRLExtensions OPTIONAL }}

CRLExtensions        ::=        SEQUENCE SIZE (1..MAX) OF CRLExtension

CRLExtension         ::=        SEQUENCE {
   extnId            EXTENSION.&id ({CRLExtensionSet}),
   critical          BOOLEAN DEFAULT FALSE,

   extnValue         OCTET STRING }
                -- contains a DER encoding of a value of type
                -- &ExtnType for the
                -- extension object identified by extnId --

-- The following information object set is defined to constrain the
-- set of legal CRL extensions.

CRLExtensionSet EXTENSION       ::=     { authorityKeyIdentifier |
                                        issuerAltName |
                                        cRLNumber |
                                        deltaCRLIndicator |
                                        issuingDistributionPoint }

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

typedef struct X509_crl_info_st
        {
        ASN1_INTEGER *version;
        X509_ALGOR *sig_alg;
        X509_NAME *issuer;
        ASN1_UTCTIME *lastUpdate;
        ASN1_UTCTIME *nextUpdate;
        STACK /* X509_REVOKED */ *revoked;
        STACK /* [0] X509_EXTENSION */ *extensions;
        } X509_CRL_INFO;

typedef struct X509_crl_st
        {
        /* actual signature */
        X509_CRL_INFO *crl;
        X509_ALGOR *sig_alg;
        ASN1_BIT_STRING *signature;
        int references;
        } X509_CRL;

typedef struct X509_revoked_st
        {
        ASN1_INTEGER *serialNumber;
        ASN1_UTCTIME *revocationDate;
        STACK /* optional X509_EXTENSION */ *extensions;
        int sequence; /* load sequence */
        } X509_REVOKED;

typedef struct X509_extension_st
        {
        ASN1_OBJECT *object;
        short critical;
        short netscape_hack;
        ASN1_OCTET_STRING *value;
        long argl;                      /* used when decoding */
        char *argp;                     /* used when decoding */
        void (*ex_free)();              /* clear argp stuff */
        } X509_EXTENSION;

Treating the certificate revocation list as a more-or-less opaque type, we have the following operations we can perform on it:

make a new one, free an old one, copy it

X509_CRL_new, X509_CRL_free, X509_CRL_dup

convert it to/from DER-encoded form

i2d_X509_CRL, d2i_X509_CRL

write it to a file, or read it from a file, either in DER-encoded form or in human-readable text or in PEM (base64-encoded) form

d2i_X509_CRL_fp, i2d_X509_CRL_fp, d2i_X509_CRL_bio, i2d_X509_CRL_bio, PEM_write_bio_X509_CRL, PEM_write_X509_CRL, PEM_read_bio_X509_CRL, PEM_read_X509_CRL

verify it, sign it

X509_CRL_verify, X509_CRL_sign,

There is also a collection of functions that deal with X.509v3 extensions, determining how many there are, which ones are critical, what each one actually it, adding them and deleting them to the cerificate revocation list

X509_CRL_get_ext_count, X509_CRL_get_ext_by_NID, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext_by_critical, X509_CRL_get_ext, X509_CRL_delete_ext, X509_CRL_add_ext

And finally there is a a routine that compares two CRLs:

X509_CRL_cmp

and a collection of routines that deal with the X509_CRL_INFO structure:

X509_CRL_INFO_new, X509_CRL_INFO_free, i2d_X509_CRL_INFO, d2i_X509_CRL_INFO

We'll look at each of these in turn.

X509_CRL_new creates a new X509_CRL structure and returns a pointer to it; if memory cannot be allocated it returns NULL.

X509_CRL_free frees the memory of the X509_CRL structure pointed to by x, unless the argument is NULL, in which case it does nothing.

X509_CRL_dup is actually a macro:

#define X509_CRL_dup(crl) 
  (X509_CRL *)ASN1_dup((int (*)())i2d_X509_CRL,(char *(*)())d2i_X509_CRL,(char *)crl)

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

i2d_X509_CRL converts an X509_CRL structure pointed to by a to DER-encoded form; it places the results in *pp and then increments *pp to point to the end of the byte string it has just written, so you can call several i2d functions in a row. It returns the number of bytes written to the string or 0 on error.

See ASN.1 conversion to and from DER-encoded form for more on i2d functions.

d2i_X509_CRL converts length bytes of the DER-encoded string in *pp to an X509_CRL structure, updates *pp to point to the next byte to be processed, places the new X509_CRL structure in *a, and returns it, or NULL on error.

See ASN.1 conversion to and from DER-encoded form for more on d2i functions.

The following macros are provided for the convenience of the user:

#define d2i_X509_CRL_fp(fp,crl)
  (X509_CRL *)ASN1_d2i_fp((char *(*)()) \
                X509_CRL_new,(char *(*)())d2i_X509_CRL, (fp),\
                (unsigned char **)(crl))

#define i2d_X509_CRL_fp(fp,crl) 
  ASN1_i2d_fp(i2d_X509_CRL,fp,(unsigned char *)crl)

#define d2i_X509_CRL_bio(bp,crl) 
  (X509_CRL *)ASN1_d2i_bio((char *(*)()) X509_CRL_new,
  (char *(*)())d2i_X509_CRL, (bp),(unsigned char **)(crl))

#define i2d_X509_CRL_bio(bp,crl) 
  ASN1_i2d_bio(i2d_X509_CRL,bp,(unsigned char *)crl)

d2i_X509_CRL_fp reads from fp as much data as it can, in DER-encoded form, and then uses d2i_X509_CRL to translate that into an X509_CRL structure, which is placed in crl if that argument is not NULL, or into a newly malloced structure otherwise. A pointer to the populated structure is returned, or NULL on error.

i2d_X509_CRL_fp converts the X509_CRL structure pointed to by crl to DER-encoded form and writes it out to the file pointer fp.

It returns 1 on success and 0 on error.

d2i_X509_CRL_bio does exactly what d2i_X509_CRL_fp does, except that it reads from a BIO instead of a file pointer.

i2d_X509_CRL_bio does exactly what i2d_X509_CRL_fp does, except that it writes to a BIO instead of a file pointer.

X509_CRL_print_fp translates the X509_CRL structure crl into human-readable format and writes the result to the file pointer fp. It returns 1 on success or 0 on error.

It uses a fixed format to display the certificate revocation list information. An example is below:


X509_CRL_print does exactly the same thing as X509_CRL_print_fp, except that it writes to a BIO instead of a file pointer.

The following macros are provided for the convenience of the user:

#define PEM_write_X509_CRL(fp,x)
  PEM_ASN1_write((int (*)())i2d_X509_CRL,PEM_STRING_X509_CRL,
  fp,(char *)x, NULL,NULL,0,NULL)

#define PEM_write_bio_X509_CRL(bp,x) 
  PEM_ASN1_write_bio((int (*)())i2d_X509_CRL,PEM_STRING_X509_CRL,
  bp,(char *)x, NULL,NULL,0,NULL)

#define PEM_read_X509_CRL(fp,x,cb)
  (X509_CRL *)PEM_ASN1_read((char *(*)())d2i_X509_CRL,PEM_STRING_X509_CRL,
  fp,(char **)x,cb)

#define PEM_read_bio_X509_CRL(bp,x,cb) 
  (X509_CRL *)PEM_ASN1_read_bio((char *(*)())d2i_X509_CRL,PEM_STRING_X509_CRL,
  bp,(char **)x,cb)

PEM_write_X509_CRL converts the X509_CRL structure pointed to by x to DER-encoded form. The data is then base64-encoded and written out to fp with BEGIN X509 CRL and END headers around it. 1 is returned on success, or 0 on error.

PEM_write_bio_X509_CRL does the same thing as PEM_write_X509_CRL except that it uses a BIO instead of a FILE.

PEM_read_X509_CRL reads a PEM-encoded X509 certificate revocation list from the file fp using PEM_read; calls PEM_get_EVP_CIPHER_INFO to process any DEK-Info header that might be present, in particular determining the cipher that was used to encrypt the message body and retrieving the ivec from the header; calls PEM_do_header to decrypt the message body if it was encrypted (see the description of that function in PEM library routines for details about how a pass phrase (key string) is retrieved from the user, using the callback cb, or retrieved from somewhere else); and then converts it to an X509_CRL structure and places the result in x.

It then returns a pointer to that structure, or NULL on error.

The file must contain a BEGIN X509 CRL header or it will not be parsed properly.

Note that since this function calls PEM_get_EVP_CIPHER_INFO, the appropriate cipher type (according to the name that is present in the PEM header) must be loaded into the static cipher and possibly static alias stack in order for the function to succeed; EVP cipher/digest lookup routines for more on this. Ordinaily this will not be a problem, since the certificate revocation list will not have been written out in encrypted form.

This function can be used to read a list of crls from a file.

PEM_read_bio_X509_CRL does the same thing as PEM_X509_CRL_read but uses a BIO instead of a file pointer.

The following macros are provided for the convenience of the user:

#define X509_CRL_verify(a,r) 
  ASN1_verify((int (*)())i2d_X509_CRL_INFO,a->sig_alg, a->signature,
  (char *)a->crl,r)

#define X509_CRL_sign(x,pkey,md)
  ASN1_sign((int (*)())i2d_X509_CRL_INFO,x->crl->sig_alg,x->sig_alg,
  x->signature, (char *)x->crl,pkey,md)

X509_CRL_verify converts the X509_CRL structure a to DER-encoded form; computes the message digest of it, using a->sig_alg as the message digest algorithm; signs it using r as the key for signing; and finally compares the results against a->signature. 1 is returned if they match, 0 on failure or error.

This function actually just calls ASN1_verify, which calls EVP_VerifyInit, EVP_VerifyUpdate, and EVP_VerifyFinal; see EVP digest handling, signing, verification if you want details on these functions.

NOTE: this routine calls the dreaded EVP_get_digestbyname() which means that the static digest and alias stacks must be initialized; see EVP cipher/digest lookup routines for more on this.

X509_CRL_sign sets both x->crl->sig_alg and x->sig_alg to hold the appropriate information for the algorithm md->pkey_type, which might be for example NID_shaWithRSAEncryption. Then it converts x->crl to DER-encoded form, uses the digest algorithm specified by type to compute a message digest of the DER-encoded string and uses the pkey to sign it. The result is placed in x->signature->data with the length in x->signature->length. That same length is returned to the caller, or 0 on error.

This function actually just calls ASN1_sign, which calls EVP_SignInit, EVP_SignUpdate, and EVP_SignFinal; see EVP digest handling, signing, verification if you want details on these functions.

The following functions all rely on X509v3_* functions that manipulate extenstions; see X.509 Extension Handling for details on these.

X509_CRL_get_ext_count just calls X509v3_get_ext_count on the extenstions subfield of x.

X509_CRL_get_ext_by_NID just calls X509v3_get_ext_by_NID on the extension subfield of x, passing the other arguments through unchanged.

X509_CRL_get_ext_by_OBJ just calls X509v3_get_ext_by_OBJ on the extension subfield of x, passing the other arguments through unchanged.

X509_CRL_get_ext_by_critical just calls X509v3_get_ext_by_critical on the extension subfield of x, passing the other arguments through unchanged.

X509_CRL_get_ext just calls X509v3_get_ext on the extension subfield of x, passing the other argument through unchanged.

X509_CRL_delete_ext just calls X509v3_delete_ext on the extension subfield of x, passing the other argument through unchanged.

X509_CRL_add_ext just calls X509v3_add_ext on the extension subfield of x, passing the other arguments through unchanged.

X509_CRL_cmp returns an integer less than, equal to, or greater than zero depending on whether the issuer name in a is less than, equal to, or greater than the issuer name in b.

This function calls X509_NAME_cmp to do the comparison.

X509_CRL_INFO_new creates a new X509_CRL_INFO structure and returns a pointer to it; if memory cannot be allocated it returns NULL.

X509_CRL_INFO_free frees the memory of the X509_CRL_INFO structure pointed to by x, unless the argument is NULL, in which case it does nothing.

i2d_X509_CRL_INFO converts an X509_CRL_INFO structure pointed to by a to DER-encoded form; it places the results in *pp and then increments *pp to point to the end of the byte string it has just written, so you can call several i2d functions in a row. It returns the number of bytes written to the string or 0 on error.

See ASN.1 conversion to and from DER-encoded form for more on i2d functions.

d2i_X509_CRL_INFO converts length bytes of the DER-encoded string in *pp to an X509_CRL_INFO structure, updates *pp to point to the next byte to be processed, places the new X509_CRL_INFO structure in *a, and returns it, or NULL on error.

See ASN.1 conversion to and from DER-encoded form for more on d2i functions.