summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES25
-rw-r--r--apps/openssl.cnf7
-rw-r--r--apps/req.c273
-rw-r--r--crypto/asn1/a_mbstr.c50
-rw-r--r--crypto/asn1/a_strnid.c79
-rw-r--r--crypto/asn1/asn1.h3
-rw-r--r--crypto/x509/Makefile.ssl4
-rw-r--r--crypto/x509/x509.h27
-rw-r--r--crypto/x509/x509_att.c258
-rw-r--r--crypto/x509/x509_err.c6
-rw-r--r--doc/man/ca.pod2
-rw-r--r--doc/man/req.pod27
12 files changed, 655 insertions, 106 deletions
diff --git a/CHANGES b/CHANGES
index 52e0ffb3f2..7853e6c7d2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,31 @@
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
SSL_get_peer_finished to allow applications to obtain the latest
Finished messages sent to the peer or expected from the peer,
diff --git a/apps/openssl.cnf b/apps/openssl.cnf
index 13aeb9b0ba..dbe8cbefe0 100644
--- a/apps/openssl.cnf
+++ b/apps/openssl.cnf
@@ -95,16 +95,15 @@ x509_extensions = v3_ca # The extentions to add to the self signed cert
# input_password = secret
# output_password = secret
-# This sets the permitted types in a DirectoryString. There are several
-# options.
+# This sets a mask for permitted string types. There are several options.
# default: PrintableString, T61String, BMPString.
# pkix : PrintableString, BMPString.
# utf8only: only UTF8Strings.
-# nobmp : PrintableString, T61String (no BMPStrings).
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
# MASK:XXXX a literal mask value.
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
# so use this option with caution!
-dirstring_type = nobmp
+string_mask = nombstr
# req_extensions = v3_req # The extensions to add to a certificate request
diff --git a/apps/req.c b/apps/req.c
index 5c14c71e57..76a4514263 100644
--- a/apps/req.c
+++ b/apps/req.c
@@ -78,11 +78,12 @@
#define BITS "default_bits"
#define KEYFILE "default_keyfile"
+#define PROMPT "prompt"
#define DISTINGUISHED_NAME "distinguished_name"
#define ATTRIBUTES "attributes"
#define V3_EXTENSIONS "x509_extensions"
#define REQ_EXTENSIONS "req_extensions"
-#define DIRSTRING_TYPE "dirstring_type"
+#define STRING_MASK "string_mask"
#define DEFAULT_KEY_LENGTH 512
#define MIN_KEY_LENGTH 384
@@ -109,6 +110,11 @@
*/
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,
char *def, char *value, int nid, int min,
int max);
@@ -491,10 +497,10 @@ bad:
if(!passout)
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)) {
- BIO_printf(bio_err, "Invalid DiretoryString setting %s", p);
+ BIO_printf(bio_err, "Invalid global string mask setting %s", p);
goto end;
}
@@ -892,46 +898,47 @@ end:
static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, int attribs)
{
int ret=0,i;
- char *p,*q;
- X509_REQ_INFO *ri;
- char buf[100];
- int nid,min,max;
- char *type,*def,*tmp,*value,*tmp_attr;
- STACK_OF(CONF_VALUE) *sk, *attr=NULL;
- CONF_VALUE *v;
-
- tmp=CONF_get_string(req_conf,SECTION,DISTINGUISHED_NAME);
- if (tmp == NULL)
+ char no_prompt = 0;
+ STACK_OF(CONF_VALUE) *dn_sk, *attr_sk = NULL;
+ char *tmp, *dn_sect,*attr_sect;
+
+ tmp=CONF_get_string(req_conf,SECTION,PROMPT);
+ if((tmp != NULL) && !strcmp(tmp, "no")) no_prompt = 1;
+
+ dn_sect=CONF_get_string(req_conf,SECTION,DISTINGUISHED_NAME);
+ if (dn_sect == NULL)
{
BIO_printf(bio_err,"unable to find '%s' in config\n",
DISTINGUISHED_NAME);
goto err;
}
- sk=CONF_get_section(req_conf,tmp);
- if (sk == NULL)
+ dn_sk=CONF_get_section(req_conf,dn_sect);
+ 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;
}
- tmp_attr=CONF_get_string(req_conf,SECTION,ATTRIBUTES);
- if (tmp_attr == NULL)
- attr=NULL;
+ attr_sect=CONF_get_string(req_conf,SECTION,ATTRIBUTES);
+ if (attr_sect == NULL)
+ attr_sk=NULL;
else
{
- attr=CONF_get_section(req_conf,tmp_attr);
- if (attr == NULL)
+ attr_sk=CONF_get_section(req_conf,attr_sect);
+ 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;
}
}
- ri=req->req_info;
-
/* 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,"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");
@@ -1039,7 +1046,7 @@ start2: for (;;)
BIO_printf(bio_err,"No template, please set one up.\n");
goto err;
}
-
+#endif
X509_REQ_set_pubkey(req,pkey);
ret=1;
@@ -1047,6 +1054,220 @@ err:
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,
int nid, int min, int max)
{
diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c
index bc9cb14248..ca8d9ea951 100644
--- a/crypto/asn1/a_mbstr.c
+++ b/crypto/asn1/a_mbstr.c
@@ -72,54 +72,6 @@ static int cpy_univ(unsigned long value, void *arg);
static int cpy_utf8(unsigned long value, void *arg);
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
* a mask of permissible ASN1 string types. It then works out the minimal
* 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];
int (*cpyfunc)(unsigned long,void *) = NULL;
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 */
switch(inform) {
diff --git a/crypto/asn1/a_strnid.c b/crypto/asn1/a_strnid.c
index 2f9c09b705..a51ae43d96 100644
--- a/crypto/asn1/a_strnid.c
+++ b/crypto/asn1/a_strnid.c
@@ -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 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.
* Frequently the types and length of an ASN1_STRING are restricted by a
* 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 *str = NULL;
+ unsigned long mask;
int ret;
if(!out) out = &str;
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);
- 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;
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 */
static ASN1_STRING_TABLE tbl_standard[] = {
-{NID_commonName, 1, ub_common_name, 0, 0},
-{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, 0},
-{NID_localityName, 1, ub_locality_name, 0, 0},
-{NID_stateOrProvinceName, 1, ub_state_name, 0, 0},
-{NID_organizationName, 1, ub_organization_name, 0, 0},
-{NID_organizationalUnitName, 1, ub_organization_unit_name, 0, 0},
-{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, 0},
-{NID_givenName, 1, ub_name, 0, 0},
-{NID_surname, 1, ub_name, 0, 0},
-{NID_initials, 1, ub_name, 0, 0},
-{NID_name, 1, ub_name, 0, 0},
-{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, 0},
+{NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
+{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
+{NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
+{NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
+{NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
+{NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0},
+{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK},
+{NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
};
static int sk_table_cmp(ASN1_STRING_TABLE **a, ASN1_STRING_TABLE **b)
diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h
index c9500a6489..aba0b5fe71 100644
--- a/crypto/asn1/asn1.h
+++ b/crypto/asn1/asn1.h
@@ -212,6 +212,9 @@ typedef struct asn1_string_st
} ASN1_STRING;
#define STABLE_FLAGS_MALLOC 0x01
+#define STABLE_NO_MASK 0x02
+#define DIRSTRING_TYPE \
+ (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING)
typedef struct asn1_string_table_st {
int nid;
diff --git a/crypto/x509/Makefile.ssl b/crypto/x509/Makefile.ssl
index 346ffb2895..a569c80919 100644
--- a/crypto/x509/Makefile.ssl
+++ b/crypto/x509/Makefile.ssl
@@ -25,13 +25,13 @@ LIB=$(TOP)/libcrypto.a
LIBSRC= x509_def.c x509_d2.c x509_r2x.c x509_cmp.c \
x509_obj.c x509_req.c x509spki.c x509_vfy.c \
x509_set.c x509rset.c x509_err.c \
- x509name.c x509_v3.c x509_ext.c \
+ x509name.c x509_v3.c x509_ext.c x509_att.c \
x509type.c x509_lu.c x_all.c x509_txt.c \
x509_trs.c by_file.c by_dir.c
LIBOBJ= x509_def.o x509_d2.o x509_r2x.o x509_cmp.o \
x509_obj.o x509_req.o x509spki.o x509_vfy.o \
x509_set.o x509rset.o x509_err.o \
- x509name.o x509_v3.o x509_ext.o \
+ x509name.o x509_v3.o x509_ext.o x509_att.o \
x509type.o x509_lu.o x_all.o x509_txt.o \
x509_trs.o by_file.o by_dir.o
diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
index 2e6d2072af..9f5f9a1a15 100644
--- a/crypto/x509/x509.h
+++ b/crypto/x509/x509.h
@@ -1019,6 +1019,27 @@ ASN1_OBJECT * X509_EXTENSION_get_object(X509_EXTENSION *ex);
ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne);
int X509_EXTENSION_get_critical(X509_EXTENSION *ex);
+
+int X509_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x);
+int X509_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
+ int lastpos);
+int X509_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, ASN1_OBJECT *obj,
+ int lastpos);
+X509_ATTRIBUTE *X509_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc);
+X509_ATTRIBUTE *X509_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc);
+STACK_OF(X509_ATTRIBUTE) *X509_radd_attr(STACK_OF(X509_ATTRIBUTE) **x,
+ X509_ATTRIBUTE *attr, int loc);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
+ int atrtype, void *data);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
+ ASN1_OBJECT *obj, int atrtype, void *data);
+int X509_ATTRIBUTE_rset_object(X509_ATTRIBUTE *attr, ASN1_OBJECT *obj);
+int X509_ATTRIBUTE_iset_data(X509_ATTRIBUTE *attr, int attrtype, void *data);
+void *X509_ATTRIBUTE_iget_data(X509_ATTRIBUTE *attr, int idx,
+ int atrtype, void *data);
+ASN1_OBJECT *X509_ATTRIBUTE_iget_object(X509_ATTRIBUTE *attr);
+ASN1_TYPE *X509_ATTRIBUTE_type_iget(X509_ATTRIBUTE *attr, int idx);
+
int X509_verify_cert(X509_STORE_CTX *ctx);
/* lookup a cert from a X509 STACK */
@@ -1082,6 +1103,11 @@ int X509_TRUST_get_trust(X509_TRUST *xp);
#define X509_F_NETSCAPE_SPKI_B64_DECODE 129
#define X509_F_NETSCAPE_SPKI_B64_ENCODE 130
#define X509_F_X509V3_ADD_EXT 104
+#define X509_F_X509_ADD_ATTR 135
+#define X509_F_X509_ATTRIBUTE_CREATE_BY_NID 136
+#define X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ 137
+#define X509_F_X509_ATTRIBUTE_IGET_DATA 139
+#define X509_F_X509_ATTRIBUTE_ISET_DATA 138
#define X509_F_X509_CHECK_PRIVATE_KEY 128
#define X509_F_X509_EXTENSION_CREATE_BY_NID 108
#define X509_F_X509_EXTENSION_CREATE_BY_OBJ 109
@@ -1130,6 +1156,7 @@ int X509_TRUST_get_trust(X509_TRUST *xp);
#define X509_R_UNKNOWN_TRUST_ID 120
#define X509_R_UNSUPPORTED_ALGORITHM 111
#define X509_R_WRONG_LOOKUP_TYPE 112
+#define X509_R_WRONG_TYPE 122
#ifdef __cplusplus
}
diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c
new file mode 100644
index 0000000000..f755ccee85
--- /dev/null
+++ b/crypto/x509/x509_att.c
@@ -0,0 +1,258 @@
+/* crypto/x509/x509_att.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <openssl/stack.h>
+#include "cryptlib.h"
+#include <openssl/asn1.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+int X509_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
+{
+ if (!x) return 0;
+ return(sk_X509_ATTRIBUTE_num(x));
+}
+
+int X509_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
+ int lastpos)
+{
+ ASN1_OBJECT *obj;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL) return(-2);
+ return(X509_get_attr_by_OBJ(x,obj,lastpos));
+}
+
+int X509_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, ASN1_OBJECT *obj,
+ int lastpos)
+{
+ int n;
+ X509_ATTRIBUTE *ex;
+
+ if (sk == NULL) return(-1);
+ lastpos++;
+ if (lastpos < 0)
+ lastpos=0;
+ n=sk_X509_ATTRIBUTE_num(sk);
+ for ( ; lastpos < n; lastpos++)
+ {
+ ex=sk_X509_ATTRIBUTE_value(sk,lastpos);
+ if (OBJ_cmp(ex->object,obj) == 0)
+ return(lastpos);
+ }
+ return(-1);
+}
+
+X509_ATTRIBUTE *X509_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc)
+{
+ if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0)
+ return NULL;
+ else
+ return sk_X509_ATTRIBUTE_value(x,loc);
+}
+
+X509_ATTRIBUTE *X509_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc)
+{
+ X509_ATTRIBUTE *ret;
+
+ if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0)
+ return(NULL);
+ ret=sk_X509_ATTRIBUTE_delete(x,loc);
+ return(ret);
+}
+
+STACK_OF(X509_ATTRIBUTE) *X509_radd_attr(STACK_OF(X509_ATTRIBUTE) **x,
+ X509_ATTRIBUTE *attr, int loc)
+{
+ X509_ATTRIBUTE *new_attr=NULL;
+ int n;
+ STACK_OF(X509_ATTRIBUTE) *sk=NULL;
+
+ if ((x != NULL) && (*x == NULL))
+ {
+ if ((sk=sk_X509_ATTRIBUTE_new_null()) == NULL)
+ goto err;
+ }
+ else
+ sk= *x;
+
+ n=sk_X509_ATTRIBUTE_num(sk);
+ if (loc > n) loc=n;
+ else if (loc < 0) loc=n;
+
+ if ((new_attr=X509_ATTRIBUTE_dup(attr)) == NULL)
+ goto err2;
+ if (!sk_X509_ATTRIBUTE_insert(sk,new_attr,loc))
+ goto err;
+ if ((x != NULL) && (*x == NULL))
+ *x=sk;
+ return(sk);
+err:
+ X509err(X509_F_X509_ADD_ATTR,ERR_R_MALLOC_FAILURE);
+err2:
+ if (new_attr != NULL) X509_ATTRIBUTE_free(new_attr);
+ if (sk != NULL) sk_X509_ATTRIBUTE_free(sk);
+ return(NULL);
+}
+
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
+ int atrtype, void *data)
+{
+ ASN1_OBJECT *obj;
+ X509_ATTRIBUTE *ret;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL)
+ {
+ X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_NID,X509_R_UNKNOWN_NID);
+ return(NULL);
+ }
+ ret=X509_ATTRIBUTE_create_by_OBJ(attr,obj,atrtype,data);
+ if (ret == NULL) ASN1_OBJECT_free(obj);
+ return(ret);
+}
+
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
+ ASN1_OBJECT *obj, int atrtype, void *data)
+{
+ X509_ATTRIBUTE *ret;
+
+ if ((attr == NULL) || (*attr == NULL))
+ {
+ if ((ret=X509_ATTRIBUTE_new()) == NULL)
+ {
+ X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ,ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ }
+ else
+ ret= *attr;
+
+ if (!X509_ATTRIBUTE_rset_object(ret,obj))
+ goto err;
+ if (!X509_ATTRIBUTE_iset_data(ret,atrtype,data))
+ goto err;
+
+ if ((attr != NULL) && (*attr == NULL)) *attr=ret;
+ return(ret);
+err:
+ if ((attr == NULL) || (ret != *attr))
+ X509_ATTRIBUTE_free(ret);
+ return(NULL);
+}
+
+int X509_ATTRIBUTE_rset_object(X509_ATTRIBUTE *attr, ASN1_OBJECT *obj)
+{
+ if ((attr == NULL) || (obj == NULL))
+ return(0);
+ ASN1_OBJECT_free(attr->object);
+ attr->object=OBJ_dup(obj);
+ return(1);
+}
+
+int X509_ATTRIBUTE_iset_data(X509_ATTRIBUTE *attr, int attrtype, void *data)
+{
+ ASN1_TYPE *ttmp;
+ if (!attr) return 0;
+ if(!(attr->value.set = sk_ASN1_TYPE_new_null())) goto err;
+ if(!(ttmp = ASN1_TYPE_new())) goto err;
+ if(!sk_ASN1_TYPE_push(attr->value.set, ttmp)) goto err;
+ attr->set = 1;
+ ASN1_TYPE_set(ttmp, attrtype, data);
+ return 1;
+ err:
+ X509err(X509_F_X509_ATTRIBUTE_ISET_DATA, ERR_R_MALLOC_FAILURE);
+ return 0;
+}
+
+int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr)
+{
+ if(attr->set) return sk_ASN1_TYPE_num(attr->value.set);
+ if(attr->value.single) return 1;
+ return 0;
+}
+
+ASN1_OBJECT *X509_ATTRIBUTE_iget_object(X509_ATTRIBUTE *attr)
+{
+ if (attr == NULL) return(NULL);
+ return(attr->object);
+}
+
+void *X509_ATTRIBUTE_iget_data(X509_ATTRIBUTE *attr, int idx,
+ int atrtype, void *data)
+{
+ ASN1_TYPE *ttmp;
+ ttmp = X509_ATTRIBUTE_type_iget(attr, idx);
+ if(!ttmp) return NULL;
+ if(atrtype != ASN1_TYPE_get(ttmp)){
+ X509err(X509_F_X509_ATTRIBUTE_IGET_DATA, X509_R_WRONG_TYPE);
+ return NULL;
+ }
+ return ttmp->value.ptr;
+}
+
+ASN1_TYPE *X509_ATTRIBUTE_type_iget(X509_ATTRIBUTE *attr, int idx)
+{
+ if (attr == NULL) return(NULL);
+ if(idx >= X509_ATTRIBUTE_count(attr)) return NULL;
+ if(attr->set) return sk_ASN1_TYPE_value(attr->value.set, idx);
+ else return attr->value.single;
+}
diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c
index 6c85ddb84d..326aeca348 100644
--- a/crypto/x509/x509_err.c
+++ b/crypto/x509/x509_err.c
@@ -72,6 +72,11 @@ static ERR_STRING_DATA X509_str_functs[]=
{ERR_PACK(0,X509_F_NETSCAPE_SPKI_B64_DECODE,0), "NETSCAPE_SPKI_b64_decode"},
{ERR_PACK(0,X509_F_NETSCAPE_SPKI_B64_ENCODE,0), "NETSCAPE_SPKI_b64_encode"},
{ERR_PACK(0,X509_F_X509V3_ADD_EXT,0), "X509v3_add_ext"},
+{ERR_PACK(0,X509_F_X509_ADD_ATTR,0), "X509_ADD_ATTR"},
+{ERR_PACK(0,X509_F_X509_ATTRIBUTE_CREATE_BY_NID,0), "X509_ATTRIBUTE_create_by_NID"},
+{ERR_PACK(0,X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ,0), "X509_ATTRIBUTE_create_by_OBJ"},
+{ERR_PACK(0,X509_F_X509_ATTRIBUTE_IGET_DATA,0), "X509_ATTRIBUTE_iget_data"},
+{ERR_PACK(0,X509_F_X509_ATTRIBUTE_ISET_DATA,0), "X509_ATTRIBUTE_iset_data"},
{ERR_PACK(0,X509_F_X509_CHECK_PRIVATE_KEY,0), "X509_check_private_key"},
{ERR_PACK(0,X509_F_X509_EXTENSION_CREATE_BY_NID,0), "X509_EXTENSION_create_by_NID"},
{ERR_PACK(0,X509_F_X509_EXTENSION_CREATE_BY_OBJ,0), "X509_EXTENSION_create_by_OBJ"},
@@ -123,6 +128,7 @@ static ERR_STRING_DATA X509_str_reasons[]=
{X509_R_UNKNOWN_TRUST_ID ,"unknown trust id"},
<