[git] GnuPG - branch, master, updated. post-nuke-of-trailing-ws-16-g28c157b

by Werner Koch cvs at cvs.gnupg.org
Tue Mar 1 15:12:48 CET 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  28c157b55cf6db6b6988def5c9512e388c512b10 (commit)
       via  bb6d1b48f61d483fc75a17b4d140c489afe43ef0 (commit)
       via  dfdda3b344e525f4fdb5e2c07ac63b52e501941f (commit)
      from  cf8878cb18f3ad830994b77f6ee05b5d47a1c557 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 28c157b55cf6db6b6988def5c9512e388c512b10
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Mar 1 14:42:56 2011 +0100

    Support X.509 certificate creation.
    
    Using "gpgsm --genkey" allows the creation of a self-signed
    certificate via a new prompt.
    
    Using "gpgsm --genkey --batch" should allow the creation of arbitrary
    certificates controlled by a parameter file.  An example parameter file
    is
    
        Key-Type: RSA
        Key-Length: 1024
        Key-Grip: 2C50DC6101C10C9C643E315FE3EADCCBC24F4BEA
        Key-Usage: sign, encrypt
        Serial: random
        Name-DN: CN=some test key
        Name-Email: foo at example.org
        Name-Email: bar at exmaple.org
        Hash-Algo: SHA384
        not-after: 2038-01-16 12:44
    
    This creates a self-signed X.509 certificate using the key given by
    the keygrip and using SHA-384 as hash algorithm.  The keyword
    signing-key can be used to sign the certificate with a different key.
    See sm/certreggen.c for details.

diff --git a/NEWS b/NEWS
index f58871a..1255b34 100644
--- a/NEWS
+++ b/NEWS
@@ -19,9 +19,13 @@ Noteworthy changes in version 2.1.0beta2 (unreleased)
 
  * Dirmngr has taken over the function of the keyserver helpers.  Thus
    we now have a specified direct interface to keyservers via Dirmngr.
+   LDAP, DNS and mail backends are not yet implemented.
 
  * ECC support for GPG as described by draft-jivsov-openpgp-ecc-06.txt.
 
+ * New GPGSM feature to create certificates from a parameter file.
+   Add prompt to the --gen-key UI to create self-signed certificates.
+
 
 Noteworthy changes in version 2.1.0beta1 (2010-10-26)
 -----------------------------------------------------
diff --git a/doc/DETAILS b/doc/DETAILS
index 8998d87..5870927 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -793,7 +793,8 @@ Unattended key generation
 This feature allows unattended generation of keys controlled by a
 parameter file.  To use this feature, you use --gen-key together with
 --batch and feed the parameters either from stdin or from a file given
-on the commandline.
+on the commandline.  The description below is only for GPG; GPGSM has
+a similar feature, see the file sm/certreqgen.c for a description.
 
 The format of this file is as follows:
   o Text only, line length is limited to about 1000 chars.
@@ -1220,6 +1221,8 @@ OIDs below the GnuPG arc:
  1.3.6.1.4.1.11591.2          GnuPG
  1.3.6.1.4.1.11591.2.1          notation
  1.3.6.1.4.1.11591.2.1.1          pkaAddress
+ 1.3.6.1.4.1.11591.2.2          X.509 extensions
+ 1.3.6.1.4.1.11591.2.2.1          standaloneCertificate
  1.3.6.1.4.1.11591.2.12242973   invalid encoded OID
 
 
diff --git a/sm/ChangeLog b/sm/ChangeLog
index 22db032..44e4eb3 100644
--- a/sm/ChangeLog
+++ b/sm/ChangeLog
@@ -1,3 +1,24 @@
+2011-03-01  Werner Koch  <wk at g10code.com>
+
+	* certreqgen.c (pSERIAL, pISSUERDN, pNOTBEFORE, pNOTAFTER)
+	(pSIGNINGKEY, pHASHALGO): New.
+	(reqgen_ctrl_s): Remove field WRITER.
+	(read_parameters): Support new keywords.  Change arg WRITER to
+	OUT_FP; pass that to proc_parameters.
+	(proc_parameters): Add arg WRITER.  Check values of new keywords.
+	Create writer object here.  Support generation of certificates.
+	(create_request): Take new arg SIGKEY.  Allow for hash algorithms
+	other than SHA-1.  Set serialno and other values for certificate
+	creation.
+	(gpgsm_genkey): Do not create writer object but pass output stream
+	to read_parameters.
+	* certreqgen-ui.c (gpgsm_gencertreq_tty): Ask for self-signed.
+	* misc.c (transform_sigval): New.
+
+2011-02-25  Werner Koch  <wk at g10code.com>
+
+	* certreqgen.c (create_request): Add arg SIGKEY.
+
 2010-11-25  Werner Koch  <wk at g10code.com>
 
 	* base64.c (gpgsm_create_writer): Remove arg FP which is not used
@@ -2876,7 +2897,7 @@ h2007-11-22  Werner Koch  <wk at g10code.com>
 
 
  Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-	   2010 Free Software Foundation, Inc.
+	   2010, 2011 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c
index 526a182..b5b4219 100644
--- a/sm/certreqgen-ui.c
+++ b/sm/certreqgen-ui.c
@@ -1,5 +1,5 @@
 /* certreqgen-ui.c - Simple user interface for certreqgen.c
- * Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -145,6 +145,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
   char *result = NULL;
   int i;
   const char *s, *s2;
+  int selfsigned;
 
   answer = NULL;
   init_membuf (&mb_email, 100);
@@ -346,6 +347,11 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
   ask_mb_lines (&mb_email, "Name-URI: ");
 
 
+  /* Want a self-signed certificate?  */
+  selfsigned = tty_get_answer_is_yes
+    (_("Create self-signed certificate? (y/N) "));
+
+
   /* Put it all together.  */
   store_key_value_lf (&mb_result, "Key-Type: ", keytype);
   {
@@ -353,10 +359,12 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
     snprintf (numbuf, sizeof numbuf, "%u", nbits);
     store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
   }
-  store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
-  store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
   if (keygrip)
     store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
+  store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
+  if (selfsigned)
+    store_key_value_lf (&mb_result, "Serial: ", "random");
+  store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
   if (store_mb_lines (&mb_result, &mb_email))
     goto mem_error;
   if (store_mb_lines (&mb_result, &mb_dns))
@@ -368,14 +376,13 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
   if (!result)
     goto mem_error;
 
-  tty_printf (_("Parameters to be used for the certificate request:\n"));
+  tty_printf (_("These parameters are used:\n"));
   for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
     tty_printf ("    %.*s\n", (int)(s2-s), s);
   tty_printf ("\n");
 
-
-  if (!tty_get_answer_is_yes ("Really create request? (y/N) "))
-     goto leave;
+  if (!tty_get_answer_is_yes ("Proceed with creation? (y/N) "))
+    goto leave;
 
   /* Now create a parameter file and generate the key.  */
   fp = es_fopenmem (0, "w+");
@@ -386,8 +393,9 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
     }
   es_fputs (result, fp);
   es_rewind (fp);
-  tty_printf (_("Now creating certificate request.  "
-                "This may take a while ...\n"));
+  tty_printf (_("Now creating %s.  "
+                "This may take a while ...\n"),
+              selfsigned?_("self-signed certificate"):_("certificate request"));
   {
     int save_pem = ctrl->create_pem;
     ctrl->create_pem = 1; /* Force creation of PEM. */
@@ -395,7 +403,13 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
     ctrl->create_pem = save_pem;
   }
   if (!err)
-    tty_printf (_("Ready.  You should now send this request to your CA.\n"));
+    {
+      if (selfsigned)
+        tty_printf (_("Ready.\n"));
+      else
+        tty_printf
+          (_("Ready.  You should now send this request to your CA.\n"));
+    }
 
 
   goto leave;
diff --git a/sm/certreqgen.c b/sm/certreqgen.c
index 4218908..7d0bfbd 100644
--- a/sm/certreqgen.c
+++ b/sm/certreqgen.c
@@ -1,6 +1,6 @@
-/* certreqgen.c - Generate a key and a certification request
- * Copyright (C) 2002, 2003, 2005, 2007,
- *               2010 Free Software Foundation, Inc.
+/* certreqgen.c - Generate a key and a certification [request]
+ * Copyright (C) 2002, 2003, 2005, 2007, 2010,
+ *               2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -43,6 +43,7 @@ The format of the native parameter file is follows:
 	Perform the key generation.  Note that an implicit commit is done
 	at the next "Key-Type" parameter.
     %certfile <filename>
+        [Not yet implemented!]
 	Do not write the certificate to the keyDB but to <filename>.
         This must be given before the first
 	commit to take place, duplicate specification of the same filename
@@ -51,35 +52,83 @@ The format of the native parameter file is follows:
 	and all keys are written to that file.	If a new filename is given,
 	this file is created (and overwrites an existing one).
 	Both control statements must be given.
+
    o The order of the parameters does not matter except for "Key-Type"
      which must be the first parameter.  The parameters are only for the
      generated keyblock and parameters from previous key generations are not
      used. Some syntactically checks may be performed.
+
      The currently defined parameters are:
+
      Key-Type: <algo>
 	Starts a new parameter block by giving the type of the
 	primary key. The algorithm must be capable of signing.
 	This is a required parameter.  For now the only supported
         algorithm is "rsa".
+
      Key-Length: <length-in-bits>
 	Length of the key in bits.  Default is 2048.
-     Key-Grip: hexstring
+
+     Key-Grip: <hexstring>
         This is optional and used to generate a request for an already
         existing key.  Key-Length will be ignored when given,
+
      Key-Usage: <usage-list>
         Space or comma delimited list of key usage, allowed values are
         "encrypt" and "sign".  This is used to generate the KeyUsage extension.
         Please make sure that the algorithm is capable of this usage.  Default
         is to allow encrypt and sign.
-     Name-DN: subject name
+
+     Name-DN: <subject_name>
         This is the DN name of the subject in rfc2253 format.
+
      Name-Email: <string>
 	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
 
+     The following parameters are only used if a certificate (and not
+     a certificate signing request) is requested:
+
+     Serial: <sn>
+        If this parameter is given an X.509 certificate will be
+        generated.  SN is expected to be a hex string representing an
+        unsigned integer of arbitary length.  The special value
+        "random" can be used to crete a 64 bit random serial number.
+
+     Issuer-DN: <issuer_name>
+        This is the DN name of the issuer in rfc2253 format.  If it is
+        not set the subject DN will be used instead.  This creates a
+        self-signed certificate.  Only in this case a special GnuPG
+        extension will then be included in the certificate to mark it
+        as a standalone certificate.
+
+     Creation-Date: <iso-date>
+        Set the notBefore date of the certificate.  Either a date like
+        "1986-04-26" or a full timestamp like "19860426T042640" may be
+        used.  The time is considered to be UTC.  If it is not given
+        the current date is used.
+
+     Expire-Date: <iso-date>
+        Set the notBefore date of the certificate.  Either a date like
+        "1986-04-26" or a full timestamp like "19860426T042640" may be
+        used.  The time is considered to be UTC.  If it is not given a
+        default value is used.
+
+     Signing-Key: <keygrip>
+        This gives the keygrip of the key used to sign the
+        certificate.  If it is not given a self-signed certificate
+        will be created.
+
+     Hash-Algo: <hash-algo>
+        Use HASH-ALGO for this certificate.  The supported hash
+        algorithms are: "sha-1", "sha-256", "sha-384" and "sha-512".
+        "sha-1" is the default.
+
 Here is an example:
 $ cat >foo <<EOF
 %echo Generating a standard key
@@ -111,18 +160,26 @@ EOF
 #include "i18n.h"
 
 
-enum para_name {
-  pKEYTYPE,
-  pKEYLENGTH,
-  pKEYGRIP,
-  pKEYUSAGE,
-  pNAMEDN,
-  pNAMEEMAIL,
-  pNAMEDNS,
-  pNAMEURI
-};
+enum para_name
+  {
+    pKEYTYPE,
+    pKEYLENGTH,
+    pKEYGRIP,
+    pKEYUSAGE,
+    pNAMEDN,
+    pNAMEEMAIL,
+    pNAMEDNS,
+    pNAMEURI,
+    pSERIAL,
+    pISSUERDN,
+    pNOTBEFORE,
+    pNOTAFTER,
+    pSIGNINGKEY,
+    pHASHALGO
+  };
 
-struct para_data_s {
+struct para_data_s
+{
   struct para_data_s *next;
   int lnr;
   enum para_name key;
@@ -132,24 +189,28 @@ struct para_data_s {
   } u;
 };
 
-struct reqgen_ctrl_s {
+struct reqgen_ctrl_s
+{
   int lnr;
   int dryrun;
-  ksba_writer_t writer;
 };
 
 
 static const char oidstr_keyUsage[] = "2.5.29.15";
+static const char oidstr_basicConstraints[] = "2.5.29.19";
+static const char oidstr_standaloneCertificate[] = "1.3.6.1.4.1.11591.2.2.1";
 
 
 static int proc_parameters (ctrl_t ctrl,
                             struct para_data_s *para,
+                            estream_t out_fp,
                             struct reqgen_ctrl_s *outctrl);
 static int create_request (ctrl_t ctrl,
                            struct para_data_s *para,
                            const char *carddirect,
                            ksba_const_sexp_t public,
-                           struct reqgen_ctrl_s *outctrl);
+                           ksba_const_sexp_t sigkey,
+                           ksba_writer_t writer);
 
 
 
@@ -248,7 +309,7 @@ get_parameter_uint (struct para_data_s *para, enum para_name key)
 /* Read the certificate generation parameters from FP and generate
    (all) certificate requests.  */
 static int
-read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
+read_parameters (ctrl_t ctrl, estream_t fp, estream_t out_fp)
 {
   static struct {
     const char *name;
@@ -263,6 +324,14 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
     { "Name-Email",     pNAMEEMAIL, 1 },
     { "Name-DNS",       pNAMEDNS, 1 },
     { "Name-URI",       pNAMEURI, 1 },
+    { "Serial",         pSERIAL },
+    { "Issuer-DN",      pISSUERDN },
+    { "Creation-Date",  pNOTBEFORE },
+    { "Not-Before",     pNOTBEFORE },
+    { "Expire-Date",    pNOTAFTER },
+    { "Not-After",      pNOTAFTER },
+    { "Signing-Key",    pSIGNINGKEY },
+    { "Hash-Algo",      pHASHALGO },
     { NULL, 0 }
   };
   char line[1024], *p;
@@ -272,7 +341,6 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
   struct reqgen_ctrl_s outctrl;
 
   memset (&outctrl, 0, sizeof (outctrl));
-  outctrl.writer = writer;
 
   err = NULL;
   para = NULL;
@@ -309,7 +377,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
             outctrl.dryrun = 1;
           else if (!ascii_strcasecmp( keyword, "%commit"))
             {
-              rc = proc_parameters (ctrl, para, &outctrl);
+              rc = proc_parameters (ctrl, para, out_fp, &outctrl);
               if (rc)
                 goto leave;
               any = 1;
@@ -356,7 +424,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
 
       if (keywords[i].key == pKEYTYPE && para)
         {
-          rc = proc_parameters (ctrl, para, &outctrl);
+          rc = proc_parameters (ctrl, para, out_fp, &outctrl);
           if (rc)
             goto leave;
           any = 1;
@@ -399,7 +467,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
     }
   else if (para)
     {
-      rc = proc_parameters (ctrl, para, &outctrl);
+      rc = proc_parameters (ctrl, para, out_fp, &outctrl);
       if (rc)
         goto leave;
       any = 1;
@@ -438,18 +506,19 @@ has_invalid_email_chars (const char *s)
 
 /* Check that all required parameters are given and perform the action */
 static int
-proc_parameters (ctrl_t ctrl,
-                 struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
+proc_parameters (ctrl_t ctrl, struct para_data_s *para,
+                 estream_t out_fp, struct reqgen_ctrl_s *outctrl)
 {
   gpg_error_t err;
   struct para_data_s *r;
-  const char *s;
+  const char *s, *string;
   int i;
   unsigned int nbits;
   char numbuf[20];
   unsigned char keyparms[100];
   int rc;
   ksba_sexp_t public;
+  ksba_sexp_t sigkey = NULL;
   int seq;
   size_t erroff, errlen;
   char *cardkeyid = NULL;
@@ -539,6 +608,100 @@ proc_parameters (ctrl_t ctrl,
         }
     }
 
+  /* Check the optional serial number.  */
+  string = get_parameter_value (para, pSERIAL, 0);
+  if (string)
+    {
+      if (!strcmp (string, "random"))
+        ; /* Okay.  */
+      else
+        {
+          for (s=string, i=0; hexdigitp (s); s++, i++)
+            ;
+          if (*s)
+            {
+              r = get_parameter (para, pSERIAL, 0);
+              log_error (_("line %d: invalid serial number\n"), r->lnr);
+              xfree (cardkeyid);
+              return gpg_error (GPG_ERR_INV_PARAMETER);
+            }
+        }
+    }
+
+  /* Check the optional issuer DN.  */
+  string = get_parameter_value (para, pISSUERDN, 0);
+  if (string)
+    {
+      err = ksba_dn_teststr (string, 0, &erroff, &errlen);
+      if (err)
+        {
+          r = get_parameter (para, pISSUERDN, 0);
+          if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
+            log_error (_("line %d: invalid issuer name label `%.*s'\n"),
+                       r->lnr, (int)errlen, string+erroff);
+          else
+            log_error (_("line %d: invalid issuer name `%s' at pos %d\n"),
+                       r->lnr, string, (int)erroff);
+          xfree (cardkeyid);
+          return gpg_error (GPG_ERR_INV_PARAMETER);
+        }
+    }
+
+  /* Check the optional creation date.  */
+  string = get_parameter_value (para, pNOTBEFORE, 0);
+  if (string && !string2isotime (NULL, string))
+    {
+      r = get_parameter (para, pNOTBEFORE, 0);
+      log_error (_("line %d: invalid date given\n"), r->lnr);
+      xfree (cardkeyid);
+      return gpg_error (GPG_ERR_INV_PARAMETER);
+    }
+
+
+  /* Check the optional expire date.  */
+  string = get_parameter_value (para, pNOTAFTER, 0);
+  if (string && !string2isotime (NULL, string))
+    {
+      r = get_parameter (para, pNOTAFTER, 0);
+      log_error (_("line %d: invalid date given\n"), r->lnr);
+      xfree (cardkeyid);
+      return gpg_error (GPG_ERR_INV_PARAMETER);
+    }
+
+  /* Get the optional signing key.  */
+  string = get_parameter_value (para, pSIGNINGKEY, 0);
+  if (string)
+    {
+      rc = gpgsm_agent_readkey (ctrl, 0, string, &sigkey);
+      if (rc)
+        {
+          r = get_parameter (para, pKEYTYPE, 0);
+          log_error (_("line %d: error getting signing key by keygrip `%s'"
+                       ": %s\n"), r->lnr, s, gpg_strerror (rc));
+          xfree (cardkeyid);
+          return rc;
+        }
+    }
+
+  /* Check the optional hash-algo.  */
+  {
+    int mdalgo;
+
+    string = get_parameter_value (para, pHASHALGO, 0);
+    if (string && !((mdalgo = gcry_md_map_name (string))
+                    && (mdalgo == GCRY_MD_SHA1
+                        || mdalgo == GCRY_MD_SHA256
+                        || mdalgo == GCRY_MD_SHA384
+                        || mdalgo == GCRY_MD_SHA512)))
+      {
+        r = get_parameter (para, pHASHALGO, 0);
+        log_error (_("line %d: invalid hash algorithm given\n"), r->lnr);
+        xfree (cardkeyid);
+        return gpg_error (GPG_ERR_INV_PARAMETER);
+      }
+  }
+
+  /* Create or retrieve the public key.  */
   if (cardkeyid) /* Take the key from the current smart card. */
     {
       rc = gpgsm_agent_readkey (ctrl, 1, cardkeyid, &public);
@@ -547,6 +710,7 @@ proc_parameters (ctrl_t ctrl,
           r = get_parameter (para, pKEYTYPE, 0);
           log_error (_("line %d: error reading key `%s' from card: %s\n"),
                      r->lnr, cardkeyid, gpg_strerror (rc));
+          xfree (sigkey);
           xfree (cardkeyid);
           return rc;
         }
@@ -559,11 +723,12 @@ proc_parameters (ctrl_t ctrl,
           r = get_parameter (para, pKEYTYPE, 0);
           log_error (_("line %d: error getting key by keygrip `%s': %s\n"),
                      r->lnr, s, gpg_strerror (rc));
+          xfree (sigkey);
           xfree (cardkeyid);
           return rc;
         }
     }
-  else /* Generate new key.  */
+  else if (!outctrl->dryrun) /* Generate new key.  */
     {
       sprintf (numbuf, "%u", nbits);
       snprintf ((char*)keyparms, DIM (keyparms)-1,
@@ -575,12 +740,45 @@ proc_parameters (ctrl_t ctrl,
           r = get_parameter (para, pKEYTYPE, 0);
           log_error (_("line %d: key generation failed: %s <%s>\n"),
                      r->lnr, gpg_strerror (rc), gpg_strsource (rc));
+          xfree (sigkey);
           xfree (cardkeyid);
           return rc;
         }
     }
 
-  rc = create_request (ctrl, para, cardkeyid, public, outctrl);
+
+  if (!outctrl->dryrun)
+    {
+      Base64Context b64writer = NULL;
+      ksba_writer_t writer;
+      int create_cert ;
+
+      create_cert = !!get_parameter_value (para, pSERIAL, 0);
+
+      ctrl->pem_name = create_cert? "CERTIFICATE" : "CERTIFICATE REQUEST";
+      rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
+      if (rc)
+        log_error ("can't create writer: %s\n", gpg_strerror (rc));
+      else
+        {
+          rc = create_request (ctrl, para, cardkeyid, public, sigkey, writer);
+          if (!rc)
+            {
+              rc = gpgsm_finish_writer (b64writer);
+              if (rc)
+                log_error ("write failed: %s\n", gpg_strerror (rc));
+              else
+                {
+                  gpgsm_status (ctrl, STATUS_KEY_CREATED, "P");
+                  log_info ("certificate%s created\n",
+                            create_cert?"":" request");
+                }
+            }
+          gpgsm_destroy_writer (b64writer);
+        }
+    }
+
+  xfree (sigkey);
   xfree (public);
   xfree (cardkeyid);
 
@@ -595,25 +793,34 @@ create_request (ctrl_t ctrl,
                 struct para_data_s *para,
                 const char *carddirect,
                 ksba_const_sexp_t public,
-                struct reqgen_ctrl_s *outctrl)
+                ksba_const_sexp_t sigkey,
+                ksba_writer_t writer)
 {
   ksba_certreq_t cr;
   gpg_error_t err;
   gcry_md_hd_t md;
   ksba_stop_reason_t stopreason;
   int rc = 0;
-  const char *s;
+  const char *s, *string;
   unsigned int use;
   int seq;
   char *buf, *p;
   size_t len;
   char numbuf[30];
+  ksba_isotime_t atime;
+  int certmode = 0;
+  int mdalgo;
 
   err = ksba_certreq_new (&cr);
   if (err)
     return err;
 
-  rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
+  string = get_parameter_value (para, pHASHALGO, 0);
+  if (string)
+    mdalgo = gcry_md_map_name (string);
+  else
+    mdalgo = GCRY_MD_SHA1;
+  rc = gcry_md_open (&md, mdalgo, 0);
   if (rc)
     {
       log_error ("md_open failed: %s\n", gpg_strerror (rc));
@@ -623,7 +830,7 @@ create_request (ctrl_t ctrl,
     gcry_md_start_debug (md, "cr.cri");
 
   ksba_certreq_set_hash_function (cr, HASH_FNC, md);
-  ksba_certreq_set_writer (cr, outctrl->writer);
+  ksba_certreq_set_writer (cr, writer);
 
   err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN, 0));
   if (err)
@@ -720,7 +927,7 @@ create_request (ctrl_t ctrl,
       goto leave;
     }
 
-
+  /* Set key usage flags.  */
   use = get_parameter_uint (para, pKEYUSAGE);
   if (use == GCRY_PK_USAGE_SIGN)
     {
@@ -749,6 +956,170 @@ create_request (ctrl_t ctrl,
     }
 
 
+  /* See whether we want to create an X.509 certificate.  */
+  string = get_parameter_value (para, pSERIAL, 0);
+  if (string)
+    {
+      certmode = 1;
+
+      /* Store the serial number.  */
+      if (!strcmp (string, "random"))
+        {
+          char snbuf[3+8+1];
+
+          memcpy (snbuf, "(8:", 3);
+          gcry_create_nonce (snbuf+3, 8);
+          /* Clear high bit to guarantee a positive integer.  */
+          snbuf[3] &= 0x7f;
+          snbuf[3+8] = ')';
+          err = ksba_certreq_set_serial (cr, snbuf);
+        }
+      else
+        {
+          char *hexbuf;
+
+          /* Allocate a buffer large enough to prefix the string with
+             a '0' so to have an even number of digits.  Prepend two
+             further '0' so that the binary result will have a leading
+             0 byte and thus can't be the representation of a negative
+             number.  Note that ksba_certreq_set_serial strips all
+             unneeded leading 0 bytes.  */
+          hexbuf = p = xtrymalloc (2 + 1 + strlen (string) + 1);
+          if (!hexbuf)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          if ((strlen (string) & 1))
+            *p++ = '0';
+          *p++ = '0';
+          *p++ = '0';
+          strcpy (p, string);
+          for (p=hexbuf, len=0; p[0] && p[1]; p += 2)
+            ((unsigned char*)hexbuf)[len++] = xtoi_2 (s);
+          /* Now build the S-expression.  */
+          snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
+          buf = p = xtrymalloc (1 + strlen (numbuf) + len + 1 + 1);
+          if (!buf)
+            {
+              err = gpg_error_from_syserror ();
+              xfree (hexbuf);
+              goto leave;
+            }
+          p = stpcpy (stpcpy (buf, "("), numbuf);
+          memcpy (p, hexbuf, len);
+          p += len;
+          strcpy (p, ")");
+          xfree (hexbuf);
+          err = ksba_certreq_set_serial (cr, buf);
+          xfree (buf);
+        }
+      if (err)
+        {
+          log_error ("error setting the serial number: %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
+
+
+      /* Store the issuer DN.  If no issuer DN is given and no signing
+         key has been set we add the standalone extension and the
+         basic constraints to mark it as a self-signed CA
+         certificate.  */
+      string = get_parameter_value (para, pISSUERDN, 0);
+      if (string)
+        {
+          /* Issuer DN given.  Note that this may be the same as the
+             subject DN and thus this could as well be a self-signed
+             certificate.  However the caller needs to explicitly
+             specify basicConstraints and so forth.  */
+          err = ksba_certreq_set_issuer (cr, string);
+          if (err)
+            {
+              log_error ("error setting the issuer DN: %s\n",
+                         gpg_strerror (err));
+              goto leave;
+            }
+
+        }
+      else if (!string && !sigkey)
+        {
+          /* Self-signed certificate requested.  Add basicConstraints
+             and the custom GnuPG standalone extension.  */
+          err = ksba_certreq_add_extension (cr, oidstr_basicConstraints, 1,
+                                            "\x30\x03\x01\x01\xff", 5);
+          if (err)
+            goto leave;
+          err = ksba_certreq_add_extension (cr, oidstr_standaloneCertificate, 0,
+                                            "\x01\x01\xff", 3);
+          if (err)
+            goto leave;
+        }
+
+      /* Store the creation date.  */
+      string = get_parameter_value (para, pNOTBEFORE, 0);
+      if (string)
+        {
+          if (!string2isotime (atime, string))
+            BUG (); /* We already checked the value.  */
+        }
+      else
+        gnupg_get_isotime (atime);
+      err = ksba_certreq_set_validity (cr, 0, atime);
+      if (err)
+        {
+          log_error ("error setting the creation date: %s\n",
+                     gpg_strerror (err));
+          goto leave;
+        }
+
+
+      /* Store the expire date.  If it is not given, libksba inserts a
+         default value.  */
+      string = get_parameter_value (para, pNOTAFTER, 0);
+      if (string)
+        {
+          if (!string2isotime (atime, string))
+            BUG (); /* We already checked the value.  */
+          err = ksba_certreq_set_validity (cr, 1, atime);
+          if (err)
+            {
+              log_error ("error setting the expire date: %s\n",
+                         gpg_strerror (err));
+              goto leave;
+            }
+        }
+
+
+      /* Figure out the signing algorithm.  If no sigkey has been
+         given we set it to the public key to create a self-signed
+         certificate. */
+      if (!sigkey)
+        sigkey = public;
+
+      {
+        unsigned char *siginfo;
+
+        err = transform_sigval (sigkey,
+                                gcry_sexp_canon_len (sigkey, 0, NULL, NULL),
+                                mdalgo, &siginfo, NULL);
+        if (!err)
+          {
+            err = ksba_certreq_set_siginfo (cr, siginfo);
+            xfree (siginfo);
+          }
+        if (err)
+          {
+            log_error ("error setting the siginfo: %s\n",
+                       gpg_strerror (err));
+            rc = err;
+            goto leave;
+          }
+      }
+    }
+  else
+    sigkey = public;
+
   do
     {
       err = ksba_certreq_build (cr, &stopreason);
@@ -764,17 +1135,17 @@ create_request (ctrl_t ctrl,
           size_t n;
           unsigned char grip[20];
           char hexgrip[41];
-          unsigned char *sigval;
+          unsigned char *sigval, *newsigval;
           size_t siglen;
 
-          n = gcry_sexp_canon_len (public, 0, NULL, NULL);
+          n = gcry_sexp_canon_len (sigkey, 0, NULL, NULL);
           if (!n)
             {
               log_error ("libksba did not return a proper S-Exp\n");
               rc = gpg_error (GPG_ERR_BUG);
               goto leave;
             }
-          rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)public, n);
+          rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)sigkey, n);
           if (rc)
             {
               log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
@@ -790,14 +1161,15 @@ create_request (ctrl_t ctrl,
           gcry_sexp_release (s_pkey);
           bin2hex (grip, 20, hexgrip);
 
-          log_info ("about to sign CSR for key: &%s\n", hexgrip);
+          log_info ("about to sign the %s for key: &%s\n",
+                    certmode? "certificate":"CSR", hexgrip);
 
           if (carddirect)
             rc = gpgsm_scd_pksign (ctrl, carddirect, NULL,
-                                     gcry_md_read(md, GCRY_MD_SHA1),
-                                     gcry_md_get_algo_dlen (GCRY_MD_SHA1),
-                                     GCRY_MD_SHA1,
-                                     &sigval, &siglen);
+                                   gcry_md_read (md, mdalgo),
+                                   gcry_md_get_algo_dlen (mdalgo),
+                                   mdalgo,
+                                   &sigval, &siglen);
           else
             {
               char *orig_codeset;
@@ -810,9 +1182,9 @@ create_request (ctrl_t ctrl,
                    " more.\n"));
               i18n_switchback (orig_codeset);
               rc = gpgsm_agent_pksign (ctrl, hexgrip, desc,
-                                       gcry_md_read(md, GCRY_MD_SHA1),
-                                       gcry_md_get_algo_dlen (GCRY_MD_SHA1),
-                                       GCRY_MD_SHA1,
+                                       gcry_md_read(md, mdalgo),
+                                       gcry_md_get_algo_dlen (mdalgo),
+                                       mdalgo,
                                        &sigval, &siglen);
               xfree (desc);
             }
@@ -822,8 +1194,14 @@ create_request (ctrl_t ctrl,
               goto leave;
             }
 
-          err = ksba_certreq_set_sig_val (cr, sigval);
+          err = transform_sigval (sigval, siglen, mdalgo,
+                                  &newsigval, NULL);
           xfree (sigval);
+          if (!err)
+            {
+              err = ksba_certreq_set_sig_val (cr, newsigval);
+              xfree (newsigval);
+            }
           if (err)
             {
               log_error ("failed to store the sig_val: %s\n",
@@ -850,18 +1228,8 @@ int
 gpgsm_genkey (ctrl_t ctrl, estream_t in_stream, estream_t out_stream)
 {
   int rc;
-  Base64Context b64writer = NULL;
-  ksba_writer_t writer;
 
-  ctrl->pem_name = "CERTIFICATE REQUEST";
-  rc = gpgsm_create_writer (&b64writer, ctrl, out_stream, &writer);
-  if (rc)
-    {
-      log_error ("can't create writer: %s\n", gpg_strerror (rc));
-      goto leave;
-    }
-
-  rc = read_parameters (ctrl, in_stream, writer);
+  rc = read_parameters (ctrl, in_stream, out_stream);
   if (rc)
     {
       log_error ("error creating certificate request: %s <%s>\n",
@@ -869,17 +1237,6 @@ gpgsm_genkey (ctrl_t ctrl, estream_t in_stream, estream_t out_stream)
       goto leave;
     }
 
-  rc = gpgsm_finish_writer (b64writer);
-  if (rc)
-    {
-      log_error ("write failed: %s\n", gpg_strerror (rc));
-      goto leave;
-    }
-
-  gpgsm_status (ctrl, STATUS_KEY_CREATED, "P");
-  log_info ("certificate request created\n");
-
  leave:
-  gpgsm_destroy_writer (b64writer);
   return rc;
 }
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 54d4aff..31cd951 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -429,6 +429,10 @@ int gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
 
 /*-- misc.c --*/
 void setup_pinentry_env (void);
+gpg_error_t transform_sigval (const unsigned char *sigval, size_t sigvallen,
+                              int mdalgo,
+                              unsigned char **r_newsigval,
+                              size_t *r_newsigvallen);
 
 
 
diff --git a/sm/keylist.c b/sm/keylist.c
index 1d6ce6e..fc903ba 100644
--- a/sm/keylist.c
+++ b/sm/keylist.c
@@ -186,6 +186,7 @@ static struct
 
   /* GnuPG extensions */
   { "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
+  { "1.3.6.1.4.1.11591.2.2.1", "standaloneCertificate" },
 
   /* Extensions used by the Bundesnetzagentur.  */
   { "1.3.6.1.4.1.8301.3.5", "validityModel" },
diff --git a/sm/misc.c b/sm/misc.c
index 2d6cdd6..4c6293f 100644
--- a/sm/misc.c
+++ b/sm/misc.c
@@ -1,5 +1,5 @@
 /* misc.c - Miscellaneous fucntions
- * Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2009, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -31,6 +31,9 @@
 #include "gpgsm.h"
 #include "i18n.h"
 #include "sysutils.h"
+#include "../common/tlv.h"
+#include "../common/sexp-parse.h"
+
 
 /* Setup the environment so that the pinentry is able to get all
    required information.  This is used prior to an exec of the
@@ -86,3 +89,130 @@ setup_pinentry_env (void)
 
 #endif /*!HAVE_W32_SYSTEM*/
 }
+
+
+
+/* Transform a sig-val style s-expression as returned by Libgcrypt to
+   one which includes an algorithm identifier encoding the public key
+   and the hash algorithm.  The public key algorithm is taken directly
+   from SIGVAL and the hash algorithm is given by MDALGO.  This is
+   required because X.509 merges the public key algorithm and the hash
+   algorithm into one OID but Libgcrypt is not aware of that.  The
+   function ignores missing parameters so that it can also be used to
+   create an siginfo value as expected by ksba_certreq_set_siginfo.
+   To create a siginfo s-expression a public-key s-expression may be
+   used instead of a sig-val.  We only support RSA for now.  */
+gpg_error_t
+transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
+                  unsigned char **r_newsigval, size_t *r_newsigvallen)
+{
+  gpg_error_t err;
+  const unsigned char *buf, *tok;
+  size_t buflen, toklen;
+  int depth, last_depth1, last_depth2;
+  int is_pubkey = 0;
+  const unsigned char *rsa_s = NULL;
+  size_t rsa_s_len;
+  const char *oid;
+  gcry_sexp_t sexp;
+
+  *r_newsigval = NULL;
+  if (r_newsigvallen)
+    *r_newsigvallen = 0;
+
+  buf = sigval;
+  buflen = sigvallen;
+  depth = 0;
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if (tok && toklen == 7 && !memcmp ("sig-val", tok, toklen))
+    ;
+  else if (tok && toklen == 10 && !memcmp ("public-key", tok, toklen))
+    is_pubkey = 1;
+  else
+    return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+    return err;
+  if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen))
+    return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
+  last_depth1 = depth;
+  while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+         && depth && depth >= last_depth1)
+    {
+      if (tok)
+        return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+      if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+        return err;
+      if (tok && toklen == 1)
+        {
+          const unsigned char **mpi;
+          size_t *mpi_len;
+
+          switch (*tok)
+            {
+            case 's': mpi = &rsa_s; mpi_len = &rsa_s_len; break;
+            default:  mpi = NULL;   mpi_len = NULL; break;
+            }
+          if (mpi && *mpi)
+            return gpg_error (GPG_ERR_DUP_VALUE);
+
+          if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+            return err;
+          if (tok && mpi)
+            {
+              *mpi = tok;
+              *mpi_len = toklen;
+            }
+        }
+
+      /* Skip to the end of the list. */
+      last_depth2 = depth;
+      while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+             && depth && depth >= last_depth2)
+        ;
+      if (err)
+        return err;
+    }
+  if (err)
+    return err;
+
+  /* Map the hash algorithm to an OID.  */
+  switch (mdalgo)
+    {
+    case GCRY_MD_SHA1:
+      oid = "1.2.840.113549.1.1.5";  /* sha1WithRSAEncryption */
+      break;
+
+    case GCRY_MD_SHA256:
+      oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */
+      break;
+
+    case GCRY_MD_SHA384:
+      oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */
+      break;
+
+    case GCRY_MD_SHA512:
+      oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */
+      break;
+
+    default:
+      return gpg_error (GPG_ERR_DIGEST_ALGO);
+    }
+
+  if (rsa_s && !is_pubkey)
+    err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(s%b)))",
+                           oid, (int)rsa_s_len, rsa_s);
+  else
+    err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s))", oid);
+  if (err)
+    return err;
+  err = make_canon_sexp (sexp, r_newsigval, r_newsigvallen);
+  gcry_sexp_release (sexp);
+
+  return err;
+}

commit bb6d1b48f61d483fc75a17b4d140c489afe43ef0
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Mar 1 14:28:59 2011 +0100

    Update some M4 files and AUTHORS.

diff --git a/AUTHORS b/AUTHORS
index de27957..d690e77 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,6 +14,8 @@ Ales Nyakhaychyk <nyakhaychyk at i1fn.linux.by> Translations [be]
 Andrey Jivsov <openpgp at brainhub.org>  Assigns past and future changes for ECC.
     (g10/ecdh.c.  other changes to support ECC)
 
+Ben Kibbey  <bjk at luxsci.net>  Assigns past and future changes.
+
 Birger Langkjer <birger.langkjer at image.dk> Translations [da]
 
 Maxim Britov <maxim.britov at gmail.com> Translations [ru]
@@ -123,6 +125,8 @@ Werner Koch  <wk at gnupg.org>  Assigns GNU Privacy Guard and future changes.
 
 Yosiaki IIDA <iida at ring.gr.jp> Translations [ja]
 
+Yutaka Niibe   Assigns Past and Future Changes
+     (scd/)
 
 
 Other authors
@@ -145,7 +149,7 @@ by Colin Tuckley and Daniel Leidert for the GNU/Debian distribution.
 Copyright
 =========
 
-GnuPG is distributed under the GNU General Public License, version 2
+GnuPG is distributed under the GNU General Public License, version 3
 or later.  A few files are under the Lesser General Public License, a
 few other files carry the all permissive license note as found at the
 bottom of this file.  Certain files in keyserver/ allow one specific
@@ -168,7 +172,7 @@ name gpg2keys_*.
 =========
 
  Copyright 1998, 1999, 2000, 2001, 2002, 2004, 2005,
-           2006, 2007, 2008, 2010 Free Software Foundation, Inc.
+           2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
diff --git a/ChangeLog b/ChangeLog
index 17d049f..4acd121 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2011-02-25  Werner Koch  <wk at g10code.com>
+
+	* configure.ac: Require libksba 1.2.
+
 2011-02-04  Werner Koch  <wk at g10code.com>
 
 	* autogen.sh: Ensure that the git pre-commit hoom has been
diff --git a/configure.ac b/configure.ac
index f79ff53..e372d33 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,7 +49,7 @@ NEED_LIBASSUAN_API=2
 NEED_LIBASSUAN_VERSION=2.0.0
 
 NEED_KSBA_API=1
-NEED_KSBA_VERSION=1.1.0
+NEED_KSBA_VERSION=1.2.0
 
 
 PACKAGE=$PACKAGE_NAME
diff --git a/m4/ChangeLog b/m4/ChangeLog
index c633468..29af1fb 100644
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,3 +1,7 @@
+2011-02-25  Werner Koch  <wk at g10code.com>
+
+	* ksba.m4: Update from git master.
+
 2011-02-23  Werner Koch  <wk at g10code.com>
 
 	* libgcrypt.m4, gpg-error.m4: Update from their GIT masters.
diff --git a/m4/gpg-error.m4 b/m4/gpg-error.m4
index 8d82925..2e5a0ab 100644
--- a/m4/gpg-error.m4
+++ b/m4/gpg-error.m4
@@ -1,5 +1,5 @@
 # gpg-error.m4 - autoconf macro to detect libgpg-error.
-# Copyright (C) 2002, 2003, 2004 g10 Code GmbH
+# Copyright (C) 2002, 2003, 2004, 2011 g10 Code GmbH
 #
 # This file is free software; as a special exception the author gives
 # unlimited permission to copy and/or distribute it, with or without
@@ -14,7 +14,8 @@ dnl                   [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
 dnl Test for libgpg-error and define GPG_ERROR_CFLAGS and GPG_ERROR_LIBS
 dnl
 AC_DEFUN([AM_PATH_GPG_ERROR],
-[ AC_ARG_WITH(gpg-error-prefix,
+[ AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_ARG_WITH(gpg-error-prefix,
             AC_HELP_STRING([--with-gpg-error-prefix=PFX],
                            [prefix where GPG Error is installed (optional)]),
      gpg_error_config_prefix="$withval", gpg_error_config_prefix="")
@@ -53,10 +54,9 @@ AC_DEFUN([AM_PATH_GPG_ERROR],
     GPG_ERROR_LIBS=`$GPG_ERROR_CONFIG $gpg_error_config_args --libs`
     AC_MSG_RESULT([yes ($gpg_error_config_version)])
     ifelse([$2], , :, [$2])
-    if test x"$host" != x ; then
-      gpg_error_config_host=`$GPG_ERROR_CONFIG $gpg_error_config_args --host 2>/dev/null || echo none`
-      if test x"$gpg_error_config_host" != xnone ; then
-        if test x"$gpg_error_config_host" != x"$host" ; then
+    gpg_error_config_host=`$GPG_ERROR_CONFIG $gpg_error_config_args --host 2>/dev/null || echo none`
+    if test x"$gpg_error_config_host" != xnone ; then
+      if test x"$gpg_error_config_host" != x"$host" ; then
   AC_MSG_WARN([[
 ***
 *** The config script $GPG_ERROR_CONFIG was
@@ -65,7 +65,6 @@ AC_DEFUN([AM_PATH_GPG_ERROR],
 *** You may want to use the configure option --with-gpg-error-prefix
 *** to specify a matching config script.
 ***]])
-        fi
       fi
     fi
   else
diff --git a/m4/ksba.m4 b/m4/ksba.m4
index 1100387..73b2e26 100644
--- a/m4/ksba.m4
+++ b/m4/ksba.m4
@@ -15,13 +15,14 @@ dnl              [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
 dnl Test for libksba and define KSBA_CFLAGS and KSBA_LIBS
 dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed
 dnl with the API version to also check the API compatibility. Example:
-dnl a MINIMUN-VERSION of 1:1.0.7 won't pass the test unless the installed 
+dnl a MINIMUN-VERSION of 1:1.0.7 won't pass the test unless the installed
 dnl version of libksba is at least 1.0.7 *and* the API number is 1.  Using
 dnl this features allows to prevent build against newer versions of libksba
 dnl with a changed API.
 dnl
 AC_DEFUN([AM_PATH_KSBA],
-[ AC_ARG_WITH(ksba-prefix,
+[AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_ARG_WITH(ksba-prefix,
             AC_HELP_STRING([--with-ksba-prefix=PFX],
                            [prefix where KSBA is installed (optional)]),
      ksba_config_prefix="$withval", ksba_config_prefix="")
@@ -60,7 +61,7 @@ AC_DEFUN([AM_PATH_KSBA],
                sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
     if test "$major" -gt "$req_major"; then
         ok=yes
-    else 
+    else
         if test "$major" -eq "$req_major"; then
             if test "$minor" -gt "$req_minor"; then
                ok=yes
@@ -99,6 +100,19 @@ AC_DEFUN([AM_PATH_KSBA],
     KSBA_CFLAGS=`$KSBA_CONFIG $ksba_config_args --cflags`
     KSBA_LIBS=`$KSBA_CONFIG $ksba_config_args --libs`
     ifelse([$2], , :, [$2])
+    libksba_config_host=`$LIBKSBA_CONFIG $ksba_config_args --host 2>/dev/null || echo none`
+    if test x"$libksba_config_host" != xnone ; then
+      if test x"$libksba_config_host" != x"$host" ; then
+  AC_MSG_WARN([[
+***
+*** The config script $LIBKSBA_CONFIG was
+*** built for $libksba_config_host and thus may not match the
+*** used host $host.
+*** You may want to use the configure option --with-libksba-prefix
+*** to specify a matching config script.
+***]])
+      fi
+    fi
   else
     KSBA_CFLAGS=""
     KSBA_LIBS=""
diff --git a/m4/libgcrypt.m4 b/m4/libgcrypt.m4
index 831dc0c..6cf482f 100644
--- a/m4/libgcrypt.m4
+++ b/m4/libgcrypt.m4
@@ -1,5 +1,5 @@
 dnl Autoconf macros for libgcrypt
-dnl       Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+dnl       Copyright (C) 2002, 2004, 2011 Free Software Foundation, Inc.
 dnl
 dnl This file is free software; as a special exception the author gives
 dnl unlimited permission to copy and/or distribute it, with or without
@@ -21,7 +21,8 @@ dnl this features allows to prevent build against newer versions of libgcrypt
 dnl with a changed API.
 dnl
 AC_DEFUN([AM_PATH_LIBGCRYPT],
-[ AC_ARG_WITH(libgcrypt-prefix,
+[ AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_ARG_WITH(libgcrypt-prefix,
             AC_HELP_STRING([--with-libgcrypt-prefix=PFX],
                            [prefix where LIBGCRYPT is installed (optional)]),
      libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="")
@@ -98,10 +99,9 @@ AC_DEFUN([AM_PATH_LIBGCRYPT],
     LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
     LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
     ifelse([$2], , :, [$2])
-    if test x"$host" != x ; then
-      libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none`
-      if test x"$libgcrypt_config_host" != xnone ; then
-        if test x"$libgcrypt_config_host" != x"$host" ; then
+    libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none`
+    if test x"$libgcrypt_config_host" != xnone ; then
+      if test x"$libgcrypt_config_host" != x"$host" ; then
   AC_MSG_WARN([[
 ***
 *** The config script $LIBGCRYPT_CONFIG was
@@ -110,7 +110,6 @@ AC_DEFUN([AM_PATH_LIBGCRYPT],
 *** You may want to use the configure option --with-libgcrypt-prefix
 *** to specify a matching config script.
 ***]])
-        fi
       fi
     fi
   else

commit dfdda3b344e525f4fdb5e2c07ac63b52e501941f
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Mar 1 14:22:41 2011 +0100

    Add new functions to convert iso time strings.

diff --git a/common/ChangeLog b/common/ChangeLog
index f6380c6..cebc0ec 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -1,3 +1,11 @@
+2011-02-27  Werner Koch  <wk at g10code.com>
+
+	* gettime.c (isotime2epoch): Factor check code out to ..
+	(isotime_p): .. new.
+	(isotime_human_p): New.
+	(string2isotime): New.
+	* t-gettime.c (test_string2isotime): New.
+
 2011-02-11  Andrey Jivsov <openpgp at brainhub.org>
 
 	* openpgp-oid.c (openpgp_oid_to_str): Use unsigned int for
diff --git a/common/gettime.c b/common/gettime.c
index 27dc845..e5462a7 100644
--- a/common/gettime.c
+++ b/common/gettime.c
@@ -1,5 +1,5 @@
 /* gettime.c - Wrapper for time functions
- *	Copyright (C) 1998, 2002, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -179,29 +179,162 @@ scan_isodatestr( const char *string )
     return stamp;
 }
 
-/* Scan am ISO timestamp and return an Epoch based timestamp.  The only
-   supported format is "yyyymmddThhmmss" delimited by white space, nul, a
-   colon or a comma.  Returns (time_t)(-1) for an invalid string.  */
-time_t
-isotime2epoch (const char *string)
+
+int
+isotime_p (const char *string)
 {
   const char *s;
-  int year, month, day, hour, minu, sec;
-  struct tm tmbuf;
   int i;
 
   if (!*string)
-    return (time_t)(-1);
+    return 0;
   for (s=string, i=0; i < 8; i++, s++)
     if (!digitp (s))
-      return (time_t)(-1);
+      return 0;
   if (*s != 'T')
-      return (time_t)(-1);
+      return 0;
   for (s++, i=9; i < 15; i++, s++)
     if (!digitp (s))
-      return (time_t)(-1);
+      return 0;
   if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
-    return (time_t)(-1);  /* Wrong delimiter.  */
+    return 0;  /* Wrong delimiter.  */
+
+  return 1;
+}
+
+
+/* Scan a string and return true if the string represents the human
+   readable format of an ISO time.  This format is:
+      yyyy-mm-dd[ hh[:mm[:ss]]]
+   Scanning stops at the second space or at a comma.  */
+int
+isotime_human_p (const char *string)
+{
+  const char *s;
+  int i;
+
+  if (!*string)
+    return 0;
+  for (s=string, i=0; i < 4; i++, s++)
+    if (!digitp (s))
+      return 0;
+  if (*s != '-')
+    return 0;
+  s++;
+  if (!digitp (s) || !digitp (s+1) || s[2] != '-')
+    return 0;
+  i = atoi_2 (s);
+  if (i < 1 || i > 12)
+    return 0;
+  s += 3;
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 1 || i > 31)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',')
+    return 1; /* Okay; only date given.  */
+  if (!spacep (s))
+    return 0;
+  s++;
+  if (spacep (s))
+    return 1; /* Okay, second space stops scanning.  */
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 0 || i > 23)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',')
+    return 1; /* Okay; only date and hour given.  */
+  if (*s != ':')
+    return 0;
+  s++;
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 0 || i > 59)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',')
+    return 1; /* Okay; only date, hour and minute given.  */
+  if (*s != ':')
+    return 0;
+  s++;
+  if (!digitp (s) || !digitp (s+1))
+    return 0;
+  i = atoi_2 (s);
+  if (i < 0 || i > 60)
+    return 0;
+  s += 2;
+  if (!*s || *s == ',' || spacep (s))
+    return 1; /* Okay; date, hour and minute and second given.  */
+
+  return 0; /* Unexpected delimiter.  */
+}
+
+/* Convert a standard isotime or a human readable variant into an
+   isotime structure.  The allowed formats are those described by
+   isotime_p and isotime_human_p.  The function returns 0 on failure
+   or the length of the scanned string on success.  */
+size_t
+string2isotime (gnupg_isotime_t atime, const char *string)
+{
+  gnupg_isotime_t dummyatime;
+
+  if (!atime)
+    atime = dummyatime;
+
+  atime[0] = 0;
+  if (isotime_p (string))
+    {
+      memcpy (atime, string, 15);
+      atime[15] = 0;
+      return 15;
+    }
+  if (!isotime_human_p (string))
+    return 0;
+  atime[0] = string[0];
+  atime[1] = string[1];
+  atime[2] = string[2];
+  atime[3] = string[3];
+  atime[4] = string[5];
+  atime[5] = string[6];
+  atime[6] = string[8];
+  atime[7] = string[9];
+  atime[8] = 'T';
+  memset (atime+9, '0', 6);
+  atime[15] = 0;
+  if (!spacep (string+10))
+    return 10;
+  if (spacep (string+11))
+    return 11; /* As per def, second space stops scanning.  */
+  atime[9] = string[11];
+  atime[10] = string[12];
+  if (string[13] != ':')
+    return 13;
+  atime[11] = string[14];
+  atime[12] = string[15];
+  if (string[16] != ':')
+    return 16;
+  atime[13] = string[17];
+  atime[14] = string[18];
+  return 19;
+}
+
+
+/* Scan an ISO timestamp and return an Epoch based timestamp.  The only
+   supported format is "yyyymmddThhmmss" delimited by white space, nul, a
+   colon or a comma.  Returns (time_t)(-1) for an invalid string.  */
+time_t
+isotime2epoch (const char *string)
+{
+  int year, month, day, hour, minu, sec;
+  struct tm tmbuf;
+
+  if (!isotime_p (string))
+    return (time_t)(-1);
 
   year  = atoi_4 (string);
   month = atoi_2 (string + 4);
diff --git a/common/gettime.h b/common/gettime.h
index 731be56..4199369 100644
--- a/common/gettime.h
+++ b/common/gettime.h
@@ -34,6 +34,9 @@ void   gnupg_set_time (time_t newtime, int freeze);
 int    gnupg_faked_time_p (void);
 u32    make_timestamp (void);
 u32    scan_isodatestr (const char *string);
+int    isotime_p (const char *string);
+int    isotime_human_p (const char *string);
+size_t string2isotime (gnupg_isotime_t atime, const char *string);
 time_t isotime2epoch (const char *string);
 void   epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
 u32    add_days_to_timestamp (u32 stamp, u16 days);
diff --git a/common/t-gettime.c b/common/t-gettime.c
index 1cfde69..79c3d43 100644
--- a/common/t-gettime.c
+++ b/common/t-gettime.c
@@ -1,5 +1,5 @@
 /* t-gettime.c - Module test for gettime.c
- *	Copyright (C) 2007 Free Software Foundation, Inc.
+ *	Copyright (C) 2007, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -89,6 +89,90 @@ test_isotime2epoch (void)
 
 
 
+static void
+test_string2isotime (void)
+{
+  struct {
+    const char *string;
+    size_t result;
+    const char *expected;
+  } array [] = {
+    { "19700101T000001",      15, "19700101T000001" },
+    { "19700101T235959",      15, "19700101T235959" },
+    { "19980815T143712",      15, "19980815T143712" },
+    { "19700101T000000",      15, "19700101T000000" },
+    { "19691231T235959",      15, "19691231T235959" },
+    { "19000101T000000",      15, "19000101T000000" },
+    { "",                      0, ""                },
+    { "19000101T00000",        0, ""                },
+    { "20010101t123456",       0, ""                },
+    { "20010101T123456",      15, "20010101T123456" },
+    { "20070629T160000",      15, "20070629T160000" },
+    { "20070629T160000:",     15, "20070629T160000" },
+    { "20070629T160000,",     15, "20070629T160000" },
+    { "20070629T160000 ",     15, "20070629T160000" },
+    { "20070629T160000\n",    15,"20070629T160000"  },
+    { "20070629T160000.",      0, ""                },
+    { "1066-03-20",           10, "10660320T000000" },
+    { "1066-03-20,",          10, "10660320T000000" },
+    { "1066-03-20:",           0, ""                },
+    { "1066-03-20 00",        13, "10660320T000000" },
+    { "1066-03-20 01",        13, "10660320T010000" },
+    { "1066-03-20 23",        13, "10660320T230000" },
+    { "1066-03-20 24",         0, ""                },
+    { "1066-03-20 00:",        0, ""                },
+    { "1066-03-20 00:3",       0, ""                },
+    { "1066-03-20 00:31",     16, "10660320T003100" },
+    { "1066-03-20 00:31:47",  19, "10660320T003147" },
+    { "1066-03-20 00:31:47 ", 19, "10660320T003147" },
+    { "1066-03-20 00:31:47,", 19, "10660320T003147" },
+    { "1066-03-20 00:31:47:",  0, ""                },
+    { "1-03-20 00:31:47:",     0, ""                },
+    { "10-03-20 00:31:47:",    0, ""                },
+    { "106-03-20 00:31:47:",   0, ""                },
+    { "1066-23-20 00:31:47:",  0, ""                },
+    { "1066-00-20 00:31:47:",  0, ""                },
+    { "1066-0-20 00:31:47:",   0, ""                },
+    { "1066-01-2 00:31:47:",   0, ""                },
+    { "1066-01-2  00:31:47:",  0, ""                },
+    { "1066-01-32 00:31:47:",  0, ""                },
+    { "1066-01-00 00:31:47:",  0, ""                },
+    { "1066-03-20  00:31:47:",11, "10660320T000000" },
+    { "1066-03-2000:31:47:",   0, ""                },
+    { "10666-03-20 00:31:47:", 0, ""                },
+    { NULL, 0 }
+  };
+  int idx;
+  size_t result;
+  gnupg_isotime_t tbuf;
+
+  for (idx=0; array[idx].string; idx++)
+    {
+      result = string2isotime (tbuf, array[idx].string);
+      if (result != array[idx].result)
+        {
+          fail (idx);
+          if (verbose)
+            fprintf (stderr, "string `%s' expected: %d, got: %d\n",
+                     array[idx].string, (int)array[idx].result, (int)result);
+        }
+      else if (result && strlen (tbuf) != 15)
+        {
+          fail (idx);
+          if (verbose)
+            fprintf (stderr, "string `%s' invalid isotime returned\n",
+                     array[idx].string);
+        }
+      else if (result && strcmp (array[idx].expected, tbuf))
+        {
+          fail (idx);
+          if (verbose)
+            fprintf (stderr, "string `%s' bad isotime '%s' returned\n",
+                     array[idx].string, tbuf);
+        }
+    }
+}
+
 
 int
 main (int argc, char **argv)
@@ -97,6 +181,7 @@ main (int argc, char **argv)
     verbose = 1;
 
   test_isotime2epoch ();
+  test_string2isotime ();
 
   return !!errcount;
 }
diff --git a/common/tlv.c b/common/tlv.c
index 54ef6fc..61f770e 100644
--- a/common/tlv.c
+++ b/common/tlv.c
@@ -238,14 +238,14 @@ _parse_ber_header (unsigned char const **buffer, size_t *size,
    is the pointer to the S-expression and BUFLEN is a pointer to the
    length of this S-expression (used to validate the syntax).  Both
    are updated to reflect the new position.  The token itself is
-   returned as a pointer into the orginal buffer at TOK and TOKLEN.
+   returned as a pointer into the original buffer at TOK and TOKLEN.
    If a parentheses is the next token, TOK will be set to NULL.
-   TOKLEN is checked to be within the bounds.  On error a error code
-   is returned and all pointers should are not guaranteed to point to
-   a meanigful value. DEPTH should be initialized to 0 and will
+   TOKLEN is checked to be within the bounds.  On error an error code
+   is returned and no pointer is not guaranteed to point to
+   a meaningful value.  DEPTH should be initialized to 0 and will
    reflect on return the actual depth of the tree. To detect the end
    of the S-expression it is advisable to check DEPTH after a
-   successful return:
+   successful return.
 
    depth = 0;
    while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
diff --git a/common/tlv.h b/common/tlv.h
index c7fafd5..fd57e1e 100644
--- a/common/tlv.h
+++ b/common/tlv.h
@@ -90,15 +90,15 @@ gpg_error_t _parse_ber_header (unsigned char const **buffer, size_t *size,
                            GPG_ERR_SOURCE_DEFAULT)
 
 
-/* Return the next token of an canconical encoded S-expression.  BUF
+/* Return the next token of an canonical encoded S-expression.  BUF
    is the pointer to the S-expression and BUFLEN is a pointer to the
    length of this S-expression (used to validate the syntax).  Both
    are updated to reflect the new position.  The token itself is
-   returned as a pointer into the orginal buffer at TOK and TOKLEN.
+   returned as a pointer into the original buffer at TOK and TOKLEN.
    If a parentheses is the next token, TOK will be set to NULL.
-   TOKLEN is checked to be within the bounds.  On error a error code
-   is returned and all pointers should are not guaranteed to point to
-   a meanigful value. DEPTH should be initialized to 0 and will
+   TOKLEN is checked to be within the bounds.  On error an error code
+   is returned and no pointer is not guaranteed to point to
+   a meaningful value.  DEPTH should be initialized to 0 and will
    reflect on return the actual depth of the tree. To detect the end
    of the S-expression it is advisable to check DEPTH after a
    successful return. */

-----------------------------------------------------------------------

Summary of changes:
 AUTHORS            |    8 +-
 ChangeLog          |    4 +
 NEWS               |    4 +
 common/ChangeLog   |    8 +
 common/gettime.c   |  159 ++++++++++++++++--
 common/gettime.h   |    3 +
 common/t-gettime.c |   87 +++++++++-
 common/tlv.c       |   10 +-
 common/tlv.h       |   10 +-
 configure.ac       |    2 +-
 doc/DETAILS        |    5 +-
 m4/ChangeLog       |    4 +
 m4/gpg-error.m4    |   13 +-
 m4/ksba.m4         |   20 ++-
 m4/libgcrypt.m4    |   13 +-
 sm/ChangeLog       |   23 +++-
 sm/certreqgen-ui.c |   34 +++-
 sm/certreqgen.c    |  493 ++++++++++++++++++++++++++++++++++++++++++++-------
 sm/gpgsm.h         |    4 +
 sm/keylist.c       |    1 +
 sm/misc.c          |  132 ++++++++++++++-
 21 files changed, 912 insertions(+), 125 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list