Add copy_extensions option to 'ca' utility.
[openssl.git] / apps / apps.c
index c2633b21e2247959c06797cbadc043a3a1786654..4aeabdfa38189f5e5c62cb2858269a851a9ca2cf 100644 (file)
@@ -66,6 +66,7 @@
 #undef NON_MAIN
 #include <openssl/err.h>
 #include <openssl/x509.h>
+#include <openssl/x509v3.h>
 #include <openssl/pem.h>
 #include <openssl/pkcs12.h>
 #include <openssl/safestack.h>
@@ -87,6 +88,7 @@ typedef struct {
 } NAME_EX_TBL;
 
 static int set_table_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl);
+static int set_multi_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl);
 
 int app_init(long mesgwin);
 #ifdef undef /* never finished - probably never will be :-) */
@@ -744,16 +746,21 @@ end:
 /* BIO_dump unknown extensions */
 #define X509V3_EXT_DUMP_UNKNOWN                (3L << 16)
 
+#define X509_FLAG_CA (X509_FLAG_NO_ISSUER | X509_FLAG_NO_PUBKEY | \
+                        X509_FLAG_NO_HEADER | X509_FLAG_NO_VERSION)
+
 int set_cert_ex(unsigned long *flags, const char *arg)
 {
        static const NAME_EX_TBL cert_tbl[] = {
                { "compatible", X509_FLAG_COMPAT, 0xffffffffl},
+               { "ca_default", X509_FLAG_CA, 0xffffffffl},
                { "no_header", X509_FLAG_NO_HEADER, 0},
                { "no_version", X509_FLAG_NO_VERSION, 0},
                { "no_serial", X509_FLAG_NO_SERIAL, 0},
                { "no_signame", X509_FLAG_NO_SIGNAME, 0},
                { "no_validity", X509_FLAG_NO_VALIDITY, 0},
                { "no_subject", X509_FLAG_NO_SUBJECT, 0},
+               { "no_issuer", X509_FLAG_NO_ISSUER, 0},
                { "no_pubkey", X509_FLAG_NO_PUBKEY, 0},
                { "no_extensions", X509_FLAG_NO_EXTENSIONS, 0},
                { "no_sigdump", X509_FLAG_NO_SIGDUMP, 0},
@@ -764,7 +771,7 @@ int set_cert_ex(unsigned long *flags, const char *arg)
                { "ext_dump", X509V3_EXT_DUMP_UNKNOWN, X509V3_EXT_UNKNOWN_MASK},
                { NULL, 0, 0}
        };
-       return set_table_opts(flags, arg, cert_tbl);
+       return set_multi_opts(flags, arg, cert_tbl);
 }
 
 int set_name_ex(unsigned long *flags, const char *arg)
@@ -789,15 +796,89 @@ int set_name_ex(unsigned long *flags, const char *arg)
                { "nofname", XN_FLAG_FN_NONE, XN_FLAG_FN_MASK},
                { "sname", XN_FLAG_FN_SN, XN_FLAG_FN_MASK},
                { "lname", XN_FLAG_FN_LN, XN_FLAG_FN_MASK},
+               { "align", XN_FLAG_FN_ALIGN, 0},
                { "oid", XN_FLAG_FN_OID, XN_FLAG_FN_MASK},
                { "space_eq", XN_FLAG_SPC_EQ, 0},
                { "dump_unknown", XN_FLAG_DUMP_UNKNOWN_FIELDS, 0},
                { "RFC2253", XN_FLAG_RFC2253, 0xffffffffL},
                { "oneline", XN_FLAG_ONELINE, 0xffffffffL},
                { "multiline", XN_FLAG_MULTILINE, 0xffffffffL},
+               { "ca_default", XN_FLAG_MULTILINE, 0xffffffffL},
                { NULL, 0, 0}
        };
-       return set_table_opts(flags, arg, ex_tbl);
+       return set_multi_opts(flags, arg, ex_tbl);
+}
+
+int set_ext_copy(int *copy_type, const char *arg)
+{
+       if (!strcasecmp(arg, "none"))
+               *copy_type = EXT_COPY_NONE;
+       else if (!strcasecmp(arg, "copy"))
+               *copy_type = EXT_COPY_ADD;
+       else if (!strcasecmp(arg, "copyall"))
+               *copy_type = EXT_COPY_ALL;
+       else
+               return 0;
+       return 1;
+}
+
+int copy_extensions(X509 *x, X509_REQ *req, int copy_type)
+{
+       STACK_OF(X509_EXTENSION) *exts = NULL;
+       X509_EXTENSION *ext, *tmpext;
+       ASN1_OBJECT *obj;
+       int i, idx, ret = 0;
+       if (!x || !req || (copy_type == EXT_COPY_NONE))
+               return 1;
+       exts = X509_REQ_get_extensions(req);
+
+       for(i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
+               ext = sk_X509_EXTENSION_value(exts, i);
+               obj = X509_EXTENSION_get_object(ext);
+               idx = X509_get_ext_by_OBJ(x, obj, -1);
+               /* Does extension exist? */
+               if (idx != -1) {
+                       /* If normal copy don't override existing extension */
+                       if (copy_type == EXT_COPY_ADD)
+                               continue;
+                       /* Delete all extensions of same type */
+                       do {
+                               tmpext = X509_get_ext(x, idx);
+                               X509_delete_ext(x, idx);
+                               X509_EXTENSION_free(tmpext);
+                               idx = X509_get_ext_by_OBJ(x, obj, -1);
+                       } while (idx != -1);
+               }
+               if (!X509_add_ext(x, ext, -1))
+                       goto end;
+       }
+
+       ret = 1;
+
+       end:
+
+       sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+
+       return ret;
+}
+               
+               
+                       
+
+static int set_multi_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl)
+{
+       STACK_OF(CONF_VALUE) *vals;
+       CONF_VALUE *val;
+       int i, ret = 1;
+       if(!arg) return 0;
+       vals = X509V3_parse_list(arg);
+       for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
+               val = sk_CONF_VALUE_value(vals, i);
+               if (!set_table_opts(flags, val->name, in_tbl))
+                       ret = 0;
+       }
+       sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+       return ret;
 }
 
 static int set_table_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl)