Support for certificateIssuer CRL entry extension.
[openssl.git] / crypto / x509v3 / v3_alt.c
index f0f64d76a32391b44c96e3d211a212ce5dcea463..2c2d6c44421a8d83494bf3cdca3de41d3e1688ce 100644 (file)
@@ -1,9 +1,9 @@
 /* v3_alt.c */
 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
- * project 1999.
+ * project.
  */
 /* ====================================================================
- * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2003 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
 #include <openssl/conf.h>
 #include <openssl/x509v3.h>
 
-static STACK_OF(GENERAL_NAME) *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK *nval);
-static STACK_OF(GENERAL_NAME) *v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK *nval);
-static int copy_email(X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *gens);
-static int copy_issuer(X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *gens);
-X509V3_EXT_METHOD v3_alt[] = {
-{ NID_subject_alt_name, 0,
-(X509V3_EXT_NEW)GENERAL_NAMES_new,
-GENERAL_NAMES_free,
-(X509V3_EXT_D2I)d2i_GENERAL_NAMES,
-i2d_GENERAL_NAMES,
-NULL, NULL,
+static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+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);
+static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx);
+
+const X509V3_EXT_METHOD v3_alt[] = {
+{ NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+0,0,0,0,
+0,0,
 (X509V3_EXT_I2V)i2v_GENERAL_NAMES,
 (X509V3_EXT_V2I)v2i_subject_alt,
 NULL, NULL, NULL},
-{ NID_issuer_alt_name, 0,
-(X509V3_EXT_NEW)GENERAL_NAMES_new,
-GENERAL_NAMES_free,
-(X509V3_EXT_D2I)d2i_GENERAL_NAMES,
-i2d_GENERAL_NAMES,
-NULL, NULL,
+
+{ NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+0,0,0,0,
+0,0,
 (X509V3_EXT_I2V)i2v_GENERAL_NAMES,
 (X509V3_EXT_V2I)v2i_issuer_alt,
 NULL, NULL, NULL},
-EXT_END
+
+{ NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+0,0,0,0,
+0,0,
+(X509V3_EXT_I2V)i2v_GENERAL_NAMES,
+NULL, NULL, NULL, NULL},
 };
 
-STACK *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
-                                STACK_OF(GENERAL_NAME) *gens, STACK *ret)
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+               GENERAL_NAMES *gens, STACK_OF(CONF_VALUE) *ret)
 {
        int i;
        GENERAL_NAME *gen;
@@ -96,15 +99,16 @@ STACK *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
                gen = sk_GENERAL_NAME_value(gens, i);
                ret = i2v_GENERAL_NAME(method, gen, ret);
        }
-       if(!ret) return sk_new_null();
+       if(!ret) return sk_CONF_VALUE_new_null();
        return ret;
 }
 
-STACK *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen,
-                                                                STACK *ret)
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
+                               GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret)
 {
-       char oline[256];
        unsigned char *p;
+       char oline[256], htmp[5];
+       int i;
        switch (gen->type)
        {
                case GEN_OTHERNAME:
@@ -138,12 +142,27 @@ STACK *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen,
 
                case GEN_IPADD:
                p = gen->d.ip->data;
-               /* BUG: doesn't support IPV6 */
-               if(gen->d.ip->length != 4) {
+               if(gen->d.ip->length == 4)
+                       BIO_snprintf(oline, sizeof oline,
+                                    "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+               else if(gen->d.ip->length == 16)
+                       {
+                       oline[0] = 0;
+                       for (i = 0; i < 8; i++)
+                               {
+                               BIO_snprintf(htmp, sizeof htmp,
+                                            "%X", p[0] << 8 | p[1]);
+                               p += 2;
+                               strcat(oline, htmp);
+                               if (i != 7)
+                                       strcat(oline, ":");
+                               }
+                       }
+               else
+                       {
                        X509V3_add_value("IP Address","<invalid>", &ret);
                        break;
-               }
-               sprintf(oline, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+                       }
                X509V3_add_value("IP Address",oline, &ret);
                break;
 
@@ -155,18 +174,84 @@ STACK *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen,
        return ret;
 }
 
-static STACK_OF(GENERAL_NAME) *v2i_issuer_alt(X509V3_EXT_METHOD *method,
-                                                X509V3_CTX *ctx, STACK *nval)
+int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
+{
+       unsigned char *p;
+       int i;
+       switch (gen->type)
+       {
+               case GEN_OTHERNAME:
+               BIO_printf(out, "othername:<unsupported>");
+               break;
+
+               case GEN_X400:
+               BIO_printf(out, "X400Name:<unsupported>");
+               break;
+
+               case GEN_EDIPARTY:
+               /* Maybe fix this: it is supported now */
+               BIO_printf(out, "EdiPartyName:<unsupported>");
+               break;
+
+               case GEN_EMAIL:
+               BIO_printf(out, "email:%s",gen->d.ia5->data);
+               break;
+
+               case GEN_DNS:
+               BIO_printf(out, "DNS:%s",gen->d.ia5->data);
+               break;
+
+               case GEN_URI:
+               BIO_printf(out, "URI:%s",gen->d.ia5->data);
+               break;
+
+               case GEN_DIRNAME:
+               BIO_printf(out, "DirName: ");
+               X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE);
+               break;
+
+               case GEN_IPADD:
+               p = gen->d.ip->data;
+               if(gen->d.ip->length == 4)
+                       BIO_printf(out, "IP Address:%d.%d.%d.%d",
+                                               p[0], p[1], p[2], p[3]);
+               else if(gen->d.ip->length == 16)
+                       {
+                       BIO_printf(out, "IP Address");
+                       for (i = 0; i < 8; i++)
+                               {
+                               BIO_printf(out, ":%X", p[0] << 8 | p[1]);
+                               p += 2;
+                               }
+                       BIO_puts(out, "\n");
+                       }
+               else
+                       {
+                       BIO_printf(out,"IP Address:<invalid>");
+                       break;
+                       }
+               break;
+
+               case GEN_RID:
+               BIO_printf(out, "Registered ID");
+               i2a_ASN1_OBJECT(out, gen->d.rid);
+               break;
+       }
+       return 1;
+}
+
+static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method,
+                                X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
 {
-       STACK_OF(GENERAL_NAME) *gens = NULL;
+       GENERAL_NAMES *gens = NULL;
        CONF_VALUE *cnf;
        int i;
-       if(!(gens = sk_GENERAL_NAME_new(NULL))) {
-               X509V3err(X509V3_F_V2I_GENERAL_NAMES,ERR_R_MALLOC_FAILURE);
+       if(!(gens = sk_GENERAL_NAME_new_null())) {
+               X509V3err(X509V3_F_V2I_ISSUER_ALT,ERR_R_MALLOC_FAILURE);
                return NULL;
        }
-       for(i = 0; i < sk_num(nval); i++) {
-               cnf = (CONF_VALUE *)sk_value(nval, i);
+       for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+               cnf = sk_CONF_VALUE_value(nval, i);
                if(!name_cmp(cnf->name, "issuer") && cnf->value &&
                                                !strcmp(cnf->value, "copy")) {
                        if(!copy_issuer(ctx, gens)) goto err;
@@ -185,9 +270,9 @@ static STACK_OF(GENERAL_NAME) *v2i_issuer_alt(X509V3_EXT_METHOD *method,
 
 /* Append subject altname of issuer to issuer alt name of subject */
 
-static int copy_issuer(X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *gens)
+static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens)
 {
-       STACK_OF(GENERAL_NAME) *ialt;
+       GENERAL_NAMES *ialt;
        GENERAL_NAME *gen;
        X509_EXTENSION *ext;
        int i;
@@ -220,21 +305,24 @@ static int copy_issuer(X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *gens)
        
 }
 
-static STACK_OF(GENERAL_NAME) *v2i_subject_alt(X509V3_EXT_METHOD *method,
-                                                X509V3_CTX *ctx, STACK *nval)
+static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
+                                X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
 {
-       STACK_OF(GENERAL_NAME) *gens = NULL;
+       GENERAL_NAMES *gens = NULL;
        CONF_VALUE *cnf;
        int i;
-       if(!(gens = sk_GENERAL_NAME_new(NULL))) {
-               X509V3err(X509V3_F_V2I_GENERAL_NAMES,ERR_R_MALLOC_FAILURE);
+       if(!(gens = sk_GENERAL_NAME_new_null())) {
+               X509V3err(X509V3_F_V2I_SUBJECT_ALT,ERR_R_MALLOC_FAILURE);
                return NULL;
        }
-       for(i = 0; i < sk_num(nval); i++) {
-               cnf = (CONF_VALUE *)sk_value(nval, i);
+       for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+               cnf = sk_CONF_VALUE_value(nval, i);
                if(!name_cmp(cnf->name, "email") && cnf->value &&
                                                !strcmp(cnf->value, "copy")) {
-                       if(!copy_email(ctx, gens)) goto err;
+                       if(!copy_email(ctx, gens, 0)) goto err;
+               } else if(!name_cmp(cnf->name, "email") && cnf->value &&
+                                               !strcmp(cnf->value, "move")) {
+                       if(!copy_email(ctx, gens, 1)) goto err;
                } else {
                        GENERAL_NAME *gen;
                        if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf)))
@@ -252,14 +340,15 @@ static STACK_OF(GENERAL_NAME) *v2i_subject_alt(X509V3_EXT_METHOD *method,
  * GENERAL_NAMES
  */
 
-static int copy_email(X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *gens)
+static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p)
 {
        X509_NAME *nm;
        ASN1_IA5STRING *email = NULL;
        X509_NAME_ENTRY *ne;
        GENERAL_NAME *gen = NULL;
        int i;
-       if(ctx->flags == CTX_TEST) return 1;
+       if(ctx != NULL && ctx->flags == CTX_TEST)
+               return 1;
        if(!ctx || (!ctx->subject_cert && !ctx->subject_req)) {
                X509V3err(X509V3_F_COPY_EMAIL,X509V3_R_NO_SUBJECT_DETAILS);
                goto err;
@@ -271,9 +360,14 @@ static int copy_email(X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *gens)
        /* Now add any email address(es) to STACK */
        i = -1;
        while((i = X509_NAME_get_index_by_NID(nm,
-                                        NID_pkcs9_emailAddress, i)) > 0) {
+                                        NID_pkcs9_emailAddress, i)) >= 0) {
                ne = X509_NAME_get_entry(nm, i);
-               email = ASN1_IA5STRING_dup(X509_NAME_ENTRY_get_data(ne));
+               email = M_ASN1_IA5STRING_dup(X509_NAME_ENTRY_get_data(ne));
+                if (move_p)
+                        {
+                        X509_NAME_delete_entry(nm, i);
+                        i--;
+                        }
                if(!email || !(gen = GENERAL_NAME_new())) {
                        X509V3err(X509V3_F_COPY_EMAIL,ERR_R_MALLOC_FAILURE);
                        goto err;
@@ -293,24 +387,24 @@ static int copy_email(X509V3_CTX *ctx, STACK_OF(GENERAL_NAME) *gens)
                
        err:
        GENERAL_NAME_free(gen);
-       ASN1_IA5STRING_free(email);
+       M_ASN1_IA5STRING_free(email);
        return 0;
        
 }
 
-STACK_OF(GENERAL_NAME) *v2i_GENERAL_NAMES(X509V3_EXT_METHOD *method,
-                                                X509V3_CTX *ctx, STACK *nval)
+GENERAL_NAMES *v2i_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+                               X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
 {
        GENERAL_NAME *gen;
-       STACK_OF(GENERAL_NAME) *gens = NULL;
+       GENERAL_NAMES *gens = NULL;
        CONF_VALUE *cnf;
        int i;
-       if(!(gens = sk_GENERAL_NAME_new(NULL))) {
+       if(!(gens = sk_GENERAL_NAME_new_null())) {
                X509V3err(X509V3_F_V2I_GENERAL_NAMES,ERR_R_MALLOC_FAILURE);
                return NULL;
        }
-       for(i = 0; i < sk_num(nval); i++) {
-               cnf = (CONF_VALUE *)sk_value(nval, i);
+       for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+               cnf = sk_CONF_VALUE_value(nval, i);
                if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) goto err; 
                sk_GENERAL_NAME_push(gens, gen);
        }
@@ -322,81 +416,194 @@ STACK_OF(GENERAL_NAME) *v2i_GENERAL_NAMES(X509V3_EXT_METHOD *method,
 
 GENERAL_NAME *v2i_GENERAL_NAME(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
                                                         CONF_VALUE *cnf)
-{
-char is_string = 0;
-int type;
-GENERAL_NAME *gen = NULL;
+       {
+       return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0);
+       }
 
-char *name, *value;
+GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,
+                               X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+                               int gen_type, char *value, int is_nc)
+       {
+       char is_string = 0;
+       GENERAL_NAME *gen = NULL;
 
-name = cnf->name;
-value = cnf->value;
+       if(!value)
+               {
+               X509V3err(X509V3_F_A2I_GENERAL_NAME,X509V3_R_MISSING_VALUE);
+               return NULL;
+               }
 
-if(!value) {
-       X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_MISSING_VALUE);
-       return NULL;
-}
+       if (out)
+               gen = out;
+       else
+               {
+               gen = GENERAL_NAME_new();
+               if(gen == NULL)
+                       {
+                       X509V3err(X509V3_F_A2I_GENERAL_NAME,ERR_R_MALLOC_FAILURE);
+                       return NULL;
+                       }
+               }
 
-if(!(gen = GENERAL_NAME_new())) {
-       X509V3err(X509V3_F_V2I_GENERAL_NAME,ERR_R_MALLOC_FAILURE);
-       return NULL;
-}
+       switch (gen_type)
+               {
+               case GEN_URI:
+               case GEN_EMAIL:
+               case GEN_DNS:
+               is_string = 1;
+               break;
+               
+               case GEN_RID:
+               {
+               ASN1_OBJECT *obj;
+               if(!(obj = OBJ_txt2obj(value,0)))
+                       {
+                       X509V3err(X509V3_F_A2I_GENERAL_NAME,X509V3_R_BAD_OBJECT);
+                       ERR_add_error_data(2, "value=", value);
+                       goto err;
+                       }
+               gen->d.rid = obj;
+               }
 
-if(!name_cmp(name, "email")) {
-       is_string = 1;
-       type = GEN_EMAIL;
-} else if(!name_cmp(name, "URI")) {
-       is_string = 1;
-       type = GEN_URI;
-} else if(!name_cmp(name, "DNS")) {
-       is_string = 1;
-       type = GEN_DNS;
-} else if(!name_cmp(name, "RID")) {
-       ASN1_OBJECT *obj;
-       if(!(obj = OBJ_txt2obj(value,0))) {
-               X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_BAD_OBJECT);
-               ERR_add_error_data(2, "value=", value);
-               goto err;
-       }
-       gen->d.rid = obj;
-       type = GEN_RID;
-} else if(!name_cmp(name, "IP")) {
-       int i1,i2,i3,i4;
-       unsigned char ip[4];
-       if((sscanf(value, "%d.%d.%d.%d",&i1,&i2,&i3,&i4) != 4) ||
-           (i1 < 0) || (i1 > 255) || (i2 < 0) || (i2 > 255) ||
-           (i3 < 0) || (i3 > 255) || (i4 < 0) || (i4 > 255) ) {
-               X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_BAD_IP_ADDRESS);
-               ERR_add_error_data(2, "value=", value);
-               goto err;
-       }
-       ip[0] = i1; ip[1] = i2 ; ip[2] = i3 ; ip[3] = i4;
-       if(!(gen->d.ip = ASN1_OCTET_STRING_new()) ||
-               !ASN1_STRING_set(gen->d.ip, ip, 4)) {
-                       X509V3err(X509V3_F_V2I_GENERAL_NAME,ERR_R_MALLOC_FAILURE);
+               case GEN_IPADD:
+               if (is_nc)
+                       gen->d.ip = a2i_IPADDRESS_NC(value);
+               else
+                       gen->d.ip = a2i_IPADDRESS(value);
+               if(gen->d.ip == NULL)
+                       {
+                       X509V3err(X509V3_F_A2I_GENERAL_NAME,X509V3_R_BAD_IP_ADDRESS);
+                       ERR_add_error_data(2, "value=", value);
                        goto err;
-       }
-       type = GEN_IPADD;
-} else {
-       X509V3err(X509V3_F_V2I_GENERAL_NAME,X509V3_R_UNSUPPORTED_OPTION);
-       ERR_add_error_data(2, "name=", name);
-       goto err;
-}
+                       }
+               break;
 
-if(is_string) {
-       if(!(gen->d.ia5 = ASN1_IA5STRING_new()) ||
-                     !ASN1_STRING_set(gen->d.ia5, (unsigned char*)value,
-                                      strlen(value))) {
-               X509V3err(X509V3_F_V2I_GENERAL_NAME,ERR_R_MALLOC_FAILURE);
+               case GEN_DIRNAME:
+               if (!do_dirname(gen, value, ctx))
+                       {
+                       X509V3err(X509V3_F_A2I_GENERAL_NAME,X509V3_R_DIRNAME_ERROR);
+                       goto err;
+                       }
+               break;
+
+               case GEN_OTHERNAME:
+               if (!do_othername(gen, value, ctx))
+                       {
+                       X509V3err(X509V3_F_A2I_GENERAL_NAME,X509V3_R_OTHERNAME_ERROR);
+                       goto err;
+                       }
+               default:
+               X509V3err(X509V3_F_A2I_GENERAL_NAME,X509V3_R_UNSUPPORTED_TYPE);
                goto err;
+               }
+
+       if(is_string)
+               {
+               if(!(gen->d.ia5 = M_ASN1_IA5STRING_new()) ||
+                             !ASN1_STRING_set(gen->d.ia5, (unsigned char*)value,
+                                              strlen(value)))
+                       {
+                       X509V3err(X509V3_F_A2I_GENERAL_NAME,ERR_R_MALLOC_FAILURE);
+                       goto err;
+                       }
+               }
+
+       gen->type = gen_type;
+
+       return gen;
+
+       err:
+       GENERAL_NAME_free(gen);
+       return NULL;
        }
-}
 
-gen->type = type;
+GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out,
+                               X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+                                                CONF_VALUE *cnf, int is_nc)
+       {
+       int type;
 
-return gen;
+       char *name, *value;
 
-err:
-GENERAL_NAME_free(gen);
-return NULL;
-}
+       name = cnf->name;
+       value = cnf->value;
+
+       if(!value)
+               {
+               X509V3err(X509V3_F_V2I_GENERAL_NAME_EX,X509V3_R_MISSING_VALUE);
+               return NULL;
+               }
+
+       if(!name_cmp(name, "email"))
+               type = GEN_EMAIL;
+       else if(!name_cmp(name, "URI"))
+               type = GEN_URI;
+       else if(!name_cmp(name, "DNS"))
+               type = GEN_DNS;
+       else if(!name_cmp(name, "RID"))
+               type = GEN_RID;
+       else if(!name_cmp(name, "IP"))
+               type = GEN_IPADD;
+       else if(!name_cmp(name, "dirName"))
+               type = GEN_DIRNAME;
+       else if(!name_cmp(name, "otherName"))
+               type = GEN_OTHERNAME;
+       else
+               {
+               X509V3err(X509V3_F_V2I_GENERAL_NAME_EX,X509V3_R_UNSUPPORTED_OPTION);
+               ERR_add_error_data(2, "name=", name);
+               return NULL;
+               }
+
+       return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc);
+
+       }
+
+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;
+       }
+
+static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx)
+       {
+       int ret;
+       STACK_OF(CONF_VALUE) *sk;
+       X509_NAME *nm;
+       if (!(nm = X509_NAME_new()))
+               return 0;
+       sk = X509V3_get_section(ctx, value);
+       if (!sk)
+               {
+               X509V3err(X509V3_F_DO_DIRNAME,X509V3_R_SECTION_NOT_FOUND);
+               ERR_add_error_data(2, "section=", value);
+               X509_NAME_free(nm);
+               return 0;
+               }
+       /* FIXME: should allow other character types... */
+       ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC);
+       if (!ret)
+               X509_NAME_free(nm);
+       gen->d.dirn = nm;
+               
+       return ret;
+       }