X509 Certificate Handling -- SSLeay 0.9.0b -- January 1999

NAME

X509_new, X509_free, X509_dup, i2d_X509, d2i_X509, d2i_X509_fp, i2d_X509_fp,
d2i_X509_bio, i2d_X509_bio, X509_print_fp, X509_print, PEM_write_bio_X509,
PEM_write_X509, PEM_read_bio_X509, PEM_read_X509, X509_verify, X509_sign,
X509_digest, X509_get_version, X509_get_serialNumber, X509_get_notBefore,
X509_get_notAfter, X509_get_issuer_name, X509_get_subject_name,
X509_set_version, X509_set_serialNumber, X509_set_issuer_name,
X509_set_subject_name, X509_set_notBefore, X509_set_notAfter,
X509_issuer_and_serial_cmp, X509_issuer_name_cmp, X509_subject_name_cmp,
X509_issuer_and_serial_hash, X509_issuer_name_hash, X509_subject_name_hash,
X509_find_by_issuer_and_serial, X509_find_by_subject,
X509_get_ext_count, X509_get_ext_by_NID, X509_get_ext_by_OBJ,
X509_get_ext_by_critical, X509_get_ext, X509_delete_ext, X509_add_ext,
X509_extract_key, X509_get_pubkey, X509_set_pubkey, X509_check_private_key,
X509_get_signature_type, X509_certificate_type, X509_CINF_new, X509_CINF_free,
i2d_X509_CINF, d2i_X509_CINF -- X509 Certificate Handling

SYNOPSIS

#include "x509.h"

X509 *X509_new();

void X509_free(x)
X509 *x;

int i2d_X509(a, pp)
X509 *a;
unsigned char **pp;

X509 *d2i_X509(a, pp, length)
X509 **a;
unsigned char **pp;
long length;

int X509_print_fp(fp, x)
FILE *fp;
X509 *x;

int X509_print(bp, x)
BIO *bp; X509 *x;

X509_NAME *X509_get_issuer_name(a)
X509 *a;

X509_NAME *X509_get_subject_name(a)
X509 *a;

int X509_set_version(x, version)
X509 *x;
long version;

int X509_set_serialNumber(x, serial)
X509 *x;
ASN1_INTEGER *serial;

int X509_set_issuer_name(x, name)
X509 *x;
X509_NAME *name;

int X509_set_subject_name(x, name)
X509 *x;
X509_NAME *name;

int X509_set_notBefore(x, tm)
X509 *x;
ASN1_UTCTIME *tm;

int X509_set_notAfter(x, tm)
X509 *x;
ASN1_UTCTIME *tm;

int X509_issuer_and_serial_cmp(a, b)
X509 *a, *b;

int X509_issuer_name_cmp(a, b)
X509 *a, *b;

int X509_subject_name_cmp(a, b)
X509 *a, *b;

unsigned long X509_issuer_and_serial_hash(a)
X509 *a;

unsigned long X509_issuer_name_hash(a)
X509 *a;

unsigned long X509_subject_name_hash(a)
X509 *x;

X509 *X509_find_by_issuer_and_serial(sk, name, serial)
STACK *sk;
X509_NAME *name;
ASN1_INTEGER *serial;

X509 *X509_find_by_subject(sk, name)
STACK *sk;
X509_NAME *name;

int X509_get_ext_count(x)
X509 *x;

int X509_get_ext_by_NID(x, nid, lastpos)
X509 *x;
int nid;
int lastpos;

int X509_get_ext_by_OBJ(x, obj, lastpos)
X509 *x;
ASN1_OBJECT *obj;
int lastpos;

int X509_get_ext_by_critical(x, crit, lastpos)
X509 *x;
int crit;
int lastpos;

X509_EXTENSION *X509_get_ext(x, loc)
X509 *x;
int loc;

X509_EXTENSION *X509_delete_ext(x, loc)
X509 *x;
int loc;

int X509_add_ext(x, ex, loc)
X509 *x;
X509_EXTENSION *ex;
int loc;

EVP_PKEY *X509_get_pubkey(x)
X509 *x;

int X509_set_pubkey(x, pkey)
X509 *x;
EVP_PKEY *pkey;

int X509_check_private_key(x509, pkey)
X509 *x509;
EVP_PKEY *pkey;

int X509_certificate_type(x, pubkey)
X509 *x;
EVP_PKEY *pubkey;

X509_CINF *X509_CINF_new();

void X509_CINF_free(a)
X509_CINF *a;

int i2d_X509_CINF(a, pp)
X509_CINF *a;
unsigned char **pp;

X509_CINF *d2i_X509_CINF(a, pp, length)
X509_CINF **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 itself:

Certificate  ::=  SEQUENCE  {
     tbsCertificate       TBSCertificate,
     signatureAlgorithm   AlgorithmIdentifier,
     signature            BIT STRING  }

TBSCertificate  ::=  SEQUENCE  {
     version         [0]  Version DEFAULT v1,
     serialNumber         CertificateSerialNumber,
     signature            AlgorithmIdentifier,
     issuer               Name,
     validity             Validity,
     subject              Name,
     subjectPublicKeyInfo SubjectPublicKeyInfo,
     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version shall be v2 or v3
     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version shall be v2 or v3
     extensions      [3]  Extensions OPTIONAL
                          -- If present, version shall be v3 --  }

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

typedef struct x509_cinf_st
        {
        ASN1_INTEGER *version;          /* [ 0 ] default of v1 */
        ASN1_INTEGER *serialNumber;
        X509_ALGOR *signature;
        X509_NAME *issuer;
        X509_VAL *validity;
        X509_NAME *subject;
        X509_PUBKEY *key;
        ASN1_BIT_STRING *issuerUID;             /* [ 1 ] optional in v2 */
        ASN1_BIT_STRING *subjectUID;            /* [ 2 ] optional in v2 */
        STACK /* X509_EXTENSION */ *extensions; /* [ 3 ] optional in v3 */
        } X509_CINF;

typedef struct x509_st
        {
        X509_CINF *cert_info;
        X509_ALGOR *sig_alg;
        ASN1_BIT_STRING *signature;
        int valid;
        int references;
        char *name;
        } X509;

Treating the certificate 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_new, X509_free, X509_dup

convert it to/from DER-encoded form

i2d_X509, d2i_X509

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_fp, i2d_X509_fp, d2i_X509_bio, i2d_X509_bio, X509_print_fp, X509_print, PEM_write_bio_X509, PEM_write_X509, PEM_read_bio_X509, PEM_read_X509

verify it, sign it, get the digest of it,

X509_verify, X509_sign, X509_digest,

If we want to deal with the subfields of the structure instead, we can

retrieve a pointer to any of them

X509_get_version, X509_get_serialNumber, X509_get_notBefore, X509_get_notAfter, X509_get_issuer_name, X509_get_subject_name

stuff any of them with a value or structure of our choice

X509_set_version, X509_set_serialNumber, X509_set_issuer_name, X509_set_subject_name, X509_set_notBefore, X509_set_notAfter

compare subfields of two of them

X509_issuer_and_serial_cmp, X509_issuer_name_cmp, X509_subject_name_cmp

We also have a few functions that deal with verifying this certificate against some internal list we have, either by creating a key by which it can be indexed in our list, or trying to retrieve it from our list

X509_issuer_and_serial_hash, X509_issuer_name_hash, X509_subject_name_hash, X509_find_by_issuer_and_serial, X509_find_by_subject

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

X509_get_ext_count, X509_get_ext_by_NID, X509_get_ext_by_OBJ, X509_get_ext_by_critical, X509_get_ext, X509_delete_ext, X509_add_ext

And finally there is a collection of routines that deal with the public or private key associated with the certificate on a more detailed level

X509_extract_key (=X509_get_pubkey), X509_get_pubkey, X509_set_pubkey, X509_check_private_key

and a couple of routines that get other detailed information about the certificate by prying it out of complex substructures:

X509_get_signature_type, X509_certificate_type

We'll look at each of these in turn.

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

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

X509_dup is actually a macro:

#define X509_dup(x509) (X509 *)ASN1_dup((int (*)())i2d_X509, 
    (char *(*)())d2i_X509,(char *)x509)

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

i2d_X509 converts an X.509 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 converts length bytes of the DER-encoded string in *pp to an X509 structure, updates *pp to point to the next byte to be processed, places the new X509 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_fp(fp,x509) 
  (X509 *)ASN1_d2i_fp((char *(*)())X509_new, 
  (char *(*)())d2i_X509, (fp),(unsigned char **)(x509))

#define i2d_X509_fp(fp,x509) 
  ASN1_i2d_fp(i2d_X509,fp,(unsigned char *)x509)

#define d2i_X509_bio(bp,x509) 
  (X509 *)ASN1_d2i_bio((char *(*)())X509_new, 
  (char *(*)())d2i_X509, (bp),(unsigned char **)(x509))

#define i2d_X509_bio(bp,x509) 
  ASN1_i2d_bio(i2d_X509,bp,(unsigned char *)x509)

d2i_X509_fp reads from fp as much data as it can, in DER-encoded form, and then uses d2i_X509 to translate that into an X509 structure, which is placed in x509 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_fp converts the X509 structure pointed to by x509 to DER-encoded form and writes it out to the file pointer fp.

It returns 1 on success and 0 on error.

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

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

X509_print_fp translates the X509 structure x 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 information. An example is below:

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 0 (0x0)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=AU, ST=Queensland, O=CryptSoft Pty Ltd, CN=Test CA (1024 bit)
        Validity
            Not Before: Jun  9 13:57:46 1997 GMT
            Not After : Jun  9 13:57:46 1998 GMT
        Subject: C=AU, ST=Queensland, O=CryptSoft Pty Ltd, CN=Server test cert (512 bit)
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (512 bit)
                Modulus (512 bit):
                    00:9f:b3:c3:84:27:95:ff:12:31:52:0f:15:ef:46:
                    11:c4:ad:80:e6:36:5b:0f:dd:80:d7:61:8d:e0:fc:
                    72:45:09:34:fe:55:66:45:43:4c:68:97:6a:fe:a8:
                    a0:a5:df:5f:78:ff:ee:d7:64:b8:3f:04:cb:6f:ff:
                    2a:fe:fe:b9:ed
                Exponent: 65537 (0x10001)
    Signature Algorithm: md5WithRSAEncryption
        78:4c:c4:76:0a:f6:9c:28:4f:70:02:cb:bd:8f:20:97:f1:88:
        96:9a:00:8c:f9:8a:0f:ea:4b:78:66:48:f6:cf:92:11:7e:6e:
        d6:af:27:0a:b2:7a:67:39:1f:ad:19:ea:80:8e:40:9e:67:af:
        f7:ea:8f:65:f7:54:6f:3e:73:75:54:9f:e2:c5:0b:f6:75:fd:
        0a:15:e3:2b:d3:42:24:0d:d4:cd:01:d2:16:a8:59:12:b1:94:
        c0:63:64:00:76:07:a7:6f:b3:01:d6:3a:1e:8e:ab:98:cc:ed:
        83:40:83:bb:fb:0a:47:8a:b3:9b:a4:44:b1:01:92:f2:48:29:
        8f:3e

X509_print does exactly the same thing as X509_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(fp,x) 
   PEM_ASN1_write((int (*)())i2d_X509,PEM_STRING_X509,fp,(char *)x, NULL,NULL,0,NULL)

#define PEM_write_bio_X509(bp,x) 
   PEM_ASN1_write_bio((int (*)())i2d_X509,PEM_STRING_X509,bp,(char *)x, NULL,NULL,0,NULL)

#define PEM_read_bio_X509(bp,x,cb) 
   (X509 *)PEM_ASN1_read_bio((char *(*)())d2i_X509,PEM_STRING_X509,bp,(char **)x,cb)

#define PEM_read_X509(fp,x,cb) 
   (X509 *)PEM_ASN1_read((char *(*)())d2i_X509,PEM_STRING_X509,fp,(char **)x,cb)

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

PEM_write_bio_X509 does the same thing as PEM_write_X509 except that it uses a BIO instead of a FILE.

PEM_read_X509 reads a PEM-encoded X509 certificate 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 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 CERTIFICATE 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 will not have been written out in encrypted form.

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

PEM_read_bio_X509 does the same thing as PEM_X509_read but uses a BIO instead of a file pointer.

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

#define X509_verify(a,r) 
  ASN1_verify((int (*)())i2d_X509_CINF,a->sig_alg,a->signature,(char *)a->cert_info,r)

#define X509_sign(x,pkey,md) 
   ASN1_sign((int (*)())i2d_X509_CINF, x->cert_info->signature,
       x->sig_alg, x->signature, (char *)x->cert_info,pkey,md)

#define X509_digest(data,type,md,len)
   ASN1_digest((int (*)())i2d_X509,type,(char *)data,md,len)

X509_verify converts the X509 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_sign sets both x->cert_info->signature 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->cert_info 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.

X509_digest converts the X509 structure a to DER-encoded form; computes the message digest of it, using as the message digest algorithm; and returns the results in md, with the length of the returned digest in len. 1 is returned on success, or 0 on error.

This function actually just calls ASN1_digest, which calls EVP_DigestInit, EVP_DigestUpdate, and EVP_DigestFinal; see EVP digest handling, signing, verification if you want details on these functions.

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

#define         X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version)
#define         X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
#define         X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)

X509_get_version translates the ASN1_INTEGER version subfield of the certificate pointed to by x, to a long and returns it.

X509_get_notBefore returns a pointer to the notBefore subfield of the certificate pointed to by x.

X509_get_notAfter returns a pointer to the notAfter subfield of the certificate pointed to by x.

X509_get_issuer_name returns a pointer to the issuer subfield of the certificate pointed to by a.

X509_get_subject_name returns a pointer to the subject subfield of the certificate pointed to by a.

X509_set_version translates the long version to an ASN1_INTEGER and stuffs it into the version subfield of the certificate pointed to by x. It returns 1 on success or 0 on error.

X509_set_serialNumber makes a copy of the ASN1_INTEGER pointed to by serial and stuffs it into the serialNumber subfield of the certificate pointed to by x. It returns 1 on success or 0 on error.

X509_set_issuer_name copies the X509_NAME pointed to by name into the issuer subfield of the certificate pointed to by x. It returns 1 on success or 0 on error.

X509_set_subject_name copies the X509_NAME pointed to by name into the subject subfield of the certificate pointed to by x. It returns 1 on success or 0 on error.

X509_set_notBefore copies the ASN1_UTCTIME structure pointed to by tm into the notBefore subfield of the certificate pointed to by x. It returns 1 on success or 0 on error.

X509_set_notAfter copies the ASN1_UTCTIME structure pointed to by tm into the notAfter subfield of the certificate pointed to by x. It returns 1 on success or 0 on error.

X509_issuer_and_serial_cmp returns an integer less than, equal to, or greater than zero, depending on whether the serial number and issuer of a are less than, equal to, or greater than the serial number and issuer of b. The serial numbers are checked first and only if those match are the issuers checked.

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

X509_subject_name_cmp returns an integer less than, equal to, or greater than zero, depending on whether the subject of a is less than, equal to, or greater than the issuer of b.

X509_issuer_and_serial_hash stuffs the X509_NAME issuer into one printable line and then computes the MD5 hash of it concatenated with the ASN1_INTEGER form of the serial number of a. It returns the first four bytes of the hash in an unsigned long.

This function is used in the library's routines which retrieve a certificate from a directory.

X509_issuer_name_hash converts the issuer name into DER-encoded form, applies an MD5 hash, and returns an unsigned long with the first four bytes of the hash.

X509_subject_name_hash converts the subject name into DER-encoded form, applies an MD5 hash, and returns an unsigned long with the first four bytes of the hash.

X509_find_by_issuer_and_serial searches the passed STACK sk of X509 structures and returns a pointer to the first one which has the same issuer and serial number as name and serial. If none do, NULL is returned. This function calls X509_issuer_and_serial_cmp.

X509_find_by_subject searches the passed STACK sk of X509 structures and returns a pointer to the first one which has the same subject as name. If none do, NULL is returned. This function calls X509_NAME_cmp.

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

X509_get_ext_count just calls X509v3_get_ext_count on the extenstions subfield of x.

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

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

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

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

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

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

The following functions all manipulate keys associated with an X509 certificate. See X.509 Certificate Subfields Handling for more details on the functions they call.

The following macro is provided for the convenience of the user:

#define X509_extract_key(x)     X509_get_pubkey(x) /*****/

X509_get_pubkey calls X509_PUBKEY_get on x->cert_info->key to extract the public key from the certificate and turn it into an EVP_PKEY which can be used for encryption with EVP routines. See Overview of EVP interfaces for a discussion of the EVP library.

The EVP_PKEY structure is cached in the X509 structure for later use as well. If this function is called again, a pointer to the cached copy is used rather than doing the conversion again.

It returns a pointer to the EVP_PKEY or NULL on error.

X509_set_pubkey calls X509_PUBKEY_set to convert the EVP_PKEY structure pointed to by pkey to DER-encoded form and stuff it and its various subfields into x->cert_info->key as appropriate. It returns 1 on success and 0 on error.

X509_check_private_key checks to see if the private key stored in pkey is the same as that stored in key xk->pkey; if it is, 1 is returned, else 0 is returned.

Note that this function always fails if a DH key is passed in pkey.

This function is called indirectly by SSL_use_RSAPrivateKey.

The following macro is provided for the convenience of the user:

#define X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm))

This just translates the x->sig_alg->algorithm field to a NID.

See EVP public/private key handling for more on the function it invokes.

X509_certificate_type returns a collection of flags that describe the kind of key pubkey is and what it can be used for. It also calls X509_get_signature_type on x and adds that information to the flags. Types include:

EVP_PK_RSA    RSA key
EVP_PK_DSA    DSA key
EVP_PK_DH     DH key
EVP_PKT_SIGN  key used for signing 
EVP_PKT_ENC   key used for encryption
EVP_PKT_EXCH  key used for (symmetric) key exchange
EVP_PKS_RSA   signature done with RSA
EVP_PKS_DSA   signature done with DSA
EVP_PKT_EXP   key is <= 512 bits long (exportable)

If pubkey is NULL, x->pkey will be transformed into an EVP_PKEY and that will be used instead.

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

X509_CINF_free frees the memory of a unless the argument is NULL, in which case it does nothing.

int i2d_X509_CINF(a, pp)
converts an X509_CINF 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_CINF converts length bytes of the DER-encoded string in *pp to an X509_CINF structure, updates *pp to point to the next byte to be processed, places a pointer to the new 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.