Commit b38f9f66 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Initial automation changes to 'req' and X509_ATTRIBUTE functions.

parent ca03109c
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
@@ -4,6 +4,31 @@


 Changes between 0.9.4 and 0.9.5  [xx XXX 1999]
 Changes between 0.9.4 and 0.9.5  [xx XXX 1999]


  *) Initial changes to the 'req' utility to allow request generation
     automation. This will allow an application to just generate a template
     file containing all the field values and have req construct the
     request.

     Initial support for X509_ATTRIBUTE handling. Stacks of these are
     used all over the place including certificate requests and PKCS#7
     structures. They are currently handled manually where necessary with
     some primitive wrappers for PKCS#7. The new functions behave in a
     manner analagous to the X509 extension functions: they allow
     attributes to be looked up by NID and added.

     Later something similar to the X509V3 code would be desirable to
     automatically handle the encoding, decoding and printing of the
     more complex types. The string types like challengePassword can
     be handled by the string table fuctions.

     Also modified the multi byte string table handling. Now there is
     a 'global mask' which masks out certain types. The table itself
     can use the flag STABLE_NO_MASK to ignore the mask setting: this
     is useful when for example there is only one permissible type
     (as in countryName) and using the mask might result in no valid
     types at all.
     [Steve Henson]

  *) Clean up 'Finished' handling, and add functions SSL_get_finished and
  *) Clean up 'Finished' handling, and add functions SSL_get_finished and
     SSL_get_peer_finished to allow applications to obtain the latest
     SSL_get_peer_finished to allow applications to obtain the latest
     Finished messages sent to the peer or expected from the peer,
     Finished messages sent to the peer or expected from the peer,
+3 −4
Original line number Original line Diff line number Diff line
@@ -95,16 +95,15 @@ x509_extensions = v3_ca # The extentions to add to the self signed cert
# input_password = secret
# input_password = secret
# output_password = secret
# output_password = secret


# This sets the permitted types in a DirectoryString. There are several
# This sets a mask for permitted string types. There are several options. 
# options. 
# default: PrintableString, T61String, BMPString.
# default: PrintableString, T61String, BMPString.
# pkix	 : PrintableString, BMPString.
# pkix	 : PrintableString, BMPString.
# utf8only: only UTF8Strings.
# utf8only: only UTF8Strings.
# nobmp : PrintableString, T61String (no BMPStrings).
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
# MASK:XXXX a literal mask value.
# MASK:XXXX a literal mask value.
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
# so use this option with caution!
# so use this option with caution!
dirstring_type = nobmp
string_mask = nombstr


# req_extensions = v3_req # The extensions to add to a certificate request
# req_extensions = v3_req # The extensions to add to a certificate request


+247 −26
Original line number Original line Diff line number Diff line
@@ -78,11 +78,12 @@


#define BITS		"default_bits"
#define BITS		"default_bits"
#define KEYFILE		"default_keyfile"
#define KEYFILE		"default_keyfile"
#define PROMPT		"prompt"
#define DISTINGUISHED_NAME	"distinguished_name"
#define DISTINGUISHED_NAME	"distinguished_name"
#define ATTRIBUTES	"attributes"
#define ATTRIBUTES	"attributes"
#define V3_EXTENSIONS	"x509_extensions"
#define V3_EXTENSIONS	"x509_extensions"
#define REQ_EXTENSIONS	"req_extensions"
#define REQ_EXTENSIONS	"req_extensions"
#define DIRSTRING_TYPE	"dirstring_type"
#define STRING_MASK	"string_mask"


#define DEFAULT_KEY_LENGTH	512
#define DEFAULT_KEY_LENGTH	512
#define MIN_KEY_LENGTH		384
#define MIN_KEY_LENGTH		384
@@ -109,6 +110,11 @@
 */
 */


static int make_REQ(X509_REQ *req,EVP_PKEY *pkey,int attribs);
static int make_REQ(X509_REQ *req,EVP_PKEY *pkey,int attribs);
static int prompt_info(X509_REQ *req,
		STACK_OF(CONF_VALUE) *dn_sk, char *dn_sect,
		STACK_OF(CONF_VALUE) *attr_sk, char *attr_sect, int attribs);
static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *sk,
				STACK_OF(CONF_VALUE) *attr, int attribs);
static int add_attribute_object(STACK_OF(X509_ATTRIBUTE) *n, char *text,
static int add_attribute_object(STACK_OF(X509_ATTRIBUTE) *n, char *text,
				char *def, char *value, int nid, int min,
				char *def, char *value, int nid, int min,
				int max);
				int max);
@@ -491,10 +497,10 @@ bad:
	if(!passout)
	if(!passout)
		passout = CONF_get_string(req_conf, SECTION, "output_password");
		passout = CONF_get_string(req_conf, SECTION, "output_password");


	p = CONF_get_string(req_conf, SECTION, DIRSTRING_TYPE);
	p = CONF_get_string(req_conf, SECTION, STRING_MASK);


	if(p && !ASN1_STRING_set_default_mask_asc(p)) {
	if(p && !ASN1_STRING_set_default_mask_asc(p)) {
		BIO_printf(bio_err, "Invalid DiretoryString setting %s", p);
		BIO_printf(bio_err, "Invalid global string mask setting %s", p);
		goto end;
		goto end;
	}
	}


@@ -892,46 +898,47 @@ end:
static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, int attribs)
static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, int attribs)
	{
	{
	int ret=0,i;
	int ret=0,i;
	char *p,*q;
	char no_prompt = 0;
	X509_REQ_INFO *ri;
	STACK_OF(CONF_VALUE) *dn_sk, *attr_sk = NULL;
	char buf[100];
	char *tmp, *dn_sect,*attr_sect;
	int nid,min,max;

	char *type,*def,*tmp,*value,*tmp_attr;
	tmp=CONF_get_string(req_conf,SECTION,PROMPT);
	STACK_OF(CONF_VALUE) *sk, *attr=NULL;
	if((tmp != NULL) && !strcmp(tmp, "no")) no_prompt = 1;
	CONF_VALUE *v;


	tmp=CONF_get_string(req_conf,SECTION,DISTINGUISHED_NAME);
	dn_sect=CONF_get_string(req_conf,SECTION,DISTINGUISHED_NAME);
	if (tmp == NULL)
	if (dn_sect == NULL)
		{
		{
		BIO_printf(bio_err,"unable to find '%s' in config\n",
		BIO_printf(bio_err,"unable to find '%s' in config\n",
			DISTINGUISHED_NAME);
			DISTINGUISHED_NAME);
		goto err;
		goto err;
		}
		}
	sk=CONF_get_section(req_conf,tmp);
	dn_sk=CONF_get_section(req_conf,dn_sect);
	if (sk == NULL)
	if (dn_sk == NULL)
		{
		{
		BIO_printf(bio_err,"unable to get '%s' section\n",tmp);
		BIO_printf(bio_err,"unable to get '%s' section\n",dn_sect);
		goto err;
		goto err;
		}
		}


	tmp_attr=CONF_get_string(req_conf,SECTION,ATTRIBUTES);
	attr_sect=CONF_get_string(req_conf,SECTION,ATTRIBUTES);
	if (tmp_attr == NULL)
	if (attr_sect == NULL)
		attr=NULL;
		attr_sk=NULL;
	else
	else
		{
		{
		attr=CONF_get_section(req_conf,tmp_attr);
		attr_sk=CONF_get_section(req_conf,attr_sect);
		if (attr == NULL)
		if (attr_sk == NULL)
			{
			{
			BIO_printf(bio_err,"unable to get '%s' section\n",tmp_attr);
			BIO_printf(bio_err,"unable to get '%s' section\n",attr_sect);
			goto err;
			goto err;
			}
			}
		}
		}


	ri=req->req_info;

	/* setup version number */
	/* setup version number */
	if (!ASN1_INTEGER_set(ri->version,0L)) goto err; /* version 1 */
	if (!X509_REQ_set_version(req,0L)) goto err; /* version 1 */


	if(no_prompt) i = auto_info(req, dn_sk, attr_sk, attribs);
	else i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs);
	if(!i) goto err;
#if 0
	BIO_printf(bio_err,"You are about to be asked to enter information that will be incorporated\n");
	BIO_printf(bio_err,"You are about to be asked to enter information that will be incorporated\n");
	BIO_printf(bio_err,"into your certificate request.\n");
	BIO_printf(bio_err,"into your certificate request.\n");
	BIO_printf(bio_err,"What you are about to enter is what is called a Distinguished Name or a DN.\n");
	BIO_printf(bio_err,"What you are about to enter is what is called a Distinguished Name or a DN.\n");
@@ -1039,7 +1046,7 @@ start2: for (;;)
		BIO_printf(bio_err,"No template, please set one up.\n");
		BIO_printf(bio_err,"No template, please set one up.\n");
		goto err;
		goto err;
		}
		}

#endif
	X509_REQ_set_pubkey(req,pkey);
	X509_REQ_set_pubkey(req,pkey);


	ret=1;
	ret=1;
@@ -1047,6 +1054,220 @@ err:
	return(ret);
	return(ret);
	}
	}



static int prompt_info(X509_REQ *req,
		STACK_OF(CONF_VALUE) *dn_sk, char *dn_sect,
		STACK_OF(CONF_VALUE) *attr_sk, char *attr_sect, int attribs)
	{
	int i;
	char *p,*q;
	char buf[100];
	int nid,min,max;
	char *type,*def,*value;
	CONF_VALUE *v;
	X509_NAME *subj;
	subj = X509_REQ_get_subject_name(req);
	BIO_printf(bio_err,"You are about to be asked to enter information that will be incorporated\n");
	BIO_printf(bio_err,"into your certificate request.\n");
	BIO_printf(bio_err,"What you are about to enter is what is called a Distinguished Name or a DN.\n");
	BIO_printf(bio_err,"There are quite a few fields but you can leave some blank\n");
	BIO_printf(bio_err,"For some fields there will be a default value,\n");
	BIO_printf(bio_err,"If you enter '.', the field will be left blank.\n");
	BIO_printf(bio_err,"-----\n");


	if (sk_CONF_VALUE_num(dn_sk))
		{
		i= -1;
start:		for (;;)
			{
			i++;
			if (sk_CONF_VALUE_num(dn_sk) <= i) break;

			v=sk_CONF_VALUE_value(dn_sk,i);
			p=q=NULL;
			type=v->name;
			if(!check_end(type,"_min") || !check_end(type,"_max") ||
				!check_end(type,"_default") ||
					 !check_end(type,"_value")) continue;
			/* Skip past any leading X. X: X, etc to allow for
			 * multiple instances 
			 */
			for(p = v->name; *p ; p++) 
				if ((*p == ':') || (*p == ',') ||
							 (*p == '.')) {
					p++;
					if(*p) type = p;
					break;
				}
			/* If OBJ not recognised ignore it */
			if ((nid=OBJ_txt2nid(type)) == NID_undef) goto start;
			sprintf(buf,"%s_default",v->name);
			if ((def=CONF_get_string(req_conf,dn_sect,buf)) == NULL)
				def="";
				
			sprintf(buf,"%s_value",v->name);
			if ((value=CONF_get_string(req_conf,dn_sect,buf)) == NULL)
				value=NULL;

			sprintf(buf,"%s_min",v->name);
			min=(int)CONF_get_number(req_conf,dn_sect,buf);

			sprintf(buf,"%s_max",v->name);
			max=(int)CONF_get_number(req_conf,dn_sect,buf);

			if (!add_DN_object(subj,v->value,def,value,nid,
				min,max))
				return 0;
			}
		if (X509_NAME_entry_count(subj) == 0)
			{
			BIO_printf(bio_err,"error, no objects specified in config file\n");
			return 0;
			}

		if (attribs)
			{
			if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0))
				{
				BIO_printf(bio_err,"\nPlease enter the following 'extra' attributes\n");
				BIO_printf(bio_err,"to be sent with your certificate request\n");
				}

			i= -1;
start2:			for (;;)
				{
				i++;
				if ((attr_sk == NULL) ||
					    (sk_CONF_VALUE_num(attr_sk) <= i))
					break;

				v=sk_CONF_VALUE_value(attr_sk,i);
				type=v->name;
				if ((nid=OBJ_txt2nid(type)) == NID_undef)
					goto start2;

				sprintf(buf,"%s_default",type);
				if ((def=CONF_get_string(req_conf,attr_sect,buf))
					== NULL)
					def="";
				
				sprintf(buf,"%s_value",type);
				if ((value=CONF_get_string(req_conf,attr_sect,buf))
					== NULL)
					value=NULL;

				sprintf(buf,"%s_min",type);
				min=(int)CONF_get_number(req_conf,attr_sect,buf);

				sprintf(buf,"%s_max",type);
				max=(int)CONF_get_number(req_conf,attr_sect,buf);

				if (!add_attribute_object(req->req_info->attributes,
					v->value,def,value,nid,min,max))
					return 0;
				}
			}
		}
	else
		{
		BIO_printf(bio_err,"No template, please set one up.\n");
		return 0;
		}

	return 1;

	}

static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk,
			STACK_OF(CONF_VALUE) *attr_sk, int attribs)
	{
	int i;
	char *p,*q;
	char *type;
	CONF_VALUE *v;
	X509_NAME *subj;

	subj = X509_REQ_get_subject_name(req);

	for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++)
		{
		v=sk_CONF_VALUE_value(dn_sk,i);
		p=q=NULL;
		type=v->name;
		/* Skip past any leading X. X: X, etc to allow for
		 * multiple instances 
		 */
		for(p = v->name; *p ; p++) 
			if ((*p == ':') || (*p == ',') || (*p == '.')) {
				p++;
				if(*p) type = p;
				break;
			}
		if (!X509_NAME_add_entry_by_txt(subj,type, MBSTRING_ASC,
				(unsigned char *) v->value,-1,-1,0)) return 0;

		}

		if (!X509_NAME_entry_count(subj))
			{
			BIO_printf(bio_err,"error, no objects specified in config file\n");
			return 0;
			}
#if 0
		if (attribs)
			{
			if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0))
				{
				BIO_printf(bio_err,"\nPlease enter the following 'extra' attributes\n");
				BIO_printf(bio_err,"to be sent with your certificate request\n");
				}

			i= -1;
start2:			for (;;)
				{
				i++;
				if ((attr_sk == NULL) ||
					    (sk_CONF_VALUE_num(attr_sk) <= i))
					break;

				v=sk_CONF_VALUE_value(attr_sk,i);
				type=v->name;
				if ((nid=OBJ_txt2nid(type)) == NID_undef)
					goto start2;

				sprintf(buf,"%s_default",type);
				if ((def=CONF_get_string(req_conf,attr_sect,buf))
					== NULL)
					def="";
				
				sprintf(buf,"%s_value",type);
				if ((value=CONF_get_string(req_conf,attr_sect,buf))
					== NULL)
					value=NULL;

				sprintf(buf,"%s_min",type);
				min=(int)CONF_get_number(req_conf,attr_sect,buf);

				sprintf(buf,"%s_max",type);
				max=(int)CONF_get_number(req_conf,attr_sect,buf);

				if (!add_attribute_object(ri->attributes,
					v->value,def,value,nid,min,max))
					return 0;
				}
			}
		}
	else
		{
		BIO_printf(bio_err,"No template, please set one up.\n");
		return 0;
		}
#endif
	return 1;
	}


static int add_DN_object(X509_NAME *n, char *text, char *def, char *value,
static int add_DN_object(X509_NAME *n, char *text, char *def, char *value,
	     int nid, int min, int max)
	     int nid, int min, int max)
	{
	{
+1 −49
Original line number Original line Diff line number Diff line
@@ -72,54 +72,6 @@ static int cpy_univ(unsigned long value, void *arg);
static int cpy_utf8(unsigned long value, void *arg);
static int cpy_utf8(unsigned long value, void *arg);
static int is_printable(unsigned long value);
static int is_printable(unsigned long value);


/* This is the default mask for the mbstring functions: it is designed
 * to be a "safe" DirectoryString. Netscape messenger crashes when it
 * receives a certificate containing a BMPString so by default we don't
 * use them unless we have to.
 */

static long dirstring_mask = B_ASN1_PRINTABLESTRING
				| B_ASN1_T61STRING | B_ASN1_BMPSTRING;

void ASN1_STRING_set_default_mask(unsigned long mask)
{
	dirstring_mask = mask;
}

unsigned long ASN1_STRING_get_default_mask(void)
{
	return dirstring_mask;
}

/* This function sets the default to various "flavours" of configuration.
 * based on an ASCII string. Currently this is:
 * MASK:XXXX : a numerical mask value.
 * nobmp : Don't use BMPStrings (just Printable, T61).
 * pkix : PKIX recommendation in RFC2459.
 * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
 * default:   the default value, Printable, T61, BMP.
 */

int ASN1_STRING_set_default_mask_asc(char *p)
{
	unsigned long mask;
	char *end;
	if(!strncmp(p, "MASK:", 5)) {
		if(!p[5]) return 0;
		mask = strtoul(p + 5, &end, 0);
		if(*end) return 0;
	} else if(!strcmp(p, "nobmp"))
			 mask = B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING;
	else if(!strcmp(p, "pkix"))
			mask = B_ASN1_PRINTABLESTRING | B_ASN1_BMPSTRING;
	else if(!strcmp(p, "utf8only")) mask = B_ASN1_UTF8STRING;
	else if(!strcmp(p, "default"))
	    mask = B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_BMPSTRING;
	else return 0;
	ASN1_STRING_set_default_mask(mask);
	return 1;
}

/* These functions take a string in UTF8, ASCII or multibyte form and
/* These functions take a string in UTF8, ASCII or multibyte form and
 * a mask of permissible ASN1 string types. It then works out the minimal
 * a mask of permissible ASN1 string types. It then works out the minimal
 * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8)
 * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8)
@@ -147,7 +99,7 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
	char strbuf[32];
	char strbuf[32];
	int (*cpyfunc)(unsigned long,void *) = NULL;
	int (*cpyfunc)(unsigned long,void *) = NULL;
	if(len == -1) len = strlen((const char *)in);
	if(len == -1) len = strlen((const char *)in);
	if(!mask) mask = dirstring_mask;
	if(!mask) mask = DIRSTRING_TYPE;


	/* First do a string check and work out the number of characters */
	/* First do a string check and work out the number of characters */
	switch(inform) {
	switch(inform) {
+65 −14
Original line number Original line Diff line number Diff line
@@ -68,6 +68,53 @@ static void st_free(ASN1_STRING_TABLE *tbl);
static int sk_table_cmp(ASN1_STRING_TABLE **a, ASN1_STRING_TABLE **b);
static int sk_table_cmp(ASN1_STRING_TABLE **a, ASN1_STRING_TABLE **b);
static int table_cmp(ASN1_STRING_TABLE *a, ASN1_STRING_TABLE *b);
static int table_cmp(ASN1_STRING_TABLE *a, ASN1_STRING_TABLE *b);



/* This is the global mask for the mbstring functions: this is use to
 * mask out certain types (such as BMPString and UTF8String) because
 * certain software (e.g. Netscape) has problems with them.
 */

static long global_mask = 0xFFFFFFFFL;

void ASN1_STRING_set_default_mask(unsigned long mask)
{
	global_mask = mask;
}

unsigned long ASN1_STRING_get_default_mask(void)
{
	return global_mask;
}

/* This function sets the default to various "flavours" of configuration.
 * based on an ASCII string. Currently this is:
 * MASK:XXXX : a numerical mask value.
 * nobmp : Don't use BMPStrings (just Printable, T61).
 * pkix : PKIX recommendation in RFC2459.
 * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
 * default:   the default value, Printable, T61, BMP.
 */

int ASN1_STRING_set_default_mask_asc(char *p)
{
	unsigned long mask;
	char *end;
	if(!strncmp(p, "MASK:", 5)) {
		if(!p[5]) return 0;
		mask = strtoul(p + 5, &end, 0);
		if(*end) return 0;
	} else if(!strcmp(p, "nombchar"))
			 mask = ~(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING);
	else if(!strcmp(p, "pkix"))
			mask = ~B_ASN1_T61STRING;
	else if(!strcmp(p, "utf8only")) mask = B_ASN1_UTF8STRING;
	else if(!strcmp(p, "default"))
	    mask = 0xFFFFFFFFL;
	else return 0;
	ASN1_STRING_set_default_mask(mask);
	return 1;
}

/* The following function generates an ASN1_STRING based on limits in a table.
/* The following function generates an ASN1_STRING based on limits in a table.
 * Frequently the types and length of an ASN1_STRING are restricted by a 
 * Frequently the types and length of an ASN1_STRING are restricted by a 
 * corresponding OID. For example certificates and certificate requests.
 * corresponding OID. For example certificates and certificate requests.
@@ -78,12 +125,16 @@ ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in,
{
{
	ASN1_STRING_TABLE *tbl;
	ASN1_STRING_TABLE *tbl;
	ASN1_STRING *str = NULL;
	ASN1_STRING *str = NULL;
	unsigned long mask;
	int ret;
	int ret;
	if(!out) out = &str;
	if(!out) out = &str;
	tbl = ASN1_STRING_TABLE_get(nid);
	tbl = ASN1_STRING_TABLE_get(nid);
	if(tbl) ret = ASN1_mbstring_ncopy(out, in, inlen, inform, tbl->mask,
	if(tbl) {
		mask = tbl->mask;
		if(!(tbl->flags & STABLE_NO_MASK)) mask &= global_mask;
		ret = ASN1_mbstring_ncopy(out, in, inlen, inform, tbl->mask,
					tbl->minsize, tbl->maxsize);
					tbl->minsize, tbl->maxsize);
	else ret = ASN1_mbstring_copy(out, in, inlen, inform, 0);
	} else ret = ASN1_mbstring_copy(out, in, inlen, inform, DIRSTRING_TYPE & global_mask);
	if(ret <= 0) return NULL;
	if(ret <= 0) return NULL;
	return *out;
	return *out;
}
}
@@ -105,18 +156,18 @@ ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in,
/* This table must be kept in NID order */
/* This table must be kept in NID order */


static ASN1_STRING_TABLE tbl_standard[] = {
static ASN1_STRING_TABLE tbl_standard[] = {
{NID_commonName,		1, ub_common_name, 0, 0},
{NID_commonName,		1, ub_common_name, DIRSTRING_TYPE, 0},
{NID_countryName,		2, 2, B_ASN1_PRINTABLESTRING, 0},
{NID_countryName,		2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_localityName,		1, ub_locality_name, 0, 0},
{NID_localityName,		1, ub_locality_name, DIRSTRING_TYPE, 0},
{NID_stateOrProvinceName,	1, ub_state_name, 0, 0},
{NID_stateOrProvinceName,	1, ub_state_name, DIRSTRING_TYPE, 0},
{NID_organizationName,		1, ub_organization_name, 0, 0},
{NID_organizationName,		1, ub_organization_name, DIRSTRING_TYPE, 0},
{NID_organizationalUnitName,	1, ub_organization_unit_name, 0, 0},
{NID_organizationalUnitName,	1, ub_organization_unit_name, DIRSTRING_TYPE, 0},
{NID_pkcs9_emailAddress,	1, ub_email_address, B_ASN1_IA5STRING, 0},
{NID_pkcs9_emailAddress,	1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK},
{NID_givenName,			1, ub_name, 0, 0},
{NID_givenName,			1, ub_name, DIRSTRING_TYPE, 0},
{NID_surname,			1, ub_name, 0, 0},
{NID_surname,			1, ub_name, DIRSTRING_TYPE, 0},
{NID_initials,			1, ub_name, 0, 0},
{NID_initials,			1, ub_name, DIRSTRING_TYPE, 0},
{NID_name,			1, ub_name, 0, 0},
{NID_name,			1, ub_name, DIRSTRING_TYPE, 0},
{NID_dnQualifier,		-1, -1, B_ASN1_PRINTABLESTRING, 0},
{NID_dnQualifier,		-1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
};
};


static int sk_table_cmp(ASN1_STRING_TABLE **a, ASN1_STRING_TABLE **b)
static int sk_table_cmp(ASN1_STRING_TABLE **a, ASN1_STRING_TABLE **b)
Loading