PEM_proc_type -- SSLeay 0.9.0b -- January 1999

NAME

PEM_proc_type, PEM_dek_info, PEM_do_header, PEM_get_EVP_CIPHER_INFO,
PEM_SealInit, PEM_SealUpdate, PEM_SealFinal, PEM_SignInit, PEM_SignUpdate,
PEM_SignFinal, ERR_load_PEM_strings -- PEM library routines

SYNOPSIS

#include "pem.h"

void PEM_proc_type(buf, type)
char *buf; int type;

void PEM_dek_info(buf, type, len, str)
char *buf, *type, *str; int len;

int PEM_do_header (cipher, data, len, callback)
EVP_CIPHER_INFO *cipher; unsigned char *data; long *len; int (*callback)());

int PEM_get_EVP_CIPHER_INFO(header, cipher)
char *header; EVP_CIPHER_INFO *cipher);

int PEM_SealInit(ctx, type, md_type, ek, ekl, iv, pubk, npubk)
PEM_ENCODE_SEAL_CTX *ctx; EVP_CIPHER *type; EVP_MD *md_type; unsigned char **ek, *iv; int *ekl, npubk; EVP_PKEY **pubk;

void PEM_SealUpdate(ctx, out, outl, in, inl)
PEM_ENCODE_SEAL_CTX *ctx; unsigned char *out, *in; int *outl, *inl;

int PEM_SealFinal(ctx, sig, sigl, out, outl, priv)
PEM_ENCODE_SEAL_CTX *ctx; unsigned char *sig, *out; int *sigl, *outl; EVP_PKEY *priv;

void PEM_SignInit(ctx, type)
EVP_MD_CTX *ctx; EVP_MD *type;

void PEM_SignUpdate(ctx, d, cnt)
EVP_MD_CTX *ctx; unsigned char *d; unsigned int cnt;

int PEM_SignFinal(ctx, sigret, siglen, pkey)
EVP_MD_CTX *ctx; unsigned char *sigret; unsigned int *siglen; EVP_PKEY *pkey;

void ERR_load_PEM_strings();

DESCRIPTION

PEM_proc_type puts together the PEM Proc-Type header depending on the type.

The resultant character string is copied into buf, which must be large enough to hold the result.

Valid types are:

PEM_TYPE_ENCRYPTED
string will contain "Proc-Type: 4,ENCRYPTED"
PEM_TYPE_MIC_CLEAR
string will contain "Proc-Type: 4,MIC-CLEAR"
PEM_TYPE_MIC_ONLY
string will contain "Proc-Type: 4,MIC-ONLY"

Any other type will result in the header "Proc-Type: 4,BAD-TYPE".

The header is terminated with a newline.

Note that the MIC headers may look nice but there is no implementation of the MIC computation in this library (yet). Of course, one could use one of the RSA-MD* routines (for example) on the message body and use the resultant digest as the MIC. You could write a MIC-Info header generator by stealing from PEM_dek_info (described below). It would probably take all of about 5 minutes...

PEM_dek_info puts together the PEM DEK-Info header depending on the type.

The resultant character string is copied into buf, which must be large enough to hold the result.

The ivec needed for this header is presumed to be in str and its length is presumed to be len bytes.

The type is presumed to be the short or long name of a cipher; these could be arbitrary strings but you'd like to be able to interpret the header later, so you should get the nid of the particular cipher and then call nid2sn on it to get the short name; this then becomes type.

For example, PEM_ASN1_write_bio expects to be passed an EVP_CIPHER enc; it then calls objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc)); where objstr is a character string that now contains the short name corresponding to the cipher; later it calls PEM_dek_info(buf,objstr,8,(char *)iv); passing objstr as the short name.

PEM_do_header is perhaps a little misleading in its name. It actually decrypts data from the body of a PEM-encoded object, if any decryption needs to be done. This function is called by PEM_read_bio.

It expects that the PEM headers have been processed already; in particular, that the DEK-Info header has already been read (if there is one) and that the cipher name in the header has been used to retrieve the EVP_CIPHER structure appropriate to the message (passed as argument cipher). It also expects that cipher->iv has been set to the iv in the DEK-Info header.

If this doesn't make much sense to you, try looking at the overview to the PEM library and then at the EVP handling for symmetric ciphers.

Now if header is NULL or the empty string then this function just returns 1 (success) since no decryption needs to be done.

Otherwise, it tries to get a pass phrase from somewhere. First, it checks callback; if this is set to something it is called as

callback(buffer, blen, verify)

where buffer is where the pass phrase will be put, blen is the length of the buffer, and verify is set if yopur callback is supposed to prompt twice for the password and check that the user typed the same thing both times. Naturally, in the current situation verify is 0.

If callback is NULL, the default callback def_callback, a static internal function of the PEM library, is called. Because the pass phrase handling has caused some confusion I will spell out the calls (-> indicates that one function calls the next):

def_callback ->
  EVP_read_pw_string ->
    write a prompt,
    des_read_pw_string ->
      des_read_pw

PEM_do_header then takes the key and length and uses them together with the ivec in cipher to to decrypt the data.

The decrypted data goes right back into data; the length of the decrypted data goes into plen. The function returns 1 on success, 0 on error.

PEM_get_EVP_CIPHER_INFO is called by PEM_read_bio.

It expects that the PEM headers of a message have been read into header as plain text but that no other processing has been done on them.

If header is NULL then 1 is returned (success), since no header processing needs to be done.

Otherwise, it first looks to be sure that header starts with

Proc-Type:4,ENCRYPTED

It won't process any other type of Proc-Type header.

Then it skips the terminating newline and checks that the next part of header reads

DEK-Info:

It gets an EVP_CIPHER structure associated with the cipher name that should be next in the header, by calling EVP_get_cipherbyname (see EVP EVP handling for symmetric ciphers r details). This is then placed into cipher->cipher. The function next calls an internal function to get the ivec, if any, out of the header and places it into cipher->iv.

Finally, it returns 1. If an error was encountered, 0 is returned.

Note that since this function calls EVP_get_cipherbyname, you must' have preloaded the static cipher stack for the lookup to succeed, via EVP_add_cipher and EVP_add_alias, or by SSLeay_add_all_algorithms; see EVP cipher/digest lookup routines for details.

PEM_SealInit sets up for PEM_SealUpdate and PEM_SealFinal (naturally).

First, this function inits ctx->md from md_type (calling EVP_SignInit). Then it looks up the EVP_CIPHER associated with type, generates a key and ivec suitable for use with that cipher, and encrypts the key with each element of pubk (calling EVP_SealInit).

Each such encrypted copy is base64-encoded and placed in the appropriate element of ek, with length placed in ekl.

The key and ivec are stored for you in ctx->cipher, so that they can be used later to encrypt a message body.

This function is not called by anything else in the library (yet).

Note that, as above, you must have preloaded the static cipher stack for the lookup from type to a EVP_CIPHER to succeed.

PEM_SealUpdate can be used to encrypt a message body with a key that has been generated during the PEM_SealInit stage.

It encrypts the data in in, all inl bytes of it, using the ctx->cipher provided (and the key and ivec that should already have been set in the structure). This then is base64-encoded and placed in out, with the length in outl.

It simultaneously creates a message digest of the data in in, using ctx-d>>md as the digest algorithm.

Note that if inl is greater than 1200 bytes it is silently reset to 1200 and the new value is used. Hmmmm...

PEM_SealFinal completes the PEM_Seal operation.

It finishes the symmetric encryption of the data previously passed in PEM_SealUpdate, finishes the base64-encoding of that and tacks it onto out with the length in outl.

It finishes the digest computation as well and encrypts that with the private key priv, placing the resulting signature in sig with the length in sigl.

Note that this routine clears ctx->md and ctx->cipher, so if you wted to save the key and ivec used in symmetric encryption for any reason, you should make cipes before calling this routine.

Most likely you won't need to preserve them, however, since these are temporary keys, meant only for encryption of one message.

At this point you could send the encrypted key and ivec you got back from PEM_SealInit in PEM headers and send the encrypted b64-encoded message body as the PEM message body, if you took 5 minutes to write the code to package it up nicely. I guess that the signed digest is what they call the MIC in the PEM specs. Generate that header (and code to read it back in) and you'd be done. The rest is already in the library.

PEM_SignInit just calls EVP_DigestInit with the same arguments. See EVP digest handling, signing, verification for information on this function.

PEM_SignUpdate just calls EVP_DigestUpdate with the same arguments. See EVP digest handling, signing, verification for information on this function.

PEM_SignFinal on the other hand... calls EVP_SignFinal to finish the digest and sign it with the pkey provided, calls EVP_EncodeBlock to base64-encode the signature, and places the result in sigret with the length in siglen.

ERR_load_PEM_strings initializes arrays for the error-handling library with messages specific to the PEM library. Call this before using any PEM routines in your code.