]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added functions to directly set the DN in a certificate or request from an RFC4514...
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 15 Jan 2013 22:32:26 +0000 (23:32 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 15 Jan 2013 22:34:50 +0000 (23:34 +0100)
15 files changed:
NEWS
doc/TODO
doc/cha-cert-auth2.texi
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/x509/Makefile.am
lib/x509/common.c
lib/x509/common.h
lib/x509/x509_dn.c [new file with mode: 0644]
src/certtool-args.c
src/certtool-args.def
src/certtool-args.h
src/certtool-cfg.c
src/certtool-cfg.h
src/certtool.c

diff --git a/NEWS b/NEWS
index 54d5aa60bb42697d71d30e81bc839f266f188ab2..9037d8ceb5c366eb454a65a5dfbb4f46425fa9d8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,12 @@ See the end for copying conditions.
 
 * Version 3.1.7 (unreleased)
 
+** certtool: Added option "dn" which allows to directly set the DN
+in a template from an RFC4514 string.
+
+** libgnutls: Added functions to directly set the DN in a certificate
+or request from an RFC4514 string.
+
 ** libgnutls: Simplified the DTLS sliding window implementation.
 
 ** libgnutls: Added the gnutls_sbuf_t structure and accompanying 
@@ -20,6 +26,8 @@ gnutls_sbuf_deinit: Added
 gnutls_sbuf_init: Added
 gnutls_sbuf_flush: Added
 gnutls_sbuf_queue: Added
+gnutls_x509_crt_set_dn: Added
+gnutls_x509_crq_set_dn: Added
 
 
 * Version 3.1.6 (released 2013-01-02)
index 165f568ee657e9f5607c748c40def26bdfc78817..0b7d0e1b783c27e5cad91ceca3b3440fe3d6c51c 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -3,6 +3,8 @@ anything), contact the developer's mailing list (gnutls-dev@lists.gnupg.org),
 in order to avoid having people working on the same thing. 
 
 Current list:
+* Add gnutls_x509_crt_set_dn() to allow setting a DN using an RFC4514
+  string (as well as the x509_crq_set_dn).
 * When importing a PKCS #11 certificate, check for its issuers to generate a
   chain (e.g. use the DN to retrieve possible signers).
 * Think about supporting the groups in RFC3526 and RFC5114. If other
index b49c201740541f3586cf8a727aceb7bfabc33e12..369326f7bce7bd1d20174332762812169f65cd66 100644 (file)
@@ -35,7 +35,7 @@ subject's information and finally self signing it.
 The last step ensures that the requester is in
 possession of the private key.
 
-@showfuncE{gnutls_x509_crq_set_version,gnutls_x509_crq_set_dn_by_oid,gnutls_x509_crq_set_key_usage,gnutls_x509_crq_set_key_purpose_oid,gnutls_x509_crq_set_basic_constraints}
+@showfuncF{gnutls_x509_crq_set_version,gnutls_x509_crq_set_dn,gnutls_x509_crq_set_dn_by_oid,gnutls_x509_crq_set_key_usage,gnutls_x509_crq_set_key_purpose_oid,gnutls_x509_crq_set_basic_constraints}
 
 The @funcref{gnutls_x509_crq_set_key} and @funcref{gnutls_x509_crq_sign2} 
 functions associate the request with a private key and sign it. If a 
index 0737863f3cc23c9ddb7b44089e6abef64a8a26f5..0cded3cd60dc1095f91a0b2a74c8ba9da53f3a81 100644 (file)
@@ -397,6 +397,8 @@ extern "C"
 
 /* X.509 Certificate writing.
  */
+  int gnutls_x509_crt_set_dn (gnutls_x509_crt_t crt, const char *dn, const char** err);
+
   int gnutls_x509_crt_set_dn_by_oid (gnutls_x509_crt_t crt,
                                      const char *oid,
                                      unsigned int raw_flag,
@@ -918,6 +920,7 @@ extern "C"
                                      const char *oid, int indx,
                                      unsigned int raw_flag, void *buf,
                                      size_t * sizeof_buf);
+  int gnutls_x509_crq_set_dn (gnutls_x509_crq_t crq, const char *dn, const char** err);
   int gnutls_x509_crq_set_dn_by_oid (gnutls_x509_crq_t crq,
                                      const char *oid,
                                      unsigned int raw_flag,
index 99c97322dac1f00d22f9d52bbd146828df3ec11a..e86e8276353db30ada9813232c7d7fed314f8793 100644 (file)
@@ -881,6 +881,8 @@ GNUTLS_3_1_0 {
        gnutls_sbuf_init;
        gnutls_sbuf_flush;
        gnutls_sbuf_queue;
+       gnutls_x509_crt_set_dn;
+       gnutls_x509_crq_set_dn;
 } GNUTLS_3_0_0;
 
 GNUTLS_PRIVATE {
index c80fc43906159f9549e4f3d48238ce04b48ff96e..93fbd240573bb54b9a48da34168173694c60b3f0 100644 (file)
@@ -53,7 +53,7 @@ libgnutls_x509_la_SOURCES =   \
        rfc2818_hostname.c      \
        sign.c                  \
        verify.c                \
-       x509.c                  \
+       x509.c x509_dn.c        \
        x509_int.h              \
        x509_write.c            \
        verify-high.c           \
index 02f9fdacf4abd861cd479ee0fd023d82bc03d8f3..5f89fa0a1d76b465db21324df9cc5192fea22b60 100644 (file)
@@ -47,15 +47,14 @@ struct oid_to_string
 static const struct oid_to_string _oid2str[] = {
   /* PKIX
    */
-  {"1.3.6.1.5.5.7.9.1", "dateOfBirth", NULL, ASN1_ETYPE_GENERALIZED_TIME},
   {"1.3.6.1.5.5.7.9.2", "placeOfBirth", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
   {"1.3.6.1.5.5.7.9.3", "gender", NULL, ASN1_ETYPE_PRINTABLE_STRING},
   {"1.3.6.1.5.5.7.9.4", "countryOfCitizenship", NULL, ASN1_ETYPE_PRINTABLE_STRING},
   {"1.3.6.1.5.5.7.9.5", "countryOfResidence", NULL, ASN1_ETYPE_PRINTABLE_STRING},
 
   {"2.5.4.6", "C", NULL, ASN1_ETYPE_PRINTABLE_STRING},
-  {"2.5.4.9", "STREET", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
-  {"2.5.4.12", "T", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
+  {"2.5.4.9", "street", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
+  {"2.5.4.12", "title", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
   {"2.5.4.10", "O", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
   {"2.5.4.11", "OU", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
   {"2.5.4.3", "CN", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
@@ -71,7 +70,7 @@ static const struct oid_to_string _oid2str[] = {
   {"2.5.4.65", "pseudonym", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
   {"2.5.4.46", "dnQualifier", NULL, ASN1_ETYPE_PRINTABLE_STRING},
   {"2.5.4.17", "postalCode", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
-  {"2.5.4.41", "Name", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
+  {"2.5.4.41", "name", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
   {"2.5.4.15", "businessCategory", "PKIX1.DirectoryString", ASN1_ETYPE_INVALID},
 
   {"0.9.2342.19200300.100.1.25", "DC", NULL, ASN1_ETYPE_IA5_STRING},
@@ -116,9 +115,26 @@ static const struct oid_to_string* get_oid_entry (const char* oid)
   while (_oid2str[i].oid != NULL);
 
   return NULL;
+}
+
+const char* _gnutls_ldap_string_to_oid (const char* str, unsigned str_len)
+{
+  unsigned int i = 0;
+
+  do
+    {
+      if ((_oid2str[i].ldap_desc != NULL) &&
+          (str_len == strlen(_oid2str[i].ldap_desc)) && 
+          (strncasecmp (_oid2str[i].ldap_desc, str, str_len) == 0))
+        return _oid2str[i].oid;
+      i++;
+    }
+  while (_oid2str[i].oid != NULL);
 
+  return NULL;
 }
 
+
 /**
  * gnutls_x509_dn_oid_known:
  * @oid: holds an Object Identifier in a null terminated string
index faf29a12b2b19ef63c99303f35a6e618d03fbacd..023c22c016bf168e8ea1cdb2be77a0fbfd52f46f 100644 (file)
@@ -78,6 +78,8 @@ int _gnutls_x509_encode_string(unsigned int etype,
 
 int _gnutls_x509_dn_to_string (const char *OID, void *value,
                                   int value_size, gnutls_datum_t* out);
+const char* _gnutls_ldap_string_to_oid (const char* str, unsigned str_len);
+
 int _gnutls_x509_data2hex (const void * data, size_t data_size,
                            void * out, size_t * sizeof_out);
 
diff --git a/lib/x509/x509_dn.c b/lib/x509/x509_dn.c
new file mode 100644 (file)
index 0000000..740c42d
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2013 Nikos Mavrogiannopoulos
+ * Copyright (C) 2005 Andrew Suffield <asuffield@debian.org>
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains functions to handle X.509 certificate generation.
+ */
+
+#include <gnutls_int.h>
+
+#include <gnutls_datum.h>
+#include <gnutls_global.h>
+#include <gnutls_errors.h>
+#include <common.h>
+#include <gnutls_x509.h>
+#include <x509_b64.h>
+
+enum { CRQ, CRT };
+
+static
+int dn_attr_crt_set( unsigned crt_type, void* crt, const char *attr, unsigned attr_len, 
+                     const char *value, unsigned value_len)
+{
+  char _oid[MAX_OID_SIZE];
+  const char *oid;
+  int ret;
+  
+  if (value_len == 0 || attr_len == 0)
+    return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+    
+  if (isdigit(attr[0]) != 0)
+    {
+      if (attr_len >= sizeof(_oid))
+        return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+        
+      memcpy(_oid, attr, attr_len);
+      _oid[attr_len] = 0;
+      
+      oid = _oid;
+
+      if (gnutls_x509_dn_oid_known(oid) == 0)
+        {
+          _gnutls_debug_log("Unknown OID: '%s'\n", oid);
+          return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+        }
+    }
+  else
+    {
+      oid = _gnutls_ldap_string_to_oid(attr, attr_len);
+    }
+
+  if (oid == NULL)
+    {
+      _gnutls_debug_log("Unknown DN attribute: '%.*s'\n", attr_len, attr);
+      return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+    }
+    
+  if (value[0] == '#')
+    return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+  
+  ret = GNUTLS_E_INTERNAL_ERROR;
+  if (crt_type == CRT)
+    ret = gnutls_x509_crt_set_dn_by_oid(crt, oid, 0, value, value_len);
+  else if (crt_type == CRQ)
+    ret = gnutls_x509_crq_set_dn_by_oid(crt, oid, 0, value, value_len);
+  if (ret < 0)
+    return gnutls_assert_val(ret);
+    
+  return 0;
+}
+
+static int
+crt_set_dn (unsigned crt_type, void* crt, const char *dn, const char** err)
+{
+const char *p = dn;
+const char *name_start;
+const char *name_end;
+const char *value_start;
+const char *value_end;
+unsigned name_len;
+unsigned value_len;
+int ret;
+
+  if (crt == NULL || dn == NULL)
+    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+    
+  /* For each element */
+  while (*p != 0 && *p != '\n')
+    {
+      /* Skip leading whitespace */
+      while (isspace(*p))
+        p++;
+      
+      if (err)
+        *err = p;
+
+      /* Attribute name */
+      name_start = p;
+      while (*p != '=' && *p != 0)
+        p++;
+      name_end = p;
+
+      /* Whitespace */
+      while (isspace(*p))
+        p++;
+
+      /* Equals sign */
+      if (*p != '=')
+        {
+          *err = p;
+          return GNUTLS_E_PARSING_ERROR;
+        }
+      p++;
+
+      /* Whitespace */
+      while (isspace(*p))
+        p++;
+
+      /* Attribute value */
+      value_start = p;
+      while (*p != 0 && (*p != ',' || (*p == ',' && *(p-1) == '\\')) && *p != '\n')
+        p++;
+      value_end = p;
+      while (value_end > value_start && isspace(value_end[-1]))
+        value_end--;
+
+      /* Comma, or the end of the string */
+      if (*p)
+        p++;
+
+      name_len = name_end - name_start;
+      value_len = value_end - value_start;
+
+      ret = dn_attr_crt_set(crt_type, crt, name_start, name_len, value_start, value_len);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
+    }
+    
+  return 0;
+}
+
+
+/**
+ * gnutls_x509_crt_set_dn:
+ * @crt: a certificate of type #gnutls_x509_crt_t
+ * @dn: a comma separated DN string (RFC4514)
+ * @err: indicates the error position (if any)
+ *
+ * This function will set the DN on the provided certificate.
+ * The input string should be plain ASCII or UTF-8 encoded.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_crt_set_dn (gnutls_x509_crt_t crt, const char *dn, const char** err)
+{
+  return crt_set_dn( CRT, crt, dn, err);
+}
+
+/**
+ * gnutls_x509_crq_set_dn:
+ * @crq: a certificate of type #gnutls_x509_crq_t
+ * @dn: a comma separated DN string (RFC4514)
+ * @err: indicates the error position (if any)
+ *
+ * This function will set the DN on the provided certificate.
+ * The input string should be plain ASCII or UTF-8 encoded.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_crq_set_dn (gnutls_x509_crq_t crq, const char *dn, const char** err)
+{
+  return crt_set_dn( CRQ, crq, dn, err);
+}
index 39b62c5ed5542b8b57a21727ec7e5da860f2d267..3f861b7bacfa433ef008c7dd4972f70f8a3332a4 100644 (file)
@@ -2,7 +2,7 @@
  *  
  *  DO NOT EDIT THIS FILE   (certtool-args.c)
  *  
- *  It has been AutoGen-ed  December 15, 2012 at 11:11:26 AM by AutoGen 5.16
+ *  It has been AutoGen-ed  January 15, 2013 at 11:30:45 PM by AutoGen 5.16
  *  From the definitions    certtool-args.def
  *  and the template file   options
  *
index 07e6406b8d1f3956e8b059bf67d631a573f3395e..82753599860dd08467c796a709179d6647deca0b 100644 (file)
@@ -557,6 +557,18 @@ cn = "Cindy Lauper"
 # certificates.
 # pkcs9_email = "none@@none.org"
 
+# An alternative way to set the certificate's distinguished name directly
+# is with the "dn" option. The attribute names allowed are:
+# C (country), street, O (organization), OU (unit), title, CN (common name),
+# L (locality), ST (state), placeOfBirth, gender, countryOfCitizenship, 
+# countryOfResidence, serialNumber, telephoneNumber, surName, initials, 
+# generationQualifier, givenName, pseudonym, dnQualifier, postalCode, name, 
+# businessCategory, DC, UID, jurisdictionOfIncorporationLocalityName, 
+# jurisdictionOfIncorporationStateOrProvinceName,
+# jurisdictionOfIncorporationCountryName, XmppAddr, and numeric OIDs.
+
+#dn = "cn=Nik,st=Attiki,C=GR,surName=Mavrogiannopoulos,2.5.4.9=Arkadias"
+
 # The serial number of the certificate
 serial = 007
 
index bd1f67090ccec2c763ce604c82d9029ed7eda328..1fa15df473abc84ab35a23d4546d76f801266769 100644 (file)
@@ -2,7 +2,7 @@
  *  
  *  DO NOT EDIT THIS FILE   (certtool-args.h)
  *  
- *  It has been AutoGen-ed  December 15, 2012 at 11:11:26 AM by AutoGen 5.16
+ *  It has been AutoGen-ed  January 15, 2013 at 11:30:45 PM by AutoGen 5.16
  *  From the definitions    certtool-args.def
  *  and the template file   options
  *
index b1113c61fef7ee8c8199775b08f6f9d539297947..4cace7bb36abf399ec7242d75f13ecd0b7be00ae 100644 (file)
@@ -57,6 +57,7 @@ typedef struct _cfg_ctx
   char *unit;
   char *locality;
   char *state;
+  char *dn;
   char *cn;
   char *uid;
   char *challenge_password;
@@ -213,6 +214,10 @@ template_parse (const char *template)
   if (val != NULL && val->valType == OPARG_TYPE_STRING)
     cfg.state = strdup(val->v.strVal);
 
+  val = optionGetValue(pov, "dn");
+  if (val != NULL && val->valType == OPARG_TYPE_STRING)
+    cfg.dn = strdup(val->v.strVal);
+
   val = optionGetValue(pov, "cn");
   if (val != NULL && val->valType == OPARG_TYPE_STRING)
     cfg.cn = strdup(val->v.strVal);
@@ -663,6 +668,26 @@ get_cn_crt_set (gnutls_x509_crt_t crt)
 
 }
 
+void
+get_dn_crt_set (gnutls_x509_crt_t crt)
+{
+  int ret;
+  const char* err;
+
+  if (batch)
+    {
+      if (!cfg.dn)
+        return;
+      ret =
+        gnutls_x509_crt_set_dn (crt, cfg.dn, &err);
+      if (ret < 0)
+        {
+          fprintf (stderr, "set_dn: %s at: %s\n", gnutls_strerror (ret), err);
+          exit (1);
+        }
+    }
+}
+
 void
 get_uid_crt_set (gnutls_x509_crt_t crt)
 {
@@ -1668,6 +1693,26 @@ get_locality_crq_set (gnutls_x509_crq_t crq)
 
 }
 
+void
+get_dn_crq_set (gnutls_x509_crq_t crq)
+{
+  int ret;
+  const char* err;
+
+  if (batch)
+    {
+      if (!cfg.dn)
+        return;
+      ret =
+        gnutls_x509_crq_set_dn (crq, cfg.dn, &err);
+      if (ret < 0)
+        {
+          fprintf (stderr, "set_dn: %s at: %s\n", gnutls_strerror (ret), err);
+          exit (1);
+        }
+    }
+}
+
 void
 get_cn_crq_set (gnutls_x509_crq_t crq)
 {
index bcb96d742896205d413732e1e8733b50c7664845..87b5be1eb4d0b7fb7c70cec39401bfed702ca954 100644 (file)
@@ -44,6 +44,8 @@ void get_unit_crt_set (gnutls_x509_crt_t crt);
 void get_state_crt_set (gnutls_x509_crt_t crt);
 void get_locality_crt_set (gnutls_x509_crt_t crt);
 void get_cn_crt_set (gnutls_x509_crt_t crt);
+void get_dn_crt_set (gnutls_x509_crt_t crt);
+void get_dn_crq_set (gnutls_x509_crq_t crt);
 void get_uid_crt_set (gnutls_x509_crt_t crt);
 void get_pkcs9_email_crt_set (gnutls_x509_crt_t crt);
 void get_oid_crt_set (gnutls_x509_crt_t crt);
index ab9c7bae2f0a7d7bdb2bab2fff4fea07d1785602..e76f1976413d452ea3f55d0260705f271dd80736 100644 (file)
@@ -271,18 +271,22 @@ generate_certificate (gnutls_privkey_t * ret_key,
             error (EXIT_FAILURE, 0, "set_proxy_dn: %s",
                    gnutls_strerror (result));
 
+          get_dn_crt_set (crt);
           get_cn_crt_set (crt);
         }
       else
         {
+          get_dn_crt_set (crt);
+
           get_country_crt_set (crt);
+          get_state_crt_set (crt);
+          get_locality_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_dc_set (TYPE_CRT, crt);
           get_uid_crt_set (crt);
+
           get_oid_crt_set (crt);
           get_key_purpose_set (crt);
 
@@ -1778,11 +1782,13 @@ generate_request (common_info_st * cinfo)
 
   /* Set the DN.
    */
+  get_dn_crq_set (crq);
+
   get_country_crq_set (crq);
+  get_state_crq_set (crq);
+  get_locality_crq_set (crq);
   get_organization_crq_set (crq);
   get_unit_crq_set (crq);
-  get_locality_crq_set (crq);
-  get_state_crq_set (crq);
   get_cn_crq_set (crq);
   get_dc_set (TYPE_CRQ, crq);
   get_uid_crq_set (crq);