From 74400f7348c589bf9e7cd17f657c05b25f8758b1 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 27 Oct 1999 00:15:11 +0000 Subject: [PATCH] Continued multibyte character support. Add a bunch of functions to simplify the creation of X509_NAME structures. Change the X509_NAME_entry_add stuff in req/ca so it no longer uses X509_NAME_entry_count(): passing -1 has the same effect. --- CHANGES | 18 ++++++++++++++++++ apps/ca.c | 6 ++---- apps/openssl.cnf | 11 +++++++++++ apps/req.c | 28 ++++++++++++++-------------- crypto/asn1/a_mbstr.c | 29 +++++++++++++++++++++++++++++ crypto/asn1/a_strnid.c | 2 +- crypto/asn1/asn1.h | 1 + crypto/x509/x509.h | 10 ++++++++++ crypto/x509/x509_err.c | 2 ++ crypto/x509/x509name.c | 42 ++++++++++++++++++++++++++++++++++++++++++ util/libeay.num | 5 +++++ 11 files changed, 135 insertions(+), 19 deletions(-) diff --git a/CHANGES b/CHANGES index 474319de06..1c4ce47afb 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,24 @@ Changes between 0.9.4 and 0.9.5 [xx XXX 1999] + *) Add a bunch of functions that should simplify the creation of + X509_NAME structures. Now you should be able to do: + X509_NAME_add_entry_by_txt(nm, "CN", MBSTRING_ASC, "Steve", -1, -1, 0); + and have it automatically work out the correct field type and fill in + the structures. The more adventurous can try: + X509_NAME_add_entry_by_txt(nm, field, MBSTRING_UTF8, str, -1, -1, 0); + and it will (hopefully) work out the correct multibyte encoding. + [Steve Henson] + + *) Change the 'req' utility to use the new field handling and multibyte + copy routines. Before the DN field creation was handled in an ad hoc + way in req, ca, and x509 which was rather broken and didn't support + BMPStrings or UTF8Strings. Since some software doesn't implement + BMPStrings or UTF8Strings yet, they can be enabled using the config file + using the dirstring_type option. See the new comment in the default + openssl.cnf for more info. + [Steve Henson] + *) Make crypto/rand/md_rand.c more robust: - Assure unique random numbers after fork(). - Make sure that concurrent threads access the global counter and diff --git a/apps/ca.c b/apps/ca.c index 9cafe400e6..36c314e1c1 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -1691,8 +1691,7 @@ again2: if (push != NULL) { - if (!X509_NAME_add_entry(subject,push, - X509_NAME_entry_count(subject),0)) + if (!X509_NAME_add_entry(subject,push, -1, 0)) { if (push != NULL) X509_NAME_ENTRY_free(push); @@ -2053,8 +2052,7 @@ static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, strlen(buf))) == NULL) goto err; - if (!X509_NAME_add_entry(n,ne,X509_NAME_entry_count(n),0)) - goto err; + if (!X509_NAME_add_entry(n,ne,-1, 0)) goto err; } if (spki == NULL) { diff --git a/apps/openssl.cnf b/apps/openssl.cnf index 8d044fb6b2..33b0866f43 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf @@ -86,6 +86,17 @@ distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert +# This sets the permitted types in a DirectoryString. There are several +# options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nobmp : PrintableString, T61String (no BMPStrings). +# 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 + # req_extensions = v3_req # The extensions to add to a certificate request [ req_distinguished_name ] diff --git a/apps/req.c b/apps/req.c index a945610f92..a395c39f4b 100644 --- a/apps/req.c +++ b/apps/req.c @@ -82,6 +82,7 @@ #define ATTRIBUTES "attributes" #define V3_EXTENSIONS "x509_extensions" #define REQ_EXTENSIONS "req_extensions" +#define DIRSTRING_TYPE "dirstring_type" #define DEFAULT_KEY_LENGTH 512 #define MIN_KEY_LENGTH 384 @@ -452,6 +453,13 @@ bad: } } + p = CONF_get_string(req_conf, SECTION, DIRSTRING_TYPE); + + if(p && !ASN1_STRING_set_default_mask_asc(p)) { + BIO_printf(bio_err, "Invalid DiretoryString setting %s", p); + goto end; + } + if(!req_exts) req_exts = CONF_get_string(req_conf, SECTION, REQ_EXTENSIONS); if(req_exts) { @@ -883,6 +891,9 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, int attribs) ri=req->req_info; + /* setup version number */ + if (!ASN1_INTEGER_set(ri->version,0L)) goto err; /* version 1 */ + 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"); @@ -891,8 +902,6 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, int attribs) BIO_printf(bio_err,"If you enter '.', the field will be left blank.\n"); BIO_printf(bio_err,"-----\n"); - /* setup version number */ - if (!ASN1_INTEGER_set(ri->version,0L)) goto err; /* version 1 */ if (sk_CONF_VALUE_num(sk)) { @@ -1003,8 +1012,7 @@ err: static int add_DN_object(X509_NAME *n, char *text, char *def, char *value, int nid, int min, int max) { - int i,j,ret=0; - X509_NAME_ENTRY *ne=NULL; + int i,ret=0; MS_STATIC char buf[1024]; BIO_printf(bio_err,"%s [%s]:",text,def); @@ -1039,21 +1047,13 @@ static int add_DN_object(X509_NAME *n, char *text, char *def, char *value, } buf[--i]='\0'; - j=ASN1_PRINTABLE_type((unsigned char *)buf,-1); - if (req_fix_data(nid,&j,i,min,max) == 0) - goto err; #ifdef CHARSET_EBCDIC ebcdic2ascii(buf, buf, i); #endif - if ((ne=X509_NAME_ENTRY_create_by_NID(NULL,nid,j,(unsigned char *)buf, - strlen(buf))) - == NULL) goto err; - if (!X509_NAME_add_entry(n,ne,X509_NAME_entry_count(n),0)) - goto err; - + if (!X509_NAME_add_entry_by_NID(n,nid, MBSTRING_ASC, + (unsigned char *) buf, -1,-1,0)) goto err; ret=1; err: - if (ne != NULL) X509_NAME_ENTRY_free(ne); return(ret); } diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c index 2fe658e085..9e7c7c39e5 100644 --- a/crypto/asn1/a_mbstr.c +++ b/crypto/asn1/a_mbstr.c @@ -91,6 +91,35 @@ 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) diff --git a/crypto/asn1/a_strnid.c b/crypto/asn1/a_strnid.c index 520b11883f..cb37024db2 100644 --- a/crypto/asn1/a_strnid.c +++ b/crypto/asn1/a_strnid.c @@ -85,7 +85,7 @@ ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, tbl->minsize, tbl->maxsize); else ret = ASN1_mbstring_copy(out, in, inlen, inform, 0); if(ret <= 0) return NULL; - return str; + return *out; } /* Now the tables and helper functions for the string table: diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index 2a7da6bf4b..8c42101d55 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -744,6 +744,7 @@ void *ASN1_unpack_string(ASN1_STRING *oct, char *(*d2i)()); ASN1_STRING *ASN1_pack_string(void *obj, int (*i2d)(), ASN1_OCTET_STRING **oct); void ASN1_STRING_set_default_mask(unsigned long mask); +int ASN1_STRING_set_default_mask_asc(char *p); unsigned long ASN1_STRING_get_default_mask(void); int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, int inform, unsigned long mask); diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index 64b07e4786..6091ffd4ef 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h @@ -859,8 +859,16 @@ X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc); X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc); int X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne, int loc, int set); +int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set); +int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + char *field, int type, unsigned char *bytes, int len); X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, int type,unsigned char *bytes, int len); +int X509_NAME_add_entry_by_txt(X509_NAME *name, char *field, int type, + unsigned char *bytes, int len, int loc, int set); X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, ASN1_OBJECT *obj, int type,unsigned char *bytes, int len); @@ -979,6 +987,7 @@ PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken); #define X509_F_X509_LOAD_CRL_FILE 112 #define X509_F_X509_NAME_ADD_ENTRY 113 #define X509_F_X509_NAME_ENTRY_CREATE_BY_NID 114 +#define X509_F_X509_NAME_ENTRY_CREATE_BY_TXT 131 #define X509_F_X509_NAME_ENTRY_SET_OBJECT 115 #define X509_F_X509_NAME_ONELINE 116 #define X509_F_X509_NAME_PRINT 117 @@ -1000,6 +1009,7 @@ PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken); #define X509_R_CERT_ALREADY_IN_HASH_TABLE 101 #define X509_R_ERR_ASN1_LIB 102 #define X509_R_INVALID_DIRECTORY 113 +#define X509_R_INVALID_FIELD_NAME 119 #define X509_R_KEY_TYPE_MISMATCH 115 #define X509_R_KEY_VALUES_MISMATCH 116 #define X509_R_LOADING_CERT_DIR 103 diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c index a2a0f1184f..0a0b704043 100644 --- a/crypto/x509/x509_err.c +++ b/crypto/x509/x509_err.c @@ -80,6 +80,7 @@ static ERR_STRING_DATA X509_str_functs[]= {ERR_PACK(0,X509_F_X509_LOAD_CRL_FILE,0), "X509_load_crl_file"}, {ERR_PACK(0,X509_F_X509_NAME_ADD_ENTRY,0), "X509_NAME_add_entry"}, {ERR_PACK(0,X509_F_X509_NAME_ENTRY_CREATE_BY_NID,0), "X509_NAME_ENTRY_create_by_NID"}, +{ERR_PACK(0,X509_F_X509_NAME_ENTRY_CREATE_BY_TXT,0), "X509_NAME_ENTRY_create_by_txt"}, {ERR_PACK(0,X509_F_X509_NAME_ENTRY_SET_OBJECT,0), "X509_NAME_ENTRY_set_object"}, {ERR_PACK(0,X509_F_X509_NAME_ONELINE,0), "X509_NAME_oneline"}, {ERR_PACK(0,X509_F_X509_NAME_PRINT,0), "X509_NAME_print"}, @@ -104,6 +105,7 @@ static ERR_STRING_DATA X509_str_reasons[]= {X509_R_CERT_ALREADY_IN_HASH_TABLE ,"cert already in hash table"}, {X509_R_ERR_ASN1_LIB ,"err asn1 lib"}, {X509_R_INVALID_DIRECTORY ,"invalid directory"}, +{X509_R_INVALID_FIELD_NAME ,"invalid field name"}, {X509_R_KEY_TYPE_MISMATCH ,"key type mismatch"}, {X509_R_KEY_VALUES_MISMATCH ,"key values mismatch"}, {X509_R_LOADING_CERT_DIR ,"loading cert dir"}, diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c index 64c1315495..bd7b985629 100644 --- a/crypto/x509/x509name.c +++ b/crypto/x509/x509name.c @@ -171,6 +171,33 @@ X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc) return(ret); } +int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len); + if(!ne) return 0; + return X509_NAME_add_entry(name, ne, loc, set); +} + +int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); + if(!ne) return 0; + return X509_NAME_add_entry(name, ne, loc, set); +} + +int X509_NAME_add_entry_by_txt(X509_NAME *name, char *field, int type, + unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len); + if(!ne) return 0; + return X509_NAME_add_entry(name, ne, loc, set); +} + /* if set is -1, append to previous set, 0 'a new one', and 1, * prepend to the guy we are about to stomp on. */ int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc, @@ -236,6 +263,21 @@ err: return(0); } +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + char *field, int type, unsigned char *bytes, int len) + { + ASN1_OBJECT *obj; + + obj=OBJ_txt2obj(field, 0); + if (obj == NULL) + { + X509err(X509_F_X509_NAME_ENTRY_CREATE_BY_TXT, + X509_R_INVALID_FIELD_NAME); + return(NULL); + } + return(X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len)); + } + X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, int type, unsigned char *bytes, int len) { diff --git a/util/libeay.num b/util/libeay.num index 04d14eab86..939b6e90f5 100755 --- a/util/libeay.num +++ b/util/libeay.num @@ -1993,3 +1993,8 @@ EVP_PKEY_get_RSA 2017 EVP_PKEY_get_DH 2018 EVP_PKEY_get_DSA 2019 X509_PURPOSE_cleanup 2020 +ASN1_STRING_set_default_mask_asc 2021 +X509_NAME_add_entry_by_txt 2022 +X509_NAME_add_entry_by_NID 2023 +X509_NAME_add_entry_by_OBJ 2024 +X509_NAME_ENTRY_create_by_txt 2025 -- 2.34.1