Initial automation changes to 'req' and X509_ATTRIBUTE functions.
authorDr. Stephen Henson <steve@openssl.org>
Thu, 6 Jan 2000 01:26:48 +0000 (01:26 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 6 Jan 2000 01:26:48 +0000 (01:26 +0000)
12 files changed:
CHANGES
apps/openssl.cnf
apps/req.c
crypto/asn1/a_mbstr.c
crypto/asn1/a_strnid.c
crypto/asn1/asn1.h
crypto/x509/Makefile.ssl
crypto/x509/x509.h
crypto/x509/x509_att.c [new file with mode: 0644]
crypto/x509/x509_err.c
doc/man/ca.pod
doc/man/req.pod

diff --git a/CHANGES b/CHANGES
index 52e0ffb..7853e6c 100644 (file)
--- 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,
index 13aeb9b..dbe8cbe 100644 (file)
@@ -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
 
index 5c14c71..76a4514 100644 (file)
 
 #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
  */
 
 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)
        {
index bc9cb14..ca8d9ea 100644 (file)
@@ -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) {
index 2f9c09b..a51ae43 100644 (file)
@@ -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)
index c9500a6..aba0b5f 100644 (file)
@@ -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;
index 346ffb2..a569c80 100644 (file)
@@ -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
 
index 2e6d207..9f5f9a1 100644 (file)
@@ -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 (file)
index 0000000..f755cce
--- /dev/null
@@ -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;
+}
index 6c85ddb..326aeca 100644 (file)
@@ -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"},
 {X509_R_UNSUPPORTED_ALGORITHM            ,"unsupported algorithm"},
 {X509_R_WRONG_LOOKUP_TYPE                ,"wrong lookup type"},
+{X509_R_WRONG_TYPE                       ,"wrong type"},
 {0,NULL}
        };
 
index fbc4cba..1f2d6f2 100644 (file)
@@ -448,7 +448,7 @@ from the request.
 
 It is not possible to certify two certificates with the same DN: this
 is a side effect of how the text database is indexed and it cannot easily
-be fixed without introducing other problems. Netscape apparently can use
+be fixed without introducing other problems. Some S/MIME clients can use
 two certificates with the same DN for separate signing and encryption
 keys.
 
index 0211530..7dbd5d5 100644 (file)
@@ -146,7 +146,7 @@ will not be encrypted.
 
 this specifies the message digest to sign the request with. This
 overrides the digest algorithm specified in the configuration file.
-This option is ignore for DSA requests: they always use SHA1.
+This option is ignored for DSA requests: they always use SHA1.
 
 =item B<-config filename>
 
@@ -203,6 +203,13 @@ The options available are described in detail below.
 
 =over 4
 
+=item B<input_password output_password>
+
+The passwords for the input private key file (if present) and
+the output private key file (if one will be created). The
+command line options B<passin>, B<envpassin>, B<passout> and
+B<envpassout> override the configuration file values.
+
 =item B<default_bits>
 
 This specifies the default key size in bits. If not specified then
@@ -234,11 +241,11 @@ and long names are the same when this option is used.
 This specifies a filename in which random number seed information is
 placed and read from. It is used for private key generation.
 
-=item B<encrypt_rsa_key|encrypt_key>
+=item B<encrypt_key>
 
 If this is set to B<no> then if a private key is generated it is
 B<not> encrypted. This is equivalent to the B<-nodes> command line
-option.
+option. For compatability B<encrypt_rsai_key> is an equivalent option.
 
 =item B<default_md>
 
@@ -246,19 +253,19 @@ This option specifies the digest algorithm to use. Possible values
 include B<md5 sha1 mdc2>. If not present then MD5 is used. This
 option can be overridden on the command line.
 
-=item B<dirstring_type>
+=item B<string_mask>
 
-This option specifies which string types are permissible in a
-B<DirectoryString>. Most users will not need to change this option.
+This option masks out the use of certain string types in certain
+fields. Most users will not need to change this option.
 
 It can be set to several values B<default> which is also the default
 option uses PrintableStrings, T61Strings and BMPStrings if the 
 B<pkix> value is used then only PrintableStrings and BMPStrings will
 be used. This follows the PKIX recommendation in RFC2459. If the
 B<utf8only> option is used then only UTF8Strings will be used: this
-is the PKIX recommendation in RFC2459 after 2003. Finally the B<nobmp>
+is the PKIX recommendation in RFC2459 after 2003. Finally the B<nombstr>
 option just uses PrintableStrings and T61Strings: certain software has
-problems with BMPStrings.
+problems with BMPStrings and UTF8Strings: in particular Netscape.
 
 =item B<req_extensions>
 
@@ -277,8 +284,8 @@ is used. It can be overridden by the B<-extensions> command line switch.
 this specifies the section containing any request attributes: its format
 is the same as B<distinguished_name> described below. Typically these
 may contain the challengePassword or unstructuredName types. They are
-currently ignored by OpenSSLs request signing utilities but some CAs might want
-want them.
+currently ignored by OpenSSLs request signing utilities but some CAs
+might want them.
 
 =item B<distinguished_name>