From b38f9f66c3ac92d7ad1a23f6b951b966c779905c Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Thu, 6 Jan 2000 01:26:48 +0000 Subject: [PATCH] Initial automation changes to 'req' and X509_ATTRIBUTE functions. --- CHANGES | 25 ++++ apps/openssl.cnf | 7 +- apps/req.c | 273 +++++++++++++++++++++++++++++++++++---- crypto/asn1/a_mbstr.c | 50 +------ crypto/asn1/a_strnid.c | 79 +++++++++-- crypto/asn1/asn1.h | 3 + crypto/x509/Makefile.ssl | 4 +- crypto/x509/x509.h | 27 ++++ crypto/x509/x509_att.c | 258 ++++++++++++++++++++++++++++++++++++ crypto/x509/x509_err.c | 6 + doc/man/ca.pod | 2 +- doc/man/req.pod | 27 ++-- 12 files changed, 655 insertions(+), 106 deletions(-) create mode 100644 crypto/x509/x509_att.c 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 +#include +#include "cryptlib.h" +#include +#include +#include +#include +#include + +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"}, {X509_R_UNSUPPORTED_ALGORITHM ,"unsupported algorithm"}, {X509_R_WRONG_LOOKUP_TYPE ,"wrong lookup type"}, +{X509_R_WRONG_TYPE ,"wrong type"}, {0,NULL} }; diff --git a/doc/man/ca.pod b/doc/man/ca.pod index fbc4cbac9a..1f2d6f2916 100644 --- a/doc/man/ca.pod +++ b/doc/man/ca.pod @@ -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. diff --git a/doc/man/req.pod b/doc/man/req.pod index 0211530552..7dbd5d5f0c 100644 --- a/doc/man/req.pod +++ b/doc/man/req.pod @@ -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 + +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, B, B and +B override the configuration file values. + =item B 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 +=item B If this is set to B then if a private key is generated it is B encrypted. This is equivalent to the B<-nodes> command line -option. +option. For compatability B is an equivalent option. =item B @@ -246,19 +253,19 @@ This option specifies the digest algorithm to use. Possible values include B. If not present then MD5 is used. This option can be overridden on the command line. -=item B +=item B -This option specifies which string types are permissible in a -B. 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 which is also the default option uses PrintableStrings, T61Strings and BMPStrings if the B value is used then only PrintableStrings and BMPStrings will be used. This follows the PKIX recommendation in RFC2459. If the B option is used then only UTF8Strings will be used: this -is the PKIX recommendation in RFC2459 after 2003. Finally the B +is the PKIX recommendation in RFC2459 after 2003. Finally the B option just uses PrintableStrings and T61Strings: certain software has -problems with BMPStrings. +problems with BMPStrings and UTF8Strings: in particular Netscape. =item B @@ -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 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 -- 2.34.1