doc/
authorMarcus Brinkmann <mb@g10code.com>
Sat, 1 Oct 2005 02:33:35 +0000 (02:33 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Sat, 1 Oct 2005 02:33:35 +0000 (02:33 +0000)
2005-10-01  Marcus Brinkmann  <marcus@g10code.de>

* gpgme.texi (Signature Notation Data): New section.
(Verify): Added more about the notation data structure.

gpgme/
2005-10-01  Marcus Brinkmann  <marcus@g10code.de>

* gpgme.def: Add gpgme_data_set_file_name,
gpgme_data_get_file_name, gpgme_sig_notation_clear,
gpgme_sig_notation_add and gpgme_sig_notation_get.
* libgpgme.vers: Add gpgme_sig_notation_clear,
gpgme_sig_notation_add and gpgme_sig_notation_get.
* Makefile.am (libgpgme_real_la_SOURCES): Add sig-notation.c.
* context.h (struct gpgme_context): New field sig_notations.
* gpgme.h (struct _gpgme_sig_notation): New member value_len and
critical.
(GPGME_SIG_NOTATION_CRITICAL): New symbol.
(gpgme_sig_notation_flags_t): New type.
(gpgme_sig_notation_add, gpgme_sig_notation_clear,
gpgme_sig_notation_get): New prototypes.
* ops.h (_gpgme_sig_notation_create, _gpgme_sig_notation_free):
New prototypes.
* sig-notation.c (_gpgme_sig_notation_free): New file.
* verify.c (parse_notation): Use support functions.
(release_op_data): Likewise.
* rungpg.c (append_args_from_sig_notations): New function.
(gpg_encrypt_sign, gpg_sign): Call it.

tests/
2005-10-01  Marcus Brinkmann  <marcus@g10code.de>

* gpg/Makefile.am (TESTS): Add t-sig-notation.
* gpg/t-sig-notation.c (check_result): New file.
* gpg/t-verify.c (check_result): Also check the length of the
notation data.
* gpg/gpg.conf: New file.

21 files changed:
NEWS
TODO
doc/ChangeLog
doc/gpgme.texi
gpgme/ChangeLog
gpgme/Makefile.am
gpgme/context.h
gpgme/data.h
gpgme/gpgme.c
gpgme/gpgme.def
gpgme/gpgme.h
gpgme/libgpgme.vers
gpgme/ops.h
gpgme/rungpg.c
gpgme/sig-notation.c [new file with mode: 0644]
gpgme/verify.c
tests/ChangeLog
tests/gpg/Makefile.am
tests/gpg/gpg.conf [new file with mode: 0644]
tests/gpg/t-sig-notation.c [new file with mode: 0644]
tests/gpg/t-verify.c

diff --git a/NEWS b/NEWS
index 44eeca7..fd093ee 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,10 +33,13 @@ Noteworthy changes in version 1.1.0 (unreleased)
    to local government regulations.
 
  * You can associate a filename with a data object using the new
-   gpgme_data_set_filename() function.  This filename will be stored
+   function gpgme_data_set_filename().  This filename will be stored
    in the output when encrypting or signing the data and will be
    returned when decrypting or verifying the output data.
 
+ * You can now set notation data at signature creation with the new
+   function gpgme_sig_notation_add().
+
  * Interface changes relative to the 1.0.3 release:
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 gpgme_set_engine_info          NEW
@@ -51,6 +54,12 @@ GPGME_STATUS_PLAINTEXT               NEW
 gpgme_key_t                    EXTENDED: New field is_qualified.
 gpgme_subkey_t                 EXTENDED: New field is_qualified.
 gpgme_data_set_filename                NEW
+gpgme_sig_notation_flags_t     NEW
+GPGME_SIG_NOTATION_HUMAN_READABLE NEW
+GPGME_SIG_NOTATAION_CRITICAL   NEW
+gpgme_sig_notation_clear       NEW
+gpgme_sig_notation_add         NEW
+gpgme_sig_notation_get         NEW
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
diff --git a/TODO b/TODO
index af2a384..1ab91fb 100644 (file)
--- a/TODO
+++ b/TODO
@@ -37,6 +37,8 @@ Hey Emacs, this is -*- outline -*- mode!
    There is a configure time warning, though.
 
 * New features:
+** Extended notation support.  When gpg supports arbitrary binary
+   notation data, provide a user interface for that.
 ** notification system
    We need a simple notification system, probably a simple callback
    with a string and some optional arguments.  This is for example
index 681ed9b..4d227f8 100644 (file)
@@ -1,3 +1,8 @@
+2005-10-01  Marcus Brinkmann  <marcus@g10code.de>
+
+       * gpgme.texi (Signature Notation Data): New section.
+       (Verify): Added more about the notation data structure.
+
 2005-09-30  Marcus Brinkmann  <marcus@g10code.de>
 
        * gpgme.texi (Data Buffer I/O Operations, Data Buffer Meta-Data):
index 44cdcbb..1ddf9a0 100644 (file)
@@ -209,6 +209,7 @@ Sign
 
 * Selecting Signers::             How to choose the keys to sign with.
 * Creating a Signature::          How to create a signature.
+* Signature Notation Data::       How to add notation data to a signature.
 
 Encrypt
 
@@ -3753,6 +3754,8 @@ the context.
 @cindex signature, verification
 @cindex cryptographic operation, verification
 @cindex cryptographic operation, signature check
+@cindex signature notation data
+@cindex notation data
 
 @deftypefun gpgme_error_t gpgme_op_verify (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{sig}}, @w{gpgme_data_t @var{signed_text}}, @w{gpgme_data_t @var{plain}})
 The function @code{gpgme_op_verify} verifies that the signature in the
@@ -3801,9 +3804,45 @@ linked list, or @code{NULL} if this is the last element.
 The name of the notation field.  If this is @code{NULL}, then the
 member @code{value} will contain a policy URL.
 
+@item int name_len
+The length of the @code{name} field.  For strings the length is
+counted without the trailing binary zero.
+
 @item char *value
 The value of the notation field.  If @code{name} is @code{NULL}, then
 this is a policy URL.
+
+@item int value_len
+The length of the @code{value} field.  For strings the length is
+counted without the trailing binary zero.
+
+@item gpgme_sig_notation_flags_t flags
+The accumulated flags field.  This field contains the flags associated
+with the notation data in an accumulated form which can be used as an
+argument to the function @code{gpgme_sig_notation_add}.  The value
+@code{flags} is a bitwise-or combination of one or multiple of the
+following bit values:
+
+@table @code
+@item GPGME_SIG_NOTATION_HUMAN_READABLE
+The @code{GPGME_SIG_NOTATION_HUMAN_READABLE} symbol specifies that the
+notation data is in human readable form
+
+@item GPGME_SIG_NOTATION_CRITICAL
+The @code{GPGME_SIG_NOTATION_CRITICAL} symbol specifies that the
+notation data is critical.
+
+@end table
+
+@item unsigned int human_readable : 1
+This is true if the @code{GPGME_SIG_NOTATION_HUMAN_READABLE} flag is
+set and false otherwise.  This flag is only valid for notation data,
+not for policy URLs.
+
+@item unsigned int critical : 1
+This is true if the @code{GPGME_SIG_NOTATION_CRITICAL} flag is set and
+false otherwise.  This flag is valid for notation data and policy URLs.
+
 @end table
 @end deftp
 
@@ -4258,6 +4297,7 @@ set is changed).
 @menu
 * Selecting Signers::             How to choose the keys to sign with.
 * Creating a Signature::          How to create a signature.
+* Signature Notation Data::       How to add notation data to a signature.
 @end menu
 
 
@@ -4406,6 +4446,58 @@ context.
 @end deftypefun
 
 
+@node Signature Notation Data
+@subsubsection Signature Notation Data
+@cindex notation data
+@cindex signature notation data
+@cindex policy URL
+
+Using the following functions, you can attach arbitrary notation data
+to a signature.  This information is then available to the user when
+the signature is verified.
+
+@deftypefun void gpgme_sig_notation_clear (@w{gpgme_ctx_t @var{ctx}})
+The function @code{gpgme_sig_notation_clear} removes the notation data
+from the context @var{ctx}.  Subsequent signing operations from this
+context will not include any notation data.
+
+Every context starts with an empty notation data list.
+@end deftypefun
+
+@deftypefun gpgme_error_t gpgme_sig_notation_add (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{name}}, @w{const char *@var{value}}, @w{gpgme_sig_notation_flags_t @var{flags}})
+The function @code{gpgme_sig_notation_add} adds the notation data with
+the name @var{name} and the value @var{value} to the context
+@var{ctx}.
+
+Subsequent signing operations will include this notation data, as well
+as any other notation data that was added since the creation of the
+context or the last @code{gpgme_sig_notation_clear} operation.
+
+The arguments @var{name} and @var{value} must be @code{NUL}-terminated
+strings in human-readable form.  The flag
+@code{GPGME_SIG_NOTATION_HUMAN_READABLE} is implied
+(non-human-readable notation data is currently not supported).  The
+strings must be in UTF-8 encoding.
+
+If @var{name} is @code{NULL}, then @var{value} should be a policy URL.
+
+The function @code{gpgme_sig_notation_add} returns the error code
+@code{GPG_ERR_NO_ERROR} if the notation data could be added
+successfully, @code{GPG_ERR_INV_VALUE} if @var{ctx} is not a valid
+pointer, or if @var{name}, @var{value} and @var{flags} are an invalid
+combination.  The function also passes through any errors that are
+reported by the crypto engine support routines.
+@end deftypefun
+
+@deftypefun gpgme_sig_notation_t gpgme_sig_notation_get (@w{const gpgme_ctx_t @var{ctx}})
+The function @code{gpgme_sig_notation_get} returns the linked list of
+notation data structures that are contained in the context @var{ctx}.
+
+If @var{ctx} is not a valid pointer, or there is no notation data
+added for this context, @code{NULL} is returned.
+@end deftypefun
+
+
 @node Encrypt
 @subsection Encrypt
 @cindex encryption
index 6ec0bfd..4150db0 100644 (file)
@@ -1,3 +1,26 @@
+2005-10-01  Marcus Brinkmann  <marcus@g10code.de>
+
+       * gpgme.def: Add gpgme_data_set_file_name,
+       gpgme_data_get_file_name, gpgme_sig_notation_clear,
+       gpgme_sig_notation_add and gpgme_sig_notation_get.
+       * libgpgme.vers: Add gpgme_sig_notation_clear,
+       gpgme_sig_notation_add and gpgme_sig_notation_get.
+       * Makefile.am (libgpgme_real_la_SOURCES): Add sig-notation.c.
+       * context.h (struct gpgme_context): New field sig_notations.
+       * gpgme.h (struct _gpgme_sig_notation): New member value_len and
+       critical.
+       (GPGME_SIG_NOTATION_CRITICAL): New symbol.
+       (gpgme_sig_notation_flags_t): New type.
+       (gpgme_sig_notation_add, gpgme_sig_notation_clear,
+       gpgme_sig_notation_get): New prototypes.
+       * ops.h (_gpgme_sig_notation_create, _gpgme_sig_notation_free):
+       New prototypes.
+       * sig-notation.c (_gpgme_sig_notation_free): New file.
+       * verify.c (parse_notation): Use support functions.
+       (release_op_data): Likewise.
+       * rungpg.c (append_args_from_sig_notations): New function.
+       (gpg_encrypt_sign, gpg_sign): Call it.
+
 2005-09-30  Marcus Brinkmann  <marcus@g10code.de>
 
        * data.h (struct gpgme_data): New member file_name.
index b8f27f9..994d576 100644 (file)
@@ -72,7 +72,7 @@ libgpgme_real_la_SOURCES =                                            \
        gpgme.h util.h conversion.c get-env.c context.h ops.h           \
        data.h data.c data-fd.c data-stream.c data-mem.c data-user.c    \
        data-compat.c                                                   \
-       signers.c                                                       \
+       signers.c sig-notation.c                                        \
        wait.c wait-global.c wait-private.c wait-user.c wait.h          \
        op-support.c                                                    \
        encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c    \
index 3afd61b..e7e2afa 100644 (file)
@@ -1,6 +1,6 @@
 /* context.h - Definitions for a GPGME context.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
 
    This file is part of GPGME.
  
@@ -91,6 +91,9 @@ struct gpgme_context
   unsigned int signers_size;
   gpgme_key_t *signers;
 
+  /* The signature notations for this context.  */
+  gpgme_sig_notation_t sig_notations;
+
   /* The locale for the pinentry.  */
   char *lc_ctype;
   char *lc_messages;
index 80eeae8..80a86e6 100644 (file)
@@ -1,5 +1,5 @@
 /* data.h - Internal data object abstraction interface.
-   Copyright (C) 2002, 2004 g10 Code GmbH
+   Copyright (C) 2002, 2004, 2005 g10 Code GmbH
  
    This file is part of GPGME.
  
index 85eaf3a..da59833 100644 (file)
@@ -430,6 +430,71 @@ gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto,
 }
 
 \f
+/* Clear all notation data from the context.  */
+void
+gpgme_sig_notation_clear (gpgme_ctx_t ctx)
+{
+  gpgme_sig_notation_t notation;
+
+  if (!ctx)
+    return;
+
+  notation = ctx->sig_notations;
+  while (notation)
+    {
+      gpgme_sig_notation_t next_notation = notation->next;
+      _gpgme_sig_notation_free (notation);
+      notation = next_notation;
+    }
+}
+
+
+/* Add the human-readable notation data with name NAME and value VALUE
+   to the context CTX, using the flags FLAGS.  If NAME is NULL, then
+   VALUE should be a policy URL.  The flag
+   GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
+   data, and false for policy URLs.  */
+gpgme_error_t
+gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name,
+                       const char *value, gpgme_sig_notation_flags_t flags)
+{
+  gpgme_error_t err;
+  gpgme_sig_notation_t notation;
+  gpgme_sig_notation_t *lastp;
+
+  if (!ctx)
+     gpg_error (GPG_ERR_INV_VALUE);
+
+  if (name)
+    flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
+  else
+    flags &= ~GPGME_SIG_NOTATION_HUMAN_READABLE;
+
+  err = _gpgme_sig_notation_create (&notation, name, name ? strlen (name) : 0,
+                                   value, value ? strlen (value) : 0, flags);
+  if (err)
+    return err;
+
+  lastp = &ctx->sig_notations;
+  while (*lastp)
+    lastp = &(*lastp)->next;
+
+  *lastp = notation;
+  return 0;
+}
+
+
+/* Get the sig notations for this context.  */
+gpgme_sig_notation_t
+gpgme_sig_notation_get (gpgme_ctx_t ctx)
+{
+  if (!ctx)
+    return NULL;
+
+  return ctx->sig_notations;
+}
+  
+\f
 const char *
 gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
 {
index f7117e0..07a72eb 100644 (file)
@@ -144,5 +144,12 @@ EXPORTS
     gpgme_ctx_get_engine_info             @113 
     gpgme_ctx_set_engine_info             @114
 
+    gpgme_data_set_file_name             @115
+    gpgme_data_get_file_name             @116
+
+    gpgme_sig_notation_clear             @117
+    gpgme_sig_notation_add               @118
+    gpgme_sig_notation_get               @119
+
 ; END
 
index f0f27d9..28d8957 100644 (file)
@@ -1,6 +1,6 @@
 /* gpgme.h - Public interface to GnuPG Made Easy.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
 
    This file is part of GPGME.
  
@@ -313,6 +313,46 @@ gpgme_protocol_t;
 typedef unsigned int gpgme_keylist_mode_t;
 
 \f
+/* Signature notations.  */
+
+/* The available signature notation flags.  */
+#define GPGME_SIG_NOTATION_HUMAN_READABLE      1
+#define GPGME_SIG_NOTATION_CRITICAL            2
+
+typedef unsigned int gpgme_sig_notation_flags_t;
+
+struct _gpgme_sig_notation
+{
+  struct _gpgme_sig_notation *next;
+
+  /* If NAME is a null pointer, then VALUE contains a policy URL
+     rather than a notation.  */
+  char *name;
+
+  /* The value of the notation data.  */
+  char *value;
+
+  /* The length of the name of the notation data.  */
+  int name_len;
+
+  /* The length of the value of the notation data.  */
+  int value_len;
+
+  /* The accumulated flags.  */
+  gpgme_sig_notation_flags_t flags;
+
+  /* Notation data is human-readable.  */
+  unsigned int human_readable : 1;
+
+  /* Notation data is critical.  */
+  unsigned int critical : 1;
+
+  /* Internal to GPGME, do not use.  */
+  int _unused : 30;
+};
+typedef struct _gpgme_sig_notation *gpgme_sig_notation_t;
+
+\f
 /* The possible stati for the edit operation.  */
 typedef enum
   {
@@ -819,6 +859,22 @@ gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
      _GPGME_DEPRECATED;
 
 \f
+/* Clear all notation data from the context.  */
+void gpgme_sig_notation_clear (gpgme_ctx_t ctx);
+
+/* Add the human-readable notation data with name NAME and value VALUE
+   to the context CTX, using the flags FLAGS.  If NAME is NULL, then
+   VALUE should be a policy URL.  The flag
+   GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
+   data, and false for policy URLs.  */
+gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name,
+                                     const char *value,
+                                     gpgme_sig_notation_flags_t flags);
+
+/* Get the sig notations for this context.  */
+gpgme_sig_notation_t gpgme_sig_notation_get (gpgme_ctx_t ctx);
+
+\f
 /* Run control.  */
 
 /* The type of an I/O callback function.  */
@@ -1209,16 +1265,6 @@ gpgme_error_t gpgme_op_sign (gpgme_ctx_t ctx,
 
 \f
 /* Verify.  */
-struct _gpgme_sig_notation
-{
-  struct _gpgme_sig_notation *next;
-
-  /* If NAME is a null pointer, then VALUE contains a policy URL
-     rather than a notation.  */
-  char *name;
-  char *value;
-};
-typedef struct _gpgme_sig_notation *gpgme_sig_notation_t;
 
 /* Flags used for the SUMMARY field in a gpgme_signature_t.  */
 typedef enum
index 4735f49..2007303 100644 (file)
@@ -1,5 +1,5 @@
 # libgpgme.vers - List of symbols to export.
-# Copyright (C) 2002, 2004 g10 Code GmbH
+# Copyright (C) 2002, 2004, 2005 g10 Code GmbH
 #
 # This file is part of GPGME.
 #
@@ -30,6 +30,10 @@ GPGME_1.1 {
 
     gpgme_data_set_file_name;
     gpgme_data_get_file_name;
+
+    gpgme_sig_notation_clear;
+    gpgme_sig_notation_add;
+    gpgme_sig_notation_get;
 };
 
 
index 79fb3b4..9525e7c 100644 (file)
@@ -1,6 +1,6 @@
 /* ops.h - Internal operation support.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
  
    This file is part of GPGME.
  
@@ -138,11 +138,26 @@ void _gpgme_op_trustlist_event_cb (void *data, gpgme_event_io_t type,
                                   void *type_data);
 
 \f
-/*-- version.c --*/
+/* From version.c.  */
+
 /* Return true if MY_VERSION is at least REQ_VERSION, and false
    otherwise.  */
 int _gpgme_compare_versions (const char *my_version,
                             const char *req_version);
 char *_gpgme_get_program_version (const char *const path);
 
+\f
+/* From sig-notation.c.  */
+
+/* Create a new, empty signature notation data object.  */
+gpgme_error_t _gpgme_sig_notation_create (gpgme_sig_notation_t *notationp,
+                                         const char *name, int name_len,
+                                         const char *value, int value_len,
+                                         gpgme_sig_notation_flags_t flags);
+
+/* Free the signature notation object and all associated resources.
+   The object must already be removed from any linked list as the next
+   pointer is ignored.  */
+void _gpgme_sig_notation_free (gpgme_sig_notation_t notation);
+
 #endif /* OPS_H */
index 86710a0..e5ef030 100644 (file)
@@ -1256,6 +1256,91 @@ append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
 
 
 static gpgme_error_t
+append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
+{
+  gpgme_error_t err = 0;
+  gpgme_sig_notation_t notation;
+
+  notation = gpgme_sig_notation_get (ctx);
+
+  while (!err && notation)
+    {
+      if (notation->name
+         && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
+       err = gpg_error (GPG_ERR_INV_VALUE);
+      else if (notation->name)
+       {
+         char *arg;
+
+         /* Maximum space needed is one byte for the "critical" flag,
+            the name, one byte for '=', the value, and a terminating
+            '\0'.  */
+
+         arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
+         if (!arg)
+           err = gpg_error_from_errno (errno);
+
+         if (!err)
+           {
+             char *argp = arg;
+
+             if (notation->critical)
+               *(argp++) = '!';
+
+             memcpy (argp, notation->name, notation->name_len);
+             argp += notation->name_len;
+
+             *(argp++) = '=';
+
+             /* We know that notation->name is '\0' terminated.  */
+             strcpy (argp, notation->value);
+           }
+
+         if (!err)
+           err = add_arg (gpg, "--sig-notation");
+         if (!err)
+           err = add_arg (gpg, arg);
+
+         if (arg)
+           free (arg);
+       }
+      else
+       {
+         /* This is a policy URL.  */
+
+         char *value;
+
+         if (notation->critical)
+           {
+             value = malloc (1 + notation->value_len + 1);
+             if (!value)
+               err = gpg_error_from_errno (errno);
+             else
+               {
+                 value[0] = '!';
+                 /* We know that notation->value is '\0' terminated.  */
+                 strcpy (&value[1], notation->value);
+               }
+           }
+         else
+           value = notation->value;
+
+         if (!err)
+           err = add_arg (gpg, "--sig-policy-url");
+         if (!err)
+           err = add_arg (gpg, value);
+
+         if (value != notation->value)
+           free (value);
+       }
+
+      notation = notation->next;
+    }
+  return err;
+}
+
+
+static gpgme_error_t
 gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
          gpgme_ctx_t ctx /* FIXME */)
 {
@@ -1383,6 +1468,8 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
 
   if (!err)
     err = append_args_from_signers (gpg, ctx);
+  if (!err)
+    err = append_args_from_sig_notations (gpg, ctx);
 
   /* Tell the gpg object about the data.  */
   if (!err)
@@ -1608,6 +1695,8 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
 
   if (!err)
     err = append_args_from_signers (gpg, ctx);
+  if (!err)
+    err = append_args_from_sig_notations (gpg, ctx);
 
   if (gpgme_data_get_file_name (in))
     {
diff --git a/gpgme/sig-notation.c b/gpgme/sig-notation.c
new file mode 100644 (file)
index 0000000..6a04fd0
--- /dev/null
@@ -0,0 +1,123 @@
+/* sig-notation.c - Signature notation data support.
+   Copyright (C) 2005 g10 Code GmbH
+
+   This file is part of GPGME.
+   GPGME 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.
+   
+   GPGME 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+
+\f
+/* Free the signature notation object and all associated resources.
+   The object must already be removed from any linked list as the next
+   pointer is ignored.  */
+void
+_gpgme_sig_notation_free (gpgme_sig_notation_t notation)
+{
+  if (notation->name)
+    free (notation->name);
+
+  if (notation->value)
+    free (notation->value);
+
+  free (notation);
+}
+
+\f
+/* Set the flags of NOTATION to FLAGS.  */
+static void
+sig_notation_set_flags (gpgme_sig_notation_t notation,
+                       gpgme_sig_notation_flags_t flags)
+{
+  /* We copy the flags into individual bits to make them easier
+     accessible individually for the user.  */
+  notation->human_readable = flags & GPGME_SIG_NOTATION_HUMAN_READABLE ? 1 : 0;
+  notation->critical = flags & GPGME_SIG_NOTATION_CRITICAL ? 1 : 0; 
+
+  notation->flags = flags;
+}
+
+
+/* Create a new, empty signature notation data object.  */
+gpgme_error_t
+_gpgme_sig_notation_create (gpgme_sig_notation_t *notationp,
+                           const char *name, int name_len,
+                           const char *value, int value_len,
+                           gpgme_sig_notation_flags_t flags)
+{
+  gpgme_error_t err = 0;
+  gpgme_sig_notation_t notation;
+
+  /* Currently, we require all notations to be human-readable.  */
+  if (name && !(flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  notation = calloc (1, sizeof (*notation));
+  if (!notation)
+    return gpg_error_from_errno (errno);
+
+  if (name_len)
+    {
+      /* We add a trailing '\0' for stringification in the good
+        case.  */
+      notation->name = malloc (name_len + 1);
+      if (!notation->name)
+       {
+         err = gpg_error_from_errno (errno);
+         goto err;
+       }
+
+      memcpy (notation->name, name, name_len);
+      notation->name[name_len] = '\0';
+      notation->name_len = name_len;
+    }
+
+  if (value_len)
+    {
+      /* We add a trailing '\0' for stringification in the good
+        case.  */
+      notation->value = malloc (value_len + 1);
+      if (!notation->value)
+       {
+         err = gpg_error_from_errno (errno);
+         goto err;
+       }
+
+      memcpy (notation->value, value, value_len);
+      notation->value[value_len] = '\0';
+      notation->value_len = value_len;
+    }
+
+  sig_notation_set_flags (notation, flags);
+
+  *notationp = notation;
+  return 0;
+
+ err:
+  _gpgme_sig_notation_free (notation);
+  return err;
+}
index 90b4cf8..d7c3216 100644 (file)
@@ -1,6 +1,6 @@
 /* verify.c - Signature verification.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
 
    This file is part of GPGME.
  
@@ -58,10 +58,7 @@ release_op_data (void *hook)
        {
          gpgme_sig_notation_t next_nota = notation->next;
 
-         if (notation->name)
-           free (notation->name);
-         if (notation->value)
-           free (notation->value);
+         _gpgme_sig_notation_free (notation);
          notation = next_nota;
        }
 
@@ -431,51 +428,39 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
           previous one.  The crypto backend misbehaves.  */
        return gpg_error (GPG_ERR_INV_ENGINE);
 
-      notation = malloc (sizeof (*sig));
-      if (!notation)
-       return gpg_error_from_errno (errno);
-      notation->next = NULL;
+      err = _gpgme_sig_notation_create (&notation, NULL, 0, NULL, 0, 0);
+      if (err)
+       return err;
 
       if (code == GPGME_STATUS_NOTATION_NAME)
        {
-         int len = strlen (args) + 1;
-
-         notation->name = malloc (len);
-         if (!notation->name)
-           {
-             int saved_errno = errno;
-             free (notation);
-             return gpg_error_from_errno (saved_errno);
-           }
-         err = _gpgme_decode_percent_string (args, &notation->name, len);
+         err = _gpgme_decode_percent_string (args, &notation->name, 0);
          if (err)
            {
-             free (notation->name);
-             free (notation);
+             _gpgme_sig_notation_free (notation);
              return err;
            }
 
-         notation->value = NULL;
+         notation->name_len = strlen (notation->name);
+
+         /* FIXME: For now we fake the human-readable flag.  The
+            critical flag can not be reported as it is not
+            provided.  */
+         notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
+         notation->human_readable = 1;
        }
       else
        {
-         int len = strlen (args) + 1;
+         /* This is a policy URL.  */
 
-         notation->name = NULL;
-         notation->value = malloc (len);
-         if (!notation->value)
-           {
-             int saved_errno = errno;
-             free (notation);
-             return gpg_error_from_errno (saved_errno);
-           }
-         err = _gpgme_decode_percent_string (args, &notation->value, len);
+         err = _gpgme_decode_percent_string (args, &notation->value, 0);
          if (err)
            {
-             free (notation->value);
-             free (notation);
+             _gpgme_sig_notation_free (notation);
              return err;
            }
+
+         notation->value_len = strlen (notation->value);
        }
       *lastp = notation;
     }
@@ -515,6 +500,8 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
       err = _gpgme_decode_percent_string (args, &dest, len);
       if (err)
        return err;
+
+      notation->value_len += strlen (dest);
     }
   else
     return gpg_error (GPG_ERR_INV_ENGINE);
index 9464592..42d9e14 100644 (file)
@@ -1,3 +1,11 @@
+2005-10-01  Marcus Brinkmann  <marcus@g10code.de>
+
+       * gpg/Makefile.am (TESTS): Add t-sig-notation.
+       * gpg/t-sig-notation.c (check_result): New file.
+       * gpg/t-verify.c (check_result): Also check the length of the
+       notation data.
+       * gpg/gpg.conf: New file.
+
 2005-09-30  Marcus Brinkmann  <marcus@g10code.de>
 
        * gpg/Makefile.am (TESTS): Add t-filename.
index 0fa0349..e946eaf 100644 (file)
@@ -26,7 +26,7 @@ TESTS_ENVIRONMENT = GNUPGHOME=. GPG_AGENT_INFO=
 # The keylist tests must come after the import and the edit test.
 noinst_HEADERS = t-support.h
 TESTS = t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers        \
-       t-decrypt t-verify t-decrypt-verify \
+       t-decrypt t-verify t-decrypt-verify t-sig-notation \
        t-export t-import t-trustlist t-eventloop t-edit \
        t-keylist t-keylist-sig t-thread1 t-wait t-encrypt-large \
        t-file-name
diff --git a/tests/gpg/gpg.conf b/tests/gpg/gpg.conf
new file mode 100644 (file)
index 0000000..f1196a1
--- /dev/null
@@ -0,0 +1,27 @@
+# Options for GnuPG
+# Copyright 1998, 1999, 2000, 2001, 2002, 2003 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
+# modifications, as long as this notice is preserved.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Unless you specify which option file to use (with the command line
+# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf
+# by default.
+#
+# An options file can contain any long options which are available in
+# GnuPG. If the first non white space character of a line is a '#',
+# this line is ignored.  Empty lines are also ignored.
+#
+# See the man page for a list of options.
+
+# By default GnuPG creates version 3 signatures for data files.  This
+# is not strictly OpenPGP compliant but PGP 6 and most versions of PGP
+# 7 require them.  To disable this behavior, you may use this option
+# or --openpgp.
+
+no-force-v3-sigs
diff --git a/tests/gpg/t-sig-notation.c b/tests/gpg/t-sig-notation.c
new file mode 100644 (file)
index 0000000..a901473
--- /dev/null
@@ -0,0 +1,166 @@
+/* t-sig-notation.c - Regression test.
+   Copyright (C) 2005 g10 Code GmbH
+
+   This file is part of GPGME.
+   GPGME 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.
+   
+   GPGME 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* We need to include config.h so that we know whether we are building
+   with large file system (LFS) support. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#include "t-support.h"
+
+\f
+static struct {
+  const char *name;
+  const char *value;
+  gpgme_sig_notation_flags_t flags;
+  int seen;
+} expected_notations[] = { 
+  { "laughing@me",
+    "Just Squeeze Me",
+    GPGME_SIG_NOTATION_HUMAN_READABLE },
+  { "leave@home",
+    "Right Now",
+    GPGME_SIG_NOTATION_HUMAN_READABLE | GPGME_SIG_NOTATION_CRITICAL },
+  { NULL, 
+    "http://www.gnu.org/policy/",
+    0 }
+};
+
+static void
+check_result (gpgme_verify_result_t result)
+{
+  int i;
+  gpgme_sig_notation_t r;
+  
+  gpgme_signature_t sig;
+
+  sig = result->signatures;
+  if (!sig || sig->next)
+    {
+      fprintf (stderr, "%s:%i: Unexpected number of signatures\n",
+              __FILE__, __LINE__);
+      exit (1);
+    }
+
+  for (i=0; i < DIM(expected_notations); i++ )
+    expected_notations[i].seen = 0;
+  
+  for (r = result->signatures->notations; r; r = r->next)
+    {
+      int any = 0;
+      for (i=0; i < DIM(expected_notations); i++)
+       {
+         if ( ((r->name && expected_notations[i].name
+                && !strcmp (r->name, expected_notations[i].name)
+                && r->name_len
+                == strlen (expected_notations[i].name))
+               || (!r->name && !expected_notations[i].name
+                   && r->name_len == 0))
+              && r->value
+              && !strcmp (r->value, expected_notations[i].value)
+              && r->value_len == strlen (expected_notations[i].value)
+              && r->flags
+              == (expected_notations[i].flags & ~GPGME_SIG_NOTATION_CRITICAL)
+              && r->human_readable
+              == !!(r->flags & GPGME_SIG_NOTATION_HUMAN_READABLE)
+              && r->critical == 0)
+           {
+             expected_notations[i].seen++;
+             any++;
+           }
+       }
+      if (!any)
+       {
+         fprintf (stderr, "%s:%i: Unexpected notation data\n",
+                  __FILE__, __LINE__);
+         exit (1);
+       }
+    }
+  for (i=0; i < DIM(expected_notations); i++ )
+    {
+      if (expected_notations[i].seen != 1)
+       {
+         fprintf (stderr, "%s:%i: Missing or duplicate notation data\n",
+                  __FILE__, __LINE__);
+         exit (1);
+       }
+    }
+}
+
+
+int 
+main (int argc, char *argv[])
+{
+  gpgme_ctx_t ctx;
+  gpgme_error_t err;
+  gpgme_data_t in, out;
+  gpgme_verify_result_t result;
+  char *agent_info;
+  int i;
+
+  init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+  err = gpgme_new (&ctx);
+  fail_if_err (err);
+
+  agent_info = getenv ("GPG_AGENT_INFO");
+  if (!(agent_info && strchr (agent_info, ':')))
+    gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
+
+  err = gpgme_data_new_from_mem (&in, "Hallo Leute\n", 12, 0);
+  fail_if_err (err);
+  err = gpgme_data_new (&out);
+  fail_if_err (err);
+
+  for (i = 0; i < sizeof (expected_notations) / sizeof (expected_notations[0]);
+       i++)
+    {
+      err = gpgme_sig_notation_add (ctx, expected_notations[i].name,
+                                   expected_notations[i].value,
+                                   expected_notations[i].flags);
+      fail_if_err (err);
+    }
+  
+  err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_NORMAL);
+  fail_if_err (err);
+
+  gpgme_data_release (in);
+  err = gpgme_data_new (&in);
+  fail_if_err (err);
+
+  gpgme_data_seek (out, 0, SEEK_SET);
+
+  err = gpgme_op_verify (ctx, out, NULL, in);
+  fail_if_err (err);
+  result = gpgme_op_verify_result (ctx);
+  check_result (result);
+
+  gpgme_data_release (in);
+  gpgme_data_release (out);
+  gpgme_release (ctx);
+  return 0;
+}
index 1b63829..22f0477 100644 (file)
@@ -136,10 +136,14 @@ check_result (gpgme_verify_result_t result, unsigned int summary, char *fpr,
           for (i=0; i < DIM(expected_notations); i++)
             {
               if ( ((r->name && expected_notations[i].name
-                     && !strcmp (r->name, expected_notations[i].name))
-                    || (!r->name && !expected_notations[i].name))
+                     && !strcmp (r->name, expected_notations[i].name)
+                    && r->name_len
+                    == strlen (expected_notations[i].name))
+                    || (!r->name && !expected_notations[i].name
+                       && r->name_len == 0))
                    && r->value
-                   && !strcmp (r->value, expected_notations[i].value))
+                   && !strcmp (r->value, expected_notations[i].value)
+                  && r->value_len == strlen (expected_notations[i].value))
                 {
                   expected_notations[i].seen++;
                   any++;