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.
This commit is contained in:
Marcus Brinkmann 2005-10-01 02:33:35 +00:00
parent c6ee58ef55
commit b3304042aa
21 changed files with 731 additions and 56 deletions

11
NEWS
View File

@ -33,10 +33,13 @@ Noteworthy changes in version 1.1.0 (unreleased)
to local government regulations. to local government regulations.
* You can associate a filename with a data object using the new * 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 in the output when encrypting or signing the data and will be
returned when decrypting or verifying the output data. 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: * Interface changes relative to the 1.0.3 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_set_engine_info NEW gpgme_set_engine_info NEW
@ -51,6 +54,12 @@ GPGME_STATUS_PLAINTEXT NEW
gpgme_key_t EXTENDED: New field is_qualified. gpgme_key_t EXTENDED: New field is_qualified.
gpgme_subkey_t EXTENDED: New field is_qualified. gpgme_subkey_t EXTENDED: New field is_qualified.
gpgme_data_set_filename NEW 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2
TODO
View File

@ -37,6 +37,8 @@ Hey Emacs, this is -*- outline -*- mode!
There is a configure time warning, though. There is a configure time warning, though.
* New features: * New features:
** Extended notation support. When gpg supports arbitrary binary
notation data, provide a user interface for that.
** notification system ** notification system
We need a simple notification system, probably a simple callback We need a simple notification system, probably a simple callback
with a string and some optional arguments. This is for example with a string and some optional arguments. This is for example

View 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> 2005-09-30 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Data Buffer I/O Operations, Data Buffer Meta-Data): * gpgme.texi (Data Buffer I/O Operations, Data Buffer Meta-Data):

View File

@ -209,6 +209,7 @@ Sign
* Selecting Signers:: How to choose the keys to sign with. * Selecting Signers:: How to choose the keys to sign with.
* Creating a Signature:: How to create a signature. * Creating a Signature:: How to create a signature.
* Signature Notation Data:: How to add notation data to a signature.
Encrypt Encrypt
@ -3753,6 +3754,8 @@ the context.
@cindex signature, verification @cindex signature, verification
@cindex cryptographic operation, verification @cindex cryptographic operation, verification
@cindex cryptographic operation, signature check @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}}) @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 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 The name of the notation field. If this is @code{NULL}, then the
member @code{value} will contain a policy URL. 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 @item char *value
The value of the notation field. If @code{name} is @code{NULL}, then The value of the notation field. If @code{name} is @code{NULL}, then
this is a policy URL. 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 table
@end deftp @end deftp
@ -4258,6 +4297,7 @@ set is changed).
@menu @menu
* Selecting Signers:: How to choose the keys to sign with. * Selecting Signers:: How to choose the keys to sign with.
* Creating a Signature:: How to create a signature. * Creating a Signature:: How to create a signature.
* Signature Notation Data:: How to add notation data to a signature.
@end menu @end menu
@ -4406,6 +4446,58 @@ context.
@end deftypefun @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 @node Encrypt
@subsection Encrypt @subsection Encrypt
@cindex encryption @cindex encryption

View 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> 2005-09-30 Marcus Brinkmann <marcus@g10code.de>
* data.h (struct gpgme_data): New member file_name. * data.h (struct gpgme_data): New member file_name.

View File

@ -72,7 +72,7 @@ libgpgme_real_la_SOURCES = \
gpgme.h util.h conversion.c get-env.c context.h ops.h \ 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.h data.c data-fd.c data-stream.c data-mem.c data-user.c \
data-compat.c \ data-compat.c \
signers.c \ signers.c sig-notation.c \
wait.c wait-global.c wait-private.c wait-user.c wait.h \ wait.c wait-global.c wait-private.c wait-user.c wait.h \
op-support.c \ op-support.c \
encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \ encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \

View File

@ -1,6 +1,6 @@
/* context.h - Definitions for a GPGME context. /* context.h - Definitions for a GPGME context.
Copyright (C) 2000 Werner Koch (dd9jn) 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. This file is part of GPGME.
@ -91,6 +91,9 @@ struct gpgme_context
unsigned int signers_size; unsigned int signers_size;
gpgme_key_t *signers; gpgme_key_t *signers;
/* The signature notations for this context. */
gpgme_sig_notation_t sig_notations;
/* The locale for the pinentry. */ /* The locale for the pinentry. */
char *lc_ctype; char *lc_ctype;
char *lc_messages; char *lc_messages;

View File

@ -1,5 +1,5 @@
/* data.h - Internal data object abstraction interface. /* 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. This file is part of GPGME.

View File

@ -429,6 +429,71 @@ gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto,
file_name, home_dir); file_name, home_dir);
} }
/* 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;
}
const char * const char *
gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo) gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)

View File

@ -144,5 +144,12 @@ EXPORTS
gpgme_ctx_get_engine_info @113 gpgme_ctx_get_engine_info @113
gpgme_ctx_set_engine_info @114 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 ; END

View File

@ -1,6 +1,6 @@
/* gpgme.h - Public interface to GnuPG Made Easy. /* gpgme.h - Public interface to GnuPG Made Easy.
Copyright (C) 2000 Werner Koch (dd9jn) 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. This file is part of GPGME.
@ -312,6 +312,46 @@ gpgme_protocol_t;
typedef unsigned int gpgme_keylist_mode_t; typedef unsigned int gpgme_keylist_mode_t;
/* 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;
/* The possible stati for the edit operation. */ /* The possible stati for the edit operation. */
typedef enum typedef enum
@ -818,6 +858,22 @@ const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx,
gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key) gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
_GPGME_DEPRECATED; _GPGME_DEPRECATED;
/* 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);
/* Run control. */ /* Run control. */
@ -1209,16 +1265,6 @@ gpgme_error_t gpgme_op_sign (gpgme_ctx_t ctx,
/* Verify. */ /* 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. */ /* Flags used for the SUMMARY field in a gpgme_signature_t. */
typedef enum typedef enum

View File

@ -1,5 +1,5 @@
# libgpgme.vers - List of symbols to export. # 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. # This file is part of GPGME.
# #
@ -30,6 +30,10 @@ GPGME_1.1 {
gpgme_data_set_file_name; gpgme_data_set_file_name;
gpgme_data_get_file_name; gpgme_data_get_file_name;
gpgme_sig_notation_clear;
gpgme_sig_notation_add;
gpgme_sig_notation_get;
}; };

View File

@ -1,6 +1,6 @@
/* ops.h - Internal operation support. /* ops.h - Internal operation support.
Copyright (C) 2000 Werner Koch (dd9jn) 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. 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); void *type_data);
/*-- version.c --*/ /* From version.c. */
/* Return true if MY_VERSION is at least REQ_VERSION, and false /* Return true if MY_VERSION is at least REQ_VERSION, and false
otherwise. */ otherwise. */
int _gpgme_compare_versions (const char *my_version, int _gpgme_compare_versions (const char *my_version,
const char *req_version); const char *req_version);
char *_gpgme_get_program_version (const char *const path); char *_gpgme_get_program_version (const char *const path);
/* 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 */ #endif /* OPS_H */

View File

@ -1255,6 +1255,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 static gpgme_error_t
gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out, gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
gpgme_ctx_t ctx /* FIXME */) gpgme_ctx_t ctx /* FIXME */)
@ -1383,6 +1468,8 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
if (!err) if (!err)
err = append_args_from_signers (gpg, ctx); err = append_args_from_signers (gpg, ctx);
if (!err)
err = append_args_from_sig_notations (gpg, ctx);
/* Tell the gpg object about the data. */ /* Tell the gpg object about the data. */
if (!err) if (!err)
@ -1608,6 +1695,8 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
if (!err) if (!err)
err = append_args_from_signers (gpg, ctx); err = append_args_from_signers (gpg, ctx);
if (!err)
err = append_args_from_sig_notations (gpg, ctx);
if (gpgme_data_get_file_name (in)) if (gpgme_data_get_file_name (in))
{ {

123
gpgme/sig-notation.c Normal file
View File

@ -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"
/* 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);
}
/* 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;
}

View File

@ -1,6 +1,6 @@
/* verify.c - Signature verification. /* verify.c - Signature verification.
Copyright (C) 2000 Werner Koch (dd9jn) 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. This file is part of GPGME.
@ -58,10 +58,7 @@ release_op_data (void *hook)
{ {
gpgme_sig_notation_t next_nota = notation->next; gpgme_sig_notation_t next_nota = notation->next;
if (notation->name) _gpgme_sig_notation_free (notation);
free (notation->name);
if (notation->value)
free (notation->value);
notation = next_nota; 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. */ previous one. The crypto backend misbehaves. */
return gpg_error (GPG_ERR_INV_ENGINE); return gpg_error (GPG_ERR_INV_ENGINE);
notation = malloc (sizeof (*sig)); err = _gpgme_sig_notation_create (&notation, NULL, 0, NULL, 0, 0);
if (!notation) if (err)
return gpg_error_from_errno (errno); return err;
notation->next = NULL;
if (code == GPGME_STATUS_NOTATION_NAME) if (code == GPGME_STATUS_NOTATION_NAME)
{ {
int len = strlen (args) + 1; err = _gpgme_decode_percent_string (args, &notation->name, 0);
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);
if (err) if (err)
{ {
free (notation->name); _gpgme_sig_notation_free (notation);
free (notation);
return err; 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 else
{ {
int len = strlen (args) + 1; /* This is a policy URL. */
notation->name = NULL; err = _gpgme_decode_percent_string (args, &notation->value, 0);
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);
if (err) if (err)
{ {
free (notation->value); _gpgme_sig_notation_free (notation);
free (notation);
return err; return err;
} }
notation->value_len = strlen (notation->value);
} }
*lastp = notation; *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); err = _gpgme_decode_percent_string (args, &dest, len);
if (err) if (err)
return err; return err;
notation->value_len += strlen (dest);
} }
else else
return gpg_error (GPG_ERR_INV_ENGINE); return gpg_error (GPG_ERR_INV_ENGINE);

View 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> 2005-09-30 Marcus Brinkmann <marcus@g10code.de>
* gpg/Makefile.am (TESTS): Add t-filename. * gpg/Makefile.am (TESTS): Add t-filename.

View File

@ -26,7 +26,7 @@ TESTS_ENVIRONMENT = GNUPGHOME=. GPG_AGENT_INFO=
# The keylist tests must come after the import and the edit test. # The keylist tests must come after the import and the edit test.
noinst_HEADERS = t-support.h noinst_HEADERS = t-support.h
TESTS = t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers \ 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-export t-import t-trustlist t-eventloop t-edit \
t-keylist t-keylist-sig t-thread1 t-wait t-encrypt-large \ t-keylist t-keylist-sig t-thread1 t-wait t-encrypt-large \
t-file-name t-file-name

27
tests/gpg/gpg.conf Normal file
View File

@ -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

166
tests/gpg/t-sig-notation.c Normal file
View File

@ -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"
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;
}

View 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++) for (i=0; i < DIM(expected_notations); i++)
{ {
if ( ((r->name && expected_notations[i].name if ( ((r->name && expected_notations[i].name
&& !strcmp (r->name, expected_notations[i].name)) && !strcmp (r->name, expected_notations[i].name)
|| (!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 && 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++; expected_notations[i].seen++;
any++; any++;