* gpgsm.c (main): New options --no-log-file and --debug-none.
authorWerner Koch <wk@gnupg.org>
Thu, 21 Jul 2005 18:29:13 +0000 (18:29 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 21 Jul 2005 18:29:13 +0000 (18:29 +0000)
* certreqgen.c (get_parameter, get_parameter_value): Add SEQ arg
to allow enumeration.  Changed all callers.
(create_request): Process DNS and URI parameters.

* gpgsm-gencert.sh: Reworked to allow for multiple email addresses
as well as DNsanmes and URi.  Present the parameter file before
creating the certificate.

sm/ChangeLog
sm/certreqgen.c
sm/gpgsm.c
tools/ChangeLog
tools/gpgsm-gencert.sh

index cefa77e..a76f586 100644 (file)
@@ -1,3 +1,11 @@
+2005-07-21  Werner Koch  <wk@g10code.com>
+
+       * gpgsm.c (main): New options --no-log-file and --debug-none.
+
+       * certreqgen.c (get_parameter, get_parameter_value): Add SEQ arg
+       to allow enumeration.  Changed all callers.
+       (create_request): Process DNS and URI parameters.
+
 2005-07-20  Werner Koch  <wk@g10code.com>
 
        * keylist.c (email_kludge): Reworked.
index 2b920da..c9a0920 100644 (file)
@@ -1,5 +1,5 @@
 /* certreqgen.c - Generate a key and a certification request
- *     Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -71,7 +71,11 @@ The format of the native parameter file is follows:
      Name-DN: subject name
         This is the DN name of the subject in rfc2253 format.
      Name-Email: <string>
-       The ist the email address
+       The is an email address for the altSubjectName
+     Name-DNS: <string> 
+       The is an DNS name for the altSubjectName
+     Name-URI: <string> 
+       The is an URI for the altSubjectName
 
 Here is an example:
 $ cat >foo <<EOF
@@ -109,7 +113,9 @@ enum para_name {
   pKEYLENGTH,
   pKEYUSAGE,
   pNAMEDN,
-  pNAMEEMAIL
+  pNAMEEMAIL,
+  pNAMEDNS,
+  pNAMEURI
 };
 
 struct para_data_s {
@@ -155,26 +161,27 @@ release_parameter_list (struct para_data_s *r)
 }
 
 static struct para_data_s *
-get_parameter (struct para_data_s *para, enum para_name key)
+get_parameter (struct para_data_s *para, enum para_name key, int seq)
 {
   struct para_data_s *r;
   
-  for (r = para; r && r->key != key; r = r->next)
-    ;
-  return r;
+  for (r = para; r ; r = r->next)
+    if ( r->key == key && !seq--)
+      return r;
+  return NULL;
 }
 
 static const char *
-get_parameter_value (struct para_data_s *para, enum para_name key)
+get_parameter_value (struct para_data_s *para, enum para_name key, int seq)
 {
-  struct para_data_s *r = get_parameter (para, key);
+  struct para_data_s *r = get_parameter (para, key, seq);
   return (r && *r->u.value)? r->u.value : NULL;
 }
 
 static int
 get_parameter_algo (struct para_data_s *para, enum para_name key)
 {
-  struct para_data_s *r = get_parameter (para, key);
+  struct para_data_s *r = get_parameter (para, key, 0);
   if (!r)
     return -1;
   if (digitp (r->u.value))
@@ -189,7 +196,7 @@ get_parameter_algo (struct para_data_s *para, enum para_name key)
 static int
 parse_parameter_usage (struct para_data_s *para, enum para_name key)
 {
-  struct para_data_s *r = get_parameter (para, key);
+  struct para_data_s *r = get_parameter (para, key, 0);
   char *p, *pn;
   unsigned int use;
   
@@ -220,7 +227,7 @@ parse_parameter_usage (struct para_data_s *para, enum para_name key)
 static unsigned int
 get_parameter_uint (struct para_data_s *para, enum para_name key)
 {
-  struct para_data_s *r = get_parameter (para, key);
+  struct para_data_s *r = get_parameter (para, key, 0);
 
   if (!r)
     return 0;
@@ -241,12 +248,15 @@ read_parameters (ctrl_t ctrl, FILE *fp, ksba_writer_t writer)
   static struct {
     const char *name;
     enum para_name key;
+    int allow_dups;
   } keywords[] = {
     { "Key-Type",       pKEYTYPE},
     { "Key-Length",     pKEYLENGTH },
     { "Key-Usage",      pKEYUSAGE },
     { "Name-DN",        pNAMEDN },
-    { "Name-Email",     pNAMEEMAIL },
+    { "Name-Email",     pNAMEEMAIL, 1 },
+    { "Name-DNS",       pNAMEDNS, 1 },
+    { "Name-URI",       pNAMEURI, 1 },
     { NULL, 0 }
   };
   char line[1024], *p;
@@ -347,7 +357,7 @@ read_parameters (ctrl_t ctrl, FILE *fp, ksba_writer_t writer)
           release_parameter_list (para);
           para = NULL;
        }
-      else
+      else if (!keywords[i].allow_dups)
         {
           for (r = para; r && r->key != keywords[i].key; r = r->next)
             ;
@@ -433,9 +443,10 @@ proc_parameters (ctrl_t ctrl,
   unsigned char keyparms[100];
   int rc;
   ksba_sexp_t public;
+  int seq;
   
   /* check that we have all required parameters */
-  assert (get_parameter (para, pKEYTYPE));
+  assert (get_parameter (para, pKEYTYPE, 0));
 
   /* We can only use RSA for now.  There is a with pkcs-10 on how to
      use ElGamal because it is expected that a PK algorithm can always
@@ -443,20 +454,20 @@ proc_parameters (ctrl_t ctrl,
   i = get_parameter_algo (para, pKEYTYPE);
   if (i < 1 || i != GCRY_PK_RSA )
     {
-      r = get_parameter (para, pKEYTYPE);
+      r = get_parameter (para, pKEYTYPE, 0);
       log_error (_("line %d: invalid algorithm\n"), r->lnr);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
   
   /* check the keylength */
-  if (!get_parameter (para, pKEYLENGTH))
+  if (!get_parameter (para, pKEYLENGTH, 0))
     nbits = 1024;
   else
     nbits = get_parameter_uint (para, pKEYLENGTH);
   if (nbits < 1024 || nbits > 4096)
     {
       /* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */
-      r = get_parameter (para, pKEYTYPE);
+      r = get_parameter (para, pKEYLENGTH, 0);
       log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"),
                  r->lnr, nbits, 1024, 4096);
       return gpg_error (GPG_ERR_INV_PARAMETER);
@@ -468,16 +479,16 @@ proc_parameters (ctrl_t ctrl,
 
   /* check that there is a subject name and that this DN fits our
      requirements */
-  if (!(s=get_parameter_value (para, pNAMEDN)))
+  if (!(s=get_parameter_value (para, pNAMEDN, 0)))
     {
-      r = get_parameter (para, pKEYTYPE);
+      r = get_parameter (para, pKEYTYPE, 0);
       log_error (_("line %d: no subject name given\n"), r->lnr);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
   /* fixme check s */
 
   /* check that the optional email address is okay */
-  if ((s=get_parameter_value (para, pNAMEEMAIL)))
+  for (seq=0; (s=get_parameter_value (para, pNAMEEMAIL, seq)); seq++)
     { 
       if (has_invalid_email_chars (s)
           || *s == '@'
@@ -485,7 +496,7 @@ proc_parameters (ctrl_t ctrl,
           || s[strlen(s)-1] == '.'
           || strstr(s, ".."))
         {
-          r = get_parameter (para, pKEYTYPE);
+          r = get_parameter (para, pNAMEEMAIL, seq);
           log_error (_("line %d: not a valid email address\n"), r->lnr);
           return gpg_error (GPG_ERR_INV_PARAMETER);
         }
@@ -497,7 +508,7 @@ proc_parameters (ctrl_t ctrl,
   rc = gpgsm_agent_genkey (ctrl, keyparms, &public);
   if (rc)
     {
-      r = get_parameter (para, pKEYTYPE);
+      r = get_parameter (para, pKEYTYPE, 0);
       log_error (_("line %d: key generation failed: %s\n"),
                  r->lnr, gpg_strerror (rc));
       return rc;
@@ -524,6 +535,10 @@ create_request (ctrl_t ctrl,
   int rc = 0;
   const char *s;
   unsigned int use;
+  int seq;
+  char *buf, *p;
+  size_t len;
+  char numbuf[30];
 
   err = ksba_certreq_new (&cr);
   if (err)
@@ -541,7 +556,7 @@ create_request (ctrl_t ctrl,
   ksba_certreq_set_hash_function (cr, HASH_FNC, md);
   ksba_certreq_set_writer (cr, outctrl->writer);
   
-  err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN));
+  err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN, 0));
   if (err)
     {
       log_error ("error setting the subject's name: %s\n",
@@ -550,11 +565,8 @@ create_request (ctrl_t ctrl,
       goto leave;
     }
 
-  s = get_parameter_value (para, pNAMEEMAIL);
-  if (s)
+  for (seq=0; (s = get_parameter_value (para, pNAMEEMAIL, seq)); seq++)
     {
-      char *buf;
-
       buf = xtrymalloc (strlen (s) + 3);
       if (!buf)
         {
@@ -575,6 +587,60 @@ create_request (ctrl_t ctrl,
         }
     }
 
+  for (seq=0; (s = get_parameter_value (para, pNAMEDNS, seq)); seq++)
+    {
+      len = strlen (s);
+      assert (len);
+      snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
+      buf = p = xtrymalloc (11 + strlen (numbuf) + len + 3);
+      if (!buf)
+        {
+          rc = OUT_OF_CORE (errno);
+          goto leave;
+        }
+      p = stpcpy (p, "(8:dns-name");
+      p = stpcpy (p, numbuf);
+      p = stpcpy (p, s);
+      strcpy (p, ")");
+
+      err = ksba_certreq_add_subject (cr, buf);
+      xfree (buf);
+      if (err)
+        {
+          log_error ("error setting the subject's alternate name: %s\n",
+                     gpg_strerror (err));
+          rc = err;
+          goto leave;
+        }
+    }
+
+  for (seq=0; (s = get_parameter_value (para, pNAMEURI, seq)); seq++)
+    {
+      len = strlen (s);
+      assert (len);
+      snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
+      buf = p = xtrymalloc (6 + strlen (numbuf) + len + 3);
+      if (!buf)
+        {
+          rc = OUT_OF_CORE (errno);
+          goto leave;
+        }
+      p = stpcpy (p, "(3:uri");
+      p = stpcpy (p, numbuf);
+      p = stpcpy (p, s);
+      strcpy (p, ")");
+
+      err = ksba_certreq_add_subject (cr, buf);
+      xfree (buf);
+      if (err)
+        {
+          log_error ("error setting the subject's alternate name: %s\n",
+                     gpg_strerror (err));
+          rc = err;
+          goto leave;
+        }
+    }
+
 
   err = ksba_certreq_set_public_key (cr, public);
   if (err)
index fb65330..0f9745a 100644 (file)
@@ -99,12 +99,14 @@ enum cmd_and_opt_values {
   oDebug,
   oDebugLevel,
   oDebugAll,
+  oDebugNone,
   oDebugWait,
   oDebugAllowCoreDump,
   oDebugNoChainValidation,
   oDebugIgnoreExpiration,
   oFixedPassphrase,
   oLogFile,
+  oNoLogFile,
 
   oEnableSpecialFilenames,
 
@@ -330,6 +332,7 @@ static ARGPARSE_OPTS opts[] = {
     { oQuiet,  "quiet",   0, N_("be somewhat more quiet") },
     { oNoTTY, "no-tty", 0, N_("don't use the terminal at all") },
     { oLogFile, "log-file"   ,2, N_("use a log file for the server")},
+    { oNoLogFile, "no-log-file" ,0, "@"},
 #if 0
     { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") },
     { oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") },
@@ -351,6 +354,7 @@ static ARGPARSE_OPTS opts[] = {
     { oDebug, "debug"     ,4|16, "@"},
     { oDebugLevel, "debug-level" ,2, N_("|LEVEL|set the debugging level to LEVEL")},
     { oDebugAll, "debug-all" ,0, "@"},
+    { oDebugNone, "debug-none" ,0, "@"},
     { oDebugWait, "debug-wait" ,1, "@"},
     { oDebugAllowCoreDump, "debug-allow-core-dump", 0, "@" },
     { oDebugNoChainValidation, "debug-no-chain-validation", 0, "@"},
@@ -1032,7 +1036,8 @@ main ( int argc, char **argv)
           break;
 
         case oLogFile: logfile = pargs.r.ret_str; break;
-          
+        case oNoLogFile: logfile = NULL; break;          
+
         case oBatch: 
           opt.batch = 1;
           greeting = 0;
@@ -1046,6 +1051,7 @@ main ( int argc, char **argv)
 
         case oDebug: debug_value |= pargs.r.ret_ulong; break;
         case oDebugAll: debug_value = ~0; break;
+        case oDebugNone: debug_value = 0; break;
         case oDebugLevel: debug_level = pargs.r.ret_str; break;
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
         case oDebugAllowCoreDump:
index c09819e..e1dfce4 100644 (file)
@@ -1,3 +1,9 @@
+2005-07-21  Werner Koch  <wk@g10code.com>
+
+       * gpgsm-gencert.sh: Reworked to allow for multiple email addresses
+       as well as DNsanmes and URi.  Present the parameter file before
+       creating the certificate.
+
 2005-07-04  Marcus Brinkmann  <marcus@g10code.de>
 
        * symcryptrun.c (SYMC_BAD_PASSPHRASE, SYMC_CANCELED): New symbols,
index ec5025b..44b06f3 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #                                                              -*- sh -*-
 # gpgsm-gencert.c - Generate X.509 certificates through GPGSM.  
-#      Copyright (C) 2004 Free Software Foundation, Inc.
+#      Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 #
 # This file is part of GnuPG.
 #
@@ -93,25 +93,67 @@ KEY_LENGTH=$ANSWER
 query_user_menu "Key usage" "sign, encrypt" "sign" "encrypt"
 KEY_USAGE=$ANSWER
 
-query_user "Name"
+query_user "Name (DN)"
 NAME=$ANSWER
 
-query_user "E-Mail address"
-EMAIL_ADDRESS=$ANSWER
+EMAIL_ADDRESSES=
+LF=
+while : ; do
+  query_user "E-Mail addresses (end with an empty line)"
+  [ -z "$ANSWER" ] && break
+  EMAIL_ADDRESSES="${EMAIL_ADDRESSES}${LF}Name-Email: $ANSWER"
+  LF='
+'
+done
+
+DNS_ADDRESSES=
+LF=
+while : ; do
+  query_user "DNS Names (optional; end with an empty line)"
+  [ -z "$ANSWER" ] && break
+  DNS_ADDRESSES="${DNS_ADDRESSES}${LF}Name-DNS: $ANSWER"
+  LF='
+'
+done
+
+URI_ADDRESSES=
+LF=
+while : ; do
+  query_user "URIs (optional; end with an empty line)"
+  [ -z "$ANSWER" ] && break
+  URI_ADDRESSES="${URI_ADDRESSES}${LF}Name-URI: $ANSWER"
+  LF='
+'
+done
 
 file_parameter=$(mktemp "/tmp/gpgsm.XXXXXX")
 outfile=$(mktemp "/tmp/gpgsm.XXXXXX")
 
-cat > "$file_parameter" <<EOF
+
+(
+cat <<EOF
 Key-Type: $KEY_TYPE
 Key-Length: $KEY_LENGTH
 Key-Usage: $KEY_USAGE
 Name-DN: $NAME
-Name-Email: $EMAIL_ADDRESS
 EOF
+[ -n "$EMAIL_ADDRESSES" ] && echo "$EMAIL_ADDRESSES"
+[ -n "$DNS_ADDRESSES" ] && echo "$DNS_ADDRESSES"
+[ -n "$URI_ADDRESSES" ] && echo "$URI_ADDRESSES"
+) > "$file_parameter"
+
+
+echo 'Parameters for certificate request to create:' >&2
+cat -n "$file_parameter" >&2
+echo  >&2
+
+query_user_menu "Really create such a CSR?" "yes" "no"
+[ "$ANSWER" != "yes" ] && exit 1
+    
 
 echo -e "$ASSUAN_COMMANDS" | \
-   gpgsm --server 4< "$file_parameter" 5>"$outfile" >/dev/null
+   ./gpgsm --no-log-file --debug-level none --debug-none \
+           --server 4< "$file_parameter" 5>"$outfile" >/dev/null
 
 cat "$outfile"