Table of Contents


1. Certificate Handling Overview

By default we store the all the certificates in either files or series of hashed directories (where the hash is generated from the subject name appended with a unique number to handle any name clashes).

The format of the certificates can be any of:

By default the code we are shipping uses the directory and PEM-style encoding for the certificates contained therein.

1.1 Set Certificate Cache

 X509_add_cert_dir(char *dir,int type)

dir can be either a single directory or a colon separated list of directories. type must be one of

1.2 Add Certificate File

To add a certificate:

 X509_add_cert_file(char *file,int type)

file contains the certificate. type must be one of

For X509_FILETYPE_PEM the file can contain multiple certificates.

1.3 Set Certifying Authority Certificate Location

As part of the general struture used, you can specify the location from which to load "trusted" certifying authority certificates. The cerficates can either be in a single file or in a "hashed" directory.

All certificates loaded via this interface must be in PEM format as this function simply calls X509_add_cert_dir() and X509_add_cert_file().

 X509_load_verify_locations(char *file,char *dir)

Either of file or dir can be NULL.

The standard behaviour of using the locations as specified in rsa/location.h can be activated by using

 X509_set_default_verify_paths(void)

This loads certificates from the "standard" locations and from whatever the standard environment variables point to.

The default values in rsa/location.h are:

 #define SSL_CERT_DIR           "/usr/local/ssl/certs"
 #define SSL_CERT_FILE  "/usr/local/ssl/cert.pem"
 
 #define SSL_CERT_DIR_ENV       "SSL_CERT_DIR"
 #define SSL_CERT_FILE_ENV      "SSL_CERT_FILE"

Note: the verify and x509 utility programs use X509_set_default_verify_locations() so if you want different behaviour you will have to change the calls in those programs.


2. Certificate Verification Process

Certificate verification is controlled by ssl_set_verify. This sets the verify mode and the optional callback function.

 void ssl_set_verify(SSL *s,int mode, int (*callback)() )

Supported modes are:

If SSL_VERIFY_PEER then the server will request a certificate from the client during initial protocol negotiation. If the client does not provide one and SSL_FAIL_IF_NO_PEER_CERT is being used then the verification process will fail and the caller will be returned an error code from ssl_accept().

From the client point of view, if SSL_VERIFY_PEER is set then the client will verify the server's certificate.

The callback function can be used to control the entire certificate hierarchy trust policy. It is called after each attempted verification of a certificate - either because the certificate was received or a certificate was referenced during traversal of the Certifying Authority hierarchy.

 int (*callback)(int ok,X509 *subj_cert,X509 *issuer_cert,
                 int depth,int errorcode)

ok is set to 1 if the X509 certificate is syntactically "valid" and has been verified (i.e. the checksum is okay, date range correct, etc). The callback function can return either 1 to accept, or 0 to reject - i.e. the return value would have been ok if there was no callback function registered.

subj_cert is the certificate of the subject

issuer_cert is the certificate of the issuer (the signer of the subjects certificate). It may be NULL (if there is an error).

depth is the recursion depth. A depth of 1 indicates that you are attempting to verify the issuer of the subjects certificate. If you do not wish to traverse the CA hierarchy simply return 1 when the depth is greater than or equal to 1.

errorcode is one of the VERIFY_ERR_ defines from rsa/X509.h. VERIFY_OK indicates that there is no error.

TODO: There are lots of X509 interface routines that you will have to look at if you actually want to do anything useful with certificates :-)

Have a look at rsa/verify.c for a decent example usage of this stuff.

The following are probably of the most imediate use in the callback function:

2.0.1 X509_get_issuer_name

Return the X509_NAME encoding for the issuer of this certificate.

 X509_NAME *X509_get_issuer_name(X509 *cert)

2.0.2 X509_get_subject_name

Return the X509_NAME encoding for the subject of this certificate.

 X509_NAME *X509_get_issuer_name(X509 *cert)

2.0.3 X509_oneline_X509_NAME

To turn a X509_NAME encoding into a "normal" string:

 char *X509_oneline_X509_NAME(X509_NAME *name)

It is the responsibility of the caller to free() the returned string.


3. Generating and Signing Certificates

There are five programs in the rsa directory that are required for generating and managing certificates.

The following two environment variables influence the behaviour of the certificate verification process in verify and x509.

It is considered a good idea for all implementations to standarise on usage of these environment variables.

3.1 genrsa

Used to generate RSA private keys.

 genrsa [-enc] [numbits] > key

Number of bits to make the RSA private key, default of 512. writes to stdout when finished, in PEM format. If the enc option is set you will be prompted for a pass phrase.

3.2 verify

To verify that a certificate is "okay"

 verify file1 [file2 ...]

verify will attempt to verify a certificate via either looking through a directory or simply a single file - this behaviour is compiled into the program and you really should decide what your "site" default for this is.

verify requires the arguments to be in PEM format and the lookup files also must be in PEM format.

You may want to tailor this program (or rsa/location.h as it has hard coded paths for the location for the certificates used to verify.

3.3 rsa

Convert keys from one format to another - i.e. rsa is a filter.

 rsa [-enc] [-inform format] [-outform format] [-in infile] [-out 
outfile]

Terse help is given on error. When a PEM format file is encountered you will be prompted for the pass phrase to encrypt/decrypt the private key if the enc option is used.

rsa can be used to change pass phrases by simply running


 rsa -enc <in >out

3.4 x509

x509 is the real key to the signing process and to managing certificates.

 x509
     [-inform format]
     [-outform format]
     [-keyform format]
     [-CAform format]
     [-CAkeyform format]
     [-in input-filename]
     [-out output-filename]
     [-signkey self-signing-key-filename]
     [-CA certifying-authority-certificate-filename]
     [-CAkey certifying-authority-key-filename]
     [-CAcreateserial]
 
 Output options:
     [-serial]     prints the serial number
     [-hash]       prints the hash vaulue used to dir lookups
     [-subject]    prints the cert's subject DN
     [-issuer]     prints the cert's issuer DN
     [-startdate]  prints the cert's notBefore field
     [-enddate]    prints the cert's notAfter field
     [-noout]      do not display the certificate

If a given input or output file format is not specified it defaults to PEM.

If the CAkey is not specified and the CAform is PEM (which is the default) then it is assumed that the CAkey is also stored in the CA certificate file.

The Output options generate output in the order in which they are specified on the command line.

If -signkey is set, the certificate has the public component of the key inserted and is signed with the private key. This is required so the certificate can be sent to a CA for certifying.

If the -CA flag is present, the certificate is certified/signed by the CAkey and has the issuer copied from the CA certificate. The date is also set and a file of the form CAkey filename.serial is updated and the new serial number is put in the certificate. Unless CAcreateserial is set the file will not be created or edited unless it is in the correct format.

The -signkey and -CA commands are processed in the same order as their command line arguments. Note that this means you will be prompted for the pass phrase for each in the order in which you specified them on the command line. The prompt however does indicate which pass phrase is required so you should read it.

3.5 make_cert

make_cert is a simple bit of perl code that can be used to generate a certificate skeleton. It asks a couple of simple questions and generates the skeleton in TEXT format.

So to make a certificate, assuming eay1024.PEM exists in your directory and is in the verify path, and it is your CA.

 # make the certificate
 genrsa 512 >mytest.key
 make_cert 2>mytest.text
 
 # to make it self signed
 x509 -inform TEXT -in mytest.text -signkey mytest.key > mytest.PEM
 
 # to sign it by a CA that you trust
 x509 -in mytest.PEM -CA cacert.PEM > mytest2.PEM
 cp mytest2.PEM mytest.PEM
 
 # to turn it into a CA certificate that you trust
 x509 -in mytest.PEM -CA mytest.PEM -CAkey mytest.key \
             -CAcreateserial > mytestca.PEM
 
 # clean up
 cat mytest.PEM mytest.key > mytest.cert
 /bin/rm mytest.key mytest.PEM mytest.text
 
 # verify it - assuming that the CA used in the x509 step is listed 
in
 # whatever verify has been compiled to look at or you have
 # set SSL_CERT_FILE to point to the CA used above
 
 verify mytest.cert

Note: A CA certificate is simply a self-signed certificate so you can generate your own rather easily as outlined above. To add a certificate to the hash directory setup simply find out it's hash and copy it to the directory.

 HASH=`x509 -noout -in mytest.cert -hash`
 cp mytest.cert /usr/local/ssl/certs/$HASH.0

To check what is inside a PEM certificate you probably will want to use:

 x509 -noout -subject -issuer -enddate < filename

3.6 der_parse

Prints the DER structure of the file.

 der_parse
   -inform [PEM|DER]
   -in <file>