From 9ea1b87862f286932544180cbf6a80a510266831 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 12 Nov 2002 13:34:51 +0000 Subject: [PATCH] Initial ASN1 generation code. This can construct arbitrary encodings from strings and config files. Documentation to follow... --- apps/asn1pars.c | 115 +++++- crypto/asn1/Makefile.ssl | 4 +- crypto/asn1/asn1.h | 32 ++ crypto/asn1/asn1_err.c | 29 ++ crypto/asn1/asn1_gen.c | 831 +++++++++++++++++++++++++++++++++++++++ crypto/conf/conf.h | 3 +- crypto/ossl_typ.h | 3 + crypto/x509v3/v3_alt.c | 36 +- crypto/x509v3/v3_conf.c | 47 ++- crypto/x509v3/v3err.c | 3 +- crypto/x509v3/x509v3.h | 2 +- 11 files changed, 1076 insertions(+), 29 deletions(-) create mode 100644 crypto/asn1/asn1_gen.c diff --git a/apps/asn1pars.c b/apps/asn1pars.c index 8f178db851..dc41da38a0 100644 --- a/apps/asn1pars.c +++ b/apps/asn1pars.c @@ -82,6 +82,8 @@ int MAIN(int, char **); +static int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf); + int MAIN(int argc, char **argv) { int i,badops=0,offset=0,ret=1,j; @@ -90,6 +92,7 @@ int MAIN(int argc, char **argv) BIO *in=NULL,*out=NULL,*b64=NULL, *derout = NULL; int informat,indent=0, noout = 0, dump = 0; char *infile=NULL,*str=NULL,*prog,*oidfile=NULL, *derfile=NULL; + char *genstr=NULL, *genconf=NULL; unsigned char *tmpbuf; BUF_MEM *buf=NULL; STACK *osk=NULL; @@ -167,6 +170,16 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; sk_push(osk,*(++argv)); } + else if (strcmp(*argv,"-genstr") == 0) + { + if (--argc < 1) goto bad; + genstr= *(++argv); + } + else if (strcmp(*argv,"-genconf") == 0) + { + if (--argc < 1) goto bad; + genconf= *(++argv); + } else { BIO_printf(bio_err,"unknown option %s\n",*argv); @@ -195,6 +208,8 @@ bad: BIO_printf(bio_err," -strparse offset\n"); BIO_printf(bio_err," a series of these can be used to 'dig' into multiple\n"); BIO_printf(bio_err," ASN1 blob wrappings\n"); + BIO_printf(bio_err," -genstr str string to generate ASN1 structure from\n"); + BIO_printf(bio_err," -genconf file file to generate ASN1 structure from\n"); goto end; } @@ -248,25 +263,39 @@ bad: if ((buf=BUF_MEM_new()) == NULL) goto end; if (!BUF_MEM_grow(buf,BUFSIZ*8)) goto end; /* Pre-allocate :-) */ - if (informat == FORMAT_PEM) + if (genstr || genconf) { - BIO *tmp; - - if ((b64=BIO_new(BIO_f_base64())) == NULL) + num = do_generate(bio_err, genstr, genconf, buf); + if (num < 0) + { + ERR_print_errors(bio_err); goto end; - BIO_push(b64,in); - tmp=in; - in=b64; - b64=tmp; + } } - num=0; - for (;;) + else { - if (!BUF_MEM_grow(buf,(int)num+BUFSIZ)) goto end; - i=BIO_read(in,&(buf->data[num]),BUFSIZ); - if (i <= 0) break; - num+=i; + + if (informat == FORMAT_PEM) + { + BIO *tmp; + + if ((b64=BIO_new(BIO_f_base64())) == NULL) + goto end; + BIO_push(b64,in); + tmp=in; + in=b64; + b64=tmp; + } + + num=0; + for (;;) + { + if (!BUF_MEM_grow(buf,(int)num+BUFSIZ)) goto end; + i=BIO_read(in,&(buf->data[num]),BUFSIZ); + if (i <= 0) break; + num+=i; + } } str=buf->data; @@ -335,3 +364,61 @@ end: EXIT(ret); } +static int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf) + { + CONF *cnf = NULL; + int len; + long errline; + unsigned char *p; + ASN1_TYPE *atyp = NULL; + + if (genconf) + { + cnf = NCONF_new(NULL); + if (!NCONF_load(cnf, genconf, &errline)) + goto conferr; + if (!genstr) + genstr = NCONF_get_string(cnf, "default", "asn1"); + if (!genstr) + { + BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf); + goto err; + } + } + + atyp = ASN1_generate_nconf(genstr, cnf); + NCONF_free(cnf); + + if (!atyp) + return -1; + + len = i2d_ASN1_TYPE(atyp, NULL); + + if (len <= 0) + goto err; + + if (!BUF_MEM_grow(buf,len)) + goto err; + + p=(unsigned char *)buf->data; + + i2d_ASN1_TYPE(atyp, &p); + + ASN1_TYPE_free(atyp); + return len; + + conferr: + + if (errline > 0) + BIO_printf(bio, "Error on line %ld of config file '%s'\n", + errline, genconf); + else + BIO_printf(bio, "Error loading config file '%s'\n", genconf); + + err: + NCONF_free(cnf); + ASN1_TYPE_free(atyp); + + return -1; + + } diff --git a/crypto/asn1/Makefile.ssl b/crypto/asn1/Makefile.ssl index ae74b50d40..2f1e64dfe8 100644 --- a/crypto/asn1/Makefile.ssl +++ b/crypto/asn1/Makefile.ssl @@ -33,7 +33,7 @@ LIBSRC= a_object.c a_bitstr.c a_utctm.c a_gentm.c a_time.c a_int.c a_octet.c \ tasn_new.c tasn_fre.c tasn_enc.c tasn_dec.c tasn_utl.c tasn_typ.c \ f_int.c f_string.c n_pkey.c \ f_enum.c a_hdr.c x_pkey.c a_bool.c x_exten.c \ - asn1_par.c asn1_lib.c asn1_err.c a_meth.c a_bytes.c a_strnid.c \ + asn1_gen.c asn1_par.c asn1_lib.c asn1_err.c a_meth.c a_bytes.c a_strnid.c \ evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p8_pkey.c asn_moid.c LIBOBJ= a_object.o a_bitstr.o a_utctm.o a_gentm.o a_time.o a_int.o a_octet.o \ a_print.o a_type.o a_set.o a_dup.o a_d2i_fp.o a_i2d_fp.o \ @@ -45,7 +45,7 @@ LIBOBJ= a_object.o a_bitstr.o a_utctm.o a_gentm.o a_time.o a_int.o a_octet.o \ tasn_new.o tasn_fre.o tasn_enc.o tasn_dec.o tasn_utl.o tasn_typ.o \ f_int.o f_string.o n_pkey.o \ f_enum.o a_hdr.o x_pkey.o a_bool.o x_exten.o \ - asn1_par.o asn1_lib.o asn1_err.o a_meth.o a_bytes.o a_strnid.o \ + asn1_gen.o asn1_par.o asn1_lib.o asn1_err.o a_meth.o a_bytes.o a_strnid.o \ evp_asn1.o asn_pack.o p5_pbe.o p5_pbev2.o p8_pkey.o asn_moid.o SRC= $(LIBSRC) diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index 599cc8bb14..460e0eb6e7 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -949,6 +949,9 @@ int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it void ASN1_add_oid_module(void); +ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf); +ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf); + /* BEGIN ERROR CODES */ /* The following lines are auto generated by the script mkerr.pl. Any changes * made after this point may be overwritten when the script is next run. @@ -962,6 +965,8 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_A2I_ASN1_ENUMERATED 101 #define ASN1_F_A2I_ASN1_INTEGER 102 #define ASN1_F_A2I_ASN1_STRING 103 +#define ASN1_F_APPEND_TAG 177 +#define ASN1_F_ASN1_CB 178 #define ASN1_F_ASN1_CHECK_TLEN 104 #define ASN1_F_ASN1_COLLATE_PRIMITIVE 105 #define ASN1_F_ASN1_COLLECT 106 @@ -972,6 +977,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_ASN1_DUP 111 #define ASN1_F_ASN1_ENUMERATED_SET 112 #define ASN1_F_ASN1_ENUMERATED_TO_BN 113 +#define ASN1_F_ASN1_GENERATE_V3 182 #define ASN1_F_ASN1_GET_OBJECT 114 #define ASN1_F_ASN1_HEADER_NEW 115 #define ASN1_F_ASN1_I2D_BIO 116 @@ -987,6 +993,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_ASN1_SEQ_PACK 126 #define ASN1_F_ASN1_SEQ_UNPACK 127 #define ASN1_F_ASN1_SIGN 128 +#define ASN1_F_ASN1_STR2TYPE 179 #define ASN1_F_ASN1_STRING_TABLE_ADD 129 #define ASN1_F_ASN1_STRING_TYPE_NEW 130 #define ASN1_F_ASN1_TEMPLATE_D2I 131 @@ -996,6 +1003,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_ASN1_TYPE_GET_OCTETSTRING 135 #define ASN1_F_ASN1_UNPACK_STRING 136 #define ASN1_F_ASN1_VERIFY 137 +#define ASN1_F_BITSTR_CB 180 #define ASN1_F_BN_TO_ASN1_ENUMERATED 138 #define ASN1_F_BN_TO_ASN1_INTEGER 139 #define ASN1_F_COLLECT_DATA 140 @@ -1028,6 +1036,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_I2D_RSA_PUBKEY 165 #define ASN1_F_LONG_C2I 166 #define ASN1_F_OID_MODULE_INIT 175 +#define ASN1_F_PARSE_TAGGING 181 #define ASN1_F_PKCS5_PBE2_SET 167 #define ASN1_F_X509_CINF_NEW 168 #define ASN1_F_X509_CRL_ADD0_REVOKED 169 @@ -1050,6 +1059,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_DATA_IS_WRONG 109 #define ASN1_R_DECODE_ERROR 110 #define ASN1_R_DECODING_ERROR 111 +#define ASN1_R_DEPTH_EXCEEDED 173 #define ASN1_R_ENCODE_ERROR 112 #define ASN1_R_ERROR_LOADING_SECTION 172 #define ASN1_R_ERROR_PARSING_SET_ELEMENT 113 @@ -1063,38 +1073,57 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_FIELD_MISSING 121 #define ASN1_R_FIRST_NUM_TOO_LARGE 122 #define ASN1_R_HEADER_TOO_LONG 123 +#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 174 +#define ASN1_R_ILLEGAL_BOOLEAN 175 #define ASN1_R_ILLEGAL_CHARACTERS 124 +#define ASN1_R_ILLEGAL_FORMAT 176 +#define ASN1_R_ILLEGAL_HEX 177 +#define ASN1_R_ILLEGAL_IMPLICIT_TAG 178 +#define ASN1_R_ILLEGAL_INTEGER 179 +#define ASN1_R_ILLEGAL_NESTED_TAGGING 180 #define ASN1_R_ILLEGAL_NULL 125 +#define ASN1_R_ILLEGAL_NULL_VALUE 181 +#define ASN1_R_ILLEGAL_OBJECT 182 #define ASN1_R_ILLEGAL_OPTIONAL_ANY 126 #define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 170 #define ASN1_R_ILLEGAL_TAGGED_ANY 127 +#define ASN1_R_ILLEGAL_TIME_VALUE 183 +#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 184 #define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128 #define ASN1_R_INVALID_BMPSTRING_LENGTH 129 #define ASN1_R_INVALID_DIGIT 130 +#define ASN1_R_INVALID_MODIFIER 185 +#define ASN1_R_INVALID_NUMBER 186 #define ASN1_R_INVALID_SEPARATOR 131 #define ASN1_R_INVALID_TIME_FORMAT 132 #define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 133 #define ASN1_R_INVALID_UTF8STRING 134 #define ASN1_R_IV_TOO_LARGE 135 #define ASN1_R_LENGTH_ERROR 136 +#define ASN1_R_LIST_ERROR 187 #define ASN1_R_MISSING_EOC 137 #define ASN1_R_MISSING_SECOND_NUMBER 138 +#define ASN1_R_MISSING_VALUE 188 #define ASN1_R_MSTRING_NOT_UNIVERSAL 139 #define ASN1_R_MSTRING_WRONG_TAG 140 #define ASN1_R_NON_HEX_CHARACTERS 141 +#define ASN1_R_NOT_ASCII_FORMAT 189 #define ASN1_R_NOT_ENOUGH_DATA 142 #define ASN1_R_NO_MATCHING_CHOICE_TYPE 143 #define ASN1_R_NULL_IS_WRONG_LENGTH 144 +#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 190 #define ASN1_R_ODD_NUMBER_OF_CHARS 145 #define ASN1_R_PRIVATE_KEY_HEADER_MISSING 146 #define ASN1_R_SECOND_NUMBER_TOO_LARGE 147 #define ASN1_R_SEQUENCE_LENGTH_MISMATCH 148 #define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149 +#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 195 #define ASN1_R_SHORT_LINE 150 #define ASN1_R_STRING_TOO_LONG 151 #define ASN1_R_STRING_TOO_SHORT 152 #define ASN1_R_TAG_VALUE_TOO_HIGH 153 #define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154 +#define ASN1_R_TIME_NOT_ASCII_FORMAT 191 #define ASN1_R_TOO_LONG 155 #define ASN1_R_TYPE_NOT_CONSTRUCTED 156 #define ASN1_R_UNABLE_TO_DECODE_RSA_KEY 157 @@ -1104,10 +1133,13 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161 #define ASN1_R_UNKNOWN_OBJECT_TYPE 162 #define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 163 +#define ASN1_R_UNKNOWN_TAG 192 +#define ASN1_R_UNKOWN_FORMAT 193 #define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 164 #define ASN1_R_UNSUPPORTED_CIPHER 165 #define ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM 166 #define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 167 +#define ASN1_R_UNSUPPORTED_TYPE 194 #define ASN1_R_WRONG_TAG 168 #define ASN1_R_WRONG_TYPE 169 diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index d64f987ac6..55aef5e790 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -70,6 +70,8 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_PACK(0,ASN1_F_A2I_ASN1_ENUMERATED,0), "a2i_ASN1_ENUMERATED"}, {ERR_PACK(0,ASN1_F_A2I_ASN1_INTEGER,0), "a2i_ASN1_INTEGER"}, {ERR_PACK(0,ASN1_F_A2I_ASN1_STRING,0), "a2i_ASN1_STRING"}, +{ERR_PACK(0,ASN1_F_APPEND_TAG,0), "APPEND_TAG"}, +{ERR_PACK(0,ASN1_F_ASN1_CB,0), "ASN1_CB"}, {ERR_PACK(0,ASN1_F_ASN1_CHECK_TLEN,0), "ASN1_CHECK_TLEN"}, {ERR_PACK(0,ASN1_F_ASN1_COLLATE_PRIMITIVE,0), "ASN1_COLLATE_PRIMITIVE"}, {ERR_PACK(0,ASN1_F_ASN1_COLLECT,0), "ASN1_COLLECT"}, @@ -80,6 +82,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_PACK(0,ASN1_F_ASN1_DUP,0), "ASN1_dup"}, {ERR_PACK(0,ASN1_F_ASN1_ENUMERATED_SET,0), "ASN1_ENUMERATED_set"}, {ERR_PACK(0,ASN1_F_ASN1_ENUMERATED_TO_BN,0), "ASN1_ENUMERATED_to_BN"}, +{ERR_PACK(0,ASN1_F_ASN1_GENERATE_V3,0), "ASN1_generate_v3"}, {ERR_PACK(0,ASN1_F_ASN1_GET_OBJECT,0), "ASN1_get_object"}, {ERR_PACK(0,ASN1_F_ASN1_HEADER_NEW,0), "ASN1_HEADER_new"}, {ERR_PACK(0,ASN1_F_ASN1_I2D_BIO,0), "ASN1_i2d_bio"}, @@ -95,6 +98,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_PACK(0,ASN1_F_ASN1_SEQ_PACK,0), "ASN1_seq_pack"}, {ERR_PACK(0,ASN1_F_ASN1_SEQ_UNPACK,0), "ASN1_seq_unpack"}, {ERR_PACK(0,ASN1_F_ASN1_SIGN,0), "ASN1_sign"}, +{ERR_PACK(0,ASN1_F_ASN1_STR2TYPE,0), "ASN1_STR2TYPE"}, {ERR_PACK(0,ASN1_F_ASN1_STRING_TABLE_ADD,0), "ASN1_STRING_TABLE_add"}, {ERR_PACK(0,ASN1_F_ASN1_STRING_TYPE_NEW,0), "ASN1_STRING_type_new"}, {ERR_PACK(0,ASN1_F_ASN1_TEMPLATE_D2I,0), "ASN1_TEMPLATE_D2I"}, @@ -104,6 +108,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_PACK(0,ASN1_F_ASN1_TYPE_GET_OCTETSTRING,0), "ASN1_TYPE_get_octetstring"}, {ERR_PACK(0,ASN1_F_ASN1_UNPACK_STRING,0), "ASN1_unpack_string"}, {ERR_PACK(0,ASN1_F_ASN1_VERIFY,0), "ASN1_verify"}, +{ERR_PACK(0,ASN1_F_BITSTR_CB,0), "BITSTR_CB"}, {ERR_PACK(0,ASN1_F_BN_TO_ASN1_ENUMERATED,0), "BN_to_ASN1_ENUMERATED"}, {ERR_PACK(0,ASN1_F_BN_TO_ASN1_INTEGER,0), "BN_to_ASN1_INTEGER"}, {ERR_PACK(0,ASN1_F_COLLECT_DATA,0), "COLLECT_DATA"}, @@ -136,6 +141,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_PACK(0,ASN1_F_I2D_RSA_PUBKEY,0), "i2d_RSA_PUBKEY"}, {ERR_PACK(0,ASN1_F_LONG_C2I,0), "LONG_C2I"}, {ERR_PACK(0,ASN1_F_OID_MODULE_INIT,0), "OID_MODULE_INIT"}, +{ERR_PACK(0,ASN1_F_PARSE_TAGGING,0), "PARSE_TAGGING"}, {ERR_PACK(0,ASN1_F_PKCS5_PBE2_SET,0), "PKCS5_pbe2_set"}, {ERR_PACK(0,ASN1_F_X509_CINF_NEW,0), "X509_CINF_NEW"}, {ERR_PACK(0,ASN1_F_X509_CRL_ADD0_REVOKED,0), "X509_CRL_add0_revoked"}, @@ -161,6 +167,7 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ASN1_R_DATA_IS_WRONG ,"data is wrong"}, {ASN1_R_DECODE_ERROR ,"decode error"}, {ASN1_R_DECODING_ERROR ,"decoding error"}, +{ASN1_R_DEPTH_EXCEEDED ,"depth exceeded"}, {ASN1_R_ENCODE_ERROR ,"encode error"}, {ASN1_R_ERROR_LOADING_SECTION ,"error loading section"}, {ASN1_R_ERROR_PARSING_SET_ELEMENT ,"error parsing set element"}, @@ -174,38 +181,57 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ASN1_R_FIELD_MISSING ,"field missing"}, {ASN1_R_FIRST_NUM_TOO_LARGE ,"first num too large"}, {ASN1_R_HEADER_TOO_LONG ,"header too long"}, +{ASN1_R_ILLEGAL_BITSTRING_FORMAT ,"illegal bitstring format"}, +{ASN1_R_ILLEGAL_BOOLEAN ,"illegal boolean"}, {ASN1_R_ILLEGAL_CHARACTERS ,"illegal characters"}, +{ASN1_R_ILLEGAL_FORMAT ,"illegal format"}, +{ASN1_R_ILLEGAL_HEX ,"illegal hex"}, +{ASN1_R_ILLEGAL_IMPLICIT_TAG ,"illegal implicit tag"}, +{ASN1_R_ILLEGAL_INTEGER ,"illegal integer"}, +{ASN1_R_ILLEGAL_NESTED_TAGGING ,"illegal nested tagging"}, {ASN1_R_ILLEGAL_NULL ,"illegal null"}, +{ASN1_R_ILLEGAL_NULL_VALUE ,"illegal null value"}, +{ASN1_R_ILLEGAL_OBJECT ,"illegal object"}, {ASN1_R_ILLEGAL_OPTIONAL_ANY ,"illegal optional any"}, {ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE ,"illegal options on item template"}, {ASN1_R_ILLEGAL_TAGGED_ANY ,"illegal tagged any"}, +{ASN1_R_ILLEGAL_TIME_VALUE ,"illegal time value"}, +{ASN1_R_INTEGER_NOT_ASCII_FORMAT ,"integer not ascii format"}, {ASN1_R_INTEGER_TOO_LARGE_FOR_LONG ,"integer too large for long"}, {ASN1_R_INVALID_BMPSTRING_LENGTH ,"invalid bmpstring length"}, {ASN1_R_INVALID_DIGIT ,"invalid digit"}, +{ASN1_R_INVALID_MODIFIER ,"invalid modifier"}, +{ASN1_R_INVALID_NUMBER ,"invalid number"}, {ASN1_R_INVALID_SEPARATOR ,"invalid separator"}, {ASN1_R_INVALID_TIME_FORMAT ,"invalid time format"}, {ASN1_R_INVALID_UNIVERSALSTRING_LENGTH ,"invalid universalstring length"}, {ASN1_R_INVALID_UTF8STRING ,"invalid utf8string"}, {ASN1_R_IV_TOO_LARGE ,"iv too large"}, {ASN1_R_LENGTH_ERROR ,"length error"}, +{ASN1_R_LIST_ERROR ,"list error"}, {ASN1_R_MISSING_EOC ,"missing eoc"}, {ASN1_R_MISSING_SECOND_NUMBER ,"missing second number"}, +{ASN1_R_MISSING_VALUE ,"missing value"}, {ASN1_R_MSTRING_NOT_UNIVERSAL ,"mstring not universal"}, {ASN1_R_MSTRING_WRONG_TAG ,"mstring wrong tag"}, {ASN1_R_NON_HEX_CHARACTERS ,"non hex characters"}, +{ASN1_R_NOT_ASCII_FORMAT ,"not ascii format"}, {ASN1_R_NOT_ENOUGH_DATA ,"not enough data"}, {ASN1_R_NO_MATCHING_CHOICE_TYPE ,"no matching choice type"}, {ASN1_R_NULL_IS_WRONG_LENGTH ,"null is wrong length"}, +{ASN1_R_OBJECT_NOT_ASCII_FORMAT ,"object not ascii format"}, {ASN1_R_ODD_NUMBER_OF_CHARS ,"odd number of chars"}, {ASN1_R_PRIVATE_KEY_HEADER_MISSING ,"private key header missing"}, {ASN1_R_SECOND_NUMBER_TOO_LARGE ,"second number too large"}, {ASN1_R_SEQUENCE_LENGTH_MISMATCH ,"sequence length mismatch"}, {ASN1_R_SEQUENCE_NOT_CONSTRUCTED ,"sequence not constructed"}, +{ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG ,"sequence or set needs config"}, {ASN1_R_SHORT_LINE ,"short line"}, {ASN1_R_STRING_TOO_LONG ,"string too long"}, {ASN1_R_STRING_TOO_SHORT ,"string too short"}, {ASN1_R_TAG_VALUE_TOO_HIGH ,"tag value too high"}, {ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD,"the asn1 object identifier is not known for this md"}, +{ASN1_R_TIME_NOT_ASCII_FORMAT ,"time not ascii format"}, {ASN1_R_TOO_LONG ,"too long"}, {ASN1_R_TYPE_NOT_CONSTRUCTED ,"type not constructed"}, {ASN1_R_UNABLE_TO_DECODE_RSA_KEY ,"unable to decode rsa key"}, @@ -215,10 +241,13 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM ,"unknown message digest algorithm"}, {ASN1_R_UNKNOWN_OBJECT_TYPE ,"unknown object type"}, {ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE ,"unknown public key type"}, +{ASN1_R_UNKNOWN_TAG ,"unknown tag"}, +{ASN1_R_UNKOWN_FORMAT ,"unkown format"}, {ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE ,"unsupported any defined by type"}, {ASN1_R_UNSUPPORTED_CIPHER ,"unsupported cipher"}, {ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM ,"unsupported encryption algorithm"}, {ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE ,"unsupported public key type"}, +{ASN1_R_UNSUPPORTED_TYPE ,"unsupported type"}, {ASN1_R_WRONG_TAG ,"wrong tag"}, {ASN1_R_WRONG_TYPE ,"wrong type"}, {0,NULL} diff --git a/crypto/asn1/asn1_gen.c b/crypto/asn1/asn1_gen.c new file mode 100644 index 0000000000..d6f7c9b31e --- /dev/null +++ b/crypto/asn1/asn1_gen.c @@ -0,0 +1,831 @@ +/* asn1_gen.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2002. + */ +/* ==================================================================== + * Copyright (c) 2002 The OpenSSL Project. All rights reserved. + * + * 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 above 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 acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 OpenSSL PROJECT OR + * ITS 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include "cryptlib.h" +#include +#include + +#define ASN1_GEN_FLAG 0x10000 +#define ASN1_GEN_FLAG_IMP (ASN1_GEN_FLAG|1) +#define ASN1_GEN_FLAG_EXP (ASN1_GEN_FLAG|2) +#define ASN1_GEN_FLAG_TAG (ASN1_GEN_FLAG|3) +#define ASN1_GEN_FLAG_BITWRAP (ASN1_GEN_FLAG|4) +#define ASN1_GEN_FLAG_OCTWRAP (ASN1_GEN_FLAG|5) +#define ASN1_GEN_FLAG_SEQWRAP (ASN1_GEN_FLAG|6) +#define ASN1_GEN_FLAG_FORMAT (ASN1_GEN_FLAG|7) + +#define ASN1_GEN_STR(str,val) {str, sizeof(str) - 1, val} + +#define ASN1_FLAG_EXP_MAX 20 + +/* Input formats */ + +/* ASCII: default */ +#define ASN1_GEN_FORMAT_ASCII 1 +/* UTF8 */ +#define ASN1_GEN_FORMAT_UTF8 2 +/* Hex */ +#define ASN1_GEN_FORMAT_HEX 3 +/* List of bits */ +#define ASN1_GEN_FORMAT_BITLIST 4 + + +struct tag_name_st + { + char *strnam; + int len; + int tag; + }; + +typedef struct + { + int exp_tag; + int exp_class; + int exp_constructed; + int exp_pad; + long exp_len; + } tag_exp_type; + +typedef struct + { + int imp_tag; + int imp_class; + int utype; + int format; + const char *str; + tag_exp_type exp_list[ASN1_FLAG_EXP_MAX]; + int exp_count; + } tag_exp_arg; + +static int bitstr_cb(const char *elem, int len, void *bitstr); +static int asn1_cb(const char *elem, int len, void *bitstr); +static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok); +static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass); +static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf); +static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype); +static int asn1_str2tag(const char *tagstr, int len); + +ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf) + { + X509V3_CTX cnf; + + if (!nconf) + return ASN1_generate_v3(str, NULL); + + X509V3_set_nconf(&cnf, nconf); + return ASN1_generate_v3(str, &cnf); + } + +ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf) + { + ASN1_TYPE *ret; + tag_exp_arg asn1_tags; + tag_exp_type *etmp; + + int i, len; + + unsigned char *orig_der = NULL, *new_der = NULL; + unsigned char *cpy_start, *p; + int cpy_len; + long hdr_len; + int hdr_constructed, hdr_tag, hdr_class; + int r; + + asn1_tags.imp_tag = -1; + asn1_tags.imp_class = -1; + asn1_tags.format = ASN1_GEN_FORMAT_ASCII; + asn1_tags.exp_count = 0; + if (CONF_parse_list(str, ',', 1, asn1_cb, &asn1_tags) != 0) + return NULL; + + if ((asn1_tags.utype == V_ASN1_SEQUENCE) || (asn1_tags.utype == V_ASN1_SET)) + { + if (!cnf) + { + ASN1err(ASN1_F_ASN1_GENERATE_V3, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG); + return NULL; + } + ret = asn1_multi(asn1_tags.utype, asn1_tags.str, cnf); + } + else + ret = asn1_str2type(asn1_tags.str, asn1_tags.format, asn1_tags.utype); + + if (!ret) + return NULL; + + /* If no tagging return base type */ + if ((asn1_tags.imp_tag == -1) && (asn1_tags.exp_count == 0)) + return ret; + + /* Generate the encoding */ + cpy_len = i2d_ASN1_TYPE(ret, &orig_der); + ASN1_TYPE_free(ret); + ret = NULL; + /* Set point to start copying for modified encoding */ + cpy_start = orig_der; + + /* Do we need IMPLICIT tagging? */ + if (asn1_tags.imp_tag != -1) + { + /* If IMPLICIT we will replace the underlying tag */ + /* Skip existing tag+len */ + r = ASN1_get_object(&cpy_start, &hdr_len, &hdr_tag, &hdr_class, cpy_len); + if (r & 0x80) + goto err; + /* Update copy length */ + cpy_len -= cpy_start - orig_der; + /* For IMPLICIT tagging the length should match the + * original length and constructed flag should be + * consistent. + */ + if (r & 0x1) + { + /* Indefinite length constructed */ + hdr_constructed = 2; + hdr_len = 0; + } + else + /* Just retain constructed flag */ + hdr_constructed = r & V_ASN1_CONSTRUCTED; + /* Work out new length with IMPLICIT tag: ignore constructed + * because it will mess up if indefinite length + */ + len = ASN1_object_size(0, hdr_len, asn1_tags.imp_tag); + } + else + len = cpy_len; + + /* Work out length in any EXPLICIT, starting from end */ + + for(i = 0, etmp = asn1_tags.exp_list + asn1_tags.exp_count - 1; i < asn1_tags.exp_count; i++, etmp--) + { + /* Content length: number of content octets + any padding */ + len += etmp->exp_pad; + etmp->exp_len = len; + /* Total object length: length including new header */ + len = ASN1_object_size(0, len, etmp->exp_tag); + } + + /* Allocate buffer for new encoding */ + + new_der = OPENSSL_malloc(len); + + /* Generate tagged encoding */ + + p = new_der; + + /* Output explicit tags first */ + + for (i = 0, etmp = asn1_tags.exp_list; i < asn1_tags.exp_count; i++, etmp++) + { + ASN1_put_object(&p, etmp->exp_constructed, etmp->exp_len, + etmp->exp_tag, etmp->exp_class); + if (etmp->exp_pad) + *p++ = 0; + } + + /* If IMPLICIT, output tag */ + + if (asn1_tags.imp_tag != -1) + ASN1_put_object(&p, hdr_constructed, hdr_len, + asn1_tags.imp_tag, asn1_tags.imp_class); + + /* Copy across original encoding */ + memcpy(p, cpy_start, cpy_len); + + p = new_der; + + /* Obtain new ASN1_TYPE structure */ + ret = d2i_ASN1_TYPE(NULL, &p, len); + + err: + if (orig_der) + OPENSSL_free(orig_der); + if (new_der) + OPENSSL_free(new_der); + + return ret; + + } + +static int asn1_cb(const char *elem, int len, void *bitstr) + { + tag_exp_arg *arg = bitstr; + int i; + int utype; + int vlen; + const char *p, *vstart = NULL; + + int tmp_tag, tmp_class; + + for(i = 0, p = elem; i < len; p++, i++) + { + /* Look for the ':' in name value pairs */ + if (*p == ':') + { + vstart = p + 1; + vlen = len - (vstart - elem); + len = p - elem; + break; + } + } + + utype = asn1_str2tag(elem, len); + + if (utype == -1) + { + ASN1err(ASN1_F_ASN1_CB, ASN1_R_UNKNOWN_TAG); + ERR_add_error_data(2, "tag=", elem); + return -1; + } + + /* If this is not a modifier mark end of string and exit */ + if (!(utype & ASN1_GEN_FLAG)) + { + arg->utype = utype; + arg->str = vstart; + /* If no value and not end of string, error */ + if (!vstart && elem[len]) + { + ASN1err(ASN1_F_ASN1_CB, ASN1_R_MISSING_VALUE); + return -1; + } + return 0; + } + + switch(utype) + { + + case ASN1_GEN_FLAG_IMP: + /* Check for illegal multiple IMPLICIT tagging */ + if (arg->imp_tag != -1) + { + ASN1err(ASN1_F_ASN1_CB, ASN1_R_ILLEGAL_NESTED_TAGGING); + return -1; + } + if (!parse_tagging(vstart, vlen, &arg->imp_tag, &arg->imp_class)) + return -1; + break; + + case ASN1_GEN_FLAG_EXP: + + if (!parse_tagging(vstart, vlen, &tmp_tag, &tmp_class)) + return -1; + if (!append_exp(arg, tmp_tag, tmp_class, 1, 0, 0)) + return -1; + break; + + case ASN1_GEN_FLAG_SEQWRAP: + if (!append_exp(arg, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, 1, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_BITWRAP: + if (!append_exp(arg, V_ASN1_BIT_STRING, V_ASN1_UNIVERSAL, 0, 1, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_OCTWRAP: + if (!append_exp(arg, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL, 0, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_FORMAT: + if (!strncmp(vstart, "ASCII", 5)) + arg->format = ASN1_GEN_FORMAT_ASCII; + else if (!strncmp(vstart, "UTF8", 4)) + arg->format = ASN1_GEN_FORMAT_UTF8; + else if (!strncmp(vstart, "HEX", 3)) + arg->format = ASN1_GEN_FORMAT_HEX; + else if (!strncmp(vstart, "BITLIST", 3)) + arg->format = ASN1_GEN_FORMAT_BITLIST; + else + { + ASN1err(ASN1_F_ASN1_CB, ASN1_R_UNKOWN_FORMAT); + return -1; + } + break; + + } + + return 1; + + } + +static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass) + { + char erch[2]; + long tag_num; + char *eptr; + if (!vstart) + return 0; + tag_num = strtoul(vstart, &eptr, 10); + /* Check we haven't gone past max length: should be impossible */ + if (eptr && *eptr && (eptr > vstart + vlen)) + return 0; + if (tag_num < 0) + { + ASN1err(ASN1_F_PARSE_TAGGING, ASN1_R_INVALID_NUMBER); + return 0; + } + *ptag = tag_num; + /* If we have non numeric characters, parse them */ + if (eptr) + vlen -= eptr - vstart; + else + vlen = 0; + if (vlen) + { + switch (*eptr) + { + + case 'U': + *pclass = V_ASN1_UNIVERSAL; + break; + + case 'A': + *pclass = V_ASN1_APPLICATION; + break; + + case 'P': + *pclass = V_ASN1_PRIVATE; + break; + + case 'C': + *pclass = V_ASN1_CONTEXT_SPECIFIC; + break; + + default: + erch[0] = *eptr; + erch[1] = 0; + ASN1err(ASN1_F_PARSE_TAGGING, ASN1_R_INVALID_MODIFIER); + ERR_add_error_data(2, "Char=", erch); + return 0; + break; + + } + } + else + *pclass = V_ASN1_CONTEXT_SPECIFIC; + + return 1; + + } + +/* Handle multiple types: SET and SEQUENCE */ + +static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf) + { + ASN1_TYPE *ret = NULL, *typ = NULL; + STACK_OF(ASN1_TYPE) *sk = NULL; + STACK_OF(CONF_VALUE) *sect = NULL; + unsigned char *der = NULL, *p; + int derlen; + int i, is_set; + sk = sk_ASN1_TYPE_new_null(); + if (section) + { + if (!cnf) + goto bad; + sect = X509V3_get_section(cnf, (char *)section); + if (!sect) + goto bad; + for (i = 0; i < sk_CONF_VALUE_num(sect); i++) + { + typ = ASN1_generate_v3(sk_CONF_VALUE_value(sect, i)->value, cnf); + if (!typ) + goto bad; + sk_ASN1_TYPE_push(sk, typ); + typ = NULL; + } + } + + /* Now we has a STACK of the components, convert to the correct form */ + + if (utype == V_ASN1_SET) + is_set = 1; + else + is_set = 0; + + + derlen = i2d_ASN1_SET((STACK *)sk, NULL, i2d_ASN1_TYPE, utype, V_ASN1_UNIVERSAL, is_set); + der = OPENSSL_malloc(derlen); + p = der; + i2d_ASN1_SET((STACK *)sk, &p, i2d_ASN1_TYPE, utype, V_ASN1_UNIVERSAL, is_set); + + if (!(ret = ASN1_TYPE_new())) + goto bad; + + if (!(ret->value.asn1_string = ASN1_STRING_type_new(utype))) + goto bad; + + ret->type = utype; + + ret->value.asn1_string->data = der; + ret->value.asn1_string->length = derlen; + + der = NULL; + + bad: + + if (der) + OPENSSL_free(der); + + if (sk) + sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); + if (typ) + ASN1_TYPE_free(typ); + if (sect) + X509V3_section_free(cnf, sect); + + return ret; + } + +static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok) + { + tag_exp_type *exp_tmp; + /* Can only have IMPLICIT if permitted */ + if ((arg->imp_tag != -1) && !imp_ok) + { + ASN1err(ASN1_F_APPEND_TAG, ASN1_R_ILLEGAL_IMPLICIT_TAG); + return 0; + } + + if (arg->exp_count == ASN1_FLAG_EXP_MAX) + { + ASN1err(ASN1_F_APPEND_TAG, ASN1_R_DEPTH_EXCEEDED); + return 0; + } + + exp_tmp = &arg->exp_list[arg->exp_count++]; + + /* If IMPLICIT set tag to implicit value then + * reset implicit tag since it has been used. + */ + if (arg->imp_tag != -1) + { + exp_tmp->exp_tag = arg->imp_tag; + exp_tmp->exp_class = arg->imp_class; + arg->imp_tag = -1; + arg->imp_class = -1; + } + else + { + exp_tmp->exp_tag = exp_tag; + exp_tmp->exp_class = exp_class; + } + exp_tmp->exp_constructed = exp_constructed; + exp_tmp->exp_pad = exp_pad; + + return 1; + } + + +static int asn1_str2tag(const char *tagstr, int len) + { + int i; + static struct tag_name_st *tntmp, tnst [] = { + ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN), + ASN1_GEN_STR("BOOLEAN", V_ASN1_BOOLEAN), + ASN1_GEN_STR("NULL", V_ASN1_NULL), + ASN1_GEN_STR("INT", V_ASN1_INTEGER), + ASN1_GEN_STR("INTEGER", V_ASN1_INTEGER), + ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED), + ASN1_GEN_STR("ENUMERATED", V_ASN1_ENUMERATED), + ASN1_GEN_STR("OID", V_ASN1_OBJECT), + ASN1_GEN_STR("OBJECT", V_ASN1_OBJECT), + ASN1_GEN_STR("UTCTIME", V_ASN1_UTCTIME), + ASN1_GEN_STR("UTC", V_ASN1_UTCTIME), + ASN1_GEN_STR("GENERALIZEDTIME", V_ASN1_GENERALIZEDTIME), + ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME), + ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING), + ASN1_GEN_STR("OCTETSTRING", V_ASN1_OCTET_STRING), + ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING), + ASN1_GEN_STR("BITSTRING", V_ASN1_BIT_STRING), + ASN1_GEN_STR("UNIVERSALSTRING", V_ASN1_UNIVERSALSTRING), + ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING), + ASN1_GEN_STR("IA5", V_ASN1_IA5STRING), + ASN1_GEN_STR("IA5STRING", V_ASN1_IA5STRING), + ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING), + ASN1_GEN_STR("UTF8String", V_ASN1_UTF8STRING), + ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING), + ASN1_GEN_STR("BMPSTRING", V_ASN1_BMPSTRING), + ASN1_GEN_STR("VISIBLESTRING", V_ASN1_VISIBLESTRING), + ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING), + ASN1_GEN_STR("PRINTABLESTRING", V_ASN1_PRINTABLESTRING), + ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING), + ASN1_GEN_STR("T61", V_ASN1_T61STRING), + ASN1_GEN_STR("T61STRING", V_ASN1_T61STRING), + ASN1_GEN_STR("TELETEXSTRING", V_ASN1_T61STRING), + + /* Special cases */ + ASN1_GEN_STR("SEQUENCE", V_ASN1_SEQUENCE), + ASN1_GEN_STR("SEQ", V_ASN1_SEQUENCE), + ASN1_GEN_STR("SET", V_ASN1_SET), + /* type modifiers */ + /* Explicit tag */ + ASN1_GEN_STR("EXP", ASN1_GEN_FLAG_EXP), + ASN1_GEN_STR("EXPLICIT", ASN1_GEN_FLAG_EXP), + /* Implicit tag */ + ASN1_GEN_STR("IMP", ASN1_GEN_FLAG_IMP), + ASN1_GEN_STR("IMPLICIT", ASN1_GEN_FLAG_IMP), + /* OCTET STRING wrapper */ + ASN1_GEN_STR("OCTWRAP", ASN1_GEN_FLAG_OCTWRAP), + /* SEQUENCE wrapper */ + ASN1_GEN_STR("SEQWRAP", ASN1_GEN_FLAG_SEQWRAP), + /* BIT STRING wrapper */ + ASN1_GEN_STR("BITWRAP", ASN1_GEN_FLAG_BITWRAP), + ASN1_GEN_STR("FORM", ASN1_GEN_FLAG_FORMAT), + ASN1_GEN_STR("FORMAT", ASN1_GEN_FLAG_FORMAT), + }; + + if (len == -1) + len = strlen(tagstr); + + tntmp = tnst; + for (i = 0; i < sizeof(tnst) / sizeof(struct tag_name_st); i++, tntmp++) + { + if (!strncmp(tntmp->strnam, tagstr, tntmp->len)) + return tntmp->tag; + } + + return -1; + } + +static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype) + { + ASN1_TYPE *atmp = NULL; + + CONF_VALUE vtmp; + + unsigned char *rdata; + long rdlen; + + int no_unused = 1; + + if (!(atmp = ASN1_TYPE_new())) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!str) + str = ""; + + switch(utype) + { + + case V_ASN1_NULL: + if (str && *str) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_NULL_VALUE); + goto bad_form; + } + break; + + case V_ASN1_BOOLEAN: + if (format != ASN1_GEN_FORMAT_ASCII) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_NOT_ASCII_FORMAT); + goto bad_form; + } + vtmp.value = (char *)str; + if (!X509V3_get_value_bool(&vtmp, &atmp->value.boolean)) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_BOOLEAN); + goto bad_str; + } + break; + + case V_ASN1_INTEGER: + case V_ASN1_ENUMERATED: + if (format != ASN1_GEN_FORMAT_ASCII) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_INTEGER_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.integer = s2i_ASN1_INTEGER(NULL, (char *)str))) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_INTEGER); + goto bad_str; + } + break; + + case V_ASN1_OBJECT: + if (format != ASN1_GEN_FORMAT_ASCII) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_OBJECT_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.object = OBJ_txt2obj(str, 0))) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_OBJECT); + goto bad_str; + } + break; + + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + if (format != ASN1_GEN_FORMAT_ASCII) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_TIME_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.asn1_string = ASN1_STRING_new())) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + atmp->value.asn1_string->type = utype; + if (!ASN1_TIME_check(atmp->value.asn1_string)) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_TIME_VALUE); + goto bad_str; + } + + break; + + case V_ASN1_BMPSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_IA5STRING: + case V_ASN1_T61STRING: + case V_ASN1_UTF8STRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_UNIVERSALSTRING: + + if (format == ASN1_GEN_FORMAT_ASCII) + format = MBSTRING_ASC; + else if (format == ASN1_GEN_FORMAT_UTF8) + format = MBSTRING_UTF8; + else + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_FORMAT); + goto bad_form; + } + + + if (ASN1_mbstring_copy(&atmp->value.asn1_string, (unsigned char *)str, + -1, format, ASN1_tag2bit(utype)) <= 0) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + + + break; + + case V_ASN1_BIT_STRING: + + case V_ASN1_OCTET_STRING: + + if (!(atmp->value.asn1_string = ASN1_STRING_new())) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ERR_R_MALLOC_FAILURE); + goto bad_form; + } + + if (format == ASN1_GEN_FORMAT_HEX) + { + + if (!(rdata = string_to_hex((char *)str, &rdlen))) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_HEX); + goto bad_str; + } + + atmp->value.asn1_string->data = rdata; + atmp->value.asn1_string->length = rdlen; + atmp->value.asn1_string->type = utype; + + } + else if (format == ASN1_GEN_FORMAT_ASCII) + ASN1_STRING_set(atmp->value.asn1_string, str, -1); + else if ((format == ASN1_GEN_FORMAT_BITLIST) && (utype == V_ASN1_BIT_STRING)) + { + if (!CONF_parse_list(str, ',', 1, bitstr_cb, atmp->value.bit_string)) + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_LIST_ERROR); + goto bad_str; + } + no_unused = 0; + + } + else + { + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_ILLEGAL_BITSTRING_FORMAT); + goto bad_form; + } + + if ((utype == V_ASN1_BIT_STRING) && no_unused) + { + atmp->value.asn1_string->flags + &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + atmp->value.asn1_string->flags + |= ASN1_STRING_FLAG_BITS_LEFT; + } + + + break; + + default: + ASN1err(ASN1_F_ASN1_STR2TYPE, ASN1_R_UNSUPPORTED_TYPE); + goto bad_str; + break; + } + + + atmp->type = utype; + return atmp; + + + bad_str: + ERR_add_error_data(2, "string=", str); + bad_form: + + ASN1_TYPE_free(atmp); + return NULL; + + } + +static int bitstr_cb(const char *elem, int len, void *bitstr) + { + long bitnum; + char *eptr; + if (!elem) + return 0; + bitnum = strtoul(elem, &eptr, 10); + if (eptr && *eptr && (eptr != elem + len)) + return 0; + if (bitnum < 0) + { + ASN1err(ASN1_F_BITSTR_CB, ASN1_R_INVALID_NUMBER); + return 0; + } + if (!ASN1_BIT_STRING_set_bit(bitstr, bitnum, 1)) + { + ASN1err(ASN1_F_BITSTR_CB, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; + } + diff --git a/crypto/conf/conf.h b/crypto/conf/conf.h index f4671442ab..48695a0642 100644 --- a/crypto/conf/conf.h +++ b/crypto/conf/conf.h @@ -65,6 +65,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -81,7 +83,6 @@ DECLARE_STACK_OF(CONF_MODULE) DECLARE_STACK_OF(CONF_IMODULE) struct conf_st; -typedef struct conf_st CONF; struct conf_method_st; typedef struct conf_method_st CONF_METHOD; diff --git a/crypto/ossl_typ.h b/crypto/ossl_typ.h index 6bd42aee4d..420d5e68fb 100644 --- a/crypto/ossl_typ.h +++ b/crypto/ossl_typ.h @@ -111,6 +111,9 @@ typedef struct X509_name_st X509_NAME; typedef struct x509_store_st X509_STORE; typedef struct x509_store_ctx_st X509_STORE_CTX; +typedef struct v3_ext_ctx X509V3_CTX; +typedef struct conf_st CONF; + typedef struct engine_st ENGINE; /* If placed in pkcs12.h, we end up with a circular depency with pkcs7.h */ diff --git a/crypto/x509v3/v3_alt.c b/crypto/x509v3/v3_alt.c index 0e9e7dcb4f..baa9ca103d 100644 --- a/crypto/x509v3/v3_alt.c +++ b/crypto/x509v3/v3_alt.c @@ -3,7 +3,7 @@ * project 1999. */ /* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -65,6 +65,8 @@ static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p); static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens); +static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx); + X509V3_EXT_METHOD v3_alt[] = { { NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), 0,0,0,0, @@ -432,6 +434,13 @@ if(!name_cmp(name, "email")) { goto err; } type = GEN_IPADD; +} else if(!name_cmp(name, "otherName")) { + if (!do_othername(gen, value, ctx)) + { + X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_OTHERNAME_ERROR); + goto err; + } + type = GEN_OTHERNAME; } else { X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_UNSUPPORTED_OPTION); ERR_add_error_data(2, "name=", name); @@ -455,3 +464,28 @@ err: GENERAL_NAME_free(gen); return NULL; } + +static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) + { + char *objtmp = NULL, *p; + int objlen; + if (!(p = strchr(value, ';'))) + return 0; + if (!(gen->d.otherName = OTHERNAME_new())) + return 0; + /* Free this up because we will overwrite it. + * no need to free type_id because it is static + */ + ASN1_TYPE_free(gen->d.otherName->value); + if (!(gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx))) + return 0; + objlen = p - value; + objtmp = OPENSSL_malloc(objlen + 1); + strncpy(objtmp, value, objlen); + objtmp[objlen] = 0; + gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0); + OPENSSL_free(objtmp); + if (!gen->d.otherName->type_id) + return 0; + return 1; + } diff --git a/crypto/x509v3/v3_conf.c b/crypto/x509v3/v3_conf.c index 1a3448e121..372c65d885 100644 --- a/crypto/x509v3/v3_conf.c +++ b/crypto/x509v3/v3_conf.c @@ -3,7 +3,7 @@ * project 1999. */ /* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -69,11 +69,12 @@ static int v3_check_critical(char **value); static int v3_check_generic(char **value); static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, int crit, char *value); -static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, int crit, int type); +static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, int crit, int type, X509V3_CTX *ctx); static char *conf_lhash_get_string(void *db, char *section, char *value); static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, char *section); static X509_EXTENSION *do_ext_i2d(X509V3_EXT_METHOD *method, int ext_nid, int crit, void *ext_struc); +static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len); /* CONF *conf: Config file */ /* char *name: Name */ /* char *value: Value */ @@ -85,7 +86,7 @@ X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, X509_EXTENSION *ret; crit = v3_check_critical(&value); if ((ext_type = v3_check_generic(&value))) - return v3_generic_extension(name, value, crit, ext_type); + return v3_generic_extension(name, value, crit, ext_type, ctx); ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value); if (!ret) { @@ -105,7 +106,7 @@ X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, crit = v3_check_critical(&value); if ((ext_type = v3_check_generic(&value))) return v3_generic_extension(OBJ_nid2sn(ext_nid), - value, crit, ext_type); + value, crit, ext_type, ctx); return do_ext_nconf(conf, ctx, ext_nid, crit, value); } @@ -235,17 +236,29 @@ static int v3_check_critical(char **value) /* Check extension string for generic extension and return the type */ static int v3_check_generic(char **value) { + int gen_type = 0; char *p = *value; - if ((strlen(p) < 4) || strncmp(p, "DER:,", 4)) return 0; - p+=4; + if ((strlen(p) >= 4) && !strncmp(p, "DER:,", 4)) + { + p+=4; + gen_type = 1; + } + if ((strlen(p) >= 5) && !strncmp(p, "ASN1:,", 5)) + { + p+=5; + gen_type = 2; + } + else + return 0; + while (isspace((unsigned char)*p)) p++; *value = p; - return 1; + return gen_type; } /* Create a generic extension: for now just handle DER type */ static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, - int crit, int type) + int crit, int gen_type, X509V3_CTX *ctx) { unsigned char *ext_der=NULL; long ext_len; @@ -259,7 +272,12 @@ static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, goto err; } - if (!(ext_der = string_to_hex(value, &ext_len))) + if (gen_type == 1) + ext_der = string_to_hex(value, &ext_len); + else if (gen_type == 2) + ext_der = generic_asn1(value, ctx, &ext_len); + + if (ext_der == NULL) { X509V3err(X509V3_F_V3_GENERIC_EXTENSION,X509V3_R_EXTENSION_VALUE_ERROR); ERR_add_error_data(2, "value=", value); @@ -286,6 +304,17 @@ static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, } +static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len) + { + ASN1_TYPE *typ; + unsigned char *ext_der = NULL; + typ = ASN1_generate_v3(value, ctx); + if (typ == NULL) + return NULL; + *ext_len = i2d_ASN1_TYPE(typ, &ext_der); + ASN1_TYPE_free(typ); + return ext_der; + } /* This is the main function: add a bunch of extensions based on a config file * section to an extension STACK. diff --git a/crypto/x509v3/v3err.c b/crypto/x509v3/v3err.c index 6458e95bb9..3cb543e629 100644 --- a/crypto/x509v3/v3err.c +++ b/crypto/x509v3/v3err.c @@ -1,6 +1,6 @@ /* crypto/x509v3/v3err.c */ /* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -152,6 +152,7 @@ static ERR_STRING_DATA X509V3_str_reasons[]= {X509V3_R_NO_PUBLIC_KEY ,"no public key"}, {X509V3_R_NO_SUBJECT_DETAILS ,"no subject details"}, {X509V3_R_ODD_NUMBER_OF_DIGITS ,"odd number of digits"}, +{X509V3_R_OTHERNAME_ERROR ,"othername error"}, {X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS ,"unable to get issuer details"}, {X509V3_R_UNABLE_TO_GET_ISSUER_KEYID ,"unable to get issuer keyid"}, {X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT ,"unknown bit string argument"}, diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h index daecc55271..e1334b4717 100644 --- a/crypto/x509v3/x509v3.h +++ b/crypto/x509v3/x509v3.h @@ -132,7 +132,6 @@ void *db; }; typedef struct v3_ext_method X509V3_EXT_METHOD; -typedef struct v3_ext_ctx X509V3_CTX; DECLARE_STACK_OF(X509V3_EXT_METHOD) @@ -640,6 +639,7 @@ void ERR_load_X509V3_strings(void); #define X509V3_R_NO_PUBLIC_KEY 114 #define X509V3_R_NO_SUBJECT_DETAILS 125 #define X509V3_R_ODD_NUMBER_OF_DIGITS 112 +#define X509V3_R_OTHERNAME_ERROR 147 #define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 122 #define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 123 #define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 111