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

NAME

ASN1_dup, ASN1_sign, ASN1_verify, ASN1_PRINTABLE_type, ASN1_parse,
i2t_ASN1_OBJECT, i2a_ASN1_OBJECT -- ASN1 miscellaneous routines

SYNOPSIS

#include "asn1.h"

char *ASN1_dup(i2d,d2i,x)
int (*i2d)();
char *(*d2i)(), *x;

int ASN1_sign(i2d,algor1,algor2,signature,data,pkey,type)
int (*i2d)();
X509_ALGOR *algor1, *algor2; ASN1_BIT_STRING *signature;
char *data;
EVP_PKEY *pkey;
EVP_MD *type;

int ASN1_verify(i2d,a,signature,data,pkey)
int (*i2d)();
X509_ALGOR *a;
ASN1_BIT_STRING *signature;
char *data;
EVP_PKEY *pkey;

int ASN1_PRINTABLE_type(s)
unsigned char *s;

int ASN1_parse(bp, pp, len)
BIO *bp;
unsigned char *pp;
long len;

int i2t_ASN1_OBJECT(buf, buf_len, a)
char *buf;
int buf_len;
ASN1_OBJECT *a;

int i2a_ASN1_OBJECT(bp,a)
BIO *bp;
ASN1_OBJECT *a;

DESCRIPTION

ANS1_dup makes a copy of an ANS1 object. i2d should be the name of an internal-to-DER converter for the particular kind of object you want to duplicate; d2i should be the name of a DER-to-internal converter for the same kind of object. For example,

        ri=(X509_REQ_INFO *)ASN1_dup(i2d_X509_REQ_INFO,
                (char *(*)())d2i_X509_REQ_INFO,(char *)r->req_info);
to duplicate a certificate request object.

For more information on the converters, see ASN.1 conversion to and from DER-encoded form.

ASN1_sign() is used only for X509-related things. Here's what it does:

First, it sets both algor1 and algor2 to hold the appropriate information for the algorithm type->pkey_type. pkey_type is the NID corresponding to the algorithm used for digest-and-sign, for example NID_shaWithRSAEncryption. See EVP digest handling, signing, verification for more informaton on the EVP_MD structure.

Then, it calls the i2d function passed to it to convert the data (which is some internal ASN1 structure) to DER-encoded form. It then 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 signature->data with the length in signature->length. That same length is returned to the caller, or 0 on error.

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

Now, you are no doubt wondering what happened to those algor1 and algor2 arguments; what are we supposed to do with them now?

Here's the trick. These arguments are supposed to be subfields in the main structure data! When they get adjusted, and the i2d is done on data afterwards, the information gets stuffed right into the string that is going to be signed.

Now, not all the structures in this library have two slots for X509_ALGORs (and in particular two copies of the *same one*). In fact, here are the ones that do:

X509_CINF
X509_REQ_INFO
X509_CRL_INFO
NETSCAPE_SPKAC

So the moral of this story is: don't call this function directly. Use one of the following macros instead, which is as God intended:

#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_REQ_sign(x,pkey,md) \ ASN1_sign((int (*)())i2d_X509_REQ_INFO,x->sig_alg, NULL, \ x->signature, (char *)x->req_info,pkey,md) #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) #define NETSCAPE_SPKI_sign(x,pkey,md) \ ASN1_sign((int (*)())i2d_NETSCAPE_SPKAC, x->sig_algor,NULL, \ x->signature, (char *)x->spkac,pkey,md)

ASN1_verify converts the data passed to DER-encoded form using with the passed i2d function; computes the message digest of it using a->algorithm as the message digest algorithm; signs it using pkey as the key for signing; and finally compares the results against the passed signature. 1 is returned if they match, 0 on failure or error.

This function 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.

This function, like ASN1_sign, is really not intended to be called directly. Use one of the macros instead:

#define X509_verify(a,r) ASN1_verify((int (*)())i2d_X509_CINF,a->sig_alg,\
        a->signature,(char *)a->cert_info,r)
#define X509_REQ_verify(a,r) ASN1_verify((int (*)())i2d_X509_REQ_INFO, \
        a->sig_alg,a->signature,(char *)a->req_info,r)
#define X509_CRL_verify(a,r) ASN1_verify((int (*)())i2d_X509_CRL_INFO, \
        a->sig_alg, a->signature,(char *)a->crl,r)

ASN1_PRINTABLE_type wades through the characters in the string s and checks to see which of various ASN1 string types this string is, (return the most restrictive type that has all the characters in the definition), and returns the approriate tag, one of V_ASN1_T61STRING, V_ASN1_IA5STRING, or V_ASN1_PRINTABLESTRING. I guess we should really deal with some of the more obscure string types. Oh well...

Note that if s is NULL we return the 'default' V_ASN1_PRINTABLESTRING.

ASN1_parse is the greatest routine ever written.

Well, ok, maybe not, but it's still pretty damn good.

It tries to write a human-readable description of the DER-encoded data in pp, len bytes of it, to the BIO pointed to by bp. pp is updated to point to the next unread byte in the string. It returns 1 on success or 0 on error, except in one case where it returns 2 after encountering an END OF SEQUENCE octet. I really don't know why it does that.

i2t_ASN1_OBJECT tries to find the LN (long name) associated with the ASN1_OBJECT a and puts it in the buffer buf, or up to buf_len bytes of it, at any rate. If no LN can be found, then the OID (a->data) is written out into buf instead, in "##.##.##" format, where the ## are digits. If there is room, the string written into buf is null-termnated. The number of bytes written into buf is returned.

i2a_ASN1_OBJECT does exactly what i2t_ASN1_OBJECT does except that it writes the result the the BIO bp, and the maximum length of the string it will write out is 80 bytes. It also returns the number of bytes written, or 0 on error. One additional difference is that if a is NULL, i2t_ASN1_OBJECT will write '\0' into the buffer, whereas i2a_ASN1_OBJECT will write "NULL" to the BIO (and return 4).