EVP_add_cipher() -- SSLeay 0.9.0b -- January 1999

NAME

EVP_add_cipher, EVP_get_cipherbyname, EVP_add_digest, EVP_get_digestbyname,
EVP_add_alias, EVP_delete_alias, EVP_cleanup -- EVP cipher/digest lookup routines

SYNOPSIS

#include "evp.h"

int EVP_add_cipher(cipher)
EVP_CIPHER *cipher;

EVP_CIPHER *EVP_get_cipherbyname()
char *name;

int EVP_add_digest(digest)
EVP_MD *digest;

EVP_MD *EVP_get_digestbyname(name)
char *name;

int EVP_add_alias(name, alias)
char *name, *alias;

int EVP_delete_alias(name)
char *name;

void EVP_cleanup();

DESCRIPTION

There are three static STACKs referenced by the EVP routines:

ciphers, a stack of EVP_CIPHER (see EVP handling for symmetric ciphers for the definition of this structure);

digests, a stack of EVP_MD (see EVP digest handling, signing, verification for the definition of this structure); and

aliases, a stack of ALIASES, where the ALIAS structure is defined as:

typedef struct aliases_st {
   char *alias;
   /* This must be the last field becaue I will allocate things
    * so they go off the end of it */
   char name[4];
} ALIASES;

The cipher stack and the digest stack have nids for indices (treated as a char * string) the alias stack has the short name 'sn' for the cipher or digest as the alias and the value is the concatenation of the sn with the long name 'ln'. See the section on Objects for more about sn, ln, and so on. An example, though, is

#define SN_rc4                          "RC4"
#define LN_rc4                          "rc4"
#define NID_rc4                         5

Ok, so the short name is not necessarily that much shorter :)

EVP_add_alias expects name to be the ln, and alias to be the sn. It then concatenates them and stuffs a pointer to the result into the aliases stack if it is not already there.

EVP_add_cipher just stuffs a pointer to the particular EVP_CIPHER structure on the cipher stack if it is not already there.

EVP_add_digest stuffs a pointer to the particular EVP_DIGEST structure on the digest stack if it is not already there. It also, as an added bonus, calls EVP_add_alias with sn = OBJ_nid2sn(md->pkey_type) and ln = OBJ_nid2sn(md->type) AND ln = OBJ_nid2ln(md->type) (two separate calls with the same sn). So for example, for md5, we would get the aliases:

sn of NID_md5WithRSAEncryption mapped to sn of NID_md5, which translates to: RSA-MD5 mapped to MD5

sn of NID_md5WithRSAEncryption mapped to ln of NID_md5, which translates to: RSA-MD5 mapped to md5

EVP_get_cipherbyname expects name to be either the sn of the cipher or the real name. It first tries to find a stack entry which starts with the sn; if it finds one then it takes the rest of the ery to be the real name and uses that in place of name for the next step. Now it converts the name to a nid, tries to find an entry in the cipher stack that points to an EVP_CIPHER structure which has that nid as the nid subfield, and returns that entry.

Note that if the cipher stack is empty or the nid is undefined, NULL will be returned.

So this is basically a complicated way to get from a fixename for a cipher to an EVP_CIPHER structure with the init, update and final functions and other useful goodies.

What is the point of having these stacks and these routines to fill them?

The idea then is that you can choose to load only certain ciphers or digests into the stacks in your code, and then only those ciphers or digests are linked into your program. If you passed an integer that specified which cipher or digest to use, the routine that mapped that integer to a set of cipher or digest functions would cause all of the ciphers or digests to be linked into the code.

Now, the down side of this...

Here, you need to know a little about the SSL routines.

Any SSL connection needs at least an SSL structure; you get one of these by calling SSL_new, which calls an internal routine ssl_create_cipher_list, which, if the cipher list for SSL has not been initialized (it checks a flag to see) calls load_ciphers. That routine in turn calls EVP_get_cipherbyname on the following cipher SNs:

SN_des_cbc, SN_des_ede3_cbc, SN_rc4, SN_rc2_cbc, SN_idea_cbc

For each one of these that is gotten successfully, an appropriate element in the static array ssl_cipher_methods[] is set to the particular EVP_CIPHER.

After load_ciphers completes, ssl_create_cipher_list looks at a default list of ciphers according to the ssl method being used, gets rid of the ones in the list that aren't in the ssl_cipher_methods array, and eventually uses the rest to set up a stack of algorithms available; this is then returned to SSL_new.

If the stack returned is NULL, SSL_new complains with this error:

"library has no ciphers"

Look familiar? That's what you get if you haven't loaded up the cipher and alias stacks with those ciphers previously.

PEM does the same thing when it processes a file (PEM_read_bio); if it sees a DEK-Info header it needs to be able to use the name provided to look up the EVP_CIPHER structure and so it calls EVP_get_cipherbyname too.

Now, we said that the point of not having a prefedined static array was that then you can choose which algorithms to load in so that you don't load them all in and have a huge bloated binary. but how does this work when you don't know in advance which cipher you are going to read for PEM? Or when SSL_CTX_new knows it needs those five particular ciphers? Well, you just have to know to preload those. If your code is going to handle PEM messages with certain algorithms used, it has to have the code compiled in. And you have to decide in advance which algorithms you're going to support. Makes sense when you think about it that way, eh?

But if this is too much of a pain, just call SSLeay_add_all_algorithms which adds all the ciphers, all the digests *and* all the aliases. Your code may be bigger, but what the heck, it'll support everything.

EVP_get_digestbyname does the same thing for digests that EVP_get_cipherbyname does for ciphers; it tries to map name to a 'real' name in the alias stack, gets the nid associated with the real name and looks for the appropriate entry in the digest stack to return.

EVP_delete_alias looks for an entry in the aliases stack that starts with name and removes it. This function appears to be unused at present.

EVP_cleanup frees all three stacks and sets their pointers to NULL. It is invoked for example at the end of the ssleay app.