Package: gnutls-bin
Tags: patch

The DN input mechanism used by certtool when creating certificates is
braindamaged. Instead of asking for a fully-formed DN, it asks for a
handful of attributes, and enforces a particlar order on them. This is
useless when you wanted a certificate that has a given attribute more
than once, or in a more normal order (who the heck puts O before OU,
or C at the start?).

Not exactly complete, because I couldn't remember all the attribute
names offhand, but here's a quickly hacked up patch that does it
properly. Supports c, ou, o, and cn, which is enough for most things
and lets me create my "cn=foo, ou=bar, ou=baz, o=quux" certificates.

-- 
  .''`.  ** Debian GNU/Linux ** | Andrew Suffield
 : :' :  http://www.debian.org/ |
 `. `'                          |
   `-             -><-          |
diff -u gnutls11-1.0.16/src/certtool.c gnutls11-1.0.16/src/certtool.c
--- gnutls11-1.0.16/src/certtool.c
+++ gnutls11-1.0.16/src/certtool.c
@@ -248,14 +248,17 @@
 
                /* set the DN.
                 */
-               get_country_crt_set( crt);
-               get_organization_crt_set(crt);
-               get_unit_crt_set( crt);
-               get_locality_crt_set( crt);
-               get_state_crt_set( crt);
-               get_cn_crt_set( crt);
-               get_uid_crt_set( crt);
-               get_oid_crt_set( crt);
+                if (!get_dn_crt_set( crt))
+                  {
+                    get_unit_crt_set( crt);
+                    get_country_crt_set( crt);
+                    get_organization_crt_set(crt);
+                    get_locality_crt_set( crt);
+                    get_state_crt_set( crt);
+                    get_cn_crt_set( crt);
+                    get_uid_crt_set( crt);
+                    get_oid_crt_set( crt);
+                  }
        
                if (!batch) fprintf(stderr, "This field should not be used in 
new certificates.\n");
 
--- gnutls11-1.0.16.orig/src/certtool-cfg.c
+++ gnutls11-1.0.16/src/certtool-cfg.c
@@ -29,11 +29,13 @@
 #include <cfg+.h>
 #include <gnutls/x509.h>
 #include <string.h>
+#include <ctype.h>
 
 extern int batch;
 
 typedef struct _cfg_ctx
 {
+        char *dn;
        char *organization;
        char *unit;
        char *locality;
@@ -84,6 +86,7 @@
 
        /* Option set */
        struct cfg_option options[] = {
+               {NULL, '\0', "dn", CFG_STR, (void *) &cfg.dn, 0},
                {NULL, '\0', "organization", CFG_STR, (void *) 
&cfg.organization, 0},
                {NULL, '\0', "unit", CFG_STR, (void *) &cfg.unit, 0},
                {NULL, '\0', "locality", CFG_STR, (void *) &cfg.locality, 0},
@@ -245,6 +248,119 @@
                return read_str( "Enter the URI of the CRL distribution point: 
");
 }
 
+int attrcmp(const char *attr1, const char *attr2, size_t attr2_len)
+{
+  size_t attr1_len = strlen(attr1);
+  if (attr1_len != attr2_len)
+    return 0;
+  return strncasecmp(attr1, attr2, attr1_len) == 0;
+}
+
+void dn_attr_crt_set( gnutls_x509_crt crt, const char *attr, size_t attr_len, 
const char *value, size_t value_len)
+{
+  const char *oid = NULL;
+  int ret;
+
+  if (attrcmp("cn", attr, attr_len))
+    oid = GNUTLS_OID_X520_COMMON_NAME;
+  else if (attrcmp("o", attr, attr_len))
+    oid = GNUTLS_OID_X520_ORGANIZATION_NAME;
+  else if (attrcmp("ou", attr, attr_len))
+    oid = GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME;
+  else if (attrcmp("c", attr, attr_len))
+    oid = GNUTLS_OID_X520_COUNTRY_NAME;
+
+  if (!oid)
+    {
+      fprintf(stderr, "dn_attr_crt_set: unknown attribute '%.*s'\n", attr_len, 
attr);
+      exit(1);
+    }
+
+  ret = gnutls_x509_crt_set_dn_by_oid(crt, oid, 0, value, value_len);
+  if (ret < 0) {
+    fprintf(stderr, "dn_attr_crt_set: %s\n", gnutls_strerror(ret));
+    exit(1);
+  }
+}
+
+void dn_crt_set( gnutls_x509_crt crt, const char *dn)
+{
+  const char *p = dn;
+
+  /* For each element */
+  while (*p && *p != '\n')
+    {
+      const char *attribute_name_start;
+      const char *attribute_name_end;
+      const char *attribute_value_start;
+      const char *attribute_value_end;
+      size_t attribute_name_len;
+      size_t attribute_value_len;
+
+      /* Skip leading whitespace */
+      while (isspace(*p))
+        p++;
+
+      /* Attribute name */
+      attribute_name_start = p;
+      while (isalpha(*p))
+        p++;
+      attribute_name_end = p;
+
+      /* Whitespace */
+      while (isspace(*p))
+        p++;
+
+      /* Equals sign */
+      if (*p != '=')
+        {
+          fprintf(stderr, "dn_crt_set: syntax error\n");
+          exit(1);
+        }
+      p++;
+
+      /* Whitespace */
+      while (isspace(*p))
+        p++;
+
+      /* Attribute value */
+      attribute_value_start = p;
+      while (*p && *p != ',' && *p != '\n')
+        p++;
+      attribute_value_end = p;
+      while (attribute_value_end > attribute_value_start && 
isspace(attribute_value_end[-1]))
+        attribute_value_end--;
+
+      /* Comma, or the end of the string */
+      if (*p)
+        p++;
+
+      attribute_name_len = attribute_name_end - attribute_name_start;
+      attribute_value_len = attribute_value_end - attribute_value_start;
+
+      dn_attr_crt_set(crt, attribute_name_start, attribute_name_len, 
attribute_value_start, attribute_value_len);
+    }
+}
+
+int get_dn_crt_set( gnutls_x509_crt crt)
+{
+       if (batch) {
+          if (!cfg.dn) return 0;
+          dn_crt_set(crt, cfg.dn);
+          return 1;
+       } else {
+          char input[256];
+
+          fputs( "Enter the full DN of the certificate:", stderr);
+          fgets( input, sizeof(input), stdin);
+       
+          if (strlen(input)==1) /* only newline */ return 0;
+
+          dn_crt_set(crt, input);
+          return 1;
+       }
+}
+
 void get_country_crt_set( gnutls_x509_crt crt)
 {
 int ret;
only in patch2:
unchanged:
--- gnutls11-1.0.16.orig/src/certtool-cfg.h
+++ gnutls11-1.0.16/src/certtool-cfg.h
@@ -19,6 +19,7 @@
 const char* get_pass(void);
 const char* get_challenge_pass(void);
 const char* get_crl_dist_point_url(void);
+int get_dn_crt_set( gnutls_x509_crt crt);
 void get_country_crt_set( gnutls_x509_crt crt);
 void get_organization_crt_set( gnutls_x509_crt crt);
 void get_unit_crt_set( gnutls_x509_crt crt);
only in patch2:
unchanged:

Attachment: signature.asc
Description: Digital signature

Reply via email to